summaryrefslogtreecommitdiff
path: root/chromium/components
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components')
-rw-r--r--chromium/components/BUILD.gn18
-rw-r--r--chromium/components/OWNERS10
-rw-r--r--chromium/components/about_handler/OWNERS2
-rw-r--r--chromium/components/about_ui/OWNERS2
-rw-r--r--chromium/components/app_modal/javascript_dialog_manager.cc9
-rw-r--r--chromium/components/arc/BUILD.gn7
-rw-r--r--chromium/components/arc/DEPS1
-rw-r--r--chromium/components/arc/arc_bridge_host_impl.cc11
-rw-r--r--chromium/components/arc/arc_bridge_host_impl.h3
-rw-r--r--chromium/components/arc/arc_bridge_service.h10
-rw-r--r--chromium/components/arc/arc_session.cc3
-rw-r--r--chromium/components/arc/arc_util.cc10
-rw-r--r--chromium/components/arc/arc_util.h8
-rw-r--r--chromium/components/arc/audio/arc_audio_bridge.cc2
-rw-r--r--chromium/components/arc/bluetooth/bluetooth_type_converters.cc10
-rw-r--r--chromium/components/arc/bluetooth/bluetooth_type_converters_unittest.cc10
-rw-r--r--chromium/components/arc/common/OWNERS5
-rw-r--r--chromium/components/arc/common/app.mojom9
-rw-r--r--chromium/components/arc/common/arc_bridge.mojom13
-rw-r--r--chromium/components/arc/common/file_system.typemap11
-rw-r--r--chromium/components/arc/common/input.mojom17
-rw-r--r--chromium/components/arc/common/notifications.mojom14
-rw-r--r--chromium/components/arc/common/power.mojom14
-rw-r--r--chromium/components/arc/common/tracing.mojom18
-rw-r--r--chromium/components/arc/common/typemaps.gni1
-rw-r--r--chromium/components/arc/common/voice_interaction_framework.mojom36
-rw-r--r--chromium/components/arc/common/wallpaper.mojom15
-rw-r--r--chromium/components/arc/file_system/OWNERS2
-rw-r--r--chromium/components/arc/file_system/file_system_struct_traits.cc42
-rw-r--r--chromium/components/arc/file_system/file_system_struct_traits.h23
-rw-r--r--chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc17
-rw-r--r--chromium/components/arc/kiosk/arc_kiosk_bridge_unittest.cc59
-rw-r--r--chromium/components/arc/net/arc_net_host_impl.cc6
-rw-r--r--chromium/components/arc/power/arc_power_bridge.cc49
-rw-r--r--chromium/components/arc/power/arc_power_bridge.h11
-rw-r--r--chromium/components/autofill/OWNERS5
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.cc16
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.h7
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc11
-rw-r--r--chromium/components/autofill/content/browser/key_press_handler_manager_unittest.cc2
-rw-r--r--chromium/components/autofill/content/browser/risk/fingerprint.cc2
-rw-r--r--chromium/components/autofill/content/common/OWNERS2
-rw-r--r--chromium/components/autofill/content/common/autofill_agent.mojom4
-rw-r--r--chromium/components/autofill/content/common/autofill_driver.mojom3
-rw-r--r--chromium/components/autofill/content/common/autofill_types.mojom21
-rw-r--r--chromium/components/autofill/content/common/autofill_types.typemap2
-rw-r--r--chromium/components/autofill/content/common/autofill_types_struct_traits.cc62
-rw-r--r--chromium/components/autofill/content/common/autofill_types_struct_traits.h70
-rw-r--r--chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc30
-rw-r--r--chromium/components/autofill/content/renderer/BUILD.gn2
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.cc265
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.h67
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.cc587
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.h21
-rw-r--r--chromium/components/autofill/content/renderer/form_cache.cc77
-rw-r--r--chromium/components/autofill/content/renderer/form_classifier.cc48
-rw-r--r--chromium/components/autofill/content/renderer/page_click_tracker.cc67
-rw-r--r--chromium/components/autofill/content/renderer/page_click_tracker.h42
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.cc394
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.h30
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils.cc229
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils.h7
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc168
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.cc235
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.h12
-rw-r--r--chromium/components/autofill/content/renderer/provisionally_saved_password_form.cc41
-rw-r--r--chromium/components/autofill/content/renderer/provisionally_saved_password_form.h58
-rw-r--r--chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.cc4
-rw-r--r--chromium/components/autofill/content/renderer/test_password_generation_agent.cc2
-rw-r--r--chromium/components/autofill/content/renderer/test_password_generation_agent.h2
-rw-r--r--chromium/components/autofill/core/browser/BUILD.gn23
-rw-r--r--chromium/components/autofill/core/browser/address_i18n_unittest.cc132
-rw-r--r--chromium/components/autofill/core/browser/autocomplete_history_manager.cc2
-rw-r--r--chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc3
-rw-r--r--chromium/components/autofill/core/browser/autofill_address_util.cc165
-rw-r--r--chromium/components/autofill/core/browser/autofill_address_util.h78
-rw-r--r--chromium/components/autofill/core/browser/autofill_assistant_unittest.cc12
-rw-r--r--chromium/components/autofill/core/browser/autofill_client.h23
-rw-r--r--chromium/components/autofill/core/browser/autofill_data_model_unittest.cc104
-rw-r--r--chromium/components/autofill/core/browser/autofill_data_util_unittest.cc293
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager.cc78
-rw-r--r--chromium/components/autofill/core/browser/autofill_driver.h9
-rw-r--r--chromium/components/autofill/core/browser/autofill_driver_factory.cc13
-rw-r--r--chromium/components/autofill/core/browser/autofill_driver_factory.h8
-rw-r--r--chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc61
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments.cc12
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments.h5
-rw-r--r--chromium/components/autofill/core/browser/autofill_field_unittest.cc763
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.cc253
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.h21
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager_unittest.cc451
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics.cc244
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics.h160
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics_unittest.cc804
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile.cc4
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_comparator.cc16
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_unittest.cc33
-rw-r--r--chromium/components/autofill/core/browser/autofill_regex_constants.cc29
-rw-r--r--chromium/components/autofill/core/browser/autofill_regex_constants.h6
-rw-r--r--chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc1
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.cc10
-rw-r--r--chromium/components/autofill/core/browser/autofill_type.cc10
-rw-r--r--chromium/components/autofill/core/browser/contact_info_unittest.cc398
-rw-r--r--chromium/components/autofill/core/browser/country_combobox_model.h2
-rw-r--r--chromium/components/autofill/core/browser/country_names.cc2
-rw-r--r--chromium/components/autofill/core/browser/credit_card.cc6
-rw-r--r--chromium/components/autofill/core/browser/credit_card_field.h2
-rw-r--r--chromium/components/autofill/core/browser/credit_card_field_unittest.cc263
-rw-r--r--chromium/components/autofill/core/browser/credit_card_unittest.cc883
-rw-r--r--chromium/components/autofill/core/browser/field_types.h5
-rw-r--r--chromium/components/autofill/core/browser/form_group.cc10
-rw-r--r--chromium/components/autofill/core/browser/form_group.h4
-rw-r--r--chromium/components/autofill/core/browser/form_structure.cc154
-rw-r--r--chromium/components/autofill/core/browser/form_structure.h52
-rw-r--r--chromium/components/autofill/core/browser/form_structure_unittest.cc128
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request.cc8
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request.h7
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client.cc38
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.cc6
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.h14
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_unittest.cc873
-rw-r--r--chromium/components/autofill/core/browser/phone_number_i18n_unittest.cc126
-rw-r--r--chromium/components/autofill/core/browser/region_combobox_model.cc117
-rw-r--r--chromium/components/autofill/core/browser/region_combobox_model.h88
-rw-r--r--chromium/components/autofill/core/browser/region_combobox_model_unittest.cc107
-rw-r--r--chromium/components/autofill/core/browser/risk_data_loader.h26
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.cc18
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.h6
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_driver.cc2
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_driver.h2
-rw-r--r--chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller.h1
-rw-r--r--chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc4
-rw-r--r--chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h2
-rw-r--r--chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc219
-rw-r--r--chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.cc22
-rw-r--r--chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h42
-rw-r--r--chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h70
-rw-r--r--chromium/components/autofill/core/browser/validation.cc22
-rw-r--r--chromium/components/autofill/core/browser/validation.h16
-rw-r--r--chromium/components/autofill/core/browser/validation_unittest.cc77
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc6
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h7
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc3
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc186
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.cc20
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.h2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc139
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc5
-rw-r--r--chromium/components/autofill/core/common/BUILD.gn1
-rw-r--r--chromium/components/autofill/core/common/autofill_clock.cc2
-rw-r--r--chromium/components/autofill/core/common/autofill_clock.h2
-rw-r--r--chromium/components/autofill/core/common/autofill_data_validation.cc1
-rw-r--r--chromium/components/autofill/core/common/autofill_regexes_unittest.cc341
-rw-r--r--chromium/components/autofill/core/common/autofill_util_unittest.cc221
-rw-r--r--chromium/components/autofill/core/common/password_form.cc17
-rw-r--r--chromium/components/autofill/core/common/password_form.h12
-rw-r--r--chromium/components/autofill/core/common/password_form_fill_data.cc11
-rw-r--r--chromium/components/autofill/core/common/password_form_fill_data.h5
-rw-r--r--chromium/components/autofill/core/common/password_form_generation_data.cc21
-rw-r--r--chromium/components/autofill/core/common/password_form_generation_data.h11
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger.cc40
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger.h16
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc6
-rw-r--r--chromium/components/autofill/ios/browser/autofill_driver_ios.h2
-rw-r--r--chromium/components/autofill/ios/browser/autofill_driver_ios.mm2
-rw-r--r--chromium/components/autofill_strings.grdp9
-rw-r--r--chromium/components/background_task_scheduler/README.md52
-rw-r--r--chromium/components/bookmarks/browser/bookmark_codec.cc2
-rw-r--r--chromium/components/bookmarks/browser/bookmark_expanded_state_tracker.cc4
-rw-r--r--chromium/components/bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc2
-rw-r--r--chromium/components/bookmarks/browser/bookmark_utils.cc3
-rw-r--r--chromium/components/bookmarks/browser/titled_url_index.cc4
-rw-r--r--chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc27
-rw-r--r--chromium/components/browser_sync/BUILD.gn3
-rw-r--r--chromium/components/browser_sync/profile_sync_components_factory_impl.cc11
-rw-r--r--chromium/components/browser_sync/profile_sync_service.cc69
-rw-r--r--chromium/components/browser_sync/profile_sync_service.h27
-rw-r--r--chromium/components/browser_sync/profile_sync_service_mock.cc8
-rw-r--r--chromium/components/browser_sync/profile_sync_service_mock.h3
-rw-r--r--chromium/components/browser_sync/profile_sync_service_typed_url_unittest.cc4
-rw-r--r--chromium/components/browser_sync/profile_sync_service_unittest.cc37
-rw-r--r--chromium/components/browser_sync/profile_sync_test_util.cc4
-rw-r--r--chromium/components/browser_watcher/BUILD.gn36
-rw-r--r--chromium/components/browser_watcher/dump_postmortem_minidump_main_win.cc7
-rw-r--r--chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc23
-rw-r--r--chromium/components/browser_watcher/features.cc3
-rw-r--r--chromium/components/browser_watcher/features.h6
-rw-r--r--chromium/components/browser_watcher/fetch_system_session_events_main_win.cc48
-rw-r--r--chromium/components/browser_watcher/postmortem_report_collector.cc321
-rw-r--r--chromium/components/browser_watcher/postmortem_report_collector.h52
-rw-r--r--chromium/components/browser_watcher/postmortem_report_collector_unittest.cc222
-rw-r--r--chromium/components/browser_watcher/postmortem_report_extractor.cc268
-rw-r--r--chromium/components/browser_watcher/postmortem_report_extractor.h36
-rw-r--r--chromium/components/browser_watcher/stability_data_names.cc1
-rw-r--r--chromium/components/browser_watcher/stability_data_names.h1
-rw-r--r--chromium/components/browser_watcher/stability_debugging.cc2
-rw-r--r--chromium/components/browser_watcher/stability_report.proto30
-rw-r--r--chromium/components/browser_watcher/system_session_analyzer_win.cc244
-rw-r--r--chromium/components/browser_watcher/system_session_analyzer_win.h75
-rw-r--r--chromium/components/browser_watcher/system_session_analyzer_win_unittest.cc117
-rw-r--r--chromium/components/browser_watcher/watcher_metrics_provider_win.cc19
-rw-r--r--chromium/components/browsing_data/content/BUILD.gn4
-rw-r--r--chromium/components/browsing_data/content/conditional_cache_deletion_helper.cc96
-rw-r--r--chromium/components/browsing_data/content/conditional_cache_deletion_helper.h73
-rw-r--r--chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.cc194
-rw-r--r--chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.h101
-rw-r--r--chromium/components/browsing_data/core/BUILD.gn7
-rw-r--r--chromium/components/browsing_data/core/DEPS1
-rw-r--r--chromium/components/browsing_data/core/browsing_data_utils.cc78
-rw-r--r--chromium/components/browsing_data/core/browsing_data_utils.h17
-rw-r--r--chromium/components/browsing_data/core/browsing_data_utils_unittest.cc39
-rw-r--r--chromium/components/browsing_data/core/clear_browsing_data_tab.h21
-rw-r--r--chromium/components/browsing_data/core/counters/browsing_data_counter.cc11
-rw-r--r--chromium/components/browsing_data/core/counters/browsing_data_counter.h18
-rw-r--r--chromium/components/browsing_data/core/counters/browsing_data_counter_unittest.cc4
-rw-r--r--chromium/components/browsing_data/core/counters/history_counter.cc4
-rw-r--r--chromium/components/browsing_data/core/pref_names.cc30
-rw-r--r--chromium/components/browsing_data/core/pref_names.h5
-rw-r--r--chromium/components/browsing_data_strings.grdp12
-rw-r--r--chromium/components/captive_portal/OWNERS2
-rw-r--r--chromium/components/captive_portal/captive_portal_detector_unittest.cc3
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator.cc54
-rw-r--r--chromium/components/cast_certificate/cast_crl.cc2
-rw-r--r--chromium/components/cdm/browser/BUILD.gn26
-rw-r--r--chromium/components/cdm/browser/DEPS3
-rw-r--r--chromium/components/cdm/browser/media_drm_storage_impl.cc312
-rw-r--r--chromium/components/cdm/browser/media_drm_storage_impl.h73
-rw-r--r--chromium/components/cdm/browser/media_drm_storage_impl_unittest.cc196
-rw-r--r--chromium/components/cdm/renderer/android_key_systems.cc2
-rw-r--r--chromium/components/certificate_reporting/OWNERS4
-rw-r--r--chromium/components/certificate_transparency/OWNERS3
-rw-r--r--chromium/components/certificate_transparency/ct_policy_manager_unittest.cc5
-rw-r--r--chromium/components/chrome_apps/webstore_widget/cws_widget/compiled_resources.gypi1
-rw-r--r--chromium/components/chrome_apps/webstore_widget/cws_widget/compiled_resources2.gyp47
-rw-r--r--chromium/components/chrome_apps/webstore_widget/externs/compiled_resources2.gyp15
-rw-r--r--chromium/components/chrome_cleaner/DEPS10
-rw-r--r--chromium/components/chrome_cleaner/OWNERS5
-rw-r--r--chromium/components/chrome_cleaner/public/interfaces/BUILD.gn11
-rw-r--r--chromium/components/chrome_cleaner/public/interfaces/OWNERS7
-rw-r--r--chromium/components/chrome_cleaner/public/interfaces/chrome_prompt.mojom72
-rw-r--r--chromium/components/client_update_protocol/ecdsa.cc9
-rw-r--r--chromium/components/cloud_devices/common/cloud_devices_urls.h1
-rw-r--r--chromium/components/component_updater/component_updater_service.h4
-rw-r--r--chromium/components/component_updater/configurator_impl.cc4
-rw-r--r--chromium/components/component_updater/configurator_impl.h3
-rw-r--r--chromium/components/component_updater/configurator_impl_unittest.cc2
-rw-r--r--chromium/components/components_strings.grd15
-rw-r--r--chromium/components/constrained_window/BUILD.gn1
-rw-r--r--chromium/components/constrained_window/OWNERS2
-rw-r--r--chromium/components/constrained_window/constrained_window_views.cc2
-rw-r--r--chromium/components/constrained_window/constrained_window_views_unittest.cc2
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_registry.cc2
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_registry.h2
-rw-r--r--chromium/components/content_settings/core/browser/host_content_settings_map.cc6
-rw-r--r--chromium/components/content_settings/core/browser/website_settings_registry.cc9
-rw-r--r--chromium/components/content_settings/core/browser/website_settings_registry.h2
-rw-r--r--chromium/components/content_settings/core/common/content_settings_types.h4
-rw-r--r--chromium/components/contextual_search/renderer/contextual_search_wrapper.cc4
-rw-r--r--chromium/components/cookie_config/cookie_store_util.cc4
-rw-r--r--chromium/components/crash/content/app/breakpad_linux.cc15
-rw-r--r--chromium/components/crash/content/app/breakpad_win.cc10
-rw-r--r--chromium/components/crash/content/app/crash_reporter_client.cc6
-rw-r--r--chromium/components/crash/content/app/crash_reporter_client.h16
-rw-r--r--chromium/components/crash/content/app/crashpad.cc6
-rw-r--r--chromium/components/crash/content/app/crashpad.h13
-rw-r--r--chromium/components/crash/content/app/crashpad_mac.mm30
-rw-r--r--chromium/components/crash/content/app/crashpad_win.cc53
-rw-r--r--chromium/components/crash/content/app/fallback_crash_handler_launcher_win_unittest.cc5
-rw-r--r--chromium/components/crash/content/app/fallback_crash_handler_win.cc1
-rw-r--r--chromium/components/crash/content/app/fallback_crash_handler_win_unittest.cc6
-rw-r--r--chromium/components/crash/content/app/fallback_crash_handling_win_unittest.cc6
-rw-r--r--chromium/components/crash/content/app/run_as_crashpad_handler_win.cc43
-rw-r--r--chromium/components/crash/content/app/run_as_crashpad_handler_win.h9
-rw-r--r--chromium/components/crash/content/browser/crash_dump_observer_android.cc3
-rw-r--r--chromium/components/crash/content/browser/crash_dump_observer_android.h2
-rw-r--r--chromium/components/cronet/android/BUILD.gn28
-rw-r--r--chromium/components/cronet/ios/BUILD.gn78
-rw-r--r--chromium/components/cronet/ios/test/BUILD.gn1
-rw-r--r--chromium/components/crx_file/crx_file.cc6
-rw-r--r--chromium/components/crx_file/id_util.cc8
-rw-r--r--chromium/components/crx_file/id_util.h4
-rw-r--r--chromium/components/crx_file/id_util_unittest.cc7
-rw-r--r--chromium/components/cryptauth/BUILD.gn4
-rw-r--r--chromium/components/cryptauth/OWNERS2
-rw-r--r--chromium/components/cryptauth/ble/OWNERS2
-rw-r--r--chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc2
-rw-r--r--chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h3
-rw-r--r--chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc46
-rw-r--r--chromium/components/cryptauth/bluetooth_throttler_impl.cc10
-rw-r--r--chromium/components/cryptauth/bluetooth_throttler_impl.h13
-rw-r--r--chromium/components/cryptauth/cryptauth_device_manager_unittest.cc12
-rw-r--r--chromium/components/cryptauth/cryptauth_enrollment_manager.h4
-rw-r--r--chromium/components/cryptauth/cryptauth_enrollment_manager_unittest.cc11
-rw-r--r--chromium/components/cryptauth/cryptauth_service.cc20
-rw-r--r--chromium/components/cryptauth/cryptauth_service.h45
-rw-r--r--chromium/components/cryptauth/fake_cryptauth_service.cc46
-rw-r--r--chromium/components/cryptauth/fake_cryptauth_service.h65
-rw-r--r--chromium/components/cryptauth/fake_secure_channel.cc4
-rw-r--r--chromium/components/cryptauth/fake_secure_channel.h4
-rw-r--r--chromium/components/cryptauth/secure_channel.cc22
-rw-r--r--chromium/components/cryptauth/secure_channel.h18
-rw-r--r--chromium/components/cryptauth/secure_channel_unittest.cc33
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc6
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc15
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc97
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc95
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h13
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc314
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc19
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h4
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h1
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc25
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc3
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc7
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h33
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc36
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc23
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc21
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc59
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc176
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h9
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc510
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc66
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h23
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc281
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs_unittest.cc3
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc28
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h18
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc55
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc31
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h18
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc20
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h11
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc3
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.cc5
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc6
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_store.cc4
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_store.h3
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc9
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_store_impl.h8
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc28
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_usage_store.h6
-rw-r--r--chromium/components/data_reduction_proxy/core/common/BUILD.gn3
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_bypass_type_list.h5
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc9
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc20
-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.cc117
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h17
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc160
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc6
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h5
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc8
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h3
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc38
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc4
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h1
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_savings_recorder.h30
-rw-r--r--chromium/components/data_reduction_proxy/proto/pageload_metrics.proto29
-rw-r--r--chromium/components/data_usage/core/data_use_aggregator_unittest.cc5
-rw-r--r--chromium/components/data_use_measurement/content/BUILD.gn1
-rw-r--r--chromium/components/data_use_measurement/content/DEPS1
-rw-r--r--chromium/components/data_use_measurement/content/content_url_request_classifier.cc97
-rw-r--r--chromium/components/data_use_measurement/content/content_url_request_classifier.h7
-rw-r--r--chromium/components/data_use_measurement/core/data_use_measurement.cc35
-rw-r--r--chromium/components/data_use_measurement/core/data_use_measurement.h5
-rw-r--r--chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc13
-rw-r--r--chromium/components/data_use_measurement/core/data_use_network_delegate_unittest.cc13
-rw-r--r--chromium/components/data_use_measurement/core/data_use_recorder.h9
-rw-r--r--chromium/components/data_use_measurement/core/data_use_user_data.cc4
-rw-r--r--chromium/components/data_use_measurement/core/data_use_user_data.h5
-rw-r--r--chromium/components/data_use_measurement/core/url_request_classifier.h9
-rw-r--r--chromium/components/device_event_log/README.md49
-rw-r--r--chromium/components/device_event_log/device_event_log.h31
-rw-r--r--chromium/components/device_event_log/device_event_log_impl.cc41
-rw-r--r--chromium/components/display_compositor/BUILD.gn8
-rw-r--r--chromium/components/display_compositor/DEPS2
-rw-r--r--chromium/components/display_compositor/buffer_queue.cc5
-rw-r--r--chromium/components/display_compositor/compositor_overlay_candidate_validator_android.cc4
-rw-r--r--chromium/components/display_compositor/compositor_overlay_candidate_validator_android.h1
-rw-r--r--chromium/components/display_compositor/compositor_overlay_candidate_validator_mac.h1
-rw-r--r--chromium/components/display_compositor/compositor_overlay_candidate_validator_mac.mm4
-rw-r--r--chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.cc18
-rw-r--r--chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.h1
-rw-r--r--chromium/components/display_compositor/compositor_overlay_candidate_validator_win.cc17
-rw-r--r--chromium/components/display_compositor/compositor_overlay_candidate_validator_win.h1
-rw-r--r--chromium/components/display_compositor/host_shared_bitmap_manager.cc264
-rw-r--r--chromium/components/display_compositor/host_shared_bitmap_manager.h121
-rw-r--r--chromium/components/display_compositor/host_shared_bitmap_manager_unittest.cc165
-rw-r--r--chromium/components/display_compositor/yuv_readback_unittest.cc3
-rw-r--r--chromium/components/dom_distiller/DEPS1
-rw-r--r--chromium/components/dom_distiller/content/browser/distillability_driver.cc2
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc22
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h3
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc3
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_ui_handle.h5
-rw-r--r--chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc6
-rw-r--r--chromium/components/dom_distiller/content/browser/external_feedback_reporter.h32
-rw-r--r--chromium/components/dom_distiller/content/browser/web_contents_main_frame_observer.cc2
-rw-r--r--chromium/components/dom_distiller/content/common/distiller_javascript_service.mojom3
-rw-r--r--chromium/components/dom_distiller/content/renderer/distillability_agent.cc42
-rw-r--r--chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc8
-rw-r--r--chromium/components/dom_distiller/core/BUILD.gn2
-rw-r--r--chromium/components/dom_distiller/core/css/distilledpage.css75
-rw-r--r--chromium/components/dom_distiller/core/distiller_unittest.cc5
-rw-r--r--chromium/components/dom_distiller/core/distiller_url_fetcher.cc34
-rw-r--r--chromium/components/dom_distiller/core/dom_distiller_request_view_base.cc8
-rw-r--r--chromium/components/dom_distiller/core/experiments.cc25
-rw-r--r--chromium/components/dom_distiller/core/experiments.h1
-rw-r--r--chromium/components/dom_distiller/core/html/dom_distiller_viewer.html1
-rw-r--r--chromium/components/dom_distiller/core/javascript/dom_distiller_viewer.js65
-rw-r--r--chromium/components/dom_distiller/core/javascript/domdistiller.js5
-rw-r--r--chromium/components/dom_distiller/core/page_features_unittest.cc2
-rw-r--r--chromium/components/dom_distiller/core/viewer.cc32
-rw-r--r--chromium/components/dom_distiller/core/viewer.h3
-rw-r--r--chromium/components/dom_distiller/ios/distiller_page_ios.mm6
-rw-r--r--chromium/components/domain_reliability/OWNERS2
-rw-r--r--chromium/components/domain_reliability/quic_error_mapping.cc463
-rw-r--r--chromium/components/doodle/BUILD.gn6
-rw-r--r--chromium/components/doodle/DEPS3
-rw-r--r--chromium/components/doodle/doodle_fetcher.h8
-rw-r--r--chromium/components/doodle/doodle_fetcher_impl.cc180
-rw-r--r--chromium/components/doodle/doodle_fetcher_impl.h23
-rw-r--r--chromium/components/doodle/doodle_fetcher_impl_unittest.cc321
-rw-r--r--chromium/components/doodle/doodle_service.cc218
-rw-r--r--chromium/components/doodle/doodle_service.h80
-rw-r--r--chromium/components/doodle/doodle_service_unittest.cc412
-rw-r--r--chromium/components/doodle/doodle_types.cc204
-rw-r--r--chromium/components/doodle/doodle_types.h42
-rw-r--r--chromium/components/doodle/doodle_types_unittest.cc259
-rw-r--r--chromium/components/doodle/pref_names.cc14
-rw-r--r--chromium/components/doodle/pref_names.h17
-rw-r--r--chromium/components/error_page/OWNERS4
-rw-r--r--chromium/components/error_page/common/localized_error.cc9
-rw-r--r--chromium/components/error_page/renderer/net_error_helper_core.cc38
-rw-r--r--chromium/components/error_page/renderer/net_error_helper_core_unittest.cc18
-rw-r--r--chromium/components/exo/BUILD.gn5
-rw-r--r--chromium/components/exo/buffer.cc2
-rw-r--r--chromium/components/exo/compositor_frame_sink.cc35
-rw-r--r--chromium/components/exo/compositor_frame_sink.h8
-rw-r--r--chromium/components/exo/compositor_frame_sink_holder.cc54
-rw-r--r--chromium/components/exo/compositor_frame_sink_holder.h17
-rw-r--r--chromium/components/exo/display.cc11
-rw-r--r--chromium/components/exo/display.h1
-rw-r--r--chromium/components/exo/display_unittest.cc9
-rw-r--r--chromium/components/exo/gaming_seat.cc8
-rw-r--r--chromium/components/exo/gaming_seat.h2
-rw-r--r--chromium/components/exo/gaming_seat_unittest.cc8
-rw-r--r--chromium/components/exo/pointer.cc93
-rw-r--r--chromium/components/exo/pointer.h4
-rw-r--r--chromium/components/exo/pointer_delegate.h3
-rw-r--r--chromium/components/exo/pointer_unittest.cc20
-rw-r--r--chromium/components/exo/shell_surface.cc323
-rw-r--r--chromium/components/exo/shell_surface.h25
-rw-r--r--chromium/components/exo/shell_surface_unittest.cc77
-rw-r--r--chromium/components/exo/surface.cc85
-rw-r--r--chromium/components/exo/surface.h29
-rw-r--r--chromium/components/exo/surface_unittest.cc45
-rw-r--r--chromium/components/exo/touch_unittest.cc20
-rw-r--r--chromium/components/exo/wayland/BUILD.gn5
-rw-r--r--chromium/components/exo/wayland/clients/client_base.cc19
-rw-r--r--chromium/components/exo/wayland/clients/client_base.h4
-rw-r--r--chromium/components/exo/wayland/clients/yuv.cc10
-rw-r--r--chromium/components/exo/wayland/server.cc83
-rw-r--r--chromium/components/exo/wm_helper.cc15
-rw-r--r--chromium/components/exo/wm_helper.h13
-rw-r--r--chromium/components/exo/wm_helper_ash.cc74
-rw-r--r--chromium/components/exo/wm_helper_ash.h21
-rw-r--r--chromium/components/exo/wm_helper_mus.cc23
-rw-r--r--chromium/components/exo/wm_helper_mus.h16
-rw-r--r--chromium/components/favicon/content/content_favicon_driver.cc5
-rw-r--r--chromium/components/favicon/content/content_favicon_driver_unittest.cc48
-rw-r--r--chromium/components/favicon/core/BUILD.gn5
-rw-r--r--chromium/components/favicon/core/DEPS3
-rw-r--r--chromium/components/favicon/core/fallback_icon_service.cc11
-rw-r--r--chromium/components/favicon/core/favicon_driver_impl.cc37
-rw-r--r--chromium/components/favicon/core/favicon_driver_impl.h7
-rw-r--r--chromium/components/favicon/core/favicon_handler.cc488
-rw-r--r--chromium/components/favicon/core/favicon_handler.h147
-rw-r--r--chromium/components/favicon/core/favicon_handler_unittest.cc2470
-rw-r--r--chromium/components/favicon/core/favicon_service.h14
-rw-r--r--chromium/components/favicon/core/favicon_service_impl.cc43
-rw-r--r--chromium/components/favicon/core/favicon_service_impl.h5
-rw-r--r--chromium/components/favicon/core/large_icon_service.cc350
-rw-r--r--chromium/components/favicon/core/large_icon_service.h58
-rw-r--r--chromium/components/favicon/core/large_icon_service_unittest.cc473
-rw-r--r--chromium/components/favicon/ios/web_favicon_driver.mm11
-rw-r--r--chromium/components/favicon_base/favicon_callback.h9
-rw-r--r--chromium/components/favicon_base/favicon_types.cc12
-rw-r--r--chromium/components/favicon_base/favicon_types.h20
-rw-r--r--chromium/components/favicon_base/select_favicon_frames.cc3
-rw-r--r--chromium/components/feature_engagement_tracker/BUILD.gn35
-rw-r--r--chromium/components/feature_engagement_tracker/DEPS5
-rw-r--r--chromium/components/feature_engagement_tracker/OWNERS2
-rw-r--r--chromium/components/feature_engagement_tracker/README.md14
-rw-r--r--chromium/components/feature_engagement_tracker/internal/BUILD.gn103
-rw-r--r--chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc131
-rw-r--r--chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h79
-rw-r--r--chromium/components/feature_engagement_tracker/internal/condition_validator.h36
-rw-r--r--chromium/components/feature_engagement_tracker/internal/configuration.cc20
-rw-r--r--chromium/components/feature_engagement_tracker/internal/configuration.h59
-rw-r--r--chromium/components/feature_engagement_tracker/internal/editable_configuration.cc31
-rw-r--r--chromium/components/feature_engagement_tracker/internal/editable_configuration.h43
-rw-r--r--chromium/components/feature_engagement_tracker/internal/editable_configuration_unittest.cc86
-rw-r--r--chromium/components/feature_engagement_tracker/internal/feature_constants.cc17
-rw-r--r--chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc108
-rw-r--r--chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h56
-rw-r--r--chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc95
-rw-r--r--chromium/components/feature_engagement_tracker/internal/feature_list.cc23
-rw-r--r--chromium/components/feature_engagement_tracker/internal/feature_list.h20
-rw-r--r--chromium/components/feature_engagement_tracker/internal/in_memory_store.cc46
-rw-r--r--chromium/components/feature_engagement_tracker/internal/in_memory_store.h47
-rw-r--r--chromium/components/feature_engagement_tracker/internal/in_memory_store_unittest.cc69
-rw-r--r--chromium/components/feature_engagement_tracker/internal/model.h67
-rw-r--r--chromium/components/feature_engagement_tracker/internal/model_impl.cc120
-rw-r--r--chromium/components/feature_engagement_tracker/internal/model_impl.h80
-rw-r--r--chromium/components/feature_engagement_tracker/internal/model_impl_unittest.cc385
-rw-r--r--chromium/components/feature_engagement_tracker/internal/never_condition_validator.cc20
-rw-r--r--chromium/components/feature_engagement_tracker/internal/never_condition_validator.h37
-rw-r--r--chromium/components/feature_engagement_tracker/internal/never_condition_validator_unittest.cc78
-rw-r--r--chromium/components/feature_engagement_tracker/internal/once_condition_validator.cc37
-rw-r--r--chromium/components/feature_engagement_tracker/internal/once_condition_validator.h51
-rw-r--r--chromium/components/feature_engagement_tracker/internal/once_condition_validator_unittest.cc163
-rw-r--r--chromium/components/feature_engagement_tracker/internal/proto/BUILD.gn11
-rw-r--r--chromium/components/feature_engagement_tracker/internal/proto/event.proto27
-rw-r--r--chromium/components/feature_engagement_tracker/internal/single_invalid_configuration.cc23
-rw-r--r--chromium/components/feature_engagement_tracker/internal/single_invalid_configuration.h39
-rw-r--r--chromium/components/feature_engagement_tracker/internal/single_invalid_configuration_unittest.cc46
-rw-r--r--chromium/components/feature_engagement_tracker/internal/store.h44
-rw-r--r--chromium/components/feature_engagement_tracker/public/BUILD.gn38
-rw-r--r--chromium/components/feature_engagement_tracker/public/feature_constants.h23
-rw-r--r--chromium/components/feature_engagement_tracker/public/feature_engagement_tracker.h77
-rw-r--r--chromium/components/feedback/DEPS1
-rw-r--r--chromium/components/feedback/OWNERS4
-rw-r--r--chromium/components/feedback/feedback_data_unittest.cc8
-rw-r--r--chromium/components/feedback/feedback_uploader_chrome.cc38
-rw-r--r--chromium/components/feedback/feedback_uploader_unittest.cc9
-rw-r--r--chromium/components/filesystem/file_system_app.cc15
-rw-r--r--chromium/components/filesystem/file_system_app.h8
-rw-r--r--chromium/components/flags_ui/OWNERS2
-rw-r--r--chromium/components/flags_ui/feature_entry.cc42
-rw-r--r--chromium/components/flags_ui/feature_entry.h34
-rw-r--r--chromium/components/flags_ui/feature_entry_macros.h7
-rw-r--r--chromium/components/flags_ui/flags_state.cc29
-rw-r--r--chromium/components/flags_ui/flags_state_unittest.cc38
-rw-r--r--chromium/components/flags_ui/pref_service_flags_storage.cc2
-rw-r--r--chromium/components/flags_ui_strings.grdp12
-rw-r--r--chromium/components/font_service/font_service_app.cc16
-rw-r--r--chromium/components/font_service/font_service_app.h7
-rw-r--r--chromium/components/google/core/browser/BUILD.gn11
-rw-r--r--chromium/components/google/core/browser/google_url_tracker.cc46
-rw-r--r--chromium/components/google/core/browser/google_url_tracker.h12
-rw-r--r--chromium/components/google/core/browser/google_url_tracker_unittest.cc3
-rw-r--r--chromium/components/guest_view/browser/guest_view_base.cc25
-rw-r--r--chromium/components/guest_view/browser/guest_view_base.h5
-rw-r--r--chromium/components/guest_view/browser/guest_view_manager.cc7
-rw-r--r--chromium/components/guest_view/renderer/BUILD.gn5
-rw-r--r--chromium/components/guest_view/renderer/guest_view_container.cc4
-rw-r--r--chromium/components/guest_view/renderer/guest_view_request.cc9
-rw-r--r--chromium/components/history/core/browser/BUILD.gn7
-rw-r--r--chromium/components/history/core/browser/download_database.cc36
-rw-r--r--chromium/components/history/core/browser/download_database.h6
-rw-r--r--chromium/components/history/core/browser/download_row.cc15
-rw-r--r--chromium/components/history/core/browser/download_row.h13
-rw-r--r--chromium/components/history/core/browser/history_backend.cc156
-rw-r--r--chromium/components/history/core/browser/history_backend.h38
-rw-r--r--chromium/components/history/core/browser/history_backend_db_unittest.cc76
-rw-r--r--chromium/components/history/core/browser/history_backend_unittest.cc106
-rw-r--r--chromium/components/history/core/browser/history_database.cc187
-rw-r--r--chromium/components/history/core/browser/history_database.h8
-rw-r--r--chromium/components/history/core/browser/history_model_worker.cc89
-rw-r--r--chromium/components/history/core/browser/history_model_worker.h6
-rw-r--r--chromium/components/history/core/browser/history_model_worker_unittest.cc227
-rw-r--r--chromium/components/history/core/browser/history_service.cc26
-rw-r--r--chromium/components/history/core/browser/history_service.h22
-rw-r--r--chromium/components/history/core/browser/history_service_unittest.cc62
-rw-r--r--chromium/components/history/core/browser/history_types.cc82
-rw-r--r--chromium/components/history/core/browser/history_types.h70
-rw-r--r--chromium/components/history/core/browser/in_memory_database.cc26
-rw-r--r--chromium/components/history/core/browser/thumbnail_database.cc240
-rw-r--r--chromium/components/history/core/browser/thumbnail_database_unittest.cc30
-rw-r--r--chromium/components/history/core/browser/top_sites_database.cc144
-rw-r--r--chromium/components/history/core/browser/top_sites_database_unittest.cc40
-rw-r--r--chromium/components/history/core/browser/top_sites_impl.cc3
-rw-r--r--chromium/components/history/core/browser/top_sites_impl_unittest.cc39
-rw-r--r--chromium/components/history/core/browser/typed_url_sync_bridge.cc103
-rw-r--r--chromium/components/history/core/browser/typed_url_sync_bridge.h63
-rw-r--r--chromium/components/history/core/browser/typed_url_sync_metadata_database.cc136
-rw-r--r--chromium/components/history/core/browser/typed_url_sync_metadata_database.h74
-rw-r--r--chromium/components/history/core/browser/typed_url_sync_metadata_database_unittest.cc143
-rw-r--r--chromium/components/history/core/browser/typed_url_syncable_service.cc81
-rw-r--r--chromium/components/history/core/browser/typed_url_syncable_service.h18
-rw-r--r--chromium/components/history/core/browser/typed_url_syncable_service_unittest.cc91
-rw-r--r--chromium/components/history/core/browser/url_database.cc85
-rw-r--r--chromium/components/history/core/browser/url_database.h3
-rw-r--r--chromium/components/history/core/browser/url_database_unittest.cc113
-rw-r--r--chromium/components/history/core/browser/url_row.cc73
-rw-r--r--chromium/components/history/core/browser/url_row.h40
-rw-r--r--chromium/components/history/core/browser/web_history_service_unittest.cc3
-rw-r--r--chromium/components/image_fetcher/core/BUILD.gn (renamed from chromium/components/image_fetcher/BUILD.gn)4
-rw-r--r--chromium/components/image_fetcher/core/image_data_fetcher.cc (renamed from chromium/components/image_fetcher/image_data_fetcher.cc)66
-rw-r--r--chromium/components/image_fetcher/core/image_data_fetcher.h (renamed from chromium/components/image_fetcher/image_data_fetcher.h)35
-rw-r--r--chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc297
-rw-r--r--chromium/components/image_fetcher/core/image_decoder.h (renamed from chromium/components/image_fetcher/image_decoder.h)6
-rw-r--r--chromium/components/image_fetcher/core/image_fetcher.h (renamed from chromium/components/image_fetcher/image_fetcher.h)29
-rw-r--r--chromium/components/image_fetcher/core/image_fetcher_delegate.h (renamed from chromium/components/image_fetcher/image_fetcher_delegate.h)11
-rw-r--r--chromium/components/image_fetcher/core/image_fetcher_impl.cc (renamed from chromium/components/image_fetcher/image_fetcher_impl.cc)36
-rw-r--r--chromium/components/image_fetcher/core/image_fetcher_impl.h (renamed from chromium/components/image_fetcher/image_fetcher_impl.h)34
-rw-r--r--chromium/components/image_fetcher/core/request_metadata.cc (renamed from chromium/components/image_fetcher/request_metadata.cc)9
-rw-r--r--chromium/components/image_fetcher/core/request_metadata.h35
-rw-r--r--chromium/components/image_fetcher/core/request_metadata_unittest.cc57
-rw-r--r--chromium/components/image_fetcher/image_data_fetcher_unittest.cc167
-rw-r--r--chromium/components/image_fetcher/ios/BUILD.gn8
-rw-r--r--chromium/components/image_fetcher/ios/DEPS1
-rw-r--r--chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h2
-rw-r--r--chromium/components/image_fetcher/ios/ios_image_decoder_impl.h23
-rw-r--r--chromium/components/image_fetcher/ios/ios_image_decoder_impl.mm106
-rw-r--r--chromium/components/image_fetcher/ios/ios_image_decoder_impl_unittest.mm112
-rw-r--r--chromium/components/image_fetcher/request_metadata.h24
-rw-r--r--chromium/components/image_fetcher/request_metadata_unittest.cc39
-rw-r--r--chromium/components/infobars/core/BUILD.gn1
-rw-r--r--chromium/components/infobars/core/infobar_delegate.cc5
-rw-r--r--chromium/components/infobars/core/infobar_delegate.h4
-rw-r--r--chromium/components/json_schema/json_schema_validator_unittest_base.cc74
-rw-r--r--chromium/components/keyed_service/content/browser_context_dependency_manager.cc8
-rw-r--r--chromium/components/keyed_service/content/browser_context_dependency_manager.h19
-rw-r--r--chromium/components/keyed_service/content/browser_context_keyed_base_factory.cc6
-rw-r--r--chromium/components/keyed_service/content/browser_context_keyed_service_factory.cc6
-rw-r--r--chromium/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc6
-rw-r--r--chromium/components/keyed_service/core/dependency_manager.cc19
-rw-r--r--chromium/components/keyed_service/core/dependency_manager.h22
-rw-r--r--chromium/components/keyed_service/core/keyed_service_base_factory.cc11
-rw-r--r--chromium/components/keyed_service/core/keyed_service_base_factory.h12
-rw-r--r--chromium/components/keyed_service/core/keyed_service_factory.cc4
-rw-r--r--chromium/components/keyed_service/core/refcounted_keyed_service_factory.cc6
-rw-r--r--chromium/components/keyed_service/ios/browser_state_context_converter.cc28
-rw-r--r--chromium/components/keyed_service/ios/browser_state_context_converter.h55
-rw-r--r--chromium/components/keyed_service/ios/browser_state_dependency_manager.cc8
-rw-r--r--chromium/components/keyed_service/ios/browser_state_dependency_manager.h14
-rw-r--r--chromium/components/keyed_service/ios/browser_state_keyed_service_factory.cc6
-rw-r--r--chromium/components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.cc6
-rw-r--r--chromium/components/leveldb/env_mojo.cc47
-rw-r--r--chromium/components/leveldb/env_mojo.h14
-rw-r--r--chromium/components/leveldb/leveldb_app.cc15
-rw-r--r--chromium/components/leveldb/leveldb_app.h7
-rw-r--r--chromium/components/leveldb/leveldb_service_impl.cc13
-rw-r--r--chromium/components/leveldb/leveldb_service_impl.h3
-rw-r--r--chromium/components/leveldb/public/interfaces/leveldb.mojom5
-rw-r--r--chromium/components/login/BUILD.gn2
-rw-r--r--chromium/components/login/base_screen_handler_utils.cc12
-rw-r--r--chromium/components/login/base_screen_handler_utils.h6
-rw-r--r--chromium/components/login/screens/screen_context.cc4
-rw-r--r--chromium/components/login/secure_module_util_chromeos.cc50
-rw-r--r--chromium/components/login/secure_module_util_chromeos.h29
-rw-r--r--chromium/components/memory_pressure/direct_memory_pressure_calculator_win.cc2
-rw-r--r--chromium/components/memory_pressure/direct_memory_pressure_calculator_win_unittest.cc4
-rw-r--r--chromium/components/memory_pressure/memory_pressure_monitor_unittest.cc13
-rw-r--r--chromium/components/metrics/BUILD.gn10
-rw-r--r--chromium/components/metrics/OWNERS2
-rw-r--r--chromium/components/metrics/data_use_tracker.cc3
-rw-r--r--chromium/components/metrics/data_use_tracker_unittest.cc5
-rw-r--r--chromium/components/metrics/file_metrics_provider.cc18
-rw-r--r--chromium/components/metrics/file_metrics_provider.h8
-rw-r--r--chromium/components/metrics/file_metrics_provider_unittest.cc7
-rw-r--r--chromium/components/metrics/leak_detector/leak_detector.h4
-rw-r--r--chromium/components/metrics/log_decoder.cc16
-rw-r--r--chromium/components/metrics/log_decoder.h21
-rw-r--r--chromium/components/metrics/metrics_log.cc5
-rw-r--r--chromium/components/metrics/metrics_log_unittest.cc2
-rw-r--r--chromium/components/metrics/metrics_log_uploader.cc22
-rw-r--r--chromium/components/metrics/metrics_log_uploader.h28
-rw-r--r--chromium/components/metrics/metrics_pref_names.cc4
-rw-r--r--chromium/components/metrics/metrics_pref_names.h1
-rw-r--r--chromium/components/metrics/metrics_reporting_scheduler.cc175
-rw-r--r--chromium/components/metrics/metrics_reporting_scheduler.h113
-rw-r--r--chromium/components/metrics/metrics_reporting_scheduler_unittest.cc71
-rw-r--r--chromium/components/metrics/metrics_reporting_service.cc86
-rw-r--r--chromium/components/metrics/metrics_reporting_service.h65
-rw-r--r--chromium/components/metrics/metrics_service.cc191
-rw-r--r--chromium/components/metrics/metrics_service.h40
-rw-r--r--chromium/components/metrics/metrics_service_accessor.cc8
-rw-r--r--chromium/components/metrics/metrics_service_accessor.h10
-rw-r--r--chromium/components/metrics/metrics_service_client.cc17
-rw-r--r--chromium/components/metrics/metrics_service_client.h6
-rw-r--r--chromium/components/metrics/metrics_service_unittest.cc3
-rw-r--r--chromium/components/metrics/metrics_state_manager.cc42
-rw-r--r--chromium/components/metrics/metrics_state_manager.h5
-rw-r--r--chromium/components/metrics/metrics_state_manager_unittest.cc157
-rw-r--r--chromium/components/metrics/metrics_upload_scheduler.cc14
-rw-r--r--chromium/components/metrics/metrics_upload_scheduler.h12
-rw-r--r--chromium/components/metrics/net/net_metrics_log_uploader.cc110
-rw-r--r--chromium/components/metrics/net/net_metrics_log_uploader.h28
-rw-r--r--chromium/components/metrics/net/net_metrics_log_uploader_unittest.cc2
-rw-r--r--chromium/components/metrics/net/network_metrics_provider.cc1
-rw-r--r--chromium/components/metrics/proto/cast_logs.proto1
-rw-r--r--chromium/components/metrics/proto/omnibox_event.proto16
-rw-r--r--chromium/components/metrics/proto/translate_event.proto3
-rw-r--r--chromium/components/metrics/reporting_service.cc202
-rw-r--r--chromium/components/metrics/reporting_service.h146
-rw-r--r--chromium/components/metrics/stability_metrics_helper.cc1
-rw-r--r--chromium/components/metrics/stability_metrics_helper.h1
-rw-r--r--chromium/components/metrics/test_metrics_log_uploader.cc13
-rw-r--r--chromium/components/metrics/test_metrics_log_uploader.h7
-rw-r--r--chromium/components/metrics/test_metrics_service_client.cc9
-rw-r--r--chromium/components/metrics/test_metrics_service_client.h6
-rw-r--r--chromium/components/metrics/url_constants.cc10
-rw-r--r--chromium/components/metrics/url_constants.h7
-rw-r--r--chromium/components/metrics_services_manager/OWNERS2
-rw-r--r--chromium/components/metrics_services_manager/metrics_services_manager.cc20
-rw-r--r--chromium/components/metrics_services_manager/metrics_services_manager_client.h8
-rw-r--r--chromium/components/mime_util/mime_util.cc2
-rw-r--r--chromium/components/minidump_uploader/BUILD.gn1
-rw-r--r--chromium/components/minidump_uploader/OWNERS2
-rw-r--r--chromium/components/nacl/broker/BUILD.gn1
-rw-r--r--chromium/components/nacl/browser/BUILD.gn6
-rw-r--r--chromium/components/nacl/common/BUILD.gn4
-rw-r--r--chromium/components/nacl/loader/sandbox_linux/BUILD.gn1
-rw-r--r--chromium/components/nacl/renderer/plugin/BUILD.gn9
-rw-r--r--chromium/components/navigation_interception/intercept_navigation_throttle.cc3
-rw-r--r--chromium/components/navigation_interception/navigation_params.cc26
-rw-r--r--chromium/components/navigation_interception/navigation_params.h10
-rw-r--r--chromium/components/navigation_interception/navigation_params_android.cc5
-rw-r--r--chromium/components/navigation_metrics/BUILD.gn13
-rw-r--r--chromium/components/navigation_metrics/OWNERS2
-rw-r--r--chromium/components/navigation_metrics/navigation_metrics.cc9
-rw-r--r--chromium/components/navigation_metrics/navigation_metrics_unittest.cc77
-rw-r--r--chromium/components/net_log/net_log_file_writer_unittest.cc4
-rw-r--r--chromium/components/net_log/resources/net_export.css6
-rw-r--r--chromium/components/net_log/resources/net_export.html49
-rw-r--r--chromium/components/net_log/resources/net_export.js40
-rw-r--r--chromium/components/neterror/OWNERS4
-rw-r--r--chromium/components/neterror/resources/neterror.css1
-rw-r--r--chromium/components/neterror/resources/offline.js40
-rw-r--r--chromium/components/network_hints/common/BUILD.gn5
-rw-r--r--chromium/components/network_hints/common/network_hints_messages.h9
-rw-r--r--chromium/components/network_hints/renderer/prescient_networking_dispatcher.cc24
-rw-r--r--chromium/components/network_hints/renderer/prescient_networking_dispatcher.h10
-rw-r--r--chromium/components/network_session_configurator/network_session_configurator.cc19
-rw-r--r--chromium/components/network_session_configurator/network_session_configurator_unittest.cc20
-rw-r--r--chromium/components/network_time/network_time_tracker.cc26
-rw-r--r--chromium/components/new_or_sad_tab_strings.grdp30
-rw-r--r--chromium/components/ntp_snippets/BUILD.gn24
-rw-r--r--chromium/components/ntp_snippets/DEPS5
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc46
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils_unittest.cc2
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc13
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h11
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider_unittest.cc20
-rw-r--r--chromium/components/ntp_snippets/category.cc7
-rw-r--r--chromium/components/ntp_snippets/category.h3
-rw-r--r--chromium/components/ntp_snippets/category_info.cc6
-rw-r--r--chromium/components/ntp_snippets/category_info.h32
-rw-r--r--chromium/components/ntp_snippets/category_rankers/category_ranker.h13
-rw-r--r--chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.cc42
-rw-r--r--chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.h11
-rw-r--r--chromium/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc238
-rw-r--r--chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc22
-rw-r--r--chromium/components/ntp_snippets/category_rankers/constant_category_ranker.h4
-rw-r--r--chromium/components/ntp_snippets/category_rankers/fake_category_ranker.cc12
-rw-r--r--chromium/components/ntp_snippets/category_rankers/fake_category_ranker.h4
-rw-r--r--chromium/components/ntp_snippets/category_rankers/mock_category_ranker.h4
-rw-r--r--chromium/components/ntp_snippets/category_status.h9
-rw-r--r--chromium/components/ntp_snippets/content_suggestion.cc14
-rw-r--r--chromium/components/ntp_snippets/content_suggestion.h42
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_metrics.cc15
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_metrics.h2
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_provider.h1
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service.cc178
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service.h107
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service_unittest.cc16
-rw-r--r--chromium/components/ntp_snippets/features.cc14
-rw-r--r--chromium/components/ntp_snippets/features.h12
-rw-r--r--chromium/components/ntp_snippets/mock_content_suggestions_provider.cc3
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_constants.cc11
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_constants.h4
-rw-r--r--chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc3
-rw-r--r--chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc39
-rw-r--r--chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc32
-rw-r--r--chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider_unittest.cc3
-rw-r--r--chromium/components/ntp_snippets/pref_names.cc11
-rw-r--r--chromium/components/ntp_snippets/pref_names.h9
-rw-r--r--chromium/components/ntp_snippets/pref_util.cc4
-rw-r--r--chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.cc50
-rw-r--r--chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.h23
-rw-r--r--chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc248
-rw-r--r--chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.h83
-rw-r--r--chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider_unittest.cc158
-rwxr-xr-xchromium/components/ntp_snippets/remote/fetch.py228
-rw-r--r--chromium/components/ntp_snippets/remote/json_request.cc140
-rw-r--r--chromium/components/ntp_snippets/remote/json_request.h12
-rw-r--r--chromium/components/ntp_snippets/remote/json_request_unittest.cc81
-rw-r--r--chromium/components/ntp_snippets/remote/persistent_scheduler.h4
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestion.cc22
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_fetcher.cc249
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_fetcher.h27
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_unittest.cc148
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_provider.h9
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc235
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h34
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc282
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_scheduler.h24
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc (renamed from chromium/components/ntp_snippets/remote/scheduling_remote_suggestions_provider.cc)585
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h164
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc842
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_status_service.cc36
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_status_service.h11
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_status_service_unittest.cc2
-rw-r--r--chromium/components/ntp_snippets/remote/request_throttler.cc15
-rw-r--r--chromium/components/ntp_snippets/remote/scheduling_remote_suggestions_provider.h212
-rw-r--r--chromium/components/ntp_snippets/remote/scheduling_remote_suggestions_provider_unittest.cc768
-rw-r--r--chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc21
-rw-r--r--chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc5
-rw-r--r--chromium/components/ntp_snippets/user_classifier.cc16
-rw-r--r--chromium/components/ntp_snippets/user_classifier.h9
-rw-r--r--chromium/components/ntp_snippets/user_classifier_unittest.cc317
-rw-r--r--chromium/components/ntp_snippets_strings.grdp16
-rw-r--r--chromium/components/ntp_tiles/BUILD.gn12
-rw-r--r--chromium/components/ntp_tiles/icon_cacher_impl.cc84
-rw-r--r--chromium/components/ntp_tiles/icon_cacher_impl.h26
-rw-r--r--chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc56
-rw-r--r--chromium/components/ntp_tiles/metrics.cc99
-rw-r--r--chromium/components/ntp_tiles/metrics.h39
-rw-r--r--chromium/components/ntp_tiles/metrics_unittest.cc130
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites.cc68
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites.h26
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites_unittest.cc211
-rw-r--r--chromium/components/ntp_tiles/ntp_tile.cc13
-rw-r--r--chromium/components/ntp_tiles/ntp_tile.h7
-rw-r--r--chromium/components/ntp_tiles/popular_sites_impl.cc8
-rw-r--r--chromium/components/ntp_tiles/switches.cc4
-rw-r--r--chromium/components/ntp_tiles/tile_source.h (renamed from chromium/components/ntp_tiles/ntp_tile_source.h)10
-rw-r--r--chromium/components/ntp_tiles/tile_visual_type.h46
-rw-r--r--chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc29
-rw-r--r--chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h4
-rw-r--r--chromium/components/ntp_tiles/webui/popular_sites_internals_message_handler.cc8
-rw-r--r--chromium/components/offline_items_collection/OWNERS6
-rw-r--r--chromium/components/offline_items_collection/core/BUILD.gn96
-rw-r--r--chromium/components/offline_items_collection/core/DEPS8
-rw-r--r--chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc176
-rw-r--r--chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h95
-rw-r--r--chromium/components/offline_items_collection/core/android/offline_item_bridge.cc70
-rw-r--r--chromium/components/offline_items_collection/core/android/offline_item_bridge.h38
-rw-r--r--chromium/components/offline_items_collection/core/offline_content_aggregator.cc263
-rw-r--r--chromium/components/offline_items_collection/core/offline_content_aggregator.h147
-rw-r--r--chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc477
-rw-r--r--chromium/components/offline_items_collection/core/offline_content_provider.h97
-rw-r--r--chromium/components/offline_items_collection/core/offline_item.cc72
-rw-r--r--chromium/components/offline_items_collection/core/offline_item.h138
-rw-r--r--chromium/components/offline_items_collection/core/offline_item_filter.h27
-rw-r--r--chromium/components/offline_items_collection/core/offline_item_state.h26
-rw-r--r--chromium/components/offline_items_collection/core/test_support/BUILD.gn23
-rw-r--r--chromium/components/offline_items_collection/core/test_support/mock_offline_content_provider.cc54
-rw-r--r--chromium/components/offline_items_collection/core/test_support/mock_offline_content_provider.h58
-rw-r--r--chromium/components/offline_items_collection/core/test_support/scoped_mock_offline_content_provider.cc41
-rw-r--r--chromium/components/offline_items_collection/core/test_support/scoped_mock_offline_content_provider.h40
-rw-r--r--chromium/components/offline_items_collection/core/throttled_offline_content_provider.cc154
-rw-r--r--chromium/components/offline_items_collection/core/throttled_offline_content_provider.h83
-rw-r--r--chromium/components/offline_items_collection/core/throttled_offline_content_provider_unittest.cc279
-rw-r--r--chromium/components/offline_pages/OWNERS2
-rw-r--r--chromium/components/offline_pages/core/background/cleanup_task.cc4
-rw-r--r--chromium/components/offline_pages/core/background/network_quality_provider_stub.cc8
-rw-r--r--chromium/components/offline_pages/core/background/network_quality_provider_stub.h8
-rw-r--r--chromium/components/offline_pages/core/background/offliner_policy.h2
-rw-r--r--chromium/components/offline_pages/core/background/pick_request_task.cc72
-rw-r--r--chromium/components/offline_pages/core/background/pick_request_task.h5
-rw-r--r--chromium/components/offline_pages/core/background/pick_request_task_unittest.cc74
-rw-r--r--chromium/components/offline_pages/core/background/reconcile_task.cc2
-rw-r--r--chromium/components/offline_pages/core/background/request_coordinator.cc76
-rw-r--r--chromium/components/offline_pages/core/background/request_coordinator.h31
-rw-r--r--chromium/components/offline_pages/core/background/request_coordinator_unittest.cc85
-rw-r--r--chromium/components/offline_pages/core/background/request_queue.cc16
-rw-r--r--chromium/components/offline_pages/core/background/request_queue.h4
-rw-r--r--chromium/components/offline_pages/core/background/request_queue_store_sql.cc16
-rw-r--r--chromium/components/offline_pages/core/background/request_queue_store_sql.h11
-rw-r--r--chromium/components/offline_pages/core/background/request_queue_store_unittest.cc7
-rw-r--r--chromium/components/offline_pages/core/background/request_queue_unittest.cc1
-rw-r--r--chromium/components/offline_pages/core/background/save_page_request.cc23
-rw-r--r--chromium/components/offline_pages/core/background/save_page_request.h11
-rw-r--r--chromium/components/offline_pages/core/background/save_page_request_unittest.cc8
-rw-r--r--chromium/components/offline_pages/core/offline_page_archiver.h8
-rw-r--r--chromium/components/offline_pages/core/offline_page_feature.cc14
-rw-r--r--chromium/components/offline_pages/core/offline_page_feature.h8
-rw-r--r--chromium/components/offline_pages/core/offline_page_metadata_store_impl_unittest.cc8
-rw-r--r--chromium/components/offline_pages/core/offline_page_metadata_store_sql.cc4
-rw-r--r--chromium/components/offline_pages/core/offline_page_model_impl.cc37
-rw-r--r--chromium/components/offline_pages/core/offline_page_model_impl.h2
-rw-r--r--chromium/components/offline_pages/core/offline_page_model_impl_unittest.cc11
-rw-r--r--chromium/components/offline_pages/core/offline_page_storage_manager.cc1
-rw-r--r--chromium/components/offline_pages/core/offline_page_test_archiver.h2
-rw-r--r--chromium/components/offline_pages/core/offline_page_test_store.cc3
-rw-r--r--chromium/components/offline_pages/core/offline_page_types.h4
-rw-r--r--chromium/components/offline_pages/core/offline_store_types.h1
-rw-r--r--chromium/components/offline_pages/core/snapshot_controller.cc53
-rw-r--r--chromium/components/offline_pages/core/snapshot_controller.h14
-rw-r--r--chromium/components/offline_pages/core/snapshot_controller_unittest.cc3
-rw-r--r--chromium/components/omnibox/browser/BUILD.gn13
-rw-r--r--chromium/components/onc/OWNERS1
-rw-r--r--chromium/components/onc/docs/onc_spec.css62
-rw-r--r--chromium/components/onc/docs/onc_spec.html3180
-rw-r--r--chromium/components/onc/docs/onc_spec.js55
-rw-r--r--chromium/components/onc/docs/onc_spec.md1782
-rw-r--r--chromium/components/open_from_clipboard/BUILD.gn34
-rw-r--r--chromium/components/open_from_clipboard/DEPS6
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content.cc57
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content.h20
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_generic.cc65
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_generic.h33
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_generic_unittest.cc122
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_impl_ios.h55
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_impl_ios.mm219
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_ios.h56
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_ios.mm244
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm96
-rw-r--r--chromium/components/os_crypt/BUILD.gn1
-rw-r--r--chromium/components/os_crypt/key_storage_linux.cc3
-rw-r--r--chromium/components/ownership/owner_settings_service.cc16
-rw-r--r--chromium/components/packed_ct_ev_whitelist/OWNERS3
-rw-r--r--chromium/components/page_info_strings.grdp (renamed from chromium/components/pageinfo_strings.grdp)3
-rw-r--r--chromium/components/pairing/bluetooth_host_pairing_controller.cc62
-rw-r--r--chromium/components/pairing/bluetooth_host_pairing_controller.h10
-rw-r--r--chromium/components/password_manager/DEPS1
-rw-r--r--chromium/components/password_manager/OWNERS1
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver.cc6
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc67
-rw-r--r--chromium/components/password_manager/content/browser/credential_manager_impl.cc6
-rw-r--r--chromium/components/password_manager/content/browser/credential_manager_impl_unittest.cc60
-rw-r--r--chromium/components/password_manager/content/renderer/credential_manager_client.cc55
-rw-r--r--chromium/components/password_manager/content/renderer/credential_manager_client.h6
-rw-r--r--chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc22
-rw-r--r--chromium/components/password_manager/core/browser/BUILD.gn60
-rw-r--r--chromium/components/password_manager/core/browser/DEPS1
-rw-r--r--chromium/components/password_manager/core/browser/affiliation_fetcher.cc6
-rw-r--r--chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc2
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc6
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h5
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc24
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h8
-rw-r--r--chromium/components/password_manager/core/browser/fake_form_fetcher.cc8
-rw-r--r--chromium/components/password_manager/core/browser/fake_form_fetcher.h5
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher.h8
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher_impl.cc49
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher_impl.h10
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc162
-rw-r--r--chromium/components/password_manager/core/browser/hsts_query.cc44
-rw-r--r--chromium/components/password_manager/core/browser/hsts_query.h28
-rw-r--r--chromium/components/password_manager/core/browser/hsts_query_unittest.cc64
-rw-r--r--chromium/components/password_manager/core/browser/http_data_cleaner.cc272
-rw-r--r--chromium/components/password_manager/core/browser/http_data_cleaner.h29
-rw-r--r--chromium/components/password_manager/core/browser/http_data_cleaner_unittest.cc241
-rw-r--r--chromium/components/password_manager/core/browser/http_password_migrator.cc73
-rw-r--r--chromium/components/password_manager/core/browser/http_password_migrator.h65
-rw-r--r--chromium/components/password_manager/core/browser/http_password_migrator_unittest.cc156
-rw-r--r--chromium/components/password_manager/core/browser/http_password_store_migrator.cc119
-rw-r--r--chromium/components/password_manager/core/browser/http_password_store_migrator.h86
-rw-r--r--chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc233
-rw-r--r--chromium/components/password_manager/core/browser/import/password_importer_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/login_database.cc105
-rw-r--r--chromium/components/password_manager/core/browser/login_database_unittest.cc62
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_store.h6
-rw-r--r--chromium/components/password_manager/core/browser/obsolete_http_cleaner.cc118
-rw-r--r--chromium/components/password_manager/core/browser/obsolete_http_cleaner.h50
-rw-r--r--chromium/components/password_manager/core/browser/obsolete_http_cleaner_unittest.cc233
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.cc227
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.h55
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager_unittest.cc364
-rw-r--r--chromium/components/password_manager/core/browser/password_generation_manager.cc55
-rw-r--r--chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc21
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.cc5
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client.cc8
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client.h32
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_util.cc5
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_util.h10
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_test_utils.cc30
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_test_utils.h28
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_unittest.cc116
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util.cc16
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc10
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detection_manager.h1
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc3
-rw-r--r--chromium/components/password_manager/core/browser/password_store.cc31
-rw-r--r--chromium/components/password_manager/core/browser/password_store.h20
-rw-r--r--chromium/components/password_manager/core/browser/password_store_consumer.h2
-rw-r--r--chromium/components/password_manager/core/browser/password_store_unittest.cc17
-rw-r--r--chromium/components/password_manager/core/browser/password_ui_utils.cc5
-rw-r--r--chromium/components/password_manager/core/browser/psl_matching_helper.cc58
-rw-r--r--chromium/components/password_manager/core/browser/psl_matching_helper.h21
-rw-r--r--chromium/components/password_manager/core/browser/psl_matching_helper_unittest.cc324
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.cc8
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.h5
-rw-r--r--chromium/components/password_manager/core/browser/test_password_store.cc17
-rw-r--r--chromium/components/password_manager/core/common/password_manager_pref_names.cc3
-rw-r--r--chromium/components/password_manager/core/common/password_manager_pref_names.h3
-rw-r--r--chromium/components/password_manager/sync/browser/password_model_worker.cc55
-rw-r--r--chromium/components/password_manager/sync/browser/password_model_worker.h6
-rw-r--r--chromium/components/payments/DEPS3
-rw-r--r--chromium/components/payments/README35
-rw-r--r--chromium/components/payments/android/BUILD.gn32
-rw-r--r--chromium/components/payments/android/DEPS5
-rw-r--r--chromium/components/payments/android/payment_method_manifest_table.cc102
-rw-r--r--chromium/components/payments/android/payment_method_manifest_table.h56
-rw-r--r--chromium/components/payments/android/payment_method_manifest_table_unittest.cc126
-rw-r--r--chromium/components/payments/android/web_app_manifest_section_table.cc144
-rw-r--r--chromium/components/payments/android/web_app_manifest_section_table.h57
-rw-r--r--chromium/components/payments/android/web_app_manifest_section_table_unittest.cc140
-rw-r--r--chromium/components/payments/content/BUILD.gn85
-rw-r--r--chromium/components/payments/content/DEPS10
-rw-r--r--chromium/components/payments/content/android/BUILD.gn35
-rw-r--r--chromium/components/payments/content/android/OWNERS2
-rw-r--r--chromium/components/payments/content/android/currency_formatter_android.cc6
-rw-r--r--chromium/components/payments/content/android/currency_formatter_android.h15
-rw-r--r--chromium/components/payments/content/android/payment_details_validation_android.cc13
-rw-r--r--chromium/components/payments/content/android/payment_details_validation_android.h4
-rw-r--r--chromium/components/payments/content/android/payment_manifest_downloader_android.cc140
-rw-r--r--chromium/components/payments/content/android/payment_manifest_downloader_android.h16
-rw-r--r--chromium/components/payments/content/android/payment_manifest_parser_android.cc152
-rw-r--r--chromium/components/payments/content/android/payment_manifest_parser_android.h56
-rw-r--r--chromium/components/payments/content/payment_app.mojom15
-rw-r--r--chromium/components/payments/content/payment_details_validation.cc21
-rw-r--r--chromium/components/payments/content/payment_manifest_downloader.cc151
-rw-r--r--chromium/components/payments/content/payment_manifest_downloader.h107
-rw-r--r--chromium/components/payments/content/payment_manifest_downloader_unittest.cc259
-rw-r--r--chromium/components/payments/content/payment_manifest_parser.mojom25
-rw-r--r--chromium/components/payments/content/payment_manifest_parser_host.cc170
-rw-r--r--chromium/components/payments/content/payment_manifest_parser_host.h72
-rw-r--r--chromium/components/payments/content/payment_request.cc304
-rw-r--r--chromium/components/payments/content/payment_request.h185
-rw-r--r--chromium/components/payments/content/payment_request.mojom4
-rw-r--r--chromium/components/payments/content/payment_request_delegate.h38
-rw-r--r--chromium/components/payments/content/payment_request_dialog.h17
-rw-r--r--chromium/components/payments/content/payment_request_spec.cc220
-rw-r--r--chromium/components/payments/content/payment_request_spec.h163
-rw-r--r--chromium/components/payments/content/payment_request_spec_unittest.cc317
-rw-r--r--chromium/components/payments/content/payment_request_state.cc238
-rw-r--r--chromium/components/payments/content/payment_request_state.h201
-rw-r--r--chromium/components/payments/content/payment_request_state_unittest.cc250
-rw-r--r--chromium/components/payments/content/payment_request_web_contents_manager.cc8
-rw-r--r--chromium/components/payments/content/payment_request_web_contents_manager.h7
-rw-r--r--chromium/components/payments/content/payment_response_helper.cc149
-rw-r--r--chromium/components/payments/content/payment_response_helper.h71
-rw-r--r--chromium/components/payments/content/payment_response_helper_unittest.cc300
-rw-r--r--chromium/components/payments/content/payments_validators_unittest.cc (renamed from chromium/components/payments/content/payments_validators_test.cc)0
-rw-r--r--chromium/components/payments/content/utility/BUILD.gn30
-rw-r--r--chromium/components/payments/content/utility/DEPS3
-rw-r--r--chromium/components/payments/content/utility/fingerprint_parser.cc50
-rw-r--r--chromium/components/payments/content/utility/fingerprint_parser.h21
-rw-r--r--chromium/components/payments/content/utility/fingerprint_parser_unittest.cc90
-rw-r--r--chromium/components/payments/content/utility/payment_manifest_parser.cc192
-rw-r--r--chromium/components/payments/content/utility/payment_manifest_parser.h70
-rw-r--r--chromium/components/payments/content/utility/payment_manifest_parser_unittest.cc494
-rw-r--r--chromium/components/payments/core/BUILD.gn37
-rw-r--r--chromium/components/payments/core/DEPS6
-rw-r--r--chromium/components/payments/core/address_normalizer.cc20
-rw-r--r--chromium/components/payments/core/address_normalizer.h4
-rw-r--r--chromium/components/payments/core/address_normalizer_unittest.cc90
-rw-r--r--chromium/components/payments/core/autofill_payment_instrument.cc103
-rw-r--r--chromium/components/payments/core/autofill_payment_instrument.h71
-rw-r--r--chromium/components/payments/core/autofill_payment_instrument_unittest.cc127
-rw-r--r--chromium/components/payments/core/basic_card_response.cc63
-rw-r--r--chromium/components/payments/core/basic_card_response.h55
-rw-r--r--chromium/components/payments/core/basic_card_response_unittest.cc68
-rw-r--r--chromium/components/payments/core/journey_logger.cc237
-rw-r--r--chromium/components/payments/core/journey_logger.h178
-rw-r--r--chromium/components/payments/core/journey_logger_unittest.cc753
-rw-r--r--chromium/components/payments/core/payment_address.cc90
-rw-r--r--chromium/components/payments/core/payment_address.h78
-rw-r--r--chromium/components/payments/core/payment_address_unittest.cc105
-rw-r--r--chromium/components/payments/core/payment_instrument.cc22
-rw-r--r--chromium/components/payments/core/payment_instrument.h71
-rw-r--r--chromium/components/payments/core/payment_method_data.cc94
-rw-r--r--chromium/components/payments/core/payment_method_data.h49
-rw-r--r--chromium/components/payments/core/payment_method_data_unittest.cc110
-rw-r--r--chromium/components/payments/core/payment_options_provider.h44
-rw-r--r--chromium/components/payments/core/payment_request_data_util.cc172
-rw-r--r--chromium/components/payments/core/payment_request_data_util.h73
-rw-r--r--chromium/components/payments/core/payment_request_data_util_unittest.cc95
-rw-r--r--chromium/components/payments/core/payment_request_delegate.h71
-rw-r--r--chromium/components/payments/core/profile_util.cc123
-rw-r--r--chromium/components/payments/core/profile_util.h69
-rw-r--r--chromium/components/payments/core/profile_util_unittest.cc231
-rw-r--r--chromium/components/payments/core/strings_util.cc61
-rw-r--r--chromium/components/payments/core/strings_util.h30
-rw-r--r--chromium/components/payments_strings.grdp130
-rw-r--r--chromium/components/pdf/browser/BUILD.gn5
-rw-r--r--chromium/components/pdf/browser/pdf_web_contents_helper.cc30
-rw-r--r--chromium/components/pdf/browser/pdf_web_contents_helper.h19
-rw-r--r--chromium/components/pdf/common/BUILD.gn21
-rw-r--r--chromium/components/pdf/common/OWNERS4
-rw-r--r--chromium/components/pdf/common/pdf.mojom19
-rw-r--r--chromium/components/pdf/common/pdf_message_generator.cc39
-rw-r--r--chromium/components/pdf/common/pdf_message_generator.h7
-rw-r--r--chromium/components/pdf/common/pdf_messages.h26
-rw-r--r--chromium/components/pdf/renderer/BUILD.gn2
-rw-r--r--chromium/components/pdf/renderer/pepper_pdf_host.cc42
-rw-r--r--chromium/components/pdf/renderer/pepper_pdf_host.h5
-rw-r--r--chromium/components/physical_web/data_source/fake_physical_web_data_source.cc2
-rw-r--r--chromium/components/physical_web/data_source/fake_physical_web_data_source.h3
-rw-r--r--chromium/components/physical_web/data_source/physical_web_data_source.h15
-rw-r--r--chromium/components/physical_web/data_source/physical_web_data_source_impl.cc10
-rw-r--r--chromium/components/physical_web/data_source/physical_web_data_source_impl.h7
-rw-r--r--chromium/components/physical_web/data_source/physical_web_data_source_impl_unittest.cc2
-rw-r--r--chromium/components/physical_web/eddystone/BUILD.gn27
-rw-r--r--chromium/components/physical_web/eddystone/eddystone_encoder.cc90
-rw-r--r--chromium/components/physical_web/eddystone/eddystone_encoder.h34
-rw-r--r--chromium/components/physical_web/eddystone/eddystone_encoder_unittest.cc422
-rw-r--r--chromium/components/physical_web/resources/ic_link_grey600_36dp.pngbin0 -> 337 bytes
-rw-r--r--chromium/components/physical_web/webui/physical_web_base_message_handler.cc63
-rw-r--r--chromium/components/physical_web/webui/physical_web_base_message_handler.h29
-rw-r--r--chromium/components/physical_web/webui/physical_web_ui_constants.cc6
-rw-r--r--chromium/components/physical_web/webui/physical_web_ui_constants.h6
-rw-r--r--chromium/components/physical_web/webui/resources/physical_web.html29
-rw-r--r--chromium/components/physical_web/webui/resources/physical_web.js40
-rw-r--r--chromium/components/plugins/renderer/loadable_plugin_placeholder.cc67
-rw-r--r--chromium/components/plugins/renderer/plugin_placeholder.cc26
-rw-r--r--chromium/components/plugins/renderer/webview_plugin.cc145
-rw-r--r--chromium/components/plugins/renderer/webview_plugin.h46
-rw-r--r--chromium/components/policy/BUILD.gn14
-rw-r--r--chromium/components/precache/content/precache_manager.cc24
-rw-r--r--chromium/components/precache/content/precache_manager.h19
-rw-r--r--chromium/components/precache/content/precache_manager_unittest.cc106
-rw-r--r--chromium/components/precache/core/BUILD.gn2
-rw-r--r--chromium/components/precache/core/precache_database.cc14
-rw-r--r--chromium/components/precache/core/precache_database.h4
-rw-r--r--chromium/components/precache/core/precache_database_unittest.cc122
-rw-r--r--chromium/components/precache/core/precache_fetcher.cc149
-rw-r--r--chromium/components/precache/core/precache_fetcher.h4
-rw-r--r--chromium/components/precache/core/precache_fetcher_unittest.cc77
-rw-r--r--chromium/components/precache/core/precache_manifest_util.cc60
-rw-r--r--chromium/components/precache/core/precache_manifest_util.h30
-rw-r--r--chromium/components/precache/core/proto/precache.proto2
-rw-r--r--chromium/components/pref_registry/OWNERS2
-rw-r--r--chromium/components/prefs/OWNERS2
-rw-r--r--chromium/components/prefs/command_line_pref_store.cc16
-rw-r--r--chromium/components/prefs/default_pref_store_unittest.cc11
-rw-r--r--chromium/components/prefs/json_pref_store.cc26
-rw-r--r--chromium/components/prefs/json_pref_store.h12
-rw-r--r--chromium/components/prefs/json_pref_store_unittest.cc210
-rw-r--r--chromium/components/prefs/pref_change_registrar_unittest.cc18
-rw-r--r--chromium/components/prefs/pref_member.cc2
-rw-r--r--chromium/components/prefs/pref_member_unittest.cc7
-rw-r--r--chromium/components/prefs/pref_registry.cc11
-rw-r--r--chromium/components/prefs/pref_registry.h4
-rw-r--r--chromium/components/prefs/pref_registry_simple.cc85
-rw-r--r--chromium/components/prefs/pref_registry_simple.h19
-rw-r--r--chromium/components/prefs/pref_service.cc23
-rw-r--r--chromium/components/prefs/pref_service.h3
-rw-r--r--chromium/components/prefs/pref_service_unittest.cc35
-rw-r--r--chromium/components/prefs/pref_value_map.cc2
-rw-r--r--chromium/components/prefs/pref_value_map_unittest.cc36
-rw-r--r--chromium/components/prefs/pref_value_store.h61
-rw-r--r--chromium/components/prefs/testing_pref_service.h39
-rw-r--r--chromium/components/prefs/testing_pref_store.cc3
-rw-r--r--chromium/components/previews/core/BUILD.gn5
-rw-r--r--chromium/components/previews/core/DEPS1
-rw-r--r--chromium/components/previews/core/previews_data_savings.cc71
-rw-r--r--chromium/components/previews/core/previews_data_savings.h51
-rw-r--r--chromium/components/previews/core/previews_data_savings_unittest.cc166
-rw-r--r--chromium/components/previews/core/previews_experiments.cc255
-rw-r--r--chromium/components/previews/core/previews_experiments.h46
-rw-r--r--chromium/components/previews/core/previews_experiments_unittest.cc230
-rw-r--r--chromium/components/previews/core/previews_io_data.cc42
-rw-r--r--chromium/components/previews/core/previews_io_data.h9
-rw-r--r--chromium/components/previews/core/previews_io_data_unittest.cc320
-rw-r--r--chromium/components/previews/core/previews_opt_out_store_sql.cc23
-rw-r--r--chromium/components/previews/core/previews_opt_out_store_sql.h6
-rw-r--r--chromium/components/previews/core/previews_opt_out_store_sql_unittest.cc101
-rw-r--r--chromium/components/previews/core/previews_ui_service.cc7
-rw-r--r--chromium/components/previews/core/previews_ui_service.h4
-rw-r--r--chromium/components/previews/core/previews_ui_service_unittest.cc3
-rw-r--r--chromium/components/printing/browser/print_manager_utils.cc2
-rw-r--r--chromium/components/printing/common/print_messages.cc6
-rw-r--r--chromium/components/printing/common/print_messages.h22
-rw-r--r--chromium/components/printing/renderer/print_web_view_helper.cc400
-rw-r--r--chromium/components/printing/renderer/print_web_view_helper.h28
-rw-r--r--chromium/components/printing/renderer/print_web_view_helper_linux.cc6
-rw-r--r--chromium/components/printing/renderer/print_web_view_helper_mac.mm34
-rw-r--r--chromium/components/printing/renderer/print_web_view_helper_pdf_win.cc8
-rw-r--r--chromium/components/proximity_auth/BUILD.gn11
-rw-r--r--chromium/components/proxy_config/pref_proxy_config_tracker_impl.cc13
-rw-r--r--chromium/components/proxy_config/proxy_config_dictionary.cc28
-rw-r--r--chromium/components/proxy_config/proxy_config_dictionary.h18
-rw-r--r--chromium/components/proxy_config/proxy_config_dictionary_unittest.cc32
-rw-r--r--chromium/components/query_parser/snippet.cc7
-rw-r--r--chromium/components/query_parser/snippet.h3
-rw-r--r--chromium/components/rappor/BUILD.gn13
-rw-r--r--chromium/components/rappor/OWNERS2
-rw-r--r--chromium/components/rappor/log_uploader.cc31
-rw-r--r--chromium/components/rappor/public/rappor_parameters.h24
-rw-r--r--chromium/components/rappor/rappor_service_impl.cc26
-rw-r--r--chromium/components/rappor/rappor_service_impl.h13
-rw-r--r--chromium/components/rappor/rappor_service_unittest.cc38
-rw-r--r--chromium/components/rappor/test_rappor_service.cc2
-rw-r--r--chromium/components/reading_list/core/BUILD.gn56
-rw-r--r--chromium/components/reading_list/core/offline_url_utils.cc (renamed from chromium/components/reading_list/ios/offline_url_utils.cc)24
-rw-r--r--chromium/components/reading_list/core/offline_url_utils.h (renamed from chromium/components/reading_list/ios/offline_url_utils.h)6
-rw-r--r--chromium/components/reading_list/core/offline_url_utils_unittest.cc85
-rw-r--r--chromium/components/reading_list/core/proto/BUILD.gn (renamed from chromium/components/reading_list/ios/proto/BUILD.gn)0
-rw-r--r--chromium/components/reading_list/core/proto/reading_list.proto (renamed from chromium/components/reading_list/ios/proto/reading_list.proto)8
-rw-r--r--chromium/components/reading_list/core/reading_list_entry.cc (renamed from chromium/components/reading_list/ios/reading_list_entry.cc)159
-rw-r--r--chromium/components/reading_list/core/reading_list_entry.h (renamed from chromium/components/reading_list/ios/reading_list_entry.h)107
-rw-r--r--chromium/components/reading_list/core/reading_list_entry_unittest.cc (renamed from chromium/components/reading_list/ios/reading_list_entry_unittest.cc)207
-rw-r--r--chromium/components/reading_list/core/reading_list_model.cc (renamed from chromium/components/reading_list/ios/reading_list_model.cc)2
-rw-r--r--chromium/components/reading_list/core/reading_list_model.h (renamed from chromium/components/reading_list/ios/reading_list_model.h)16
-rw-r--r--chromium/components/reading_list/core/reading_list_model_impl.cc (renamed from chromium/components/reading_list/ios/reading_list_model_impl.cc)61
-rw-r--r--chromium/components/reading_list/core/reading_list_model_impl.h (renamed from chromium/components/reading_list/ios/reading_list_model_impl.h)37
-rw-r--r--chromium/components/reading_list/core/reading_list_model_observer.h (renamed from chromium/components/reading_list/ios/reading_list_model_observer.h)8
-rw-r--r--chromium/components/reading_list/core/reading_list_model_storage.cc (renamed from chromium/components/reading_list/ios/reading_list_model_storage.cc)2
-rw-r--r--chromium/components/reading_list/core/reading_list_model_storage.h (renamed from chromium/components/reading_list/ios/reading_list_model_storage.h)17
-rw-r--r--chromium/components/reading_list/core/reading_list_model_unittest.cc (renamed from chromium/components/reading_list/ios/reading_list_model_unittest.mm)169
-rw-r--r--chromium/components/reading_list/core/reading_list_pref_names.cc (renamed from chromium/components/reading_list/ios/reading_list_pref_names.cc)2
-rw-r--r--chromium/components/reading_list/core/reading_list_pref_names.h (renamed from chromium/components/reading_list/ios/reading_list_pref_names.h)6
-rw-r--r--chromium/components/reading_list/core/reading_list_store.cc (renamed from chromium/components/reading_list/ios/reading_list_store.cc)27
-rw-r--r--chromium/components/reading_list/core/reading_list_store.h (renamed from chromium/components/reading_list/ios/reading_list_store.h)17
-rw-r--r--chromium/components/reading_list/core/reading_list_store_delegate.h (renamed from chromium/components/reading_list/ios/reading_list_store_delegate.h)6
-rw-r--r--chromium/components/reading_list/core/reading_list_store_unittest.cc (renamed from chromium/components/reading_list/ios/reading_list_store_unittest.mm)64
-rw-r--r--chromium/components/reading_list/ios/BUILD.gn43
-rw-r--r--chromium/components/reading_list/ios/offline_url_utils_unittest.cc61
-rw-r--r--chromium/components/reading_list/ios/reading_list_model_bridge_observer.h2
-rw-r--r--chromium/components/reading_list/ios/reading_list_model_bridge_observer.mm4
-rw-r--r--chromium/components/renderer_context_menu/context_menu_content_type.cc16
-rw-r--r--chromium/components/resources/BUILD.gn4
-rw-r--r--chromium/components/resources/OWNERS5
-rw-r--r--chromium/components/resources/ntp_tiles_resources.grdp16
-rw-r--r--chromium/components/resources/physical_web_ui_resources.grdp1
-rw-r--r--chromium/components/resources/proximity_auth_resources.grdp68
-rw-r--r--chromium/components/safe_browsing/BUILD.gn8
-rw-r--r--chromium/components/safe_browsing/DEPS1
-rw-r--r--chromium/components/safe_browsing/OWNERS1
-rw-r--r--chromium/components/safe_browsing/base_blocking_page.cc20
-rw-r--r--chromium/components/safe_browsing/base_blocking_page.h2
-rw-r--r--chromium/components/safe_browsing/base_resource_throttle.cc18
-rw-r--r--chromium/components/safe_browsing/base_resource_throttle.h7
-rw-r--r--chromium/components/safe_browsing/common/BUILD.gn1
-rw-r--r--chromium/components/safe_browsing/common/safebrowsing_messages.h4
-rw-r--r--chromium/components/safe_browsing/common/safebrowsing_types.h16
-rw-r--r--chromium/components/safe_browsing/csd.proto1032
-rw-r--r--chromium/components/safe_browsing/password_protection/BUILD.gn15
-rw-r--r--chromium/components/safe_browsing/password_protection/DEPS5
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_request.cc217
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_request.h128
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_service.cc402
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_service.h163
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc458
-rw-r--r--chromium/components/safe_browsing/renderer/BUILD.gn22
-rw-r--r--chromium/components/safe_browsing/renderer/DEPS5
-rw-r--r--chromium/components/safe_browsing/renderer/threat_dom_details.cc307
-rw-r--r--chromium/components/safe_browsing/renderer/threat_dom_details.h81
-rw-r--r--chromium/components/safe_browsing_db/android/safe_browsing_api_handler_bridge.cc20
-rw-r--r--chromium/components/safe_browsing_db/safe_browsing_prefs_unittest.cc5
-rw-r--r--chromium/components/safe_browsing_db/v4_database.cc48
-rw-r--r--chromium/components/safe_browsing_db/v4_database.h47
-rw-r--r--chromium/components/safe_browsing_db/v4_database_unittest.cc24
-rw-r--r--chromium/components/safe_browsing_db/v4_local_database_manager.cc5
-rw-r--r--chromium/components/safe_browsing_db/v4_local_database_manager_unittest.cc191
-rw-r--r--chromium/components/safe_browsing_db/v4_protocol_manager_util.cc51
-rw-r--r--chromium/components/safe_browsing_db/v4_protocol_manager_util.h72
-rw-r--r--chromium/components/safe_browsing_db/v4_rice.h5
-rw-r--r--chromium/components/safe_browsing_db/v4_store.cc4
-rw-r--r--chromium/components/safe_browsing_db/v4_store.h51
-rw-r--r--chromium/components/search_engines/default_search_manager_unittest.cc10
-rw-r--r--chromium/components/search_engines/default_search_policy_handler_unittest.cc24
-rw-r--r--chromium/components/search_engines/keyword_table.cc3
-rw-r--r--chromium/components/search_engines/prepopulated_engines.json81
-rw-r--r--chromium/components/search_engines/search_engines_test_util.cc4
-rw-r--r--chromium/components/search_engines/template_url.cc4
-rw-r--r--chromium/components/search_engines/template_url_data_util.cc4
-rw-r--r--chromium/components/search_engines/template_url_fetcher.cc2
-rw-r--r--chromium/components/search_engines/template_url_prepopulate_data_unittest.cc20
-rw-r--r--chromium/components/search_engines/template_url_service.cc191
-rw-r--r--chromium/components/search_engines/template_url_service.h24
-rw-r--r--chromium/components/search_engines/template_url_service_observer.h5
-rw-r--r--chromium/components/search_engines/template_url_unittest.cc8
-rw-r--r--chromium/components/search_provider_logos/google_logo_api.cc14
-rw-r--r--chromium/components/search_provider_logos/google_logo_api.h2
-rw-r--r--chromium/components/search_provider_logos/logo_tracker.cc52
-rw-r--r--chromium/components/search_provider_logos/logo_tracker.h14
-rw-r--r--chromium/components/search_provider_logos/logo_tracker_unittest.cc2
-rw-r--r--chromium/components/security_interstitials/OWNERS2
-rw-r--r--chromium/components/security_interstitials/core/bad_clock_ui.cc1
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/images/1x/brokenssl_red.pngbin1563 -> 0 bytes
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/images/1x/stop_sign.pngbin1621 -> 0 bytes
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/images/2x/brokenssl_red.pngbin2970 -> 0 bytes
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/images/2x/stop_sign.pngbin3103 -> 0 bytes
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/interstitial_ui.html6
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/interstitial_v2.css16
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/interstitial_v2.js5
-rw-r--r--chromium/components/security_interstitials/core/common_string_util.cc11
-rw-r--r--chromium/components/security_interstitials/core/safe_browsing_error_ui.cc4
-rw-r--r--chromium/components/security_interstitials/core/safe_browsing_error_ui.h10
-rw-r--r--chromium/components/security_interstitials/core/ssl_error_ui.cc1
-rw-r--r--chromium/components/security_state/OWNERS4
-rw-r--r--chromium/components/security_state/content/content_utils.cc28
-rw-r--r--chromium/components/security_state/content/content_utils_unittest.cc45
-rw-r--r--chromium/components/security_state/core/BUILD.gn3
-rw-r--r--chromium/components/security_state/core/security_state.cc11
-rw-r--r--chromium/components/security_state/core/security_state.h8
-rw-r--r--chromium/components/security_state/core/security_state_unittest.cc41
-rw-r--r--chromium/components/session_manager/core/session_manager.cc14
-rw-r--r--chromium/components/session_manager/core/session_manager.h4
-rw-r--r--chromium/components/sessions/content/content_live_tab.cc4
-rw-r--r--chromium/components/sessions/content/content_live_tab.h1
-rw-r--r--chromium/components/sessions/content/content_serialized_navigation_driver.cc106
-rw-r--r--chromium/components/sessions/content/content_serialized_navigation_driver.h11
-rw-r--r--chromium/components/sessions/content/content_serialized_navigation_driver_unittest.cc79
-rw-r--r--chromium/components/sessions/core/live_tab.h4
-rw-r--r--chromium/components/sessions/core/serialized_navigation_driver.h5
-rw-r--r--chromium/components/sessions/core/serialized_navigation_entry.h29
-rw-r--r--chromium/components/sessions/core/session_service_commands.cc17
-rw-r--r--chromium/components/sessions/core/session_types.cc29
-rw-r--r--chromium/components/sessions/core/session_types.h8
-rw-r--r--chromium/components/sessions/core/session_types_unittest.cc11
-rw-r--r--chromium/components/sessions/core/tab_restore_service_client.h6
-rw-r--r--chromium/components/sessions/core/tab_restore_service_helper.cc9
-rw-r--r--chromium/components/sessions/ios/ios_live_tab.h1
-rw-r--r--chromium/components/sessions/ios/ios_live_tab.mm6
-rw-r--r--chromium/components/signin/OWNERS2
-rw-r--r--chromium/components/signin/core/browser/about_signin_internals.cc10
-rw-r--r--chromium/components/signin/core/browser/account_tracker_service.cc4
-rw-r--r--chromium/components/signin/core/browser/android/BUILD.gn2
-rw-r--r--chromium/components/signin/core/browser/child_account_info_fetcher_impl.cc9
-rw-r--r--chromium/components/signin/core/browser/gaia_cookie_manager_service.cc72
-rw-r--r--chromium/components/signin/core/browser/gaia_cookie_manager_service.h10
-rw-r--r--chromium/components/signin/core/browser/signin_client.cc4
-rw-r--r--chromium/components/signin/core/browser/signin_client.h11
-rw-r--r--chromium/components/signin/core/browser/signin_error_controller.cc2
-rw-r--r--chromium/components/signin/core/browser/signin_error_controller_unittest.cc13
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper_unittest.cc20
-rw-r--r--chromium/components/signin/core/browser/signin_manager.cc7
-rw-r--r--chromium/components/signin/core/browser/signin_manager_base.cc3
-rw-r--r--chromium/components/signin/core/browser/signin_metrics.cc1
-rw-r--r--chromium/components/signin/core/browser/signin_metrics.h3
-rw-r--r--chromium/components/signin/core/browser/test_signin_client.cc4
-rw-r--r--chromium/components/signin/core/browser/test_signin_client.h2
-rw-r--r--chromium/components/signin/core/common/profile_management_switches.cc133
-rw-r--r--chromium/components/signin/core/common/profile_management_switches.h16
-rw-r--r--chromium/components/signin/core/common/signin_switches.cc21
-rw-r--r--chromium/components/signin/core/common/signin_switches.h7
-rw-r--r--chromium/components/signin/ios/OWNERS2
-rw-r--r--chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm7
-rw-r--r--chromium/components/signin/public/interfaces/account_id_traits.h4
-rw-r--r--chromium/components/spellcheck/browser/spelling_service_client.cc26
-rw-r--r--chromium/components/spellcheck/renderer/BUILD.gn2
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck.cc32
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc22
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_panel.cc80
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_panel.h49
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider.cc128
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider.h39
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_test.cc9
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_test.h4
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc4
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_unittest.cc33
-rw-r--r--chromium/components/ssl_config/OWNERS2
-rw-r--r--chromium/components/ssl_config/ssl_config_service_manager_pref.cc4
-rw-r--r--chromium/components/ssl_config/ssl_config_service_manager_pref_unittest.cc23
-rw-r--r--chromium/components/ssl_errors/OWNERS2
-rw-r--r--chromium/components/ssl_errors/error_classification.cc3
-rw-r--r--chromium/components/storage_monitor/volume_mount_watcher_win.cc1
-rw-r--r--chromium/components/strings/BUILD.gn4
-rw-r--r--chromium/components/strings/components_chromium_strings_ca.xtb2
-rw-r--r--chromium/components/strings/components_chromium_strings_es.xtb2
-rw-r--r--chromium/components/strings/components_chromium_strings_id.xtb2
-rw-r--r--chromium/components/strings/components_chromium_strings_zh-TW.xtb10
-rw-r--r--chromium/components/strings/components_google_chrome_strings_ca.xtb2
-rw-r--r--chromium/components/strings/components_google_chrome_strings_es.xtb2
-rw-r--r--chromium/components/strings/components_google_chrome_strings_id.xtb2
-rw-r--r--chromium/components/strings/components_google_chrome_strings_zh-TW.xtb12
-rw-r--r--chromium/components/strings/components_strings_am.xtb87
-rw-r--r--chromium/components/strings/components_strings_ar.xtb89
-rw-r--r--chromium/components/strings/components_strings_bg.xtb87
-rw-r--r--chromium/components/strings/components_strings_bn.xtb89
-rw-r--r--chromium/components/strings/components_strings_ca.xtb93
-rw-r--r--chromium/components/strings/components_strings_cs.xtb87
-rw-r--r--chromium/components/strings/components_strings_da.xtb91
-rw-r--r--chromium/components/strings/components_strings_de.xtb89
-rw-r--r--chromium/components/strings/components_strings_el.xtb87
-rw-r--r--chromium/components/strings/components_strings_en-GB.xtb87
-rw-r--r--chromium/components/strings/components_strings_es-419.xtb87
-rw-r--r--chromium/components/strings/components_strings_es.xtb97
-rw-r--r--chromium/components/strings/components_strings_et.xtb89
-rw-r--r--chromium/components/strings/components_strings_fa.xtb93
-rw-r--r--chromium/components/strings/components_strings_fi.xtb87
-rw-r--r--chromium/components/strings/components_strings_fil.xtb87
-rw-r--r--chromium/components/strings/components_strings_fr.xtb89
-rw-r--r--chromium/components/strings/components_strings_gu.xtb87
-rw-r--r--chromium/components/strings/components_strings_hi.xtb87
-rw-r--r--chromium/components/strings/components_strings_hr.xtb87
-rw-r--r--chromium/components/strings/components_strings_hu.xtb87
-rw-r--r--chromium/components/strings/components_strings_id.xtb103
-rw-r--r--chromium/components/strings/components_strings_it.xtb91
-rw-r--r--chromium/components/strings/components_strings_iw.xtb87
-rw-r--r--chromium/components/strings/components_strings_ja.xtb89
-rw-r--r--chromium/components/strings/components_strings_kn.xtb93
-rw-r--r--chromium/components/strings/components_strings_ko.xtb87
-rw-r--r--chromium/components/strings/components_strings_lt.xtb87
-rw-r--r--chromium/components/strings/components_strings_lv.xtb87
-rw-r--r--chromium/components/strings/components_strings_ml.xtb93
-rw-r--r--chromium/components/strings/components_strings_mr.xtb89
-rw-r--r--chromium/components/strings/components_strings_ms.xtb87
-rw-r--r--chromium/components/strings/components_strings_nl.xtb87
-rw-r--r--chromium/components/strings/components_strings_no.xtb87
-rw-r--r--chromium/components/strings/components_strings_pl.xtb87
-rw-r--r--chromium/components/strings/components_strings_pt-BR.xtb97
-rw-r--r--chromium/components/strings/components_strings_pt-PT.xtb135
-rw-r--r--chromium/components/strings/components_strings_ro.xtb87
-rw-r--r--chromium/components/strings/components_strings_ru.xtb87
-rw-r--r--chromium/components/strings/components_strings_sk.xtb89
-rw-r--r--chromium/components/strings/components_strings_sl.xtb87
-rw-r--r--chromium/components/strings/components_strings_sr.xtb91
-rw-r--r--chromium/components/strings/components_strings_sv.xtb89
-rw-r--r--chromium/components/strings/components_strings_sw.xtb101
-rw-r--r--chromium/components/strings/components_strings_ta.xtb87
-rw-r--r--chromium/components/strings/components_strings_te.xtb89
-rw-r--r--chromium/components/strings/components_strings_th.xtb95
-rw-r--r--chromium/components/strings/components_strings_tr.xtb87
-rw-r--r--chromium/components/strings/components_strings_uk.xtb87
-rw-r--r--chromium/components/strings/components_strings_vi.xtb89
-rw-r--r--chromium/components/strings/components_strings_zh-CN.xtb89
-rw-r--r--chromium/components/strings/components_strings_zh-TW.xtb165
-rw-r--r--chromium/components/subresource_filter/content/browser/BUILD.gn35
-rw-r--r--chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc29
-rw-r--r--chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h23
-rw-r--r--chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc416
-rw-r--r--chromium/components/subresource_filter/content/browser/async_document_subresource_filter.cc27
-rw-r--r--chromium/components/subresource_filter/content/browser/async_document_subresource_filter.h33
-rw-r--r--chromium/components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.cc48
-rw-r--r--chromium/components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h42
-rw-r--r--chromium/components/subresource_filter/content/browser/async_document_subresource_filter_unittest.cc68
-rw-r--r--chromium/components/subresource_filter/content/browser/content_activation_list_utils.cc31
-rw-r--r--chromium/components/subresource_filter/content/browser/content_activation_list_utils.h19
-rw-r--r--chromium/components/subresource_filter/content/browser/content_ruleset_service.cc (renamed from chromium/components/subresource_filter/content/browser/content_ruleset_service_delegate.cc)42
-rw-r--r--chromium/components/subresource_filter/content/browser/content_ruleset_service.h (renamed from chromium/components/subresource_filter/content/browser/content_ruleset_service_delegate.h)44
-rw-r--r--chromium/components/subresource_filter/content/browser/content_ruleset_service_unittest.cc (renamed from chromium/components/subresource_filter/content/browser/content_ruleset_service_delegate_unittest.cc)38
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc274
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h53
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc221
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc248
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h165
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc700
-rw-r--r--chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc193
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_client.h (renamed from chromium/components/subresource_filter/core/browser/subresource_filter_client.h)14
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc144
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h51
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc321
-rw-r--r--chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.cc16
-rw-r--r--chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.h10
-rw-r--r--chromium/components/subresource_filter/content/common/BUILD.gn3
-rw-r--r--chromium/components/subresource_filter/content/common/ruleset_dealer.cc8
-rw-r--r--chromium/components/subresource_filter/content/common/ruleset_dealer.h11
-rw-r--r--chromium/components/subresource_filter/content/common/subresource_filter_messages.h15
-rw-r--r--chromium/components/subresource_filter/content/renderer/BUILD.gn4
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc53
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h16
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc128
-rw-r--r--chromium/components/subresource_filter/content/renderer/unverified_ruleset_dealer.h2
-rw-r--r--chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc108
-rw-r--r--chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h13
-rw-r--r--chromium/components/subresource_filter/core/browser/BUILD.gn3
-rw-r--r--chromium/components/subresource_filter/core/browser/ruleset_service.cc4
-rw-r--r--chromium/components/subresource_filter/core/browser/ruleset_service.h9
-rw-r--r--chromium/components/subresource_filter/core/browser/ruleset_service_unittest.cc25
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_constants.cc6
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_constants.h9
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features.cc143
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features.h82
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc5
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc40
-rw-r--r--chromium/components/subresource_filter/core/common/BUILD.gn5
-rw-r--r--chromium/components/subresource_filter/core/common/DEPS3
-rw-r--r--chromium/components/subresource_filter/core/common/activation_list.cc3
-rw-r--r--chromium/components/subresource_filter/core/common/activation_list.h3
-rw-r--r--chromium/components/subresource_filter/core/common/document_subresource_filter.cc55
-rw-r--r--chromium/components/subresource_filter/core/common/document_subresource_filter.h13
-rw-r--r--chromium/components/subresource_filter/core/common/document_subresource_filter_unittest.cc77
-rw-r--r--chromium/components/subresource_filter/core/common/flat/rules.fbs29
-rw-r--r--chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.cc21
-rw-r--r--chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.h101
-rw-r--r--chromium/components/subresource_filter/core/common/fuzzy_pattern_matching_unittest.cc49
-rw-r--r--chromium/components/subresource_filter/core/common/indexed_ruleset.cc348
-rw-r--r--chromium/components/subresource_filter/core/common/indexed_ruleset.h1
-rw-r--r--chromium/components/subresource_filter/core/common/indexed_ruleset_unittest.cc379
-rw-r--r--chromium/components/subresource_filter/core/common/knuth_morris_pratt.h249
-rw-r--r--chromium/components/subresource_filter/core/common/knuth_morris_pratt_unittest.cc218
-rw-r--r--chromium/components/subresource_filter/core/common/proto/rules.proto5
-rw-r--r--chromium/components/subresource_filter/core/common/test_ruleset_creator.cc18
-rw-r--r--chromium/components/subresource_filter/core/common/test_ruleset_creator.h2
-rw-r--r--chromium/components/subresource_filter/core/common/test_ruleset_utils.h5
-rw-r--r--chromium/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc10
-rw-r--r--chromium/components/subresource_filter/core/common/url_pattern.cc210
-rw-r--r--chromium/components/subresource_filter/core/common/url_pattern.h42
-rw-r--r--chromium/components/subresource_filter/core/common/url_pattern_matching.h277
-rw-r--r--chromium/components/subresource_filter/core/common/url_pattern_unittest.cc (renamed from chromium/components/subresource_filter/core/common/url_pattern_matching_unittest.cc)86
-rw-r--r--chromium/components/suggestions/BUILD.gn4
-rw-r--r--chromium/components/suggestions/image_manager.cc5
-rw-r--r--chromium/components/suggestions/image_manager.h2
-rw-r--r--chromium/components/suggestions/image_manager_unittest.cc16
-rw-r--r--chromium/components/suggestions/suggestions_service_impl.cc36
-rw-r--r--chromium/components/supervised_user_error_page/OWNERS2
-rw-r--r--chromium/components/supervised_user_error_page/gin_wrapper.cc8
-rw-r--r--chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.css2
-rw-r--r--chromium/components/sync/BUILD.gn4
-rw-r--r--chromium/components/sync/protocol/protocol_sources.gni1
-rw-r--r--chromium/components/sync_preferences/BUILD.gn1
-rw-r--r--chromium/components/sync_preferences/DEPS2
-rw-r--r--chromium/components/sync_preferences/OWNERS2
-rw-r--r--chromium/components/sync_preferences/pref_model_associator.cc15
-rw-r--r--chromium/components/sync_preferences/pref_model_associator_unittest.cc8
-rw-r--r--chromium/components/sync_preferences/pref_service_syncable_factory.cc49
-rw-r--r--chromium/components/sync_preferences/pref_service_syncable_factory.h9
-rw-r--r--chromium/components/sync_preferences/pref_service_syncable_unittest.cc48
-rw-r--r--chromium/components/sync_preferences/synced_pref_change_registrar.cc2
-rw-r--r--chromium/components/sync_sessions/fake_sync_sessions_client.cc3
-rw-r--r--chromium/components/sync_sessions/fake_sync_sessions_client.h3
-rw-r--r--chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.cc2
-rw-r--r--chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc54
-rw-r--r--chromium/components/sync_sessions/session_sync_test_helper.cc2
-rw-r--r--chromium/components/sync_sessions/sessions_sync_manager.cc31
-rw-r--r--chromium/components/sync_sessions/sessions_sync_manager.h18
-rw-r--r--chromium/components/sync_sessions/sessions_sync_manager_unittest.cc50
-rw-r--r--chromium/components/sync_sessions/sync_sessions_client.h3
-rw-r--r--chromium/components/sync_sessions/sync_sessions_metrics.cc3
-rw-r--r--chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc24
-rw-r--r--chromium/components/sync_sessions/synced_session.cc20
-rw-r--r--chromium/components/sync_sessions/synced_session.h27
-rw-r--r--chromium/components/sync_sessions/synced_session_tracker.cc45
-rw-r--r--chromium/components/sync_sessions/synced_session_tracker.h7
-rw-r--r--chromium/components/sync_sessions/synced_session_tracker_unittest.cc32
-rw-r--r--chromium/components/sync_sessions/synced_tab_delegate.h6
-rw-r--r--chromium/components/sync_sessions/tab_node_pool.cc1
-rw-r--r--chromium/components/sync_sessions/tab_node_pool.h1
-rw-r--r--chromium/components/sync_wifi/wifi_config_delegate_chromeos_unittest.cc6
-rw-r--r--chromium/components/sync_wifi/wifi_credential.cc8
-rw-r--r--chromium/components/task_scheduler_util/browser/initialization.cc48
-rw-r--r--chromium/components/task_scheduler_util/browser/initialization.h22
-rw-r--r--chromium/components/task_scheduler_util/common/variations_util.cc140
-rw-r--r--chromium/components/task_scheduler_util/common/variations_util.h45
-rw-r--r--chromium/components/task_scheduler_util/common/variations_util_unittest.cc249
-rw-r--r--chromium/components/task_scheduler_util/renderer/initialization.cc49
-rw-r--r--chromium/components/task_scheduler_util/renderer/initialization.h24
-rw-r--r--chromium/components/toolbar/BUILD.gn17
-rw-r--r--chromium/components/toolbar/DEPS1
-rw-r--r--chromium/components/toolbar/toolbar_model_impl.cc3
-rw-r--r--chromium/components/toolbar/vector_icons/business.icon87
-rw-r--r--chromium/components/tracing/BUILD.gn3
-rw-r--r--chromium/components/tracing/child/child_memory_dump_manager_delegate_impl.cc114
-rw-r--r--chromium/components/tracing/child/child_memory_dump_manager_delegate_impl.h85
-rw-r--r--chromium/components/tracing/child/child_trace_message_filter.cc91
-rw-r--r--chromium/components/tracing/child/child_trace_message_filter.h19
-rw-r--r--chromium/components/tracing/child/child_trace_message_filter_browsertest.cc326
-rw-r--r--chromium/components/tracing/common/process_metrics_memory_dump_provider.cc104
-rw-r--r--chromium/components/tracing/common/process_metrics_memory_dump_provider_unittest.cc23
-rw-r--r--chromium/components/tracing/common/trace_startup.cc8
-rw-r--r--chromium/components/tracing/core/proto_zero_message.cc2
-rw-r--r--chromium/components/tracing/tools/proto_zero_plugin/BUILD.gn6
-rw-r--r--chromium/components/translate/core/browser/BUILD.gn18
-rw-r--r--chromium/components/translate/core/browser/proto/BUILD.gn1
-rw-r--r--chromium/components/translate/ios/browser/BUILD.gn1
-rw-r--r--chromium/components/ui_devtools/string_util.h5
-rw-r--r--chromium/components/ukm/BUILD.gn6
-rw-r--r--chromium/components/ukm/OWNERS2
-rw-r--r--chromium/components/ukm/metrics_reporting_scheduler.cc31
-rw-r--r--chromium/components/ukm/metrics_reporting_scheduler.h37
-rw-r--r--chromium/components/ukm/test_ukm_service.cc41
-rw-r--r--chromium/components/ukm/test_ukm_service.h5
-rw-r--r--chromium/components/ukm/ukm_entry.cc1
-rw-r--r--chromium/components/ukm/ukm_entry.h1
-rw-r--r--chromium/components/ukm/ukm_entry_builder.cc3
-rw-r--r--chromium/components/ukm/ukm_reporting_service.cc104
-rw-r--r--chromium/components/ukm/ukm_reporting_service.h65
-rw-r--r--chromium/components/ukm/ukm_rotation_scheduler.cc24
-rw-r--r--chromium/components/ukm/ukm_rotation_scheduler.h33
-rw-r--r--chromium/components/ukm/ukm_service.cc177
-rw-r--r--chromium/components/ukm/ukm_service.h45
-rw-r--r--chromium/components/ukm/ukm_service_unittest.cc108
-rw-r--r--chromium/components/ukm/ukm_source.cc22
-rw-r--r--chromium/components/update_client/BUILD.gn3
-rw-r--r--chromium/components/update_client/DEPS1
-rw-r--r--chromium/components/update_client/OWNERS1
-rw-r--r--chromium/components/update_client/action_update.cc11
-rw-r--r--chromium/components/update_client/component_patcher.cc2
-rw-r--r--chromium/components/update_client/configurator.h3
-rw-r--r--chromium/components/update_client/ping_manager_unittest.cc6
-rw-r--r--chromium/components/update_client/request_sender.cc6
-rw-r--r--chromium/components/update_client/test_configurator.cc4
-rw-r--r--chromium/components/update_client/test_configurator.h1
-rw-r--r--chromium/components/update_client/update_query_params.cc6
-rw-r--r--chromium/components/update_client/update_query_params.h3
-rw-r--r--chromium/components/update_client/update_query_params_unittest.cc10
-rw-r--r--chromium/components/url_formatter/elide_url.h2
-rw-r--r--chromium/components/url_formatter/elide_url_unittest.cc6
-rw-r--r--chromium/components/url_formatter/url_formatter.cc34
-rw-r--r--chromium/components/url_formatter/url_formatter_unittest.cc56
-rw-r--r--chromium/components/url_matcher/url_matcher_factory.cc8
-rw-r--r--chromium/components/user_manager/fake_user_manager.cc8
-rw-r--r--chromium/components/user_manager/fake_user_manager.h1
-rw-r--r--chromium/components/user_manager/known_user.cc24
-rw-r--r--chromium/components/user_manager/known_user.h15
-rw-r--r--chromium/components/user_manager/user.h9
-rw-r--r--chromium/components/user_manager/user_manager.h8
-rw-r--r--chromium/components/user_manager/user_manager_base.cc31
-rw-r--r--chromium/components/user_manager/user_manager_base.h5
-rw-r--r--chromium/components/user_manager/user_unittest.cc8
-rw-r--r--chromium/components/user_prefs/OWNERS2
-rw-r--r--chromium/components/user_prefs/tracked/BUILD.gn92
-rw-r--r--chromium/components/user_prefs/tracked/DEPS4
-rw-r--r--chromium/components/user_prefs/tracked/OWNERS2
-rw-r--r--chromium/components/user_prefs/tracked/device_id.h23
-rw-r--r--chromium/components/user_prefs/tracked/device_id_mac.cc32
-rw-r--r--chromium/components/user_prefs/tracked/device_id_stub.cc11
-rw-r--r--chromium/components/user_prefs/tracked/device_id_unittest.cc35
-rw-r--r--chromium/components/user_prefs/tracked/device_id_win.cc72
-rw-r--r--chromium/components/user_prefs/tracked/dictionary_hash_store_contents.cc134
-rw-r--r--chromium/components/user_prefs/tracked/dictionary_hash_store_contents.h62
-rw-r--r--chromium/components/user_prefs/tracked/hash_store_contents.h90
-rw-r--r--chromium/components/user_prefs/tracked/interceptable_pref_filter.cc41
-rw-r--r--chromium/components/user_prefs/tracked/interceptable_pref_filter.h68
-rw-r--r--chromium/components/user_prefs/tracked/mock_validation_delegate.cc73
-rw-r--r--chromium/components/user_prefs/tracked/mock_validation_delegate.h89
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_calculator.cc113
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_calculator.h55
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_calculator_unittest.cc197
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_filter.cc370
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_filter.h176
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_filter_unittest.cc1393
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_store.h48
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_store_impl.cc319
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_store_impl.h61
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_store_impl_unittest.cc518
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_store_transaction.h102
-rw-r--r--chromium/components/user_prefs/tracked/pref_names.cc13
-rw-r--r--chromium/components/user_prefs/tracked/pref_names.h14
-rw-r--r--chromium/components/user_prefs/tracked/registry_hash_store_contents_win.cc182
-rw-r--r--chromium/components/user_prefs/tracked/registry_hash_store_contents_win.h49
-rw-r--r--chromium/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc120
-rw-r--r--chromium/components/user_prefs/tracked/segregated_pref_store.cc194
-rw-r--r--chromium/components/user_prefs/tracked/segregated_pref_store.h115
-rw-r--r--chromium/components/user_prefs/tracked/segregated_pref_store_unittest.cc306
-rw-r--r--chromium/components/user_prefs/tracked/tracked_atomic_preference.cc91
-rw-r--r--chromium/components/user_prefs/tracked/tracked_atomic_preference.h49
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preference.h44
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preference_helper.cc135
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preference_helper.h70
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preference_histogram_names.cc31
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preference_histogram_names.h26
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preference_validation_delegate.h47
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preferences_migration.cc342
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preferences_migration.h45
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc655
-rw-r--r--chromium/components/user_prefs/tracked/tracked_split_preference.cc121
-rw-r--r--chromium/components/user_prefs/tracked/tracked_split_preference.h52
-rw-r--r--chromium/components/variations/OWNERS2
-rw-r--r--chromium/components/variations/metrics_util.cc7
-rw-r--r--chromium/components/variations/metrics_util.h5
-rw-r--r--chromium/components/variations/variations_url_constants.cc7
-rw-r--r--chromium/components/version_info/BUILD.gn10
-rw-r--r--chromium/components/version_info/channel.h15
-rw-r--r--chromium/components/version_info/version_info.h5
-rw-r--r--chromium/components/version_ui/OWNERS2
-rw-r--r--chromium/components/version_ui/resources/about_version.html11
-rw-r--r--chromium/components/version_ui/version_ui_constants.cc3
-rw-r--r--chromium/components/version_ui/version_ui_constants.h3
-rw-r--r--chromium/components/version_ui_strings.grdp32
-rw-r--r--chromium/components/visitedlink/browser/visitedlink_event_listener.cc5
-rw-r--r--chromium/components/visitedlink/renderer/visitedlink_slave.cc4
-rw-r--r--chromium/components/viz/DEPS4
-rw-r--r--chromium/components/viz/OWNERS10
-rw-r--r--chromium/components/viz/PRESUBMIT.py318
-rw-r--r--chromium/components/viz/frame_sinks/BUILD.gn25
-rw-r--r--chromium/components/viz/frame_sinks/DEPS6
-rw-r--r--chromium/components/viz/frame_sinks/display_provider.h36
-rw-r--r--chromium/components/viz/frame_sinks/gpu_compositor_frame_sink.cc (renamed from chromium/components/display_compositor/gpu_compositor_frame_sink.cc)23
-rw-r--r--chromium/components/viz/frame_sinks/gpu_compositor_frame_sink.h (renamed from chromium/components/display_compositor/gpu_compositor_frame_sink.h)20
-rw-r--r--chromium/components/viz/frame_sinks/gpu_compositor_frame_sink_delegate.h (renamed from chromium/components/display_compositor/gpu_compositor_frame_sink_delegate.h)10
-rw-r--r--chromium/components/viz/frame_sinks/gpu_root_compositor_frame_sink.cc (renamed from chromium/components/display_compositor/gpu_root_compositor_frame_sink.cc)25
-rw-r--r--chromium/components/viz/frame_sinks/gpu_root_compositor_frame_sink.h (renamed from chromium/components/display_compositor/gpu_root_compositor_frame_sink.h)21
-rw-r--r--chromium/components/viz/frame_sinks/mojo_frame_sink_manager.cc147
-rw-r--r--chromium/components/viz/frame_sinks/mojo_frame_sink_manager.h111
-rw-r--r--chromium/components/wallpaper/OWNERS2
-rw-r--r--chromium/components/wallpaper/wallpaper_color_calculator.cc60
-rw-r--r--chromium/components/wallpaper/wallpaper_color_calculator.h15
-rw-r--r--chromium/components/wallpaper/wallpaper_color_calculator_unittest.cc142
-rw-r--r--chromium/components/wallpaper/wallpaper_manager_base.cc16
-rw-r--r--chromium/components/wallpaper/wallpaper_manager_base.h5
-rw-r--r--chromium/components/wallpaper/wallpaper_resizer.cc19
-rw-r--r--chromium/components/wallpaper/wallpaper_resizer.h5
-rw-r--r--chromium/components/web_cache/browser/web_cache_manager.cc2
-rw-r--r--chromium/components/web_cache/browser/web_cache_manager_unittest.cc12
-rw-r--r--chromium/components/web_cache/renderer/web_cache_impl.cc8
-rw-r--r--chromium/components/web_contents_delegate_android/OWNERS2
-rw-r--r--chromium/components/web_modal/BUILD.gn7
-rw-r--r--chromium/components/web_resource/BUILD.gn1
-rw-r--r--chromium/components/web_resource/web_resource_service.cc36
-rw-r--r--chromium/components/web_resource/web_resource_service.h41
-rw-r--r--chromium/components/web_resource/web_resource_service_unittest.cc156
-rw-r--r--chromium/components/webcrypto/BUILD.gn2
-rw-r--r--chromium/components/webcrypto/algorithm_dispatch.cc69
-rw-r--r--chromium/components/webcrypto/algorithm_registry.cc32
-rw-r--r--chromium/components/webcrypto/algorithms/aes.cc35
-rw-r--r--chromium/components/webcrypto/algorithms/aes_cbc.cc6
-rw-r--r--chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc196
-rw-r--r--chromium/components/webcrypto/algorithms/aes_ctr.cc8
-rw-r--r--chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc22
-rw-r--r--chromium/components/webcrypto/algorithms/aes_gcm.cc10
-rw-r--r--chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc20
-rw-r--r--chromium/components/webcrypto/algorithms/aes_kw.cc6
-rw-r--r--chromium/components/webcrypto/algorithms/aes_kw_unittest.cc260
-rw-r--r--chromium/components/webcrypto/algorithms/asymmetric_key_util.cc8
-rw-r--r--chromium/components/webcrypto/algorithms/ec.cc116
-rw-r--r--chromium/components/webcrypto/algorithms/ecdh.cc18
-rw-r--r--chromium/components/webcrypto/algorithms/ecdh_unittest.cc80
-rw-r--r--chromium/components/webcrypto/algorithms/ecdsa.cc16
-rw-r--r--chromium/components/webcrypto/algorithms/ecdsa_unittest.cc81
-rw-r--r--chromium/components/webcrypto/algorithms/hkdf.cc23
-rw-r--r--chromium/components/webcrypto/algorithms/hmac.cc62
-rw-r--r--chromium/components/webcrypto/algorithms/hmac_unittest.cc280
-rw-r--r--chromium/components/webcrypto/algorithms/pbkdf2.cc20
-rw-r--r--chromium/components/webcrypto/algorithms/rsa.cc105
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_oaep.cc25
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc179
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_pss.cc16
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_pss_unittest.cc42
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_sign.cc11
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_ssa.cc12
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc528
-rw-r--r--chromium/components/webcrypto/algorithms/secret_key_util.cc10
-rw-r--r--chromium/components/webcrypto/algorithms/sha.cc6
-rw-r--r--chromium/components/webcrypto/algorithms/sha_unittest.cc6
-rw-r--r--chromium/components/webcrypto/algorithms/test_helpers.cc138
-rw-r--r--chromium/components/webcrypto/algorithms/util.cc10
-rw-r--r--chromium/components/webcrypto/blink_key_handle.cc6
-rw-r--r--chromium/components/webcrypto/crypto_data.cc5
-rw-r--r--chromium/components/webcrypto/ec_import_key_pkcs8_fuzzer.cc2
-rw-r--r--chromium/components/webcrypto/ec_import_key_spki_fuzzer.cc2
-rw-r--r--chromium/components/webcrypto/fuzzer_support.cc44
-rw-r--r--chromium/components/webcrypto/generate_key_result.cc4
-rw-r--r--chromium/components/webcrypto/jwk.cc22
-rw-r--r--chromium/components/webcrypto/rsa_import_key_pkcs8_fuzzer.cc2
-rw-r--r--chromium/components/webcrypto/rsa_import_key_spki_fuzzer.cc2
-rw-r--r--chromium/components/webcrypto/status.cc122
-rw-r--r--chromium/components/webcrypto/status_unittest.cc12
-rw-r--r--chromium/components/webcrypto/webcrypto_impl.cc64
-rw-r--r--chromium/components/webcrypto/webcrypto_impl.h30
-rw-r--r--chromium/components/webdata/OWNERS2
-rw-r--r--chromium/components/webdata_services/BUILD.gn4
-rw-r--r--chromium/components/webdata_services/DEPS1
-rw-r--r--chromium/components/webdata_services/OWNERS2
-rw-r--r--chromium/components/webdata_services/web_data_service_wrapper.cc19
-rw-r--r--chromium/components/wifi/fake_wifi_service.cc4
-rw-r--r--chromium/components/wifi/wifi_service_mac.mm5
-rw-r--r--chromium/components/zoom/OWNERS2
-rw-r--r--chromium/components/zoom/page_zoom.cc12
-rw-r--r--chromium/components/zoom/zoom_controller.cc2
1756 files changed, 64549 insertions, 38366 deletions
diff --git a/chromium/components/BUILD.gn b/chromium/components/BUILD.gn
index f7fdf61ab08..42e7def6964 100644
--- a/chromium/components/BUILD.gn
+++ b/chromium/components/BUILD.gn
@@ -91,7 +91,7 @@ test("components_unittests") {
"//components/grpc_support/test:unit_tests",
"//components/history/core/browser:unit_tests",
"//components/history/core/common:unit_tests",
- "//components/image_fetcher:unit_tests",
+ "//components/image_fetcher/core:unit_tests",
"//components/json_schema:unit_tests",
"//components/keyed_service/core:unit_tests",
"//components/language_usage_metrics:unit_tests",
@@ -100,11 +100,13 @@ test("components_unittests") {
"//components/memory_pressure:unit_tests",
"//components/metrics:unit_tests",
"//components/mime_util:unit_tests",
+ "//components/navigation_metrics:unit_tests",
"//components/net_log:unit_tests",
"//components/network_session_configurator:unit_tests",
"//components/network_time:unit_tests",
"//components/ntp_snippets:unit_tests",
"//components/ntp_tiles:unit_tests",
+ "//components/offline_items_collection/core:unit_tests",
"//components/offline_pages/core:unit_tests",
"//components/offline_pages/core/background:unit_tests",
"//components/offline_pages/core/downloads:unit_tests",
@@ -117,12 +119,14 @@ test("components_unittests") {
"//components/password_manager/sync/browser:unit_tests",
"//components/payments/core:unit_tests",
"//components/physical_web/data_source:unit_tests",
+ "//components/physical_web/eddystone:unit_tests",
"//components/precache/core:unit_tests",
"//components/prefs:unit_tests",
"//components/previews/core:unit_tests",
"//components/proxy_config:unit_tests",
"//components/query_parser:unit_tests",
"//components/rappor:unit_tests",
+ "//components/reading_list/core:unit_tests",
"//components/search:unit_tests",
"//components/search_engines:unit_tests",
"//components/search_provider_logos:unit_tests",
@@ -150,7 +154,6 @@ test("components_unittests") {
"//components/upload_list:unit_tests",
"//components/url_formatter:unit_tests",
"//components/url_matcher:unit_tests",
- "//components/user_prefs/tracked:unit_tests",
"//components/variations:unit_tests",
"//components/variations/service:unit_tests",
"//components/web_resource:unit_tests",
@@ -164,7 +167,6 @@ test("components_unittests") {
if (is_ios) {
deps += [
"//components/image_fetcher/ios:unit_tests",
- "//components/reading_list/ios:unit_tests",
"//components/signin/ios/browser:unit_tests",
"//components/translate/ios/browser:unit_tests",
]
@@ -202,6 +204,7 @@ test("components_unittests") {
"//components/packed_ct_ev_whitelist:unit_tests",
"//components/password_manager/content/browser:unit_tests",
"//components/payments/content:unit_tests",
+ "//components/payments/content/utility:unit_tests",
"//components/policy/core/browser:unit_tests",
"//components/policy/core/common:unit_tests",
"//components/precache/content:unit_tests",
@@ -239,11 +242,14 @@ test("components_unittests") {
if (is_android) {
deps += [
+ "//components/cdm/browser:unit_tests",
+ "//components/feature_engagement_tracker:unit_tests",
"//components/gcm_driver/instance_id:test_support",
"//components/gcm_driver/instance_id/android:instance_id_driver_java",
"//components/gcm_driver/instance_id/android:instance_id_driver_test_support_java",
"//components/invalidation/impl",
"//components/invalidation/impl:java",
+ "//components/payments/android:unit_tests",
"//components/policy/android:policy_java",
"//components/safe_json",
"//components/safe_json/android:safe_json_java",
@@ -378,11 +384,6 @@ if (is_android) {
resource_dirs = [ "//components/test/android/browsertests_apk/res" ]
custom_package = "org.chromium.components_browsertests_apk"
}
-
- # TODO(GYP_GONE): Delete this target once recipes no longer require it.
- junit_binary("components_junit_tests") {
- java_files = [ "//testing/android/junit/DummyTest.java" ]
- }
}
if (!is_ios) {
@@ -397,7 +398,6 @@ if (!is_ios) {
"dom_distiller/content/browser/test/dom_distiller_js_browsertest.cc",
"password_manager/content/renderer/credential_manager_client_browsertest.cc",
"security_state/content/content_utils_browsertest.cc",
- "tracing/child/child_trace_message_filter_browsertest.cc",
]
data = [
diff --git a/chromium/components/OWNERS b/chromium/components/OWNERS
index 1dbc3891925..00b920b916f 100644
--- a/chromium/components/OWNERS
+++ b/chromium/components/OWNERS
@@ -11,13 +11,11 @@ per-file browsing_data_strings.grdp=file://components/browsing_data/OWNERS
per-file crash_strings.grdp=file://components/crash/OWNERS
per-file dom_distiller_strings.grdp=file://components/dom_distiller/OWNERS
per-file error_page_strings.grdp=file://components/error_page/OWNERS
-per-file nacl_helper_nonsfi_unittests.isolate=file://components/nacl/OWNERS
-per-file nacl_loader_unittests.isolate=file://components/nacl/OWNERS
per-file ntp_snippets_strings.grdp=file://components/ntp_snippets/OWNERS
per-file omnibox_strings.grdp=file://components/omnibox/OWNERS
+per-file page_info_strings.grdp=estark@chromium.org
+per-file page_info_strings.grdp=lgarron@chromium.org
per-file password_manager_strings.grdp=file://components/password_manager/OWNERS
-per-file pageinfo_strings.grdp=estark@chromium.org
-per-file pageinfo_strings.grdp=lgarron@chromium.org
per-file payments_strings.grdp=file://components/payments/OWNERS
per-file pdf_strings.grdp=raymes@chromium.org
per-file pdf_strings.grdp=tsergeant@chromium.org
@@ -30,10 +28,8 @@ per-file supervised_user_error_page_strings.grdp=file://components/supervised_us
per-file sync_ui_strings.grdp=file://components/sync/OWNERS
per-file translate_strings.grdp=file://components/translate/OWNERS
per-file undo_strings.grdp=file://components/undo/OWNERS
+per-file version_ui_strings.grdp=file://components/version_ui/OWNERS
per-file web_contents_delegate_android_strings.grdp=file://components/web_contents_delegate_android/OWNERS
-per-file *.isolate=maruel@chromium.org
-per-file *.isolate=tandrii@chromium.org
-per-file *.isolate=vadimsh@chromium.org
# These are for the common case of adding or removing tests. If you're making
# structural changes, please get a review from one of the overall components
diff --git a/chromium/components/about_handler/OWNERS b/chromium/components/about_handler/OWNERS
index e48155ce8b4..da122a46657 100644
--- a/chromium/components/about_handler/OWNERS
+++ b/chromium/components/about_handler/OWNERS
@@ -1,2 +1,4 @@
mmenke@chromium.org
davidben@chromium.org
+
+# COMPONENT: Internals>Network
diff --git a/chromium/components/about_ui/OWNERS b/chromium/components/about_ui/OWNERS
index c4cf1964147..e87625e132a 100644
--- a/chromium/components/about_ui/OWNERS
+++ b/chromium/components/about_ui/OWNERS
@@ -1 +1,3 @@
file://ui/webui/OWNERS
+
+# COMPONENT: UI>Browser>WebUI
diff --git a/chromium/components/app_modal/javascript_dialog_manager.cc b/chromium/components/app_modal/javascript_dialog_manager.cc
index cec07c96d5f..c5a368384b5 100644
--- a/chromium/components/app_modal/javascript_dialog_manager.cc
+++ b/chromium/components/app_modal/javascript_dialog_manager.cc
@@ -248,8 +248,17 @@ bool JavaScriptDialogManager::HandleJavaScriptDialog(
dialog_queue->active_dialog()->web_contents() != web_contents) {
return false;
}
+
JavaScriptAppModalDialog* dialog = static_cast<JavaScriptAppModalDialog*>(
dialog_queue->active_dialog());
+
+ if (dialog->javascript_dialog_type() ==
+ content::JavaScriptDialogType::JAVASCRIPT_DIALOG_TYPE_ALERT) {
+ // Alert dialogs only have one button: OK. Any "handling" of this dialog has
+ // to be a click on the OK button.
+ accept = true;
+ }
+
if (accept) {
if (prompt_override)
dialog->SetOverridePromptText(*prompt_override);
diff --git a/chromium/components/arc/BUILD.gn b/chromium/components/arc/BUILD.gn
index 8ff0e78341e..b0ac5a31e6f 100644
--- a/chromium/components/arc/BUILD.gn
+++ b/chromium/components/arc/BUILD.gn
@@ -21,6 +21,8 @@ static_library("arc") {
"clipboard/arc_clipboard_bridge.h",
"crash_collector/arc_crash_collector_bridge.cc",
"crash_collector/arc_crash_collector_bridge.h",
+ "file_system/file_system_struct_traits.cc",
+ "file_system/file_system_struct_traits.h",
"ime/arc_ime_bridge.h",
"ime/arc_ime_bridge_impl.cc",
"ime/arc_ime_bridge_impl.h",
@@ -30,6 +32,7 @@ static_library("arc") {
"intent_helper/activity_icon_loader.h",
"intent_helper/arc_intent_helper_bridge.cc",
"intent_helper/arc_intent_helper_bridge.h",
+ "intent_helper/arc_intent_helper_observer.h",
"intent_helper/font_size_util.cc",
"intent_helper/font_size_util.h",
"intent_helper/intent_constants.cc",
@@ -152,9 +155,11 @@ mojom("arc_bindings") {
"common/scale_factor.mojom",
"common/screen_rect.mojom",
"common/storage_manager.mojom",
+ "common/tracing.mojom",
"common/tts.mojom",
"common/video.mojom",
"common/video_accelerator.mojom",
+ "common/voice_interaction_framework.mojom",
"common/wallpaper.mojom",
]
@@ -211,6 +216,7 @@ source_set("unit_tests") {
"intent_helper/link_handler_model_impl_unittest.cc",
"intent_helper/local_activity_resolver_unittest.cc",
"intent_helper/page_transition_util_unittest.cc",
+ "kiosk/arc_kiosk_bridge_unittest.cc",
]
deps = [
@@ -220,6 +226,7 @@ source_set("unit_tests") {
"//chromeos",
"//device/bluetooth",
"//mojo/public/cpp/system:system",
+ "//testing/gmock",
"//testing/gtest",
"//ui/aura",
"//ui/aura:test_support",
diff --git a/chromium/components/arc/DEPS b/chromium/components/arc/DEPS
index b0c29d218e2..25269a06a31 100644
--- a/chromium/components/arc/DEPS
+++ b/chromium/components/arc/DEPS
@@ -7,6 +7,7 @@ include_rules = [
"+components/signin/core/account_id",
"+components/user_manager",
"+mojo",
+ "+storage/browser/fileapi",
"+third_party/re2",
"+third_party/skia",
"+ui/gfx/geometry/rect.h",
diff --git a/chromium/components/arc/arc_bridge_host_impl.cc b/chromium/components/arc/arc_bridge_host_impl.cc
index 437aa1a419e..b08a7da0fd0 100644
--- a/chromium/components/arc/arc_bridge_host_impl.cc
+++ b/chromium/components/arc/arc_bridge_host_impl.cc
@@ -198,6 +198,11 @@ void ArcBridgeHostImpl::OnStorageManagerInstanceReady(
std::move(storage_manager_ptr));
}
+void ArcBridgeHostImpl::OnTracingInstanceReady(
+ mojom::TracingInstancePtr tracing_ptr) {
+ OnInstanceReady(arc_bridge_service_->tracing(), std::move(tracing_ptr));
+}
+
void ArcBridgeHostImpl::OnTtsInstanceReady(mojom::TtsInstancePtr tts_ptr) {
OnInstanceReady(arc_bridge_service_->tts(), std::move(tts_ptr));
}
@@ -207,6 +212,12 @@ void ArcBridgeHostImpl::OnVideoInstanceReady(
OnInstanceReady(arc_bridge_service_->video(), std::move(video_ptr));
}
+void ArcBridgeHostImpl::OnVoiceInteractionFrameworkInstanceReady(
+ mojom::VoiceInteractionFrameworkInstancePtr framework_ptr) {
+ OnInstanceReady(arc_bridge_service_->voice_interaction_framework(),
+ std::move(framework_ptr));
+}
+
void ArcBridgeHostImpl::OnWallpaperInstanceReady(
mojom::WallpaperInstancePtr wallpaper_ptr) {
OnInstanceReady(arc_bridge_service_->wallpaper(), std::move(wallpaper_ptr));
diff --git a/chromium/components/arc/arc_bridge_host_impl.h b/chromium/components/arc/arc_bridge_host_impl.h
index 9ee3664d3a2..6120a5db43f 100644
--- a/chromium/components/arc/arc_bridge_host_impl.h
+++ b/chromium/components/arc/arc_bridge_host_impl.h
@@ -71,8 +71,11 @@ class ArcBridgeHostImpl : public mojom::ArcBridgeHost {
void OnProcessInstanceReady(mojom::ProcessInstancePtr process_ptr) override;
void OnStorageManagerInstanceReady(
mojom::StorageManagerInstancePtr storage_manager_ptr) override;
+ void OnTracingInstanceReady(mojom::TracingInstancePtr trace_ptr) override;
void OnTtsInstanceReady(mojom::TtsInstancePtr tts_ptr) override;
void OnVideoInstanceReady(mojom::VideoInstancePtr video_ptr) override;
+ void OnVoiceInteractionFrameworkInstanceReady(
+ mojom::VoiceInteractionFrameworkInstancePtr framework_ptr) override;
void OnWallpaperInstanceReady(
mojom::WallpaperInstancePtr wallpaper_ptr) override;
diff --git a/chromium/components/arc/arc_bridge_service.h b/chromium/components/arc/arc_bridge_service.h
index 60abe9d52dc..48fca23f2e8 100644
--- a/chromium/components/arc/arc_bridge_service.h
+++ b/chromium/components/arc/arc_bridge_service.h
@@ -36,8 +36,10 @@ class PowerInstance;
class PrintInstance;
class ProcessInstance;
class StorageManagerInstance;
+class TracingInstance;
class TtsInstance;
class VideoInstance;
+class VoiceInteractionFrameworkInstance;
class WallpaperInstance;
} // namespace mojom
@@ -89,8 +91,13 @@ class ArcBridgeService {
InstanceHolder<mojom::StorageManagerInstance>* storage_manager() {
return &storage_manager_;
}
+ InstanceHolder<mojom::TracingInstance>* tracing() { return &tracing_; }
InstanceHolder<mojom::TtsInstance>* tts() { return &tts_; }
InstanceHolder<mojom::VideoInstance>* video() { return &video_; }
+ InstanceHolder<mojom::VoiceInteractionFrameworkInstance>*
+ voice_interaction_framework() {
+ return &voice_interaction_framework_;
+ }
InstanceHolder<mojom::WallpaperInstance>* wallpaper() { return &wallpaper_; }
private:
@@ -116,8 +123,11 @@ class ArcBridgeService {
InstanceHolder<mojom::PrintInstance> print_;
InstanceHolder<mojom::ProcessInstance> process_;
InstanceHolder<mojom::StorageManagerInstance> storage_manager_;
+ InstanceHolder<mojom::TracingInstance> tracing_;
InstanceHolder<mojom::TtsInstance> tts_;
InstanceHolder<mojom::VideoInstance> video_;
+ InstanceHolder<mojom::VoiceInteractionFrameworkInstance>
+ voice_interaction_framework_;
InstanceHolder<mojom::WallpaperInstance> wallpaper_;
DISALLOW_COPY_AND_ASSIGN(ArcBridgeService);
diff --git a/chromium/components/arc/arc_session.cc b/chromium/components/arc/arc_session.cc
index c369d28c9c4..5738ed67443 100644
--- a/chromium/components/arc/arc_session.cc
+++ b/chromium/components/arc/arc_session.cc
@@ -442,7 +442,8 @@ mojo::ScopedMessagePipeHandle ArcSessionImpl::ConnectMojo(
const base::ProcessHandle kUnusedChildProcessHandle = 0;
mojo::edk::PlatformChannelPair channel_pair;
mojo::edk::PendingProcessConnection process;
- process.Connect(kUnusedChildProcessHandle, channel_pair.PassServerHandle());
+ process.Connect(kUnusedChildProcessHandle,
+ mojo::edk::ConnectionParams(channel_pair.PassServerHandle()));
mojo::edk::ScopedPlatformHandleVectorPtr handles(
new mojo::edk::PlatformHandleVector{
diff --git a/chromium/components/arc/arc_util.cc b/chromium/components/arc/arc_util.cc
index 339f6cb2346..7c3ee3f5a08 100644
--- a/chromium/components/arc/arc_util.cc
+++ b/chromium/components/arc/arc_util.cc
@@ -55,6 +55,16 @@ bool IsArcAvailable() {
base::FeatureList::IsEnabled(kEnableArcFeature));
}
+bool ShouldArcAlwaysStart() {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ chromeos::switches::kArcAlwaysStart);
+}
+
+void SetArcAlwaysStartForTesting() {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ chromeos::switches::kArcAlwaysStart);
+}
+
bool IsArcKioskAvailable() {
const auto* command_line = base::CommandLine::ForCurrentProcess();
diff --git a/chromium/components/arc/arc_util.h b/chromium/components/arc/arc_util.h
index eb31c076339..a9e69d36878 100644
--- a/chromium/components/arc/arc_util.h
+++ b/chromium/components/arc/arc_util.h
@@ -26,6 +26,14 @@ namespace arc {
// check, so it is ok to access them directly.
bool IsArcAvailable();
+// Returns true if ARC should always start within the primary user session
+// (opted in user or not), and other supported mode such as guest and Kiosk
+// mode.
+bool ShouldArcAlwaysStart();
+
+// Enables to always start ARC for testing, by appending the command line flag.
+void SetArcAlwaysStartForTesting();
+
// Returns true if ARC is installed and running ARC kiosk apps on the current
// device is officially supported.
// It doesn't follow that ARC is available for user sessions and
diff --git a/chromium/components/arc/audio/arc_audio_bridge.cc b/chromium/components/arc/audio/arc_audio_bridge.cc
index bdf7e4feafc..9a0da08829a 100644
--- a/chromium/components/arc/audio/arc_audio_bridge.cc
+++ b/chromium/components/arc/audio/arc_audio_bridge.cc
@@ -4,7 +4,7 @@
#include "components/arc/audio/arc_audio_bridge.h"
-#include "ash/common/system/chromeos/audio/tray_audio.h"
+#include "ash/system/audio/tray_audio.h"
#include "base/logging.h"
#include "chromeos/audio/audio_device.h"
#include "components/arc/arc_bridge_service.h"
diff --git a/chromium/components/arc/bluetooth/bluetooth_type_converters.cc b/chromium/components/arc/bluetooth/bluetooth_type_converters.cc
index 33b1a9f3569..03cbd21ffb9 100644
--- a/chromium/components/arc/bluetooth/bluetooth_type_converters.cc
+++ b/chromium/components/arc/bluetooth/bluetooth_type_converters.cc
@@ -127,7 +127,7 @@ TypeConverter<arc::mojom::BluetoothSdpAttributePtr,
switch (result->type) {
case bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE:
- result->value.Append(base::Value::CreateNullValue());
+ result->value.Append(base::MakeUnique<base::Value>());
break;
case bluez::BluetoothServiceAttributeValueBlueZ::UINT:
case bluez::BluetoothServiceAttributeValueBlueZ::INT:
@@ -142,7 +142,7 @@ TypeConverter<arc::mojom::BluetoothSdpAttributePtr,
if (depth + 1 >= arc::kBluetoothSDPMaxDepth) {
result->type = bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE;
result->type_size = 0;
- result->value.Append(base::Value::CreateNullValue());
+ result->value.Append(base::MakeUnique<base::Value>());
return result;
}
for (const auto& child : attr_bluez.sequence()) {
@@ -177,7 +177,7 @@ TypeConverter<bluez::BluetoothServiceAttributeValueBlueZ,
if (attr->value.GetSize() != 1) {
return bluez::BluetoothServiceAttributeValueBlueZ(
bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE, 0,
- base::Value::CreateNullValue());
+ base::MakeUnique<base::Value>());
}
std::unique_ptr<base::Value> value;
@@ -190,7 +190,7 @@ TypeConverter<bluez::BluetoothServiceAttributeValueBlueZ,
if (depth + 1 >= arc::kBluetoothSDPMaxDepth || attr->sequence.empty()) {
return bluez::BluetoothServiceAttributeValueBlueZ(
bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE, 0,
- base::Value::CreateNullValue());
+ base::MakeUnique<base::Value>());
}
auto bluez_sequence = base::MakeUnique<
@@ -207,7 +207,7 @@ TypeConverter<bluez::BluetoothServiceAttributeValueBlueZ,
}
return bluez::BluetoothServiceAttributeValueBlueZ(
bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE, 0,
- base::Value::CreateNullValue());
+ base::MakeUnique<base::Value>());
}
// static
diff --git a/chromium/components/arc/bluetooth/bluetooth_type_converters_unittest.cc b/chromium/components/arc/bluetooth/bluetooth_type_converters_unittest.cc
index c89ad8a029d..45c0106c523 100644
--- a/chromium/components/arc/bluetooth/bluetooth_type_converters_unittest.cc
+++ b/chromium/components/arc/bluetooth/bluetooth_type_converters_unittest.cc
@@ -114,7 +114,7 @@ TEST(BluetoothTypeConvertorTest, ConvertMojoValueAttributeToBlueZAttribute) {
nulltypeAttributeMojo->type =
bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE;
nulltypeAttributeMojo->type_size = 0;
- nulltypeAttributeMojo->value.Append(base::Value::CreateNullValue());
+ nulltypeAttributeMojo->value.Append(base::MakeUnique<base::Value>());
auto nulltypeAttributeBlueZ =
nulltypeAttributeMojo.To<bluez::BluetoothServiceAttributeValueBlueZ>();
@@ -287,7 +287,7 @@ TEST(BluetoothTypeConvertorTest,
auto sequenceNoData = arc::mojom::BluetoothSdpAttribute::New();
sequenceNoData->type = bluez::BluetoothServiceAttributeValueBlueZ::SEQUENCE;
sequenceNoData->type_size = 0;
- sequenceNoData->value.Append(base::Value::CreateNullValue());
+ sequenceNoData->value.Append(base::MakeUnique<base::Value>());
auto sequenceNoDataBlueZ =
sequenceNoData.To<bluez::BluetoothServiceAttributeValueBlueZ>();
@@ -362,7 +362,7 @@ TEST(BluetoothTypeConvertorTest, ConvertBlueZValueAttributeToMojoAttribute) {
std::string actualUUID;
auto uuidAttributeBlueZ = bluez::BluetoothServiceAttributeValueBlueZ(
bluez::BluetoothServiceAttributeValueBlueZ::UUID, sizeof(uint16_t),
- base::MakeUnique<base::StringValue>(valueUUID));
+ base::MakeUnique<base::Value>(valueUUID));
auto uuidAttributeMojo =
ConvertTo<arc::mojom::BluetoothSdpAttributePtr>(uuidAttributeBlueZ);
@@ -379,7 +379,7 @@ TEST(BluetoothTypeConvertorTest, ConvertBlueZValueAttributeToMojoAttribute) {
std::string actualString;
auto stringAttributeBlueZ = bluez::BluetoothServiceAttributeValueBlueZ(
bluez::BluetoothServiceAttributeValueBlueZ::STRING, valueString.length(),
- base::MakeUnique<base::StringValue>(valueString));
+ base::MakeUnique<base::Value>(valueString));
auto stringAttributeMojo =
ConvertTo<arc::mojom::BluetoothSdpAttributePtr>(stringAttributeBlueZ);
@@ -400,7 +400,7 @@ TEST(BluetoothTypeConvertorTest, ConvertBlueZSequenceAttributeToMojoAttribute) {
sequence(new bluez::BluetoothServiceAttributeValueBlueZ::Sequence());
sequence->push_back(bluez::BluetoothServiceAttributeValueBlueZ(
bluez::BluetoothServiceAttributeValueBlueZ::UUID, sizeof(uint16_t),
- base::MakeUnique<base::StringValue>(l2capUUID)));
+ base::MakeUnique<base::Value>(l2capUUID)));
sequence->push_back(bluez::BluetoothServiceAttributeValueBlueZ(
bluez::BluetoothServiceAttributeValueBlueZ::UINT, sizeof(uint16_t),
base::MakeUnique<base::Value>(l2capChannel)));
diff --git a/chromium/components/arc/common/OWNERS b/chromium/components/arc/common/OWNERS
index 16f082a0ddf..253d9465a02 100644
--- a/chromium/components/arc/common/OWNERS
+++ b/chromium/components/arc/common/OWNERS
@@ -1,5 +1,8 @@
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
+
per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS \ No newline at end of file
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/arc/common/app.mojom b/chromium/components/arc/common/app.mojom
index c255ea85544..5d6045ba2cb 100644
--- a/chromium/components/arc/common/app.mojom
+++ b/chromium/components/arc/common/app.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Next MinVersion: 18
+// Next MinVersion: 19
module arc.mojom;
@@ -75,7 +75,7 @@ enum ShowPackageInfoPage {
MANAGE_LINKS = 1,
};
-// Next method ID: 16
+// Next method ID: 17
interface AppHost {
// Sends newly added ARC app to Chrome. This message is sent when ARC receives
// package added notification. Multiple apps may be added in the one package.
@@ -148,6 +148,11 @@ interface AppHost {
// Notifies that task requested orientation lock.
[MinVersion=12] OnTaskOrientationLockRequested@12(int32 task_id,
OrientationLock lock);
+
+ // Notifies that an application shortcut needs to be deleted. Shortcut is
+ // defined by its |intent_uri| and |package_name|.
+ [MinVersion=18] OnUninstallShortcut@16(string package_name,
+ string intent_uri);
};
// TODO(lhchavez): Migrate all request/response messages to Mojo.
diff --git a/chromium/components/arc/common/arc_bridge.mojom b/chromium/components/arc/common/arc_bridge.mojom
index 7b8a9c528d4..c7b308f6094 100644
--- a/chromium/components/arc/common/arc_bridge.mojom
+++ b/chromium/components/arc/common/arc_bridge.mojom
@@ -26,13 +26,15 @@ import "power.mojom";
import "print.mojom";
import "process.mojom";
import "storage_manager.mojom";
+import "tracing.mojom";
import "tts.mojom";
import "video.mojom";
+import "voice_interaction_framework.mojom";
import "wallpaper.mojom";
-// Next MinVersion: 22
+// Next MinVersion: 24
// Deprecated method IDs: 101, 105
-// Next method ID: 128
+// Next method ID: 130
interface ArcBridgeHost {
// Keep the entries alphabetical. In order to do so without breaking
// compatibility with the ARC instance, explicitly assign each interface a
@@ -110,12 +112,19 @@ interface ArcBridgeHost {
// Notifies Chrome that the StorageManagerInstance interface is ready.
[MinVersion=12] OnStorageManagerInstanceReady@118(StorageManagerInstance instance_ptr);
+ // Notifies Chrome that the TracingInstance interface is ready.
+ [MinVersion=22] OnTracingInstanceReady@128(TracingInstance instance_ptr);
+
// Notifies Chrome that the TtsInstance interface is ready.
[MinVersion=17] OnTtsInstanceReady@123(TtsInstance instance_ptr);
// Notifies Chrome that the VideoInstance interface is ready.
[MinVersion=6] OnVideoInstanceReady@107(VideoInstance instance_ptr);
+ // Notifies Chrome that the VoiceInteractionFrameworkInstance is ready.
+ [MinVersion=23] OnVoiceInteractionFrameworkInstanceReady@129(
+ VoiceInteractionFrameworkInstance instance_ptr);
+
// Notifies Chrome that the WallpaperInstance interface is ready.
[MinVersion=18] OnWallpaperInstanceReady@124(WallpaperInstance instance_ptr);
};
diff --git a/chromium/components/arc/common/file_system.typemap b/chromium/components/arc/common/file_system.typemap
new file mode 100644
index 00000000000..cb71bf2d616
--- /dev/null
+++ b/chromium/components/arc/common/file_system.typemap
@@ -0,0 +1,11 @@
+# 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.
+
+mojom = "//components/arc/common/file_system.mojom"
+public_headers = [ "//storage/browser/fileapi/watcher_manager.h" ]
+public_deps = [
+ "//storage/browser",
+]
+traits_headers = [ "//components/arc/file_system/file_system_struct_traits.h" ]
+type_mappings = [ "arc.mojom.ChangeType=storage::WatcherManager::ChangeType" ]
diff --git a/chromium/components/arc/common/input.mojom b/chromium/components/arc/common/input.mojom
deleted file mode 100644
index 17ecc4397e3..00000000000
--- a/chromium/components/arc/common/input.mojom
+++ /dev/null
@@ -1,17 +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.
-
-module arc.mojom;
-
-interface InputInstance {
- // Registers a virtual input device on the container side.
- // |name| is the device name, like "Chrome OS Keyboard".
- // |device_type| is the device type, like "keyboard".
- // The virtual device will be reading 'struct input_event's from |fd|. The
- // ownership of |fd| will be transferred to the receiver, so the sender must
- // not close it.
- RegisterInputDevice@0(string name,
- string device_type,
- handle fd);
-};
diff --git a/chromium/components/arc/common/notifications.mojom b/chromium/components/arc/common/notifications.mojom
index 50621f101b0..ae9a48cc9d8 100644
--- a/chromium/components/arc/common/notifications.mojom
+++ b/chromium/components/arc/common/notifications.mojom
@@ -33,6 +33,16 @@ enum ArcNotificationType {
LIST = 3,
};
+// These values are corresponding to the priorities of Android notification.
+[Extensible]
+enum ArcNotificationPriority {
+ MIN = -2, // same value as Notification.PRIORITY_MIN
+ LOW = -1, // same value as Notification.PRIORITY_LOW
+ DEFAULT = 0, // same value as Notification.PRIORITY_DEFAULT
+ HIGH = 1, // same value as Notification.PRIORITY_HIGH
+ MAX = 2, // same value as Notification.PRIORITY_MAX
+};
+
struct ArcNotificationButton {
// Title
string label;
@@ -67,8 +77,8 @@ struct ArcNotificationData {
string icon_mimetype;
// Binary data of the icon
array<uint8> icon_data;
- // Priority of notification, must be [2,-2]
- int32 priority;
+ // Priority of notification
+ ArcNotificationPriority priority;
// Timestamp related to the notification
int64 time;
// The current value of progress, must be [0, progress_max].
diff --git a/chromium/components/arc/common/power.mojom b/chromium/components/arc/common/power.mojom
index 195c7c828e3..f2fc4d87de9 100644
--- a/chromium/components/arc/common/power.mojom
+++ b/chromium/components/arc/common/power.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Next min version: 3
+// Next min version: 4
module arc.mojom;
@@ -19,7 +19,7 @@ enum DisplayWakeLockType {
DIM = 1
};
-// Next method ID: 3
+// Next method ID: 4
interface PowerHost {
// Acquire and release wake locks on the host side.
OnAcquireDisplayWakeLock@0(DisplayWakeLockType type);
@@ -27,9 +27,13 @@ interface PowerHost {
// Checks if there is a display on.
[MinVersion=1] IsDisplayOn@2() => (bool is_on);
+
+ // Request that the screen brightness be changed to |percent|.
+ // |percent| is of the range [0, 100]
+ [MinVersion=3] OnScreenBrightnessUpdateRequest@3(double percent);
};
-// Next method ID: 4
+// Next method ID: 5
interface PowerInstance {
// Establishes full-duplex communication with the host.
Init@0(PowerHost host_ptr);
@@ -43,4 +47,8 @@ interface PowerInstance {
// Called when the system has just resumed.
[MinVersion=2] Resume@3();
+
+ // Update Android brightness settings.
+ // |percent| is of the range [0, 100]
+ [MinVersion=3] UpdateScreenBrightnessSettings@4(double percent);
};
diff --git a/chromium/components/arc/common/tracing.mojom b/chromium/components/arc/common/tracing.mojom
new file mode 100644
index 00000000000..e27d89ba0b3
--- /dev/null
+++ b/chromium/components/arc/common/tracing.mojom
@@ -0,0 +1,18 @@
+// 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.
+
+// Next MinVersion: 1
+
+module arc.mojom;
+
+interface TracingInstance {
+ // Queries available tracing categories in the container.
+ QueryAvailableCategories@0() => (array<string> categories);
+
+ // Starts tracing in the container with the given categories.
+ StartTracing@1(array<string> categories) => (bool success);
+
+ // Stops tracing in the container.
+ StopTracing@2() => (bool success);
+};
diff --git a/chromium/components/arc/common/typemaps.gni b/chromium/components/arc/common/typemaps.gni
index ca0c1675e6b..c130ddcd185 100644
--- a/chromium/components/arc/common/typemaps.gni
+++ b/chromium/components/arc/common/typemaps.gni
@@ -6,6 +6,7 @@ typemaps = [
"//components/arc/common/app.typemap",
"//components/arc/common/bitmap.typemap",
"//components/arc/common/bluetooth.typemap",
+ "//components/arc/common/file_system.typemap",
"//components/arc/common/intent_helper.typemap",
"//components/arc/common/video_accelerator.typemap",
]
diff --git a/chromium/components/arc/common/voice_interaction_framework.mojom b/chromium/components/arc/common/voice_interaction_framework.mojom
new file mode 100644
index 00000000000..adf25f4bd92
--- /dev/null
+++ b/chromium/components/arc/common/voice_interaction_framework.mojom
@@ -0,0 +1,36 @@
+// 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.
+//
+// Next MinVersion: 2
+
+module arc.mojom;
+
+import "screen_rect.mojom";
+
+// Handles voice interaction queries from Android.
+// Next method ID: 2
+interface VoiceInteractionFrameworkHost {
+ // Returns a screenshot of currently focused window or empty array if
+ // no window is focused.
+ CaptureFocusedWindow@0() => (array<uint8> png_data);
+
+ // Returns a fullscreen screenshot of the primary display.
+ [MinVersion=1]CaptureFullscreen@1() => (array<uint8> png_data);
+};
+
+// Connects with Android system server.
+// Next method ID:4
+interface VoiceInteractionFrameworkInstance {
+ Init@0(VoiceInteractionFrameworkHost host_ptr);
+
+ // Starts the voice interaction session in container.
+ StartVoiceInteractionSession@1();
+
+ // Starts the voice interaction session in container, with a screen region
+ // selected.
+ [MinVersion=1] StartVoiceInteractionSessionForRegion@2(ScreenRect region);
+
+ // Toggles the metalayer.
+ [MinVersion=1] ToggleMetalayer@3();
+};
diff --git a/chromium/components/arc/common/wallpaper.mojom b/chromium/components/arc/common/wallpaper.mojom
index 4feb1f428bf..d2dd78dc52f 100644
--- a/chromium/components/arc/common/wallpaper.mojom
+++ b/chromium/components/arc/common/wallpaper.mojom
@@ -2,27 +2,30 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Next MinVersion: 2
+// Next MinVersion: 3
module arc.mojom;
// Handles wallpaper calls from ARC in Chrome.
-// Next method ID:2
+// Next method ID:3
interface WallpaperHost {
// Gets current wallpaper encoded in PNG and send it back to ARC.
GetWallpaper@0() => (array<uint8> wallpaper);
// Sets an image from ARC as the wallpaper.
// |data| is a byte array of the wallpaper image.
- SetWallpaper@1(array<uint8> data);
+ SetWallpaper@1(array<uint8> data, [MinVersion=2] int32 wallpaper_id);
+
+ // Sets the default wallpaper.
+ [MinVersion=2] SetDefaultWallpaper@2();
};
// Connects with container side to publish wallpaper related intents.
-// Next method ID:2
+// Next method ID:3
interface WallpaperInstance {
// Establishes communication with the container side.
Init@0(WallpaperHost host_ptr);
// Notifies ArcWallpaperManagerService that wallpaper is changed.
- [MinVersion=1] OnWallpaperChanged@1();
-}; \ No newline at end of file
+ [MinVersion=1] OnWallpaperChanged@1([MinVersion=2] int32 wallpaper_id);
+};
diff --git a/chromium/components/arc/file_system/OWNERS b/chromium/components/arc/file_system/OWNERS
new file mode 100644
index 00000000000..bb6511619b7
--- /dev/null
+++ b/chromium/components/arc/file_system/OWNERS
@@ -0,0 +1,2 @@
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/arc/file_system/file_system_struct_traits.cc b/chromium/components/arc/file_system/file_system_struct_traits.cc
new file mode 100644
index 00000000000..df97e6bb621
--- /dev/null
+++ b/chromium/components/arc/file_system/file_system_struct_traits.cc
@@ -0,0 +1,42 @@
+// 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/arc/file_system/file_system_struct_traits.h"
+
+#include "base/logging.h"
+#include "components/arc/common/file_system.mojom.h"
+
+namespace mojo {
+
+// static
+arc::mojom::ChangeType
+EnumTraits<arc::mojom::ChangeType, storage::WatcherManager::ChangeType>::
+ ToMojom(storage::WatcherManager::ChangeType type) {
+ switch (type) {
+ case storage::WatcherManager::CHANGED:
+ return arc::mojom::ChangeType::CHANGED;
+ case storage::WatcherManager::DELETED:
+ return arc::mojom::ChangeType::DELETED;
+ }
+ NOTREACHED();
+ return arc::mojom::ChangeType::CHANGED;
+}
+
+// static
+bool EnumTraits<arc::mojom::ChangeType, storage::WatcherManager::ChangeType>::
+ FromMojom(arc::mojom::ChangeType mojom_type,
+ storage::WatcherManager::ChangeType* type) {
+ switch (mojom_type) {
+ case arc::mojom::ChangeType::CHANGED:
+ *type = storage::WatcherManager::CHANGED;
+ return true;
+ case arc::mojom::ChangeType::DELETED:
+ *type = storage::WatcherManager::DELETED;
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
+} // namespace mojo
diff --git a/chromium/components/arc/file_system/file_system_struct_traits.h b/chromium/components/arc/file_system/file_system_struct_traits.h
new file mode 100644
index 00000000000..eae87efd1f4
--- /dev/null
+++ b/chromium/components/arc/file_system/file_system_struct_traits.h
@@ -0,0 +1,23 @@
+// 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_ARC_FILE_SYSTEM_FILE_SYSTEM_STRUCT_TRAITS_H_
+#define COMPONENTS_ARC_FILE_SYSTEM_FILE_SYSTEM_STRUCT_TRAITS_H_
+
+#include "components/arc/common/file_system.mojom.h"
+#include "storage/browser/fileapi/watcher_manager.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<arc::mojom::ChangeType, storage::WatcherManager::ChangeType> {
+ static arc::mojom::ChangeType ToMojom(
+ storage::WatcherManager::ChangeType type);
+ static bool FromMojom(arc::mojom::ChangeType mojom_type,
+ storage::WatcherManager::ChangeType* type);
+};
+
+} // namespace mojo
+
+#endif // COMPONENTS_ARC_FILE_SYSTEM_FILE_SYSTEM_STRUCT_TRAITS_H_
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 953b249cb36..b9e2f350cfd 100644
--- a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc
+++ b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc
@@ -6,11 +6,10 @@
#include <utility>
-#include "ash/common/new_window_controller.h"
-#include "ash/common/shell_delegate.h"
-#include "ash/common/wallpaper/wallpaper_controller.h"
-#include "ash/common/wm_shell.h"
+#include "ash/new_window_controller.h"
#include "ash/shell.h"
+#include "ash/shell_delegate.h"
+#include "ash/wallpaper/wallpaper_controller.h"
#include "base/memory/weak_ptr.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_service_manager.h"
@@ -46,7 +45,7 @@ ArcIntentHelperBridge::~ArcIntentHelperBridge() {
void ArcIntentHelperBridge::OnInstanceReady() {
DCHECK(thread_checker_.CalledOnValidThread());
- ash::Shell::GetInstance()->set_link_handler_model_factory(this);
+ ash::Shell::Get()->set_link_handler_model_factory(this);
auto* instance =
ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service()->intent_helper(), Init);
DCHECK(instance);
@@ -55,7 +54,7 @@ void ArcIntentHelperBridge::OnInstanceReady() {
void ArcIntentHelperBridge::OnInstanceClosed() {
DCHECK(thread_checker_.CalledOnValidThread());
- ash::Shell::GetInstance()->set_link_handler_model_factory(nullptr);
+ ash::Shell::Get()->set_link_handler_model_factory(nullptr);
}
void ArcIntentHelperBridge::OnIconInvalidated(const std::string& package_name) {
@@ -69,17 +68,17 @@ void ArcIntentHelperBridge::OnOpenDownloads() {
// downloads by default, which is what we want. However if it is open it will
// simply be brought to the forgeground without forcibly being navigated to
// downloads, which is probably not ideal.
- ash::WmShell::Get()->new_window_controller()->OpenFileManager();
+ ash::Shell::Get()->new_window_controller()->OpenFileManager();
}
void ArcIntentHelperBridge::OnOpenUrl(const std::string& url) {
DCHECK(thread_checker_.CalledOnValidThread());
- ash::WmShell::Get()->delegate()->OpenUrlFromArc(GURL(url));
+ ash::Shell::Get()->shell_delegate()->OpenUrlFromArc(GURL(url));
}
void ArcIntentHelperBridge::OpenWallpaperPicker() {
DCHECK(thread_checker_.CalledOnValidThread());
- ash::WmShell::Get()->wallpaper_controller()->OpenSetWallpaperPage();
+ ash::Shell::Get()->wallpaper_controller()->OpenSetWallpaperPage();
}
void ArcIntentHelperBridge::SetWallpaperDeprecated(
diff --git a/chromium/components/arc/kiosk/arc_kiosk_bridge_unittest.cc b/chromium/components/arc/kiosk/arc_kiosk_bridge_unittest.cc
new file mode 100644
index 00000000000..b2243f7ca37
--- /dev/null
+++ b/chromium/components/arc/kiosk/arc_kiosk_bridge_unittest.cc
@@ -0,0 +1,59 @@
+// 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 <memory>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "components/arc/arc_bridge_service.h"
+#include "components/arc/kiosk/arc_kiosk_bridge.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class MockArcKioskBridgeDelegate : public arc::ArcKioskBridge::Delegate {
+ public:
+ MockArcKioskBridgeDelegate() = default;
+
+ MOCK_METHOD0(OnMaintenanceSessionCreated, void());
+ MOCK_METHOD0(OnMaintenanceSessionFinished, void());
+};
+
+} // namespace
+
+namespace arc {
+
+class ArcKioskBridgeTest : public testing::Test {
+ public:
+ ArcKioskBridgeTest()
+ : bridge_service_(base::MakeUnique<ArcBridgeService>()),
+ delegate_(base::MakeUnique<MockArcKioskBridgeDelegate>()),
+ kiosk_bridge_(base::MakeUnique<ArcKioskBridge>(bridge_service_.get(),
+ delegate_.get())) {}
+
+ protected:
+ std::unique_ptr<ArcBridgeService> bridge_service_;
+ std::unique_ptr<MockArcKioskBridgeDelegate> delegate_;
+ std::unique_ptr<ArcKioskBridge> kiosk_bridge_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ArcKioskBridgeTest);
+};
+
+TEST_F(ArcKioskBridgeTest, MaintenanceSessionFinished) {
+ EXPECT_CALL(*delegate_, OnMaintenanceSessionCreated()).Times(1);
+ kiosk_bridge_->OnMaintenanceSessionCreated(1);
+ EXPECT_CALL(*delegate_, OnMaintenanceSessionFinished()).Times(1);
+ kiosk_bridge_->OnMaintenanceSessionFinished(1, true);
+}
+
+TEST_F(ArcKioskBridgeTest, MaintenanceSessionNotFinished) {
+ EXPECT_CALL(*delegate_, OnMaintenanceSessionCreated()).Times(1);
+ kiosk_bridge_->OnMaintenanceSessionCreated(1);
+ EXPECT_CALL(*delegate_, OnMaintenanceSessionFinished()).Times(0);
+ kiosk_bridge_->OnMaintenanceSessionFinished(2, true);
+}
+
+} // namespace arc
diff --git a/chromium/components/arc/net/arc_net_host_impl.cc b/chromium/components/arc/net/arc_net_host_impl.cc
index 05cb78d126c..2531cdf881f 100644
--- a/chromium/components/arc/net/arc_net_host_impl.cc
+++ b/chromium/components/arc/net/arc_net_host_impl.cc
@@ -374,8 +374,8 @@ void ArcNetHostImpl::GetNetworks(mojom::GetNetworksRequestType type,
for (const auto& value : *network_properties_list) {
mojom::WifiConfigurationPtr wc = mojom::WifiConfiguration::New();
- base::DictionaryValue* network_dict = nullptr;
- value->GetAsDictionary(&network_dict);
+ const base::DictionaryValue* network_dict = nullptr;
+ value.GetAsDictionary(&network_dict);
DCHECK(network_dict);
// kName is a post-processed version of kHexSSID.
@@ -389,7 +389,7 @@ void ArcNetHostImpl::GetNetworks(mojom::GetNetworksRequestType type,
DCHECK(!tmp.empty());
wc->guid = tmp;
- base::DictionaryValue* wifi_dict = nullptr;
+ const base::DictionaryValue* wifi_dict = nullptr;
network_dict->GetDictionary(onc::network_config::kWiFi, &wifi_dict);
DCHECK(wifi_dict);
diff --git a/chromium/components/arc/power/arc_power_bridge.cc b/chromium/components/arc/power/arc_power_bridge.cc
index a9a47f52230..d63f49c4fdb 100644
--- a/chromium/components/arc/power/arc_power_bridge.cc
+++ b/chromium/components/arc/power/arc_power_bridge.cc
@@ -16,8 +16,13 @@
namespace arc {
+// Delay for notifying Android about screen brightness changes, added in
+// order to prevent spammy brightness updates.
+constexpr base::TimeDelta kNotifyBrightnessDelay =
+ base::TimeDelta::FromMilliseconds(200);
+
ArcPowerBridge::ArcPowerBridge(ArcBridgeService* bridge_service)
- : ArcService(bridge_service), binding_(this) {
+ : ArcService(bridge_service), binding_(this), weak_ptr_factory_(this) {
arc_bridge_service()->power()->AddObserver(this);
}
@@ -31,13 +36,18 @@ void ArcPowerBridge::OnInstanceReady() {
ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service()->power(), Init);
DCHECK(power_instance);
power_instance->Init(binding_.CreateInterfacePtrAndBind());
- ash::Shell::GetInstance()->display_configurator()->AddObserver(this);
+ ash::Shell::Get()->display_configurator()->AddObserver(this);
chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
AddObserver(this);
+ chromeos::DBusThreadManager::Get()
+ ->GetPowerManagerClient()
+ ->GetScreenBrightnessPercent(
+ base::Bind(&ArcPowerBridge::UpdateAndroidScreenBrightness,
+ weak_ptr_factory_.GetWeakPtr()));
}
void ArcPowerBridge::OnInstanceClosed() {
- ash::Shell::GetInstance()->display_configurator()->RemoveObserver(this);
+ ash::Shell::Get()->display_configurator()->RemoveObserver(this);
chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
RemoveObserver(this);
ReleaseAllDisplayWakeLocks();
@@ -63,6 +73,22 @@ void ArcPowerBridge::SuspendDone(const base::TimeDelta& sleep_duration) {
power_instance->Resume();
}
+void ArcPowerBridge::BrightnessChanged(int level, bool user_initiated) {
+ double percent = static_cast<double>(level);
+ const base::TimeTicks now = base::TimeTicks::Now();
+ if (last_brightness_changed_time_.is_null() ||
+ (now - last_brightness_changed_time_) >= kNotifyBrightnessDelay) {
+ UpdateAndroidScreenBrightness(percent);
+ notify_brightness_timer_.Stop();
+ } else {
+ notify_brightness_timer_.Start(
+ FROM_HERE, kNotifyBrightnessDelay,
+ base::Bind(&ArcPowerBridge::UpdateAndroidScreenBrightness,
+ weak_ptr_factory_.GetWeakPtr(), percent));
+ }
+ last_brightness_changed_time_ = now;
+}
+
void ArcPowerBridge::OnPowerStateChanged(
chromeos::DisplayPowerState power_state) {
mojom::PowerInstance* power_instance = ARC_GET_INSTANCE_FOR_METHOD(
@@ -122,8 +148,13 @@ void ArcPowerBridge::OnReleaseDisplayWakeLock(mojom::DisplayWakeLockType type) {
}
void ArcPowerBridge::IsDisplayOn(const IsDisplayOnCallback& callback) {
- callback.Run(
- ash::Shell::GetInstance()->display_configurator()->IsDisplayOn());
+ callback.Run(ash::Shell::Get()->display_configurator()->IsDisplayOn());
+}
+
+void ArcPowerBridge::OnScreenBrightnessUpdateRequest(double percent) {
+ chromeos::DBusThreadManager::Get()
+ ->GetPowerManagerClient()
+ ->SetScreenBrightnessPercent(percent, true);
}
void ArcPowerBridge::ReleaseAllDisplayWakeLocks() {
@@ -140,4 +171,12 @@ void ArcPowerBridge::ReleaseAllDisplayWakeLocks() {
wake_locks_.clear();
}
+void ArcPowerBridge::UpdateAndroidScreenBrightness(double percent) {
+ mojom::PowerInstance* power_instance = ARC_GET_INSTANCE_FOR_METHOD(
+ arc_bridge_service()->power(), UpdateScreenBrightnessSettings);
+ if (!power_instance)
+ return;
+ power_instance->UpdateScreenBrightnessSettings(percent);
+}
+
} // namespace arc
diff --git a/chromium/components/arc/power/arc_power_bridge.h b/chromium/components/arc/power/arc_power_bridge.h
index c459cffbb07..e6a5c7a51a3 100644
--- a/chromium/components/arc/power/arc_power_bridge.h
+++ b/chromium/components/arc/power/arc_power_bridge.h
@@ -37,6 +37,7 @@ class ArcPowerBridge : public ArcService,
// chromeos::PowerManagerClient::Observer overrides.
void SuspendImminent() override;
void SuspendDone(const base::TimeDelta& sleep_duration) override;
+ void BrightnessChanged(int level, bool user_initiated) override;
// DisplayConfigurator::Observer overrides.
void OnPowerStateChanged(chromeos::DisplayPowerState power_state) override;
@@ -45,9 +46,11 @@ class ArcPowerBridge : public ArcService,
void OnAcquireDisplayWakeLock(mojom::DisplayWakeLockType type) override;
void OnReleaseDisplayWakeLock(mojom::DisplayWakeLockType type) override;
void IsDisplayOn(const IsDisplayOnCallback& callback) override;
+ void OnScreenBrightnessUpdateRequest(double percent) override;
private:
void ReleaseAllDisplayWakeLocks();
+ void UpdateAndroidScreenBrightness(double percent);
mojo::Binding<mojom::PowerHost> binding_;
@@ -55,6 +58,14 @@ class ArcPowerBridge : public ArcService,
// held by ARC.
std::multimap<mojom::DisplayWakeLockType, int> wake_locks_;
+ // Last time that the power manager notified about a brightness change.
+ base::TimeTicks last_brightness_changed_time_;
+ // Timer used to run UpdateAndroidScreenBrightness() to notify Android
+ // about brightness changes.
+ base::OneShotTimer notify_brightness_timer_;
+
+ base::WeakPtrFactory<ArcPowerBridge> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(ArcPowerBridge);
};
diff --git a/chromium/components/autofill/OWNERS b/chromium/components/autofill/OWNERS
index 585db25ef2c..4afcbe94aa4 100644
--- a/chromium/components/autofill/OWNERS
+++ b/chromium/components/autofill/OWNERS
@@ -4,9 +4,4 @@ rogerm@chromium.org
sebsg@chromium.org
vabr@chromium.org
-# Owners for password autofill/generation only.
-# TODO(gcasto): Change to per-file ownership after http://crbug.com/235756
-# is fixed.
-gcasto@chromium.org
-
# COMPONENT: UI>Browser>Autofill
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.cc b/chromium/components/autofill/content/browser/content_autofill_driver.cc
index 38bf3070fd2..d7403b73d04 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.cc
@@ -36,7 +36,6 @@ ContentAutofillDriver::ContentAutofillDriver(
const std::string& app_locale,
AutofillManager::AutofillDownloadManagerState enable_download_manager)
: render_frame_host_(render_frame_host),
- client_(client),
autofill_manager_(new AutofillManager(this,
client,
app_locale,
@@ -62,7 +61,7 @@ void ContentAutofillDriver::BindRequest(mojom::AutofillDriverRequest request) {
binding_.Bind(std::move(request));
}
-bool ContentAutofillDriver::IsOffTheRecord() const {
+bool ContentAutofillDriver::IsIncognito() const {
return render_frame_host_->GetSiteInstance()
->GetBrowserContext()
->IsOffTheRecord();
@@ -181,11 +180,6 @@ void ContentAutofillDriver::DidInteractWithCreditCardForm() {
contents->OnCreditCardInputShownOnHttp();
}
-// mojom::AutofillDriver:
-void ContentAutofillDriver::FirstUserGestureObserved() {
- client_->OnFirstUserGestureObserved();
-}
-
void ContentAutofillDriver::FormsSeen(const std::vector<FormData>& forms,
base::TimeTicks timestamp) {
autofill_manager_->OnFormsSeen(forms, timestamp);
@@ -243,8 +237,10 @@ void ContentAutofillDriver::SetDataList(
void ContentAutofillDriver::DidNavigateFrame(
content::NavigationHandle* navigation_handle) {
- if (navigation_handle->IsInMainFrame() && !navigation_handle->IsSamePage())
+ if (navigation_handle->IsInMainFrame() &&
+ !navigation_handle->IsSameDocument()) {
autofill_manager_->Reset();
+ }
}
void ContentAutofillDriver::SetAutofillManager(
@@ -253,10 +249,6 @@ void ContentAutofillDriver::SetAutofillManager(
autofill_manager_->SetExternalDelegate(&autofill_external_delegate_);
}
-void ContentAutofillDriver::NotifyFirstUserGestureObservedInTab() {
- GetAutofillAgent()->FirstUserGestureObservedInTab();
-}
-
const mojom::AutofillAgentPtr& ContentAutofillDriver::GetAutofillAgent() {
// Here is a lazy binding, and will not reconnect after connection error.
if (!autofill_agent_) {
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.h b/chromium/components/autofill/content/browser/content_autofill_driver.h
index f038f76f89c..56a8f91fe94 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.h
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.h
@@ -47,7 +47,7 @@ class ContentAutofillDriver : public AutofillDriver,
void BindRequest(mojom::AutofillDriverRequest request);
// AutofillDriver:
- bool IsOffTheRecord() const override;
+ bool IsIncognito() const override;
net::URLRequestContextGetter* GetURLRequestContext() override;
base::SequencedWorkerPool* GetBlockingPool() override;
bool RendererIsAvailable() override;
@@ -69,10 +69,8 @@ class ContentAutofillDriver : public AutofillDriver,
gfx::RectF TransformBoundingBoxToViewportCoordinates(
const gfx::RectF& bounding_box) override;
void DidInteractWithCreditCardForm() override;
- void NotifyFirstUserGestureObservedInTab() override;
// mojom::AutofillDriver:
- void FirstUserGestureObserved() override;
void FormsSeen(const std::vector<FormData>& forms,
base::TimeTicks timestamp) override;
void WillSubmitForm(const FormData& form, base::TimeTicks timestamp) override;
@@ -126,9 +124,6 @@ class ContentAutofillDriver : public AutofillDriver,
// always be non-NULL and valid for lifetime of |this|.
content::RenderFrameHost* const render_frame_host_;
- // The per-tab client.
- AutofillClient* client_;
-
// AutofillManager instance via which this object drives the shared Autofill
// code.
std::unique_ptr<AutofillManager> autofill_manager_;
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 9d7fcb2a767..95227ba5997 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -491,15 +491,4 @@ TEST_F(ContentAutofillDriverTest, CreditCardFormInteractionOnHTTPS) {
content::SSLStatus::DISPLAYED_CREDIT_CARD_FIELD_ON_HTTP));
}
-TEST_F(ContentAutofillDriverTest, NotifyFirstUserGestureObservedInTab) {
- driver_->NotifyFirstUserGestureObservedInTab();
- EXPECT_CALL(fake_agent_, FirstUserGestureObservedInTab());
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(ContentAutofillDriverTest, FirstUserGestureObserved) {
- EXPECT_CALL(*test_autofill_client_, OnFirstUserGestureObserved());
- driver_->FirstUserGestureObserved();
-}
-
} // namespace autofill
diff --git a/chromium/components/autofill/content/browser/key_press_handler_manager_unittest.cc b/chromium/components/autofill/content/browser/key_press_handler_manager_unittest.cc
index e839b3d2b2e..79bc0eea36d 100644
--- a/chromium/components/autofill/content/browser/key_press_handler_manager_unittest.cc
+++ b/chromium/components/autofill/content/browser/key_press_handler_manager_unittest.cc
@@ -15,7 +15,7 @@ namespace autofill {
namespace {
const content::NativeWebKeyboardEvent
- kDummyEvent(blink::WebInputEvent::Undefined, 0, 0);
+ kDummyEvent(blink::WebInputEvent::kUndefined, 0, 0);
// Dummy keyboard event handler: ignores the event, but appends the given |name|
// to a logging |target|.
diff --git a/chromium/components/autofill/content/browser/risk/fingerprint.cc b/chromium/components/autofill/content/browser/risk/fingerprint.cc
index 09041403ccc..d382553c87c 100644
--- a/chromium/components/autofill/content/browser/risk/fingerprint.cc
+++ b/chromium/components/autofill/content/browser/risk/fingerprint.cc
@@ -86,7 +86,7 @@ void AddFontsToFingerprint(const base::ListValue& fonts,
// 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.
const base::ListValue* font_description = NULL;
- bool success = it->GetAsList(&font_description);
+ bool success = it.GetAsList(&font_description);
DCHECK(success);
std::string font_name;
diff --git a/chromium/components/autofill/content/common/OWNERS b/chromium/components/autofill/content/common/OWNERS
index 4a41b7b1a6c..92c6ef9d844 100644
--- a/chromium/components/autofill/content/common/OWNERS
+++ b/chromium/components/autofill/content/common/OWNERS
@@ -2,6 +2,8 @@
# new sandbox escapes.
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
per-file *_struct_traits*.*=set noparent
per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
per-file *_message*.*=set noparent
diff --git a/chromium/components/autofill/content/common/autofill_agent.mojom b/chromium/components/autofill/content/common/autofill_agent.mojom
index 7870cafc8b4..f75445c7d58 100644
--- a/chromium/components/autofill/content/common/autofill_agent.mojom
+++ b/chromium/components/autofill/content/common/autofill_agent.mojom
@@ -10,10 +10,6 @@ import "mojo/common/string16.mojom";
// There is one instance of this interface per render frame in the render
// process.
interface AutofillAgent {
- // Tells the render frame that a user gesture was observed
- // somewhere in the tab (including in a different frame).
- FirstUserGestureObservedInTab();
-
// Instructs the renderer to fill the active form with the given form data.
// Please refer AutofillDriver.QueryFormFieldAutofill comments about the |id|.
FillForm(int32 id, FormData form);
diff --git a/chromium/components/autofill/content/common/autofill_driver.mojom b/chromium/components/autofill/content/common/autofill_driver.mojom
index ce08780300c..1a8d5c2bb2f 100644
--- a/chromium/components/autofill/content/common/autofill_driver.mojom
+++ b/chromium/components/autofill/content/common/autofill_driver.mojom
@@ -13,9 +13,6 @@ import "ui/gfx/geometry/mojo/geometry.mojom";
// There is one instance of this interface per render frame host in the browser
// process.
interface AutofillDriver {
- // Notification that there has been a user gesture.
- FirstUserGestureObserved();
-
// Notification that forms have been seen that are candidates for
// filling/submitting by the AutofillManager.
FormsSeen(array<FormData> forms, mojo.common.mojom.TimeTicks timestamp);
diff --git a/chromium/components/autofill/content/common/autofill_types.mojom b/chromium/components/autofill/content/common/autofill_types.mojom
index 0ff43e1976a..5e0c6ee9f3a 100644
--- a/chromium/components/autofill/content/common/autofill_types.mojom
+++ b/chromium/components/autofill/content/common/autofill_types.mojom
@@ -117,12 +117,6 @@ struct PasswordAndRealm {
string realm;
};
-// autofill::UsernamesCollectionKey
-struct UsernamesCollectionKey {
- string username;
- string password;
- string realm;
-};
// autofill::PasswordFormFillData
struct PasswordFormFillData {
@@ -133,11 +127,6 @@ struct PasswordFormFillData {
FormFieldData password_field;
string preferred_realm;
map<string, PasswordAndRealm> additional_logins;
- // TODO(leonhsl): Use map directly after http://crbug.com/628104 solved.
- // Keys for std::map<UsernamesCollectionKey, std::vector<base::string16>>
- array<UsernamesCollectionKey> other_possible_usernames_keys;
- // Values for std::map<UsernamesCollectionKey, std::vector<base::string16>>
- array<array<string>> other_possible_usernames_values;
bool wait_for_username;
bool is_possible_change_password_form;
};
@@ -146,6 +135,14 @@ struct PasswordFormFillData {
struct PasswordFormGenerationData {
uint64 form_signature;
uint32 field_signature;
+ bool has_confirmation_field;
+ uint32 confirmation_field_signature;
+};
+
+// autofill::PossibleUsernamePair
+struct PossibleUsernamePair {
+ string value;
+ string field_name;
};
// autofill::PasswordForm
@@ -159,7 +156,7 @@ struct PasswordForm {
string username_element;
bool username_marked_by_site;
string username_value;
- array<string> other_possible_usernames;
+ array<PossibleUsernamePair> other_possible_usernames;
string password_element;
string password_value;
bool password_value_is_default;
diff --git a/chromium/components/autofill/content/common/autofill_types.typemap b/chromium/components/autofill/content/common/autofill_types.typemap
index 7072d03c967..22e639391d6 100644
--- a/chromium/components/autofill/content/common/autofill_types.typemap
+++ b/chromium/components/autofill/content/common/autofill_types.typemap
@@ -42,5 +42,5 @@ type_mappings = [
"autofill.mojom.PasswordFormScheme=autofill::PasswordForm::Scheme",
"autofill.mojom.PasswordFormType=autofill::PasswordForm::Type",
"autofill.mojom.RoleAttribute=autofill::FormFieldData::RoleAttribute",
- "autofill.mojom.UsernamesCollectionKey=autofill::UsernamesCollectionKey",
+ "autofill.mojom.PossibleUsernamePair=autofill::PossibleUsernamePair",
]
diff --git a/chromium/components/autofill/content/common/autofill_types_struct_traits.cc b/chromium/components/autofill/content/common/autofill_types_struct_traits.cc
index 1b3d8ab6214..d63283688a4 100644
--- a/chromium/components/autofill/content/common/autofill_types_struct_traits.cc
+++ b/chromium/components/autofill/content/common/autofill_types_struct_traits.cc
@@ -403,40 +403,6 @@ bool StructTraits<mojom::PasswordAndRealmDataView, PasswordAndRealm>::Read(
}
// static
-bool StructTraits<
- mojom::UsernamesCollectionKeyDataView,
- UsernamesCollectionKey>::Read(mojom::UsernamesCollectionKeyDataView data,
- UsernamesCollectionKey* out) {
- if (!data.ReadUsername(&out->username))
- return false;
- if (!data.ReadPassword(&out->password))
- return false;
- if (!data.ReadRealm(&out->realm))
- return false;
-
- return true;
-}
-
-// static
-void* StructTraits<mojom::PasswordFormFillDataDataView, PasswordFormFillData>::
- SetUpContext(const PasswordFormFillData& r) {
- // Extracts keys vector and values vector from the map, saves them as a pair.
- auto* pair = new UsernamesCollectionKeysValuesPair();
- for (const auto& i : r.other_possible_usernames) {
- pair->first.push_back(i.first);
- pair->second.push_back(i.second);
- }
-
- return pair;
-}
-
-// static
-void StructTraits<mojom::PasswordFormFillDataDataView, PasswordFormFillData>::
- TearDownContext(const PasswordFormFillData& r, void* context) {
- delete static_cast<UsernamesCollectionKeysValuesPair*>(context);
-}
-
-// static
bool StructTraits<mojom::PasswordFormFillDataDataView, PasswordFormFillData>::
Read(mojom::PasswordFormFillDataDataView data, PasswordFormFillData* out) {
if (!data.ReadName(&out->name) || !data.ReadOrigin(&out->origin) ||
@@ -447,19 +413,6 @@ bool StructTraits<mojom::PasswordFormFillDataDataView, PasswordFormFillData>::
!data.ReadAdditionalLogins(&out->additional_logins))
return false;
- // Combines keys vector and values vector to the map.
- std::vector<UsernamesCollectionKey> keys;
- if (!data.ReadOtherPossibleUsernamesKeys(&keys))
- return false;
- std::vector<std::vector<base::string16>> values;
- if (!data.ReadOtherPossibleUsernamesValues(&values))
- return false;
- if (keys.size() != values.size())
- return false;
- out->other_possible_usernames.clear();
- for (size_t i = 0; i < keys.size(); ++i)
- out->other_possible_usernames.insert({keys[i], values[i]});
-
out->wait_for_username = data.wait_for_username();
out->is_possible_change_password_form =
data.is_possible_change_password_form();
@@ -474,6 +427,12 @@ bool StructTraits<mojom::PasswordFormGenerationDataDataView,
PasswordFormGenerationData* out) {
out->form_signature = data.form_signature();
out->field_signature = data.field_signature();
+ if (data.has_confirmation_field()) {
+ out->confirmation_field_signature.emplace(
+ data.confirmation_field_signature());
+ } else {
+ DCHECK(!out->confirmation_field_signature);
+ }
return true;
}
@@ -626,4 +585,13 @@ bool StructTraits<mojom::FormsPredictionsMapDataView, FormsPredictionsMap>::
return true;
}
+// static
+bool StructTraits<mojom::PossibleUsernamePairDataView, PossibleUsernamePair>::
+ Read(mojom::PossibleUsernamePairDataView data, PossibleUsernamePair* out) {
+ if (!data.ReadValue(&out->first) || !data.ReadFieldName(&out->second))
+ return false;
+
+ return true;
+}
+
} // namespace mojo
diff --git a/chromium/components/autofill/content/common/autofill_types_struct_traits.h b/chromium/components/autofill/content/common/autofill_types_struct_traits.h
index f5156bb888d..7d4c0303542 100644
--- a/chromium/components/autofill/content/common/autofill_types_struct_traits.h
+++ b/chromium/components/autofill/content/common/autofill_types_struct_traits.h
@@ -270,37 +270,8 @@ struct StructTraits<autofill::mojom::PasswordAndRealmDataView,
};
template <>
-struct StructTraits<autofill::mojom::UsernamesCollectionKeyDataView,
- autofill::UsernamesCollectionKey> {
- static const base::string16& username(
- const autofill::UsernamesCollectionKey& r) {
- return r.username;
- }
-
- static const base::string16& password(
- const autofill::UsernamesCollectionKey& r) {
- return r.password;
- }
-
- static const std::string& realm(const autofill::UsernamesCollectionKey& r) {
- return r.realm;
- }
-
- static bool Read(autofill::mojom::UsernamesCollectionKeyDataView data,
- autofill::UsernamesCollectionKey* out);
-};
-
-template <>
struct StructTraits<autofill::mojom::PasswordFormFillDataDataView,
autofill::PasswordFormFillData> {
- using UsernamesCollectionKeysValuesPair =
- std::pair<std::vector<autofill::UsernamesCollectionKey>,
- std::vector<std::vector<base::string16>>>;
-
- static void* SetUpContext(const autofill::PasswordFormFillData& r);
-
- static void TearDownContext(const autofill::PasswordFormFillData& r,
- void* context);
static const base::string16& name(const autofill::PasswordFormFillData& r) {
return r.name;
@@ -334,18 +305,6 @@ struct StructTraits<autofill::mojom::PasswordFormFillDataDataView,
return r.additional_logins;
}
- static const std::vector<autofill::UsernamesCollectionKey>&
- other_possible_usernames_keys(const autofill::PasswordFormFillData& r,
- void* context) {
- return static_cast<UsernamesCollectionKeysValuesPair*>(context)->first;
- }
-
- static const std::vector<std::vector<base::string16>>&
- other_possible_usernames_values(const autofill::PasswordFormFillData& r,
- void* context) {
- return static_cast<UsernamesCollectionKeysValuesPair*>(context)->second;
- }
-
static bool wait_for_username(const autofill::PasswordFormFillData& r) {
return r.wait_for_username;
}
@@ -372,6 +331,16 @@ struct StructTraits<autofill::mojom::PasswordFormGenerationDataDataView,
return r.field_signature;
}
+ static bool has_confirmation_field(
+ const autofill::PasswordFormGenerationData& r) {
+ return r.confirmation_field_signature.has_value();
+ }
+
+ static uint32_t confirmation_field_signature(
+ const autofill::PasswordFormGenerationData& r) {
+ return r.confirmation_field_signature.value_or(0);
+ }
+
static bool Read(autofill::mojom::PasswordFormGenerationDataDataView data,
autofill::PasswordFormGenerationData* out);
};
@@ -418,8 +387,8 @@ struct StructTraits<autofill::mojom::PasswordFormDataView,
return r.username_value;
}
- static const std::vector<base::string16>& other_possible_usernames(
- const autofill::PasswordForm& r) {
+ static const std::vector<autofill::PossibleUsernamePair>&
+ other_possible_usernames(const autofill::PasswordForm& r) {
return r.other_possible_usernames;
}
@@ -588,6 +557,21 @@ struct StructTraits<autofill::mojom::FormsPredictionsMapDataView,
autofill::FormsPredictionsMap* out);
};
+template <>
+struct StructTraits<autofill::mojom::PossibleUsernamePairDataView,
+ autofill::PossibleUsernamePair> {
+ static base::string16 value(const autofill::PossibleUsernamePair& r) {
+ return r.first;
+ }
+
+ static base::string16 field_name(const autofill::PossibleUsernamePair& r) {
+ return r.second;
+ }
+
+ static bool Read(autofill::mojom::PossibleUsernamePairDataView data,
+ autofill::PossibleUsernamePair* out);
+};
+
} // namespace mojo
#endif // COMPONENTS_AUTOFILL_CONTENT_COMMON_AUTOFILL_TYPES_STRUCT_TRAITS_H_
diff --git a/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc b/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc
index f4ab58b1278..b60bff05a7e 100644
--- a/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc
+++ b/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc
@@ -54,21 +54,6 @@ void CreateTestPasswordFormFillData(PasswordFormFillData* fill_data) {
pr.realm = "https://bar.com/";
fill_data->additional_logins[name] = pr;
- UsernamesCollectionKey key;
- key.username = base::ASCIIToUTF16("Tom");
- key.password = base::ASCIIToUTF16("Tom_Password");
- key.realm = "https://foo.com/";
- std::vector<base::string16>& possible_names =
- fill_data->other_possible_usernames[key];
- possible_names.push_back(base::ASCIIToUTF16("Tom_1"));
- possible_names.push_back(base::ASCIIToUTF16("Tom_2"));
- key.username = base::ASCIIToUTF16("Jerry");
- key.password = base::ASCIIToUTF16("Jerry_Password");
- key.realm = "https://bar.com/";
- possible_names = fill_data->other_possible_usernames[key];
- possible_names.push_back(base::ASCIIToUTF16("Jerry_1"));
- possible_names.push_back(base::ASCIIToUTF16("Jerry_2"));
-
fill_data->wait_for_username = true;
fill_data->is_possible_change_password_form = false;
}
@@ -83,8 +68,10 @@ void CreateTestPasswordForm(PasswordForm* form) {
form->username_element = base::ASCIIToUTF16("username");
form->username_marked_by_site = true;
form->username_value = base::ASCIIToUTF16("test@gmail.com");
- form->other_possible_usernames.push_back(base::ASCIIToUTF16("Jerry_1"));
- form->other_possible_usernames.push_back(base::ASCIIToUTF16("Jerry_2"));
+ form->other_possible_usernames.push_back(PossibleUsernamePair(
+ base::ASCIIToUTF16("Jerry_1"), base::ASCIIToUTF16("id1")));
+ form->other_possible_usernames.push_back(PossibleUsernamePair(
+ base::ASCIIToUTF16("Jerry_2"), base::ASCIIToUTF16("id2")));
form->password_element = base::ASCIIToUTF16("password");
form->password_value = base::ASCIIToUTF16("test");
form->password_value_is_default = true;
@@ -201,6 +188,10 @@ void CheckEqualPasswordFormGenerationData(
const PasswordFormGenerationData& actual) {
EXPECT_EQ(expected.form_signature, actual.form_signature);
EXPECT_EQ(expected.field_signature, actual.field_signature);
+ ASSERT_EQ(expected.confirmation_field_signature.has_value(),
+ actual.confirmation_field_signature.has_value());
+ EXPECT_EQ(expected.confirmation_field_signature.value(),
+ actual.confirmation_field_signature.value());
}
} // namespace
@@ -407,7 +398,10 @@ TEST_F(AutofillTypeTraitsTestImpl, PassPasswordFormGenerationData) {
FormSignature form_signature = CalculateFormSignature(form);
FieldSignature field_signature =
CalculateFieldSignatureForField(form.fields[0]);
- PasswordFormGenerationData input{form_signature, field_signature};
+ FieldSignature confirmation_field_signature =
+ CalculateFieldSignatureForField(form.fields[1]);
+ PasswordFormGenerationData input(form_signature, field_signature);
+ input.confirmation_field_signature.emplace(confirmation_field_signature);
base::RunLoop loop;
mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy();
diff --git a/chromium/components/autofill/content/renderer/BUILD.gn b/chromium/components/autofill/content/renderer/BUILD.gn
index 2ddd7715dc2..ce916440990 100644
--- a/chromium/components/autofill/content/renderer/BUILD.gn
+++ b/chromium/components/autofill/content/renderer/BUILD.gn
@@ -21,6 +21,8 @@ static_library("renderer") {
"password_form_conversion_utils.h",
"password_generation_agent.cc",
"password_generation_agent.h",
+ "provisionally_saved_password_form.cc",
+ "provisionally_saved_password_form.h",
"renderer_save_password_progress_logger.cc",
"renderer_save_password_progress_logger.h",
]
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.cc b/chromium/components/autofill/content/renderer/autofill_agent.cc
index c655255b936..ef165ba059e 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/autofill_agent.cc
@@ -15,6 +15,7 @@
#include "base/location.h"
#include "base/metrics/field_trial.h"
#include "base/single_thread_task_runner.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -22,7 +23,6 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/autofill/content/renderer/form_autofill_util.h"
-#include "components/autofill/content/renderer/page_click_tracker.h"
#include "components/autofill/content/renderer/password_autofill_agent.h"
#include "components/autofill/content/renderer/password_generation_agent.h"
#include "components/autofill/content/renderer/renderer_save_password_progress_logger.h"
@@ -108,10 +108,10 @@ bool IsSingleClickEnabled() {
void GetDataListSuggestions(const WebInputElement& element,
std::vector<base::string16>* values,
std::vector<base::string16>* labels) {
- for (const auto& option : element.filteredDataListOptions()) {
- values->push_back(option.value().utf16());
- if (option.value() != option.label())
- labels->push_back(option.label().utf16());
+ for (const auto& option : element.FilteredDataListOptions()) {
+ values->push_back(option.Value().Utf16());
+ if (option.Value() != option.Label())
+ labels->push_back(option.Label().Utf16());
else
labels->push_back(base::string16());
}
@@ -147,26 +147,20 @@ AutofillAgent::AutofillAgent(content::RenderFrame* render_frame,
form_cache_(*render_frame->GetWebFrame()),
password_autofill_agent_(password_autofill_agent),
password_generation_agent_(password_generation_agent),
- legacy_(render_frame->GetRenderView(), this),
autofill_query_id_(0),
was_query_node_autofilled_(false),
ignore_text_changes_(false),
is_popup_possibly_visible_(false),
is_generation_popup_possibly_visible_(false),
+ page_click_tracker_(new PageClickTracker(render_frame, this)),
binding_(this),
weak_ptr_factory_(this) {
- render_frame->GetWebFrame()->setAutofillClient(this);
+ render_frame->GetWebFrame()->SetAutofillClient(this);
password_autofill_agent->SetAutofillAgent(this);
// AutofillAgent is guaranteed to outlive |render_frame|.
render_frame->GetInterfaceRegistry()->AddInterface(
base::Bind(&AutofillAgent::BindRequest, base::Unretained(this)));
-
- // This owns itself, and will delete itself when |render_frame| is destructed
- // (same as AutofillAgent). This object must be constructed after
- // AutofillAgent so that password generation UI is shown before password
- // manager UI (see https://crbug.com/498545).
- new PageClickTracker(render_frame, this);
}
AutofillAgent::~AutofillAgent() {}
@@ -182,20 +176,20 @@ bool AutofillAgent::FormDataCompare::operator()(const FormData& lhs,
}
void AutofillAgent::DidCommitProvisionalLoad(bool is_new_navigation,
- bool is_same_page_navigation) {
+ bool is_same_document_navigation) {
blink::WebFrame* frame = render_frame()->GetWebFrame();
// TODO(dvadym): check if we need to check if it is main frame navigation
// http://crbug.com/443155
- if (frame->parent())
+ if (frame->Parent())
return; // Not a top-level navigation.
- if (is_same_page_navigation) {
- OnSamePageNavigationCompleted();
+ if (is_same_document_navigation) {
+ OnSameDocumentNavigationCompleted();
} else {
// Navigation to a new page or a page refresh.
form_cache_.Reset();
submitted_forms_.clear();
- last_interacted_form_.reset();
+ last_interacted_form_.Reset();
formless_elements_user_edited_.clear();
}
}
@@ -220,10 +214,12 @@ void AutofillAgent::DidChangeScrollOffset() {
}
void AutofillAgent::FocusedNodeChanged(const WebNode& node) {
+ page_click_tracker_->FocusedNodeChanged(node);
+
HidePopup();
- if (node.isNull() || !node.isElementNode()) {
- if (!last_interacted_form_.isNull()) {
+ if (node.IsNull() || !node.IsElementNode()) {
+ if (!last_interacted_form_.IsNull()) {
// Focus moved away from the last interacted form to somewhere else on
// the page.
GetAutofillDriver()->FocusNoLongerOnForm();
@@ -231,19 +227,19 @@ void AutofillAgent::FocusedNodeChanged(const WebNode& node) {
return;
}
- WebElement web_element = node.toConst<WebElement>();
- const WebInputElement* element = toWebInputElement(&web_element);
+ WebElement web_element = node.ToConst<WebElement>();
+ const WebInputElement* element = ToWebInputElement(&web_element);
- if (!last_interacted_form_.isNull() &&
- (!element || last_interacted_form_ != element->form())) {
+ if (!last_interacted_form_.IsNull() &&
+ (!element || last_interacted_form_ != element->Form())) {
// The focused element is not part of the last interacted form (could be
// in a different form).
GetAutofillDriver()->FocusNoLongerOnForm();
return;
}
- if (!element || !element->isEnabled() || element->isReadOnly() ||
- !element->isTextField())
+ if (!element || !element->IsEnabled() || element->IsReadOnly() ||
+ !element->IsTextField())
return;
element_ = *element;
@@ -280,40 +276,20 @@ void AutofillAgent::FireHostSubmitEvents(const FormData& form_data,
void AutofillAgent::Shutdown() {
binding_.Close();
- legacy_.Shutdown();
weak_ptr_factory_.InvalidateWeakPtrs();
}
-void AutofillAgent::FocusChangeComplete() {
- WebDocument doc = render_frame()->GetWebFrame()->document();
- WebElement focused_element;
- if (!doc.isNull())
- focused_element = doc.focusedElement();
- if (!focused_element.isNull()) {
- if (password_generation_agent_ &&
- password_generation_agent_->FocusedNodeHasChanged(focused_element)) {
- is_generation_popup_possibly_visible_ = true;
- is_popup_possibly_visible_ = true;
- }
- if (password_autofill_agent_)
- password_autofill_agent_->FocusedNodeHasChanged(focused_element);
- }
-}
void AutofillAgent::FormControlElementClicked(
const WebFormControlElement& element,
bool was_focused) {
- // TODO(estade): Remove this check when PageClickTracker is per-frame.
- if (element.document().frame() != render_frame()->GetWebFrame())
- return;
-
- const WebInputElement* input_element = toWebInputElement(&element);
+ const WebInputElement* input_element = ToWebInputElement(&element);
if (!input_element && !form_util::IsTextAreaElement(element))
return;
ShowSuggestionsOptions options;
options.autofill_on_empty_values = true;
- options.show_full_suggestion_list = element.isAutofilled();
+ options.show_full_suggestion_list = element.IsAutofilled();
if (!IsSingleClickEnabled()) {
// Show full suggestions when clicking on an already-focused form field. On
@@ -325,12 +301,12 @@ void AutofillAgent::FormControlElementClicked(
ShowSuggestions(element, options);
}
-void AutofillAgent::textFieldDidEndEditing(const WebInputElement& element) {
+void AutofillAgent::TextFieldDidEndEditing(const WebInputElement& element) {
GetAutofillDriver()->DidEndTextFieldEditing();
}
-void AutofillAgent::textFieldDidChange(const WebFormControlElement& element) {
- DCHECK(toWebInputElement(&element) || form_util::IsTextAreaElement(element));
+void AutofillAgent::TextFieldDidChange(const WebFormControlElement& element) {
+ DCHECK(ToWebInputElement(&element) || form_util::IsTextAreaElement(element));
if (ignore_text_changes_)
return;
@@ -354,16 +330,16 @@ void AutofillAgent::TextFieldDidChangeImpl(
const WebFormControlElement& element) {
// If the element isn't focused then the changes don't matter. This check is
// required to properly handle IME interactions.
- if (!element.focused())
+ if (!element.Focused())
return;
- const WebInputElement* input_element = toWebInputElement(&element);
+ const WebInputElement* input_element = ToWebInputElement(&element);
if (input_element) {
// Remember the last form the user interacted with.
- if (element.form().isNull()) {
+ if (element.Form().IsNull()) {
formless_elements_user_edited_.insert(element);
} else {
- last_interacted_form_ = element.form();
+ last_interacted_form_ = element.Form();
}
// |password_autofill_agent_| keeps track of all text changes even if
@@ -396,10 +372,10 @@ void AutofillAgent::TextFieldDidChangeImpl(
}
}
-void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element,
+void AutofillAgent::TextFieldDidReceiveKeyDown(const WebInputElement& element,
const WebKeyboardEvent& event) {
- if (event.windowsKeyCode == ui::VKEY_DOWN ||
- event.windowsKeyCode == ui::VKEY_UP) {
+ if (event.windows_key_code == ui::VKEY_DOWN ||
+ event.windows_key_code == ui::VKEY_UP) {
ShowSuggestionsOptions options;
options.autofill_on_empty_values = true;
options.requires_caret_at_end = true;
@@ -407,40 +383,38 @@ void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element,
}
}
-void AutofillAgent::openTextDataListChooser(const WebInputElement& element) {
+void AutofillAgent::OpenTextDataListChooser(const WebInputElement& element) {
ShowSuggestionsOptions options;
options.autofill_on_empty_values = true;
ShowSuggestions(element, options);
}
-void AutofillAgent::dataListOptionsChanged(const WebInputElement& element) {
- if (!is_popup_possibly_visible_ || !element.focused())
+void AutofillAgent::DataListOptionsChanged(const WebInputElement& element) {
+ if (!is_popup_possibly_visible_ || !element.Focused())
return;
TextFieldDidChangeImpl(element);
}
-void AutofillAgent::firstUserGestureObserved() {
- password_autofill_agent_->FirstUserGestureObserved();
-
- GetAutofillDriver()->FirstUserGestureObserved();
+void AutofillAgent::UserGestureObserved() {
+ password_autofill_agent_->UserGestureObserved();
}
void AutofillAgent::DoAcceptDataListSuggestion(
const base::string16& suggested_value) {
- WebInputElement* input_element = toWebInputElement(&element_);
+ WebInputElement* input_element = ToWebInputElement(&element_);
DCHECK(input_element);
base::string16 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::vector<base::string16> parts = base::SplitString(
- input_element->editingValue().utf16(), base::ASCIIToUTF16(","),
+ if (input_element->IsMultiple() && input_element->IsEmailField()) {
+ std::vector<base::StringPiece16> parts = base::SplitStringPiece(
+ input_element->EditingValue().Utf16(), base::ASCIIToUTF16(","),
base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
if (parts.size() == 0)
- parts.push_back(base::string16());
+ parts.push_back(base::StringPiece16());
- base::string16 last_part = parts.back();
+ base::string16 last_part = parts.back().as_string();
// We want to keep just the leading whitespace.
for (size_t i = 0; i < last_part.size(); ++i) {
if (!base::IsUnicodeWhitespace(last_part[i])) {
@@ -457,18 +431,14 @@ void AutofillAgent::DoAcceptDataListSuggestion(
}
// mojom::AutofillAgent:
-void AutofillAgent::FirstUserGestureObservedInTab() {
- password_autofill_agent_->FirstUserGestureObserved();
-}
-
void AutofillAgent::FillForm(int32_t id, const FormData& form) {
if (id != autofill_query_id_ && id != kNoQueryId)
return;
- was_query_node_autofilled_ = element_.isAutofilled();
+ was_query_node_autofilled_ = element_.IsAutofilled();
form_util::FillForm(form, element_);
- if (!element_.form().isNull())
- last_interacted_form_ = element_.form();
+ if (!element_.Form().IsNull())
+ last_interacted_form_ = element_.Form();
GetAutofillDriver()->DidFillAutofillFormData(form, base::TimeTicks::Now());
}
@@ -477,7 +447,7 @@ void AutofillAgent::PreviewForm(int32_t id, const FormData& form) {
if (id != autofill_query_id_)
return;
- was_query_node_autofilled_ = element_.isAutofilled();
+ was_query_node_autofilled_ = element_.IsAutofilled();
form_util::PreviewForm(form, element_);
GetAutofillDriver()->DidPreviewAutofillFormData();
@@ -495,7 +465,7 @@ void AutofillAgent::ClearForm() {
}
void AutofillAgent::ClearPreviewedForm() {
- if (!element_.isNull()) {
+ if (!element_.IsNull()) {
if (password_autofill_agent_->DidClearAutofillSelection(element_))
return;
@@ -512,15 +482,15 @@ void AutofillAgent::ClearPreviewedForm() {
}
void AutofillAgent::FillFieldWithValue(const base::string16& value) {
- WebInputElement* input_element = toWebInputElement(&element_);
+ WebInputElement* input_element = ToWebInputElement(&element_);
if (input_element) {
DoFillFieldWithValue(value, input_element);
- input_element->setAutofilled(true);
+ input_element->SetAutofilled(true);
}
}
void AutofillAgent::PreviewFieldWithValue(const base::string16& value) {
- WebInputElement* input_element = toWebInputElement(&element_);
+ WebInputElement* input_element = ToWebInputElement(&element_);
if (input_element)
DoPreviewFieldWithValue(value, input_element);
}
@@ -539,8 +509,8 @@ void AutofillAgent::FillPasswordSuggestion(const base::string16& username,
void AutofillAgent::PreviewPasswordSuggestion(const base::string16& username,
const base::string16& password) {
bool handled = password_autofill_agent_->PreviewSuggestion(
- element_, blink::WebString::fromUTF16(username),
- blink::WebString::fromUTF16(password));
+ element_, blink::WebString::FromUTF16(username),
+ blink::WebString::FromUTF16(password));
DCHECK(handled);
}
@@ -578,8 +548,8 @@ void AutofillAgent::ShowNotSecureWarning(
is_popup_possibly_visible_ = true;
}
-void AutofillAgent::OnSamePageNavigationCompleted() {
- if (last_interacted_form_.isNull()) {
+void AutofillAgent::OnSameDocumentNavigationCompleted() {
+ if (last_interacted_form_.IsNull()) {
// If no last interacted form is available (i.e., there is no form tag),
// we check if all the elements the user has interacted with are gone,
// to decide if submission has occurred.
@@ -599,12 +569,12 @@ void AutofillAgent::OnSamePageNavigationCompleted() {
FireHostSubmitEvents(last_interacted_form_, /*form_submitted=*/true);
}
- last_interacted_form_.reset();
+ last_interacted_form_.Reset();
formless_elements_user_edited_.clear();
}
bool AutofillAgent::CollectFormlessElements(FormData* output) {
- WebDocument document = render_frame()->GetWebFrame()->document();
+ WebDocument document = render_frame()->GetWebFrame()->GetDocument();
// Build up the FormData from the unowned elements. This logic mostly
// mirrors the construction of the synthetic form in form_cache.cc, but
@@ -612,7 +582,7 @@ bool AutofillAgent::CollectFormlessElements(FormData* output) {
// has made, and doesn't depend on form_cache's internal state.
std::vector<WebElement> fieldsets;
std::vector<WebFormControlElement> control_elements =
- form_util::GetUnownedAutofillableFormFieldElements(document.all(),
+ form_util::GetUnownedAutofillableFormFieldElements(document.All(),
&fieldsets);
if (control_elements.size() > form_util::kMaxParseableFields)
@@ -629,31 +599,31 @@ bool AutofillAgent::CollectFormlessElements(FormData* output) {
void AutofillAgent::ShowSuggestions(const WebFormControlElement& element,
const ShowSuggestionsOptions& options) {
- if (!element.isEnabled() || element.isReadOnly())
+ if (!element.IsEnabled() || element.IsReadOnly())
return;
- if (!element.suggestedValue().isEmpty())
+ if (!element.SuggestedValue().IsEmpty())
return;
- const WebInputElement* input_element = toWebInputElement(&element);
+ const WebInputElement* input_element = ToWebInputElement(&element);
if (input_element) {
- if (!input_element->isTextField())
+ 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.ToConst<WebFormControlElement>().SuggestedValue().IsEmpty())
return;
}
// Don't attempt to autofill with values that are too large or if filling
// criteria are not met.
- WebString value = element.editingValue();
+ WebString value = element.EditingValue();
if (value.length() > kMaxDataLength ||
- (!options.autofill_on_empty_values && value.isEmpty()) ||
+ (!options.autofill_on_empty_values && value.IsEmpty()) ||
(options.requires_caret_at_end &&
- (element.selectionStart() != element.selectionEnd() ||
- element.selectionEnd() != static_cast<int>(value.length())))) {
+ (element.SelectionStart() != element.SelectionEnd() ||
+ element.SelectionEnd() != static_cast<int>(value.length())))) {
// Any popup currently showing is obsolete.
HidePopup();
return;
@@ -676,7 +646,7 @@ void AutofillAgent::ShowSuggestions(const WebFormControlElement& element,
// Password field elements should only have suggestions shown by the password
// autofill agent.
- if (input_element && input_element->isPasswordField())
+ if (input_element && input_element->IsPasswordField())
return;
QueryAutofillSuggestions(element);
@@ -684,10 +654,10 @@ void AutofillAgent::ShowSuggestions(const WebFormControlElement& element,
void AutofillAgent::QueryAutofillSuggestions(
const WebFormControlElement& element) {
- if (!element.document().frame())
+ if (!element.GetDocument().GetFrame())
return;
- DCHECK(toWebInputElement(&element) || form_util::IsTextAreaElement(element));
+ DCHECK(ToWebInputElement(&element) || form_util::IsTextAreaElement(element));
static int query_counter = 0;
autofill_query_id_ = query_counter++;
@@ -704,7 +674,7 @@ void AutofillAgent::QueryAutofillSuggestions(
std::vector<base::string16> data_list_values;
std::vector<base::string16> data_list_labels;
- const WebInputElement* input_element = toWebInputElement(&element);
+ const WebInputElement* input_element = ToWebInputElement(&element);
if (input_element) {
// Find the datalist values and send them to the browser process.
GetDataListSuggestions(*input_element,
@@ -725,18 +695,18 @@ void AutofillAgent::QueryAutofillSuggestions(
void AutofillAgent::DoFillFieldWithValue(const base::string16& value,
WebInputElement* node) {
base::AutoReset<bool> auto_reset(&ignore_text_changes_, true);
- node->setEditingValue(
- blink::WebString::fromUTF16(value.substr(0, node->maxLength())));
+ node->SetEditingValue(
+ blink::WebString::FromUTF16(value.substr(0, node->MaxLength())));
}
void AutofillAgent::DoPreviewFieldWithValue(const base::string16& value,
WebInputElement* node) {
- was_query_node_autofilled_ = element_.isAutofilled();
- node->setSuggestedValue(
- blink::WebString::fromUTF16(value.substr(0, node->maxLength())));
- node->setAutofilled(true);
- form_util::PreviewSuggestion(node->suggestedValue().utf16(),
- node->value().utf16(), node);
+ was_query_node_autofilled_ = element_.IsAutofilled();
+ node->SetSuggestedValue(
+ blink::WebString::FromUTF16(value.substr(0, node->MaxLength())));
+ node->SetAutofilled(true);
+ form_util::PreviewSuggestion(node->SuggestedValue().Utf16(),
+ node->Value().Utf16(), node);
}
void AutofillAgent::ProcessForms() {
@@ -748,7 +718,7 @@ void AutofillAgent::ProcessForms() {
std::vector<FormData> forms = form_cache_.ExtractNewForms();
// Always communicate to browser process for topmost frame.
- if (!forms.empty() || !frame->parent()) {
+ if (!forms.empty() || !frame->Parent()) {
GetAutofillDriver()->FormsSeen(forms, forms_seen_timestamp);
}
}
@@ -763,24 +733,45 @@ void AutofillAgent::HidePopup() {
}
bool AutofillAgent::IsUserGesture() const {
- return WebUserGestureIndicator::isProcessingUserGesture();
+ return WebUserGestureIndicator::IsProcessingUserGesture();
}
-void AutofillAgent::didAssociateFormControlsDynamically() {
- blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
+void AutofillAgent::DidAssociateFormControlsDynamically() {
+ // If the control flow is here than the document was at least loaded. The
+ // whole page doesn't have to be loaded.
+ ProcessForms();
+ password_autofill_agent_->OnDynamicFormsSeen();
+ if (password_generation_agent_)
+ password_generation_agent_->OnDynamicFormsSeen();
+}
- // Frame is only processed if it has finished loading, otherwise you can end
- // up with a partially parsed form.
- if (frame && !frame->isLoading()) {
- ProcessForms();
- password_autofill_agent_->OnDynamicFormsSeen();
- if (password_generation_agent_)
- password_generation_agent_->OnDynamicFormsSeen();
+void AutofillAgent::DidCompleteFocusChangeInFrame() {
+ WebDocument doc = render_frame()->GetWebFrame()->GetDocument();
+ WebElement focused_element;
+ if (!doc.IsNull())
+ focused_element = doc.FocusedElement();
+ // PasswordGenerationAgent needs to know about focus changes, even if there is
+ // no focused element.
+ if (password_generation_agent_ &&
+ password_generation_agent_->FocusedNodeHasChanged(focused_element)) {
+ is_generation_popup_possibly_visible_ = true;
+ is_popup_possibly_visible_ = true;
}
+ if (!focused_element.IsNull() && password_autofill_agent_)
+ password_autofill_agent_->FocusedNodeHasChanged(focused_element);
+
+ // PageClickTracker needs to be notified after
+ // |is_generation_popup_possibly_visible_| has been updated.
+ page_click_tracker_->DidCompleteFocusChangeInFrame();
+}
+
+void AutofillAgent::DidReceiveLeftMouseDownOrGestureTapInNode(
+ const WebNode& node) {
+ page_click_tracker_->DidReceiveLeftMouseDownOrGestureTapInNode(node);
}
-void AutofillAgent::ajaxSucceeded() {
- OnSamePageNavigationCompleted();
+void AutofillAgent::AjaxSucceeded() {
+ OnSameDocumentNavigationCompleted();
password_autofill_agent_->AJAXSucceeded();
}
@@ -799,28 +790,4 @@ AutofillAgent::GetPasswordManagerDriver() {
return password_autofill_agent_->GetPasswordManagerDriver();
}
-// LegacyAutofillAgent ---------------------------------------------------------
-
-AutofillAgent::LegacyAutofillAgent::LegacyAutofillAgent(
- content::RenderView* render_view,
- AutofillAgent* agent)
- : content::RenderViewObserver(render_view), agent_(agent) {
-}
-
-AutofillAgent::LegacyAutofillAgent::~LegacyAutofillAgent() {
-}
-
-void AutofillAgent::LegacyAutofillAgent::Shutdown() {
- agent_ = nullptr;
-}
-
-void AutofillAgent::LegacyAutofillAgent::OnDestruct() {
- // No-op. Don't delete |this|.
-}
-
-void AutofillAgent::LegacyAutofillAgent::FocusChangeComplete() {
- if (agent_)
- agent_->FocusChangeComplete();
-}
-
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.h b/chromium/components/autofill/content/renderer/autofill_agent.h
index 698e5c9fc70..ef1287b090d 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/autofill_agent.h
@@ -17,8 +17,8 @@
#include "components/autofill/content/common/autofill_driver.mojom.h"
#include "components/autofill/content/renderer/form_cache.h"
#include "components/autofill/content/renderer/page_click_listener.h"
+#include "components/autofill/content/renderer/page_click_tracker.h"
#include "content/public/renderer/render_frame_observer.h"
-#include "content/public/renderer/render_view_observer.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "third_party/WebKit/public/web/WebAutofillClient.h"
#include "third_party/WebKit/public/web/WebFormControlElement.h"
@@ -65,7 +65,6 @@ class AutofillAgent : public content::RenderFrameObserver,
const mojom::PasswordManagerDriverPtr& GetPasswordManagerDriver();
// mojom::AutofillAgent:
- void FirstUserGestureObservedInTab() override;
void FillForm(int32_t id, const FormData& form) override;
void PreviewForm(int32_t id, const FormData& form) override;
void FieldTypePredictionsAvailable(
@@ -85,9 +84,14 @@ class AutofillAgent : public content::RenderFrameObserver,
void ShowNotSecureWarning(const blink::WebInputElement& element);
+ void set_page_click_tracker_for_testing(
+ std::unique_ptr<PageClickTracker> page_click_tracker) {
+ page_click_tracker_ = std::move(page_click_tracker);
+ }
+
protected:
// blink::WebAutofillClient:
- void didAssociateFormControlsDynamically() override;
+ void DidAssociateFormControlsDynamically() override;
private:
// Functor used as a simplified comparison function for FormData. Only
@@ -96,29 +100,6 @@ class AutofillAgent : public content::RenderFrameObserver,
bool operator()(const FormData& lhs, const FormData& rhs) const;
};
- // Thunk class for RenderViewObserver methods that haven't yet been migrated
- // to RenderFrameObserver. Should eventually be removed.
- // http://crbug.com/433486
- class LegacyAutofillAgent : public content::RenderViewObserver {
- public:
- LegacyAutofillAgent(content::RenderView* render_view, AutofillAgent* agent);
- ~LegacyAutofillAgent() override;
-
- // Shuts the LegacyAutofillAgent down on RenderFrame deletion. Safe to call
- // multiple times.
- void Shutdown();
-
- private:
- // content::RenderViewObserver:
- void OnDestruct() override;
- void FocusChangeComplete() override;
-
- AutofillAgent* agent_;
-
- DISALLOW_COPY_AND_ASSIGN(LegacyAutofillAgent);
- };
- friend class LegacyAutofillAgent;
-
// Flags passed to ShowSuggestions.
struct ShowSuggestionsOptions {
// All fields are default initialized to false.
@@ -149,7 +130,7 @@ class AutofillAgent : public content::RenderFrameObserver,
// content::RenderFrameObserver:
void DidCommitProvisionalLoad(bool is_new_navigation,
- bool is_same_page_navigation) override;
+ bool is_same_document_navigation) override;
void DidFinishDocumentLoad() override;
void WillSendSubmitEvent(const blink::WebFormElement& form) override;
void WillSubmitForm(const blink::WebFormElement& form) override;
@@ -170,27 +151,26 @@ class AutofillAgent : public content::RenderFrameObserver,
// times.
void Shutdown();
- // Pass-through from LegacyAutofillAgent. This correlates with the
- // RenderViewObserver method.
- void FocusChangeComplete();
-
// PageClickListener:
void FormControlElementClicked(const blink::WebFormControlElement& element,
bool was_focused) override;
// blink::WebAutofillClient:
- void textFieldDidEndEditing(const blink::WebInputElement& element) override;
- void textFieldDidChange(const blink::WebFormControlElement& element) override;
- void textFieldDidReceiveKeyDown(
+ void TextFieldDidEndEditing(const blink::WebInputElement& element) override;
+ void TextFieldDidChange(const blink::WebFormControlElement& element) override;
+ void TextFieldDidReceiveKeyDown(
const blink::WebInputElement& element,
const blink::WebKeyboardEvent& event) override;
- void openTextDataListChooser(const blink::WebInputElement& element) override;
- void dataListOptionsChanged(const blink::WebInputElement& element) override;
- void firstUserGestureObserved() override;
- void ajaxSucceeded() override;
-
- // Called when a same-page navigation is detected.
- void OnSamePageNavigationCompleted();
+ void OpenTextDataListChooser(const blink::WebInputElement& element) override;
+ void DataListOptionsChanged(const blink::WebInputElement& element) override;
+ void UserGestureObserved() override;
+ void AjaxSucceeded() override;
+ void DidCompleteFocusChangeInFrame() override;
+ void DidReceiveLeftMouseDownOrGestureTapInNode(
+ const blink::WebNode& node) override;
+
+ // Called when a same-document navigation is detected.
+ void OnSameDocumentNavigationCompleted();
// Helper method which collects unowned elements (i.e., those not inside a
// form tag) and writes them into |output|. Returns true if the process is
// successful, and all conditions for firing events are true.
@@ -260,9 +240,6 @@ class AutofillAgent : public content::RenderFrameObserver,
PasswordAutofillAgent* password_autofill_agent_; // Weak reference.
PasswordGenerationAgent* password_generation_agent_; // Weak reference.
- // Passes through RenderViewObserver methods to |this|.
- LegacyAutofillAgent legacy_;
-
// The ID of the last request sent for form field Autofill. Used to ignore
// out of date responses.
int autofill_query_id_;
@@ -299,6 +276,8 @@ class AutofillAgent : public content::RenderFrameObserver,
// for the password manager. TODO(gcasto): Have both UIs show on focus.
bool is_generation_popup_possibly_visible_;
+ std::unique_ptr<PageClickTracker> page_click_tracker_;
+
mojo::Binding<mojom::AutofillAgent> binding_;
mojom::AutofillDriverPtr autofill_driver_;
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.cc b/chromium/components/autofill/content/renderer/form_autofill_util.cc
index 9677f8c184a..71d53fc1416 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.cc
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.cc
@@ -85,45 +85,44 @@ void TruncateString(base::string16* str, size_t max_length) {
bool IsOptionElement(const WebElement& element) {
CR_DEFINE_STATIC_LOCAL(WebString, kOption, ("option"));
- return element.hasHTMLTagName(kOption);
+ return element.HasHTMLTagName(kOption);
}
bool IsScriptElement(const WebElement& element) {
CR_DEFINE_STATIC_LOCAL(WebString, kScript, ("script"));
- return element.hasHTMLTagName(kScript);
+ return element.HasHTMLTagName(kScript);
}
bool IsNoScriptElement(const WebElement& element) {
CR_DEFINE_STATIC_LOCAL(WebString, kNoScript, ("noscript"));
- return element.hasHTMLTagName(kNoScript);
+ return element.HasHTMLTagName(kNoScript);
}
bool HasTagName(const WebNode& node, const blink::WebString& tag) {
- return node.isElementNode() && node.toConst<WebElement>().hasHTMLTagName(tag);
+ return node.IsElementNode() && node.ToConst<WebElement>().HasHTMLTagName(tag);
}
bool IsElementInControlElementSet(
const WebElement& element,
const std::vector<WebFormControlElement>& control_elements) {
- if (!element.isFormControlElement())
+ if (!element.IsFormControlElement())
return false;
const WebFormControlElement form_control_element =
- element.toConst<WebFormControlElement>();
+ element.ToConst<WebFormControlElement>();
return std::find(control_elements.begin(),
control_elements.end(),
form_control_element) != control_elements.end();
}
bool IsElementInsideFormOrFieldSet(const WebElement& element) {
- for (WebNode parent_node = element.parentNode();
- !parent_node.isNull();
- parent_node = parent_node.parentNode()) {
- if (!parent_node.isElementNode())
+ for (WebNode parent_node = element.ParentNode(); !parent_node.IsNull();
+ parent_node = parent_node.ParentNode()) {
+ if (!parent_node.IsElementNode())
continue;
- WebElement cur_element = parent_node.to<WebElement>();
- if (cur_element.hasHTMLTagName("form") ||
- cur_element.hasHTMLTagName("fieldset")) {
+ WebElement cur_element = parent_node.To<WebElement>();
+ if (cur_element.HasHTMLTagName("form") ||
+ cur_element.HasHTMLTagName("fieldset")) {
return true;
}
}
@@ -133,25 +132,22 @@ bool IsElementInsideFormOrFieldSet(const WebElement& element) {
// Returns true if |node| is an element and it is a container type that
// InferLabelForElement() can traverse.
bool IsTraversableContainerElement(const WebNode& node) {
- if (!node.isElementNode())
+ if (!node.IsElementNode())
return false;
- const WebElement element = node.toConst<WebElement>();
- return element.hasHTMLTagName("dd") ||
- element.hasHTMLTagName("div") ||
- element.hasHTMLTagName("fieldset") ||
- element.hasHTMLTagName("li") ||
- element.hasHTMLTagName("td") ||
- element.hasHTMLTagName("table");
+ const WebElement element = node.ToConst<WebElement>();
+ return element.HasHTMLTagName("dd") || element.HasHTMLTagName("div") ||
+ element.HasHTMLTagName("fieldset") || element.HasHTMLTagName("li") ||
+ element.HasHTMLTagName("td") || element.HasHTMLTagName("table");
}
// Returns the colspan for a <td> / <th>. Defaults to 1.
size_t CalculateTableCellColumnSpan(const WebElement& element) {
- DCHECK(element.hasHTMLTagName("td") || element.hasHTMLTagName("th"));
+ DCHECK(element.HasHTMLTagName("td") || element.HasHTMLTagName("th"));
size_t span = 1;
- if (element.hasAttribute("colspan")) {
- base::string16 colspan = element.getAttribute("colspan").utf16();
+ if (element.HasAttribute("colspan")) {
+ base::string16 colspan = element.GetAttribute("colspan").Utf16();
// Do not check return value to accept imperfect conversions.
base::StringToSizeT(colspan, &span);
// Handle overflow.
@@ -204,46 +200,45 @@ const base::string16 CombineAndCollapseWhitespace(
base::string16 FindChildTextInner(const WebNode& node,
int depth,
const std::set<WebNode>& divs_to_skip) {
- if (depth <= 0 || node.isNull())
+ if (depth <= 0 || node.IsNull())
return base::string16();
// Skip over comments.
- if (node.isCommentNode())
- return FindChildTextInner(node.nextSibling(), depth - 1, divs_to_skip);
+ if (node.IsCommentNode())
+ return FindChildTextInner(node.NextSibling(), depth - 1, divs_to_skip);
- if (!node.isElementNode() && !node.isTextNode())
+ if (!node.IsElementNode() && !node.IsTextNode())
return base::string16();
// Ignore elements known not to contain inferable labels.
- if (node.isElementNode()) {
- const WebElement element = node.toConst<WebElement>();
- if (IsOptionElement(element) ||
- IsScriptElement(element) ||
+ if (node.IsElementNode()) {
+ const WebElement element = node.ToConst<WebElement>();
+ if (IsOptionElement(element) || IsScriptElement(element) ||
IsNoScriptElement(element) ||
- (element.isFormControlElement() &&
- IsAutofillableElement(element.toConst<WebFormControlElement>()))) {
+ (element.IsFormControlElement() &&
+ IsAutofillableElement(element.ToConst<WebFormControlElement>()))) {
return base::string16();
}
- if (element.hasHTMLTagName("div") && base::ContainsKey(divs_to_skip, node))
+ if (element.HasHTMLTagName("div") && base::ContainsKey(divs_to_skip, node))
return base::string16();
}
// Extract the text exactly at this node.
- base::string16 node_text = node.nodeValue().utf16();
+ base::string16 node_text = node.NodeValue().Utf16();
// Recursively compute the children's text.
// Preserve inter-element whitespace separation.
base::string16 child_text =
- FindChildTextInner(node.firstChild(), depth - 1, divs_to_skip);
- bool add_space = node.isTextNode() && node_text.empty();
+ FindChildTextInner(node.FirstChild(), depth - 1, divs_to_skip);
+ bool add_space = node.IsTextNode() && node_text.empty();
node_text = CombineAndCollapseWhitespace(node_text, child_text, add_space);
// Recursively compute the siblings' text.
// Again, preserve inter-element whitespace separation.
base::string16 sibling_text =
- FindChildTextInner(node.nextSibling(), depth - 1, divs_to_skip);
- add_space = node.isTextNode() && node_text.empty();
+ FindChildTextInner(node.NextSibling(), depth - 1, divs_to_skip);
+ add_space = node.IsTextNode() && node_text.empty();
node_text = CombineAndCollapseWhitespace(node_text, sibling_text, add_space);
return node_text;
@@ -254,10 +249,10 @@ base::string16 FindChildTextInner(const WebNode& node,
base::string16 FindChildTextWithIgnoreList(
const WebNode& node,
const std::set<WebNode>& divs_to_skip) {
- if (node.isTextNode())
- return node.nodeValue().utf16();
+ if (node.IsTextNode())
+ return node.NodeValue().Utf16();
- WebNode child = node.firstChild();
+ WebNode child = node.FirstChild();
const int kChildSearchDepth = 10;
base::string16 node_text =
@@ -282,16 +277,16 @@ base::string16 InferLabelFromSibling(const WebFormControlElement& element,
base::string16 inferred_label;
WebNode sibling = element;
while (true) {
- sibling = forward ? sibling.nextSibling() : sibling.previousSibling();
- if (sibling.isNull())
+ sibling = forward ? sibling.NextSibling() : sibling.PreviousSibling();
+ if (sibling.IsNull())
break;
// Skip over comments.
- if (sibling.isCommentNode())
+ if (sibling.IsCommentNode())
continue;
// Otherwise, only consider normal HTML elements and their contents.
- if (!sibling.isElementNode() && !sibling.isTextNode())
+ if (!sibling.IsElementNode() && !sibling.IsTextNode())
break;
// A label might be split across multiple "lightweight" nodes.
@@ -302,12 +297,12 @@ base::string16 InferLabelFromSibling(const WebFormControlElement& element,
CR_DEFINE_STATIC_LOCAL(WebString, kStrong, ("strong"));
CR_DEFINE_STATIC_LOCAL(WebString, kSpan, ("span"));
CR_DEFINE_STATIC_LOCAL(WebString, kFont, ("font"));
- if (sibling.isTextNode() ||
- HasTagName(sibling, kBold) || HasTagName(sibling, kStrong) ||
- HasTagName(sibling, kSpan) || HasTagName(sibling, kFont)) {
+ if (sibling.IsTextNode() || HasTagName(sibling, kBold) ||
+ HasTagName(sibling, kStrong) || HasTagName(sibling, kSpan) ||
+ HasTagName(sibling, kFont)) {
base::string16 value = FindChildText(sibling);
// A text node's value will be empty if it is for a line break.
- bool add_space = sibling.isTextNode() && value.empty();
+ bool add_space = sibling.IsTextNode() && value.empty();
inferred_label =
CombineAndCollapseWhitespace(value, inferred_label, add_space);
continue;
@@ -362,8 +357,8 @@ base::string16 InferLabelFromNext(const WebFormControlElement& element) {
// the placeholder text. e.g. <input placeholder="foo">
base::string16 InferLabelFromPlaceholder(const WebFormControlElement& element) {
CR_DEFINE_STATIC_LOCAL(WebString, kPlaceholder, ("placeholder"));
- if (element.hasAttribute(kPlaceholder))
- return element.getAttribute(kPlaceholder).utf16();
+ if (element.HasAttribute(kPlaceholder))
+ return element.GetAttribute(kPlaceholder).Utf16();
return base::string16();
}
@@ -373,9 +368,9 @@ base::string16 InferLabelFromPlaceholder(const WebFormControlElement& element) {
// element's value attribute is same as the element's value).
base::string16 InferLabelFromValueAttr(const WebFormControlElement& element) {
CR_DEFINE_STATIC_LOCAL(WebString, kValue, ("value"));
- if (element.hasAttribute(kValue) && element.getAttribute(kValue) ==
- element.value()) {
- return element.getAttribute(kValue).utf16();
+ if (element.HasAttribute(kValue) &&
+ element.GetAttribute(kValue) == element.Value()) {
+ return element.GetAttribute(kValue).Utf16();
}
return base::string16();
@@ -385,14 +380,14 @@ base::string16 InferLabelFromValueAttr(const WebFormControlElement& element) {
// enclosing list item,
// e.g. <li>Some Text<input ...><input ...><input ...></li>
base::string16 InferLabelFromListItem(const WebFormControlElement& element) {
- WebNode parent = element.parentNode();
+ WebNode parent = element.ParentNode();
CR_DEFINE_STATIC_LOCAL(WebString, kListItem, ("li"));
- while (!parent.isNull() && parent.isElementNode() &&
- !parent.to<WebElement>().hasHTMLTagName(kListItem)) {
- parent = parent.parentNode();
+ while (!parent.IsNull() && parent.IsElementNode() &&
+ !parent.To<WebElement>().HasHTMLTagName(kListItem)) {
+ parent = parent.ParentNode();
}
- if (!parent.isNull() && HasTagName(parent, kListItem))
+ if (!parent.IsNull() && HasTagName(parent, kListItem))
return FindChildText(parent);
return base::string16();
@@ -403,14 +398,14 @@ base::string16 InferLabelFromListItem(const WebFormControlElement& element) {
// e.g. <label>Some Text<input ...><input ...><input ...></label>
base::string16 InferLabelFromEnclosingLabel(
const WebFormControlElement& element) {
- WebNode parent = element.parentNode();
+ WebNode parent = element.ParentNode();
CR_DEFINE_STATIC_LOCAL(WebString, kLabel, ("label"));
- while (!parent.isNull() && parent.isElementNode() &&
- !parent.to<WebElement>().hasHTMLTagName(kLabel)) {
- parent = parent.parentNode();
+ while (!parent.IsNull() && parent.IsElementNode() &&
+ !parent.To<WebElement>().HasHTMLTagName(kLabel)) {
+ parent = parent.ParentNode();
}
- if (!parent.isNull() && HasTagName(parent, kLabel))
+ if (!parent.IsNull() && HasTagName(parent, kLabel))
return FindChildText(parent);
return base::string16();
@@ -424,25 +419,25 @@ base::string16 InferLabelFromEnclosingLabel(
// or <tr><th><b>Some Text</b></th><td><b><input ...></b></td></tr>
base::string16 InferLabelFromTableColumn(const WebFormControlElement& element) {
CR_DEFINE_STATIC_LOCAL(WebString, kTableCell, ("td"));
- WebNode parent = element.parentNode();
- while (!parent.isNull() && parent.isElementNode() &&
- !parent.to<WebElement>().hasHTMLTagName(kTableCell)) {
- parent = parent.parentNode();
+ WebNode parent = element.ParentNode();
+ while (!parent.IsNull() && parent.IsElementNode() &&
+ !parent.To<WebElement>().HasHTMLTagName(kTableCell)) {
+ parent = parent.ParentNode();
}
- if (parent.isNull())
+ if (parent.IsNull())
return base::string16();
// Check all previous siblings, skipping non-element nodes, until we find a
// non-empty text block.
base::string16 inferred_label;
- WebNode previous = parent.previousSibling();
+ WebNode previous = parent.PreviousSibling();
CR_DEFINE_STATIC_LOCAL(WebString, kTableHeader, ("th"));
- while (inferred_label.empty() && !previous.isNull()) {
+ while (inferred_label.empty() && !previous.IsNull()) {
if (HasTagName(previous, kTableCell) || HasTagName(previous, kTableHeader))
inferred_label = FindChildText(previous);
- previous = previous.previousSibling();
+ previous = previous.PreviousSibling();
}
return inferred_label;
@@ -463,41 +458,39 @@ base::string16 InferLabelFromTableRow(const WebFormControlElement& element) {
base::string16 inferred_label;
// First find the <td> that contains |element|.
- WebNode cell = element.parentNode();
- while (!cell.isNull()) {
- if (cell.isElementNode() &&
- cell.to<WebElement>().hasHTMLTagName(kTableCell)) {
+ WebNode cell = element.ParentNode();
+ while (!cell.IsNull()) {
+ if (cell.IsElementNode() &&
+ cell.To<WebElement>().HasHTMLTagName(kTableCell)) {
break;
}
- cell = cell.parentNode();
+ cell = cell.ParentNode();
}
// Not in a cell - bail out.
- if (cell.isNull())
+ if (cell.IsNull())
return inferred_label;
// Count the cell holding |element|.
- size_t cell_count = CalculateTableCellColumnSpan(cell.to<WebElement>());
+ size_t cell_count = CalculateTableCellColumnSpan(cell.To<WebElement>());
size_t cell_position = 0;
size_t cell_position_end = cell_count - 1;
// Count cells to the left to figure out |element|'s cell's position.
- for (WebNode cell_it = cell.previousSibling();
- !cell_it.isNull();
- cell_it = cell_it.previousSibling()) {
- if (cell_it.isElementNode() &&
- cell_it.to<WebElement>().hasHTMLTagName(kTableCell)) {
- cell_position += CalculateTableCellColumnSpan(cell_it.to<WebElement>());
+ for (WebNode cell_it = cell.PreviousSibling(); !cell_it.IsNull();
+ cell_it = cell_it.PreviousSibling()) {
+ if (cell_it.IsElementNode() &&
+ cell_it.To<WebElement>().HasHTMLTagName(kTableCell)) {
+ cell_position += CalculateTableCellColumnSpan(cell_it.To<WebElement>());
}
}
// Count cells to the right.
- for (WebNode cell_it = cell.nextSibling();
- !cell_it.isNull();
- cell_it = cell_it.nextSibling()) {
- if (cell_it.isElementNode() &&
- cell_it.to<WebElement>().hasHTMLTagName(kTableCell)) {
- cell_count += CalculateTableCellColumnSpan(cell_it.to<WebElement>());
+ for (WebNode cell_it = cell.NextSibling(); !cell_it.IsNull();
+ cell_it = cell_it.NextSibling()) {
+ if (cell_it.IsElementNode() &&
+ cell_it.To<WebElement>().HasHTMLTagName(kTableCell)) {
+ cell_count += CalculateTableCellColumnSpan(cell_it.To<WebElement>());
}
}
@@ -507,37 +500,37 @@ base::string16 InferLabelFromTableRow(const WebFormControlElement& element) {
// Find the current row.
CR_DEFINE_STATIC_LOCAL(WebString, kTableRow, ("tr"));
- WebNode parent = element.parentNode();
- while (!parent.isNull() && parent.isElementNode() &&
- !parent.to<WebElement>().hasHTMLTagName(kTableRow)) {
- parent = parent.parentNode();
+ WebNode parent = element.ParentNode();
+ while (!parent.IsNull() && parent.IsElementNode() &&
+ !parent.To<WebElement>().HasHTMLTagName(kTableRow)) {
+ parent = parent.ParentNode();
}
- if (parent.isNull())
+ if (parent.IsNull())
return inferred_label;
// Now find the previous row.
- WebNode row_it = parent.previousSibling();
- while (!row_it.isNull()) {
- if (row_it.isElementNode() &&
- row_it.to<WebElement>().hasHTMLTagName(kTableRow)) {
+ WebNode row_it = parent.PreviousSibling();
+ while (!row_it.IsNull()) {
+ if (row_it.IsElementNode() &&
+ row_it.To<WebElement>().HasHTMLTagName(kTableRow)) {
break;
}
- row_it = row_it.previousSibling();
+ row_it = row_it.PreviousSibling();
}
// If there exists a previous row, check its cells and size. If they align
// with the current row, infer the label from the cell above.
- if (!row_it.isNull()) {
+ if (!row_it.IsNull()) {
WebNode matching_cell;
size_t prev_row_count = 0;
- WebNode prev_row_it = row_it.firstChild();
+ WebNode prev_row_it = row_it.FirstChild();
CR_DEFINE_STATIC_LOCAL(WebString, kTableHeader, ("th"));
- while (!prev_row_it.isNull()) {
- if (prev_row_it.isElementNode()) {
- WebElement prev_row_element = prev_row_it.to<WebElement>();
- if (prev_row_element.hasHTMLTagName(kTableCell) ||
- prev_row_element.hasHTMLTagName(kTableHeader)) {
+ while (!prev_row_it.IsNull()) {
+ if (prev_row_it.IsElementNode()) {
+ WebElement prev_row_element = prev_row_it.To<WebElement>();
+ if (prev_row_element.HasHTMLTagName(kTableCell) ||
+ prev_row_element.HasHTMLTagName(kTableHeader)) {
size_t span = CalculateTableCellColumnSpan(prev_row_element);
size_t prev_row_count_end = prev_row_count + span - 1;
if (prev_row_count == cell_position &&
@@ -547,9 +540,9 @@ base::string16 InferLabelFromTableRow(const WebFormControlElement& element) {
prev_row_count += span;
}
}
- prev_row_it = prev_row_it.nextSibling();
+ prev_row_it = prev_row_it.NextSibling();
}
- if ((cell_count == prev_row_count) && !matching_cell.isNull()) {
+ if ((cell_count == prev_row_count) && !matching_cell.IsNull()) {
inferred_label = FindChildText(matching_cell);
if (!inferred_label.empty())
return inferred_label;
@@ -559,12 +552,12 @@ base::string16 InferLabelFromTableRow(const WebFormControlElement& element) {
// If there is no previous row, or if the previous row and current row do not
// align, check all previous siblings, skipping non-element nodes, until we
// find a non-empty text block.
- WebNode previous = parent.previousSibling();
- while (inferred_label.empty() && !previous.isNull()) {
+ WebNode previous = parent.PreviousSibling();
+ while (inferred_label.empty() && !previous.IsNull()) {
if (HasTagName(previous, kTableRow))
inferred_label = FindChildText(previous);
- previous = previous.previousSibling();
+ previous = previous.PreviousSibling();
}
return inferred_label;
@@ -578,7 +571,7 @@ base::string16 InferLabelFromTableRow(const WebFormControlElement& element) {
// Because this is already traversing the <div> structure, if it finds a <label>
// sibling along the way, infer from that <label>.
base::string16 InferLabelFromDivTable(const WebFormControlElement& element) {
- WebNode node = element.parentNode();
+ WebNode node = element.ParentNode();
bool looking_for_parent = true;
std::set<WebNode> divs_to_skip;
@@ -586,7 +579,7 @@ base::string16 InferLabelFromDivTable(const WebFormControlElement& element) {
base::string16 inferred_label;
CR_DEFINE_STATIC_LOCAL(WebString, kDiv, ("div"));
CR_DEFINE_STATIC_LOCAL(WebString, kLabel, ("label"));
- while (inferred_label.empty() && !node.isNull()) {
+ while (inferred_label.empty() && !node.IsNull()) {
if (HasTagName(node, kDiv)) {
if (looking_for_parent)
inferred_label = FindChildTextWithIgnoreList(node, divs_to_skip);
@@ -597,8 +590,8 @@ base::string16 InferLabelFromDivTable(const WebFormControlElement& element) {
if (!looking_for_parent && !inferred_label.empty()) {
CR_DEFINE_STATIC_LOCAL(WebString, kSelector,
("input, select, textarea"));
- WebElement result_element = node.querySelector(kSelector);
- if (!result_element.isNull()) {
+ WebElement result_element = node.QuerySelector(kSelector);
+ if (!result_element.IsNull()) {
inferred_label.clear();
divs_to_skip.insert(node);
}
@@ -606,20 +599,20 @@ base::string16 InferLabelFromDivTable(const WebFormControlElement& element) {
looking_for_parent = false;
} else if (!looking_for_parent && HasTagName(node, kLabel)) {
- WebLabelElement label_element = node.to<WebLabelElement>();
- if (label_element.correspondingControl().isNull())
+ WebLabelElement label_element = node.To<WebLabelElement>();
+ if (label_element.CorrespondingControl().IsNull())
inferred_label = FindChildText(node);
} else if (looking_for_parent && IsTraversableContainerElement(node)) {
// If the element is in a non-div container, its label most likely is too.
break;
}
- if (node.previousSibling().isNull()) {
+ if (node.PreviousSibling().IsNull()) {
// If there are no more siblings, continue walking up the tree.
looking_for_parent = true;
}
- node = looking_for_parent ? node.parentNode() : node.previousSibling();
+ node = looking_for_parent ? node.ParentNode() : node.PreviousSibling();
}
return inferred_label;
@@ -632,21 +625,21 @@ base::string16 InferLabelFromDivTable(const WebFormControlElement& element) {
base::string16 InferLabelFromDefinitionList(
const WebFormControlElement& element) {
CR_DEFINE_STATIC_LOCAL(WebString, kDefinitionData, ("dd"));
- WebNode parent = element.parentNode();
- while (!parent.isNull() && parent.isElementNode() &&
- !parent.to<WebElement>().hasHTMLTagName(kDefinitionData))
- parent = parent.parentNode();
+ WebNode parent = element.ParentNode();
+ while (!parent.IsNull() && parent.IsElementNode() &&
+ !parent.To<WebElement>().HasHTMLTagName(kDefinitionData))
+ parent = parent.ParentNode();
- if (parent.isNull() || !HasTagName(parent, kDefinitionData))
+ if (parent.IsNull() || !HasTagName(parent, kDefinitionData))
return base::string16();
// Skip by any intervening text nodes.
- WebNode previous = parent.previousSibling();
- while (!previous.isNull() && previous.isTextNode())
- previous = previous.previousSibling();
+ WebNode previous = parent.PreviousSibling();
+ while (!previous.IsNull() && previous.IsTextNode())
+ previous = previous.PreviousSibling();
CR_DEFINE_STATIC_LOCAL(WebString, kDefinitionTag, ("dt"));
- if (previous.isNull() || !HasTagName(previous, kDefinitionTag))
+ if (previous.IsNull() || !HasTagName(previous, kDefinitionTag))
return base::string16();
return FindChildText(previous);
@@ -657,13 +650,12 @@ base::string16 InferLabelFromDefinitionList(
std::vector<std::string> AncestorTagNames(
const WebFormControlElement& element) {
std::vector<std::string> tag_names;
- for (WebNode parent_node = element.parentNode();
- !parent_node.isNull();
- parent_node = parent_node.parentNode()) {
- if (!parent_node.isElementNode())
+ for (WebNode parent_node = element.ParentNode(); !parent_node.IsNull();
+ parent_node = parent_node.ParentNode()) {
+ if (!parent_node.IsElementNode())
continue;
- tag_names.push_back(parent_node.to<WebElement>().tagName().utf8());
+ tag_names.push_back(parent_node.To<WebElement>().TagName().Utf8());
}
return tag_names;
}
@@ -685,7 +677,7 @@ base::string16 InferLabelForElement(const WebFormControlElement& element,
const std::vector<base::char16>& stop_words) {
base::string16 inferred_label;
- if (IsCheckableElement(toWebInputElement(&element))) {
+ if (IsCheckableElement(ToWebInputElement(&element))) {
inferred_label = InferLabelFromNext(element);
if (IsLabelValid(inferred_label, stop_words))
return inferred_label;
@@ -742,11 +734,11 @@ base::string16 InferLabelForElement(const WebFormControlElement& element,
void GetOptionStringsFromElement(const WebSelectElement& select_element,
std::vector<base::string16>* option_values,
std::vector<base::string16>* option_contents) {
- DCHECK(!select_element.isNull());
+ DCHECK(!select_element.IsNull());
option_values->clear();
option_contents->clear();
- WebVector<WebElement> list_items = select_element.listItems();
+ WebVector<WebElement> list_items = select_element.GetListItems();
// Constrain the maximum list length to prevent a malicious site from DOS'ing
// the browser, without entirely breaking autocomplete for some extreme
@@ -758,9 +750,9 @@ void GetOptionStringsFromElement(const WebSelectElement& select_element,
option_contents->reserve(list_items.size());
for (size_t i = 0; i < list_items.size(); ++i) {
if (IsOptionElement(list_items[i])) {
- const WebOptionElement option = list_items[i].toConst<WebOptionElement>();
- option_values->push_back(option.value().utf16());
- option_contents->push_back(option.text().utf16());
+ const WebOptionElement option = list_items[i].ToConst<WebOptionElement>();
+ option_values->push_back(option.Value().Utf16());
+ option_contents->push_back(option.GetText().Utf16());
}
}
}
@@ -793,7 +785,7 @@ void ForEachMatchingFormFieldCommon(
for (size_t i = 0; i < control_elements->size(); ++i) {
WebFormControlElement* element = &(*control_elements)[i];
- if (element->nameForAutofill().utf16() != data.fields[i].name) {
+ if (element->NameForAutofill().Utf16() != data.fields[i].name) {
// This case should be reachable only for pathological websites, which
// rename form fields while the user is interacting with the Autofill
// popup. I (isherman) am not aware of any such websites, and so am
@@ -808,7 +800,7 @@ void 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 = ToWebInputElement(element);
CR_DEFINE_STATIC_LOCAL(WebString, kValue, ("value"));
CR_DEFINE_STATIC_LOCAL(WebString, kPlaceholder, ("placeholder"));
if (!force_override && !is_initiating_element &&
@@ -816,20 +808,20 @@ void ForEachMatchingFormFieldCommon(
// input field's "value" or "placeholder" attribute, is skipped.
(IsAutofillableInputElement(input_element) ||
IsTextAreaElement(*element)) &&
- !element->value().isEmpty() &&
- (!element->hasAttribute(kValue) ||
- element->getAttribute(kValue) != element->value()) &&
- (!element->hasAttribute(kPlaceholder) ||
- element->getAttribute(kPlaceholder) != element->value()))
+ !element->Value().IsEmpty() &&
+ (!element->HasAttribute(kValue) ||
+ element->GetAttribute(kValue) != element->Value()) &&
+ (!element->HasAttribute(kPlaceholder) ||
+ element->GetAttribute(kPlaceholder) != element->Value()))
continue;
DCHECK(!g_prevent_layout || !(filters & FILTER_NON_FOCUSABLE_ELEMENTS))
<< "The callsite of this code wanted to both prevent layout and check "
"isFocusable. Pick one.";
- if (((filters & FILTER_DISABLED_ELEMENTS) && !element->isEnabled()) ||
- ((filters & FILTER_READONLY_ELEMENTS) && element->isReadOnly()) ||
+ if (((filters & FILTER_DISABLED_ELEMENTS) && !element->IsEnabled()) ||
+ ((filters & FILTER_READONLY_ELEMENTS) && element->IsReadOnly()) ||
// See description for FILTER_NON_FOCUSABLE_ELEMENTS.
- ((filters & FILTER_NON_FOCUSABLE_ELEMENTS) && !element->isFocusable() &&
+ ((filters & FILTER_NON_FOCUSABLE_ELEMENTS) && !element->IsFocusable() &&
!IsSelectElement(*element)))
continue;
@@ -859,12 +851,12 @@ void ForEachMatchingUnownedFormField(const WebElement& initiating_element,
FieldFilterMask filters,
bool force_override,
const Callback& callback) {
- if (initiating_element.isNull())
+ if (initiating_element.IsNull())
return;
std::vector<WebFormControlElement> control_elements =
GetUnownedAutofillableFormFieldElements(
- initiating_element.document().all(), nullptr);
+ initiating_element.GetDocument().All(), nullptr);
if (!IsElementInControlElementSet(initiating_element, control_elements))
return;
@@ -884,32 +876,32 @@ void FillFormField(const FormFieldData& data,
if (!data.is_autofilled)
return;
- WebInputElement* input_element = toWebInputElement(field);
+ WebInputElement* input_element = ToWebInputElement(field);
if (IsCheckableElement(input_element)) {
- input_element->setChecked(IsChecked(data.check_status), true);
+ input_element->SetChecked(IsChecked(data.check_status), true);
} else {
base::string16 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));
+ field->SetAutofillValue(blink::WebString::FromUTF16(value));
}
// Setting the form might trigger JavaScript, which is capable of
// destroying the frame.
- if (!field->document().frame())
+ if (!field->GetDocument().GetFrame())
return;
- field->setAutofilled(true);
+ field->SetAutofilled(true);
if (is_initiating_node &&
((IsTextInput(input_element) || IsMonthInput(input_element)) ||
IsTextAreaElement(*field))) {
- int length = field->value().length();
- field->setSelectionRange(length, length);
+ int length = field->Value().length();
+ field->SetSelectionRange(length, length);
// Clear the current IME composition (the underline), if there is one.
- field->document().frame()->unmarkText();
+ field->GetDocument().GetFrame()->UnmarkText();
}
}
@@ -928,22 +920,22 @@ 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 = ToWebInputElement(field);
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->setAutofilled(true);
+ input_element->SetSuggestedValue(blink::WebString::FromUTF16(
+ data.value.substr(0, input_element->MaxLength())));
+ input_element->SetAutofilled(true);
} else if (IsTextAreaElement(*field) || IsSelectElement(*field)) {
- field->setSuggestedValue(blink::WebString::fromUTF16(data.value));
- field->setAutofilled(true);
+ field->SetSuggestedValue(blink::WebString::FromUTF16(data.value));
+ field->SetAutofilled(true);
}
if (is_initiating_node &&
(IsTextInput(input_element) || IsTextAreaElement(*field))) {
// Select the part of the text that the user didn't type.
- PreviewSuggestion(field->suggestedValue().utf16(), field->value().utf16(),
+ PreviewSuggestion(field->SuggestedValue().Utf16(), field->Value().Utf16(),
field);
}
}
@@ -1002,16 +994,16 @@ void MatchLabelsAndFields(
CR_DEFINE_STATIC_LOCAL(WebString, kFor, ("for"));
CR_DEFINE_STATIC_LOCAL(WebString, kHidden, ("hidden"));
- for (WebElement item = labels.firstItem(); !item.isNull();
- item = labels.nextItem()) {
- WebLabelElement label = item.to<WebLabelElement>();
- WebElement control = label.correspondingControl();
+ for (WebElement item = labels.FirstItem(); !item.IsNull();
+ item = labels.NextItem()) {
+ WebLabelElement label = item.To<WebLabelElement>();
+ WebElement control = label.CorrespondingControl();
FormFieldData* field_data = nullptr;
- if (control.isNull()) {
+ if (control.IsNull()) {
// Sometimes site authors will incorrectly specify the corresponding
// field element's name rather than its id, so we compensate here.
- base::string16 element_name = label.getAttribute(kFor).utf16();
+ base::string16 element_name = label.GetAttribute(kFor).Utf16();
if (element_name.empty())
continue;
// Look through the list for elements with this name. There can actually
@@ -1027,9 +1019,9 @@ void MatchLabelsAndFields(
}
}
}
- } else if (control.isFormControlElement()) {
- WebFormControlElement form_control = control.to<WebFormControlElement>();
- if (form_control.formControlType() == kHidden)
+ } else if (control.IsFormControlElement()) {
+ WebFormControlElement form_control = control.To<WebFormControlElement>();
+ if (form_control.FormControlType() == kHidden)
continue;
// Typical case: look up |field_data| in |element_map|.
auto iter = element_map->find(form_control);
@@ -1098,15 +1090,15 @@ bool FormOrFieldsetsToFormData(
// previously created FormFieldData and set the FormFieldData's label to the
// label.firstChild().nodeValue() of the label element.
WebElementCollection labels =
- form_element->getElementsByHTMLTagName(kLabel);
- DCHECK(!labels.isNull());
+ form_element->GetElementsByHTMLTagName(kLabel);
+ DCHECK(!labels.IsNull());
MatchLabelsAndFields(labels, &element_map);
} else {
// Same as the if block, but for all the labels in fieldsets.
for (size_t i = 0; i < fieldsets.size(); ++i) {
WebElementCollection labels =
- fieldsets[i].getElementsByHTMLTagName(kLabel);
- DCHECK(!labels.isNull());
+ fieldsets[i].GetElementsByHTMLTagName(kLabel);
+ DCHECK(!labels.IsNull());
MatchLabelsAndFields(labels, &element_map);
}
}
@@ -1203,12 +1195,13 @@ bool ExtractFormData(const WebFormElement& form_element, FormData* data) {
}
bool IsFormVisible(blink::WebFrame* frame,
+ const blink::WebFormElement& form_element,
const GURL& canonical_action,
const GURL& canonical_origin,
const FormData& form_data) {
- const GURL frame_origin = GetCanonicalOriginForDocument(frame->document());
+ const GURL frame_origin = GetCanonicalOriginForDocument(frame->GetDocument());
blink::WebVector<WebFormElement> forms;
- frame->document().forms(forms);
+ frame->GetDocument().Forms(forms);
// Omitting the action attribute would result in |canonical_origin| for
// hierarchical schemes like http:, and in an empty URL for non-hierarchical
@@ -1226,6 +1219,11 @@ bool IsFormVisible(blink::WebFrame* frame,
if (!AreFormContentsVisible(form))
continue;
+ // Try to match the WebFormElement reference first.
+ if (!form_element.IsNull() && form == form_element) {
+ return true; // Form still exists.
+ }
+
GURL iter_canonical_action = GetCanonicalActionForForm(form);
bool form_action_is_empty = iter_canonical_action.is_empty() ||
iter_canonical_action == frame_origin;
@@ -1252,7 +1250,7 @@ bool IsFormVisible(blink::WebFrame* frame,
bool IsSomeControlElementVisible(
const WebVector<WebFormControlElement>& control_elements) {
for (const WebFormControlElement& control_element : control_elements) {
- if (IsWebNodeVisible(control_element))
+ if (IsWebElementVisible(control_element))
return true;
}
return false;
@@ -1260,50 +1258,50 @@ bool IsSomeControlElementVisible(
bool AreFormContentsVisible(const WebFormElement& form) {
WebVector<WebFormControlElement> control_elements;
- form.getFormControlElements(control_elements);
+ form.GetFormControlElements(control_elements);
return IsSomeControlElementVisible(control_elements);
}
GURL GetCanonicalActionForForm(const WebFormElement& form) {
- WebString action = form.action();
- if (action.isNull())
+ WebString action = form.Action();
+ if (action.IsNull())
action = WebString(""); // missing 'action' attribute implies current URL.
- GURL full_action(form.document().completeURL(action));
+ GURL full_action(form.GetDocument().CompleteURL(action));
return StripAuthAndParams(full_action);
}
GURL GetCanonicalOriginForDocument(const WebDocument& document) {
- GURL full_origin(document.url());
+ GURL full_origin(document.Url());
return StripAuthAndParams(full_origin);
}
bool IsMonthInput(const WebInputElement* element) {
CR_DEFINE_STATIC_LOCAL(WebString, kMonth, ("month"));
- return element && !element->isNull() && element->formControlType() == kMonth;
+ return element && !element->IsNull() && element->FormControlType() == kMonth;
}
// All text fields, including password fields, should be extracted.
bool IsTextInput(const WebInputElement* element) {
- return element && !element->isNull() && element->isTextField();
+ return element && !element->IsNull() && element->IsTextField();
}
bool IsSelectElement(const WebFormControlElement& element) {
// Static for improved performance.
CR_DEFINE_STATIC_LOCAL(WebString, kSelectOne, ("select-one"));
- return !element.isNull() && element.formControlType() == kSelectOne;
+ return !element.IsNull() && element.FormControlType() == kSelectOne;
}
bool IsTextAreaElement(const WebFormControlElement& element) {
// Static for improved performance.
CR_DEFINE_STATIC_LOCAL(WebString, kTextArea, ("textarea"));
- return !element.isNull() && element.formControlType() == kTextArea;
+ return !element.IsNull() && element.FormControlType() == kTextArea;
}
bool IsCheckableElement(const WebInputElement* element) {
- if (!element || element->isNull())
+ if (!element || element->IsNull())
return false;
- return element->isCheckbox() || element->isRadioButton();
+ return element->IsCheckbox() || element->IsRadioButton();
}
bool IsAutofillableInputElement(const WebInputElement* element) {
@@ -1313,28 +1311,27 @@ bool IsAutofillableInputElement(const WebInputElement* element) {
}
bool IsAutofillableElement(const WebFormControlElement& element) {
- const WebInputElement* input_element = toWebInputElement(&element);
+ const WebInputElement* input_element = ToWebInputElement(&element);
return IsAutofillableInputElement(input_element) ||
IsSelectElement(element) || IsTextAreaElement(element);
}
const base::string16 GetFormIdentifier(const WebFormElement& form) {
- base::string16 identifier = form.name().utf16();
+ base::string16 identifier = form.GetName().Utf16();
CR_DEFINE_STATIC_LOCAL(WebString, kId, ("id"));
if (identifier.empty())
- identifier = form.getAttribute(kId).utf16();
+ identifier = form.GetAttribute(kId).Utf16();
return identifier;
}
-bool IsWebNodeVisible(const blink::WebNode& node) {
- // TODO(esprehn): This code doesn't really check if the node is visible, just
- // if the node takes up space in the layout. Does it want to check opacity,
- // transform, and visibility too?
- if (!node.isElementNode())
- return false;
- const WebElement element = node.toConst<WebElement>();
- return element.hasNonEmptyLayoutSize();
+bool IsWebElementVisible(const blink::WebElement& element) {
+ // hasNonEmptyLayoutSize might trigger layout, but it didn't cause problems so
+ // far. If the layout is prohibited, hasNonEmptyLayoutSize is still used. See
+ // details in crbug.com/595078.
+ bool res = g_prevent_layout ? element.HasNonEmptyLayoutSize()
+ : element.IsFocusable();
+ return res;
}
std::vector<blink::WebFormControlElement> ExtractAutofillableElementsFromSet(
@@ -1353,7 +1350,7 @@ std::vector<blink::WebFormControlElement> ExtractAutofillableElementsFromSet(
std::vector<WebFormControlElement> ExtractAutofillableElementsInForm(
const WebFormElement& form_element) {
WebVector<WebFormControlElement> control_elements;
- form_element.getFormControlElements(control_elements);
+ form_element.GetFormControlElements(control_elements);
return ExtractAutofillableElementsFromSet(control_elements);
}
@@ -1364,7 +1361,7 @@ void WebFormControlElementToFormField(
ExtractMask extract_mask,
FormFieldData* field) {
DCHECK(field);
- DCHECK(!element.isNull());
+ DCHECK(!element.IsNull());
CR_DEFINE_STATIC_LOCAL(WebString, kAutocomplete, ("autocomplete"));
CR_DEFINE_STATIC_LOCAL(WebString, kId, ("id"));
CR_DEFINE_STATIC_LOCAL(WebString, kRole, ("role"));
@@ -1373,26 +1370,26 @@ void WebFormControlElementToFormField(
// Save both id and name attributes, if present. If there is only one of them,
// it will be saved to |name|. See HTMLFormControlElement::nameForAutofill.
- field->name = element.nameForAutofill().utf16();
- base::string16 id = element.getAttribute(kId).utf16();
+ field->name = element.NameForAutofill().Utf16();
+ base::string16 id = element.GetAttribute(kId).Utf16();
if (id != field->name)
field->id = id;
- field->form_control_type = element.formControlType().utf8();
- field->autocomplete_attribute = element.getAttribute(kAutocomplete).utf8();
+ field->form_control_type = element.FormControlType().Utf8();
+ field->autocomplete_attribute = element.GetAttribute(kAutocomplete).Utf8();
if (field->autocomplete_attribute.size() > kMaxDataLength) {
// Discard overly long attribute values to avoid DOS-ing the browser
// process. However, send over a default string to indicate that the
// attribute was present.
field->autocomplete_attribute = "x-max-data-length-exceeded";
}
- if (base::LowerCaseEqualsASCII(element.getAttribute(kRole).utf16(),
+ if (base::LowerCaseEqualsASCII(element.GetAttribute(kRole).Utf16(),
"presentation"))
field->role = FormFieldData::ROLE_ATTRIBUTE_PRESENTATION;
- field->placeholder = element.getAttribute(kPlaceholder).utf16();
- if (element.hasAttribute(kClass))
- field->css_classes = element.getAttribute(kClass).utf16();
+ field->placeholder = element.GetAttribute(kPlaceholder).Utf16();
+ if (element.HasAttribute(kClass))
+ field->css_classes = element.GetAttribute(kClass).Utf16();
if (field_value_and_properties_map) {
FieldValueAndPropertiesMaskMap::const_iterator it =
@@ -1404,37 +1401,38 @@ void WebFormControlElementToFormField(
if (!IsAutofillableElement(element))
return;
- const WebInputElement* input_element = toWebInputElement(&element);
+ const WebInputElement* input_element = ToWebInputElement(&element);
if (IsAutofillableInputElement(input_element) ||
IsTextAreaElement(element) ||
IsSelectElement(element)) {
- field->is_autofilled = element.isAutofilled();
+ field->is_autofilled = element.IsAutofilled();
if (!g_prevent_layout)
- field->is_focusable = element.isFocusable();
- field->should_autocomplete = element.autoComplete();
+ field->is_focusable = element.IsFocusable();
+ field->should_autocomplete = element.AutoComplete();
// Use 'text-align: left|right' if set or 'direction' otherwise.
// See crbug.com/482339
- field->text_direction = element.directionForFormData() ==
- "rtl" ? base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT;
- if (element.alignmentForFormData() == "left")
- field->text_direction = base::i18n::LEFT_TO_RIGHT;
- else if (element.alignmentForFormData() == "right")
- field->text_direction = base::i18n::RIGHT_TO_LEFT;
+ field->text_direction = element.DirectionForFormData() == "rtl"
+ ? base::i18n::RIGHT_TO_LEFT
+ : base::i18n::LEFT_TO_RIGHT;
+ if (element.AlignmentForFormData() == "left")
+ field->text_direction = base::i18n::LEFT_TO_RIGHT;
+ else if (element.AlignmentForFormData() == "right")
+ field->text_direction = base::i18n::RIGHT_TO_LEFT;
}
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.ToConst<WebSelectElement>();
GetOptionStringsFromElement(select_element,
&field->option_values,
&field->option_contents);
@@ -1443,18 +1441,18 @@ void WebFormControlElementToFormField(
if (!(extract_mask & EXTRACT_VALUE))
return;
- base::string16 value = element.value().utf16();
+ base::string16 value = element.Value().Utf16();
if (IsSelectElement(element) && (extract_mask & EXTRACT_OPTION_TEXT)) {
- const WebSelectElement select_element = element.toConst<WebSelectElement>();
+ const WebSelectElement select_element = element.ToConst<WebSelectElement>();
// Convert the |select_element| value to text if requested.
- WebVector<WebElement> list_items = select_element.listItems();
+ WebVector<WebElement> list_items = select_element.GetListItems();
for (size_t i = 0; i < list_items.size(); ++i) {
if (IsOptionElement(list_items[i])) {
const WebOptionElement option_element =
- list_items[i].toConst<WebOptionElement>();
- if (option_element.value().utf16() == value) {
- value = option_element.text().utf16();
+ list_items[i].ToConst<WebOptionElement>();
+ if (option_element.Value().Utf16() == value) {
+ value = option_element.GetText().Utf16();
break;
}
}
@@ -1475,21 +1473,21 @@ bool WebFormElementToFormData(
ExtractMask extract_mask,
FormData* form,
FormFieldData* field) {
- const WebFrame* frame = form_element.document().frame();
+ const WebFrame* frame = form_element.GetDocument().GetFrame();
if (!frame)
return false;
form->name = GetFormIdentifier(form_element);
- form->origin = GetCanonicalOriginForDocument(frame->document());
- form->action = frame->document().completeURL(form_element.action());
+ form->origin = GetCanonicalOriginForDocument(frame->GetDocument());
+ form->action = frame->GetDocument().CompleteURL(form_element.Action());
// If the completed URL is not valid, just use the action we get from
// WebKit.
if (!form->action.is_valid())
- form->action = GURL(blink::WebStringToGURL(form_element.action()));
+ form->action = GURL(blink::WebStringToGURL(form_element.Action()));
WebVector<WebFormControlElement> control_elements;
- form_element.getFormControlElements(control_elements);
+ form_element.GetFormControlElements(control_elements);
std::vector<blink::WebElement> dummy_fieldset;
return FormOrFieldsetsToFormData(
@@ -1501,16 +1499,15 @@ std::vector<WebFormControlElement> GetUnownedFormFieldElements(
const WebElementCollection& elements,
std::vector<WebElement>* fieldsets) {
std::vector<WebFormControlElement> unowned_fieldset_children;
- for (WebElement element = elements.firstItem();
- !element.isNull();
- element = elements.nextItem()) {
- if (element.isFormControlElement()) {
- WebFormControlElement control = element.to<WebFormControlElement>();
- if (control.form().isNull())
+ for (WebElement element = elements.FirstItem(); !element.IsNull();
+ element = elements.NextItem()) {
+ if (element.IsFormControlElement()) {
+ WebFormControlElement control = element.To<WebFormControlElement>();
+ if (control.Form().IsNull())
unowned_fieldset_children.push_back(control);
}
- if (fieldsets && element.hasHTMLTagName("fieldset") &&
+ if (fieldsets && element.HasHTMLTagName("fieldset") &&
!IsElementInsideFormOrFieldSet(element)) {
fieldsets->push_back(element);
}
@@ -1536,14 +1533,14 @@ bool UnownedCheckoutFormElementsAndFieldSetsToFormData(
// Only attempt formless Autofill on checkout flows. This avoids the many
// false positives found on the non-checkout web. See
// http://crbug.com/462375.
- WebElement html_element = document.documentElement();
+ WebElement html_element = document.DocumentElement();
// For now this restriction only applies to English-language pages, because
// the keywords are not translated. Note that an empty "lang" attribute
// counts as English.
std::string lang;
- if (!html_element.isNull())
- lang = html_element.getAttribute("lang").utf8();
+ if (!html_element.IsNull())
+ lang = html_element.GetAttribute("lang").Utf8();
if (!lang.empty() &&
!base::StartsWith(lang, "en", base::CompareCase::INSENSITIVE_ASCII)) {
return UnownedFormElementsAndFieldSetsToFormData(
@@ -1554,12 +1551,12 @@ bool UnownedCheckoutFormElementsAndFieldSetsToFormData(
// A potential problem is that this only checks document.title(), but should
// actually check the main frame's title. Thus it may make bad decisions for
// iframes.
- base::string16 title(base::ToLowerASCII(document.title().utf16()));
+ base::string16 title(base::ToLowerASCII(document.Title().Utf16()));
// Don't check the path for url's without a standard format path component,
// such as data:.
std::string path;
- GURL url(document.url());
+ GURL url(document.Url());
if (url.IsStandard())
path = base::ToLowerASCII(url.path());
@@ -1592,7 +1589,7 @@ bool UnownedCheckoutFormElementsAndFieldSetsToFormData(
CR_DEFINE_STATIC_LOCAL(WebString, kOffAttribute, ("off"));
std::vector<WebFormControlElement> elements_with_autocomplete;
for (const WebFormControlElement& element : control_elements) {
- blink::WebString autocomplete = element.getAttribute("autocomplete");
+ blink::WebString autocomplete = element.GetAttribute("autocomplete");
if (autocomplete.length() && autocomplete != kOffAttribute)
elements_with_autocomplete.push_back(element);
}
@@ -1623,20 +1620,20 @@ bool UnownedPasswordFormElementsAndFieldSetsToFormData(
bool FindFormAndFieldForFormControlElement(const WebFormControlElement& element,
FormData* form,
FormFieldData* field) {
- DCHECK(!element.isNull());
+ DCHECK(!element.IsNull());
if (!IsAutofillableElement(element))
return false;
ExtractMask extract_mask =
static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS);
- const WebFormElement form_element = element.form();
- if (form_element.isNull()) {
+ const WebFormElement form_element = element.Form();
+ if (form_element.IsNull()) {
// No associated form, try the synthetic form for unowned form elements.
- WebDocument document = element.document();
+ WebDocument document = element.GetDocument();
std::vector<WebElement> fieldsets;
std::vector<WebFormControlElement> control_elements =
- GetUnownedAutofillableFormFieldElements(document.all(), &fieldsets);
+ GetUnownedAutofillableFormFieldElements(document.All(), &fieldsets);
return UnownedCheckoutFormElementsAndFieldSetsToFormData(
fieldsets, control_elements, &element, document, extract_mask,
form, field);
@@ -1647,8 +1644,8 @@ bool FindFormAndFieldForFormControlElement(const WebFormControlElement& element,
}
void FillForm(const FormData& form, const WebFormControlElement& element) {
- WebFormElement form_element = element.form();
- if (form_element.isNull()) {
+ WebFormElement form_element = element.Form();
+ if (form_element.IsNull()) {
ForEachMatchingUnownedFormField(element,
form,
FILTER_ALL_NON_EDITABLE_ELEMENTS,
@@ -1667,7 +1664,7 @@ void FillForm(const FormData& form, const WebFormControlElement& element) {
void FillFormIncludingNonFocusableElements(const FormData& form_data,
const WebFormElement& form_element) {
- if (form_element.isNull()) {
+ if (form_element.IsNull()) {
NOTREACHED();
return;
}
@@ -1683,8 +1680,8 @@ void FillFormIncludingNonFocusableElements(const FormData& form_data,
}
void PreviewForm(const FormData& form, const WebFormControlElement& element) {
- WebFormElement form_element = element.form();
- if (form_element.isNull()) {
+ WebFormElement form_element = element.Form();
+ if (form_element.IsNull()) {
ForEachMatchingUnownedFormField(element,
form,
FILTER_ALL_NON_EDITABLE_ELEMENTS,
@@ -1703,11 +1700,11 @@ void PreviewForm(const FormData& form, const WebFormControlElement& element) {
bool ClearPreviewedFormWithElement(const WebFormControlElement& element,
bool was_autofilled) {
- WebFormElement form_element = element.form();
+ WebFormElement form_element = element.Form();
std::vector<WebFormControlElement> control_elements;
- if (form_element.isNull()) {
+ if (form_element.IsNull()) {
control_elements = GetUnownedAutofillableFormFieldElements(
- element.document().all(), nullptr);
+ element.GetDocument().All(), nullptr);
if (!IsElementInControlElementSet(element, control_elements))
return false;
} else {
@@ -1722,7 +1719,7 @@ bool ClearPreviewedFormWithElement(const WebFormControlElement& element,
WebFormControlElement control_element = control_elements[i];
// Only text input, textarea and select elements can be previewed.
- WebInputElement* input_element = toWebInputElement(&control_element);
+ WebInputElement* input_element = ToWebInputElement(&control_element);
if (!IsTextInput(input_element) &&
!IsMonthInput(input_element) &&
!IsTextAreaElement(control_element) &&
@@ -1731,35 +1728,34 @@ bool ClearPreviewedFormWithElement(const WebFormControlElement& element,
// If the element is not auto-filled, we did not preview it,
// so there is nothing to reset.
- if (!control_element.isAutofilled())
+ if (!control_element.IsAutofilled())
continue;
- if ((IsTextInput(input_element) ||
- IsMonthInput(input_element) ||
+ if ((IsTextInput(input_element) || IsMonthInput(input_element) ||
IsTextAreaElement(control_element) ||
IsSelectElement(control_element)) &&
- control_element.suggestedValue().isEmpty())
+ control_element.SuggestedValue().IsEmpty())
continue;
// Clear the suggested value. For the initiating node, also restore the
// original value.
if (IsTextInput(input_element) || IsMonthInput(input_element) ||
IsTextAreaElement(control_element)) {
- control_element.setSuggestedValue(WebString());
+ control_element.SetSuggestedValue(WebString());
bool is_initiating_node = (element == control_element);
if (is_initiating_node) {
- control_element.setAutofilled(was_autofilled);
+ control_element.SetAutofilled(was_autofilled);
// Clearing the suggested value in the focused node (above) can cause
// selection to be lost. We force selection range to restore the text
// cursor.
- int length = control_element.value().length();
- control_element.setSelectionRange(length, length);
+ int length = control_element.Value().length();
+ control_element.SetSelectionRange(length, length);
} else {
- control_element.setAutofilled(false);
+ control_element.SetAutofilled(false);
}
} else if (IsSelectElement(control_element)) {
- control_element.setSuggestedValue(WebString());
- control_element.setAutofilled(false);
+ control_element.SetSuggestedValue(WebString());
+ control_element.SetAutofilled(false);
}
}
@@ -1767,10 +1763,10 @@ bool ClearPreviewedFormWithElement(const WebFormControlElement& element,
}
bool IsWebpageEmpty(const blink::WebFrame* frame) {
- blink::WebDocument document = frame->document();
+ blink::WebDocument document = frame->GetDocument();
- return IsWebElementEmpty(document.head()) &&
- IsWebElementEmpty(document.body());
+ return IsWebElementEmpty(document.Head()) &&
+ IsWebElementEmpty(document.Body());
}
bool IsWebElementEmpty(const blink::WebElement& root) {
@@ -1778,24 +1774,21 @@ bool IsWebElementEmpty(const blink::WebElement& root) {
CR_DEFINE_STATIC_LOCAL(WebString, kMeta, ("meta"));
CR_DEFINE_STATIC_LOCAL(WebString, kTitle, ("title"));
- if (root.isNull())
+ if (root.IsNull())
return true;
- for (WebNode child = root.firstChild();
- !child.isNull();
- child = child.nextSibling()) {
- if (child.isTextNode() &&
- !base::ContainsOnlyChars(child.nodeValue().utf8(),
- base::kWhitespaceASCII))
+ for (WebNode child = root.FirstChild(); !child.IsNull();
+ child = child.NextSibling()) {
+ if (child.IsTextNode() && !base::ContainsOnlyChars(child.NodeValue().Utf8(),
+ base::kWhitespaceASCII))
return false;
- if (!child.isElementNode())
+ if (!child.IsElementNode())
continue;
- WebElement element = child.to<WebElement>();
- if (!element.hasHTMLTagName(kScript) &&
- !element.hasHTMLTagName(kMeta) &&
- !element.hasHTMLTagName(kTitle))
+ WebElement element = child.To<WebElement>();
+ if (!element.HasHTMLTagName(kScript) && !element.HasHTMLTagName(kMeta) &&
+ !element.HasHTMLTagName(kTitle))
return false;
}
return true;
@@ -1812,7 +1805,7 @@ void PreviewSuggestion(const base::string16& suggestion,
selection_start = (offset == base::string16::npos) ? 0 : offset;
}
- input_element->setSelectionRange(selection_start, suggestion.length());
+ input_element->SetSelectionRange(selection_start, suggestion.length());
}
} // namespace form_util
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.h b/chromium/components/autofill/content/renderer/form_autofill_util.h
index ccf29157086..998d5b0459a 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.h
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.h
@@ -83,14 +83,12 @@ GURL StripAuthAndParams(const GURL& gurl);
// successful.
bool ExtractFormData(const blink::WebFormElement& form_element, FormData* data);
-// Helper function to check if there exist any form on |frame| where its action
+// Helper function to check if there exist any visible form on |frame| which
+// equals |form_element|. If |form_element| is null, checks if forms action
// equals |action|. Returns true if so. For forms with empty or unspecified
-// actions, all form data are used for comparison. Form data comparison is
-// disabled on Mac and Android because the update prompt isn't implemented.
-// It may cause many false password updates.
-// TODO(kolos) Turn on all data comparing when the update prompt will be
-// implemented on Mac and Android.
+// actions, all form data are used for comparison.
bool IsFormVisible(blink::WebFrame* frame,
+ const blink::WebFormElement& form_element,
const GURL& action,
const GURL& origin,
const FormData& form_data);
@@ -131,13 +129,10 @@ bool IsAutofillableInputElement(const blink::WebInputElement* element);
// {Text, Radiobutton, Checkbox, Select, TextArea}.
bool IsAutofillableElement(const blink::WebFormControlElement& element);
-// True if this node takes up space in the layout, ie. this node or a descendant
-// has a non-empty bounding bounding client rect.
-//
-// TODO(esprehn): This isn't really about visibility, it's about the size.
-// We should remove this function and just call hasNonEmptyLayoutSize()
-// directly.
-bool IsWebNodeVisible(const blink::WebNode& node);
+// True if this node can take focus. If layout is blocked, then the function
+// checks if the element takes up space in the layout, ie. this element or a
+// descendant has a non-empty bounding bounding client rect.
+bool IsWebElementVisible(const blink::WebElement& element);
// Returns the form's |name| attribute if non-empty; otherwise the form's |id|
// attribute.
diff --git a/chromium/components/autofill/content/renderer/form_cache.cc b/chromium/components/autofill/content/renderer/form_cache.cc
index 03cb04f47cd..2f360bc0fcb 100644
--- a/chromium/components/autofill/content/renderer/form_cache.cc
+++ b/chromium/components/autofill/content/renderer/form_cache.cc
@@ -41,7 +41,7 @@ namespace {
void LogDeprecationMessages(const WebFormControlElement& element) {
std::string autocomplete_attribute =
- element.getAttribute("autocomplete").utf8();
+ element.GetAttribute("autocomplete").Utf8();
static const char* const deprecated[] = { "region", "locality" };
for (const char* str : deprecated) {
@@ -50,8 +50,8 @@ void LogDeprecationMessages(const WebFormControlElement& element) {
std::string msg = std::string("autocomplete='") + str +
"' is deprecated and will soon be ignored. See http://goo.gl/YjeSsW";
WebConsoleMessage console_message = WebConsoleMessage(
- WebConsoleMessage::LevelWarning, WebString::fromASCII(msg));
- element.document().frame()->addMessageToConsole(console_message);
+ WebConsoleMessage::kLevelWarning, WebString::FromASCII(msg));
+ element.GetDocument().GetFrame()->AddMessageToConsole(console_message);
}
}
@@ -90,14 +90,14 @@ FormCache::~FormCache() {
std::vector<FormData> FormCache::ExtractNewForms() {
std::vector<FormData> forms;
- WebDocument document = frame_.document();
- if (document.isNull())
+ WebDocument document = frame_.GetDocument();
+ if (document.IsNull())
return forms;
initial_checked_state_.clear();
initial_select_values_.clear();
WebVector<WebFormElement> web_forms;
- document.forms(web_forms);
+ document.Forms(web_forms);
// Log an error message for deprecated attributes, but only the first time
// the form is parsed.
@@ -147,7 +147,7 @@ std::vector<FormData> FormCache::ExtractNewForms() {
// Look for more parseable fields outside of forms.
std::vector<WebElement> fieldsets;
std::vector<WebFormControlElement> control_elements =
- form_util::GetUnownedAutofillableFormFieldElements(document.all(),
+ form_util::GetUnownedAutofillableFormFieldElements(document.All(),
&fieldsets);
size_t num_editable_elements =
@@ -186,11 +186,11 @@ void FormCache::Reset() {
}
bool FormCache::ClearFormWithElement(const WebFormControlElement& element) {
- WebFormElement form_element = element.form();
+ WebFormElement form_element = element.Form();
std::vector<WebFormControlElement> control_elements;
- if (form_element.isNull()) {
+ if (form_element.IsNull()) {
control_elements = form_util::GetUnownedAutofillableFormFieldElements(
- element.document().all(), nullptr);
+ element.GetDocument().All(), nullptr);
} else {
control_elements =
form_util::ExtractAutofillableElementsInForm(form_element);
@@ -198,46 +198,46 @@ bool FormCache::ClearFormWithElement(const WebFormControlElement& element) {
for (size_t i = 0; i < control_elements.size(); ++i) {
WebFormControlElement control_element = control_elements[i];
// Don't modify the value of disabled fields.
- if (!control_element.isEnabled())
+ if (!control_element.IsEnabled())
continue;
// Don't clear field that was not autofilled
- if (!control_element.isAutofilled())
+ if (!control_element.IsAutofilled())
continue;
- control_element.setAutofilled(false);
+ control_element.SetAutofilled(false);
- WebInputElement* input_element = toWebInputElement(&control_element);
+ WebInputElement* input_element = ToWebInputElement(&control_element);
if (form_util::IsTextInput(input_element) ||
form_util::IsMonthInput(input_element)) {
- input_element->setValue(blink::WebString(), true);
+ input_element->SetAutofillValue(blink::WebString());
// Clearing the value in the focused node (above) can cause selection
// to be lost. We force selection range to restore the text cursor.
if (element == *input_element) {
- int length = input_element->value().length();
- input_element->setSelectionRange(length, length);
+ int length = input_element->Value().length();
+ input_element->SetSelectionRange(length, length);
}
} else if (form_util::IsTextAreaElement(control_element)) {
- control_element.setValue(blink::WebString(), true);
+ control_element.SetAutofillValue(blink::WebString());
} else if (form_util::IsSelectElement(control_element)) {
- WebSelectElement select_element = control_element.to<WebSelectElement>();
+ WebSelectElement select_element = control_element.To<WebSelectElement>();
std::map<const WebSelectElement, base::string16>::const_iterator
initial_value_iter = initial_select_values_.find(select_element);
if (initial_value_iter != initial_select_values_.end() &&
- select_element.value().utf16() != initial_value_iter->second) {
- select_element.setValue(
- blink::WebString::fromUTF16(initial_value_iter->second), true);
+ select_element.Value().Utf16() != initial_value_iter->second) {
+ select_element.SetAutofillValue(
+ blink::WebString::FromUTF16(initial_value_iter->second));
}
} else {
- WebInputElement input_element = control_element.to<WebInputElement>();
+ WebInputElement input_element = control_element.To<WebInputElement>();
DCHECK(form_util::IsCheckableElement(&input_element));
std::map<const WebInputElement, bool>::const_iterator it =
initial_checked_state_.find(input_element);
if (it != initial_checked_state_.end() &&
- input_element.isChecked() != it->second) {
- input_element.setChecked(it->second, true);
+ input_element.IsChecked() != it->second) {
+ input_element.SetChecked(it->second, true);
}
}
}
@@ -254,9 +254,9 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form) {
bool found_synthetic_form = false;
if (form.data.SameFormAs(synthetic_form_)) {
found_synthetic_form = true;
- WebDocument document = frame_.document();
+ WebDocument document = frame_.GetDocument();
control_elements = form_util::GetUnownedAutofillableFormFieldElements(
- document.all(), nullptr);
+ document.All(), nullptr);
}
if (!found_synthetic_form) {
@@ -264,7 +264,7 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form) {
bool found_form = false;
WebFormElement form_element;
WebVector<WebFormElement> web_forms;
- frame_.document().forms(web_forms);
+ frame_.GetDocument().Forms(web_forms);
for (size_t i = 0; i < web_forms.size(); ++i) {
form_element = web_forms[i];
@@ -277,7 +277,8 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form) {
// an "empty" string (rhs). We don't want that distinction, so forcing
// to string16.
base::string16 element_name = form_util::GetFormIdentifier(form_element);
- GURL action(form_element.document().completeURL(form_element.action()));
+ GURL action(
+ form_element.GetDocument().CompleteURL(form_element.Action()));
if (element_name == form.data.name && action == form.data.action) {
found_form = true;
control_elements =
@@ -300,7 +301,7 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form) {
WebFormControlElement& element = control_elements[i];
const FormFieldData& field_data = form.data.fields[i];
- if (element.nameForAutofill().utf16() != field_data.name) {
+ if (element.NameForAutofill().Utf16() != field_data.name) {
// Keep things simple. Don't show predictions for elements whose names
// were modified between page load and the server's response to our query.
continue;
@@ -324,10 +325,10 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form) {
replacements.push_back(base::UTF8ToUTF16(form.signature));
const base::string16 title = l10n_util::GetStringFUTF16(
IDS_AUTOFILL_SHOW_PREDICTIONS_TITLE, replacements, nullptr);
- element.setAttribute("title", WebString::fromUTF16(title));
+ element.SetAttribute("title", WebString::FromUTF16(title));
- element.setAttribute("autofill-prediction",
- WebString::fromUTF16(overall_type));
+ element.SetAttribute("autofill-prediction",
+ WebString::FromUTF16(overall_type));
}
return true;
@@ -349,7 +350,7 @@ size_t FormCache::ScanFormControlElements(
form_util::IsTextAreaElement(element)) {
++num_editable_elements;
} else {
- const WebInputElement input_element = element.toConst<WebInputElement>();
+ const WebInputElement input_element = element.ToConst<WebInputElement>();
if (!form_util::IsCheckableElement(&input_element))
++num_editable_elements;
}
@@ -362,14 +363,14 @@ void FormCache::SaveInitialValues(
for (const WebFormControlElement& element : control_elements) {
if (form_util::IsSelectElement(element)) {
const WebSelectElement select_element =
- element.toConst<WebSelectElement>();
+ element.ToConst<WebSelectElement>();
initial_select_values_.insert(
- std::make_pair(select_element, select_element.value().utf16()));
+ std::make_pair(select_element, select_element.Value().Utf16()));
} else {
- const WebInputElement* input_element = toWebInputElement(&element);
+ const WebInputElement* input_element = ToWebInputElement(&element);
if (form_util::IsCheckableElement(input_element)) {
initial_checked_state_.insert(
- std::make_pair(*input_element, input_element->isChecked()));
+ std::make_pair(*input_element, input_element->IsChecked()));
}
}
}
diff --git a/chromium/components/autofill/content/renderer/form_classifier.cc b/chromium/components/autofill/content/renderer/form_classifier.cc
index 4a4ea3e35c4..09a0499f66f 100644
--- a/chromium/components/autofill/content/renderer/form_classifier.cc
+++ b/chromium/components/autofill/content/renderer/form_classifier.cc
@@ -59,9 +59,9 @@ bool FindTextFeaturesForClass(const blink::WebElement& element,
size_t number_of_features) {
DCHECK(features);
- for (unsigned i = 0; i < element.attributeCount(); ++i) {
+ for (unsigned i = 0; i < element.AttributeCount(); ++i) {
std::string filtered_value =
- base::ToLowerASCII(element.attributeValue(i).utf8());
+ base::ToLowerASCII(element.AttributeValue(i).Utf8());
ClearAttributeValue(&filtered_value);
if (filtered_value.empty())
@@ -88,10 +88,10 @@ bool FindCaptchaInImgElements(const blink::WebElement& form,
CR_DEFINE_STATIC_LOCAL(WebString, kImageTag, ("img"));
blink::WebElementCollection img_elements =
- form.getElementsByHTMLTagName(kImageTag);
- for (blink::WebElement element = img_elements.firstItem(); !element.isNull();
- element = img_elements.nextItem()) {
- if (ingnore_invisible && !form_util::IsWebNodeVisible(element))
+ form.GetElementsByHTMLTagName(kImageTag);
+ for (blink::WebElement element = img_elements.FirstItem(); !element.IsNull();
+ element = img_elements.NextItem()) {
+ if (ingnore_invisible && !form_util::IsWebElementVisible(element))
continue;
if (FindTextFeaturesForClass(element, kCaptchaFeatures,
kNumberOfCaptchaFeatures)) {
@@ -125,22 +125,22 @@ bool IsButtonOrImageElement(const WebFormControlElement& element) {
CR_DEFINE_STATIC_LOCAL(WebString, kButton, ("button"));
CR_DEFINE_STATIC_LOCAL(WebString, kImage, ("image"));
- return element.formControlType() == kButton ||
- element.formControlType() == kImage;
+ return element.FormControlType() == kButton ||
+ element.FormControlType() == kImage;
}
// Returns true if |element| has type "submit".
bool IsSubmitElement(const WebFormControlElement& element) {
CR_DEFINE_STATIC_LOCAL(WebString, kSubmit, ("submit"));
- return element.formControlType() == kSubmit;
+ return element.FormControlType() == kSubmit;
}
// Returns true if |element| has type "hidden";
bool IsHiddenElement(const WebFormControlElement& element) {
CR_DEFINE_STATIC_LOCAL(WebString, kHidden, ("hidden"));
- return element.formControlType() == kHidden;
+ return element.FormControlType() == kHidden;
}
// Returns true if |element| has type "select-multiple" or "select-one".
@@ -148,20 +148,20 @@ bool IsSelectElement(const WebFormControlElement& element) {
CR_DEFINE_STATIC_LOCAL(WebString, kSelectOne, ("select-one"));
CR_DEFINE_STATIC_LOCAL(WebString, kSelectMultiple, ("select-multiple"));
- return element.formControlType() == kSelectOne ||
- element.formControlType() == kSelectMultiple;
+ return element.FormControlType() == kSelectOne ||
+ element.FormControlType() == kSelectMultiple;
}
// Return true if |form| contains at least one visible password element.
bool FormContainsVisiblePasswordFields(const blink::WebFormElement& form) {
WebVector<WebFormControlElement> control_elements;
- form.getFormControlElements(control_elements);
+ form.GetFormControlElements(control_elements);
for (auto& control_element : control_elements) {
- const WebInputElement* input_element = toWebInputElement(&control_element);
+ const WebInputElement* input_element = ToWebInputElement(&control_element);
if (!input_element)
continue;
- if (input_element->isPasswordField() &&
- form_util::IsWebNodeVisible(*input_element)) {
+ if (input_element->IsPasswordField() &&
+ form_util::IsWebElementVisible(*input_element)) {
return true;
}
}
@@ -174,7 +174,7 @@ bool ClassifyFormAndFindGenerationField(const blink::WebFormElement& form,
base::string16* generation_field) {
DCHECK(generation_field);
- if (form.isNull())
+ if (form.IsNull())
return false;
bool ignore_invisible_elements = FormContainsVisiblePasswordFields(form);
@@ -193,13 +193,13 @@ bool ClassifyFormAndFindGenerationField(const blink::WebFormElement& form,
std::vector<WebInputElement> passwords;
WebVector<WebFormControlElement> control_elements;
- form.getFormControlElements(control_elements);
+ form.GetFormControlElements(control_elements);
for (const WebFormControlElement& control_element : control_elements) {
if (IsHiddenElement(control_element))
continue;
if (ignore_invisible_elements) {
- if (!form_util::IsWebNodeVisible(control_element))
+ if (!form_util::IsWebElementVisible(control_element))
continue;
}
@@ -217,12 +217,12 @@ bool ClassifyFormAndFindGenerationField(const blink::WebFormElement& form,
number_of_other_input_fields++;
} else {
const WebInputElement* input_element =
- toWebInputElement(&control_element);
+ ToWebInputElement(&control_element);
if (!input_element)
continue;
- if (input_element->isTextField()) {
- if (input_element->isPasswordField()) {
+ if (input_element->IsTextField()) {
+ if (input_element->IsPasswordField()) {
++number_of_password_input_fields;
passwords.push_back(*input_element);
} else {
@@ -230,7 +230,7 @@ bool ClassifyFormAndFindGenerationField(const blink::WebFormElement& form,
found_captcha = found_captcha || IsCaptchaInput(*input_element);
}
} else { // Non-text fields.
- if (input_element->isCheckbox())
+ if (input_element->IsCheckbox())
++number_of_checkbox_input_fields;
else if (!IsSubmitElement(*input_element))
++number_of_other_input_fields;
@@ -257,7 +257,7 @@ bool ClassifyFormAndFindGenerationField(const blink::WebFormElement& form,
else
password_creation_field = passwords[0];
- *generation_field = password_creation_field.nameForAutofill().utf16();
+ *generation_field = password_creation_field.NameForAutofill().Utf16();
return true;
}
return false;
diff --git a/chromium/components/autofill/content/renderer/page_click_tracker.cc b/chromium/components/autofill/content/renderer/page_click_tracker.cc
index 0af746045e8..fa18796a71f 100644
--- a/chromium/components/autofill/content/renderer/page_click_tracker.cc
+++ b/chromium/components/autofill/content/renderer/page_click_tracker.cc
@@ -22,7 +22,6 @@
using blink::WebElement;
using blink::WebFormControlElement;
-using blink::WebGestureEvent;
using blink::WebInputElement;
using blink::WebNode;
using blink::WebPoint;
@@ -34,14 +33,14 @@ namespace autofill {
namespace {
// Casts |element| to a WebFormControlElement, but only if it's a text field.
-// Returns an empty (isNull()) wrapper otherwise.
+// Returns an empty (IsNull()) wrapper otherwise.
const WebFormControlElement GetTextFormControlElement(
const WebElement& element) {
- if (!element.isFormControlElement())
+ if (!element.IsFormControlElement())
return WebFormControlElement();
- if (form_util::IsTextInput(blink::toWebInputElement(&element)) ||
- element.hasHTMLTagName("textarea"))
- return element.toConst<WebFormControlElement>();
+ if (form_util::IsTextInput(blink::ToWebInputElement(&element)) ||
+ element.HasHTMLTagName("textarea"))
+ return element.ToConst<WebFormControlElement>();
return WebFormControlElement();
}
@@ -49,48 +48,47 @@ const WebFormControlElement GetTextFormControlElement(
PageClickTracker::PageClickTracker(content::RenderFrame* render_frame,
PageClickListener* listener)
- : content::RenderFrameObserver(render_frame),
- focused_node_was_last_clicked_(false),
+ : focused_node_was_last_clicked_(false),
was_focused_before_now_(false),
listener_(listener),
- legacy_(this) {
-}
+ render_frame_(render_frame) {}
PageClickTracker::~PageClickTracker() {
}
-void PageClickTracker::OnMouseDown(const WebNode& mouse_down_node) {
- focused_node_was_last_clicked_ = !mouse_down_node.isNull() &&
- mouse_down_node.focused();
-
- if (IsKeyboardAccessoryEnabled())
- DoFocusChangeComplete();
-}
-
void PageClickTracker::FocusedNodeChanged(const WebNode& node) {
was_focused_before_now_ = false;
if (IsKeyboardAccessoryEnabled() &&
- WebUserGestureIndicator::isProcessingUserGesture()) {
+ WebUserGestureIndicator::IsProcessingUserGesture()) {
focused_node_was_last_clicked_ = true;
DoFocusChangeComplete();
}
}
-void PageClickTracker::FocusChangeComplete() {
+void PageClickTracker::DidCompleteFocusChangeInFrame() {
if (IsKeyboardAccessoryEnabled())
return;
DoFocusChangeComplete();
}
+void PageClickTracker::DidReceiveLeftMouseDownOrGestureTapInNode(
+ const blink::WebNode& node) {
+ DCHECK(!node.IsNull());
+ focused_node_was_last_clicked_ = node.Focused();
+
+ if (IsKeyboardAccessoryEnabled())
+ DoFocusChangeComplete();
+}
+
void PageClickTracker::DoFocusChangeComplete() {
WebElement focused_element =
- render_frame()->GetWebFrame()->document().focusedElement();
- if (focused_node_was_last_clicked_ && !focused_element.isNull()) {
+ render_frame()->GetWebFrame()->GetDocument().FocusedElement();
+ if (focused_node_was_last_clicked_ && !focused_element.IsNull()) {
const WebFormControlElement control =
GetTextFormControlElement(focused_element);
- if (!control.isNull()) {
+ if (!control.IsNull()) {
listener_->FormControlElementClicked(control,
was_focused_before_now_);
}
@@ -100,27 +98,4 @@ void PageClickTracker::DoFocusChangeComplete() {
focused_node_was_last_clicked_ = false;
}
-void PageClickTracker::OnDestruct() {
- delete this;
-}
-
-// PageClickTracker::Legacy ----------------------------------------------------
-
-PageClickTracker::Legacy::Legacy(PageClickTracker* tracker)
- : content::RenderViewObserver(tracker->render_frame()->GetRenderView()),
- tracker_(tracker) {
-}
-
-void PageClickTracker::Legacy::OnDestruct() {
- // No-op. Don't delete |this|.
-}
-
-void PageClickTracker::Legacy::OnMouseDown(const WebNode& mouse_down_node) {
- tracker_->OnMouseDown(mouse_down_node);
-}
-
-void PageClickTracker::Legacy::FocusChangeComplete() {
- tracker_->FocusChangeComplete();
-}
-
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/page_click_tracker.h b/chromium/components/autofill/content/renderer/page_click_tracker.h
index f77b7a4b5f4..3b1dda447cb 100644
--- a/chromium/components/autofill/content/renderer/page_click_tracker.h
+++ b/chromium/components/autofill/content/renderer/page_click_tracker.h
@@ -9,10 +9,12 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "content/public/renderer/render_frame_observer.h"
-#include "content/public/renderer/render_view_observer.h"
#include "third_party/WebKit/public/web/WebNode.h"
+namespace content {
+class RenderFrame;
+}
+
namespace autofill {
class PageClickListener;
@@ -25,39 +27,21 @@ class PageClickListener;
// suggestion popup when a text input is clicked.
//
// There is one PageClickTracker per AutofillAgent.
-class PageClickTracker : public content::RenderFrameObserver {
+class PageClickTracker {
public:
// The |listener| will be notified when an element is clicked. It must
// outlive this class.
PageClickTracker(content::RenderFrame* render_frame,
PageClickListener* listener);
- ~PageClickTracker() override;
+ ~PageClickTracker();
+
+ void FocusedNodeChanged(const blink::WebNode& node);
+ void DidCompleteFocusChangeInFrame();
+ void DidReceiveLeftMouseDownOrGestureTapInNode(const blink::WebNode& node);
+
+ content::RenderFrame* render_frame() const { return render_frame_; }
private:
- // TODO(estade): migrate this stuff to content::RenderFrameObserver, and
- // remove this class.
- class Legacy : public content::RenderViewObserver {
- public:
- Legacy(PageClickTracker* tracker);
-
- // RenderViewObserver implementation.
- void OnDestruct() override;
- void OnMouseDown(const blink::WebNode& mouse_down_node) override;
- void FocusChangeComplete() override;
-
- private:
- PageClickTracker* tracker_;
- };
- friend class Legacy;
-
- // RenderFrameObserver implementation.
- void FocusedNodeChanged(const blink::WebNode& node) override;
- void OnDestruct() override;
-
- // RenderViewObserver methods forwarded from Legacy. Should be
- // merged into RenderFrameObserver.
- void OnMouseDown(const blink::WebNode& mouse_down_node);
- void FocusChangeComplete();
void DoFocusChangeComplete();
// True when the last click was on the focused node.
@@ -71,7 +55,7 @@ class PageClickTracker : public content::RenderFrameObserver {
// The listener getting the actual notifications.
PageClickListener* listener_;
- Legacy legacy_;
+ content::RenderFrame* const render_frame_;
DISALLOW_COPY_AND_ASSIGN(PageClickTracker);
};
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.cc b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
index abac9479d63..26748925a77 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
@@ -99,12 +99,12 @@ bool IsPasswordField(const FormFieldData& field) {
bool HasPasswordWithAutocompleteAttribute(
const std::vector<blink::WebFormControlElement>& control_elements) {
for (const blink::WebFormControlElement& control_element : control_elements) {
- if (!control_element.hasHTMLTagName("input"))
+ if (!control_element.HasHTMLTagName("input"))
continue;
const blink::WebInputElement input_element =
- control_element.toConst<blink::WebInputElement>();
- if (input_element.isPasswordField() &&
+ control_element.ToConst<blink::WebInputElement>();
+ if (input_element.IsPasswordField() &&
(HasAutocompleteAttributeValue(input_element, "current-password") ||
HasAutocompleteAttributeValue(input_element, "new-password")))
return true;
@@ -124,10 +124,14 @@ base::string16 FieldName(const FormFieldData& field,
}
bool IsUnownedPasswordFormVisible(blink::WebFrame* frame,
+ const blink::WebInputElement& input_element,
const GURL& action,
const GURL& origin,
const FormData& form_data,
const FormsPredictionsMap& form_predictions) {
+ if (!input_element.IsNull() && form_util::IsWebElementVisible(input_element))
+ return true;
+
std::unique_ptr<PasswordForm> unowned_password_form(
CreatePasswordFormFromUnownedInputElements(*frame, nullptr,
&form_predictions));
@@ -135,7 +139,7 @@ bool IsUnownedPasswordFormVisible(blink::WebFrame* frame,
return false;
std::vector<blink::WebFormControlElement> control_elements =
form_util::GetUnownedAutofillableFormFieldElements(
- frame->document().all(), nullptr);
+ frame->GetDocument().All(), nullptr);
if (!form_util::IsSomeControlElementVisible(control_elements))
return false;
@@ -170,19 +174,19 @@ bool FindFormInputElement(
base::string16 field_name = FieldName(field, ambiguous_or_empty_names);
for (const blink::WebFormControlElement& control_element : control_elements) {
if (!ambiguous_or_empty_names &&
- control_element.nameForAutofill().utf16() != field_name) {
+ control_element.NameForAutofill().Utf16() != field_name) {
continue;
}
- if (!control_element.hasHTMLTagName("input"))
+ if (!control_element.HasHTMLTagName("input"))
continue;
// Only fill saved passwords into password fields and usernames into text
// fields.
const blink::WebInputElement input_element =
- control_element.toConst<blink::WebInputElement>();
- if (!input_element.isTextField() ||
- input_element.isPasswordField() != is_password_field)
+ control_element.ToConst<blink::WebInputElement>();
+ if (!input_element.IsTextField() ||
+ input_element.IsPasswordField() != is_password_field)
continue;
// For change password form with ambiguous or empty names keep only the
@@ -198,7 +202,7 @@ bool FindFormInputElement(
if (found_input) {
// For change password form keep only the first password field entry.
if (does_password_field_has_ambigous_or_empty_name) {
- if (!form_util::IsWebNodeVisible((*result)[field_name])) {
+ if (!form_util::IsWebElementVisible((*result)[field_name])) {
// If a previously chosen field was invisible then take the current
// one.
(*result)[field_name] = input_element;
@@ -247,13 +251,14 @@ void FindFormElements(content::RenderFrame* render_frame,
FormElementsList* results) {
DCHECK(results);
- blink::WebDocument doc = render_frame->GetWebFrame()->document();
+ blink::WebDocument doc = render_frame->GetWebFrame()->GetDocument();
- if (data.origin != form_util::GetCanonicalOriginForDocument(doc))
+ if (GetSignOnRealm(data.origin) !=
+ GetSignOnRealm(form_util::GetCanonicalOriginForDocument(doc)))
return;
blink::WebVector<blink::WebFormElement> forms;
- doc.forms(forms);
+ doc.Forms(forms);
for (size_t i = 0; i < forms.size(); ++i) {
blink::WebFormElement fe = forms[i];
@@ -275,7 +280,7 @@ void FindFormElements(content::RenderFrame* render_frame,
return;
std::vector<blink::WebFormControlElement> control_elements =
- form_util::GetUnownedAutofillableFormFieldElements(doc.all(), nullptr);
+ form_util::GetUnownedAutofillableFormFieldElements(doc.All(), nullptr);
FormInputElementMap unowned_elements_map;
if (FindFormInputElements(control_elements, data, ambiguous_or_empty_names,
&unowned_elements_map))
@@ -283,7 +288,7 @@ void FindFormElements(content::RenderFrame* render_frame,
}
bool IsElementEditable(const blink::WebInputElement& element) {
- return element.isEnabled() && !element.isReadOnly();
+ return element.IsEnabled() && !element.IsReadOnly();
}
bool DoUsernamesMatch(const base::string16& username1,
@@ -313,9 +318,8 @@ bool FormContainsNonDefaultPasswordValue(const PasswordForm& password_form) {
void LogHTMLForm(SavePasswordProgressLogger* logger,
SavePasswordProgressLogger::StringID message_id,
const blink::WebFormElement& form) {
- logger->LogHTMLForm(message_id,
- form.name().utf8(),
- GURL(form.action().utf8()));
+ logger->LogHTMLForm(message_id, form.GetName().Utf8(),
+ GURL(form.Action().Utf8()));
}
@@ -401,8 +405,8 @@ bool FillUserNameAndPassword(
return false;
base::string16 current_username;
- if (!username_element->isNull()) {
- current_username = username_element->value().utf16();
+ if (!username_element->IsNull()) {
+ current_username = username_element->Value().Utf16();
}
// username and password will contain the match found if any.
@@ -453,14 +457,14 @@ bool FillUserNameAndPassword(
// fields.
// Input matches the username, fill in required values.
- if (!username_element->isNull() &&
+ if (!username_element->IsNull() &&
IsElementAutocompletable(*username_element)) {
// TODO(crbug.com/507714): Why not setSuggestedValue?
- username_element->setValue(blink::WebString::fromUTF16(username), true);
+ username_element->SetAutofillValue(blink::WebString::FromUTF16(username));
UpdateFieldValueAndPropertiesMaskMap(*username_element, &username,
FieldPropertiesFlags::AUTOFILLED,
field_value_and_properties_map);
- username_element->setAutofilled(true);
+ username_element->SetAutofilled(true);
if (logger)
logger->LogElementName(Logger::STRING_USERNAME_FILLED, *username_element);
if (set_selection) {
@@ -476,13 +480,13 @@ bool FillUserNameAndPassword(
// Wait to fill in the password until a user gesture occurs. This is to make
// sure that we do not fill in the DOM with a password until we believe the
// user is intentionally interacting with the page.
- password_element->setSuggestedValue(blink::WebString::fromUTF16(password));
+ password_element->SetSuggestedValue(blink::WebString::FromUTF16(password));
UpdateFieldValueAndPropertiesMaskMap(*password_element, &password,
FieldPropertiesFlags::AUTOFILLED,
field_value_and_properties_map);
registration_callback.Run(password_element);
- password_element->setAutofilled(true);
+ password_element->SetAutofilled(true);
if (logger)
logger->LogElementName(Logger::STRING_PASSWORD_FILLED, *password_element);
return true;
@@ -505,15 +509,15 @@ bool FillFormOnPasswordReceived(
RendererSavePasswordProgressLogger* logger) {
// Do not fill if the password field is in a chain of iframes not having
// identical origin.
- blink::WebFrame* cur_frame = password_element.document().frame();
+ blink::WebFrame* cur_frame = password_element.GetDocument().GetFrame();
blink::WebString bottom_frame_origin =
- cur_frame->getSecurityOrigin().toString();
+ cur_frame->GetSecurityOrigin().ToString();
DCHECK(cur_frame);
- while (cur_frame->parent()) {
- cur_frame = cur_frame->parent();
- if (!bottom_frame_origin.equals(cur_frame->getSecurityOrigin().toString()))
+ while (cur_frame->Parent()) {
+ cur_frame = cur_frame->Parent();
+ if (!bottom_frame_origin.Equals(cur_frame->GetSecurityOrigin().ToString()))
return false;
}
@@ -549,10 +553,10 @@ bool FillFormOnPasswordReceived(
bool form_has_fillable_username = !username_field_name.empty() &&
IsElementAutocompletable(username_element);
- if (form_has_fillable_username && username_element.value().isEmpty()) {
+ if (form_has_fillable_username && username_element.Value().IsEmpty()) {
// TODO(tkent): Check maxlength and pattern.
- username_element.setValue(
- blink::WebString::fromUTF16(fill_data.username_field.value), true);
+ username_element.SetAutofillValue(
+ blink::WebString::FromUTF16(fill_data.username_field.value));
}
// Fill if we have an exact match for the username. Note that this sets
@@ -570,9 +574,9 @@ void AnnotateFormsWithSignatures(
std::unique_ptr<PasswordForm> password_form(
CreatePasswordFormFromWebForm(form, nullptr, nullptr));
if (password_form) {
- form.setAttribute(
- blink::WebString::fromASCII(kDebugAttributeForFormSignature),
- blink::WebString::fromUTF8(base::Uint64ToString(
+ form.SetAttribute(
+ blink::WebString::FromASCII(kDebugAttributeForFormSignature),
+ blink::WebString::FromUTF8(base::Uint64ToString(
CalculateFormSignature(password_form->form_data))));
std::vector<blink::WebFormControlElement> control_elements =
@@ -585,17 +589,34 @@ void AnnotateFormsWithSignatures(
blink::WebFormControlElement control_element = control_elements[i];
const FormFieldData& field = password_form->form_data.fields[i];
- if (field.name != control_element.nameForAutofill().utf16())
+ if (field.name != control_element.NameForAutofill().Utf16())
continue;
- control_element.setAttribute(
- blink::WebString::fromASCII(kDebugAttributeForFieldSignature),
- blink::WebString::fromUTF8(
+ control_element.SetAttribute(
+ blink::WebString::FromASCII(kDebugAttributeForFieldSignature),
+ blink::WebString::FromUTF8(
base::Uint64ToString(CalculateFieldSignatureForField(field))));
}
}
}
}
+// Returns true iff there is a password field in |frame|.
+bool HasPasswordField(const blink::WebLocalFrame& frame) {
+ CR_DEFINE_STATIC_LOCAL(blink::WebString, kPassword, ("password"));
+
+ const blink::WebElementCollection elements = frame.GetDocument().All();
+ for (blink::WebElement element = elements.FirstItem(); !element.IsNull();
+ element = elements.NextItem()) {
+ if (element.IsFormControlElement()) {
+ const blink::WebFormControlElement& control =
+ element.To<blink::WebFormControlElement>();
+ if (control.FormControlType() == kPassword)
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -606,6 +627,7 @@ PasswordAutofillAgent::PasswordAutofillAgent(content::RenderFrame* render_frame)
logging_state_active_(false),
was_username_autofilled_(false),
was_password_autofilled_(false),
+ sent_request_to_store_(false),
binding_(this) {
// PasswordAutofillAgent is guaranteed to outlive |render_frame|.
render_frame->GetInterfaceRegistry()->AddInterface(
@@ -640,6 +662,9 @@ void PasswordAutofillAgent::PasswordValueGatekeeper::RegisterElement(
}
void PasswordAutofillAgent::PasswordValueGatekeeper::OnUserGesture() {
+ if (was_user_gesture_seen_)
+ return;
+
was_user_gesture_seen_ = true;
for (blink::WebInputElement& element : elements_)
@@ -655,15 +680,15 @@ void PasswordAutofillAgent::PasswordValueGatekeeper::Reset() {
void PasswordAutofillAgent::PasswordValueGatekeeper::ShowValue(
blink::WebInputElement* element) {
- if (!element->isNull() && !element->suggestedValue().isEmpty())
- element->setValue(element->suggestedValue(), true);
+ if (!element->IsNull() && !element->SuggestedValue().IsEmpty())
+ element->SetAutofillValue(element->SuggestedValue());
}
bool PasswordAutofillAgent::TextDidChangeInTextField(
const blink::WebInputElement& element) {
// TODO(vabr): Get a mutable argument instead. http://crbug.com/397083
blink::WebInputElement mutable_element = element; // We need a non-const.
- mutable_element.setAutofilled(false);
+ mutable_element.SetAutofilled(false);
WebInputToPasswordInfoMap::iterator iter =
web_input_to_password_info_.find(element);
@@ -680,14 +705,14 @@ void PasswordAutofillAgent::UpdateStateForTextChange(
// TODO(vabr): Get a mutable argument instead. http://crbug.com/397083
blink::WebInputElement mutable_element = element; // We need a non-const.
- if (element.isTextField()) {
- const base::string16 element_value = element.value().utf16();
+ if (element.IsTextField()) {
+ const base::string16 element_value = element.Value().Utf16();
UpdateFieldValueAndPropertiesMaskMap(element, &element_value,
FieldPropertiesFlags::USER_TYPED,
&field_value_and_properties_map_);
}
- blink::WebFrame* const element_frame = element.document().frame();
+ blink::WebFrame* const element_frame = element.GetDocument().GetFrame();
// The element's frame might have been detached in the meantime (see
// http://crbug.com/585363, comments 5 and 6), in which case frame() will
// return null. This was hardly caused by form submission (unless the user
@@ -703,22 +728,23 @@ void PasswordAutofillAgent::UpdateStateForTextChange(
// To honor the user having explicitly cleared the password, even an empty
// password will be saved here.
std::unique_ptr<PasswordForm> password_form;
- if (element.form().isNull()) {
+ if (element.Form().IsNull()) {
password_form = CreatePasswordFormFromUnownedInputElements(
*element_frame, &field_value_and_properties_map_, &form_predictions_);
} else {
password_form = CreatePasswordFormFromWebForm(
- element.form(), &field_value_and_properties_map_, &form_predictions_);
+ element.Form(), &field_value_and_properties_map_, &form_predictions_);
}
- ProvisionallySavePassword(std::move(password_form), RESTRICTION_NONE);
+ ProvisionallySavePassword(std::move(password_form), element.Form(), element,
+ RESTRICTION_NONE);
- if (element.isPasswordField()) {
+ if (element.IsPasswordField()) {
PasswordToLoginMap::iterator iter = password_to_username_.find(element);
if (iter != password_to_username_.end()) {
web_input_to_password_info_[iter->second].password_was_edited_last = true;
// Note that the suggested value of |mutable_element| was reset when its
// value changed.
- mutable_element.setAutofilled(false);
+ mutable_element.SetAutofilled(false);
}
}
}
@@ -728,7 +754,7 @@ bool PasswordAutofillAgent::FillSuggestion(
const base::string16& username,
const base::string16& password) {
// The element in context of the suggestion popup.
- const blink::WebInputElement* element = toWebInputElement(&control_element);
+ const blink::WebInputElement* element = ToWebInputElement(&control_element);
if (!element)
return false;
@@ -743,27 +769,27 @@ bool PasswordAutofillAgent::FillSuggestion(
}
password_info->password_was_edited_last = false;
- if (element->isPasswordField()) {
+ if (element->IsPasswordField()) {
password_info->password_field_suggestion_was_accepted = true;
password_info->password_field = password_element;
- } else if (!username_element.isNull() &&
+ } else if (!username_element.IsNull() &&
IsElementAutocompletable(username_element)) {
- username_element.setValue(blink::WebString::fromUTF16(username), true);
- username_element.setAutofilled(true);
+ username_element.SetAutofillValue(blink::WebString::FromUTF16(username));
+ username_element.SetAutofilled(true);
UpdateFieldValueAndPropertiesMaskMap(username_element, &username,
FieldPropertiesFlags::AUTOFILLED,
&field_value_and_properties_map_);
}
- password_element.setValue(blink::WebString::fromUTF16(password), true);
- password_element.setAutofilled(true);
+ password_element.SetAutofillValue(blink::WebString::FromUTF16(password));
+ password_element.SetAutofilled(true);
UpdateFieldValueAndPropertiesMaskMap(password_element, &password,
FieldPropertiesFlags::AUTOFILLED,
&field_value_and_properties_map_);
blink::WebInputElement mutable_filled_element = *element;
- mutable_filled_element.setSelectionRange(element->value().length(),
- element->value().length());
+ mutable_filled_element.SetSelectionRange(element->Value().length(),
+ element->Value().length());
return true;
}
@@ -773,7 +799,7 @@ bool PasswordAutofillAgent::PreviewSuggestion(
const blink::WebString& username,
const blink::WebString& password) {
// The element in context of the suggestion popup.
- const blink::WebInputElement* element = toWebInputElement(&control_element);
+ const blink::WebInputElement* element = ToWebInputElement(&control_element);
if (!element)
return false;
@@ -787,27 +813,27 @@ bool PasswordAutofillAgent::PreviewSuggestion(
return false;
}
- if (!element->isPasswordField() && !username_element.isNull() &&
+ if (!element->IsPasswordField() && !username_element.IsNull() &&
IsElementAutocompletable(username_element)) {
if (username_query_prefix_.empty())
- username_query_prefix_ = username_element.value().utf16();
+ username_query_prefix_ = username_element.Value().Utf16();
- was_username_autofilled_ = username_element.isAutofilled();
- username_element.setSuggestedValue(username);
- username_element.setAutofilled(true);
- form_util::PreviewSuggestion(username_element.suggestedValue().utf16(),
+ was_username_autofilled_ = username_element.IsAutofilled();
+ username_element.SetSuggestedValue(username);
+ username_element.SetAutofilled(true);
+ form_util::PreviewSuggestion(username_element.SuggestedValue().Utf16(),
username_query_prefix_, &username_element);
}
- was_password_autofilled_ = password_element.isAutofilled();
- password_element.setSuggestedValue(password);
- password_element.setAutofilled(true);
+ was_password_autofilled_ = password_element.IsAutofilled();
+ password_element.SetSuggestedValue(password);
+ password_element.SetAutofilled(true);
return true;
}
bool PasswordAutofillAgent::DidClearAutofillSelection(
const blink::WebFormControlElement& control_element) {
- const blink::WebInputElement* element = toWebInputElement(&control_element);
+ const blink::WebInputElement* element = ToWebInputElement(&control_element);
if (!element)
return false;
@@ -829,9 +855,9 @@ bool PasswordAutofillAgent::FindPasswordInfoForElement(
blink::WebInputElement* password_element,
PasswordInfo** password_info) {
DCHECK(username_element && password_element && password_info);
- username_element->reset();
- password_element->reset();
- if (!element.isPasswordField()) {
+ username_element->Reset();
+ password_element->Reset();
+ if (!element.IsPasswordField()) {
*username_element = element;
} else {
WebInputToPasswordInfoMap::iterator iter =
@@ -865,7 +891,7 @@ bool PasswordAutofillAgent::FindPasswordInfoForElement(
return false;
*password_info = &iter->second;
- if (password_element->isNull())
+ if (password_element->IsNull())
*password_element = (*password_info)->password_field;
return true;
@@ -876,7 +902,7 @@ bool PasswordAutofillAgent::ShouldShowNotSecureWarning(
// Do not show a warning if the feature is disabled or the context is secure.
if (!security_state::IsHttpWarningInFormEnabled() ||
content::IsOriginSecure(
- url::Origin(render_frame()->GetWebFrame()->top()->getSecurityOrigin())
+ url::Origin(render_frame()->GetWebFrame()->Top()->GetSecurityOrigin())
.GetURL()))
return false;
@@ -884,7 +910,7 @@ bool PasswordAutofillAgent::ShouldShowNotSecureWarning(
// Note: A site may use a Password field to collect a CVV or a Credit Card
// number, but showing a slightly misleading warning here is better than
// showing no warning at all.
- if (element.isPasswordField())
+ if (element.IsPasswordField())
return true;
// If a field declares itself a username input, show the warning.
@@ -894,8 +920,8 @@ bool PasswordAutofillAgent::ShouldShowNotSecureWarning(
// Otherwise, analyze the form and return true if this input element seems
// to be the username field.
std::unique_ptr<PasswordForm> password_form;
- if (element.form().isNull()) {
- blink::WebFrame* const element_frame = element.document().frame();
+ if (element.Form().IsNull()) {
+ blink::WebFrame* const element_frame = element.GetDocument().GetFrame();
if (!element_frame)
return false;
@@ -903,12 +929,12 @@ bool PasswordAutofillAgent::ShouldShowNotSecureWarning(
*element_frame, &field_value_and_properties_map_, &form_predictions_);
} else {
password_form = CreatePasswordFormFromWebForm(
- element.form(), &field_value_and_properties_map_, &form_predictions_);
+ element.Form(), &field_value_and_properties_map_, &form_predictions_);
}
if (!password_form)
return false;
- return (password_form->username_element == element.nameForAutofill().utf16());
+ return (password_form->username_element == element.NameForAutofill().Utf16());
}
bool PasswordAutofillAgent::ShowSuggestions(
@@ -932,22 +958,22 @@ bool PasswordAutofillAgent::ShowSuggestions(
// should be shown. However, return |true| to indicate that this is a known
// password form and that the request to show suggestions has been handled (as
// a no-op).
- if (!element.isTextField() || !IsElementAutocompletable(element) ||
+ if (!element.IsTextField() || !IsElementAutocompletable(element) ||
!IsElementAutocompletable(password_element))
return true;
- if (element.nameForAutofill().isEmpty() &&
+ if (element.NameForAutofill().IsEmpty() &&
!DoesFormContainAmbiguousOrEmptyNames(password_info->fill_data)) {
return false; // If the field has no name, then we won't have values.
}
// Don't attempt to autofill with values that are too large.
- if (element.value().length() > kMaximumTextSizeForAutocomplete)
+ if (element.Value().length() > kMaximumTextSizeForAutocomplete)
return false;
// If the element is a password field, do not to show a popup if the user has
// already accepted a password suggestion on another password field.
- if (element.isPasswordField() &&
+ if (element.IsPasswordField() &&
(password_info->password_field_suggestion_was_accepted &&
element != password_info->password_field))
return true;
@@ -964,8 +990,8 @@ bool PasswordAutofillAgent::ShowSuggestions(
// |show_all| is true, check if the element in question is a password element
// for the call to ShowSuggestionPopup.
return ShowSuggestionPopup(*password_info, element,
- show_all && !element.isPasswordField(),
- element.isPasswordField());
+ show_all && !element.IsPasswordField(),
+ element.IsPasswordField());
}
void PasswordAutofillAgent::ShowNotSecureWarning(
@@ -980,7 +1006,7 @@ void PasswordAutofillAgent::ShowNotSecureWarning(
bool PasswordAutofillAgent::OriginCanAccessPasswordManager(
const blink::WebSecurityOrigin& origin) {
- return origin.canAccessPasswordManager();
+ return origin.CanAccessPasswordManager();
}
void PasswordAutofillAgent::OnDynamicFormsSeen() {
@@ -988,31 +1014,33 @@ void PasswordAutofillAgent::OnDynamicFormsSeen() {
}
void PasswordAutofillAgent::AJAXSucceeded() {
- OnSamePageNavigationCompleted();
+ OnSameDocumentNavigationCompleted();
}
-void PasswordAutofillAgent::OnSamePageNavigationCompleted() {
- if (!ProvisionallySavedPasswordIsValid())
+void PasswordAutofillAgent::OnSameDocumentNavigationCompleted() {
+ if (!provisionally_saved_form_.IsPasswordValid())
return;
// Prompt to save only if the form is now gone, either invisible or
// removed from the DOM.
blink::WebFrame* frame = render_frame()->GetWebFrame();
- if (form_util::IsFormVisible(frame, provisionally_saved_form_->action,
- provisionally_saved_form_->origin,
- provisionally_saved_form_->form_data) ||
- IsUnownedPasswordFormVisible(frame, provisionally_saved_form_->action,
- provisionally_saved_form_->origin,
- provisionally_saved_form_->form_data,
- form_predictions_)) {
+ const auto& password_form = provisionally_saved_form_.password_form();
+ if (form_util::IsFormVisible(frame, provisionally_saved_form_.form_element(),
+ password_form.action, password_form.origin,
+ password_form.form_data) ||
+ (provisionally_saved_form_.form_element().IsNull() &&
+ IsUnownedPasswordFormVisible(
+ frame, provisionally_saved_form_.input_element(),
+ password_form.action, password_form.origin, password_form.form_data,
+ form_predictions_))) {
return;
}
- GetPasswordManagerDriver()->InPageNavigation(*provisionally_saved_form_);
- provisionally_saved_form_.reset();
+ GetPasswordManagerDriver()->InPageNavigation(password_form);
+ provisionally_saved_form_.Reset();
}
-void PasswordAutofillAgent::FirstUserGestureObserved() {
+void PasswordAutofillAgent::UserGestureObserved() {
gatekeeper_.OnUserGesture();
}
@@ -1028,10 +1056,10 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) {
blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
// Make sure that this security origin is allowed to use password manager.
- blink::WebSecurityOrigin origin = frame->document().getSecurityOrigin();
+ blink::WebSecurityOrigin origin = frame->GetDocument().GetSecurityOrigin();
if (logger) {
logger->LogURL(Logger::STRING_SECURITY_ORIGIN,
- GURL(origin.toString().utf8()));
+ GURL(origin.ToString().Utf8()));
}
if (!OriginCanAccessPasswordManager(origin)) {
if (logger) {
@@ -1049,7 +1077,7 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) {
}
blink::WebVector<blink::WebFormElement> forms;
- frame->document().forms(forms);
+ frame->GetDocument().Forms(forms);
if (IsShowAutofillSignaturesEnabled())
AnnotateFormsWithSignatures(forms);
@@ -1088,7 +1116,7 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) {
if (only_visible) {
std::vector<blink::WebFormControlElement> control_elements =
form_util::GetUnownedAutofillableFormFieldElements(
- frame->document().all(), nullptr);
+ frame->GetDocument().All(), nullptr);
add_unowned_inputs =
form_util::IsSomeControlElementVisible(control_elements);
if (logger) {
@@ -1109,20 +1137,31 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) {
}
}
- if (password_forms.empty() && !only_visible) {
- // We need to send the PasswordFormsRendered message regardless of whether
- // there are any forms visible, as this is also the code path that triggers
- // showing the infobar.
- return;
- }
-
if (only_visible) {
- blink::WebFrame* main_frame = render_frame()->GetWebFrame()->top();
- bool did_stop_loading = !main_frame || !main_frame->isLoading();
+ // Send the PasswordFormsRendered message regardless of whether
+ // |password_forms| is empty. The empty |password_forms| are a possible
+ // signal to the browser that a pending login attempt succeeded.
+ blink::WebFrame* main_frame = render_frame()->GetWebFrame()->Top();
+ bool did_stop_loading = !main_frame || !main_frame->IsLoading();
GetPasswordManagerDriver()->PasswordFormsRendered(password_forms,
did_stop_loading);
} else {
- GetPasswordManagerDriver()->PasswordFormsParsed(password_forms);
+ // If there is a password field, but the list of password forms is empty for
+ // some reason, add a dummy form to the list. It will cause a request to the
+ // store. Therefore, saved passwords will be available for filling on click.
+ if (!sent_request_to_store_ && password_forms.empty() &&
+ HasPasswordField(*frame)) {
+ // Set everything that |FormDigest| needs.
+ password_forms.push_back(PasswordForm());
+ password_forms.back().scheme = PasswordForm::SCHEME_HTML;
+ password_forms.back().origin =
+ form_util::GetCanonicalOriginForDocument(frame->GetDocument());
+ password_forms.back().signon_realm =
+ GetSignOnRealm(password_forms.back().origin);
+ sent_request_to_store_ = true;
+ }
+ if (!password_forms.empty())
+ GetPasswordManagerDriver()->PasswordFormsParsed(password_forms);
}
}
@@ -1147,9 +1186,10 @@ void PasswordAutofillAgent::WillCommitProvisionalLoad() {
}
void PasswordAutofillAgent::DidCommitProvisionalLoad(
- bool is_new_navigation, bool is_same_page_navigation) {
- if (is_same_page_navigation) {
- OnSamePageNavigationCompleted();
+ bool is_new_navigation,
+ bool is_same_document_navigation) {
+ if (is_same_document_navigation) {
+ OnSameDocumentNavigationCompleted();
}
}
@@ -1157,9 +1197,10 @@ void PasswordAutofillAgent::FrameDetached() {
// If a sub frame has been destroyed while the user was entering information
// into a password form, try to save the data. See https://crbug.com/450806
// for examples of sites that perform login using this technique.
- if (render_frame()->GetWebFrame()->parent() &&
- ProvisionallySavedPasswordIsValid()) {
- GetPasswordManagerDriver()->InPageNavigation(*provisionally_saved_form_);
+ if (render_frame()->GetWebFrame()->Parent() &&
+ provisionally_saved_form_.IsPasswordValid()) {
+ GetPasswordManagerDriver()->InPageNavigation(
+ provisionally_saved_form_.password_form());
}
FrameClosing();
}
@@ -1181,7 +1222,8 @@ void PasswordAutofillAgent::WillSendSubmitEvent(
// already have been updated in TextDidChangeInTextField.
std::unique_ptr<PasswordForm> password_form = CreatePasswordFormFromWebForm(
form, &field_value_and_properties_map_, &form_predictions_);
- ProvisionallySavePassword(std::move(password_form),
+ ProvisionallySavePassword(std::move(password_form), form,
+ blink::WebInputElement(),
RESTRICTION_NON_EMPTY_PASSWORD);
}
@@ -1207,16 +1249,15 @@ void PasswordAutofillAgent::WillSubmitForm(const blink::WebFormElement& form) {
logger->LogPasswordForm(Logger::STRING_CREATED_PASSWORD_FORM,
*submitted_form);
}
- if (provisionally_saved_form_ &&
- submitted_form->action == provisionally_saved_form_->action) {
+ if (provisionally_saved_form_.IsSet() &&
+ submitted_form->action ==
+ provisionally_saved_form_.password_form().action) {
if (logger)
logger->LogMessage(Logger::STRING_SUBMITTED_PASSWORD_REPLACED);
- submitted_form->password_value =
- provisionally_saved_form_->password_value;
- submitted_form->new_password_value =
- provisionally_saved_form_->new_password_value;
- submitted_form->username_value =
- provisionally_saved_form_->username_value;
+ const auto& saved_form = provisionally_saved_form_.password_form();
+ submitted_form->password_value = saved_form.password_value;
+ submitted_form->new_password_value = saved_form.new_password_value;
+ submitted_form->username_value = saved_form.username_value;
}
// Some observers depend on sending this information now instead of when
@@ -1224,7 +1265,7 @@ void PasswordAutofillAgent::WillSubmitForm(const blink::WebFormElement& form) {
// RenderView to be instantiated (such as redirects to the WebStore)
// we will never get to finish the load.
GetPasswordManagerDriver()->PasswordFormSubmitted(*submitted_form);
- provisionally_saved_form_.reset();
+ provisionally_saved_form_.Reset();
} else if (logger) {
logger->LogMessage(Logger::STRING_FORM_IS_NOT_PASSWORD);
}
@@ -1245,7 +1286,7 @@ void PasswordAutofillAgent::DidStartProvisionalLoad(
}
const blink::WebLocalFrame* navigated_frame = render_frame()->GetWebFrame();
- if (navigated_frame->parent()) {
+ if (navigated_frame->Parent()) {
if (logger)
logger->LogMessage(Logger::STRING_FRAME_NOT_MAIN_FRAME);
return;
@@ -1261,23 +1302,23 @@ void PasswordAutofillAgent::DidStartProvisionalLoad(
ui::PageTransition type = navigation_state->GetTransitionType();
if (ui::PageTransitionIsWebTriggerable(type) &&
ui::PageTransitionIsNewNavigation(type) &&
- !blink::WebUserGestureIndicator::isProcessingUserGesture()) {
+ !blink::WebUserGestureIndicator::IsProcessingUserGesture()) {
// If onsubmit has been called, try and save that form.
- if (provisionally_saved_form_) {
+ if (provisionally_saved_form_.IsSet()) {
if (logger) {
logger->LogPasswordForm(
Logger::STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME,
- *provisionally_saved_form_);
+ provisionally_saved_form_.password_form());
}
GetPasswordManagerDriver()->PasswordFormSubmitted(
- *provisionally_saved_form_);
- provisionally_saved_form_.reset();
+ provisionally_saved_form_.password_form());
+ provisionally_saved_form_.Reset();
} else {
std::vector<std::unique_ptr<PasswordForm>> possible_submitted_forms;
// Loop through the forms on the page looking for one that has been
// filled out. If one exists, try and save the credentials.
blink::WebVector<blink::WebFormElement> forms;
- render_frame()->GetWebFrame()->document().forms(forms);
+ render_frame()->GetWebFrame()->GetDocument().Forms(forms);
bool password_forms_found = false;
for (size_t i = 0; i < forms.size(); ++i) {
@@ -1339,9 +1380,9 @@ void PasswordAutofillAgent::FillPasswordForm(
for (auto element : elements) {
blink::WebInputElement username_element =
- !element.isPasswordField() ? element : password_to_username_[element];
+ !element.IsPasswordField() ? element : password_to_username_[element];
blink::WebInputElement password_element =
- element.isPasswordField()
+ element.IsPasswordField()
? element
: web_input_to_password_info_[element].password_field;
FillFormOnPasswordReceived(
@@ -1414,7 +1455,7 @@ void PasswordAutofillAgent::GetFillableElementFromFormData(
}
blink::WebInputElement main_element =
- username_element.isNull() ? password_element : username_element;
+ username_element.IsNull() ? password_element : username_element;
// We might have already filled this form if there are two <form> elements
// with identical markup.
@@ -1427,7 +1468,7 @@ void PasswordAutofillAgent::GetFillableElementFromFormData(
password_info.key = key;
password_info.password_field = password_element;
web_input_to_password_info_[main_element] = password_info;
- if (!main_element.isPasswordField())
+ if (!main_element.IsPasswordField())
password_to_username_[password_element] = username_element;
if (elements)
elements->push_back(main_element);
@@ -1448,13 +1489,13 @@ void PasswordAutofillAgent::GetFillableElementFromFormData(
}
void PasswordAutofillAgent::FocusedNodeHasChanged(const blink::WebNode& node) {
- if (node.isNull() || !node.isElementNode())
+ if (node.IsNull() || !node.IsElementNode())
return;
- const blink::WebElement web_element = node.toConst<blink::WebElement>();
- if (!web_element.isFormControlElement())
+ const blink::WebElement web_element = node.ToConst<blink::WebElement>();
+ if (!web_element.IsFormControlElement())
return;
const blink::WebFormControlElement control_element =
- web_element.toConst<blink::WebFormControlElement>();
+ web_element.ToConst<blink::WebFormControlElement>();
UpdateFieldValueAndPropertiesMaskMap(control_element, nullptr,
FieldPropertiesFlags::HAD_FOCUS,
&field_value_and_properties_map_);
@@ -1475,13 +1516,13 @@ void PasswordAutofillAgent::FindFocusedPasswordForm(
std::unique_ptr<PasswordForm> password_form;
blink::WebElement element =
- render_frame()->GetWebFrame()->document().focusedElement();
- if (!element.isNull() && element.hasHTMLTagName("input")) {
- blink::WebInputElement input = element.to<blink::WebInputElement>();
- if (input.isPasswordField()) {
- if (!input.form().isNull()) {
+ render_frame()->GetWebFrame()->GetDocument().FocusedElement();
+ if (!element.IsNull() && element.HasHTMLTagName("input")) {
+ blink::WebInputElement input = element.To<blink::WebInputElement>();
+ if (input.IsPasswordField()) {
+ if (!input.Form().IsNull()) {
password_form = CreatePasswordFormFromWebForm(
- input.form(), &field_value_and_properties_map_, &form_predictions_);
+ input.Form(), &field_value_and_properties_map_, &form_predictions_);
} else {
password_form = CreatePasswordFormFromUnownedInputElements(
*render_frame()->GetWebFrame(), &field_value_and_properties_map_,
@@ -1489,9 +1530,9 @@ void PasswordAutofillAgent::FindFocusedPasswordForm(
// Only try to use this form if |input| is one of the password elements
// for |password_form|.
if (password_form->password_element !=
- input.nameForAutofill().utf16() &&
+ input.NameForAutofill().Utf16() &&
password_form->new_password_element !=
- input.nameForAutofill().utf16())
+ input.NameForAutofill().Utf16())
password_form.reset();
}
}
@@ -1511,17 +1552,17 @@ bool PasswordAutofillAgent::ShowSuggestionPopup(
const blink::WebInputElement& user_input,
bool show_all,
bool show_on_password_field) {
- DCHECK(!user_input.isNull());
- blink::WebFrame* frame = user_input.document().frame();
+ DCHECK(!user_input.IsNull());
+ blink::WebFrame* frame = user_input.GetDocument().GetFrame();
if (!frame)
return false;
- blink::WebView* webview = frame->view();
+ blink::WebView* webview = frame->View();
if (!webview)
return false;
- if (user_input.isPasswordField() && !user_input.isAutofilled() &&
- !user_input.value().isEmpty()) {
+ if (user_input.IsPasswordField() && !user_input.IsAutofilled() &&
+ !user_input.Value().IsEmpty()) {
GetAutofillDriver()->HidePopup();
return false;
}
@@ -1536,9 +1577,9 @@ bool PasswordAutofillAgent::ShowSuggestionPopup(
if (show_on_password_field)
options |= IS_PASSWORD_FIELD;
- base::string16 username_string(user_input.isPasswordField()
+ base::string16 username_string(user_input.IsPasswordField()
? base::string16()
- : user_input.value().utf16());
+ : user_input.Value().Utf16());
GetPasswordManagerDriver()->ShowPasswordSuggestions(
password_info.key, field.text_direction, username_string, options,
@@ -1552,41 +1593,38 @@ void PasswordAutofillAgent::FrameClosing() {
password_to_username_.erase(iter.second.password_field);
}
web_input_to_password_info_.clear();
- provisionally_saved_form_.reset();
+ provisionally_saved_form_.Reset();
field_value_and_properties_map_.clear();
+ sent_request_to_store_ = false;
}
void PasswordAutofillAgent::ClearPreview(
blink::WebInputElement* username,
blink::WebInputElement* password) {
- if (!username->isNull() && !username->suggestedValue().isEmpty()) {
- username->setSuggestedValue(blink::WebString());
- username->setAutofilled(was_username_autofilled_);
- username->setSelectionRange(username_query_prefix_.length(),
- username->value().length());
+ if (!username->IsNull() && !username->SuggestedValue().IsEmpty()) {
+ username->SetSuggestedValue(blink::WebString());
+ username->SetAutofilled(was_username_autofilled_);
+ username->SetSelectionRange(username_query_prefix_.length(),
+ username->Value().length());
}
- if (!password->suggestedValue().isEmpty()) {
- password->setSuggestedValue(blink::WebString());
- password->setAutofilled(was_password_autofilled_);
+ if (!password->SuggestedValue().IsEmpty()) {
+ password->SetSuggestedValue(blink::WebString());
+ password->SetAutofilled(was_password_autofilled_);
}
}
void PasswordAutofillAgent::ProvisionallySavePassword(
std::unique_ptr<PasswordForm> password_form,
+ const blink::WebFormElement& form,
+ const blink::WebInputElement& input,
ProvisionallySaveRestriction restriction) {
if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD &&
password_form->password_value.empty() &&
password_form->new_password_value.empty())) {
return;
}
- provisionally_saved_form_ = std::move(password_form);
-}
-
-bool PasswordAutofillAgent::ProvisionallySavedPasswordIsValid() {
- return provisionally_saved_form_ &&
- !provisionally_saved_form_->username_value.empty() &&
- !(provisionally_saved_form_->password_value.empty() &&
- provisionally_saved_form_->new_password_value.empty());
+ DCHECK(password_form && (!form.IsNull() || !input.IsNull()));
+ provisionally_saved_form_.Set(std::move(password_form), form, input);
}
const mojom::AutofillDriverPtr& PasswordAutofillAgent::GetAutofillDriver() {
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.h b/chromium/components/autofill/content/renderer/password_autofill_agent.h
index 12b7d03c639..486e8eb34e3 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.h
@@ -14,6 +14,7 @@
#include "components/autofill/content/common/autofill_driver.mojom.h"
#include "components/autofill/content/renderer/autofill_agent.h"
#include "components/autofill/content/renderer/password_form_conversion_utils.h"
+#include "components/autofill/content/renderer/provisionally_saved_password_form.h"
#include "components/autofill/core/common/form_data_predictions.h"
#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/password_form_field_prediction_map.h"
@@ -114,10 +115,10 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
// a form has been submitted by AJAX without navigation.
void AJAXSucceeded();
- // Called when the user first interacts with the page after a load. This is a
+ // Called when the user interacts with the page after a load. This is a
// signal to make autofilled values of password input elements accessible to
// JavaScript.
- void FirstUserGestureObserved();
+ void UserGestureObserved();
// Given password form data |form_data| and a supplied key |key| for
// referencing the password info, returns a set of WebInputElements in
@@ -199,7 +200,7 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
void DidStartProvisionalLoad(blink::WebDataSource* data_source) override;
void WillCommitProvisionalLoad() override;
void DidCommitProvisionalLoad(bool is_new_navigation,
- bool is_same_page_navigation) override;
+ bool is_same_document_navigation) override;
void WillSendSubmitEvent(const blink::WebFormElement& form) override;
void WillSubmitForm(const blink::WebFormElement& form) override;
void OnDestruct() override;
@@ -239,17 +240,19 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
void ClearPreview(blink::WebInputElement* username,
blink::WebInputElement* password);
- // Saves |password_form| in |provisionally_saved_form_|, as long as it
- // satisfies |restriction|.
+ // Saves |password_form|, |form| and |input| in |provisionally_saved_form_|,
+ // as long as it satisfies |restriction|. |form| and |input| are the elements
+ // user has just been interacting with before the form save. |form| or |input|
+ // can be null but not both at the same time. For example: if the form is
+ // unowned, |form| will be null; if the user has submitted the form, |input|
+ // will be null.
void ProvisionallySavePassword(std::unique_ptr<PasswordForm> password_form,
+ const blink::WebFormElement& form,
+ const blink::WebInputElement& input,
ProvisionallySaveRestriction restriction);
- // Returns true if |provisionally_saved_form_| has enough information that
- // it is likely filled out.
- bool ProvisionallySavedPasswordIsValid();
-
- // Helper function called when in-page navigation completed
- void OnSamePageNavigationCompleted();
+ // Helper function called when same-document navigation completed
+ void OnSameDocumentNavigationCompleted();
const mojom::AutofillDriverPtr& GetAutofillDriver();
@@ -260,7 +263,7 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
// Set if the user might be submitting a password form on the current page,
// but the submit may still fail (i.e. doesn't pass JavaScript validation).
- std::unique_ptr<PasswordForm> provisionally_saved_form_;
+ ProvisionallySavedPasswordForm provisionally_saved_form_;
// Map WebFormControlElement to the pair of:
// 1) The most recent text that user typed or PasswordManager autofilled in
@@ -280,6 +283,9 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
// True indicates that the password field was autofilled, false otherwise.
bool was_password_autofilled_;
+ // True indicates that a request for credentials has been sent to the store.
+ bool sent_request_to_store_;
+
// Records the username typed before suggestions preview.
base::string16 username_query_prefix_;
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 3aa8e5b3da2..aed99de7057 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -15,6 +15,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
+#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/content/renderer/form_autofill_util.h"
@@ -93,6 +94,7 @@ const char kLoginAndSignupRegex[] =
const char kAutocompleteUsername[] = "username";
const char kAutocompleteCurrentPassword[] = "current-password";
const char kAutocompleteNewPassword[] = "new-password";
+const char kAutocompleteCreditCardPrefix[] = "cc-";
re2::RE2* CreateMatcher(void* instance, const char* pattern) {
re2::RE2::Options options;
@@ -105,7 +107,7 @@ re2::RE2* CreateMatcher(void* instance, const char* pattern) {
}
struct LoginAndSignupLazyInstanceTraits
- : public base::DefaultLazyInstanceTraits<re2::RE2> {
+ : public base::internal::DestructorAtExitLazyInstanceTraits<re2::RE2> {
static re2::RE2* New(void* instance) {
return CreateMatcher(instance, kLoginAndSignupRegex);
}
@@ -134,22 +136,22 @@ void PopulateSyntheticFormFromWebForm(const WebFormElement& web_form,
// test frame origin to match GAIA login page. Once this code gets moved to
// browser, we need to add tests for this as well.
blink::WebVector<blink::WebFormControlElement> web_control_elements;
- web_form.getFormControlElements(web_control_elements);
+ web_form.GetFormControlElements(web_control_elements);
synthetic_form->control_elements.assign(web_control_elements.begin(),
web_control_elements.end());
- synthetic_form->action = web_form.action();
- synthetic_form->document = web_form.document();
+ synthetic_form->action = web_form.Action();
+ synthetic_form->document = web_form.GetDocument();
}
-// Helper function that removes |username_element.value()| from the vector
+// Helper function that removes |possible_username_pair| from the vector
// |other_possible_usernames|, if the value presents in the vector.
void ExcludeUsernameFromOtherUsernamesList(
- const WebInputElement& username_element,
- std::vector<base::string16>* other_possible_usernames) {
- other_possible_usernames->erase(std::remove(other_possible_usernames->begin(),
- other_possible_usernames->end(),
- username_element.value().utf16()),
- other_possible_usernames->end());
+ const PossibleUsernamePair& possible_username_pair,
+ PossibleUsernamesVector* other_possible_usernames) {
+ other_possible_usernames->erase(
+ std::remove(other_possible_usernames->begin(),
+ other_possible_usernames->end(), possible_username_pair),
+ other_possible_usernames->end());
}
// Helper to determine which password is the main (current) one, and which is
@@ -160,22 +162,22 @@ bool LocateSpecificPasswords(std::vector<WebInputElement> passwords,
WebInputElement* current_password,
WebInputElement* new_password,
WebInputElement* confirmation_password) {
- DCHECK(current_password && current_password->isNull());
- DCHECK(new_password && new_password->isNull());
- DCHECK(confirmation_password && confirmation_password->isNull());
+ DCHECK(current_password && current_password->IsNull());
+ DCHECK(new_password && new_password->IsNull());
+ DCHECK(confirmation_password && confirmation_password->IsNull());
// First, look for elements marked with either autocomplete='current-password'
// or 'new-password' -- if we find any, take the hint, and treat the first of
// each kind as the element we are looking for.
for (const WebInputElement& it : passwords) {
if (HasAutocompleteAttributeValue(it, kAutocompleteCurrentPassword) &&
- current_password->isNull()) {
+ current_password->IsNull()) {
*current_password = it;
} else if (HasAutocompleteAttributeValue(it, kAutocompleteNewPassword) &&
- new_password->isNull()) {
+ new_password->IsNull()) {
*new_password = it;
- } else if (!new_password->isNull() &&
- (new_password->value() == it.value())) {
+ } else if (!new_password->IsNull() &&
+ (new_password->Value() == it.Value())) {
*confirmation_password = it;
}
}
@@ -185,7 +187,7 @@ bool LocateSpecificPasswords(std::vector<WebInputElement> passwords,
// rest of the password fields unmarked. Perhaps they are used for other
// purposes, e.g., PINs, OTPs, and the like. So we skip all the heuristics we
// normally do, and ignore the rest of the password fields.
- if (!current_password->isNull() || !new_password->isNull())
+ if (!current_password->IsNull() || !new_password->IsNull())
return true;
if (passwords.empty())
@@ -197,8 +199,8 @@ bool LocateSpecificPasswords(std::vector<WebInputElement> passwords,
*current_password = passwords[0];
break;
case 2:
- if (!passwords[0].value().isEmpty() &&
- passwords[0].value() == passwords[1].value()) {
+ if (!passwords[0].Value().IsEmpty() &&
+ passwords[0].Value() == passwords[1].Value()) {
// Two identical non-empty passwords: assume we are seeing a new
// password with a confirmation. This can be either a sign-up form or a
// password change form that does not ask for the old password.
@@ -214,19 +216,19 @@ bool LocateSpecificPasswords(std::vector<WebInputElement> passwords,
}
break;
default:
- if (!passwords[0].value().isEmpty() &&
- passwords[0].value() == passwords[1].value() &&
- passwords[0].value() == passwords[2].value()) {
+ if (!passwords[0].Value().IsEmpty() &&
+ passwords[0].Value() == passwords[1].Value() &&
+ passwords[0].Value() == passwords[2].Value()) {
// All three passwords are the same and non-empty? This does not make
// any sense, give up.
return false;
- } else if (passwords[1].value() == passwords[2].value()) {
+ } else if (passwords[1].Value() == passwords[2].Value()) {
// New password is the duplicated one, and comes second; or empty form
// with 3 password fields, in which case we will assume this layout.
*current_password = passwords[0];
*new_password = passwords[1];
*confirmation_password = passwords[2];
- } else if (passwords[0].value() == passwords[1].value()) {
+ } else if (passwords[0].Value() == passwords[1].Value()) {
// It is strange that the new password comes first, but trust more which
// fields are duplicated than the ordering of fields. Assume that
// any password fields after the new password contain sensitive
@@ -287,9 +289,9 @@ void FindPredictedElements(
const FormFieldData& target_field = prediction.first;
const PasswordFormFieldPredictionType& type = prediction.second;
for (const auto& control_element : autofillable_elements) {
- if (control_element.nameForAutofill().utf16() == target_field.name) {
+ if (control_element.NameForAutofill().Utf16() == target_field.name) {
const WebInputElement* input_element =
- toWebInputElement(&control_element);
+ ToWebInputElement(&control_element);
// TODO(sebsg): Investigate why this guard is necessary, see
// https://crbug.com/517490 for more details.
@@ -308,7 +310,7 @@ const char kPasswordSiteUrlRegex[] =
"passwords(?:-[a-z-]+\\.corp)?\\.google\\.com";
struct PasswordSiteUrlLazyInstanceTraits
- : public base::DefaultLazyInstanceTraits<re2::RE2> {
+ : public base::internal::DestructorAtExitLazyInstanceTraits<re2::RE2> {
static re2::RE2* New(void* instance) {
return CreateMatcher(instance, kPasswordSiteUrlRegex);
}
@@ -320,7 +322,7 @@ base::LazyInstance<re2::RE2, PasswordSiteUrlLazyInstanceTraits>
// Returns the |input_field| name if its non-empty; otherwise a |dummy_name|.
base::string16 FieldName(const WebInputElement& input_field,
const char dummy_name[]) {
- base::string16 field_name = input_field.nameForAutofill().utf16();
+ base::string16 field_name = input_field.NameForAutofill().Utf16();
return field_name.empty() ? base::ASCIIToUTF16(dummy_name) : field_name;
}
@@ -349,15 +351,15 @@ void FoundVisiblePasswordAndVisibleUsernameBeforePassword(
bool found_visible_username = false;
for (auto& control_element : form.control_elements) {
- const WebInputElement* input_element = toWebInputElement(&control_element);
- if (!input_element || !input_element->isEnabled() ||
- !input_element->isTextField())
+ const WebInputElement* input_element = ToWebInputElement(&control_element);
+ if (!input_element || !input_element->IsEnabled() ||
+ !input_element->IsTextField())
continue;
- if (!form_util::IsWebNodeVisible(*input_element))
+ if (!form_util::IsWebElementVisible(*input_element))
continue;
- if (input_element->isPasswordField()) {
+ if (input_element->IsPasswordField()) {
*found_visible_password = true;
*found_visible_username_before_visible_password = found_visible_username;
break;
@@ -367,6 +369,12 @@ void FoundVisiblePasswordAndVisibleUsernameBeforePassword(
}
}
+autofill::PossibleUsernamePair MakePossibleUsernamePair(
+ const blink::WebInputElement& input) {
+ return autofill::PossibleUsernamePair(input.Value().Utf16(),
+ input.NameForAutofill().Utf16());
+}
+
// Get information about a login form encapsulated in a PasswordForm struct.
// If an element of |form| has an entry in |nonscript_modified_values|, the
// associated string is used instead of the element's value to create
@@ -382,13 +390,13 @@ bool GetPasswordForm(
std::vector<WebInputElement> passwords;
std::map<blink::WebInputElement, blink::WebInputElement>
last_text_input_before_password;
- std::vector<base::string16> other_possible_usernames;
+ autofill::PossibleUsernamesVector other_possible_usernames;
// Bail if this is a GAIA passwords site reauthentication form, so that
// the form will be ignored.
// TODO(msramek): Move this logic to the browser, and disable filling only
// for the sync credential and if passwords are being synced.
- if (IsGaiaReauthenticationForm(GURL(form.document.url()).GetOrigin(),
+ if (IsGaiaReauthenticationForm(GURL(form.document.Url()).GetOrigin(),
form.control_elements)) {
return false;
}
@@ -415,13 +423,16 @@ bool GetPasswordForm(
for (size_t i = 0; i < form.control_elements.size(); ++i) {
WebFormControlElement control_element = form.control_elements[i];
- WebInputElement* input_element = toWebInputElement(&control_element);
- if (!input_element || !input_element->isEnabled())
+ WebInputElement* input_element = ToWebInputElement(&control_element);
+ if (!input_element || !input_element->IsEnabled())
continue;
- bool element_is_invisible = !form_util::IsWebNodeVisible(*input_element);
- if (input_element->isTextField()) {
- if (input_element->isPasswordField()) {
+ if (HasCreditCardAutocompleteAttributes(*input_element))
+ continue;
+
+ bool element_is_invisible = !form_util::IsWebElementVisible(*input_element);
+ if (input_element->IsTextField()) {
+ if (input_element->IsPasswordField()) {
if (element_is_invisible && ignore_invisible_passwords)
continue;
layout_sequence.push_back('P');
@@ -446,8 +457,8 @@ bool GetPasswordForm(
// passwords for now. Continue processing in case when the password field
// was made readonly by JavaScript before submission. We can do this by
// checking whether password element was updated not from JavaScript.
- if (input_element->isPasswordField() &&
- (!input_element->isReadOnly() ||
+ if (input_element->IsPasswordField() &&
+ (!input_element->IsReadOnly() ||
FieldHasNonscriptModifiedValue(field_value_and_properties_map,
*input_element) ||
password_marked_by_autocomplete_attribute)) {
@@ -469,7 +480,7 @@ bool GetPasswordForm(
}
// Various input types such as text, url, email can be a username field.
- if (input_element->isTextField() && !input_element->isPasswordField()) {
+ if (input_element->IsTextField() && !input_element->IsPasswordField()) {
if (HasAutocompleteAttributeValue(*input_element,
kAutocompleteUsername)) {
if (password_form->username_marked_by_site) {
@@ -481,8 +492,9 @@ bool GetPasswordForm(
// unlike username_element, other_possible_usernames is used only for
// autofill, not for form identification, and blank autofill entries
// are not useful, so we do not collect empty strings.
- if (!input_element->value().isEmpty())
- other_possible_usernames.push_back(input_element->value().utf16());
+ if (!input_element->Value().IsEmpty())
+ other_possible_usernames.push_back(
+ MakePossibleUsernamePair(*input_element));
} else {
// The first element marked with autocomplete='username'. Take the
// hint and treat it as the username (overruling the tentative choice
@@ -503,10 +515,11 @@ bool GetPasswordForm(
// then remember this element for the case when the next field turns
// out to be a password. Save a non-empty username as a possible
// alternative, at least for now.
- if (username_element.isNull())
+ if (username_element.IsNull())
latest_input_element = *input_element;
- if (!input_element->value().isEmpty())
- other_possible_usernames.push_back(input_element->value().utf16());
+ if (!input_element->Value().IsEmpty())
+ other_possible_usernames.push_back(
+ MakePossibleUsernamePair(*input_element));
}
}
}
@@ -520,14 +533,15 @@ bool GetPasswordForm(
return false;
DCHECK_EQ(passwords.size(), last_text_input_before_password.size());
- if (username_element.isNull()) {
- if (!password.isNull())
+ if (username_element.IsNull()) {
+ if (!password.IsNull())
username_element = last_text_input_before_password[password];
- if (username_element.isNull() && !new_password.isNull())
+ if (username_element.IsNull() && !new_password.IsNull())
username_element = last_text_input_before_password[new_password];
- if (!username_element.isNull())
- ExcludeUsernameFromOtherUsernamesList(username_element,
- &other_possible_usernames);
+ if (!username_element.IsNull())
+ ExcludeUsernameFromOtherUsernamesList(
+ MakePossibleUsernamePair(username_element),
+ &other_possible_usernames);
}
password_form->layout = SequenceToLayout(layout_sequence);
@@ -542,19 +556,21 @@ bool GetPasswordForm(
if (map_has_username_prediction &&
(username_element_iterator == predicted_elements.end() ||
username_element_iterator->second != PREDICTION_USERNAME)) {
- ExcludeUsernameFromOtherUsernamesList(predicted_username_element,
- &other_possible_usernames);
- if (!username_element.isNull()) {
- other_possible_usernames.push_back(username_element.value().utf16());
+ ExcludeUsernameFromOtherUsernamesList(
+ MakePossibleUsernamePair(predicted_username_element),
+ &other_possible_usernames);
+ if (!username_element.IsNull()) {
+ other_possible_usernames.push_back(
+ MakePossibleUsernamePair(username_element));
}
username_element = predicted_username_element;
password_form->was_parsed_using_autofill_predictions = true;
}
- if (!username_element.isNull()) {
+ if (!username_element.IsNull()) {
password_form->username_element =
FieldName(username_element, "anonymous_username");
- base::string16 username_value = username_element.value().utf16();
+ base::string16 username_value = username_element.Value().Utf16();
if (FieldHasNonscriptModifiedValue(field_value_and_properties_map,
username_element)) {
base::string16 typed_username_value =
@@ -573,36 +589,33 @@ bool GetPasswordForm(
password_form->origin =
form_util::GetCanonicalOriginForDocument(form.document);
- GURL::Replacements rep;
- rep.SetPathStr("");
- password_form->signon_realm =
- password_form->origin.ReplaceComponents(rep).spec();
+ password_form->signon_realm = GetSignOnRealm(password_form->origin);
password_form->other_possible_usernames.swap(other_possible_usernames);
- if (!password.isNull()) {
+ if (!password.IsNull()) {
password_form->password_element = FieldName(password, "anonymous_password");
- blink::WebString password_value = password.value();
+ blink::WebString password_value = password.Value();
if (FieldHasNonscriptModifiedValue(field_value_and_properties_map,
password))
- password_value = blink::WebString::fromUTF16(
+ password_value = blink::WebString::FromUTF16(
*field_value_and_properties_map->at(password).first);
- password_form->password_value = password_value.utf16();
+ password_form->password_value = password_value.Utf16();
}
- if (!new_password.isNull()) {
+ if (!new_password.IsNull()) {
password_form->new_password_element =
FieldName(new_password, "anonymous_new_password");
- password_form->new_password_value = new_password.value().utf16();
+ password_form->new_password_value = new_password.Value().Utf16();
password_form->new_password_value_is_default =
- new_password.getAttribute("value") == new_password.value();
+ new_password.GetAttribute("value") == new_password.Value();
if (HasAutocompleteAttributeValue(new_password, kAutocompleteNewPassword))
password_form->new_password_marked_by_site = true;
- if (!confirmation_password.isNull()) {
+ if (!confirmation_password.IsNull()) {
password_form->confirmation_password_element =
FieldName(confirmation_password, "anonymous_confirmation_password");
}
}
- if (username_element.isNull()) {
+ if (username_element.IsNull()) {
// To get a better idea on how password forms without a username field
// look like, report the total number of text and password fields.
UMA_HISTOGRAM_COUNTS_100(
@@ -645,18 +658,18 @@ bool IsGaiaReauthenticationForm(
// We're only interested in the presence
// of <input type="hidden" /> elements.
CR_DEFINE_STATIC_LOCAL(WebString, kHidden, ("hidden"));
- const blink::WebInputElement* input = blink::toWebInputElement(&element);
- if (!input || input->formControlType() != kHidden)
+ const blink::WebInputElement* input = blink::ToWebInputElement(&element);
+ if (!input || input->FormControlType() != kHidden)
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;
}
@@ -669,7 +682,7 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromWebForm(
const WebFormElement& web_form,
const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
const FormsPredictionsMap* form_predictions) {
- if (web_form.isNull())
+ if (web_form.IsNull())
return std::unique_ptr<PasswordForm>();
std::unique_ptr<PasswordForm> password_form(new PasswordForm());
@@ -680,10 +693,11 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromWebForm(
SyntheticForm synthetic_form;
PopulateSyntheticFormFromWebForm(web_form, &synthetic_form);
- WebFormElementToFormData(web_form, blink::WebFormControlElement(),
- field_value_and_properties_map,
- form_util::EXTRACT_NONE, &password_form->form_data,
- NULL /* FormFieldData */);
+ if (!WebFormElementToFormData(
+ web_form, blink::WebFormControlElement(),
+ field_value_and_properties_map, form_util::EXTRACT_NONE,
+ &password_form->form_data, NULL /* FormFieldData */))
+ return std::unique_ptr<PasswordForm>();
if (!GetPasswordForm(synthetic_form, password_form.get(),
field_value_and_properties_map, form_predictions))
@@ -698,17 +712,19 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromUnownedInputElements(
const FormsPredictionsMap* form_predictions) {
SyntheticForm synthetic_form;
synthetic_form.control_elements = form_util::GetUnownedFormFieldElements(
- frame.document().all(), &synthetic_form.fieldsets);
- synthetic_form.document = frame.document();
+ frame.GetDocument().All(), &synthetic_form.fieldsets);
+ synthetic_form.document = frame.GetDocument();
if (synthetic_form.control_elements.empty())
return std::unique_ptr<PasswordForm>();
std::unique_ptr<PasswordForm> password_form(new PasswordForm());
- UnownedPasswordFormElementsAndFieldSetsToFormData(
- synthetic_form.fieldsets, synthetic_form.control_elements, nullptr,
- frame.document(), field_value_and_properties_map, form_util::EXTRACT_NONE,
- &password_form->form_data, nullptr /* FormFieldData */);
+ if (!UnownedPasswordFormElementsAndFieldSetsToFormData(
+ synthetic_form.fieldsets, synthetic_form.control_elements, nullptr,
+ frame.GetDocument(), field_value_and_properties_map,
+ form_util::EXTRACT_NONE, &password_form->form_data,
+ nullptr /* FormFieldData */))
+ return std::unique_ptr<PasswordForm>();
if (!GetPasswordForm(synthetic_form, password_form.get(),
field_value_and_properties_map, form_predictions))
return std::unique_ptr<PasswordForm>();
@@ -721,12 +737,35 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromUnownedInputElements(
bool HasAutocompleteAttributeValue(const blink::WebInputElement& element,
const char* value_in_lowercase) {
- base::string16 autocomplete_attribute(
- element.getAttribute("autocomplete").utf16());
- std::vector<std::string> tokens = LowercaseAndTokenizeAttributeString(
- base::UTF16ToUTF8(autocomplete_attribute));
+ std::string autocomplete_value_lowercase = base::ToLowerASCII(
+ base::UTF16ToUTF8(element.GetAttribute("autocomplete").Utf16()));
+
+ std::vector<base::StringPiece> tokens = base::SplitStringPiece(
+ autocomplete_value_lowercase, base::kWhitespaceASCII,
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
return base::ContainsValue(tokens, value_in_lowercase);
}
+bool HasCreditCardAutocompleteAttributes(
+ const blink::WebInputElement& element) {
+ std::string autocomplete_value_lowercase = base::ToLowerASCII(
+ base::UTF16ToUTF8(element.GetAttribute("autocomplete").Utf16()));
+
+ for (const auto& token : base::SplitStringPiece(
+ autocomplete_value_lowercase, base::kWhitespaceASCII,
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
+ if (base::StartsWith(token, kAutocompleteCreditCardPrefix,
+ base::CompareCase::SENSITIVE)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::string GetSignOnRealm(const GURL& origin) {
+ GURL::Replacements rep;
+ rep.SetPathStr("");
+ return origin.ReplaceComponents(rep).spec();
+}
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils.h b/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
index 4c8cd645e46..8029c16cb96 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
@@ -64,6 +64,13 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromUnownedInputElements(
bool HasAutocompleteAttributeValue(const blink::WebInputElement& element,
const char* value_in_lowercase);
+// Checks in a case-insensitive way if credit card autocomplete attributes for
+// the given |element| are present.
+bool HasCreditCardAutocompleteAttributes(const blink::WebInputElement& element);
+
+// The "Realm" for the sign-on. This is scheme, host, port.
+std::string GetSignOnRealm(const GURL& origin);
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CONTENT_RENDERER_PASSWORD_FORM_CONVERSION_UTILS_H__
diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc b/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
index ead27968a84..2d3ceda9320 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
@@ -103,9 +103,6 @@ class PasswordFormBuilder {
// Append a text field with "display: none".
void AddNonDisplayedTextField(const char* name_and_id,
const char* value) {
- // TODO(crbug.com/570628): Add tests with style="visibility: hidden;" too
- // when IsWebNodeVisible in form_autofill_util.cc has changed according to
- // esprehn's TODO in the function. Now tests with visibility attribute fail.
base::StringAppendF(
&html_,
"<INPUT type=\"text\" name=\"%s\" id=\"%s\" value=\"%s\""
@@ -123,6 +120,24 @@ class PasswordFormBuilder {
name_and_id, name_and_id, value);
}
+ // Append a text field with "visibility: hidden".
+ void AddNonVisibleTextField(const char* name_and_id, const char* value) {
+ base::StringAppendF(
+ &html_,
+ "<INPUT type=\"text\" name=\"%s\" id=\"%s\" value=\"%s\""
+ "style=\"visibility: hidden;\"/>",
+ name_and_id, name_and_id, value);
+ }
+
+ // Append a password field with "visibility: hidden".
+ void AddNonVisiblePasswordField(const char* name_and_id, const char* value) {
+ base::StringAppendF(
+ &html_,
+ "<INPUT type=\"password\" name=\"%s\" id=\"%s\" value=\"%s\""
+ "style=\"visibility: hidden;\"/>",
+ name_and_id, name_and_id, value);
+ }
+
// Appends a new submit-type field at the end of the form with the specified
// |name|.
void AddSubmitButton(const char* name) {
@@ -179,14 +194,14 @@ class MAYBE_PasswordFormConversionUtilsTest : public content::RenderViewTest {
LoadWebFormFromHTML(html, &form);
WebVector<WebFormControlElement> control_elements;
- form.getFormControlElements(control_elements);
+ form.GetFormControlElements(control_elements);
FieldValueAndPropertiesMaskMap user_input;
for (size_t i = 0; i < control_elements.size(); ++i) {
- WebInputElement* input_element = toWebInputElement(&control_elements[i]);
- if (input_element->hasAttribute("set-activated-submit"))
- input_element->setActivatedSubmit(true);
+ WebInputElement* input_element = ToWebInputElement(&control_elements[i]);
+ if (input_element->HasAttribute("set-activated-submit"))
+ input_element->SetActivatedSubmit(true);
if (with_user_input) {
- const base::string16 element_value = input_element->value().utf16();
+ const base::string16 element_value = input_element->Value().Utf16();
user_input[control_elements[i]] =
std::make_pair(base::MakeUnique<base::string16>(element_value), 0U);
}
@@ -231,7 +246,7 @@ class MAYBE_PasswordFormConversionUtilsTest : public content::RenderViewTest {
ASSERT_NE(nullptr, frame);
WebVector<WebFormElement> forms;
- frame->document().forms(forms);
+ frame->GetDocument().Forms(forms);
ASSERT_EQ(1U, forms.size());
*form = forms[0];
@@ -298,7 +313,10 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IdentifyingUsernameFields) {
// When no elements are marked with autocomplete='username', the text-type
// input field before the first password element should get selected as
// the username, and the rest should be marked as alternatives.
- {{nullptr, nullptr, nullptr}, "username2", "William", "John+Smith"},
+ {{nullptr, nullptr, nullptr},
+ "username2",
+ "William",
+ "John+username1, Smith+username3"},
// When a sole element is marked with autocomplete='username', it should
// be treated as the username for sure, with no other_possible_usernames.
{{"username", nullptr, nullptr}, "username1", "John", ""},
@@ -306,21 +324,36 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IdentifyingUsernameFields) {
{{nullptr, nullptr, "username"}, "username3", "Smith", ""},
// When >=2 elements have the attribute, the first should be selected as
// the username, and the rest should go to other_possible_usernames.
- {{"username", "username", nullptr}, "username1", "John", "William"},
- {{nullptr, "username", "username"}, "username2", "William", "Smith"},
- {{"username", nullptr, "username"}, "username1", "John", "Smith"},
+ {{"username", "username", nullptr},
+ "username1",
+ "John",
+ "William+username2"},
+ {{nullptr, "username", "username"},
+ "username2",
+ "William",
+ "Smith+username3"},
+ {{"username", nullptr, "username"},
+ "username1",
+ "John",
+ "Smith+username3"},
{{"username", "username", "username"},
"username1",
"John",
- "William+Smith"},
+ "William+username2, Smith+username3"},
// When there is an empty autocomplete attribute (i.e. autocomplete=""),
// it should have the same effect as having no attribute whatsoever.
- {{"", "", ""}, "username2", "William", "John+Smith"},
+ {{"", "", ""}, "username2", "William", "John+username1, Smith+username3"},
{{"", "", "username"}, "username3", "Smith", ""},
- {{"username", "", "username"}, "username1", "John", "Smith"},
+ {{"username", "", "username"}, "username1", "John", "Smith+username3"},
// It should not matter if attribute values are upper or mixed case.
- {{"USERNAME", nullptr, "uSeRNaMe"}, "username1", "John", "Smith"},
- {{"uSeRNaMe", nullptr, "USERNAME"}, "username1", "John", "Smith"}};
+ {{"USERNAME", nullptr, "uSeRNaMe"},
+ "username1",
+ "John",
+ "Smith+username3"},
+ {{"uSeRNaMe", nullptr, "USERNAME"},
+ "username1",
+ "John",
+ "Smith+username3"}};
for (size_t i = 0; i < arraysize(cases); ++i) {
for (size_t nonempty_username_fields = 0; nonempty_username_fields < 2;
@@ -360,8 +393,8 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IdentifyingUsernameFields) {
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_value),
password_form->username_value);
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_other_possible_usernames),
- base::JoinString(password_form->other_possible_usernames,
- base::ASCIIToUTF16("+")));
+ OtherPossibleUsernamesToString(
+ password_form->other_possible_usernames));
} else {
EXPECT_TRUE(password_form->username_value.empty());
EXPECT_TRUE(password_form->other_possible_usernames.empty());
@@ -427,8 +460,10 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IdentifyingTwoPasswordFields) {
// Do a basic sanity check that we are still selecting the right username.
EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element);
EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value);
- EXPECT_THAT(password_form->other_possible_usernames,
- testing::ElementsAre(base::UTF8ToUTF16("Smith")));
+ EXPECT_THAT(
+ password_form->other_possible_usernames,
+ testing::ElementsAre(PossibleUsernamePair(
+ base::UTF8ToUTF16("Smith"), base::UTF8ToUTF16("username2"))));
}
}
@@ -496,8 +531,10 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IdentifyingThreePasswordFields) {
// Do a basic sanity check that we are still selecting the right username.
EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element);
EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value);
- EXPECT_THAT(password_form->other_possible_usernames,
- testing::ElementsAre(base::UTF8ToUTF16("Smith")));
+ EXPECT_THAT(
+ password_form->other_possible_usernames,
+ testing::ElementsAre(PossibleUsernamePair(
+ base::UTF8ToUTF16("Smith"), base::UTF8ToUTF16("username2"))));
}
}
@@ -848,11 +885,15 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest,
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_value),
password_form->username_value);
if (strcmp(cases[i].expected_username_value, "William") == 0) {
- EXPECT_THAT(password_form->other_possible_usernames,
- testing::ElementsAre(base::UTF8ToUTF16("Smith")));
+ EXPECT_THAT(
+ password_form->other_possible_usernames,
+ testing::ElementsAre(PossibleUsernamePair(
+ base::UTF8ToUTF16("Smith"), base::UTF8ToUTF16("username2"))));
} else {
- EXPECT_THAT(password_form->other_possible_usernames,
- testing::ElementsAre(base::UTF8ToUTF16("William")));
+ EXPECT_THAT(
+ password_form->other_possible_usernames,
+ testing::ElementsAre(PossibleUsernamePair(
+ base::UTF8ToUTF16("William"), base::UTF8ToUTF16("username1"))));
}
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element),
password_form->password_element);
@@ -867,12 +908,14 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest,
}
}
-TEST_F(MAYBE_PasswordFormConversionUtilsTest, IgnoreNonDisplayedTextFields) {
+TEST_F(MAYBE_PasswordFormConversionUtilsTest, IgnoreInvisibledTextFields) {
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddNonDisplayedTextField("nondisplayed1", "nodispalyed_value1");
+ builder.AddNonVisibleTextField("nonvisible1", "nonvisible_value1");
builder.AddTextField("username", "johnsmith", nullptr);
builder.AddNonDisplayedTextField("nondisplayed2", "nodispalyed_value2");
+ builder.AddNonVisiblePasswordField("nonvisible2", "nonvisible_value2");
builder.AddPasswordField("password", "secret", nullptr);
builder.AddPasswordField("password", "secret", nullptr);
builder.AddSubmitButton("submit");
@@ -888,12 +931,16 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IgnoreNonDisplayedTextFields) {
EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->new_password_value);
}
-TEST_F(MAYBE_PasswordFormConversionUtilsTest, IgnoreNonDisplayedLoginPairs) {
+TEST_F(MAYBE_PasswordFormConversionUtilsTest, IgnoreInvisiblLoginPairs) {
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddNonDisplayedTextField("nondisplayed1", "nodispalyed_value1");
builder.AddNonDisplayedPasswordField("nondisplayed2", "nodispalyed_value2");
+ builder.AddNonVisibleTextField("nonvisible1", "nonvisible_value1");
+ builder.AddNonVisiblePasswordField("nonvisible2", "nonvisible_value2");
builder.AddTextField("username", "johnsmith", nullptr);
+ builder.AddNonVisibleTextField("nonvisible3", "nonvisible_value3");
+ builder.AddNonVisiblePasswordField("nonvisible4", "nonvisible_value4");
builder.AddNonDisplayedTextField("nondisplayed3", "nodispalyed_value3");
builder.AddNonDisplayedPasswordField("nondisplayed4", "nodispalyed_value4");
builder.AddPasswordField("password", "secret", nullptr);
@@ -932,6 +979,23 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyNonDisplayedLoginPair) {
password_form->password_value);
}
+TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyNonVisibleLoginPair) {
+ PasswordFormBuilder builder(kTestFormActionURL);
+
+ builder.AddNonVisibleTextField("username", "William");
+ builder.AddNonVisiblePasswordField("password", "secret");
+ builder.AddSubmitButton("submit");
+ std::string html = builder.ProduceHTML();
+
+ std::unique_ptr<PasswordForm> password_form =
+ LoadHTMLAndConvertForm(html, nullptr, false);
+ ASSERT_TRUE(password_form);
+ EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element);
+ EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value);
+ EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element);
+ EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
+}
+
TEST_F(MAYBE_PasswordFormConversionUtilsTest,
VisiblePasswordAndInvisibleUsername) {
PasswordFormBuilder builder(kTestFormActionURL);
@@ -1330,7 +1394,7 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, IsGaiaReauthFormIgnored) {
LoadWebFormFromHTML(html, &form);
std::vector<WebFormControlElement> control_elements;
WebVector<blink::WebFormControlElement> web_control_elements;
- form.getFormControlElements(web_control_elements);
+ form.GetFormControlElements(web_control_elements);
control_elements.assign(web_control_elements.begin(),
web_control_elements.end());
EXPECT_EQ(test_case.expected_form_is_reauth,
@@ -1470,4 +1534,46 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest,
EXPECT_FALSE(password_form->does_look_like_signup_form);
}
+TEST_F(MAYBE_PasswordFormConversionUtilsTest, TooManyFieldsToParseForm) {
+ PasswordFormBuilder builder(kTestFormActionURL);
+ for (size_t i = 0; i < form_util::kMaxParseableFields + 1; ++i)
+ builder.AddTextField("id", "value", "autocomplete");
+ std::unique_ptr<PasswordForm> password_form =
+ LoadHTMLAndConvertForm(builder.ProduceHTML(), nullptr, false);
+ EXPECT_FALSE(password_form);
+}
+
+TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyCreditCardFields) {
+ PasswordFormBuilder builder(kTestFormActionURL);
+ builder.AddTextField("ccname", "johnsmith", "cc-name");
+ builder.AddPasswordField("cc_security_code", "0123456789", "cc-csc");
+ builder.AddSubmitButton("submit");
+ std::string html = builder.ProduceHTML();
+
+ std::unique_ptr<PasswordForm> password_form =
+ LoadHTMLAndConvertForm(html, nullptr, false);
+ EXPECT_FALSE(password_form);
+}
+
+TEST_F(MAYBE_PasswordFormConversionUtilsTest,
+ FieldsWithAndWithoutCreditCardAttributes) {
+ PasswordFormBuilder builder(kTestFormActionURL);
+ builder.AddTextField("username", "johnsmith", nullptr);
+ builder.AddTextField("ccname", "john_smith", "cc-name");
+ builder.AddPasswordField("cc_security_code", "0123456789", "random cc-csc");
+ builder.AddPasswordField("password", "secret", nullptr);
+ builder.AddSubmitButton("submit");
+ std::string html = builder.ProduceHTML();
+
+ std::unique_ptr<PasswordForm> password_form =
+ LoadHTMLAndConvertForm(html, nullptr, false);
+
+ ASSERT_TRUE(password_form);
+
+ EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element);
+ EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value);
+ EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element);
+ EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.cc b/chromium/components/autofill/content/renderer/password_generation_agent.cc
index ebca6d4b1cb..020c5b383e8 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.cc
@@ -37,6 +37,8 @@ namespace autofill {
namespace {
+using Logger = autofill::SavePasswordProgressLogger;
+
// Returns true if we think that this form is for account creation. |passwords|
// is filled with the password field(s) in the form.
bool GetAccountCreationPasswordFields(
@@ -44,9 +46,9 @@ bool GetAccountCreationPasswordFields(
std::vector<blink::WebInputElement>* passwords) {
for (size_t i = 0; i < control_elements.size(); i++) {
const blink::WebInputElement* input_element =
- toWebInputElement(&control_elements[i]);
- if (input_element && input_element->isTextField()) {
- if (input_element->isPasswordField())
+ ToWebInputElement(&control_elements[i]);
+ if (input_element && input_element->IsTextField()) {
+ if (input_element->IsPasswordField())
passwords->push_back(*input_element);
}
}
@@ -75,21 +77,30 @@ const PasswordFormGenerationData* FindFormGenerationData(
// than 2 elements.
std::vector<blink::WebInputElement> FindPasswordElementsForGeneration(
const std::vector<blink::WebInputElement>& all_password_elements,
- const FieldSignature field_signature) {
- auto iter = std::find_if(
- all_password_elements.begin(), all_password_elements.end(),
- [&field_signature](const blink::WebInputElement& input) {
- FieldSignature signature = CalculateFieldSignatureByNameAndType(
- input.nameForAutofill().utf16(), input.formControlType().utf8());
- return signature == field_signature;
- });
+ const PasswordFormGenerationData& generation_data) {
+ auto generation_field_iter = all_password_elements.end();
+ auto confirmation_field_iter = all_password_elements.end();
+ for (auto iter = all_password_elements.begin();
+ iter != all_password_elements.end(); ++iter) {
+ const blink::WebInputElement& input = *iter;
+ FieldSignature signature = CalculateFieldSignatureByNameAndType(
+ input.NameForAutofill().Utf16(), input.FormControlType().Utf8());
+ if (signature == generation_data.field_signature)
+ generation_field_iter = iter;
+ else if (generation_data.confirmation_field_signature &&
+ signature == *generation_data.confirmation_field_signature)
+ confirmation_field_iter = iter;
+ }
+
std::vector<blink::WebInputElement> passwords;
+ if (generation_field_iter != all_password_elements.end()) {
+ passwords.push_back(*generation_field_iter);
- // We copy not more than 2 fields because occasionally there are forms where
- // the security question answers are put in password fields and we don't want
- // to fill those.
- for (; iter != all_password_elements.end() && passwords.size() < 2; ++iter)
- passwords.push_back(*iter);
+ if (confirmation_field_iter == all_password_elements.end())
+ confirmation_field_iter = generation_field_iter + 1;
+ if (confirmation_field_iter != all_password_elements.end())
+ passwords.push_back(*confirmation_field_iter);
+ }
return passwords;
}
@@ -98,7 +109,7 @@ void CopyElementValueToOtherInputElements(
std::vector<blink::WebInputElement>* elements) {
for (blink::WebInputElement& it : *elements) {
if (*element != it) {
- it.setValue(element->value(), true /* sendEvents */);
+ it.SetAutofillValue(element->Value());
}
}
}
@@ -133,7 +144,7 @@ PasswordGenerationAgent::PasswordGenerationAgent(
form_classifier_enabled_(false),
password_agent_(password_agent),
binding_(this) {
- VLOG(2) << "Password Generation is " << (enabled_ ? "Enabled" : "Disabled");
+ LogBoolean(Logger::STRING_GENERATION_RENDERER_ENABLED, enabled_);
// PasswordGenerationAgent is guaranteed to outlive |render_frame|.
render_frame->GetInterfaceRegistry()->AddInterface(base::Bind(
&PasswordGenerationAgent::BindRequest, base::Unretained(this)));
@@ -147,7 +158,7 @@ void PasswordGenerationAgent::BindRequest(
void PasswordGenerationAgent::DidFinishDocumentLoad() {
// Update stats for main frame navigation.
- if (!render_frame()->GetWebFrame()->parent()) {
+ if (!render_frame()->GetWebFrame()->Parent()) {
// In every navigation, the IPC message sent by the password autofill
// manager to query whether the current form is blacklisted or not happens
// when the document load finishes, so we need to clear previous states
@@ -158,7 +169,7 @@ void PasswordGenerationAgent::DidFinishDocumentLoad() {
// each frame.
not_blacklisted_password_form_origins_.clear();
generation_enabled_forms_.clear();
- generation_element_.reset();
+ generation_element_.Reset();
possible_account_creation_forms_.clear();
// Log statistics after navigation so that we only log once per page.
@@ -239,9 +250,9 @@ void PasswordGenerationAgent::FindPossibleGenerationForm() {
return;
blink::WebVector<blink::WebFormElement> forms;
- render_frame()->GetWebFrame()->document().forms(forms);
+ render_frame()->GetWebFrame()->GetDocument().Forms(forms);
for (size_t i = 0; i < forms.size(); ++i) {
- if (forms[i].isNull())
+ if (forms[i].IsNull())
continue;
// If we can't get a valid PasswordForm, we skip this form because the
@@ -249,7 +260,7 @@ void PasswordGenerationAgent::FindPossibleGenerationForm() {
std::unique_ptr<PasswordForm> password_form(
CreatePasswordFormFromWebForm(forms[i], nullptr, nullptr));
if (!password_form.get()) {
- VLOG(2) << "Skipping form as it would not be saved";
+ LogMessage(Logger::STRING_GENERATION_RENDERER_INVALID_PASSWORD_FORM);
continue;
}
@@ -272,22 +283,22 @@ void PasswordGenerationAgent::FindPossibleGenerationForm() {
}
if (!possible_account_creation_forms_.empty()) {
- VLOG(2) << possible_account_creation_forms_.size()
- << " possible account creation forms deteceted";
+ LogNumber(
+ Logger::STRING_GENERATION_RENDERER_POSSIBLE_ACCOUNT_CREATION_FORMS,
+ possible_account_creation_forms_.size());
DetermineGenerationElement();
}
}
-bool PasswordGenerationAgent::ShouldAnalyzeDocument() const {
+bool PasswordGenerationAgent::ShouldAnalyzeDocument() {
// Make sure that this security origin is allowed to use password manager.
// Generating a password that can't be saved is a bad idea.
- if (!render_frame() ||
- !render_frame()
- ->GetWebFrame()
- ->document()
- .getSecurityOrigin()
- .canAccessPasswordManager()) {
- VLOG(1) << "No PasswordManager access";
+ if (!render_frame() || !render_frame()
+ ->GetWebFrame()
+ ->GetDocument()
+ .GetSecurityOrigin()
+ .CanAccessPasswordManager()) {
+ LogMessage(Logger::STRING_GENERATION_RENDERER_NO_PASSWORD_MANAGER_ACCESS);
return false;
}
@@ -304,13 +315,14 @@ void PasswordGenerationAgent::GeneratedPasswordAccepted(
password_is_generated_ = true;
password_generation::LogPasswordGenerationEvent(
password_generation::PASSWORD_ACCEPTED);
+ LogMessage(Logger::STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED);
for (auto& password_element : generation_form_data_->password_elements) {
- password_element.setValue(blink::WebString::fromUTF16(password),
- true /* sendEvents */);
- // setValue() above may have resulted in JavaScript closing the frame.
+ password_element.SetAutofillValue(blink::WebString::FromUTF16(password));
+ // setAutofillValue() above may have resulted in JavaScript closing the
+ // frame.
if (!render_frame())
return;
- password_element.setAutofilled(true);
+ password_element.SetAutofilled(true);
// Needed to notify password_autofill_agent that the content of the field
// has changed. Without this we will overwrite the generated
// password with an Autofilled password when saving.
@@ -318,7 +330,7 @@ void PasswordGenerationAgent::GeneratedPasswordAccepted(
password_agent_->UpdateStateForTextChange(password_element);
// Advance focus to the next input field. We assume password fields in
// an account creation form are always adjacent.
- render_frame()->GetRenderView()->GetWebView()->advanceFocus(false);
+ render_frame()->GetRenderView()->GetWebView()->AdvanceFocus(false);
}
std::unique_ptr<PasswordForm> presaved_form(CreatePasswordFormToPresave());
if (presaved_form) {
@@ -328,13 +340,13 @@ void PasswordGenerationAgent::GeneratedPasswordAccepted(
std::unique_ptr<PasswordForm>
PasswordGenerationAgent::CreatePasswordFormToPresave() {
- DCHECK(!generation_element_.isNull());
+ DCHECK(!generation_element_.IsNull());
// Since the form for presaving should match a form in the browser, create it
// with the same algorithm (to match html attributes, action, etc.), but
// change username and password values.
std::unique_ptr<PasswordForm> password_form;
- if (!generation_element_.form().isNull()) {
- password_form = CreatePasswordFormFromWebForm(generation_element_.form(),
+ if (!generation_element_.Form().IsNull()) {
+ password_form = CreatePasswordFormFromWebForm(generation_element_.Form(),
nullptr, nullptr);
} else {
password_form = CreatePasswordFormFromUnownedInputElements(
@@ -344,7 +356,7 @@ PasswordGenerationAgent::CreatePasswordFormToPresave() {
// TODO(kolos): when we are good in username detection, save username
// as well.
password_form->username_value = base::string16();
- password_form->password_value = generation_element_.value().utf16();
+ password_form->password_value = generation_element_.Value().Utf16();
}
return password_form;
@@ -359,15 +371,14 @@ void PasswordGenerationAgent::FoundFormsEligibleForGeneration(
void PasswordGenerationAgent::DetermineGenerationElement() {
if (generation_form_data_) {
- VLOG(2) << "Account creation form already found";
+ LogMessage(Logger::STRING_GENERATION_RENDERER_FORM_ALREADY_FOUND);
return;
}
// Make sure local heuristics have identified a possible account creation
// form.
if (possible_account_creation_forms_.empty()) {
- VLOG(2) << "Local hueristics have not detected a possible account "
- << "creation form";
+ LogMessage(Logger::STRING_GENERATION_RENDERER_NO_POSSIBLE_CREATION_FORMS);
return;
}
@@ -381,42 +392,37 @@ void PasswordGenerationAgent::DetermineGenerationElement() {
VLOG(2) << "Bypassing additional checks.";
} else if (!ContainsURL(not_blacklisted_password_form_origins_,
possible_password_form->origin)) {
- VLOG(2) << "Have not received confirmation that password form isn't "
- << "blacklisted";
+ LogMessage(Logger::STRING_GENERATION_RENDERER_NOT_BLACKLISTED);
continue;
} else {
generation_data = FindFormGenerationData(generation_enabled_forms_,
*possible_password_form);
if (!generation_data) {
if (AutocompleteAttributesSetForGeneration(*possible_password_form)) {
- VLOG(2) << "Ignoring lack of Autofill signal due to Autocomplete "
- << "attributes";
+ LogMessage(Logger::STRING_GENERATION_RENDERER_AUTOCOMPLETE_ATTRIBUTE);
password_generation::LogPasswordGenerationEvent(
password_generation::AUTOCOMPLETE_ATTRIBUTES_ENABLED_GENERATION);
} else {
- VLOG(2)
- << "Have not received confirmation from Autofill that form is "
- << "used for account creation";
+ LogMessage(Logger::STRING_GENERATION_RENDERER_NO_SERVER_SIGNAL);
continue;
}
}
}
-
- VLOG(2) << "Password generation eligible form found";
+ LogMessage(Logger::STRING_GENERATION_RENDERER_ELIGIBLE_FORM_FOUND);
std::vector<blink::WebInputElement> password_elements =
- generation_data ? FindPasswordElementsForGeneration(
- possible_form_data.password_elements,
- generation_data->field_signature)
- : possible_form_data.password_elements;
+ generation_data
+ ? FindPasswordElementsForGeneration(
+ possible_form_data.password_elements, *generation_data)
+ : possible_form_data.password_elements;
if (password_elements.empty()) {
// It might be if JavaScript changes field names.
- VLOG(2) << "Fields for generation are not found";
+ LogMessage(Logger::STRING_GENERATION_RENDERER_NO_FIELD_FOUND);
return;
}
generation_form_data_.reset(new AccountCreationFormData(
possible_form_data.form, std::move(password_elements)));
generation_element_ = generation_form_data_->password_elements[0];
- generation_element_.setAttribute("aria-autocomplete", "list");
+ generation_element_.SetAttribute("aria-autocomplete", "list");
password_generation::LogPasswordGenerationEvent(
password_generation::GENERATION_AVAILABLE);
possible_account_creation_forms_.clear();
@@ -428,34 +434,37 @@ void PasswordGenerationAgent::DetermineGenerationElement() {
bool PasswordGenerationAgent::FocusedNodeHasChanged(
const blink::WebNode& node) {
- if (!generation_element_.isNull())
- generation_element_.setShouldRevealPassword(false);
+ if (!generation_element_.IsNull())
+ generation_element_.SetShouldRevealPassword(false);
- if (node.isNull() || !node.isElementNode())
+ if (node.IsNull() || !node.IsElementNode())
return false;
- const blink::WebElement web_element = node.toConst<blink::WebElement>();
- if (!web_element.document().frame())
+ const blink::WebElement web_element = node.ToConst<blink::WebElement>();
+ if (!web_element.GetDocument().GetFrame())
return false;
- const blink::WebInputElement* element = toWebInputElement(&web_element);
- if (element && element->isPasswordField())
+ const blink::WebInputElement* element = ToWebInputElement(&web_element);
+ if (element && element->IsPasswordField())
last_focused_password_element_ = *element;
if (!element || *element != generation_element_)
return false;
if (password_is_generated_) {
- generation_element_.setShouldRevealPassword(true);
- ShowEditingPopup();
+ if (generation_element_.Value().IsEmpty()) {
+ PasswordNoLongerGenerated();
+ } else {
+ generation_element_.SetShouldRevealPassword(true);
+ ShowEditingPopup();
+ }
return true;
}
// Assume that if the password field has less than kMaximumOfferSize
// characters then the user is not finished typing their password and display
// the password suggestion.
- if (!element->isReadOnly() &&
- element->isEnabled() &&
- element->value().length() <= kMaximumOfferSize) {
+ if (!element->IsReadOnly() && element->IsEnabled() &&
+ element->Value().length() <= kMaximumOfferSize) {
ShowGenerationPopup();
return true;
}
@@ -468,24 +477,12 @@ bool PasswordGenerationAgent::TextDidChangeInTextField(
if (element != generation_element_)
return false;
- if (element.value().isEmpty()) {
+ if (element.Value().IsEmpty()) {
if (password_is_generated_) {
// User generated a password and then deleted it.
- password_generation::LogPasswordGenerationEvent(
- password_generation::PASSWORD_DELETED);
- CopyElementValueToOtherInputElements(&element,
- &generation_form_data_->password_elements);
- std::unique_ptr<PasswordForm> presaved_form(
- CreatePasswordFormToPresave());
- if (presaved_form) {
- GetPasswordManagerDriver()->PasswordNoLongerGenerated(*presaved_form);
- }
+ PasswordNoLongerGenerated();
}
- // Do not treat the password as generated, either here or in the browser.
- password_is_generated_ = false;
- generation_element_.setShouldRevealPassword(false);
-
// Offer generation again.
ShowGenerationPopup();
} else if (password_is_generated_) {
@@ -497,7 +494,7 @@ bool PasswordGenerationAgent::TextDidChangeInTextField(
if (presaved_form) {
GetPasswordManagerDriver()->PresaveGeneratedPassword(*presaved_form);
}
- } else if (element.value().length() > kMaximumOfferSize) {
+ } else if (element.Value().length() > kMaximumOfferSize) {
// User has rejected the feature and has started typing a password.
HidePopup();
} else {
@@ -513,11 +510,12 @@ bool PasswordGenerationAgent::TextDidChangeInTextField(
void PasswordGenerationAgent::ShowGenerationPopup() {
if (!render_frame())
return;
+ LogMessage(Logger::STRING_GENERATION_RENDERER_SHOW_GENERATION_POPUP);
GetPasswordManagerClient()->ShowPasswordGenerationPopup(
render_frame()->GetRenderView()->ElementBoundsInWindow(
generation_element_),
- generation_element_.maxLength(),
- generation_element_.nameForAutofill().utf16(), is_manually_triggered_,
+ generation_element_.MaxLength(),
+ generation_element_.NameForAutofill().Utf16(), is_manually_triggered_,
*generation_form_data_->form);
generation_popup_shown_ = true;
}
@@ -536,25 +534,41 @@ void PasswordGenerationAgent::HidePopup() {
GetPasswordManagerClient()->HidePasswordGenerationPopup();
}
+void PasswordGenerationAgent::PasswordNoLongerGenerated() {
+ // Do not treat the password as generated, either here or in the browser.
+ password_is_generated_ = false;
+ generation_element_.SetShouldRevealPassword(false);
+ for (blink::WebInputElement& password :
+ generation_form_data_->password_elements)
+ password.SetAutofilled(false);
+ password_generation::LogPasswordGenerationEvent(
+ password_generation::PASSWORD_DELETED);
+ CopyElementValueToOtherInputElements(
+ &generation_element_, &generation_form_data_->password_elements);
+ std::unique_ptr<PasswordForm> presaved_form(CreatePasswordFormToPresave());
+ if (presaved_form)
+ GetPasswordManagerDriver()->PasswordNoLongerGenerated(*presaved_form);
+}
+
void PasswordGenerationAgent::UserTriggeredGeneratePassword() {
- if (last_focused_password_element_.isNull() || !render_frame())
+ if (last_focused_password_element_.IsNull() || !render_frame())
return;
- blink::WebFormElement form = last_focused_password_element_.form();
+ blink::WebFormElement form = last_focused_password_element_.Form();
std::unique_ptr<PasswordForm> password_form;
std::vector<blink::WebFormControlElement> control_elements;
- if (!form.isNull()) {
+ if (!form.IsNull()) {
password_form = CreatePasswordFormFromWebForm(form, nullptr, nullptr);
control_elements = form_util::ExtractAutofillableElementsInForm(form);
} else {
const blink::WebFrame& frame = *render_frame()->GetWebFrame();
- blink::WebDocument doc = frame.document();
- if (doc.isNull())
+ blink::WebDocument doc = frame.GetDocument();
+ if (doc.IsNull())
return;
password_form =
CreatePasswordFormFromUnownedInputElements(frame, nullptr, nullptr);
control_elements =
- form_util::GetUnownedFormFieldElements(doc.all(), nullptr);
+ form_util::GetUnownedFormFieldElements(doc.All(), nullptr);
}
if (!password_form)
@@ -565,9 +579,11 @@ void PasswordGenerationAgent::UserTriggeredGeneratePassword() {
GetAccountCreationPasswordFields(control_elements, &password_elements);
password_elements = FindPasswordElementsForGeneration(
password_elements,
- CalculateFieldSignatureByNameAndType(
- last_focused_password_element_.nameForAutofill().utf16(),
- last_focused_password_element_.formControlType().utf8()));
+ PasswordFormGenerationData(
+ 0, /* form_signature */
+ CalculateFieldSignatureByNameAndType(
+ last_focused_password_element_.NameForAutofill().Utf16(),
+ last_focused_password_element_.FormControlType().Utf8())));
generation_form_data_.reset(new AccountCreationFormData(
make_linked_ptr(password_form.release()), password_elements));
is_manually_triggered_ = true;
@@ -590,4 +606,27 @@ PasswordGenerationAgent::GetPasswordManagerClient() {
return password_manager_client_;
}
+void PasswordGenerationAgent::LogMessage(Logger::StringID message_id) {
+ if (!password_agent_->logging_state_active())
+ return;
+ RendererSavePasswordProgressLogger logger(GetPasswordManagerDriver().get());
+ logger.LogMessage(message_id);
+}
+
+void PasswordGenerationAgent::LogBoolean(Logger::StringID message_id,
+ bool truth_value) {
+ if (!password_agent_->logging_state_active())
+ return;
+ RendererSavePasswordProgressLogger logger(GetPasswordManagerDriver().get());
+ logger.LogBoolean(message_id, truth_value);
+}
+
+void PasswordGenerationAgent::LogNumber(Logger::StringID message_id,
+ int number) {
+ if (!password_agent_->logging_state_active())
+ return;
+ RendererSavePasswordProgressLogger logger(GetPasswordManagerDriver().get());
+ logger.LogNumber(message_id, number);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.h b/chromium/components/autofill/content/renderer/password_generation_agent.h
index 694c5fc990c..2af62823a76 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.h
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.h
@@ -16,6 +16,7 @@
#include "base/memory/linked_ptr.h"
#include "components/autofill/content/common/autofill_agent.mojom.h"
#include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/content/renderer/renderer_save_password_progress_logger.h"
#include "content/public/renderer/render_frame_observer.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "third_party/WebKit/public/web/WebInputElement.h"
@@ -66,7 +67,7 @@ class PasswordGenerationAgent : public content::RenderFrameObserver,
protected:
// Returns true if the document for |render_frame()| is one that we should
// consider analyzing. Virtual so that it can be overriden during testing.
- virtual bool ShouldAnalyzeDocument() const;
+ virtual bool ShouldAnalyzeDocument();
// Use to force enable during testing.
void set_enabled(bool enabled) { enabled_ = enabled; }
@@ -112,12 +113,21 @@ class PasswordGenerationAgent : public content::RenderFrameObserver,
// Hides a password generation popup if one exists.
void HidePopup();
+ // Stops treating a password as generated.
+ void PasswordNoLongerGenerated();
+
// Runs HTML parsing based classifier and saves its outcome to proto.
// TODO(crbug.com/621442): Remove client-side form classifier when server-side
// classifier is ready.
void RunFormClassifierAndSaveVote(const blink::WebFormElement& web_form,
const PasswordForm& form);
+ void LogMessage(autofill::SavePasswordProgressLogger::StringID message_id);
+ void LogBoolean(autofill::SavePasswordProgressLogger::StringID message_id,
+ bool truth_value);
+ void LogNumber(autofill::SavePasswordProgressLogger::StringID message_id,
+ int number);
+
// Creates a password form to presave a generated password. It copies behavior
// of CreatePasswordFormFromWebForm/FromUnownedInputElements, but takes
// |password_value| from |generation_element_| and empties |username_value|.
diff --git a/chromium/components/autofill/content/renderer/provisionally_saved_password_form.cc b/chromium/components/autofill/content/renderer/provisionally_saved_password_form.cc
new file mode 100644
index 00000000000..34bbee19bf4
--- /dev/null
+++ b/chromium/components/autofill/content/renderer/provisionally_saved_password_form.cc
@@ -0,0 +1,41 @@
+// 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/content/renderer/provisionally_saved_password_form.h"
+
+#include <utility>
+
+#include "components/autofill/core/common/password_form.h"
+
+namespace autofill {
+
+ProvisionallySavedPasswordForm::ProvisionallySavedPasswordForm() = default;
+
+ProvisionallySavedPasswordForm::~ProvisionallySavedPasswordForm() = default;
+
+void ProvisionallySavedPasswordForm::Set(
+ std::unique_ptr<PasswordForm> password_form,
+ const blink::WebFormElement& form_element,
+ const blink::WebInputElement& input_element) {
+ password_form_ = std::move(password_form);
+ form_element_ = form_element;
+ input_element_ = input_element;
+}
+
+void ProvisionallySavedPasswordForm::Reset() {
+ password_form_.reset();
+ form_element_.Reset();
+ input_element_.Reset();
+}
+
+bool ProvisionallySavedPasswordForm::IsSet() const {
+ return static_cast<bool>(password_form_);
+}
+
+bool ProvisionallySavedPasswordForm::IsPasswordValid() const {
+ return IsSet() && !(password_form_->password_value.empty() &&
+ password_form_->new_password_value.empty());
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/provisionally_saved_password_form.h b/chromium/components/autofill/content/renderer/provisionally_saved_password_form.h
new file mode 100644
index 00000000000..318eb189aed
--- /dev/null
+++ b/chromium/components/autofill/content/renderer/provisionally_saved_password_form.h
@@ -0,0 +1,58 @@
+// 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_CONTENT_RENDERER_PROVISIONALLY_SAVED_PASSWORD_FORM_H_
+#define COMPONENTS_AUTOFILL_CONTENT_RENDERER_PROVISIONALLY_SAVED_PASSWORD_FORM_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "third_party/WebKit/public/web/WebInputElement.h"
+
+namespace autofill {
+
+struct PasswordForm;
+
+// Represents a possibly submitted password form.
+class ProvisionallySavedPasswordForm {
+ public:
+ ProvisionallySavedPasswordForm();
+ ~ProvisionallySavedPasswordForm();
+
+ // Sets the PasswordForm and web elements that were used in the PasswordForm
+ // update.
+ void Set(std::unique_ptr<PasswordForm> password_form,
+ const blink::WebFormElement& form_element,
+ const blink::WebInputElement& input_element);
+ void Reset();
+
+ // Returns true if the instance has |password_form_| set, but the actual
+ // password data may be invalid (e.g. empty username or password).
+ bool IsSet() const;
+ // Returns true if |password_form_| has enough information that it is likely
+ // filled out.
+ bool IsPasswordValid() const;
+
+ const PasswordForm& password_form() const {
+ DCHECK(IsSet());
+ return *password_form_;
+ }
+ const blink::WebFormElement& form_element() const { return form_element_; }
+ const blink::WebInputElement& input_element() const { return input_element_; }
+
+ private:
+ std::unique_ptr<PasswordForm> password_form_;
+ // Last used WebFormElement for the PasswordForm submission. Can be null if
+ // the form is unowned.
+ blink::WebFormElement form_element_;
+ // Last used WebInputElement which led to the PasswordForm update. Can be null
+ // if the user has performed a form submission (via a button, for example).
+ blink::WebInputElement input_element_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProvisionallySavedPasswordForm);
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CONTENT_RENDERER_PROVISIONALLY_SAVED_PASSWORD_FORM_H_
diff --git a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.cc b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.cc
index bd71dbc0d88..a590525dc42 100644
--- a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.cc
+++ b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.cc
@@ -25,8 +25,8 @@ void RendererSavePasswordProgressLogger::SendLog(const std::string& log) {
void RendererSavePasswordProgressLogger::LogElementName(
StringID label,
const blink::WebFormControlElement& element) {
- LogValue(label, base::StringValue(
- ScrubElementID((element.nameForAutofill().utf16()))));
+ LogValue(label,
+ base::Value(ScrubElementID((element.NameForAutofill().Utf16()))));
}
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/test_password_generation_agent.cc b/chromium/components/autofill/content/renderer/test_password_generation_agent.cc
index d8707b0f20e..84d937a7989 100644
--- a/chromium/components/autofill/content/renderer/test_password_generation_agent.cc
+++ b/chromium/components/autofill/content/renderer/test_password_generation_agent.cc
@@ -15,7 +15,7 @@ TestPasswordGenerationAgent::TestPasswordGenerationAgent(
TestPasswordGenerationAgent::~TestPasswordGenerationAgent() {}
-bool TestPasswordGenerationAgent::ShouldAnalyzeDocument() const {
+bool TestPasswordGenerationAgent::ShouldAnalyzeDocument() {
return true;
}
diff --git a/chromium/components/autofill/content/renderer/test_password_generation_agent.h b/chromium/components/autofill/content/renderer/test_password_generation_agent.h
index 333b4321016..11aef9d06a0 100644
--- a/chromium/components/autofill/content/renderer/test_password_generation_agent.h
+++ b/chromium/components/autofill/content/renderer/test_password_generation_agent.h
@@ -21,7 +21,7 @@ class TestPasswordGenerationAgent : public PasswordGenerationAgent {
// PasswordGenreationAgent implementation:
// Always return true to allow loading of data URLs.
- bool ShouldAnalyzeDocument() const override;
+ bool ShouldAnalyzeDocument() override;
private:
DISALLOW_COPY_AND_ASSIGN(TestPasswordGenerationAgent);
diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn
index 4e6332c41f8..87a22f6efa1 100644
--- a/chromium/components/autofill/core/browser/BUILD.gn
+++ b/chromium/components/autofill/core/browser/BUILD.gn
@@ -18,6 +18,8 @@ static_library("browser") {
"autocomplete_history_manager.cc",
"autocomplete_history_manager.h",
"autofill-inl.h",
+ "autofill_address_util.cc",
+ "autofill_address_util.h",
"autofill_client.h",
"autofill_country.cc",
"autofill_country.h",
@@ -109,6 +111,9 @@ static_library("browser") {
"phone_number_i18n.cc",
"phone_number_i18n.h",
"popup_item_ids.h",
+ "region_combobox_model.cc",
+ "region_combobox_model.h",
+ "risk_data_loader.h",
"server_field_types_util.cc",
"server_field_types_util.h",
"state_names.cc",
@@ -178,12 +183,19 @@ static_library("browser") {
]
}
+ if (!is_android) {
+ sources += [
+ "ui/save_card_bubble_controller.h",
+ ]
+ }
+
configs += [ "//build/config:precompiled_headers" ]
public_deps = [
"//components/autofill/core/browser/proto",
"//components/autofill/core/common",
"//components/resources",
+ "//skia",
]
deps = [
"//base",
@@ -206,11 +218,10 @@ static_library("browser") {
"//components/webdata/common",
"//google_apis",
"//net",
- "//skia",
"//sql",
"//third_party/fips181",
"//third_party/icu",
- "//third_party/libaddressinput:util",
+ "//third_party/libaddressinput",
"//third_party/libphonenumber",
"//third_party/re2",
"//ui/base",
@@ -247,6 +258,13 @@ static_library("test_support") {
"test_personal_data_manager.h",
]
+ if (!is_android) {
+ sources += [
+ "ui/mock_save_card_bubble_controller.cc",
+ "ui/mock_save_card_bubble_controller.h",
+ ]
+ }
+
public_deps = [
":browser",
]
@@ -336,6 +354,7 @@ source_set("unit_tests") {
"phone_field_unittest.cc",
"phone_number_i18n_unittest.cc",
"phone_number_unittest.cc",
+ "region_combobox_model_unittest.cc",
"ui/card_unmask_prompt_controller_impl_unittest.cc",
"validation_unittest.cc",
"webdata/autocomplete_sync_bridge_unittest.cc",
diff --git a/chromium/components/autofill/core/browser/address_i18n_unittest.cc b/chromium/components/autofill/core/browser/address_i18n_unittest.cc
index 59ddc2137a3..7b0a9a0da21 100644
--- a/chromium/components/autofill/core/browser/address_i18n_unittest.cc
+++ b/chromium/components/autofill/core/browser/address_i18n_unittest.cc
@@ -35,61 +35,91 @@ using ::i18n::addressinput::RECIPIENT;
using ::i18n::addressinput::SORTING_CODE;
using ::i18n::addressinput::STREET_ADDRESS;
-TEST(AddressI18nTest, FieldTypeMirrorConversions) {
- static const struct {
- bool billing;
- ServerFieldType server_field;
- AddressField address_field;
- } kTestData[] = {
- {true, ADDRESS_BILLING_COUNTRY, COUNTRY},
- {true, ADDRESS_BILLING_STATE, ADMIN_AREA},
- {true, ADDRESS_BILLING_CITY, LOCALITY},
- {true, ADDRESS_BILLING_DEPENDENT_LOCALITY, DEPENDENT_LOCALITY},
- {true, ADDRESS_BILLING_SORTING_CODE, SORTING_CODE},
- {true, ADDRESS_BILLING_ZIP, POSTAL_CODE},
- {true, ADDRESS_BILLING_STREET_ADDRESS, STREET_ADDRESS},
- {true, COMPANY_NAME, ORGANIZATION},
- {true, NAME_BILLING_FULL, RECIPIENT},
- {false, ADDRESS_HOME_COUNTRY, COUNTRY},
- {false, ADDRESS_HOME_STATE, ADMIN_AREA},
- {false, ADDRESS_HOME_CITY, LOCALITY},
- {false, ADDRESS_HOME_DEPENDENT_LOCALITY, DEPENDENT_LOCALITY},
- {false, ADDRESS_HOME_SORTING_CODE, SORTING_CODE},
- {false, ADDRESS_HOME_ZIP, POSTAL_CODE},
- {false, ADDRESS_HOME_STREET_ADDRESS, STREET_ADDRESS},
- {false, COMPANY_NAME, ORGANIZATION},
- {false, NAME_FULL, RECIPIENT},
- };
-
- for (const auto& test_data : kTestData) {
- AddressField address_field;
- EXPECT_TRUE(FieldForType(test_data.server_field, &address_field));
- EXPECT_EQ(test_data.address_field, address_field);
-
- ServerFieldType server_field =
- TypeForField(test_data.address_field, test_data.billing);
- EXPECT_EQ(test_data.server_field, server_field);
- }
+struct FieldTypeMirrorConversionsTestCase {
+ bool billing;
+ ServerFieldType server_field;
+ AddressField address_field;
+};
+
+class FieldTypeMirrorConversionsTest
+ : public testing::TestWithParam<FieldTypeMirrorConversionsTestCase> {};
+
+TEST_P(FieldTypeMirrorConversionsTest, FieldTypeMirrorConversions) {
+ auto test_data = GetParam();
+ AddressField address_field;
+ EXPECT_TRUE(FieldForType(test_data.server_field, &address_field));
+ EXPECT_EQ(test_data.address_field, address_field);
+
+ ServerFieldType server_field =
+ TypeForField(test_data.address_field, test_data.billing);
+ EXPECT_EQ(test_data.server_field, server_field);
}
-TEST(AddressI18nTest, FieldTypeUnidirectionalConversions) {
- static const struct {
- ServerFieldType server_field;
- AddressField expected_address_field;
- } kTestData[] = {
- {ADDRESS_BILLING_LINE1, STREET_ADDRESS},
- {ADDRESS_BILLING_LINE2, STREET_ADDRESS},
- {ADDRESS_HOME_LINE1, STREET_ADDRESS},
- {ADDRESS_HOME_LINE2, STREET_ADDRESS},
- };
-
- for (const auto& test_data : kTestData) {
- AddressField actual_address_field;
- FieldForType(test_data.server_field, &actual_address_field);
- EXPECT_EQ(test_data.expected_address_field, actual_address_field);
- }
+INSTANTIATE_TEST_CASE_P(
+ AddressI18nTest,
+ FieldTypeMirrorConversionsTest,
+ testing::Values(
+ FieldTypeMirrorConversionsTestCase{true, ADDRESS_BILLING_COUNTRY,
+ COUNTRY},
+ FieldTypeMirrorConversionsTestCase{true, ADDRESS_BILLING_STATE,
+ ADMIN_AREA},
+ FieldTypeMirrorConversionsTestCase{true, ADDRESS_BILLING_CITY,
+ LOCALITY},
+ FieldTypeMirrorConversionsTestCase{
+ true, ADDRESS_BILLING_DEPENDENT_LOCALITY, DEPENDENT_LOCALITY},
+ FieldTypeMirrorConversionsTestCase{true, ADDRESS_BILLING_SORTING_CODE,
+ SORTING_CODE},
+ FieldTypeMirrorConversionsTestCase{true, ADDRESS_BILLING_ZIP,
+ POSTAL_CODE},
+ FieldTypeMirrorConversionsTestCase{true, ADDRESS_BILLING_STREET_ADDRESS,
+ STREET_ADDRESS},
+ FieldTypeMirrorConversionsTestCase{true, COMPANY_NAME, ORGANIZATION},
+ FieldTypeMirrorConversionsTestCase{true, NAME_BILLING_FULL, RECIPIENT},
+ FieldTypeMirrorConversionsTestCase{false, ADDRESS_HOME_COUNTRY,
+ COUNTRY},
+ FieldTypeMirrorConversionsTestCase{false, ADDRESS_HOME_STATE,
+ ADMIN_AREA},
+ FieldTypeMirrorConversionsTestCase{false, ADDRESS_HOME_CITY, LOCALITY},
+ FieldTypeMirrorConversionsTestCase{
+ false, ADDRESS_HOME_DEPENDENT_LOCALITY, DEPENDENT_LOCALITY},
+ FieldTypeMirrorConversionsTestCase{false, ADDRESS_HOME_SORTING_CODE,
+ SORTING_CODE},
+ FieldTypeMirrorConversionsTestCase{false, ADDRESS_HOME_ZIP,
+ POSTAL_CODE},
+ FieldTypeMirrorConversionsTestCase{false, ADDRESS_HOME_STREET_ADDRESS,
+ STREET_ADDRESS},
+ FieldTypeMirrorConversionsTestCase{false, COMPANY_NAME, ORGANIZATION},
+ FieldTypeMirrorConversionsTestCase{false, NAME_FULL, RECIPIENT}));
+
+struct FieldTypeUnidirectionalConversionsTestCase {
+ ServerFieldType server_field;
+ AddressField expected_address_field;
+};
+
+class FieldTypeUnidirectionalConversionsTest
+ : public testing::TestWithParam<
+ FieldTypeUnidirectionalConversionsTestCase> {};
+
+TEST_P(FieldTypeUnidirectionalConversionsTest,
+ FieldTypeUnidirectionalConversions) {
+ auto test_data = GetParam();
+ AddressField actual_address_field;
+ FieldForType(test_data.server_field, &actual_address_field);
+ EXPECT_EQ(test_data.expected_address_field, actual_address_field);
}
+INSTANTIATE_TEST_CASE_P(AddressI18nTest,
+ FieldTypeUnidirectionalConversionsTest,
+ testing::Values(
+ FieldTypeUnidirectionalConversionsTestCase{
+ ADDRESS_BILLING_LINE1, STREET_ADDRESS},
+ FieldTypeUnidirectionalConversionsTestCase{
+ ADDRESS_BILLING_LINE2, STREET_ADDRESS},
+ FieldTypeUnidirectionalConversionsTestCase{
+ ADDRESS_HOME_LINE1, STREET_ADDRESS},
+ FieldTypeUnidirectionalConversionsTestCase{
+ ADDRESS_HOME_LINE2, STREET_ADDRESS}));
+
TEST(AddressI18nTest, UnconvertableServerFields) {
EXPECT_FALSE(FieldForType(PHONE_HOME_NUMBER, NULL));
EXPECT_FALSE(FieldForType(EMAIL_ADDRESS, NULL));
diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
index fa4aa7ce877..ec5738c43a5 100644
--- a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
+++ b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
@@ -78,7 +78,7 @@ void AutocompleteHistoryManager::OnWillSubmitForm(const FormData& form) {
if (!autofill_client_->IsAutocompleteEnabled())
return;
- if (driver_->IsOffTheRecord())
+ if (driver_->IsIncognito())
return;
// We put the following restriction on stored FormFields:
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 df3820d9128..56c8d274114 100644
--- a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
@@ -10,6 +10,7 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/autofill/core/browser/autocomplete_history_manager.h"
#include "components/autofill/core/browser/autofill_external_delegate.h"
@@ -78,7 +79,7 @@ class AutocompleteHistoryManagerTest : public testing::Test {
void TearDown() override { autocomplete_manager_.reset(); }
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
scoped_refptr<MockWebDataService> web_data_service_;
std::unique_ptr<AutocompleteHistoryManager> autocomplete_manager_;
std::unique_ptr<AutofillDriver> autofill_driver_;
diff --git a/chromium/components/autofill/core/browser/autofill_address_util.cc b/chromium/components/autofill/core/browser/autofill_address_util.cc
new file mode 100644
index 00000000000..c232e002651
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_address_util.cc
@@ -0,0 +1,165 @@
+// 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_address_util.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "components/autofill/core/browser/autofill_country.h"
+#include "components/autofill/core/browser/country_combobox_model.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui_component.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/localization.h"
+#include "ui/base/l10n/l10n_util.h"
+
+using autofill::AutofillCountry;
+using autofill::ServerFieldType;
+using i18n::addressinput::AddressUiComponent;
+
+namespace autofill {
+
+// Dictionary keys for address components info.
+const char kFieldTypeKey[] = "field";
+const char kFieldLengthKey[] = "length";
+const char kFieldNameKey[] = "name";
+
+// Field names for the address components.
+const char kFullNameField[] = "fullName";
+const char kCompanyNameField[] = "companyName";
+const char kAddressLineField[] = "addrLines";
+const char kDependentLocalityField[] = "dependentLocality";
+const char kCityField[] = "city";
+const char kStateField[] = "state";
+const char kPostalCodeField[] = "postalCode";
+const char kSortingCodeField[] = "sortingCode";
+const char kCountryField[] = "country";
+
+// Address field length values.
+const char kShortField[] = "short";
+const char kLongField[] = "long";
+
+// Fills |components| with the address UI components that should be used to
+// input an address for |country_code| when UI BCP 47 language code is
+// |ui_language_code|. If |components_language_code| is not NULL, then sets it
+// to the BCP 47 language code that should be used to format the address for
+// display.
+void GetAddressComponents(const std::string& country_code,
+ const std::string& ui_language_code,
+ base::ListValue* address_components,
+ std::string* components_language_code) {
+ DCHECK(address_components);
+
+ i18n::addressinput::Localization localization;
+ localization.SetGetter(l10n_util::GetStringUTF8);
+ std::string not_used;
+ std::vector<AddressUiComponent> components =
+ i18n::addressinput::BuildComponents(
+ country_code, localization, ui_language_code,
+ components_language_code ? components_language_code : &not_used);
+ if (components.empty()) {
+ static const char kDefaultCountryCode[] = "US";
+ components = i18n::addressinput::BuildComponents(
+ kDefaultCountryCode, localization, ui_language_code,
+ components_language_code ? components_language_code : &not_used);
+ }
+ DCHECK(!components.empty());
+
+ base::ListValue* line = nullptr;
+ for (size_t i = 0; i < components.size(); ++i) {
+ if (i == 0 ||
+ components[i - 1].length_hint == AddressUiComponent::HINT_LONG ||
+ components[i].length_hint == AddressUiComponent::HINT_LONG) {
+ line = new base::ListValue;
+ address_components->Append(base::WrapUnique(line));
+ // |line| is invalidated at this point, so it needs to be reset.
+ address_components->GetList(address_components->GetSize() - 1, &line);
+ }
+
+ std::unique_ptr<base::DictionaryValue> component(new base::DictionaryValue);
+ component->SetString(kFieldNameKey, components[i].name);
+
+ switch (components[i].field) {
+ case i18n::addressinput::COUNTRY:
+ component->SetString(kFieldTypeKey, kCountryField);
+ break;
+ case i18n::addressinput::ADMIN_AREA:
+ component->SetString(kFieldTypeKey, kStateField);
+ break;
+ case i18n::addressinput::LOCALITY:
+ component->SetString(kFieldTypeKey, kCityField);
+ break;
+ case i18n::addressinput::DEPENDENT_LOCALITY:
+ component->SetString(kFieldTypeKey, kDependentLocalityField);
+ break;
+ case i18n::addressinput::SORTING_CODE:
+ component->SetString(kFieldTypeKey, kSortingCodeField);
+ break;
+ case i18n::addressinput::POSTAL_CODE:
+ component->SetString(kFieldTypeKey, kPostalCodeField);
+ break;
+ case i18n::addressinput::STREET_ADDRESS:
+ component->SetString(kFieldTypeKey, kAddressLineField);
+ break;
+ case i18n::addressinput::ORGANIZATION:
+ component->SetString(kFieldTypeKey, kCompanyNameField);
+ break;
+ case i18n::addressinput::RECIPIENT:
+ component->SetString(kFieldTypeKey, kFullNameField);
+ break;
+ }
+
+ switch (components[i].length_hint) {
+ case AddressUiComponent::HINT_LONG:
+ component->SetString(kFieldLengthKey, kLongField);
+ break;
+ case AddressUiComponent::HINT_SHORT:
+ component->SetString(kFieldLengthKey, kShortField);
+ break;
+ }
+
+ line->Append(std::move(component));
+ }
+}
+
+// Sets data related to the country <select>.
+void SetCountryData(const PersonalDataManager& manager,
+ base::DictionaryValue* localized_strings,
+ const std::string& ui_language_code) {
+ autofill::CountryComboboxModel model;
+ model.SetCountries(manager, base::Callback<bool(const std::string&)>(),
+ ui_language_code);
+ const std::vector<std::unique_ptr<autofill::AutofillCountry>>& countries =
+ model.countries();
+ localized_strings->SetString("defaultCountryCode",
+ countries.front()->country_code());
+
+ // An ordered list of options to show in the <select>.
+ std::unique_ptr<base::ListValue> country_list(new base::ListValue());
+ for (size_t i = 0; i < countries.size(); ++i) {
+ std::unique_ptr<base::DictionaryValue> option_details(
+ new base::DictionaryValue());
+ option_details->SetString("name", model.GetItemAt(i));
+ option_details->SetString(
+ "value", countries[i] ? countries[i]->country_code() : "separator");
+ country_list->Append(std::move(option_details));
+ }
+ localized_strings->Set("autofillCountrySelectList", country_list.release());
+
+ std::unique_ptr<base::ListValue> default_country_components(
+ new base::ListValue);
+ std::string default_country_language_code;
+ GetAddressComponents(countries.front()->country_code(), ui_language_code,
+ default_country_components.get(),
+ &default_country_language_code);
+ localized_strings->Set("autofillDefaultCountryComponents",
+ default_country_components.release());
+ localized_strings->SetString("autofillDefaultCountryLanguageCode",
+ default_country_language_code);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_address_util.h b/chromium/components/autofill/core/browser/autofill_address_util.h
new file mode 100644
index 00000000000..e90ff5bfabe
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_address_util.h
@@ -0,0 +1,78 @@
+// 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_ADDRESS_UTIL_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_ADDRESS_UTIL_H_
+
+#include <string>
+
+namespace base {
+class ListValue;
+class DictionaryValue;
+}
+
+namespace autofill {
+
+class PersonalDataManager;
+
+// Dictionary key for the field type.
+extern const char kFieldTypeKey[];
+
+// Dictionary key for the field length.
+extern const char kFieldLengthKey[];
+
+// Dictionary key for the field name.
+extern const char kFieldNameKey[];
+
+// Field name for autofill::NAME_FULL.
+extern const char kFullNameField[];
+
+// Field name for autofill::COMPANY_NAME.
+extern const char kCompanyNameField[];
+
+// Field name for autofill::ADDRESS_HOME_STREET_ADDRESS.
+extern const char kAddressLineField[];
+
+// Field name for autofill::ADDRESS_HOME_DEPENDENT_LOCALITY.
+extern const char kDependentLocalityField[];
+
+// Field name for autofill::ADDRESS_HOME_CITY.
+extern const char kCityField[];
+
+// Field name for autofill::ADDRESS_HOME_STATE.
+extern const char kStateField[];
+
+// Field name for autofill::ADDRESS_HOME_ZIP.
+extern const char kPostalCodeField[];
+
+// Field name for autofill::ADDRESS_HOME_SORTING_CODE.
+extern const char kSortingCodeField[];
+
+// Field name for autofill::ADDRESS_HOME_COUNTRY.
+extern const char kCountryField[];
+
+// AddressUiComponent::HINT_SHORT.
+extern const char kShortField[];
+
+// AddressUiComponent::HINT_LONG.
+extern const char kLongField[];
+
+// Fills |components| with the address UI components that should be used to
+// input an address for |country_code| when UI BCP 47 language code is
+// |ui_language_code|. If |components_language_code| is not NULL, then sets it
+// to the BCP 47 language code that should be used to format the address for
+// display.
+void GetAddressComponents(const std::string& country_code,
+ const std::string& ui_language_code,
+ base::ListValue* address_components,
+ std::string* components_language_code);
+
+// Sets data related to the country combobox.
+void SetCountryData(const PersonalDataManager& manager,
+ base::DictionaryValue* localized_strings,
+ const std::string& ui_language_code);
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_ADDRESS_UTIL_H_
diff --git a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc
index 3364c6f92fd..d5b27e105b2 100644
--- a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc
@@ -103,7 +103,7 @@ class AutofillAssistantTest : public testing::Test {
std::unique_ptr<FormStructure> CreateValidCreditCardForm() {
std::unique_ptr<FormStructure> form_structure;
form_structure.reset(new FormStructure(CreateValidCreditCardFormData()));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
return form_structure;
}
@@ -152,7 +152,7 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_Secure) {
// Can be shown if the context is secure.
FormData form = CreateValidCreditCardFormData();
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
std::vector<std::unique_ptr<FormStructure>> form_structures;
form_structures.push_back(std::move(form_structure));
@@ -169,7 +169,7 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_NotSecure) {
form.origin = GURL("http://myform.com");
form.action = GURL("http://myform.com/submit");
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
std::vector<std::unique_ptr<FormStructure>> form_structures;
form_structures.push_back(std::move(form_structure));
@@ -184,7 +184,7 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_Javascript) {
FormData form = CreateValidCreditCardFormData();
form.action = GURL("javascript:alert('hello');");
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
std::vector<std::unique_ptr<FormStructure>> form_structures;
form_structures.push_back(std::move(form_structure));
@@ -199,7 +199,7 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_WeirdJs) {
FormData form = CreateValidCreditCardFormData();
form.action = GURL("javascript:myFunc");
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
std::vector<std::unique_ptr<FormStructure>> form_structures;
form_structures.push_back(std::move(form_structure));
@@ -213,7 +213,7 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_EmptyAction) {
FormData form = CreateValidCreditCardFormData();
form.action = GURL();
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
std::vector<std::unique_ptr<FormStructure>> form_structures;
form_structures.push_back(std::move(form_structure));
diff --git a/chromium/components/autofill/core/browser/autofill_client.h b/chromium/components/autofill/core/browser/autofill_client.h
index d36f0026ffc..f6ff075d059 100644
--- a/chromium/components/autofill/core/browser/autofill_client.h
+++ b/chromium/components/autofill/core/browser/autofill_client.h
@@ -14,6 +14,7 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "base/values.h"
+#include "components/autofill/core/browser/risk_data_loader.h"
#include "ui/base/window_open_disposition.h"
#include "url/gurl.h"
@@ -48,6 +49,7 @@ class CardUnmaskDelegate;
class CreditCard;
class FormStructure;
class PersonalDataManager;
+class SaveCardBubbleController;
struct Suggestion;
// A client interface that needs to be supplied to the Autofill component by the
@@ -57,7 +59,7 @@ struct Suggestion;
// AutofillManager is used (e.g. a single tab), so when we say "for the client"
// below, we mean "in the execution context the client is associated with" (e.g.
// for the tab the AutofillManager is attached to).
-class AutofillClient {
+class AutofillClient : public RiskDataLoader {
public:
enum PaymentsRpcResult {
// Empty result. Used for initializing variables and should generally
@@ -89,7 +91,7 @@ class AutofillClient {
typedef base::Callback<void(const CreditCard&)> CreditCardScanCallback;
- virtual ~AutofillClient() {}
+ ~AutofillClient() override {}
// Gets the PersonalDataManager instance associated with the client.
virtual PersonalDataManager* GetPersonalDataManager() = 0;
@@ -109,9 +111,13 @@ class AutofillClient {
// Gets the RapporServiceImpl associated with the client (for metrics).
virtual rappor::RapporServiceImpl* GetRapporServiceImpl() = 0;
- // Gets the UKM service assiciated with this client (for metrics).
+ // Gets the UKM service associated with this client (for metrics).
virtual ukm::UkmService* GetUkmService() = 0;
+ // Gets the SaveCardBubbleController instance associated with the client.
+ // May return nullptr if the save card bubble has not been shown yet.
+ virtual SaveCardBubbleController* GetSaveCardBubbleController() = 0;
+
// Causes the Autofill settings UI to be shown.
virtual void ShowAutofillSettings() = 0;
@@ -128,10 +134,12 @@ class AutofillClient {
const base::Closure& callback) = 0;
// Runs |callback| if the |card| should be uploaded to Payments. Displays the
- // contents of |legal_message| to the user.
+ // contents of |legal_message| to the user. Display a CVC field in the bubble
+ // if |should_cvc_be_requested| is true.
virtual void ConfirmSaveCreditCardToCloud(
const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message,
+ bool should_cvc_be_requested,
const base::Closure& callback) = 0;
// Will show an infobar to get user consent for Credit Card assistive filling.
@@ -139,10 +147,6 @@ class AutofillClient {
virtual void ConfirmCreditCardFillAssist(const CreditCard& card,
const base::Closure& callback) = 0;
- // Gathers risk data and provides it to |callback|.
- virtual void LoadRiskData(
- const base::Callback<void(const std::string&)>& callback) = 0;
-
// Returns true if both the platform and the device support scanning credit
// cards. Should be called before ScanCreditCard().
virtual bool HasCreditCardScanFeature() = 0;
@@ -183,9 +187,6 @@ class AutofillClient {
const base::string16& autofilled_value,
const base::string16& profile_full_name) = 0;
- // Informs the client that a user gesture has been observed.
- virtual void OnFirstUserGestureObserved() = 0;
-
// If the context is secure.
virtual bool IsContextSecure() = 0;
diff --git a/chromium/components/autofill/core/browser/autofill_data_model_unittest.cc b/chromium/components/autofill/core/browser/autofill_data_model_unittest.cc
index 990217406a1..8432b105cf7 100644
--- a/chromium/components/autofill/core/browser/autofill_data_model_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_data_model_unittest.cc
@@ -71,53 +71,63 @@ TEST(AutofillDataModelTest, IsVerified) {
EXPECT_FALSE(model.IsVerified());
}
-TEST(AutofillDataModelTest, CompareFrecency) {
- base::Time now = base::Time::Now();
- enum Expectation { GREATER, LESS };
-
- struct {
- const std::string guid_a;
- const int use_count_a;
- const base::Time use_date_a;
- const std::string guid_b;
- const int use_count_b;
- const base::Time use_date_b;
- Expectation expectation;
- } test_cases[] = {
- // Same frecency, model_a has a smaller GUID (tie breaker).
- {"guid_a", 8, now, "guid_b", 8, now, LESS},
- // Same recency, model_a has a bigger frequency.
- {"guid_a", 10, now, "guid_b", 8, now, GREATER},
- // Same recency, model_a has a smaller frequency.
- {"guid_a", 8, now, "guid_b", 10, now, LESS},
- // Same frequency, model_a is more recent.
- {"guid_a", 8, now, "guid_b", 8, now - base::TimeDelta::FromDays(1),
- GREATER},
- // Same frequency, model_a is less recent.
- {"guid_a", 8, now - base::TimeDelta::FromDays(1), "guid_b", 8, now, LESS},
- // Special case: occasional profiles. A profile with relatively low usage
- // and used recently (model_b) should not rank higher than a more used
- // profile that has been unused for a short amount of time (model_a).
- {"guid_a", 300, now - base::TimeDelta::FromDays(5), "guid_b", 10,
- now - base::TimeDelta::FromDays(1), GREATER},
- // Special case: moving. A new profile used frequently (model_b) should
- // rank higher than a profile with more usage that has not been used for a
- // while (model_a).
- {"guid_a", 300, now - base::TimeDelta::FromDays(15), "guid_b", 10,
- now - base::TimeDelta::FromDays(1), LESS},
- };
-
- for (auto test_case : test_cases) {
- TestAutofillDataModel model_a(test_case.guid_a, test_case.use_count_a,
- test_case.use_date_a);
- TestAutofillDataModel model_b(test_case.guid_b, test_case.use_count_b,
- test_case.use_date_b);
-
- EXPECT_EQ(test_case.expectation == GREATER,
- model_a.CompareFrecency(&model_b, now));
- EXPECT_NE(test_case.expectation == GREATER,
- model_b.CompareFrecency(&model_a, now));
- }
+enum Expectation { GREATER, LESS };
+struct CompareFrecencyTestCase {
+ const std::string guid_a;
+ const int use_count_a;
+ const base::Time use_date_a;
+ const std::string guid_b;
+ const int use_count_b;
+ const base::Time use_date_b;
+ Expectation expectation;
+};
+
+base::Time now = base::Time::Now();
+
+class CompareFrecencyTest
+ : public testing::TestWithParam<CompareFrecencyTestCase> {};
+
+TEST_P(CompareFrecencyTest, CompareFrecency) {
+ auto test_case = GetParam();
+ TestAutofillDataModel model_a(test_case.guid_a, test_case.use_count_a,
+ test_case.use_date_a);
+ TestAutofillDataModel model_b(test_case.guid_b, test_case.use_count_b,
+ test_case.use_date_b);
+
+ EXPECT_EQ(test_case.expectation == GREATER,
+ model_a.CompareFrecency(&model_b, now));
+ EXPECT_NE(test_case.expectation == GREATER,
+ model_b.CompareFrecency(&model_a, now));
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillDataModelTest,
+ CompareFrecencyTest,
+ testing::Values(
+ // Same frecency, model_a has a smaller GUID (tie breaker).
+ CompareFrecencyTestCase{"guid_a", 8, now, "guid_b", 8, now, LESS},
+ // Same recency, model_a has a bigger frequency.
+ CompareFrecencyTestCase{"guid_a", 10, now, "guid_b", 8, now, GREATER},
+ // Same recency, model_a has a smaller frequency.
+ CompareFrecencyTestCase{"guid_a", 8, now, "guid_b", 10, now, LESS},
+ // Same frequency, model_a is more recent.
+ CompareFrecencyTestCase{"guid_a", 8, now, "guid_b", 8,
+ now - base::TimeDelta::FromDays(1), GREATER},
+ // Same frequency, model_a is less recent.
+ CompareFrecencyTestCase{"guid_a", 8, now - base::TimeDelta::FromDays(1),
+ "guid_b", 8, now, LESS},
+ // Special case: occasional profiles. A profile with relatively low
+ // usage and used recently (model_b) should not rank higher than a more
+ // used profile that has been unused for a short amount of time
+ // (model_a).
+ CompareFrecencyTestCase{
+ "guid_a", 300, now - base::TimeDelta::FromDays(5), "guid_b", 10,
+ now - base::TimeDelta::FromDays(1), GREATER},
+ // Special case: moving. A new profile used frequently (model_b) should
+ // rank higher than a profile with more usage that has not been used for
+ // a while (model_a).
+ CompareFrecencyTestCase{"guid_a", 300,
+ now - base::TimeDelta::FromDays(15), "guid_b",
+ 10, now - base::TimeDelta::FromDays(1), LESS}));
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc b/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc
index 584690d7871..9aadd58bf4f 100644
--- a/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc
@@ -11,151 +11,166 @@
namespace autofill {
namespace data_util {
-TEST(AutofillDataUtilTest, IsCJKName) {
- typedef struct {
- const char* full_name;
- bool is_cjk;
- } TestCase;
-
- TestCase test_cases[] = {
- // Non-CJK language with only ASCII characters.
- {"Homer Jay Simpson", false},
- // Non-CJK language with some ASCII characters.
- {"Éloïse Paré", false},
- // Non-CJK language with no ASCII characters.
- {"ΣωκÏάτης", false},
-
- // (Simplified) Chinese name, Unihan.
- {"刘翔", true},
- // (Simplified) Chinese name, Unihan, with an ASCII space.
- {"æˆ é¾™", true},
- // Korean name, Hangul.
- {"송지효", true},
- // Korean name, Hangul, with an 'IDEOGRAPHIC SPACE' (U+3000).
- {"김 종국", true},
- // Japanese name, Unihan.
- {"山田貴洋", true},
- // Japanese name, Katakana, with a 'KATAKANA MIDDLE DOT' (U+30FB).
- {"ビル・ゲイツ", true},
- // Japanese name, Katakana, with a 'MIDDLE DOT' (U+00B7) (likely a typo).
- {"ビル·ゲイツ", true},
-
- // CJK names don't have a middle name, so a 3-part name is bogus to us.
- {"반 기 문", false}
- };
-
- for (const TestCase& test_case : test_cases) {
- EXPECT_EQ(test_case.is_cjk,
- IsCJKName(base::UTF8ToUTF16(test_case.full_name)))
- << "Failed for: " << test_case.full_name;
- }
+struct IsCJKNameTestCase {
+ const char* full_name;
+ bool is_cjk;
+};
+
+class IsCJKNameTest : public testing::TestWithParam<IsCJKNameTestCase> {};
+
+TEST_P(IsCJKNameTest, IsCJKName) {
+ auto test_case = GetParam();
+ EXPECT_EQ(test_case.is_cjk, IsCJKName(base::UTF8ToUTF16(test_case.full_name)))
+ << "Failed for: " << test_case.full_name;
}
-TEST(AutofillDataUtilTest, SplitName) {
- typedef struct {
- std::string full_name;
- std::string given_name;
- std::string middle_name;
- std::string family_name;
-
- } TestCase;
-
- const TestCase test_cases[] = {
- // Full name including given, middle and family names.
- {"Homer Jay Simpson", "Homer", "Jay", "Simpson"},
- // No middle name.
- {"Moe Szyslak", "Moe", "", "Szyslak"},
- // Common name prefixes removed.
- {"Reverend Timothy Lovejoy", "Timothy", "", "Lovejoy"},
- // Common name suffixes removed.
- {"John Frink Phd", "John", "", "Frink"},
- // Exception to the name suffix removal.
- {"John Ma", "John", "", "Ma"},
- // Common family name prefixes not considered a middle name.
- {"Milhouse Van Houten", "Milhouse", "", "Van Houten"},
-
- // CJK names have reverse order (surname goes first, given name goes
- // second).
- {"孫 德明", "德明", "", "孫"}, // Chinese name, Unihan
- {"孫 德明", "德明", "", "孫"}, // Chinese name, Unihan, 'IDEOGRAPHIC SPACE'
- {"í™ ê¸¸ë™", "길ë™", "", "í™"}, // Korean name, Hangul
- {"山田 貴洋", "貴洋", "", "山田"}, // Japanese name, Unihan
-
- // In Japanese, foreign names use 'KATAKANA MIDDLE DOT' (U+30FB) as a
- // separator. There is no consensus for the ordering. For now, we use the
- // same ordering as regular Japanese names ("last・first").
- {"ゲイツ・ビル", "ビル", "", "ゲイツ"}, // Foreign name in Japanese, Katakana
- // 'KATAKANA MIDDLE DOT' is occasionally typoed as 'MIDDLE DOT' (U+00B7).
- {"ゲイツ·ビル", "ビル", "", "ゲイツ"}, // Foreign name in Japanese, Katakana
-
- // CJK names don't usually have a space in the middle, but most of the
- // time, the surname is only one character (in Chinese & Korean).
- {"최성훈", "성훈", "", "최"}, // Korean name, Hangul
- {"刘翔", "翔", "", "刘"}, // (Simplified) Chinese name, Unihan
- {"劉翔", "翔", "", "劉"}, // (Traditional) Chinese name, Unihan
-
- // There are a few exceptions. Occasionally, the surname has two
- // characters.
- {"남ê¶ë„", "ë„", "", "남ê¶"}, // Korean name, Hangul
- {"황보혜정", "혜정", "", "황보"}, // Korean name, Hangul
- {"æ­é™½é–", "é–", "", "æ­é™½"}, // (Traditional) Chinese name, Unihan
-
- // In Korean, some 2-character surnames are rare/ambiguous, like "ê°•ì „":
- // "ê°•" is a common surname, and "ì „" can be part of a given name. In
- // those cases, we assume it's 1/2 for 3-character names, or 2/2 for
- // 4-character names.
- {"ê°•ì „í¬", "ì „í¬", "", "ê°•"}, // Korean name, Hangul
- {"황목치승", "치승", "", "황목"}, // Korean name, Hangul
-
- // It occasionally happens that a full name is 2 characters, 1/1.
- {"ì´ë„", "ë„", "", "ì´"}, // Korean name, Hangul
- {"å­«æ–‡", "æ–‡", "", "å­«"} // Chinese name, Unihan
- };
-
- for (TestCase test_case : test_cases) {
- NameParts name_parts = SplitName(base::UTF8ToUTF16(test_case.full_name));
-
- EXPECT_EQ(base::UTF8ToUTF16(test_case.given_name), name_parts.given);
- EXPECT_EQ(base::UTF8ToUTF16(test_case.middle_name), name_parts.middle);
- EXPECT_EQ(base::UTF8ToUTF16(test_case.family_name), name_parts.family);
- }
+INSTANTIATE_TEST_CASE_P(
+ AutofillDataUtilTest,
+ IsCJKNameTest,
+ testing::Values(
+ // Non-CJK language with only ASCII characters.
+ IsCJKNameTestCase{"Homer Jay Simpson", false},
+ // Non-CJK language with some ASCII characters.
+ IsCJKNameTestCase{"Éloïse Paré", false},
+ // Non-CJK language with no ASCII characters.
+ IsCJKNameTestCase{"ΣωκÏάτης", false},
+
+ // (Simplified) Chinese name, Unihan.
+ IsCJKNameTestCase{"刘翔", true},
+ // (Simplified) Chinese name, Unihan, with an ASCII space.
+ IsCJKNameTestCase{"æˆ é¾™", true},
+ // Korean name, Hangul.
+ IsCJKNameTestCase{"송지효", true},
+ // Korean name, Hangul, with an 'IDEOGRAPHIC SPACE' (U+3000).
+ IsCJKNameTestCase{"김 종국", true},
+ // Japanese name, Unihan.
+ IsCJKNameTestCase{"山田貴洋", true},
+ // Japanese name, Katakana, with a 'KATAKANA MIDDLE DOT' (U+30FB).
+ IsCJKNameTestCase{"ビル・ゲイツ", true},
+ // Japanese name, Katakana, with a 'MIDDLE DOT' (U+00B7) (likely a
+ // typo).
+ IsCJKNameTestCase{"ビル·ゲイツ", true},
+
+ // CJK names don't have a middle name, so a 3-part name is bogus to us.
+ IsCJKNameTestCase{"반 기 문", false}));
+
+struct FullNameTestCase {
+ std::string full_name;
+ std::string given_name;
+ std::string middle_name;
+ std::string family_name;
+};
+
+class SplitNameTest : public testing::TestWithParam<FullNameTestCase> {};
+
+TEST_P(SplitNameTest, SplitName) {
+ auto test_case = GetParam();
+ NameParts name_parts = SplitName(base::UTF8ToUTF16(test_case.full_name));
+
+ EXPECT_EQ(base::UTF8ToUTF16(test_case.given_name), name_parts.given);
+ EXPECT_EQ(base::UTF8ToUTF16(test_case.middle_name), name_parts.middle);
+ EXPECT_EQ(base::UTF8ToUTF16(test_case.family_name), name_parts.family);
}
-TEST(AutofillDataUtilTest, JoinNameParts) {
- typedef struct {
- std::string given_name;
- std::string middle_name;
- std::string family_name;
- std::string full_name;
- } TestCase;
-
- TestCase test_cases[] = {
- // Full name including given, middle and family names.
- {"Homer", "Jay", "Simpson", "Homer Jay Simpson"},
- // No middle name.
- {"Moe", "", "Szyslak", "Moe Szyslak"},
-
- // CJK names have reversed order, no space.
- {"德明", "", "孫", "孫德明"}, // Chinese name, Unihan
- {"길ë™", "", "í™", "í™ê¸¸ë™"}, // Korean name, Hangul
- {"貴洋", "", "山田", "山田貴洋"}, // Japanese name, Unihan
-
- // These are no CJK names for us, they're just bogus.
- {"Homer", "", "シンプソン", "Homer シンプソン"},
- {"ホーマー", "", "Simpson", "ホーマー Simpson"},
- {"반", "기", "문", "반 기 문"} // Has a middle-name, too unusual
- };
-
- for (const TestCase& test_case : test_cases) {
- base::string16 joined = JoinNameParts(
- base::UTF8ToUTF16(test_case.given_name),
- base::UTF8ToUTF16(test_case.middle_name),
- base::UTF8ToUTF16(test_case.family_name));
-
- EXPECT_EQ(base::UTF8ToUTF16(test_case.full_name), joined);
- }
+INSTANTIATE_TEST_CASE_P(
+ AutofillDataUtil,
+ SplitNameTest,
+ testing::Values(
+ // Full name including given, middle and family names.
+ FullNameTestCase{"Homer Jay Simpson", "Homer", "Jay", "Simpson"},
+ // No middle name.
+ FullNameTestCase{"Moe Szyslak", "Moe", "", "Szyslak"},
+ // Common name prefixes removed.
+ FullNameTestCase{"Reverend Timothy Lovejoy", "Timothy", "", "Lovejoy"},
+ // Common name suffixes removed.
+ FullNameTestCase{"John Frink Phd", "John", "", "Frink"},
+ // Exception to the name suffix removal.
+ FullNameTestCase{"John Ma", "John", "", "Ma"},
+ // Common family name prefixes not considered a middle name.
+ FullNameTestCase{"Milhouse Van Houten", "Milhouse", "", "Van Houten"},
+
+ // CJK names have reverse order (surname goes first, given name goes
+ // second).
+ FullNameTestCase{"孫 德明", "德明", "", "孫"}, // Chinese name, Unihan
+ FullNameTestCase{"孫 德明", "德明", "",
+ "å­«"}, // Chinese name, Unihan, 'IDEOGRAPHIC SPACE'
+ FullNameTestCase{"í™ ê¸¸ë™", "길ë™", "", "í™"}, // Korean name, Hangul
+ FullNameTestCase{"山田 貴洋", "貴洋", "",
+ "山田"}, // Japanese name, Unihan
+
+ // In Japanese, foreign names use 'KATAKANA MIDDLE DOT' (U+30FB) as a
+ // separator. There is no consensus for the ordering. For now, we use
+ // the same ordering as regular Japanese names ("last・first").
+ FullNameTestCase{"ゲイツ・ビル", "ビル", "",
+ "ゲイツ"}, // Foreign name in Japanese, Katakana
+ // 'KATAKANA MIDDLE DOT' is occasionally typoed as 'MIDDLE DOT'
+ // (U+00B7).
+ FullNameTestCase{"ゲイツ·ビル", "ビル", "",
+ "ゲイツ"}, // Foreign name in Japanese, Katakana
+
+ // CJK names don't usually have a space in the middle, but most of the
+ // time, the surname is only one character (in Chinese & Korean).
+ FullNameTestCase{"최성훈", "성훈", "", "최"}, // Korean name, Hangul
+ FullNameTestCase{"刘翔", "翔", "",
+ "刘"}, // (Simplified) Chinese name, Unihan
+ FullNameTestCase{"劉翔", "翔", "",
+ "劉"}, // (Traditional) Chinese name, Unihan
+
+ // There are a few exceptions. Occasionally, the surname has two
+ // characters.
+ FullNameTestCase{"남ê¶ë„", "ë„", "", "남ê¶"}, // Korean name, Hangul
+ FullNameTestCase{"황보혜정", "혜정", "",
+ "황보"}, // Korean name, Hangul
+ FullNameTestCase{"æ­é™½é–", "é–", "",
+ "æ­é™½"}, // (Traditional) Chinese name, Unihan
+
+ // In Korean, some 2-character surnames are rare/ambiguous, like "ê°•ì „":
+ // "ê°•" is a common surname, and "ì „" can be part of a given name. In
+ // those cases, we assume it's 1/2 for 3-character names, or 2/2 for
+ // 4-character names.
+ FullNameTestCase{"ê°•ì „í¬", "ì „í¬", "", "ê°•"}, // Korean name, Hangul
+ FullNameTestCase{"황목치승", "치승", "",
+ "황목"}, // Korean name, Hangul
+
+ // It occasionally happens that a full name is 2 characters, 1/1.
+ FullNameTestCase{"ì´ë„", "ë„", "", "ì´"}, // Korean name, Hangul
+ FullNameTestCase{"å­«æ–‡", "æ–‡", "", "å­«"} // Chinese name, Unihan
+ ));
+
+class JoinNamePartsTest : public testing::TestWithParam<FullNameTestCase> {};
+
+TEST_P(JoinNamePartsTest, JoinNameParts) {
+ auto test_case = GetParam();
+ base::string16 joined =
+ JoinNameParts(base::UTF8ToUTF16(test_case.given_name),
+ base::UTF8ToUTF16(test_case.middle_name),
+ base::UTF8ToUTF16(test_case.family_name));
+
+ EXPECT_EQ(base::UTF8ToUTF16(test_case.full_name), joined);
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillDataUtil,
+ JoinNamePartsTest,
+ testing::Values(
+ // Full name including given, middle and family names.
+ FullNameTestCase{"Homer Jay Simpson", "Homer", "Jay", "Simpson"},
+ // No middle name.
+ FullNameTestCase{"Moe Szyslak", "Moe", "", "Szyslak"},
+
+ // CJK names have reversed order, no space.
+ FullNameTestCase{"孫德明", "德明", "", "孫"}, // Chinese name, Unihan
+ FullNameTestCase{"í™ê¸¸ë™", "길ë™", "", "í™"}, // Korean name, Hangul
+ FullNameTestCase{"山田貴洋", "貴洋", "",
+ "山田"}, // Japanese name, Unihan
+
+ // These are no CJK names for us, they're just bogus.
+ FullNameTestCase{"Homer シンプソン", "Homer", "", "シンプソン"},
+ FullNameTestCase{"ホーマー Simpson", "ホーマー", "", "Simpson"},
+ FullNameTestCase{"반 기 문", "반", "기", "문"}
+ // Has a middle-name, too unusual
+ ));
+
TEST(AutofillDataUtilTest, ProfileMatchesFullName) {
autofill::AutofillProfile profile;
autofill::test::SetProfileInfo(
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.cc b/chromium/components/autofill/core/browser/autofill_download_manager.cc
index 07084c52be4..8d7d72588f4 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager.cc
@@ -24,9 +24,82 @@
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h"
#include "url/gurl.h"
+namespace {
+
+net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotation(
+ const autofill::AutofillDownloadManager::RequestType& request_type) {
+ if (request_type == autofill::AutofillDownloadManager::REQUEST_QUERY) {
+ return net::DefineNetworkTrafficAnnotation("autofill_query", R"(
+ semantics {
+ sender: "Autofill"
+ description:
+ "Chromium can automatically fill in web forms. If the feature is "
+ "enabled, Chromium will send a non-identifying description of the "
+ "form to Google's servers, which will respond with the type of "
+ "data required by each of the form's fields, if known. I.e., if a "
+ "field expects to receive a name, phone number, street address, "
+ "etc."
+ trigger: "User encounters a web form."
+ data:
+ "Hashed descriptions of the form and its fields. User data is not "
+ "sent."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "You can enable or disable this feature via 'Enable autofill to "
+ "fill out web forms in a single click.' in Chromium's settings "
+ "under 'Passwords and forms'. The feature is enabled by default."
+ chrome_policy {
+ AutoFillEnabled {
+ policy_options {mode: MANDATORY}
+ AutoFillEnabled: false
+ }
+ }
+ })");
+ }
+
+ DCHECK_EQ(request_type, autofill::AutofillDownloadManager::REQUEST_UPLOAD);
+ return net::DefineNetworkTrafficAnnotation("autofill_upload", R"(
+ semantics {
+ sender: "Autofill"
+ description:
+ "Chromium relies on crowd-sourced field type classifications to "
+ "help it automatically fill in web forms. If the feature is "
+ "enabled, Chromium will send a non-identifying description of the "
+ "form to Google's servers along with the type of data Chromium "
+ "observed being given to the form. I.e., if you entered your first "
+ "name into a form field, Chromium will 'vote' for that form field "
+ "being a first name field."
+ trigger: "User submits a web form."
+ data:
+ "Hashed descriptions of the form and its fields along with type of "
+ "data given to each field, if recognized from the user's "
+ "profile(s). User data is not sent."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "You can enable or disable this feature via 'Enable autofill to "
+ "fill out web forms in a single click.' in Chromium's settings "
+ "under 'Passwords and forms'. The feature is enabled by default."
+ chrome_policy {
+ AutoFillEnabled {
+ policy_options {mode: MANDATORY}
+ AutoFillEnabled: false
+ }
+ }
+ })");
+}
+
+} // namespace
+
namespace autofill {
namespace {
@@ -234,7 +307,8 @@ bool AutofillDownloadManager::StartRequest(
// Id is ignored for regular chrome, in unit test id's for fake fetcher
// factory will be 0, 1, 2, ...
std::unique_ptr<net::URLFetcher> owned_fetcher = net::URLFetcher::Create(
- fetcher_id_for_unittest_++, request_url, net::URLFetcher::POST, this);
+ fetcher_id_for_unittest_++, request_url, net::URLFetcher::POST, this,
+ GetNetworkTrafficAnnotation(request_data.request_type));
net::URLFetcher* fetcher = owned_fetcher.get();
data_use_measurement::DataUseUserData::AttachToFetcher(
fetcher, data_use_measurement::DataUseUserData::AUTOFILL);
@@ -251,7 +325,7 @@ bool AutofillDownloadManager::StartRequest(
// not affect transmission of experiments coming from the variations server.
bool is_signed_in = false;
variations::AppendVariationHeaders(fetcher->GetOriginalURL(),
- driver_->IsOffTheRecord(), false,
+ driver_->IsIncognito(), false,
is_signed_in, &headers);
fetcher->SetExtraRequestHeaders(headers.ToString());
fetcher->Start();
diff --git a/chromium/components/autofill/core/browser/autofill_driver.h b/chromium/components/autofill/core/browser/autofill_driver.h
index e8b95d87a02..cc1a5fd38c1 100644
--- a/chromium/components/autofill/core/browser/autofill_driver.h
+++ b/chromium/components/autofill/core/browser/autofill_driver.h
@@ -40,9 +40,8 @@ class AutofillDriver {
virtual ~AutofillDriver() {}
- // Returns whether the user is currently operating in an off-the-record
- // (i.e., incognito) context.
- virtual bool IsOffTheRecord() const = 0;
+ // Returns whether the user is currently operating in an incognito context.
+ virtual bool IsIncognito() const = 0;
// Returns the URL request context information associated with this driver.
virtual net::URLRequestContextGetter* GetURLRequestContext() = 0;
@@ -103,10 +102,6 @@ class AutofillDriver {
// Called when the user interacted with a credit card form, so that
// the current page's security state can be updated appropriately.
virtual void DidInteractWithCreditCardForm() = 0;
-
- // Tells the associated frame that a user gesture was observed somewhere in
- // the tab (including in a different frame).
- virtual void NotifyFirstUserGestureObservedInTab() {}
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_driver_factory.cc b/chromium/components/autofill/core/browser/autofill_driver_factory.cc
index 224c1efde47..58ec815c2ba 100644
--- a/chromium/components/autofill/core/browser/autofill_driver_factory.cc
+++ b/chromium/components/autofill/core/browser/autofill_driver_factory.cc
@@ -21,7 +21,6 @@ AutofillDriver* AutofillDriverFactory::DriverForKey(void* key) {
}
void AutofillDriverFactory::NavigationFinished() {
- user_gesture_seen_ = false;
client_->HideAutofillPopup();
}
@@ -29,16 +28,6 @@ void AutofillDriverFactory::TabHidden() {
client_->HideAutofillPopup();
}
-void AutofillDriverFactory::OnFirstUserGestureObserved() {
- if (user_gesture_seen_)
- return;
-
- for (auto& driver : driver_map_)
- driver.second->NotifyFirstUserGestureObservedInTab();
-
- user_gesture_seen_ = true;
-}
-
void AutofillDriverFactory::AddForKey(
void* key,
base::Callback<std::unique_ptr<AutofillDriver>()> factory_method) {
@@ -46,8 +35,6 @@ void AutofillDriverFactory::AddForKey(
// This can be called twice for the key representing the main frame.
if (insertion_result.second) {
insertion_result.first->second = factory_method.Run();
- if (user_gesture_seen_)
- insertion_result.first->second->NotifyFirstUserGestureObservedInTab();
}
}
diff --git a/chromium/components/autofill/core/browser/autofill_driver_factory.h b/chromium/components/autofill/core/browser/autofill_driver_factory.h
index ff48bb67ec3..f5e21c68257 100644
--- a/chromium/components/autofill/core/browser/autofill_driver_factory.h
+++ b/chromium/components/autofill/core/browser/autofill_driver_factory.h
@@ -34,12 +34,6 @@ class AutofillDriverFactory {
// Handles hiding of the corresponding tab.
void TabHidden();
- // Call this to notify the factory that one of the frames saw a user gesture.
- // The factory will distribute this information to all drivers when it comes
- // for the first time since the last main frame navigation to a different
- // page. It will also notify drivers added later (see AddForKey).
- void OnFirstUserGestureObserved();
-
AutofillClient* client() { return client_; };
protected:
@@ -61,8 +55,6 @@ class AutofillDriverFactory {
std::unordered_map<void*, std::unique_ptr<AutofillDriver>> driver_map_;
- bool user_gesture_seen_ = false; // The state for OnFirstUserGestureObserved.
-
DISALLOW_COPY_AND_ASSIGN(AutofillDriverFactory);
};
diff --git a/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc b/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc
index 8355161333c..fdc88828cb2 100644
--- a/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc
@@ -36,19 +36,8 @@ class CountingAutofillDriver : public TestAutofillDriver {
~CountingAutofillDriver() override { --*instance_counter_; }
- // Note that EXPECT_CALL cannot be used here, because creation and
- // notification of the same driver might be done by a single AddForKey call
- // from the test. Therefore tracking the "gesture_observed" flag is done
- // explicitly here.
- void NotifyFirstUserGestureObservedInTab() override {
- gesture_observed_ = true;
- }
-
- bool gesture_observed() { return gesture_observed_; }
-
private:
int* const instance_counter_;
- bool gesture_observed_ = false;
DISALLOW_COPY_AND_ASSIGN(CountingAutofillDriver);
};
@@ -187,54 +176,4 @@ TEST_F(AutofillDriverFactoryTest, TabHidden) {
factory_.TabHidden();
}
-// Without calling OnFirstUserGestureObserved on the factory, the factory will
-// not call NotifyFirstUserGestureObservedInTab on a driver.
-TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_NotCalled) {
- factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
- EXPECT_FALSE(GetDriver(KeyFrom(1))->gesture_observed());
-}
-
-// Call OnFirstUserGestureObserved on the factory with one driver. The factory
-// will call NotifyFirstUserGestureObservedInTab on that driver.
-TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_CalledOld) {
- factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
- factory_.OnFirstUserGestureObserved();
- EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed());
-}
-
-// Call OnFirstUserGestureObserved on the factory without drivers. Add a
-// driver. The factory will call NotifyFirstUserGestureObservedInTab on that
-// driver.
-TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_CalledNew) {
- factory_.OnFirstUserGestureObserved();
- factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
- EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed());
-}
-
-// Combining the CalledOld and CalledNew test cases into one.
-TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_MultipleDrivers) {
- factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
- factory_.OnFirstUserGestureObserved();
- EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed());
-
- factory_.AddForKey(KeyFrom(7), CreateDriverCallback());
- EXPECT_TRUE(GetDriver(KeyFrom(7))->gesture_observed());
-}
-
-// Call OnFirstUserGestureObserved on the factory with one driver. Simulate
-// navigation to a different page. Add a driver. The factory will not call
-// NotifyFirstUserGestureObservedInTab on that driver.
-TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_CalledNavigation) {
- factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
- factory_.OnFirstUserGestureObserved();
- EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed());
-
- EXPECT_CALL(client_, HideAutofillPopup());
- factory_.NavigationFinished();
-
- // Adding a sub-frame
- factory_.AddForKey(KeyFrom(2), CreateDriverCallback());
- EXPECT_FALSE(GetDriver(KeyFrom(2))->gesture_observed());
-}
-
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_experiments.cc b/chromium/components/autofill/core/browser/autofill_experiments.cc
index b27569f4d8c..ef37213e57a 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments.cc
+++ b/chromium/components/autofill/core/browser/autofill_experiments.cc
@@ -32,8 +32,10 @@ const base::Feature kAutofillCreditCardPopupLayout{
"AutofillCreditCardPopupLayout", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kAutofillCreditCardLastUsedDateDisplay{
"AutofillCreditCardLastUsedDateDisplay", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kAutofillUkmLogging{"kAutofillUkmLogging",
+const base::Feature kAutofillUkmLogging{"AutofillUkmLogging",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillUpstreamRequestCvcIfMissing{
+ "AutofillUpstreamRequestCvcIfMissing", base::FEATURE_DISABLED_BY_DEFAULT};
const char kCreditCardSigninPromoImpressionLimitParamKey[] = "impression_limit";
const char kAutofillCreditCardPopupBackgroundColorKey[] = "background_color";
const char kAutofillCreditCardPopupDividerColorKey[] = "dropdown_divider_color";
@@ -229,4 +231,12 @@ bool IsUkmLoggingEnabled() {
return base::FeatureList::IsEnabled(kAutofillUkmLogging);
}
+bool IsAutofillUpstreamRequestCvcIfMissingExperimentEnabled() {
+#if defined(OS_ANDROID)
+ return false;
+#else
+ return base::FeatureList::IsEnabled(kAutofillUpstreamRequestCvcIfMissing);
+#endif
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_experiments.h b/chromium/components/autofill/core/browser/autofill_experiments.h
index 70c3f411c60..ba03ac21eb7 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments.h
+++ b/chromium/components/autofill/core/browser/autofill_experiments.h
@@ -29,6 +29,7 @@ extern const base::Feature kAutofillScanCardholderName;
extern const base::Feature kAutofillCreditCardPopupLayout;
extern const base::Feature kAutofillCreditCardLastUsedDateDisplay;
extern const base::Feature kAutofillUkmLogging;
+extern const base::Feature kAutofillUpstreamRequestCvcIfMissing;
extern const char kCreditCardSigninPromoImpressionLimitParamKey[];
extern const char kAutofillCreditCardPopupSettingsSuggestionValueKey[];
extern const char kAutofillCreditCardLastUsedDateShowExpirationDateKey[];
@@ -104,6 +105,10 @@ unsigned int GetPopupMargin();
// Returns whether the feature to log UKMs is enabled.
bool IsUkmLoggingEnabled();
+// Returns whether the experiment is enabled where Chrome Upstream requests CVC
+// in the offer to save bubble if it was not detected during the checkout flow.
+bool IsAutofillUpstreamRequestCvcIfMissingExperimentEnabled();
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_EXPERIMENTS_H_
diff --git a/chromium/components/autofill/core/browser/autofill_field_unittest.cc b/chromium/components/autofill/core/browser/autofill_field_unittest.cc
index ef4c0473f9a..5731f376ace 100644
--- a/chromium/components/autofill/core/browser/autofill_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_field_unittest.cc
@@ -283,181 +283,240 @@ TEST_F(AutofillFieldTest, FillFormField_AutocompleteOff_CreditCardField) {
EXPECT_EQ(ASCIIToUTF16("4111111111111111"), field.value);
}
+struct AutofillFieldTestCase {
+ HtmlFieldType field_type;
+ size_t field_max_length;
+ std::string value_to_fill;
+ std::string expected_value;
+};
+
+class AutofillFieldPhoneNumberTest
+ : public testing::TestWithParam<AutofillFieldTestCase> {
+ public:
+ AutofillFieldPhoneNumberTest() { CountryNames::SetLocaleString("en-US"); }
+};
+
// TODO(crbug.com/581514): Add support for filling only the prefix/suffix for
// phone numbers with 10 or 11 digits.
-TEST_F(AutofillFieldTest, FillPhoneNumber) {
- typedef struct {
- HtmlFieldType field_type;
- size_t field_max_length;
- std::string value_to_fill;
- std::string expected_value;
- } TestCase;
-
- TestCase test_cases[] = {
- // Filling a phone type field with text should fill the text as is.
- {HTML_TYPE_TEL, /* default value */ 0, "Oh hai", "Oh hai"},
- // Filling a prefix type field with a phone number of 7 digits should just
- // fill the prefix.
- {HTML_TYPE_TEL_LOCAL_PREFIX, /* default value */ 0, "5551234", "555"},
- // Filling a suffix type field with a phone number of 7 digits should just
- // fill the suffix.
- {HTML_TYPE_TEL_LOCAL_SUFFIX, /* default value */ 0, "5551234", "1234"},
- // Filling a phone type field with a max length of 3 with a phone number
- // of
- // 7 digits should fill only the prefix.
- {HTML_TYPE_TEL, 3, "5551234", "555"},
- // Filling a phone type field with a max length of 4 with a phone number
- // of
- // 7 digits should fill only the suffix.
- {HTML_TYPE_TEL, 4, "5551234", "1234"},
- // Filling a phone type field with a max length of 10 with a phone number
- // including the country code should fill the phone number without the
- // country code.
- {HTML_TYPE_TEL, 10, "15141254578", "5141254578"},
- // Filling a phone type field with a max length of 5 with a phone number
- // should fill with the last 5 digits of that phone number.
- {HTML_TYPE_TEL, 5, "5141254578", "54578"}};
-
- for (TestCase test_case : test_cases) {
- AutofillField field;
- field.SetHtmlType(test_case.field_type, HtmlFieldMode());
- field.max_length = test_case.field_max_length;
-
- AutofillField::FillFormField(field, ASCIIToUTF16(test_case.value_to_fill),
- "en-US", "en-US", &field);
- EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
- }
+TEST_P(AutofillFieldPhoneNumberTest, FillPhoneNumber) {
+ auto test_case = GetParam();
+ AutofillField field;
+ field.SetHtmlType(test_case.field_type, HtmlFieldMode());
+ field.max_length = test_case.field_max_length;
+
+ AutofillField::FillFormField(field, ASCIIToUTF16(test_case.value_to_fill),
+ "en-US", "en-US", &field);
+ EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
}
-TEST_F(AutofillFieldTest, FillExpirationYearInput) {
- typedef struct {
- HtmlFieldType field_type;
- size_t field_max_length;
- std::string value_to_fill;
- std::string expected_value;
- } TestCase;
-
- TestCase test_cases[] = {
- // A field predicted as a 2 digits expiration year should fill the last 2
- // digits of the expiration year if the field has an unspecified max
- // length (0) or if it's greater than 1.
- {HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR, /* default value */ 0, "2023",
- "23"},
- {HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR, 2, "2023", "23"},
- {HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR, 12, "2023", "23"},
- // A field predicted as a 2 digit expiration year should fill the last
- // digit of the expiration year if the field has a max length of 1.
- {HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR, 1, "2023", "3"},
- // A field predicted as a 4 digit expiration year should fill the 4
- // digits of the expiration year if the field has an unspecified max
- // length (0) or if it's greater than 3 .
- {HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, /* default value */ 0, "2023",
- "2023"},
- {HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 4, "2023", "2023"},
- {HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 12, "2023", "2023"},
- // A field predicted as a 4 digits expiration year should fill the last 2
- // digits of the expiration year if the field has a max length of 2.
- {HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 2, "2023", "23"},
- // A field predicted as a 4 digits expiration year should fill the last
- // digit of the expiration year if the field has a max length of 1.
- {HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 1, "2023", "3"},
- };
+INSTANTIATE_TEST_CASE_P(
+ AutofillFieldTest,
+ AutofillFieldPhoneNumberTest,
+ testing::Values(
+ // Filling a phone type field with text should fill the text as is.
+ AutofillFieldTestCase{HTML_TYPE_TEL, /* default value */ 0, "Oh hai",
+ "Oh hai"},
+ // Filling a prefix type field with a phone number of 7 digits should
+ // just fill the prefix.
+ AutofillFieldTestCase{HTML_TYPE_TEL_LOCAL_PREFIX, /* default value */ 0,
+ "5551234", "555"},
+ // Filling a suffix type field with a phone number of 7 digits should
+ // just fill the suffix.
+ AutofillFieldTestCase{HTML_TYPE_TEL_LOCAL_SUFFIX, /* default value */ 0,
+ "5551234", "1234"},
+ // Filling a phone type field with a max length of 3 with a phone number
+ // of
+ // 7 digits should fill only the prefix.
+ AutofillFieldTestCase{HTML_TYPE_TEL, 3, "5551234", "555"},
+ // Filling a phone type field with a max length of 4 with a phone number
+ // of
+ // 7 digits should fill only the suffix.
+ AutofillFieldTestCase{HTML_TYPE_TEL, 4, "5551234", "1234"},
+ // Filling a phone type field with a max length of 10 with a phone
+ // number including the country code should fill the phone number
+ // without the country code.
+ AutofillFieldTestCase{HTML_TYPE_TEL, 10, "15141254578", "5141254578"},
+ // Filling a phone type field with a max length of 5 with a phone number
+ // should fill with the last 5 digits of that phone number.
+ AutofillFieldTestCase{HTML_TYPE_TEL, 5, "5141254578", "54578"}));
+
+class AutofillFieldExpirationYearTest
+ : public testing::TestWithParam<AutofillFieldTestCase> {
+ public:
+ AutofillFieldExpirationYearTest() { CountryNames::SetLocaleString("en-US"); }
+};
- for (TestCase test_case : test_cases) {
- AutofillField field;
- field.form_control_type = "text";
- field.SetHtmlType(test_case.field_type, HtmlFieldMode());
- field.max_length = test_case.field_max_length;
+TEST_P(AutofillFieldExpirationYearTest, FillExpirationYearInput) {
+ auto test_case = GetParam();
+ AutofillField field;
+ field.form_control_type = "text";
+ field.SetHtmlType(test_case.field_type, HtmlFieldMode());
+ field.max_length = test_case.field_max_length;
- AutofillField::FillFormField(field, ASCIIToUTF16(test_case.value_to_fill),
- "en-US", "en-US", &field);
- EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
- }
+ AutofillField::FillFormField(field, ASCIIToUTF16(test_case.value_to_fill),
+ "en-US", "en-US", &field);
+ EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
}
-TEST_F(AutofillFieldTest, FillExpirationDateInput) {
- typedef struct {
- HtmlFieldType field_type;
- size_t field_max_length;
- std::string value_to_fill;
- std::string expected_value;
- bool expected_response;
- } TestCase;
-
- TestCase test_cases[] = {
- // Test invalid inputs
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 0, "1/21", "", false},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 0, "01-21", "", false},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 0, "1/2021", "", false},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 0, "01-2021", "", false},
- // Trim whitespace
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 0, "01/22 ", "01/22",
- true},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 0, "01/2022 ", "01/2022",
- true},
- // A field predicted as a expiration date w/ 2 digit year should fill
- // with a format of MM/YY unless it has max-length of:
- // 4: Use format MMYY
- // 6: Use format MMYYYY
- // 7: Use format MM/YYYY
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, /* default value */ 0,
- "01/23", "01/23", true},
- // Unsupported max lengths of 1-3, fail
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 1, "01/23", "", false},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 2, "02/23", "", false},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 3, "03/23", "", false},
- // A max length of 4 indicates a format of MMYY.
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 4, "02/23", "0223", true},
- // A max length of 6 indicates a format of MMYYYY, the 21st century is
- // assumed.
- // Desired case of proper max length >= 5
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 5, "03/23", "03/23", true},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 6, "04/23", "042023", true},
- // A max length of 7 indicates a format of MM/YYYY, the 21st century is
- // assumed.
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 7, "05/23", "05/2023",
- true},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 12, "06/23", "06/23", true},
-
- // A field predicted as a expiration date w/ 4 digit year should fill
- // with a format of MM/YYYY unless it has max-length of:
- // 4: Use format MMYY
- // 5: Use format MM/YY
- // 6: Use format MMYYYY
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, /* default value */ 0,
- "01/2024", "01/2024", true},
- // Unsupported max lengths of 1-3, fail
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 1, "01/2024", "", false},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 2, "02/2024", "", false},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 3, "03/2024", "", false},
- // A max length of 4 indicates a format of MMYY.
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 4, "02/2024", "0224", true},
- // A max length of 5 indicates a format of MM/YY.
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 5, "03/2024", "03/24",
- true},
- // A max length of 6 indicates a format of MMYYYY.
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 6, "04/2024", "042024",
- true},
- // Desired case of proper max length >= 7
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 7, "05/2024", "05/2024",
- true},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 12, "06/2024", "06/2024",
- true},
- };
+INSTANTIATE_TEST_CASE_P(
+ AutofillFieldTest,
+ AutofillFieldExpirationYearTest,
+ testing::Values(
+ // A field predicted as a 2 digits expiration year should fill the last
+ // 2 digits of the expiration year if the field has an unspecified max
+ // length (0) or if it's greater than 1.
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR,
+ /* default value */ 0, "2023", "23"},
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR, 2, "2023",
+ "23"},
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR, 12,
+ "2023", "23"},
+ // A field predicted as a 2 digit expiration year should fill the last
+ // digit of the expiration year if the field has a max length of 1.
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR, 1, "2023",
+ "3"},
+ // A field predicted as a 4 digit expiration year should fill the 4
+ // digits of the expiration year if the field has an unspecified max
+ // length (0) or if it's greater than 3 .
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR,
+ /* default value */ 0, "2023", "2023"},
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 4, "2023",
+ "2023"},
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 12,
+ "2023", "2023"},
+ // A field predicted as a 4 digits expiration year should fill the last
+ // 2 digits of the expiration year if the field has a max length of 2.
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 2, "2023",
+ "23"},
+ // A field predicted as a 4 digits expiration year should fill the last
+ // digit of the expiration year if the field has a max length of 1.
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 1, "2023",
+ "3"}));
+
+struct AutofillFieldExpirationDateTestCase {
+ HtmlFieldType field_type;
+ size_t field_max_length;
+ std::string value_to_fill;
+ std::string expected_value;
+ bool expected_response;
+};
- for (TestCase test_case : test_cases) {
- AutofillField field;
- field.form_control_type = "text";
- field.SetHtmlType(test_case.field_type, HtmlFieldMode());
- field.max_length = test_case.field_max_length;
+class AutofillFieldExpirationDateTest
+ : public testing::TestWithParam<AutofillFieldExpirationDateTestCase> {
+ public:
+ AutofillFieldExpirationDateTest() { CountryNames::SetLocaleString("en-US"); }
+};
+
+TEST_P(AutofillFieldExpirationDateTest, FillExpirationDateInput) {
+ auto test_case = GetParam();
+ AutofillField field;
+ field.form_control_type = "text";
+ field.SetHtmlType(test_case.field_type, HtmlFieldMode());
+ field.max_length = test_case.field_max_length;
- bool response = AutofillField::FillFormField(
+ bool response = AutofillField::FillFormField(
field, ASCIIToUTF16(test_case.value_to_fill), "en-US", "en-US", &field);
- EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
- EXPECT_EQ(response, test_case.expected_response);
- }
+ EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
+ EXPECT_EQ(response, test_case.expected_response);
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillFieldTest,
+ AutofillFieldExpirationDateTest,
+ testing::Values(
+ // Test invalid inputs
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 0, "1/21", "", false},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 0, "01-21", "", false},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 0, "1/2021", "",
+ false},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 0, "01-2021", "",
+ false},
+ // Trim whitespace
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 0, "01/22 ", "01/22",
+ true},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 0, "01/2022 ",
+ "01/2022", true},
+ // A field predicted as a expiration date w/ 2 digit year should fill
+ // with a format of MM/YY unless it has max-length of:
+ // 4: Use format MMYY
+ // 6: Use format MMYYYY
+ // 7: Use format MM/YYYY
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, /* default value */ 0,
+ "01/23", "01/23", true},
+ // Unsupported max lengths of 1-3, fail
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 1, "01/23", "", false},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 2, "02/23", "", false},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 3, "03/23", "", false},
+ // A max length of 4 indicates a format of MMYY.
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 4, "02/23", "0223",
+ true},
+ // A max length of 6 indicates a format of MMYYYY, the 21st century is
+ // assumed.
+ // Desired case of proper max length >= 5
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 5, "03/23", "03/23",
+ true},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 6, "04/23", "042023",
+ true},
+ // A max length of 7 indicates a format of MM/YYYY, the 21st century is
+ // assumed.
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 7, "05/23", "05/2023",
+ true},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 12, "06/23", "06/23",
+ true},
+
+ // A field predicted as a expiration date w/ 4 digit year should fill
+ // with a format of MM/YYYY unless it has max-length of:
+ // 4: Use format MMYY
+ // 5: Use format MM/YY
+ // 6: Use format MMYYYY
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, /* default value */ 0,
+ "01/2024", "01/2024", true},
+ // Unsupported max lengths of 1-3, fail
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 1, "01/2024", "",
+ false},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 2, "02/2024", "",
+ false},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 3, "03/2024", "",
+ false},
+ // A max length of 4 indicates a format of MMYY.
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 4, "02/2024", "0224",
+ true},
+ // A max length of 5 indicates a format of MM/YY.
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 5, "03/2024", "03/24",
+ true},
+ // A max length of 6 indicates a format of MMYYYY.
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 6, "04/2024", "042024",
+ true},
+ // Desired case of proper max length >= 7
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 7, "05/2024",
+ "05/2024", true},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 12, "06/2024",
+ "06/2024", true}));
+
TEST_F(AutofillFieldTest, FillSelectControlByValue) {
std::vector<const char*> kOptions = {
"Eenie", "Meenie", "Miney", "Mo",
@@ -493,131 +552,179 @@ TEST_F(AutofillFieldTest, FillSelectControlByContents) {
EXPECT_EQ(ASCIIToUTF16("2"), field.value); // Corresponds to "Miney".
}
-TEST_F(AutofillFieldTest, FillSelectWithStates) {
- typedef struct {
- std::vector<const char*> select_values;
- const char* input_value;
- const char* expected_value;
- } TestCase;
-
- TestCase test_cases[] = {
- // Filling the abbreviation.
- {{"Alabama", "California"}, "CA", "California"},
- // Attempting to fill the full name in a select full of abbreviations.
- {{"AL", "CA"}, "California", "CA"},
- // Different case and diacritics.
- {{"QUÉBEC", "ALBERTA"}, "Quebec", "QUÉBEC"},
- // Inexact state names.
- {{"SC - South Carolina", "CA - California", "NC - North Carolina"},
- "California",
- "CA - California"},
- // Don't accidentally match "Virginia" to "West Virginia".
- {{"WV - West Virginia", "VA - Virginia", "NV - North Virginia"},
- "Virginia",
- "VA - Virginia"},
- // Do accidentally match "Virginia" to "West Virginia".
- // TODO(crbug.com/624770): This test should not pass, but it does because
- // "Virginia" is a substring of "West Virginia".
- {{"WV - West Virginia", "TX - Texas"}, "Virginia", "WV - West Virginia"},
- // Tests that substring matches work for full state names (a full token
- // match isn't required). Also tests that matches work for states with
- // whitespace in the middle.
- {{"California.", "North Carolina."}, "North Carolina", "North Carolina."},
- {{"NC - North Carolina", "CA - California"}, "CA", "CA - California"},
- // These are not states.
- {{"NCNCA", "SCNCA"}, "NC", ""}};
-
- for (TestCase test_case : test_cases) {
- AutofillField field;
- test::CreateTestSelectField(test_case.select_values, &field);
- field.set_heuristic_type(ADDRESS_HOME_STATE);
-
- AutofillField::FillFormField(field, UTF8ToUTF16(test_case.input_value),
- "en-US", "en-US", &field);
- EXPECT_EQ(UTF8ToUTF16(test_case.expected_value), field.value);
- }
-}
+struct FillSelectTestCase {
+ std::vector<const char*> select_values;
+ const char* input_value;
+ const char* expected_value;
+};
+
+class AutofillSelectWithStatesTest
+ : public testing::TestWithParam<FillSelectTestCase> {
+ public:
+ AutofillSelectWithStatesTest() { CountryNames::SetLocaleString("en-US"); }
+};
-TEST_F(AutofillFieldTest, FillSelectWithCountries) {
- typedef struct {
- std::vector<const char*> select_values;
- const char* input_value;
- const char* expected_value;
- } TestCase;
+TEST_P(AutofillSelectWithStatesTest, FillSelectWithStates) {
+ auto test_case = GetParam();
+ AutofillField field;
+ test::CreateTestSelectField(test_case.select_values, &field);
+ field.set_heuristic_type(ADDRESS_HOME_STATE);
- TestCase test_cases[] = {// Full country names.
- {{"Albania", "Canada"}, "CA", "Canada"},
- // Abbreviations.
- {{"AL", "CA"}, "Canada", "CA"}};
+ AutofillField::FillFormField(field, UTF8ToUTF16(test_case.input_value),
+ "en-US", "en-US", &field);
+ EXPECT_EQ(UTF8ToUTF16(test_case.expected_value), field.value);
+}
- for (TestCase test_case : test_cases) {
- AutofillField field;
- test::CreateTestSelectField(test_case.select_values, &field);
- field.set_heuristic_type(ADDRESS_HOME_COUNTRY);
+INSTANTIATE_TEST_CASE_P(
+ AutofillFieldTest,
+ AutofillSelectWithStatesTest,
+ testing::Values(
+ // Filling the abbreviation.
+ FillSelectTestCase{{"Alabama", "California"}, "CA", "California"},
+ // Attempting to fill the full name in a select full of abbreviations.
+ FillSelectTestCase{{"AL", "CA"}, "California", "CA"},
+ // Different case and diacritics.
+ FillSelectTestCase{{"QUÉBEC", "ALBERTA"}, "Quebec", "QUÉBEC"},
+ // Inexact state names.
+ FillSelectTestCase{
+ {"SC - South Carolina", "CA - California", "NC - North Carolina"},
+ "California",
+ "CA - California"},
+ // Don't accidentally match "Virginia" to "West Virginia".
+ FillSelectTestCase{
+ {"WV - West Virginia", "VA - Virginia", "NV - North Virginia"},
+ "Virginia",
+ "VA - Virginia"},
+ // Do accidentally match "Virginia" to "West Virginia".
+ // TODO(crbug.com/624770): This test should not pass, but it does
+ // because "Virginia" is a substring of "West Virginia".
+ FillSelectTestCase{{"WV - West Virginia", "TX - Texas"},
+ "Virginia",
+ "WV - West Virginia"},
+ // Tests that substring matches work for full state names (a full token
+ // match isn't required). Also tests that matches work for states with
+ // whitespace in the middle.
+ FillSelectTestCase{{"California.", "North Carolina."},
+ "North Carolina",
+ "North Carolina."},
+ FillSelectTestCase{{"NC - North Carolina", "CA - California"},
+ "CA",
+ "CA - California"},
+ // These are not states.
+ FillSelectTestCase{{"NCNCA", "SCNCA"}, "NC", ""}));
+
+class AutofillSelectWithCountriesTest
+ : public testing::TestWithParam<FillSelectTestCase> {
+ public:
+ AutofillSelectWithCountriesTest() { CountryNames::SetLocaleString("en-US"); }
+};
- AutofillField::FillFormField(field, UTF8ToUTF16(test_case.input_value),
- "en-US", "en-US", &field);
- EXPECT_EQ(UTF8ToUTF16(test_case.expected_value), field.value);
- }
+TEST_P(AutofillSelectWithCountriesTest, FillSelectWithCountries) {
+ auto test_case = GetParam();
+ AutofillField field;
+ test::CreateTestSelectField(test_case.select_values, &field);
+ field.set_heuristic_type(ADDRESS_HOME_COUNTRY);
+
+ AutofillField::FillFormField(field, UTF8ToUTF16(test_case.input_value),
+ "en-US", "en-US", &field);
+ EXPECT_EQ(UTF8ToUTF16(test_case.expected_value), field.value);
}
-TEST_F(AutofillFieldTest, FillSelectControlWithExpirationMonth) {
- typedef struct {
- std::vector<const char*> select_values;
- std::vector<const char*> select_contents;
- } TestCase;
-
- TestCase test_cases[] = {
- // Values start at 1.
- {{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"},
- NotNumericMonthsContentsNoPlaceholder()},
- // Values start at 1 but single digits are whitespace padded!
- {{" 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9", "10", "11", "12"},
- NotNumericMonthsContentsNoPlaceholder()},
- // Values start at 0.
- {{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"},
- NotNumericMonthsContentsNoPlaceholder()},
- // Values start at 00.
- {{"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11"},
- NotNumericMonthsContentsNoPlaceholder()},
- // The AngularJS framework adds a prefix to number types. Test that it is
- // removed.
- {{"number:1", "number:2", "number:3", "number:4", "number:5", "number:6",
- "number:7", "number:8", "number:9", "number:10", "number:11",
- "number:12"},
- NotNumericMonthsContentsNoPlaceholder()},
- // Values start at 0 and the first content is a placeholder.
- {{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"},
- NotNumericMonthsContentsWithPlaceholder()},
- // Values start at 1 and the first content is a placeholder.
- {{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13"},
- NotNumericMonthsContentsWithPlaceholder()},
- // Values start at 01 and the first content is a placeholder.
- {{"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12",
- "13"},
- NotNumericMonthsContentsWithPlaceholder()},
- // Values start at 0 after a placeholder.
- {{"?", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"},
- NotNumericMonthsContentsWithPlaceholder()},
- // Values start at 1 after a placeholder.
- {{"?", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"},
- NotNumericMonthsContentsWithPlaceholder()},
- // Values start at 0 after a negative number.
- {{"-1", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"},
- NotNumericMonthsContentsWithPlaceholder()},
- // Values start at 1 after a negative number.
- {{"-1", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"},
- NotNumericMonthsContentsWithPlaceholder()}};
-
- for (TestCase test_case : test_cases) {
- ASSERT_EQ(test_case.select_values.size(), test_case.select_contents.size());
-
- TestFillingExpirationMonth(test_case.select_values,
- test_case.select_contents,
- test_case.select_values.size());
+INSTANTIATE_TEST_CASE_P(
+ AutofillFieldTest,
+ AutofillSelectWithCountriesTest,
+ testing::Values(
+ // Full country names.
+ FillSelectTestCase{{"Albania", "Canada"}, "CA", "Canada"},
+ // Abbreviations.
+ FillSelectTestCase{{"AL", "CA"}, "Canada", "CA"}));
+
+struct FillWithExpirationMonthTestCase {
+ std::vector<const char*> select_values;
+ std::vector<const char*> select_contents;
+};
+
+class AutofillSelectWithExpirationMonthTest
+ : public testing::TestWithParam<FillWithExpirationMonthTestCase> {
+ public:
+ AutofillSelectWithExpirationMonthTest() {
+ CountryNames::SetLocaleString("en-US");
}
+};
+
+TEST_P(AutofillSelectWithExpirationMonthTest,
+ FillSelectControlWithExpirationMonth) {
+ auto test_case = GetParam();
+ ASSERT_EQ(test_case.select_values.size(), test_case.select_contents.size());
+
+ TestFillingExpirationMonth(test_case.select_values, test_case.select_contents,
+ test_case.select_values.size());
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillFieldTest,
+ AutofillSelectWithExpirationMonthTest,
+ testing::Values(
+ // Values start at 1.
+ FillWithExpirationMonthTestCase{
+ {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"},
+ NotNumericMonthsContentsNoPlaceholder()},
+ // Values start at 1 but single digits are whitespace padded!
+ FillWithExpirationMonthTestCase{
+ {" 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9", "10", "11",
+ "12"},
+ NotNumericMonthsContentsNoPlaceholder()},
+ // Values start at 0.
+ FillWithExpirationMonthTestCase{
+ {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"},
+ NotNumericMonthsContentsNoPlaceholder()},
+ // Values start at 00.
+ FillWithExpirationMonthTestCase{
+ {"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10",
+ "11"},
+ NotNumericMonthsContentsNoPlaceholder()},
+ // The AngularJS framework adds a prefix to number types. Test that it
+ // is removed.
+ FillWithExpirationMonthTestCase{
+ {"number:1", "number:2", "number:3", "number:4", "number:5",
+ "number:6", "number:7", "number:8", "number:9", "number:10",
+ "number:11", "number:12"},
+ NotNumericMonthsContentsNoPlaceholder()},
+ // Values start at 0 and the first content is a placeholder.
+ FillWithExpirationMonthTestCase{
+ {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
+ "12"},
+ NotNumericMonthsContentsWithPlaceholder()},
+ // Values start at 1 and the first content is a placeholder.
+ FillWithExpirationMonthTestCase{
+ {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
+ "13"},
+ NotNumericMonthsContentsWithPlaceholder()},
+ // Values start at 01 and the first content is a placeholder.
+ FillWithExpirationMonthTestCase{
+ {"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11",
+ "12", "13"},
+ NotNumericMonthsContentsWithPlaceholder()},
+ // Values start at 0 after a placeholder.
+ FillWithExpirationMonthTestCase{
+ {"?", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"},
+ NotNumericMonthsContentsWithPlaceholder()},
+ // Values start at 1 after a placeholder.
+ FillWithExpirationMonthTestCase{
+ {"?", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
+ "12"},
+ NotNumericMonthsContentsWithPlaceholder()},
+ // Values start at 0 after a negative number.
+ FillWithExpirationMonthTestCase{
+ {"-1", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "11"},
+ NotNumericMonthsContentsWithPlaceholder()},
+ // Values start at 1 after a negative number.
+ FillWithExpirationMonthTestCase{
+ {"-1", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
+ "12"},
+ NotNumericMonthsContentsWithPlaceholder()}));
+
TEST_F(AutofillFieldTest, FillSelectControlWithAbbreviatedMonthName) {
std::vector<const char*> kMonthsAbbreviated = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
@@ -920,50 +1027,64 @@ TEST_F(AutofillFieldTest, FindShortestSubstringMatchInSelect) {
// Tests that text state fields are filled correctly depending on their
// maxlength attribute value.
-TEST_F(AutofillFieldTest, FillStateText) {
- typedef struct {
- HtmlFieldType field_type;
- size_t field_max_length;
- std::string value_to_fill;
- std::string expected_value;
- bool should_fill;
- } TestCase;
-
- TestCase test_cases[] = {
- // Filling a state to a text field with the default maxlength value should
- // fill the state value as is.
- {HTML_TYPE_ADDRESS_LEVEL1, /* default value */ 0, "New York", "New York",
- true},
- {HTML_TYPE_ADDRESS_LEVEL1, /* default value */ 0, "NY", "NY", true},
- // Filling a state to a text field with a maxlength value equal to the
- // value's length should fill the state value as is.
- {HTML_TYPE_ADDRESS_LEVEL1, 8, "New York", "New York", true},
- // Filling a state to a text field with a maxlength value lower than the
- // value's length but higher than the value's abbreviation should fill the
- // state abbreviation.
- {HTML_TYPE_ADDRESS_LEVEL1, 2, "New York", "NY", true},
- {HTML_TYPE_ADDRESS_LEVEL1, 2, "NY", "NY", true},
- // Filling a state to a text field with a maxlength value lower than the
- // value's length and the value's abbreviation should not fill at all.
- {HTML_TYPE_ADDRESS_LEVEL1, 1, "New York", "", false},
- {HTML_TYPE_ADDRESS_LEVEL1, 1, "NY", "", false},
- // Filling a state to a text field with a maxlength value lower than the
- // value's length and that has no associated abbreviation should not fill
- // at all.
- {HTML_TYPE_ADDRESS_LEVEL1, 3, "Quebec", "", false}};
-
- for (const TestCase& test_case : test_cases) {
- AutofillField field;
- field.SetHtmlType(test_case.field_type, HtmlFieldMode());
- field.max_length = test_case.field_max_length;
-
- bool has_filled = AutofillField::FillFormField(
- field, ASCIIToUTF16(test_case.value_to_fill), "en-US", "en-US", &field);
-
- EXPECT_EQ(test_case.should_fill, has_filled);
- EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
- }
+struct FillStateTextTestCase {
+ HtmlFieldType field_type;
+ size_t field_max_length;
+ std::string value_to_fill;
+ std::string expected_value;
+ bool should_fill;
+};
+
+class AutofillStateTextTest
+ : public testing::TestWithParam<FillStateTextTestCase> {
+ public:
+ AutofillStateTextTest() { CountryNames::SetLocaleString("en-US"); }
+};
+
+TEST_P(AutofillStateTextTest, FillStateText) {
+ auto test_case = GetParam();
+ AutofillField field;
+ field.SetHtmlType(test_case.field_type, HtmlFieldMode());
+ field.max_length = test_case.field_max_length;
+
+ bool has_filled = AutofillField::FillFormField(
+ field, ASCIIToUTF16(test_case.value_to_fill), "en-US", "en-US", &field);
+
+ EXPECT_EQ(test_case.should_fill, has_filled);
+ EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillFieldTest,
+ AutofillStateTextTest,
+ testing::Values(
+ // Filling a state to a text field with the default maxlength value
+ // should
+ // fill the state value as is.
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, /* default value */ 0,
+ "New York", "New York", true},
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, /* default value */ 0,
+ "NY", "NY", true},
+ // Filling a state to a text field with a maxlength value equal to the
+ // value's length should fill the state value as is.
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, 8, "New York",
+ "New York", true},
+ // Filling a state to a text field with a maxlength value lower than the
+ // value's length but higher than the value's abbreviation should fill
+ // the state abbreviation.
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, 2, "New York", "NY",
+ true},
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, 2, "NY", "NY", true},
+ // Filling a state to a text field with a maxlength value lower than the
+ // value's length and the value's abbreviation should not fill at all.
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, 1, "New York", "",
+ false},
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, 1, "NY", "", false},
+ // Filling a state to a text field with a maxlength value lower than the
+ // value's length and that has no associated abbreviation should not
+ // fill at all.
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, 3, "Quebec", "",
+ false}));
+
} // namespace
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc
index 056793fe09b..933b7c5dd41 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager.cc
@@ -26,6 +26,7 @@
#include "base/path_service.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -50,6 +51,7 @@
#include "components/autofill/core/browser/phone_number.h"
#include "components/autofill/core/browser/phone_number_i18n.h"
#include "components/autofill/core/browser/popup_item_ids.h"
+#include "components/autofill/core/browser/ui/save_card_bubble_controller.h"
#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_constants.h"
@@ -60,6 +62,7 @@
#include "components/autofill/core/common/form_data_predictions.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/password_form_fill_data.h"
+#include "components/autofill/core/common/signatures_util.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "components/rappor/public/rappor_utils.h"
@@ -129,9 +132,9 @@ base::string16 SanitizeCreditCardFieldValue(const base::string16& value) {
// want the logic of which variations of names are considered to be the same to
// exactly match the logic applied on the Payments server.
base::string16 RemoveMiddleInitial(const base::string16& name) {
- std::vector<base::string16> parts =
- base::SplitString(name, base::kWhitespaceUTF16, base::KEEP_WHITESPACE,
- base::SPLIT_WANT_NONEMPTY);
+ std::vector<base::StringPiece16> parts =
+ base::SplitStringPiece(name, base::kWhitespaceUTF16,
+ base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (parts.size() == 3 && (parts[1].length() == 1 ||
(parts[1].length() == 2 &&
base::EndsWith(parts[1], base::ASCIIToUTF16("."),
@@ -215,16 +218,24 @@ AutofillManager::AutofillManager(
AutofillDownloadManagerState enable_download_manager)
: driver_(driver),
client_(client),
- payments_client_(
- new payments::PaymentsClient(driver->GetURLRequestContext(), this)),
+ payments_client_(base::MakeUnique<payments::PaymentsClient>(
+ driver->GetURLRequestContext(),
+ this)),
app_locale_(app_locale),
personal_data_(client->GetPersonalDataManager()),
autocomplete_history_manager_(
- new AutocompleteHistoryManager(driver, client)),
+ base::MakeUnique<AutocompleteHistoryManager>(driver, client)),
+ form_interactions_ukm_logger_(
+ base::MakeUnique<AutofillMetrics::FormInteractionsUkmLogger>(
+ client->GetUkmService())),
address_form_event_logger_(
- new AutofillMetrics::FormEventLogger(false /* is_for_credit_card */)),
+ base::MakeUnique<AutofillMetrics::FormEventLogger>(
+ false /* is_for_credit_card */,
+ form_interactions_ukm_logger_.get())),
credit_card_form_event_logger_(
- new AutofillMetrics::FormEventLogger(true /* is_for_credit_card */)),
+ base::MakeUnique<AutofillMetrics::FormEventLogger>(
+ true /* is_for_credit_card */,
+ form_interactions_ukm_logger_.get())),
has_logged_autofill_enabled_(false),
has_logged_address_suggestions_count_(false),
did_show_suggestions_(false),
@@ -232,6 +243,7 @@ AutofillManager::AutofillManager(
user_did_autofill_(false),
user_did_edit_autofilled_field_(false),
user_did_accept_upload_prompt_(false),
+ should_cvc_be_requested_(false),
external_delegate_(NULL),
test_delegate_(NULL),
#if defined(OS_ANDROID) || defined(OS_IOS)
@@ -245,10 +257,8 @@ AutofillManager::AutofillManager(
if (personal_data_ && client_)
personal_data_->OnSyncServiceInitialized(client_->GetSyncService());
-#if defined(OS_ANDROID)
if (personal_data_ && driver_)
personal_data_->SetURLRequestContextGetter(driver_->GetURLRequestContext());
-#endif
}
AutofillManager::~AutofillManager() {}
@@ -493,7 +503,7 @@ void AutofillManager::ProcessPendingFormForUpload() {
if (!upload_form)
return;
- StartUploadProcess(std::move(upload_form), base::TimeTicks::Now(), false);
+ StartUploadProcess(std::move(upload_form), TimeTicks::Now(), false);
}
void AutofillManager::OnTextFieldDidChange(const FormData& form,
@@ -512,6 +522,9 @@ void AutofillManager::OnTextFieldDidChange(const FormData& form,
UpdatePendingForm(form);
+ if (!user_did_type_ || autofill_field->is_autofilled)
+ form_interactions_ukm_logger_->LogTextFieldDidChange(*autofill_field);
+
if (!user_did_type_) {
user_did_type_ = true;
AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::USER_DID_TYPE);
@@ -1033,13 +1046,16 @@ void AutofillManager::OnDidGetUploadDetails(
user_did_accept_upload_prompt_ = false;
client_->ConfirmSaveCreditCardToCloud(
upload_request_.card, std::move(legal_message),
+ should_cvc_be_requested_,
base::Bind(&AutofillManager::OnUserDidAcceptUpload,
weak_ptr_factory_.GetWeakPtr()));
client_->LoadRiskData(base::Bind(&AutofillManager::OnDidGetUploadRiskData,
weak_ptr_factory_.GetWeakPtr()));
- AutofillMetrics::LogCardUploadDecisionMetric(
- AutofillMetrics::UPLOAD_OFFERED);
- LogCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
+ AutofillMetrics::CardUploadDecisionMetric card_upload_decision_metric =
+ should_cvc_be_requested_ ? AutofillMetrics::UPLOAD_OFFERED_NO_CVC
+ : AutofillMetrics::UPLOAD_OFFERED;
+ AutofillMetrics::LogCardUploadDecisionMetric(card_upload_decision_metric);
+ LogCardUploadDecisionUkm(card_upload_decision_metric);
} else {
// If the upload details request failed, fall back to a local save. The
// reasoning here is as follows:
@@ -1099,6 +1115,13 @@ void AutofillManager::OnUserDidAcceptUpload() {
user_did_accept_upload_prompt_ = true;
if (!upload_request_.risk_data.empty()) {
upload_request_.app_locale = app_locale_;
+ // If the upload request does not have card CVC, populate it with the
+ // value provided by the user:
+ if (upload_request_.cvc.empty()) {
+ DCHECK(client_->GetSaveCardBubbleController());
+ upload_request_.cvc =
+ client_->GetSaveCardBubbleController()->GetCvcEnteredByUser();
+ }
payments_client_->UploadCard(upload_request_);
}
}
@@ -1107,6 +1130,13 @@ void AutofillManager::OnDidGetUploadRiskData(const std::string& risk_data) {
upload_request_.risk_data = risk_data;
if (user_did_accept_upload_prompt_) {
upload_request_.app_locale = app_locale_;
+ // If the upload request does not have card CVC, populate it with the
+ // value provided by the user:
+ if (upload_request_.cvc.empty()) {
+ DCHECK(client_->GetSaveCardBubbleController());
+ upload_request_.cvc =
+ client_->GetSaveCardBubbleController()->GetCvcEnteredByUser();
+ }
payments_client_->UploadCard(upload_request_);
}
}
@@ -1126,7 +1156,7 @@ bool AutofillManager::IsCreditCardUploadEnabled() {
}
bool AutofillManager::ShouldUploadForm(const FormStructure& form) {
- return IsAutofillEnabled() && !driver_->IsOffTheRecord() &&
+ return IsAutofillEnabled() && !driver_->IsIncognito() &&
form.ShouldBeParsed() &&
(form.active_field_count() >= kRequiredFieldsForUpload ||
(form.all_fields_are_passwords() &&
@@ -1199,9 +1229,11 @@ void AutofillManager::ImportFormData(const FormStructure& submitted_form) {
// because if only one of the two is missing, it may be fixable.
// Check for a CVC to determine whether we can prompt the user to upload
- // their card. If no CVC is present, do nothing. We could fall back to a
- // local save but we believe that sometimes offering upload and sometimes
- // offering local save is a confusing user experience.
+ // their card. If no CVC is present and the experiment is off, do nothing.
+ // We could fall back to a local save but we believe that sometimes offering
+ // upload and sometimes offering local save is a confusing user experience.
+ // If no CVC and the experiment is on, request CVC from the user in the
+ // bubble and save using the provided value.
for (const auto& field : submitted_form) {
if (field->Type().GetStorableType() == CREDIT_CARD_VERIFICATION_CODE &&
IsValidCreditCardSecurityCode(field->value,
@@ -1226,14 +1258,19 @@ void AutofillManager::ImportFormData(const FormStructure& submitted_form) {
// Both the CVC and address checks are done. Conform to the legacy order of
// reporting on CVC then address.
+ should_cvc_be_requested_ = false;
if (upload_request_.cvc.empty()) {
- AutofillMetrics::LogCardUploadDecisionMetric(
- AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
- LogCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
- pending_upload_request_url_ = GURL();
- CollectRapportSample(submitted_form.source_url(),
- "Autofill.CardUploadNotOfferedNoCvc");
- return;
+ if (IsAutofillUpstreamRequestCvcIfMissingExperimentEnabled()) {
+ should_cvc_be_requested_ = true;
+ } else {
+ AutofillMetrics::LogCardUploadDecisionMetric(
+ AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
+ LogCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
+ pending_upload_request_url_ = GURL();
+ CollectRapportSample(submitted_form.source_url(),
+ "Autofill.CardUploadNotOfferedNoCvc");
+ return;
+ }
}
if (!get_profiles_succeeded) {
DCHECK(get_profiles_decision_metric != AutofillMetrics::UPLOAD_OFFERED);
@@ -1378,11 +1415,10 @@ void AutofillManager::UploadFormDataAsyncCallback(
const TimeTicks& interaction_time,
const TimeTicks& submission_time,
bool observed_submission) {
- submitted_form->LogQualityMetrics(load_time, interaction_time,
- submission_time,
- client_->GetRapporServiceImpl(),
- did_show_suggestions_, observed_submission);
-
+ submitted_form->LogQualityMetrics(
+ load_time, interaction_time, submission_time,
+ client_->GetRapporServiceImpl(), form_interactions_ukm_logger_.get(),
+ did_show_suggestions_, observed_submission);
if (submitted_form->ShouldBeCrowdsourced())
UploadFormData(*submitted_form, observed_submission);
}
@@ -1416,10 +1452,12 @@ void AutofillManager::Reset() {
ProcessPendingFormForUpload();
DCHECK(!pending_form_data_);
form_structures_.clear();
- address_form_event_logger_.reset(
- new AutofillMetrics::FormEventLogger(false /* is_for_credit_card */));
- credit_card_form_event_logger_.reset(
- new AutofillMetrics::FormEventLogger(true /* is_for_credit_card */));
+ form_interactions_ukm_logger_.reset(
+ new AutofillMetrics::FormInteractionsUkmLogger(client_->GetUkmService()));
+ address_form_event_logger_.reset(new AutofillMetrics::FormEventLogger(
+ false /* is_for_credit_card */, form_interactions_ukm_logger_.get()));
+ credit_card_form_event_logger_.reset(new AutofillMetrics::FormEventLogger(
+ true /* is_for_credit_card */, form_interactions_ukm_logger_.get()));
#if defined(OS_ANDROID) || defined(OS_IOS)
autofill_assistant_.Reset();
#endif
@@ -1443,16 +1481,24 @@ AutofillManager::AutofillManager(AutofillDriver* driver,
PersonalDataManager* personal_data)
: driver_(driver),
client_(client),
- payments_client_(
- new payments::PaymentsClient(driver->GetURLRequestContext(), this)),
+ payments_client_(base::MakeUnique<payments::PaymentsClient>(
+ driver->GetURLRequestContext(),
+ this)),
app_locale_("en-US"),
personal_data_(personal_data),
autocomplete_history_manager_(
- new AutocompleteHistoryManager(driver, client)),
+ base::MakeUnique<AutocompleteHistoryManager>(driver, client)),
+ form_interactions_ukm_logger_(
+ base::MakeUnique<AutofillMetrics::FormInteractionsUkmLogger>(
+ client->GetUkmService())),
address_form_event_logger_(
- new AutofillMetrics::FormEventLogger(false /* is_for_credit_card */)),
+ base::MakeUnique<AutofillMetrics::FormEventLogger>(
+ false /* is_for_credit_card */,
+ form_interactions_ukm_logger_.get())),
credit_card_form_event_logger_(
- new AutofillMetrics::FormEventLogger(true /* is_for_credit_card */)),
+ base::MakeUnique<AutofillMetrics::FormEventLogger>(
+ true /* is_for_credit_card */,
+ form_interactions_ukm_logger_.get())),
has_logged_autofill_enabled_(false),
has_logged_address_suggestions_count_(false),
did_show_suggestions_(false),
@@ -1483,34 +1529,34 @@ bool AutofillManager::RefreshDataModels() {
// Updating the FormEventLoggers for addresses and credit cards.
{
- bool is_server_data_available = false;
- bool is_local_data_available = false;
+ size_t server_record_type_count = 0;
+ size_t local_record_type_count = 0;
for (CreditCard* credit_card : credit_cards) {
if (credit_card->record_type() == CreditCard::LOCAL_CARD)
- is_local_data_available = true;
+ local_record_type_count++;
else
- is_server_data_available = true;
+ server_record_type_count++;
}
- credit_card_form_event_logger_->set_is_server_data_available(
- is_server_data_available);
- credit_card_form_event_logger_->set_is_local_data_available(
- is_local_data_available);
+ credit_card_form_event_logger_->set_server_record_type_count(
+ server_record_type_count);
+ credit_card_form_event_logger_->set_local_record_type_count(
+ local_record_type_count);
credit_card_form_event_logger_->set_is_context_secure(
client_->IsContextSecure());
}
{
- bool is_server_data_available = false;
- bool is_local_data_available = false;
+ size_t server_record_type_count = 0;
+ size_t local_record_type_count = 0;
for (AutofillProfile* profile : profiles) {
if (profile->record_type() == AutofillProfile::LOCAL_PROFILE)
- is_local_data_available = true;
+ local_record_type_count++;
else if (profile->record_type() == AutofillProfile::SERVER_PROFILE)
- is_server_data_available = true;
+ server_record_type_count++;
}
- address_form_event_logger_->set_is_server_data_available(
- is_server_data_available);
- address_form_event_logger_->set_is_local_data_available(
- is_local_data_available);
+ address_form_event_logger_->set_server_record_type_count(
+ server_record_type_count);
+ address_form_event_logger_->set_local_record_type_count(
+ local_record_type_count);
}
if (profiles.empty() && credit_cards.empty())
@@ -1679,7 +1725,8 @@ void AutofillManager::FillOrPreviewDataModelForm(
std::unique_ptr<FormStructure> AutofillManager::ValidateSubmittedForm(
const FormData& form) {
- std::unique_ptr<FormStructure> submitted_form(new FormStructure(form));
+ std::unique_ptr<FormStructure> submitted_form(
+ base::MakeUnique<FormStructure>(form));
if (!ShouldUploadForm(*submitted_form))
return std::unique_ptr<FormStructure>();
@@ -1689,7 +1736,7 @@ std::unique_ptr<FormStructure> AutofillManager::ValidateSubmittedForm(
if (!FindCachedForm(form, &cached_submitted_form))
return std::unique_ptr<FormStructure>();
- submitted_form->UpdateFromCache(*cached_submitted_form);
+ submitted_form->UpdateFromCache(*cached_submitted_form, false);
return submitted_form;
}
@@ -1702,8 +1749,9 @@ bool AutofillManager::FindCachedForm(const FormData& form,
// protocol with the crowdsourcing server does not permit us to discard the
// original versions of the forms.
*form_structure = NULL;
+ const auto& form_signature = autofill::CalculateFormSignature(form);
for (auto& cur_form : base::Reversed(form_structures_)) {
- if (*cur_form == form) {
+ if (cur_form->form_signature() == form_signature || *cur_form == form) {
*form_structure = cur_form.get();
// The same form might be cached with multiple field counts: in some
@@ -1785,41 +1833,17 @@ bool AutofillManager::UpdateCachedForm(const FormData& live_form,
if (!needs_update)
return true;
- if (form_structures_.size() >= kMaxFormCacheSize)
+ // Note: We _must not_ remove the original version of the cached form from
+ // the list of |form_structures_|. Otherwise, we break parsing of the
+ // crowdsourcing server's response to our query.
+ if (!ParseForm(live_form, updated_form))
return false;
- // Add the new or updated form to our cache.
- form_structures_.push_back(base::MakeUnique<FormStructure>(live_form));
- *updated_form = form_structures_.rbegin()->get();
- (*updated_form)->DetermineHeuristicTypes();
-
- // If we have cached data, propagate it to the updated form.
- if (cached_form) {
- std::map<base::string16, const AutofillField*> cached_fields;
- for (size_t i = 0; i < cached_form->field_count(); ++i) {
- const AutofillField* field = cached_form->field(i);
- cached_fields[field->unique_name()] = field;
- }
-
- for (size_t i = 0; i < (*updated_form)->field_count(); ++i) {
- AutofillField* field = (*updated_form)->field(i);
- auto cached_field = cached_fields.find(field->unique_name());
- if (cached_field != cached_fields.end()) {
- field->set_server_type(cached_field->second->server_type());
- field->is_autofilled = cached_field->second->is_autofilled;
- field->set_previously_autofilled(
- cached_field->second->previously_autofilled());
- }
- }
-
- // Note: We _must not_ remove the original version of the cached form from
- // the list of |form_structures_|. Otherwise, we break parsing of the
- // crowdsourcing server's response to our query.
- }
+ if (cached_form)
+ (*updated_form)->UpdateFromCache(*cached_form, true);
// Annotate the updated form with its predicted types.
- std::vector<FormStructure*> forms(1, *updated_form);
- driver_->SendAutofillTypePredictionsToRenderer(forms);
+ driver_->SendAutofillTypePredictionsToRenderer({*updated_form});
return true;
}
@@ -1878,27 +1902,21 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) {
std::vector<FormStructure*> non_queryable_forms;
std::vector<FormStructure*> queryable_forms;
for (const FormData& form : forms) {
- const auto parse_form_start_time = base::TimeTicks::Now();
+ const auto parse_form_start_time = TimeTicks::Now();
- std::unique_ptr<FormStructure> form_structure =
- base::MakeUnique<FormStructure>(form);
- form_structure->ParseFieldTypesFromAutocompleteAttributes();
- if (!form_structure->ShouldBeParsed())
+ FormStructure* form_structure = nullptr;
+ if (!ParseForm(form, &form_structure))
continue;
+ DCHECK(form_structure);
- form_structure->DetermineHeuristicTypes();
-
- // Ownership is transferred to |form_structures_| which maintains it until
- // the manager is Reset() or destroyed. It is safe to use references below
- // as long as receivers don't take ownership.
- form_structures_.push_back(std::move(form_structure));
-
- if (form_structures_.back()->ShouldBeCrowdsourced())
- queryable_forms.push_back(form_structures_.back().get());
+ // Set aside forms with method GET or author-specified types, so that they
+ // are not included in the query to the server.
+ if (form_structure->ShouldBeCrowdsourced())
+ queryable_forms.push_back(form_structure);
else
- non_queryable_forms.push_back(form_structures_.back().get());
+ non_queryable_forms.push_back(form_structure);
- AutofillMetrics::LogParseFormTiming(base::TimeTicks::Now() -
+ AutofillMetrics::LogParseFormTiming(TimeTicks::Now() -
parse_form_start_time);
}
@@ -1909,6 +1927,9 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) {
if (!queryable_forms.empty() || !non_queryable_forms.empty()) {
AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED);
+ // Setup the url for metrics that we will collect for this form.
+ form_interactions_ukm_logger_->OnFormsLoaded(forms[0].origin);
+
#if defined(OS_IOS)
// Log this from same location as AutofillMetrics::FORMS_LOADED to ensure
// that KeyboardAccessoryButtonsIOS and UserHappiness UMA metrics will be
@@ -1938,6 +1959,26 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) {
driver_->SendAutofillTypePredictionsToRenderer(non_queryable_forms);
}
+bool AutofillManager::ParseForm(const FormData& form,
+ FormStructure** parsed_form_structure) {
+ DCHECK(parsed_form_structure);
+ if (form_structures_.size() >= kMaxFormCacheSize)
+ return false;
+
+ auto form_structure = base::MakeUnique<FormStructure>(form);
+ form_structure->ParseFieldTypesFromAutocompleteAttributes();
+ if (!form_structure->ShouldBeParsed())
+ return false;
+
+ // Ownership is transferred to |form_structures_| which maintains it until
+ // the manager is Reset() or destroyed. It is safe to use references below
+ // as long as receivers don't take ownership.
+ form_structures_.push_back(std::move(form_structure));
+ *parsed_form_structure = form_structures_.back().get();
+ (*parsed_form_structure)->DetermineHeuristicTypes(client_->GetUkmService());
+ return true;
+}
+
int AutofillManager::BackendIDToInt(const std::string& backend_id) const {
if (!base::IsValidGUID(backend_id))
return 0;
@@ -2016,7 +2057,7 @@ void AutofillManager::DeterminePossibleFieldTypesForUpload(
// profile or credit card, identify any stored types that match the value.
for (size_t i = 0; i < submitted_form->field_count(); ++i) {
AutofillField* field = submitted_form->field(i);
- ServerFieldTypeSet matching_types;
+ ServerFieldTypeSet matching_types = field->possible_types();
base::string16 value;
base::TrimWhitespace(field->value, base::TRIM_ALL, &value);
diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h
index 290126ec108..c8597275741 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_manager.h
@@ -43,8 +43,6 @@
#define ENABLE_FORM_DEBUG_DUMP
#endif
-class GURL;
-
namespace gfx {
class RectF;
}
@@ -191,9 +189,9 @@ class AutofillManager : public AutofillDownloadManager::Observer,
// Will send an upload based on the |form_structure| data and the local
// Autofill profile data. |observed_submission| is specified if the upload
// follows an observed submission event.
- void StartUploadProcess(std::unique_ptr<FormStructure> form_structure,
- const base::TimeTicks& timestamp,
- bool observed_submission);
+ virtual void StartUploadProcess(std::unique_ptr<FormStructure> form_structure,
+ const base::TimeTicks& timestamp,
+ bool observed_submission);
// Update the pending form with |form|, possibly processing the current
// pending form for upload.
@@ -270,6 +268,10 @@ class AutofillManager : public AutofillDownloadManager::Observer,
return &form_structures_;
}
+ AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger() {
+ return form_interactions_ukm_logger_.get();
+ }
+
// Exposed for testing.
AutofillExternalDelegate* external_delegate() {
return external_delegate_;
@@ -414,6 +416,9 @@ class AutofillManager : public AutofillDownloadManager::Observer,
// Parses the forms using heuristic matching and querying the Autofill server.
void ParseForms(const std::vector<FormData>& forms);
+ // Parses the form and adds it to |form_structures_|.
+ bool ParseForm(const FormData& form, FormStructure** parsed_form_structure);
+
// Imports the form data, submitted by the user, into |personal_data_|.
void ImportFormData(const FormStructure& submitted_form);
@@ -507,6 +512,10 @@ class AutofillManager : public AutofillDownloadManager::Observer,
// Handles single-field autocomplete form data.
std::unique_ptr<AutocompleteHistoryManager> autocomplete_history_manager_;
+ // Utility for logging URL keyed metrics.
+ std::unique_ptr<AutofillMetrics::FormInteractionsUkmLogger>
+ form_interactions_ukm_logger_;
+
// Utilities for logging form events.
std::unique_ptr<AutofillMetrics::FormEventLogger> address_form_event_logger_;
std::unique_ptr<AutofillMetrics::FormEventLogger>
@@ -552,6 +561,7 @@ class AutofillManager : public AutofillDownloadManager::Observer,
payments::PaymentsClient::UploadRequestDetails upload_request_;
bool user_did_accept_upload_prompt_;
GURL pending_upload_request_url_;
+ bool should_cvc_be_requested_;
#ifdef ENABLE_FORM_DEBUG_DUMP
// The last few autofilled forms (key/value pairs) submitted, for debugging.
@@ -592,6 +602,7 @@ class AutofillManager : public AutofillDownloadManager::Observer,
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, AddressSubmittedFormEvents);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, AddressWillSubmitFormEvents);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, AddressSuggestionsCount);
+ FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, AutofillFormSubmittedState);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, AutofillIsEnabledAtPageLoad);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, CreditCardSelectedFormEvents);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, CreditCardFilledFormEvents);
diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
index 54643c65a6a..e9d94a48d40 100644
--- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -8,6 +8,7 @@
#include <algorithm>
#include <memory>
+#include <utility>
#include <vector>
#include "base/command_line.h"
@@ -27,6 +28,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -57,6 +59,7 @@
#include "components/ukm/ukm_entry.h"
#include "components/ukm/ukm_source.h"
#include "components/variations/variations_associated_data.h"
+#include "net/base/url_util.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -170,9 +173,11 @@ class TestPersonalDataManager : public PersonalDataManager {
web_profiles_.push_back(std::move(profile));
}
- void AddCreditCard(std::unique_ptr<CreditCard> credit_card) {
- credit_card->set_modification_date(base::Time::Now());
- local_credit_cards_.push_back(std::move(credit_card));
+ void AddCreditCard(const CreditCard& credit_card) override {
+ std::unique_ptr<CreditCard> local_credit_card =
+ base::MakeUnique<CreditCard>(credit_card);
+ local_credit_card->set_modification_date(base::Time::Now());
+ local_credit_cards_.push_back(std::move(local_credit_card));
}
void RecordUseOf(const AutofillDataModel& data_model) override {
@@ -492,18 +497,18 @@ class MockAutocompleteHistoryManager : public AutocompleteHistoryManager {
class MockAutofillDriver : public TestAutofillDriver {
public:
MockAutofillDriver()
- : is_off_the_record_(false), did_interact_with_credit_card_form_(false) {}
+ : is_incognito_(false), did_interact_with_credit_card_form_(false) {}
// Mock methods to enable testability.
MOCK_METHOD3(SendFormDataToRenderer, void(int query_id,
RendererFormDataAction action,
const FormData& data));
- void SetIsOffTheRecord(bool is_off_the_record) {
- is_off_the_record_ = is_off_the_record;
+ void SetIsIncognito(bool is_incognito) {
+ is_incognito_ = is_incognito;
}
- bool IsOffTheRecord() const override { return is_off_the_record_; }
+ bool IsIncognito() const override { return is_incognito_; }
void DidInteractWithCreditCardForm() override {
did_interact_with_credit_card_form_ = true;
@@ -518,7 +523,7 @@ class MockAutofillDriver : public TestAutofillDriver {
}
private:
- bool is_off_the_record_;
+ bool is_incognito_;
bool did_interact_with_credit_card_form_;
DISALLOW_COPY_AND_ASSIGN(MockAutofillDriver);
};
@@ -628,8 +633,8 @@ class TestAutofillManager : public AutofillManager {
personal_data_->AddProfile(std::move(profile));
}
- void AddCreditCard(std::unique_ptr<CreditCard> credit_card) {
- personal_data_->AddCreditCard(std::move(credit_card));
+ void AddCreditCard(const CreditCard& credit_card) {
+ personal_data_->AddCreditCard(credit_card);
}
int GetPackedCreditCardID(int credit_card_id) {
@@ -790,6 +795,15 @@ const ukm::Entry_Metric* FindMetric(
return nullptr;
}
+// Get Ukm sources from the Ukm service.
+std::vector<const ukm::UkmSource*> GetUkmSources(ukm::TestUkmService* service) {
+ std::vector<const ukm::UkmSource*> sources;
+ for (const auto& kv : service->GetSources())
+ sources.push_back(kv.second.get());
+
+ return sources;
+}
+
} // namespace
class AutofillManagerTest : public testing::Test {
@@ -1018,13 +1032,17 @@ class AutofillManagerTest : public testing::Test {
scoped_feature_list_.InitAndEnableFeature(kAutofillUkmLogging);
}
- void ExpectUniqueCardUploadDecisionUkm(
- AutofillMetrics::CardUploadDecisionMetric upload_decision) {
+ void EnableAutofillUpstreamRequestCvcIfMissingExperimentAndUkmLogging() {
+ scoped_feature_list_.InitWithFeatures(
+ {kAutofillUpstreamRequestCvcIfMissing, kAutofillUkmLogging}, {});
+ }
+
+ void ExpectUniqueFillableFormParsedUkm() {
ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
// Check that one source is logged.
ASSERT_EQ(1U, ukm_service->sources_count());
- const ukm::UkmSource* source = ukm_service->GetSource(0);
+ const ukm::UkmSource* source = GetUkmSources(ukm_service)[0];
// Check that one entry is logged.
EXPECT_EQ(1U, ukm_service->entries_count());
@@ -1035,20 +1053,67 @@ class AutofillManagerTest : public testing::Test {
entry->PopulateProto(&entry_proto);
EXPECT_EQ(source->id(), entry_proto.source_id());
- // Check if there is an entry for card upload decisions.
- EXPECT_EQ(base::HashMetricName(internal::kUKMCardUploadDecisionEntryName),
+ // Check if there is an entry for developer engagement decision.
+ EXPECT_EQ(base::HashMetricName(internal::kUKMDeveloperEngagementEntryName),
entry_proto.event_hash());
EXPECT_EQ(1, entry_proto.metrics_size());
- // Check that the expected upload decision is logged.
+ // Check that the expected developer engagement metric is logged.
const ukm::Entry_Metric* metric = FindMetric(
- internal::kUKMCardUploadDecisionMetricName, entry_proto.metrics());
+ internal::kUKMDeveloperEngagementMetricName, entry_proto.metrics());
ASSERT_NE(nullptr, metric);
- EXPECT_EQ(static_cast<int>(upload_decision), metric->value());
+ EXPECT_EQ(static_cast<int>(
+ AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS),
+ metric->value());
+ }
+
+ void ExpectCardUploadDecisionUkm(
+ AutofillMetrics::CardUploadDecisionMetric upload_decision) {
+ ExpectMetric(internal::kUKMCardUploadDecisionMetricName,
+ internal::kUKMCardUploadDecisionEntryName,
+ static_cast<int>(upload_decision),
+ 1 /* expected_num_matching_entries */);
+ }
+
+ void ExpectFillableFormParsedUkm(int num_fillable_forms_parsed) {
+ ExpectMetric(internal::kUKMDeveloperEngagementMetricName,
+ internal::kUKMDeveloperEngagementEntryName,
+ static_cast<int>(
+ AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS),
+ num_fillable_forms_parsed);
+ }
+
+ void ExpectMetric(const char* metric_name,
+ const char* entry_name,
+ int metric_value,
+ int expected_num_matching_entries) {
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
+ int num_matching_entries = 0;
+ for (size_t i = 0; i < ukm_service->entries_count(); ++i) {
+ const ukm::UkmEntry* entry = ukm_service->GetEntry(i);
+
+ ukm::Entry entry_proto;
+ entry->PopulateProto(&entry_proto);
+ EXPECT_EQ(entry->source_id(), entry_proto.source_id());
+
+ // Check if there is an entry for |entry_name|.
+ if (entry_proto.event_hash() == base::HashMetricName(entry_name)) {
+ EXPECT_EQ(1, entry_proto.metrics_size());
+
+ // Check that the expected |metric_value| is logged.
+ const ukm::Entry_Metric* metric =
+ FindMetric(metric_name, entry_proto.metrics());
+ ASSERT_NE(nullptr, metric);
+ EXPECT_EQ(metric_value, metric->value());
+ ++num_matching_entries;
+ }
+ }
+ EXPECT_EQ(expected_num_matching_entries, num_matching_entries);
}
protected:
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
MockAutofillClient autofill_client_;
std::unique_ptr<MockAutofillDriver> autofill_driver_;
std::unique_ptr<TestAutofillManager> autofill_manager_;
@@ -1541,12 +1606,12 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_StopCharsOnly) {
// field has stop characters in it and some input.
TEST_F(AutofillManagerTest, GetCreditCardSuggestions_StopCharsWithInput) {
// Add a credit card with particular numbers that we will attempt to recall.
- std::unique_ptr<CreditCard> credit_card = base::MakeUnique<CreditCard>();
- test::SetCreditCardInfo(credit_card.get(), "John Smith",
+ CreditCard credit_card;
+ test::SetCreditCardInfo(&credit_card, "John Smith",
"5255667890123123", // Mastercard
"08", "2017");
- credit_card->set_guid("00000000-0000-0000-0000-000000000007");
- autofill_manager_->AddCreditCard(std::move(credit_card));
+ credit_card.set_guid("00000000-0000-0000-0000-000000000007");
+ autofill_manager_->AddCreditCard(credit_card);
// Set up our form data.
FormData form;
@@ -1823,13 +1888,13 @@ TEST_F(AutofillManagerTest,
TEST_F(AutofillManagerTest, GetCreditCardSuggestions_RepeatedObfuscatedNumber) {
// Add a credit card with the same obfuscated number as Elvis's.
// |credit_card| will be owned by the mock PersonalDataManager.
- std::unique_ptr<CreditCard> credit_card = base::MakeUnique<CreditCard>();
- test::SetCreditCardInfo(credit_card.get(), "Elvis Presley",
+ CreditCard credit_card;
+ test::SetCreditCardInfo(&credit_card, "Elvis Presley",
"5231567890123456", // Mastercard
"05", "2999");
- credit_card->set_guid("00000000-0000-0000-0000-000000000007");
- credit_card->set_use_date(base::Time::Now() - base::TimeDelta::FromDays(15));
- autofill_manager_->AddCreditCard(std::move(credit_card));
+ credit_card.set_guid("00000000-0000-0000-0000-000000000007");
+ credit_card.set_use_date(base::Time::Now() - base::TimeDelta::FromDays(15));
+ autofill_manager_->AddCreditCard(credit_card);
// Set up our form data.
FormData form;
@@ -3445,7 +3510,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions) {
// Simulate having seen this form on page load.
// |form_structure| will be owned by |autofill_manager_|.
TestFormStructure* form_structure = new TestFormStructure(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
autofill_manager_->AddSeenForm(base::WrapUnique(form_structure));
// Similarly, a second form.
@@ -3465,7 +3530,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions) {
form2.fields.push_back(field);
TestFormStructure* form_structure2 = new TestFormStructure(form2);
- form_structure2->DetermineHeuristicTypes();
+ form_structure2->DetermineHeuristicTypes(nullptr /* ukm_service */);
autofill_manager_->AddSeenForm(base::WrapUnique(form_structure2));
AutofillQueryResponseContents response;
@@ -3518,7 +3583,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions_ResetManager) {
// Simulate having seen this form on page load.
// |form_structure| will be owned by |autofill_manager_|.
TestFormStructure* form_structure = new TestFormStructure(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
autofill_manager_->AddSeenForm(base::WrapUnique(form_structure));
AutofillQueryResponseContents response;
@@ -3556,7 +3621,7 @@ TEST_F(AutofillManagerTest, FormSubmittedServerTypes) {
// Simulate having seen this form on page load.
// |form_structure| will be owned by |autofill_manager_|.
TestFormStructure* form_structure = new TestFormStructure(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
// Clear the heuristic types, and instead set the appropriate server types.
std::vector<ServerFieldType> heuristic_types, server_types;
@@ -4151,10 +4216,10 @@ TEST_F(AutofillManagerTest, RemoveProfile) {
TEST_F(AutofillManagerTest, RemoveCreditCard) {
// Add and remove an Autofill credit card.
- std::unique_ptr<CreditCard> credit_card = base::MakeUnique<CreditCard>();
+ CreditCard credit_card;
const char guid[] = "00000000-0000-0000-0000-000000100007";
- credit_card->set_guid(guid);
- autofill_manager_->AddCreditCard(std::move(credit_card));
+ credit_card.set_guid(guid);
+ autofill_manager_->AddCreditCard(credit_card);
int id = MakeFrontendID(guid, std::string());
@@ -4526,6 +4591,8 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard) {
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
+ ExpectUniqueFillableFormParsedUkm();
+
ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
FormSubmitted(address_form);
@@ -4533,6 +4600,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard) {
FormData credit_card_form;
CreateTestCreditCardFormData(&credit_card_form, true, false);
FormsSeen(std::vector<FormData>(1, credit_card_form));
+ ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
@@ -4550,7 +4618,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard) {
histogram_tester.ExpectUniqueSample("Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_OFFERED, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
}
// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
@@ -4610,6 +4678,8 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_CvcUnavailable) {
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
+ ExpectUniqueFillableFormParsedUkm();
+
ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
FormSubmitted(address_form);
@@ -4617,6 +4687,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_CvcUnavailable) {
FormData credit_card_form;
CreateTestCreditCardFormData(&credit_card_form, true, false);
FormsSeen(std::vector<FormData>(1, credit_card_form));
+ ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
@@ -4637,7 +4708,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_CvcUnavailable) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
rappor::TestRapporServiceImpl* rappor_service =
autofill_client_.test_rappor_service();
@@ -4693,7 +4764,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_CvcInvalidLength) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
rappor::TestRapporServiceImpl* rappor_service =
autofill_client_.test_rappor_service();
@@ -4771,7 +4842,146 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_MultipleCvcFields) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_OFFERED, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
+}
+
+// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
+#if defined(OS_ANDROID)
+#define MAYBE_UploadCreditCard_NoCvcFieldOnForm \
+ DISABLED_UploadCreditCard_NoCvcFieldOnForm
+#else
+#define MAYBE_UploadCreditCard_NoCvcFieldOnForm \
+ UploadCreditCard_NoCvcFieldOnForm
+#endif
+TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_NoCvcFieldOnForm) {
+ EnableAutofillUpstreamRequestCvcIfMissingExperimentAndUkmLogging();
+ autofill_manager_->set_credit_card_upload_enabled(true);
+
+ // Remove the profiles that were created in the TestPersonalDataManager
+ // constructor because they would result in conflicting names that would
+ // prevent the upload.
+ personal_data_.ClearAutofillProfiles();
+
+ // 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. Note that CVC field is missing.
+ FormData credit_card_form;
+ credit_card_form.name = ASCIIToUTF16("MyForm");
+ credit_card_form.origin = GURL("https://myform.com/form.html");
+ credit_card_form.action = GURL("https://myform.com/submit.html");
+
+ FormFieldData field;
+ test::CreateTestFormField("Card Name", "cardname", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+ test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+ test::CreateTestFormField("Expiration Month", "ccmonth", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+ test::CreateTestFormField("Expiration Year", "ccyear", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+
+ FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+ // Edit the data, and submit.
+ credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
+ credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+ credit_card_form.fields[2].value = ASCIIToUTF16("11");
+ credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+
+ base::HistogramTester histogram_tester;
+
+ // Upload should still happen as long as the user provides CVC in the bubble.
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0);
+ FormSubmitted(credit_card_form);
+ EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded());
+
+ // Verify that the correct histogram entry (and only that) was logged.
+ histogram_tester.ExpectUniqueSample("Autofill.CardUploadDecisionExpanded",
+ AutofillMetrics::UPLOAD_OFFERED_NO_CVC,
+ 1);
+ // Verify that the correct UKM was logged.
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED_NO_CVC);
+}
+
+// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
+#if defined(OS_ANDROID)
+#define MAYBE_UploadCreditCard_NoCvcFieldOnFormExperimentOff \
+ DISABLED_UploadCreditCard_NoCvcFieldOnFormExperimentOff
+#else
+#define MAYBE_UploadCreditCard_NoCvcFieldOnFormExperimentOff \
+ UploadCreditCard_NoCvcFieldOnFormExperimentOff
+#endif
+TEST_F(AutofillManagerTest,
+ MAYBE_UploadCreditCard_NoCvcFieldOnFormExperimentOff) {
+ EnableUkmLogging();
+ autofill_manager_->set_credit_card_upload_enabled(true);
+
+ // Remove the profiles that were created in the TestPersonalDataManager
+ // constructor because they would result in conflicting names that would
+ // prevent the upload.
+ personal_data_.ClearAutofillProfiles();
+
+ // 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. Note that CVC field is missing.
+ FormData credit_card_form;
+ credit_card_form.name = ASCIIToUTF16("MyForm");
+ credit_card_form.origin = GURL("https://myform.com/form.html");
+ credit_card_form.action = GURL("https://myform.com/submit.html");
+
+ FormFieldData field;
+ test::CreateTestFormField("Card Name", "cardname", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+ test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+ test::CreateTestFormField("Expiration Month", "ccmonth", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+ test::CreateTestFormField("Expiration Year", "ccyear", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+
+ FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+ // Edit the data, and submit.
+ credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
+ credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+ credit_card_form.fields[2].value = ASCIIToUTF16("11");
+ credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+
+ base::HistogramTester histogram_tester;
+
+ // Neither a local save nor an upload should happen in this case.
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0);
+ FormSubmitted(credit_card_form);
+ EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded());
+
+ // Verify that the correct histogram entry (and only that) was logged.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.CardUploadDecisionExpanded",
+ AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC, 1);
+ // Verify that the correct UKM was logged.
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
+
+ rappor::TestRapporServiceImpl* rappor_service =
+ autofill_client_.test_rappor_service();
+ EXPECT_EQ(1, rappor_service->GetReportsCount());
+ std::string sample;
+ rappor::RapporType type;
+ EXPECT_TRUE(rappor_service->GetRecordedSampleForMetric(
+ "Autofill.CardUploadNotOfferedNoCvc", &sample, &type));
+ EXPECT_EQ("myform.com", sample);
+ EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type);
}
// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
@@ -4811,8 +5021,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_NoProfileAvailable) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ADDRESS, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(
- AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ADDRESS);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ADDRESS);
rappor::TestRapporServiceImpl* rappor_service =
autofill_client_.test_rappor_service();
@@ -4865,7 +5074,7 @@ TEST_F(AutofillManagerTest,
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
rappor::TestRapporServiceImpl* rappor_service =
autofill_client_.test_rappor_service();
@@ -4921,8 +5130,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_NoNameAvailable) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_NO_NAME, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(
- AutofillMetrics::UPLOAD_NOT_OFFERED_NO_NAME);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_NAME);
rappor::TestRapporServiceImpl* rappor_service =
autofill_client_.test_rappor_service();
@@ -4955,6 +5163,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_ZipCodesConflict) {
address_forms.push_back(address_form1);
address_forms.push_back(address_form2);
FormsSeen(address_forms);
+ ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
ManuallyFillAddressForm("Flo", "Master", "77401-8294", "US", &address_form1);
FormSubmitted(address_form1);
@@ -4966,6 +5175,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_ZipCodesConflict) {
FormData credit_card_form;
CreateTestCreditCardFormData(&credit_card_form, true, false);
FormsSeen(std::vector<FormData>(1, credit_card_form));
+ ExpectFillableFormParsedUkm(3 /* num_fillable_forms_parsed */);
// Edit the data, but don't include a name, and submit.
credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
@@ -4986,7 +5196,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_ZipCodesConflict) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_ZIPS, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(
+ ExpectCardUploadDecisionUkm(
AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_ZIPS);
}
@@ -5041,7 +5251,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_ZipCodesHavePrefixMatch) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_OFFERED, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
}
// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
@@ -5094,8 +5304,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_NoZipCodeAvailable) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ZIP_CODE, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(
- AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ZIP_CODE);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ZIP_CODE);
}
// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
@@ -5152,7 +5361,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_NamesMatchLoosely) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_OFFERED, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
}
// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
@@ -5206,7 +5415,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_NamesHaveToMatch) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_NAMES, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(
+ ExpectCardUploadDecisionUkm(
AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_NAMES);
rappor::TestRapporServiceImpl* rappor_service =
@@ -5267,7 +5476,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_UploadDetailsFails) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_GET_UPLOAD_DETAILS_FAILED, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(
+ ExpectCardUploadDecisionUkm(
AutofillMetrics::UPLOAD_NOT_OFFERED_GET_UPLOAD_DETAILS_FAILED);
}
@@ -5617,11 +5826,11 @@ TEST_F(AutofillManagerTest, ShouldUploadForm) {
EXPECT_TRUE(autofill_manager_->ShouldUploadForm(form_structure_4));
// Is off the record.
- autofill_driver_->SetIsOffTheRecord(true);
+ autofill_driver_->SetIsIncognito(true);
EXPECT_FALSE(autofill_manager_->ShouldUploadForm(form_structure_4));
// Make sure it's reset for the next test case.
- autofill_driver_->SetIsOffTheRecord(false);
+ autofill_driver_->SetIsIncognito(false);
EXPECT_TRUE(autofill_manager_->ShouldUploadForm(form_structure_4));
// Has one field which is a password field.
@@ -5742,4 +5951,140 @@ TEST_F(AutofillManagerTest, NotifyDriverOfCreditCardInteraction) {
}
}
+// Tests that a form with server only types is still autofillable if the form
+// gets updated in cache.
+TEST_F(AutofillManagerTest, DisplaySuggestionsForUpdatedServerTypedForm) {
+ // Create a form with unknown heuristic fields.
+ FormData form;
+ form.name = ASCIIToUTF16("MyForm");
+ form.origin = GURL("http://myform.com/form.html");
+ form.action = GURL("http://myform.com/submit.html");
+
+ FormFieldData field;
+ test::CreateTestFormField("Field 1", "field1", "", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Field 2", "field2", "", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Field 3", "field3", "", "text", &field);
+ form.fields.push_back(field);
+
+ auto form_structure = base::MakeUnique<TestFormStructure>(form);
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
+ // Make sure the form can not be autofilled now.
+ ASSERT_EQ(0u, form_structure->autofill_count());
+ for (size_t idx = 0; idx < form_structure->field_count(); ++idx) {
+ ASSERT_EQ(UNKNOWN_TYPE, form_structure->field(idx)->heuristic_type());
+ }
+
+ // Prepare and set known server fields.
+ const std::vector<ServerFieldType> heuristic_types(form.fields.size(),
+ UNKNOWN_TYPE);
+ const std::vector<ServerFieldType> server_types{NAME_FIRST, NAME_MIDDLE,
+ NAME_LAST};
+ form_structure->SetFieldTypes(heuristic_types, server_types);
+ autofill_manager_->AddSeenForm(std::move(form_structure));
+
+ // Make sure the form can be autofilled.
+ for (const FormFieldData& field : form.fields) {
+ GetAutofillSuggestions(form, field);
+ ASSERT_TRUE(external_delegate_->on_suggestions_returned_seen());
+ }
+
+ // Modify one of the fields in the original form.
+ form.fields[0].css_classes += ASCIIToUTF16("a");
+
+ // Expect the form still can be autofilled.
+ for (const FormFieldData& field : form.fields) {
+ GetAutofillSuggestions(form, field);
+ EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+ }
+
+ // Modify form action URL. This can happen on in-page navitaion if the form
+ // doesn't have an actual action (attribute is empty).
+ form.action = net::AppendQueryParameter(form.action, "arg", "value");
+
+ // Expect the form still can be autofilled.
+ for (const FormFieldData& field : form.fields) {
+ GetAutofillSuggestions(form, field);
+ EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+ }
+}
+
+// Tests that a form with <select> field is accepted if <option> value (not
+// content) is quite long. Some websites use value to propagate long JSON to
+// JS-backed logic.
+TEST_F(AutofillManagerTest, FormWithLongOptionValuesIsAcceptable) {
+ FormData form;
+ form.name = ASCIIToUTF16("MyForm");
+ form.origin = GURL("http://myform.com/form.html");
+ form.action = GURL("http://myform.com/submit.html");
+
+ FormFieldData field;
+ test::CreateTestFormField("First name", "firstname", "", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Last name", "lastname", "", "text", &field);
+ form.fields.push_back(field);
+
+ // Prepare <select> field with long <option> values.
+ const size_t kOptionValueLength = 10240;
+ const std::string long_string(kOptionValueLength, 'a');
+ const std::vector<const char*> values(3, long_string.c_str());
+ const std::vector<const char*> contents{"A", "B", "C"};
+ test::CreateTestSelectField("Country", "country", "", values, contents,
+ values.size(), &field);
+ form.fields.push_back(field);
+
+ FormsSeen({form});
+
+ // Suggestions should be displayed.
+ for (const FormFieldData& field : form.fields) {
+ GetAutofillSuggestions(form, field);
+ EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+ }
+}
+
+// Test that a sign-in form submission sends an upload with types matching the
+// fields.
+TEST_F(AutofillManagerTest, SignInFormSubmission_Upload) {
+ // Set up our form data (it's already filled out with user data).
+ FormData form;
+ form.origin = GURL("http://myform.com/form.html");
+ form.action = GURL("http://myform.com/submit.html");
+
+ std::vector<ServerFieldTypeSet> expected_types;
+ ServerFieldTypeSet types;
+
+ FormFieldData field;
+ test::CreateTestFormField("Email", "email", "theking@gmail.com", "text",
+ &field);
+ form.fields.push_back(field);
+ types.insert(EMAIL_ADDRESS);
+ expected_types.push_back(types);
+
+ test::CreateTestFormField("Password", "pw", "secret", "password", &field);
+ form.fields.push_back(field);
+ types.clear();
+ types.insert(PASSWORD);
+ expected_types.push_back(types);
+
+ // We will expect these types in the upload and no observed submission. (the
+ // callback initiated by WaitForAsyncUploadProcess checks these expectations.)
+ autofill_manager_->set_expected_submitted_field_types(expected_types);
+ autofill_manager_->set_expected_observed_submission(true);
+ autofill_manager_->ResetRunLoop();
+
+ std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
+ form_structure->set_is_signin_upload(true);
+ form_structure->field(1)->set_possible_types({autofill::PASSWORD});
+
+ std::string signature = form_structure->FormSignatureAsStr();
+ autofill_manager_->StartUploadProcess(std::move(form_structure),
+ base::TimeTicks::Now(), true);
+
+ // Wait for upload to complete (will check expected types as well).
+ autofill_manager_->WaitForAsyncUploadProcess();
+
+ EXPECT_EQ(signature, autofill_manager_->GetSubmittedFormSignature());
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_metrics.cc b/chromium/components/autofill/core/browser/autofill_metrics.cc
index 239334c5e66..77442395f20 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics.cc
@@ -5,6 +5,8 @@
#include "components/autofill/core/browser/autofill_metrics.h"
#include <algorithm>
+#include <utility>
+#include <vector>
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
@@ -12,6 +14,7 @@
#include "base/metrics/user_metrics.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_experiments.h"
+#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/form_data.h"
@@ -20,6 +23,30 @@
namespace internal {
const char kUKMCardUploadDecisionEntryName[] = "Autofill.CardUploadDecision";
const char kUKMCardUploadDecisionMetricName[] = "UploadDecision";
+const char kUKMDeveloperEngagementEntryName[] = "Autofill.DeveloperEngagement";
+const char kUKMDeveloperEngagementMetricName[] = "DeveloperEngagement";
+const char kUKMMillisecondsSinceFormLoadedMetricName[] =
+ "MillisecondsSinceFormLoaded";
+const char kUKMInteractedWithFormEntryName[] = "Autofill.InteractedWithForm";
+const char kUKMIsForCreditCardMetricName[] = "IsForCreditCard";
+const char kUKMLocalRecordTypeCountMetricName[] = "LocalRecordTypeCount";
+const char kUKMServerRecordTypeCountMetricName[] = "ServerRecordTypeCount";
+const char kUKMSuggestionsShownEntryName[] = "Autofill.SuggestionsShown";
+const char kUKMSelectedMaskedServerCardEntryName[] =
+ "Autofill.SelectedMaskedServerCard";
+const char kUKMSuggestionFilledEntryName[] = "Autofill.SuggestionFilled";
+const char kUKMRecordTypeMetricName[] = "RecordType";
+const char kUKMTextFieldDidChangeEntryName[] = "Autofill.TextFieldDidChange";
+const char kUKMFieldTypeGroupMetricName[] = "FieldTypeGroup";
+const char kUKMHeuristicTypeMetricName[] = "HeuristicType";
+const char kUKMServerTypeMetricName[] = "ServerType";
+const char kUKMHtmlFieldTypeMetricName[] = "HtmlFieldType";
+const char kUKMHtmlFieldModeMetricName[] = "HtmlFieldMode";
+const char kUKMIsAutofilledMetricName[] = "IsAutofilled";
+const char kUKMIsEmptyMetricName[] = "IsEmpty";
+const char kUKMFormSubmittedEntryName[] = "Autofill.AutofillFormSubmitted";
+const char kUKMAutofillFormSubmittedStateMetricName[] =
+ "AutofillFormSubmittedState";
} // namespace internal
namespace autofill {
@@ -614,7 +641,8 @@ void AutofillMetrics::LogProfileActionOnFormSubmitted(
// static
void AutofillMetrics::LogAutofillFormSubmittedState(
- AutofillFormSubmittedState state) {
+ AutofillFormSubmittedState state,
+ AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger) {
UMA_HISTOGRAM_ENUMERATION("Autofill.FormSubmittedState", state,
AUTOFILL_FORM_SUBMITTED_STATE_ENUM_SIZE);
@@ -648,6 +676,7 @@ void AutofillMetrics::LogAutofillFormSubmittedState(
NOTREACHED();
break;
}
+ form_interactions_ukm_logger->LogFormSubmitted(state);
}
// static
@@ -704,18 +733,32 @@ void AutofillMetrics::LogCardUploadDecisionUkm(
if (upload_decision >= AutofillMetrics::NUM_CARD_UPLOAD_DECISION_METRICS)
return;
- // Set up as a map because the follow-up CL will add more metrics.
- std::map<std::string, int> metrics = {
+ const std::vector<std::pair<const char*, int>> metrics = {
{internal::kUKMCardUploadDecisionMetricName,
static_cast<int>(upload_decision)}};
LogUkm(ukm_service, url, internal::kUKMCardUploadDecisionEntryName, metrics);
}
// static
-bool AutofillMetrics::LogUkm(ukm::UkmService* ukm_service,
- const GURL& url,
- const std::string& ukm_entry_name,
- const std::map<std::string, int>& metrics) {
+void AutofillMetrics::LogDeveloperEngagementUkm(
+ ukm::UkmService* ukm_service,
+ const GURL& url,
+ std::vector<AutofillMetrics::DeveloperEngagementMetric> metrics) {
+ std::vector<std::pair<const char*, int>> form_structure_metrics;
+ for (const auto it : metrics)
+ form_structure_metrics.push_back(
+ {internal::kUKMDeveloperEngagementMetricName, static_cast<int>(it)});
+
+ LogUkm(ukm_service, url, internal::kUKMDeveloperEngagementEntryName,
+ form_structure_metrics);
+}
+
+// static
+bool AutofillMetrics::LogUkm(
+ ukm::UkmService* ukm_service,
+ const GURL& url,
+ const std::string& ukm_entry_name,
+ const std::vector<std::pair<const char*, int>>& metrics) {
if (!IsUkmLoggingEnabled() || !ukm_service || !url.is_valid() ||
metrics.empty()) {
return false;
@@ -727,16 +770,18 @@ bool AutofillMetrics::LogUkm(ukm::UkmService* ukm_service,
ukm_service->GetEntryBuilder(source_id, ukm_entry_name.c_str());
for (auto it = metrics.begin(); it != metrics.end(); ++it) {
- builder->AddMetric(it->first.c_str(), it->second);
+ builder->AddMetric(it->first, it->second);
}
return true;
}
-AutofillMetrics::FormEventLogger::FormEventLogger(bool is_for_credit_card)
+AutofillMetrics::FormEventLogger::FormEventLogger(
+ bool is_for_credit_card,
+ AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger)
: is_for_credit_card_(is_for_credit_card),
- is_server_data_available_(false),
- is_local_data_available_(false),
+ server_record_type_count_(0),
+ local_record_type_count_(0),
is_context_secure_(false),
has_logged_interacted_(false),
has_logged_suggestions_shown_(false),
@@ -745,11 +790,15 @@ AutofillMetrics::FormEventLogger::FormEventLogger(bool is_for_credit_card)
has_logged_will_submit_(false),
has_logged_submitted_(false),
logged_suggestion_filled_was_server_data_(false),
- logged_suggestion_filled_was_masked_server_card_(false) {}
+ logged_suggestion_filled_was_masked_server_card_(false),
+ form_interactions_ukm_logger_(form_interactions_ukm_logger) {}
void AutofillMetrics::FormEventLogger::OnDidInteractWithAutofillableForm() {
if (!has_logged_interacted_) {
has_logged_interacted_ = true;
+ form_interactions_ukm_logger_->LogInteractedWithForm(
+ is_for_credit_card_, local_record_type_count_,
+ server_record_type_count_);
Log(AutofillMetrics::FORM_EVENT_INTERACTED_ONCE);
}
}
@@ -774,6 +823,8 @@ void AutofillMetrics::FormEventLogger::OnDidPollSuggestions(
}
void AutofillMetrics::FormEventLogger::OnDidShowSuggestions() {
+ form_interactions_ukm_logger_->LogSuggestionsShown();
+
Log(AutofillMetrics::FORM_EVENT_SUGGESTIONS_SHOWN);
if (!has_logged_suggestions_shown_) {
has_logged_suggestions_shown_ = true;
@@ -791,17 +842,22 @@ void AutofillMetrics::FormEventLogger::OnDidShowSuggestions() {
void AutofillMetrics::FormEventLogger::OnDidSelectMaskedServerCardSuggestion() {
DCHECK(is_for_credit_card_);
+ form_interactions_ukm_logger_->LogSelectedMaskedServerCard();
+
Log(AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED);
if (!has_logged_masked_server_card_suggestion_selected_) {
has_logged_masked_server_card_suggestion_selected_ = true;
- Log(AutofillMetrics
- ::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED_ONCE);
+ Log(AutofillMetrics::
+ FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED_ONCE);
}
}
void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
const CreditCard& credit_card) {
DCHECK(is_for_credit_card_);
+ form_interactions_ukm_logger_->LogDidFillSuggestion(
+ static_cast<int>(credit_card.record_type()));
+
if (credit_card.record_type() == CreditCard::MASKED_SERVER_CARD)
Log(AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED);
else if (credit_card.record_type() == CreditCard::FULL_SERVER_CARD)
@@ -817,8 +873,8 @@ void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
logged_suggestion_filled_was_masked_server_card_ =
credit_card.record_type() == CreditCard::MASKED_SERVER_CARD;
if (credit_card.record_type() == CreditCard::MASKED_SERVER_CARD) {
- Log(AutofillMetrics
- ::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED_ONCE);
+ Log(AutofillMetrics::
+ FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED_ONCE);
} else if (credit_card.record_type() == CreditCard::FULL_SERVER_CARD) {
Log(AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_FILLED_ONCE);
} else {
@@ -833,6 +889,9 @@ void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
const AutofillProfile& profile) {
DCHECK(!is_for_credit_card_);
+ form_interactions_ukm_logger_->LogDidFillSuggestion(
+ static_cast<int>(profile.record_type()));
+
if (profile.record_type() == AutofillProfile::SERVER_PROFILE)
Log(AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_FILLED);
else
@@ -843,8 +902,8 @@ void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
logged_suggestion_filled_was_server_data_ =
profile.record_type() == AutofillProfile::SERVER_PROFILE;
Log(profile.record_type() == AutofillProfile::SERVER_PROFILE
- ? AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_FILLED_ONCE
- : AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_FILLED_ONCE);
+ ? AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_FILLED_ONCE
+ : AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_FILLED_ONCE);
}
base::RecordAction(
@@ -892,8 +951,8 @@ void AutofillMetrics::FormEventLogger::OnFormSubmitted() {
if (!has_logged_suggestion_filled_) {
Log(AutofillMetrics::FORM_EVENT_NO_SUGGESTION_SUBMITTED_ONCE);
} else if (logged_suggestion_filled_was_masked_server_card_) {
- Log(AutofillMetrics
- ::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE);
+ Log(AutofillMetrics::
+ FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE);
} else if (logged_suggestion_filled_was_server_data_) {
Log(AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_SUBMITTED_ONCE);
} else {
@@ -925,15 +984,154 @@ void AutofillMetrics::FormEventLogger::Log(FormEvent event) const {
// Logging again in a different histogram for segmentation purposes.
// TODO(waltercacau): Re-evaluate if we still need such fine grained
// segmentation. http://crbug.com/454018
- if (!is_server_data_available_ && !is_local_data_available_)
+ if (server_record_type_count_ == 0 && local_record_type_count_ == 0)
name += ".WithNoData";
- else if (is_server_data_available_ && !is_local_data_available_)
+ else if (server_record_type_count_ > 0 && local_record_type_count_ == 0)
name += ".WithOnlyServerData";
- else if (!is_server_data_available_ && is_local_data_available_)
+ else if (server_record_type_count_ == 0 && local_record_type_count_ > 0)
name += ".WithOnlyLocalData";
else
name += ".WithBothServerAndLocalData";
LogUMAHistogramEnumeration(name, event, NUM_FORM_EVENTS);
}
+AutofillMetrics::FormInteractionsUkmLogger::FormInteractionsUkmLogger(
+ ukm::UkmService* ukm_service)
+ : ukm_service_(ukm_service) {}
+
+void AutofillMetrics::FormInteractionsUkmLogger::OnFormsLoaded(
+ const GURL& url) {
+ if (!IsUkmLoggingEnabled() || ukm_service_ == nullptr)
+ return;
+
+ url_ = url;
+ form_loaded_timestamp_ = base::TimeTicks::Now();
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::LogInteractedWithForm(
+ bool is_for_credit_card,
+ size_t local_record_type_count,
+ size_t server_record_type_count) {
+ if (!CanLog())
+ return;
+
+ if (source_id_ == -1)
+ GetNewSourceID();
+
+ std::unique_ptr<ukm::UkmEntryBuilder> builder = ukm_service_->GetEntryBuilder(
+ source_id_, internal::kUKMInteractedWithFormEntryName);
+ builder->AddMetric(internal::kUKMIsForCreditCardMetricName,
+ is_for_credit_card);
+ builder->AddMetric(internal::kUKMLocalRecordTypeCountMetricName,
+ local_record_type_count);
+ builder->AddMetric(internal::kUKMServerRecordTypeCountMetricName,
+ server_record_type_count);
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::LogSuggestionsShown() {
+ if (!CanLog())
+ return;
+
+ if (source_id_ == -1)
+ GetNewSourceID();
+
+ std::unique_ptr<ukm::UkmEntryBuilder> builder = ukm_service_->GetEntryBuilder(
+ source_id_, internal::kUKMSuggestionsShownEntryName);
+ builder->AddMetric(internal::kUKMMillisecondsSinceFormLoadedMetricName,
+ MillisecondsSinceFormLoaded());
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::LogSelectedMaskedServerCard() {
+ if (!CanLog())
+ return;
+
+ if (source_id_ == -1)
+ GetNewSourceID();
+
+ std::unique_ptr<ukm::UkmEntryBuilder> builder = ukm_service_->GetEntryBuilder(
+ source_id_, internal::kUKMSelectedMaskedServerCardEntryName);
+ builder->AddMetric(internal::kUKMMillisecondsSinceFormLoadedMetricName,
+ MillisecondsSinceFormLoaded());
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::LogDidFillSuggestion(
+ int record_type) {
+ if (!CanLog())
+ return;
+
+ if (source_id_ == -1)
+ GetNewSourceID();
+
+ std::unique_ptr<ukm::UkmEntryBuilder> builder = ukm_service_->GetEntryBuilder(
+ source_id_, internal::kUKMSuggestionFilledEntryName);
+ builder->AddMetric(internal::kUKMRecordTypeMetricName, record_type);
+ builder->AddMetric(internal::kUKMMillisecondsSinceFormLoadedMetricName,
+ MillisecondsSinceFormLoaded());
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::LogTextFieldDidChange(
+ const AutofillField& field) {
+ if (!CanLog())
+ return;
+
+ if (source_id_ == -1)
+ GetNewSourceID();
+
+ std::unique_ptr<ukm::UkmEntryBuilder> builder = ukm_service_->GetEntryBuilder(
+ source_id_, internal::kUKMTextFieldDidChangeEntryName);
+ builder->AddMetric(internal::kUKMFieldTypeGroupMetricName,
+ static_cast<int>(field.Type().group()));
+ builder->AddMetric(internal::kUKMHeuristicTypeMetricName,
+ static_cast<int>(field.heuristic_type()));
+ builder->AddMetric(internal::kUKMServerTypeMetricName,
+ static_cast<int>(field.server_type()));
+ builder->AddMetric(internal::kUKMHtmlFieldTypeMetricName,
+ static_cast<int>(field.html_type()));
+ builder->AddMetric(internal::kUKMHtmlFieldModeMetricName,
+ static_cast<int>(field.html_mode()));
+ builder->AddMetric(internal::kUKMIsAutofilledMetricName, field.is_autofilled);
+ builder->AddMetric(internal::kUKMIsEmptyMetricName, field.IsEmpty());
+ builder->AddMetric(internal::kUKMMillisecondsSinceFormLoadedMetricName,
+ MillisecondsSinceFormLoaded());
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::LogFormSubmitted(
+ AutofillFormSubmittedState state) {
+ if (!CanLog())
+ return;
+
+ if (source_id_ == -1)
+ GetNewSourceID();
+
+ std::unique_ptr<ukm::UkmEntryBuilder> builder = ukm_service_->GetEntryBuilder(
+ source_id_, internal::kUKMFormSubmittedEntryName);
+ builder->AddMetric(internal::kUKMAutofillFormSubmittedStateMetricName,
+ static_cast<int>(state));
+ builder->AddMetric(internal::kUKMMillisecondsSinceFormLoadedMetricName,
+ MillisecondsSinceFormLoaded());
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::UpdateSourceURL(
+ const GURL& url) {
+ url_ = url;
+ if (CanLog())
+ ukm_service_->UpdateSourceURL(source_id_, url_);
+}
+
+bool AutofillMetrics::FormInteractionsUkmLogger::CanLog() const {
+ return IsUkmLoggingEnabled() && ukm_service_ && url_.is_valid();
+}
+
+int64_t
+AutofillMetrics::FormInteractionsUkmLogger::MillisecondsSinceFormLoaded()
+ const {
+ DCHECK(!form_loaded_timestamp_.is_null());
+ return (base::TimeTicks::Now() - form_loaded_timestamp_).InMilliseconds();
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::GetNewSourceID() {
+ source_id_ = ukm_service_->GetNewSourceID();
+ ukm_service_->UpdateSourceURL(source_id_, url_);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_metrics.h b/chromium/components/autofill/core/browser/autofill_metrics.h
index d0aba8221f6..58ab8d26aa0 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics.h
+++ b/chromium/components/autofill/core/browser/autofill_metrics.h
@@ -7,18 +7,17 @@
#include <stddef.h>
#include <string>
+#include <utility>
+#include <vector>
#include "base/macros.h"
+#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/credit_card.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/common/form_field_data.h"
-namespace base {
-class TimeDelta;
-} // namespace base
-
namespace ukm {
class UkmService;
} // namespace ukm
@@ -27,10 +26,55 @@ namespace internal {
// Name constants are exposed here so they can be referenced from tests.
extern const char kUKMCardUploadDecisionEntryName[];
extern const char kUKMCardUploadDecisionMetricName[];
+extern const char kUKMDeveloperEngagementEntryName[];
+extern const char kUKMDeveloperEngagementMetricName[];
+
+// Each form interaction event has a separate |UkmEntry|.
+
+// The first form event |UkmEntry| contains metrics for metadata that apply
+// to all subsequent events.
+extern const char kUKMInteractedWithFormEntryName[];
+extern const char kUKMIsForCreditCardMetricName[];
+extern const char kUKMLocalRecordTypeCountMetricName[];
+extern const char kUKMServerRecordTypeCountMetricName[];
+
+// |UkmEntry| when we show suggestions.
+extern const char kUKMSuggestionsShownEntryName[];
+
+// |UkmEntry| when user selects a masked server credit card.
+extern const char kUKMSelectedMaskedServerCardEntryName[];
+
+// Each |UkmEntry|, except the first interaction with the form, has a metric for
+// time elapsed, in milliseconds, since we loaded the form.
+extern const char kUKMMillisecondsSinceFormLoadedMetricName[];
+
+// |FormEvent| for FORM_EVENT_*_SUGGESTION_FILLED in credit card forms include a
+// |CreditCard| |record_type()| to indicate if the suggestion was for a local
+// card, masked server card or full server card. Similarly, address/profile
+// forms include a |AutofillProfile| |record_type()| to indicate if the
+// profile was a local profile or server profile.
+extern const char kUKMSuggestionFilledEntryName[];
+extern const char kUKMRecordTypeMetricName[];
+
+// |UkmEntry| for user editing text field. Metrics contain field's attributes.
+extern const char kUKMTextFieldDidChangeEntryName[];
+extern const char kUKMFieldTypeGroupMetricName[];
+extern const char kUKMHeuristicTypeMetricName[];
+extern const char kUKMServerTypeMetricName[];
+extern const char kUKMHtmlFieldTypeMetricName[];
+extern const char kUKMHtmlFieldModeMetricName[];
+extern const char kUKMIsAutofilledMetricName[];
+extern const char kUKMIsEmptyMetricName[];
+
+// |UkmEntry| for |AutofillFormSubmittedState|.
+extern const char kUKMFormSubmittedEntryName[];
+extern const char kUKMAutofillFormSubmittedStateMetricName[];
} // namespace internal
namespace autofill {
+class AutofillField;
+
class AutofillMetrics {
public:
enum AutofillProfileAction {
@@ -80,16 +124,23 @@ class AutofillMetrics {
// were otherwise valid nor whether we would have been able to get upload
// details.
UPLOAD_NOT_OFFERED_CONFLICTING_NAMES,
+ // No CVC was detected, but valid addresses and names were. Upload is still
+ // possible if the user manually enters CVC, so upload was offered.
+ UPLOAD_OFFERED_NO_CVC,
NUM_CARD_UPLOAD_DECISION_METRICS,
};
enum DeveloperEngagementMetric {
- // Parsed a form that is potentially autofillable.
- FILLABLE_FORM_PARSED = 0,
+ // Parsed a form that is potentially autofillable and does not contain any
+ // web developer-specified field type hint.
+ FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS = 0,
// Parsed a form that is potentially autofillable and contains at least one
// web developer-specified field type hint, a la
// http://is.gd/whatwg_autocomplete
- FILLABLE_FORM_CONTAINS_TYPE_HINTS,
+ FILLABLE_FORM_PARSED_WITH_TYPE_HINTS,
+ // Parsed a form that is potentially autofillable and contains at least one
+ // UPI Virtual Payment Address hint (upi-vpa)
+ FORM_CONTAINS_UPI_VPA_HINT,
NUM_DEVELOPER_ENGAGEMENT_METRICS,
};
@@ -256,6 +307,7 @@ class AutofillMetrics {
SAVE_CARD_PROMPT_DISMISS_CLICK_LEARN_MORE,
// The prompt was dismissed because the user clicked a legal message link.
SAVE_CARD_PROMPT_DISMISS_CLICK_LEGAL_MESSAGE,
+
NUM_SAVE_CARD_PROMPT_METRICS,
};
@@ -264,9 +316,27 @@ class AutofillMetrics {
// the heuristic prediction, for the crowd-sourced prediction, and for the
// overall prediction.
enum FieldTypeQualityMetric {
- TYPE_UNKNOWN = 0, // Offered no prediction.
- TYPE_MATCH, // Predicted correctly.
- TYPE_MISMATCH, // Predicted incorrectly.
+ // The field was found to be of type T, but autofill made no prediction.
+ TYPE_UNKNOWN = 0,
+ // The field was found to be of type T, which matches the predicted type.
+ TYPE_MATCH,
+ // The field was found to be of type T, autofill predicted some other type.
+ TYPE_MISMATCH,
+ // The field was left empty and autofil predicted that the field type would
+ // be UNKNOWN.
+ TYPE_MATCH_EMPTY,
+ // The field was populated with data that did not match any part of the
+ // user's profile (it's type could not be determined). Autofill predicted
+ // the field's type would be UNKNOWN.
+ TYPE_MATCH_UNKNOWN,
+ // The field was left empty, autofill predicted the user would populate it
+ // with autofillable data.
+ TYPE_MISMATCH_EMPTY,
+ // The field was populated with data that did not match any part of the
+ // user's profile (it's type could not be determined). Autofill predicted
+ // the user would populate it with autofillable data.
+ TYPE_MISMATCH_UNKNOWN,
+ // This must be the last value.
NUM_FIELD_TYPE_QUALITY_METRICS,
};
@@ -345,6 +415,10 @@ class AutofillMetrics {
USER_DID_EDIT_AUTOFILLED_FIELD,
// Same as above, but only logged once per page load.
USER_DID_EDIT_AUTOFILLED_FIELD_ONCE,
+
+ // User entered form data that appears to be a UPI Virtual Payment Address.
+ USER_DID_ENTER_UPI_VPA,
+
NUM_USER_HAPPINESS_METRICS,
};
@@ -537,6 +611,39 @@ class AutofillMetrics {
NUM_CONVERTED_ADDRESS_CONVERSION_TYPES
};
+ // Utility to log URL keyed form interaction events.
+ class FormInteractionsUkmLogger {
+ public:
+ explicit FormInteractionsUkmLogger(ukm::UkmService* ukm_service);
+
+ const GURL& url() const { return url_; }
+
+ void OnFormsLoaded(const GURL& url);
+ void LogInteractedWithForm(bool is_for_credit_card,
+ size_t local_record_type_count,
+ size_t server_record_type_count);
+ void LogSuggestionsShown();
+ void LogSelectedMaskedServerCard();
+ void LogDidFillSuggestion(int record_type);
+ void LogTextFieldDidChange(const AutofillField& field);
+ void LogFormSubmitted(AutofillFormSubmittedState state);
+
+ // We initialize |url_| with the form's URL when we log the first form
+ // interaction. Later, we may update |url_| with the |source_url()| for the
+ // submitted form.
+ void UpdateSourceURL(const GURL& url);
+
+ private:
+ bool CanLog() const;
+ int64_t MillisecondsSinceFormLoaded() const;
+ void GetNewSourceID();
+
+ ukm::UkmService* ukm_service_; // Weak reference.
+ int32_t source_id_ = -1;
+ GURL url_;
+ base::TimeTicks form_loaded_timestamp_;
+ };
+
static void LogCardUploadDecisionMetric(CardUploadDecisionMetric metric);
static void LogCreditCardInfoBarMetric(InfoBarMetric metric,
bool is_uploading);
@@ -663,7 +770,9 @@ class AutofillMetrics {
// This should be called at each form submission to indicate the autofilled
// state of the form.
- static void LogAutofillFormSubmittedState(AutofillFormSubmittedState state);
+ static void LogAutofillFormSubmittedState(
+ AutofillFormSubmittedState state,
+ FormInteractionsUkmLogger* form_interactions_ukm_logger);
// This should be called when determining the heuristic types for a form's
// fields.
@@ -697,25 +806,33 @@ class AutofillMetrics {
const GURL& url,
AutofillMetrics::CardUploadDecisionMetric upload_decision);
+ // Logs the developer engagement ukm for the specified |url| and autofill
+ // fields in the form structure.
+ static void LogDeveloperEngagementUkm(
+ ukm::UkmService* ukm_service,
+ const GURL& url,
+ std::vector<AutofillMetrics::DeveloperEngagementMetric> metrics);
+
// Logs the the |ukm_entry_name| with the specified |url| and the specified
// |metrics|. Returns whether the ukm was sucessfully logged.
static bool LogUkm(ukm::UkmService* ukm_service,
const GURL& url,
const std::string& ukm_entry_name,
- const std::map<std::string, int>& metrics);
+ const std::vector<std::pair<const char*, int>>& metrics);
- // Utility to autofill form events in the relevant histograms depending on
+ // Utility to log autofill form events in the relevant histograms depending on
// the presence of server and/or local data.
class FormEventLogger {
public:
- FormEventLogger(bool is_for_credit_card);
+ FormEventLogger(bool is_for_credit_card,
+ FormInteractionsUkmLogger* form_interactions_ukm_logger);
- inline void set_is_server_data_available(bool is_server_data_available) {
- is_server_data_available_ = is_server_data_available;
+ inline void set_server_record_type_count(size_t server_record_type_count) {
+ server_record_type_count_ = server_record_type_count;
}
- inline void set_is_local_data_available(bool is_local_data_available) {
- is_local_data_available_ = is_local_data_available;
+ inline void set_local_record_type_count(size_t local_record_type_count) {
+ local_record_type_count_ = local_record_type_count;
}
inline void set_is_context_secure(bool is_context_secure) {
@@ -744,8 +861,8 @@ class AutofillMetrics {
void Log(FormEvent event) const;
bool is_for_credit_card_;
- bool is_server_data_available_;
- bool is_local_data_available_;
+ size_t server_record_type_count_;
+ size_t local_record_type_count_;
bool is_context_secure_;
bool has_logged_interacted_;
bool has_logged_suggestions_shown_;
@@ -758,6 +875,9 @@ class AutofillMetrics {
// The last field that was polled for suggestions.
FormFieldData last_polled_field_;
+
+ FormInteractionsUkmLogger*
+ form_interactions_ukm_logger_; // Weak reference.
};
private:
diff --git a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
index 36039f5f382..3372ee37884 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -6,8 +6,8 @@
#include <stddef.h>
-#include <map>
#include <memory>
+#include <utility>
#include <vector>
#include "base/feature_list.h"
@@ -19,6 +19,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
#include "base/test/user_action_tester.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_experiments.h"
@@ -54,6 +55,8 @@ using base::Bucket;
using base::TimeTicks;
using rappor::TestRapporServiceImpl;
using ::testing::ElementsAre;
+using ::testing::Matcher;
+using ::testing::UnorderedPointwise;
namespace autofill {
namespace {
@@ -263,6 +266,8 @@ class TestAutofillManager : public AutofillManager {
base::MakeUnique<TestFormStructure>(empty_form);
form_structure->SetFieldTypes(heuristic_types, server_types);
form_structures()->push_back(std::move(form_structure));
+
+ form_interactions_ukm_logger()->OnFormsLoaded(form.origin);
}
// Calls AutofillManager::OnWillSubmitForm and waits for it to complete.
@@ -287,9 +292,9 @@ class TestAutofillManager : public AutofillManager {
void RunRunLoop() { run_loop_->Run(); }
void UploadFormDataAsyncCallback(const FormStructure* submitted_form,
- const base::TimeTicks& load_time,
- const base::TimeTicks& interaction_time,
- const base::TimeTicks& submission_time,
+ const TimeTicks& load_time,
+ const TimeTicks& interaction_time,
+ const TimeTicks& submission_time,
bool observed_submission) override {
run_loop_->Quit();
@@ -316,6 +321,83 @@ const ukm::Entry_Metric* FindMetric(
return nullptr;
}
+MATCHER(CompareMetrics, "") {
+ const ukm::Entry_Metric& lhs = ::testing::get<0>(arg);
+ const std::pair<const char*, int64_t>& rhs = ::testing::get<1>(arg);
+ return lhs.metric_hash() == base::HashMetricName(rhs.first) &&
+ lhs.value() == rhs.second;
+}
+
+void VerifyDeveloperEngagementUkm(
+ const FormData& form,
+ const ukm::TestUkmService* ukm_service,
+ const std::vector<int64_t>& expected_metric_values) {
+ const ukm::UkmEntry* entry = ukm_service->GetEntryForEntryName(
+ internal::kUKMDeveloperEngagementEntryName);
+ ASSERT_NE(nullptr, entry);
+ ukm::Entry entry_proto;
+ entry->PopulateProto(&entry_proto);
+
+ const ukm::UkmSource* source =
+ ukm_service->GetSourceForSourceId(entry_proto.source_id());
+ ASSERT_NE(nullptr, source);
+ EXPECT_EQ(form.origin, source->url());
+
+ std::vector<std::pair<const char*, int64_t>> expected_metrics;
+ for (const auto it : expected_metric_values)
+ expected_metrics.push_back(
+ {internal::kUKMDeveloperEngagementMetricName, it});
+
+ EXPECT_THAT(entry_proto.metrics(),
+ UnorderedPointwise(CompareMetrics(), expected_metrics));
+}
+
+MATCHER(CompareMetricsIgnoringMillisecondsSinceFormLoaded, "") {
+ const ukm::Entry_Metric& lhs = ::testing::get<0>(arg);
+ const std::pair<const char*, int64_t>& rhs = ::testing::get<1>(arg);
+ return lhs.metric_hash() == base::HashMetricName(rhs.first) &&
+ (lhs.value() == rhs.second ||
+ (lhs.value() > 0 &&
+ rhs.first == internal::kUKMMillisecondsSinceFormLoadedMetricName));
+}
+
+void VerifyFormInteractionUkm(
+ const FormData& form,
+ const ukm::TestUkmService* ukm_service,
+ const char* event_name,
+ const std::vector<std::vector<std::pair<const char*, int64_t>>>&
+ expected_metrics) {
+ size_t expected_metrics_index = 0;
+ for (size_t i = 0; i < ukm_service->entries_count(); ++i) {
+ const ukm::UkmEntry* entry = ukm_service->GetEntry(i);
+ if (entry->event_hash() != base::HashMetricName(event_name))
+ continue;
+
+ ukm::Entry entry_proto;
+ entry->PopulateProto(&entry_proto);
+
+ const ukm::UkmSource* source =
+ ukm_service->GetSourceForSourceId(entry_proto.source_id());
+ ASSERT_NE(nullptr, source);
+ EXPECT_EQ(form.origin, source->url());
+
+ ASSERT_LT(expected_metrics_index, expected_metrics.size());
+ EXPECT_THAT(
+ entry_proto.metrics(),
+ UnorderedPointwise(CompareMetricsIgnoringMillisecondsSinceFormLoaded(),
+ expected_metrics[expected_metrics_index++]));
+ }
+}
+
+void VerifySubmitFormUkm(const FormData& form,
+ const ukm::TestUkmService* ukm_service,
+ AutofillMetrics::AutofillFormSubmittedState state) {
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMFormSubmittedEntryName,
+ {{{internal::kUKMAutofillFormSubmittedStateMetricName, state},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+}
+
} // namespace
// This is defined in the autofill_metrics.cc implementation file.
@@ -333,7 +415,7 @@ class AutofillMetricsTest : public testing::Test {
void EnableWalletSync();
void EnableUkmLogging();
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
TestAutofillClient autofill_client_;
std::unique_ptr<AccountTrackerService> account_tracker_;
std::unique_ptr<FakeSigninManagerBase> signin_manager_;
@@ -393,6 +475,7 @@ void AutofillMetricsTest::TearDown() {
account_tracker_.reset();
signin_client_.reset();
test::ReenableSystemServices();
+ autofill_client_.GetTestUkmService()->Purge();
}
void AutofillMetricsTest::EnableWalletSync() {
@@ -542,6 +625,129 @@ TEST_F(AutofillMetricsTest, QualityMetrics) {
GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TYPE_MISMATCH), 1);
}
+// Tests the true negatives (empty + no prediction and unknown + no prediction)
+// and false positives (empty + bad prediction and unknown + bad prediction)
+// are counted correctly.
+
+struct UnrecognizedOrEmptyFieldsCase {
+ const ServerFieldType actual_field_type;
+ const bool make_prediction;
+ const AutofillMetrics::FieldTypeQualityMetric metric_to_test;
+};
+
+class UnrecognizedOrEmptyFieldsTest
+ : public AutofillMetricsTest,
+ public testing::WithParamInterface<UnrecognizedOrEmptyFieldsCase> {};
+
+TEST_P(UnrecognizedOrEmptyFieldsTest, QualityMetrics) {
+ // Setup the test parameters.
+ const ServerFieldType actual_field_type = GetParam().actual_field_type;
+ const ServerFieldType heuristic_type =
+ GetParam().make_prediction ? EMAIL_ADDRESS : UNKNOWN_TYPE;
+ const ServerFieldType server_type =
+ GetParam().make_prediction ? EMAIL_ADDRESS : NO_SERVER_DATA;
+ const AutofillMetrics::FieldTypeQualityMetric metric_to_test =
+ GetParam().metric_to_test;
+
+ // Set up our form data.
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+
+ std::vector<ServerFieldType> heuristic_types, server_types;
+ AutofillField field;
+
+ // Add a first name field, that is predicted correctly.
+ test::CreateTestFormField("first", "first", "Elvis", "text", &field);
+ field.set_possible_types({NAME_FIRST});
+ form.fields.push_back(field);
+ heuristic_types.push_back(NAME_FIRST);
+ server_types.push_back(NAME_FIRST);
+
+ // Add a last name field, that is predicted correctly.
+ test::CreateTestFormField("last", "last", "Presley", "test", &field);
+ field.set_possible_types({NAME_LAST});
+ form.fields.push_back(field);
+ heuristic_types.push_back(NAME_LAST);
+ server_types.push_back(NAME_LAST);
+
+ // Add an empty or unknown field, that is predicted as per the test params.
+ test::CreateTestFormField("Unknown", "Unknown",
+ (actual_field_type == EMPTY_TYPE ? "" : "unknown"),
+ "text", &field);
+ field.set_possible_types({actual_field_type});
+ form.fields.push_back(field);
+ heuristic_types.push_back(heuristic_type);
+ server_types.push_back(server_type);
+
+ // Simulate having seen this form on page load.
+ autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
+
+ // Run the form submission code while tracking the histograms.
+ base::HistogramTester histogram_tester;
+ autofill_manager_->SubmitForm(form, TimeTicks::Now());
+
+ // Validate the histogram counter values.
+ for (int i = 0; i < AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS; ++i) {
+ // The metric enum value we're currently examining.
+ auto metric = static_cast<AutofillMetrics::FieldTypeQualityMetric>(i);
+
+ // For the overall metric counts...
+ // If the current metric is the metric we're testing, then we expect its
+ // count to be 1. Otherwise, the metric's count should be zero (0) except
+ // for the TYPE_MATCH metric which should be 2 (because of the matching
+ // first and last name fields)
+ int overall_expected_count =
+ (metric == metric_to_test)
+ ? 1
+ : ((metric == AutofillMetrics::TYPE_MATCH) ? 2 : 0);
+
+ histogram_tester.ExpectBucketCount("Autofill.Quality.HeuristicType", metric,
+ overall_expected_count);
+ histogram_tester.ExpectBucketCount("Autofill.Quality.ServerType", metric,
+ overall_expected_count);
+ histogram_tester.ExpectBucketCount("Autofill.Quality.PredictedType", metric,
+ overall_expected_count);
+
+ // For the ByFieldType metric counts...
+ // We only examine the counter for the field_type being tested. If the
+ // current metric is the metric we're testing, then we expect its
+ // count to be 1 otherwise it should be 0.
+ int field_type_expected_count = (metric == metric_to_test) ? 1 : 0;
+
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Quality.HeuristicType.ByFieldType",
+ GetFieldTypeGroupMetric(actual_field_type, metric),
+ field_type_expected_count);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Quality.ServerType.ByFieldType",
+ GetFieldTypeGroupMetric(actual_field_type, metric),
+ field_type_expected_count);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Quality.PredictedType.ByFieldType",
+ GetFieldTypeGroupMetric(actual_field_type, metric),
+ field_type_expected_count);
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(
+ AutofillMetricsTest,
+ UnrecognizedOrEmptyFieldsTest,
+ testing::Values(
+ UnrecognizedOrEmptyFieldsCase{EMPTY_TYPE,
+ /* make_prediction = */ false,
+ AutofillMetrics::TYPE_MATCH_EMPTY},
+ UnrecognizedOrEmptyFieldsCase{UNKNOWN_TYPE,
+ /* make_prediction = */ false,
+ AutofillMetrics::TYPE_MATCH_UNKNOWN},
+ UnrecognizedOrEmptyFieldsCase{EMPTY_TYPE,
+ /* make_prediction = */ true,
+ AutofillMetrics::TYPE_MISMATCH_EMPTY},
+ UnrecognizedOrEmptyFieldsCase{UNKNOWN_TYPE,
+ /* make_prediction = */ true,
+ AutofillMetrics::TYPE_MISMATCH_UNKNOWN}));
+
// Ensures that metrics that measure timing some important Autofill functions
// actually are recorded and retrieved.
TEST_F(AutofillMetricsTest, TimingMetrics) {
@@ -570,7 +776,7 @@ TEST_F(AutofillMetricsTest, TimingMetrics) {
// Simulate a OnFormsSeen() call that should trigger the recording.
std::vector<FormData> forms;
forms.push_back(form);
- autofill_manager_->OnFormsSeen(forms, base::TimeTicks::Now());
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::Now());
// Because these metrics are related to timing, it is not possible to know in
// advance which bucket the sample will fall into, so we just need to make
@@ -766,7 +972,7 @@ TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) {
std::unique_ptr<TestFormStructure> form_structure =
base::MakeUnique<TestFormStructure>(form);
TestFormStructure* form_structure_ptr = form_structure.get();
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
autofill_manager_->form_structures()->push_back(std::move(form_structure));
AutofillQueryResponseContents response;
@@ -851,6 +1057,47 @@ TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) {
GetFieldTypeGroupMetric(NAME_MIDDLE, AutofillMetrics::TYPE_MISMATCH), 1);
}
+// Test that we log UPI Virtual Payment Address.
+TEST_F(AutofillMetricsTest, UpiVirtualPaymentAddress) {
+ // Set up our form data.
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+
+ std::vector<ServerFieldType> heuristic_types, server_types;
+ FormFieldData field;
+
+ // Heuristic value will match with Autocomplete attribute.
+ test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
+ form.fields.push_back(field);
+ heuristic_types.push_back(NAME_LAST);
+ server_types.push_back(NAME_LAST);
+
+ // Heuristic value will NOT match with Autocomplete attribute.
+ test::CreateTestFormField("First Name", "firstname", "", "text", &field);
+ form.fields.push_back(field);
+ heuristic_types.push_back(NAME_FIRST);
+ server_types.push_back(NAME_FIRST);
+
+ // Heuristic value will NOT match with Autocomplete attribute.
+ test::CreateTestFormField("Payment Address", "payment_address", "user@upi",
+ "text", &field);
+ form.fields.push_back(field);
+ heuristic_types.push_back(UNKNOWN_TYPE);
+ server_types.push_back(NO_SERVER_DATA);
+
+ // Simulate having seen this form on page load.
+ autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
+
+ // Simulate form submission.
+ base::HistogramTester histogram_tester;
+ autofill_manager_->SubmitForm(form, TimeTicks::Now());
+
+ histogram_tester.ExpectBucketCount(
+ "Autofill.UserHappiness", AutofillMetrics::USER_DID_ENTER_UPI_VPA, 1);
+}
+
// Test that we do not log RAPPOR metrics when the number of mismatches is not
// high enough.
TEST_F(AutofillMetricsTest, Rappor_LowMismatchRate_NoMetricsReported) {
@@ -1380,6 +1627,11 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields) {
// fields is logged.
histogram_tester.ExpectUniqueSample(
"Autofill.NumberOfEditedAutofilledFieldsAtSubmission", 2, 1);
+
+ // UKM must not be logged unless enabled.
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+ EXPECT_EQ(0U, ukm_service->sources_count());
+ EXPECT_EQ(0U, ukm_service->entries_count());
}
// Verify that when resetting the autofill manager (such as during a
@@ -1434,6 +1686,8 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields_NoSubmission) {
// Verify that we correctly log metrics regarding developer engagement.
TEST_F(AutofillMetricsTest, DeveloperEngagement) {
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
// Start with a non-fillable form.
FormData form;
form.name = ASCIIToUTF16("TestForm");
@@ -1454,21 +1708,28 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
autofill_manager_->OnFormsSeen(forms, TimeTicks());
autofill_manager_->Reset();
histogram_tester.ExpectTotalCount("Autofill.DeveloperEngagement", 0);
+
+ // UKM must not be logged unless enabled.
+ EXPECT_EQ(0U, ukm_service->sources_count());
+ EXPECT_EQ(0U, ukm_service->entries_count());
}
// Add another field to the form, so that it becomes fillable.
test::CreateTestFormField("Phone", "phone", "", "text", &field);
forms.back().fields.push_back(field);
- // Expect only the "form parsed" metric to be logged; no metrics about
- // author-specified field type hints.
+ // Expect the "form parsed without hints" metric to be logged.
{
base::HistogramTester histogram_tester;
autofill_manager_->OnFormsSeen(forms, TimeTicks());
autofill_manager_->Reset();
- histogram_tester.ExpectUniqueSample("Autofill.DeveloperEngagement",
- AutofillMetrics::FILLABLE_FORM_PARSED,
- 1);
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.DeveloperEngagement",
+ AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS, 1);
+
+ // UKM must not be logged unless enabled.
+ EXPECT_EQ(0U, ukm_service->sources_count());
+ EXPECT_EQ(0U, ukm_service->entries_count());
}
// Add some fields with an author-specified field type to the form.
@@ -1486,18 +1747,193 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
field.autocomplete_attribute = "address-line1";
forms.back().fields.push_back(field);
- // Expect both the "form parsed" metric and the author-specified field type
- // hints metric to be logged.
+ // Expect the "form parsed with field type hints" metric to be logged.
{
base::HistogramTester histogram_tester;
autofill_manager_->OnFormsSeen(forms, TimeTicks());
autofill_manager_->Reset();
- histogram_tester.ExpectBucketCount("Autofill.DeveloperEngagement",
- AutofillMetrics::FILLABLE_FORM_PARSED,
- 1);
histogram_tester.ExpectBucketCount(
"Autofill.DeveloperEngagement",
- AutofillMetrics::FILLABLE_FORM_CONTAINS_TYPE_HINTS, 1);
+ AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS, 1);
+
+ // UKM must not be logged unless enabled.
+ EXPECT_EQ(0U, ukm_service->sources_count());
+ EXPECT_EQ(0U, ukm_service->entries_count());
+
+ histogram_tester.ExpectBucketCount(
+ "Autofill.DeveloperEngagement",
+ AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT, 0);
+ }
+
+ // Add a field with an author-specified UPI-VPA field type in the form.
+ test::CreateTestFormField("", "", "", "text", &field);
+ field.autocomplete_attribute = "upi-vpa";
+ forms.back().fields.push_back(field);
+
+ // Expect the "form parsed with type hints" metric, and the
+ // "author-specified upi-vpa type" metric to be logged.
+ {
+ base::HistogramTester histogram_tester;
+ autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->Reset();
+ histogram_tester.ExpectBucketCount(
+ "Autofill.DeveloperEngagement",
+ AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS, 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.DeveloperEngagement",
+ AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT, 1);
+ }
+}
+
+// Verify that we correctly log UKM for form parsed without type hints regarding
+// developer engagement.
+TEST_F(AutofillMetricsTest,
+ UkmDeveloperEngagement_LogFillableFormParsedWithoutTypeHints) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
+ // Start with a non-fillable form.
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+
+ FormFieldData field;
+ test::CreateTestFormField("Name", "name", "", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Email", "email", "", "text", &field);
+ form.fields.push_back(field);
+
+ std::vector<FormData> forms(1, form);
+
+ // Ensure no metrics are logged when loading a non-fillable form.
+ {
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::Now());
+ autofill_manager_->Reset();
+
+ EXPECT_EQ(0U, ukm_service->sources_count());
+ EXPECT_EQ(0U, ukm_service->entries_count());
+ }
+
+ // Add another field to the form, so that it becomes fillable.
+ test::CreateTestFormField("Phone", "phone", "", "text", &field);
+ forms.back().fields.push_back(field);
+
+ // Expect the "form parsed without field type hints" metric and the
+ // "form loaded" form interaction event to be logged.
+ {
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::Now());
+ autofill_manager_->Reset();
+
+ ASSERT_EQ(1U, ukm_service->entries_count());
+ ASSERT_EQ(1U, ukm_service->sources_count());
+ VerifyDeveloperEngagementUkm(
+ form, ukm_service,
+ {AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS});
+ }
+}
+
+// Verify that we correctly log UKM for form parsed with type hints regarding
+// developer engagement.
+TEST_F(AutofillMetricsTest,
+ UkmDeveloperEngagement_LogFillableFormParsedWithTypeHints) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+
+ FormFieldData field;
+ test::CreateTestFormField("Name", "name", "", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Email", "email", "", "text", &field);
+ form.fields.push_back(field);
+
+ std::vector<FormData> forms(1, form);
+
+ // Add another field to the form, so that it becomes fillable.
+ test::CreateTestFormField("Phone", "phone", "", "text", &field);
+ forms.back().fields.push_back(field);
+
+ // Add some fields with an author-specified field type to the form.
+ // We need to add at least three fields, because a form must have at least
+ // three fillable fields to be considered to be autofillable; and if at least
+ // one field specifies an explicit type hint, we don't apply any of our usual
+ // local heuristics to detect field types in the rest of the form.
+ test::CreateTestFormField("", "", "", "text", &field);
+ field.autocomplete_attribute = "given-name";
+ forms.back().fields.push_back(field);
+ test::CreateTestFormField("", "", "", "text", &field);
+ field.autocomplete_attribute = "email";
+ forms.back().fields.push_back(field);
+ test::CreateTestFormField("", "", "", "text", &field);
+ field.autocomplete_attribute = "address-line1";
+ forms.back().fields.push_back(field);
+
+ // Expect the "form parsed without field type hints" metric and the
+ // "form loaded" form interaction event to be logged.
+ {
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::Now());
+ autofill_manager_->Reset();
+
+ ASSERT_EQ(1U, ukm_service->entries_count());
+ ASSERT_EQ(1U, ukm_service->sources_count());
+ VerifyDeveloperEngagementUkm(
+ form, ukm_service,
+ {AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS});
+ }
+}
+
+// Verify that we correctly log UKM for form parsed with type hints regarding
+// developer engagement.
+TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+
+ FormFieldData field;
+ test::CreateTestFormField("Name", "name", "", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Email", "email", "", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Payment", "payment", "", "text", &field);
+ field.autocomplete_attribute = "upi-vpa";
+ form.fields.push_back(field);
+
+ std::vector<FormData> forms(1, form);
+
+ // Expect the "upi-vpa hint" metric to be logged and the "form loaded" form
+ // interaction event to be logged.
+ {
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::Now());
+ autofill_manager_->Reset();
+
+ ASSERT_EQ(1U, ukm_service->entries_count());
+ ASSERT_EQ(1U, ukm_service->sources_count());
+ VerifyDeveloperEngagementUkm(form, ukm_service,
+ {AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT});
+ ukm_service->Purge();
+ }
+
+ // Add another field with an author-specified field type to the form.
+ test::CreateTestFormField("", "", "", "text", &field);
+ field.autocomplete_attribute = "address-line1";
+ forms.back().fields.push_back(field);
+
+ {
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::Now());
+ autofill_manager_->Reset();
+
+ VerifyDeveloperEngagementUkm(
+ form, ukm_service,
+ {AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS,
+ AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT});
}
}
@@ -1680,6 +2116,9 @@ TEST_F(AutofillMetricsTest, AddressSuggestionsCount) {
// Test that the credit card checkout flow user actions are correctly logged.
TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
personal_data_->RecreateCreditCards(
true /* include_local_credit_card */,
false /* include_masked_server_credit_card */,
@@ -1755,10 +2194,30 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_NonFillable"));
}
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionsShownEntryName,
+ {{{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ // Expect 2 |FORM_EVENT_LOCAL_SUGGESTION_FILLED| events. First, from
+ // call to |external_delegate_->DidAcceptSuggestion|. Second, from call to
+ // |autofill_manager_->FillOrPreviewForm|.
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionFilledEntryName,
+ {{{internal::kUKMRecordTypeMetricName, CreditCard::LOCAL_CARD},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}},
+ {{internal::kUKMRecordTypeMetricName, CreditCard::LOCAL_CARD},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ // Expect |NON_FILLABLE_FORM_OR_NEW_DATA| in |AutofillFormSubmittedState|
+ // because |field.value| is empty in |DeterminePossibleFieldTypesForUpload|.
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
// Test that the profile checkout flow user actions are correctly logged.
TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
// Create a profile.
personal_data_->RecreateProfile();
@@ -1806,7 +2265,7 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
std::string guid("00000000-0000-0000-0000-000000000001"); // local profile.
external_delegate_->DidAcceptSuggestion(
ASCIIToUTF16("Test"),
- autofill_manager_->MakeFrontendID(guid, std::string()), 0);
+ autofill_manager_->MakeFrontendID(std::string(), guid), 0);
EXPECT_EQ(1,
user_action_tester.GetActionCount("Autofill_SelectedSuggestion"));
}
@@ -1832,6 +2291,23 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_NonFillable"));
}
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionsShownEntryName,
+ {{{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ // Expect 2 |FORM_EVENT_LOCAL_SUGGESTION_FILLED| events. First, from
+ // call to |external_delegate_->DidAcceptSuggestion|. Second, from call to
+ // |autofill_manager_->FillOrPreviewForm|.
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionFilledEntryName,
+ {{{internal::kUKMRecordTypeMetricName, AutofillProfile::LOCAL_PROFILE},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}},
+ {{internal::kUKMRecordTypeMetricName, AutofillProfile::LOCAL_PROFILE},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ // Expect |NON_FILLABLE_FORM_OR_NEW_DATA| in |AutofillFormSubmittedState|
+ // because |field.value| is empty in |DeterminePossibleFieldTypesForUpload|.
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
// Tests that the Autofill_PolledCreditCardSuggestions user action is only
@@ -2121,6 +2597,11 @@ TEST_F(AutofillMetricsTest, CreditCardShownFormEvents) {
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 0);
}
+
+ // UKM must not be logged unless enabled.
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+ EXPECT_EQ(0U, ukm_service->sources_count());
+ EXPECT_EQ(0U, ukm_service->entries_count());
}
// Test that we log selected form event for credit cards.
@@ -2253,6 +2734,7 @@ TEST_F(AutofillMetricsTest, CreditCardFilledFormEvents) {
autofill_manager_->MakeFrontendID(guid, std::string()));
autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS,
"6011000990139424");
+ autofill_manager_->SubmitForm(form, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1);
@@ -2386,6 +2868,9 @@ TEST_F(AutofillMetricsTest, CreditCardGetRealPanDuration) {
// Test that we log submitted form events for credit cards.
TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
EnableWalletSync();
// Creating all kinds of cards.
personal_data_->RecreateCreditCards(
@@ -2425,10 +2910,15 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_SUBMITTED_ONCE, 1);
+
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
- // Reset the autofill manager state.
+ // Reset the autofill manager state and purge UKM logs.
autofill_manager_->Reset();
+ ukm_service->Purge();
+
autofill_manager_->AddSeenForm(form, field_types, field_types);
{
@@ -2443,10 +2933,18 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 1);
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionsShownEntryName,
+ {{{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
- // Reset the autofill manager state.
+ // Reset the autofill manager state and purge UKM logs.
autofill_manager_->Reset();
+ ukm_service->Purge();
+
autofill_manager_->AddSeenForm(form, field_types, field_types);
{
@@ -2464,10 +2962,19 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_SUBMITTED_ONCE, 1);
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionFilledEntryName,
+ {{{internal::kUKMRecordTypeMetricName, CreditCard::LOCAL_CARD},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
- // Reset the autofill manager state.
+ // Reset the autofill manager state and purge UKM logs.
autofill_manager_->Reset();
+ ukm_service->Purge();
+
autofill_manager_->AddSeenForm(form, field_types, field_types);
{
@@ -2486,10 +2993,19 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_SUBMITTED_ONCE, 1);
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionFilledEntryName,
+ {{{internal::kUKMRecordTypeMetricName, CreditCard::FULL_SERVER_CARD},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
- // Reset the autofill manager state.
+ // Reset the autofill manager state and purge UKM logs.
autofill_manager_->Reset();
+ ukm_service->Purge();
+
autofill_manager_->AddSeenForm(form, field_types, field_types);
{
@@ -2502,6 +3018,7 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
autofill_manager_->MakeFrontendID(guid, std::string()));
autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS,
"6011000990139424");
+ autofill_manager_->SubmitForm(form, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1);
@@ -2509,8 +3026,22 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED_ONCE,
1);
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionFilledEntryName,
+ {{{internal::kUKMRecordTypeMetricName, CreditCard::MASKED_SERVER_CARD},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSelectedMaskedServerCardEntryName,
+ {{{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
+ // Reset the autofill manager state and purge UKM logs.
+ autofill_manager_->Reset();
+ ukm_service->Purge();
+
// Recreating cards as the previous test should have upgraded the masked
// card to a full card.
personal_data_->RecreateCreditCards(
@@ -2527,7 +3058,24 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
base::HistogramTester histogram_tester;
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
autofill_manager_->SubmitForm(form, TimeTicks::Now());
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMFormSubmittedEntryName,
+ {{{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+
autofill_manager_->SubmitForm(form, TimeTicks::Now());
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMFormSubmittedEntryName,
+ {{{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}},
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -2564,8 +3112,10 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
0);
}
- // Reset the autofill manager state.
+ // Reset the autofill manager state and purge UKM logs.
autofill_manager_->Reset();
+ ukm_service->Purge();
+
autofill_manager_->AddSeenForm(form, field_types, field_types);
{
@@ -2608,6 +3158,12 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
AutofillMetrics::
FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE,
0);
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionsShownEntryName,
+ {{{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
}
@@ -3029,6 +3585,9 @@ TEST_F(AutofillMetricsTest, AddressFilledFormEvents) {
// Test that we log submitted form events for address.
TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
EnableWalletSync();
// Create a profile.
personal_data_->RecreateProfile();
@@ -3065,10 +3624,15 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_SUBMITTED_ONCE, 1);
+
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
- // Reset the autofill manager state.
+ // Reset the autofill manager state and purge UKM logs.
autofill_manager_->Reset();
+ ukm_service->Purge();
+
autofill_manager_->AddSeenForm(form, field_types, field_types);
{
@@ -3116,6 +3680,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
autofill_manager_->SubmitForm(form, TimeTicks::Now());
autofill_manager_->SubmitForm(form, TimeTicks::Now());
+
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -3152,6 +3717,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager_->SubmitForm(form, TimeTicks::Now());
+
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 0);
@@ -3522,7 +4088,6 @@ TEST_F(AutofillMetricsTest, AddressFormEventsAreSegmented) {
}
}
-
// Test that we log that Autofill is enabled when filling a form.
TEST_F(AutofillMetricsTest, AutofillIsEnabledAtPageLoad) {
base::HistogramTester histogram_tester;
@@ -3561,6 +4126,9 @@ TEST_F(AutofillMetricsTest, DaysSinceLastUse_Profile) {
// Verify that we correctly log the submitted form's state.
TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
// Start with a form with insufficiently many fields.
FormData form;
form.name = ASCIIToUTF16("TestForm");
@@ -3581,10 +4149,16 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
// Expect no notifications when the form is first seen.
{
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::Now());
histogram_tester.ExpectTotalCount("Autofill.FormSubmittedState", 0);
}
+ std::vector<std::vector<std::pair<const char*, int64_t>>>
+ expected_form_submission_ukm_metrics = {
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}};
+
// No data entered in the form.
{
base::HistogramTester histogram_tester;
@@ -3595,6 +4169,17 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_NonFillable"));
+
+ // Expect an entry for |DeveloperEngagement| and an entry for form
+ // interactions. Both entries are for the same URL.
+ ASSERT_EQ(2U, ukm_service->entries_count());
+ ASSERT_EQ(2U, ukm_service->sources_count());
+ VerifyDeveloperEngagementUkm(
+ form, ukm_service,
+ {AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS});
+ VerifyFormInteractionUkm(form, ukm_service,
+ internal::kUKMFormSubmittedEntryName,
+ expected_form_submission_ukm_metrics);
}
// Non fillable form.
@@ -3611,6 +4196,14 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_NonFillable"));
+
+ expected_form_submission_ukm_metrics.push_back(
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}});
+ VerifyFormInteractionUkm(form, ukm_service,
+ internal::kUKMFormSubmittedEntryName,
+ expected_form_submission_ukm_metrics);
}
// Fill in the third field.
@@ -3628,6 +4221,15 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
1);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_FilledNone_SuggestionsNotShown"));
+
+ expected_form_submission_ukm_metrics.push_back(
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::
+ FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}});
+ VerifyFormInteractionUkm(form, ukm_service,
+ internal::kUKMFormSubmittedEntryName,
+ expected_form_submission_ukm_metrics);
}
// Autofilled none with suggestions shown.
@@ -3641,6 +4243,17 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS, 1);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_FilledNone_SuggestionsShown"));
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionsShownEntryName,
+ {{{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ expected_form_submission_ukm_metrics.push_back(
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}});
+ VerifyFormInteractionUkm(form, ukm_service,
+ internal::kUKMFormSubmittedEntryName,
+ expected_form_submission_ukm_metrics);
}
// Mark one of the fields as autofilled.
@@ -3657,6 +4270,14 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME, 1);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_FilledSome"));
+
+ expected_form_submission_ukm_metrics.push_back(
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}});
+ VerifyFormInteractionUkm(form, ukm_service,
+ internal::kUKMFormSubmittedEntryName,
+ expected_form_submission_ukm_metrics);
}
// Mark all of the fillable fields as autofilled.
@@ -3674,6 +4295,14 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL, 1);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_FilledAll"));
+
+ expected_form_submission_ukm_metrics.push_back(
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}});
+ VerifyFormInteractionUkm(form, ukm_service,
+ internal::kUKMFormSubmittedEntryName,
+ expected_form_submission_ukm_metrics);
}
// Clear out the third field's value.
@@ -3690,12 +4319,23 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_NonFillable"));
+
+ expected_form_submission_ukm_metrics.push_back(
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}});
+ VerifyFormInteractionUkm(form, ukm_service,
+ internal::kUKMFormSubmittedEntryName,
+ expected_form_submission_ukm_metrics);
}
}
// Verify that we correctly log user happiness metrics dealing with form
// interaction.
TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
// Load a fillable form.
FormData form;
form.name = ASCIIToUTF16("TestForm");
@@ -3795,6 +4435,50 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) {
"Autofill.UserHappiness",
AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD, 1);
}
+
+ autofill_manager_->Reset();
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMInteractedWithFormEntryName,
+ {{{internal::kUKMIsForCreditCardMetricName, false},
+ {internal::kUKMLocalRecordTypeCountMetricName, 0},
+ {internal::kUKMServerRecordTypeCountMetricName, 0}}});
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionsShownEntryName,
+ {{{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}},
+ {{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionFilledEntryName,
+ {{{internal::kUKMRecordTypeMetricName, AutofillProfile::LOCAL_PROFILE},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}},
+ {{internal::kUKMRecordTypeMetricName, AutofillProfile::LOCAL_PROFILE},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMTextFieldDidChangeEntryName,
+ {{{internal::kUKMFieldTypeGroupMetricName, NAME},
+ {internal::kUKMHeuristicTypeMetricName, NAME_FULL},
+ {internal::kUKMServerTypeMetricName, NO_SERVER_DATA},
+ {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
+ {internal::kUKMHtmlFieldModeMetricName, HTML_MODE_NONE},
+ {internal::kUKMIsAutofilledMetricName, false},
+ {internal::kUKMIsEmptyMetricName, true},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}},
+ {{internal::kUKMFieldTypeGroupMetricName, NAME},
+ {internal::kUKMHeuristicTypeMetricName, NAME_FULL},
+ {internal::kUKMServerTypeMetricName, NO_SERVER_DATA},
+ {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
+ {internal::kUKMHtmlFieldModeMetricName, HTML_MODE_NONE},
+ {internal::kUKMIsAutofilledMetricName, true},
+ {internal::kUKMIsEmptyMetricName, true},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}},
+ {{internal::kUKMFieldTypeGroupMetricName, EMAIL},
+ {internal::kUKMHeuristicTypeMetricName, EMAIL_ADDRESS},
+ {internal::kUKMServerTypeMetricName, NO_SERVER_DATA},
+ {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
+ {internal::kUKMHtmlFieldModeMetricName, HTML_MODE_NONE},
+ {internal::kUKMIsAutofilledMetricName, true},
+ {internal::kUKMIsEmptyMetricName, true},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
}
// Verify that we correctly log metrics tracking the duration of form fill.
@@ -4366,15 +5050,14 @@ TEST_F(AutofillMetricsTest,
}
}
-// Tests that logging a UKM works as expected.
+// Tests that logging CardUploadDecision UKM works as expected.
TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric) {
EnableUkmLogging();
ukm::UkmServiceTestingHarness ukm_service_test_harness;
GURL url("https://www.google.com");
int upload_decision = 1;
- std::map<std::string, int> metrics;
- metrics.insert(std::make_pair(internal::kUKMCardUploadDecisionMetricName,
- upload_decision));
+ std::vector<std::pair<const char*, int>> metrics = {
+ {internal::kUKMCardUploadDecisionMetricName, upload_decision}};
EXPECT_TRUE(AutofillMetrics::LogUkm(
ukm_service_test_harness.test_ukm_service(), url,
@@ -4385,14 +5068,15 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric) {
ukm_service_test_harness.test_ukm_service();
ASSERT_EQ(1U, ukm_service->sources_count());
- const ukm::UkmSource* source = ukm_service->GetSource(0);
+ const ukm::UkmSource* source =
+ ukm_service->GetSourceForUrl(url.spec().c_str());
EXPECT_EQ(url.spec(), source->url().spec());
- EXPECT_EQ(1U, ukm_service->entries_count());
+ ASSERT_EQ(1U, ukm_service->entries_count());
const ukm::UkmEntry* entry = ukm_service->GetEntry(0);
EXPECT_EQ(source->id(), entry->source_id());
- // Make sure that an card upload decision entry was logged.
+ // Make sure that a card upload decision entry was logged.
ukm::Entry entry_proto;
entry->PopulateProto(&entry_proto);
EXPECT_EQ(source->id(), entry_proto.source_id());
@@ -4407,13 +5091,53 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric) {
EXPECT_EQ(upload_decision, metric->value());
}
+// Tests that logging DeveloperEngagement UKM works as expected.
+TEST_F(AutofillMetricsTest, RecordDeveloperEngagementMetric) {
+ EnableUkmLogging();
+ ukm::UkmServiceTestingHarness ukm_service_test_harness;
+ GURL url("https://www.google.com");
+ int form_structure_metric = 1;
+ std::vector<std::pair<const char*, int>> metrics = {
+ {internal::kUKMDeveloperEngagementMetricName, form_structure_metric}};
+
+ EXPECT_TRUE(AutofillMetrics::LogUkm(
+ ukm_service_test_harness.test_ukm_service(), url,
+ internal::kUKMDeveloperEngagementEntryName, metrics));
+
+ // Make sure that the UKM was logged correctly.
+ ukm::TestUkmService* ukm_service =
+ ukm_service_test_harness.test_ukm_service();
+
+ ASSERT_EQ(1U, ukm_service->sources_count());
+ const ukm::UkmSource* source =
+ ukm_service->GetSourceForUrl(url.spec().c_str());
+ EXPECT_EQ(url.spec(), source->url().spec());
+
+ ASSERT_EQ(1U, ukm_service->entries_count());
+ const ukm::UkmEntry* entry = ukm_service->GetEntry(0);
+ EXPECT_EQ(source->id(), entry->source_id());
+
+ // Make sure that a developer engagement entry was logged.
+ ukm::Entry entry_proto;
+ entry->PopulateProto(&entry_proto);
+ EXPECT_EQ(source->id(), entry_proto.source_id());
+ EXPECT_EQ(base::HashMetricName(internal::kUKMDeveloperEngagementEntryName),
+ entry_proto.event_hash());
+ EXPECT_EQ(1, entry_proto.metrics_size());
+
+ // Make sure that the correct developer engagement metric was logged.
+ const ukm::Entry_Metric* metric = FindMetric(
+ internal::kUKMDeveloperEngagementMetricName, entry_proto.metrics());
+ ASSERT_NE(nullptr, metric);
+ EXPECT_EQ(form_structure_metric, metric->value());
+}
+
// Tests that no UKM is logged when the URL is not valid.
TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_InvalidUrl) {
EnableUkmLogging();
ukm::UkmServiceTestingHarness ukm_service_test_harness;
GURL url("");
- std::map<std::string, int> metrics;
- metrics.insert(std::make_pair("metric", 1));
+ std::vector<std::pair<const char*, int>> metrics = {{"metric", 1}};
EXPECT_FALSE(AutofillMetrics::LogUkm(
ukm_service_test_harness.test_ukm_service(), url, "test_ukm", metrics));
@@ -4425,7 +5149,7 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_NoMetrics) {
EnableUkmLogging();
ukm::UkmServiceTestingHarness ukm_service_test_harness;
GURL url("https://www.google.com");
- std::map<std::string, int> metrics;
+ std::vector<std::pair<const char*, int>> metrics;
EXPECT_FALSE(AutofillMetrics::LogUkm(
ukm_service_test_harness.test_ukm_service(), url, "test_ukm", metrics));
@@ -4437,8 +5161,7 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_NoUkmService) {
EnableUkmLogging();
ukm::UkmServiceTestingHarness ukm_service_test_harness;
GURL url("https://www.google.com");
- std::map<std::string, int> metrics;
- metrics.insert(std::make_pair("metric", 1));
+ std::vector<std::pair<const char*, int>> metrics = {{"metric", 1}};
EXPECT_FALSE(AutofillMetrics::LogUkm(nullptr, url, "test_ukm", metrics));
ASSERT_EQ(0U, ukm_service_test_harness.test_ukm_service()->sources_count());
@@ -4448,8 +5171,7 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_NoUkmService) {
TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_FeatureDisabled) {
ukm::UkmServiceTestingHarness ukm_service_test_harness;
GURL url("https://www.google.com");
- std::map<std::string, int> metrics;
- metrics.insert(std::make_pair("metric", 1));
+ std::vector<std::pair<const char*, int>> metrics = {{"metric", 1}};
EXPECT_FALSE(AutofillMetrics::LogUkm(
ukm_service_test_harness.test_ukm_service(), url, "test_ukm", metrics));
diff --git a/chromium/components/autofill/core/browser/autofill_profile.cc b/chromium/components/autofill/core/browser/autofill_profile.cc
index 1828497e688..4ef1222b02a 100644
--- a/chromium/components/autofill/core/browser/autofill_profile.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile.cc
@@ -48,8 +48,8 @@
using base::ASCIIToUTF16;
using base::UTF16ToUTF8;
-using i18n::addressinput::AddressData;
-using i18n::addressinput::AddressField;
+using ::i18n::addressinput::AddressData;
+using ::i18n::addressinput::AddressField;
namespace autofill {
namespace {
diff --git a/chromium/components/autofill/core/browser/autofill_profile_comparator.cc b/chromium/components/autofill/core/browser/autofill_profile_comparator.cc
index c3e8709549b..8bfcd193dd5 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_comparator.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_comparator.cc
@@ -9,7 +9,7 @@
#include "base/i18n/case_conversion.h"
#include "base/i18n/char_iterator.h"
-#include "base/strings/string_piece.h"
+#include "base/i18n/unicodestring.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversion_utils.h"
@@ -128,7 +128,7 @@ base::string16 AutofillProfileComparator::NormalizeForComparison(
icu::UnicodeString value = icu::UnicodeString(result.data(), result.length());
transliterator_->transliterate(value);
- return base::string16(value.getBuffer(), value.length());
+ return base::i18n::UnicodeStringToString16(value);
}
bool AutofillProfileComparator::AreMergeable(const AutofillProfile& p1,
@@ -667,7 +667,7 @@ std::set<base::string16> AutofillProfileComparator::GetNamePartVariants(
const base::string16& name_part) {
const size_t kMaxSupportedSubNames = 8;
- std::vector<base::string16> sub_names = base::SplitString(
+ std::vector<base::StringPiece16> sub_names = base::SplitStringPiece(
name_part, kSpace, base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
// Limit the number of sub-names we support (to constrain memory usage);
@@ -680,7 +680,7 @@ std::set<base::string16> AutofillProfileComparator::GetNamePartVariants(
// For each sub-name, add a variant of all the already existing variants that
// appends this sub-name and one that appends the initial of this sub-name.
// Duplicates will be discarded when they're added to the variants set.
- for (const base::string16& sub_name : sub_names) {
+ for (const auto& sub_name : sub_names) {
if (sub_name.empty())
continue;
std::vector<base::string16> new_variants;
@@ -696,7 +696,7 @@ std::set<base::string16> AutofillProfileComparator::GetNamePartVariants(
// As a common case, also add the variant that just concatenates all of the
// initials.
base::string16 initials;
- for (const base::string16& sub_name : sub_names) {
+ for (const auto& sub_name : sub_names) {
if (sub_name.empty())
continue;
initials.push_back(sub_name[0]);
@@ -720,12 +720,12 @@ bool AutofillProfileComparator::IsNameVariantOf(
GetNamePartVariants(name_1_parts.given);
const std::set<base::string16> middle_name_variants =
GetNamePartVariants(name_1_parts.middle);
- const base::string16& family_name = name_1_parts.family;
+ base::StringPiece16 family_name = name_1_parts.family;
// Iterate over all full name variants of profile 2 and see if any of them
// match the full name from profile 1.
- for (const base::string16& given_name : given_name_variants) {
- for (const base::string16& middle_name : middle_name_variants) {
+ for (const auto& given_name : given_name_variants) {
+ for (const auto& middle_name : middle_name_variants) {
base::string16 candidate = base::CollapseWhitespace(
base::JoinString({given_name, middle_name, family_name}, kSpace),
true);
diff --git a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
index c54f2ae61c4..ee55bc0857b 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -39,39 +39,6 @@ base::string16 GetLabel(AutofillProfile* profile) {
return labels[0];
}
-// Holds the autofill profile |first|, |middle| and |last| names.
-struct NameParts {
- NameParts(const std::string& first,
- const std::string& middle,
- const std::string& last)
- : first(first), middle(middle), last(last) {}
-
- std::string first;
- std::string middle;
- std::string last;
-};
-
-// Test case to be executed to validate OverwriteOrAppendNames.
-struct TestCase {
- TestCase(const NameParts& starting_name,
- const NameParts& additional_name,
- const NameParts& expected_result)
- : starting_names(std::vector<NameParts>(1, starting_name)),
- additional_names(std::vector<NameParts>(1, additional_name)),
- expected_result(std::vector<NameParts>(1, expected_result)) {}
-
- TestCase(const std::vector<NameParts>& starting_names,
- const std::vector<NameParts>& additional_names,
- const std::vector<NameParts>& expected_result)
- : starting_names(starting_names),
- additional_names(additional_names),
- expected_result(expected_result) {}
-
- std::vector<NameParts> starting_names;
- std::vector<NameParts> additional_names;
- std::vector<NameParts> expected_result;
-};
-
void SetupTestProfile(AutofillProfile& profile) {
profile.set_guid(base::GenerateGUID());
profile.set_origin(kSettingsOrigin);
diff --git a/chromium/components/autofill/core/browser/autofill_regex_constants.cc b/chromium/components/autofill/core/browser/autofill_regex_constants.cc
index e5587bea511..57b961df461 100644
--- a/chromium/components/autofill/core/browser/autofill_regex_constants.cc
+++ b/chromium/components/autofill/core/browser/autofill_regex_constants.cc
@@ -309,5 +309,34 @@ const char kPhoneSuffixRe[] =
const char kPhoneExtensionRe[] =
"\\bext|ext\\b|extension"
"|ramal"; // pt-BR, pt-PT
+const char kUPIVirtualPaymentAddressRe[] =
+ "^\\w+@("
+ "upi|" // BHIM Bharat Interface for Money
+ "allbank|" // Allahabad Bank UPI
+ "andb|" // Andhra Bank ONE
+ "axisbank|" // Axis Pay
+ "barodampay|" // Baroda MPay
+ "mahb|" // MAHAUPI
+ "cnrb|" // Canara Bank UPI - Empower
+ "csbpay|" // CSB UPI
+ "dcb|" // DCB Bank
+ "federal|" // Lotza
+ "hdfcbank|" // HDFC Bank MobileBanking
+ "pockets|" // Pockets- ICICI Bank
+ "icici|" // Pockets- ICICI Bank
+ "idfcbank|" // IDFC Bank UPI App
+ "indus|" // Indus Pay
+ "kbl|" // KBL Smartz
+ "kaypay|" // KayPay
+ "pnb|" // PNB UPI
+ "sib|" // SIB M-Pay (UPI Pay)
+ "sbi|" // SBI Pay
+ "tjsp|" // TranZapp
+ "uco|" // UCO UPI
+ "unionbank|" // Union Bank UPI
+ "united|" // United UPI
+ "vijb|" // Vijaya UPI App
+ "ybl" // Yes Pay
+ ")$";
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_regex_constants.h b/chromium/components/autofill/core/browser/autofill_regex_constants.h
index db85f540f69..8be7b2c39a6 100644
--- a/chromium/components/autofill/core/browser/autofill_regex_constants.h
+++ b/chromium/components/autofill/core/browser/autofill_regex_constants.h
@@ -56,6 +56,12 @@ extern const char kPhonePrefixRe[];
extern const char kPhoneSuffixRe[];
extern const char kPhoneExtensionRe[];
+// Used to match field data that might be a UPI Virtual Payment Address.
+// See:
+// - http://crbug.com/702220
+// - https://upipayments.co.in/virtual-payment-address-vpa/
+extern const char kUPIVirtualPaymentAddressRe[];
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_
diff --git a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
index fe2e1d3f566..28f7aea7b07 100644
--- a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
+++ b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
@@ -17,7 +17,6 @@
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/window_open_disposition.h"
-#include "ui/gfx/vector_icons_public.h"
#include "url/gurl.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.cc b/chromium/components/autofill/core/browser/autofill_test_utils.cc
index 78b1f0e09ed..10a23dcb2c6 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.cc
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.cc
@@ -226,15 +226,15 @@ AutofillProfile GetVerifiedProfile2() {
CreditCard GetCreditCard() {
CreditCard credit_card(base::GenerateGUID(), "http://www.example.com");
- SetCreditCardInfo(
- &credit_card, "Test User", "4111111111111111" /* Visa */, "11", "2017");
+ SetCreditCardInfo(&credit_card, "Test User", "4111111111111111" /* Visa */,
+ "11", "2022");
return credit_card;
}
CreditCard GetCreditCard2() {
CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
- SetCreditCardInfo(
- &credit_card, "Someone Else", "378282246310005" /* AmEx */, "07", "2019");
+ SetCreditCardInfo(&credit_card, "Someone Else", "378282246310005" /* AmEx */,
+ "07", "2022");
return credit_card;
}
@@ -253,7 +253,7 @@ CreditCard GetVerifiedCreditCard2() {
CreditCard GetMaskedServerCard() {
CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "a123");
test::SetCreditCardInfo(&credit_card, "Bonnie Parker",
- "2109" /* Mastercard */, "12", "2012");
+ "2109" /* Mastercard */, "12", "2020");
credit_card.SetTypeForMaskedCard(kMasterCard);
return credit_card;
}
diff --git a/chromium/components/autofill/core/browser/autofill_type.cc b/chromium/components/autofill/core/browser/autofill_type.cc
index 8dc9dbc85ad..2b97a2f6eda 100644
--- a/chromium/components/autofill/core/browser/autofill_type.cc
+++ b/chromium/components/autofill/core/browser/autofill_type.cc
@@ -208,6 +208,10 @@ FieldTypeGroup AutofillType::group() const {
case HTML_TYPE_EMAIL:
return EMAIL;
+ case HTML_TYPE_UPI_VPA:
+ // TODO(crbug/702223): Add support for UPI-VPA.
+ break;
+
case HTML_TYPE_UNSPECIFIED:
case HTML_TYPE_UNRECOGNIZED:
break;
@@ -418,6 +422,10 @@ ServerFieldType AutofillType::GetStorableType() const {
case HTML_TYPE_TRANSACTION_CURRENCY:
return UNKNOWN_TYPE;
+ // TODO(crbug/702223): Add autofill support for UPI-VPA.
+ case HTML_TYPE_UPI_VPA:
+ return UNKNOWN_TYPE;
+
case HTML_TYPE_UNRECOGNIZED:
return UNKNOWN_TYPE;
}
@@ -591,6 +599,8 @@ std::string AutofillType::ToString() const {
return "HTML_TRANSACTION_AMOUNT";
case HTML_TYPE_TRANSACTION_CURRENCY:
return "HTML_TRANSACTION_CURRENCY";
+ case HTML_TYPE_UPI_VPA:
+ return "HTML_TYPE_UPI_VPA";
case HTML_TYPE_UNRECOGNIZED:
return "HTML_TYPE_UNRECOGNIZED";
}
diff --git a/chromium/components/autofill/core/browser/contact_info_unittest.cc b/chromium/components/autofill/core/browser/contact_info_unittest.cc
index d501b5d782d..d07dfa041f1 100644
--- a/chromium/components/autofill/core/browser/contact_info_unittest.cc
+++ b/chromium/components/autofill/core/browser/contact_info_unittest.cc
@@ -25,47 +25,53 @@ struct FullNameTestCase {
std::string given_name_output;
std::string middle_name_output;
std::string family_name_output;
-} full_name_test_cases[] = {
- { "", "", "", "" },
- { "John Smith", "John", "", "Smith" },
- { "Julien van der Poel", "Julien", "", "van der Poel" },
- { "John J Johnson", "John", "J", "Johnson" },
- { "John Smith, Jr.", "John", "", "Smith" },
- { "Mr John Smith", "John", "", "Smith" },
- { "Mr. John Smith", "John", "", "Smith" },
- { "Mr. John Smith, M.D.", "John", "", "Smith" },
- { "Mr. John Smith, MD", "John", "", "Smith" },
- { "Mr. John Smith MD", "John", "", "Smith" },
- { "William Hubert J.R.", "William", "Hubert", "J.R." },
- { "John Ma", "John", "", "Ma" },
- { "John Smith, MA", "John", "", "Smith" },
- { "John Jacob Jingleheimer Smith", "John Jacob", "Jingleheimer", "Smith" },
- { "Virgil", "Virgil", "", "" },
- { "Murray Gell-Mann", "Murray", "", "Gell-Mann" },
- { "Mikhail Yevgrafovich Saltykov-Shchedrin", "Mikhail", "Yevgrafovich",
- "Saltykov-Shchedrin" },
- { "Arthur Ignatius Conan Doyle", "Arthur Ignatius", "Conan", "Doyle" },
};
-TEST(NameInfoTest, SetFullName) {
- for (const FullNameTestCase& test_case : full_name_test_cases) {
- SCOPED_TRACE(test_case.full_name_input);
+class SetFullNameTest : public testing::TestWithParam<FullNameTestCase> {};
- NameInfo name;
- name.SetInfo(AutofillType(NAME_FULL),
- ASCIIToUTF16(test_case.full_name_input),
- "en-US");
- EXPECT_EQ(ASCIIToUTF16(test_case.given_name_output),
- name.GetInfo(AutofillType(NAME_FIRST), "en-US"));
- EXPECT_EQ(ASCIIToUTF16(test_case.middle_name_output),
- name.GetInfo(AutofillType(NAME_MIDDLE), "en-US"));
- EXPECT_EQ(ASCIIToUTF16(test_case.family_name_output),
- name.GetInfo(AutofillType(NAME_LAST), "en-US"));
- EXPECT_EQ(ASCIIToUTF16(test_case.full_name_input),
- name.GetInfo(AutofillType(NAME_FULL), "en-US"));
- }
+TEST_P(SetFullNameTest, SetFullName) {
+ auto test_case = GetParam();
+ SCOPED_TRACE(test_case.full_name_input);
+
+ NameInfo name;
+ name.SetInfo(AutofillType(NAME_FULL), ASCIIToUTF16(test_case.full_name_input),
+ "en-US");
+ EXPECT_EQ(ASCIIToUTF16(test_case.given_name_output),
+ name.GetInfo(AutofillType(NAME_FIRST), "en-US"));
+ EXPECT_EQ(ASCIIToUTF16(test_case.middle_name_output),
+ name.GetInfo(AutofillType(NAME_MIDDLE), "en-US"));
+ EXPECT_EQ(ASCIIToUTF16(test_case.family_name_output),
+ name.GetInfo(AutofillType(NAME_LAST), "en-US"));
+ EXPECT_EQ(ASCIIToUTF16(test_case.full_name_input),
+ name.GetInfo(AutofillType(NAME_FULL), "en-US"));
}
+INSTANTIATE_TEST_CASE_P(
+ ContactInfoTest,
+ SetFullNameTest,
+ testing::Values(
+ FullNameTestCase{"", "", "", ""},
+ FullNameTestCase{"John Smith", "John", "", "Smith"},
+ FullNameTestCase{"Julien van der Poel", "Julien", "", "van der Poel"},
+ FullNameTestCase{"John J Johnson", "John", "J", "Johnson"},
+ FullNameTestCase{"John Smith, Jr.", "John", "", "Smith"},
+ FullNameTestCase{"Mr John Smith", "John", "", "Smith"},
+ FullNameTestCase{"Mr. John Smith", "John", "", "Smith"},
+ FullNameTestCase{"Mr. John Smith, M.D.", "John", "", "Smith"},
+ FullNameTestCase{"Mr. John Smith, MD", "John", "", "Smith"},
+ FullNameTestCase{"Mr. John Smith MD", "John", "", "Smith"},
+ FullNameTestCase{"William Hubert J.R.", "William", "Hubert", "J.R."},
+ FullNameTestCase{"John Ma", "John", "", "Ma"},
+ FullNameTestCase{"John Smith, MA", "John", "", "Smith"},
+ FullNameTestCase{"John Jacob Jingleheimer Smith", "John Jacob",
+ "Jingleheimer", "Smith"},
+ FullNameTestCase{"Virgil", "Virgil", "", ""},
+ FullNameTestCase{"Murray Gell-Mann", "Murray", "", "Gell-Mann"},
+ FullNameTestCase{"Mikhail Yevgrafovich Saltykov-Shchedrin", "Mikhail",
+ "Yevgrafovich", "Saltykov-Shchedrin"},
+ FullNameTestCase{"Arthur Ignatius Conan Doyle", "Arthur Ignatius",
+ "Conan", "Doyle"}));
+
TEST(NameInfoTest, GetFullName) {
NameInfo name;
name.SetRawInfo(NAME_FIRST, ASCIIToUTF16("First"));
@@ -174,209 +180,221 @@ TEST(NameInfoTest, GetFullName) {
name.GetInfo(AutofillType(NAME_FULL), "en-US"));
}
-TEST(NameInfoTest, ParsedNamesAreEqual) {
- struct TestCase {
- std::string starting_names[3];
- std::string additional_names[3];
- bool expected_result;
+struct ParsedNamesAreEqualTestCase {
+ std::string starting_names[3];
+ std::string additional_names[3];
+ bool expected_result;
};
- struct TestCase test_cases[] = {
- // Identical name comparison.
- {{"Marion", "Mitchell", "Morrison"},
- {"Marion", "Mitchell", "Morrison"},
- true},
-
- // Case-sensitive comparisons.
- {{"Marion", "Mitchell", "Morrison"},
- {"Marion", "Mitchell", "MORRISON"},
- false},
- {{"Marion", "Mitchell", "Morrison"},
- {"MARION", "Mitchell", "MORRISON"},
- false},
- {{"Marion", "Mitchell", "Morrison"},
- {"MARION", "MITCHELL", "MORRISON"},
- false},
- {{"Marion", "", "Mitchell Morrison"},
- {"MARION", "", "MITCHELL MORRISON"},
- false},
- {{"Marion Mitchell", "", "Morrison"},
- {"MARION MITCHELL", "", "MORRISON"},
- false},
-
- // Identical full names but different canonical forms.
- {{"Marion", "Mitchell", "Morrison"},
- {"Marion", "", "Mitchell Morrison"},
- false},
- {{"Marion", "Mitchell", "Morrison"},
- {"Marion Mitchell", "", "MORRISON"},
- false},
-
- // Different names.
- {{"Marion", "Mitchell", "Morrison"}, {"Marion", "M.", "Morrison"}, false},
- {{"Marion", "Mitchell", "Morrison"}, {"MARION", "M.", "MORRISON"}, false},
- {{"Marion", "Mitchell", "Morrison"},
- {"David", "Mitchell", "Morrison"},
- false},
-
- // Non-ASCII characters.
- {{"M\xc3\xa1rion Mitchell", "", "Morrison"},
- {"M\xc3\xa1rion Mitchell", "", "Morrison"},
- true},
- };
+ class ParsedNamesAreEqualTest
+ : public testing::TestWithParam<ParsedNamesAreEqualTestCase> {};
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
- SCOPED_TRACE(base::StringPrintf("i: %" PRIuS, i));
+ TEST_P(ParsedNamesAreEqualTest, ParsedNamesAreEqual) {
+ auto test_case = GetParam();
// Construct the starting_profile.
NameInfo starting_profile;
starting_profile.SetRawInfo(NAME_FIRST,
- UTF8ToUTF16(test_cases[i].starting_names[0]));
+ UTF8ToUTF16(test_case.starting_names[0]));
starting_profile.SetRawInfo(NAME_MIDDLE,
- UTF8ToUTF16(test_cases[i].starting_names[1]));
+ UTF8ToUTF16(test_case.starting_names[1]));
starting_profile.SetRawInfo(NAME_LAST,
- UTF8ToUTF16(test_cases[i].starting_names[2]));
+ UTF8ToUTF16(test_case.starting_names[2]));
// Construct the additional_profile.
NameInfo additional_profile;
- additional_profile.SetRawInfo(
- NAME_FIRST, UTF8ToUTF16(test_cases[i].additional_names[0]));
- additional_profile.SetRawInfo(
- NAME_MIDDLE, UTF8ToUTF16(test_cases[i].additional_names[1]));
- additional_profile.SetRawInfo(
- NAME_LAST, UTF8ToUTF16(test_cases[i].additional_names[2]));
+ additional_profile.SetRawInfo(NAME_FIRST,
+ UTF8ToUTF16(test_case.additional_names[0]));
+ additional_profile.SetRawInfo(NAME_MIDDLE,
+ UTF8ToUTF16(test_case.additional_names[1]));
+ additional_profile.SetRawInfo(NAME_LAST,
+ UTF8ToUTF16(test_case.additional_names[2]));
// Verify the test expectations.
- EXPECT_EQ(test_cases[i].expected_result,
+ EXPECT_EQ(test_case.expected_result,
starting_profile.ParsedNamesAreEqual(additional_profile));
}
-}
-TEST(NameInfoTest, OverwriteName) {
- struct TestCase {
+ INSTANTIATE_TEST_CASE_P(
+ ContactInfoTest,
+ ParsedNamesAreEqualTest,
+ testing::Values(
+ // Identical name comparison.
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"Marion", "Mitchell", "Morrison"},
+ true},
+
+ // Case-sensitive comparisons.
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"Marion", "Mitchell", "MORRISON"},
+ false},
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"MARION", "Mitchell", "MORRISON"},
+ false},
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"MARION", "MITCHELL", "MORRISON"},
+ false},
+ ParsedNamesAreEqualTestCase{{"Marion", "", "Mitchell Morrison"},
+ {"MARION", "", "MITCHELL MORRISON"},
+ false},
+ ParsedNamesAreEqualTestCase{{"Marion Mitchell", "", "Morrison"},
+ {"MARION MITCHELL", "", "MORRISON"},
+ false},
+
+ // Identical full names but different canonical forms.
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"Marion", "", "Mitchell Morrison"},
+ false},
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"Marion Mitchell", "", "MORRISON"},
+ false},
+
+ // Different names.
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"Marion", "M.", "Morrison"},
+ false},
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"MARION", "M.", "MORRISON"},
+ false},
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"David", "Mitchell", "Morrison"},
+ false},
+
+ // Non-ASCII characters.
+ ParsedNamesAreEqualTestCase{
+ {"M\xc3\xa1rion Mitchell", "", "Morrison"},
+ {"M\xc3\xa1rion Mitchell", "", "Morrison"},
+ true}));
+
+ struct OverwriteNameTestCase {
std::string existing_name[4];
std::string new_name[4];
std::string expected_name[4];
};
- struct TestCase test_cases[] = {
- // Missing information in the original name gets filled with the new
- // name's information.
- {
- {"", "", "", ""},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- },
- // The new name's values overwrite the exsiting name values if they are
- // different
- {
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- {"Mario", "Mitchell", "Thompson", "Mario Mitchell Morrison"},
- {"Mario", "Mitchell", "Thompson", "Mario Mitchell Morrison"},
- },
- // An existing name values do not get replaced with empty values.
- {
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- {"", "", "", ""},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- },
- // An existing full middle not does not get replaced by a middle name
- // initial.
- {
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- {"Marion", "M", "Morrison", "Marion Mitchell Morrison"},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- },
- // An existing middle name initial is overwritten by the new profile's
- // middle name value.
- {
- {"Marion", "M", "Morrison", "Marion Mitchell Morrison"},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- },
- // A NameInfo with only the full name set overwritten with a NameInfo
- // with only the name parts set result in a NameInfo with all the name
- // parts and name full set.
- {
- {"", "", "", "Marion Mitchell Morrison"},
- {"Marion", "Mitchell", "Morrison", ""},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- },
- // A NameInfo with only the name parts set overwritten with a NameInfo
- // with only the full name set result in a NameInfo with all the name
- // parts and name full set.
- {
- {"Marion", "Mitchell", "Morrison", ""},
- {"", "", "", "Marion Mitchell Morrison"},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- },
- };
-
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
- SCOPED_TRACE(base::StringPrintf("i: %" PRIuS, i));
+ class OverwriteNameTest
+ : public testing::TestWithParam<OverwriteNameTestCase> {};
+ TEST_P(OverwriteNameTest, OverwriteName) {
+ auto test_case = GetParam();
// Construct the starting_profile.
NameInfo existing_name;
existing_name.SetRawInfo(NAME_FIRST,
- UTF8ToUTF16(test_cases[i].existing_name[0]));
+ UTF8ToUTF16(test_case.existing_name[0]));
existing_name.SetRawInfo(NAME_MIDDLE,
- UTF8ToUTF16(test_cases[i].existing_name[1]));
+ UTF8ToUTF16(test_case.existing_name[1]));
existing_name.SetRawInfo(NAME_LAST,
- UTF8ToUTF16(test_cases[i].existing_name[2]));
+ UTF8ToUTF16(test_case.existing_name[2]));
existing_name.SetRawInfo(NAME_FULL,
- UTF8ToUTF16(test_cases[i].existing_name[3]));
+ UTF8ToUTF16(test_case.existing_name[3]));
// Construct the additional_profile.
NameInfo new_name;
- new_name.SetRawInfo(NAME_FIRST, UTF8ToUTF16(test_cases[i].new_name[0]));
- new_name.SetRawInfo(NAME_MIDDLE, UTF8ToUTF16(test_cases[i].new_name[1]));
- new_name.SetRawInfo(NAME_LAST, UTF8ToUTF16(test_cases[i].new_name[2]));
- new_name.SetRawInfo(NAME_FULL, UTF8ToUTF16(test_cases[i].new_name[3]));
+ new_name.SetRawInfo(NAME_FIRST, UTF8ToUTF16(test_case.new_name[0]));
+ new_name.SetRawInfo(NAME_MIDDLE, UTF8ToUTF16(test_case.new_name[1]));
+ new_name.SetRawInfo(NAME_LAST, UTF8ToUTF16(test_case.new_name[2]));
+ new_name.SetRawInfo(NAME_FULL, UTF8ToUTF16(test_case.new_name[3]));
existing_name.OverwriteName(new_name);
// Verify the test expectations.
- EXPECT_EQ(UTF8ToUTF16(test_cases[i].expected_name[0]),
+ EXPECT_EQ(UTF8ToUTF16(test_case.expected_name[0]),
existing_name.GetRawInfo(NAME_FIRST));
- EXPECT_EQ(UTF8ToUTF16(test_cases[i].expected_name[1]),
+ EXPECT_EQ(UTF8ToUTF16(test_case.expected_name[1]),
existing_name.GetRawInfo(NAME_MIDDLE));
- EXPECT_EQ(UTF8ToUTF16(test_cases[i].expected_name[2]),
+ EXPECT_EQ(UTF8ToUTF16(test_case.expected_name[2]),
existing_name.GetRawInfo(NAME_LAST));
- EXPECT_EQ(UTF8ToUTF16(test_cases[i].expected_name[3]),
+ EXPECT_EQ(UTF8ToUTF16(test_case.expected_name[3]),
existing_name.GetRawInfo(NAME_FULL));
- }
}
-TEST(NameInfoTest, NamePartsAreEmpty) {
- struct TestCase {
- std::string first;
- std::string middle;
- std::string last;
- std::string full;
- bool expected_result;
+INSTANTIATE_TEST_CASE_P(
+ ContactInfoTest,
+ OverwriteNameTest,
+ testing::Values(
+ // Missing information in the original name gets filled with the new
+ // name's information.
+ OverwriteNameTestCase{
+ {"", "", "", ""},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ },
+ // The new name's values overwrite the exsiting name values if they are
+ // different
+ OverwriteNameTestCase{
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ {"Mario", "Mitchell", "Thompson", "Mario Mitchell Morrison"},
+ {"Mario", "Mitchell", "Thompson", "Mario Mitchell Morrison"},
+ },
+ // An existing name values do not get replaced with empty values.
+ OverwriteNameTestCase{
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ {"", "", "", ""},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ },
+ // An existing full middle not does not get replaced by a middle name
+ // initial.
+ OverwriteNameTestCase{
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ {"Marion", "M", "Morrison", "Marion Mitchell Morrison"},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ },
+ // An existing middle name initial is overwritten by the new profile's
+ // middle name value.
+ OverwriteNameTestCase{
+ {"Marion", "M", "Morrison", "Marion Mitchell Morrison"},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ },
+ // A NameInfo with only the full name set overwritten with a NameInfo
+ // with only the name parts set result in a NameInfo with all the name
+ // parts and name full set.
+ OverwriteNameTestCase{
+ {"", "", "", "Marion Mitchell Morrison"},
+ {"Marion", "Mitchell", "Morrison", ""},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ },
+ // A NameInfo with only the name parts set overwritten with a NameInfo
+ // with only the full name set result in a NameInfo with all the name
+ // parts and name full set.
+ OverwriteNameTestCase{
+ {"Marion", "Mitchell", "Morrison", ""},
+ {"", "", "", "Marion Mitchell Morrison"},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ }));
+
+struct NamePartsAreEmptyTestCase {
+ std::string first;
+ std::string middle;
+ std::string last;
+ std::string full;
+ bool expected_result;
};
- struct TestCase test_cases[] = {
- {"", "", "", "", true},
- {"", "", "", "Marion Mitchell Morrison", true},
- {"Marion", "", "", "", false},
- {"", "Mitchell", "", "", false},
- {"", "", "Morrison", "", false},
- };
-
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
- SCOPED_TRACE(base::StringPrintf("i: %" PRIuS, i));
+ class NamePartsAreEmptyTest
+ : public testing::TestWithParam<NamePartsAreEmptyTestCase> {};
+ TEST_P(NamePartsAreEmptyTest, NamePartsAreEmpty) {
+ auto test_case = GetParam();
// Construct the NameInfo.
NameInfo name;
- name.SetRawInfo(NAME_FIRST, UTF8ToUTF16(test_cases[i].first));
- name.SetRawInfo(NAME_MIDDLE, UTF8ToUTF16(test_cases[i].middle));
- name.SetRawInfo(NAME_LAST, UTF8ToUTF16(test_cases[i].last));
- name.SetRawInfo(NAME_FULL, UTF8ToUTF16(test_cases[i].full));
+ name.SetRawInfo(NAME_FIRST, UTF8ToUTF16(test_case.first));
+ name.SetRawInfo(NAME_MIDDLE, UTF8ToUTF16(test_case.middle));
+ name.SetRawInfo(NAME_LAST, UTF8ToUTF16(test_case.last));
+ name.SetRawInfo(NAME_FULL, UTF8ToUTF16(test_case.full));
// Verify the test expectations.
- EXPECT_EQ(test_cases[i].expected_result, name.NamePartsAreEmpty());
- }
+ EXPECT_EQ(test_case.expected_result, name.NamePartsAreEmpty());
}
+INSTANTIATE_TEST_CASE_P(
+ ContactInfoTest,
+ NamePartsAreEmptyTest,
+ testing::Values(NamePartsAreEmptyTestCase{"", "", "", "", true},
+ NamePartsAreEmptyTestCase{"", "", "",
+ "Marion Mitchell Morrison", true},
+ NamePartsAreEmptyTestCase{"Marion", "", "", "", false},
+ NamePartsAreEmptyTestCase{"", "Mitchell", "", "", false},
+ NamePartsAreEmptyTestCase{"", "", "Morrison", "", false}));
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/country_combobox_model.h b/chromium/components/autofill/core/browser/country_combobox_model.h
index b3d90c3abf6..4e36d91ba45 100644
--- a/chromium/components/autofill/core/browser/country_combobox_model.h
+++ b/chromium/components/autofill/core/browser/country_combobox_model.h
@@ -38,6 +38,8 @@ class CountryComboboxModel : public ui::ComboboxModel {
base::string16 GetItemAt(int index) override;
bool IsItemSeparatorAt(int index) override;
+ // The list of countries always has the default country at the top as well as
+ // within the sorted vector.
const CountryVector& countries() const { return countries_; }
// Returns the default country code for this model.
diff --git a/chromium/components/autofill/core/browser/country_names.cc b/chromium/components/autofill/core/browser/country_names.cc
index bbf1fb6c0ae..2f9a022e363 100644
--- a/chromium/components/autofill/core/browser/country_names.cc
+++ b/chromium/components/autofill/core/browser/country_names.cc
@@ -24,7 +24,7 @@ namespace {
// A copy of the application locale string, which should be ready for
// CountryName's construction.
-static base::LazyInstance<std::string> g_application_locale =
+static base::LazyInstance<std::string>::DestructorAtExit g_application_locale =
LAZY_INSTANCE_INITIALIZER;
// Returns the ICU sort key corresponding to |str| for the given |collator|.
diff --git a/chromium/components/autofill/core/browser/credit_card.cc b/chromium/components/autofill/core/browser/credit_card.cc
index bd5110eced3..0e54c44176a 100644
--- a/chromium/components/autofill/core/browser/credit_card.cc
+++ b/chromium/components/autofill/core/browser/credit_card.cc
@@ -13,6 +13,7 @@
#include "base/guid.h"
#include "base/i18n/time_formatting.h"
+#include "base/i18n/unicodestring.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
@@ -870,7 +871,8 @@ bool CreditCard::ConvertMonth(const base::string16& month,
int32_t num_months;
const icu::UnicodeString* months = date_format_symbols.getMonths(num_months);
for (int32_t i = 0; i < num_months; ++i) {
- const base::string16 icu_month(months[i].getBuffer(), months[i].length());
+ const base::string16 icu_month(
+ base::i18n::UnicodeStringToString16(months[i]));
if (compare.StringsEqual(icu_month, month)) {
*num = i + 1; // Adjust from 0-indexed to 1-indexed.
return true;
@@ -883,7 +885,7 @@ bool CreditCard::ConvertMonth(const base::string16& month,
base::string16 trimmed_month;
base::TrimString(month, ASCIIToUTF16("."), &trimmed_month);
for (int32_t i = 0; i < num_months; ++i) {
- base::string16 icu_month(months[i].getBuffer(), months[i].length());
+ base::string16 icu_month(base::i18n::UnicodeStringToString16(months[i]));
base::TrimString(icu_month, ASCIIToUTF16("."), &icu_month);
if (compare.StringsEqual(icu_month, trimmed_month)) {
*num = i + 1; // Adjust from 0-indexed to 1-indexed.
diff --git a/chromium/components/autofill/core/browser/credit_card_field.h b/chromium/components/autofill/core/browser/credit_card_field.h
index a737add0440..3d462507fb7 100644
--- a/chromium/components/autofill/core/browser/credit_card_field.h
+++ b/chromium/components/autofill/core/browser/credit_card_field.h
@@ -27,7 +27,7 @@ class CreditCardField : public FormField {
void AddClassifications(FieldCandidatesMap* field_candidates) const override;
private:
- friend class CreditCardFieldTest;
+ friend class CreditCardFieldTestBase;
// Returns true if |scanner| points to a field that looks like a month
// <select>.
diff --git a/chromium/components/autofill/core/browser/credit_card_field_unittest.cc b/chromium/components/autofill/core/browser/credit_card_field_unittest.cc
index 5b44a651d9c..bb7b6b252d1 100644
--- a/chromium/components/autofill/core/browser/credit_card_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/credit_card_field_unittest.cc
@@ -19,10 +19,10 @@ using base::ASCIIToUTF16;
namespace autofill {
-class CreditCardFieldTest : public testing::Test {
+class CreditCardFieldTestBase {
public:
- CreditCardFieldTest() {}
- ~CreditCardFieldTest() override {}
+ CreditCardFieldTestBase() {}
+ ~CreditCardFieldTestBase() {}
protected:
std::vector<std::unique_ptr<AutofillField>> list_;
@@ -59,6 +59,15 @@ class CreditCardFieldTest : public testing::Test {
}
private:
+ DISALLOW_COPY_AND_ASSIGN(CreditCardFieldTestBase);
+};
+
+class CreditCardFieldTest : public CreditCardFieldTestBase,
+ public testing::Test {
+ public:
+ CreditCardFieldTest() {}
+
+ private:
DISALLOW_COPY_AND_ASSIGN(CreditCardFieldTest);
};
@@ -292,124 +301,144 @@ TEST_F(CreditCardFieldTest, ParseExpMonthYear2) {
field_candidates_map_[ASCIIToUTF16("year4")].BestHeuristicType());
}
-TEST_F(CreditCardFieldTest, ParseExpField) {
- typedef struct {
- const std::string label;
- const int max_length;
- const ServerFieldType expected_prediction;
- } TestCase;
-
- TestCase test_cases[] = {
- // General label, no maxlength.
- {"Expiration Date", 0, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- // General label, maxlength 4.
- {"Expiration Date", 4, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- // General label, maxlength 5.
- {"Expiration Date", 5, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- // General label, maxlength 6.
- {"Expiration Date", 6, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- // General label, maxlength 7.
- {"Expiration Date", 7, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- // General label, large maxlength.
- {"Expiration Date", 12, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
-
- // Unsupported maxlength, general label.
- {"Expiration Date", 3, UNKNOWN_TYPE},
- // Unsupported maxlength, two digit year label.
- {"Expiration Date (MM/YY)", 3, UNKNOWN_TYPE},
- // Unsupported maxlength, four digit year label.
- {"Expiration Date (MM/YYYY)", 3, UNKNOWN_TYPE},
-
- // Two digit year, simple label.
- {"MM / YY", 0, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- // Two digit year, with slash (MM/YY).
- {"Expiration Date (MM/YY)", 0, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- // Two digit year, no slash (MMYY).
- {"Expiration Date (MMYY)", 4, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- // Two digit year, with slash and maxlength (MM/YY).
- {"Expiration Date (MM/YY)", 5, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- // Two digit year, with slash and large maxlength (MM/YY).
- {"Expiration Date (MM/YY)", 12, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
-
- // Four digit year, simple label.
- {"MM / YYYY", 0, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- // Four digit year, with slash (MM/YYYY).
- {"Expiration Date (MM/YYYY)", 0, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- // Four digit year, no slash (MMYYYY).
- {"Expiration Date (MMYYYY)", 6, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- // Four digit year, with slash and maxlength (MM/YYYY).
- {"Expiration Date (MM/YYYY)", 7, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- // Four digit year, with slash and large maxlength (MM/YYYY).
- {"Expiration Date (MM/YYYY)", 12, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
-
- // Four digit year label with restrictive maxlength (4).
- {"Expiration Date (MM/YYYY)", 4, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- // Four digit year label with restrictive maxlength (5).
- {"Expiration Date (MM/YYYY)", 5, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- };
-
- for (const TestCase &test_case : test_cases) {
- // Clean up after previous test cases.
- list_.clear();
- field_.reset();
- field_candidates_map_.clear();
-
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Name on Card");
- field.name = ASCIIToUTF16("name_on_card");
- list_.push_back(
- base::MakeUnique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number");
- list_.push_back(
- base::MakeUnique<AutofillField>(field, ASCIIToUTF16("num2")));
-
- field.label = ASCIIToUTF16(test_case.label);
- if (test_case.max_length != 0) {
- field.max_length = test_case.max_length;
- }
- field.name = ASCIIToUTF16("cc_exp");
- list_.push_back(
- base::MakeUnique<AutofillField>(field, ASCIIToUTF16("exp3")));
-
- Parse();
-
- // Assists in identifing which case has failed.
- SCOPED_TRACE(test_case.expected_prediction);
- SCOPED_TRACE(test_case.max_length);
- SCOPED_TRACE(test_case.label);
-
- if (test_case.expected_prediction == UNKNOWN_TYPE) {
- // Expect failure and continue to next test case.
- // The expiry date is a required field for credit card forms, and thus the
- // parse sets |field_| to nullptr.
- EXPECT_EQ(nullptr, field_.get());
- continue;
- }
+typedef struct {
+ const std::string label;
+ const int max_length;
+ const ServerFieldType expected_prediction;
+} ParseExpFieldTestCase;
+
+class ParseExpFieldTest : public CreditCardFieldTestBase,
+ public testing::TestWithParam<ParseExpFieldTestCase> {
+};
+
+TEST_P(ParseExpFieldTest, ParseExpField) {
+ auto test_case = GetParam();
+ // Clean up after previous test cases.
+ list_.clear();
+ field_.reset();
+ field_candidates_map_.clear();
+
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("Name on Card");
+ field.name = ASCIIToUTF16("name_on_card");
+ list_.push_back(
+ base::MakeUnique<AutofillField>(field, ASCIIToUTF16("name1")));
- // Ensure that the form was determined as valid.
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("num2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("num2")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("exp3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(test_case.expected_prediction,
- field_candidates_map_[ASCIIToUTF16("exp3")].BestHeuristicType());
+ field.label = ASCIIToUTF16("Card Number");
+ field.name = ASCIIToUTF16("card_number");
+ list_.push_back(base::MakeUnique<AutofillField>(field, ASCIIToUTF16("num2")));
+
+ field.label = ASCIIToUTF16(test_case.label);
+ if (test_case.max_length != 0) {
+ field.max_length = test_case.max_length;
+ }
+ field.name = ASCIIToUTF16("cc_exp");
+ list_.push_back(base::MakeUnique<AutofillField>(field, ASCIIToUTF16("exp3")));
+
+ Parse();
+
+ // Assists in identifing which case has failed.
+ SCOPED_TRACE(test_case.expected_prediction);
+ SCOPED_TRACE(test_case.max_length);
+ SCOPED_TRACE(test_case.label);
+
+ if (test_case.expected_prediction == UNKNOWN_TYPE) {
+ // Expect failure and continue to next test case.
+ // The expiry date is a required field for credit card forms, and thus the
+ // parse sets |field_| to nullptr.
+ EXPECT_EQ(nullptr, field_.get());
+ return;
}
+
+ // Ensure that the form was determined as valid.
+ ASSERT_NE(nullptr, field_.get());
+ AddClassifications();
+ ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+ field_candidates_map_.end());
+ EXPECT_EQ(CREDIT_CARD_NAME_FULL,
+ field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+
+ ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("num2")) !=
+ field_candidates_map_.end());
+ EXPECT_EQ(CREDIT_CARD_NUMBER,
+ field_candidates_map_[ASCIIToUTF16("num2")].BestHeuristicType());
+
+ ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("exp3")) !=
+ field_candidates_map_.end());
+ EXPECT_EQ(test_case.expected_prediction,
+ field_candidates_map_[ASCIIToUTF16("exp3")].BestHeuristicType());
}
+INSTANTIATE_TEST_CASE_P(
+ CreditCardFieldTest,
+ ParseExpFieldTest,
+ testing::Values(
+ // General label, no maxlength.
+ ParseExpFieldTestCase{"Expiration Date", 0,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ // General label, maxlength 4.
+ ParseExpFieldTestCase{"Expiration Date", 4,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ // General label, maxlength 5.
+ ParseExpFieldTestCase{"Expiration Date", 5,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ // General label, maxlength 6.
+ ParseExpFieldTestCase{"Expiration Date", 6,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ // General label, maxlength 7.
+ ParseExpFieldTestCase{"Expiration Date", 7,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ // General label, large maxlength.
+ ParseExpFieldTestCase{"Expiration Date", 12,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+
+ // Unsupported maxlength, general label.
+ ParseExpFieldTestCase{"Expiration Date", 3, UNKNOWN_TYPE},
+ // Unsupported maxlength, two digit year label.
+ ParseExpFieldTestCase{"Expiration Date (MM/YY)", 3, UNKNOWN_TYPE},
+ // Unsupported maxlength, four digit year label.
+ ParseExpFieldTestCase{"Expiration Date (MM/YYYY)", 3, UNKNOWN_TYPE},
+
+ // Two digit year, simple label.
+ ParseExpFieldTestCase{"MM / YY", 0, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ // Two digit year, with slash (MM/YY).
+ ParseExpFieldTestCase{"Expiration Date (MM/YY)", 0,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ // Two digit year, no slash (MMYY).
+ ParseExpFieldTestCase{"Expiration Date (MMYY)", 4,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ // Two digit year, with slash and maxlength (MM/YY).
+ ParseExpFieldTestCase{"Expiration Date (MM/YY)", 5,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ // Two digit year, with slash and large maxlength (MM/YY).
+ ParseExpFieldTestCase{"Expiration Date (MM/YY)", 12,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+
+ // Four digit year, simple label.
+ ParseExpFieldTestCase{"MM / YYYY", 0,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ // Four digit year, with slash (MM/YYYY).
+ ParseExpFieldTestCase{"Expiration Date (MM/YYYY)", 0,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ // Four digit year, no slash (MMYYYY).
+ ParseExpFieldTestCase{"Expiration Date (MMYYYY)", 6,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ // Four digit year, with slash and maxlength (MM/YYYY).
+ ParseExpFieldTestCase{"Expiration Date (MM/YYYY)", 7,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ // Four digit year, with slash and large maxlength (MM/YYYY).
+ ParseExpFieldTestCase{"Expiration Date (MM/YYYY)", 12,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+
+ // Four digit year label with restrictive maxlength (4).
+ ParseExpFieldTestCase{"Expiration Date (MM/YYYY)", 4,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ // Four digit year label with restrictive maxlength (5).
+ ParseExpFieldTestCase{"Expiration Date (MM/YYYY)", 5,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR}));
+
TEST_F(CreditCardFieldTest, ParseCreditCardHolderNameWithCCFullName) {
FormFieldData field;
field.form_control_type = "text";
diff --git a/chromium/components/autofill/core/browser/credit_card_unittest.cc b/chromium/components/autofill/core/browser/credit_card_unittest.cc
index 993862f6d6d..4e371ec4656 100644
--- a/chromium/components/autofill/core/browser/credit_card_unittest.cc
+++ b/chromium/components/autofill/core/browser/credit_card_unittest.cc
@@ -158,77 +158,90 @@ TEST(CreditCardTest, AssignmentOperator) {
EXPECT_TRUE(a == b);
}
-TEST(CreditCardTest, SetExpirationYearFromString) {
- static const struct {
- std::string expiration_year;
- int expected_year;
- } kTestCases[] = {
- // Valid values.
- {"2040", 2040},
- {"45", 2045},
- {"045", 2045},
- {"9", 2009},
-
- // Unrecognized year values.
- {"052045", 0},
- {"123", 0},
- {"y2045", 0},
- };
+struct SetExpirationYearFromStringTestCase {
+ std::string expiration_year;
+ int expected_year;
+};
- for (const auto& test_case : kTestCases) {
- CreditCard card(base::GenerateGUID(), "some origin");
- card.SetExpirationYearFromString(ASCIIToUTF16(test_case.expiration_year));
+class SetExpirationYearFromStringTest
+ : public testing::TestWithParam<SetExpirationYearFromStringTestCase> {};
- EXPECT_EQ(test_case.expected_year, card.expiration_year())
- << test_case.expiration_year << " " << test_case.expected_year;
- }
+TEST_P(SetExpirationYearFromStringTest, SetExpirationYearFromString) {
+ auto test_case = GetParam();
+ CreditCard card(base::GenerateGUID(), "some origin");
+ card.SetExpirationYearFromString(ASCIIToUTF16(test_case.expiration_year));
+
+ EXPECT_EQ(test_case.expected_year, card.expiration_year())
+ << test_case.expiration_year << " " << test_case.expected_year;
}
-TEST(CreditCardTest, SetExpirationDateFromString) {
- static const struct {
- std::string expiration_date;
- int expected_month;
- int expected_year;
- } kTestCases[] = {{"10", 0, 0}, // Too small.
- {"1020451", 0, 0}, // Too long.
-
- // No separators.
- {"105", 0, 0}, // Too ambiguous.
- {"0545", 5, 2045},
- {"52045", 0, 0}, // Too ambiguous.
- {"052045", 5, 2045},
-
- // "/" separator.
- {"05/45", 5, 2045},
- {"5/2045", 5, 2045},
- {"05/2045", 5, 2045},
-
- // "-" separator.
- {"05-45", 5, 2045},
- {"5-2045", 5, 2045},
- {"05-2045", 5, 2045},
-
- // "|" separator.
- {"05|45", 5, 2045},
- {"5|2045", 5, 2045},
- {"05|2045", 5, 2045},
-
- // Invalid values.
- {"13/2016", 0, 2016},
- {"16/13", 0, 2013},
- {"May-2015", 0, 0},
- {"05-/2045", 0, 0},
- {"05_2045", 0, 0}};
+INSTANTIATE_TEST_CASE_P(CreditCardTest,
+ SetExpirationYearFromStringTest,
+ testing::Values(
+ // Valid values.
+ SetExpirationYearFromStringTestCase{"2040", 2040},
+ SetExpirationYearFromStringTestCase{"45", 2045},
+ SetExpirationYearFromStringTestCase{"045", 2045},
+ SetExpirationYearFromStringTestCase{"9", 2009},
+
+ // Unrecognized year values.
+ SetExpirationYearFromStringTestCase{"052045", 0},
+ SetExpirationYearFromStringTestCase{"123", 0},
+ SetExpirationYearFromStringTestCase{"y2045", 0}));
+
+struct SetExpirationDateFromStringTestCase {
+ std::string expiration_date;
+ int expected_month;
+ int expected_year;
+};
- for (const auto& test_case : kTestCases) {
- CreditCard card(base::GenerateGUID(), "some origin");
- card.SetExpirationDateFromString(ASCIIToUTF16(test_case.expiration_date));
+class SetExpirationDateFromStringTest
+ : public testing::TestWithParam<SetExpirationDateFromStringTestCase> {};
- EXPECT_EQ(test_case.expected_month, card.expiration_month());
- EXPECT_EQ(test_case.expected_year, card.expiration_year());
- }
+TEST_P(SetExpirationDateFromStringTest, SetExpirationDateFromString) {
+ auto test_case = GetParam();
+ CreditCard card(base::GenerateGUID(), "some origin");
+ card.SetExpirationDateFromString(ASCIIToUTF16(test_case.expiration_date));
+
+ EXPECT_EQ(test_case.expected_month, card.expiration_month());
+ EXPECT_EQ(test_case.expected_year, card.expiration_year());
}
+INSTANTIATE_TEST_CASE_P(
+ CreditCardTest,
+ SetExpirationDateFromStringTest,
+ testing::Values(
+ SetExpirationDateFromStringTestCase{"10", 0, 0}, // Too small.
+ SetExpirationDateFromStringTestCase{"1020451", 0, 0}, // Too long.
+
+ // No separators.
+ SetExpirationDateFromStringTestCase{"105", 0, 0}, // Too ambiguous.
+ SetExpirationDateFromStringTestCase{"0545", 5, 2045},
+ SetExpirationDateFromStringTestCase{"52045", 0, 0}, // Too ambiguous.
+ SetExpirationDateFromStringTestCase{"052045", 5, 2045},
+
+ // "/" separator.
+ SetExpirationDateFromStringTestCase{"05/45", 5, 2045},
+ SetExpirationDateFromStringTestCase{"5/2045", 5, 2045},
+ SetExpirationDateFromStringTestCase{"05/2045", 5, 2045},
+
+ // "-" separator.
+ SetExpirationDateFromStringTestCase{"05-45", 5, 2045},
+ SetExpirationDateFromStringTestCase{"5-2045", 5, 2045},
+ SetExpirationDateFromStringTestCase{"05-2045", 5, 2045},
+
+ // "|" separator.
+ SetExpirationDateFromStringTestCase{"05|45", 5, 2045},
+ SetExpirationDateFromStringTestCase{"5|2045", 5, 2045},
+ SetExpirationDateFromStringTestCase{"05|2045", 5, 2045},
+
+ // Invalid values.
+ SetExpirationDateFromStringTestCase{"13/2016", 0, 2016},
+ SetExpirationDateFromStringTestCase{"16/13", 0, 2013},
+ SetExpirationDateFromStringTestCase{"May-2015", 0, 0},
+ SetExpirationDateFromStringTestCase{"05-/2045", 0, 0},
+ SetExpirationDateFromStringTestCase{"05_2045", 0, 0}));
+
TEST(CreditCardTest, Copy) {
CreditCard a(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&a, "John Dillinger", "123456789012", "01", "2010");
@@ -238,73 +251,85 @@ TEST(CreditCardTest, Copy) {
EXPECT_TRUE(a == b);
}
-TEST(CreditCardTest, IsLocalDuplicateOfServerCard) {
- struct {
- CreditCard::RecordType first_card_record_type;
- const char* first_card_name;
- const char* first_card_number;
- const char* first_card_exp_mo;
- const char* first_card_exp_yr;
-
- CreditCard::RecordType second_card_record_type;
- const char* second_card_name;
- const char* second_card_number;
- const char* second_card_exp_mo;
- const char* second_card_exp_yr;
- const char* second_card_type;
-
- bool is_local_duplicate;
- } test_cases[] = {
- { LOCAL_CARD, "", "", "", "",
- LOCAL_CARD, "", "", "", "", nullptr, false },
- { LOCAL_CARD, "", "", "", "",
- FULL_SERVER_CARD, "", "", "", "", nullptr, true},
- { FULL_SERVER_CARD, "", "", "", "",
- FULL_SERVER_CARD, "", "", "", "", nullptr, false},
- { LOCAL_CARD, "John Dillinger", "423456789012", "01", "2010",
- FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010", nullptr,
- true },
- { LOCAL_CARD, "J Dillinger", "423456789012", "01", "2010",
- FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010", nullptr,
- false },
- { LOCAL_CARD, "", "423456789012", "01", "2010",
- FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010", nullptr,
- true },
- { LOCAL_CARD, "", "423456789012", "", "",
- FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010", nullptr,
- true },
- { LOCAL_CARD, "", "423456789012", "", "",
- MASKED_SERVER_CARD, "John Dillinger", "9012", "01", "2010", kVisaCard,
- true },
- { LOCAL_CARD, "", "423456789012", "", "",
- MASKED_SERVER_CARD, "John Dillinger", "9012", "01", "2010", kMasterCard,
- false },
- { LOCAL_CARD, "John Dillinger", "4234-5678-9012", "01", "2010",
- FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010", nullptr,
- true },
- };
+struct IsLocalDuplicateOfServerCardTestCase {
+ CreditCard::RecordType first_card_record_type;
+ const char* first_card_name;
+ const char* first_card_number;
+ const char* first_card_exp_mo;
+ const char* first_card_exp_yr;
+
+ CreditCard::RecordType second_card_record_type;
+ const char* second_card_name;
+ const char* second_card_number;
+ const char* second_card_exp_mo;
+ const char* second_card_exp_yr;
+ const char* second_card_type;
+
+ bool is_local_duplicate;
+};
- for (const auto& test_case : test_cases) {
- CreditCard a(base::GenerateGUID(), std::string());
- a.set_record_type(test_case.first_card_record_type);
- test::SetCreditCardInfo(
- &a, test_case.first_card_name, test_case.first_card_number,
- test_case.first_card_exp_mo, test_case.first_card_exp_yr);
+class IsLocalDuplicateOfServerCardTest
+ : public testing::TestWithParam<IsLocalDuplicateOfServerCardTestCase> {};
- CreditCard b(base::GenerateGUID(), std::string());
- b.set_record_type(test_case.second_card_record_type);
- test::SetCreditCardInfo(
- &b, test_case.second_card_name, test_case.second_card_number,
- test_case.second_card_exp_mo, test_case.second_card_exp_yr);
+TEST_P(IsLocalDuplicateOfServerCardTest, IsLocalDuplicateOfServerCard) {
+ auto test_case = GetParam();
+ CreditCard a(base::GenerateGUID(), std::string());
+ a.set_record_type(test_case.first_card_record_type);
+ test::SetCreditCardInfo(
+ &a, test_case.first_card_name, test_case.first_card_number,
+ test_case.first_card_exp_mo, test_case.first_card_exp_yr);
- if (test_case.second_card_record_type == CreditCard::MASKED_SERVER_CARD)
- b.SetTypeForMaskedCard(test_case.second_card_type);
+ CreditCard b(base::GenerateGUID(), std::string());
+ b.set_record_type(test_case.second_card_record_type);
+ test::SetCreditCardInfo(
+ &b, test_case.second_card_name, test_case.second_card_number,
+ test_case.second_card_exp_mo, test_case.second_card_exp_yr);
- EXPECT_EQ(test_case.is_local_duplicate, a.IsLocalDuplicateOfServerCard(b))
- << " when comparing cards " << a.Label() << " and " << b.Label();
- }
+ if (test_case.second_card_record_type == CreditCard::MASKED_SERVER_CARD)
+ b.SetTypeForMaskedCard(test_case.second_card_type);
+
+ EXPECT_EQ(test_case.is_local_duplicate, a.IsLocalDuplicateOfServerCard(b))
+ << " when comparing cards " << a.Label() << " and " << b.Label();
}
+INSTANTIATE_TEST_CASE_P(
+ CreditCardTest,
+ IsLocalDuplicateOfServerCardTest,
+ testing::Values(
+ IsLocalDuplicateOfServerCardTestCase{LOCAL_CARD, "", "", "", "",
+ LOCAL_CARD, "", "", "", "",
+ nullptr, false},
+ IsLocalDuplicateOfServerCardTestCase{LOCAL_CARD, "", "", "", "",
+ FULL_SERVER_CARD, "", "", "", "",
+ nullptr, true},
+ IsLocalDuplicateOfServerCardTestCase{FULL_SERVER_CARD, "", "", "", "",
+ FULL_SERVER_CARD, "", "", "", "",
+ nullptr, false},
+ IsLocalDuplicateOfServerCardTestCase{
+ LOCAL_CARD, "John Dillinger", "423456789012", "01", "2010",
+ FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010",
+ nullptr, true},
+ IsLocalDuplicateOfServerCardTestCase{
+ LOCAL_CARD, "J Dillinger", "423456789012", "01", "2010",
+ FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010",
+ nullptr, false},
+ IsLocalDuplicateOfServerCardTestCase{
+ LOCAL_CARD, "", "423456789012", "01", "2010", FULL_SERVER_CARD,
+ "John Dillinger", "423456789012", "01", "2010", nullptr, true},
+ IsLocalDuplicateOfServerCardTestCase{
+ LOCAL_CARD, "", "423456789012", "", "", FULL_SERVER_CARD,
+ "John Dillinger", "423456789012", "01", "2010", nullptr, true},
+ IsLocalDuplicateOfServerCardTestCase{
+ LOCAL_CARD, "", "423456789012", "", "", MASKED_SERVER_CARD,
+ "John Dillinger", "9012", "01", "2010", kVisaCard, true},
+ IsLocalDuplicateOfServerCardTestCase{
+ LOCAL_CARD, "", "423456789012", "", "", MASKED_SERVER_CARD,
+ "John Dillinger", "9012", "01", "2010", kMasterCard, false},
+ IsLocalDuplicateOfServerCardTestCase{
+ LOCAL_CARD, "John Dillinger", "4234-5678-9012", "01", "2010",
+ FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010",
+ nullptr, true}));
+
TEST(CreditCardTest, HasSameNumberAs) {
CreditCard a(base::GenerateGUID(), std::string());
CreditCard b(base::GenerateGUID(), std::string());
@@ -603,178 +628,223 @@ TEST(CreditCardTest, CreditCardVerificationCode) {
EXPECT_EQ(base::string16(), card.GetRawInfo(CREDIT_CARD_VERIFICATION_CODE));
}
+struct GetCreditCardTypeTestCase {
+ std::string card_number;
+ std::string type;
+ bool is_valid;
+};
-TEST(CreditCardTest, GetCreditCardType) {
- struct {
- std::string card_number;
- std::string type;
- bool is_valid;
- } test_cases[] = {
- // The relevant sample numbers from
- // http://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm
- { "378282246310005", kAmericanExpressCard, true },
- { "371449635398431", kAmericanExpressCard, true },
- { "378734493671000", kAmericanExpressCard, true },
- { "30569309025904", kDinersCard, true },
- { "38520000023237", kDinersCard, true },
- { "6011111111111117", kDiscoverCard, true },
- { "6011000990139424", kDiscoverCard, true },
- { "3530111333300000", kJCBCard, true },
- { "3566002020360505", kJCBCard, true },
- { "5555555555554444", kMasterCard, true },
- { "5105105105105100", kMasterCard, true },
- { "4111111111111111", kVisaCard, true },
- { "4012888888881881", kVisaCard, true },
- { "4222222222222", kVisaCard, true },
-
- // The relevant sample numbers from
- // https://www.auricsystems.com/sample-credit-card-numbers/
- { "343434343434343", kAmericanExpressCard, true },
- { "371144371144376", kAmericanExpressCard, true },
- { "341134113411347", kAmericanExpressCard, true },
- { "36438936438936", kDinersCard, true },
- { "36110361103612", kDinersCard, true },
- { "36111111111111", kDinersCard, true },
- { "6011016011016011", kDiscoverCard, true },
- { "6011000990139424", kDiscoverCard, true },
- { "6011000000000004", kDiscoverCard, true },
- { "6011000995500000", kDiscoverCard, true },
- { "6500000000000002", kDiscoverCard, true },
- { "3566002020360505", kJCBCard, true },
- { "3528000000000007", kJCBCard, true },
- { "5500005555555559", kMasterCard, true },
- { "5555555555555557", kMasterCard, true },
- { "5454545454545454", kMasterCard, true },
- { "5555515555555551", kMasterCard, true },
- { "5405222222222226", kMasterCard, true },
- { "5478050000000007", kMasterCard, true },
- { "5111005111051128", kMasterCard, true },
- { "5112345112345114", kMasterCard, true },
- { "5115915115915118", kMasterCard, true },
- { "6247130048162403", kUnionPay, true },
- { "6247130048162403", kUnionPay, true },
- { "622384452162063648", kUnionPay, true },
- { "2204883716636153", kMirCard, true },
- { "2200111234567898", kMirCard, true },
- { "2200481349288130", kMirCard, true },
-
- // Empty string
- { std::string(), kGenericCard, false },
-
- // Non-numeric
- { "garbage", kGenericCard, false },
- { "4garbage", kVisaCard, false },
-
- // Fails Luhn check.
- { "4111111111111112", kVisaCard, false },
- { "6247130048162413", kUnionPay, false },
- { "2204883716636154", kMirCard, false },
-
- // Invalid length.
- { "3434343434343434", kAmericanExpressCard, false },
- { "411111111111116", kVisaCard, false },
- { "220011123456783", kMirCard, false },
-
- // Issuer Identification Numbers (IINs) that Chrome recognizes.
- { "4", kVisaCard, false },
- { "22", kMirCard, false },
- { "34", kAmericanExpressCard, false },
- { "37", kAmericanExpressCard, false },
- { "300", kDinersCard, false },
- { "301", kDinersCard, false },
- { "302", kDinersCard, false },
- { "303", kDinersCard, false },
- { "304", kDinersCard, false },
- { "305", kDinersCard, false },
- { "3095", kDinersCard, false },
- { "36", kDinersCard, false },
- { "38", kDinersCard, false },
- { "39", kDinersCard, false },
- { "6011", kDiscoverCard, false },
- { "644", kDiscoverCard, false },
- { "645", kDiscoverCard, false },
- { "646", kDiscoverCard, false },
- { "647", kDiscoverCard, false },
- { "648", kDiscoverCard, false },
- { "649", kDiscoverCard, false },
- { "65", kDiscoverCard, false },
- { "3528", kJCBCard, false },
- { "3531", kJCBCard, false },
- { "3589", kJCBCard, false },
- { "51", kMasterCard, false },
- { "52", kMasterCard, false },
- { "53", kMasterCard, false },
- { "54", kMasterCard, false },
- { "55", kMasterCard, false },
- { "62", kUnionPay, false },
-
- // Not enough data to determine an IIN uniquely.
- { "2", kGenericCard, false },
- { "3", kGenericCard, false },
- { "30", kGenericCard, false },
- { "309", kGenericCard, false },
- { "35", kGenericCard, false },
- { "5", kGenericCard, false },
- { "6", kGenericCard, false },
- { "60", kGenericCard, false },
- { "601", kGenericCard, false },
- { "64", kGenericCard, false },
-
- // Unknown IINs.
- { "0", kGenericCard, false },
- { "1", kGenericCard, false },
- { "306", kGenericCard, false },
- { "307", kGenericCard, false },
- { "308", kGenericCard, false },
- { "3091", kGenericCard, false },
- { "3094", kGenericCard, false },
- { "3096", kGenericCard, false },
- { "31", kGenericCard, false },
- { "32", kGenericCard, false },
- { "33", kGenericCard, false },
- { "351", kGenericCard, false },
- { "3527", kGenericCard, false },
- { "359", kGenericCard, false },
- { "50", kGenericCard, false },
- { "56", kGenericCard, false },
- { "57", kGenericCard, false },
- { "58", kGenericCard, false },
- { "59", kGenericCard, false },
- { "600", kGenericCard, false },
- { "602", kGenericCard, false },
- { "603", kGenericCard, false },
- { "604", kGenericCard, false },
- { "605", kGenericCard, false },
- { "606", kGenericCard, false },
- { "607", kGenericCard, false },
- { "608", kGenericCard, false },
- { "609", kGenericCard, false },
- { "61", kGenericCard, false },
- { "63", kGenericCard, false },
- { "640", kGenericCard, false },
- { "641", kGenericCard, false },
- { "642", kGenericCard, false },
- { "643", kGenericCard, false },
- { "66", kGenericCard, false },
- { "67", kGenericCard, false },
- { "68", kGenericCard, false },
- { "69", kGenericCard, false },
- { "7", kGenericCard, false },
- { "8", kGenericCard, false },
- { "9", kGenericCard, false },
-
- // Oddball case: Unknown issuer, but valid Luhn check and plausible length.
- { "7000700070007000", kGenericCard, true },
- };
+// We are doing batches here because INSTANTIATE_TEST_CASE_P has a
+// 50 upper limit.
+class GetCreditCardTypeTestBatch1
+ : public testing::TestWithParam<GetCreditCardTypeTestCase> {};
+
+TEST_P(GetCreditCardTypeTestBatch1, GetCreditCardType) {
+ auto test_case = GetParam();
+ base::string16 card_number = ASCIIToUTF16(test_case.card_number);
+ SCOPED_TRACE(card_number);
+ EXPECT_EQ(test_case.type, CreditCard::GetCreditCardType(card_number));
+ EXPECT_EQ(test_case.is_valid, IsValidCreditCardNumber(card_number));
+}
- for (const auto& test_case : test_cases) {
- base::string16 card_number = ASCIIToUTF16(test_case.card_number);
- SCOPED_TRACE(card_number);
- EXPECT_EQ(test_case.type, CreditCard::GetCreditCardType(card_number));
- EXPECT_EQ(test_case.is_valid, IsValidCreditCardNumber(card_number));
- }
+INSTANTIATE_TEST_CASE_P(
+ CreditCardTest,
+ GetCreditCardTypeTestBatch1,
+ testing::Values(
+ // The relevant sample numbers from
+ // http://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm
+ GetCreditCardTypeTestCase{"378282246310005", kAmericanExpressCard,
+ true},
+ GetCreditCardTypeTestCase{"371449635398431", kAmericanExpressCard,
+ true},
+ GetCreditCardTypeTestCase{"378734493671000", kAmericanExpressCard,
+ true},
+ GetCreditCardTypeTestCase{"30569309025904", kDinersCard, true},
+ GetCreditCardTypeTestCase{"38520000023237", kDinersCard, true},
+ GetCreditCardTypeTestCase{"6011111111111117", kDiscoverCard, true},
+ GetCreditCardTypeTestCase{"6011000990139424", kDiscoverCard, true},
+ GetCreditCardTypeTestCase{"3530111333300000", kJCBCard, true},
+ GetCreditCardTypeTestCase{"3566002020360505", kJCBCard, true},
+ GetCreditCardTypeTestCase{"5555555555554444", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5105105105105100", kMasterCard, true},
+ GetCreditCardTypeTestCase{"4111111111111111", kVisaCard, true},
+ GetCreditCardTypeTestCase{"4012888888881881", kVisaCard, true},
+ GetCreditCardTypeTestCase{"4222222222222", kVisaCard, true},
+
+ // The relevant sample numbers from
+ // https://www.auricsystems.com/sample-credit-card-numbers/
+ GetCreditCardTypeTestCase{"343434343434343", kAmericanExpressCard,
+ true},
+ GetCreditCardTypeTestCase{"371144371144376", kAmericanExpressCard,
+ true},
+ GetCreditCardTypeTestCase{"341134113411347", kAmericanExpressCard,
+ true},
+ GetCreditCardTypeTestCase{"36438936438936", kDinersCard, true},
+ GetCreditCardTypeTestCase{"36110361103612", kDinersCard, true},
+ GetCreditCardTypeTestCase{"36111111111111", kDinersCard, true},
+ GetCreditCardTypeTestCase{"6011016011016011", kDiscoverCard, true},
+ GetCreditCardTypeTestCase{"6011000990139424", kDiscoverCard, true},
+ GetCreditCardTypeTestCase{"6011000000000004", kDiscoverCard, true},
+ GetCreditCardTypeTestCase{"6011000995500000", kDiscoverCard, true},
+ GetCreditCardTypeTestCase{"6500000000000002", kDiscoverCard, true},
+ GetCreditCardTypeTestCase{"3566002020360505", kJCBCard, true},
+ GetCreditCardTypeTestCase{"3528000000000007", kJCBCard, true},
+ GetCreditCardTypeTestCase{"5500005555555559", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5555555555555557", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5454545454545454", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5555515555555551", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5405222222222226", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5478050000000007", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5111005111051128", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5112345112345114", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5115915115915118", kMasterCard, true},
+ GetCreditCardTypeTestCase{"6247130048162403", kUnionPay, true},
+ GetCreditCardTypeTestCase{"6247130048162403", kUnionPay, true},
+ GetCreditCardTypeTestCase{"622384452162063648", kUnionPay, true},
+ GetCreditCardTypeTestCase{"2204883716636153", kMirCard, true},
+ GetCreditCardTypeTestCase{"2200111234567898", kMirCard, true},
+ GetCreditCardTypeTestCase{"2200481349288130", kMirCard, true},
+
+ // Empty string
+ GetCreditCardTypeTestCase{std::string(), kGenericCard, false},
+
+ // Non-numeric
+ GetCreditCardTypeTestCase{"garbage", kGenericCard, false},
+ GetCreditCardTypeTestCase{"4garbage", kVisaCard, false},
+
+ // Fails Luhn check.
+ GetCreditCardTypeTestCase{"4111111111111112", kVisaCard, false},
+ GetCreditCardTypeTestCase{"6247130048162413", kUnionPay, false},
+ GetCreditCardTypeTestCase{"2204883716636154", kMirCard, false}));
+
+class GetCreditCardTypeTestBatch2
+ : public testing::TestWithParam<GetCreditCardTypeTestCase> {};
+
+TEST_P(GetCreditCardTypeTestBatch2, GetCreditCardType) {
+ auto test_case = GetParam();
+ base::string16 card_number = ASCIIToUTF16(test_case.card_number);
+ SCOPED_TRACE(card_number);
+ EXPECT_EQ(test_case.type, CreditCard::GetCreditCardType(card_number));
+ EXPECT_EQ(test_case.is_valid, IsValidCreditCardNumber(card_number));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ CreditCardTest,
+ GetCreditCardTypeTestBatch2,
+ testing::Values(
+ // Invalid length.
+ GetCreditCardTypeTestCase{"3434343434343434", kAmericanExpressCard,
+ false},
+ GetCreditCardTypeTestCase{"411111111111116", kVisaCard, false},
+ GetCreditCardTypeTestCase{"220011123456783", kMirCard, false},
+
+ // Issuer Identification Numbers (IINs) that Chrome recognizes.
+ GetCreditCardTypeTestCase{"4", kVisaCard, false},
+ GetCreditCardTypeTestCase{"22", kMirCard, false},
+ GetCreditCardTypeTestCase{"34", kAmericanExpressCard, false},
+ GetCreditCardTypeTestCase{"37", kAmericanExpressCard, false},
+ GetCreditCardTypeTestCase{"300", kDinersCard, false},
+ GetCreditCardTypeTestCase{"301", kDinersCard, false},
+ GetCreditCardTypeTestCase{"302", kDinersCard, false},
+ GetCreditCardTypeTestCase{"303", kDinersCard, false},
+ GetCreditCardTypeTestCase{"304", kDinersCard, false},
+ GetCreditCardTypeTestCase{"305", kDinersCard, false},
+ GetCreditCardTypeTestCase{"3095", kDinersCard, false},
+ GetCreditCardTypeTestCase{"36", kDinersCard, false},
+ GetCreditCardTypeTestCase{"38", kDinersCard, false},
+ GetCreditCardTypeTestCase{"39", kDinersCard, false},
+ GetCreditCardTypeTestCase{"6011", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"644", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"645", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"646", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"647", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"648", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"649", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"65", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"3528", kJCBCard, false},
+ GetCreditCardTypeTestCase{"3531", kJCBCard, false},
+ GetCreditCardTypeTestCase{"3589", kJCBCard, false},
+ GetCreditCardTypeTestCase{"51", kMasterCard, false},
+ GetCreditCardTypeTestCase{"52", kMasterCard, false},
+ GetCreditCardTypeTestCase{"53", kMasterCard, false},
+ GetCreditCardTypeTestCase{"54", kMasterCard, false},
+ GetCreditCardTypeTestCase{"55", kMasterCard, false},
+ GetCreditCardTypeTestCase{"62", kUnionPay, false},
+
+ // Not enough data to determine an IIN uniquely.
+ GetCreditCardTypeTestCase{"2", kGenericCard, false},
+ GetCreditCardTypeTestCase{"3", kGenericCard, false},
+ GetCreditCardTypeTestCase{"30", kGenericCard, false},
+ GetCreditCardTypeTestCase{"309", kGenericCard, false},
+ GetCreditCardTypeTestCase{"35", kGenericCard, false},
+ GetCreditCardTypeTestCase{"5", kGenericCard, false},
+ GetCreditCardTypeTestCase{"6", kGenericCard, false},
+ GetCreditCardTypeTestCase{"60", kGenericCard, false},
+ GetCreditCardTypeTestCase{"601", kGenericCard, false},
+ GetCreditCardTypeTestCase{"64", kGenericCard, false}));
+
+class GetCreditCardTypeTestBatch3
+ : public testing::TestWithParam<GetCreditCardTypeTestCase> {};
+
+TEST_P(GetCreditCardTypeTestBatch3, GetCreditCardType) {
+ auto test_case = GetParam();
+ base::string16 card_number = ASCIIToUTF16(test_case.card_number);
+ SCOPED_TRACE(card_number);
+ EXPECT_EQ(test_case.type, CreditCard::GetCreditCardType(card_number));
+ EXPECT_EQ(test_case.is_valid, IsValidCreditCardNumber(card_number));
}
+INSTANTIATE_TEST_CASE_P(
+ CreditCardTest,
+ GetCreditCardTypeTestBatch3,
+ testing::Values(
+ // Unknown IINs.
+ GetCreditCardTypeTestCase{"0", kGenericCard, false},
+ GetCreditCardTypeTestCase{"1", kGenericCard, false},
+ GetCreditCardTypeTestCase{"306", kGenericCard, false},
+ GetCreditCardTypeTestCase{"307", kGenericCard, false},
+ GetCreditCardTypeTestCase{"308", kGenericCard, false},
+ GetCreditCardTypeTestCase{"3091", kGenericCard, false},
+ GetCreditCardTypeTestCase{"3094", kGenericCard, false},
+ GetCreditCardTypeTestCase{"3096", kGenericCard, false},
+ GetCreditCardTypeTestCase{"31", kGenericCard, false},
+ GetCreditCardTypeTestCase{"32", kGenericCard, false},
+ GetCreditCardTypeTestCase{"33", kGenericCard, false},
+ GetCreditCardTypeTestCase{"351", kGenericCard, false},
+ GetCreditCardTypeTestCase{"3527", kGenericCard, false},
+ GetCreditCardTypeTestCase{"359", kGenericCard, false},
+ GetCreditCardTypeTestCase{"50", kGenericCard, false},
+ GetCreditCardTypeTestCase{"56", kGenericCard, false},
+ GetCreditCardTypeTestCase{"57", kGenericCard, false},
+ GetCreditCardTypeTestCase{"58", kGenericCard, false},
+ GetCreditCardTypeTestCase{"59", kGenericCard, false},
+ GetCreditCardTypeTestCase{"600", kGenericCard, false},
+ GetCreditCardTypeTestCase{"602", kGenericCard, false},
+ GetCreditCardTypeTestCase{"603", kGenericCard, false},
+ GetCreditCardTypeTestCase{"604", kGenericCard, false},
+ GetCreditCardTypeTestCase{"605", kGenericCard, false},
+ GetCreditCardTypeTestCase{"606", kGenericCard, false},
+ GetCreditCardTypeTestCase{"607", kGenericCard, false},
+ GetCreditCardTypeTestCase{"608", kGenericCard, false},
+ GetCreditCardTypeTestCase{"609", kGenericCard, false},
+ GetCreditCardTypeTestCase{"61", kGenericCard, false},
+ GetCreditCardTypeTestCase{"63", kGenericCard, false},
+ GetCreditCardTypeTestCase{"640", kGenericCard, false},
+ GetCreditCardTypeTestCase{"641", kGenericCard, false},
+ GetCreditCardTypeTestCase{"642", kGenericCard, false},
+ GetCreditCardTypeTestCase{"643", kGenericCard, false},
+ GetCreditCardTypeTestCase{"66", kGenericCard, false},
+ GetCreditCardTypeTestCase{"67", kGenericCard, false},
+ GetCreditCardTypeTestCase{"68", kGenericCard, false},
+ GetCreditCardTypeTestCase{"69", kGenericCard, false},
+ GetCreditCardTypeTestCase{"7", kGenericCard, false},
+ GetCreditCardTypeTestCase{"8", kGenericCard, false},
+ GetCreditCardTypeTestCase{"9", kGenericCard, false},
+
+ // Oddball case: Unknown issuer, but valid Luhn check and plausible
+ // length.
+ GetCreditCardTypeTestCase{"7000700070007000", kGenericCard, true}));
+
TEST(CreditCardTest, LastFourDigits) {
CreditCard card(base::GenerateGUID(), "https://www.example.com/");
ASSERT_EQ(base::string16(), card.LastFourDigits());
@@ -791,104 +861,149 @@ TEST(CreditCardTest, LastFourDigits) {
}
// Verifies that a credit card should be updated.
-TEST(CreditCardTest, ShouldUpdateExpiration) {
- base::Time now = base::Time::Now();
-
- base::Time::Exploded last_year;
- (now - base::TimeDelta::FromDays(365)).LocalExplode(&last_year);
-
- base::Time::Exploded last_month;
- (now - base::TimeDelta::FromDays(31)).LocalExplode(&last_month);
-
- base::Time::Exploded current;
- now.LocalExplode(&current);
-
- base::Time::Exploded next_month;
- (now + base::TimeDelta::FromDays(31)).LocalExplode(&next_month);
+struct ShouldUpdateExpirationTestCase {
+ bool should_update_expiration;
+ int month;
+ int year;
+ CreditCard::RecordType record_type;
+ CreditCard::ServerStatus server_status;
+};
- base::Time::Exploded next_year;
- (now + base::TimeDelta::FromDays(365)).LocalExplode(&next_year);
+class ShouldUpdateExpirationTest
+ : public testing::TestWithParam<ShouldUpdateExpirationTestCase> {};
+
+class TestingTimes {
+ public:
+ TestingTimes() {
+ now_ = base::Time::Now();
+ (now_ - base::TimeDelta::FromDays(365)).LocalExplode(&last_year_);
+ (now_ - base::TimeDelta::FromDays(31)).LocalExplode(&last_month_);
+ now_.LocalExplode(&current_);
+ (now_ + base::TimeDelta::FromDays(31)).LocalExplode(&next_month_);
+ (now_ + base::TimeDelta::FromDays(365)).LocalExplode(&next_year_);
+ }
- static const struct {
- bool should_update_expiration;
- int month;
- int year;
- CreditCard::RecordType record_type;
- CreditCard::ServerStatus server_status;
- } kTestCases[] = {
+ base::Time now_;
+ base::Time::Exploded last_year_;
+ base::Time::Exploded last_month_;
+ base::Time::Exploded current_;
+ base::Time::Exploded next_month_;
+ base::Time::Exploded next_year_;
+};
- // Cards that expired last year should always be updated.
- {true, last_year.month, last_year.year, CreditCard::LOCAL_CARD},
- {true, last_year.month, last_year.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::OK},
- {true, last_year.month, last_year.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::OK},
- {true, last_year.month, last_year.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::EXPIRED},
- {true, last_year.month, last_year.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::EXPIRED},
-
- // Cards that expired last month should always be updated.
- {true, last_month.month, last_month.year, CreditCard::LOCAL_CARD},
- {true, last_month.month, last_month.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::OK},
- {true, last_month.month, last_month.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::OK},
- {true, last_month.month, last_month.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::EXPIRED},
- {true, last_month.month, last_month.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::EXPIRED},
-
- // Cards that expire this month should be updated only if the server
- // status is EXPIRED.
- {false, current.month, current.year, CreditCard::LOCAL_CARD},
- {false, current.month, current.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::OK},
- {false, current.month, current.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::OK},
- {true, current.month, current.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::EXPIRED},
- {true, current.month, current.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::EXPIRED},
-
- // Cards that expire next month should be updated only if the server
- // status is EXPIRED.
- {false, next_month.month, next_month.year, CreditCard::LOCAL_CARD},
- {false, next_month.month, next_month.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::OK},
- {false, next_month.month, next_month.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::OK},
- {true, next_month.month, next_month.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::EXPIRED},
- {true, next_month.month, next_month.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::EXPIRED},
-
- // Cards that expire next year should be updated only if the server status
- // is EXPIRED.
- {false, next_year.month, next_year.year, CreditCard::LOCAL_CARD},
- {false, next_year.month, next_year.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::OK},
- {false, next_year.month, next_year.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::OK},
- {true, next_year.month, next_year.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::EXPIRED},
- {true, next_year.month, next_year.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::EXPIRED},
- };
+TestingTimes testingTimes;
- for (const auto& test_case : kTestCases) {
- CreditCard card;
- card.SetExpirationMonth(test_case.month);
- card.SetExpirationYear(test_case.year);
- card.set_record_type(test_case.record_type);
- if (card.record_type() != CreditCard::LOCAL_CARD)
- card.SetServerStatus(test_case.server_status);
-
- EXPECT_EQ(test_case.should_update_expiration,
- card.ShouldUpdateExpiration(now));
- }
+TEST_P(ShouldUpdateExpirationTest, ShouldUpdateExpiration) {
+ auto test_case = GetParam();
+ CreditCard card;
+ card.SetExpirationMonth(test_case.month);
+ card.SetExpirationYear(test_case.year);
+ card.set_record_type(test_case.record_type);
+ if (card.record_type() != CreditCard::LOCAL_CARD)
+ card.SetServerStatus(test_case.server_status);
+
+ EXPECT_EQ(test_case.should_update_expiration,
+ card.ShouldUpdateExpiration(testingTimes.now_));
}
+INSTANTIATE_TEST_CASE_P(
+ CreditCardTest,
+ ShouldUpdateExpirationTest,
+ testing::Values(
+ // Cards that expired last year should always be updated.
+ ShouldUpdateExpirationTestCase{true, testingTimes.last_year_.month,
+ testingTimes.last_year_.year,
+ CreditCard::LOCAL_CARD},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_year_.month, testingTimes.last_year_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_year_.month, testingTimes.last_year_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_year_.month, testingTimes.last_year_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::EXPIRED},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_year_.month, testingTimes.last_year_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::EXPIRED},
+
+ // Cards that expired last month should always be updated.
+ ShouldUpdateExpirationTestCase{true, testingTimes.last_month_.month,
+ testingTimes.last_month_.year,
+ CreditCard::LOCAL_CARD},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_month_.month, testingTimes.last_month_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_month_.month, testingTimes.last_month_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_month_.month, testingTimes.last_month_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::EXPIRED},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_month_.month, testingTimes.last_month_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::EXPIRED},
+
+ // Cards that expire this month should be updated only if the server
+ // status is EXPIRED.
+ ShouldUpdateExpirationTestCase{false, testingTimes.current_.month,
+ testingTimes.current_.year,
+ CreditCard::LOCAL_CARD},
+ ShouldUpdateExpirationTestCase{
+ false, testingTimes.current_.month, testingTimes.current_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ false, testingTimes.current_.month, testingTimes.current_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.current_.month, testingTimes.current_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::EXPIRED},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.current_.month, testingTimes.current_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::EXPIRED},
+
+ // Cards that expire next month should be updated only if the server
+ // status is EXPIRED.
+ ShouldUpdateExpirationTestCase{false, testingTimes.next_month_.month,
+ testingTimes.next_month_.year,
+ CreditCard::LOCAL_CARD},
+ ShouldUpdateExpirationTestCase{false, testingTimes.next_month_.month,
+ testingTimes.next_month_.year,
+ CreditCard::MASKED_SERVER_CARD,
+ CreditCard::OK},
+ ShouldUpdateExpirationTestCase{false, testingTimes.next_month_.month,
+ testingTimes.next_month_.year,
+ CreditCard::FULL_SERVER_CARD,
+ CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.next_month_.month, testingTimes.next_month_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::EXPIRED},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.next_month_.month, testingTimes.next_month_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::EXPIRED},
+
+ // Cards that expire next year should be updated only if the server
+ // status is EXPIRED.
+ ShouldUpdateExpirationTestCase{false, testingTimes.next_year_.month,
+ testingTimes.next_year_.year,
+ CreditCard::LOCAL_CARD},
+ ShouldUpdateExpirationTestCase{
+ false, testingTimes.next_year_.month, testingTimes.next_year_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ false, testingTimes.next_year_.month, testingTimes.next_year_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.next_year_.month, testingTimes.next_year_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::EXPIRED},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.next_year_.month, testingTimes.next_year_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::EXPIRED}));
+
+// TODO(wuandy): rewriting below test with INSTANTIATE_TEST_CASE_P seems to
+// trigger a complaint on windows compilers. Removing it and revert to
+// original test for now.
+
// Test that credit card last used date suggestion can be generated correctly
// in different variations.
TEST(CreditCardTest, GetLastUsedDateForDisplay) {
diff --git a/chromium/components/autofill/core/browser/field_types.h b/chromium/components/autofill/core/browser/field_types.h
index 6c2aa807752..cee305fcda5 100644
--- a/chromium/components/autofill/core/browser/field_types.h
+++ b/chromium/components/autofill/core/browser/field_types.h
@@ -234,7 +234,10 @@ enum HtmlFieldType {
HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR,
HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR,
- // Non standard autcomplete types.
+ // Universal Payment Interface - Virtual Payment Address.
+ HTML_TYPE_UPI_VPA,
+
+ // Non-standard autocomplete types.
HTML_TYPE_UNRECOGNIZED,
};
diff --git a/chromium/components/autofill/core/browser/form_group.cc b/chromium/components/autofill/core/browser/form_group.cc
index 417f08a9043..1f248ccf94e 100644
--- a/chromium/components/autofill/core/browser/form_group.cc
+++ b/chromium/components/autofill/core/browser/form_group.cc
@@ -57,4 +57,14 @@ bool FormGroup::SetInfo(const AutofillType& type,
return true;
}
+bool FormGroup::HasInfo(ServerFieldType type) const {
+ return HasInfo(AutofillType(type));
+}
+
+bool FormGroup::HasInfo(const AutofillType& type) const {
+ // Use "en-US" as a placeholder locale. We are only interested in emptiness,
+ // not in the presentation of the string.
+ return !GetInfo(type, "en-US").empty();
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_group.h b/chromium/components/autofill/core/browser/form_group.h
index 86bd4531bb1..c3d9cd14e2d 100644
--- a/chromium/components/autofill/core/browser/form_group.h
+++ b/chromium/components/autofill/core/browser/form_group.h
@@ -53,6 +53,10 @@ class FormGroup {
const base::string16& value,
const std::string& app_locale);
+ // Returns true iff the string associated with |type| is nonempty.
+ bool HasInfo(ServerFieldType type) const;
+ bool HasInfo(const AutofillType& type) const;
+
protected:
// AutofillProfile needs to call into GetSupportedTypes() for objects of
// non-AutofillProfile type, for which mere inheritance is insufficient.
diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc
index addf89f686b..9bff7e2f0bc 100644
--- a/chromium/components/autofill/core/browser/form_structure.cc
+++ b/chromium/components/autofill/core/browser/form_structure.cc
@@ -9,6 +9,7 @@
#include <algorithm>
#include <map>
#include <utility>
+#include <vector>
#include "base/command_line.h"
#include "base/i18n/case_conversion.h"
@@ -27,6 +28,7 @@
#include "components/autofill/core/browser/field_candidates.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_field.h"
+#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/form_data.h"
@@ -36,6 +38,7 @@
#include "components/autofill/core/common/signatures_util.h"
#include "components/rappor/public/rappor_utils.h"
#include "components/rappor/rappor_service_impl.h"
+#include "components/ukm/ukm_service.h"
namespace autofill {
namespace {
@@ -268,6 +271,9 @@ HtmlFieldType FieldTypeFromAutocompleteAttributeValue(
if (autocomplete_attribute_value == "email")
return HTML_TYPE_EMAIL;
+ if (autocomplete_attribute_value == "upi-vpa")
+ return HTML_TYPE_UPI_VPA;
+
return HTML_TYPE_UNRECOGNIZED;
}
@@ -300,11 +306,13 @@ FormStructure::FormStructure(const FormData& form)
upload_required_(USE_UPLOAD_RATES),
has_author_specified_types_(false),
has_author_specified_sections_(false),
+ has_author_specified_upi_vpa_hint_(false),
was_parsed_for_autocomplete_attributes_(false),
has_password_field_(false),
is_form_tag_(form.is_form_tag),
is_formless_checkout_(form.is_formless_checkout),
- all_fields_are_passwords_(true) {
+ all_fields_are_passwords_(true),
+ is_signin_upload_(false) {
// Copy the form fields.
std::map<base::string16, size_t> unique_names;
for (const FormFieldData& field : form.fields) {
@@ -332,7 +340,7 @@ FormStructure::FormStructure(const FormData& form)
FormStructure::~FormStructure() {}
-void FormStructure::DetermineHeuristicTypes() {
+void FormStructure::DetermineHeuristicTypes(ukm::UkmService* ukm_service) {
const auto determine_heuristic_types_start_time = base::TimeTicks::Now();
// First, try to detect field types based on each field's |autocomplete|
@@ -357,15 +365,25 @@ void FormStructure::DetermineHeuristicTypes() {
UpdateAutofillCount();
IdentifySections(has_author_specified_sections_);
+ std::vector<AutofillMetrics::DeveloperEngagementMetric> metrics;
if (IsAutofillable()) {
+ AutofillMetrics::DeveloperEngagementMetric metric =
+ has_author_specified_types_
+ ? AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS
+ : AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS;
+ metrics.push_back(metric);
+ AutofillMetrics::LogDeveloperEngagementMetric(metric);
+ }
+
+ if (has_author_specified_upi_vpa_hint_) {
AutofillMetrics::LogDeveloperEngagementMetric(
- AutofillMetrics::FILLABLE_FORM_PARSED);
- if (has_author_specified_types_) {
- AutofillMetrics::LogDeveloperEngagementMetric(
- AutofillMetrics::FILLABLE_FORM_CONTAINS_TYPE_HINTS);
- }
+ AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT);
+ metrics.push_back(AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT);
}
+ AutofillMetrics::LogDeveloperEngagementUkm(ukm_service, source_url(),
+ metrics);
+
AutofillMetrics::LogDetermineHeuristicTypesTiming(
base::TimeTicks::Now() - determine_heuristic_types_start_time);
}
@@ -600,7 +618,7 @@ bool FormStructure::ShouldBeParsed() const {
if (active_field_count() < kRequiredFieldsForPredictionRoutines &&
(!all_fields_are_passwords() ||
active_field_count() < kRequiredFieldsForFormsWithOnlyPasswordFields) &&
- !has_author_specified_types_) {
+ !is_signin_upload_ && !has_author_specified_types_) {
return false;
}
@@ -624,17 +642,16 @@ bool FormStructure::ShouldBeCrowdsourced() const {
ShouldBeParsed();
}
-void FormStructure::UpdateFromCache(const FormStructure& cached_form) {
+void FormStructure::UpdateFromCache(const FormStructure& cached_form,
+ const bool apply_is_autofilled) {
// Map from field signatures to cached fields.
- std::map<std::string, const AutofillField*> cached_fields;
+ std::map<base::string16, const AutofillField*> cached_fields;
for (size_t i = 0; i < cached_form.field_count(); ++i) {
auto* const field = cached_form.field(i);
- cached_fields[field->FieldSignatureAsStr()] = field;
+ cached_fields[field->unique_name()] = field;
}
-
for (auto& field : *this) {
- std::map<std::string, const AutofillField*>::const_iterator cached_field =
- cached_fields.find(field->FieldSignatureAsStr());
+ const auto& cached_field = cached_fields.find(field->unique_name());
if (cached_field != cached_fields.end()) {
if (field->form_control_type != "select-one" &&
field->value == cached_field->second->value) {
@@ -649,6 +666,9 @@ void FormStructure::UpdateFromCache(const FormStructure& cached_form) {
field->set_server_type(cached_field->second->server_type());
field->SetHtmlType(cached_field->second->html_type(),
cached_field->second->html_mode());
+ if (apply_is_autofilled) {
+ field->is_autofilled = cached_field->second->is_autofilled;
+ }
field->set_previously_autofilled(
cached_field->second->previously_autofilled());
field->set_section(cached_field->second->section());
@@ -662,24 +682,30 @@ void FormStructure::UpdateFromCache(const FormStructure& cached_form) {
// rearranged via JavaScript between page load and form submission, so we
// copy over the |form_signature_field_names_| corresponding to the query
// request.
- DCHECK_EQ(cached_form.form_name_, form_name_);
- DCHECK_EQ(cached_form.source_url_, source_url_);
- DCHECK_EQ(cached_form.target_url_, target_url_);
form_signature_ = cached_form.form_signature_;
}
-void FormStructure::LogQualityMetrics(const base::TimeTicks& load_time,
- const base::TimeTicks& interaction_time,
- const base::TimeTicks& submission_time,
- rappor::RapporServiceImpl* rappor_service,
- bool did_show_suggestions,
- bool observed_submission) const {
+void FormStructure::LogQualityMetrics(
+ const base::TimeTicks& load_time,
+ const base::TimeTicks& interaction_time,
+ const base::TimeTicks& submission_time,
+ rappor::RapporServiceImpl* rappor_service,
+ AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger,
+ bool did_show_suggestions,
+ bool observed_submission) const {
size_t num_detected_field_types = 0;
size_t num_server_mismatches = 0;
size_t num_heuristic_mismatches = 0;
size_t num_edited_autofilled_fields = 0;
bool did_autofill_all_possible_fields = true;
bool did_autofill_some_possible_fields = false;
+
+ // Determine the correct suffix for the metric, depending on whether or
+ // not a submission was observed.
+ const AutofillMetrics::QualityMetricType metric_type =
+ observed_submission ? AutofillMetrics::TYPE_SUBMISSION
+ : AutofillMetrics::TYPE_NO_SUBMISSION;
+
for (size_t i = 0; i < field_count(); ++i) {
auto* const field = this->field(i);
@@ -689,17 +715,51 @@ void FormStructure::LogQualityMetrics(const base::TimeTicks& load_time,
if (field->form_control_type == "password")
continue;
+ if (IsUPIVirtualPaymentAddress(field->value)) {
+ AutofillMetrics::LogUserHappinessMetric(
+ AutofillMetrics::USER_DID_ENTER_UPI_VPA);
+ }
// We count fields that were autofilled but later modified, regardless of
// whether the data now in the field is recognized.
if (field->previously_autofilled())
num_edited_autofilled_fields++;
- // No further logging for empty fields nor for fields where the entered data
- // does not appear to already exist in the user's stored Autofill data.
+ // Aliases for the field types predicted by heuristics, server and overall.
+ ServerFieldType heuristic_type =
+ AutofillType(field->heuristic_type()).GetStorableType();
+ ServerFieldType server_type =
+ AutofillType(field->server_type()).GetStorableType();
+ ServerFieldType predicted_type = field->Type().GetStorableType();
+
const ServerFieldTypeSet& field_types = field->possible_types();
DCHECK(!field_types.empty());
- if (field_types.count(EMPTY_TYPE) || field_types.count(UNKNOWN_TYPE))
+
+ // If the field data is empty, or unrecognized, log whether or not autofill
+ // predicted that it would be populated with an autofillable data type.
+ bool has_empty_data = field_types.count(EMPTY_TYPE) != 0;
+ bool has_unrecognized_data = field_types.count(UNKNOWN_TYPE) != 0;
+ if (has_empty_data || has_unrecognized_data) {
+ AutofillMetrics::FieldTypeQualityMetric match_empty_or_unknown =
+ has_empty_data ? AutofillMetrics::TYPE_MATCH_EMPTY
+ : AutofillMetrics::TYPE_MATCH_UNKNOWN;
+ AutofillMetrics::FieldTypeQualityMetric mismatch_empty_or_unknown =
+ has_empty_data ? AutofillMetrics::TYPE_MISMATCH_EMPTY
+ : AutofillMetrics::TYPE_MISMATCH_UNKNOWN;
+ ServerFieldType field_type = has_empty_data ? EMPTY_TYPE : UNKNOWN_TYPE;
+ AutofillMetrics::LogHeuristicTypePrediction(
+ (heuristic_type == UNKNOWN_TYPE ? match_empty_or_unknown
+ : mismatch_empty_or_unknown),
+ field_type, metric_type);
+ AutofillMetrics::LogServerTypePrediction(
+ (server_type == NO_SERVER_DATA ? match_empty_or_unknown
+ : mismatch_empty_or_unknown),
+ field_type, metric_type);
+ AutofillMetrics::LogOverallTypePrediction(
+ (predicted_type == UNKNOWN_TYPE ? match_empty_or_unknown
+ : mismatch_empty_or_unknown),
+ field_type, metric_type);
continue;
+ }
++num_detected_field_types;
if (field->is_autofilled)
@@ -726,17 +786,7 @@ void FormStructure::LogQualityMetrics(const base::TimeTicks& load_time,
if (collapsed_field_types.size() == 1)
field_type = *collapsed_field_types.begin();
- ServerFieldType heuristic_type =
- AutofillType(field->heuristic_type()).GetStorableType();
- ServerFieldType server_type =
- AutofillType(field->server_type()).GetStorableType();
- ServerFieldType predicted_type = field->Type().GetStorableType();
-
- // Log heuristic, server, and overall type quality metrics, independently of
- // whether the field was autofilled.
- const AutofillMetrics::QualityMetricType metric_type =
- observed_submission ? AutofillMetrics::TYPE_SUBMISSION
- : AutofillMetrics::TYPE_NO_SUBMISSION;
+ // Log heuristic, server, and overall type quality metrics.
if (heuristic_type == UNKNOWN_TYPE) {
AutofillMetrics::LogHeuristicTypePrediction(AutofillMetrics::TYPE_UNKNOWN,
field_type, metric_type);
@@ -779,24 +829,20 @@ void FormStructure::LogQualityMetrics(const base::TimeTicks& load_time,
// We log "submission" and duration metrics if we are here after observing a
// submission event.
if (observed_submission) {
+ AutofillMetrics::AutofillFormSubmittedState state;
if (num_detected_field_types < kRequiredFieldsForPredictionRoutines) {
- AutofillMetrics::LogAutofillFormSubmittedState(
- AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
+ state = AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA;
} else {
if (did_autofill_all_possible_fields) {
- AutofillMetrics::LogAutofillFormSubmittedState(
- AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL);
+ state = AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL;
} else if (did_autofill_some_possible_fields) {
- AutofillMetrics::LogAutofillFormSubmittedState(
- AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME);
+ state = AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME;
} else if (!did_show_suggestions) {
- AutofillMetrics::LogAutofillFormSubmittedState(
- AutofillMetrics::
- FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS);
+ state = AutofillMetrics::
+ FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS;
} else {
- AutofillMetrics::LogAutofillFormSubmittedState(
- AutofillMetrics::
- FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS);
+ state =
+ AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS;
}
// Log some RAPPOR metrics for problematic cases.
@@ -843,6 +889,10 @@ void FormStructure::LogQualityMetrics(const base::TimeTicks& load_time,
}
}
}
+ if (form_interactions_ukm_logger->url() != source_url())
+ form_interactions_ukm_logger->UpdateSourceURL(source_url());
+ AutofillMetrics::LogAutofillFormSubmittedState(
+ state, form_interactions_ukm_logger);
}
}
@@ -888,6 +938,7 @@ void FormStructure::ParseFieldTypesFromAutocompleteAttributes() {
has_author_specified_types_ = false;
has_author_specified_sections_ = false;
+ has_author_specified_upi_vpa_hint_ = false;
for (const auto& field : fields_) {
// To prevent potential section name collisions, add a default suffix for
// other fields. Without this, 'autocomplete' attribute values
@@ -925,6 +976,11 @@ void FormStructure::ParseFieldTypesFromAutocompleteAttributes() {
tokens.pop_back();
HtmlFieldType field_type =
FieldTypeFromAutocompleteAttributeValue(field_type_token, *field);
+ if (field_type == HTML_TYPE_UPI_VPA) {
+ has_author_specified_upi_vpa_hint_ = true;
+ // TODO(crbug/702223): Flesh out support for UPI-VPA.
+ field_type = HTML_TYPE_UNRECOGNIZED;
+ }
if (field_type == HTML_TYPE_UNSPECIFIED)
continue;
diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h
index 09c4ee13b89..5365ec17fff 100644
--- a/chromium/components/autofill/core/browser/form_structure.h
+++ b/chromium/components/autofill/core/browser/form_structure.h
@@ -18,6 +18,7 @@
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/proto/server.pb.h"
@@ -37,6 +38,10 @@ namespace rappor {
class RapporServiceImpl;
}
+namespace ukm {
+class UkmService;
+}
+
namespace autofill {
struct FormData;
@@ -50,8 +55,9 @@ class FormStructure {
virtual ~FormStructure();
// Runs several heuristics against the form fields to determine their possible
- // types.
- void DetermineHeuristicTypes();
+ // types. If |ukm_service| is specified, logs UKM for the form structure
+ // corresponding to |source_url_|.
+ void DetermineHeuristicTypes(ukm::UkmService* ukm_service);
// Encodes the proto |upload| request from this FormStructure.
// In some cases, a |login_form_signature| is included as part of the upload.
@@ -116,7 +122,8 @@ class FormStructure {
bool ShouldBeCrowdsourced() const;
// Sets the field types to be those set for |cached_form|.
- void UpdateFromCache(const FormStructure& cached_form);
+ void UpdateFromCache(const FormStructure& cached_form,
+ const bool apply_is_autofilled);
// Logs quality metrics for |this|, which should be a user-submitted form.
// This method should only be called after the possible field types have been
@@ -126,12 +133,16 @@ class FormStructure {
// indicates whether this method is called as a result of observing a
// submission event (otherwise, it may be that an upload was triggered after
// a form was unfocused or a navigation occurred).
- void LogQualityMetrics(const base::TimeTicks& load_time,
- const base::TimeTicks& interaction_time,
- const base::TimeTicks& submission_time,
- rappor::RapporServiceImpl* rappor_service,
- bool did_show_suggestions,
- bool observed_submission) const;
+ // TODO(sebsg): We log more than quality metrics. Maybe rename or split
+ // function?
+ void LogQualityMetrics(
+ const base::TimeTicks& load_time,
+ const base::TimeTicks& interaction_time,
+ const base::TimeTicks& submission_time,
+ rappor::RapporServiceImpl* rappor_service,
+ AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger,
+ bool did_show_suggestions,
+ bool observed_submission) const;
// Log the quality of the heuristics and server predictions for this form
// structure, if autocomplete attributes are present on the fields (they are
@@ -201,12 +212,18 @@ class FormStructure {
const GURL& target_url() const { return target_url_; }
- bool has_author_specified_types() { return has_author_specified_types_; }
+ bool has_author_specified_types() const {
+ return has_author_specified_types_;
+ }
- bool has_author_specified_sections() {
+ bool has_author_specified_sections() const {
return has_author_specified_sections_;
}
+ bool has_author_specified_upi_vpa_hint() const {
+ return has_author_specified_upi_vpa_hint_;
+ }
+
void set_upload_required(UploadRequired required) {
upload_required_ = required;
}
@@ -214,6 +231,11 @@ class FormStructure {
bool all_fields_are_passwords() const { return all_fields_are_passwords_; }
+ bool is_signin_upload() const { return is_signin_upload_; }
+ void set_is_signin_upload(bool is_signin_upload) {
+ is_signin_upload_ = is_signin_upload;
+ }
+
FormSignature form_signature() const { return form_signature_; }
// Returns a FormData containing the data this form structure knows about.
@@ -292,6 +314,10 @@ class FormStructure {
// author, via the autocomplete attribute.
bool has_author_specified_sections_;
+ // Whether the form includes a field that explicitly sets it autocomplete
+ // type to "upi-vpa".
+ bool has_author_specified_upi_vpa_hint_;
+
// Whether the form was parsed for autocomplete attribute, thus assigning
// the real values of |has_author_specified_types_| and
// |has_author_specified_sections_|.
@@ -309,6 +335,10 @@ class FormStructure {
// True if all form fields are password fields.
bool all_fields_are_passwords_;
+ // True if the form is submitted and has 2 fields: one text and one password
+ // field.
+ bool is_signin_upload_;
+
// The unique signature for this form, composed of the target url domain,
// the form name, and the form field names in a 64-bit hash.
FormSignature form_signature_;
diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc
index c1ecb59405c..ac809717668 100644
--- a/chromium/components/autofill/core/browser/form_structure_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc
@@ -149,7 +149,7 @@ TEST_F(FormStructureTest, AutofillCount) {
// Only text and select fields that are heuristically matched are counted.
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_EQ(3U, form_structure->autofill_count());
// Add a field with should_autocomplete=false. This should not be considered a
@@ -161,7 +161,7 @@ TEST_F(FormStructureTest, AutofillCount) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_EQ(4U, form_structure->autofill_count());
}
@@ -196,7 +196,7 @@ TEST_F(FormStructureTest, IsAutofillable) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(form_structure->IsAutofillable());
// We now have three text fields, but only two auto-fillable fields.
@@ -211,7 +211,7 @@ TEST_F(FormStructureTest, IsAutofillable) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(form_structure->IsAutofillable());
// We now have three auto-fillable fields.
@@ -221,19 +221,19 @@ TEST_F(FormStructureTest, IsAutofillable) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// The target cannot include http(s)://*/search...
form.action = GURL("http://google.com/search?q=hello");
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(form_structure->IsAutofillable());
// But search can be in the URL.
form.action = GURL("http://search.com/?q=hello");
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
}
@@ -334,6 +334,19 @@ TEST_F(FormStructureTest, ShouldBeParsed) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
EXPECT_TRUE(form_structure->ShouldBeParsed());
+
+ // There are 2 fields, one of which is password, and this is an upload of
+ // a sign-in form submission, should be parsed.
+ form.fields.clear();
+ field.name = ASCIIToUTF16("username");
+ field.form_control_type = "text";
+ form.fields.push_back(field);
+ field.name = ASCIIToUTF16("pw");
+ field.form_control_type = "password";
+ form.fields.push_back(field);
+ form_structure.reset(new FormStructure(form));
+ form_structure->set_is_signin_upload(true);
+ EXPECT_TRUE(form_structure->ShouldBeParsed());
}
// Tests that ShouldBeParsed returns true for a form containing less than three
@@ -405,7 +418,7 @@ TEST_F(FormStructureTest, HeuristicsContactInfo) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -456,20 +469,29 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttribute) {
field.autocomplete_attribute = "email";
form.fields.push_back(field);
+ field.label = base::string16();
+ field.name = ASCIIToUTF16("field4");
+ field.autocomplete_attribute = "upi-vpa";
+ form.fields.push_back(field);
+
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
+ EXPECT_TRUE(form_structure->has_author_specified_types());
+ EXPECT_TRUE(form_structure->has_author_specified_upi_vpa_hint());
// Expect the correct number of fields.
- ASSERT_EQ(3U, form_structure->field_count());
+ ASSERT_EQ(4U, form_structure->field_count());
ASSERT_EQ(3U, form_structure->autofill_count());
EXPECT_EQ(HTML_TYPE_GIVEN_NAME, form_structure->field(0)->html_type());
EXPECT_EQ(HTML_TYPE_FAMILY_NAME, form_structure->field(1)->html_type());
EXPECT_EQ(HTML_TYPE_EMAIL, form_structure->field(2)->html_type());
+ EXPECT_EQ(HTML_TYPE_UNRECOGNIZED, form_structure->field(3)->html_type());
EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(0)->heuristic_type());
EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(1)->heuristic_type());
EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(2)->heuristic_type());
+ EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(3)->heuristic_type());
}
// Verify that the heuristics are not run for non checkout formless forms.
@@ -496,7 +518,7 @@ TEST_F(FormStructureTest, Heuristics_FormlessNonCheckoutForm) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -512,7 +534,7 @@ TEST_F(FormStructureTest, Heuristics_FormlessNonCheckoutForm) {
form.is_form_tag = false;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -553,7 +575,7 @@ TEST_F(FormStructureTest, StripCommonNamePrefix) {
form.fields.push_back(field);
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -593,7 +615,7 @@ TEST_F(FormStructureTest, StripCommonNamePrefix_SmallPrefix) {
form.fields.push_back(field);
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -629,7 +651,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_Minimal) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsCompleteCreditCardForm());
}
@@ -667,7 +689,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_Full) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsCompleteCreditCardForm());
}
@@ -685,7 +707,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_OnlyCCNumber) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(form_structure->IsCompleteCreditCardForm());
}
@@ -726,7 +748,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_AddressForm) {
field.name = base::string16();
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(form_structure->IsCompleteCreditCardForm());
}
@@ -756,7 +778,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributePhoneTypes) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -796,7 +818,7 @@ TEST_F(FormStructureTest,
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
EXPECT_TRUE(form_structure->ShouldBeCrowdsourced());
@@ -834,7 +856,7 @@ TEST_F(FormStructureTest,
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
EXPECT_TRUE(form_structure->ShouldBeCrowdsourced());
@@ -877,7 +899,7 @@ TEST_F(FormStructureTest,
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
EXPECT_TRUE(form_structure->ShouldBeCrowdsourced());
@@ -909,7 +931,7 @@ TEST_F(FormStructureTest,
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(form_structure->IsAutofillable());
EXPECT_FALSE(form_structure->ShouldBeCrowdsourced());
@@ -944,7 +966,7 @@ TEST_F(FormStructureTest,
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(form_structure->IsAutofillable());
EXPECT_FALSE(form_structure->ShouldBeCrowdsourced());
@@ -987,7 +1009,7 @@ TEST_F(FormStructureTest, PasswordFormShouldBeCrowdsourced) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure.ShouldBeCrowdsourced());
}
@@ -1038,7 +1060,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSections) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure.IsAutofillable());
// Expect the correct number of fields.
@@ -1083,7 +1105,7 @@ TEST_F(FormStructureTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
// Expect the correct number of fields.
ASSERT_EQ(6U, form_structure.field_count());
@@ -1112,7 +1134,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSectionsRepeated) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
// Expect the correct number of fields.
ASSERT_EQ(2U, form_structure.field_count());
@@ -1149,7 +1171,7 @@ TEST_F(FormStructureTest, HeuristicsDontOverrideAutocompleteAttributeSections) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
// Expect the correct number of fields.
ASSERT_EQ(4U, form_structure.field_count());
@@ -1213,7 +1235,7 @@ TEST_F(FormStructureTest, HeuristicsSample8) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(10U, form_structure->field_count());
ASSERT_EQ(9U, form_structure->autofill_count());
@@ -1279,7 +1301,7 @@ TEST_F(FormStructureTest, HeuristicsSample6) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(7U, form_structure->field_count());
ASSERT_EQ(6U, form_structure->autofill_count());
@@ -1344,7 +1366,7 @@ TEST_F(FormStructureTest, HeuristicsLabelsOnly) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(8U, form_structure->field_count());
ASSERT_EQ(7U, form_structure->autofill_count());
@@ -1401,7 +1423,7 @@ TEST_F(FormStructureTest, HeuristicsCreditCardInfo) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(6U, form_structure->field_count());
ASSERT_EQ(5U, form_structure->autofill_count());
@@ -1461,7 +1483,7 @@ TEST_F(FormStructureTest, HeuristicsCreditCardInfoWithUnknownCardField) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(7U, form_structure->field_count());
ASSERT_EQ(5U, form_structure->autofill_count());
@@ -1508,7 +1530,7 @@ TEST_F(FormStructureTest, ThreeAddressLines) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(4U, form_structure->field_count());
ASSERT_EQ(4U, form_structure->autofill_count());
@@ -1548,7 +1570,7 @@ TEST_F(FormStructureTest, SurplusAddressLinesIgnored) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
ASSERT_EQ(4U, form_structure->field_count());
ASSERT_EQ(3U, form_structure->autofill_count());
@@ -1591,7 +1613,7 @@ TEST_F(FormStructureTest, ThreeAddressLinesExpedia) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(4U, form_structure->field_count());
EXPECT_EQ(4U, form_structure->autofill_count());
@@ -1629,7 +1651,7 @@ TEST_F(FormStructureTest, TwoAddressLinesEbay) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(3U, form_structure->field_count());
ASSERT_EQ(3U, form_structure->autofill_count());
@@ -1662,7 +1684,7 @@ TEST_F(FormStructureTest, HeuristicsStateWithProvince) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(3U, form_structure->field_count());
ASSERT_EQ(3U, form_structure->autofill_count());
@@ -1728,7 +1750,7 @@ TEST_F(FormStructureTest, HeuristicsWithBilling) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(11U, form_structure->field_count());
ASSERT_EQ(11U, form_structure->autofill_count());
@@ -1777,7 +1799,7 @@ TEST_F(FormStructureTest, ThreePartPhoneNumber) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(4U, form_structure->field_count());
ASSERT_EQ(4U, form_structure->autofill_count());
@@ -1822,7 +1844,7 @@ TEST_F(FormStructureTest, HeuristicsInfernoCC) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -1876,7 +1898,7 @@ TEST_F(FormStructureTest, HeuristicsInferCCNames_NamesNotFirst) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -1934,7 +1956,7 @@ TEST_F(FormStructureTest, HeuristicsInferCCNames_NamesFirst) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -2117,7 +2139,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest) {
std::vector<ServerFieldTypeSet> possible_field_types;
FormData form;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.form_control_type = "text";
@@ -2293,7 +2315,7 @@ TEST_F(FormStructureTest,
std::vector<ServerFieldTypeSet> possible_field_types;
FormData form;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.label = ASCIIToUTF16("First Name");
@@ -2432,7 +2454,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithAutocomplete) {
std::vector<ServerFieldTypeSet> possible_field_types;
FormData form;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.form_control_type = "text";
@@ -2503,7 +2525,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_ObservedSubmissionFalse) {
std::vector<ServerFieldTypeSet> possible_field_types;
FormData form;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.form_control_type = "text";
@@ -2572,7 +2594,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithLabels) {
std::vector<ServerFieldTypeSet> possible_field_types;
FormData form;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.form_control_type = "text";
@@ -2709,7 +2731,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithFormName) {
// Setting the form name which we expect to see in the upload.
form.name = ASCIIToUTF16("myform");
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.form_control_type = "text";
@@ -2771,7 +2793,7 @@ TEST_F(FormStructureTest, EncodeUploadRequestPartialMetadata) {
std::vector<ServerFieldTypeSet> possible_field_types;
FormData form;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.form_control_type = "text";
@@ -2844,7 +2866,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_DisabledMetadataTrial) {
std::vector<ServerFieldTypeSet> possible_field_types;
FormData form;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.form_control_type = "text";
@@ -3772,7 +3794,7 @@ TEST_F(FormStructureTest, ParseQueryResponseAuthorDefinedTypes) {
FormStructure form_structure(form);
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
- forms.front()->DetermineHeuristicTypes();
+ forms.front()->DetermineHeuristicTypes(nullptr /* ukm_service */);
AutofillQueryResponseContents response;
response.add_field()->set_autofill_type(EMAIL_ADDRESS);
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 ee21ebaf829..68177a70329 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request.cc
+++ b/chromium/components/autofill/core/browser/payments/full_card_request.cc
@@ -16,17 +16,17 @@
namespace autofill {
namespace payments {
-FullCardRequest::FullCardRequest(AutofillClient* autofill_client,
+FullCardRequest::FullCardRequest(RiskDataLoader* risk_data_loader,
payments::PaymentsClient* payments_client,
PersonalDataManager* personal_data_manager)
- : autofill_client_(autofill_client),
+ : risk_data_loader_(risk_data_loader),
payments_client_(payments_client),
personal_data_manager_(personal_data_manager),
result_delegate_(nullptr),
ui_delegate_(nullptr),
should_unmask_card_(false),
weak_ptr_factory_(this) {
- DCHECK(autofill_client_);
+ DCHECK(risk_data_loader_);
DCHECK(payments_client_);
DCHECK(personal_data_manager_);
}
@@ -62,7 +62,7 @@ void FullCardRequest::GetFullCard(const CreditCard& card,
weak_ptr_factory_.GetWeakPtr());
if (should_unmask_card_) {
- autofill_client_->LoadRiskData(
+ risk_data_loader_->LoadRiskData(
base::Bind(&FullCardRequest::OnDidGetUnmaskRiskData,
weak_ptr_factory_.GetWeakPtr()));
}
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 263b3c88fe7..9db61fd5ad3 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request.h
+++ b/chromium/components/autofill/core/browser/payments/full_card_request.h
@@ -48,7 +48,7 @@ class FullCardRequest : public CardUnmaskDelegate {
};
// The parameters should outlive the FullCardRequest.
- FullCardRequest(AutofillClient* autofill_client,
+ FullCardRequest(RiskDataLoader* risk_data_loader,
payments::PaymentsClient* payments_client,
PersonalDataManager* personal_data_manager);
~FullCardRequest();
@@ -83,9 +83,8 @@ class FullCardRequest : public CardUnmaskDelegate {
// Resets the state of the request.
void Reset();
- // Responsible for showing the UI that prompts the user for the CVC and/or the
- // updated expiration date.
- AutofillClient* const autofill_client_;
+ // Used to fetch risk data for this request.
+ RiskDataLoader* const risk_data_loader_;
// Responsible for unmasking a masked server card.
payments::PaymentsClient* const payments_client_;
diff --git a/chromium/components/autofill/core/browser/payments/payments_client.cc b/chromium/components/autofill/core/browser/payments/payments_client.cc
index 5fbeca35005..44e85c2e8d9 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client.cc
@@ -28,6 +28,7 @@
#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_context_getter.h"
@@ -415,9 +416,44 @@ void PaymentsClient::IssueRequest(std::unique_ptr<PaymentsRequest> request,
}
void PaymentsClient::InitializeUrlFetcher() {
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("payments_sync_cards", R"(
+ semantics {
+ sender: "Payments"
+ description:
+ "This service communicates with Google Payments servers to upload "
+ "(save) or receive the user's credit card info."
+ trigger:
+ "Requests are triggered by a user action, such as selecting a "
+ "masked server card from Chromium's credit card autofill dropdown, "
+ "submitting a form which has credit card information, or accepting "
+ "the prompt to save a credit card to Payments servers."
+ data:
+ "In case of save, a protocol buffer containing relevant address "
+ "and credit card information which should be saved in Google "
+ "Payments servers, along with user credentials. In case of load, a "
+ "protocol buffer containing the id of the credit card to unmask, "
+ "an encrypted cvc value, an optional updated card expiration date, "
+ "and user credentials."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "Users can enable or disable this feature in Chromium settings by "
+ "toggling 'Credit cards and addresses using Google Payments', "
+ "under 'Advanced sync settings...'. This feature is enabled by "
+ "default."
+ chrome_policy {
+ AutoFillEnabled {
+ policy_options {mode: MANDATORY}
+ AutoFillEnabled: false
+ }
+ }
+ })");
url_fetcher_ =
net::URLFetcher::Create(0, GetRequestUrl(request_->GetRequestUrlPath()),
- net::URLFetcher::POST, this);
+ net::URLFetcher::POST, this, traffic_annotation);
data_use_measurement::DataUseUserData::AttachToFetcher(
url_fetcher_.get(), data_use_measurement::DataUseUserData::AUTOFILL);
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc
index 1ea5a2f555f..e634110a718 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager.cc
@@ -883,7 +883,11 @@ std::vector<Suggestion> PersonalDataManager::GetProfileSuggestions(
// trial group or SIZE_MAX if no limit is defined.
std::string limit_str = variations::GetVariationParamValue(
kFrecencyFieldTrialName, kFrecencyFieldTrialLimitParam);
- size_t limit = base::StringToSizeT(limit_str, &limit) ? limit : SIZE_MAX;
+ size_t limit = SIZE_MAX;
+ // Reassign SIZE_MAX to |limit| is needed after calling base::StringToSizeT,
+ // as this method can modify |limit| even if it returns false.
+ if (!base::StringToSizeT(limit_str, &limit))
+ limit = SIZE_MAX;
unique_suggestions.resize(std::min(unique_suggestions.size(), limit));
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.h b/chromium/components/autofill/core/browser/personal_data_manager.h
index a7f9808e53a..d8247d526c0 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.h
+++ b/chromium/components/autofill/core/browser/personal_data_manager.h
@@ -27,9 +27,7 @@
#include "components/keyed_service/core/keyed_service.h"
#include "components/prefs/pref_member.h"
#include "components/webdata/common/web_data_service_consumer.h"
-#if defined(OS_ANDROID)
#include "net/url_request/url_request_context_getter.h"
-#endif
class AccountTrackerService;
class Browser;
@@ -148,7 +146,7 @@ class PersonalDataManager : public KeyedService,
const std::vector<AutofillProfile*>& profiles);
// Adds |credit_card| to the web database.
- void AddCreditCard(const CreditCard& credit_card);
+ virtual void AddCreditCard(const CreditCard& credit_card);
// Updates |credit_card| which already exists in the web database. This
// can only be used on local credit cards.
@@ -274,7 +272,6 @@ class PersonalDataManager : public KeyedService,
NotifyPersonalDataChanged();
}
-#if defined(OS_ANDROID)
// Sets the URL request context getter to be used when normalizing addresses
// with libaddressinput's address validator.
void SetURLRequestContextGetter(
@@ -286,7 +283,6 @@ class PersonalDataManager : public KeyedService,
net::URLRequestContextGetter* GetURLRequestContextGetter() const {
return context_getter_.get();
}
-#endif
protected:
// Only PersonalDataManagerFactory and certain tests can create instances of
@@ -330,17 +326,19 @@ class PersonalDataManager : public KeyedService,
ConvertWalletAddressesAndUpdateWalletCards_MergedProfile);
FRIEND_TEST_ALL_PREFIXES(
PersonalDataManagerTest,
- ConvertWalletAddressesAndUpdateWalletCards_NewCard_AddressAlreadyConverted);
+ ConvertWalletAddressesAndUpdateWalletCards_NewCard_AddressAlreadyConverted); // NOLINT
FRIEND_TEST_ALL_PREFIXES(
PersonalDataManagerTest,
ConvertWalletAddressesAndUpdateWalletCards_AlreadyConverted);
FRIEND_TEST_ALL_PREFIXES(
PersonalDataManagerTest,
- ConvertWalletAddressesAndUpdateWalletCards_MultipleSimilarWalletAddresses);
+ ConvertWalletAddressesAndUpdateWalletCards_MultipleSimilarWalletAddresses); // NOLINT
friend class autofill::AutofillInteractiveTest;
friend class autofill::AutofillTest;
friend class autofill::PersonalDataManagerFactory;
friend class PersonalDataManagerTest;
+ friend class PersonalDataManagerTestBase;
+ friend class SaveImportedProfileTest;
friend class ProfileSyncServiceAutofillTest;
friend class ::RemoveAutofillTester;
friend std::default_delete<PersonalDataManager>;
@@ -600,11 +598,9 @@ class PersonalDataManager : public KeyedService,
// Whether new information was received from the sync server.
bool has_synced_new_data_ = false;
-#if defined(OS_ANDROID)
// The context for the request to be used to fetch libaddressinput's address
// validation rules.
scoped_refptr<net::URLRequestContextGetter> context_getter_;
-#endif
DISALLOW_COPY_AND_ASSIGN(PersonalDataManager);
};
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 6bb7a52b7e0..f5b2aa6d4ce 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -119,60 +119,9 @@ void ExpectSameElements(const std::vector<T*>& expectations,
} // anonymous namespace
-class PersonalDataManagerTest : public testing::Test {
+class PersonalDataManagerTestBase {
protected:
- PersonalDataManagerTest() : autofill_table_(nullptr) {}
-
- void SetUp() override {
- OSCryptMocker::SetUpWithSingleton();
- prefs_ = test::PrefServiceForTesting();
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- base::FilePath path = temp_dir_.GetPath().AppendASCII("TestWebDB");
- web_database_ =
- new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
- base::ThreadTaskRunnerHandle::Get());
-
- // Setup account tracker.
- signin_client_.reset(new TestSigninClient(prefs_.get()));
- account_tracker_.reset(new AccountTrackerService());
- account_tracker_->Initialize(signin_client_.get());
- signin_manager_.reset(new FakeSigninManagerBase(signin_client_.get(),
- account_tracker_.get()));
- signin_manager_->Initialize(prefs_.get());
-
- // Hacky: hold onto a pointer but pass ownership.
- autofill_table_ = new AutofillTable;
- web_database_->AddTable(std::unique_ptr<WebDatabaseTable>(autofill_table_));
- web_database_->LoadDatabase();
- autofill_database_service_ = new AutofillWebDataService(
- web_database_, base::ThreadTaskRunnerHandle::Get(),
- base::ThreadTaskRunnerHandle::Get(),
- WebDataServiceBase::ProfileErrorCallback());
- autofill_database_service_->Init();
-
- test::DisableSystemServices(prefs_.get());
- ResetPersonalDataManager(USER_MODE_NORMAL);
-
- // Reset the deduping pref to its default value.
- personal_data_->pref_service_->SetInteger(
- prefs::kAutofillLastVersionDeduped, 0);
- personal_data_->pref_service_->SetBoolean(
- prefs::kAutofillProfileUseDatesFixed, false);
- }
-
- void TearDown() override {
- // Order of destruction is important as AutofillManager relies on
- // PersonalDataManager to be around when it gets destroyed.
- signin_manager_->Shutdown();
- signin_manager_.reset();
-
- account_tracker_->Shutdown();
- account_tracker_.reset();
- signin_client_.reset();
-
- test::DisableSystemServices(prefs_.get());
- OSCryptMocker::TearDown();
- }
+ PersonalDataManagerTestBase() : autofill_table_(nullptr) {}
void ResetPersonalDataManager(UserMode user_mode) {
bool is_incognito = (user_mode == USER_MODE_INCOGNITO);
@@ -315,7 +264,7 @@ class PersonalDataManagerTest : public testing::Test {
const char* exp_cc_month,
const char* exp_cc_year) {
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -351,6 +300,60 @@ class PersonalDataManagerTest : public testing::Test {
variations::testing::VariationParamsManager variation_params_;
};
+class PersonalDataManagerTest : public PersonalDataManagerTestBase,
+ public testing::Test {
+ void SetUp() override {
+ OSCryptMocker::SetUpWithSingleton();
+ prefs_ = test::PrefServiceForTesting();
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ base::FilePath path = temp_dir_.GetPath().AppendASCII("TestWebDB");
+ web_database_ =
+ new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get());
+
+ // Setup account tracker.
+ signin_client_.reset(new TestSigninClient(prefs_.get()));
+ account_tracker_.reset(new AccountTrackerService());
+ account_tracker_->Initialize(signin_client_.get());
+ signin_manager_.reset(new FakeSigninManagerBase(signin_client_.get(),
+ account_tracker_.get()));
+ signin_manager_->Initialize(prefs_.get());
+
+ // Hacky: hold onto a pointer but pass ownership.
+ autofill_table_ = new AutofillTable;
+ web_database_->AddTable(std::unique_ptr<WebDatabaseTable>(autofill_table_));
+ web_database_->LoadDatabase();
+ autofill_database_service_ = new AutofillWebDataService(
+ web_database_, base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get(),
+ WebDataServiceBase::ProfileErrorCallback());
+ autofill_database_service_->Init();
+
+ test::DisableSystemServices(prefs_.get());
+ ResetPersonalDataManager(USER_MODE_NORMAL);
+
+ // Reset the deduping pref to its default value.
+ personal_data_->pref_service_->SetInteger(
+ prefs::kAutofillLastVersionDeduped, 0);
+ personal_data_->pref_service_->SetBoolean(
+ prefs::kAutofillProfileUseDatesFixed, false);
+ }
+
+ void TearDown() override {
+ // Order of destruction is important as AutofillManager relies on
+ // PersonalDataManager to be around when it gets destroyed.
+ signin_manager_->Shutdown();
+ signin_manager_.reset();
+
+ account_tracker_->Shutdown();
+ account_tracker_.reset();
+ signin_client_.reset();
+
+ test::DisableSystemServices(prefs_.get());
+ OSCryptMocker::TearDown();
+ }
+};
+
TEST_F(PersonalDataManagerTest, AddProfile) {
// Add profile0 to the database.
AutofillProfile profile0(test::GetFullProfile());
@@ -1030,7 +1033,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles) {
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Verify that the web database has been updated and the notification sent.
@@ -1068,7 +1071,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_BadEmail) {
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure));
const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
@@ -1098,7 +1101,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_TwoEmails) {
"Confirm email:", "confirm_email", "example@example.com", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
ASSERT_EQ(1U, results.size());
@@ -1127,7 +1130,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_TwoDifferentEmails) {
"Email:", "email2", "example2@example.com", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure));
const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
ASSERT_EQ(0U, results.size());
@@ -1147,7 +1150,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_NotEnoughFilledFields) {
"Card number:", "card_number", "4111 1111 1111 1111", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure));
const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
@@ -1175,7 +1178,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressUSA) {
test::CreateTestFormField("Country:", "country", "USA", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
ASSERT_EQ(1U, profiles.size());
@@ -1200,7 +1203,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressGB) {
"Country:", "country", "United Kingdom", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
ASSERT_EQ(1U, profiles.size());
@@ -1220,7 +1223,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressGI) {
test::CreateTestFormField("Country:", "country", "Gibraltar", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
ASSERT_EQ(1U, profiles.size());
@@ -1258,7 +1261,7 @@ TEST_F(PersonalDataManagerTest,
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Verify that the web database has been updated and the notification sent.
@@ -1302,7 +1305,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MultilineAddress) {
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Verify that the web database has been updated and the notification sent.
@@ -1343,7 +1346,7 @@ TEST_F(PersonalDataManagerTest,
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure1));
// Verify that the web database has been updated and the notification sent.
@@ -1381,7 +1384,7 @@ TEST_F(PersonalDataManagerTest,
form2.fields.push_back(field);
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
// Verify that the web database has been updated and the notification sent.
@@ -1442,7 +1445,7 @@ TEST_F(PersonalDataManagerTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Verify that the web database has been updated and the notification sent.
@@ -1520,7 +1523,7 @@ TEST_F(PersonalDataManagerTest,
// Still able to do the import.
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Verify that the web database has been updated and the notification sent.
@@ -1604,7 +1607,7 @@ TEST_F(PersonalDataManagerTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Verify that the web database has been updated and the notification sent.
@@ -1659,7 +1662,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_SameProfileWithConflict) {
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure1));
// Verify that the web database has been updated and the notification sent.
@@ -1707,7 +1710,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_SameProfileWithConflict) {
form2.fields.push_back(field);
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
// Verify that the web database has been updated and the notification sent.
@@ -1745,7 +1748,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInOld) {
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure1));
// Verify that the web database has been updated and the notification sent.
@@ -1783,7 +1786,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInOld) {
form2.fields.push_back(field);
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
// Verify that the web database has been updated and the notification sent.
@@ -1828,7 +1831,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInNew) {
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure1));
// Verify that the web database has been updated and the notification sent.
@@ -1867,7 +1870,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInNew) {
form2.fields.push_back(field);
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
// Verify that the web database has been updated and the notification sent.
@@ -1905,7 +1908,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_InsufficientAddress) {
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure1));
// Since no refresh is expected, reload the data from the database to make
@@ -1962,7 +1965,7 @@ TEST_F(PersonalDataManagerTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Wait for the refresh, which in this case is a no-op.
@@ -1983,7 +1986,7 @@ TEST_F(PersonalDataManagerTest,
form.fields[0] = field;
FormStructure form_structure2(form);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
// Wait for the refresh, which in this case is a no-op.
@@ -2024,7 +2027,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_UnrecognizedCountry) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure));
// Since no refresh is expected, reload the data from the database to make
@@ -2065,7 +2068,7 @@ TEST_F(PersonalDataManagerTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Verify that the web database has been updated and the notification sent.
@@ -2114,7 +2117,7 @@ TEST_F(PersonalDataManagerTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure));
// Since no refresh is expected, reload the data from the database to make
@@ -2137,7 +2140,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_Valid) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2163,7 +2166,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_Invalid) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_FALSE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
@@ -2197,7 +2200,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_MonthSelectInvalidText) {
form.fields[2].option_contents = contents;
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2224,7 +2227,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_TwoValidCards) {
"2999");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2247,7 +2250,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_TwoValidCards) {
AddFullCreditCardForm(&form2, "", "5500 0000 0000 0004", "02", "2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(ImportCreditCard(form_structure2, false, &imported_credit_card2));
ASSERT_TRUE(imported_credit_card2);
@@ -2362,7 +2365,7 @@ TEST_F(PersonalDataManagerTest,
// The card should be offered to be saved locally because it only matches the
// masked server card.
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2392,7 +2395,7 @@ TEST_F(PersonalDataManagerTest,
// The card should not be offered to be saved locally because it only matches
// the full server card.
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_FALSE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
@@ -2405,7 +2408,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_SameCreditCardWithConflict) {
"2998");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2430,7 +2433,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_SameCreditCardWithConflict) {
/* different year */ "2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(ImportCreditCard(form_structure2, false, &imported_credit_card2));
EXPECT_FALSE(imported_credit_card2);
@@ -2457,7 +2460,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_ShouldReturnLocalCard) {
"2998");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2482,7 +2485,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_ShouldReturnLocalCard) {
/* different year */ "2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(ImportCreditCard(form_structure2,
/* should_return_local_card= */ true,
@@ -2512,7 +2515,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_EmptyCardWithConflict) {
"2998");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2536,7 +2539,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_EmptyCardWithConflict) {
"2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_FALSE(
ImportCreditCard(form_structure2, false, &imported_credit_card2));
@@ -2562,7 +2565,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_MissingInfoInNew) {
"2999");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2587,7 +2590,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_MissingInfoInNew) {
"4111-1111-1111-1111", "01", "2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(ImportCreditCard(form_structure2, false, &imported_credit_card2));
EXPECT_FALSE(imported_credit_card2);
@@ -2611,7 +2614,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_MissingInfoInNew) {
/* no year */ nullptr);
FormStructure form_structure3(form3);
- form_structure3.DetermineHeuristicTypes();
+ form_structure3.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card3;
EXPECT_FALSE(
ImportCreditCard(form_structure3, false, &imported_credit_card3));
@@ -2654,7 +2657,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_MissingInfoInOld) {
/* different year */ "2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
EXPECT_FALSE(imported_credit_card);
@@ -2699,7 +2702,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_SameCardWithSeparators) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
EXPECT_FALSE(imported_credit_card);
@@ -2738,7 +2741,7 @@ TEST_F(PersonalDataManagerTest,
/* different year */ "2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
@@ -2785,7 +2788,7 @@ TEST_F(PersonalDataManagerTest, ImportFormData_OneAddressOneCreditCard) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(personal_data_->ImportFormData(form_structure, false,
&imported_credit_card));
@@ -2863,7 +2866,7 @@ TEST_F(PersonalDataManagerTest, ImportFormData_TwoAddressesOneCreditCard) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
// Still returns true because the credit card import was successful.
EXPECT_TRUE(personal_data_->ImportFormData(form_structure, false,
@@ -4139,7 +4142,7 @@ TEST_F(PersonalDataManagerTest, DontDuplicateServerCard) {
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_FALSE(personal_data_->ImportFormData(form_structure1, false,
&imported_credit_card));
@@ -4161,7 +4164,7 @@ TEST_F(PersonalDataManagerTest, DontDuplicateServerCard) {
form2.fields.push_back(field);
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_FALSE(personal_data_->ImportFormData(form_structure2, false,
&imported_credit_card2));
@@ -4170,10 +4173,9 @@ TEST_F(PersonalDataManagerTest, DontDuplicateServerCard) {
// Tests the SaveImportedProfile method with different profiles to make sure the
// merge logic works correctly.
-TEST_F(PersonalDataManagerTest, SaveImportedProfile) {
- typedef struct {
- autofill::ServerFieldType field_type;
- std::string field_value;
+typedef struct {
+ autofill::ServerFieldType field_type;
+ std::string field_value;
} ProfileField;
typedef std::vector<ProfileField> ProfileFields;
@@ -4188,254 +4190,72 @@ TEST_F(PersonalDataManagerTest, SaveImportedProfile) {
// For tests with profile merging, makes sure that these fields' values are
// the ones we expect (depending on the test).
ProfileFields changed_field_values;
- } TestCase;
-
- TestCase test_cases[] = {
- // Test that saving an identical profile except for the name results in
- // two profiles being saved.
- {ProfileFields(), {{NAME_FIRST, "Marionette"}}},
-
- // Test that saving an identical profile except with the middle name
- // initial instead of the full middle name results in the profiles
- // getting merged and the full middle name being kept.
- {ProfileFields(),
- {{NAME_MIDDLE, "M"}},
- {{NAME_MIDDLE, "Mitchell"}, {NAME_FULL, "Marion Mitchell Morrison"}}},
-
- // Test that saving an identical profile except with the full middle name
- // instead of the middle name initial results in the profiles getting
- // merged and the full middle name replacing the initial.
- {{{NAME_MIDDLE, "M"}},
- {{NAME_MIDDLE, "Mitchell"}},
- {{NAME_MIDDLE, "Mitchell"}}},
-
- // Test that saving an identical profile except with no middle name
- // results in the profiles getting merged and the full middle name being
- // kept.
- {ProfileFields(), {{NAME_MIDDLE, ""}}, {{NAME_MIDDLE, "Mitchell"}}},
-
- // Test that saving an identical profile except with a middle name initial
- // results in the profiles getting merged and the middle name initial
- // being saved.
- {{{NAME_MIDDLE, ""}}, {{NAME_MIDDLE, "M"}}, {{NAME_MIDDLE, "M"}}},
-
- // Test that saving an identical profile except with a middle name
- // results in the profiles getting merged and the full middle name being
- // saved.
- {{{NAME_MIDDLE, ""}},
- {{NAME_MIDDLE, "Mitchell"}},
- {{NAME_MIDDLE, "Mitchell"}}},
-
- // Test that saving a identical profile except with the full name set
- // instead of the name parts results in the two profiles being merged and
- // all the name parts kept and the full name being added.
- {
- {
- {NAME_FIRST, "Marion"},
- {NAME_MIDDLE, "Mitchell"},
- {NAME_LAST, "Morrison"},
- {NAME_FULL, ""},
- },
- {
- {NAME_FIRST, ""},
- {NAME_MIDDLE, ""},
- {NAME_LAST, ""},
- {NAME_FULL, "Marion Mitchell Morrison"},
- },
- {
- {NAME_FIRST, "Marion"},
- {NAME_MIDDLE, "Mitchell"},
- {NAME_LAST, "Morrison"},
- {NAME_FULL, "Marion Mitchell Morrison"},
- },
- },
-
- // Test that saving a identical profile except with the name parts set
- // instead of the full name results in the two profiles being merged and
- // the full name being kept and all the name parts being added.
- {
- {
- {NAME_FIRST, ""},
- {NAME_MIDDLE, ""},
- {NAME_LAST, ""},
- {NAME_FULL, "Marion Mitchell Morrison"},
- },
- {
- {NAME_FIRST, "Marion"},
- {NAME_MIDDLE, "Mitchell"},
- {NAME_LAST, "Morrison"},
- {NAME_FULL, ""},
- },
- {
- {NAME_FIRST, "Marion"},
- {NAME_MIDDLE, "Mitchell"},
- {NAME_LAST, "Morrison"},
- {NAME_FULL, "Marion Mitchell Morrison"},
- },
- },
-
- // Test that saving a profile that has only a full name set does not get
- // merged with a profile with only the name parts set if the names are
- // different.
- {
- {
- {NAME_FIRST, "Marion"},
- {NAME_MIDDLE, "Mitchell"},
- {NAME_LAST, "Morrison"},
- {NAME_FULL, ""},
- },
- {
- {NAME_FIRST, ""},
- {NAME_MIDDLE, ""},
- {NAME_LAST, ""},
- {NAME_FULL, "John Thompson Smith"},
- },
- },
-
- // Test that saving a profile that has only the name parts set does not
- // get merged with a profile with only the full name set if the names are
- // different.
- {
- {
- {NAME_FIRST, ""},
- {NAME_MIDDLE, ""},
- {NAME_LAST, ""},
- {NAME_FULL, "John Thompson Smith"},
- },
- {
- {NAME_FIRST, "Marion"},
- {NAME_MIDDLE, "Mitchell"},
- {NAME_LAST, "Morrison"},
- {NAME_FULL, ""},
- },
- },
-
- // Test that saving an identical profile except for the first address line
- // results in two profiles being saved.
- {ProfileFields(), {{ADDRESS_HOME_LINE1, "123 Aquarium St."}}},
-
- // Test that saving an identical profile except for the second address
- // line results in two profiles being saved.
- {ProfileFields(), {{ADDRESS_HOME_LINE2, "unit 7"}}},
-
- // Tests that saving an identical profile that has a new piece of
- // information (company name) results in a merge and that the original
- // empty value gets overwritten by the new information.
- {{{COMPANY_NAME, ""}}, ProfileFields(), {{COMPANY_NAME, "Fox"}}},
-
- // Tests that saving an identical profile except a loss of information
- // results in a merge but the original value is not overwritten (no
- // information loss).
- {ProfileFields(), {{COMPANY_NAME, ""}}, {{COMPANY_NAME, "Fox"}}},
-
- // Tests that saving an identical profile except a slightly different
- // postal code results in a merge with the new value kept.
- {{{ADDRESS_HOME_ZIP, "R2C 0A1"}},
- {{ADDRESS_HOME_ZIP, "R2C0A1"}},
- {{ADDRESS_HOME_ZIP, "R2C0A1"}}},
- {{{ADDRESS_HOME_ZIP, "R2C0A1"}},
- {{ADDRESS_HOME_ZIP, "R2C 0A1"}},
- {{ADDRESS_HOME_ZIP, "R2C 0A1"}}},
- {{{ADDRESS_HOME_ZIP, "r2c 0a1"}},
- {{ADDRESS_HOME_ZIP, "R2C0A1"}},
- {{ADDRESS_HOME_ZIP, "R2C0A1"}}},
-
- // Tests that saving an identical profile plus a new piece of information
- // on the address line 2 results in a merge and that the original empty
- // value gets overwritten by the new information.
- {{{ADDRESS_HOME_LINE2, ""}},
- ProfileFields(),
- {{ADDRESS_HOME_LINE2, "unit 5"}}},
-
- // Tests that saving an identical profile except a loss of information on
- // the address line 2 results in a merge but that the original value gets
- // not overwritten (no information loss).
- {ProfileFields(),
- {{ADDRESS_HOME_LINE2, ""}},
- {{ADDRESS_HOME_LINE2, "unit 5"}}},
-
- // Tests that saving an identical except with more punctuation in the fist
- // address line, while the second is empty, results in a merge and that
- // the original address gets overwritten.
- {{{ADDRESS_HOME_LINE2, ""}},
- {{ADDRESS_HOME_LINE2, ""}, {ADDRESS_HOME_LINE1, "123, Zoo St."}},
- {{ADDRESS_HOME_LINE1, "123, Zoo St."}}},
-
- // Tests that saving an identical profile except with less punctuation in
- // the fist address line, while the second is empty, results in a merge
- // and that the longer address is retained.
- {{{ADDRESS_HOME_LINE2, ""}, {ADDRESS_HOME_LINE1, "123, Zoo St."}},
- {{ADDRESS_HOME_LINE2, ""}},
- {{ADDRESS_HOME_LINE1, "123 Zoo St"}}},
-
- // Tests that saving an identical profile except additional punctuation in
- // the two address lines results in a merge and that the newer address
- // is retained.
- {ProfileFields(),
- {{ADDRESS_HOME_LINE1, "123, Zoo St."}, {ADDRESS_HOME_LINE2, "unit. 5"}},
- {{ADDRESS_HOME_LINE1, "123, Zoo St."}, {ADDRESS_HOME_LINE2, "unit. 5"}}},
-
- // Tests that saving an identical profile except less punctuation in the
- // two address lines results in a merge and that the newer address is
- // retained.
- {{{ADDRESS_HOME_LINE1, "123, Zoo St."}, {ADDRESS_HOME_LINE2, "unit. 5"}},
- ProfileFields(),
- {{ADDRESS_HOME_LINE1, "123 Zoo St"}, {ADDRESS_HOME_LINE2, "unit 5"}}},
-
- // Tests that saving an identical profile with accented characters in
- // the two address lines results in a merge and that the newer address
- // is retained.
- {ProfileFields(),
- {{ADDRESS_HOME_LINE1, "123 Zôö St"}, {ADDRESS_HOME_LINE2, "üñìt 5"}},
- {{ADDRESS_HOME_LINE1, "123 Zôö St"}, {ADDRESS_HOME_LINE2, "üñìt 5"}}},
-
- // Tests that saving an identical profile without accented characters in
- // the two address lines results in a merge and that the newer address
- // is retained.
- {{{ADDRESS_HOME_LINE1, "123 Zôö St"}, {ADDRESS_HOME_LINE2, "üñìt 5"}},
- ProfileFields(),
- {{ADDRESS_HOME_LINE1, "123 Zoo St"}, {ADDRESS_HOME_LINE2, "unit 5"}}},
-
- // Tests that saving an identical profile except that the address line 1
- // is in the address line 2 results in a merge and that the multi-lne
- // address is retained.
- {ProfileFields(),
- {{ADDRESS_HOME_LINE1, "123 Zoo St, unit 5"}, {ADDRESS_HOME_LINE2, ""}},
- {{ADDRESS_HOME_LINE1, "123 Zoo St"}, {ADDRESS_HOME_LINE2, "unit 5"}}},
-
- // Tests that saving an identical profile except that the address line 2
- // contains part of the old address line 1 results in a merge and that the
- // original address lines of the reference profile get overwritten.
- {{{ADDRESS_HOME_LINE1, "123 Zoo St, unit 5"}, {ADDRESS_HOME_LINE2, ""}},
- ProfileFields(),
- {{ADDRESS_HOME_LINE1, "123 Zoo St"}, {ADDRESS_HOME_LINE2, "unit 5"}}},
-
- // Tests that saving an identical profile except that the state is the
- // abbreviation instead of the full form results in a merge and that the
- // original state gets overwritten.
- {{{ADDRESS_HOME_STATE, "California"}},
- ProfileFields(),
- {{ADDRESS_HOME_STATE, "CA"}}},
-
- // Tests that saving an identical profile except that the state is the
- // full form instead of the abbreviation results in a merge and that the
- // abbreviated state is retained.
- {ProfileFields(),
- {{ADDRESS_HOME_STATE, "California"}},
- {{ADDRESS_HOME_STATE, "CA"}}},
-
- // Tests that saving and identical profile except that the company name
- // has different punctuation and case results in a merge and that the
- // syntax of the new profile replaces the old one.
- {{{COMPANY_NAME, "Stark inc"}},
- {{COMPANY_NAME, "Stark Inc."}},
- {{COMPANY_NAME, "Stark Inc."}}},
- };
+ } SaveImportedProfileTestCase;
+
+ class SaveImportedProfileTest
+ : public PersonalDataManagerTestBase,
+ public testing::TestWithParam<SaveImportedProfileTestCase> {
+ public:
+ SaveImportedProfileTest() {}
+ ~SaveImportedProfileTest() override {}
+
+ void SetUp() override {
+ OSCryptMocker::SetUpWithSingleton();
+ prefs_ = test::PrefServiceForTesting();
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ base::FilePath path = temp_dir_.GetPath().AppendASCII("TestWebDB");
+ web_database_ =
+ new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get());
+
+ // Setup account tracker.
+ signin_client_.reset(new TestSigninClient(prefs_.get()));
+ account_tracker_.reset(new AccountTrackerService());
+ account_tracker_->Initialize(signin_client_.get());
+ signin_manager_.reset(new FakeSigninManagerBase(signin_client_.get(),
+ account_tracker_.get()));
+ signin_manager_->Initialize(prefs_.get());
+
+ // Hacky: hold onto a pointer but pass ownership.
+ autofill_table_ = new AutofillTable;
+ web_database_->AddTable(
+ std::unique_ptr<WebDatabaseTable>(autofill_table_));
+ web_database_->LoadDatabase();
+ autofill_database_service_ = new AutofillWebDataService(
+ web_database_, base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get(),
+ WebDataServiceBase::ProfileErrorCallback());
+ autofill_database_service_->Init();
+
+ test::DisableSystemServices(prefs_.get());
+ ResetPersonalDataManager(USER_MODE_NORMAL);
+
+ // Reset the deduping pref to its default value.
+ personal_data_->pref_service_->SetInteger(
+ prefs::kAutofillLastVersionDeduped, 0);
+ personal_data_->pref_service_->SetBoolean(
+ prefs::kAutofillProfileUseDatesFixed, false);
+ }
- // Create the test clock.
- TestAutofillClock test_clock;
+ void TearDown() override {
+ // Order of destruction is important as AutofillManager relies on
+ // PersonalDataManager to be around when it gets destroyed.
+ signin_manager_->Shutdown();
+ signin_manager_.reset();
+
+ account_tracker_->Shutdown();
+ account_tracker_.reset();
+ signin_client_.reset();
+
+ test::DisableSystemServices(prefs_.get());
+ OSCryptMocker::TearDown();
+ }
+ };
- for (TestCase test_case : test_cases) {
+ TEST_P(SaveImportedProfileTest, SaveImportedProfile) {
+ // Create the test clock.
+ TestAutofillClock test_clock;
+ auto test_case = GetParam();
// Set the time to a specific value.
test_clock.SetNow(kArbitraryTime);
@@ -4490,45 +4310,322 @@ TEST_F(PersonalDataManagerTest, SaveImportedProfile) {
// Erase the profiles for the next test.
ResetProfiles();
}
-}
-
-// Tests that MergeProfile tries to merge the imported profile into the
-// existing profile in decreasing order of frecency.
-TEST_F(PersonalDataManagerTest, MergeProfile_Frecency) {
- // Create two very similar profiles except with different company names.
- std::unique_ptr<AutofillProfile> profile1 = base::MakeUnique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com");
- test::SetProfileInfo(profile1.get(), "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "SNP", "742 Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "12345678910");
- AutofillProfile* profile2 =
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
- test::SetProfileInfo(profile2, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "12345678910");
- // Give the "Fox" profile a bigger frecency score.
- profile2->set_use_count(15);
+ INSTANTIATE_TEST_CASE_P(
+ PersonalDataManagerTest,
+ SaveImportedProfileTest,
+ testing::Values(
+ // Test that saving an identical profile except for the name results
+ // in two profiles being saved.
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{NAME_FIRST, "Marionette"}}},
+
+ // Test that saving an identical profile except with the middle name
+ // initial instead of the full middle name results in the profiles
+ // getting merged and the full middle name being kept.
+ SaveImportedProfileTestCase{
+ ProfileFields(),
+ {{NAME_MIDDLE, "M"}},
+ {{NAME_MIDDLE, "Mitchell"},
+ {NAME_FULL, "Marion Mitchell Morrison"}}},
+
+ // Test that saving an identical profile except with the full middle
+ // name instead of the middle name initial results in the profiles
+ // getting merged and the full middle name replacing the initial.
+ SaveImportedProfileTestCase{{{NAME_MIDDLE, "M"}},
+ {{NAME_MIDDLE, "Mitchell"}},
+ {{NAME_MIDDLE, "Mitchell"}}},
+
+ // Test that saving an identical profile except with no middle name
+ // results in the profiles getting merged and the full middle name
+ // being kept.
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{NAME_MIDDLE, ""}},
+ {{NAME_MIDDLE, "Mitchell"}}},
+
+ // Test that saving an identical profile except with a middle name
+ // initial results in the profiles getting merged and the middle name
+ // initial being saved.
+ SaveImportedProfileTestCase{{{NAME_MIDDLE, ""}},
+ {{NAME_MIDDLE, "M"}},
+ {{NAME_MIDDLE, "M"}}},
+
+ // Test that saving an identical profile except with a middle name
+ // results in the profiles getting merged and the full middle name
+ // being saved.
+ SaveImportedProfileTestCase{{{NAME_MIDDLE, ""}},
+ {{NAME_MIDDLE, "Mitchell"}},
+ {{NAME_MIDDLE, "Mitchell"}}},
+
+ // Test that saving a identical profile except with the full name set
+ // instead of the name parts results in the two profiles being merged
+ // and all the name parts kept and the full name being added.
+ SaveImportedProfileTestCase{
+ {
+ {NAME_FIRST, "Marion"},
+ {NAME_MIDDLE, "Mitchell"},
+ {NAME_LAST, "Morrison"},
+ {NAME_FULL, ""},
+ },
+ {
+ {NAME_FIRST, ""},
+ {NAME_MIDDLE, ""},
+ {NAME_LAST, ""},
+ {NAME_FULL, "Marion Mitchell Morrison"},
+ },
+ {
+ {NAME_FIRST, "Marion"},
+ {NAME_MIDDLE, "Mitchell"},
+ {NAME_LAST, "Morrison"},
+ {NAME_FULL, "Marion Mitchell Morrison"},
+ },
+ },
- // Create the |existing_profiles| vector.
- std::vector<std::unique_ptr<AutofillProfile>> existing_profiles;
- existing_profiles.push_back(std::move(profile1));
- existing_profiles.push_back(base::WrapUnique(profile2));
+ // Test that saving a identical profile except with the name parts set
+ // instead of the full name results in the two profiles being merged
+ // and the full name being kept and all the name parts being added.
+ SaveImportedProfileTestCase{
+ {
+ {NAME_FIRST, ""},
+ {NAME_MIDDLE, ""},
+ {NAME_LAST, ""},
+ {NAME_FULL, "Marion Mitchell Morrison"},
+ },
+ {
+ {NAME_FIRST, "Marion"},
+ {NAME_MIDDLE, "Mitchell"},
+ {NAME_LAST, "Morrison"},
+ {NAME_FULL, ""},
+ },
+ {
+ {NAME_FIRST, "Marion"},
+ {NAME_MIDDLE, "Mitchell"},
+ {NAME_LAST, "Morrison"},
+ {NAME_FULL, "Marion Mitchell Morrison"},
+ },
+ },
- // Create a new imported profile with no company name.
- AutofillProfile imported_profile(base::GenerateGUID(),
- "https://www.example.com");
- test::SetProfileInfo(&imported_profile, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
- "Springfield", "IL", "91601", "US", "12345678910");
+ // Test that saving a profile that has only a full name set does not
+ // get merged with a profile with only the name parts set if the names
+ // are different.
+ SaveImportedProfileTestCase{
+ {
+ {NAME_FIRST, "Marion"},
+ {NAME_MIDDLE, "Mitchell"},
+ {NAME_LAST, "Morrison"},
+ {NAME_FULL, ""},
+ },
+ {
+ {NAME_FIRST, ""},
+ {NAME_MIDDLE, ""},
+ {NAME_LAST, ""},
+ {NAME_FULL, "John Thompson Smith"},
+ },
+ },
- // Merge the imported profile into the existing profiles.
- std::vector<AutofillProfile> profiles;
- std::string guid = personal_data_->MergeProfile(
- imported_profile, &existing_profiles, "US-EN", &profiles);
+ // Test that saving a profile that has only the name parts set does
+ // not get merged with a profile with only the full name set if the
+ // names are different.
+ SaveImportedProfileTestCase{
+ {
+ {NAME_FIRST, ""},
+ {NAME_MIDDLE, ""},
+ {NAME_LAST, ""},
+ {NAME_FULL, "John Thompson Smith"},
+ },
+ {
+ {NAME_FIRST, "Marion"},
+ {NAME_MIDDLE, "Mitchell"},
+ {NAME_LAST, "Morrison"},
+ {NAME_FULL, ""},
+ },
+ },
- // The new profile should be merged into the "fox" profile.
- EXPECT_EQ(profile2->guid(), guid);
+ // Test that saving an identical profile except for the first address
+ // line results in two profiles being saved.
+ SaveImportedProfileTestCase{
+ ProfileFields(),
+ {{ADDRESS_HOME_LINE1, "123 Aquarium St."}}},
+
+ // Test that saving an identical profile except for the second address
+ // line results in two profiles being saved.
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{ADDRESS_HOME_LINE2, "unit 7"}}},
+
+ // Tests that saving an identical profile that has a new piece of
+ // information (company name) results in a merge and that the original
+ // empty value gets overwritten by the new information.
+ SaveImportedProfileTestCase{{{COMPANY_NAME, ""}},
+ ProfileFields(),
+ {{COMPANY_NAME, "Fox"}}},
+
+ // Tests that saving an identical profile except a loss of information
+ // results in a merge but the original value is not overwritten (no
+ // information loss).
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{COMPANY_NAME, ""}},
+ {{COMPANY_NAME, "Fox"}}},
+
+ // Tests that saving an identical profile except a slightly different
+ // postal code results in a merge with the new value kept.
+ SaveImportedProfileTestCase{{{ADDRESS_HOME_ZIP, "R2C 0A1"}},
+ {{ADDRESS_HOME_ZIP, "R2C0A1"}},
+ {{ADDRESS_HOME_ZIP, "R2C0A1"}}},
+ SaveImportedProfileTestCase{{{ADDRESS_HOME_ZIP, "R2C0A1"}},
+ {{ADDRESS_HOME_ZIP, "R2C 0A1"}},
+ {{ADDRESS_HOME_ZIP, "R2C 0A1"}}},
+ SaveImportedProfileTestCase{{{ADDRESS_HOME_ZIP, "r2c 0a1"}},
+ {{ADDRESS_HOME_ZIP, "R2C0A1"}},
+ {{ADDRESS_HOME_ZIP, "R2C0A1"}}},
+
+ // Tests that saving an identical profile plus a new piece of
+ // information on the address line 2 results in a merge and that the
+ // original empty value gets overwritten by the new information.
+ SaveImportedProfileTestCase{{{ADDRESS_HOME_LINE2, ""}},
+ ProfileFields(),
+ {{ADDRESS_HOME_LINE2, "unit 5"}}},
+
+ // Tests that saving an identical profile except a loss of information
+ // on the address line 2 results in a merge but that the original
+ // value gets not overwritten (no information loss).
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{ADDRESS_HOME_LINE2, ""}},
+ {{ADDRESS_HOME_LINE2, "unit 5"}}},
+
+ // Tests that saving an identical except with more punctuation in the
+ // fist address line, while the second is empty, results in a merge
+ // and that the original address gets overwritten.
+ SaveImportedProfileTestCase{
+ {{ADDRESS_HOME_LINE2, ""}},
+ {{ADDRESS_HOME_LINE2, ""}, {ADDRESS_HOME_LINE1, "123, Zoo St."}},
+ {{ADDRESS_HOME_LINE1, "123, Zoo St."}}},
+
+ // Tests that saving an identical profile except with less punctuation
+ // in the fist address line, while the second is empty, results in a
+ // merge and that the longer address is retained.
+ SaveImportedProfileTestCase{
+ {{ADDRESS_HOME_LINE2, ""}, {ADDRESS_HOME_LINE1, "123, Zoo St."}},
+ {{ADDRESS_HOME_LINE2, ""}},
+ {{ADDRESS_HOME_LINE1, "123 Zoo St"}}},
+
+ // Tests that saving an identical profile except additional
+ // punctuation in the two address lines results in a merge and that
+ // the newer address is retained.
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{ADDRESS_HOME_LINE1, "123, Zoo St."},
+ {ADDRESS_HOME_LINE2, "unit. 5"}},
+ {{ADDRESS_HOME_LINE1, "123, Zoo St."},
+ {ADDRESS_HOME_LINE2, "unit. 5"}}},
+
+ // Tests that saving an identical profile except less punctuation in
+ // the two address lines results in a merge and that the newer address
+ // is retained.
+ SaveImportedProfileTestCase{{{ADDRESS_HOME_LINE1, "123, Zoo St."},
+ {ADDRESS_HOME_LINE2, "unit. 5"}},
+ ProfileFields(),
+ {{ADDRESS_HOME_LINE1, "123 Zoo St"},
+ {ADDRESS_HOME_LINE2, "unit 5"}}},
+
+ // Tests that saving an identical profile with accented characters in
+ // the two address lines results in a merge and that the newer address
+ // is retained.
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{ADDRESS_HOME_LINE1, "123 Zôö St"},
+ {ADDRESS_HOME_LINE2, "üñìt 5"}},
+ {{ADDRESS_HOME_LINE1, "123 Zôö St"},
+ {ADDRESS_HOME_LINE2, "üñìt 5"}}},
+
+ // Tests that saving an identical profile without accented characters
+ // in the two address lines results in a merge and that the newer
+ // address is retained.
+ SaveImportedProfileTestCase{{{ADDRESS_HOME_LINE1, "123 Zôö St"},
+ {ADDRESS_HOME_LINE2, "üñìt 5"}},
+ ProfileFields(),
+ {{ADDRESS_HOME_LINE1, "123 Zoo St"},
+ {ADDRESS_HOME_LINE2, "unit 5"}}},
+
+ // Tests that saving an identical profile except that the address line
+ // 1 is in the address line 2 results in a merge and that the
+ // multi-lne address is retained.
+ SaveImportedProfileTestCase{
+ ProfileFields(),
+ {{ADDRESS_HOME_LINE1, "123 Zoo St, unit 5"},
+ {ADDRESS_HOME_LINE2, ""}},
+ {{ADDRESS_HOME_LINE1, "123 Zoo St"},
+ {ADDRESS_HOME_LINE2, "unit 5"}}},
+
+ // Tests that saving an identical profile except that the address line
+ // 2 contains part of the old address line 1 results in a merge and
+ // that the original address lines of the reference profile get
+ // overwritten.
+ SaveImportedProfileTestCase{
+ {{ADDRESS_HOME_LINE1, "123 Zoo St, unit 5"},
+ {ADDRESS_HOME_LINE2, ""}},
+ ProfileFields(),
+ {{ADDRESS_HOME_LINE1, "123 Zoo St"},
+ {ADDRESS_HOME_LINE2, "unit 5"}}},
+
+ // Tests that saving an identical profile except that the state is the
+ // abbreviation instead of the full form results in a merge and that
+ // the original state gets overwritten.
+ SaveImportedProfileTestCase{{{ADDRESS_HOME_STATE, "California"}},
+ ProfileFields(),
+ {{ADDRESS_HOME_STATE, "CA"}}},
+
+ // Tests that saving an identical profile except that the state is the
+ // full form instead of the abbreviation results in a merge and that
+ // the abbreviated state is retained.
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{ADDRESS_HOME_STATE, "California"}},
+ {{ADDRESS_HOME_STATE, "CA"}}},
+
+ // Tests that saving and identical profile except that the company
+ // name has different punctuation and case results in a merge and that
+ // the syntax of the new profile replaces the old one.
+ SaveImportedProfileTestCase{{{COMPANY_NAME, "Stark inc"}},
+ {{COMPANY_NAME, "Stark Inc."}},
+ {{COMPANY_NAME, "Stark Inc."}}}));
+
+ // Tests that MergeProfile tries to merge the imported profile into the
+ // existing profile in decreasing order of frecency.
+ TEST_F(PersonalDataManagerTest, MergeProfile_Frecency) {
+ // Create two very similar profiles except with different company names.
+ std::unique_ptr<AutofillProfile> profile1 =
+ base::MakeUnique<AutofillProfile>(base::GenerateGUID(),
+ "https://www.example.com");
+ test::SetProfileInfo(profile1.get(), "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "SNP",
+ "742 Evergreen Terrace", "", "Springfield", "IL",
+ "91601", "US", "12345678910");
+ AutofillProfile* profile2 =
+ new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+ test::SetProfileInfo(profile2, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "Fox",
+ "742 Evergreen Terrace", "", "Springfield", "IL",
+ "91601", "US", "12345678910");
+
+ // Give the "Fox" profile a bigger frecency score.
+ profile2->set_use_count(15);
+
+ // Create the |existing_profiles| vector.
+ std::vector<std::unique_ptr<AutofillProfile>> existing_profiles;
+ existing_profiles.push_back(std::move(profile1));
+ existing_profiles.push_back(base::WrapUnique(profile2));
+
+ // Create a new imported profile with no company name.
+ AutofillProfile imported_profile(base::GenerateGUID(),
+ "https://www.example.com");
+ test::SetProfileInfo(&imported_profile, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "", "742 Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "12345678910");
+
+ // Merge the imported profile into the existing profiles.
+ std::vector<AutofillProfile> profiles;
+ std::string guid = personal_data_->MergeProfile(
+ imported_profile, &existing_profiles, "US-EN", &profiles);
+
+ // The new profile should be merged into the "fox" profile.
+ EXPECT_EQ(profile2->guid(), guid);
}
// Tests that MergeProfile produces a merged profile with the expected usage
diff --git a/chromium/components/autofill/core/browser/phone_number_i18n_unittest.cc b/chromium/components/autofill/core/browser/phone_number_i18n_unittest.cc
index 240319e1663..17a24311876 100644
--- a/chromium/components/autofill/core/browser/phone_number_i18n_unittest.cc
+++ b/chromium/components/autofill/core/browser/phone_number_i18n_unittest.cc
@@ -46,101 +46,117 @@ TEST(PhoneNumberI18NTest, NormalizePhoneNumber) {
EXPECT_EQ(NormalizePhoneNumber(phone5, "US"), ASCIIToUTF16("6502346789"));
}
-TEST(PhoneNumberI18NTest, ParsePhoneNumber) {
- const struct test_case {
- // Expected parsing result.
- bool valid;
- // Inputs.
- std::string input;
- std::string assumed_region;
- // Further expectations.
- std::string number;
- std::string city_code;
- std::string country_code;
- std::string deduced_region;
- } test_cases[] = {
+struct ParseNumberTestCase {
+ // Expected parsing result.
+ bool valid;
+ // Inputs.
+ std::string input;
+ std::string assumed_region;
+ // Further expectations.
+ std::string number;
+ std::string city_code;
+ std::string country_code;
+ std::string deduced_region;
+};
+
+class ParseNumberTest : public testing::TestWithParam<ParseNumberTestCase> {};
+
+TEST_P(ParseNumberTest, ParsePhoneNumber) {
+ auto test_case = GetParam();
+ SCOPED_TRACE("Testing phone number " + test_case.input);
+
+ base::string16 country_code, city_code, number;
+ std::string deduced_region;
+ ::i18n::phonenumbers::PhoneNumber unused_i18n_number;
+ EXPECT_EQ(
+ test_case.valid,
+ ParsePhoneNumber(ASCIIToUTF16(test_case.input), test_case.assumed_region,
+ &country_code, &city_code, &number, &deduced_region,
+ &unused_i18n_number));
+ EXPECT_EQ(ASCIIToUTF16(test_case.number), number);
+ EXPECT_EQ(ASCIIToUTF16(test_case.city_code), city_code);
+ EXPECT_EQ(ASCIIToUTF16(test_case.country_code), country_code);
+ EXPECT_EQ(test_case.deduced_region, deduced_region);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ PhoneNumberI18NTest,
+ ParseNumberTest,
+ testing::Values(
// Test for empty string. Should give back empty strings.
- {false, "", "US"},
+ ParseNumberTestCase{false, "", "US"},
// Test for string with less than 7 digits. Should give back empty
// strings.
- {false, "1234", "US"},
+ ParseNumberTestCase{false, "1234", "US"},
// Test for string with exactly 7 digits.
// Not a valid number - starts with 1
- {false, "17134567", "US"},
+ ParseNumberTestCase{false, "17134567", "US"},
// Not a valid number - does not have area code.
- {false, "7134567", "US"},
+ ParseNumberTestCase{false, "7134567", "US"},
// Valid Canadian toll-free number.
- {true, "3101234", "US", "3101234", "", "", "CA"},
+ ParseNumberTestCase{true, "3101234", "US", "3101234", "", "", "CA"},
// Test for string with greater than 7 digits but less than 10 digits.
// Should fail parsing in US.
- {false, "123456789", "US"},
+ ParseNumberTestCase{false, "123456789", "US"},
// Test for string with greater than 7 digits but less than 10 digits
// and
// separators.
// Should fail parsing in US.
- {false, "12.345-6789", "US"},
+ ParseNumberTestCase{false, "12.345-6789", "US"},
// Test for string with exactly 10 digits.
// Should give back phone number and city code.
// This one going to fail because of the incorrect area code.
- {false, "1234567890", "US"},
+ ParseNumberTestCase{false, "1234567890", "US"},
// This one going to fail because of the incorrect number (starts with
// 1).
- {false, "6501567890", "US"},
- {true, "6504567890", "US", "4567890", "650", "", "US"},
+ ParseNumberTestCase{false, "6501567890", "US"},
+ ParseNumberTestCase{true, "6504567890", "US", "4567890", "650", "",
+ "US"},
// Test for string with exactly 10 digits and separators.
// Should give back phone number and city code.
- {true, "(650) 456-7890", "US", "4567890", "650", "", "US"},
+ ParseNumberTestCase{true, "(650) 456-7890", "US", "4567890", "650", "",
+ "US"},
// Tests for string with over 10 digits.
// 01 is incorrect prefix in the USA, and if we interpret 011 as prefix,
// the
// rest is too short for international number - the parsing should fail.
- {false, "0116504567890", "US"},
+ ParseNumberTestCase{false, "0116504567890", "US"},
// 011 is a correct "dial out" prefix in the USA - the parsing should
// succeed.
- {true, "01116504567890", "US", "4567890", "650", "1", "US"},
+ ParseNumberTestCase{true, "01116504567890", "US", "4567890", "650", "1",
+ "US"},
// 011 is a correct "dial out" prefix in the USA but the rest of the
// number
// can't parse as a US number.
- {true, "01178124567890", "US", "4567890", "812", "7", "RU"},
+ ParseNumberTestCase{true, "01178124567890", "US", "4567890", "812", "7",
+ "RU"},
// Test for string with over 10 digits with separator characters.
// Should give back phone number, city code, and country code. "011" is
// US "dial out" code, which is discarded.
- {true, "(0111) 650-456.7890", "US", "4567890", "650", "1", "US"},
+ ParseNumberTestCase{true, "(0111) 650-456.7890", "US", "4567890", "650",
+ "1", "US"},
// Now try phone from Czech republic - it has 00 dial out code, 420
// country
// code and variable length area codes.
- {true, "+420 27-89.10.112", "US", "910112", "278", "420", "CZ"},
- {false, "27-89.10.112", "US"},
- {true, "27-89.10.112", "CZ", "910112", "278", "", "CZ"},
- {false, "420 57-89.10.112", "US"},
- {true, "420 57-89.10.112", "CZ", "910112", "578", "420", "CZ"},
+ ParseNumberTestCase{true, "+420 27-89.10.112", "US", "910112", "278",
+ "420", "CZ"},
+ ParseNumberTestCase{false, "27-89.10.112", "US"},
+ ParseNumberTestCase{true, "27-89.10.112", "CZ", "910112", "278", "",
+ "CZ"},
+ ParseNumberTestCase{false, "420 57-89.10.112", "US"},
+ ParseNumberTestCase{true, "420 57-89.10.112", "CZ", "910112", "578",
+ "420", "CZ"},
// Parses vanity numbers.
- {true, "1-650-FLOWERS", "US", "3569377", "650", "1", "US"},
+ ParseNumberTestCase{true, "1-650-FLOWERS", "US", "3569377", "650", "1",
+ "US"},
// 800 is not an area code, but the destination code. In our library
// these
// codes should be treated the same as area codes.
- {true, "1-800-FLOWERS", "US", "3569377", "800", "1", "US"},
+ ParseNumberTestCase{true, "1-800-FLOWERS", "US", "3569377", "800", "1",
+ "US"},
// Don't add a country code where there was none.
- {true, "(08) 450 777 7777", "DE", "7777777", "8450", "", "DE"},
- };
-
- for (const auto& test_case : test_cases) {
- SCOPED_TRACE("Testing phone number " + test_case.input);
-
- base::string16 country_code, city_code, number;
- std::string deduced_region;
- ::i18n::phonenumbers::PhoneNumber unused_i18n_number;
- EXPECT_EQ(
- test_case.valid,
- ParsePhoneNumber(ASCIIToUTF16(test_case.input),
- test_case.assumed_region, &country_code, &city_code,
- &number, &deduced_region, &unused_i18n_number));
- EXPECT_EQ(ASCIIToUTF16(test_case.number), number);
- EXPECT_EQ(ASCIIToUTF16(test_case.city_code), city_code);
- EXPECT_EQ(ASCIIToUTF16(test_case.country_code), country_code);
- EXPECT_EQ(test_case.deduced_region, deduced_region);
- }
-}
+ ParseNumberTestCase{true, "(08) 450 777 7777", "DE", "7777777", "8450",
+ "", "DE"}));
TEST(PhoneNumberI18NTest, ConstructPhoneNumber) {
base::string16 number;
diff --git a/chromium/components/autofill/core/browser/region_combobox_model.cc b/chromium/components/autofill/core/browser/region_combobox_model.cc
new file mode 100644
index 00000000000..509bd596e31
--- /dev/null
+++ b/chromium/components/autofill/core/browser/region_combobox_model.cc
@@ -0,0 +1,117 @@
+// 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/region_combobox_model.h"
+
+#include <utility>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/strings/grit/components_strings.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/region_data.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/region_data_builder.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/combobox_model_observer.h"
+
+namespace autofill {
+
+RegionComboboxModel::RegionComboboxModel(
+ std::unique_ptr<const ::i18n::addressinput::Source> source,
+ std::unique_ptr<::i18n::addressinput::Storage> storage,
+ const std::string& app_locale,
+ const std::string& country_code)
+ : failed_to_load_data_(false),
+ pending_region_data_load_(false),
+ app_locale_(app_locale),
+ region_data_supplier_(source.release(), storage.release()) {
+ region_data_supplier_callback_.reset(::i18n::addressinput::BuildCallback(
+ this, &RegionComboboxModel::RegionDataLoaded));
+ LoadRegionData(country_code);
+}
+
+RegionComboboxModel::~RegionComboboxModel() {}
+
+int RegionComboboxModel::GetItemCount() const {
+ // The combobox view needs to always have at least one item. If the regions
+ // have not been completely loaded yet, we display a single "loading" item.
+ if (regions_.size() == 0)
+ return 1;
+ return regions_.size();
+}
+
+base::string16 RegionComboboxModel::GetItemAt(int index) {
+ DCHECK_GE(index, 0);
+ // This might happen because of the asynchonous nature of the data.
+ if (static_cast<size_t>(index) >= regions_.size())
+ return l10n_util::GetStringUTF16(IDS_AUTOFILL_LOADING_REGIONS);
+
+ if (!regions_[index].first.empty())
+ return base::UTF8ToUTF16(regions_[index].second);
+
+ // The separator item. Implemented for platforms that don't yet support
+ // IsItemSeparatorAt().
+ return base::ASCIIToUTF16("---");
+}
+
+bool RegionComboboxModel::IsItemSeparatorAt(int index) {
+ // This might happen because of the asynchonous nature of the data.
+ DCHECK_GE(index, 0);
+ if (static_cast<size_t>(index) >= regions_.size())
+ return false;
+ return regions_[index].first.empty();
+}
+
+void RegionComboboxModel::AddObserver(ui::ComboboxModelObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void RegionComboboxModel::RemoveObserver(ui::ComboboxModelObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void RegionComboboxModel::SetFailureModeForTests(bool failed_to_load_data) {
+ failed_to_load_data_ = failed_to_load_data;
+ for (auto& observer : observers_) {
+ observer.OnComboboxModelChanged(this);
+ }
+}
+
+void RegionComboboxModel::LoadRegionData(const std::string& country_code) {
+ pending_region_data_load_ = true;
+ region_data_supplier_.LoadRules(country_code,
+ *region_data_supplier_callback_.get());
+}
+
+void RegionComboboxModel::RegionDataLoaded(bool success,
+ const std::string& country_code,
+ int rule_count) {
+ pending_region_data_load_ = false;
+ if (success) {
+ std::string best_region_tree_language_tag;
+ ::i18n::addressinput::RegionDataBuilder builder(&region_data_supplier_);
+ const std::vector<const ::i18n::addressinput::RegionData*>& regions =
+ builder.Build(country_code, app_locale_, &best_region_tree_language_tag)
+ .sub_regions();
+ // Some countries expose a state field but have not region names available.
+ if (regions.size() > 0) {
+ failed_to_load_data_ = false;
+ for (auto* const region : regions) {
+ regions_.push_back(std::make_pair(region->key(), region->name()));
+ }
+ } else {
+ failed_to_load_data_ = true;
+ }
+ } else {
+ // TODO(mad): Maybe use a static list as is done for countries in
+ // components\autofill\core\browser\country_data.cc
+ failed_to_load_data_ = true;
+ }
+
+ for (auto& observer : observers_) {
+ observer.OnComboboxModelChanged(this);
+ }
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/region_combobox_model.h b/chromium/components/autofill/core/browser/region_combobox_model.h
new file mode 100644
index 00000000000..aa16bc88e5d
--- /dev/null
+++ b/chromium/components/autofill/core/browser/region_combobox_model.h
@@ -0,0 +1,88 @@
+// 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_REGION_COMBOBOX_MODEL_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_REGION_COMBOBOX_MODEL_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/preload_supplier.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h"
+#include "ui/base/models/combobox_model.h"
+
+namespace autofill {
+
+// A model for country regions (aka state/provinces) to be used to enter
+// addresses. Note that loading these regions can happen asynchronously so a
+// ui::ComboboxModelObserver should be attached to this model to be updated when
+// the regions load is completed.
+class RegionComboboxModel : public ui::ComboboxModel {
+ public:
+ // |source| and |storage| are needed to initialize the
+ // ::i18n::addressinput::PreloadSupplier, |app_locale| is needed for
+ // ::i18n::addressinput::RegionDataBuilder and |country_code| identifies which
+ // country's region to load into the model.
+ RegionComboboxModel(
+ std::unique_ptr<const ::i18n::addressinput::Source> source,
+ std::unique_ptr<::i18n::addressinput::Storage> storage,
+ const std::string& app_locale,
+ const std::string& country_code);
+ ~RegionComboboxModel() override;
+
+ bool pending_region_data_load() const { return pending_region_data_load_; }
+ bool failed_to_load_data() const { return failed_to_load_data_; }
+
+ // ui::ComboboxModel implementation:
+ int GetItemCount() const override;
+ base::string16 GetItemAt(int index) override;
+ bool IsItemSeparatorAt(int index) override;
+ void AddObserver(ui::ComboboxModelObserver* observer) override;
+ void RemoveObserver(ui::ComboboxModelObserver* observer) override;
+
+ // To allow testing failure states.
+ void SetFailureModeForTests(bool failed_to_load_data);
+
+ private:
+ // Start the potentially asynchronous process of loading region data.
+ void LoadRegionData(const std::string& country_code);
+
+ // Callback for ::i18n::addressinput::PreloadSupplier::LoadRules
+ void RegionDataLoaded(bool success, const std::string&, int rule_count);
+
+ // Whether the region data load failed or not.
+ bool failed_to_load_data_;
+
+ // Set to true during region data load, and false otherwise. Whether the load
+ // succeeded or not doesn't affect this value.
+ bool pending_region_data_load_;
+
+ // The application locale.
+ const std::string app_locale_;
+
+ // The callback to give to |region_data_supplier_| for async operations.
+ ::i18n::addressinput::scoped_ptr<
+ ::i18n::addressinput::PreloadSupplier::Callback>
+ region_data_supplier_callback_;
+
+ // A supplier of region data.
+ ::i18n::addressinput::PreloadSupplier region_data_supplier_;
+
+ // List of <code, name> pairs for ADDRESS_HOME_STATE combobox values;
+ std::vector<std::pair<std::string, std::string>> regions_;
+
+ // To be called when the data for the given country code was loaded.
+ base::ObserverList<ui::ComboboxModelObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(RegionComboboxModel);
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_REGION_COMBOBOX_MODEL_H_
diff --git a/chromium/components/autofill/core/browser/region_combobox_model_unittest.cc b/chromium/components/autofill/core/browser/region_combobox_model_unittest.cc
new file mode 100644
index 00000000000..52878f0e921
--- /dev/null
+++ b/chromium/components/autofill/core/browser/region_combobox_model_unittest.cc
@@ -0,0 +1,107 @@
+// 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/region_combobox_model.h"
+
+#include <memory>
+
+#include "base/json/json_writer.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/prefs/pref_service.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/include/libaddressinput/source.h"
+
+namespace autofill {
+
+// Strings used in more than one place and must be the same everywhere.
+const char kTestCountryCode[] = "CA";
+const char kQuebec[] = "Quebec";
+const char kOntario[] = "Ontario";
+
+class RegionComboboxModelTest : public testing::Test {
+ public:
+ RegionComboboxModelTest()
+ : pref_service_(autofill::test::PrefServiceForTesting()) {
+ manager_.SetTestingPrefService(pref_service_.get());
+ manager_.set_timezone_country_code(kTestCountryCode);
+ }
+
+ void SetupCombobox(bool source_failure) {
+ model_.reset(new RegionComboboxModel(
+ base::MakeUnique<TestSource>(source_failure),
+ base::MakeUnique<::i18n::addressinput::NullStorage>(),
+ manager_.app_locale(), kTestCountryCode));
+ }
+
+ void TearDown() override { manager_.SetTestingPrefService(nullptr); }
+
+ RegionComboboxModel* model() { return model_.get(); }
+
+ private:
+ // The source that returns the region data. Using
+ // third_party/libaddressinput/src/cpp/test/testdata_source.h wouldn't help
+ // much since it only implements the Get method overriden below anyway.
+ class TestSource : public ::i18n::addressinput::Source {
+ public:
+ explicit TestSource(bool source_failure)
+ : source_failure_(source_failure) {}
+ ~TestSource() override {}
+
+ void Get(const std::string& key,
+ const ::i18n::addressinput::Source::Callback& data_ready)
+ const override {
+ if (source_failure_) {
+ data_ready(false, key, nullptr);
+ return;
+ }
+ // Only set the fields needed to fill the combobox, since only the
+ // combobox code needs to be tested here.
+ std::string* json = new std::string("{\"data/CA\":{");
+ *json += "\"id\":\"data/CA\",";
+ *json += "\"key\":\"CA\",";
+ *json += "\"sub_keys\":\"QC~ON\"},";
+
+ *json += "\"data/CA/ON\":{";
+ *json += "\"id\":\"data/CA/ON\",";
+ *json += "\"key\":\"ON\",";
+ *json += "\"name\":\"Ontario\"},";
+
+ *json += "\"data/CA/QC\":{";
+ *json += "\"id\":\"data/CA/QC\",";
+ *json += "\"key\":\"QC\",";
+ *json += "\"name\":\"Quebec\"}}";
+ data_ready(true, key, json);
+ }
+
+ private:
+ bool source_failure_{false};
+ };
+ TestPersonalDataManager manager_;
+ std::unique_ptr<PrefService> pref_service_;
+ std::unique_ptr<RegionComboboxModel> model_;
+};
+
+// Make sure the two regions returned by the source are properly set in the
+// model.
+TEST_F(RegionComboboxModelTest, QuebecOntarioRegions) {
+ SetupCombobox(false);
+ EXPECT_EQ(2, model()->GetItemCount());
+ EXPECT_EQ(base::ASCIIToUTF16(kQuebec), model()->GetItemAt(0));
+ EXPECT_EQ(base::ASCIIToUTF16(kOntario), model()->GetItemAt(1));
+ EXPECT_FALSE(model()->failed_to_load_data());
+}
+
+// Make sure the combo box properly support source failures.
+TEST_F(RegionComboboxModelTest, FailingSource) {
+ SetupCombobox(true);
+ EXPECT_EQ(1, model()->GetItemCount());
+ EXPECT_TRUE(model()->failed_to_load_data());
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/risk_data_loader.h b/chromium/components/autofill/core/browser/risk_data_loader.h
new file mode 100644
index 00000000000..be3def3bdda
--- /dev/null
+++ b/chromium/components/autofill/core/browser/risk_data_loader.h
@@ -0,0 +1,26 @@
+// 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_RISK_DATA_LOADER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_RISK_DATA_LOADER_H_
+
+#include <string>
+
+#include "base/callback.h"
+
+namespace autofill {
+
+class RiskDataLoader {
+ public:
+ // Gathers risk data and provides it to |callback|.
+ virtual void LoadRiskData(
+ const base::Callback<void(const std::string&)>& callback) = 0;
+
+ protected:
+ virtual ~RiskDataLoader() {}
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_RISK_DATA_LOADER_H_
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.cc b/chromium/components/autofill/core/browser/test_autofill_client.cc
index 72b2da47cc1..1c67ac60f38 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_client.cc
@@ -3,6 +3,9 @@
// found in the LICENSE file.
#include "components/autofill/core/browser/test_autofill_client.h"
+#if !defined(OS_ANDROID)
+#include "components/autofill/core/browser/ui/mock_save_card_bubble_controller.h"
+#endif
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
@@ -12,6 +15,9 @@ TestAutofillClient::TestAutofillClient()
: token_service_(new FakeOAuth2TokenService()),
identity_provider_(new FakeIdentityProvider(token_service_.get())),
rappor_service_(new rappor::TestRapporServiceImpl()),
+#if !defined(OS_ANDROID)
+ save_card_bubble_controller_(new MockSaveCardBubbleController()),
+#endif
form_origin_(GURL("https://example.test")) {}
TestAutofillClient::~TestAutofillClient() {
@@ -45,6 +51,14 @@ ukm::UkmService* TestAutofillClient::GetUkmService() {
return ukm_service_test_harness_.test_ukm_service();
}
+SaveCardBubbleController* TestAutofillClient::GetSaveCardBubbleController() {
+#if defined(OS_ANDROID)
+ return nullptr;
+#else
+ return save_card_bubble_controller_.get();
+#endif
+}
+
void TestAutofillClient::ShowAutofillSettings() {
}
@@ -65,6 +79,7 @@ void TestAutofillClient::ConfirmSaveCreditCardLocally(
void TestAutofillClient::ConfirmSaveCreditCardToCloud(
const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message,
+ bool should_cvc_be_requested,
const base::Closure& callback) {
callback.Run();
}
@@ -117,9 +132,6 @@ void TestAutofillClient::DidFillOrPreviewField(
const base::string16& profile_full_name) {
}
-void TestAutofillClient::OnFirstUserGestureObserved() {
-}
-
bool TestAutofillClient::IsContextSecure() {
// Simplified secure context check for tests.
return form_origin_.SchemeIs("https");
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.h b/chromium/components/autofill/core/browser/test_autofill_client.h
index 5b25ecfabab..a140c772665 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.h
+++ b/chromium/components/autofill/core/browser/test_autofill_client.h
@@ -36,6 +36,7 @@ class TestAutofillClient : public AutofillClient {
IdentityProvider* GetIdentityProvider() override;
rappor::RapporServiceImpl* GetRapporServiceImpl() override;
ukm::UkmService* GetUkmService() override;
+ SaveCardBubbleController* GetSaveCardBubbleController() override;
void ShowAutofillSettings() override;
void ShowUnmaskPrompt(const CreditCard& card,
UnmaskCardReason reason,
@@ -46,6 +47,7 @@ class TestAutofillClient : public AutofillClient {
void ConfirmSaveCreditCardToCloud(
const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message,
+ bool should_cvc_be_requested,
const base::Closure& callback) override;
void ConfirmCreditCardFillAssist(const CreditCard& card,
const base::Closure& callback) override;
@@ -68,7 +70,6 @@ class TestAutofillClient : public AutofillClient {
const std::vector<autofill::FormStructure*>& forms) override;
void DidFillOrPreviewField(const base::string16& autofilled_value,
const base::string16& profile_full_name) override;
- void OnFirstUserGestureObserved() override;
// By default, TestAutofillClient will report that the context is
// secure. This can be adjusted by calling set_form_origin() with an
// http:// URL.
@@ -98,6 +99,9 @@ class TestAutofillClient : public AutofillClient {
std::unique_ptr<FakeIdentityProvider> identity_provider_;
std::unique_ptr<rappor::TestRapporServiceImpl> rappor_service_;
ukm::UkmServiceTestingHarness ukm_service_test_harness_;
+#if !defined(OS_ANDROID)
+ std::unique_ptr<SaveCardBubbleController> save_card_bubble_controller_;
+#endif
GURL form_origin_;
DISALLOW_COPY_AND_ASSIGN(TestAutofillClient);
diff --git a/chromium/components/autofill/core/browser/test_autofill_driver.cc b/chromium/components/autofill/core/browser/test_autofill_driver.cc
index be3bc7b3fec..51a61ce03d5 100644
--- a/chromium/components/autofill/core/browser/test_autofill_driver.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_driver.cc
@@ -17,7 +17,7 @@ TestAutofillDriver::TestAutofillDriver()
TestAutofillDriver::~TestAutofillDriver() {}
-bool TestAutofillDriver::IsOffTheRecord() const {
+bool TestAutofillDriver::IsIncognito() const {
return false;
}
diff --git a/chromium/components/autofill/core/browser/test_autofill_driver.h b/chromium/components/autofill/core/browser/test_autofill_driver.h
index 6ac0c9ccd02..c1839293b7f 100644
--- a/chromium/components/autofill/core/browser/test_autofill_driver.h
+++ b/chromium/components/autofill/core/browser/test_autofill_driver.h
@@ -25,7 +25,7 @@ class TestAutofillDriver : public AutofillDriver {
~TestAutofillDriver() override;
// AutofillDriver implementation.
- bool IsOffTheRecord() const override;
+ bool IsIncognito() const override;
// Returns the value passed in to the last call to |SetURLRequestContext()|
// or NULL if that method has never been called.
net::URLRequestContextGetter* GetURLRequestContext() override;
diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller.h b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller.h
index 98a4fa59d93..6e63936060c 100644
--- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller.h
+++ b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller.h
@@ -37,6 +37,7 @@ class CardUnmaskPromptController {
virtual bool InputCvcIsValid(const base::string16& input_text) const = 0;
virtual bool InputExpirationIsValid(const base::string16& month,
const base::string16& year) const = 0;
+ virtual int GetExpectedCvcLength() const = 0;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc
index 38778caf3bd..00c26f4c732 100644
--- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc
+++ b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc
@@ -309,6 +309,10 @@ bool CardUnmaskPromptControllerImpl::InputExpirationIsValid(
AutofillClock::Now());
}
+int CardUnmaskPromptControllerImpl::GetExpectedCvcLength() const {
+ return GetCvcLengthForCardType(card_.type());
+}
+
base::TimeDelta CardUnmaskPromptControllerImpl::GetSuccessMessageDuration()
const {
return base::TimeDelta::FromMilliseconds(
diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h
index e6b6af6dc44..f2717397cfd 100644
--- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h
+++ b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h
@@ -52,11 +52,13 @@ class CardUnmaskPromptControllerImpl : public CardUnmaskPromptController {
bool InputCvcIsValid(const base::string16& input_text) const override;
bool InputExpirationIsValid(const base::string16& month,
const base::string16& year) const override;
+ int GetExpectedCvcLength() const override;
base::TimeDelta GetSuccessMessageDuration() const override;
protected:
// Exposed for testing.
CardUnmaskPromptView* view() { return card_unmask_view_; }
+ void SetCreditCardForTesting(CreditCard test_card) { card_ = test_card; }
private:
bool AllowsRetry(AutofillClient::PaymentsRpcResult result);
diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc
index 7a6ff9f04fc..703b6404fa4 100644
--- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc
@@ -15,6 +15,7 @@
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/credit_card.h"
#include "components/autofill/core/browser/ui/card_unmask_prompt_view.h"
#include "components/autofill/core/common/autofill_pref_names.h"
#include "components/prefs/pref_registry_simple.h"
@@ -71,6 +72,10 @@ class TestCardUnmaskPromptController : public CardUnmaskPromptControllerImpl {
void set_can_store_locally(bool can) { can_store_locally_ = can; }
+ void SetCreditCardForTesting(CreditCard card) {
+ CardUnmaskPromptControllerImpl::SetCreditCardForTesting(card);
+ }
+
base::WeakPtr<TestCardUnmaskPromptController> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
@@ -82,19 +87,9 @@ class TestCardUnmaskPromptController : public CardUnmaskPromptControllerImpl {
DISALLOW_COPY_AND_ASSIGN(TestCardUnmaskPromptController);
};
-class CardUnmaskPromptControllerImplTest : public testing::Test {
+class CardUnmaskPromptControllerImplGenericTest {
public:
- CardUnmaskPromptControllerImplTest() {}
- ~CardUnmaskPromptControllerImplTest() override {}
-
- void SetUp() override {
- test_unmask_prompt_view_.reset(new TestCardUnmaskPromptView());
- pref_service_.reset(new TestingPrefServiceSimple());
- controller_.reset(new TestCardUnmaskPromptController(pref_service_.get()));
- delegate_.reset(new TestCardUnmaskDelegate());
- pref_service_->registry()->RegisterBooleanPref(
- prefs::kAutofillWalletImportStorageCheckboxState, false);
- }
+ CardUnmaskPromptControllerImplGenericTest() {}
void ShowPrompt() {
controller_->ShowPrompt(test_unmask_prompt_view_.get(),
@@ -134,6 +129,26 @@ class CardUnmaskPromptControllerImplTest : public testing::Test {
std::unique_ptr<TestCardUnmaskDelegate> delegate_;
private:
+ DISALLOW_COPY_AND_ASSIGN(CardUnmaskPromptControllerImplGenericTest);
+};
+
+class CardUnmaskPromptControllerImplTest
+ : public CardUnmaskPromptControllerImplGenericTest,
+ public testing::Test {
+ public:
+ CardUnmaskPromptControllerImplTest() {}
+ ~CardUnmaskPromptControllerImplTest() override {}
+
+ void SetUp() override {
+ test_unmask_prompt_view_.reset(new TestCardUnmaskPromptView());
+ pref_service_.reset(new TestingPrefServiceSimple());
+ controller_.reset(new TestCardUnmaskPromptController(pref_service_.get()));
+ delegate_.reset(new TestCardUnmaskDelegate());
+ pref_service_->registry()->RegisterBooleanPref(
+ prefs::kAutofillWalletImportStorageCheckboxState, false);
+ }
+
+ private:
DISALLOW_COPY_AND_ASSIGN(CardUnmaskPromptControllerImplTest);
};
@@ -433,80 +448,138 @@ TEST_F(CardUnmaskPromptControllerImplTest,
"Autofill.UnmaskPrompt.UnmaskingDuration.Failure", 1);
}
-TEST_F(CardUnmaskPromptControllerImplTest, CvcInputValidation) {
- struct CvcCase {
- const char* input;
- bool valid;
- // null when |valid| is false.
- const char* canonicalized_input;
- };
- CvcCase cvc_cases[] = {
- { "123", true, "123" },
- { "123 ", true, "123" },
- { " 1234 ", false },
- { "IOU", false },
- };
+struct CvcCase {
+ const char* input;
+ bool valid;
+ // null when |valid| is false.
+ const char* canonicalized_input;
+};
- ShowPrompt();
+class CvcInputValidationTest : public CardUnmaskPromptControllerImplGenericTest,
+ public testing::TestWithParam<CvcCase> {
+ public:
+ CvcInputValidationTest() {}
+ ~CvcInputValidationTest() override {}
- for (const CvcCase& cvc_case : cvc_cases) {
- EXPECT_EQ(cvc_case.valid,
- controller_->InputCvcIsValid(ASCIIToUTF16(cvc_case.input)));
- if (!cvc_case.valid)
- continue;
-
- controller_->OnUnmaskResponse(ASCIIToUTF16(cvc_case.input),
- ASCIIToUTF16("1"), ASCIIToUTF16("2050"),
- false);
- EXPECT_EQ(ASCIIToUTF16(cvc_case.canonicalized_input),
- delegate_->response().cvc);
+ void SetUp() override {
+ test_unmask_prompt_view_.reset(new TestCardUnmaskPromptView());
+ pref_service_.reset(new TestingPrefServiceSimple());
+ controller_.reset(new TestCardUnmaskPromptController(pref_service_.get()));
+ delegate_.reset(new TestCardUnmaskDelegate());
+ pref_service_->registry()->RegisterBooleanPref(
+ prefs::kAutofillWalletImportStorageCheckboxState, false);
}
- CvcCase cvc_cases_amex[] = {
- { "123", false },
- { "123 ", false },
- { "1234", true, "1234" },
- { "\t1234 ", true, "1234" },
- { " 1234", true, "1234" },
- { "IOU$", false },
- };
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CvcInputValidationTest);
+};
- ShowPromptAmex();
+TEST_P(CvcInputValidationTest, CvcInputValidation) {
+ auto cvc_case = GetParam();
+ ShowPrompt();
+ EXPECT_EQ(cvc_case.valid,
+ controller_->InputCvcIsValid(ASCIIToUTF16(cvc_case.input)));
+ if (!cvc_case.valid)
+ return;
+
+ controller_->OnUnmaskResponse(ASCIIToUTF16(cvc_case.input), ASCIIToUTF16("1"),
+ ASCIIToUTF16("2050"), false);
+ EXPECT_EQ(ASCIIToUTF16(cvc_case.canonicalized_input),
+ delegate_->response().cvc);
+}
- for (const CvcCase& cvc_case_amex : cvc_cases_amex) {
- EXPECT_EQ(cvc_case_amex.valid,
- controller_->InputCvcIsValid(ASCIIToUTF16(cvc_case_amex.input)));
- if (!cvc_case_amex.valid)
- continue;
+INSTANTIATE_TEST_CASE_P(CardUnmaskPromptControllerImplTest,
+ CvcInputValidationTest,
+ testing::Values(CvcCase{"123", true, "123"},
+ CvcCase{"123 ", true, "123"},
+ CvcCase{" 1234 ", false},
+ CvcCase{"IOU", false}));
- controller_->OnUnmaskResponse(ASCIIToUTF16(cvc_case_amex.input),
- base::string16(), base::string16(), false);
- EXPECT_EQ(ASCIIToUTF16(cvc_case_amex.canonicalized_input),
- delegate_->response().cvc);
+class CvcInputAmexValidationTest
+ : public CardUnmaskPromptControllerImplGenericTest,
+ public testing::TestWithParam<CvcCase> {
+ public:
+ CvcInputAmexValidationTest() {}
+ ~CvcInputAmexValidationTest() override {}
+
+ void SetUp() override {
+ test_unmask_prompt_view_.reset(new TestCardUnmaskPromptView());
+ pref_service_.reset(new TestingPrefServiceSimple());
+ controller_.reset(new TestCardUnmaskPromptController(pref_service_.get()));
+ delegate_.reset(new TestCardUnmaskDelegate());
+ pref_service_->registry()->RegisterBooleanPref(
+ prefs::kAutofillWalletImportStorageCheckboxState, false);
}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CvcInputAmexValidationTest);
+};
+
+TEST_P(CvcInputAmexValidationTest, CvcInputValidation) {
+ auto cvc_case_amex = GetParam();
+ ShowPromptAmex();
+ EXPECT_EQ(cvc_case_amex.valid,
+ controller_->InputCvcIsValid(ASCIIToUTF16(cvc_case_amex.input)));
+ if (!cvc_case_amex.valid)
+ return;
+
+ controller_->OnUnmaskResponse(ASCIIToUTF16(cvc_case_amex.input),
+ base::string16(), base::string16(), false);
+ EXPECT_EQ(ASCIIToUTF16(cvc_case_amex.canonicalized_input),
+ delegate_->response().cvc);
}
-TEST_F(CardUnmaskPromptControllerImplTest, ExpirationDateValidation) {
- struct {
- const char* input_month;
- const char* input_year;
- bool valid;
- } exp_cases[] = {
- {"01", "2040", true},
- {"1", "2040", true},
- {"1", "40", true},
- {"10", "40", true},
- {"01", "1940", false},
- {"13", "2040", false},
- };
+INSTANTIATE_TEST_CASE_P(CardUnmaskPromptControllerImplTest,
+ CvcInputAmexValidationTest,
+ testing::Values(CvcCase{"123", false},
+ CvcCase{"123 ", false},
+ CvcCase{"1234", true, "1234"},
+ CvcCase{"\t1234 ", true, "1234"},
+ CvcCase{" 1234", true, "1234"},
+ CvcCase{"IOU$", false}));
+
+struct ExpirationDateTestCase {
+ const char* input_month;
+ const char* input_year;
+ bool valid;
+};
- ShowPrompt();
+class ExpirationDateValidationTest
+ : public CardUnmaskPromptControllerImplGenericTest,
+ public testing::TestWithParam<ExpirationDateTestCase> {
+ public:
+ ExpirationDateValidationTest() {}
+ ~ExpirationDateValidationTest() override {}
- for (const auto& exp_case : exp_cases) {
- EXPECT_EQ(exp_case.valid, controller_->InputExpirationIsValid(
- ASCIIToUTF16(exp_case.input_month),
- ASCIIToUTF16(exp_case.input_year)));
+ void SetUp() override {
+ test_unmask_prompt_view_.reset(new TestCardUnmaskPromptView());
+ pref_service_.reset(new TestingPrefServiceSimple());
+ controller_.reset(new TestCardUnmaskPromptController(pref_service_.get()));
+ delegate_.reset(new TestCardUnmaskDelegate());
+ pref_service_->registry()->RegisterBooleanPref(
+ prefs::kAutofillWalletImportStorageCheckboxState, false);
}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ExpirationDateValidationTest);
+};
+
+TEST_P(ExpirationDateValidationTest, ExpirationDateValidation) {
+ auto exp_case = GetParam();
+ ShowPrompt();
+ EXPECT_EQ(exp_case.valid, controller_->InputExpirationIsValid(
+ ASCIIToUTF16(exp_case.input_month),
+ ASCIIToUTF16(exp_case.input_year)));
}
+INSTANTIATE_TEST_CASE_P(
+ CardUnmaskPromptControllerImplTest,
+ ExpirationDateValidationTest,
+ testing::Values(ExpirationDateTestCase{"01", "2040", true},
+ ExpirationDateTestCase{"1", "2040", true},
+ ExpirationDateTestCase{"1", "40", true},
+ ExpirationDateTestCase{"10", "40", true},
+ ExpirationDateTestCase{"01", "1940", false},
+ ExpirationDateTestCase{"13", "2040", false}));
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.cc b/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.cc
new file mode 100644
index 00000000000..b0c8d787035
--- /dev/null
+++ b/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.cc
@@ -0,0 +1,22 @@
+// 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/ui/mock_save_card_bubble_controller.h"
+
+namespace autofill {
+
+MockSaveCardBubbleController::MockSaveCardBubbleController() {}
+
+MockSaveCardBubbleController::~MockSaveCardBubbleController() {}
+
+base::string16 MockSaveCardBubbleController::GetCvcEnteredByUser() const {
+ return cvc_entered_by_user_;
+}
+
+void MockSaveCardBubbleController::OnSaveButton(const base::string16& cvc) {
+ if (!cvc.empty())
+ cvc_entered_by_user_ = cvc;
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h b/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h
new file mode 100644
index 00000000000..ce040ae2008
--- /dev/null
+++ b/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h
@@ -0,0 +1,42 @@
+// 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_UI_MOCK_SAVE_CARD_BUBBLE_CONTROLLER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_MOCK_SAVE_CARD_BUBBLE_CONTROLLER_H_
+
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/ui/save_card_bubble_controller.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill {
+
+class MockSaveCardBubbleController : public SaveCardBubbleController {
+ public:
+ MockSaveCardBubbleController();
+ ~MockSaveCardBubbleController() override;
+
+ MOCK_CONST_METHOD0(GetWindowTitle, base::string16());
+ MOCK_CONST_METHOD0(GetExplanatoryMessage, base::string16());
+ MOCK_CONST_METHOD0(GetCard, const CreditCard());
+ MOCK_CONST_METHOD0(GetCvcImageResourceId, int());
+ MOCK_CONST_METHOD0(ShouldRequestCvcFromUser, bool());
+ MOCK_METHOD0(OnCancelButton, void());
+ MOCK_METHOD0(OnLearnMoreClicked, void());
+ MOCK_METHOD1(OnLegalMessageLinkClicked, void(const GURL& url));
+ MOCK_METHOD0(OnBubbleClosed, void());
+ MOCK_CONST_METHOD0(GetLegalMessageLines, const LegalMessageLines&());
+ MOCK_CONST_METHOD1(InputCvcIsValid, bool(const base::string16& input_text));
+
+ base::string16 GetCvcEnteredByUser() const override;
+ void OnSaveButton(const base::string16& cvc = base::string16()) override;
+
+ private:
+ base::string16 cvc_entered_by_user_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockSaveCardBubbleController);
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_MOCK_SAVE_CARD_BUBBLE_CONTROLLER_H_
diff --git a/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h b/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h
new file mode 100644
index 00000000000..f01cac3f220
--- /dev/null
+++ b/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h
@@ -0,0 +1,70 @@
+// 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_AUTOFILL_CORE_BROWSER_UI_SAVE_CARD_BUBBLE_CONTROLLER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_SAVE_CARD_BUBBLE_CONTROLLER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/autofill/core/browser/legal_message_line.h"
+#include "url/gurl.h"
+
+namespace autofill {
+
+class CreditCard;
+class SaveCardBubbleView;
+
+// Interface that exposes controller functionality to SaveCardBubbleView.
+class SaveCardBubbleController {
+ public:
+ SaveCardBubbleController() {}
+ virtual ~SaveCardBubbleController() {}
+
+ // Returns the title that should be displayed in the bubble.
+ virtual base::string16 GetWindowTitle() const = 0;
+
+ // Returns the explanatory text that should be displayed in the bubble.
+ // Returns an empty string if no message should be displayed.
+ virtual base::string16 GetExplanatoryMessage() const = 0;
+
+ // Returns the card that will be uploaded if the user accepts.
+ virtual const CreditCard GetCard() const = 0;
+
+ // Returns the CVC image icon resource ID.
+ virtual int GetCvcImageResourceId() const = 0;
+
+ // Returns whether the dialog should include a field requesting the card's CVC
+ // from the user.
+ virtual bool ShouldRequestCvcFromUser() const = 0;
+
+ // Returns the CVC provided by the user in the save card bubble.
+ virtual base::string16 GetCvcEnteredByUser() const = 0;
+
+ // Interaction.
+ // OnSaveButton takes in a string value representing the CVC entered by the
+ // user if it was requested, or an empty string otherwise.
+ virtual void OnSaveButton(const base::string16& cvc) = 0;
+ virtual void OnCancelButton() = 0;
+ virtual void OnLearnMoreClicked() = 0;
+ virtual void OnLegalMessageLinkClicked(const GURL& url) = 0;
+ virtual void OnBubbleClosed() = 0;
+
+ // State.
+
+ // Returns empty vector if no legal message should be shown.
+ virtual const LegalMessageLines& GetLegalMessageLines() const = 0;
+
+ // Utilities.
+ virtual bool InputCvcIsValid(const base::string16& input_text) const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SaveCardBubbleController);
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_SAVE_CARD_BUBBLE_CONTROLLER_H_
diff --git a/chromium/components/autofill/core/browser/validation.cc b/chromium/components/autofill/core/browser/validation.cc
index d18ccbab5cf..e7237f7b3b7 100644
--- a/chromium/components/autofill/core/browser/validation.cc
+++ b/chromium/components/autofill/core/browser/validation.cc
@@ -13,7 +13,9 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_data_util.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/phone_number_i18n.h"
#include "components/autofill/core/browser/state_names.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_regexes.h"
@@ -94,8 +96,7 @@ bool IsValidCreditCardNumber(const base::string16& text) {
bool IsValidCreditCardSecurityCode(const base::string16& code,
const base::StringPiece card_type) {
- size_t required_length = card_type == kAmericanExpressCard ? 4 : 3;
- return code.length() == required_length &&
+ return code.length() == GetCvcLengthForCardType(card_type) &&
base::ContainsOnlyChars(code, base::ASCIIToUTF16("0123456789"));
}
@@ -137,6 +138,12 @@ bool IsValidState(const base::string16& text) {
!state_names::GetNameForAbbreviation(text).empty();
}
+bool IsValidPhoneNumber(const base::string16& text,
+ const std::string& country_code) {
+ i18n::PhoneObject phone_number(text, country_code);
+ return phone_number.IsValidNumber();
+}
+
bool IsValidZip(const base::string16& text) {
const base::string16 kZipPattern = base::ASCIIToUTF16("^\\d{5}(-\\d{4})?$");
return MatchesPattern(text, kZipPattern);
@@ -308,4 +315,15 @@ bool IsValidForType(const base::string16& value,
return false;
}
+size_t GetCvcLengthForCardType(const base::StringPiece card_type) {
+ if (card_type == kAmericanExpressCard)
+ return AMEX_CVC_LENGTH;
+
+ return GENERAL_CVC_LENGTH;
+}
+
+bool IsUPIVirtualPaymentAddress(const base::string16& value) {
+ return MatchesPattern(value, base::ASCIIToUTF16(kUPIVirtualPaymentAddressRe));
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/validation.h b/chromium/components/autofill/core/browser/validation.h
index 0b496e2b950..93a52e59b4f 100644
--- a/chromium/components/autofill/core/browser/validation.h
+++ b/chromium/components/autofill/core/browser/validation.h
@@ -15,6 +15,10 @@ class Time;
namespace autofill {
+// Constants for the length of a CVC.
+static const size_t GENERAL_CVC_LENGTH = 3;
+static const size_t AMEX_CVC_LENGTH = 4;
+
// Returns true if |year| and |month| describe a date later than |now|.
// |year| must have 4 digits.
bool IsValidCreditCardExpirationDate(int year,
@@ -45,6 +49,11 @@ bool IsValidEmailAddress(const base::string16& text);
// insensitive. Valid for US states only.
bool IsValidState(const base::string16& text);
+// Returns whether the number contained in |text| is valid for the specified
+// |country_code|. Callers should cache the result as the parsing is expensive.
+bool IsValidPhoneNumber(const base::string16& text,
+ const std::string& country_code);
+
// Returns true if |text| looks like a valid zip code.
// Valid for US zip codes only.
bool IsValidZip(const base::string16& text);
@@ -58,6 +67,13 @@ bool IsValidForType(const base::string16& value,
ServerFieldType type,
base::string16* error_message);
+// Returns the expected CVC length based on the |card_type|.
+size_t GetCvcLengthForCardType(const base::StringPiece card_type);
+
+// Returns true if |value| appears to be a UPI Virtual Payment Address.
+// https://upipayments.co.in/virtual-payment-address-vpa/
+bool IsUPIVirtualPaymentAddress(const base::string16& value);
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_VALIDATION_H_
diff --git a/chromium/components/autofill/core/browser/validation_unittest.cc b/chromium/components/autofill/core/browser/validation_unittest.cc
index ec6ff0a346f..ee36fbc4543 100644
--- a/chromium/components/autofill/core/browser/validation_unittest.cc
+++ b/chromium/components/autofill/core/browser/validation_unittest.cc
@@ -412,4 +412,81 @@ INSTANTIATE_TEST_CASE_P(
false,
IDS_PAYMENTS_VALIDATION_UNSUPPORTED_CREDIT_CARD_TYPE)));
+struct GetCvcLengthForCardTypeCase {
+ GetCvcLengthForCardTypeCase(const char* card_type, size_t expected_length)
+ : card_type(card_type), expected_length(expected_length) {}
+ ~GetCvcLengthForCardTypeCase() {}
+
+ const char* const card_type;
+ const size_t expected_length;
+};
+
+class AutofillGetCvcLengthForCardType
+ : public testing::TestWithParam<GetCvcLengthForCardTypeCase> {};
+
+TEST_P(AutofillGetCvcLengthForCardType, GetCvcLengthForCardType) {
+ EXPECT_EQ(GetParam().expected_length,
+ GetCvcLengthForCardType(GetParam().card_type));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ CreditCardCvcLength,
+ AutofillGetCvcLengthForCardType,
+ testing::Values(
+ GetCvcLengthForCardTypeCase{kAmericanExpressCard, AMEX_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kDinersCard, GENERAL_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kDiscoverCard, GENERAL_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kGenericCard, GENERAL_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kJCBCard, GENERAL_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kMasterCard, GENERAL_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kMirCard, GENERAL_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kUnionPay, GENERAL_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kVisaCard, GENERAL_CVC_LENGTH}));
+
+class AutofillIsUPIVirtualPaymentAddress
+ : public testing::TestWithParam<std::string> {};
+
+TEST_P(AutofillIsUPIVirtualPaymentAddress, IsUPIVirtualPaymentAddress) {
+ // Expected format is user@bank
+ EXPECT_TRUE(IsUPIVirtualPaymentAddress(ASCIIToUTF16("user@" + GetParam())));
+
+ // Deviations should not match: bank, @bank, user@prefixbank, user@banksuffix.
+ EXPECT_FALSE(IsUPIVirtualPaymentAddress(ASCIIToUTF16(GetParam())));
+ EXPECT_FALSE(IsUPIVirtualPaymentAddress(ASCIIToUTF16(GetParam() + "@")));
+ EXPECT_FALSE(IsUPIVirtualPaymentAddress(ASCIIToUTF16("@" + GetParam())));
+ EXPECT_FALSE(
+ IsUPIVirtualPaymentAddress(ASCIIToUTF16("user@invalid" + GetParam())));
+ EXPECT_FALSE(
+ IsUPIVirtualPaymentAddress(ASCIIToUTF16("user@" + GetParam() + ".com")));
+}
+
+INSTANTIATE_TEST_CASE_P(UPIVirtualPaymentAddress,
+ AutofillIsUPIVirtualPaymentAddress,
+ testing::Values("upi",
+ "allbank",
+ "andb",
+ "axisbank",
+ "barodampay",
+ "mahb",
+ "cnrb",
+ "csbpay",
+ "dcb",
+ "federal",
+ "hdfcbank",
+ "pockets",
+ "icici",
+ "idfcbank",
+ "indus",
+ "kbl",
+ "kaypay",
+ "pnb",
+ "sib",
+ "sbi",
+ "tjsp",
+ "uco",
+ "unionbank",
+ "united",
+ "vijb",
+ "ybl"));
+
} // namespace autofill
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 589df1628af..9ed91408190 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
@@ -458,6 +458,9 @@ void AutocompleteSyncBridge::LoadMetadata() {
std::string AutocompleteSyncBridge::GetClientTag(
const EntityData& entity_data) {
DCHECK(entity_data.specifics.has_autofill());
+ // Must have the format "autofill_entry|$name|$value" where $name and $value
+ // are URL escaped. This is to maintain compatibility with the previous sync
+ // integration (Directory and SyncableService).
return std::string(kAutocompleteEntryNamespaceTag) +
EscapeIdentifiers(entity_data.specifics.autofill());
}
@@ -465,6 +468,9 @@ std::string AutocompleteSyncBridge::GetClientTag(
std::string AutocompleteSyncBridge::GetStorageKey(
const EntityData& entity_data) {
DCHECK(entity_data.specifics.has_autofill());
+ // Marginally more space efficient than GetClientTag() by omitting the
+ // kAutocompleteEntryNamespaceTag prefix and using protobuf serialization
+ // instead of URL escaping for Unicode characters.
const AutofillSpecifics specifics = entity_data.specifics.autofill();
return BuildSerializedStorageKey(specifics.name(), specifics.value());
}
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
index 2ec41c5ae51..3d3053c6110 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
@@ -54,14 +54,7 @@ class AutocompleteSyncBridge : public base::SupportsUserData::Data,
syncer::EntityChangeList entity_changes) override;
void GetData(StorageKeyList storage_keys, DataCallback callback) override;
void GetAllData(DataCallback callback) override;
- // Generate a tag that uniquely identifies |entity_data| across all data
- // types. This is used to identify the entity on the server. The format, which
- // must remain the same for server compatibility, is:
- // "autofill_entry|$name|$value" where $name and $value are escaped.
std::string GetClientTag(const syncer::EntityData& entity_data) override;
- // Generate a string key uniquely identifying |entity_data| in the context of
- // local storage. The format, which should stay the same, is $name|$value"
- // where $name and $value are escaped.
std::string GetStorageKey(const syncer::EntityData& entity_data) override;
// AutofillWebDataServiceObserverOnDBThread implementation.
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 a4334eaa230..bdb786daa6a 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
@@ -16,6 +16,7 @@
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/webdata/autofill_entry.h"
@@ -276,7 +277,7 @@ class AutocompleteSyncBridgeTest : public testing::Test {
}
ScopedTempDir temp_dir_;
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
FakeAutofillBackend backend_;
AutofillTable table_;
WebDatabase db_;
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
index e5bc5b989bf..7c840464cf4 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
@@ -1191,77 +1191,127 @@ TEST_F(AutofillProfileSyncableServiceTest, NoUsageStatsNoSync) {
autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
}
-// Usage stats should be updated by sync.
-TEST_F(AutofillProfileSyncableServiceTest, SyncUpdatesUsageStats) {
- typedef struct {
- size_t local_use_count;
- base::Time local_use_date;
- size_t remote_use_count;
- int remote_use_date;
- size_t synced_use_count;
- base::Time synced_use_date;
- } TestCase;
-
- TestCase test_cases[] = {
- // Local profile with default stats.
- {0U, base::Time(), 9U, 4321, 9U, base::Time::FromTimeT(4321)},
- // Local profile has older stats than the server.
- {3U, base::Time::FromTimeT(1234), 9U, 4321, 9U,
- base::Time::FromTimeT(4321)},
- // Local profile has newer stats than the server
- {10U, base::Time::FromTimeT(9999), 9U, 4321, 9U,
- base::Time::FromTimeT(4321)}};
-
- for (const TestCase& test_case : test_cases) {
- SetUp();
- std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
-
- AutofillProfile profile(kGuid1, kHttpsOrigin);
- profile.set_language_code("en");
- profile.set_use_count(test_case.local_use_count);
- profile.set_use_date(test_case.local_use_date);
- EXPECT_EQ(test_case.local_use_count, profile.use_count());
- EXPECT_EQ(test_case.local_use_date, profile.use_date());
- profiles_from_web_db.push_back(base::MakeUnique<AutofillProfile>(profile));
-
- // Remote data has usage stats.
- sync_pb::EntitySpecifics specifics;
- sync_pb::AutofillProfileSpecifics* autofill_specifics =
- specifics.mutable_autofill_profile();
- autofill_specifics->set_guid(profile.guid());
- autofill_specifics->set_origin(profile.origin());
- autofill_specifics->add_name_first(std::string());
- autofill_specifics->add_name_middle(std::string());
- autofill_specifics->add_name_last(std::string());
- autofill_specifics->add_name_full(std::string());
- autofill_specifics->add_email_address(std::string());
- autofill_specifics->add_phone_home_whole_number(std::string());
- autofill_specifics->set_address_home_language_code("en");
- autofill_specifics->set_use_count(test_case.remote_use_count);
- autofill_specifics->set_use_date(test_case.remote_use_date);
- EXPECT_TRUE(autofill_specifics->has_use_count());
- EXPECT_TRUE(autofill_specifics->has_use_date());
-
- syncer::SyncDataList data_list;
- data_list.push_back(syncer::SyncData::CreateLocalData(
- profile.guid(), profile.guid(), specifics));
-
- // Expect the local autofill profile to have usage stats after sync.
- MockAutofillProfileSyncableService::DataBundle expected_bundle;
- AutofillProfile expected_profile = profile;
- expected_profile.set_use_count(test_case.synced_use_count);
- expected_profile.set_use_date(test_case.synced_use_date);
- expected_bundle.profiles_to_update.push_back(&expected_profile);
-
- // Expect no changes to remote data.
- syncer::SyncChangeList expected_empty_change_list;
-
- MergeDataAndStartSyncing(std::move(profiles_from_web_db), data_list,
- expected_bundle, expected_empty_change_list);
- autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
+struct SyncUpdatesUsageStatsTestCase {
+ size_t local_use_count;
+ base::Time local_use_date;
+ size_t remote_use_count;
+ int remote_use_date;
+ size_t synced_use_count;
+ base::Time synced_use_date;
+};
+
+class SyncUpdatesUsageStatsTest
+ : public testing::TestWithParam<SyncUpdatesUsageStatsTestCase> {
+ public:
+ SyncUpdatesUsageStatsTest() { CountryNames::SetLocaleString("en-US"); }
+
+ void SetUp() override { sync_processor_.reset(new MockSyncChangeProcessor); }
+
+ // Wrapper around AutofillProfileSyncableService::MergeDataAndStartSyncing()
+ // that also verifies expectations.
+ void MergeDataAndStartSyncing(
+ std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db,
+ const syncer::SyncDataList& data_list,
+ const MockAutofillProfileSyncableService::DataBundle& expected_bundle,
+ const syncer::SyncChangeList& expected_change_list) {
+ auto profile_returner = [&profiles_from_web_db]() {
+ return std::move(profiles_from_web_db);
+ };
+ EXPECT_CALL(autofill_syncable_service_, LoadAutofillData(_))
+ .Times(1)
+ .WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
+ EXPECT_CALL(autofill_syncable_service_,
+ SaveChangesToWebData(DataBundleCheck(expected_bundle)))
+ .Times(1)
+ .WillOnce(Return(true));
+ if (expected_change_list.empty()) {
+ EXPECT_CALL(*sync_processor_, ProcessSyncChanges(_, _)).Times(0);
+ } else {
+ ON_CALL(*sync_processor_, ProcessSyncChanges(_, _))
+ .WillByDefault(Return(syncer::SyncError()));
+ EXPECT_CALL(*sync_processor_,
+ ProcessSyncChanges(_, CheckSyncChanges(expected_change_list)))
+ .Times(1)
+ .WillOnce(Return(syncer::SyncError()));
+ }
+
+ // Takes ownership of sync_processor_.
+ autofill_syncable_service_.MergeDataAndStartSyncing(
+ syncer::AUTOFILL_PROFILE, data_list, std::move(sync_processor_),
+ std::unique_ptr<syncer::SyncErrorFactory>(
+ new syncer::SyncErrorFactoryMock()));
}
+
+ protected:
+ base::MessageLoop message_loop_;
+ MockAutofillProfileSyncableService autofill_syncable_service_;
+ std::unique_ptr<MockSyncChangeProcessor> sync_processor_;
+};
+
+TEST_P(SyncUpdatesUsageStatsTest, SyncUpdatesUsageStats) {
+ auto test_case = GetParam();
+ SetUp();
+ std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
+
+ AutofillProfile profile(kGuid1, kHttpsOrigin);
+ profile.set_language_code("en");
+ profile.set_use_count(test_case.local_use_count);
+ profile.set_use_date(test_case.local_use_date);
+ EXPECT_EQ(test_case.local_use_count, profile.use_count());
+ EXPECT_EQ(test_case.local_use_date, profile.use_date());
+ profiles_from_web_db.push_back(base::MakeUnique<AutofillProfile>(profile));
+
+ // Remote data has usage stats.
+ sync_pb::EntitySpecifics specifics;
+ sync_pb::AutofillProfileSpecifics* autofill_specifics =
+ specifics.mutable_autofill_profile();
+ autofill_specifics->set_guid(profile.guid());
+ autofill_specifics->set_origin(profile.origin());
+ autofill_specifics->add_name_first(std::string());
+ autofill_specifics->add_name_middle(std::string());
+ autofill_specifics->add_name_last(std::string());
+ autofill_specifics->add_name_full(std::string());
+ autofill_specifics->add_email_address(std::string());
+ autofill_specifics->add_phone_home_whole_number(std::string());
+ autofill_specifics->set_address_home_language_code("en");
+ autofill_specifics->set_use_count(test_case.remote_use_count);
+ autofill_specifics->set_use_date(test_case.remote_use_date);
+ EXPECT_TRUE(autofill_specifics->has_use_count());
+ EXPECT_TRUE(autofill_specifics->has_use_date());
+
+ syncer::SyncDataList data_list;
+ data_list.push_back(syncer::SyncData::CreateLocalData(
+ profile.guid(), profile.guid(), specifics));
+
+ // Expect the local autofill profile to have usage stats after sync.
+ MockAutofillProfileSyncableService::DataBundle expected_bundle;
+ AutofillProfile expected_profile = profile;
+ expected_profile.set_use_count(test_case.synced_use_count);
+ expected_profile.set_use_date(test_case.synced_use_date);
+ expected_bundle.profiles_to_update.push_back(&expected_profile);
+
+ // Expect no changes to remote data.
+ syncer::SyncChangeList expected_empty_change_list;
+
+ MergeDataAndStartSyncing(std::move(profiles_from_web_db), data_list,
+ expected_bundle, expected_empty_change_list);
+ autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillProfileSyncableServiceTest,
+ SyncUpdatesUsageStatsTest,
+ testing::Values(
+ // Local profile with default stats.
+ SyncUpdatesUsageStatsTestCase{0U, base::Time(), 9U, 4321, 9U,
+ base::Time::FromTimeT(4321)},
+ // Local profile has older stats than the server.
+ SyncUpdatesUsageStatsTestCase{3U, base::Time::FromTimeT(1234), 9U, 4321,
+ 9U, base::Time::FromTimeT(4321)},
+ // Local profile has newer stats than the server
+ SyncUpdatesUsageStatsTestCase{10U, base::Time::FromTimeT(9999), 9U,
+ 4321, 9U, base::Time::FromTimeT(4321)}));
+
// Usage stats should be updated by the client.
TEST_F(AutofillProfileSyncableServiceTest, ClientOverwritesUsageStats) {
TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor;
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.cc b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
index 72cf35b3c7b..27d1c00d470 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
@@ -1700,13 +1700,8 @@ bool AutofillTable::GetAllSyncMetadata(syncer::ModelType model_type,
syncer::MetadataBatch* metadata_batch) {
DCHECK_EQ(model_type, syncer::AUTOFILL)
<< "Only the AUTOFILL model type is supported";
- syncer::EntityMetadataMap metadata_records;
- if (GetAllSyncEntityMetadata(model_type, &metadata_records)) {
- for (const auto& pair : metadata_records) {
- // TODO(pnoland): Add batch transfer of metadata map.
- metadata_batch->AddMetadata(pair.first, pair.second);
- }
- } else {
+ DCHECK(metadata_batch);
+ if (!GetAllSyncEntityMetadata(model_type, metadata_batch)) {
return false;
}
@@ -1722,9 +1717,10 @@ bool AutofillTable::GetAllSyncMetadata(syncer::ModelType model_type,
bool AutofillTable::GetAllSyncEntityMetadata(
syncer::ModelType model_type,
- syncer::EntityMetadataMap* metadata_records) {
+ syncer::MetadataBatch* metadata_batch) {
DCHECK_EQ(model_type, syncer::AUTOFILL)
<< "Only the AUTOFILL model type is supported";
+ DCHECK(metadata_batch);
sql::Statement s(db_->GetUniqueStatement(
"SELECT storage_key, value FROM autofill_sync_metadata"));
@@ -1732,10 +1728,12 @@ bool AutofillTable::GetAllSyncEntityMetadata(
while (s.Step()) {
std::string storage_key = s.ColumnString(0);
std::string serialized_metadata = s.ColumnString(1);
- sync_pb::EntityMetadata metadata_record;
- if (metadata_record.ParseFromString(serialized_metadata)) {
- metadata_records->insert(std::make_pair(storage_key, metadata_record));
+ sync_pb::EntityMetadata entity_metadata;
+ if (entity_metadata.ParseFromString(serialized_metadata)) {
+ metadata_batch->AddMetadata(storage_key, entity_metadata);
} else {
+ DLOG(WARNING) << "Failed to deserialize AUTOFILL model type "
+ "sync_pb::EntityMetadata.";
return false;
}
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.h b/chromium/components/autofill/core/browser/webdata/autofill_table.h
index f3f8a14dcc4..872d127b393 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.h
@@ -517,7 +517,7 @@ class AutofillTable : public WebDatabaseTable {
base::Time time);
bool GetAllSyncEntityMetadata(syncer::ModelType model_type,
- syncer::EntityMetadataMap* metadata_records);
+ syncer::MetadataBatch* metadata_batch);
bool GetModelTypeState(syncer::ModelType model_type,
sync_pb::ModelTypeState* state);
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 235dd06230b..58439067907 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -1955,61 +1955,112 @@ TEST_F(AutofillTableTest, DeleteUnmaskedCard) {
outputs.clear();
}
-TEST_F(AutofillTableTest, GetFormValuesForElementName_SubstringMatchEnabled) {
+const size_t kMaxCount = 2;
+struct GetFormValuesTestCase {
+ const char* const field_suggestion[kMaxCount];
+ const char* const field_contents;
+ size_t expected_suggestion_count;
+ const char* const expected_suggestion[kMaxCount];
+};
+
+class GetFormValuesTest : public testing::TestWithParam<GetFormValuesTestCase> {
+ public:
+ GetFormValuesTest() {}
+ ~GetFormValuesTest() override {}
+
+ protected:
+ void SetUp() override {
+ OSCryptMocker::SetUpWithSingleton();
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ file_ = temp_dir_.GetPath().AppendASCII("TestWebDatabase");
+
+ table_.reset(new AutofillTable);
+ db_.reset(new WebDatabase);
+ db_->AddTable(table_.get());
+ ASSERT_EQ(sql::INIT_OK, db_->Init(file_));
+ }
+
+ void TearDown() override { OSCryptMocker::TearDown(); }
+
+ base::FilePath file_;
+ base::ScopedTempDir temp_dir_;
+ std::unique_ptr<AutofillTable> table_;
+ std::unique_ptr<WebDatabase> db_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GetFormValuesTest);
+};
+
+TEST_P(GetFormValuesTest, GetFormValuesForElementName_SubstringMatchEnabled) {
// Token matching is currently behind a flag.
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableSuggestionsWithSubstringMatch);
- const size_t kMaxCount = 2;
- const struct {
- const char* const field_suggestion[kMaxCount];
- const char* const field_contents;
- size_t expected_suggestion_count;
- const char* const expected_suggestion[kMaxCount];
- } kTestCases[] = {
- {{"user.test", "test_user"}, "TEST", 2, {"test_user", "user.test"}},
- {{"user test", "test-user"}, "user", 2, {"user test", "test-user"}},
- {{"user test", "test-rest"}, "user", 1, {"user test", nullptr}},
- {{"user@test", "test_user"}, "user@t", 1, {"user@test", nullptr}},
- {{"user.test", "test_user"}, "er.tes", 0, {nullptr, nullptr}},
- {{"user test", "test_user"}, "_ser", 0, {nullptr, nullptr}},
- {{"user.test", "test_user"}, "%ser", 0, {nullptr, nullptr}},
- {{"user.test", "test_user"},
- "; DROP TABLE autofill;",
- 0,
- {nullptr, nullptr}},
- };
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message()
- << "suggestion = " << test_case.field_suggestion[0]
- << ", contents = " << test_case.field_contents);
-
- Time t1 = Time::Now();
+ auto test_case = GetParam();
+ SCOPED_TRACE(testing::Message()
+ << "suggestion = " << test_case.field_suggestion[0]
+ << ", contents = " << test_case.field_contents);
- // Simulate the submission of a handful of entries in a field called "Name".
- AutofillChangeList changes;
- FormFieldData field;
- for (size_t k = 0; k < kMaxCount; ++k) {
- field.name = ASCIIToUTF16("Name");
- field.value = ASCIIToUTF16(test_case.field_suggestion[k]);
- table_->AddFormFieldValue(field, &changes);
- }
+ Time t1 = Time::Now();
- std::vector<base::string16> v;
- table_->GetFormValuesForElementName(
- ASCIIToUTF16("Name"), ASCIIToUTF16(test_case.field_contents), &v, 6);
+ // Simulate the submission of a handful of entries in a field called "Name".
+ AutofillChangeList changes;
+ FormFieldData field;
+ for (size_t k = 0; k < kMaxCount; ++k) {
+ field.name = ASCIIToUTF16("Name");
+ field.value = ASCIIToUTF16(test_case.field_suggestion[k]);
+ table_->AddFormFieldValue(field, &changes);
+ }
- EXPECT_EQ(test_case.expected_suggestion_count, v.size());
- for (size_t j = 0; j < test_case.expected_suggestion_count; ++j) {
- EXPECT_EQ(ASCIIToUTF16(test_case.expected_suggestion[j]), v[j]);
- }
+ std::vector<base::string16> v;
+ table_->GetFormValuesForElementName(
+ ASCIIToUTF16("Name"), ASCIIToUTF16(test_case.field_contents), &v, 6);
- changes.clear();
- table_->RemoveFormElementsAddedBetween(t1, Time(), &changes);
+ EXPECT_EQ(test_case.expected_suggestion_count, v.size());
+ for (size_t j = 0; j < test_case.expected_suggestion_count; ++j) {
+ EXPECT_EQ(ASCIIToUTF16(test_case.expected_suggestion[j]), v[j]);
}
+
+ changes.clear();
+ table_->RemoveFormElementsAddedBetween(t1, Time(), &changes);
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillTableTest,
+ GetFormValuesTest,
+ testing::Values(GetFormValuesTestCase{{"user.test", "test_user"},
+ "TEST",
+ 2,
+ {"test_user", "user.test"}},
+ GetFormValuesTestCase{{"user test", "test-user"},
+ "user",
+ 2,
+ {"user test", "test-user"}},
+ GetFormValuesTestCase{{"user test", "test-rest"},
+ "user",
+ 1,
+ {"user test", nullptr}},
+ GetFormValuesTestCase{{"user@test", "test_user"},
+ "user@t",
+ 1,
+ {"user@test", nullptr}},
+ GetFormValuesTestCase{{"user.test", "test_user"},
+ "er.tes",
+ 0,
+ {nullptr, nullptr}},
+ GetFormValuesTestCase{{"user test", "test_user"},
+ "_ser",
+ 0,
+ {nullptr, nullptr}},
+ GetFormValuesTestCase{{"user.test", "test_user"},
+ "%ser",
+ 0,
+ {nullptr, nullptr}},
+ GetFormValuesTestCase{{"user.test", "test_user"},
+ "; DROP TABLE autofill;",
+ 0,
+ {nullptr, nullptr}}));
+
TEST_F(AutofillTableTest, AutofillNoMetadata) {
MetadataBatch metadata_batch;
EXPECT_TRUE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
index b43f4fc3ed7..fc6948f1aef 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
@@ -10,6 +10,7 @@
#include <utility>
#include "base/logging.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
@@ -86,8 +87,8 @@ AutofillProfile ProfileFromSpecifics(
AutofillProfile profile(AutofillProfile::SERVER_PROFILE, std::string());
// AutofillProfile stores multi-line addresses with newline separators.
- std::vector<std::string> street_address(address.street_address().begin(),
- address.street_address().end());
+ std::vector<base::StringPiece> street_address(
+ address.street_address().begin(), address.street_address().end());
profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
base::UTF8ToUTF16(base::JoinString(street_address, "\n")));
diff --git a/chromium/components/autofill/core/common/BUILD.gn b/chromium/components/autofill/core/common/BUILD.gn
index f7a34bb28b6..f3b320f0827 100644
--- a/chromium/components/autofill/core/common/BUILD.gn
+++ b/chromium/components/autofill/core/common/BUILD.gn
@@ -33,6 +33,7 @@ static_library("common") {
"password_form_field_prediction_map.h",
"password_form_fill_data.cc",
"password_form_fill_data.h",
+ "password_form_generation_data.cc",
"password_form_generation_data.h",
"password_generation_util.cc",
"password_generation_util.h",
diff --git a/chromium/components/autofill/core/common/autofill_clock.cc b/chromium/components/autofill/core/common/autofill_clock.cc
index 8702403d9e5..20d70c95413 100644
--- a/chromium/components/autofill/core/common/autofill_clock.cc
+++ b/chromium/components/autofill/core/common/autofill_clock.cc
@@ -13,7 +13,7 @@ namespace autofill {
namespace {
-static base::LazyInstance<AutofillClock> g_autofill_clock =
+static base::LazyInstance<AutofillClock>::DestructorAtExit g_autofill_clock =
LAZY_INSTANCE_INITIALIZER;
} // namespace
diff --git a/chromium/components/autofill/core/common/autofill_clock.h b/chromium/components/autofill/core/common/autofill_clock.h
index 45a991211ba..b94ff272ab4 100644
--- a/chromium/components/autofill/core/common/autofill_clock.h
+++ b/chromium/components/autofill/core/common/autofill_clock.h
@@ -26,7 +26,7 @@ class AutofillClock {
private:
friend class TestAutofillClock;
- friend struct base::DefaultLazyInstanceTraits<AutofillClock>;
+ friend struct base::LazyInstanceTraitsBase<AutofillClock>;
// Resets a normal clock.
static void SetClock();
diff --git a/chromium/components/autofill/core/common/autofill_data_validation.cc b/chromium/components/autofill/core/common/autofill_data_validation.cc
index 07c2b9dc9db..f1075dc384d 100644
--- a/chromium/components/autofill/core/common/autofill_data_validation.cc
+++ b/chromium/components/autofill/core/common/autofill_data_validation.cc
@@ -35,7 +35,6 @@ bool IsValidFormFieldData(const FormFieldData& field) {
IsValidString16(field.value) &&
IsValidString(field.form_control_type) &&
IsValidString(field.autocomplete_attribute) &&
- IsValidString16Vector(field.option_values) &&
IsValidString16Vector(field.option_contents);
}
diff --git a/chromium/components/autofill/core/common/autofill_regexes_unittest.cc b/chromium/components/autofill/core/common/autofill_regexes_unittest.cc
index 107830d52d1..a267e414991 100644
--- a/chromium/components/autofill/core/common/autofill_regexes_unittest.cc
+++ b/chromium/components/autofill/core/common/autofill_regexes_unittest.cc
@@ -16,194 +16,217 @@ using base::ASCIIToUTF16;
namespace autofill {
-TEST(AutofillRegexesTest, SampleRegexes) {
- struct TestCase {
- const char* const input;
- const char* const pattern;
+struct InputPatternTestCase {
+ const char* const input;
+ const char* const pattern;
};
- const TestCase kPositiveCases[] = {
- // Empty pattern
- {"", ""},
- {"Look, ma' -- a non-empty string!", ""},
- // Substring
- {"string", "tri"},
- // Substring at beginning
- {"string", "str"},
- {"string", "^str"},
- // Substring at end
- {"string", "ring"},
- {"string", "ring$"},
- // Case-insensitive
- {"StRiNg", "string"},
- };
- for (const auto& test_case : kPositiveCases) {
+ class PositiveSampleTest
+ : public testing::TestWithParam<InputPatternTestCase> {};
+
+ TEST_P(PositiveSampleTest, SampleRegexes) {
+ auto test_case = GetParam();
SCOPED_TRACE(test_case.input);
SCOPED_TRACE(test_case.pattern);
EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input),
ASCIIToUTF16(test_case.pattern)));
}
- const TestCase kNegativeCases[] = {
- // Empty string
- {"", "Look, ma' -- a non-empty pattern!"},
- // Substring
- {"string", "trn"},
- // Substring at beginning
- {"string", " str"},
- {"string", "^tri"},
- // Substring at end
- {"string", "ring "},
- {"string", "rin$"},
- };
- for (const auto& test_case : kNegativeCases) {
+ INSTANTIATE_TEST_CASE_P(AutofillRegexes,
+ PositiveSampleTest,
+ testing::Values(
+ // Empty pattern
+ InputPatternTestCase{"", ""},
+ InputPatternTestCase{
+ "Look, ma' -- a non-empty string!", ""},
+ // Substring
+ InputPatternTestCase{"string", "tri"},
+ // Substring at beginning
+ InputPatternTestCase{"string", "str"},
+ InputPatternTestCase{"string", "^str"},
+ // Substring at end
+ InputPatternTestCase{"string", "ring"},
+ InputPatternTestCase{"string", "ring$"},
+ // Case-insensitive
+ InputPatternTestCase{"StRiNg", "string"}));
+
+ class NegativeSampleTest
+ : public testing::TestWithParam<InputPatternTestCase> {};
+
+ TEST_P(NegativeSampleTest, SampleRegexes) {
+ auto test_case = GetParam();
SCOPED_TRACE(test_case.input);
SCOPED_TRACE(test_case.pattern);
EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input),
ASCIIToUTF16(test_case.pattern)));
- }
}
-TEST(AutofillRegexesTest, ExpirationDate2DigitYearRegexes) {
- struct TestCase {
- const char* const input;
+INSTANTIATE_TEST_CASE_P(AutofillRegexes,
+ NegativeSampleTest,
+ testing::Values(
+ // Empty string
+ InputPatternTestCase{
+ "", "Look, ma' -- a non-empty pattern!"},
+ // Substring
+ InputPatternTestCase{"string", "trn"},
+ // Substring at beginning
+ InputPatternTestCase{"string", " str"},
+ InputPatternTestCase{"string", "^tri"},
+ // Substring at end
+ InputPatternTestCase{"string", "ring "},
+ InputPatternTestCase{"string", "rin$"}));
+
+struct InputTestCase {
+ const char* const input;
};
- const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
-
- const TestCase kPositiveCases[] = {
- // Simple two year cases
- {"mm / yy"},
- {"mm/ yy"},
- {"mm /yy"},
- {"mm/yy"},
- {"mm - yy"},
- {"mm- yy"},
- {"mm -yy"},
- {"mm-yy"},
- {"mmyy"},
- // Complex two year cases
- {"Expiration Date (MM / YY)"},
- {"Expiration Date (MM/YY)"},
- {"Expiration Date (MM - YY)"},
- {"Expiration Date (MM-YY)"},
- {"Expiration Date MM / YY"},
- {"Expiration Date MM/YY"},
- {"Expiration Date MM - YY"},
- {"Expiration Date MM-YY"},
- {"expiration date yy"},
- {"Exp Date (MM / YY)"},
- };
+ class ExpirationDate2DigitYearPositive
+ : public testing::TestWithParam<InputTestCase> {};
- for (const auto& test_case : kPositiveCases) {
+ TEST_P(ExpirationDate2DigitYearPositive, ExpirationDate2DigitYearRegexes) {
+ auto test_case = GetParam();
SCOPED_TRACE(test_case.input);
- EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input),pattern));
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
+ EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
}
- const TestCase kNegativeCases[] = {
- {""},
- {"Look, ma' -- an invalid string!"},
- {"mmfavouritewordyy"},
- {"mm a yy"},
- {"mm a yyyy"},
- // Simple four year cases
- {"mm / yyyy"},
- {"mm/ yyyy"},
- {"mm /yyyy"},
- {"mm/yyyy"},
- {"mm - yyyy"},
- {"mm- yyyy"},
- {"mm -yyyy"},
- {"mm-yyyy"},
- {"mmyyyy"},
- // Complex four year cases
- {"Expiration Date (MM / YYYY)"},
- {"Expiration Date (MM/YYYY)"},
- {"Expiration Date (MM - YYYY)"},
- {"Expiration Date (MM-YYYY)"},
- {"Expiration Date MM / YYYY"},
- {"Expiration Date MM/YYYY"},
- {"Expiration Date MM - YYYY"},
- {"Expiration Date MM-YYYY"},
- {"expiration date yyyy"},
- {"Exp Date (MM / YYYY)"},
- };
-
- for (const auto& test_case : kNegativeCases) {
+ INSTANTIATE_TEST_CASE_P(
+ AutofillRegexes,
+ ExpirationDate2DigitYearPositive,
+ testing::Values(InputTestCase{"mm / yy"},
+ InputTestCase{"mm/ yy"},
+ InputTestCase{"mm /yy"},
+ InputTestCase{"mm/yy"},
+ InputTestCase{"mm - yy"},
+ InputTestCase{"mm- yy"},
+ InputTestCase{"mm -yy"},
+ InputTestCase{"mm-yy"},
+ InputTestCase{"mmyy"},
+ // Complex two year cases
+ InputTestCase{"Expiration Date (MM / YY)"},
+ InputTestCase{"Expiration Date (MM/YY)"},
+ InputTestCase{"Expiration Date (MM - YY)"},
+ InputTestCase{"Expiration Date (MM-YY)"},
+ InputTestCase{"Expiration Date MM / YY"},
+ InputTestCase{"Expiration Date MM/YY"},
+ InputTestCase{"Expiration Date MM - YY"},
+ InputTestCase{"Expiration Date MM-YY"},
+ InputTestCase{"expiration date yy"},
+ InputTestCase{"Exp Date (MM / YY)"}));
+
+ class ExpirationDate2DigitYearNegative
+ : public testing::TestWithParam<InputTestCase> {};
+
+ TEST_P(ExpirationDate2DigitYearNegative, ExpirationDate2DigitYearRegexes) {
+ auto test_case = GetParam();
SCOPED_TRACE(test_case.input);
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
}
-}
-TEST(AutofillRegexesTest, ExpirationDate4DigitYearRegexes) {
- struct TestCase {
- const char* const input;
- };
-
- const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
-
- const TestCase kPositiveCases[] = {
- // Simple four year cases
- {"mm / yyyy"},
- {"mm/ yyyy"},
- {"mm /yyyy"},
- {"mm/yyyy"},
- {"mm - yyyy"},
- {"mm- yyyy"},
- {"mm -yyyy"},
- {"mm-yyyy"},
- {"mmyyyy"},
- // Complex four year cases
- {"Expiration Date (MM / YYYY)"},
- {"Expiration Date (MM/YYYY)"},
- {"Expiration Date (MM - YYYY)"},
- {"Expiration Date (MM-YYYY)"},
- {"Expiration Date MM / YYYY"},
- {"Expiration Date MM/YYYY"},
- {"Expiration Date MM - YYYY"},
- {"Expiration Date MM-YYYY"},
- {"expiration date yyyy"},
- {"Exp Date (MM / YYYY)"},
- };
-
- for (const auto& test_case : kPositiveCases) {
+ INSTANTIATE_TEST_CASE_P(
+ AutofillRegexes,
+ ExpirationDate2DigitYearNegative,
+ testing::Values(InputTestCase{""},
+ InputTestCase{"Look, ma' -- an invalid string!"},
+ InputTestCase{"mmfavouritewordyy"},
+ InputTestCase{"mm a yy"},
+ InputTestCase{"mm a yyyy"},
+ // Simple four year cases
+ InputTestCase{"mm / yyyy"},
+ InputTestCase{"mm/ yyyy"},
+ InputTestCase{"mm /yyyy"},
+ InputTestCase{"mm/yyyy"},
+ InputTestCase{"mm - yyyy"},
+ InputTestCase{"mm- yyyy"},
+ InputTestCase{"mm -yyyy"},
+ InputTestCase{"mm-yyyy"},
+ InputTestCase{"mmyyyy"},
+ // Complex four year cases
+ InputTestCase{"Expiration Date (MM / YYYY)"},
+ InputTestCase{"Expiration Date (MM/YYYY)"},
+ InputTestCase{"Expiration Date (MM - YYYY)"},
+ InputTestCase{"Expiration Date (MM-YYYY)"},
+ InputTestCase{"Expiration Date MM / YYYY"},
+ InputTestCase{"Expiration Date MM/YYYY"},
+ InputTestCase{"Expiration Date MM - YYYY"},
+ InputTestCase{"Expiration Date MM-YYYY"},
+ InputTestCase{"expiration date yyyy"},
+ InputTestCase{"Exp Date (MM / YYYY)"}));
+
+ class ExpirationDate4DigitYearPositive
+ : public testing::TestWithParam<InputTestCase> {};
+
+ TEST_P(ExpirationDate4DigitYearPositive, ExpirationDate4DigitYearRegexes) {
+ auto test_case = GetParam();
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
SCOPED_TRACE(test_case.input);
- EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input),pattern));
+ EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
}
- const TestCase kNegativeCases[] = {
- {""},
- {"Look, ma' -- an invalid string!"},
- {"mmfavouritewordyy"},
- {"mm a yy"},
- {"mm a yyyy"},
- // Simple two year cases
- {"mm / yy"},
- {"mm/ yy"},
- {"mm /yy"},
- {"mm/yy"},
- {"mm - yy"},
- {"mm- yy"},
- {"mm -yy"},
- {"mm-yy"},
- {"mmyy"},
- // Complex two year cases
- {"Expiration Date (MM / YY)"},
- {"Expiration Date (MM/YY)"},
- {"Expiration Date (MM - YY)"},
- {"Expiration Date (MM-YY)"},
- {"Expiration Date MM / YY"},
- {"Expiration Date MM/YY"},
- {"Expiration Date MM - YY"},
- {"Expiration Date MM-YY"},
- {"expiration date yy"},
- {"Exp Date (MM / YY)"},
- };
-
- for (const auto& test_case : kNegativeCases) {
+ INSTANTIATE_TEST_CASE_P(AutofillRegexes,
+ ExpirationDate4DigitYearPositive,
+ testing::Values(
+ // Simple four year cases
+ InputTestCase{"mm / yyyy"},
+ InputTestCase{"mm/ yyyy"},
+ InputTestCase{"mm /yyyy"},
+ InputTestCase{"mm/yyyy"},
+ InputTestCase{"mm - yyyy"},
+ InputTestCase{"mm- yyyy"},
+ InputTestCase{"mm -yyyy"},
+ InputTestCase{"mm-yyyy"},
+ InputTestCase{"mmyyyy"},
+ // Complex four year cases
+ InputTestCase{"Expiration Date (MM / YYYY)"},
+ InputTestCase{"Expiration Date (MM/YYYY)"},
+ InputTestCase{"Expiration Date (MM - YYYY)"},
+ InputTestCase{"Expiration Date (MM-YYYY)"},
+ InputTestCase{"Expiration Date MM / YYYY"},
+ InputTestCase{"Expiration Date MM/YYYY"},
+ InputTestCase{"Expiration Date MM - YYYY"},
+ InputTestCase{"Expiration Date MM-YYYY"},
+ InputTestCase{"expiration date yyyy"},
+ InputTestCase{"Exp Date (MM / YYYY)"}));
+
+ class ExpirationDate4DigitYearNegative
+ : public testing::TestWithParam<InputTestCase> {};
+
+ TEST_P(ExpirationDate4DigitYearNegative, ExpirationDate4DigitYearRegexes) {
+ auto test_case = GetParam();
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
SCOPED_TRACE(test_case.input);
EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
- }
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillRegexes,
+ ExpirationDate4DigitYearNegative,
+ testing::Values(InputTestCase{""},
+ InputTestCase{"Look, ma' -- an invalid string!"},
+ InputTestCase{"mmfavouritewordyy"},
+ InputTestCase{"mm a yy"},
+ InputTestCase{"mm a yyyy"},
+ // Simple two year cases
+ InputTestCase{"mm / yy"},
+ InputTestCase{"mm/ yy"},
+ InputTestCase{"mm /yy"},
+ InputTestCase{"mm/yy"},
+ InputTestCase{"mm - yy"},
+ InputTestCase{"mm- yy"},
+ InputTestCase{"mm -yy"},
+ InputTestCase{"mm-yy"},
+ InputTestCase{"mmyy"},
+ // Complex two year cases
+ InputTestCase{"Expiration Date (MM / YY)"},
+ InputTestCase{"Expiration Date (MM/YY)"},
+ InputTestCase{"Expiration Date (MM - YY)"},
+ InputTestCase{"Expiration Date (MM-YY)"},
+ InputTestCase{"Expiration Date MM / YY"},
+ InputTestCase{"Expiration Date MM/YY"},
+ InputTestCase{"Expiration Date MM - YY"},
+ InputTestCase{"Expiration Date MM-YY"},
+ InputTestCase{"expiration date yy"},
+ InputTestCase{"Exp Date (MM / YY)"}));
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_util_unittest.cc b/chromium/components/autofill/core/common/autofill_util_unittest.cc
index 2115b3ed3ab..6e04dc76031 100644
--- a/chromium/components/autofill/core/common/autofill_util_unittest.cc
+++ b/chromium/components/autofill/core/common/autofill_util_unittest.cc
@@ -15,7 +15,18 @@
namespace autofill {
// Tests for FieldIsSuggestionSubstringStartingOnTokenBoundary().
-TEST(AutofillUtilTest, FieldIsSuggestionSubstringStartingOnTokenBoundary) {
+struct FieldIsTokenBoundarySubstringCase {
+ const char* const field_suggestion;
+ const char* const field_contents;
+ const bool case_sensitive;
+ const bool expected_result;
+};
+
+class FieldIsTokenBoundarySubstringCaseTest
+ : public testing::TestWithParam<FieldIsTokenBoundarySubstringCase> {};
+
+TEST_P(FieldIsTokenBoundarySubstringCaseTest,
+ FieldIsSuggestionSubstringStartingOnTokenBoundary) {
// FieldIsSuggestionSubstringStartingOnTokenBoundary should not work yet
// without a flag.
EXPECT_FALSE(FieldIsSuggestionSubstringStartingOnTokenBoundary(
@@ -25,106 +36,124 @@ TEST(AutofillUtilTest, FieldIsSuggestionSubstringStartingOnTokenBoundary) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableSuggestionsWithSubstringMatch);
- const struct {
- const char* const field_suggestion;
- const char* const field_contents;
- bool case_sensitive;
- bool expected_result;
- } kTestCases[] = {
- {"ab@cd.b", "a", false, true},
- {"ab@cd.b", "b", false, true},
- {"ab@cd.b", "Ab", false, true},
- {"ab@cd.b", "Ab", true, false},
- {"ab@cd.b", "cd", true, true},
- {"ab@cd.b", "d", false, false},
- {"ab@cd.b", "b@", true, false},
- {"ab@cd.b", "ab", false, true},
- {"ab@cd.b", "cd.b", true, true},
- {"ab@cd.b", "b@cd", false, false},
- {"ab@cd.b", "ab@c", false, true},
- {"ba.a.ab", "a.a", false, true},
- {"", "ab", false, false},
- {"", "ab", true, false},
- {"ab", "", false, true},
- {"ab", "", true, true},
- };
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message()
- << "suggestion = " << test_case.field_suggestion
- << ", contents = " << test_case.field_contents
- << ", case_sensitive = " << test_case.case_sensitive);
-
- EXPECT_EQ(test_case.expected_result,
- FieldIsSuggestionSubstringStartingOnTokenBoundary(
- base::ASCIIToUTF16(test_case.field_suggestion),
- base::ASCIIToUTF16(test_case.field_contents),
- test_case.case_sensitive));
- }
+ auto test_case = GetParam();
+ SCOPED_TRACE(testing::Message()
+ << "suggestion = " << test_case.field_suggestion
+ << ", contents = " << test_case.field_contents
+ << ", case_sensitive = " << test_case.case_sensitive);
+
+ EXPECT_EQ(test_case.expected_result,
+ FieldIsSuggestionSubstringStartingOnTokenBoundary(
+ base::ASCIIToUTF16(test_case.field_suggestion),
+ base::ASCIIToUTF16(test_case.field_contents),
+ test_case.case_sensitive));
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillUtilTest,
+ FieldIsTokenBoundarySubstringCaseTest,
+ testing::Values(
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "a", false, true},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "b", false, true},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "Ab", false, true},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "Ab", true, false},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "cd", true, true},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "d", false, false},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "b@", true, false},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "ab", false, true},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "cd.b", true, true},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "b@cd", false, false},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "ab@c", false, true},
+ FieldIsTokenBoundarySubstringCase{"ba.a.ab", "a.a", false, true},
+ FieldIsTokenBoundarySubstringCase{"", "ab", false, false},
+ FieldIsTokenBoundarySubstringCase{"", "ab", true, false},
+ FieldIsTokenBoundarySubstringCase{"ab", "", false, true},
+ FieldIsTokenBoundarySubstringCase{"ab", "", true, true}));
+
// Tests for GetTextSelectionStart().
-TEST(AutofillUtilTest, GetTextSelectionStart) {
- const size_t kInvalid = base::string16::npos;
- const struct {
- const char* const field_suggestion;
- const char* const field_contents;
- bool case_sensitive;
- size_t expected_start;
- } kTestCases[] = {
- {"ab@cd.b", "a", false, 1},
- {"ab@cd.b", "A", true, kInvalid},
- {"ab@cd.b", "Ab", false, 2},
- {"ab@cd.b", "Ab", true, kInvalid},
- {"ab@cd.b", "cd", false, 5},
- {"ab@cd.b", "ab@c", false, 4},
- {"ab@cd.b", "cd.b", false, 7},
- {"ab@cd.b", "b@cd", false, kInvalid},
- {"ab@cd.b", "b", false, 7},
- {"ba.a.ab", "a.a", false, 6},
- {"texample@example.com", "example", false, 16},
- };
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message()
- << "suggestion = " << test_case.field_suggestion
- << ", contents = " << test_case.field_contents
- << ", case_sensitive = " << test_case.case_sensitive);
-
- EXPECT_EQ(
- test_case.expected_start,
- GetTextSelectionStart(base::ASCIIToUTF16(test_case.field_suggestion),
- base::ASCIIToUTF16(test_case.field_contents),
- test_case.case_sensitive));
- }
+struct GetTextSelectionStartCase {
+ const char* const field_suggestion;
+ const char* const field_contents;
+ const bool case_sensitive;
+ const size_t expected_start;
+};
+
+class GetTextSelectionStartTest
+ : public testing::TestWithParam<GetTextSelectionStartCase> {};
+
+TEST_P(GetTextSelectionStartTest, GetTextSelectionStart) {
+ auto test_case = GetParam();
+ SCOPED_TRACE(testing::Message()
+ << "suggestion = " << test_case.field_suggestion
+ << ", contents = " << test_case.field_contents
+ << ", case_sensitive = " << test_case.case_sensitive);
+ EXPECT_EQ(
+ test_case.expected_start,
+ GetTextSelectionStart(base::ASCIIToUTF16(test_case.field_suggestion),
+ base::ASCIIToUTF16(test_case.field_contents),
+ test_case.case_sensitive));
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillUtilTest,
+ GetTextSelectionStartTest,
+ testing::Values(
+ GetTextSelectionStartCase{"ab@cd.b", "a", false, 1},
+ GetTextSelectionStartCase{"ab@cd.b", "A", true, base::string16::npos},
+ GetTextSelectionStartCase{"ab@cd.b", "Ab", false, 2},
+ GetTextSelectionStartCase{"ab@cd.b", "Ab", true, base::string16::npos},
+ GetTextSelectionStartCase{"ab@cd.b", "cd", false, 5},
+ GetTextSelectionStartCase{"ab@cd.b", "ab@c", false, 4},
+ GetTextSelectionStartCase{"ab@cd.b", "cd.b", false, 7},
+ GetTextSelectionStartCase{"ab@cd.b", "b@cd", false,
+ base::string16::npos},
+ GetTextSelectionStartCase{"ab@cd.b", "b", false, 7},
+ GetTextSelectionStartCase{"ba.a.ab", "a.a", false, 6},
+ GetTextSelectionStartCase{"texample@example.com", "example", false,
+ 16}));
+
// Tests for LowercaseAndTokenizeAttributeString
-TEST(AutofillUtilTest, LowercaseAndTokenizeAttributeString) {
- const struct {
- const char* const attribute;
- std::vector<std::string> tokens;
- } kTestCases[] = {
- // Test leading and trailing whitespace, test tabs and newlines
- {"foo bar baz", {"foo", "bar", "baz"}},
- {" foo bar baz ", {"foo", "bar", "baz"}},
- {"foo\tbar baz ", {"foo", "bar", "baz"}},
- {"foo\nbar baz ", {"foo", "bar", "baz"}},
-
- // Test different forms of capitalization
- {"FOO BAR BAZ", {"foo", "bar", "baz"}},
- {"foO baR bAz", {"foo", "bar", "baz"}},
-
- // Test collapsing of multiple whitespace characters in a row
- {" \t\t\n\n ", std::vector<std::string>()},
- {"foO baR bAz", {"foo", "bar", "baz"}},
- };
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message() << "attribute = " << test_case.attribute);
-
- EXPECT_EQ(test_case.tokens,
- LowercaseAndTokenizeAttributeString(test_case.attribute));
- }
+struct LowercaseAndTokenizeAttributeStringCase {
+ const char* const attribute;
+ std::vector<std::string> tokens;
+};
+
+class LowercaseAndTokenizeAttributeStringTest
+ : public testing::TestWithParam<LowercaseAndTokenizeAttributeStringCase> {};
+
+TEST_P(LowercaseAndTokenizeAttributeStringTest,
+ LowercaseAndTokenizeAttributeStringTest) {
+ auto test_case = GetParam();
+ SCOPED_TRACE(testing::Message() << "attribute = " << test_case.attribute);
+
+ EXPECT_EQ(test_case.tokens,
+ LowercaseAndTokenizeAttributeString(test_case.attribute));
}
+
+INSTANTIATE_TEST_CASE_P(
+ AutofillUtilTest,
+ LowercaseAndTokenizeAttributeStringTest,
+ testing::Values(
+ // Test leading and trailing whitespace, test tabs and newlines
+ LowercaseAndTokenizeAttributeStringCase{"foo bar baz",
+ {"foo", "bar", "baz"}},
+ LowercaseAndTokenizeAttributeStringCase{" foo bar baz ",
+ {"foo", "bar", "baz"}},
+ LowercaseAndTokenizeAttributeStringCase{"foo\tbar baz ",
+ {"foo", "bar", "baz"}},
+ LowercaseAndTokenizeAttributeStringCase{"foo\nbar baz ",
+ {"foo", "bar", "baz"}},
+
+ // Test different forms of capitalization
+ LowercaseAndTokenizeAttributeStringCase{"FOO BAR BAZ",
+ {"foo", "bar", "baz"}},
+ LowercaseAndTokenizeAttributeStringCase{"foO baR bAz",
+ {"foo", "bar", "baz"}},
+
+ // Test collapsing of multiple whitespace characters in a row
+ LowercaseAndTokenizeAttributeStringCase{" \t\t\n\n ",
+ std::vector<std::string>()},
+ LowercaseAndTokenizeAttributeStringCase{"foO baR bAz",
+ {"foo", "bar", "baz"}}));
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/password_form.cc b/chromium/components/autofill/core/common/password_form.cc
index 3969e1ff4e4..17892915c65 100644
--- a/chromium/components/autofill/core/common/password_form.cc
+++ b/chromium/components/autofill/core/common/password_form.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 <algorithm>
#include <ostream>
#include <sstream>
@@ -40,9 +41,9 @@ void PasswordFormToJSON(const PasswordForm& form,
form.new_password_value_is_default);
target->SetBoolean("new_password_marked_by_site",
form.new_password_marked_by_site);
- target->SetString("other_possible_usernames",
- base::JoinString(form.other_possible_usernames,
- base::ASCIIToUTF16("|")));
+ target->SetString(
+ "other_possible_usernames",
+ OtherPossibleUsernamesToString(form.other_possible_usernames));
target->SetBoolean("blacklisted", form.blacklisted_by_user);
target->SetBoolean("preferred", form.preferred);
target->SetDouble("date_created", form.date_created.ToDoubleT());
@@ -167,6 +168,16 @@ bool LessThanUniqueKey::operator()(
return left->origin < right->origin;
}
+base::string16 OtherPossibleUsernamesToString(
+ const PossibleUsernamesVector& possible_usernames) {
+ std::vector<base::string16> pairs(possible_usernames.size());
+ std::transform(possible_usernames.begin(), possible_usernames.end(),
+ pairs.begin(), [](const PossibleUsernamePair& p) {
+ return p.first + base::ASCIIToUTF16("+") + p.second;
+ });
+ return base::JoinString(pairs, base::ASCIIToUTF16(", "));
+}
+
std::ostream& operator<<(std::ostream& os, PasswordForm::Layout layout) {
switch (layout) {
case PasswordForm::Layout::LAYOUT_OTHER:
diff --git a/chromium/components/autofill/core/common/password_form.h b/chromium/components/autofill/core/common/password_form.h
index 74716230236..8bcf44850a8 100644
--- a/chromium/components/autofill/core/common/password_form.h
+++ b/chromium/components/autofill/core/common/password_form.h
@@ -17,6 +17,12 @@
namespace autofill {
+// Pair of possible username value and field name that contained this value.
+using PossibleUsernamePair = std::pair<base::string16, base::string16>;
+
+// Vector of possible username values and corresponding field names.
+using PossibleUsernamesVector = std::vector<PossibleUsernamePair>;
+
// The PasswordForm struct encapsulates information about a login form,
// which can be an HTML form or a dialog with username/password text fields.
//
@@ -141,7 +147,7 @@ struct PasswordForm {
// determining the username are incorrect. Optional.
//
// When parsing an HTML form, this is typically empty.
- std::vector<base::string16> other_possible_usernames;
+ PossibleUsernamesVector other_possible_usernames;
// The name of the input element corresponding to the current password.
// Optional (improves scoring).
@@ -301,6 +307,10 @@ struct LessThanUniqueKey {
const std::unique_ptr<PasswordForm>& right) const;
};
+// Converts a vector of possible usernames to string.
+base::string16 OtherPossibleUsernamesToString(
+ const PossibleUsernamesVector& possible_usernames);
+
// For testing.
std::ostream& operator<<(std::ostream& os, PasswordForm::Layout layout);
std::ostream& operator<<(std::ostream& os, const PasswordForm& form);
diff --git a/chromium/components/autofill/core/common/password_form_fill_data.cc b/chromium/components/autofill/core/common/password_form_fill_data.cc
index 9b1383046e0..e53c160b3be 100644
--- a/chromium/components/autofill/core/common/password_form_fill_data.cc
+++ b/chromium/components/autofill/core/common/password_form_fill_data.cc
@@ -84,10 +84,17 @@ void InitPasswordFormFillData(
if (it.second->is_public_suffix_match ||
it.second->is_affiliation_based_match)
key.realm = it.second->signon_realm;
- result->other_possible_usernames[key] =
- it.second->other_possible_usernames;
}
}
}
+PasswordFormFillData ClearPasswordValues(const PasswordFormFillData& data) {
+ PasswordFormFillData result(data);
+ if (result.wait_for_username)
+ result.password_field.value.clear();
+ for (auto& credentials : result.additional_logins)
+ credentials.second.password.clear();
+ return result;
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/password_form_fill_data.h b/chromium/components/autofill/core/common/password_form_fill_data.h
index fd0f64fe84a..b7e8e27c0cd 100644
--- a/chromium/components/autofill/core/common/password_form_fill_data.h
+++ b/chromium/components/autofill/core/common/password_form_fill_data.h
@@ -63,6 +63,7 @@ struct PasswordFormFillData {
// that the original saved username is correct. This data is keyed by the
// saved username/password to ensure uniqueness, though the username is not
// used.
+ // TODO(crbug/188908). Remove |other_possible_usernames| or launch.
UsernamesCollection other_possible_usernames;
// Tells us whether we need to wait for the user to enter a valid username
@@ -96,6 +97,10 @@ void InitPasswordFormFillData(
bool enable_other_possible_usernames,
PasswordFormFillData* result);
+// Renderer needs to have only a password that should be autofilled, all other
+// passwords might be safety erased.
+PasswordFormFillData ClearPasswordValues(const PasswordFormFillData& data);
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_FILL_DATA_H__
diff --git a/chromium/components/autofill/core/common/password_form_generation_data.cc b/chromium/components/autofill/core/common/password_form_generation_data.cc
new file mode 100644
index 00000000000..521eabc1818
--- /dev/null
+++ b/chromium/components/autofill/core/common/password_form_generation_data.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 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/common/password_form_generation_data.h"
+
+namespace autofill {
+
+PasswordFormGenerationData::PasswordFormGenerationData() = default;
+
+PasswordFormGenerationData::PasswordFormGenerationData(
+ FormSignature form_signature,
+ FieldSignature field_signature)
+ : form_signature(form_signature), field_signature(field_signature) {}
+
+PasswordFormGenerationData::PasswordFormGenerationData(
+ const PasswordFormGenerationData& other) = default;
+
+PasswordFormGenerationData::~PasswordFormGenerationData() = default;
+
+} // namespace autofill
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 d010d9a8ddb..f14d2953821 100644
--- a/chromium/components/autofill/core/common/password_form_generation_data.h
+++ b/chromium/components/autofill/core/common/password_form_generation_data.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include "base/optional.h"
#include "base/strings/string16.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/signatures_util.h"
@@ -17,6 +18,12 @@ namespace autofill {
// Structure used for sending information from browser to renderer about on
// which fields password should be generated.
struct PasswordFormGenerationData {
+ PasswordFormGenerationData();
+ PasswordFormGenerationData(FormSignature form_signature,
+ FieldSignature field_signature);
+ PasswordFormGenerationData(const PasswordFormGenerationData& other);
+ ~PasswordFormGenerationData();
+
// The unique signature of form where password should be generated
// (see components/autofill/core/browser/form_structure.h).
FormSignature form_signature;
@@ -24,6 +31,10 @@ struct PasswordFormGenerationData {
// The unique signature of field where password should be generated
// (see components/autofill/core/browser/autofill_field.h).
FieldSignature field_signature;
+
+ // The unique signature of the confirmation field where the generated password
+ // should be copied to.
+ base::Optional<FieldSignature> confirmation_field_signature;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.cc b/chromium/components/autofill/core/common/save_password_progress_logger.cc
index 5fc676c20e9..8a55fdd2b36 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger.cc
+++ b/chromium/components/autofill/core/common/save_password_progress_logger.cc
@@ -18,7 +18,6 @@
using base::checked_cast;
using base::Value;
using base::DictionaryValue;
-using base::StringValue;
namespace autofill {
@@ -94,7 +93,7 @@ void SavePasswordProgressLogger::LogHTMLForm(
void SavePasswordProgressLogger::LogURL(
SavePasswordProgressLogger::StringID label,
const GURL& url) {
- LogValue(label, StringValue(ScrubURL(url)));
+ LogValue(label, Value(ScrubURL(url)));
}
void SavePasswordProgressLogger::LogBoolean(
@@ -117,7 +116,7 @@ void SavePasswordProgressLogger::LogNumber(
void SavePasswordProgressLogger::LogMessage(
SavePasswordProgressLogger::StringID message) {
- LogValue(STRING_MESSAGE, StringValue(GetStringFromID(message)));
+ LogValue(STRING_MESSAGE, Value(GetStringFromID(message)));
}
// static
@@ -144,7 +143,7 @@ std::string SavePasswordProgressLogger::ScrubElementID(
// static
std::string SavePasswordProgressLogger::ScrubElementID(std::string element_id) {
std::replace_if(element_id.begin(), element_id.end(), IsUnwantedInElementID,
- ' ');
+ '_');
return element_id;
}
@@ -391,6 +390,39 @@ std::string SavePasswordProgressLogger::GetStringFromID(
return "Form votes";
case SavePasswordProgressLogger::STRING_REUSE_FOUND:
return "Password reused from ";
+ case SavePasswordProgressLogger::STRING_GENERATION_DISABLED_SAVING_DISABLED:
+ return "Generation disabled: saving disabled";
+ case SavePasswordProgressLogger::STRING_GENERATION_DISABLED_NO_SYNC:
+ return "Generation disabled: no sync";
+ case SavePasswordProgressLogger::
+ STRING_GENERATION_DISABLED_CUSTOM_PASSPHRASE:
+ return "Generation disabled: custom passphrase";
+ case STRING_GENERATION_RENDERER_ENABLED:
+ return "Generation renderer enabled";
+ case STRING_GENERATION_RENDERER_INVALID_PASSWORD_FORM:
+ return "Generation invalid PasswordForm";
+ case STRING_GENERATION_RENDERER_POSSIBLE_ACCOUNT_CREATION_FORMS:
+ return "Generation possible account creation forms";
+ case STRING_GENERATION_RENDERER_NO_PASSWORD_MANAGER_ACCESS:
+ return "Generation: no PasswordManager access";
+ case STRING_GENERATION_RENDERER_FORM_ALREADY_FOUND:
+ return "Generation: account creation form already found";
+ case STRING_GENERATION_RENDERER_NO_POSSIBLE_CREATION_FORMS:
+ return "Generation: no possible account creation forms";
+ case STRING_GENERATION_RENDERER_NOT_BLACKLISTED:
+ return "Generation: no non-blacklisted confirmation";
+ case STRING_GENERATION_RENDERER_AUTOCOMPLETE_ATTRIBUTE:
+ return "Generation: autocomplete attributes found";
+ case STRING_GENERATION_RENDERER_NO_SERVER_SIGNAL:
+ return "Generation: no server signal";
+ case STRING_GENERATION_RENDERER_ELIGIBLE_FORM_FOUND:
+ return "Generation: eligible form found";
+ case STRING_GENERATION_RENDERER_NO_FIELD_FOUND:
+ return "Generation: fields for generation are not found";
+ case STRING_GENERATION_RENDERER_SHOW_GENERATION_POPUP:
+ return "Show generation popup";
+ case STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED:
+ return "Generated password accepted";
case SavePasswordProgressLogger::STRING_INVALID:
return "INVALID";
// Intentionally no default: clause here -- all IDs need to get covered.
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.h b/chromium/components/autofill/core/common/save_password_progress_logger.h
index de8a08232b4..19c9e04c0dd 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger.h
+++ b/chromium/components/autofill/core/common/save_password_progress_logger.h
@@ -150,6 +150,22 @@ class SavePasswordProgressLogger {
STRING_SERVER_PREDICTIONS,
STRING_FORM_VOTES,
STRING_REUSE_FOUND,
+ STRING_GENERATION_DISABLED_SAVING_DISABLED,
+ STRING_GENERATION_DISABLED_NO_SYNC,
+ STRING_GENERATION_DISABLED_CUSTOM_PASSPHRASE,
+ STRING_GENERATION_RENDERER_ENABLED,
+ STRING_GENERATION_RENDERER_INVALID_PASSWORD_FORM,
+ STRING_GENERATION_RENDERER_POSSIBLE_ACCOUNT_CREATION_FORMS,
+ STRING_GENERATION_RENDERER_NO_PASSWORD_MANAGER_ACCESS,
+ STRING_GENERATION_RENDERER_FORM_ALREADY_FOUND,
+ STRING_GENERATION_RENDERER_NO_POSSIBLE_CREATION_FORMS,
+ STRING_GENERATION_RENDERER_NOT_BLACKLISTED,
+ STRING_GENERATION_RENDERER_AUTOCOMPLETE_ATTRIBUTE,
+ STRING_GENERATION_RENDERER_NO_SERVER_SIGNAL,
+ STRING_GENERATION_RENDERER_ELIGIBLE_FORM_FOUND,
+ STRING_GENERATION_RENDERER_NO_FIELD_FOUND,
+ STRING_GENERATION_RENDERER_SHOW_GENERATION_POPUP,
+ STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED,
STRING_INVALID, // Represents a string returned in a case of an error.
STRING_MAX = STRING_INVALID
};
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc b/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
index f047183d414..a20d11946af 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
+++ b/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
@@ -63,11 +63,11 @@ TEST(SavePasswordProgressLoggerTest, LogPasswordFormElementID) {
TestLogger logger;
PasswordForm form;
const std::string kHTMLInside("Username <script> element");
- const std::string kHTMLInsideExpected("Username script element");
+ const std::string kHTMLInsideExpected("Username__script__element");
const std::string kIPAddressInside("y128.0.0.1Y");
- const std::string kIPAddressInsideExpected("y128 0 0 1Y");
+ const std::string kIPAddressInsideExpected("y128_0_0_1Y");
const std::string kSpecialCharsInside("X@#a$%B&*c()D;:e+!x");
- const std::string kSpecialCharsInsideExpected("X a B c D e x");
+ const std::string kSpecialCharsInsideExpected("X__a__B__c__D__e__x");
form.username_element = UTF8ToUTF16(kHTMLInside);
form.password_element = UTF8ToUTF16(kIPAddressInside);
form.new_password_element = UTF8ToUTF16(kSpecialCharsInside);
diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios.h b/chromium/components/autofill/ios/browser/autofill_driver_ios.h
index c6678f31c49..cae6b8663e6 100644
--- a/chromium/components/autofill/ios/browser/autofill_driver_ios.h
+++ b/chromium/components/autofill/ios/browser/autofill_driver_ios.h
@@ -34,7 +34,7 @@ class AutofillDriverIOS : public AutofillDriver,
AutofillManager::AutofillDownloadManagerState enable_download_manager);
// AutofillDriver:
- bool IsOffTheRecord() const override;
+ bool IsIncognito() const override;
net::URLRequestContextGetter* GetURLRequestContext() override;
bool RendererIsAvailable() override;
void SendFormDataToRenderer(int query_id,
diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios.mm b/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
index 08384ae36ad..1f2deba8ef4 100644
--- a/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
+++ b/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
@@ -46,7 +46,7 @@ AutofillDriverIOS::AutofillDriverIOS(
AutofillDriverIOS::~AutofillDriverIOS() {}
-bool AutofillDriverIOS::IsOffTheRecord() const {
+bool AutofillDriverIOS::IsIncognito() const {
return web_state_->GetBrowserState()->IsOffTheRecord();
}
diff --git a/chromium/components/autofill_strings.grdp b/chromium/components/autofill_strings.grdp
index 22cf48fb601..2ab82162de1 100644
--- a/chromium/components/autofill_strings.grdp
+++ b/chromium/components/autofill_strings.grdp
@@ -210,6 +210,9 @@
<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. 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_ENTER_CVC" desc="Text displayed in the Autofill save credit card prompt explaining that the card needs additional CVC information in order to be saved to Google Payments.">
+ Please verify your CVC
+ </message>
<!-- Autofill credit card suggestion popup -->
<message name="IDS_AUTOFILL_CREDIT_CARD_EXPIRATION_DATE_ABBR" desc="Abbreviated label for credit card expiration date. [CHAR-LIMIT=32]">
@@ -343,4 +346,10 @@
<message name="IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC" desc="The placeholder/label text for credit card verification code in the requestAutocomplete dialog.">
CVC
</message>
+ <message name="IDS_AUTOFILL_LOADING_REGIONS" desc="The string to display in the regions combo box while loading the region data.">
+ Loading...
+ </message>
+ <message name="IDS_AUTOFILL_FAILED_LOADING_REGIONS" desc="The string to display in the regions combo box when loading the region data failed.">
+ Failed loading regions data
+ </message>
</grit-part>
diff --git a/chromium/components/background_task_scheduler/README.md b/chromium/components/background_task_scheduler/README.md
index c48720d51da..bc83b48d005 100644
--- a/chromium/components/background_task_scheduler/README.md
+++ b/chromium/components/background_task_scheduler/README.md
@@ -7,21 +7,39 @@ instead of using things like `IntentService` or polling using alarms. Using the
system API is beneficial as it has a full view of what goes on in the system and
can schedule jobs accordingly.
-However, this functionality was introduced in Android L, and
-the API has been very stable since Android M. This means that we also need a
-similar framework for older versions of Android, which is provided by
-Google Play services. We prefer system APIs, since they do not require including
-external libraries which bloats the APK size of Chrome and adds unnecessary
-complexity. The GcmNetworkManager is only used when the system API is not
-available.
-
-The `background_task_scheduler` component provides a new framework for use
-within chromium to schedule and execute background jobs using the frameworks
-available on a given version of Android.
-The public API of the framework is similar to that of the Android
-`JobScheduler`, but it is backed by either the system `JobScheduler` API or by
-GcmNetworkManager. What service is used to back the framework remains unknown to
-callers of the API.
+However, that leaves an API gap for Android L and below. Prior to Android L, the
+`JobScheduler` API was not available at all. It was introduced in Android L; but
+is not recommended on that platform, because it limits task execution time to 1
+minute. This is not really practically usable. For example, merely setting up a
+network connection will often burn through much of that budget. Android M+
+extends this execution time limit to 10 minutes.
+
+For these older platforms, we can leverage the GcmNetworkManager API provided by
+Google Play services to implement a suitable replacement for the JobScheduler
+API. The `background_task_scheduler` component provides a new framework for use
+within Chromium to schedule and execute background jobs using the frameworks
+available on a given version of Android. The public API of the framework is
+similar to that of the Android `JobScheduler`, but it is backed by either the
+system `JobScheduler` API or by GcmNetworkManager. What service is used to back
+the framework remains a black box to callers of the API.
+
+In practice, we prefer to use system APIs, since they do not require including
+external libraries, which would bloat the APK size of Chrome and add unnecessary
+complexity. Thus, the GcmNetworkManager is only used when the system API is not
+available (or available but not considered stable enough). That is, the
+JobScheduler API is used on Android M+; and the GcmNetworkManager is used
+otherwise.
+
+> **WARNING: The GcmNetworkManager fallback is not yet implemented.** Please
+> treat the above as a target state, and do not yet add any dependencies on the
+> BackgroundTaskScheduler API that require pre-M compatibility.
+
+> NOTE: Even with the GcmNetworkManager fallback, there are devices that would
+> remain unsupported, as not all devices have Google Play services
+> available. Ultimately, this component hopes to provide a full compatibility
+> layer on top of `JobScheduler`. However, until that is implemented, please be
+> thoughtful about whether this component provides the coverage that your
+> background task needs.
## What is a task
@@ -95,14 +113,14 @@ When the task is ready for scheduling, you use the
`BackgroundTaskScheduler` and use it to schedule the job.
```java
-BackgroundTaskScheduleFactory.getScheduler().schedule(myTaskInfo);
+BackgroundTaskSchedulerFactory.getScheduler().schedule(myTaskInfo);
```
If you ever need to cancel a task, you can do that by calling `cancel`, and
passing in the task ID:
```java
-BackgroundTaskScheduleFactory.getScheduler().cancel(TaskIds.YOUR_FEATURE);
+BackgroundTaskSchedulerFactory.getScheduler().cancel(TaskIds.YOUR_FEATURE);
```
## Passing task arguments
diff --git a/chromium/components/bookmarks/browser/bookmark_codec.cc b/chromium/components/bookmarks/browser/bookmark_codec.cc
index 38a37844579..abbb1cd7b64 100644
--- a/chromium/components/bookmarks/browser/bookmark_codec.cc
+++ b/chromium/components/bookmarks/browser/bookmark_codec.cc
@@ -89,7 +89,7 @@ base::Value* BookmarkCodec::Encode(
// We are going to store the computed checksum. So set stored checksum to be
// the same as computed checksum.
stored_checksum_ = computed_checksum_;
- main->Set(kChecksumKey, new base::StringValue(computed_checksum_));
+ main->Set(kChecksumKey, new base::Value(computed_checksum_));
main->Set(kRootsKey, roots);
return main;
}
diff --git a/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker.cc b/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker.cc
index 427f2d3c446..dd3070b039c 100644
--- a/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker.cc
+++ b/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker.cc
@@ -50,7 +50,7 @@ BookmarkExpandedStateTracker::GetExpandedNodes() {
std::string value;
int64_t node_id;
const BookmarkNode* node;
- if ((*i)->GetAsString(&value) && base::StringToInt64(value, &node_id) &&
+ if (i->GetAsString(&value) && base::StringToInt64(value, &node_id) &&
(node = GetBookmarkNodeByID(bookmark_model_, node_id)) != NULL &&
node->is_folder()) {
nodes.insert(node);
@@ -107,7 +107,7 @@ void BookmarkExpandedStateTracker::UpdatePrefs(const Nodes& nodes) {
base::ListValue values;
for (Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i) {
values.Set(values.GetSize(),
- new base::StringValue(base::Int64ToString((*i)->id())));
+ new base::Value(base::Int64ToString((*i)->id())));
}
pref_service_->Set(prefs::kBookmarkEditorExpandedNodes, values);
diff --git a/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc b/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc
index 10534745e5b..57c2f1bc570 100644
--- a/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc
+++ b/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc
@@ -44,7 +44,7 @@ BookmarkExpandedStateTrackerTest::~BookmarkExpandedStateTrackerTest() {}
void BookmarkExpandedStateTrackerTest::SetUp() {
prefs_.registry()->RegisterListPref(prefs::kBookmarkEditorExpandedNodes,
- new base::ListValue);
+ base::MakeUnique<base::ListValue>());
prefs_.registry()->RegisterListPref(prefs::kManagedBookmarks);
model_.reset(new BookmarkModel(base::MakeUnique<TestBookmarkClient>()));
model_->Load(&prefs_, base::FilePath(),
diff --git a/chromium/components/bookmarks/browser/bookmark_utils.cc b/chromium/components/bookmarks/browser/bookmark_utils.cc
index a2e114a561f..2f1bd29a657 100644
--- a/chromium/components/bookmarks/browser/bookmark_utils.cc
+++ b/chromium/components/bookmarks/browser/bookmark_utils.cc
@@ -13,6 +13,7 @@
#include "base/i18n/case_conversion.h"
#include "base/i18n/string_search.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/user_metrics_action.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -461,7 +462,7 @@ void RegisterManagedBookmarksPrefs(PrefRegistrySimple* registry) {
// want to sync the expanded state of folders, it should be part of
// bookmark sync itself (i.e., a property of the sync folder nodes).
registry->RegisterListPref(prefs::kBookmarkEditorExpandedNodes,
- new base::ListValue);
+ base::MakeUnique<base::ListValue>());
registry->RegisterListPref(prefs::kManagedBookmarks);
registry->RegisterStringPref(
prefs::kManagedBookmarksFolderName, std::string());
diff --git a/chromium/components/bookmarks/browser/titled_url_index.cc b/chromium/components/bookmarks/browser/titled_url_index.cc
index abde1aa9e54..fa9ed7647eb 100644
--- a/chromium/components/bookmarks/browser/titled_url_index.cc
+++ b/chromium/components/bookmarks/browser/titled_url_index.cc
@@ -7,6 +7,7 @@
#include <stdint.h>
#include "base/i18n/case_conversion.h"
+#include "base/i18n/unicodestring.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/utf_offset_string_conversions.h"
@@ -42,8 +43,7 @@ base::string16 Normalize(const base::string16& text) {
LOG(ERROR) << "normalization failed: " << u_errorName(status);
return text;
}
- return base::string16(unicode_normalized_text.getBuffer(),
- unicode_normalized_text.length());
+ return base::i18n::UnicodeStringToString16(unicode_normalized_text);
}
} // namespace
diff --git a/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc b/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
index f76a19688d1..3cd88d9ffe9 100644
--- a/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
+++ b/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
@@ -111,22 +111,21 @@ class ManagedBookmarksTrackerTest : public testing::Test {
static std::unique_ptr<base::DictionaryValue> CreateFolder(
const std::string& title,
- base::ListValue* children) {
+ std::unique_ptr<base::ListValue> children) {
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("name", title);
- dict->Set("children", children);
+ dict->Set("children", std::move(children));
return dict;
}
- static base::ListValue* CreateTestTree() {
- base::ListValue* folder = new base::ListValue();
- base::ListValue* empty = new base::ListValue();
- folder->Append(CreateFolder("Empty", empty));
+ static std::unique_ptr<base::ListValue> CreateTestTree() {
+ auto folder = base::MakeUnique<base::ListValue>();
+ folder->Append(CreateFolder("Empty", base::MakeUnique<base::ListValue>()));
folder->Append(CreateBookmark("Youtube", "http://youtube.com/"));
- base::ListValue* list = new base::ListValue();
+ auto list = base::MakeUnique<base::ListValue>();
list->Append(CreateBookmark("Google", "http://google.com/"));
- list->Append(CreateFolder("Folder", folder));
+ list->Append(CreateFolder("Folder", std::move(folder)));
return list;
}
@@ -248,12 +247,12 @@ TEST_F(ManagedBookmarksTrackerTest, SwapNodes) {
// These two nodes should just be swapped.
const BookmarkNode* parent = managed_node();
EXPECT_CALL(observer_, BookmarkNodeMoved(model_.get(), parent, 1, parent, 0));
- prefs_.SetManagedPref(prefs::kManagedBookmarks, updated->DeepCopy());
+ prefs_.SetManagedPref(prefs::kManagedBookmarks, updated->CreateDeepCopy());
Mock::VerifyAndClearExpectations(&observer_);
// Verify the final tree.
std::unique_ptr<base::DictionaryValue> expected(
- CreateFolder(GetManagedFolderTitle(), updated.release()));
+ CreateFolder(GetManagedFolderTitle(), std::move(updated)));
EXPECT_TRUE(NodeMatchesValue(managed_node(), expected.get()));
}
@@ -267,12 +266,12 @@ TEST_F(ManagedBookmarksTrackerTest, RemoveNode) {
const BookmarkNode* parent = managed_node();
EXPECT_CALL(observer_, BookmarkNodeRemoved(model_.get(), parent, 1, _, _));
- prefs_.SetManagedPref(prefs::kManagedBookmarks, updated->DeepCopy());
+ prefs_.SetManagedPref(prefs::kManagedBookmarks, updated->CreateDeepCopy());
Mock::VerifyAndClearExpectations(&observer_);
// Verify the final tree.
std::unique_ptr<base::DictionaryValue> expected(
- CreateFolder(GetManagedFolderTitle(), updated.release()));
+ CreateFolder(GetManagedFolderTitle(), std::move(updated)));
EXPECT_TRUE(NodeMatchesValue(managed_node(), expected.get()));
}
@@ -290,12 +289,12 @@ TEST_F(ManagedBookmarksTrackerTest, CreateNewNodes) {
const BookmarkNode* parent = managed_node();
EXPECT_CALL(observer_, BookmarkNodeRemoved(model_.get(), parent, 1, _, _))
.Times(2);
- prefs_.SetManagedPref(prefs::kManagedBookmarks, updated->DeepCopy());
+ prefs_.SetManagedPref(prefs::kManagedBookmarks, updated->CreateDeepCopy());
Mock::VerifyAndClearExpectations(&observer_);
// Verify the final tree.
std::unique_ptr<base::DictionaryValue> expected(
- CreateFolder(GetManagedFolderTitle(), updated.release()));
+ CreateFolder(GetManagedFolderTitle(), std::move(updated)));
EXPECT_TRUE(NodeMatchesValue(managed_node(), expected.get()));
}
diff --git a/chromium/components/browser_sync/BUILD.gn b/chromium/components/browser_sync/BUILD.gn
index 5b870f0a7ee..4c2e28742e6 100644
--- a/chromium/components/browser_sync/BUILD.gn
+++ b/chromium/components/browser_sync/BUILD.gn
@@ -33,8 +33,7 @@ static_library("browser_sync") {
"//components/password_manager/sync/browser",
"//components/pref_registry",
"//components/prefs",
- "//components/reading_list/core",
- "//components/reading_list/core:reading_list_enable_flags",
+ "//components/reading_list/core:flags",
"//components/signin/core/browser",
"//components/strings",
"//components/sync_bookmarks",
diff --git a/chromium/components/browser_sync/profile_sync_components_factory_impl.cc b/chromium/components/browser_sync/profile_sync_components_factory_impl.cc
index c5f9a8ddbeb..445b20bb221 100644
--- a/chromium/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/chromium/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -209,9 +209,14 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
// TypedUrl sync is enabled by default. Register unless explicitly disabled,
// or if saving history is disabled.
if (!disabled_types.Has(syncer::TYPED_URLS) && !history_disabled) {
- sync_service->RegisterDataTypeController(
- base::MakeUnique<TypedUrlDataTypeController>(
- error_callback, sync_client_, history_disabled_pref_));
+ if (base::FeatureList::IsEnabled(switches::kSyncUSSTypedURL)) {
+ // TODO(gangwu): Register controller here once typed url controller
+ // implemented.
+ } else {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<TypedUrlDataTypeController>(
+ error_callback, sync_client_, history_disabled_pref_));
+ }
}
// Delete directive sync is enabled by default. Register unless full history
diff --git a/chromium/components/browser_sync/profile_sync_service.cc b/chromium/components/browser_sync/profile_sync_service.cc
index 34924acfd23..5eb7949df19 100644
--- a/chromium/components/browser_sync/profile_sync_service.cc
+++ b/chromium/components/browser_sync/profile_sync_service.cc
@@ -148,9 +148,6 @@ const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = {
false,
};
-const base::FilePath::CharType kLevelDBFolderName[] =
- FILE_PATH_LITERAL("LevelDB");
-
} // namespace
ProfileSyncService::InitParams::InitParams() = default;
@@ -171,7 +168,6 @@ ProfileSyncService::ProfileSyncService(InitParams init_params)
network_time_update_callback_(
std::move(init_params.network_time_update_callback)),
url_request_context_(init_params.url_request_context),
- blocking_task_runner_(std::move(init_params.blocking_task_runner)),
is_first_time_sync_configure_(false),
engine_initialized_(false),
sync_disabled_by_admin_(false),
@@ -229,8 +225,8 @@ void ProfileSyncService::Initialize() {
base::Bind(&ProfileSyncService::CanEngineStart, base::Unretained(this)),
base::Bind(&ProfileSyncService::StartUpSlowEngineComponents,
weak_factory_.GetWeakPtr()));
- std::unique_ptr<sync_sessions::LocalSessionEventRouter> router(
- sync_client_->GetSyncSessionsClient()->GetLocalSessionEventRouter());
+ sync_sessions::LocalSessionEventRouter* router =
+ sync_client_->GetSyncSessionsClient()->GetLocalSessionEventRouter();
local_device_ = sync_client_->GetSyncApiComponentFactory()
->CreateLocalDeviceInfoProvider();
sync_stopped_reporter_ = base::MakeUnique<syncer::SyncStoppedReporter>(
@@ -249,8 +245,11 @@ void ProfileSyncService::Initialize() {
// TODO(skym): Stop creating leveldb files when signed out.
// TODO(skym): Verify using AsUTF8Unsafe is okay here. Should work as long
// as the Local State file is guaranteed to be UTF-8.
+ const syncer::ModelTypeStoreFactory& store_factory =
+ GetModelTypeStoreFactory(syncer::DEVICE_INFO, base_directory_,
+ sync_client_->GetBlockingPool());
device_info_sync_bridge_ = base::MakeUnique<DeviceInfoSyncBridge>(
- local_device_.get(), GetModelTypeStoreFactory(syncer::DEVICE_INFO),
+ local_device_.get(), store_factory,
base::BindRepeating(
&ModelTypeChangeProcessor::Create,
base::BindRepeating(&syncer::ReportUnrecoverableError, channel_)));
@@ -558,7 +557,7 @@ void ProfileSyncService::StartUpSlowEngineComponents() {
engine_.reset(sync_client_->GetSyncApiComponentFactory()->CreateSyncEngine(
debug_identifier_, invalidator, sync_prefs_.AsWeakPtr(),
- sync_data_folder_));
+ FormatSyncDataPath(base_directory_)));
// Clear any old errors the first time sync starts.
if (!IsFirstSetupComplete())
@@ -694,7 +693,7 @@ void ProfileSyncService::ShutdownImpl(syncer::ShutdownReason reason) {
sync_thread_->task_runner()->PostTask(
FROM_HERE,
base::Bind(&syncer::syncable::Directory::DeleteDirectoryFiles,
- sync_data_folder_));
+ FormatSyncDataPath(base_directory_)));
}
return;
}
@@ -930,7 +929,7 @@ void ProfileSyncService::OnEngineInitialized(
// Initialize local device info.
local_device_->Initialize(cache_guid, signin_scoped_device_id,
- blocking_task_runner_);
+ sync_client_->GetBlockingPool());
if (protocol_event_observers_.might_have_observers()) {
engine_->RequestBufferedProtocolEventsAndEnableForwarding();
@@ -1198,6 +1197,14 @@ void ProfileSyncService::OnClearServerDataDone() {
syncer::CLEAR_SERVER_DATA_MAX);
}
+void ProfileSyncService::ClearServerDataForTest(const base::Closure& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // Sync has a restriction that the engine must be in configuration mode
+ // in order to run clear server data.
+ engine_->StartConfiguration();
+ engine_->ClearServerData(callback);
+}
+
void ProfileSyncService::OnConfigureDone(
const DataTypeManager::ConfigureResult& result) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -1385,6 +1392,7 @@ bool ProfileSyncService::IsFirstSetupInProgress() const {
std::unique_ptr<syncer::SyncSetupInProgressHandle>
ProfileSyncService::GetSetupInProgressHandle() {
DCHECK(thread_checker_.CalledOnValidThread());
+
if (++outstanding_setup_in_progress_handles_ == 1) {
DCHECK(!startup_controller_->IsSetupInProgress());
startup_controller_->SetSetupInProgress(true);
@@ -1516,7 +1524,7 @@ void ProfileSyncService::UpdateSelectedTypesHistogram(
syncer::user_selectable_type::PROXY_TABS,
};
- static_assert(39 == syncer::MODEL_TYPE_COUNT,
+ static_assert(40 == syncer::MODEL_TYPE_COUNT,
"If adding a user selectable type, update "
"UserSelectableSyncType in user_selectable_sync_type.h and "
"histograms.xml.");
@@ -1670,12 +1678,21 @@ void ProfileSyncService::SetPlatformSyncAllowedProvider(
platform_sync_allowed_provider_ = platform_sync_allowed_provider;
}
+// static
syncer::ModelTypeStoreFactory ProfileSyncService::GetModelTypeStoreFactory(
- ModelType type) {
- return base::Bind(&ModelTypeStore::CreateStore, type,
- sync_data_folder_.Append(base::FilePath(kLevelDBFolderName))
- .AsUTF8Unsafe(),
- blocking_task_runner_);
+ ModelType type,
+ const base::FilePath& base_path,
+ base::SequencedWorkerPool* blocking_pool) {
+ // TODO(skym): Verify using AsUTF8Unsafe is okay here. Should work as long
+ // as the Local State file is guaranteed to be UTF-8.
+ std::string path = FormatSharedModelTypeStorePath(base_path).AsUTF8Unsafe();
+ base::SequencedWorkerPool::SequenceToken sequence_token =
+ blocking_pool->GetNamedSequenceToken(path);
+ scoped_refptr<base::SequencedTaskRunner> task_runner =
+ blocking_pool->GetSequencedTaskRunnerWithShutdownBehavior(
+ blocking_pool->GetNamedSequenceToken(path),
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+ return base::Bind(&ModelTypeStore::CreateStore, type, path, task_runner);
}
void ProfileSyncService::ConfigureDataTypeManager() {
@@ -1986,6 +2003,15 @@ void ProfileSyncService::OnGaiaAccountsInCookieUpdated(
const std::vector<gaia::ListedAccount>& accounts,
const std::vector<gaia::ListedAccount>& signed_out_accounts,
const GoogleServiceAuthError& error) {
+ OnGaiaAccountsInCookieUpdatedWithCallback(accounts, signed_out_accounts,
+ error, base::Closure());
+}
+
+void ProfileSyncService::OnGaiaAccountsInCookieUpdatedWithCallback(
+ const std::vector<gaia::ListedAccount>& accounts,
+ const std::vector<gaia::ListedAccount>& signed_out_accounts,
+ const GoogleServiceAuthError& error,
+ const base::Closure& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!IsEngineInitialized())
return;
@@ -2004,7 +2030,7 @@ void ProfileSyncService::OnGaiaAccountsInCookieUpdated(
DVLOG(1) << "Cookie jar mismatch: " << cookie_jar_mismatch;
DVLOG(1) << "Cookie jar empty: " << cookie_jar_empty;
- engine_->OnCookieJarChanged(cookie_jar_mismatch, cookie_jar_empty);
+ engine_->OnCookieJarChanged(cookie_jar_mismatch, cookie_jar_empty, callback);
}
void ProfileSyncService::AddProtocolEventObserver(
@@ -2084,9 +2110,11 @@ class GetAllNodesRequestHelper
virtual ~GetAllNodesRequestHelper();
std::unique_ptr<base::ListValue> result_accumulator_;
-
syncer::ModelTypeSet awaiting_types_;
base::Callback<void(std::unique_ptr<base::ListValue>)> callback_;
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(GetAllNodesRequestHelper);
};
GetAllNodesRequestHelper::GetAllNodesRequestHelper(
@@ -2109,6 +2137,8 @@ GetAllNodesRequestHelper::~GetAllNodesRequestHelper() {
void GetAllNodesRequestHelper::OnReceivedNodesForType(
const syncer::ModelType type,
std::unique_ptr<base::ListValue> node_list) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
// Add these results to our list.
std::unique_ptr<base::DictionaryValue> type_dict(new base::DictionaryValue());
type_dict->SetString("type", ModelTypeToString(type));
@@ -2330,7 +2360,7 @@ void ProfileSyncService::FlushDirectory() const {
base::FilePath ProfileSyncService::GetDirectoryPathForTest() const {
DCHECK(thread_checker_.CalledOnValidThread());
- return sync_data_folder_;
+ return FormatSyncDataPath(base_directory_);
}
base::MessageLoop* ProfileSyncService::GetSyncLoopForTest() const {
@@ -2426,5 +2456,4 @@ void ProfileSyncService::OnSetupInProgressHandleDestroyed() {
ReconfigureDatatypeManager();
NotifyObservers();
}
-
} // namespace browser_sync
diff --git a/chromium/components/browser_sync/profile_sync_service.h b/chromium/components/browser_sync/profile_sync_service.h
index 7048a483f89..88837d3b6ed 100644
--- a/chromium/components/browser_sync/profile_sync_service.h
+++ b/chromium/components/browser_sync/profile_sync_service.h
@@ -20,6 +20,7 @@
#include "base/message_loop/message_loop.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
+#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
@@ -56,7 +57,6 @@
#include "net/base/backoff_entry.h"
#include "url/gurl.h"
-class Profile;
class ProfileOAuth2TokenService;
class SigninManagerWrapper;
@@ -240,7 +240,6 @@ class ProfileSyncService : public syncer::SyncServiceBase,
scoped_refptr<net::URLRequestContextGetter> url_request_context;
std::string debug_identifier;
version_info::Channel channel = version_info::Channel::UNKNOWN;
- scoped_refptr<base::SequencedTaskRunner> blocking_task_runner;
private:
DISALLOW_COPY_AND_ASSIGN(InitParams);
@@ -396,6 +395,13 @@ class ProfileSyncService : public syncer::SyncServiceBase,
const std::vector<gaia::ListedAccount>& signed_out_accounts,
const GoogleServiceAuthError& error) override;
+ // Similar to above but with a callback that will be invoked on completion.
+ void OnGaiaAccountsInCookieUpdatedWithCallback(
+ const std::vector<gaia::ListedAccount>& accounts,
+ const std::vector<gaia::ListedAccount>& signed_out_accounts,
+ const GoogleServiceAuthError& error,
+ const base::Closure& callback);
+
// Get the sync status code.
SyncStatusSummary QuerySyncStatusSummary();
@@ -552,9 +558,13 @@ class ProfileSyncService : public syncer::SyncServiceBase,
const PlatformSyncAllowedProvider& platform_sync_allowed_provider);
// Returns a function for |type| that will create a ModelTypeStore that shares
- // the sync LevelDB backend.
- syncer::ModelTypeStoreFactory GetModelTypeStoreFactory(
- syncer::ModelType type);
+ // the sync LevelDB backend. |base_path| should be set to profile path.
+ // |sequenced_worker_pool| is obtained from content::BrowserThread or
+ // web::WebThread depending on platform.
+ static syncer::ModelTypeStoreFactory GetModelTypeStoreFactory(
+ syncer::ModelType type,
+ const base::FilePath& base_path,
+ base::SequencedWorkerPool* sequenced_worker_pool);
// Needed to test whether the directory is deleted properly.
base::FilePath GetDirectoryPathForTest() const;
@@ -568,6 +578,10 @@ class ProfileSyncService : public syncer::SyncServiceBase,
// Triggers sync cycle with request to update specified |types|.
void RefreshTypesForTest(syncer::ModelTypeSet types);
+ // Calls sync engine to send ClearServerDataMessage to server. This is used
+ // to start accounts with a clean slate when performing end to end testing.
+ void ClearServerDataForTest(const base::Closure& callback);
+
protected:
// SyncServiceBase implementation.
syncer::SyncCredentials GetCredentials() override;
@@ -759,9 +773,6 @@ class ProfileSyncService : public syncer::SyncServiceBase,
// The request context in which sync should operate.
scoped_refptr<net::URLRequestContextGetter> url_request_context_;
- // The task runner to use for blocking IO operations.
- scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-
// Indicates if this is the first time sync is being configured. This value
// is equal to !IsFirstSetupComplete() at the time of OnEngineInitialized().
bool is_first_time_sync_configure_;
diff --git a/chromium/components/browser_sync/profile_sync_service_mock.cc b/chromium/components/browser_sync/profile_sync_service_mock.cc
index d2dd85c1d21..4102a954b0b 100644
--- a/chromium/components/browser_sync/profile_sync_service_mock.cc
+++ b/chromium/components/browser_sync/profile_sync_service_mock.cc
@@ -18,4 +18,12 @@ ProfileSyncServiceMock::ProfileSyncServiceMock(InitParams* init_params)
ProfileSyncServiceMock::~ProfileSyncServiceMock() {}
+sync_sessions::OpenTabsUIDelegate*
+ProfileSyncServiceMock::GetOpenTabsUIDelegate() {
+ sync_sessions::OpenTabsUIDelegate* mock_delegate =
+ GetOpenTabsUIDelegateMock();
+ return mock_delegate ? mock_delegate
+ : ProfileSyncService::GetOpenTabsUIDelegate();
+}
+
} // namespace browser_sync
diff --git a/chromium/components/browser_sync/profile_sync_service_mock.h b/chromium/components/browser_sync/profile_sync_service_mock.h
index 29c1591cde4..35191d35e42 100644
--- a/chromium/components/browser_sync/profile_sync_service_mock.h
+++ b/chromium/components/browser_sync/profile_sync_service_mock.h
@@ -80,6 +80,9 @@ class ProfileSyncServiceMock : public ProfileSyncService {
MOCK_METHOD1(OnActionableError, void(const syncer::SyncProtocolError&));
MOCK_CONST_METHOD1(IsDataTypeControllerRunning, bool(syncer::ModelType));
+ MOCK_METHOD0(GetOpenTabsUIDelegateMock, sync_sessions::OpenTabsUIDelegate*());
+ sync_sessions::OpenTabsUIDelegate* GetOpenTabsUIDelegate() override;
+
// DataTypeManagerObserver mocks.
MOCK_METHOD1(OnConfigureDone,
void(const syncer::DataTypeManager::ConfigureResult&));
diff --git a/chromium/components/browser_sync/profile_sync_service_typed_url_unittest.cc b/chromium/components/browser_sync/profile_sync_service_typed_url_unittest.cc
index 440cd85be7e..db7db211a5e 100644
--- a/chromium/components/browser_sync/profile_sync_service_typed_url_unittest.cc
+++ b/chromium/components/browser_sync/profile_sync_service_typed_url_unittest.cc
@@ -144,7 +144,7 @@ class TestTypedUrlSyncableService : public TypedUrlSyncableService {
const history::VisitVector& visits,
syncer::WriteNode* node) {
sync_pb::TypedUrlSpecifics typed_url;
- WriteToTypedUrlSpecifics(url, visits, &typed_url);
+ ASSERT_TRUE(WriteToTypedUrlSpecifics(url, visits, &typed_url));
node->SetTypedUrlSpecifics(typed_url);
}
@@ -393,7 +393,7 @@ void AddTypedUrlEntries(ProfileSyncServiceTypedUrlTest* test,
for (size_t i = 0; i < entries.size(); ++i) {
history::VisitVector visits;
visits.push_back(history::VisitRow(entries[i].id(), entries[i].last_visit(),
- 0, ui::PageTransitionFromInt(0), 0));
+ 0, ui::PageTransitionFromInt(1), 0));
test->AddTypedUrlSyncNode(entries[i], visits);
}
}
diff --git a/chromium/components/browser_sync/profile_sync_service_unittest.cc b/chromium/components/browser_sync/profile_sync_service_unittest.cc
index 2c5d0ad7787..fc0d17f4356 100644
--- a/chromium/components/browser_sync/profile_sync_service_unittest.cc
+++ b/chromium/components/browser_sync/profile_sync_service_unittest.cc
@@ -15,6 +15,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
#include "base/test/sequenced_worker_pool_owner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
@@ -128,14 +129,12 @@ class FakeSyncEngineCollectDeleteDirParam : public FakeSyncEngine {
// called.
class SyncEngineCaptureClearServerData : public FakeSyncEngine {
public:
- using ClearServerDataCalled =
- base::Callback<void(const syncer::SyncManager::ClearServerDataCallback&)>;
+ using ClearServerDataCalled = base::Callback<void(const base::Closure&)>;
explicit SyncEngineCaptureClearServerData(
const ClearServerDataCalled& clear_server_data_called)
: clear_server_data_called_(clear_server_data_called) {}
- void ClearServerData(
- const syncer::SyncManager::ClearServerDataCallback& callback) override {
+ void ClearServerData(const base::Closure& callback) override {
clear_server_data_called_.Run(callback);
}
@@ -155,9 +154,8 @@ ACTION_P(ReturnNewMockHostCollectDeleteDirParam, delete_dir_param) {
return new FakeSyncEngineCollectDeleteDirParam(delete_dir_param);
}
-void OnClearServerDataCalled(
- syncer::SyncManager::ClearServerDataCallback* captured_callback,
- const syncer::SyncManager::ClearServerDataCallback& callback) {
+void OnClearServerDataCalled(base::Closure* captured_callback,
+ const base::Closure& callback) {
*captured_callback = callback;
}
@@ -305,7 +303,7 @@ class ProfileSyncServiceTest : public ::testing::Test {
}
void ExpectSyncEngineCreationCaptureClearServerData(
- syncer::SyncManager::ClearServerDataCallback* captured_callback) {
+ base::Closure* captured_callback) {
EXPECT_CALL(*component_factory_, CreateSyncEngine(_, _, _, _))
.Times(1)
.WillOnce(ReturnNewMockHostCaptureClearServerData(captured_callback));
@@ -353,7 +351,7 @@ class ProfileSyncServiceTest : public ::testing::Test {
}
private:
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
ProfileSyncServiceBundle profile_sync_service_bundle_;
std::unique_ptr<ProfileSyncService> service_;
@@ -373,7 +371,8 @@ TEST_F(ProfileSyncServiceTest, InitialState) {
// Verify a successful initialization.
TEST_F(ProfileSyncServiceTest, SuccessfulInitialization) {
- prefs()->SetManagedPref(syncer::prefs::kSyncManaged, new base::Value(false));
+ prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
+ base::MakeUnique<base::Value>(false));
IssueTestTokens();
CreateService(ProfileSyncService::AUTO_START);
ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
@@ -385,7 +384,8 @@ TEST_F(ProfileSyncServiceTest, SuccessfulInitialization) {
// Verify a successful initialization.
TEST_F(ProfileSyncServiceTest, SuccessfulLocalBackendInitialization) {
- prefs()->SetManagedPref(syncer::prefs::kSyncManaged, new base::Value(false));
+ prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
+ base::MakeUnique<base::Value>(false));
IssueTestTokens();
CreateServiceWithLocalSyncBackend();
ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
@@ -398,7 +398,8 @@ TEST_F(ProfileSyncServiceTest, SuccessfulLocalBackendInitialization) {
// Verify that an initialization where first setup is not complete does not
// start up the backend.
TEST_F(ProfileSyncServiceTest, NeedsConfirmation) {
- prefs()->SetManagedPref(syncer::prefs::kSyncManaged, new base::Value(false));
+ prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
+ base::MakeUnique<base::Value>(false));
IssueTestTokens();
CreateService(ProfileSyncService::MANUAL_START);
syncer::SyncPrefs sync_prefs(prefs());
@@ -433,7 +434,8 @@ TEST_F(ProfileSyncServiceTest, SetupInProgress) {
// Verify that disable by enterprise policy works.
TEST_F(ProfileSyncServiceTest, DisabledByPolicyBeforeInit) {
- prefs()->SetManagedPref(syncer::prefs::kSyncManaged, new base::Value(true));
+ prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
+ base::MakeUnique<base::Value>(true));
IssueTestTokens();
CreateService(ProfileSyncService::AUTO_START);
InitializeForNthSync();
@@ -453,7 +455,8 @@ TEST_F(ProfileSyncServiceTest, DisabledByPolicyAfterInit) {
EXPECT_FALSE(service()->IsManaged());
EXPECT_TRUE(service()->IsSyncActive());
- prefs()->SetManagedPref(syncer::prefs::kSyncManaged, new base::Value(true));
+ prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
+ base::MakeUnique<base::Value>(true));
EXPECT_TRUE(service()->IsManaged());
EXPECT_FALSE(service()->IsSyncActive());
@@ -705,7 +708,7 @@ TEST_F(ProfileSyncServiceTest, OnLocalSetPassphraseEncryption) {
IssueTestTokens();
CreateService(ProfileSyncService::AUTO_START);
- syncer::SyncManager::ClearServerDataCallback captured_callback;
+ base::Closure captured_callback;
syncer::ConfigureReason configure_reason = syncer::CONFIGURE_REASON_UNKNOWN;
// Initialize sync, ensure that both DataTypeManager and SyncEngine are
@@ -778,7 +781,7 @@ TEST_F(ProfileSyncServiceTest,
// Simulate browser restart. First configuration is a regular one.
service()->Shutdown();
- syncer::SyncManager::ClearServerDataCallback captured_callback;
+ base::Closure captured_callback;
ExpectSyncEngineCreationCaptureClearServerData(&captured_callback);
ExpectDataTypeManagerCreation(
1, GetRecordingConfigureCalledCallback(&configure_reason));
@@ -811,7 +814,7 @@ TEST_F(ProfileSyncServiceTest,
// interrupted, transition again from catch up sync cycle after browser restart.
TEST_F(ProfileSyncServiceTest,
OnLocalSetPassphraseEncryption_RestartDuringClearServerData) {
- syncer::SyncManager::ClearServerDataCallback captured_callback;
+ base::Closure captured_callback;
syncer::ConfigureReason configure_reason = syncer::CONFIGURE_REASON_UNKNOWN;
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
diff --git a/chromium/components/browser_sync/profile_sync_test_util.cc b/chromium/components/browser_sync/profile_sync_test_util.cc
index c6d34511b40..ee186d14d3c 100644
--- a/chromium/components/browser_sync/profile_sync_test_util.cc
+++ b/chromium/components/browser_sync/profile_sync_test_util.cc
@@ -261,10 +261,6 @@ ProfileSyncService::InitParams ProfileSyncServiceBundle::CreateBasicInitParams(
init_params.url_request_context = url_request_context();
init_params.debug_identifier = "dummyDebugName";
init_params.channel = version_info::Channel::UNKNOWN;
- init_params.blocking_task_runner =
- worker_pool_owner_.pool()->GetSequencedTaskRunnerWithShutdownBehavior(
- worker_pool_owner_.pool()->GetSequenceToken(),
- base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
return init_params;
}
diff --git a/chromium/components/browser_watcher/BUILD.gn b/chromium/components/browser_watcher/BUILD.gn
index 2e831c9c8b1..ff857fe05ce 100644
--- a/chromium/components/browser_watcher/BUILD.gn
+++ b/chromium/components/browser_watcher/BUILD.gn
@@ -43,36 +43,28 @@ if (is_win) {
]
}
- static_library("postmortem_minidump_writer") {
- # TODO(manzagop): remove this lib once Crashpad writes the minidumps.
+ static_library("postmortem_report_collector") {
sources = [
"postmortem_minidump_writer.h",
"postmortem_minidump_writer_win.cc",
- ]
- deps = [
- ":stability_data",
- ":stability_report_proto",
- "//base",
- "//third_party/crashpad/crashpad/client",
- "//third_party/crashpad/crashpad/minidump",
- "//third_party/crashpad/crashpad/util",
- ]
- }
-
- static_library("postmortem_report_collector") {
- sources = [
"postmortem_report_collector.cc",
"postmortem_report_collector.h",
+ "postmortem_report_extractor.cc",
+ "postmortem_report_extractor.h",
+ "system_session_analyzer_win.cc",
+ "system_session_analyzer_win.h",
]
deps = [
- ":postmortem_minidump_writer",
":stability_data",
":stability_report_proto",
"//base",
"//components/variations",
"//third_party/crashpad/crashpad/client",
+ "//third_party/crashpad/crashpad/minidump",
"//third_party/crashpad/crashpad/util",
]
+ libs = [ "wevtapi.lib" ]
+ ldflags = [ "/DELAYLOAD:wevtapi.dll" ] # Only used after unclean shutdowns.
}
}
@@ -103,6 +95,7 @@ if (is_win) {
"exit_code_watcher_win_unittest.cc",
"postmortem_minidump_writer_win_unittest.cc",
"postmortem_report_collector_unittest.cc",
+ "system_session_analyzer_win_unittest.cc",
"watcher_client_win_unittest.cc",
"watcher_metrics_provider_win_unittest.cc",
"window_hang_monitor_win_unittest.cc",
@@ -111,7 +104,6 @@ if (is_win) {
deps = [
":browser_watcher",
":browser_watcher_client",
- ":postmortem_minidump_writer",
":postmortem_report_collector",
":stability_data",
":stability_report_proto",
@@ -138,4 +130,14 @@ if (is_win) {
"//base",
]
}
+
+ executable("fetch_system_session_events") {
+ sources = [
+ "fetch_system_session_events_main_win.cc",
+ ]
+ deps = [
+ ":postmortem_report_collector",
+ "//base",
+ ]
+ }
}
diff --git a/chromium/components/browser_watcher/dump_postmortem_minidump_main_win.cc b/chromium/components/browser_watcher/dump_postmortem_minidump_main_win.cc
index db01260c57f..7a4bdb1331a 100644
--- a/chromium/components/browser_watcher/dump_postmortem_minidump_main_win.cc
+++ b/chromium/components/browser_watcher/dump_postmortem_minidump_main_win.cc
@@ -101,6 +101,8 @@ void PrintActivity(FILE* out,
fprintf(out, "type: %d\n", activity.type());
Indent(out, indent_level + 1);
fprintf(out, "time: %lld\n", activity.time());
+ Indent(out, indent_level + 1);
+ fprintf(out, "address: %llX\n", activity.address());
switch (activity.type()) {
case browser_watcher::Activity::UNKNOWN:
break;
@@ -125,6 +127,11 @@ void PrintActivity(FILE* out,
Indent(out, indent_level + 1);
fprintf(out, "process_id: %lld\n", activity.process_id());
break;
+ case browser_watcher::Activity::ACT_GENERIC:
+ Indent(out, indent_level + 1);
+ fprintf(out, "id: %u, data: %d\n", activity.generic_id(),
+ activity.generic_data());
+ break;
}
PrintUserData(out, indent_level + 1, activity.user_data());
diff --git a/chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc b/chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc
index 9c1a0741b94..1d5badfb0cf 100644
--- a/chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc
+++ b/chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc
@@ -41,36 +41,37 @@ class ScopedSleeperProcess {
}
~ScopedSleeperProcess() {
- if (process_.IsValid()) {
- process_.Terminate(-1, false);
- EXPECT_TRUE(process_.WaitForExit(nullptr));
+ if (spawn_child_.process.IsValid()) {
+ spawn_child_.process.Terminate(-1, false);
+ EXPECT_TRUE(spawn_child_.process.WaitForExit(nullptr));
}
}
void Launch() {
- ASSERT_FALSE(process_.IsValid());
+ ASSERT_FALSE(spawn_child_.process.IsValid());
base::CommandLine cmd_line(base::GetMultiProcessTestChildBaseCommandLine());
base::LaunchOptions options;
options.start_hidden = true;
- process_ = base::SpawnMultiProcessTestChild("Sleeper", cmd_line, options);
- ASSERT_TRUE(process_.IsValid());
+ spawn_child_ =
+ base::SpawnMultiProcessTestChild("Sleeper", cmd_line, options);
+ ASSERT_TRUE(spawn_child_.process.IsValid());
}
void Kill(int exit_code, bool wait) {
- ASSERT_TRUE(process_.IsValid());
+ ASSERT_TRUE(spawn_child_.process.IsValid());
ASSERT_FALSE(is_killed_);
- process_.Terminate(exit_code, false);
+ spawn_child_.process.Terminate(exit_code, false);
int seen_exit_code = 0;
- EXPECT_TRUE(process_.WaitForExit(&seen_exit_code));
+ EXPECT_TRUE(spawn_child_.process.WaitForExit(&seen_exit_code));
EXPECT_EQ(exit_code, seen_exit_code);
is_killed_ = true;
}
- const base::Process& process() const { return process_; }
+ const base::Process& process() const { return spawn_child_.process; }
private:
- base::Process process_;
+ base::SpawnChildResult spawn_child_;
bool is_killed_;
};
diff --git a/chromium/components/browser_watcher/features.cc b/chromium/components/browser_watcher/features.cc
index 87b65aa661e..399e49b9c17 100644
--- a/chromium/components/browser_watcher/features.cc
+++ b/chromium/components/browser_watcher/features.cc
@@ -6,8 +6,9 @@
namespace browser_watcher {
-// Additional stability instrumentation.
const base::Feature kStabilityDebuggingFeature{
"StabilityDebugging", base::FEATURE_DISABLED_BY_DEFAULT};
+const char kInitFlushParam[] = "init_flush";
+
} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/features.h b/chromium/components/browser_watcher/features.h
index 26ab23f353f..8f3503a6c3f 100644
--- a/chromium/components/browser_watcher/features.h
+++ b/chromium/components/browser_watcher/features.h
@@ -9,8 +9,14 @@
namespace browser_watcher {
+// Enables recording persistent stability information, which can later be
+// collected in the event of an unclean shutdown.
extern const base::Feature kStabilityDebuggingFeature;
+// Name of an experiment parameter that controls whether to perform an initial
+// flush.
+extern const char kInitFlushParam[];
+
} // namespace browser_watcher
#endif // COMPONENTS_BROWSER_WATCHER_FEATURES_H_
diff --git a/chromium/components/browser_watcher/fetch_system_session_events_main_win.cc b/chromium/components/browser_watcher/fetch_system_session_events_main_win.cc
new file mode 100644
index 00000000000..2f17b9333c7
--- /dev/null
+++ b/chromium/components/browser_watcher/fetch_system_session_events_main_win.cc
@@ -0,0 +1,48 @@
+// 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.
+
+// A utility for testing locally the retrieval of system session events.
+
+#include <iostream>
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "components/browser_watcher/system_session_analyzer_win.h"
+
+namespace {
+
+using browser_watcher::SystemSessionAnalyzer;
+
+class SystemSessionEventFetcher : public SystemSessionAnalyzer {
+ public:
+ explicit SystemSessionEventFetcher(uint32_t session_cnt)
+ : SystemSessionAnalyzer(session_cnt) {}
+ using SystemSessionAnalyzer::FetchEvents;
+};
+
+} // namespace
+
+int main(int argc, char** argv) {
+ // Retrieve events for the last 5 sessions.
+ SystemSessionEventFetcher fetcher(5U);
+ std::vector<SystemSessionEventFetcher::EventInfo> events;
+ if (!fetcher.FetchEvents(&events)) {
+ std::cerr << "Failed to fetch events." << std::endl;
+ return 1;
+ }
+
+ // Print the event ids and times.
+ for (const SystemSessionEventFetcher::EventInfo& event : events) {
+ base::Time::Exploded exploded = {};
+ event.event_time.LocalExplode(&exploded);
+ std::string time = base::StringPrintf(
+ "%d/%d/%d %d:%02d:%02d", exploded.month, exploded.day_of_month,
+ exploded.year, exploded.hour, exploded.minute, exploded.second);
+ std::cout << "Event: " << event.event_id << " (" << time << ")"
+ << std::endl;
+ }
+
+ return 0;
+}
diff --git a/chromium/components/browser_watcher/postmortem_report_collector.cc b/chromium/components/browser_watcher/postmortem_report_collector.cc
index 837f0232974..35cc7b455b3 100644
--- a/chromium/components/browser_watcher/postmortem_report_collector.cc
+++ b/chromium/components/browser_watcher/postmortem_report_collector.cc
@@ -6,7 +6,6 @@
#include <utility>
-#include "base/debug/activity_analyzer.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/logging.h"
@@ -17,135 +16,41 @@
#include "base/strings/utf_string_conversions.h"
#include "components/browser_watcher/postmortem_minidump_writer.h"
#include "components/browser_watcher/stability_data_names.h"
-#include "components/variations/active_field_trials.h"
#include "third_party/crashpad/crashpad/client/settings.h"
#include "third_party/crashpad/crashpad/util/misc/uuid.h"
-using base::FilePath;
-
namespace browser_watcher {
-using ActivitySnapshot = base::debug::ThreadActivityAnalyzer::Snapshot;
-using base::debug::ActivityUserData;
-using base::debug::GlobalActivityAnalyzer;
-using base::debug::GlobalActivityTracker;
-using base::debug::ThreadActivityAnalyzer;
+using base::FilePath;
using crashpad::CrashReportDatabase;
namespace {
-const char kFieldTrialKeyPrefix[] = "FieldTrial.";
-
-// Collects stability user data from the recorded format to the collected
-// format.
-void CollectUserData(
- const ActivityUserData::Snapshot& recorded_map,
- google::protobuf::Map<std::string, TypedValue>* collected_map,
- StabilityReport* report) {
- DCHECK(collected_map);
-
- for (const auto& name_and_value : recorded_map) {
- const std::string& key = name_and_value.first;
- const ActivityUserData::TypedValue& recorded_value = name_and_value.second;
- TypedValue collected_value;
-
- switch (recorded_value.type()) {
- case ActivityUserData::END_OF_VALUES:
- NOTREACHED();
- break;
- case ActivityUserData::RAW_VALUE: {
- base::StringPiece raw = recorded_value.Get();
- collected_value.set_bytes_value(raw.data(), raw.size());
- break;
- }
- case ActivityUserData::RAW_VALUE_REFERENCE: {
- base::StringPiece recorded_ref = recorded_value.GetReference();
- TypedValue::Reference* collected_ref =
- collected_value.mutable_bytes_reference();
- collected_ref->set_address(
- reinterpret_cast<uintptr_t>(recorded_ref.data()));
- collected_ref->set_size(recorded_ref.size());
- break;
- }
- case ActivityUserData::STRING_VALUE: {
- base::StringPiece value = recorded_value.GetString();
-
- if (report && base::StartsWith(key, kFieldTrialKeyPrefix,
- base::CompareCase::SENSITIVE)) {
- // This entry represents an active Field Trial.
- std::string trial_name =
- key.substr(std::strlen(kFieldTrialKeyPrefix));
- variations::ActiveGroupId group_id =
- variations::MakeActiveGroupId(trial_name, value.as_string());
- FieldTrial* field_trial = report->add_field_trials();
- field_trial->set_name_id(group_id.name);
- field_trial->set_group_id(group_id.group);
- continue;
- }
-
- collected_value.set_string_value(value.data(), value.size());
- break;
- }
- case ActivityUserData::STRING_VALUE_REFERENCE: {
- base::StringPiece recorded_ref = recorded_value.GetStringReference();
- TypedValue::Reference* collected_ref =
- collected_value.mutable_string_reference();
- collected_ref->set_address(
- reinterpret_cast<uintptr_t>(recorded_ref.data()));
- collected_ref->set_size(recorded_ref.size());
- break;
- }
- case ActivityUserData::CHAR_VALUE: {
- char char_value = recorded_value.GetChar();
- collected_value.set_char_value(&char_value, 1);
- break;
- }
- case ActivityUserData::BOOL_VALUE:
- collected_value.set_bool_value(recorded_value.GetBool());
- break;
- case ActivityUserData::SIGNED_VALUE:
- collected_value.set_signed_value(recorded_value.GetInt());
- break;
- case ActivityUserData::UNSIGNED_VALUE:
- collected_value.set_unsigned_value(recorded_value.GetUint());
- break;
- }
-
- (*collected_map)[key].Swap(&collected_value);
- }
-}
-
-void CollectModuleInformation(
- const std::vector<GlobalActivityTracker::ModuleInfo>& modules,
- ProcessState* process_state) {
- DCHECK(process_state);
-
- char code_identifier[17];
- char debug_identifier[41];
-
- for (const GlobalActivityTracker::ModuleInfo& recorded : modules) {
- CodeModule* collected = process_state->add_modules();
- collected->set_base_address(recorded.address);
- collected->set_size(recorded.size);
- collected->set_code_file(recorded.file);
-
- // Compute the code identifier using the required format.
- snprintf(code_identifier, sizeof(code_identifier), "%08X%zx",
- recorded.timestamp, recorded.size);
- collected->set_code_identifier(code_identifier);
- collected->set_debug_file(recorded.debug_file);
-
- // Compute the debug identifier using the required format.
- const crashpad::UUID* uuid =
- reinterpret_cast<const crashpad::UUID*>(recorded.identifier);
- snprintf(debug_identifier, sizeof(debug_identifier),
- "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x", uuid->data_1,
- uuid->data_2, uuid->data_3, uuid->data_4[0], uuid->data_4[1],
- uuid->data_5[0], uuid->data_5[1], uuid->data_5[2], uuid->data_5[3],
- uuid->data_5[4], uuid->data_5[5], recorded.age);
- collected->set_debug_identifier(debug_identifier);
- collected->set_is_unloaded(!recorded.is_loaded);
- }
+// DO NOT CHANGE VALUES. This is logged persistently in a histogram.
+enum SystemSessionAnalysisStatus {
+ SYSTEM_SESSION_ANALYSIS_SUCCESS = 0,
+ SYSTEM_SESSION_ANALYSIS_NO_TIMESTAMP = 1,
+ SYSTEM_SESSION_ANALYSIS_NO_ANALYZER = 2,
+ SYSTEM_SESSION_ANALYSIS_FAILED = 3,
+ SYSTEM_SESSION_ANALYSIS_OUTSIDE_RANGE = 4,
+ SYSTEM_SESSION_ANALYSIS_STATUS_MAX = 5
+};
+
+bool GetStartTimestamp(
+ const google::protobuf::Map<std::string, TypedValue>& global_data,
+ base::Time* time) {
+ DCHECK(time);
+
+ const auto& it = global_data.find(kStabilityStartTimestamp);
+ if (it == global_data.end())
+ return false;
+
+ const TypedValue& value = it->second;
+ if (value.value_case() != TypedValue::kSignedValue)
+ return false;
+
+ *time = base::Time::FromInternalValue(value.signed_value());
+ return true;
}
} // namespace
@@ -153,12 +58,16 @@ void CollectModuleInformation(
PostmortemReportCollector::PostmortemReportCollector(
const std::string& product_name,
const std::string& version_number,
- const std::string& channel_name)
+ const std::string& channel_name,
+ SystemSessionAnalyzer* analyzer)
: product_name_(product_name),
version_number_(version_number),
- channel_name_(channel_name) {}
+ channel_name_(channel_name),
+ system_session_analyzer_(analyzer) {}
-int PostmortemReportCollector::CollectAndSubmitForUpload(
+PostmortemReportCollector::~PostmortemReportCollector() {}
+
+int PostmortemReportCollector::CollectAndSubmitAllPendingReports(
const base::FilePath& debug_info_dir,
const base::FilePath::StringType& debug_file_pattern,
const std::set<base::FilePath>& excluded_debug_files,
@@ -186,7 +95,7 @@ int PostmortemReportCollector::CollectAndSubmitForUpload(
int success_cnt = 0;
for (const FilePath& file : debug_files) {
CollectionStatus status =
- CollectAndSubmit(client_id, file, report_database);
+ CollectAndSubmitOneReport(client_id, file, report_database);
// TODO(manzagop): consider making this a stability metric.
UMA_HISTOGRAM_ENUMERATION("ActivityTracker.Collect.Status", status,
COLLECTION_STATUS_MAX);
@@ -198,8 +107,8 @@ int PostmortemReportCollector::CollectAndSubmitForUpload(
}
std::vector<FilePath> PostmortemReportCollector::GetDebugStateFilePaths(
- const base::FilePath& debug_info_dir,
- const base::FilePath::StringType& debug_file_pattern,
+ const FilePath& debug_info_dir,
+ const FilePath::StringType& debug_file_pattern,
const std::set<FilePath>& excluded_debug_files) {
DCHECK_NE(true, debug_info_dir.empty());
DCHECK_NE(true, debug_file_pattern.empty());
@@ -216,8 +125,7 @@ std::vector<FilePath> PostmortemReportCollector::GetDebugStateFilePaths(
return paths;
}
-PostmortemReportCollector::CollectionStatus
-PostmortemReportCollector::CollectAndSubmit(
+CollectionStatus PostmortemReportCollector::CollectAndSubmitOneReport(
const crashpad::UUID& client_id,
const FilePath& file,
crashpad::CrashReportDatabase* report_database) {
@@ -228,8 +136,8 @@ PostmortemReportCollector::CollectAndSubmit(
// Collect the data from the debug file to a proto. Note: a non-empty report
// is interpreted here as an unclean exit.
- std::unique_ptr<StabilityReport> report_proto;
- CollectionStatus status = Collect(file, &report_proto);
+ StabilityReport report_proto;
+ CollectionStatus status = CollectOneReport(file, &report_proto);
if (status != SUCCESS) {
// The file was empty, or there was an error collecting the data. Detailed
// logging happens within the Collect function.
@@ -237,7 +145,6 @@ PostmortemReportCollector::CollectAndSubmit(
DLOG(ERROR) << "Failed to delete " << file.value();
return status;
}
- DCHECK_NE(nullptr, report_proto.get());
// Prepare a crashpad report.
CrashReportDatabase::NewReport* new_report = nullptr;
@@ -252,7 +159,7 @@ PostmortemReportCollector::CollectAndSubmit(
call_error_writing_crash_report(report_database, new_report);
// Write the report to a minidump.
- if (!WriteReportToMinidump(report_proto.get(), client_id, new_report->uuid,
+ if (!WriteReportToMinidump(&report_proto, client_id, new_report->uuid,
reinterpret_cast<FILE*>(new_report->handle))) {
// Assume this is not recoverable and delete the file.
if (!base::DeleteFile(file, false))
@@ -285,42 +192,30 @@ PostmortemReportCollector::CollectAndSubmit(
return SUCCESS;
}
-PostmortemReportCollector::CollectionStatus PostmortemReportCollector::Collect(
- const base::FilePath& debug_state_file,
- std::unique_ptr<StabilityReport>* report) {
- DCHECK_NE(nullptr, report);
- report->reset();
-
- // Create a global analyzer.
- std::unique_ptr<GlobalActivityAnalyzer> global_analyzer =
- GlobalActivityAnalyzer::CreateWithFile(debug_state_file);
- if (!global_analyzer)
- return ANALYZER_CREATION_FAILED;
-
- // Early exit if there is no data.
- std::vector<std::string> log_messages = global_analyzer->GetLogMessages();
- ActivityUserData::Snapshot global_data_snapshot =
- global_analyzer->GetGlobalUserDataSnapshot();
- ThreadActivityAnalyzer* thread_analyzer = global_analyzer->GetFirstAnalyzer();
- if (log_messages.empty() && global_data_snapshot.empty() &&
- !thread_analyzer) {
- return DEBUG_FILE_NO_DATA;
- }
+CollectionStatus PostmortemReportCollector::CollectOneReport(
+ const base::FilePath& file,
+ StabilityReport* report) {
+ DCHECK(report);
- // Create the report, then flesh it out.
- report->reset(new StabilityReport());
+ CollectionStatus status = Extract(file, report);
+ if (status != SUCCESS)
+ return status;
- // Collect log messages.
- for (const std::string& message : log_messages) {
- (*report)->add_log_messages(message);
- }
+ SetReporterDetails(report);
+ RecordSystemShutdownState(report);
+
+ return SUCCESS;
+}
+
+void PostmortemReportCollector::SetReporterDetails(
+ StabilityReport* report) const {
+ DCHECK(report);
- // Collect global user data.
google::protobuf::Map<std::string, TypedValue>& global_data =
- *(*report)->mutable_global_data();
- CollectUserData(global_data_snapshot, &global_data, report->get());
+ *(report->mutable_global_data());
- // Add the reporting Chrome's details to the report.
+ // Reporter version details. These are useful as the reporter may be of a
+ // different version.
global_data[kStabilityReporterChannel].set_string_value(channel_name());
#if defined(ARCH_CPU_X86)
global_data[kStabilityReporterPlatform].set_string_value(
@@ -331,79 +226,47 @@ PostmortemReportCollector::CollectionStatus PostmortemReportCollector::Collect(
#endif
global_data[kStabilityReporterProduct].set_string_value(product_name());
global_data[kStabilityReporterVersion].set_string_value(version_number());
-
- // Collect thread activity data.
- // Note: a single process is instrumented.
- ProcessState* process_state = (*report)->add_process_states();
- for (; thread_analyzer != nullptr;
- thread_analyzer = global_analyzer->GetNextAnalyzer()) {
- // Only valid analyzers are expected per contract of GetFirstAnalyzer /
- // GetNextAnalyzer.
- DCHECK(thread_analyzer->IsValid());
-
- if (!process_state->has_process_id()) {
- process_state->set_process_id(
- thread_analyzer->activity_snapshot().process_id);
- }
- DCHECK_EQ(thread_analyzer->activity_snapshot().process_id,
- process_state->process_id());
-
- ThreadState* thread_state = process_state->add_threads();
- CollectThread(thread_analyzer->activity_snapshot(), thread_state);
- }
-
- // Collect module information.
- CollectModuleInformation(global_analyzer->GetModules(), process_state);
-
- return SUCCESS;
}
-void PostmortemReportCollector::CollectThread(
- const base::debug::ThreadActivityAnalyzer::Snapshot& snapshot,
- ThreadState* thread_state) {
- DCHECK(thread_state);
-
- thread_state->set_thread_name(snapshot.thread_name);
- thread_state->set_thread_id(snapshot.thread_id);
- thread_state->set_activity_count(snapshot.activity_stack_depth);
-
- for (size_t i = 0; i < snapshot.activity_stack.size(); ++i) {
- const base::debug::Activity& recorded = snapshot.activity_stack[i];
- Activity* collected = thread_state->add_activities();
-
- // Collect activity
- switch (recorded.activity_type) {
- case base::debug::Activity::ACT_TASK_RUN:
- collected->set_type(Activity::ACT_TASK_RUN);
- collected->set_origin_address(recorded.origin_address);
- collected->set_task_sequence_id(recorded.data.task.sequence_id);
- break;
- case base::debug::Activity::ACT_LOCK_ACQUIRE:
- collected->set_type(Activity::ACT_LOCK_ACQUIRE);
- collected->set_lock_address(recorded.data.lock.lock_address);
- break;
- case base::debug::Activity::ACT_EVENT_WAIT:
- collected->set_type(Activity::ACT_EVENT_WAIT);
- collected->set_event_address(recorded.data.event.event_address);
+void PostmortemReportCollector::RecordSystemShutdownState(
+ StabilityReport* report) const {
+ DCHECK(report);
+
+ // The session state for the stability report, recorded to provided visibility
+ // into whether the system session was clean.
+ SystemState::SessionState session_state = SystemState::UNKNOWN;
+ // The status of the analysis, recorded to provide insight into the success
+ // or failure of the analysis.
+ SystemSessionAnalysisStatus status = SYSTEM_SESSION_ANALYSIS_SUCCESS;
+
+ base::Time time;
+ if (!GetStartTimestamp(report->global_data(), &time)) {
+ status = SYSTEM_SESSION_ANALYSIS_NO_TIMESTAMP;
+ } else if (!system_session_analyzer_) {
+ status = SYSTEM_SESSION_ANALYSIS_NO_ANALYZER;
+ } else {
+ SystemSessionAnalyzer::Status analyzer_status =
+ system_session_analyzer_->IsSessionUnclean(time);
+ switch (analyzer_status) {
+ case SystemSessionAnalyzer::FAILED:
+ status = SYSTEM_SESSION_ANALYSIS_FAILED;
break;
- case base::debug::Activity::ACT_THREAD_JOIN:
- collected->set_type(Activity::ACT_THREAD_JOIN);
- collected->set_thread_id(recorded.data.thread.thread_id);
+ case SystemSessionAnalyzer::CLEAN:
+ session_state = SystemState::CLEAN;
break;
- case base::debug::Activity::ACT_PROCESS_WAIT:
- collected->set_type(Activity::ACT_PROCESS_WAIT);
- collected->set_process_id(recorded.data.process.process_id);
+ case SystemSessionAnalyzer::UNCLEAN:
+ session_state = SystemState::UNCLEAN;
break;
- default:
+ case SystemSessionAnalyzer::OUTSIDE_RANGE:
+ status = SYSTEM_SESSION_ANALYSIS_OUTSIDE_RANGE;
break;
}
-
- // Collect user data
- if (i < snapshot.user_data_stack.size()) {
- CollectUserData(snapshot.user_data_stack[i],
- collected->mutable_user_data(), nullptr);
- }
}
+
+ report->mutable_system_state()->set_session_state(session_state);
+ UMA_HISTOGRAM_ENUMERATION(
+ "ActivityTracker.Collect.SystemSessionAnalysisStatus", status,
+ SYSTEM_SESSION_ANALYSIS_STATUS_MAX);
}
bool PostmortemReportCollector::WriteReportToMinidump(
diff --git a/chromium/components/browser_watcher/postmortem_report_collector.h b/chromium/components/browser_watcher/postmortem_report_collector.h
index 0650d37ece4..000b14ebbfb 100644
--- a/chromium/components/browser_watcher/postmortem_report_collector.h
+++ b/chromium/components/browser_watcher/postmortem_report_collector.h
@@ -21,33 +21,26 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/strings/string16.h"
+#include "components/browser_watcher/postmortem_report_extractor.h"
#include "components/browser_watcher/stability_report.pb.h"
+#include "components/browser_watcher/system_session_analyzer_win.h"
#include "third_party/crashpad/crashpad/client/crash_report_database.h"
namespace browser_watcher {
-// Collects unclean shutdown information and creates Crashpad minidumps.
+// Handles postmortem report collection by establishing the set of stability
+// files to collect, then for each file:
+// - extracting a report protocol buffer
+// - registering a crash report with the crash database
+// - writing a minidump file for the report
// TODO(manzagop): throttling, graceful handling of accumulating data.
-// TODO(manzagop): UMA metrics and some error logging.
class PostmortemReportCollector {
public:
- // DO NOT CHANGE VALUES. This is logged persistently in a histogram.
- enum CollectionStatus {
- NONE = 0,
- SUCCESS = 1, // Successfully registered a report with Crashpad.
- ANALYZER_CREATION_FAILED = 2,
- DEBUG_FILE_NO_DATA = 3,
- PREPARE_NEW_CRASH_REPORT_FAILED = 4,
- WRITE_TO_MINIDUMP_FAILED = 5,
- DEBUG_FILE_DELETION_FAILED = 6,
- FINISHED_WRITING_CRASH_REPORT_FAILED = 7,
- COLLECTION_STATUS_MAX = 8
- };
-
PostmortemReportCollector(const std::string& product_name,
const std::string& version_number,
- const std::string& channel_name);
- virtual ~PostmortemReportCollector() = default;
+ const std::string& channel_name,
+ SystemSessionAnalyzer* analyzer);
+ virtual ~PostmortemReportCollector();
// Collects postmortem stability reports from files found in |debug_info_dir|,
// relying on |debug_file_pattern| and |excluded_debug_files|. Reports are
@@ -55,7 +48,7 @@ class PostmortemReportCollector {
// Returns the number crash reports successfully registered with the reporter.
// TODO(manzagop): consider mechanisms for partial collection if this is to be
// used on a critical path.
- int CollectAndSubmitForUpload(
+ int CollectAndSubmitAllPendingReports(
const base::FilePath& debug_info_dir,
const base::FilePath::StringType& debug_file_pattern,
const std::set<base::FilePath>& excluded_debug_files,
@@ -77,13 +70,16 @@ class PostmortemReportCollector {
LogCollection);
FRIEND_TEST_ALL_PREFIXES(
PostmortemReportCollectorCollectionFromGlobalTrackerTest,
- GlobalUserDataCollection);
+ ProcessUserDataCollection);
FRIEND_TEST_ALL_PREFIXES(
PostmortemReportCollectorCollectionFromGlobalTrackerTest,
FieldTrialCollection);
FRIEND_TEST_ALL_PREFIXES(
PostmortemReportCollectorCollectionFromGlobalTrackerTest,
ModuleCollection);
+ FRIEND_TEST_ALL_PREFIXES(
+ PostmortemReportCollectorCollectionFromGlobalTrackerTest,
+ SystemStateTest);
// Virtual for unittesting.
virtual std::vector<base::FilePath> GetDebugStateFilePaths(
@@ -91,18 +87,18 @@ class PostmortemReportCollector {
const base::FilePath::StringType& debug_file_pattern,
const std::set<base::FilePath>& excluded_debug_files);
- CollectionStatus CollectAndSubmit(
+ CollectionStatus CollectAndSubmitOneReport(
const crashpad::UUID& client_id,
const base::FilePath& file,
crashpad::CrashReportDatabase* report_database);
- // Virtual for unittesting.
- // TODO(manzagop): move this for reuse in live scenario.
- virtual CollectionStatus Collect(const base::FilePath& debug_state_file,
- std::unique_ptr<StabilityReport>* report);
- void CollectThread(
- const base::debug::ThreadActivityAnalyzer::Snapshot& snapshot,
- ThreadState* thread_state);
+ virtual CollectionStatus CollectOneReport(
+ const base::FilePath& stability_file,
+ StabilityReport* report);
+
+ void SetReporterDetails(StabilityReport* report) const;
+
+ void RecordSystemShutdownState(StabilityReport* report) const;
virtual bool WriteReportToMinidump(StabilityReport* report,
const crashpad::UUID& client_id,
@@ -113,6 +109,8 @@ class PostmortemReportCollector {
std::string version_number_;
std::string channel_name_;
+ SystemSessionAnalyzer* system_session_analyzer_; // Not owned.
+
DISALLOW_COPY_AND_ASSIGN(PostmortemReportCollector);
};
diff --git a/chromium/components/browser_watcher/postmortem_report_collector_unittest.cc b/chromium/components/browser_watcher/postmortem_report_collector_unittest.cc
index ae241e37a5d..a022c820e4b 100644
--- a/chromium/components/browser_watcher/postmortem_report_collector_unittest.cc
+++ b/chromium/components/browser_watcher/postmortem_report_collector_unittest.cc
@@ -25,6 +25,7 @@
#include "base/process/process_handle.h"
#include "base/stl_util.h"
#include "base/threading/platform_thread.h"
+#include "components/browser_watcher/postmortem_report_extractor.h"
#include "components/browser_watcher/stability_data_names.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -55,6 +56,9 @@ const char kProductName[] = "TestProduct";
const char kVersionNumber[] = "TestVersionNumber";
const char kChannelName[] = "TestChannel";
+// The tracker creates some data entries internally.
+const size_t kInternalProcessDatums = 1;
+
void ContainsKeyValue(
const google::protobuf::Map<std::string, TypedValue>& data,
const std::string& key,
@@ -107,27 +111,23 @@ class MockCrashReportDatabase : public CrashReportDatabase {
CrashReportDatabase::OperationStatus(const UUID& uuid));
};
-// Used for testing CollectAndSubmitForUpload.
+// Used for testing CollectAndSubmitAllPendingReports.
class MockPostmortemReportCollector : public PostmortemReportCollector {
public:
MockPostmortemReportCollector()
- : PostmortemReportCollector(kProductName, kVersionNumber, kChannelName) {}
-
- // A function that returns a unique_ptr cannot be mocked, so mock a function
- // that returns a raw pointer instead.
- CollectionStatus Collect(const base::FilePath& debug_state_file,
- std::unique_ptr<StabilityReport>* report) override {
- DCHECK_NE(nullptr, report);
- report->reset(CollectRaw(debug_state_file));
- return SUCCESS;
- }
+ : PostmortemReportCollector(kProductName,
+ kVersionNumber,
+ kChannelName,
+ nullptr) {}
MOCK_METHOD3(GetDebugStateFilePaths,
std::vector<base::FilePath>(
const base::FilePath& debug_info_dir,
const base::FilePath::StringType& debug_file_pattern,
const std::set<base::FilePath>&));
- MOCK_METHOD1(CollectRaw, StabilityReport*(const base::FilePath&));
+ MOCK_METHOD2(CollectOneReport,
+ CollectionStatus(const base::FilePath&,
+ StabilityReport* report));
MOCK_METHOD4(WriteReportToMinidump,
bool(StabilityReport* report,
const crashpad::UUID& client_id,
@@ -135,6 +135,12 @@ class MockPostmortemReportCollector : public PostmortemReportCollector {
base::PlatformFile minidump_file));
};
+class MockSystemSessionAnalyzer : public SystemSessionAnalyzer {
+ public:
+ MockSystemSessionAnalyzer() : SystemSessionAnalyzer(10U) {}
+ MOCK_METHOD1(IsSessionUnclean, Status(base::Time timestamp));
+};
+
// Checks if two proto messages are the same based on their serializations. Note
// this only works if serialization is deterministic, which is not guaranteed.
// In practice, serialization is deterministic (even for protocol buffers with
@@ -156,7 +162,8 @@ MATCHER_P(EqualsProto, message, "") {
} // namespace
-class PostmortemReportCollectorCollectAndSubmitTest : public testing::Test {
+class PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest
+ : public testing::Test {
public:
void SetUp() override {
testing::Test::SetUp();
@@ -180,12 +187,10 @@ class PostmortemReportCollectorCollectAndSubmitTest : public testing::Test {
EXPECT_CALL(database_, GetSettings()).Times(1).WillOnce(Return(nullptr));
- // Expect collection to a proto of a single debug file.
- // Note: caller takes ownership.
- StabilityReport* stability_report = new StabilityReport();
- EXPECT_CALL(collector_, CollectRaw(debug_file_))
+ // Expect a single collection call.
+ EXPECT_CALL(collector_, CollectOneReport(debug_file_, _))
.Times(1)
- .WillOnce(Return(stability_report));
+ .WillOnce(Return(SUCCESS));
// Expect the call to write the proto to a minidump. This involves
// requesting a report from the crashpad database, writing the report, then
@@ -203,8 +208,7 @@ class PostmortemReportCollectorCollectAndSubmitTest : public testing::Test {
Return(CrashReportDatabase::kNoError)));
EXPECT_CALL(collector_,
- WriteReportToMinidump(stability_report, _, _,
- minidump_file.GetPlatformFile()))
+ WriteReportToMinidump(_, _, _, minidump_file.GetPlatformFile()))
.Times(1)
.WillOnce(Return(true));
}
@@ -219,22 +223,22 @@ class PostmortemReportCollectorCollectAndSubmitTest : public testing::Test {
CrashReportDatabase::NewReport crashpad_report_;
};
-TEST_F(PostmortemReportCollectorCollectAndSubmitTest,
- CollectAndSubmitForUpload) {
+TEST_F(PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest,
+ CollectAndSubmitAllPendingReports) {
EXPECT_CALL(database_, FinishedWritingCrashReport(&crashpad_report_, _))
.Times(1)
.WillOnce(Return(CrashReportDatabase::kNoError));
// Run the test.
- int success_cnt = collector_.CollectAndSubmitForUpload(
+ int success_cnt = collector_.CollectAndSubmitAllPendingReports(
debug_file_.DirName(), debug_file_pattern_, no_excluded_files_,
&database_);
ASSERT_EQ(1, success_cnt);
ASSERT_FALSE(base::PathExists(debug_file_));
}
-TEST_F(PostmortemReportCollectorCollectAndSubmitTest,
- CollectAndSubmitForUploadStuckFile) {
+TEST_F(PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest,
+ CollectAndSubmitAllPendingReportsStuckFile) {
// Open the stability debug file to prevent its deletion.
base::ScopedFILE file(base::OpenFile(debug_file_, "w"));
ASSERT_NE(file.get(), nullptr);
@@ -245,7 +249,7 @@ TEST_F(PostmortemReportCollectorCollectAndSubmitTest,
.WillOnce(Return(CrashReportDatabase::kNoError));
// Run the test.
- int success_cnt = collector_.CollectAndSubmitForUpload(
+ int success_cnt = collector_.CollectAndSubmitAllPendingReports(
debug_file_.DirName(), debug_file_pattern_, no_excluded_files_,
&database_);
ASSERT_EQ(0, success_cnt);
@@ -285,7 +289,7 @@ TEST(PostmortemReportCollectorTest, GetDebugStateFilePaths) {
}
PostmortemReportCollector collector(kProductName, kVersionNumber,
- kChannelName);
+ kChannelName, nullptr);
EXPECT_THAT(
collector.GetDebugStateFilePaths(
temp_dir.GetPath(), FILE_PATH_LITERAL("foo*.pma"), excluded_paths),
@@ -305,10 +309,10 @@ TEST(PostmortemReportCollectorTest, CollectEmptyFile) {
// Validate collection: an empty file cannot suppport an analyzer.
PostmortemReportCollector collector(kProductName, kVersionNumber,
- kChannelName);
- std::unique_ptr<StabilityReport> report;
- ASSERT_EQ(PostmortemReportCollector::ANALYZER_CREATION_FAILED,
- collector.Collect(file_path, &report));
+ kChannelName, nullptr);
+ StabilityReport report;
+ ASSERT_EQ(ANALYZER_CREATION_FAILED,
+ collector.CollectOneReport(file_path, &report));
}
TEST(PostmortemReportCollectorTest, CollectRandomFile) {
@@ -332,17 +336,16 @@ TEST(PostmortemReportCollectorTest, CollectRandomFile) {
// Validate collection: random content appears as though there is not
// stability data.
PostmortemReportCollector collector(kProductName, kVersionNumber,
- kChannelName);
- std::unique_ptr<StabilityReport> report;
- ASSERT_EQ(PostmortemReportCollector::DEBUG_FILE_NO_DATA,
- collector.Collect(file_path, &report));
+ kChannelName, nullptr);
+ StabilityReport report;
+ ASSERT_EQ(DEBUG_FILE_NO_DATA, collector.CollectOneReport(file_path, &report));
}
namespace {
// Parameters for the activity tracking.
-const size_t kFileSize = 2 * 1024;
-const int kStackDepth = 5;
+const size_t kFileSize = 64 << 10; // 64 KiB
+const int kStackDepth = 6;
const uint64_t kAllocatorId = 0;
const char kAllocatorName[] = "PostmortemReportCollectorCollectionTest";
const uint64_t kTaskSequenceNum = 42;
@@ -352,6 +355,8 @@ const uintptr_t kEventAddress = 1002U;
const int kThreadId = 43;
const int kProcessId = 44;
const int kAnotherThreadId = 45;
+const uint32_t kGenericId = 46U;
+const int32_t kGenericData = 47;
} // namespace
@@ -445,6 +450,8 @@ TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) {
ActivityData::ForThread(kThreadId));
tracker_->PushActivity(nullptr, base::debug::Activity::ACT_PROCESS_WAIT,
ActivityData::ForProcess(kProcessId));
+ tracker_->PushActivity(nullptr, base::debug::Activity::ACT_GENERIC,
+ ActivityData::ForGeneric(kGenericId, kGenericData));
// Note: this exceeds the activity stack's capacity.
tracker_->PushActivity(nullptr, base::debug::Activity::ACT_THREAD_JOIN,
ActivityData::ForThread(kAnotherThreadId));
@@ -459,15 +466,13 @@ TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) {
// Validate collection returns the expected report.
PostmortemReportCollector collector(kProductName, kVersionNumber,
- kChannelName);
- std::unique_ptr<StabilityReport> report;
- ASSERT_EQ(PostmortemReportCollector::SUCCESS,
- collector.Collect(debug_file_path(), &report));
- ASSERT_NE(nullptr, report);
+ kChannelName, nullptr);
+ StabilityReport report;
+ ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report));
// Validate the report.
- ASSERT_EQ(1, report->process_states_size());
- const ProcessState& process_state = report->process_states(0);
+ ASSERT_EQ(1, report.process_states_size());
+ const ProcessState& process_state = report.process_states(0);
EXPECT_EQ(base::GetCurrentProcId(), process_state.process_id());
ASSERT_EQ(1, process_state.threads_size());
@@ -480,8 +485,8 @@ TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) {
thread_state.thread_id());
#endif
- EXPECT_EQ(6, thread_state.activity_count());
- ASSERT_EQ(5, thread_state.activities_size());
+ EXPECT_EQ(7, thread_state.activity_count());
+ ASSERT_EQ(6, thread_state.activities_size());
{
const Activity& activity = thread_state.activities(0);
EXPECT_EQ(Activity::ACT_TASK_RUN, activity.type());
@@ -517,6 +522,13 @@ TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) {
EXPECT_EQ(kProcessId, activity.process_id());
EXPECT_EQ(0U, activity.user_data().size());
}
+ {
+ const Activity& activity = thread_state.activities(5);
+ EXPECT_EQ(Activity::ACT_GENERIC, activity.type());
+ EXPECT_EQ(kGenericId, activity.generic_id());
+ EXPECT_EQ(kGenericData, activity.generic_data());
+ EXPECT_EQ(0U, activity.user_data().size());
+ }
}
class PostmortemReportCollectorCollectionFromGlobalTrackerTest
@@ -558,47 +570,46 @@ TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest,
// Collect the stability report.
PostmortemReportCollector collector(kProductName, kVersionNumber,
- kChannelName);
- std::unique_ptr<StabilityReport> report;
- ASSERT_EQ(PostmortemReportCollector::SUCCESS,
- collector.Collect(debug_file_path(), &report));
- ASSERT_NE(nullptr, report);
+ kChannelName, nullptr);
+ StabilityReport report;
+ ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report));
// Validate the report's log content.
- ASSERT_EQ(2, report->log_messages_size());
- ASSERT_EQ("hello world", report->log_messages(0));
- ASSERT_EQ("foo bar", report->log_messages(1));
+ ASSERT_EQ(2, report.log_messages_size());
+ ASSERT_EQ("hello world", report.log_messages(0));
+ ASSERT_EQ("foo bar", report.log_messages(1));
}
TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest,
- GlobalUserDataCollection) {
+ ProcessUserDataCollection) {
const char string1[] = "foo";
const char string2[] = "bar";
- // Record some global user data.
+ // Record some process user data.
GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL,
"", 3);
- ActivityUserData& global_data = GlobalActivityTracker::Get()->global_data();
- global_data.Set("raw", "foo", 3);
- global_data.SetString("string", "bar");
- global_data.SetChar("char", '9');
- global_data.SetInt("int", -9999);
- global_data.SetUint("uint", 9999);
- global_data.SetBool("bool", true);
- global_data.SetReference("ref", string1, strlen(string1));
- global_data.SetStringReference("sref", string2);
+ ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data();
+ ActivityUserData::Snapshot snapshot;
+ ASSERT_TRUE(process_data.CreateSnapshot(&snapshot));
+ ASSERT_EQ(kInternalProcessDatums, snapshot.size());
+ process_data.Set("raw", "foo", 3);
+ process_data.SetString("string", "bar");
+ process_data.SetChar("char", '9');
+ process_data.SetInt("int", -9999);
+ process_data.SetUint("uint", 9999);
+ process_data.SetBool("bool", true);
+ process_data.SetReference("ref", string1, strlen(string1));
+ process_data.SetStringReference("sref", string2);
// Collect the stability report.
PostmortemReportCollector collector(kProductName, kVersionNumber,
- kChannelName);
- std::unique_ptr<StabilityReport> report;
- ASSERT_EQ(PostmortemReportCollector::SUCCESS,
- collector.Collect(debug_file_path(), &report));
- ASSERT_NE(nullptr, report);
+ kChannelName, nullptr);
+ StabilityReport report;
+ ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report));
// Validate the report's user data.
- const auto& collected_data = report->global_data();
- ASSERT_EQ(12U, collected_data.size());
+ const auto& collected_data = report.global_data();
+ ASSERT_EQ(kInternalProcessDatums + 12U, collected_data.size());
ASSERT_TRUE(base::ContainsKey(collected_data, "raw"));
EXPECT_EQ(TypedValue::kBytesValue, collected_data.at("raw").value_case());
@@ -654,30 +665,28 @@ TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest,
// Record some data.
GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL,
"", 3);
- ActivityUserData& global_data = GlobalActivityTracker::Get()->global_data();
- global_data.SetString("string", "bar");
- global_data.SetString("FieldTrial.string", "bar");
- global_data.SetString("FieldTrial.foo", "bar");
+ ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data();
+ process_data.SetString("string", "bar");
+ process_data.SetString("FieldTrial.string", "bar");
+ process_data.SetString("FieldTrial.foo", "bar");
// Collect the stability report.
PostmortemReportCollector collector(kProductName, kVersionNumber,
- kChannelName);
- std::unique_ptr<StabilityReport> report;
- ASSERT_EQ(PostmortemReportCollector::SUCCESS,
- collector.Collect(debug_file_path(), &report));
- ASSERT_NE(nullptr, report);
+ kChannelName, nullptr);
+ StabilityReport report;
+ ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report));
// Validate the report's experiment and global data.
- ASSERT_EQ(2, report->field_trials_size());
- EXPECT_NE(0U, report->field_trials(0).name_id());
- EXPECT_NE(0U, report->field_trials(0).group_id());
- EXPECT_NE(0U, report->field_trials(1).name_id());
- EXPECT_EQ(report->field_trials(0).group_id(),
- report->field_trials(1).group_id());
+ ASSERT_EQ(2, report.field_trials_size());
+ EXPECT_NE(0U, report.field_trials(0).name_id());
+ EXPECT_NE(0U, report.field_trials(0).group_id());
+ EXPECT_NE(0U, report.field_trials(1).name_id());
+ EXPECT_EQ(report.field_trials(0).group_id(),
+ report.field_trials(1).group_id());
// Expect 5 key/value pairs (including product details).
- const auto& collected_data = report->global_data();
- EXPECT_EQ(5U, collected_data.size());
+ const auto& collected_data = report.global_data();
+ EXPECT_EQ(kInternalProcessDatums + 5U, collected_data.size());
EXPECT_TRUE(base::ContainsKey(collected_data, "string"));
}
@@ -704,15 +713,13 @@ TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest,
// Collect the stability report.
PostmortemReportCollector collector(kProductName, kVersionNumber,
- kChannelName);
- std::unique_ptr<StabilityReport> report;
- ASSERT_EQ(PostmortemReportCollector::SUCCESS,
- collector.Collect(debug_file_path(), &report));
- ASSERT_NE(nullptr, report);
+ kChannelName, nullptr);
+ StabilityReport report;
+ ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report));
// Validate the report's modules content.
- ASSERT_EQ(1, report->process_states_size());
- const ProcessState& process_state = report->process_states(0);
+ ASSERT_EQ(1, report.process_states_size());
+ const ProcessState& process_state = report.process_states(0);
ASSERT_EQ(1, process_state.modules_size());
const CodeModule collected_module = process_state.modules(0);
@@ -729,4 +736,27 @@ TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest,
EXPECT_EQ(!module_info.is_loaded, collected_module.is_unloaded());
}
+TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest,
+ SystemStateTest) {
+ // Setup.
+ GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL,
+ "", 3);
+ ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data();
+ process_data.SetInt(kStabilityStartTimestamp, 12345LL);
+
+ // Collect.
+ MockSystemSessionAnalyzer analyzer;
+ EXPECT_CALL(analyzer,
+ IsSessionUnclean(base::Time::FromInternalValue(12345LL)))
+ .Times(1)
+ .WillOnce(Return(SystemSessionAnalyzer::CLEAN));
+ PostmortemReportCollector collector(kProductName, kVersionNumber,
+ kChannelName, &analyzer);
+ StabilityReport report;
+ ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report));
+
+ // Validate the report.
+ ASSERT_EQ(SystemState::CLEAN, report.system_state().session_state());
+}
+
} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/postmortem_report_extractor.cc b/chromium/components/browser_watcher/postmortem_report_extractor.cc
new file mode 100644
index 00000000000..d21abae3697
--- /dev/null
+++ b/chromium/components/browser_watcher/postmortem_report_extractor.cc
@@ -0,0 +1,268 @@
+// 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/browser_watcher/postmortem_report_extractor.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/debug/activity_analyzer.h"
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/browser_watcher/stability_data_names.h"
+#include "components/variations/active_field_trials.h"
+#include "third_party/crashpad/crashpad/util/misc/uuid.h"
+
+namespace browser_watcher {
+
+using ActivitySnapshot = base::debug::ThreadActivityAnalyzer::Snapshot;
+using base::debug::ActivityUserData;
+using base::debug::GlobalActivityAnalyzer;
+using base::debug::GlobalActivityTracker;
+using base::debug::ThreadActivityAnalyzer;
+
+namespace {
+
+const char kFieldTrialKeyPrefix[] = "FieldTrial.";
+
+// Collects stability user data from the recorded format to the collected
+// format.
+void CollectUserData(
+ const ActivityUserData::Snapshot& recorded_map,
+ google::protobuf::Map<std::string, TypedValue>* collected_map,
+ StabilityReport* report) {
+ DCHECK(collected_map);
+
+ for (const auto& name_and_value : recorded_map) {
+ const std::string& key = name_and_value.first;
+ const ActivityUserData::TypedValue& recorded_value = name_and_value.second;
+ TypedValue collected_value;
+
+ switch (recorded_value.type()) {
+ case ActivityUserData::END_OF_VALUES:
+ NOTREACHED();
+ break;
+ case ActivityUserData::RAW_VALUE: {
+ base::StringPiece raw = recorded_value.Get();
+ collected_value.set_bytes_value(raw.data(), raw.size());
+ break;
+ }
+ case ActivityUserData::RAW_VALUE_REFERENCE: {
+ base::StringPiece recorded_ref = recorded_value.GetReference();
+ TypedValue::Reference* collected_ref =
+ collected_value.mutable_bytes_reference();
+ collected_ref->set_address(
+ reinterpret_cast<uintptr_t>(recorded_ref.data()));
+ collected_ref->set_size(recorded_ref.size());
+ break;
+ }
+ case ActivityUserData::STRING_VALUE: {
+ base::StringPiece value = recorded_value.GetString();
+
+ if (report && base::StartsWith(key, kFieldTrialKeyPrefix,
+ base::CompareCase::SENSITIVE)) {
+ // This entry represents an active Field Trial.
+ std::string trial_name =
+ key.substr(std::strlen(kFieldTrialKeyPrefix));
+ variations::ActiveGroupId group_id =
+ variations::MakeActiveGroupId(trial_name, value.as_string());
+ FieldTrial* field_trial = report->add_field_trials();
+ field_trial->set_name_id(group_id.name);
+ field_trial->set_group_id(group_id.group);
+ continue;
+ }
+
+ collected_value.set_string_value(value.data(), value.size());
+ break;
+ }
+ case ActivityUserData::STRING_VALUE_REFERENCE: {
+ base::StringPiece recorded_ref = recorded_value.GetStringReference();
+ TypedValue::Reference* collected_ref =
+ collected_value.mutable_string_reference();
+ collected_ref->set_address(
+ reinterpret_cast<uintptr_t>(recorded_ref.data()));
+ collected_ref->set_size(recorded_ref.size());
+ break;
+ }
+ case ActivityUserData::CHAR_VALUE: {
+ char char_value = recorded_value.GetChar();
+ collected_value.set_char_value(&char_value, 1);
+ break;
+ }
+ case ActivityUserData::BOOL_VALUE:
+ collected_value.set_bool_value(recorded_value.GetBool());
+ break;
+ case ActivityUserData::SIGNED_VALUE:
+ collected_value.set_signed_value(recorded_value.GetInt());
+ break;
+ case ActivityUserData::UNSIGNED_VALUE:
+ collected_value.set_unsigned_value(recorded_value.GetUint());
+ break;
+ }
+
+ (*collected_map)[key].Swap(&collected_value);
+ }
+}
+
+void CollectModuleInformation(
+ const std::vector<GlobalActivityTracker::ModuleInfo>& modules,
+ ProcessState* process_state) {
+ DCHECK(process_state);
+
+ for (const GlobalActivityTracker::ModuleInfo& recorded : modules) {
+ CodeModule* collected = process_state->add_modules();
+ collected->set_base_address(recorded.address);
+ collected->set_size(recorded.size);
+ collected->set_code_file(recorded.file);
+
+ // Compute the code identifier using the required format.
+ std::string code_identifier =
+ base::StringPrintf("%08X%zx", recorded.timestamp, recorded.size);
+ collected->set_code_identifier(code_identifier);
+ collected->set_debug_file(recorded.debug_file);
+
+ // Compute the debug identifier using the required format.
+ const crashpad::UUID* uuid =
+ reinterpret_cast<const crashpad::UUID*>(recorded.identifier);
+ std::string debug_identifier = base::StringPrintf(
+ "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x", uuid->data_1,
+ uuid->data_2, uuid->data_3, uuid->data_4[0], uuid->data_4[1],
+ uuid->data_5[0], uuid->data_5[1], uuid->data_5[2], uuid->data_5[3],
+ uuid->data_5[4], uuid->data_5[5], recorded.age);
+ collected->set_debug_identifier(debug_identifier);
+ collected->set_is_unloaded(!recorded.is_loaded);
+ }
+}
+
+void CollectActivity(const base::debug::Activity& recorded,
+ Activity* collected) {
+ DCHECK(collected);
+
+ collected->set_time(recorded.time_internal);
+ collected->set_address(recorded.calling_address);
+ collected->set_origin_address(recorded.origin_address);
+
+ // TODO(manzagop): the current collection deals with specific activity types;
+ // consider modifying it to handle the notion of activity categories.
+ switch (recorded.activity_type) {
+ case base::debug::Activity::ACT_TASK_RUN:
+ collected->set_type(Activity::ACT_TASK_RUN);
+ collected->set_task_sequence_id(recorded.data.task.sequence_id);
+ break;
+ case base::debug::Activity::ACT_LOCK_ACQUIRE:
+ collected->set_type(Activity::ACT_LOCK_ACQUIRE);
+ collected->set_lock_address(recorded.data.lock.lock_address);
+ break;
+ case base::debug::Activity::ACT_EVENT_WAIT:
+ collected->set_type(Activity::ACT_EVENT_WAIT);
+ collected->set_event_address(recorded.data.event.event_address);
+ break;
+ case base::debug::Activity::ACT_THREAD_JOIN:
+ collected->set_type(Activity::ACT_THREAD_JOIN);
+ collected->set_thread_id(recorded.data.thread.thread_id);
+ break;
+ case base::debug::Activity::ACT_PROCESS_WAIT:
+ collected->set_type(Activity::ACT_PROCESS_WAIT);
+ collected->set_process_id(recorded.data.process.process_id);
+ break;
+ case base::debug::Activity::ACT_GENERIC:
+ collected->set_type(Activity::ACT_GENERIC);
+ collected->set_generic_id(recorded.data.generic.id);
+ collected->set_generic_data(recorded.data.generic.info);
+ break;
+ default:
+ break;
+ }
+}
+
+void CollectThread(
+ const base::debug::ThreadActivityAnalyzer::Snapshot& snapshot,
+ ThreadState* thread_state) {
+ DCHECK(thread_state);
+
+ thread_state->set_thread_name(snapshot.thread_name);
+ thread_state->set_thread_id(snapshot.thread_id);
+ thread_state->set_activity_count(snapshot.activity_stack_depth);
+
+ for (size_t i = 0; i < snapshot.activity_stack.size(); ++i) {
+ Activity* collected = thread_state->add_activities();
+
+ CollectActivity(snapshot.activity_stack[i], collected);
+ if (i < snapshot.user_data_stack.size()) {
+ CollectUserData(snapshot.user_data_stack[i],
+ collected->mutable_user_data(), nullptr);
+ }
+ }
+}
+
+} // namespace
+
+CollectionStatus Extract(const base::FilePath& stability_file,
+ StabilityReport* report) {
+ DCHECK(report);
+
+ // Create a global analyzer.
+ std::unique_ptr<GlobalActivityAnalyzer> global_analyzer =
+ GlobalActivityAnalyzer::CreateWithFile(stability_file);
+ if (!global_analyzer)
+ return ANALYZER_CREATION_FAILED;
+
+ // Extract data for only the first process.
+ // TODO(manzagop): Extend this to all processes.
+ int64_t pid = global_analyzer->GetFirstProcess();
+
+ // Early exit if there is no data.
+ std::vector<std::string> log_messages = global_analyzer->GetLogMessages();
+ ActivityUserData::Snapshot process_data_snapshot =
+ global_analyzer->GetProcessDataSnapshot(pid);
+
+ ThreadActivityAnalyzer* thread_analyzer =
+ global_analyzer->GetFirstAnalyzer(pid);
+ if (log_messages.empty() && process_data_snapshot.empty() &&
+ !thread_analyzer) {
+ return DEBUG_FILE_NO_DATA;
+ }
+
+ // Collect log messages.
+ for (const std::string& message : log_messages) {
+ report->add_log_messages(message);
+ }
+
+ // Collect global user data.
+ google::protobuf::Map<std::string, TypedValue>& global_data =
+ *(report->mutable_global_data());
+ CollectUserData(process_data_snapshot, &global_data, report);
+
+ // Collect thread activity data.
+ // Note: a single process is instrumented.
+ ProcessState* process_state = report->add_process_states();
+ for (; thread_analyzer != nullptr;
+ thread_analyzer = global_analyzer->GetNextAnalyzer()) {
+ // Only valid analyzers are expected per contract of GetFirstAnalyzer /
+ // GetNextAnalyzer.
+ DCHECK(thread_analyzer->IsValid());
+
+ if (!process_state->has_process_id()) {
+ process_state->set_process_id(
+ thread_analyzer->activity_snapshot().process_id);
+ }
+ DCHECK_EQ(thread_analyzer->activity_snapshot().process_id,
+ process_state->process_id());
+
+ ThreadState* thread_state = process_state->add_threads();
+ CollectThread(thread_analyzer->activity_snapshot(), thread_state);
+ }
+
+ // Collect module information.
+ CollectModuleInformation(global_analyzer->GetModules(), process_state);
+
+ return SUCCESS;
+}
+
+} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/postmortem_report_extractor.h b/chromium/components/browser_watcher/postmortem_report_extractor.h
new file mode 100644
index 00000000000..bc7186b191a
--- /dev/null
+++ b/chromium/components/browser_watcher/postmortem_report_extractor.h
@@ -0,0 +1,36 @@
+// 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.
+//
+// Implementation of the collection of a stability file to a protocol buffer.
+
+#ifndef COMPONENTS_BROWSER_WATCHER_POSTMORTEM_REPORT_EXTRACTOR_H_
+#define COMPONENTS_BROWSER_WATCHER_POSTMORTEM_REPORT_EXTRACTOR_H_
+
+#include "base/files/file_path.h"
+#include "components/browser_watcher/stability_report.pb.h"
+
+namespace browser_watcher {
+
+// DO NOT CHANGE VALUES. This is logged persistently in a histogram.
+enum CollectionStatus {
+ NONE = 0,
+ SUCCESS = 1, // Successfully registered a report with Crashpad.
+ ANALYZER_CREATION_FAILED = 2,
+ DEBUG_FILE_NO_DATA = 3,
+ PREPARE_NEW_CRASH_REPORT_FAILED = 4,
+ WRITE_TO_MINIDUMP_FAILED = 5,
+ DEBUG_FILE_DELETION_FAILED = 6,
+ FINISHED_WRITING_CRASH_REPORT_FAILED = 7,
+ COLLECTION_STATUS_MAX = 8
+};
+
+// Extracts a stability report from a stability file.
+// TODO(manzagop): have a function that takes a GlobalActivityAnalyzer instead
+// and simplify testing.
+CollectionStatus Extract(const base::FilePath& stability_file,
+ StabilityReport* report);
+
+} // namespace browser_watcher
+
+#endif // COMPONENTS_BROWSER_WATCHER_POSTMORTEM_REPORT_EXTRACTOR_H_
diff --git a/chromium/components/browser_watcher/stability_data_names.cc b/chromium/components/browser_watcher/stability_data_names.cc
index d1a3eedbbdd..63341220516 100644
--- a/chromium/components/browser_watcher/stability_data_names.cc
+++ b/chromium/components/browser_watcher/stability_data_names.cc
@@ -15,6 +15,7 @@ const char kStabilityReporterPlatform[] = "reporter-platform";
const char kStabilityReporterProduct[] = "reporter-product";
const char kStabilityReporterVersion[] = "reporter-version";
const char kStabilitySpecialBuild[] = "special-build";
+const char kStabilityStartTimestamp[] = "start-timestamp";
const char kStabilityVersion[] = "version";
} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/stability_data_names.h b/chromium/components/browser_watcher/stability_data_names.h
index 1bf1f89a379..4ee91012b67 100644
--- a/chromium/components/browser_watcher/stability_data_names.h
+++ b/chromium/components/browser_watcher/stability_data_names.h
@@ -17,6 +17,7 @@ extern const char kStabilityReporterPlatform[];
extern const char kStabilityReporterProduct[];
extern const char kStabilityReporterVersion[];
extern const char kStabilitySpecialBuild[];
+extern const char kStabilityStartTimestamp[];
extern const char kStabilityVersion[];
} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/stability_debugging.cc b/chromium/components/browser_watcher/stability_debugging.cc
index 59dc4fba769..c7919d2b773 100644
--- a/chromium/components/browser_watcher/stability_debugging.cc
+++ b/chromium/components/browser_watcher/stability_debugging.cc
@@ -97,7 +97,7 @@ void SetStabilityDataInt(base::StringPiece name, int64_t value) {
if (!global_tracker)
return; // Activity tracking isn't enabled.
- global_tracker->global_data().SetInt(name, value);
+ global_tracker->process_data().SetInt(name, value);
}
} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/stability_report.proto b/chromium/components/browser_watcher/stability_report.proto
index b5039a23e83..18ea17cd8dd 100644
--- a/chromium/components/browser_watcher/stability_report.proto
+++ b/chromium/components/browser_watcher/stability_report.proto
@@ -10,9 +10,18 @@ package browser_watcher;
// The state of the system on which Chrome is running (shutting down, battery
// level, load, etc.).
-// Next id: 1
+// Next id: 2
message SystemState {
- // TODO(manzagop): flesh out.
+ // The state of a system session. A system session begins when the system
+ // starts and ends when it shuts down.
+ enum SessionState {
+ UNKNOWN = 0;
+ CLEAN = 1; // Normal shutdown.
+ UNCLEAN = 2; // Abnormal shutdown (system crash, power loss).
+ }
+
+ // The state of the system session that contained Chrome's execution.
+ optional SessionState session_state = 1;
}
// Next id: 10
@@ -78,7 +87,7 @@ message TypedValue {
}
// An activity represents information about something of interest on a thread.
-// Next id: 11
+// Next id: 14
message Activity {
enum Type {
UNKNOWN = 0;
@@ -87,6 +96,7 @@ message Activity {
ACT_EVENT_WAIT = 3;
ACT_THREAD_JOIN = 4;
ACT_PROCESS_WAIT = 5;
+ ACT_GENERIC = 6;
}
// Identifies the type of the activity (and specifies which fields are
@@ -96,8 +106,12 @@ message Activity {
// Creation time of the activity.
optional int64 time = 2;
- // The address that is the origin of the activity.
- // Expected for ACT_TASK_*
+ // The address that pushed the activity onto the stack.
+ optional uint64 address = 11;
+
+ // The address that is the origin of the activity. This is useful for things
+ // like tasks that are posted from a completely different thread though most
+ // activities will leave it null.
optional uint64 origin_address = 3;
// The sequence identifier of the posted task.
@@ -116,6 +130,12 @@ message Activity {
// A unique identifier for a process.
optional int64 process_id = 8;
+ // An arbitrary identifier used for association.
+ optional uint32 generic_id = 12;
+
+ // An arbitrary value used for information purposes.
+ optional int32 generic_data = 13;
+
// Tag id 10 is reserved for server side augmentation.
// A key-value store.
diff --git a/chromium/components/browser_watcher/system_session_analyzer_win.cc b/chromium/components/browser_watcher/system_session_analyzer_win.cc
new file mode 100644
index 00000000000..e4882199e58
--- /dev/null
+++ b/chromium/components/browser_watcher/system_session_analyzer_win.cc
@@ -0,0 +1,244 @@
+// 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/browser_watcher/system_session_analyzer_win.h"
+
+#include <windows.h>
+#include <winevt.h>
+
+#include <utility>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+
+namespace browser_watcher {
+
+namespace {
+
+// The name of the log channel to query.
+const wchar_t kChannelName[] = L"System";
+
+// Event ids of system startup / shutdown events. These were obtained from
+// inspection of the System log in Event Viewer on Windows 10:
+// - id 6005: "The Event log service was started."
+// - id 6006: "The Event log service was stopped."
+// - id 6008: "The previous system shutdown at <time> on <date> was
+// unexpected."
+const uint16_t kIdSessionStart = 6005U;
+const uint16_t kIdSessionEnd = 6006U;
+const uint16_t kIdSessionEndUnclean = 6008U;
+
+// An XPATH expression to query for system startup / shutdown events. The query
+// is expected to retrieve exactly one event for each startup (kIdSessionStart)
+// and one event for each shutdown (either kIdSessionEnd or
+// kIdSessionEndUnclean).
+const wchar_t kSessionEventsQuery[] =
+ L"*[System[Provider[@Name='eventlog']"
+ L" and (EventID=6005 or EventID=6006 or EventID=6008)]]";
+
+// XPath expressions to attributes of interest.
+const wchar_t kEventIdPath[] = L"Event/System/EventID";
+const wchar_t kEventTimePath[] = L"Event/System/TimeCreated/@SystemTime";
+
+// The timeout to use for calls to ::EvtNext.
+const uint32_t kTimeoutMs = 5000;
+
+struct EvtHandleCloser {
+ using pointer = EVT_HANDLE;
+ void operator()(EVT_HANDLE handle) const {
+ if (handle)
+ ::EvtClose(handle);
+ }
+};
+
+using EvtHandle = std::unique_ptr<EVT_HANDLE, EvtHandleCloser>;
+
+base::Time ULLFileTimeToTime(ULONGLONG time_ulonglong) {
+ // Copy low / high parts as FILETIME is not always 64bit aligned.
+ ULARGE_INTEGER time;
+ time.QuadPart = time_ulonglong;
+ FILETIME ft;
+ ft.dwLowDateTime = time.LowPart;
+ ft.dwHighDateTime = time.HighPart;
+
+ return base::Time::FromFileTime(ft);
+}
+
+// Create a render context (i.e. specify attributes of interest).
+EvtHandle CreateRenderContext() {
+ LPCWSTR value_paths[] = {kEventIdPath, kEventTimePath};
+ const DWORD kValueCnt = arraysize(value_paths);
+
+ EVT_HANDLE context = NULL;
+ context =
+ ::EvtCreateRenderContext(kValueCnt, value_paths, EvtRenderContextValues);
+ if (!context)
+ DLOG(ERROR) << "Failed to create render context.";
+
+ return EvtHandle(context);
+}
+
+bool GetEventInfo(EVT_HANDLE context,
+ EVT_HANDLE event,
+ SystemSessionAnalyzer::EventInfo* info) {
+ DCHECK(context);
+ DCHECK(event);
+ DCHECK(info);
+
+ // Retrieve attributes of interest from the event. We expect the context to
+ // specify the retrieval of two attributes (event id and event time), each
+ // with a specific type.
+ const DWORD kAttributeCnt = 2U;
+ std::vector<EVT_VARIANT> buffer(kAttributeCnt);
+ DWORD buffer_size = kAttributeCnt * sizeof(EVT_VARIANT);
+ DWORD buffer_used = 0U;
+ DWORD retrieved_attribute_cnt = 0U;
+ if (!::EvtRender(context, event, EvtRenderEventValues, buffer_size,
+ buffer.data(), &buffer_used, &retrieved_attribute_cnt)) {
+ DLOG(ERROR) << "Failed to render the event.";
+ return false;
+ }
+
+ // Validate the count and types of the retrieved attributes.
+ if ((retrieved_attribute_cnt != kAttributeCnt) ||
+ (buffer[0].Type != EvtVarTypeUInt16) ||
+ (buffer[1].Type != EvtVarTypeFileTime)) {
+ return false;
+ }
+
+ info->event_id = buffer[0].UInt16Val;
+ info->event_time = ULLFileTimeToTime(buffer[1].FileTimeVal);
+
+ return true;
+}
+
+} // namespace
+
+SystemSessionAnalyzer::SystemSessionAnalyzer(uint32_t session_cnt)
+ : session_cnt_(session_cnt) {}
+
+SystemSessionAnalyzer::~SystemSessionAnalyzer() {}
+
+SystemSessionAnalyzer::Status SystemSessionAnalyzer::IsSessionUnclean(
+ base::Time timestamp) {
+ if (!initialized_) {
+ DCHECK(!init_success_);
+ init_success_ = Initialize();
+ initialized_ = true;
+ }
+ if (!init_success_)
+ return FAILED;
+ if (timestamp < coverage_start_)
+ return OUTSIDE_RANGE;
+
+ // Get the first session starting after the timestamp.
+ std::map<base::Time, base::TimeDelta>::const_iterator it =
+ unclean_sessions_.upper_bound(timestamp);
+ if (it == unclean_sessions_.begin())
+ return CLEAN; // No prior unclean session.
+
+ // Get the previous session and see if it encompasses the timestamp.
+ --it;
+ bool is_spanned = (timestamp - it->first) <= it->second;
+ return is_spanned ? UNCLEAN : CLEAN;
+}
+
+bool SystemSessionAnalyzer::FetchEvents(
+ std::vector<EventInfo>* event_infos) const {
+ DCHECK(event_infos);
+
+ // Query for the events. Note: requesting events from newest to oldest.
+ EVT_HANDLE query_raw =
+ ::EvtQuery(nullptr, kChannelName, kSessionEventsQuery,
+ EvtQueryChannelPath | EvtQueryReverseDirection);
+ if (!query_raw) {
+ DLOG(ERROR) << "Event query failed.";
+ return false;
+ }
+ EvtHandle query(query_raw);
+
+ // Retrieve events: 2 events per session, plus the current session's start.
+ DWORD desired_event_cnt = 2U * session_cnt_ + 1U;
+ std::vector<EVT_HANDLE> events_raw(desired_event_cnt, NULL);
+ DWORD event_cnt = 0U;
+ BOOL success = ::EvtNext(query.get(), desired_event_cnt, events_raw.data(),
+ kTimeoutMs, 0, &event_cnt);
+
+ // Ensure handles get closed. The MSDN sample seems to imply handles may need
+ // to be closed event in if EvtNext failed.
+ std::vector<EvtHandle> events(desired_event_cnt);
+ for (size_t i = 0; i < event_cnt; ++i)
+ events[i].reset(events_raw[i]);
+
+ if (!success) {
+ DLOG(ERROR) << "Failed to retrieve events.";
+ return false;
+ }
+
+ // Extract information from the events.
+ EvtHandle render_context = CreateRenderContext();
+ if (!render_context.get())
+ return false;
+
+ std::vector<EventInfo> event_infos_tmp;
+ event_infos_tmp.reserve(event_cnt);
+
+ EventInfo info = {};
+ for (size_t i = 0; i < event_cnt; ++i) {
+ if (!GetEventInfo(render_context.get(), events[i].get(), &info))
+ return false;
+ event_infos_tmp.push_back(info);
+ }
+
+ event_infos->swap(event_infos_tmp);
+ return true;
+}
+
+bool SystemSessionAnalyzer::Initialize() {
+ std::vector<SystemSessionAnalyzer::EventInfo> events;
+ if (!FetchEvents(&events))
+ return false;
+
+ // Validate the number and ordering of events (newest to oldest). The
+ // expectation is a (start / [unclean]shutdown) pair of events for each
+ // session, as well as an additional event for the current session's start.
+ size_t event_cnt = events.size();
+ if ((event_cnt % 2) == 0)
+ return false; // Even number is unexpected.
+ if (event_cnt < 3)
+ return false; // Not enough data for a single session.
+ for (size_t i = 1; i < event_cnt; ++i) {
+ if (events[i - 1].event_time < events[i].event_time)
+ return false;
+ }
+
+ // Step through (start / shutdown) event pairs, validating the types of events
+ // and recording unclean sessions.
+ std::map<base::Time, base::TimeDelta> unclean_sessions;
+ size_t start = 2U;
+ size_t end = 1U;
+ for (; start < event_cnt && end < event_cnt; start += 2, end += 2) {
+ uint16_t start_id = events[start].event_id;
+ uint16_t end_id = events[end].event_id;
+ if (start_id != kIdSessionStart)
+ return false; // Unexpected event type.
+ if (end_id != kIdSessionEnd && end_id != kIdSessionEndUnclean)
+ return false; // Unexpected event type.
+
+ if (end_id == kIdSessionEnd)
+ continue; // This is a clean session.
+
+ unclean_sessions.insert(
+ std::make_pair(events[start].event_time,
+ events[end].event_time - events[start].event_time));
+ }
+
+ unclean_sessions_.swap(unclean_sessions);
+ DCHECK_GT(event_cnt, 0U);
+ coverage_start_ = events[event_cnt - 1].event_time;
+
+ return true;
+}
+
+} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/system_session_analyzer_win.h b/chromium/components/browser_watcher/system_session_analyzer_win.h
new file mode 100644
index 00000000000..33162cd8419
--- /dev/null
+++ b/chromium/components/browser_watcher/system_session_analyzer_win.h
@@ -0,0 +1,75 @@
+// 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_BROWSER_WATCHER_SYSTEM_SESSION_ANALYZER_WIN_H_
+#define COMPONENTS_BROWSER_WATCHER_SYSTEM_SESSION_ANALYZER_WIN_H_
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "base/time/time.h"
+
+namespace browser_watcher {
+
+// Analyzes system session events for unclean sessions. Initialization is
+// expensive and therefore done lazily, as the analyzer is instantiated before
+// knowing whether it will be used.
+class SystemSessionAnalyzer {
+ public:
+ enum Status {
+ FAILED = 0,
+ CLEAN = 1,
+ UNCLEAN = 2,
+ OUTSIDE_RANGE = 3,
+ };
+
+ // Minimal information about a log event.
+ struct EventInfo {
+ uint16_t event_id;
+ base::Time event_time;
+ };
+
+ // Creates a SystemSessionAnalyzer that will analyze system sessions based on
+ // events pertaining to the last session_cnt system sessions.
+ explicit SystemSessionAnalyzer(uint32_t session_cnt);
+ virtual ~SystemSessionAnalyzer();
+
+ // Returns an analysis status for the system session that contains timestamp.
+ virtual Status IsSessionUnclean(base::Time timestamp);
+
+ protected:
+ // Queries for events pertaining to the last session_cnt sessions. On success,
+ // returns true and event_infos contains events ordered from newest to oldest.
+ // Returns false otherwise. Virtual for unit testing.
+ virtual bool FetchEvents(std::vector<EventInfo>* event_infos) const;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(SystemSessionAnalyzerTest, FetchEvents);
+
+ bool Initialize();
+
+ // The number of sessions to query events for.
+ uint32_t session_cnt_;
+
+ bool initialized_ = false;
+ bool init_success_ = false;
+
+ // Information about unclean sessions: start time to duration until the next
+ // session start, ie *not* session duration. Note: it's easier to get the
+ // delta to the next session start, and changes nothing wrt classifying
+ // events that occur during sessions assuming query timestamps fall within
+ // system sessions.
+ std::map<base::Time, base::TimeDelta> unclean_sessions_;
+
+ // Timestamp of the oldest event.
+ base::Time coverage_start_;
+
+ DISALLOW_COPY_AND_ASSIGN(SystemSessionAnalyzer);
+};
+
+} // namespace browser_watcher
+
+#endif // COMPONENTS_BROWSER_WATCHER_SYSTEM_SESSION_ANALYZER_WIN_H_
diff --git a/chromium/components/browser_watcher/system_session_analyzer_win_unittest.cc b/chromium/components/browser_watcher/system_session_analyzer_win_unittest.cc
new file mode 100644
index 00000000000..62c96234b7b
--- /dev/null
+++ b/chromium/components/browser_watcher/system_session_analyzer_win_unittest.cc
@@ -0,0 +1,117 @@
+// 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/browser_watcher/system_session_analyzer_win.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/time/time.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace browser_watcher {
+
+namespace {
+
+const uint16_t kIdSessionStart = 6005U;
+const uint16_t kIdSessionEnd = 6006U;
+const uint16_t kIdSessionEndUnclean = 6008U;
+
+} // namespace
+
+// Ensure the fetcher retrieves events.
+// Note: this test fails if the host system doesn't have at least 1 prior
+// session.
+TEST(SystemSessionAnalyzerTest, FetchEvents) {
+ SystemSessionAnalyzer analyzer(1U);
+ std::vector<SystemSessionAnalyzer::EventInfo> events;
+ ASSERT_TRUE(analyzer.FetchEvents(&events));
+ EXPECT_EQ(3U, events.size());
+}
+
+// Ensure the fetcher's retrieved events conform to our expectations.
+// Note: this test fails if the host system doesn't have at least 1 prior
+// session.
+TEST(SystemSessionAnalyzerTest, ValidateEvents) {
+ SystemSessionAnalyzer analyzer(1U);
+ EXPECT_EQ(SystemSessionAnalyzer::CLEAN,
+ analyzer.IsSessionUnclean(base::Time::Now()));
+}
+
+// Stubs FetchEvents.
+class StubSystemSessionAnalyzer : public SystemSessionAnalyzer {
+ public:
+ StubSystemSessionAnalyzer() : SystemSessionAnalyzer(10U) {}
+
+ bool FetchEvents(std::vector<EventInfo>* event_infos) const override {
+ DCHECK(event_infos);
+ *event_infos = events_;
+ return true;
+ }
+
+ void AddEvent(const EventInfo& info) { events_.push_back(info); }
+
+ private:
+ std::vector<EventInfo> events_;
+};
+
+TEST(SystemSessionAnalyzerTest, StandardCase) {
+ StubSystemSessionAnalyzer analyzer;
+
+ base::Time time = base::Time::Now();
+ analyzer.AddEvent({kIdSessionStart, time});
+ analyzer.AddEvent(
+ {kIdSessionEndUnclean, time - base::TimeDelta::FromSeconds(10)});
+ analyzer.AddEvent({kIdSessionStart, time - base::TimeDelta::FromSeconds(20)});
+ analyzer.AddEvent({kIdSessionEnd, time - base::TimeDelta::FromSeconds(22)});
+ analyzer.AddEvent({kIdSessionStart, time - base::TimeDelta::FromSeconds(28)});
+
+ EXPECT_EQ(SystemSessionAnalyzer::OUTSIDE_RANGE,
+ analyzer.IsSessionUnclean(time - base::TimeDelta::FromSeconds(30)));
+ EXPECT_EQ(SystemSessionAnalyzer::CLEAN,
+ analyzer.IsSessionUnclean(time - base::TimeDelta::FromSeconds(25)));
+ EXPECT_EQ(SystemSessionAnalyzer::UNCLEAN,
+ analyzer.IsSessionUnclean(time - base::TimeDelta::FromSeconds(20)));
+ EXPECT_EQ(SystemSessionAnalyzer::UNCLEAN,
+ analyzer.IsSessionUnclean(time - base::TimeDelta::FromSeconds(15)));
+ EXPECT_EQ(SystemSessionAnalyzer::UNCLEAN,
+ analyzer.IsSessionUnclean(time - base::TimeDelta::FromSeconds(10)));
+ EXPECT_EQ(SystemSessionAnalyzer::CLEAN,
+ analyzer.IsSessionUnclean(time - base::TimeDelta::FromSeconds(5)));
+ EXPECT_EQ(SystemSessionAnalyzer::CLEAN,
+ analyzer.IsSessionUnclean(time + base::TimeDelta::FromSeconds(5)));
+}
+
+TEST(SystemSessionAnalyzerTest, NoEvent) {
+ StubSystemSessionAnalyzer analyzer;
+ EXPECT_EQ(SystemSessionAnalyzer::FAILED,
+ analyzer.IsSessionUnclean(base::Time::Now()));
+}
+
+TEST(SystemSessionAnalyzerTest, TimeInversion) {
+ StubSystemSessionAnalyzer analyzer;
+
+ base::Time time = base::Time::Now();
+ analyzer.AddEvent({kIdSessionStart, time});
+ analyzer.AddEvent({kIdSessionEnd, time + base::TimeDelta::FromSeconds(1)});
+ analyzer.AddEvent({kIdSessionStart, time - base::TimeDelta::FromSeconds(1)});
+
+ EXPECT_EQ(SystemSessionAnalyzer::FAILED,
+ analyzer.IsSessionUnclean(base::Time::Now()));
+}
+
+TEST(SystemSessionAnalyzerTest, IdInversion) {
+ StubSystemSessionAnalyzer analyzer;
+
+ base::Time time = base::Time::Now();
+ analyzer.AddEvent({kIdSessionStart, time});
+ analyzer.AddEvent({kIdSessionStart, time - base::TimeDelta::FromSeconds(1)});
+ analyzer.AddEvent({kIdSessionEnd, time - base::TimeDelta::FromSeconds(2)});
+
+ EXPECT_EQ(SystemSessionAnalyzer::FAILED,
+ analyzer.IsSessionUnclean(base::Time::Now()));
+}
+
+} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/watcher_metrics_provider_win.cc b/chromium/components/browser_watcher/watcher_metrics_provider_win.cc
index 74db4f5c837..45617eb176c 100644
--- a/chromium/components/browser_watcher/watcher_metrics_provider_win.cc
+++ b/chromium/components/browser_watcher/watcher_metrics_provider_win.cc
@@ -9,6 +9,7 @@
#include <limits>
#include <memory>
#include <set>
+#include <utility>
#include <vector>
#include "base/bind.h"
@@ -25,6 +26,7 @@
#include "components/browser_watcher/features.h"
#include "components/browser_watcher/postmortem_report_collector.h"
#include "components/browser_watcher/stability_debugging.h"
+#include "components/browser_watcher/system_session_analyzer_win.h"
#include "third_party/crashpad/crashpad/client/crash_report_database.h"
namespace browser_watcher {
@@ -263,15 +265,18 @@ void WatcherMetricsProviderWin::CollectPostmortemReportsOnBlockingPool() {
LogCollectionInitStatus(INIT_SUCCESS);
- // TODO(manzagop): fix incorrect version attribution on update.
+ // Get the reporter's version details.
base::string16 product_name, version_number, channel_name;
exe_details_cb_.Run(&product_name, &version_number, &channel_name);
- PostmortemReportCollector collector(base::UTF16ToUTF8(product_name),
- base::UTF16ToUTF8(version_number),
- base::UTF16ToUTF8(channel_name));
- collector.CollectAndSubmitForUpload(stability_dir, GetStabilityFilePattern(),
- excluded_debug_files,
- crashpad_database.get());
+
+ const size_t kSystemSessionsToInspect = 5U;
+ SystemSessionAnalyzer analyzer(kSystemSessionsToInspect);
+ PostmortemReportCollector collector(
+ base::UTF16ToUTF8(product_name), base::UTF16ToUTF8(version_number),
+ base::UTF16ToUTF8(channel_name), &analyzer);
+ collector.CollectAndSubmitAllPendingReports(
+ stability_dir, GetStabilityFilePattern(), excluded_debug_files,
+ crashpad_database.get());
}
} // namespace browser_watcher
diff --git a/chromium/components/browsing_data/content/BUILD.gn b/chromium/components/browsing_data/content/BUILD.gn
index aa613cff35e..dc5b1bd505d 100644
--- a/chromium/components/browsing_data/content/BUILD.gn
+++ b/chromium/components/browsing_data/content/BUILD.gn
@@ -6,10 +6,6 @@ static_library("content") {
sources = [
"conditional_cache_counting_helper.cc",
"conditional_cache_counting_helper.h",
- "conditional_cache_deletion_helper.cc",
- "conditional_cache_deletion_helper.h",
- "storage_partition_http_cache_data_remover.cc",
- "storage_partition_http_cache_data_remover.h",
]
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
diff --git a/chromium/components/browsing_data/content/conditional_cache_deletion_helper.cc b/chromium/components/browsing_data/content/conditional_cache_deletion_helper.cc
deleted file mode 100644
index f0f500e9633..00000000000
--- a/chromium/components/browsing_data/content/conditional_cache_deletion_helper.cc
+++ /dev/null
@@ -1,96 +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/browsing_data/content/conditional_cache_deletion_helper.h"
-
-#include "base/callback.h"
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "content/public/browser/browser_thread.h"
-
-namespace {
-
-bool EntryPredicateFromURLsAndTime(
- const base::Callback<bool(const GURL&)>& url_predicate,
- const base::Time& begin_time,
- const base::Time& end_time,
- const disk_cache::Entry* entry) {
- return (entry->GetLastUsed() >= begin_time &&
- entry->GetLastUsed() < end_time &&
- url_predicate.Run(GURL(entry->GetKey())));
-}
-
-} // namespace
-
-namespace browsing_data {
-
-ConditionalCacheDeletionHelper::ConditionalCacheDeletionHelper(
- disk_cache::Backend* cache,
- const base::Callback<bool(const disk_cache::Entry*)>& condition)
- : cache_(cache),
- condition_(condition),
- current_entry_(nullptr),
- previous_entry_(nullptr) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-}
-
-// static
-base::Callback<bool(const disk_cache::Entry*)>
-ConditionalCacheDeletionHelper::CreateURLAndTimeCondition(
- const base::Callback<bool(const GURL&)>& url_predicate,
- const base::Time& begin_time,
- const base::Time& end_time) {
- return base::Bind(
- &EntryPredicateFromURLsAndTime,
- url_predicate,
- begin_time.is_null() ? base::Time() : begin_time,
- end_time.is_null() ? base::Time::Max() : end_time);
-}
-
-int ConditionalCacheDeletionHelper::DeleteAndDestroySelfWhenFinished(
- const net::CompletionCallback& completion_callback) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
- completion_callback_ = completion_callback;
- iterator_ = cache_->CreateIterator();
-
- IterateOverEntries(net::OK);
- return net::ERR_IO_PENDING;
-}
-
-ConditionalCacheDeletionHelper::~ConditionalCacheDeletionHelper() {
-}
-
-void ConditionalCacheDeletionHelper::IterateOverEntries(int error) {
- while (error != net::ERR_IO_PENDING) {
- // If the entry obtained in the previous iteration matches the condition,
- // mark it for deletion. The iterator is already one step forward, so it
- // won't be invalidated. Always close the previous entry so it does not
- // leak.
- if (previous_entry_) {
- if (condition_.Run(previous_entry_))
- previous_entry_->Doom();
- previous_entry_->Close();
- }
-
- if (error == net::ERR_FAILED) {
- // The iteration finished successfully or we can no longer iterate
- // (e.g. the cache was destroyed). We cannot distinguish between the two,
- // but we know that there is nothing more that we can do, so we return OK.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(completion_callback_, net::OK));
- base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
- return;
- }
-
- previous_entry_ = current_entry_;
- error = iterator_->OpenNextEntry(
- &current_entry_,
- base::Bind(&ConditionalCacheDeletionHelper::IterateOverEntries,
- base::Unretained(this)));
- }
-}
-
-} // namespace browsing_data
diff --git a/chromium/components/browsing_data/content/conditional_cache_deletion_helper.h b/chromium/components/browsing_data/content/conditional_cache_deletion_helper.h
deleted file mode 100644
index c46d8bed820..00000000000
--- a/chromium/components/browsing_data/content/conditional_cache_deletion_helper.h
+++ /dev/null
@@ -1,73 +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_BROWSING_DATA_CONTENT_CONDITIONAL_CACHE_DELETION_HELPER_H_
-#define COMPONENTS_BROWSING_DATA_CONTENT_CONDITIONAL_CACHE_DELETION_HELPER_H_
-
-#include <memory>
-
-#include "base/callback_forward.h"
-#include "base/message_loop/message_loop.h"
-#include "net/base/completion_callback.h"
-#include "net/base/net_errors.h"
-#include "net/disk_cache/disk_cache.h"
-#include "url/gurl.h"
-
-namespace disk_cache {
-class Entry;
-}
-
-namespace browsing_data {
-
-// Helper to remove http cache data from a StoragePartition.
-class ConditionalCacheDeletionHelper {
- public:
- // Creates a helper to delete |cache| entries that match the |condition|.
- // Must be created on the IO thread!
- ConditionalCacheDeletionHelper(
- disk_cache::Backend* cache,
- const base::Callback<bool(const disk_cache::Entry*)>& condition);
-
- // A convenience method to create a condition matching cache entries whose
- // last modified time is between |begin_time| (inclusively), |end_time|
- // (exclusively) and whose URL is matched by the |url_predicate|. Note that
- // |begin_time| and |end_time| can be null to indicate unbounded time interval
- // in their respective direction.
- static base::Callback<bool(const disk_cache::Entry*)>
- CreateURLAndTimeCondition(
- const base::Callback<bool(const GURL&)>& url_predicate,
- const base::Time& begin_time,
- const base::Time& end_time);
-
- // Deletes the cache entries according to the specified condition. Destroys
- // this instance of ConditionalCacheDeletionHelper when finished.
- // Must be called on the IO thread!
- //
- // The return value is a net error code. If this method returns
- // ERR_IO_PENDING, the |completion_callback| will be invoked when the
- // operation completes.
- int DeleteAndDestroySelfWhenFinished(
- const net::CompletionCallback& completion_callback);
-
- private:
- friend class base::DeleteHelper<ConditionalCacheDeletionHelper>;
- ~ConditionalCacheDeletionHelper();
-
- void IterateOverEntries(int error);
-
- disk_cache::Backend* cache_;
- const base::Callback<bool(const disk_cache::Entry*)> condition_;
-
- net::CompletionCallback completion_callback_;
-
- std::unique_ptr<disk_cache::Backend::Iterator> iterator_;
- disk_cache::Entry* current_entry_;
- disk_cache::Entry* previous_entry_;
-
- DISALLOW_COPY_AND_ASSIGN(ConditionalCacheDeletionHelper);
-};
-
-} // namespace browsing_data
-
-#endif // COMPONENTS_BROWSING_DATA_CONTENT_CONDITIONAL_CACHE_DELETION_HELPER_H_
diff --git a/chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.cc b/chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.cc
deleted file mode 100644
index 5eeff79f1ec..00000000000
--- a/chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.cc
+++ /dev/null
@@ -1,194 +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/browsing_data/content/storage_partition_http_cache_data_remover.h"
-
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/browsing_data/content/conditional_cache_deletion_helper.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/storage_partition.h"
-#include "net/base/sdch_manager.h"
-#include "net/disk_cache/blockfile/backend_impl.h"
-#include "net/disk_cache/disk_cache.h"
-#include "net/disk_cache/memory/mem_backend_impl.h"
-#include "net/disk_cache/simple/simple_backend_impl.h"
-#include "net/http/http_cache.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
-
-using content::BrowserThread;
-
-namespace browsing_data {
-
-StoragePartitionHttpCacheDataRemover::StoragePartitionHttpCacheDataRemover(
- base::Callback<bool(const GURL&)> url_predicate,
- base::Time delete_begin,
- base::Time delete_end,
- net::URLRequestContextGetter* main_context_getter,
- net::URLRequestContextGetter* media_context_getter)
- : url_predicate_(url_predicate),
- delete_begin_(delete_begin),
- delete_end_(delete_end),
- main_context_getter_(main_context_getter),
- media_context_getter_(media_context_getter),
- next_cache_state_(CacheState::NONE),
- cache_(nullptr) {}
-
-StoragePartitionHttpCacheDataRemover::~StoragePartitionHttpCacheDataRemover() {
-}
-
-// static.
-StoragePartitionHttpCacheDataRemover*
-StoragePartitionHttpCacheDataRemover::CreateForRange(
- content::StoragePartition* storage_partition,
- base::Time delete_begin,
- base::Time delete_end) {
- return new StoragePartitionHttpCacheDataRemover(
- base::Callback<bool(const GURL&)>(), // Null callback.
- delete_begin, delete_end,
- storage_partition->GetURLRequestContext(),
- storage_partition->GetMediaURLRequestContext());
-}
-
-// static.
-StoragePartitionHttpCacheDataRemover*
-StoragePartitionHttpCacheDataRemover::CreateForURLsAndRange(
- content::StoragePartition* storage_partition,
- const base::Callback<bool(const GURL&)>& url_predicate,
- base::Time delete_begin,
- base::Time delete_end) {
- return new StoragePartitionHttpCacheDataRemover(
- url_predicate, delete_begin, delete_end,
- storage_partition->GetURLRequestContext(),
- storage_partition->GetMediaURLRequestContext());
-}
-
-void StoragePartitionHttpCacheDataRemover::Remove(
- const base::Closure& done_callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(!done_callback.is_null());
- done_callback_ = done_callback;
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(
- &StoragePartitionHttpCacheDataRemover::ClearHttpCacheOnIOThread,
- base::Unretained(this)));
-}
-
-void StoragePartitionHttpCacheDataRemover::ClearHttpCacheOnIOThread() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- next_cache_state_ = CacheState::NONE;
- DCHECK_EQ(CacheState::NONE, next_cache_state_);
- DCHECK(main_context_getter_.get());
- DCHECK(media_context_getter_.get());
-
- next_cache_state_ = CacheState::CREATE_MAIN;
- DoClearCache(net::OK);
-}
-
-void StoragePartitionHttpCacheDataRemover::ClearedHttpCache() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- done_callback_.Run();
- base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
-}
-
-// The expected state sequence is CacheState::NONE --> CacheState::CREATE_MAIN
-// --> CacheState::PROCESS_MAIN --> CacheState::CREATE_MEDIA -->
-// CacheState::PROCESS_MEDIA --> CacheState::DONE, and any errors are ignored.
-void StoragePartitionHttpCacheDataRemover::DoClearCache(int rv) {
- DCHECK_NE(CacheState::NONE, next_cache_state_);
-
- while (rv != net::ERR_IO_PENDING && next_cache_state_ != CacheState::NONE) {
- switch (next_cache_state_) {
- case CacheState::CREATE_MAIN:
- case CacheState::CREATE_MEDIA: {
- // Get a pointer to the cache.
- net::URLRequestContextGetter* getter =
- (next_cache_state_ == CacheState::CREATE_MAIN)
- ? main_context_getter_.get()
- : media_context_getter_.get();
- net::HttpCache* http_cache = getter->GetURLRequestContext()
- ->http_transaction_factory()
- ->GetCache();
-
- next_cache_state_ = (next_cache_state_ == CacheState::CREATE_MAIN)
- ? CacheState::DELETE_MAIN
- : CacheState::DELETE_MEDIA;
-
- // Clear QUIC server information from memory and the disk cache.
- http_cache->GetSession()
- ->quic_stream_factory()
- ->ClearCachedStatesInCryptoConfig(url_predicate_);
-
- // Clear SDCH dictionary state.
- net::SdchManager* sdch_manager =
- getter->GetURLRequestContext()->sdch_manager();
- // The test is probably overkill, since chrome should always have an
- // SdchManager. But in general the URLRequestContext is *not*
- // guaranteed to have an SdchManager, so checking is wise.
- if (sdch_manager)
- sdch_manager->ClearData();
-
- rv = http_cache->GetBackend(
- &cache_,
- base::Bind(&StoragePartitionHttpCacheDataRemover::DoClearCache,
- base::Unretained(this)));
- break;
- }
- case CacheState::DELETE_MAIN:
- case CacheState::DELETE_MEDIA: {
- next_cache_state_ = (next_cache_state_ == CacheState::DELETE_MAIN)
- ? CacheState::CREATE_MEDIA
- : CacheState::DONE;
-
- // |cache_| can be null if it cannot be initialized.
- if (cache_) {
- if (!url_predicate_.is_null()) {
- rv = (new ConditionalCacheDeletionHelper(
- cache_,
- ConditionalCacheDeletionHelper::CreateURLAndTimeCondition(
- url_predicate_,
- delete_begin_,
- delete_end_)))->DeleteAndDestroySelfWhenFinished(
- base::Bind(
- &StoragePartitionHttpCacheDataRemover::DoClearCache,
- base::Unretained(this)));
- } else if (delete_begin_.is_null() && delete_end_.is_max()) {
- rv = cache_->DoomAllEntries(base::Bind(
- &StoragePartitionHttpCacheDataRemover::DoClearCache,
- base::Unretained(this)));
- } else {
- rv = cache_->DoomEntriesBetween(
- delete_begin_, delete_end_,
- base::Bind(
- &StoragePartitionHttpCacheDataRemover::DoClearCache,
- base::Unretained(this)));
- }
- cache_ = NULL;
- }
- break;
- }
- case CacheState::DONE: {
- cache_ = NULL;
- next_cache_state_ = CacheState::NONE;
-
- // Notify the UI thread that we are done.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&StoragePartitionHttpCacheDataRemover::ClearedHttpCache,
- base::Unretained(this)));
- return;
- }
- case CacheState::NONE: {
- NOTREACHED() << "bad state";
- return;
- }
- }
- }
-}
-
-} // namespace browsing_data
diff --git a/chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.h b/chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.h
deleted file mode 100644
index 8d11a4ffa6f..00000000000
--- a/chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.h
+++ /dev/null
@@ -1,101 +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_BROWSING_DATA_CONTENT_STORAGE_PARTITION_HTTP_CACHE_DATA_REMOVER_H_
-#define COMPONENTS_BROWSING_DATA_CONTENT_STORAGE_PARTITION_HTTP_CACHE_DATA_REMOVER_H_
-
-#include <stdint.h>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/sequenced_task_runner_helpers.h"
-#include "base/time/time.h"
-#include "net/base/completion_callback.h"
-#include "url/gurl.h"
-
-namespace content {
-class StoragePartition;
-}
-
-namespace disk_cache {
-class Backend;
-}
-
-namespace net {
-class URLRequestContextGetter;
-}
-
-namespace browsing_data {
-
-// Helper to remove http cache data from a StoragePartition.
-class StoragePartitionHttpCacheDataRemover {
- public:
- // Creates a StoragePartitionHttpCacheDataRemover that deletes cache entries
- // in the time range between |delete_begin| (inclusively) and |delete_end|
- // (exclusively).
- static StoragePartitionHttpCacheDataRemover* CreateForRange(
- content::StoragePartition* storage_partition,
- base::Time delete_begin,
- base::Time delete_end);
-
- // Similar to CreateForRange(), but only deletes URLs that are matched by
- // |url_predicate|. Note that the deletion with URL filtering is not built in
- // to the cache interface and might be slower.
- static StoragePartitionHttpCacheDataRemover* CreateForURLsAndRange(
- content::StoragePartition* storage_partition,
- const base::Callback<bool(const GURL&)>& url_predicate,
- base::Time delete_begin,
- base::Time delete_end);
-
- // Calls |done_callback| upon completion and also destroys itself.
- void Remove(const base::Closure& done_callback);
-
- private:
- enum CacheState {
- NONE,
- CREATE_MAIN,
- CREATE_MEDIA,
- DELETE_MAIN,
- DELETE_MEDIA,
- DONE
- };
-
- StoragePartitionHttpCacheDataRemover(
- base::Callback<bool(const GURL&)> url_predicate,
- base::Time delete_begin,
- base::Time delete_end,
- net::URLRequestContextGetter* main_context_getter,
- net::URLRequestContextGetter* media_context_getter);
-
- // StoragePartitionHttpCacheDataRemover deletes itself (using DeleteHelper)
- // and is not supposed to be deleted by other objects so make destructor
- // private and DeleteHelper a friend.
- friend class base::DeleteHelper<StoragePartitionHttpCacheDataRemover>;
-
- ~StoragePartitionHttpCacheDataRemover();
-
- void ClearHttpCacheOnIOThread();
- void ClearedHttpCache();
- // Performs the actual work to delete or count the cache.
- void DoClearCache(int rv);
-
- base::Callback<bool(const GURL&)> url_predicate_;
- const base::Time delete_begin_;
- const base::Time delete_end_;
-
- const scoped_refptr<net::URLRequestContextGetter> main_context_getter_;
- const scoped_refptr<net::URLRequestContextGetter> media_context_getter_;
-
- base::Closure done_callback_;
-
- // IO.
- int next_cache_state_;
- disk_cache::Backend* cache_;
-
- DISALLOW_COPY_AND_ASSIGN(StoragePartitionHttpCacheDataRemover);
-};
-
-} // namespace browsing_data
-
-#endif // COMPONENTS_BROWSING_DATA_CONTENT_STORAGE_PARTITION_HTTP_CACHE_DATA_REMOVER_H_
diff --git a/chromium/components/browsing_data/core/BUILD.gn b/chromium/components/browsing_data/core/BUILD.gn
index a0f40b11dbf..dd140ce5012 100644
--- a/chromium/components/browsing_data/core/BUILD.gn
+++ b/chromium/components/browsing_data/core/BUILD.gn
@@ -10,6 +10,7 @@ static_library("core") {
sources = [
"browsing_data_utils.cc",
"browsing_data_utils.h",
+ "clear_browsing_data_tab.h",
"counters/autofill_counter.cc",
"counters/autofill_counter.h",
"counters/browsing_data_counter.cc",
@@ -45,6 +46,11 @@ if (is_android) {
"browsing_data_utils.h",
]
}
+ java_cpp_enum("clear_browsing_data_tab_java") {
+ sources = [
+ "clear_browsing_data_tab.h",
+ ]
+ }
}
source_set("unit_tests") {
@@ -63,6 +69,7 @@ source_set("unit_tests") {
"//components/signin/core/browser:test_support",
"//components/sync",
"//components/sync:test_support_driver",
+ "//components/sync_preferences:test_support",
"//components/version_info:version_info",
"//net",
"//testing/gtest",
diff --git a/chromium/components/browsing_data/core/DEPS b/chromium/components/browsing_data/core/DEPS
index cd4abb34aea..a28b230b9a2 100644
--- a/chromium/components/browsing_data/core/DEPS
+++ b/chromium/components/browsing_data/core/DEPS
@@ -10,6 +10,7 @@ include_rules = [
"+components/strings/grit/components_strings.h",
"+components/sync/base",
"+components/sync/driver",
+ "+components/sync_preferences",
"+components/version_info",
"+components/webdata/common",
"+net",
diff --git a/chromium/components/browsing_data/core/browsing_data_utils.cc b/chromium/components/browsing_data/core/browsing_data_utils.cc
index 8935742efed..9f1f34fb468 100644
--- a/chromium/components/browsing_data/core/browsing_data_utils.cc
+++ b/chromium/components/browsing_data/core/browsing_data_utils.cc
@@ -9,6 +9,7 @@
#include "components/browsing_data/core/counters/history_counter.h"
#include "components/browsing_data/core/counters/passwords_counter.h"
#include "components/browsing_data/core/pref_names.h"
+#include "components/prefs/pref_service.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
@@ -18,19 +19,19 @@ base::Time CalculateBeginDeleteTime(TimePeriod time_period) {
base::TimeDelta diff;
base::Time delete_begin_time = base::Time::Now();
switch (time_period) {
- case LAST_HOUR:
+ case TimePeriod::LAST_HOUR:
diff = base::TimeDelta::FromHours(1);
break;
- case LAST_DAY:
+ case TimePeriod::LAST_DAY:
diff = base::TimeDelta::FromHours(24);
break;
- case LAST_WEEK:
+ case TimePeriod::LAST_WEEK:
diff = base::TimeDelta::FromHours(7 * 24);
break;
- case FOUR_WEEKS:
+ case TimePeriod::FOUR_WEEKS:
diff = base::TimeDelta::FromHours(4 * 7 * 24);
break;
- case ALL_TIME:
+ case TimePeriod::ALL_TIME:
delete_begin_time = base::Time();
break;
}
@@ -44,20 +45,20 @@ base::Time CalculateEndDeleteTime(TimePeriod time_period) {
void RecordDeletionForPeriod(TimePeriod period) {
switch (period) {
- case browsing_data::LAST_HOUR:
+ case TimePeriod::LAST_HOUR:
base::RecordAction(base::UserMetricsAction("ClearBrowsingData_LastHour"));
break;
- case browsing_data::LAST_DAY:
+ case TimePeriod::LAST_DAY:
base::RecordAction(base::UserMetricsAction("ClearBrowsingData_LastDay"));
break;
- case browsing_data::LAST_WEEK:
+ case TimePeriod::LAST_WEEK:
base::RecordAction(base::UserMetricsAction("ClearBrowsingData_LastWeek"));
break;
- case browsing_data::FOUR_WEEKS:
+ case TimePeriod::FOUR_WEEKS:
base::RecordAction(
base::UserMetricsAction("ClearBrowsingData_LastMonth"));
break;
- case browsing_data::ALL_TIME:
+ case TimePeriod::ALL_TIME:
base::RecordAction(
base::UserMetricsAction("ClearBrowsingData_Everything"));
break;
@@ -85,6 +86,9 @@ base::string16 GetCounterTextFromResult(
? IDS_DEL_PASSWORDS_COUNTER
: IDS_DEL_DOWNLOADS_COUNTER,
count);
+ } else if (pref_name == browsing_data::prefs::kDeleteBrowsingHistoryBasic) {
+ // The basic tab doesn't show history counter results.
+ NOTREACHED();
} else if (pref_name == browsing_data::prefs::kDeleteBrowsingHistory) {
// History counter.
const browsing_data::HistoryCounter::HistoryResult* history_result =
@@ -93,7 +97,6 @@ base::string16 GetCounterTextFromResult(
browsing_data::BrowsingDataCounter::ResultInt local_item_count =
history_result->Value();
bool has_synced_visits = history_result->has_synced_visits();
-
text = has_synced_visits
? l10n_util::GetPluralStringFUTF16(
IDS_DEL_BROWSING_HISTORY_COUNTER_SYNCED, local_item_count)
@@ -169,30 +172,55 @@ base::string16 GetCounterTextFromResult(
return text;
}
+const char* GetTimePeriodPreferenceName(
+ ClearBrowsingDataTab clear_browsing_data_tab) {
+ return clear_browsing_data_tab == ClearBrowsingDataTab::BASIC
+ ? prefs::kDeleteTimePeriodBasic
+ : prefs::kDeleteTimePeriod;
+}
+
bool GetDeletionPreferenceFromDataType(
BrowsingDataType data_type,
+ ClearBrowsingDataTab clear_browsing_data_tab,
std::string* out_pref) {
+ if (clear_browsing_data_tab == ClearBrowsingDataTab::BASIC) {
+ switch (data_type) {
+ case BrowsingDataType::HISTORY:
+ *out_pref = prefs::kDeleteBrowsingHistoryBasic;
+ return true;
+ case BrowsingDataType::CACHE:
+ *out_pref = prefs::kDeleteCacheBasic;
+ return true;
+ case BrowsingDataType::COOKIES:
+ *out_pref = prefs::kDeleteCookiesBasic;
+ return true;
+ default:
+ // This is not a valid type for the basic tab.
+ NOTREACHED();
+ return false;
+ }
+ }
switch (data_type) {
- case HISTORY:
+ case BrowsingDataType::HISTORY:
*out_pref = prefs::kDeleteBrowsingHistory;
return true;
- case CACHE:
+ case BrowsingDataType::CACHE:
*out_pref = prefs::kDeleteCache;
return true;
- case COOKIES:
+ case BrowsingDataType::COOKIES:
*out_pref = prefs::kDeleteCookies;
return true;
- case PASSWORDS:
+ case BrowsingDataType::PASSWORDS:
*out_pref = prefs::kDeletePasswords;
return true;
- case FORM_DATA:
+ case BrowsingDataType::FORM_DATA:
*out_pref = prefs::kDeleteFormData;
return true;
- case BOOKMARKS:
+ case BrowsingDataType::BOOKMARKS:
// Bookmarks are deleted on the Android side. No corresponding deletion
// preference.
return false;
- case NUM_TYPES:
+ case BrowsingDataType::NUM_TYPES:
// This is not an actual type.
NOTREACHED();
return false;
@@ -201,4 +229,18 @@ bool GetDeletionPreferenceFromDataType(
return false;
}
+void MigratePreferencesToBasic(PrefService* prefs) {
+ if (!prefs->GetBoolean(prefs::kPreferencesMigratedToBasic)) {
+ prefs->SetBoolean(prefs::kDeleteBrowsingHistoryBasic,
+ prefs->GetBoolean(prefs::kDeleteBrowsingHistory));
+ prefs->SetBoolean(prefs::kDeleteCacheBasic,
+ prefs->GetBoolean(prefs::kDeleteCache));
+ prefs->SetBoolean(prefs::kDeleteCookiesBasic,
+ prefs->GetBoolean(prefs::kDeleteCookies));
+ prefs->SetInteger(prefs::kDeleteTimePeriodBasic,
+ prefs->GetInteger(prefs::kDeleteTimePeriod));
+ prefs->SetBoolean(prefs::kPreferencesMigratedToBasic, true);
+ }
+}
+
} // namespace browsing_data
diff --git a/chromium/components/browsing_data/core/browsing_data_utils.h b/chromium/components/browsing_data/core/browsing_data_utils.h
index db0d7c2ce91..97cc7b1273e 100644
--- a/chromium/components/browsing_data/core/browsing_data_utils.h
+++ b/chromium/components/browsing_data/core/browsing_data_utils.h
@@ -7,6 +7,7 @@
#include "base/strings/string16.h"
#include "base/time/time.h"
+#include "components/browsing_data/core/clear_browsing_data_tab.h"
#include "components/browsing_data/core/counters/browsing_data_counter.h"
namespace browsing_data {
@@ -17,7 +18,7 @@ namespace browsing_data {
//
// A Java counterpart will be generated for this enum.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.browsing_data
-enum BrowsingDataType {
+enum class BrowsingDataType {
HISTORY,
CACHE,
COOKIES,
@@ -31,7 +32,7 @@ enum BrowsingDataType {
//
// A Java counterpart will be generated for this enum.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.browsing_data
-enum TimePeriod {
+enum class TimePeriod {
LAST_HOUR = 0,
LAST_DAY,
LAST_WEEK,
@@ -53,14 +54,24 @@ void RecordDeletionForPeriod(TimePeriod time_period);
// Currently this can only be used for counters for which the Result is defined
// in components/browsing_data/core/counters.
base::string16 GetCounterTextFromResult(
- const browsing_data::BrowsingDataCounter::Result* result);
+ const BrowsingDataCounter::Result* result);
+
+// Returns the preference that stores the time period.
+const char* GetTimePeriodPreferenceName(
+ ClearBrowsingDataTab clear_browsing_data_tab);
// Copies the name of the deletion preference corresponding to the given
// |data_type| to |out_pref|. Returns false if no such preference exists.
bool GetDeletionPreferenceFromDataType(
BrowsingDataType data_type,
+ ClearBrowsingDataTab clear_browsing_data_tab,
std::string* out_pref);
+// Copies the deletion preferences for timeperiod, cache, history and cookies
+// to a separate preferences that are used to on the basic CBD tab.
+// This only happens the first time this method is called.
+void MigratePreferencesToBasic(PrefService* prefs);
+
} // namespace browsing_data
#endif // COMPONENTS_BROWSING_DATA_CORE_BROWSING_DATA_UTILS_H_
diff --git a/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc b/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc
index eaad13b4b84..bd22d2867be 100644
--- a/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc
+++ b/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc
@@ -12,6 +12,9 @@
#include "base/threading/thread_task_runner_handle.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/browsing_data/core/counters/autofill_counter.h"
+#include "components/browsing_data/core/pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -33,8 +36,15 @@ class BrowsingDataUtilsTest : public testing::Test {
BrowsingDataUtilsTest() {}
~BrowsingDataUtilsTest() override {}
+ void SetUp() override {
+ browsing_data::prefs::RegisterBrowserUserPrefs(prefs_.registry());
+ }
+
+ PrefService* prefs() { return &prefs_; }
+
private:
base::MessageLoop loop_;
+ sync_preferences::TestingPrefServiceSyncable prefs_;
};
// Tests the complex output of the Autofill counter.
@@ -77,3 +87,32 @@ TEST_F(BrowsingDataUtilsTest, AutofillCounterResult) {
EXPECT_EQ(output, base::ASCIIToUTF16(test_case.expected_output));
}
}
+
+TEST_F(BrowsingDataUtilsTest, MigratePreferencesToBasic) {
+ using namespace browsing_data::prefs;
+
+ prefs()->SetBoolean(kDeleteBrowsingHistory, true);
+ prefs()->SetBoolean(kDeleteCookies, false);
+ prefs()->SetBoolean(kDeleteCache, false);
+ prefs()->SetInteger(kDeleteTimePeriod, 42);
+
+ // History, cookies and cache should be migrated to their basic counterpart.
+ browsing_data::MigratePreferencesToBasic(prefs());
+ EXPECT_TRUE(prefs()->GetBoolean(kDeleteBrowsingHistoryBasic));
+ EXPECT_FALSE(prefs()->GetBoolean(kDeleteCookiesBasic));
+ EXPECT_FALSE(prefs()->GetBoolean(kDeleteCacheBasic));
+ EXPECT_EQ(42, prefs()->GetInteger(kDeleteTimePeriodBasic));
+
+ prefs()->SetBoolean(kDeleteBrowsingHistory, true);
+ prefs()->SetBoolean(kDeleteCookies, true);
+ prefs()->SetBoolean(kDeleteCache, true);
+ prefs()->SetInteger(kDeleteTimePeriod, 100);
+
+ // After the first migration all settings should stay the same if the
+ // migration is executed again.
+ browsing_data::MigratePreferencesToBasic(prefs());
+ EXPECT_TRUE(prefs()->GetBoolean(kDeleteBrowsingHistoryBasic));
+ EXPECT_FALSE(prefs()->GetBoolean(kDeleteCookiesBasic));
+ EXPECT_FALSE(prefs()->GetBoolean(kDeleteCacheBasic));
+ EXPECT_EQ(42, prefs()->GetInteger(kDeleteTimePeriodBasic));
+}
diff --git a/chromium/components/browsing_data/core/clear_browsing_data_tab.h b/chromium/components/browsing_data/core/clear_browsing_data_tab.h
new file mode 100644
index 00000000000..c6c0b5bc2cd
--- /dev/null
+++ b/chromium/components/browsing_data/core/clear_browsing_data_tab.h
@@ -0,0 +1,21 @@
+// 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_BROWSING_DATA_CORE_CLEAR_BROWSING_DATA_TAB_H_
+#define COMPONENTS_BROWSING_DATA_CORE_CLEAR_BROWSING_DATA_TAB_H_
+
+namespace browsing_data {
+
+// This enum is used to differentiate CBD preferences from the basic and
+// advanced tab and manage their state separately. It is important that all
+// preferences and the timeperiod selection have the same type. The default
+// value for dialogs without separate tabs is advanced.
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.browsing_data
+enum class ClearBrowsingDataTab { BASIC, ADVANCED, NUM_TYPES };
+
+} // namespace browsing_data
+
+#endif // COMPONENTS_BROWSING_DATA_CORE_CLEAR_BROWSING_DATA_TAB_H_
diff --git a/chromium/components/browsing_data/core/counters/browsing_data_counter.cc b/chromium/components/browsing_data/core/counters/browsing_data_counter.cc
index af4fcc9949d..48a80180c5b 100644
--- a/chromium/components/browsing_data/core/counters/browsing_data_counter.cc
+++ b/chromium/components/browsing_data/core/counters/browsing_data_counter.cc
@@ -25,14 +25,15 @@ BrowsingDataCounter::BrowsingDataCounter()
BrowsingDataCounter::~BrowsingDataCounter() {}
void BrowsingDataCounter::Init(PrefService* pref_service,
+ ClearBrowsingDataTab clear_browsing_data_tab,
const Callback& callback) {
DCHECK(!initialized_);
callback_ = callback;
- pref_service_ = pref_service;
- pref_.Init(GetPrefName(), pref_service_,
+ clear_browsing_data_tab_ = clear_browsing_data_tab;
+ pref_.Init(GetPrefName(), pref_service,
base::Bind(&BrowsingDataCounter::Restart, base::Unretained(this)));
period_.Init(
- browsing_data::prefs::kDeleteTimePeriod, pref_service_,
+ GetTimePeriodPreferenceName(GetTab()), pref_service,
base::Bind(&BrowsingDataCounter::Restart, base::Unretained(this)));
initialized_ = true;
@@ -104,8 +105,8 @@ BrowsingDataCounter::GetStateTransitionsForTesting() {
return state_transitions_;
}
-PrefService* BrowsingDataCounter::GetPrefs() const {
- return pref_service_;
+ClearBrowsingDataTab BrowsingDataCounter::GetTab() const {
+ return clear_browsing_data_tab_;
}
void BrowsingDataCounter::TransitionToShowCalculating() {
diff --git a/chromium/components/browsing_data/core/counters/browsing_data_counter.h b/chromium/components/browsing_data/core/counters/browsing_data_counter.h
index 529d24e8acc..d7fbb956dce 100644
--- a/chromium/components/browsing_data/core/counters/browsing_data_counter.h
+++ b/chromium/components/browsing_data/core/counters/browsing_data_counter.h
@@ -13,6 +13,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/timer/timer.h"
+#include "components/browsing_data/core/clear_browsing_data_tab.h"
#include "components/prefs/pref_member.h"
class PrefService;
@@ -85,15 +86,13 @@ class BrowsingDataCounter {
virtual ~BrowsingDataCounter();
// Should be called once to initialize this class.
- void Init(PrefService* pref_service, const Callback& callback);
+ void Init(PrefService* pref_service,
+ ClearBrowsingDataTab clear_browsing_data_tab,
+ const Callback& callback);
// Name of the preference associated with this counter.
virtual const char* GetPrefName() const = 0;
- // PrefService that manages the preferences for the user profile
- // associated with this counter.
- PrefService* GetPrefs() const;
-
// Restarts the counter. Will be called automatically if the counting needs
// to be restarted, e.g. when the deletion preference changes state or when
// we are notified of data changes.
@@ -121,6 +120,10 @@ class BrowsingDataCounter {
// Calculates the beginning of the counting period as |period_| before now.
base::Time GetPeriodStart();
+ // Returns if this counter belongs to a preference on the default, basic or
+ // advanced CBD tab.
+ ClearBrowsingDataTab GetTab() const;
+
private:
// Called after the class is initialized by calling |Init|.
virtual void OnInitialized();
@@ -132,9 +135,8 @@ class BrowsingDataCounter {
void TransitionToShowCalculating();
void TransitionToReadyToReportResult();
- // Pointer to the PrefService that manages the preferences for the user
- // profile associated with this counter.
- PrefService* pref_service_;
+ // Indicates if this counter belongs to a preference on the basic CBD tab.
+ ClearBrowsingDataTab clear_browsing_data_tab_;
// The callback that will be called when the UI should be updated with a new
// counter value.
diff --git a/chromium/components/browsing_data/core/counters/browsing_data_counter_unittest.cc b/chromium/components/browsing_data/core/counters/browsing_data_counter_unittest.cc
index e7455b3c8d4..370a5a81311 100644
--- a/chromium/components/browsing_data/core/counters/browsing_data_counter_unittest.cc
+++ b/chromium/components/browsing_data/core/counters/browsing_data_counter_unittest.cc
@@ -87,7 +87,9 @@ class BrowsingDataCounterTest : public testing::Test {
pref_service_->registry()->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0);
counter_.reset(new MockBrowsingDataCounter());
- counter_->Init(pref_service_.get(), base::Bind(&IgnoreResult));
+ counter_->Init(pref_service_.get(),
+ browsing_data::ClearBrowsingDataTab::ADVANCED,
+ base::Bind(&IgnoreResult));
}
void TearDown() override {
diff --git a/chromium/components/browsing_data/core/counters/history_counter.cc b/chromium/components/browsing_data/core/counters/history_counter.cc
index daf801073c2..6fcb1c17ea9 100644
--- a/chromium/components/browsing_data/core/counters/history_counter.cc
+++ b/chromium/components/browsing_data/core/counters/history_counter.cc
@@ -46,7 +46,9 @@ bool HistoryCounter::HasTrackedTasks() {
}
const char* HistoryCounter::GetPrefName() const {
- return browsing_data::prefs::kDeleteBrowsingHistory;
+ return GetTab() == ClearBrowsingDataTab::BASIC
+ ? browsing_data::prefs::kDeleteBrowsingHistoryBasic
+ : browsing_data::prefs::kDeleteBrowsingHistory;
}
void HistoryCounter::Count() {
diff --git a/chromium/components/browsing_data/core/pref_names.cc b/chromium/components/browsing_data/core/pref_names.cc
index 87a39cbece7..59113a84cc6 100644
--- a/chromium/components/browsing_data/core/pref_names.cc
+++ b/chromium/components/browsing_data/core/pref_names.cc
@@ -12,12 +12,17 @@ namespace prefs {
// Clear browsing data deletion time period.
const char kDeleteTimePeriod[] = "browser.clear_data.time_period";
+const char kDeleteTimePeriodBasic[] = "browser.clear_data.time_period_basic";
// Clear Browsing Data dialog datatype preferences.
const char kDeleteBrowsingHistory[] = "browser.clear_data.browsing_history";
+const char kDeleteBrowsingHistoryBasic[] =
+ "browser.clear_data.browsing_history_basic";
const char kDeleteDownloadHistory[] = "browser.clear_data.download_history";
const char kDeleteCache[] = "browser.clear_data.cache";
+const char kDeleteCacheBasic[] = "browser.clear_data.cache_basic";
const char kDeleteCookies[] = "browser.clear_data.cookies";
+const char kDeleteCookiesBasic[] = "browser.clear_data.cookies_basic";
const char kDeletePasswords[] = "browser.clear_data.passwords";
const char kDeleteFormData[] = "browser.clear_data.form_data";
const char kDeleteHostedAppsData[] = "browser.clear_data.hosted_apps_data";
@@ -29,26 +34,35 @@ const char kLastClearBrowsingDataTime[] =
const char kClearBrowsingDataHistoryNoticeShownTimes[] =
"browser.clear_data.history_notice_shown_times";
const char kLastClearBrowsingDataTab[] = "browser.last_clear_browsing_data_tab";
+const char kPreferencesMigratedToBasic[] =
+ "browser.clear_data.preferences_migrated_to_basic";
void RegisterBrowserUserPrefs(user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterIntegerPref(
kDeleteTimePeriod, 0,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterIntegerPref(
+ kDeleteTimePeriodBasic, 0,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterBooleanPref(
kDeleteBrowsingHistory, true,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterBooleanPref(
- kDeleteCache, true,
+ kDeleteBrowsingHistoryBasic, true,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterBooleanPref(
- kDeleteCookies, true,
- user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ kDeleteCache, true, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterBooleanPref(
- kDeletePasswords, false,
- user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ kDeleteCacheBasic, true, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterBooleanPref(
+ kDeleteCookies, true, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterBooleanPref(
- kDeleteFormData, false,
+ kDeleteCookiesBasic, true,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterBooleanPref(
+ kDeletePasswords, false, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterBooleanPref(
+ kDeleteFormData, false, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterIntegerPref(
kClearBrowsingDataHistoryNoticeShownTimes, 0);
@@ -70,6 +84,10 @@ void RegisterBrowserUserPrefs(user_prefs::PrefRegistrySyncable* registry) {
kLastClearBrowsingDataTab, 0,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
#endif
+
+ registry->RegisterBooleanPref(
+ kPreferencesMigratedToBasic, false,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
}
} // namespace prefs
diff --git a/chromium/components/browsing_data/core/pref_names.h b/chromium/components/browsing_data/core/pref_names.h
index 560948e177f..a8af5664115 100644
--- a/chromium/components/browsing_data/core/pref_names.h
+++ b/chromium/components/browsing_data/core/pref_names.h
@@ -14,11 +14,15 @@ namespace browsing_data {
namespace prefs {
extern const char kDeleteTimePeriod[];
+extern const char kDeleteTimePeriodBasic[];
extern const char kDeleteBrowsingHistory[];
+extern const char kDeleteBrowsingHistoryBasic[];
extern const char kDeleteDownloadHistory[];
extern const char kDeleteCache[];
+extern const char kDeleteCacheBasic[];
extern const char kDeleteCookies[];
+extern const char kDeleteCookiesBasic[];
extern const char kDeletePasswords[];
extern const char kDeleteFormData[];
extern const char kDeleteHostedAppsData[];
@@ -28,6 +32,7 @@ extern const char kLastClearBrowsingDataTime[];
extern const char kClearBrowsingDataHistoryNoticeShownTimes[];
extern const char kLastClearBrowsingDataTab[];
+extern const char kPreferencesMigratedToBasic[];
// Registers the Clear Browsing Data UI prefs.
void RegisterBrowserUserPrefs(user_prefs::PrefRegistrySyncable* registry);
diff --git a/chromium/components/browsing_data_strings.grdp b/chromium/components/browsing_data_strings.grdp
index 9de1c82cc1a..0b3f9b20869 100644
--- a/chromium/components/browsing_data_strings.grdp
+++ b/chromium/components/browsing_data_strings.grdp
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<grit-part>
-
<!-- Clear Browsing Data counters-->
<message name="IDS_CLEAR_BROWSING_DATA_CALCULATING" desc="A text that is shown while the data volume is being counted.">
Calculating...
@@ -23,6 +22,9 @@
<message name="IDS_DEL_CACHE_COUNTER_ALMOST_EMPTY" desc="A counter showing that the user's cache is almost empty, having less than 1 MB of data.">
less than 1 MB
</message>
+ <message name="IDS_DEL_CACHE_COUNTER_BASIC" desc="A counter showing the size of the users's cache including either 'x MB' or 'less than x MB' as $1 and explaining that the cache is used to speed up the loading of websites.">
+ Frees up <ph name="SIZE">$1<ex>328 MB</ex></ph>. Some sites may load more slowly on your next visit.
+ </message>
<message name="IDS_DEL_PASSWORDS_COUNTER" desc="A counter showing how many passwords the user has.">
{COUNT, plural,
=0 {none}
@@ -66,6 +68,12 @@
<message name="IDS_DEL_COOKIES_COUNTER" desc="A static message shown in the Clear Browsing Data dialog explaining to the user that deleting cookies and site data will result in the user being signed out of most websites.">
This will sign you out of most websites.
</message>
+ <message name="IDS_DEL_COOKIES_COUNTER_ADVANCED" desc="A counter showing the number of sites that use cookies.">
+ {COUNT, plural,
+ =0 {No cookies}
+ =1 {1 site uses cookies. }
+ other {# sites use cookies. }}
+ </message>
<message name="IDS_DEL_DOWNLOADS_COUNTER" desc="A counter showing how many items of downloads history the user has.">
{COUNT, plural,
=0 {none}
@@ -90,4 +98,4 @@
<message name="IDS_DEL_MEDIA_LICENSES_COUNTER_SITE_COMMENT" desc="A message shown in the Clear Browsing Data dialog explaining to the user that clearing media licenses will result in the user being unable to play some premium content from at least one specific web site">
You may lose access to premium content from <ph name="SITE">$1<ex>youtube.com</ex></ph> and some other sites.
</message>
-</grit-part> \ No newline at end of file
+</grit-part>
diff --git a/chromium/components/captive_portal/OWNERS b/chromium/components/captive_portal/OWNERS
index 53e68eb7787..a122871fda3 100644
--- a/chromium/components/captive_portal/OWNERS
+++ b/chromium/components/captive_portal/OWNERS
@@ -1 +1,3 @@
mmenke@chromium.org
+
+# COMPONENT: Internals>Network
diff --git a/chromium/components/captive_portal/captive_portal_detector_unittest.cc b/chromium/components/captive_portal/captive_portal_detector_unittest.cc
index 28972bbd910..7eaa099f298 100644
--- a/chromium/components/captive_portal/captive_portal_detector_unittest.cc
+++ b/chromium/components/captive_portal/captive_portal_detector_unittest.cc
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/captive_portal/captive_portal_testing_utils.h"
@@ -113,7 +114,7 @@ class CaptivePortalDetectorTest : public testing::Test,
}
private:
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
std::unique_ptr<CaptivePortalDetector> detector_;
};
diff --git a/chromium/components/cast_certificate/cast_cert_validator.cc b/chromium/components/cast_certificate/cast_cert_validator.cc
index 60c76fb2346..18609aff085 100644
--- a/chromium/components/cast_certificate/cast_cert_validator.cc
+++ b/chromium/components/cast_certificate/cast_cert_validator.cc
@@ -83,19 +83,6 @@ class CastTrustStore {
DISALLOW_COPY_AND_ASSIGN(CastTrustStore);
};
-using ExtensionsMap = std::map<net::der::Input, net::ParsedExtension>;
-
-// Helper that looks up an extension by OID given a map of extensions.
-bool GetExtensionValue(const ExtensionsMap& extensions,
- const net::der::Input& oid,
- net::der::Input* value) {
- auto it = extensions.find(oid);
- if (it == extensions.end())
- return false;
- *value = it->second.value;
- return true;
-}
-
// Returns the OID for the Audio-Only Cast policy
// (1.3.6.1.4.1.11129.2.5.2) in DER form.
net::der::Input AudioOnlyPolicyOid() {
@@ -155,9 +142,8 @@ class CertVerificationContextImpl : public CertVerificationContext {
};
// Helper that extracts the Common Name from a certificate's subject field. On
-// success |common_name| contains the text for the attribute (unescaped, so
-// will depend on the encoding used, but for Cast device certs it should
-// be ASCII).
+// success |common_name| contains the text for the attribute (UTF-8, but for
+// Cast device certs it should be ASCII).
bool GetCommonNameFromSubject(const net::der::Input& subject_tlv,
std::string* common_name) {
net::RDNSequence rdn_sequence;
@@ -167,26 +153,16 @@ 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()) {
- return atv.ValueAsStringUnsafe(common_name);
+ return atv.ValueAsString(common_name);
}
}
}
return false;
}
-// Returns true if the extended key usage list |ekus| contains client auth.
-bool HasClientAuth(const std::vector<net::der::Input>& ekus) {
- for (const auto& oid : ekus) {
- if (oid == net::ClientAuth())
- return true;
- }
- return false;
-}
-
// Checks properties on the target certificate.
//
// * The Key Usage must include Digital Signature
-// * The Extended Key Usage must include TLS Client Auth
// * May have the policy 1.3.6.1.4.1.11129.2.5.2 to indicate it
// is an audio-only device.
WARN_UNUSED_RESULT bool CheckTargetCertificate(
@@ -201,28 +177,10 @@ WARN_UNUSED_RESULT bool CheckTargetCertificate(
if (!cert->key_usage().AssertsBit(net::KEY_USAGE_BIT_DIGITAL_SIGNATURE))
return false;
- // Get the Extended Key Usage extension.
- net::der::Input extension_value;
- if (!GetExtensionValue(cert->unparsed_extensions(), net::ExtKeyUsageOid(),
- &extension_value)) {
- return false;
- }
- std::vector<net::der::Input> ekus;
- if (!net::ParseEKUExtension(extension_value, &ekus))
- return false;
-
- // Ensure Extended Key Usage contains client auth.
- if (!HasClientAuth(ekus))
- return false;
-
// Check for an optional audio-only policy extension.
*policy = CastDeviceCertPolicy::NONE;
- if (GetExtensionValue(cert->unparsed_extensions(),
- net::CertificatePoliciesOid(), &extension_value)) {
- std::vector<net::der::Input> policies;
- if (!net::ParseCertificatePoliciesExtension(extension_value, &policies))
- return false;
-
+ if (cert->has_policy_oids()) {
+ const std::vector<net::der::Input>& policies = cert->policy_oids();
// Look for an audio-only policy. Disregard any other policy found.
if (std::find(policies.begin(), policies.end(), AudioOnlyPolicyOid()) !=
policies.end()) {
@@ -310,7 +268,7 @@ bool VerifyDeviceCertUsingCustomTrustStore(
net::CertPathBuilder::Result result;
net::CertPathBuilder path_builder(target_cert.get(), trust_store,
signature_policy.get(), verification_time,
- &result);
+ net::KeyPurpose::CLIENT_AUTH, &result);
path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
path_builder.Run();
if (!result.HasValidPath()) {
diff --git a/chromium/components/cast_certificate/cast_crl.cc b/chromium/components/cast_certificate/cast_crl.cc
index fa95ae33083..7d866e37088 100644
--- a/chromium/components/cast_certificate/cast_crl.cc
+++ b/chromium/components/cast_certificate/cast_crl.cc
@@ -147,7 +147,7 @@ bool VerifyCRL(const Crl& crl,
net::CertPathBuilder::Result result;
net::CertPathBuilder path_builder(parsed_cert.get(), trust_store,
signature_policy.get(), verification_time,
- &result);
+ net::KeyPurpose::ANY_EKU, &result);
path_builder.Run();
if (!result.HasValidPath()) {
VLOG(2) << "CRL - Issuer certificate verification failed.";
diff --git a/chromium/components/cdm/browser/BUILD.gn b/chromium/components/cdm/browser/BUILD.gn
index 79f30ddd4bc..598849388fd 100644
--- a/chromium/components/cdm/browser/BUILD.gn
+++ b/chromium/components/cdm/browser/BUILD.gn
@@ -6,14 +6,36 @@ source_set("browser") {
sources = [
"cdm_message_filter_android.cc",
"cdm_message_filter_android.h",
+ "media_drm_storage_impl.cc",
+ "media_drm_storage_impl.h",
]
- deps = [
+ public_deps = [
"//base",
- "//components/cdm/common",
"//content/public/browser",
+ "//media/mojo/interfaces",
+ "//url",
+ ]
+
+ deps = [
+ "//components/cdm/common",
+ "//components/prefs",
"//content/public/common",
"//ipc",
"//media",
]
}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "media_drm_storage_impl_unittest.cc",
+ ]
+ deps = [
+ ":browser",
+ "//base/test:test_support",
+ "//components/prefs:test_support",
+ "//media/mojo/services",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/cdm/browser/DEPS b/chromium/components/cdm/browser/DEPS
index 4b9f5cb7877..6b8b9fb586f 100644
--- a/chromium/components/cdm/browser/DEPS
+++ b/chromium/components/cdm/browser/DEPS
@@ -1,5 +1,8 @@
include_rules = [
+ "+components/prefs",
"+content/public/browser",
"+media/cdm",
"+media/media_features.h",
+ "+media/mojo",
+ "+mojo/public/cpp/bindings",
]
diff --git a/chromium/components/cdm/browser/media_drm_storage_impl.cc b/chromium/components/cdm/browser/media_drm_storage_impl.cc
new file mode 100644
index 00000000000..bcebc5a348a
--- /dev/null
+++ b/chromium/components/cdm/browser/media_drm_storage_impl.cc
@@ -0,0 +1,312 @@
+// 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/cdm/browser/media_drm_storage_impl.h"
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
+#include "content/public/browser/navigation_handle.h"
+
+// The storage will be managed by PrefService. All data will be stored in a
+// dictionary under the key "media.media_drm_storage". The dictionary is
+// structured as follows:
+//
+// {
+// $origin: {
+// "origin_id": $origin_id
+// "creation_time": $creation_time
+// "sessions" : {
+// $session_id: {
+// "key_set_id": $key_set_id,
+// "mime_type": $mime_type,
+// "creation_time": $creation_time
+// },
+// # more session_id map...
+// }
+// },
+// # more origin map...
+// }
+
+namespace cdm {
+
+namespace {
+
+const char kMediaDrmStorage[] = "media.media_drm_storage";
+const char kCreationTime[] = "creation_time";
+const char kSessions[] = "sessions";
+const char kKeySetId[] = "key_set_id";
+const char kMimeType[] = "mime_type";
+
+std::unique_ptr<base::DictionaryValue> CreateOriginDictionary() {
+ auto dict = base::MakeUnique<base::DictionaryValue>();
+ // TODO(xhwang): Create |origin_id|.
+ dict->SetDouble(kCreationTime, base::Time::Now().ToDoubleT());
+ return dict;
+}
+
+std::unique_ptr<base::DictionaryValue> CreateSessionDictionary(
+ const std::vector<uint8_t>& key_set_id,
+ const std::string& mime_type) {
+ auto dict = base::MakeUnique<base::DictionaryValue>();
+ dict->SetString(kKeySetId,
+ std::string(reinterpret_cast<const char*>(key_set_id.data()),
+ key_set_id.size()));
+ dict->SetString(kMimeType, mime_type);
+ dict->SetDouble(kCreationTime, base::Time::Now().ToDoubleT());
+ return dict;
+}
+
+bool GetSessionData(const base::DictionaryValue* sesssion_dict,
+ std::vector<uint8_t>* key_set_id,
+ std::string* mime_type) {
+ std::string key_set_id_string;
+ if (!sesssion_dict->GetString(kKeySetId, &key_set_id_string))
+ return false;
+
+ if (!sesssion_dict->GetString(kMimeType, mime_type))
+ return false;
+
+ key_set_id->assign(key_set_id_string.begin(), key_set_id_string.end());
+ return true;
+}
+
+#if DCHECK_IS_ON()
+// Returns whether |dict| has a value assocaited with the |key|.
+bool HasEntry(const base::DictionaryValue& dict, const std::string& key) {
+ return dict.GetDictionaryWithoutPathExpansion(key, nullptr);
+}
+#endif
+
+} // namespace
+
+// static
+void MediaDrmStorageImpl::RegisterProfilePrefs(PrefRegistrySimple* registry) {
+ registry->RegisterDictionaryPref(kMediaDrmStorage);
+}
+
+MediaDrmStorageImpl::MediaDrmStorageImpl(
+ content::RenderFrameHost* render_frame_host,
+ PrefService* pref_service,
+ const url::Origin& origin,
+ media::mojom::MediaDrmStorageRequest request)
+ : render_frame_host_(render_frame_host),
+ pref_service_(pref_service),
+ origin_(origin),
+ origin_string_(origin.Serialize()),
+ binding_(this, std::move(request)) {
+ DVLOG(1) << __func__ << ": origin = " << origin;
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(pref_service_);
+ DCHECK(!origin_string_.empty());
+
+ // |this| owns |binding_|, so unretained is safe.
+ binding_.set_connection_error_handler(
+ base::Bind(&MediaDrmStorageImpl::Close, base::Unretained(this)));
+}
+
+MediaDrmStorageImpl::~MediaDrmStorageImpl() {
+ DVLOG(1) << __func__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+// TODO(xhwang): Update this function to return an origin ID. If the origin is
+// not the same as |origin_|, return an empty origin ID.
+void MediaDrmStorageImpl::Initialize(const url::Origin& origin) {
+ DVLOG(1) << __func__ << ": origin = " << origin;
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!initialized_);
+
+ initialized_ = true;
+}
+
+void MediaDrmStorageImpl::OnProvisioned(const OnProvisionedCallback& callback) {
+ DVLOG(1) << __func__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!initialized_) {
+ DVLOG(1) << __func__ << ": Not initialized.";
+ callback.Run(false);
+ return;
+ }
+
+ DictionaryPrefUpdate update(pref_service_, kMediaDrmStorage);
+ base::DictionaryValue* storage_dict = update.Get();
+ DCHECK(storage_dict);
+
+ // The origin string may contain dots. Do not use path expansion.
+ DVLOG_IF(1, HasEntry(*storage_dict, origin_string_))
+ << __func__ << ": Entry for origin " << origin_string_
+ << " already exists and will be cleared";
+
+ storage_dict->SetWithoutPathExpansion(origin_string_,
+ CreateOriginDictionary());
+ callback.Run(true);
+}
+
+void MediaDrmStorageImpl::SavePersistentSession(
+ const std::string& session_id,
+ media::mojom::SessionDataPtr session_data,
+ const SavePersistentSessionCallback& callback) {
+ DVLOG(2) << __func__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!initialized_) {
+ DVLOG(1) << __func__ << ": Not initialized.";
+ callback.Run(false);
+ return;
+ }
+
+ DictionaryPrefUpdate update(pref_service_, kMediaDrmStorage);
+ base::DictionaryValue* storage_dict = update.Get();
+ DCHECK(storage_dict);
+
+ base::DictionaryValue* origin_dict = nullptr;
+ // The origin string may contain dots. Do not use path expansion.
+ storage_dict->GetDictionaryWithoutPathExpansion(origin_string_, &origin_dict);
+ if (!origin_dict) {
+ DVLOG(1) << __func__
+ << ": Failed to save persistent session data; entry for origin "
+ << origin_string_ << " does not exist.";
+ callback.Run(false);
+ return;
+ }
+
+ base::DictionaryValue* sessions_dict = nullptr;
+ if (!origin_dict->GetDictionary(kSessions, &sessions_dict)) {
+ DVLOG(2) << __func__ << ": No session exists; creating a new dict.";
+ origin_dict->Set(kSessions, base::MakeUnique<base::DictionaryValue>());
+ origin_dict->GetDictionary(kSessions, &sessions_dict);
+ DCHECK(sessions_dict);
+ }
+
+ DVLOG_IF(1, HasEntry(*sessions_dict, session_id))
+ << __func__ << ": Session ID already exists and will be replaced.";
+
+ sessions_dict->SetWithoutPathExpansion(
+ session_id, CreateSessionDictionary(session_data->key_set_id,
+ session_data->mime_type));
+
+ callback.Run(true);
+}
+
+void MediaDrmStorageImpl::LoadPersistentSession(
+ const std::string& session_id,
+ const LoadPersistentSessionCallback& callback) {
+ DVLOG(2) << __func__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!initialized_) {
+ DVLOG(1) << __func__ << ": Not initialized.";
+ callback.Run(nullptr);
+ return;
+ }
+
+ const base::DictionaryValue* storage_dict =
+ pref_service_->GetDictionary(kMediaDrmStorage);
+
+ const base::DictionaryValue* origin_dict = nullptr;
+ // The origin string may contain dots. Do not use path expansion.
+ storage_dict->GetDictionaryWithoutPathExpansion(origin_string_, &origin_dict);
+ if (!origin_dict) {
+ DVLOG(1) << __func__
+ << ": Failed to save persistent session data; entry for origin "
+ << origin_ << " does not exist.";
+ callback.Run(nullptr);
+ return;
+ }
+
+ const base::DictionaryValue* sessions_dict = nullptr;
+ if (!origin_dict->GetDictionary(kSessions, &sessions_dict)) {
+ DVLOG(2) << __func__ << ": Sessions dictionary does not exist.";
+ callback.Run(nullptr);
+ return;
+ }
+
+ const base::DictionaryValue* session_dict = nullptr;
+ if (!sessions_dict->GetDictionaryWithoutPathExpansion(session_id,
+ &session_dict)) {
+ DVLOG(2) << __func__ << ": Session dictionary does not exist.";
+ callback.Run(nullptr);
+ return;
+ }
+
+ std::vector<uint8_t> key_set_id;
+ std::string mime_type;
+ if (!GetSessionData(session_dict, &key_set_id, &mime_type)) {
+ DVLOG(2) << __func__ << ": Failed to read session data.";
+ callback.Run(nullptr);
+ return;
+ }
+
+ callback.Run(media::mojom::SessionData::New(key_set_id, mime_type));
+}
+
+void MediaDrmStorageImpl::RemovePersistentSession(
+ const std::string& session_id,
+ const RemovePersistentSessionCallback& callback) {
+ DVLOG(2) << __func__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!initialized_) {
+ DVLOG(1) << __func__ << ": Not initialized.";
+ callback.Run(false);
+ return;
+ }
+
+ DictionaryPrefUpdate update(pref_service_, kMediaDrmStorage);
+ base::DictionaryValue* storage_dict = update.Get();
+ DCHECK(storage_dict);
+
+ base::DictionaryValue* origin_dict = nullptr;
+ // The origin string may contain dots. Do not use path expansion.
+ storage_dict->GetDictionaryWithoutPathExpansion(origin_string_, &origin_dict);
+ if (!origin_dict) {
+ DVLOG(1) << __func__ << ": Entry for rigin " << origin_string_
+ << " does not exist.";
+ callback.Run(true);
+ return;
+ }
+
+ base::DictionaryValue* sessions_dict = nullptr;
+ if (!origin_dict->GetDictionary(kSessions, &sessions_dict)) {
+ DVLOG(2) << __func__ << ": Sessions dictionary does not exist.";
+ callback.Run(true);
+ return;
+ }
+
+ sessions_dict->RemoveWithoutPathExpansion(session_id, nullptr);
+ callback.Run(true);
+}
+
+void MediaDrmStorageImpl::RenderFrameDeleted(
+ content::RenderFrameHost* render_frame_host) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (render_frame_host == render_frame_host_) {
+ DVLOG(1) << __func__ << ": RenderFrame destroyed.";
+ Close();
+ }
+}
+
+void MediaDrmStorageImpl::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (navigation_handle->GetRenderFrameHost() == render_frame_host_) {
+ DVLOG(1) << __func__ << ": Close connection on navigation.";
+ Close();
+ }
+}
+
+void MediaDrmStorageImpl::Close() {
+ DVLOG(1) << __func__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ delete this;
+}
+
+} // namespace cdm
diff --git a/chromium/components/cdm/browser/media_drm_storage_impl.h b/chromium/components/cdm/browser/media_drm_storage_impl.h
new file mode 100644
index 00000000000..a581cb6f04d
--- /dev/null
+++ b/chromium/components/cdm/browser/media_drm_storage_impl.h
@@ -0,0 +1,73 @@
+// 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_CDM_BROWSER_MEDIA_DRM_STORAGE_IMPL_H_
+#define COMPONENTS_CDM_BROWSER_MEDIA_DRM_STORAGE_IMPL_H_
+
+#include "base/threading/thread_checker.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "media/mojo/interfaces/media_drm_storage.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "url/origin.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace content {
+class RenderFrameHost;
+}
+
+namespace cdm {
+
+// Implements media::mojom::MediaDrmStorage using PrefService.
+// This file is located under components/ so that it can be shared by multiple
+// content embedders (e.g. chrome and chromecast).
+class MediaDrmStorageImpl final : public media::mojom::MediaDrmStorage,
+ public content::WebContentsObserver {
+ public:
+ static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ MediaDrmStorageImpl(content::RenderFrameHost* render_frame_host,
+ PrefService* pref_service,
+ const url::Origin& origin,
+ media::mojom::MediaDrmStorageRequest request);
+ ~MediaDrmStorageImpl() final;
+
+ // media::mojom::MediaDrmStorage implementation.
+ void Initialize(const url::Origin& origin) final;
+ void OnProvisioned(const OnProvisionedCallback& callback) final;
+ void SavePersistentSession(
+ const std::string& session_id,
+ media::mojom::SessionDataPtr session_data,
+ const SavePersistentSessionCallback& callback) final;
+ void LoadPersistentSession(
+ const std::string& session_id,
+ const LoadPersistentSessionCallback& callback) final;
+ void RemovePersistentSession(
+ const std::string& session_id,
+ const RemovePersistentSessionCallback& callback) final;
+
+ // content::WebContentsObserver implementation.
+ void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) final;
+ void DidFinishNavigation(content::NavigationHandle* navigation_handle) final;
+
+ private:
+ base::ThreadChecker thread_checker_;
+
+ // Stops observing WebContents and delete |this|.
+ void Close();
+
+ content::RenderFrameHost* const render_frame_host_ = nullptr;
+ PrefService* const pref_service_ = nullptr;
+ const url::Origin origin_;
+ const std::string origin_string_;
+ bool initialized_ = false;
+
+ mojo::Binding<media::mojom::MediaDrmStorage> binding_;
+};
+
+} // namespace cdm
+
+#endif // COMPONENTS_CDM_BROWSER_MEDIA_DRM_STORAGE_IMPL_H_
diff --git a/chromium/components/cdm/browser/media_drm_storage_impl_unittest.cc b/chromium/components/cdm/browser/media_drm_storage_impl_unittest.cc
new file mode 100644
index 00000000000..6a1610ee5a3
--- /dev/null
+++ b/chromium/components/cdm/browser/media_drm_storage_impl_unittest.cc
@@ -0,0 +1,196 @@
+// 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/cdm/browser/media_drm_storage_impl.h"
+
+#include <memory>
+
+#include "base/run_loop.h"
+#include "base/test/test_message_loop.h"
+#include "components/prefs/testing_pref_service.h"
+#include "media/mojo/services/mojo_media_drm_storage.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace cdm {
+
+const char kMediaDrmStorage[] = "media.media_drm_storage";
+const char kTestOrigin[] = "https://www.testorigin.com:80";
+
+class MediaDrmStorageImplTest : public ::testing::Test {
+ public:
+ MediaDrmStorageImplTest() {}
+
+ void SetUp() override {
+ pref_service_.reset(new TestingPrefServiceSimple());
+ PrefRegistrySimple* registry = pref_service_->registry();
+ MediaDrmStorageImpl::RegisterProfilePrefs(registry);
+
+ media::mojom::MediaDrmStoragePtr media_drm_storage_ptr;
+ auto request = mojo::MakeRequest(&media_drm_storage_ptr);
+
+ media_drm_storage_.reset(
+ new media::MojoMediaDrmStorage(std::move(media_drm_storage_ptr)));
+
+ // The created object will be destroyed on connection error.
+ new MediaDrmStorageImpl(nullptr, // Use null RenderFrameHost for testing.
+ pref_service_.get(), url::Origin(GURL(kTestOrigin)),
+ std::move(request));
+
+ media_drm_storage_->Initialize(url::Origin(GURL(kTestOrigin)));
+ }
+
+ void TearDown() override {
+ media_drm_storage_.reset();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ protected:
+ using SessionData = media::MediaDrmStorage::SessionData;
+
+ void OnProvisioned() {
+ media_drm_storage_->OnProvisioned(ExpectResult(true));
+ }
+
+ void SavePersistentSession(const std::string& session_id,
+ const std::vector<uint8_t>& key_set_id,
+ const std::string& mime_type,
+ bool success = true) {
+ media_drm_storage_->SavePersistentSession(
+ session_id, SessionData(key_set_id, mime_type), ExpectResult(success));
+ }
+
+ void LoadPersistentSession(const std::string& session_id,
+ const std::vector<uint8_t>& expected_key_set_id,
+ const std::string& expected_mime_type) {
+ media_drm_storage_->LoadPersistentSession(
+ session_id, ExpectResult(base::MakeUnique<SessionData>(
+ expected_key_set_id, expected_mime_type)));
+ }
+
+ void LoadPersistentSessionAndExpectFailure(const std::string& session_id) {
+ media_drm_storage_->LoadPersistentSession(
+ session_id, ExpectResult(std::unique_ptr<SessionData>()));
+ }
+
+ void RemovePersistentSession(const std::string& session_id,
+ bool success = true) {
+ media_drm_storage_->RemovePersistentSession(session_id,
+ ExpectResult(success));
+ }
+
+ void SaveAndLoadPersistentSession(const std::string& session_id,
+ const std::vector<uint8_t>& key_set_id,
+ const std::string& mime_type) {
+ SavePersistentSession(session_id, key_set_id, mime_type);
+ LoadPersistentSession(session_id, key_set_id, mime_type);
+ }
+
+ media::MediaDrmStorage::ResultCB ExpectResult(bool expected_result) {
+ return base::BindOnce(&MediaDrmStorageImplTest::CheckResult,
+ base::Unretained(this), expected_result);
+ }
+
+ media::MediaDrmStorage::LoadPersistentSessionCB ExpectResult(
+ std::unique_ptr<SessionData> expected_session_data) {
+ return base::BindOnce(&MediaDrmStorageImplTest::CheckLoadedSession,
+ base::Unretained(this),
+ base::Passed(&expected_session_data));
+ }
+
+ void CheckResult(bool expected_result, bool result) {
+ EXPECT_EQ(expected_result, result);
+ }
+
+ void CheckLoadedSession(std::unique_ptr<SessionData> expected_session_data,
+ std::unique_ptr<SessionData> session_data) {
+ if (!expected_session_data) {
+ EXPECT_FALSE(session_data);
+ return;
+ }
+
+ EXPECT_EQ(expected_session_data->key_set_id, session_data->key_set_id);
+ EXPECT_EQ(expected_session_data->mime_type, session_data->mime_type);
+ }
+
+ base::TestMessageLoop message_loop_;
+ std::unique_ptr<TestingPrefServiceSimple> pref_service_;
+ std::unique_ptr<media::MediaDrmStorage> media_drm_storage_;
+};
+
+TEST_F(MediaDrmStorageImplTest, OnProvisioned) {
+ OnProvisioned();
+ base::RunLoop().RunUntilIdle();
+
+ // Verify the origin dictionary is created.
+ const base::DictionaryValue* storage_dict =
+ pref_service_->GetDictionary(kMediaDrmStorage);
+ EXPECT_TRUE(
+ storage_dict->GetDictionaryWithoutPathExpansion(kTestOrigin, nullptr));
+}
+
+TEST_F(MediaDrmStorageImplTest, OnProvisioned_Twice) {
+ OnProvisioned();
+ SaveAndLoadPersistentSession("session_id", {1, 0}, "mime/type1");
+ // Provisioning again will clear everything associated with the origin.
+ OnProvisioned();
+ LoadPersistentSessionAndExpectFailure("session_id");
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(MediaDrmStorageImplTest, SaveSession_Unprovisioned) {
+ SavePersistentSession("session_id", {1, 0}, "mime/type", false);
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(MediaDrmStorageImplTest, SaveSession_SaveTwice) {
+ OnProvisioned();
+ SaveAndLoadPersistentSession("session_id", {1, 0}, "mime/type1");
+ SaveAndLoadPersistentSession("session_id", {2, 3}, "mime/type2");
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(MediaDrmStorageImplTest, SaveAndLoadSession_LoadTwice) {
+ OnProvisioned();
+ SaveAndLoadPersistentSession("session_id", {1, 0}, "mime/type");
+ LoadPersistentSession("session_id", {1, 0}, "mime/type");
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(MediaDrmStorageImplTest, SaveAndLoadSession_SpecialCharacters) {
+ OnProvisioned();
+ SaveAndLoadPersistentSession("session.id", {1, 0}, "mime.type");
+ SaveAndLoadPersistentSession("session/id", {1, 0}, "mime/type");
+ SaveAndLoadPersistentSession("session-id", {1, 0}, "mime-type");
+ SaveAndLoadPersistentSession("session_id", {1, 0}, "mime_type");
+ SaveAndLoadPersistentSession("session,id", {1, 0}, "mime,type");
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(MediaDrmStorageImplTest, LoadSession_Unprovisioned) {
+ LoadPersistentSessionAndExpectFailure("session_id");
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(MediaDrmStorageImplTest, RemoveSession_Success) {
+ OnProvisioned();
+ SaveAndLoadPersistentSession("session_id", {1, 0}, "mime/type");
+ RemovePersistentSession("session_id", true);
+ LoadPersistentSessionAndExpectFailure("session_id");
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(MediaDrmStorageImplTest, RemoveSession_InvalidSession) {
+ OnProvisioned();
+ SaveAndLoadPersistentSession("session_id", {1, 0}, "mime/type");
+ RemovePersistentSession("invalid_session_id", true);
+ // Can still load "session_id" session.
+ LoadPersistentSession("session_id", {1, 0}, "mime/type");
+ base::RunLoop().RunUntilIdle();
+}
+
+} // namespace cdm
diff --git a/chromium/components/cdm/renderer/android_key_systems.cc b/chromium/components/cdm/renderer/android_key_systems.cc
index 71706cfb2ce..bd12b93422f 100644
--- a/chromium/components/cdm/renderer/android_key_systems.cc
+++ b/chromium/components/cdm/renderer/android_key_systems.cc
@@ -125,6 +125,7 @@ void AddAndroidWidevine(
: EmeSessionTypeSupport::NOT_SUPPORTED;
if (response.compositing_codecs != media::EME_CODEC_NONE) {
+ DVLOG(3) << __func__ << " Widevine supported.";
concrete_key_systems->emplace_back(new WidevineKeySystemProperties(
response.compositing_codecs, // Regular codecs.
response.non_compositing_codecs, // Hardware-secure codecs.
@@ -136,6 +137,7 @@ void AddAndroidWidevine(
EmeFeatureSupport::ALWAYS_ENABLED)); // Distinctive identifier.
} else {
// It doesn't make sense to support secure codecs but not regular codecs.
+ DVLOG(3) << __func__ << " Widevine NOT supported.";
DCHECK(response.non_compositing_codecs == media::EME_CODEC_NONE);
}
}
diff --git a/chromium/components/certificate_reporting/OWNERS b/chromium/components/certificate_reporting/OWNERS
index e99de87684f..920a9af8d88 100644
--- a/chromium/components/certificate_reporting/OWNERS
+++ b/chromium/components/certificate_reporting/OWNERS
@@ -1,4 +1,6 @@
estark@chromium.org
felt@chromium.org
palmer@chromium.org
-rsleevi@chromium.org \ No newline at end of file
+rsleevi@chromium.org
+
+# COMPONENT: Internals>CertAnalysis
diff --git a/chromium/components/certificate_transparency/OWNERS b/chromium/components/certificate_transparency/OWNERS
index facb789f58d..009e29e53fb 100644
--- a/chromium/components/certificate_transparency/OWNERS
+++ b/chromium/components/certificate_transparency/OWNERS
@@ -1,2 +1,5 @@
eranm@chromium.org
rsleevi@chromium.org
+
+# TEAM: net-dev@chromium.org
+# COMPONENT: Internals>Network>CertTrans
diff --git a/chromium/components/certificate_transparency/ct_policy_manager_unittest.cc b/chromium/components/certificate_transparency/ct_policy_manager_unittest.cc
index 6abc261cbb5..e535f98baa3 100644
--- a/chromium/components/certificate_transparency/ct_policy_manager_unittest.cc
+++ b/chromium/components/certificate_transparency/ct_policy_manager_unittest.cc
@@ -20,12 +20,13 @@ namespace certificate_transparency {
namespace {
-base::ListValue* ListValueFromStrings(const std::vector<const char*>& strings) {
+std::unique_ptr<base::ListValue> ListValueFromStrings(
+ const std::vector<const char*>& strings) {
std::unique_ptr<base::ListValue> result(new base::ListValue);
for (auto* const str : strings) {
result->AppendString(str);
}
- return result.release();
+ return result;
}
class CTPolicyManagerTest : public ::testing::Test {
diff --git a/chromium/components/chrome_apps/webstore_widget/cws_widget/compiled_resources.gypi b/chromium/components/chrome_apps/webstore_widget/cws_widget/compiled_resources.gypi
index b369bb01aee..7118a7b8edd 100644
--- a/chromium/components/chrome_apps/webstore_widget/cws_widget/compiled_resources.gypi
+++ b/chromium/components/chrome_apps/webstore_widget/cws_widget/compiled_resources.gypi
@@ -13,6 +13,7 @@
'<(WIDGET_ROOT)/cws_webview_client.js',
'<(WIDGET_ROOT)/cws_widget_container.js',
'<(WIDGET_ROOT)/cws_widget_container_error_dialog.js',
+ '<(WIDGET_ROOT)/cws_widget_container_platform_delegate.js',
]
}
}
diff --git a/chromium/components/chrome_apps/webstore_widget/cws_widget/compiled_resources2.gyp b/chromium/components/chrome_apps/webstore_widget/cws_widget/compiled_resources2.gyp
new file mode 100644
index 00000000000..b379ef8bb82
--- /dev/null
+++ b/chromium/components/chrome_apps/webstore_widget/cws_widget/compiled_resources2.gyp
@@ -0,0 +1,47 @@
+# 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.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'app_installer',
+ 'dependencies': [
+ 'cws_widget_container_platform_delegate',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'cws_widget_container',
+ 'dependencies': [
+ 'app_installer',
+ 'cws_webview_client',
+ 'cws_widget_container_error_dialog',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'cws_widget_container_error_dialog',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:dialogs',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'cws_widget_container_platform_delegate',
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'cws_webview_client',
+ 'dependencies': [
+ '../externs/compiled_resources2.gyp:webview_tag',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(DEPTH)/ui/webui/resources/js/cr/compiled_resources2.gyp:event_target',
+ '<(EXTERNS_GYP):chrome_extensions',
+ 'cws_widget_container_platform_delegate',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
+
diff --git a/chromium/components/chrome_apps/webstore_widget/externs/compiled_resources2.gyp b/chromium/components/chrome_apps/webstore_widget/externs/compiled_resources2.gyp
new file mode 100644
index 00000000000..2b2347cdc02
--- /dev/null
+++ b/chromium/components/chrome_apps/webstore_widget/externs/compiled_resources2.gyp
@@ -0,0 +1,15 @@
+# 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.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'webview_tag',
+ 'dependencies': [
+ '<(EXTERNS_GYP):chrome_extensions',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ }
+ ]
+}
diff --git a/chromium/components/chrome_cleaner/DEPS b/chromium/components/chrome_cleaner/DEPS
new file mode 100644
index 00000000000..23e3cd60e6e
--- /dev/null
+++ b/chromium/components/chrome_cleaner/DEPS
@@ -0,0 +1,10 @@
+# Undo everything in the include_rules section of //DEPS, with the exception of
+# IPC that is already removed in //components/DEPS.
+include_rules = [
+ '-base',
+ '-build',
+ '-library_loaders',
+ '-testing',
+ '-third_party',
+ '-url',
+]
diff --git a/chromium/components/chrome_cleaner/OWNERS b/chromium/components/chrome_cleaner/OWNERS
new file mode 100644
index 00000000000..e54e7edd113
--- /dev/null
+++ b/chromium/components/chrome_cleaner/OWNERS
@@ -0,0 +1,5 @@
+csharp@chromium.org
+joenotcharles@chromium.org
+robertshield@chromium.org
+
+# COMPONENT: UI>Browser>Preferences>Protector
diff --git a/chromium/components/chrome_cleaner/public/interfaces/BUILD.gn b/chromium/components/chrome_cleaner/public/interfaces/BUILD.gn
new file mode 100644
index 00000000000..039f1222a13
--- /dev/null
+++ b/chromium/components/chrome_cleaner/public/interfaces/BUILD.gn
@@ -0,0 +1,11 @@
+# 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("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+ sources = [
+ "chrome_prompt.mojom",
+ ]
+}
diff --git a/chromium/components/chrome_cleaner/public/interfaces/OWNERS b/chromium/components/chrome_cleaner/public/interfaces/OWNERS
new file mode 100644
index 00000000000..dd2568b89f3
--- /dev/null
+++ b/chromium/components/chrome_cleaner/public/interfaces/OWNERS
@@ -0,0 +1,7 @@
+csharp@chromium.org
+robertshield@chromium.org
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+# COMPONENT: UI>Browser>Preferences>Protector
diff --git a/chromium/components/chrome_cleaner/public/interfaces/chrome_prompt.mojom b/chromium/components/chrome_cleaner/public/interfaces/chrome_prompt.mojom
new file mode 100644
index 00000000000..7458a8e3f67
--- /dev/null
+++ b/chromium/components/chrome_cleaner/public/interfaces/chrome_prompt.mojom
@@ -0,0 +1,72 @@
+// 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.
+
+module chrome_cleaner.mojom;
+
+// The behaviours that have been observed for a given UwS.
+struct ObservedBehaviours {
+ bool ad_injector;
+ bool settings_hijacker;
+ bool extensions_injector;
+ bool dropper;
+};
+
+// Information about removable Unwanted Software matched by the Software
+// Reporter to be shown in the Chrome prompt.
+struct UwS {
+ // The id of this unwanted software.
+ int32 id;
+
+ // The name of this unwanted software.
+ string name;
+
+ // Behaviors observed for this UwS to be presented to the user in the Chrome
+ // prompt.
+ ObservedBehaviours observed_behaviours;
+
+ // List of fully-qualified paths of the files that will be deleted by the
+ // Chrome Cleanup Tool for this unwanted software.
+ array<string> files_to_delete;
+};
+
+// Indicates if elevation will be required for cleanup.
+[Extensible]
+enum ElevationStatus {
+ NOT_REQUIRED = 0,
+ REQUIRED = 1,
+};
+
+[Extensible]
+enum PromptAcceptance {
+ UNSPECIFIED = 0,
+ // The Chrome prompt was not shown to the user (for example, due to an
+ // experiment run that shouldn't prompt the user or because the user has
+ // been prompted recently).
+ NOT_SHOWN = 1,
+ // The user explicitly accepted the Chrome prompt, but didn't opt into
+ // uploading logs to Google.
+ ACCEPTED_WITHOUT_LOGS = 2,
+ // The user explicitly accepted the Chrome prompt and also opted into
+ // uploading logs to Google.
+ ACCEPTED_WITH_LOGS = 3,
+ // The user explicitly denied the Chrome prompt.
+ DENIED = 4,
+ // The user didn't interact with the Chrome prompt after a while.
+ IGNORED = 5,
+};
+
+// Service provided by Chrome to prompt the user to run the Chrome Cleanup Tool
+// if unwanted software is detected on the system. This service is used by the
+// Software Reporter Tool so that all user interaction is provided by Chrome.
+interface ChromePrompt {
+ // Params:
+ // - removable_uws_found: the list of UwS detected by the reporter;
+ // - elevation_status: if the cleaner will need to run in elevated mode.
+ // Returns:
+ // - prompt_acceptance: indicates if the user accepted the prompt; if the
+ // prompt is accepted, it also indicates if logs
+ // uploading is allowed.
+ PromptUser(array<UwS> removable_uws_found, ElevationStatus elevation_status)
+ => (PromptAcceptance prompt_acceptance);
+};
diff --git a/chromium/components/client_update_protocol/ecdsa.cc b/chromium/components/client_update_protocol/ecdsa.cc
index 71547936a35..38faa9aba88 100644
--- a/chromium/components/client_update_protocol/ecdsa.cc
+++ b/chromium/components/client_update_protocol/ecdsa.cc
@@ -170,10 +170,9 @@ bool Ecdsa::ValidateResponse(const base::StringPiece& response_body,
// Initialize the signature verifier.
crypto::SignatureVerifier verifier;
- if (!verifier.VerifyInit(
- crypto::SignatureVerifier::ECDSA_SHA256, &signature.front(),
- static_cast<int>(signature.size()), &public_key_.front(),
- static_cast<int>(public_key_.size()))) {
+ if (!verifier.VerifyInit(crypto::SignatureVerifier::ECDSA_SHA256,
+ &signature.front(), signature.size(),
+ &public_key_.front(), public_key_.size())) {
DVLOG(1) << "Couldn't init SignatureVerifier.";
return false;
}
@@ -184,7 +183,7 @@ bool Ecdsa::ValidateResponse(const base::StringPiece& response_body,
// client assembled -- implying that either request body or response body
// was modified, or a different nonce value was used.
verifier.VerifyUpdate(&signed_message_hash.front(),
- static_cast<int>(signed_message_hash.size()));
+ signed_message_hash.size());
return verifier.VerifyFinal();
}
diff --git a/chromium/components/cloud_devices/common/cloud_devices_urls.h b/chromium/components/cloud_devices/common/cloud_devices_urls.h
index 379850d1866..6cb761acfed 100644
--- a/chromium/components/cloud_devices/common/cloud_devices_urls.h
+++ b/chromium/components/cloud_devices/common/cloud_devices_urls.h
@@ -12,7 +12,6 @@
namespace cloud_devices {
extern const char kCloudPrintAuthScope[];
-extern const char kCloudDevicesAuthScope[];
extern const char kCloudPrintLearnMoreURL[];
extern const char kCloudPrintTestPageURL[];
diff --git a/chromium/components/component_updater/component_updater_service.h b/chromium/components/component_updater/component_updater_service.h
index 38961e2ec3e..0701e9cac0b 100644
--- a/chromium/components/component_updater/component_updater_service.h
+++ b/chromium/components/component_updater/component_updater_service.h
@@ -15,6 +15,7 @@
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/version.h"
+#include "build/build_config.h"
#include "components/update_client/update_client.h"
#include "url/gurl.h"
@@ -155,6 +156,9 @@ class OnDemandUpdater {
friend class SupervisedUserWhitelistInstaller;
friend class ::ComponentsUI;
friend class ::PluginObserver;
+#if defined(OS_CHROMEOS)
+ friend class CrOSComponent;
+#endif // defined(OS_CHROMEOS)
// Triggers an update check for a component. |id| is a value
// returned by GetCrxComponentID(). If an update for this component is already
diff --git a/chromium/components/component_updater/configurator_impl.cc b/chromium/components/component_updater/configurator_impl.cc
index 68b86ff2d6e..291b25a3bb8 100644
--- a/chromium/components/component_updater/configurator_impl.cc
+++ b/chromium/components/component_updater/configurator_impl.cc
@@ -133,10 +133,6 @@ int ConfiguratorImpl::NextCheckDelay() const {
return 5 * kDelayOneHour;
}
-int ConfiguratorImpl::StepDelay() const {
- return 1;
-}
-
int ConfiguratorImpl::OnDemandDelay() const {
return fast_update_ ? 2 : (30 * kDelayOneMinute);
}
diff --git a/chromium/components/component_updater/configurator_impl.h b/chromium/components/component_updater/configurator_impl.h
index 870dc860f16..bd0ea95ea9a 100644
--- a/chromium/components/component_updater/configurator_impl.h
+++ b/chromium/components/component_updater/configurator_impl.h
@@ -38,9 +38,6 @@ class ConfiguratorImpl {
// Delay in seconds to every subsequent update check. 0 means don't check.
int NextCheckDelay() const;
- // Delay in seconds from each task step. Used to smooth out CPU/IO usage.
- int StepDelay() const;
-
// Minimum delta time in seconds before an on-demand check is allowed for the
// same component.
int OnDemandDelay() const;
diff --git a/chromium/components/component_updater/configurator_impl_unittest.cc b/chromium/components/component_updater/configurator_impl_unittest.cc
index 401c48d5826..39b5f2f5cbf 100644
--- a/chromium/components/component_updater/configurator_impl_unittest.cc
+++ b/chromium/components/component_updater/configurator_impl_unittest.cc
@@ -36,7 +36,6 @@ TEST_F(ComponentUpdaterConfiguratorImplTest, FastUpdate) {
new ConfiguratorImpl(&cmdline, nullptr, false));
CHECK_EQ(6 * kDelayOneMinute, config->InitialDelay());
CHECK_EQ(5 * kDelayOneHour, config->NextCheckDelay());
- CHECK_EQ(1, config->StepDelay());
CHECK_EQ(30 * kDelayOneMinute, config->OnDemandDelay());
CHECK_EQ(15 * kDelayOneMinute, config->UpdateDelay());
@@ -45,7 +44,6 @@ TEST_F(ComponentUpdaterConfiguratorImplTest, FastUpdate) {
config.reset(new ConfiguratorImpl(&cmdline, nullptr, false));
CHECK_EQ(10, config->InitialDelay());
CHECK_EQ(5 * kDelayOneHour, config->NextCheckDelay());
- CHECK_EQ(1, config->StepDelay());
CHECK_EQ(2, config->OnDemandDelay());
CHECK_EQ(10, config->UpdateDelay());
}
diff --git a/chromium/components/components_strings.grd b/chromium/components/components_strings.grd
index 16ca124dd57..43c92320f6a 100644
--- a/chromium/components/components_strings.grd
+++ b/chromium/components/components_strings.grd
@@ -200,7 +200,7 @@
<part file="new_or_sad_tab_strings.grdp" />
<part file="ntp_snippets_strings.grdp" />
<part file="omnibox_strings.grdp" />
- <part file="pageinfo_strings.grdp" />
+ <part file="page_info_strings.grdp" />
<part file="password_manager_strings.grdp" />
<part file="payments_strings.grdp" />
<part file="pdf_strings.grdp" />
@@ -291,9 +291,18 @@
<message name="IDS_ACCNAME_CANCEL" desc="The accessible name for the Cancel button.">
Cancel
</message>
+ <message name="IDS_ACCNAME_DONE" desc="The accessible name for the DONE button.">
+ Done
+ </message>
<message name="IDS_ACCNAME_CLOSE" desc="The accessible name for the Close button.">
Close
</message>
+ <message name="IDS_ACCNAME_PREVIOUS" desc="The accessible name for the previous button.">
+ Previous
+ </message>
+ <message name="IDS_ACCNAME_NEXT" desc="The accessible name for the next button.">
+ Next
+ </message>
<message name="IDS_ACCNAME_LOCATION" desc="The accessible name for the editable-text portion of the omnibox.">
Address and search bar
</message>
@@ -310,8 +319,8 @@
Open startup pages
</message>
- <!-- Website Settings UI -->
- <message name="IDS_WEBSITE_SETTINGS_NON_SECURE_TRANSPORT" desc="Text that is displayed in the header of the Website Settings popup if the website uses non-secure transport.">
+ <!-- Page Info UI -->
+ <message name="IDS_PAGE_INFO_NON_SECURE_TRANSPORT" desc="Text that is displayed in the header of the Website Settings popup if the website uses non-secure transport.">
Your connection to this site is not private.
</message>
diff --git a/chromium/components/constrained_window/BUILD.gn b/chromium/components/constrained_window/BUILD.gn
index cc02308279a..a62c55548af 100644
--- a/chromium/components/constrained_window/BUILD.gn
+++ b/chromium/components/constrained_window/BUILD.gn
@@ -12,6 +12,7 @@ static_library("constrained_window") {
"constrained_window_views_client.h",
"native_web_contents_modal_dialog_manager_views.cc",
"native_web_contents_modal_dialog_manager_views.h",
+ "native_web_contents_modal_dialog_manager_views_mac.h",
"native_web_contents_modal_dialog_manager_views_mac.mm",
]
diff --git a/chromium/components/constrained_window/OWNERS b/chromium/components/constrained_window/OWNERS
index 8b25c36c776..299ed89d582 100644
--- a/chromium/components/constrained_window/OWNERS
+++ b/chromium/components/constrained_window/OWNERS
@@ -1,3 +1,5 @@
gbillock@chromium.org
msw@chromium.org
wittman@chromium.org
+
+# COMPONENT: Internals>Views
diff --git a/chromium/components/constrained_window/constrained_window_views.cc b/chromium/components/constrained_window/constrained_window_views.cc
index e493eaa7085..37de79c84e0 100644
--- a/chromium/components/constrained_window/constrained_window_views.cc
+++ b/chromium/components/constrained_window/constrained_window_views.cc
@@ -117,7 +117,7 @@ void UpdateModalDialogPosition(views::Widget* widget,
// with any display clamp its position to be fully on the nearest display.
gfx::Rect display_rect = gfx::Rect(position, size);
const display::Display display =
- display::Screen::GetScreen()->GetDisplayNearestWindow(
+ display::Screen::GetScreen()->GetDisplayNearestView(
dialog_host->GetHostView());
const gfx::Rect work_area = display.work_area();
if (!work_area.Contains(display_rect))
diff --git a/chromium/components/constrained_window/constrained_window_views_unittest.cc b/chromium/components/constrained_window/constrained_window_views_unittest.cc
index 26a4b6a21b7..b0c98d3f4d1 100644
--- a/chromium/components/constrained_window/constrained_window_views_unittest.cc
+++ b/chromium/components/constrained_window/constrained_window_views_unittest.cc
@@ -220,7 +220,7 @@ TEST_F(ConstrainedWindowViewsTest, MaximumWebContentsDialogSize) {
// Ensure CreateBrowserModalDialogViews() works correctly with a null parent.
TEST_F(ConstrainedWindowViewsTest, NullModalParent) {
// Use desktop widgets (except on ChromeOS) for extra coverage.
- views_delegate()->set_use_desktop_native_widgets(true);
+ test_views_delegate()->set_use_desktop_native_widgets(true);
SetConstrainedWindowViewsClient(
base::MakeUnique<TestConstrainedWindowViewsClient>());
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 a2d547cb09f..b782ec64617 100644
--- a/chromium/components/content_settings/core/browser/content_settings_registry.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_registry.cc
@@ -20,7 +20,7 @@ namespace content_settings {
namespace {
-base::LazyInstance<ContentSettingsRegistry> g_instance =
+base::LazyInstance<ContentSettingsRegistry>::DestructorAtExit g_instance =
LAZY_INSTANCE_INITIALIZER;
// TODO(raymes): These overloaded functions make the registration code clearer.
diff --git a/chromium/components/content_settings/core/browser/content_settings_registry.h b/chromium/components/content_settings/core/browser/content_settings_registry.h
index 84b4b514bf4..14675088fd8 100644
--- a/chromium/components/content_settings/core/browser/content_settings_registry.h
+++ b/chromium/components/content_settings/core/browser/content_settings_registry.h
@@ -46,7 +46,7 @@ class ContentSettingsRegistry {
private:
friend class ContentSettingsRegistryTest;
- friend struct base::DefaultLazyInstanceTraits<ContentSettingsRegistry>;
+ friend struct base::LazyInstanceTraitsBase<ContentSettingsRegistry>;
ContentSettingsRegistry();
ContentSettingsRegistry(WebsiteSettingsRegistry* website_settings_registry);
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 62d177bb83d..3879f3096c0 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
@@ -611,11 +611,11 @@ void HostContentSettingsMap::RecordExceptionMetrics() {
int histogram_value =
ContentSettingTypeToHistogramValue(content_type, &num_values);
if (setting_entry.primary_pattern.HasPath()) {
- UMA_HISTOGRAM_ENUMERATION(
+ UMA_HISTOGRAM_EXACT_LINEAR(
"ContentSettings.ExceptionSchemeFile.Type.WithPath",
histogram_value, num_values);
} else {
- UMA_HISTOGRAM_ENUMERATION(
+ UMA_HISTOGRAM_EXACT_LINEAR(
"ContentSettings.ExceptionSchemeFile.Type.WithoutPath",
histogram_value, num_values);
}
@@ -794,7 +794,7 @@ std::unique_ptr<base::Value> HostContentSettingsMap::GetWebsiteSetting(
content_settings_info->whitelisted_schemes()) {
DCHECK(SchemeCanBeWhitelisted(scheme));
- if (primary_url.SchemeIs(scheme.c_str())) {
+ if (primary_url.SchemeIs(scheme)) {
if (info) {
info->source = content_settings::SETTING_SOURCE_WHITELIST;
info->primary_pattern = ContentSettingsPattern::Wildcard();
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 019037c21ef..1cfb5441383 100644
--- a/chromium/components/content_settings/core/browser/website_settings_registry.cc
+++ b/chromium/components/content_settings/core/browser/website_settings_registry.cc
@@ -12,8 +12,8 @@
namespace {
-base::LazyInstance<content_settings::WebsiteSettingsRegistry> g_instance =
- LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<content_settings::WebsiteSettingsRegistry>::DestructorAtExit
+ g_instance = LAZY_INSTANCE_INITIALIZER;
} // namespace
@@ -160,6 +160,11 @@ void WebsiteSettingsRegistry::Init() {
WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE,
DESKTOP | PLATFORM_ANDROID,
WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
+ Register(
+ CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, "password-protection", nullptr,
+ WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
+ WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE,
+ DESKTOP | PLATFORM_ANDROID, WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
}
} // namespace content_settings
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 1f4ec47e9e4..ebfc93ff102 100644
--- a/chromium/components/content_settings/core/browser/website_settings_registry.h
+++ b/chromium/components/content_settings/core/browser/website_settings_registry.h
@@ -80,7 +80,7 @@ class WebsiteSettingsRegistry {
private:
friend class ContentSettingsRegistryTest;
friend class WebsiteSettingsRegistryTest;
- friend struct base::DefaultLazyInstanceTraits<WebsiteSettingsRegistry>;
+ friend struct base::LazyInstanceTraitsBase<WebsiteSettingsRegistry>;
WebsiteSettingsRegistry();
~WebsiteSettingsRegistry();
diff --git a/chromium/components/content_settings/core/common/content_settings_types.h b/chromium/components/content_settings/core/common/content_settings_types.h
index 6f6214e189a..d7584141be5 100644
--- a/chromium/components/content_settings/core/common/content_settings_types.h
+++ b/chromium/components/content_settings/core/common/content_settings_types.h
@@ -59,6 +59,10 @@ enum ContentSettingsType {
// this content type, we instead share values with NOTIFICATIONS.
CONTENT_SETTINGS_TYPE_PUSH_MESSAGING,
+ // This content setting type is for caching password protection service's
+ // verdicts of each origin.
+ CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
+
// WARNING: This enum is going to be removed soon. Do not depend on NUM_TYPES.
CONTENT_SETTINGS_NUM_TYPES_DO_NOT_USE,
};
diff --git a/chromium/components/contextual_search/renderer/contextual_search_wrapper.cc b/chromium/components/contextual_search/renderer/contextual_search_wrapper.cc
index 94986bb8a8e..8b1033fd748 100644
--- a/chromium/components/contextual_search/renderer/contextual_search_wrapper.cc
+++ b/chromium/components/contextual_search/renderer/contextual_search_wrapper.cc
@@ -37,10 +37,10 @@ void ContextualSearchWrapper::Install(content::RenderFrame* render_frame) {
// available, e.g. navigator.connect API. See crbug.com/541683.
// TODO(donnd): refactor some of this boilerplate into a reusable
// method. This was cribbed from MemoryBenchmarkingExtension.
- v8::Isolate* isolate = blink::mainThreadIsolate();
+ v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
- render_frame->GetWebFrame()->mainWorldScriptContext();
+ render_frame->GetWebFrame()->MainWorldScriptContext();
if (context.IsEmpty())
return;
diff --git a/chromium/components/cookie_config/cookie_store_util.cc b/chromium/components/cookie_config/cookie_store_util.cc
index 7c1b44b270d..c1aa494335c 100644
--- a/chromium/components/cookie_config/cookie_store_util.cc
+++ b/chromium/components/cookie_config/cookie_store_util.cc
@@ -55,8 +55,8 @@ bool CookieOSCryptoDelegate::DecryptString(const std::string& ciphertext,
// Using a LazyInstance is safe here because this class is stateless and
// requires 0 initialization.
-base::LazyInstance<CookieOSCryptoDelegate> g_cookie_crypto_delegate =
- LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<CookieOSCryptoDelegate>::DestructorAtExit
+ g_cookie_crypto_delegate = LAZY_INSTANCE_INITIALIZER;
} // namespace
diff --git a/chromium/components/crash/content/app/breakpad_linux.cc b/chromium/components/crash/content/app/breakpad_linux.cc
index 722ce16dca6..0d3de65043a 100644
--- a/chromium/components/crash/content/app/breakpad_linux.cc
+++ b/chromium/components/crash/content/app/breakpad_linux.cc
@@ -143,7 +143,7 @@ class MicrodumpInfo {
void SetMinidumpSanitizationFields(MinidumpDescriptor* minidump_descriptor,
const SanitizationInfo& sanitization_info);
-base::LazyInstance<MicrodumpInfo> g_microdump_info =
+base::LazyInstance<MicrodumpInfo>::DestructorAtExit g_microdump_info =
LAZY_INSTANCE_INITIALIZER;
#endif
@@ -980,9 +980,7 @@ void MicrodumpInfo::Initialize(const std::string& process_type,
true, // Install handlers.
-1); // Server file descriptor. -1 for in-process.
- if (process_type != kWebViewSingleProcessType &&
- process_type != kBrowserProcessType &&
- !process_type.empty()) {
+ if (!is_browser_process) {
g_signal_code_pipe_fd =
GetCrashReporterClient()->GetAndroidCrashSignalFD();
if (g_signal_code_pipe_fd != -1)
@@ -1953,7 +1951,14 @@ void InitCrashReporter(const std::string& process_type) {
if (parsed_command_line.HasSwitch(switches::kDisableBreakpad))
return;
- if (process_type.empty()) {
+ bool is_browser_process =
+#if defined(OS_ANDROID)
+ process_type == kWebViewSingleProcessType ||
+ process_type == kBrowserProcessType ||
+#endif
+ process_type.empty();
+
+ if (is_browser_process) {
bool enable_breakpad = GetCrashReporterClient()->GetCollectStatsConsent() ||
GetCrashReporterClient()->IsRunningUnattended();
enable_breakpad &=
diff --git a/chromium/components/crash/content/app/breakpad_win.cc b/chromium/components/crash/content/app/breakpad_win.cc
index c80c02303db..c09961c7f6a 100644
--- a/chromium/components/crash/content/app/breakpad_win.cc
+++ b/chromium/components/crash/content/app/breakpad_win.cc
@@ -290,10 +290,10 @@ long WINAPI ChromeExceptionFilter(EXCEPTION_POINTERS* info) {
return EXCEPTION_EXECUTE_HANDLER;
}
-// Exception filter for the service process used when breakpad is not enabled.
-// We just display the "Do you want to restart" message and then die
-// (without calling the previous filter).
-long WINAPI ServiceExceptionFilter(EXCEPTION_POINTERS* info) {
+// Exception filter for the Cloud Print service process used when breakpad is
+// not enabled. We just display the "Do you want to restart" message and then
+// die (without calling the previous filter).
+long WINAPI CloudPrintServiceExceptionFilter(EXCEPTION_POINTERS* info) {
DumpDoneCallback(NULL, NULL, NULL, info, NULL, false);
return EXCEPTION_EXECUTE_HANDLER;
}
@@ -583,7 +583,7 @@ void InitCrashReporter(const std::string& process_type_switch) {
default_filter = &ChromeExceptionFilter;
} else if (process_type == L"service") {
callback = &DumpDoneCallback;
- default_filter = &ServiceExceptionFilter;
+ default_filter = &CloudPrintServiceExceptionFilter;
}
if (GetCrashReporterClient()->ShouldCreatePipeName(process_type))
diff --git a/chromium/components/crash/content/app/crash_reporter_client.cc b/chromium/components/crash/content/app/crash_reporter_client.cc
index eac090b9cad..2e9ee28e1b0 100644
--- a/chromium/components/crash/content/app/crash_reporter_client.cc
+++ b/chromium/components/crash/content/app/crash_reporter_client.cc
@@ -173,6 +173,12 @@ bool CrashReporterClient::ShouldEnableBreakpadMicrodumps() {
}
#endif
+#if defined(OS_MACOSX) || defined(OS_WIN)
+bool CrashReporterClient::ShouldMonitorCrashHandlerExpensively() {
+ return false;
+}
+#endif
+
bool CrashReporterClient::EnableBreakpadForProcess(
const std::string& process_type) {
return false;
diff --git a/chromium/components/crash/content/app/crash_reporter_client.h b/chromium/components/crash/content/app/crash_reporter_client.h
index ccc30483da6..9f69c193dda 100644
--- a/chromium/components/crash/content/app/crash_reporter_client.h
+++ b/chromium/components/crash/content/app/crash_reporter_client.h
@@ -179,6 +179,22 @@ class CrashReporterClient {
virtual bool ShouldEnableBreakpadMicrodumps();
#endif
+#if defined(OS_MACOSX) || defined(OS_WIN)
+ // This method should return true to configure a crash reporter capable of
+ // monitoring itself for its own crashes to do so, even if self-monitoring
+ // would be expensive. "Expensive" self-monitoring dedicates an additional
+ // crash handler process to handle the crashes of the initial crash handler
+ // process.
+ //
+ // In some cases, inexpensive self-monitoring may also be available. When it
+ // is, it may be used when this method returns false. If only expensive
+ // self-monitoring is available, returning false from this function will
+ // prevent the crash handler process from being monitored for crashes at all.
+ //
+ // The default implementation returns false.
+ virtual bool ShouldMonitorCrashHandlerExpensively();
+#endif
+
// Returns true if breakpad should run in the given process type.
virtual bool EnableBreakpadForProcess(const std::string& process_type);
};
diff --git a/chromium/components/crash/content/app/crashpad.cc b/chromium/components/crash/content/app/crashpad.cc
index 76f67348ab0..dcec3468435 100644
--- a/chromium/components/crash/content/app/crashpad.cc
+++ b/chromium/components/crash/content/app/crashpad.cc
@@ -204,6 +204,12 @@ void InitializeCrashpadWithEmbeddedHandler(bool initial_client,
}
#endif // OS_WIN
+crashpad::CrashpadClient& GetCrashpadClient() {
+ static crashpad::CrashpadClient* const client =
+ new crashpad::CrashpadClient();
+ return *client;
+}
+
void SetUploadConsent(bool consent) {
if (!g_database)
return;
diff --git a/chromium/components/crash/content/app/crashpad.h b/chromium/components/crash/content/app/crashpad.h
index eeb65ac69b7..ada0eaec733 100644
--- a/chromium/components/crash/content/app/crashpad.h
+++ b/chromium/components/crash/content/app/crashpad.h
@@ -12,6 +12,15 @@
#include <vector>
#include "base/files/file_path.h"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_mach_port.h"
+#endif
+
+namespace crashpad {
+class CrashpadClient;
+}
namespace crash_reporter {
@@ -55,6 +64,10 @@ void InitializeCrashpadWithEmbeddedHandler(bool initial_client,
const std::string& process_type);
#endif // OS_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.
+crashpad::CrashpadClient& GetCrashpadClient();
+
// Enables or disables crash report upload, taking the given consent to upload
// into account. Consent may be ignored, uploads may not be enabled even with
// consent, but will only be enabled without consent when policy enforces crash
diff --git a/chromium/components/crash/content/app/crashpad_mac.mm b/chromium/components/crash/content/app/crashpad_mac.mm
index 7df66ea3d32..3bae07e14c6 100644
--- a/chromium/components/crash/content/app/crashpad_mac.mm
+++ b/chromium/components/crash/content/app/crashpad_mac.mm
@@ -66,12 +66,18 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
base::SysNSStringToUTF8(product).append("_Mac");
#if defined(GOOGLE_CHROME_BUILD)
+ // Empty means stable.
+ const bool allow_empty_channel = true;
+#else
+ const bool allow_empty_channel = false;
+#endif
NSString* channel = base::mac::ObjCCast<NSString>(
[outer_bundle objectForInfoDictionaryKey:@"KSChannelID"]);
if (channel) {
process_annotations["channel"] = base::SysNSStringToUTF8(channel);
+ } else if (allow_empty_channel) {
+ process_annotations["channel"] = "";
}
-#endif
NSString* version =
base::mac::ObjCCast<NSString>([base::mac::FrameworkBundle()
@@ -81,6 +87,16 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
process_annotations["plat"] = std::string("OS X");
std::vector<std::string> arguments;
+
+ if (crash_reporter_client->ShouldMonitorCrashHandlerExpensively()) {
+ arguments.push_back("--monitor-self");
+ }
+
+ // Set up --monitor-self-annotation even in the absence of --monitor-self
+ // so that minidumps produced by Crashpad's generate_dump tool will
+ // contain these annotations.
+ arguments.push_back("--monitor-self-annotation=ptype=crashpad-handler");
+
if (!browser_process) {
// If this is an initial client that's not the browser process, it's
// important that the new Crashpad handler also not be connected to any
@@ -90,15 +106,9 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
"--reset-own-crash-exception-port-to-system-default");
}
- crashpad::CrashpadClient crashpad_client;
- bool result = crashpad_client.StartHandler(handler_path,
- database_path,
- metrics_path,
- url,
- process_annotations,
- arguments,
- true,
- false);
+ bool result = GetCrashpadClient().StartHandler(
+ handler_path, database_path, metrics_path, url, process_annotations,
+ arguments, true, false);
// If this is an initial client that's not the browser process, it's
// important to sever the connection to any existing handler. If
diff --git a/chromium/components/crash/content/app/crashpad_win.cc b/chromium/components/crash/content/app/crashpad_win.cc
index 89f3d2b9926..94a350f4b5a 100644
--- a/chromium/components/crash/content/app/crashpad_win.cc
+++ b/chromium/components/crash/content/app/crashpad_win.cc
@@ -9,7 +9,6 @@
#include "base/debug/crash_logging.h"
#include "base/environment.h"
#include "base/files/file_util.h"
-#include "base/lazy_instance.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
@@ -26,13 +25,6 @@
namespace crash_reporter {
namespace internal {
-namespace {
-
-base::LazyInstance<crashpad::CrashpadClient>::Leaky g_crashpad_client =
- LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
void GetPlatformCrashpadAnnotations(
std::map<std::string, std::string>* annotations) {
CrashReporterClient* crash_reporter_client = GetCrashReporterClient();
@@ -43,7 +35,14 @@ void GetPlatformCrashpadAnnotations(
exe_file, &product_name, &version, &special_build, &channel_name);
(*annotations)["prod"] = base::UTF16ToUTF8(product_name);
(*annotations)["ver"] = base::UTF16ToUTF8(version);
- (*annotations)["channel"] = base::UTF16ToUTF8(channel_name);
+#if defined(GOOGLE_CHROME_BUILD)
+ // Empty means stable.
+ const bool allow_empty_channel = true;
+#else
+ const bool allow_empty_channel = false;
+#endif
+ if (allow_empty_channel || !channel_name.empty())
+ (*annotations)["channel"] = base::UTF16ToUTF8(channel_name);
if (!special_build.empty())
(*annotations)["special"] = base::UTF16ToUTF8(special_build);
#if defined(ARCH_CPU_X86)
@@ -104,32 +103,48 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
// If the handler is embedded in the binary (e.g. chrome, setup), we
// reinvoke it with --type=crashpad-handler. Otherwise, we use the
// standalone crashpad_handler.exe (for tests, etc.).
- std::vector<std::string> arguments;
+ std::vector<std::string> start_arguments;
if (embedded_handler) {
- arguments.push_back(std::string("--type=") + switches::kCrashpadHandler);
+ start_arguments.push_back(std::string("--type=") +
+ switches::kCrashpadHandler);
// The prefetch argument added here has to be documented in
// chrome_switches.cc, below the kPrefetchArgument* constants. A constant
// can't be used here because crashpad can't depend on Chrome.
- arguments.push_back("/prefetch:7");
+ start_arguments.push_back("/prefetch:7");
} else {
base::FilePath exe_dir = exe_file.DirName();
exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe"));
}
- g_crashpad_client.Get().StartHandler(
- exe_file, database_path, metrics_path, url, process_annotations,
- arguments, false, false);
+ std::vector<std::string> arguments(start_arguments);
+
+ if (crash_reporter_client->ShouldMonitorCrashHandlerExpensively()) {
+ arguments.push_back("--monitor-self");
+ for (const std::string& start_argument : start_arguments) {
+ arguments.push_back(std::string("--monitor-self-argument=") +
+ start_argument);
+ }
+ }
+
+ // Set up --monitor-self-annotation even in the absence of --monitor-self so
+ // that minidumps produced by Crashpad's generate_dump tool will contain
+ // these annotations.
+ arguments.push_back(std::string("--monitor-self-annotation=ptype=") +
+ switches::kCrashpadHandler);
+
+ GetCrashpadClient().StartHandler(exe_file, database_path, metrics_path, url,
+ process_annotations, arguments, false,
+ false);
// If we're the browser, push the pipe name into the environment so child
// processes can connect to it. If we inherited another crashpad_handler's
// pipe name, we'll overwrite it here.
env->SetVar(kPipeNameVar,
- base::UTF16ToUTF8(g_crashpad_client.Get().GetHandlerIPCPipe()));
+ base::UTF16ToUTF8(GetCrashpadClient().GetHandlerIPCPipe()));
} else {
std::string pipe_name_utf8;
if (env->GetVar(kPipeNameVar, &pipe_name_utf8)) {
- g_crashpad_client.Get().SetHandlerIPCPipe(
- base::UTF8ToUTF16(pipe_name_utf8));
+ GetCrashpadClient().SetHandlerIPCPipe(base::UTF8ToUTF16(pipe_name_utf8));
}
}
@@ -218,7 +233,7 @@ extern "C" {
// releases of Chrome. Please contact syzygy-team@chromium.org before doing so!
int __declspec(dllexport) CrashForException(
EXCEPTION_POINTERS* info) {
- crash_reporter::internal::g_crashpad_client.Get().DumpAndCrash(info);
+ crash_reporter::GetCrashpadClient().DumpAndCrash(info);
return EXCEPTION_CONTINUE_SEARCH;
}
diff --git a/chromium/components/crash/content/app/fallback_crash_handler_launcher_win_unittest.cc b/chromium/components/crash/content/app/fallback_crash_handler_launcher_win_unittest.cc
index c19ae79d17d..07340432cec 100644
--- a/chromium/components/crash/content/app/fallback_crash_handler_launcher_win_unittest.cc
+++ b/chromium/components/crash/content/app/fallback_crash_handler_launcher_win_unittest.cc
@@ -143,9 +143,10 @@ TEST_F(FallbackCrashHandlerLauncherTest, LaunchAndWaitForHandler) {
// Because this process is heavily multithreaded it's going to be flaky
// and generally fraught with peril to try and grab a minidump of it.
// Instead, fire off a sacrificial process to do the testing.
- base::Process test_process = SpawnChild("TestCrashHandlerLauncherMain");
+ base::SpawnChildResult spawn_child =
+ SpawnChild("TestCrashHandlerLauncherMain");
int exit_code = 0;
- ASSERT_TRUE(test_process.WaitForExit(&exit_code));
+ ASSERT_TRUE(spawn_child.process.WaitForExit(&exit_code));
ASSERT_EQ(0, exit_code);
}
diff --git a/chromium/components/crash/content/app/fallback_crash_handler_win.cc b/chromium/components/crash/content/app/fallback_crash_handler_win.cc
index 2e3310d874d..01f63f364dd 100644
--- a/chromium/components/crash/content/app/fallback_crash_handler_win.cc
+++ b/chromium/components/crash/content/app/fallback_crash_handler_win.cc
@@ -479,6 +479,7 @@ bool FallbackCrashHandler::GenerateCrashDump(const std::string& product,
uint32_t minidump_type = MiniDumpWithUnloadedModules |
MiniDumpWithProcessThreadData |
+ MiniDumpWithFullMemoryInfo |
MiniDumpWithThreadInfo;
// Capture more detail for canary and dev channels. The prefix search caters
diff --git a/chromium/components/crash/content/app/fallback_crash_handler_win_unittest.cc b/chromium/components/crash/content/app/fallback_crash_handler_win_unittest.cc
index 13ca131f020..92c008ea804 100644
--- a/chromium/components/crash/content/app/fallback_crash_handler_win_unittest.cc
+++ b/chromium/components/crash/content/app/fallback_crash_handler_win_unittest.cc
@@ -169,12 +169,12 @@ TEST_F(FallbackCrashHandlerWinTest, GenerateCrashDump) {
cmd_line.AppendSwitchPath("directory", database_dir_.GetPath());
base::LaunchOptions options;
options.start_hidden = true;
- base::Process test_child = base::SpawnMultiProcessTestChild(
+ base::SpawnChildResult spawn_child = base::SpawnMultiProcessTestChild(
"FallbackCrashHandlerWinMain", cmd_line, options);
- ASSERT_TRUE(test_child.IsValid());
+ ASSERT_TRUE(spawn_child.process.IsValid());
int exit_code = -1;
- ASSERT_TRUE(test_child.WaitForExit(&exit_code));
+ ASSERT_TRUE(spawn_child.process.WaitForExit(&exit_code));
ASSERT_EQ(0, exit_code);
// Validate that the database contains one valid crash dump.
diff --git a/chromium/components/crash/content/app/fallback_crash_handling_win_unittest.cc b/chromium/components/crash/content/app/fallback_crash_handling_win_unittest.cc
index 7df6b20262a..02d69c5dd27 100644
--- a/chromium/components/crash/content/app/fallback_crash_handling_win_unittest.cc
+++ b/chromium/components/crash/content/app/fallback_crash_handling_win_unittest.cc
@@ -62,12 +62,12 @@ TEST_F(FallbackCrashHandlingTest, SetupAndRunAsFallbackCrashHandler) {
base::LaunchOptions options;
options.start_hidden = true;
- base::Process test_child = base::SpawnMultiProcessTestChild(
+ base::SpawnChildResult spawn_child = base::SpawnMultiProcessTestChild(
"FallbackCrashHandlingWinRunHandler", cmd_line, options);
- ASSERT_TRUE(test_child.IsValid());
+ ASSERT_TRUE(spawn_child.process.IsValid());
int exit_code = -1;
- ASSERT_TRUE(test_child.WaitForExit(&exit_code));
+ ASSERT_TRUE(spawn_child.process.WaitForExit(&exit_code));
ASSERT_EQ(kFallbackCrashTerminationCode, static_cast<uint32_t>(exit_code));
// Validate that the database contains one valid crash dump.
diff --git a/chromium/components/crash/content/app/run_as_crashpad_handler_win.cc b/chromium/components/crash/content/app/run_as_crashpad_handler_win.cc
index 20be2d108cf..6ea93489f1f 100644
--- a/chromium/components/crash/content/app/run_as_crashpad_handler_win.cc
+++ b/chromium/components/crash/content/app/run_as_crashpad_handler_win.cc
@@ -14,25 +14,46 @@
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "third_party/crashpad/crashpad/client/crashpad_info.h"
+#include "third_party/crashpad/crashpad/client/simple_string_dictionary.h"
#include "third_party/crashpad/crashpad/handler/handler_main.h"
namespace crash_reporter {
-int RunAsCrashpadHandler(const base::CommandLine& command_line) {
+int RunAsCrashpadHandler(const base::CommandLine& command_line,
+ const char* process_type_switch) {
// Make sure this process terminates on OOM in the same mode as other Chrome
// processes.
base::EnableTerminationOnOutOfMemory();
+ // If the handler is started with --monitor-self, it'll need a ptype
+ // annotation set. It'll normally set one itself by being invoked with
+ // --monitor-self-annotation=ptype=crashpad-handler, but that leaves a window
+ // during self-monitoring initialization when the ptype is not set at all, so
+ // provide one here.
+ const std::string process_type =
+ command_line.GetSwitchValueASCII(process_type_switch);
+ if (!process_type.empty()) {
+ crashpad::SimpleStringDictionary* annotations =
+ new crashpad::SimpleStringDictionary();
+ annotations->SetKeyValue("ptype", process_type.c_str());
+ crashpad::CrashpadInfo* crashpad_info =
+ crashpad::CrashpadInfo::GetCrashpadInfo();
+ DCHECK(!crashpad_info->simple_annotations());
+ crashpad_info->set_simple_annotations(annotations);
+ }
+
std::vector<base::string16> argv = command_line.argv();
- const base::string16 process_type = L"--type=";
- argv.erase(std::remove_if(argv.begin(), argv.end(),
- [&process_type](const base::string16& str) {
- return base::StartsWith(
- str, process_type,
- base::CompareCase::SENSITIVE) ||
- (!str.empty() && str[0] == L'/');
- }),
- argv.end());
+ const base::string16 process_type_arg_prefix =
+ base::string16(L"--") + base::UTF8ToUTF16(process_type_switch) + L"=";
+ argv.erase(
+ std::remove_if(argv.begin(), argv.end(),
+ [&process_type_arg_prefix](const base::string16& str) {
+ return base::StartsWith(str, process_type_arg_prefix,
+ base::CompareCase::SENSITIVE) ||
+ (!str.empty() && str[0] == L'/');
+ }),
+ argv.end());
std::unique_ptr<char* []> argv_as_utf8(new char*[argv.size() + 1]);
std::vector<std::string> storage;
@@ -44,7 +65,7 @@ int RunAsCrashpadHandler(const base::CommandLine& command_line) {
argv_as_utf8[argv.size()] = nullptr;
argv.clear();
return crashpad::HandlerMain(static_cast<int>(storage.size()),
- argv_as_utf8.get());
+ argv_as_utf8.get(), nullptr);
}
} // namespace crash_reporter
diff --git a/chromium/components/crash/content/app/run_as_crashpad_handler_win.h b/chromium/components/crash/content/app/run_as_crashpad_handler_win.h
index 8bed61093af..ade72a01db9 100644
--- a/chromium/components/crash/content/app/run_as_crashpad_handler_win.h
+++ b/chromium/components/crash/content/app/run_as_crashpad_handler_win.h
@@ -12,10 +12,15 @@ class CommandLine;
namespace crash_reporter {
// Helper for running an embedded copy of crashpad_handler. Searches for and
-// removes --switches::kProcessType=xyz arguments in the command line, and all
+// removes --(process_type_switch)=xyz arguments in the command line, and all
// options starting with '/' (for "/prefetch:N"), and then runs
// crashpad::HandlerMain with the remaining arguments.
-int RunAsCrashpadHandler(const base::CommandLine& command_line);
+//
+// Normally, pass switches::kProcessType for process_type_switch. It's accepted
+// as a parameter because this component does not have access to content/, where
+// that variable lives.
+int RunAsCrashpadHandler(const base::CommandLine& command_line,
+ const char* process_type_switch);
} // namespace crash_reporter
diff --git a/chromium/components/crash/content/browser/crash_dump_observer_android.cc b/chromium/components/crash/content/browser/crash_dump_observer_android.cc
index bc5449f45df..72189b15d96 100644
--- a/chromium/components/crash/content/browser/crash_dump_observer_android.cc
+++ b/chromium/components/crash/content/browser/crash_dump_observer_android.cc
@@ -21,7 +21,8 @@ using content::BrowserThread;
namespace breakpad {
namespace {
-base::LazyInstance<CrashDumpObserver> g_instance = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<CrashDumpObserver>::DestructorAtExit g_instance =
+ LAZY_INSTANCE_INITIALIZER;
}
// static
diff --git a/chromium/components/crash/content/browser/crash_dump_observer_android.h b/chromium/components/crash/content/browser/crash_dump_observer_android.h
index fbff47625db..3f049f31dd4 100644
--- a/chromium/components/crash/content/browser/crash_dump_observer_android.h
+++ b/chromium/components/crash/content/browser/crash_dump_observer_android.h
@@ -70,7 +70,7 @@ class CrashDumpObserver : public content::BrowserChildProcessObserver,
content::FileDescriptorInfo* mappings);
private:
- friend struct base::DefaultLazyInstanceTraits<CrashDumpObserver>;
+ friend struct base::LazyInstanceTraitsBase<CrashDumpObserver>;
CrashDumpObserver();
~CrashDumpObserver() override;
diff --git a/chromium/components/cronet/android/BUILD.gn b/chromium/components/cronet/android/BUILD.gn
index a6b7b5237b2..c11669e7b70 100644
--- a/chromium/components/cronet/android/BUILD.gn
+++ b/chromium/components/cronet/android/BUILD.gn
@@ -255,7 +255,11 @@ cronet_static_tmpl("cronet_static") {
}
}
+_cronet_shared_lib_name = "cronet.$chrome_version_full"
+_cronet_shared_lib_file_name = "lib" + _cronet_shared_lib_name + ".so"
+
shared_library("cronet") {
+ output_name = _cronet_shared_lib_name
sources = [
"cronet_jni.cc",
]
@@ -701,6 +705,7 @@ android_library("cronet_javatests") {
"test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java",
"test/javatests/src/org/chromium/net/CronetUrlRequestTest.java",
"test/javatests/src/org/chromium/net/DiskStorageTest.java",
+ "test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java",
"test/javatests/src/org/chromium/net/GetStatusTest.java",
"test/javatests/src/org/chromium/net/MetricsTestUtil.java",
"test/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java",
@@ -876,6 +881,7 @@ instrumentation_test_apk(
android_library("cronet_perf_test_apk_java") {
testonly = true
+ android_manifest = "test/javaperftests/AndroidManifest.xml"
java_files =
[ "test/javaperftests/src/org/chromium/net/CronetPerfTestActivity.java" ]
@@ -1271,25 +1277,23 @@ copy("cronet_package_copy") {
action("cronet_combine_proguard_flags") {
script = "//components/cronet/tools/generate_proguard_file.py"
+ sources = [
+ "//base/android/proguard/chromium_code.flags",
+ "//components/cronet/android/cronet_impl_native_proguard.cfg",
+ ]
outputs = [
"$target_gen_dir/cronet_impl_native_proguard.cfg",
]
- args = [
- "--output-file",
- rebase_path("$target_gen_dir/cronet_impl_native_proguard.cfg",
- root_build_dir),
- rebase_path("//components/cronet/android/cronet_impl_native_proguard.cfg",
- root_build_dir),
- rebase_path("//base/android/proguard/chromium_code.flags", root_build_dir),
- ]
+ args = [ "--output-file" ] + rebase_path(outputs, root_build_dir) +
+ rebase_path(sources, root_build_dir)
}
copy("cronet_package_copy_native_lib") {
sources = [
- "$root_out_dir/libcronet.so",
+ "$root_out_dir/" + _cronet_shared_lib_file_name,
]
outputs = [
- "$_package_dir/libs/${android_app_abi}/libcronet.so",
+ "$_package_dir/libs/${android_app_abi}/" + _cronet_shared_lib_file_name,
]
deps = [
":cronet",
@@ -1298,10 +1302,10 @@ copy("cronet_package_copy_native_lib") {
copy("cronet_package_copy_native_lib_unstripped") {
sources = [
- "$root_out_dir/lib.unstripped/libcronet.so",
+ "$root_out_dir/lib.unstripped/" + _cronet_shared_lib_file_name,
]
outputs = [
- "$_package_dir/symbols/${android_app_abi}/libcronet.so",
+ "$_package_dir/symbols/${android_app_abi}/" + _cronet_shared_lib_file_name,
]
deps = [
":cronet",
diff --git a/chromium/components/cronet/ios/BUILD.gn b/chromium/components/cronet/ios/BUILD.gn
index e455f652bc5..ac1dfe06202 100644
--- a/chromium/components/cronet/ios/BUILD.gn
+++ b/chromium/components/cronet/ios/BUILD.gn
@@ -33,6 +33,7 @@ process_version("cronet_version_header") {
source_set("cronet_sources") {
deps = [
":cronet_version_header",
+ ":generate_accept_languages",
"//base:base",
"//components/grpc_support",
"//components/metrics:metrics",
@@ -70,77 +71,11 @@ tweak_info_plist("tweak_cronet_plist") {
info_plist = "Info.plist"
}
-bundle_data("cronet_framework_resources") {
- # This bundle contains "Accept-Languages" header values for known locales.
- # TODO(mef): These strings should be auto-generated from chrome's .xtb
- # files, not hardcoded.
- sources = [
- "Resources/Localization/am.lproj",
- "Resources/Localization/ar.lproj",
- "Resources/Localization/bg.lproj",
- "Resources/Localization/bn.lproj",
- "Resources/Localization/ca.lproj",
- "Resources/Localization/cs.lproj",
- "Resources/Localization/da.lproj",
- "Resources/Localization/de.lproj",
- "Resources/Localization/el.lproj",
- "Resources/Localization/en-GB.lproj",
- "Resources/Localization/en.lproj",
- "Resources/Localization/es-419.lproj",
- "Resources/Localization/es.lproj",
- "Resources/Localization/fa.lproj",
- "Resources/Localization/fi.lproj",
- "Resources/Localization/fil.lproj",
- "Resources/Localization/fr.lproj",
- "Resources/Localization/gu.lproj",
- "Resources/Localization/he.lproj",
- "Resources/Localization/hi.lproj",
- "Resources/Localization/hr.lproj",
- "Resources/Localization/hu.lproj",
- "Resources/Localization/id.lproj",
- "Resources/Localization/it.lproj",
- "Resources/Localization/ja.lproj",
- "Resources/Localization/kn.lproj",
- "Resources/Localization/ko.lproj",
- "Resources/Localization/lt.lproj",
- "Resources/Localization/lv.lproj",
- "Resources/Localization/ml.lproj",
- "Resources/Localization/mr.lproj",
- "Resources/Localization/ms.lproj",
- "Resources/Localization/nb.lproj",
- "Resources/Localization/nl.lproj",
- "Resources/Localization/pl.lproj",
- "Resources/Localization/pt-BR.lproj",
- "Resources/Localization/pt-PT.lproj",
- "Resources/Localization/pt.lproj",
- "Resources/Localization/ro.lproj",
- "Resources/Localization/ru.lproj",
- "Resources/Localization/sk.lproj",
- "Resources/Localization/sl.lproj",
- "Resources/Localization/sr.lproj",
- "Resources/Localization/sv.lproj",
- "Resources/Localization/sw.lproj",
- "Resources/Localization/ta.lproj",
- "Resources/Localization/te.lproj",
- "Resources/Localization/th.lproj",
- "Resources/Localization/tr.lproj",
- "Resources/Localization/uk.lproj",
- "Resources/Localization/vi.lproj",
- "Resources/Localization/zh-Hans.lproj",
- "Resources/Localization/zh-Hant.lproj",
- "Resources/Localization/zh.lproj",
- ]
- outputs = [
- "{{bundle_resources_dir}}/cronet_resources.bundle/{{source_file_part}}",
- ]
-}
-
ios_framework_bundle("cronet_framework") {
output_name = "Cronet"
info_plist_target = ":tweak_cronet_plist"
deps = [
- ":cronet_framework_resources",
":cronet_sources",
"//base",
"//net:net",
@@ -189,6 +124,17 @@ test("cronet_unittests") {
]
}
+action("generate_accept_languages") {
+ script = "//components/cronet/tools/generate_accept_languages.py"
+ args = [
+ rebase_path("$target_gen_dir"),
+ rebase_path("//"),
+ ]
+ outputs = [
+ "$target_gen_dir/accept_languages_table.h",
+ ]
+}
+
if (additional_toolchains == [] || current_toolchain == default_toolchain) {
_package_dir = "$root_out_dir/cronet"
diff --git a/chromium/components/cronet/ios/test/BUILD.gn b/chromium/components/cronet/ios/test/BUILD.gn
index db793b56b22..fc515a566eb 100644
--- a/chromium/components/cronet/ios/test/BUILD.gn
+++ b/chromium/components/cronet/ios/test/BUILD.gn
@@ -8,6 +8,7 @@ import("//testing/test.gni")
test("cronet_test") {
testonly = true
sources = [
+ "cronet_acceptlang_test.mm",
"cronet_http_test.mm",
"cronet_netlog_test.mm",
"cronet_test_runner.mm",
diff --git a/chromium/components/crx_file/crx_file.cc b/chromium/components/crx_file/crx_file.cc
index 2445ef1e662..c2b05f8e80b 100644
--- a/chromium/components/crx_file/crx_file.cc
+++ b/chromium/components/crx_file/crx_file.cc
@@ -160,8 +160,8 @@ CrxFile::ValidateError CrxFile::ValidateSignature(
crypto::SignatureVerifier verifier;
if (!verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1,
- signature.data(), static_cast<int>(signature.size()),
- key.data(), static_cast<int>(key.size()))) {
+ signature.data(), signature.size(), key.data(),
+ key.size())) {
// Signature verification initialization failed. This is most likely
// caused by a public key in the wrong format (should encode algorithm).
return ValidateError::CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED;
@@ -170,7 +170,7 @@ CrxFile::ValidateError CrxFile::ValidateSignature(
uint8_t buf[1 << 12] = {};
while ((len = ReadAndHash(buf, sizeof(buf[0]), arraysize(buf), file.get(),
hash.get())) > 0)
- verifier.VerifyUpdate(buf, static_cast<int>(len));
+ verifier.VerifyUpdate(buf, len);
if (!verifier.VerifyFinal())
return ValidateError::CRX_SIGNATURE_VERIFICATION_FAILED;
diff --git a/chromium/components/crx_file/id_util.cc b/chromium/components/crx_file/id_util.cc
index 99a24560683..85584f3ad17 100644
--- a/chromium/components/crx_file/id_util.cc
+++ b/chromium/components/crx_file/id_util.cc
@@ -42,10 +42,12 @@ const size_t kIdSize = 16;
std::string GenerateId(const std::string& input) {
uint8_t hash[kIdSize];
crypto::SHA256HashString(input, hash, sizeof(hash));
- std::string output =
- base::ToLowerASCII(base::HexEncode(hash, sizeof(hash)));
- ConvertHexadecimalToIDAlphabet(&output);
+ return GenerateIdFromHex(base::HexEncode(hash, sizeof(hash)));
+}
+std::string GenerateIdFromHex(const std::string& input) {
+ std::string output = base::ToLowerASCII(input);
+ ConvertHexadecimalToIDAlphabet(&output);
return output;
}
diff --git a/chromium/components/crx_file/id_util.h b/chromium/components/crx_file/id_util.h
index 5c73587e733..67267519c4e 100644
--- a/chromium/components/crx_file/id_util.h
+++ b/chromium/components/crx_file/id_util.h
@@ -23,6 +23,10 @@ extern const size_t kIdSize;
// always generate the same output ID.
std::string GenerateId(const std::string& input);
+// Generates an ID from a HEX string. The same input string will always generate
+// the same output ID.
+std::string GenerateIdFromHex(const std::string& input);
+
// Generates an ID for an extension in the given path.
// Used while developing extensions, before they have a key.
std::string GenerateIdForPath(const base::FilePath& path);
diff --git a/chromium/components/crx_file/id_util_unittest.cc b/chromium/components/crx_file/id_util_unittest.cc
index c198701868d..3cb19c7f63f 100644
--- a/chromium/components/crx_file/id_util_unittest.cc
+++ b/chromium/components/crx_file/id_util_unittest.cc
@@ -37,6 +37,13 @@ TEST(IDUtilTest, GenerateID) {
EXPECT_EQ("ncocknphbhhlhkikpnnlmbcnbgdempcd", GenerateId("_"));
+ EXPECT_EQ("a", GenerateIdFromHex("_"));
+
+ EXPECT_EQ(
+ "bjbdkfoakgmkndalgpadobhgbhhoanhongcmfnghaakjmggnkffgnhmdpfngkeho",
+ GenerateIdFromHex(
+ "1913a5e0a6cad30b6f03e176177e0d7ed62c5d6700a9c66da556d7c3f5d6a47e"));
+
EXPECT_EQ(
"jimneklojkjdibfkgiiophfhjhbdgcfi",
GenerateId("this_string_is_longer_than_a_single_sha256_hash_digest"));
diff --git a/chromium/components/cryptauth/BUILD.gn b/chromium/components/cryptauth/BUILD.gn
index 01954c46c65..103beaa64e8 100644
--- a/chromium/components/cryptauth/BUILD.gn
+++ b/chromium/components/cryptauth/BUILD.gn
@@ -36,6 +36,8 @@ static_library("cryptauth") {
"cryptauth_gcm_manager.h",
"cryptauth_gcm_manager_impl.cc",
"cryptauth_gcm_manager_impl.h",
+ "cryptauth_service.cc",
+ "cryptauth_service.h",
"device_to_device_authenticator.cc",
"device_to_device_authenticator.h",
"device_to_device_initiator_operations.cc",
@@ -101,6 +103,8 @@ static_library("test_support") {
"fake_connection.h",
"fake_cryptauth_gcm_manager.cc",
"fake_cryptauth_gcm_manager.h",
+ "fake_cryptauth_service.cc",
+ "fake_cryptauth_service.h",
"fake_secure_channel.cc",
"fake_secure_channel.h",
"fake_secure_context.cc",
diff --git a/chromium/components/cryptauth/OWNERS b/chromium/components/cryptauth/OWNERS
index b330adf2413..238e06011df 100644
--- a/chromium/components/cryptauth/OWNERS
+++ b/chromium/components/cryptauth/OWNERS
@@ -3,3 +3,5 @@ tengs@chromium.org
xiyuan@chromium.org
khorimoto@chromium.org
hansberry@chromium.org
+
+# COMPONENT: UI>ProximityAuth
diff --git a/chromium/components/cryptauth/ble/OWNERS b/chromium/components/cryptauth/ble/OWNERS
index 067b4517ba4..5694d5144b0 100644
--- a/chromium/components/cryptauth/ble/OWNERS
+++ b/chromium/components/cryptauth/ble/OWNERS
@@ -3,3 +3,5 @@ sacomoto@chromium.org
tengs@chromium.org
khorimoto@chromium.org
hansberry@chromium.org
+
+# COMPONENT: UI>ProximityAuth
diff --git a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc
index 8afc502b91d..42351b9e6a6 100644
--- a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc
+++ b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc
@@ -508,7 +508,7 @@ void BluetoothLowEnergyWeaveClientConnection::OnRemoteCharacteristicWritten() {
break;
case WriteRequestType::CONNECTION_CLOSE:
DestroyConnection();
- break;
+ return;
default:
NOTREACHED();
}
diff --git a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h
index ec8dfac0ee2..c77c894ab53 100644
--- a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h
+++ b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h
@@ -112,6 +112,9 @@ class BluetoothLowEnergyWeaveClientConnection
protected:
// Exposed for testing.
+ // NOTE: This method may indirectly cause this object's destructor to be
+ // called. Do not perform any operations that touch the internals of this
+ // class after calling this method.
void DestroyConnection();
// Exposed for testing.
diff --git a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
index a2f1ead19d8..cf84e960bc2 100644
--- a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
+++ b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
@@ -66,11 +66,15 @@ class MockBluetoothLowEnergyCharacteristicsFinder
class MockConnectionObserver : public ConnectionObserver {
public:
- MockConnectionObserver() : num_send_completed_(0) {}
+ MockConnectionObserver()
+ : num_send_completed_(0), delete_on_disconnect_(false) {}
void OnConnectionStatusChanged(Connection* connection,
Connection::Status old_status,
- Connection::Status new_status) override {}
+ Connection::Status new_status) override {
+ if (new_status == Connection::Status::DISCONNECTED && delete_on_disconnect_)
+ delete connection;
+ }
void OnMessageReceived(const Connection& connection,
const WireMessage& message) override {}
@@ -91,10 +95,16 @@ class MockConnectionObserver : public ConnectionObserver {
int GetNumSendCompleted() { return num_send_completed_; }
+ bool delete_on_disconnect() { return delete_on_disconnect_; }
+ void set_delete_on_disconnect(bool delete_on_disconnect) {
+ delete_on_disconnect_ = delete_on_disconnect;
+ }
+
private:
std::string last_deserialized_message_;
bool last_send_success_;
int num_send_completed_;
+ bool delete_on_disconnect_;
};
} // namespace
@@ -735,7 +745,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
NotifySessionStarted(connection.get());
// |connection| will call WriteRemoteCharacteristics(_,_) to try to send the
- // message |kMaxNumberOfTries| times. There is alredy one EXPECTA_CALL for
+ // message |kMaxNumberOfTries| times. There is alredy one EXPECT_CALL for
// WriteRemoteCharacteristic(_,_,_) in NotifySessionStated, that's why we use
// |kMaxNumberOfTries-1| in the EXPECT_CALL statement.
EXPECT_EQ(0, connection_observer_.GetNumSendCompleted());
@@ -980,6 +990,36 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
}
+// Test for fix to crbug.com/708744. Without the fix, this test will crash.
+TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ReceiverErrorAndConnectionDeletedTest) {
+ connection_observer_.set_delete_on_disconnect(true);
+
+ TestBluetoothLowEnergyWeaveClientConnection* connection =
+ CreateConnection().release();
+
+ InitializeConnection(connection, kDefaultMaxPacketSize);
+
+ EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
+ .WillOnce(
+ DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
+ SaveArg<1>(&write_remote_characteristic_success_callback_),
+ SaveArg<2>(&write_remote_characteristic_error_callback_)));
+
+ connection->GattCharacteristicValueChanged(
+ adapter_.get(), rx_characteristic_.get(), kErroneousPacket);
+
+ EXPECT_EQ(last_value_written_on_tx_characteristic_,
+ kConnectionCloseApplicationError);
+ EXPECT_EQ(receiver_factory_->GetMostRecentInstance()->GetReasonToClose(),
+ ReasonForClose::APPLICATION_ERROR);
+
+ RunWriteCharacteristicSuccessCallback();
+
+ // We cannot check if connection's status and sub_status are DISCONNECTED
+ // because it has been deleted.
+}
+
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
WriteConnectionCloseMaxNumberOfTimes) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
diff --git a/chromium/components/cryptauth/bluetooth_throttler_impl.cc b/chromium/components/cryptauth/bluetooth_throttler_impl.cc
index d72337ef593..239528a8632 100644
--- a/chromium/components/cryptauth/bluetooth_throttler_impl.cc
+++ b/chromium/components/cryptauth/bluetooth_throttler_impl.cc
@@ -6,7 +6,9 @@
#include <utility>
+#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
+#include "base/time/default_tick_clock.h"
#include "base/time/tick_clock.h"
#include "components/cryptauth/connection.h"
@@ -18,6 +20,14 @@ const int kCooldownTimeSecs = 7;
} // namespace
+// static
+BluetoothThrottlerImpl* BluetoothThrottlerImpl::GetInstance() {
+ return base::Singleton<BluetoothThrottlerImpl>::get();
+}
+
+BluetoothThrottlerImpl::BluetoothThrottlerImpl()
+ : BluetoothThrottlerImpl(base::MakeUnique<base::DefaultTickClock>()) {}
+
BluetoothThrottlerImpl::BluetoothThrottlerImpl(
std::unique_ptr<base::TickClock> clock)
: clock_(std::move(clock)) {}
diff --git a/chromium/components/cryptauth/bluetooth_throttler_impl.h b/chromium/components/cryptauth/bluetooth_throttler_impl.h
index 2933f168119..7a9fef028f0 100644
--- a/chromium/components/cryptauth/bluetooth_throttler_impl.h
+++ b/chromium/components/cryptauth/bluetooth_throttler_impl.h
@@ -9,6 +9,7 @@
#include <set>
#include "base/macros.h"
+#include "base/memory/singleton.h"
#include "base/time/time.h"
#include "components/cryptauth/bluetooth_throttler.h"
#include "components/cryptauth/connection_observer.h"
@@ -28,9 +29,7 @@ class Connection;
class BluetoothThrottlerImpl : public BluetoothThrottler,
public ConnectionObserver {
public:
- // Creates a throttler for connections to a remote device, using the |clock|
- // as a time source.
- explicit BluetoothThrottlerImpl(std::unique_ptr<base::TickClock> clock);
+ static BluetoothThrottlerImpl* GetInstance();
~BluetoothThrottlerImpl() override;
// BluetoothThrottler:
@@ -38,11 +37,19 @@ class BluetoothThrottlerImpl : public BluetoothThrottler,
void OnConnection(Connection* connection) override;
protected:
+ // Creates a throttler for connections to a remote device, using the |clock|
+ // as a time source.
+ explicit BluetoothThrottlerImpl(std::unique_ptr<base::TickClock> clock);
+
// Returns the duration to wait, after disconnecting, before reattempting a
// connection to the remote device. Exposed for testing.
base::TimeDelta GetCooldownTimeDelta() const;
private:
+ friend struct base::DefaultSingletonTraits<BluetoothThrottlerImpl>;
+
+ BluetoothThrottlerImpl();
+
// ConnectionObserver:
void OnConnectionStatusChanged(Connection* connection,
Connection::Status old_status,
diff --git a/chromium/components/cryptauth/cryptauth_device_manager_unittest.cc b/chromium/components/cryptauth/cryptauth_device_manager_unittest.cc
index 6c6af53928a..7dcd284349e 100644
--- a/chromium/components/cryptauth/cryptauth_device_manager_unittest.cc
+++ b/chromium/components/cryptauth/cryptauth_device_manager_unittest.cc
@@ -383,11 +383,13 @@ class CryptAuthDeviceManagerTest
CryptAuthDeviceManager::RegisterPrefs(pref_service_.registry());
pref_service_.SetUserPref(
prefs::kCryptAuthDeviceSyncIsRecoveringFromFailure,
- new base::Value(false));
- pref_service_.SetUserPref(prefs::kCryptAuthDeviceSyncLastSyncTimeSeconds,
- new base::Value(kLastSyncTimeSeconds));
- pref_service_.SetUserPref(prefs::kCryptAuthDeviceSyncReason,
- new base::Value(INVOCATION_REASON_UNKNOWN));
+ base::MakeUnique<base::Value>(false));
+ pref_service_.SetUserPref(
+ prefs::kCryptAuthDeviceSyncLastSyncTimeSeconds,
+ base::MakeUnique<base::Value>(kLastSyncTimeSeconds));
+ pref_service_.SetUserPref(
+ prefs::kCryptAuthDeviceSyncReason,
+ base::MakeUnique<base::Value>(INVOCATION_REASON_UNKNOWN));
std::unique_ptr<base::DictionaryValue> device_dictionary(
new base::DictionaryValue());
diff --git a/chromium/components/cryptauth/cryptauth_enrollment_manager.h b/chromium/components/cryptauth/cryptauth_enrollment_manager.h
index e621b9f5b4e..ce4c9da774d 100644
--- a/chromium/components/cryptauth/cryptauth_enrollment_manager.h
+++ b/chromium/components/cryptauth/cryptauth_enrollment_manager.h
@@ -112,8 +112,8 @@ class CryptAuthEnrollmentManager : public SyncScheduler::Delegate,
// been completed, then an empty string will be returned.
// Note: These keys are really serialized protocol buffer messages, and should
// only be used by passing to SecureMessageDelegate.
- std::string GetUserPublicKey() const;
- std::string GetUserPrivateKey() const;
+ virtual std::string GetUserPublicKey() const;
+ virtual std::string GetUserPrivateKey() const;
protected:
// Creates a new SyncScheduler instance. Exposed for testing.
diff --git a/chromium/components/cryptauth/cryptauth_enrollment_manager_unittest.cc b/chromium/components/cryptauth/cryptauth_enrollment_manager_unittest.cc
index ccb12c18f6f..7a98f86d8e4 100644
--- a/chromium/components/cryptauth/cryptauth_enrollment_manager_unittest.cc
+++ b/chromium/components/cryptauth/cryptauth_enrollment_manager_unittest.cc
@@ -170,12 +170,13 @@ class CryptAuthEnrollmentManagerTest
CryptAuthEnrollmentManager::RegisterPrefs(pref_service_.registry());
pref_service_.SetUserPref(
prefs::kCryptAuthEnrollmentIsRecoveringFromFailure,
- new base::Value(false));
+ base::MakeUnique<base::Value>(false));
pref_service_.SetUserPref(
prefs::kCryptAuthEnrollmentLastEnrollmentTimeSeconds,
- new base::Value(kLastEnrollmentTimeSeconds));
- pref_service_.SetUserPref(prefs::kCryptAuthEnrollmentReason,
- new base::Value(INVOCATION_REASON_UNKNOWN));
+ base::MakeUnique<base::Value>(kLastEnrollmentTimeSeconds));
+ pref_service_.SetUserPref(
+ prefs::kCryptAuthEnrollmentReason,
+ base::MakeUnique<base::Value>(INVOCATION_REASON_UNKNOWN));
std::string public_key_b64, private_key_b64;
base::Base64UrlEncode(public_key_,
@@ -335,7 +336,7 @@ TEST_F(CryptAuthEnrollmentManagerTest, InitWithExistingPrefs) {
TEST_F(CryptAuthEnrollmentManagerTest, InitWithExpiredEnrollment) {
pref_service_.SetUserPref(
prefs::kCryptAuthEnrollmentLastEnrollmentTimeSeconds,
- new base::Value(kLastExpiredEnrollmentTimeSeconds));
+ base::MakeUnique<base::Value>(kLastExpiredEnrollmentTimeSeconds));
EXPECT_CALL(*sync_scheduler(),
Start(clock_->Now() - base::Time::FromDoubleT(
diff --git a/chromium/components/cryptauth/cryptauth_service.cc b/chromium/components/cryptauth/cryptauth_service.cc
new file mode 100644
index 00000000000..806516b4668
--- /dev/null
+++ b/chromium/components/cryptauth/cryptauth_service.cc
@@ -0,0 +1,20 @@
+// 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/cryptauth/cryptauth_service.h"
+
+#include "components/cryptauth/cryptauth_device_manager.h"
+#include "components/cryptauth/cryptauth_enrollment_manager.h"
+#include "components/cryptauth/cryptauth_gcm_manager.h"
+
+namespace cryptauth {
+
+// static
+void CryptAuthService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
+ CryptAuthGCMManager::RegisterPrefs(registry);
+ CryptAuthDeviceManager::RegisterPrefs(registry);
+ CryptAuthEnrollmentManager::RegisterPrefs(registry);
+}
+
+} // namespace cryptauth
diff --git a/chromium/components/cryptauth/cryptauth_service.h b/chromium/components/cryptauth/cryptauth_service.h
new file mode 100644
index 00000000000..ebfc41549db
--- /dev/null
+++ b/chromium/components/cryptauth/cryptauth_service.h
@@ -0,0 +1,45 @@
+// 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_CRYPTAUTH_CRYPTAUTH_SERVICE_H_
+#define COMPONENTS_CRYPTAUTH_CRYPTAUTH_SERVICE_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "components/cryptauth/proto/cryptauth_api.pb.h"
+#include "components/prefs/pref_registry_simple.h"
+
+namespace cryptauth {
+
+class CryptAuthClientFactory;
+class CryptAuthDeviceManager;
+class CryptAuthEnrollmentManager;
+class SecureMessageDelegate;
+
+// Service which provides access to various CryptAuth singletons.
+class CryptAuthService {
+ public:
+ static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ virtual CryptAuthDeviceManager* GetCryptAuthDeviceManager() = 0;
+ virtual CryptAuthEnrollmentManager* GetCryptAuthEnrollmentManager() = 0;
+ virtual DeviceClassifier GetDeviceClassifier() = 0;
+ virtual std::string GetAccountId() = 0;
+ virtual std::unique_ptr<SecureMessageDelegate>
+ CreateSecureMessageDelegate() = 0;
+ virtual std::unique_ptr<CryptAuthClientFactory>
+ CreateCryptAuthClientFactory() = 0;
+
+ protected:
+ CryptAuthService() {}
+ virtual ~CryptAuthService() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CryptAuthService);
+};
+
+} // namespace cryptauth
+
+#endif // COMPONENTS_CRYPTAUTH_CRYPTAUTH_SERVICE_H_
diff --git a/chromium/components/cryptauth/fake_cryptauth_service.cc b/chromium/components/cryptauth/fake_cryptauth_service.cc
new file mode 100644
index 00000000000..93b9113cc42
--- /dev/null
+++ b/chromium/components/cryptauth/fake_cryptauth_service.cc
@@ -0,0 +1,46 @@
+// 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/cryptauth/fake_cryptauth_service.h"
+
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "components/cryptauth/fake_secure_message_delegate.h"
+#include "components/cryptauth/mock_cryptauth_client.h"
+
+namespace cryptauth {
+
+FakeCryptAuthService::FakeCryptAuthService() {}
+
+FakeCryptAuthService::~FakeCryptAuthService() {}
+
+CryptAuthDeviceManager* FakeCryptAuthService::GetCryptAuthDeviceManager() {
+ return cryptauth_device_manager_;
+}
+
+CryptAuthEnrollmentManager*
+FakeCryptAuthService::GetCryptAuthEnrollmentManager() {
+ return cryptauth_enrollment_manager_;
+}
+
+DeviceClassifier FakeCryptAuthService::GetDeviceClassifier() {
+ return device_classifier_;
+}
+
+std::string FakeCryptAuthService::GetAccountId() {
+ return account_id_;
+}
+
+std::unique_ptr<SecureMessageDelegate>
+FakeCryptAuthService::CreateSecureMessageDelegate() {
+ return base::MakeUnique<FakeSecureMessageDelegate>();
+}
+
+std::unique_ptr<CryptAuthClientFactory>
+FakeCryptAuthService::CreateCryptAuthClientFactory() {
+ return base::MakeUnique<MockCryptAuthClientFactory>(
+ MockCryptAuthClientFactory::MockType::MAKE_NICE_MOCKS);
+}
+
+} // namespace cryptauth
diff --git a/chromium/components/cryptauth/fake_cryptauth_service.h b/chromium/components/cryptauth/fake_cryptauth_service.h
new file mode 100644
index 00000000000..ba5ac1777f9
--- /dev/null
+++ b/chromium/components/cryptauth/fake_cryptauth_service.h
@@ -0,0 +1,65 @@
+// 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_CRYPTAUTH_FAKE_CRYPTAUTH_SERVICE_H_
+#define COMPONENTS_CRYPTAUTH_FAKE_CRYPTAUTH_SERVICE_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "components/cryptauth/cryptauth_service.h"
+#include "components/cryptauth/proto/cryptauth_api.pb.h"
+
+namespace cryptauth {
+
+class CryptAuthClientFactory;
+class CryptAuthDeviceManager;
+class CryptAuthEnrollmentManager;
+class SecureMessageDelegate;
+
+// Service which provides access to various CryptAuth singletons.
+class FakeCryptAuthService : public CryptAuthService {
+ public:
+ FakeCryptAuthService();
+ ~FakeCryptAuthService() override;
+
+ void set_cryptauth_device_manager(
+ CryptAuthDeviceManager* cryptauth_device_manager) {
+ cryptauth_device_manager_ = cryptauth_device_manager;
+ }
+
+ void set_cryptauth_enrollment_manager(
+ CryptAuthEnrollmentManager* cryptauth_enrollment_manager) {
+ cryptauth_enrollment_manager_ = cryptauth_enrollment_manager;
+ }
+
+ void set_device_classifier(const DeviceClassifier& device_classifier) {
+ device_classifier_ = device_classifier;
+ }
+
+ void set_account_id(const std::string& account_id) {
+ account_id_ = account_id;
+ }
+
+ // CryptAuthService:
+ CryptAuthDeviceManager* GetCryptAuthDeviceManager() override;
+ CryptAuthEnrollmentManager* GetCryptAuthEnrollmentManager() override;
+ DeviceClassifier GetDeviceClassifier() override;
+ std::string GetAccountId() override;
+ std::unique_ptr<SecureMessageDelegate> CreateSecureMessageDelegate() override;
+ std::unique_ptr<CryptAuthClientFactory> CreateCryptAuthClientFactory()
+ override;
+
+ private:
+ CryptAuthDeviceManager* cryptauth_device_manager_;
+ CryptAuthEnrollmentManager* cryptauth_enrollment_manager_;
+ DeviceClassifier device_classifier_;
+ std::string account_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeCryptAuthService);
+};
+
+} // namespace cryptauth
+
+#endif // COMPONENTS_CRYPTAUTH_FAKE_CRYPTAUTH_SERVICE_H_
diff --git a/chromium/components/cryptauth/fake_secure_channel.cc b/chromium/components/cryptauth/fake_secure_channel.cc
index e06a0d4dd44..03956aadc48 100644
--- a/chromium/components/cryptauth/fake_secure_channel.cc
+++ b/chromium/components/cryptauth/fake_secure_channel.cc
@@ -13,8 +13,8 @@ FakeSecureChannel::SentMessage::SentMessage(const std::string& feature,
: feature(feature), payload(payload) {}
FakeSecureChannel::FakeSecureChannel(std::unique_ptr<Connection> connection,
- std::unique_ptr<Delegate> delegate)
- : SecureChannel(std::move(connection), std::move(delegate)) {}
+ CryptAuthService* cryptauth_service)
+ : SecureChannel(std::move(connection), cryptauth_service) {}
FakeSecureChannel::~FakeSecureChannel() {}
diff --git a/chromium/components/cryptauth/fake_secure_channel.h b/chromium/components/cryptauth/fake_secure_channel.h
index e086801b957..4a202d9a771 100644
--- a/chromium/components/cryptauth/fake_secure_channel.h
+++ b/chromium/components/cryptauth/fake_secure_channel.h
@@ -10,11 +10,13 @@
namespace cryptauth {
+class CryptAuthService;
+
// A fake implementation of SecureChannel to use in tests.
class FakeSecureChannel : public SecureChannel {
public:
FakeSecureChannel(std::unique_ptr<Connection> connection,
- std::unique_ptr<Delegate> delegate);
+ CryptAuthService* cryptauth_service);
~FakeSecureChannel() override;
struct SentMessage {
diff --git a/chromium/components/cryptauth/secure_channel.cc b/chromium/components/cryptauth/secure_channel.cc
index a51b5c8e587..9048f4d4f8b 100644
--- a/chromium/components/cryptauth/secure_channel.cc
+++ b/chromium/components/cryptauth/secure_channel.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
+#include "components/cryptauth/cryptauth_service.h"
#include "components/cryptauth/wire_message.h"
#include "components/proximity_auth/logging/logging.h"
@@ -17,12 +18,12 @@ SecureChannel::Factory* SecureChannel::Factory::factory_instance_ = nullptr;
// static
std::unique_ptr<SecureChannel> SecureChannel::Factory::NewInstance(
std::unique_ptr<Connection> connection,
- std::unique_ptr<Delegate> delegate) {
+ CryptAuthService* cryptauth_service) {
if (!factory_instance_) {
factory_instance_ = new Factory();
}
return factory_instance_->BuildInstance(std::move(connection),
- std::move(delegate));
+ cryptauth_service);
}
// static
@@ -32,9 +33,9 @@ void SecureChannel::Factory::SetInstanceForTesting(Factory* factory) {
std::unique_ptr<SecureChannel> SecureChannel::Factory::BuildInstance(
std::unique_ptr<Connection> connection,
- std::unique_ptr<Delegate> delegate) {
+ CryptAuthService* cryptauth_service) {
return base::WrapUnique(
- new SecureChannel(std::move(connection), std::move(delegate)));
+ new SecureChannel(std::move(connection), cryptauth_service));
}
// static
@@ -55,8 +56,6 @@ std::string SecureChannel::StatusToString(const Status& status) {
}
}
-SecureChannel::Delegate::~Delegate() {}
-
SecureChannel::PendingMessage::PendingMessage() {}
SecureChannel::PendingMessage::PendingMessage(
@@ -66,15 +65,15 @@ SecureChannel::PendingMessage::PendingMessage(
SecureChannel::PendingMessage::~PendingMessage() {}
SecureChannel::SecureChannel(std::unique_ptr<Connection> connection,
- std::unique_ptr<Delegate> delegate)
+ CryptAuthService* cryptauth_service)
: status_(Status::DISCONNECTED),
connection_(std::move(connection)),
- delegate_(std::move(delegate)),
+ cryptauth_service_(cryptauth_service),
weak_ptr_factory_(this) {
DCHECK(connection_);
DCHECK(!connection_->IsConnected());
DCHECK(!connection_->remote_device().user_id.empty());
- DCHECK(delegate_);
+ DCHECK(cryptauth_service);
connection_->AddObserver(this);
}
@@ -201,9 +200,8 @@ void SecureChannel::Authenticate() {
DCHECK(!authenticator_);
authenticator_ = DeviceToDeviceAuthenticator::Factory::NewInstance(
- connection_.get(),
- connection_->remote_device().user_id,
- delegate_->CreateSecureMessageDelegate());
+ connection_.get(), connection_->remote_device().user_id,
+ cryptauth_service_->CreateSecureMessageDelegate());
authenticator_->Authenticate(
base::Bind(&SecureChannel::OnAuthenticationResult,
weak_ptr_factory_.GetWeakPtr()));
diff --git a/chromium/components/cryptauth/secure_channel.h b/chromium/components/cryptauth/secure_channel.h
index 3732f242ed6..e0d83b2f853 100644
--- a/chromium/components/cryptauth/secure_channel.h
+++ b/chromium/components/cryptauth/secure_channel.h
@@ -19,6 +19,8 @@
namespace cryptauth {
+class CryptAuthService;
+
// An authenticated bi-directional channel for exchanging messages with remote
// devices. |SecureChannel| manages a |Connection| by initializing it and
// authenticating it via a security handshake once the connection has occurred.
@@ -59,26 +61,18 @@ class SecureChannel : public ConnectionObserver {
const std::string& payload) = 0;
};
- class Delegate {
- public:
- virtual ~Delegate();
-
- virtual std::unique_ptr<SecureMessageDelegate>
- CreateSecureMessageDelegate() = 0;
- };
-
class Factory {
public:
static std::unique_ptr<SecureChannel> NewInstance(
std::unique_ptr<Connection> connection,
- std::unique_ptr<Delegate> delegate);
+ CryptAuthService* cryptauth_service);
static void SetInstanceForTesting(Factory* factory);
protected:
virtual std::unique_ptr<SecureChannel> BuildInstance(
std::unique_ptr<Connection> connection,
- std::unique_ptr<Delegate> delegate);
+ CryptAuthService* cryptauth_service);
private:
static Factory* factory_instance_;
@@ -112,7 +106,7 @@ class SecureChannel : public ConnectionObserver {
protected:
SecureChannel(std::unique_ptr<Connection> connection,
- std::unique_ptr<Delegate> delegate);
+ CryptAuthService* cryptauth_service);
Status status_;
@@ -141,7 +135,7 @@ class SecureChannel : public ConnectionObserver {
std::unique_ptr<SecureContext> secure_context);
std::unique_ptr<Connection> connection_;
- std::unique_ptr<Delegate> delegate_;
+ CryptAuthService* cryptauth_service_; // Outlives this instance.
std::unique_ptr<Authenticator> authenticator_;
std::unique_ptr<SecureContext> secure_context_;
std::deque<PendingMessage> queued_messages_;
diff --git a/chromium/components/cryptauth/secure_channel_unittest.cc b/chromium/components/cryptauth/secure_channel_unittest.cc
index 3e7968cdb6e..f894110238c 100644
--- a/chromium/components/cryptauth/secure_channel_unittest.cc
+++ b/chromium/components/cryptauth/secure_channel_unittest.cc
@@ -11,6 +11,7 @@
#include "base/memory/weak_ptr.h"
#include "components/cryptauth/fake_authenticator.h"
#include "components/cryptauth/fake_connection.h"
+#include "components/cryptauth/fake_cryptauth_service.h"
#include "components/cryptauth/fake_secure_context.h"
#include "components/cryptauth/fake_secure_message_delegate.h"
#include "components/cryptauth/remote_device_test_util.h"
@@ -23,21 +24,6 @@ namespace {
const std::string test_user_id = "testUserId";
-class TestDelegate : public SecureChannel::Delegate {
- public:
- TestDelegate(std::unique_ptr<SecureMessageDelegate> secure_message_delegate)
- : secure_message_delegate_(std::move(secure_message_delegate)) {}
- ~TestDelegate() override {}
-
- std::unique_ptr<SecureMessageDelegate> CreateSecureMessageDelegate()
- override {
- return std::move(secure_message_delegate_);
- }
-
- private:
- std::unique_ptr<SecureMessageDelegate> secure_message_delegate_;
-};
-
struct SecureChannelStatusChange {
SecureChannelStatusChange(
const SecureChannel::Status& old_status,
@@ -122,8 +108,8 @@ RemoteDevice CreateTestRemoteDevice() {
class TestSecureChannel : public SecureChannel {
public:
TestSecureChannel(std::unique_ptr<Connection> connection,
- std::unique_ptr<Delegate> delegate)
- : SecureChannel(std::move(connection), std::move(delegate)) {}
+ CryptAuthService* cryptauth_service)
+ : SecureChannel(std::move(connection), cryptauth_service) {}
};
} // namespace
@@ -141,17 +127,14 @@ class CryptAuthSecureChannelTest : public testing::Test {
fake_secure_context_ = nullptr;
- fake_secure_message_delegate_ = new FakeSecureMessageDelegate();
-
- test_delegate_ =
- new TestDelegate(base::WrapUnique(fake_secure_message_delegate_));
+ fake_cryptauth_service_ = base::MakeUnique<FakeCryptAuthService>();
fake_connection_ =
new FakeConnection(test_device_, /* should_auto_connect */ false);
EXPECT_FALSE(fake_connection_->observers().size());
secure_channel_ = base::MakeUnique<TestSecureChannel>(
- base::WrapUnique(fake_connection_), base::WrapUnique(test_delegate_));
+ base::WrapUnique(fake_connection_), fake_cryptauth_service_.get());
EXPECT_EQ(static_cast<size_t>(1), fake_connection_->observers().size());
EXPECT_EQ(secure_channel_.get(), fake_connection_->observers()[0]);
@@ -300,11 +283,7 @@ class CryptAuthSecureChannelTest : public testing::Test {
// Owned by secure_channel_.
FakeConnection* fake_connection_;
- // Owned by secure_chanel_.
- TestDelegate* test_delegate_;
-
- // Owned by test_delegate_.
- FakeSecureMessageDelegate* fake_secure_message_delegate_;
+ std::unique_ptr<FakeCryptAuthService> fake_cryptauth_service_;
// Owned by secure_channel_ once authentication has completed successfully.
FakeSecureContext* fake_secure_context_;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
index 40e848405f2..10f161ec10d 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
@@ -105,7 +105,7 @@ bool DataReductionProxyBypassProtocol::MaybeBypassProxyAndPrepareToRetry(
DataReductionProxyTypeInfo data_reduction_proxy_type_info;
if (!config_->WasDataReductionProxyUsed(request,
&data_reduction_proxy_type_info)) {
- if (!HasDataReductionProxyViaHeader(response_headers, nullptr)) {
+ if (!HasDataReductionProxyViaHeader(*response_headers, nullptr)) {
ReportResponseProxyServerStatusHistogram(
RESPONSE_PROXY_SERVER_STATUS_NON_DRP_NO_VIA);
return false;
@@ -138,12 +138,12 @@ bool DataReductionProxyBypassProtocol::MaybeBypassProxyAndPrepareToRetry(
// At this point, the response is expected to have the data reduction proxy
// via header, so detect and report cases where the via header is missing.
DataReductionProxyBypassStats::DetectAndRecordMissingViaHeaderResponseCode(
- data_reduction_proxy_type_info.proxy_index == 0, response_headers);
+ data_reduction_proxy_type_info.proxy_index == 0, *response_headers);
// GetDataReductionProxyBypassType will only log a net_log event if a bypass
// command was sent via the data reduction proxy headers
DataReductionProxyBypassType bypass_type = GetDataReductionProxyBypassType(
- response_headers, data_reduction_proxy_info);
+ request->url_chain(), *response_headers, data_reduction_proxy_info);
if (proxy_bypass_type)
*proxy_bypass_type = bypass_type;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc
index 3aa6b85d42d..718c1f234b0 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc
@@ -100,8 +100,8 @@ void DataReductionProxyBypassStats::RecordDataReductionProxyBypassInfo(
// static
void DataReductionProxyBypassStats::DetectAndRecordMissingViaHeaderResponseCode(
bool is_primary,
- const net::HttpResponseHeaders* headers) {
- if (HasDataReductionProxyViaHeader(headers, NULL)) {
+ const net::HttpResponseHeaders& headers) {
+ if (HasDataReductionProxyViaHeader(headers, nullptr)) {
// The data reduction proxy via header is present, so don't record anything.
return;
}
@@ -109,11 +109,11 @@ void DataReductionProxyBypassStats::DetectAndRecordMissingViaHeaderResponseCode(
if (is_primary) {
UMA_HISTOGRAM_SPARSE_SLOWLY(
"DataReductionProxy.MissingViaHeader.ResponseCode.Primary",
- headers->response_code());
+ headers.response_code());
} else {
UMA_HISTOGRAM_SPARSE_SLOWLY(
"DataReductionProxy.MissingViaHeader.ResponseCode.Fallback",
- headers->response_code());
+ headers.response_code());
}
}
@@ -385,7 +385,7 @@ void DataReductionProxyBypassStats::RecordMissingViaHeaderBytes(
if (!data_reduction_proxy_config_->WasDataReductionProxyUsed(&request,
NULL) ||
- HasDataReductionProxyViaHeader(request.response_headers(), NULL)) {
+ HasDataReductionProxyViaHeader(*request.response_headers(), NULL)) {
// Only track requests that used the data reduction proxy and had responses
// that were missing the data reduction proxy via header.
return;
@@ -537,6 +537,11 @@ void DataReductionProxyBypassStats::RecordBypassedBytes(
"Status503HttpServiceUnavailable",
content_length);
break;
+ case BYPASS_EVENT_TYPE_URL_REDIRECT_CYCLE:
+ UMA_HISTOGRAM_COUNTS(
+ "DataReductionProxy.BypassedBytes.URLRedirectCycle",
+ content_length);
+ break;
default:
break;
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
index 22674e9f1aa..222e2246172 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
@@ -45,7 +45,7 @@ class DataReductionProxyBypassStats
// proxy via header is not present.
static void DetectAndRecordMissingViaHeaderResponseCode(
bool is_primary,
- const net::HttpResponseHeaders* headers);
+ const net::HttpResponseHeaders& headers);
// |config| outlives this class instance. |unreachable_callback| provides a
// hook to inform the user that the Data Reduction Proxy is unreachable.
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
index 064d0aa45e2..cd7ddb4139b 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
@@ -335,6 +335,63 @@ class DataReductionProxyBypassStatsEndToEndTest : public testing::Test {
return request;
}
+ // Create and execute a fake request that goes through a redirect loop using
+ // the data reduction proxy stack.
+ std::unique_ptr<net::URLRequest> CreateAndExecuteURLRedirectCycleRequest() {
+ MockRead redirect_mock_reads_1[] = {
+ MockRead("HTTP/1.1 302 Found\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Location: http://bar.com/\r\n\r\n"),
+ MockRead(""), MockRead(net::SYNCHRONOUS, net::OK),
+ };
+ net::StaticSocketDataProvider redirect_socket_data_provider_1(
+ redirect_mock_reads_1, arraysize(redirect_mock_reads_1), nullptr, 0);
+ mock_socket_factory_.AddSocketDataProvider(
+ &redirect_socket_data_provider_1);
+
+ // The response after the redirect comes through proxy.
+ MockRead redirect_mock_reads_2[] = {
+ MockRead("HTTP/1.1 302 Found\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Location: http://foo.com/\r\n\r\n"),
+ MockRead(""), MockRead(net::SYNCHRONOUS, net::OK),
+ };
+ net::StaticSocketDataProvider redirect_socket_data_provider_2(
+ redirect_mock_reads_2, arraysize(redirect_mock_reads_2), nullptr, 0);
+ mock_socket_factory_.AddSocketDataProvider(
+ &redirect_socket_data_provider_2);
+
+ // The response after the redirect comes through proxy and there is a
+ // redirect cycle.
+ MockRead redirect_mock_reads_3[] = {
+ MockRead("HTTP/1.1 302 Found\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Location: http://bar.com/\r\n\r\n"),
+ MockRead(""), MockRead(net::SYNCHRONOUS, net::OK),
+ };
+ net::StaticSocketDataProvider redirect_socket_data_provider_3(
+ redirect_mock_reads_3, arraysize(redirect_mock_reads_3), nullptr, 0);
+ mock_socket_factory_.AddSocketDataProvider(
+ &redirect_socket_data_provider_3);
+
+ // Data reduction proxy should be bypassed, and the response should come
+ // directly.
+ MockRead response_mock_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead(kBody.c_str()),
+ MockRead(net::SYNCHRONOUS, net::OK),
+ };
+ net::StaticSocketDataProvider response_socket_data_provider(
+ response_mock_reads, arraysize(response_mock_reads), nullptr, 0);
+ mock_socket_factory_.AddSocketDataProvider(&response_socket_data_provider);
+
+ std::unique_ptr<net::URLRequest> request(
+ context_.CreateRequest(GURL("http://foo.com"), net::IDLE, &delegate_));
+ request->set_method("GET");
+ request->Start();
+ drp_test_context_->RunUntilIdle();
+ return request;
+ }
+
void set_proxy_service(net::ProxyService* proxy_service) {
context_.set_proxy_service(proxy_service);
}
@@ -397,6 +454,7 @@ class DataReductionProxyBypassStatsEndToEndTest : public testing::Test {
"DataReductionProxy.BypassedBytes.Status502HttpBadGateway",
"DataReductionProxy.BypassedBytes.Status503HttpServiceUnavailable",
"DataReductionProxy.BypassedBytes.NetworkErrorOther",
+ "DataReductionProxy.BypassedBytes.RedirectCycle",
};
for (const std::string& histogram : kHistograms) {
@@ -508,6 +566,31 @@ TEST_F(DataReductionProxyBypassStatsEndToEndTest, BypassedBytesNoRetry) {
}
}
+// Verify that when there is a URL redirect cycle, data reduction proxy is
+// bypassed for a single request.
+TEST_F(DataReductionProxyBypassStatsEndToEndTest, URLRedirectCycle) {
+ InitializeContext();
+ ClearBadProxies();
+ base::HistogramTester histogram_tester_1;
+ CreateAndExecuteURLRedirectCycleRequest();
+
+ histogram_tester_1.ExpectUniqueSample(
+ "DataReductionProxy.BypassedBytes.URLRedirectCycle", kBody.size(), 1);
+ ExpectOtherBypassedBytesHistogramsEmpty(
+ histogram_tester_1, "DataReductionProxy.BypassedBytes.URLRedirectCycle");
+
+ // The second request should be sent via the proxy.
+ base::HistogramTester histogram_tester_2;
+ CreateAndExecuteRequest(GURL("http://bar.com"), net::LOAD_NORMAL, net::OK,
+ "HTTP/1.1 200 OK\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ kNextBody.c_str(), nullptr, nullptr);
+ histogram_tester_2.ExpectUniqueSample(
+ "DataReductionProxy.BypassedBytes.NotBypassed", kNextBody.size(), 1);
+ ExpectOtherBypassedBytesHistogramsEmpty(
+ histogram_tester_2, "DataReductionProxy.BypassedBytes.NotBypassed");
+}
+
TEST_F(DataReductionProxyBypassStatsEndToEndTest,
BypassedBytesProxyOverridden) {
std::unique_ptr<net::ProxyService> proxy_service(
@@ -684,8 +767,10 @@ TEST_F(DataReductionProxyBypassStatsEndToEndTest,
kErrorBody.c_str(), "HTTP/1.1 200 OK\r\n\r\n",
kBody.c_str());
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.ConfigService.HTTPRequests", 1, 1);
+ EXPECT_LT(
+ 0u, histogram_tester
+ .GetAllSamples("DataReductionProxy.ConfigService.HTTPRequests")
+ .size());
// The first request caused the proxy to be marked as bad, so this second
// request should not come through the proxy.
@@ -701,10 +786,8 @@ TEST_F(DataReductionProxyBypassStatsEndToEndTest,
ExpectOtherBypassedBytesHistogramsEmpty(histogram_tester,
test_case.histogram_name);
- // "DataReductionProxy.ConfigService.HTTPRequests" should not be recorded
- // for bypassed requests.
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.ConfigService.HTTPRequests", 1, 1);
+ histogram_tester.ExpectBucketCount(
+ "DataReductionProxy.ConfigService.HTTPRequests", 0, 0);
}
}
@@ -874,7 +957,7 @@ TEST_F(DataReductionProxyBypassStatsEndToEndTest,
new net::HttpResponseHeaders(raw_headers));
DataReductionProxyBypassStats::DetectAndRecordMissingViaHeaderResponseCode(
- test_cases[i].is_primary, headers.get());
+ test_cases[i].is_primary, *headers);
if (test_cases[i].expected_primary_sample == -1) {
histogram_tester.ExpectTotalCount(kPrimaryHistogramName, 0);
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
index 5d4b87c9187..04280b08bc7 100644
--- 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
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
@@ -20,6 +21,7 @@
#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/browser/data_use_group.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"
@@ -76,7 +78,7 @@ void AddInt64ToListPref(size_t index,
int64_t length,
base::ListValue* list_update) {
int64_t value = GetInt64PrefValue(*list_update, index) + length;
- list_update->Set(index, new base::StringValue(base::Int64ToString(value)));
+ list_update->Set(index, new base::Value(base::Int64ToString(value)));
}
// DailyContentLengthUpdate maintains a data saving pref. The pref is a list
@@ -367,6 +369,16 @@ void DataReductionProxyCompressionStats::Init() {
base::Bind(
&DataReductionProxyCompressionStats::OnDataUsageReportingPrefChanged,
weak_factory_.GetWeakPtr()));
+
+#if defined(OS_ANDROID)
+ if (!base::FeatureList::IsEnabled(features::kDataReductionSiteBreakdown)) {
+ // If the user is moved out of the experiment make sure that data usage
+ // reporting is not enabled and the map is cleared.
+ SetDataUsageReportingEnabled(false);
+ DeleteHistoricalDataUsage();
+ }
+#endif
+
if (data_usage_reporting_enabled_.GetValue()) {
current_data_usage_load_status_ = LOADING;
service_->LoadCurrentDataUsageBucket(base::Bind(
@@ -424,20 +436,6 @@ void DataReductionProxyCompressionStats::Init() {
InitListPref(prefs::kDailyOriginalContentLengthWithDataReductionProxyEnabled);
}
-void DataReductionProxyCompressionStats::UpdateDataSavings(
- const std::string& data_usage_host,
- int64_t data_used,
- int64_t original_size) {
- DCHECK(thread_checker_.CalledOnValidThread());
- // Data is recorded at the URLRequest level, so an update should only change
- // the original size amount by the savings amount.
- int64_t update_to_original_size = original_size - data_used;
- int64_t update_to_data_used = 0;
- RecordData(update_to_data_used, update_to_original_size,
- true /* data_saver_enabled */, UPDATE, data_usage_host,
- std::string());
-}
-
void DataReductionProxyCompressionStats::UpdateContentLengths(
int64_t data_used,
int64_t original_size,
@@ -695,9 +693,56 @@ void DataReductionProxyCompressionStats::OnCurrentDataUsageLoaded(
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() {
DeleteHistoricalDataUsage();
+ pref_service_->ClearPref(prefs::kDailyHttpContentLengthLastUpdateDate);
+ pref_service_->ClearPref(prefs::kHttpReceivedContentLength);
+ pref_service_->ClearPref(prefs::kHttpOriginalContentLength);
+
+ pref_service_->ClearPref(prefs::kDailyHttpOriginalContentLengthApplication);
+ pref_service_->ClearPref(prefs::kDailyHttpOriginalContentLengthVideo);
+ pref_service_->ClearPref(prefs::kDailyHttpOriginalContentLengthUnknown);
+ pref_service_->ClearPref(prefs::kDailyHttpReceivedContentLengthApplication);
+ pref_service_->ClearPref(prefs::kDailyHttpReceivedContentLengthVideo);
+ pref_service_->ClearPref(prefs::kDailyHttpReceivedContentLengthUnknown);
+
+ pref_service_->ClearPref(
+ prefs::kDailyOriginalContentLengthViaDataReductionProxyApplication);
+ pref_service_->ClearPref(
+ prefs::kDailyOriginalContentLengthViaDataReductionProxyVideo);
+ pref_service_->ClearPref(
+ prefs::kDailyOriginalContentLengthViaDataReductionProxyUnknown);
+ pref_service_->ClearPref(
+ prefs::kDailyContentLengthViaDataReductionProxyApplication);
+ pref_service_->ClearPref(
+ prefs::kDailyContentLengthViaDataReductionProxyVideo);
+ pref_service_->ClearPref(
+ prefs::kDailyContentLengthViaDataReductionProxyUnknown);
+
+ pref_service_->ClearPref(
+ prefs::
+ kDailyOriginalContentLengthWithDataReductionProxyEnabledApplication);
+ pref_service_->ClearPref(
+ prefs::kDailyOriginalContentLengthWithDataReductionProxyEnabledVideo);
+ pref_service_->ClearPref(
+ prefs::kDailyOriginalContentLengthWithDataReductionProxyEnabledUnknown);
+ pref_service_->ClearPref(
+ prefs::kDailyContentLengthWithDataReductionProxyEnabledApplication);
+ pref_service_->ClearPref(
+ prefs::kDailyContentLengthWithDataReductionProxyEnabledVideo);
+ pref_service_->ClearPref(
+ prefs::kDailyContentLengthWithDataReductionProxyEnabledUnknown);
+
pref_service_->ClearPref(
prefs::kDailyContentLengthHttpsWithDataReductionProxyEnabled);
pref_service_->ClearPref(
@@ -1209,6 +1254,7 @@ void DataReductionProxyCompressionStats::DeleteHistoricalDataUsage() {
void DataReductionProxyCompressionStats::GetHistoricalDataUsageImpl(
const 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.
@@ -1218,10 +1264,13 @@ void DataReductionProxyCompressionStats::GetHistoricalDataUsageImpl(
base::MakeUnique<std::vector<DataUsageBucket>>());
return;
}
+#endif
- PersistDataUsage();
+ if (current_data_usage_load_status_ == LOADED)
+ PersistDataUsage();
- if (!DataUsageStore::AreInSameInterval(data_usage_map_last_updated_, now)) {
+ 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();
@@ -1243,7 +1292,19 @@ void DataReductionProxyCompressionStats::OnDataUsageReportingPrefChanged() {
weak_factory_.GetWeakPtr()));
}
} else {
+// Don't delete the historical data on Android, but clear the map.
+#if defined(OS_ANDROID)
+ DCHECK(current_data_usage_load_status_ != LOADING);
+
+ 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;
}
}
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
index 60c00200f0d..b3cf152cc31 100644
--- 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
@@ -22,7 +22,6 @@
#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_reduction_proxy/core/common/data_savings_recorder.h"
#include "components/prefs/pref_member.h"
class PrefService;
@@ -62,13 +61,6 @@ class DataReductionProxyCompressionStats {
const base::TimeDelta& delay);
~DataReductionProxyCompressionStats();
- // Records detailed data usage broken down by connection type and domain.
- // Assumes that the |data_used| has been recoreded by previous calls to
- // UpdateContentLengths.
- void UpdateDataSavings(const std::string& data_usage_host,
- int64_t data_used,
- int64_t original_size);
-
// Records detailed data usage broken down by connection type and domain. Also
// records daily data savings statistics to prefs and reports data savings
// UMA. |compressed_size| and |original_size| are measured in bytes.
@@ -133,6 +125,11 @@ class DataReductionProxyCompressionStats {
// 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);
+
private:
// Enum to track the state of loading data usage from storage.
enum CurrentDataUsageLoadStatus { NOT_LOADED = 0, LOADING = 1, LOADED = 2 };
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
index cadbcd3cda7..e9a5338c84c 100644
--- 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
@@ -163,13 +163,13 @@ class DataReductionProxyCompressionStatsTest : public testing::Test {
for (size_t i = 0; i < kNumDaysInHistory; ++i) {
original_daily_content_length_list->Set(
- i, new base::StringValue(base::SizeTToString(i)));
+ i, new base::Value(base::SizeTToString(i)));
}
received_daily_content_length_list->Clear();
for (size_t i = 0; i < kNumDaysInHistory / 2; ++i) {
received_daily_content_length_list->Set(
- i, new base::StringValue(base::SizeTToString(i)));
+ i, new base::Value(base::SizeTToString(i)));
}
}
@@ -178,8 +178,7 @@ class DataReductionProxyCompressionStatsTest : public testing::Test {
base::ListValue* update = compression_stats_->GetList(pref);
update->Clear();
for (size_t i = 0; i < kNumDaysInHistory; ++i) {
- update->Insert(
- 0, base::MakeUnique<base::StringValue>(base::Int64ToString(0)));
+ update->Insert(0, base::MakeUnique<base::Value>(base::Int64ToString(0)));
}
}
@@ -227,17 +226,20 @@ class DataReductionProxyCompressionStatsTest : public testing::Test {
// 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) {
- ASSERT_GE(kNumDaysInHistory, count);
+ 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(kNumDaysInHistory, update->GetSize()) << "Pref: " << pref;
+ ASSERT_EQ(num_days_in_history, update->GetSize()) << "Pref: " << pref;
for (size_t i = 0; i < count; ++i) {
EXPECT_EQ(values[i],
- GetListPrefInt64Value(*update, kNumDaysInHistory - count + i))
- << pref << "; index=" << (kNumDaysInHistory - count + i);
+ GetListPrefInt64Value(*update, num_days_in_history - count + i))
+ << pref << "; index=" << (num_days_in_history - count + i);
}
- for (size_t i = 0; i < kNumDaysInHistory - count; ++i) {
+ for (size_t i = 0; i < num_days_in_history - count; ++i) {
EXPECT_EQ(0, GetListPrefInt64Value(*update, i)) << "index=" << i;
}
}
@@ -260,31 +262,31 @@ class DataReductionProxyCompressionStatsTest : public testing::Test {
const int64_t* original_via_data_reduction_proxy_values,
size_t original_via_data_reduction_proxy_count,
const int64_t* received_via_data_reduction_proxy_values,
- size_t received_via_data_reduction_proxy_count) {
+ size_t received_via_data_reduction_proxy_count,
+ size_t num_days_in_history) {
VerifyPrefList(data_reduction_proxy::prefs::kDailyHttpOriginalContentLength,
- original_values, original_count);
+ original_values, original_count, num_days_in_history);
VerifyPrefList(data_reduction_proxy::prefs::kDailyHttpReceivedContentLength,
- received_values, received_count);
+ received_values, received_count, num_days_in_history);
+ VerifyPrefList(data_reduction_proxy::prefs::
+ kDailyOriginalContentLengthWithDataReductionProxyEnabled,
+ original_with_data_reduction_proxy_enabled_values,
+ original_with_data_reduction_proxy_enabled_count,
+ num_days_in_history);
+ VerifyPrefList(data_reduction_proxy::prefs::
+ kDailyContentLengthWithDataReductionProxyEnabled,
+ received_with_data_reduction_proxy_enabled_values,
+ received_with_data_reduction_proxy_count,
+ num_days_in_history);
+ VerifyPrefList(data_reduction_proxy::prefs::
+ kDailyOriginalContentLengthViaDataReductionProxy,
+ original_via_data_reduction_proxy_values,
+ original_via_data_reduction_proxy_count,
+ num_days_in_history);
VerifyPrefList(
- data_reduction_proxy::prefs::
- kDailyOriginalContentLengthWithDataReductionProxyEnabled,
- original_with_data_reduction_proxy_enabled_values,
- original_with_data_reduction_proxy_enabled_count);
- VerifyPrefList(
- data_reduction_proxy::prefs::
- kDailyContentLengthWithDataReductionProxyEnabled,
- received_with_data_reduction_proxy_enabled_values,
- received_with_data_reduction_proxy_count);
- VerifyPrefList(
- data_reduction_proxy::prefs::
- kDailyOriginalContentLengthViaDataReductionProxy,
- original_via_data_reduction_proxy_values,
- original_via_data_reduction_proxy_count);
- VerifyPrefList(
- data_reduction_proxy::prefs::
- kDailyContentLengthViaDataReductionProxy,
+ data_reduction_proxy::prefs::kDailyContentLengthViaDataReductionProxy,
received_via_data_reduction_proxy_values,
- received_via_data_reduction_proxy_count);
+ received_via_data_reduction_proxy_count, num_days_in_history);
VerifyPrefInt64(
data_reduction_proxy::prefs::kDailyHttpOriginalContentLengthApplication,
@@ -342,39 +344,39 @@ class DataReductionProxyCompressionStatsTest : public testing::Test {
const int64_t* unknown_with_data_reduction_proxy_enabled_values,
size_t unknown_with_data_reduction_proxy_enabled_count) {
VerifyPrefList(data_reduction_proxy::prefs::kDailyHttpOriginalContentLength,
- original_values, original_count);
+ original_values, original_count, kNumDaysInHistory);
VerifyPrefList(data_reduction_proxy::prefs::kDailyHttpReceivedContentLength,
- received_values, received_count);
- VerifyPrefList(
- data_reduction_proxy::prefs::
- kDailyOriginalContentLengthWithDataReductionProxyEnabled,
- original_with_data_reduction_proxy_enabled_values,
- original_with_data_reduction_proxy_enabled_count);
- VerifyPrefList(
- data_reduction_proxy::prefs::
- kDailyContentLengthWithDataReductionProxyEnabled,
- received_with_data_reduction_proxy_enabled_values,
- received_with_data_reduction_proxy_count);
- VerifyPrefList(
- data_reduction_proxy::prefs::
- kDailyContentLengthHttpsWithDataReductionProxyEnabled,
- https_with_data_reduction_proxy_enabled_values,
- https_with_data_reduction_proxy_enabled_count);
+ received_values, received_count, kNumDaysInHistory);
+ VerifyPrefList(data_reduction_proxy::prefs::
+ kDailyOriginalContentLengthWithDataReductionProxyEnabled,
+ original_with_data_reduction_proxy_enabled_values,
+ original_with_data_reduction_proxy_enabled_count,
+ kNumDaysInHistory);
+ VerifyPrefList(data_reduction_proxy::prefs::
+ kDailyContentLengthWithDataReductionProxyEnabled,
+ received_with_data_reduction_proxy_enabled_values,
+ received_with_data_reduction_proxy_count, kNumDaysInHistory);
+ VerifyPrefList(data_reduction_proxy::prefs::
+ kDailyContentLengthHttpsWithDataReductionProxyEnabled,
+ https_with_data_reduction_proxy_enabled_values,
+ https_with_data_reduction_proxy_enabled_count,
+ kNumDaysInHistory);
VerifyPrefList(
data_reduction_proxy::prefs::
kDailyContentLengthShortBypassWithDataReductionProxyEnabled,
short_bypass_with_data_reduction_proxy_enabled_values,
- short_bypass_with_data_reduction_proxy_enabled_count);
+ short_bypass_with_data_reduction_proxy_enabled_count,
+ kNumDaysInHistory);
VerifyPrefList(
data_reduction_proxy::prefs::
kDailyContentLengthLongBypassWithDataReductionProxyEnabled,
long_bypass_with_data_reduction_proxy_enabled_values,
- long_bypass_with_data_reduction_proxy_enabled_count);
- VerifyPrefList(
- data_reduction_proxy::prefs::
- kDailyContentLengthUnknownWithDataReductionProxyEnabled,
- unknown_with_data_reduction_proxy_enabled_values,
- unknown_with_data_reduction_proxy_enabled_count);
+ long_bypass_with_data_reduction_proxy_enabled_count, kNumDaysInHistory);
+ VerifyPrefList(data_reduction_proxy::prefs::
+ kDailyContentLengthUnknownWithDataReductionProxyEnabled,
+ unknown_with_data_reduction_proxy_enabled_values,
+ unknown_with_data_reduction_proxy_enabled_count,
+ kNumDaysInHistory);
}
int64_t GetInt64(const char* pref_path) {
@@ -433,6 +435,10 @@ class DataReductionProxyCompressionStatsTest : public testing::Test {
compression_stats_->DeleteHistoricalDataUsage();
}
+ void ClearDataSavingStatistics() {
+ compression_stats_->ClearDataSavingStatistics();
+ }
+
void DeleteBrowsingHistory(const base::Time& start, const base::Time& end) {
compression_stats_->DeleteBrowsingHistory(start, end);
}
@@ -544,8 +550,8 @@ TEST_F(DataReductionProxyCompressionStatsTest,
TEST_F(DataReductionProxyCompressionStatsTest, StatsRestoredOnOnRestart) {
base::ListValue list_value;
- list_value.Insert(
- 0, base::MakeUnique<base::StringValue>(base::Int64ToString(1234)));
+ list_value.Insert(0,
+ base::MakeUnique<base::Value>(base::Int64ToString(1234)));
pref_service()->Set(prefs::kDailyHttpOriginalContentLength, list_value);
ResetCompressionStatsWithDelay(
@@ -584,28 +590,6 @@ TEST_F(DataReductionProxyCompressionStatsTest, TotalLengths) {
GetInt64(data_reduction_proxy::prefs::kHttpOriginalContentLength));
}
-TEST_F(DataReductionProxyCompressionStatsTest, TotalLengthsUpdate) {
- const int64_t kOriginalLength = 200;
- const int64_t kReceivedLength = 100;
-
- compression_stats()->UpdateDataSavings(std::string(), kReceivedLength,
- kOriginalLength);
-
- EXPECT_EQ(0,
- GetInt64(data_reduction_proxy::prefs::kHttpReceivedContentLength));
- EXPECT_EQ(kOriginalLength - kReceivedLength,
- GetInt64(data_reduction_proxy::prefs::kHttpOriginalContentLength));
-
- // Record the same numbers again, and total lengths should be doubled.
- compression_stats()->UpdateDataSavings(std::string(), kReceivedLength,
- kOriginalLength);
-
- EXPECT_EQ(0,
- GetInt64(data_reduction_proxy::prefs::kHttpReceivedContentLength));
- EXPECT_EQ(kOriginalLength * 2 - kReceivedLength * 2,
- GetInt64(data_reduction_proxy::prefs::kHttpOriginalContentLength));
-}
-
TEST_F(DataReductionProxyCompressionStatsTest, OneResponse) {
const int64_t kOriginalLength = 200;
const int64_t kReceivedLength = 100;
@@ -617,9 +601,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, OneResponse) {
FakeNow());
VerifyDailyDataSavingContentLengthPrefLists(
- original, 1, received, 1,
- original, 1, received, 1,
- original, 1, received, 1);
+ original, 1, received, 1, original, 1, received, 1, original, 1, received,
+ 1, kNumDaysInHistory);
}
TEST_F(DataReductionProxyCompressionStatsTest, MultipleResponses) {
@@ -629,9 +612,9 @@ TEST_F(DataReductionProxyCompressionStatsTest, MultipleResponses) {
int64_t received[] = {kReceivedLength};
RecordContentLengthPrefs(
kReceivedLength, kOriginalLength, false, UNKNOWN_TYPE, FakeNow());
- VerifyDailyDataSavingContentLengthPrefLists(
- original, 1, received, 1,
- NULL, 0, NULL, 0, NULL, 0, NULL, 0);
+ VerifyDailyDataSavingContentLengthPrefLists(original, 1, received, 1, NULL, 0,
+ NULL, 0, NULL, 0, NULL, 0,
+ kNumDaysInHistory);
RecordContentLengthPrefs(
kReceivedLength, kOriginalLength, true, UNKNOWN_TYPE, FakeNow());
@@ -640,9 +623,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, MultipleResponses) {
int64_t original_proxy_enabled[] = {kOriginalLength};
int64_t received_proxy_enabled[] = {kReceivedLength};
VerifyDailyDataSavingContentLengthPrefLists(
- original, 1, received, 1,
- original_proxy_enabled, 1, received_proxy_enabled, 1,
- NULL, 0, NULL, 0);
+ original, 1, received, 1, original_proxy_enabled, 1,
+ received_proxy_enabled, 1, NULL, 0, NULL, 0, kNumDaysInHistory);
RecordContentLengthPrefs(
kReceivedLength, kOriginalLength, true, VIA_DATA_REDUCTION_PROXY,
@@ -654,9 +636,9 @@ TEST_F(DataReductionProxyCompressionStatsTest, MultipleResponses) {
int64_t original_via_proxy[] = {kOriginalLength};
int64_t received_via_proxy[] = {kReceivedLength};
VerifyDailyDataSavingContentLengthPrefLists(
- original, 1, received, 1,
- original_proxy_enabled, 1, received_proxy_enabled, 1,
- original_via_proxy, 1, received_via_proxy, 1);
+ original, 1, received, 1, original_proxy_enabled, 1,
+ received_proxy_enabled, 1, original_via_proxy, 1, received_via_proxy, 1,
+ kNumDaysInHistory);
RecordContentLengthPrefs(
kReceivedLength, kOriginalLength, true, UNKNOWN_TYPE, FakeNow());
@@ -665,18 +647,18 @@ TEST_F(DataReductionProxyCompressionStatsTest, MultipleResponses) {
original_proxy_enabled[0] += kOriginalLength;
received_proxy_enabled[0] += kReceivedLength;
VerifyDailyDataSavingContentLengthPrefLists(
- original, 1, received, 1,
- original_proxy_enabled, 1, received_proxy_enabled, 1,
- original_via_proxy, 1, received_via_proxy, 1);
+ original, 1, received, 1, original_proxy_enabled, 1,
+ received_proxy_enabled, 1, original_via_proxy, 1, received_via_proxy, 1,
+ kNumDaysInHistory);
RecordContentLengthPrefs(
kReceivedLength, kOriginalLength, false, UNKNOWN_TYPE, FakeNow());
original[0] += kOriginalLength;
received[0] += kReceivedLength;
VerifyDailyDataSavingContentLengthPrefLists(
- original, 1, received, 1,
- original_proxy_enabled, 1, received_proxy_enabled, 1,
- original_via_proxy, 1, received_via_proxy, 1);
+ original, 1, received, 1, original_proxy_enabled, 1,
+ received_proxy_enabled, 1, original_via_proxy, 1, received_via_proxy, 1,
+ kNumDaysInHistory);
}
TEST_F(DataReductionProxyCompressionStatsTest, RequestType) {
@@ -784,12 +766,10 @@ TEST_F(DataReductionProxyCompressionStatsTest, ForwardOneDay) {
int64_t original_via_data_reduction_proxy[] = {kOriginalLength, 0};
int64_t received_via_data_reduction_proxy[] = {kReceivedLength, 0};
VerifyDailyDataSavingContentLengthPrefLists(
- original, 2,
- received, 2,
- original_with_data_reduction_proxy_enabled, 2,
+ original, 2, received, 2, original_with_data_reduction_proxy_enabled, 2,
received_with_data_reduction_proxy_enabled, 2,
- original_via_data_reduction_proxy, 2,
- received_via_data_reduction_proxy, 2);
+ original_via_data_reduction_proxy, 2, received_via_data_reduction_proxy,
+ 2, kNumDaysInHistory);
// Proxy enabled. Not via proxy.
RecordContentLengthPrefs(
@@ -799,12 +779,10 @@ TEST_F(DataReductionProxyCompressionStatsTest, ForwardOneDay) {
original_with_data_reduction_proxy_enabled[1] += kOriginalLength;
received_with_data_reduction_proxy_enabled[1] += kReceivedLength;
VerifyDailyDataSavingContentLengthPrefLists(
- original, 2,
- received, 2,
- original_with_data_reduction_proxy_enabled, 2,
+ original, 2, received, 2, original_with_data_reduction_proxy_enabled, 2,
received_with_data_reduction_proxy_enabled, 2,
- original_via_data_reduction_proxy, 2,
- received_via_data_reduction_proxy, 2);
+ original_via_data_reduction_proxy, 2, received_via_data_reduction_proxy,
+ 2, kNumDaysInHistory);
// Proxy enabled and via proxy.
RecordContentLengthPrefs(
@@ -817,12 +795,10 @@ TEST_F(DataReductionProxyCompressionStatsTest, ForwardOneDay) {
original_via_data_reduction_proxy[1] += kOriginalLength;
received_via_data_reduction_proxy[1] += kReceivedLength;
VerifyDailyDataSavingContentLengthPrefLists(
- original, 2,
- received, 2,
- original_with_data_reduction_proxy_enabled, 2,
+ original, 2, received, 2, original_with_data_reduction_proxy_enabled, 2,
received_with_data_reduction_proxy_enabled, 2,
- original_via_data_reduction_proxy, 2,
- received_via_data_reduction_proxy, 2);
+ original_via_data_reduction_proxy, 2, received_via_data_reduction_proxy,
+ 2, kNumDaysInHistory);
// Proxy enabled and via proxy, with content length greater than max int32_t.
const int64_t kBigOriginalLength = 0x300000000LL; // 12G.
@@ -839,7 +815,7 @@ TEST_F(DataReductionProxyCompressionStatsTest, ForwardOneDay) {
original, 2, received, 2, original_with_data_reduction_proxy_enabled, 2,
received_with_data_reduction_proxy_enabled, 2,
original_via_data_reduction_proxy, 2, received_via_data_reduction_proxy,
- 2);
+ 2, kNumDaysInHistory);
}
TEST_F(DataReductionProxyCompressionStatsTest, PartialDayTimeChange) {
@@ -852,9 +828,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, PartialDayTimeChange) {
kReceivedLength, kOriginalLength, true, VIA_DATA_REDUCTION_PROXY,
FakeNow());
VerifyDailyDataSavingContentLengthPrefLists(
- original, 2, received, 2,
- original, 2, received, 2,
- original, 2, received, 2);
+ original, 2, received, 2, original, 2, received, 2, original, 2, received,
+ 2, kNumDaysInHistory);
// Forward 10 hours, stay in the same day.
// See kLastUpdateTime: "Now" in test is 03:45am.
@@ -865,9 +840,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, PartialDayTimeChange) {
original[1] += kOriginalLength;
received[1] += kReceivedLength;
VerifyDailyDataSavingContentLengthPrefLists(
- original, 2, received, 2,
- original, 2, received, 2,
- original, 2, received, 2);
+ original, 2, received, 2, original, 2, received, 2, original, 2, received,
+ 2, kNumDaysInHistory);
// Forward 11 more hours, comes to tomorrow.
AddFakeTimeDeltaInHours(11);
@@ -877,9 +851,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, PartialDayTimeChange) {
int64_t original2[] = {kOriginalLength * 2, kOriginalLength};
int64_t received2[] = {kReceivedLength * 2, kReceivedLength};
VerifyDailyDataSavingContentLengthPrefLists(
- original2, 2, received2, 2,
- original2, 2, received2, 2,
- original2, 2, received2, 2);
+ original2, 2, received2, 2, original2, 2, received2, 2, original2, 2,
+ received2, 2, kNumDaysInHistory);
}
TEST_F(DataReductionProxyCompressionStatsTest, ForwardMultipleDays) {
@@ -904,9 +877,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, ForwardMultipleDays) {
int64_t original[] = {kOriginalLength, 0, 0, kOriginalLength};
int64_t received[] = {kReceivedLength, 0, 0, kReceivedLength};
VerifyDailyDataSavingContentLengthPrefLists(
- original, 4, received, 4,
- original, 4, received, 4,
- original, 4, received, 4);
+ original, 4, received, 4, original, 4, received, 4, original, 4, received,
+ 4, kNumDaysInHistory);
// Forward four more days.
AddFakeTimeDeltaInHours(4 * 24);
@@ -920,9 +892,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, ForwardMultipleDays) {
kReceivedLength, 0, 0, kReceivedLength, 0, 0, 0, kReceivedLength,
};
VerifyDailyDataSavingContentLengthPrefLists(
- original2, 8, received2, 8,
- original2, 8, received2, 8,
- original2, 8, received2, 8);
+ original2, 8, received2, 8, original2, 8, received2, 8, original2, 8,
+ received2, 8, kNumDaysInHistory);
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 3);
@@ -934,9 +905,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, ForwardMultipleDays) {
int64_t original3[] = {kOriginalLength};
int64_t received3[] = {kReceivedLength};
VerifyDailyDataSavingContentLengthPrefLists(
- original3, 1, received3, 1,
- original3, 1, received3, 1,
- original3, 1, received3, 1);
+ original3, 1, received3, 1, original3, 1, received3, 1, original3, 1,
+ received3, 1, kNumDaysInHistory);
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 4);
@@ -946,9 +916,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, ForwardMultipleDays) {
kReceivedLength, kOriginalLength, true, VIA_DATA_REDUCTION_PROXY,
FakeNow());
VerifyDailyDataSavingContentLengthPrefLists(
- original3, 1, received3, 1,
- original3, 1, received3, 1,
- original3, 1, received3, 1);
+ original3, 1, received3, 1, original3, 1, received3, 1, original3, 1,
+ received3, 1, kNumDaysInHistory);
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 5);
}
@@ -974,9 +943,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, BackwardAndForwardOneDay) {
original[0] += kOriginalLength;
received[0] += kReceivedLength;
VerifyDailyDataSavingContentLengthPrefLists(
- original, 1, received, 1,
- original, 1, received, 1,
- original, 1, received, 1);
+ original, 1, received, 1, original, 1, received, 1, original, 1, received,
+ 1, kNumDaysInHistory);
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 2);
@@ -988,9 +956,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, BackwardAndForwardOneDay) {
int64_t original2[] = {kOriginalLength * 2, kOriginalLength};
int64_t received2[] = {kReceivedLength * 2, kReceivedLength};
VerifyDailyDataSavingContentLengthPrefLists(
- original2, 2, received2, 2,
- original2, 2, received2, 2,
- original2, 2, received2, 2);
+ original2, 2, received2, 2, original2, 2, received2, 2, original2, 2,
+ received2, 2, kNumDaysInHistory);
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 3);
}
@@ -1014,9 +981,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, BackwardTwoDays) {
kReceivedLength, kOriginalLength, true, VIA_DATA_REDUCTION_PROXY,
FakeNow());
VerifyDailyDataSavingContentLengthPrefLists(
- original, 1, received, 1,
- original, 1, received, 1,
- original, 1, received, 1);
+ original, 1, received, 1, original, 1, received, 1, original, 1, received,
+ 1, kNumDaysInHistory);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.SavingsCleared.NegativeSystemClock", 2);
histogram_tester.ExpectBucketCount(
@@ -1143,6 +1109,7 @@ TEST_F(DataReductionProxyCompressionStatsTest, DisableDataUsageRecording) {
DisableDataUsageReporting();
base::RunLoop().RunUntilIdle();
+#if !defined(OS_ANDROID)
// Data usage on disk must be deleted.
auto expected_data_usage1 =
base::MakeUnique<std::vector<data_reduction_proxy::DataUsageBucket>>(
@@ -1158,6 +1125,26 @@ TEST_F(DataReductionProxyCompressionStatsTest, DisableDataUsageRecording) {
GetHistoricalDataUsage(base::Bind(&DataUsageLoadVerifier::OnLoadDataUsage,
base::Unretained(&verifier2)),
now);
+#else
+ // For Android don't delete data usage.
+ auto expected_data_usage =
+ base::MakeUnique<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::Bind(&DataUsageLoadVerifier::OnLoadDataUsage,
+ base::Unretained(&verifier)),
+ now);
+#endif
+
base::RunLoop().RunUntilIdle();
}
@@ -1341,4 +1328,45 @@ TEST_F(DataReductionProxyCompressionStatsTest, DeleteBrowsingHistory) {
base::RunLoop().RunUntilIdle();
}
+TEST_F(DataReductionProxyCompressionStatsTest, ClearDataSavingStatistics) {
+ EnableDataUsageReporting();
+ base::RunLoop().RunUntilIdle();
+
+ base::Time now = base::Time::Now();
+ base::Time fifteen_mins_ago = now - TimeDelta::FromMinutes(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,
+ VIA_DATA_REDUCTION_PROXY, FakeNow());
+
+ VerifyDailyDataSavingContentLengthPrefLists(
+ original, 1, received, 1, original, 1, received, 1, original, 1, received,
+ 1, kNumDaysInHistory);
+
+ ClearDataSavingStatistics();
+ base::RunLoop().RunUntilIdle();
+
+ auto expected_data_usage =
+ base::MakeUnique<std::vector<data_reduction_proxy::DataUsageBucket>>(
+ kNumExpectedBuckets);
+ DataUsageLoadVerifier verifier(std::move(expected_data_usage));
+
+ GetHistoricalDataUsage(base::Bind(&DataUsageLoadVerifier::OnLoadDataUsage,
+ base::Unretained(&verifier)),
+ now);
+ base::RunLoop().RunUntilIdle();
+
+ VerifyDailyDataSavingContentLengthPrefLists(nullptr, 0, nullptr, 0, nullptr,
+ 0, nullptr, 0, nullptr, 0,
+ nullptr, 0, 0);
+}
+
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
index afcbb44bdb4..9ffb7f87fd1 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
@@ -312,20 +312,12 @@ class WarmupURLFetcher : public net::URLFetcherDelegate {
fetcher_->Start();
}
- void SetWarmupURLFetcherCallbackForTesting(
- base::Callback<void()> warmup_url_fetched_callback) {
- fetch_completion_callback_ = warmup_url_fetched_callback;
- }
-
private:
void OnURLFetchComplete(const net::URLFetcher* source) override {
DCHECK_EQ(source, fetcher_.get());
UMA_HISTOGRAM_BOOLEAN(
"DataReductionProxy.WarmupURL.FetchSuccessful",
source->GetStatus().status() == net::URLRequestStatus::SUCCESS);
-
- if (fetch_completion_callback_)
- fetch_completion_callback_.Run();
}
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
@@ -333,9 +325,6 @@ class WarmupURLFetcher : public net::URLFetcherDelegate {
// The URLFetcher being used for fetching the warmup URL.
std::unique_ptr<net::URLFetcher> fetcher_;
- // Called upon the completion of fetching of the warmup URL. May be null.
- base::Callback<void()> fetch_completion_callback_;
-
DISALLOW_COPY_AND_ASSIGN(WarmupURLFetcher);
};
@@ -871,14 +860,6 @@ void DataReductionProxyConfig::FetchWarmupURL() {
warmup_url_fetcher_->FetchWarmupURL();
}
-void DataReductionProxyConfig::SetWarmupURLFetcherCallbackForTesting(
- base::Callback<void()> warmup_url_fetched_callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- warmup_url_fetcher_->SetWarmupURLFetcherCallbackForTesting(
- warmup_url_fetched_callback);
-}
-
void DataReductionProxyConfig::SetLoFiModeOff() {
DCHECK(thread_checker_.CalledOnValidThread());
lofi_off_ = true;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
index 34348166047..5bc7b57a8b9 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
@@ -228,10 +228,6 @@ class DataReductionProxyConfig
// Updates the Data Reduction Proxy configurator with the current config.
void UpdateConfigForTesting(bool enabled, bool restricted);
- // Updates the callback that is called when the warmup URL has been fetched.
- void SetWarmupURLFetcherCallbackForTesting(
- base::Callback<void()> warmup_url_fetched_callback);
-
private:
friend class MockDataReductionProxyConfig;
friend class TestDataReductionProxyConfig;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
index c14d723f453..0a54c8671bd 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
@@ -120,7 +120,7 @@ class DataReductionProxyConfigServiceClient
// Examines |response_headers| to determine if an authentication failure
// occurred on a Data Reduction Proxy. Returns true if authentication failure
- // occured, and the session key specified in |request_headers| matches the
+ // occurred, and the session key specified in |request_headers| matches the
// current session in use by the client. If an authentication failure is
// detected, it fetches a new config.
bool ShouldRetryDueToAuthFailure(
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
index 4198e68ad23..05b59b391e3 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
@@ -118,7 +118,6 @@ class TestDataReductionProxyConfig : public DataReductionProxyConfig {
void SetIsCaptivePortal(bool is_captive_portal);
using DataReductionProxyConfig::UpdateConfigForTesting;
- using DataReductionProxyConfig::SetWarmupURLFetcherCallbackForTesting;
private:
bool GetIsCaptivePortal() const override;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
index 0a917ea4bf6..f70b5e700b8 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
@@ -165,17 +165,6 @@ class DataReductionProxyConfigTest : public testing::Test {
1);
}
- void WarmupURLFetchedCallBack() const {
- warmup_url_fetched_run_loop_->Quit();
- }
-
- void WarmUpURLFetchedRunLoop() {
- warmup_url_fetched_run_loop_.reset(new base::RunLoop());
- // |warmup_url_fetched_run_loop_| will run until WarmupURLFetchedCallBack()
- // is called.
- warmup_url_fetched_run_loop_->Run();
- }
-
void RunUntilIdle() {
test_context_->RunUntilIdle();
}
@@ -213,7 +202,6 @@ class DataReductionProxyConfigTest : public testing::Test {
std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
base::MessageLoopForIO message_loop_;
- std::unique_ptr<base::RunLoop> warmup_url_fetched_run_loop_;
std::unique_ptr<DataReductionProxyTestContext> test_context_;
std::unique_ptr<TestDataReductionProxyParams> expected_params_;
};
@@ -375,9 +363,6 @@ TEST_F(DataReductionProxyConfigTest, WarmupURL) {
new net::TestURLRequestContextGetter(task_runner());
config.InitializeOnIOThread(request_context_getter_.get(),
request_context_getter_.get());
- config.SetWarmupURLFetcherCallbackForTesting(
- base::Bind(&DataReductionProxyConfigTest::WarmupURLFetchedCallBack,
- base::Unretained(this)));
// Set the connection type to WiFi so that warm up URL is fetched even if
// the test device does not have connectivity.
@@ -387,12 +372,8 @@ TEST_F(DataReductionProxyConfigTest, WarmupURL) {
test.data_reduction_proxy_enabled && test.enabled_via_field_trial;
if (warmup_url_enabled) {
- // Block until warm up URL is fetched successfully.
- WarmUpURLFetchedRunLoop();
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURL.FetchInitiated", 1, 1);
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.WarmupURL.FetchSuccessful", 1, 1);
}
// Set the connection type to 4G so that warm up URL is fetched even if
@@ -402,12 +383,8 @@ TEST_F(DataReductionProxyConfigTest, WarmupURL) {
RunUntilIdle();
if (warmup_url_enabled) {
- // Block until warm up URL is fetched successfully.
- WarmUpURLFetchedRunLoop();
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURL.FetchInitiated", 1, 2);
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.WarmupURL.FetchSuccessful", 1, 2);
} else {
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 0);
@@ -424,8 +401,6 @@ TEST_F(DataReductionProxyConfigTest, WarmupURL) {
if (warmup_url_enabled) {
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURL.FetchInitiated", 1, 2);
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.WarmupURL.FetchSuccessful", 1, 2);
} else {
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 0);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc
index a98ba92d026..fbdf6768048 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc
@@ -8,6 +8,7 @@
#include <string>
#include <vector>
+#include "base/test/scoped_task_environment.h"
#include "base/values.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h"
@@ -60,7 +61,7 @@ class DataReductionProxyConfiguratorTest : public testing::Test {
}
}
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
std::unique_ptr<DataReductionProxyTestContext> test_context_;
std::unique_ptr<DataReductionProxyConfigurator> config_;
};
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc
index 5452658353b..425d1be797f 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc
@@ -14,16 +14,23 @@ const void* const kDataReductionProxyUserDataKey =
DataReductionProxyData::DataReductionProxyData()
: used_data_reduction_proxy_(false),
lofi_requested_(false),
+ lite_page_received_(false),
+ lofi_received_(false),
effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {}
+DataReductionProxyData::~DataReductionProxyData() {}
+
std::unique_ptr<DataReductionProxyData> DataReductionProxyData::DeepCopy()
const {
std::unique_ptr<DataReductionProxyData> copy(new DataReductionProxyData());
copy->used_data_reduction_proxy_ = used_data_reduction_proxy_;
copy->lofi_requested_ = lofi_requested_;
+ copy->lite_page_received_ = lite_page_received_;
+ copy->lofi_received_ = lofi_received_;
copy->session_key_ = session_key_;
copy->request_url_ = request_url_;
copy->effective_connection_type_ = effective_connection_type_;
+ copy->page_id_ = page_id_;
return copy;
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h
index 3b4b53f8546..1f12d47e502 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h
@@ -5,10 +5,13 @@
#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_DATA_H_
#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_DATA_H_
+#include <stdint.h>
+
#include <memory>
#include <string>
#include "base/macros.h"
+#include "base/optional.h"
#include "base/supports_user_data.h"
#include "net/nqe/effective_connection_type.h"
#include "url/gurl.h"
@@ -24,6 +27,7 @@ namespace data_reduction_proxy {
class DataReductionProxyData : public base::SupportsUserData::Data {
public:
DataReductionProxyData();
+ ~DataReductionProxyData() override;
// Whether the DataReductionProxy was used for this request or navigation.
bool used_data_reduction_proxy() const { return used_data_reduction_proxy_; }
@@ -39,14 +43,24 @@ class DataReductionProxyData : public base::SupportsUserData::Data {
lofi_requested_ = lofi_requested;
}
- // The session key used for this request.
+ // Whether a lite page response was seen for the request or navigation.
+ bool lite_page_received() const { return lite_page_received_; }
+ void set_lite_page_received(bool lite_page_received) {
+ lite_page_received_ = lite_page_received;
+ }
+
+ // Whether a lite page response was seen for the request or navigation.
+ bool lofi_received() const { return lofi_received_; }
+ void set_lofi_received(bool lofi_received) { lofi_received_ = lofi_received; }
+
+ // The session key used for this request. Only set for main frame requests.
std::string session_key() const { return session_key_; }
void set_session_key(const std::string& session_key) {
session_key_ = session_key;
}
// The URL the frame is navigating to. This may change during the navigation
- // when encountering a server redirect.
+ // when encountering a server redirect. Only set for main frame requests.
GURL request_url() const { return request_url_; }
void set_request_url(const GURL& request_url) { request_url_ = request_url; }
@@ -60,6 +74,11 @@ class DataReductionProxyData : public base::SupportsUserData::Data {
effective_connection_type_ = effective_connection_type;
}
+ // An identifier that is guaranteed to be unique to each page load during a
+ // data saver session. Only present on main frame requests.
+ const base::Optional<uint64_t>& page_id() const { return page_id_; }
+ void set_page_id(uint64_t page_id) { page_id_ = page_id; }
+
// Removes |this| from |request|.
static void ClearData(net::URLRequest* request);
@@ -85,6 +104,12 @@ class DataReductionProxyData : public base::SupportsUserData::Data {
// slow.
bool lofi_requested_;
+ // Whether a lite page response was seen for the request or navigation.
+ bool lite_page_received_;
+
+ // Whether a lite page response was seen for the request or navigation.
+ bool lofi_received_;
+
// The session key used for this request or navigation.
std::string session_key_;
@@ -96,6 +121,10 @@ class DataReductionProxyData : public base::SupportsUserData::Data {
// set for main frame requests only.
net::EffectiveConnectionType effective_connection_type_;
+ // An identifier that is guaranteed to be unique to each page load during a
+ // data saver session. Only present on main frame requests.
+ base::Optional<uint64_t> page_id_;
+
DISALLOW_COPY_AND_ASSIGN(DataReductionProxyData);
};
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc
index 09aaaa199ba..8ba21079bf2 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc
@@ -4,7 +4,10 @@
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
+#include <stdint.h>
+
#include <memory>
+#include <string>
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
@@ -41,19 +44,38 @@ TEST_F(DataReductionProxyDataTest, BasicSettersAndGetters) {
data->set_lofi_requested(false);
EXPECT_FALSE(data->lofi_requested());
+ EXPECT_FALSE(data->lite_page_received());
+ data->set_lite_page_received(true);
+ EXPECT_TRUE(data->lite_page_received());
+ data->set_lite_page_received(false);
+ EXPECT_FALSE(data->lite_page_received());
+
+ EXPECT_FALSE(data->lofi_received());
+ data->set_lofi_received(true);
+ EXPECT_TRUE(data->lofi_received());
+ data->set_lofi_received(false);
+ EXPECT_FALSE(data->lofi_received());
+
EXPECT_EQ(std::string(), data->session_key());
- EXPECT_EQ(GURL(std::string()), data->request_url());
std::string session_key = "test-key";
data->set_session_key(session_key);
EXPECT_EQ(session_key, data->session_key());
+
+ EXPECT_EQ(GURL(std::string()), data->request_url());
GURL test_url("test-url");
data->set_request_url(test_url);
EXPECT_EQ(test_url, data->request_url());
+
EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
data->effective_connection_type());
data->set_effective_connection_type(net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_OFFLINE,
data->effective_connection_type());
+
+ EXPECT_FALSE(data->page_id());
+ uint64_t page_id = 1;
+ data->set_page_id(page_id);
+ EXPECT_EQ(page_id, data->page_id().value());
}
TEST_F(DataReductionProxyDataTest, AddToURLRequest) {
@@ -76,7 +98,7 @@ TEST_F(DataReductionProxyDataTest, AddToURLRequest) {
TEST_F(DataReductionProxyDataTest, DeepCopy) {
const struct {
bool data_reduction_used;
- bool lofi_on;
+ bool lofi_test_value;
} tests[] = {
{
false, true,
@@ -97,17 +119,23 @@ TEST_F(DataReductionProxyDataTest, DeepCopy) {
static const GURL kTestURL("test-url");
std::unique_ptr<DataReductionProxyData> data(new DataReductionProxyData());
data->set_used_data_reduction_proxy(tests[i].data_reduction_used);
- data->set_lofi_requested(tests[i].lofi_on);
+ data->set_lofi_requested(tests[i].lofi_test_value);
+ data->set_lite_page_received(tests[i].lofi_test_value);
+ data->set_lofi_received(tests[i].lofi_test_value);
data->set_session_key(kSessionKey);
data->set_request_url(kTestURL);
data->set_effective_connection_type(net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
+ data->set_page_id(2u);
std::unique_ptr<DataReductionProxyData> copy = data->DeepCopy();
- EXPECT_EQ(tests[i].lofi_on, copy->lofi_requested());
+ EXPECT_EQ(tests[i].lofi_test_value, copy->lofi_requested());
+ EXPECT_EQ(tests[i].lofi_test_value, copy->lite_page_received());
+ EXPECT_EQ(tests[i].lofi_test_value, copy->lofi_received());
EXPECT_EQ(tests[i].data_reduction_used, copy->used_data_reduction_proxy());
EXPECT_EQ(kSessionKey, copy->session_key());
EXPECT_EQ(kTestURL, copy->request_url());
EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_OFFLINE,
copy->effective_connection_type());
+ EXPECT_EQ(2u, data->page_id().value());
}
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
index a9c344e187b..12c809f54e4 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
@@ -99,7 +99,7 @@ void DataReductionProxyDelegate::OnResolveProxy(
!config_->secure_proxy_allowed(), proxies_for_http);
OnResolveProxyHandler(url, method, proxy_config,
- proxy_service.proxy_retry_info(), config_, io_data_,
+ proxy_service.proxy_retry_info(), *config_, io_data_,
result);
if (!first_data_saver_request_recorded_ && !result->is_empty() &&
@@ -244,9 +244,7 @@ bool DataReductionProxyDelegate::SupportsQUIC(
const net::ProxyServer& proxy_server) const {
DCHECK(thread_checker_.CalledOnValidThread());
// Enable QUIC for whitelisted proxies.
- // TODO(tbansal): Use client config service to control this whitelist.
- return base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDataReductionProxyEnableQuicOnNonCoreProxies) ||
+ return params::IsQuicEnabledForNonCoreProxies() ||
proxy_server ==
net::ProxyServer(net::ProxyServer::SCHEME_HTTPS,
net::HostPortPair(kDataReductionCoreProxy, 443));
@@ -277,12 +275,11 @@ void OnResolveProxyHandler(
const std::string& method,
const net::ProxyConfig& proxy_config,
const net::ProxyRetryInfoMap& proxy_retry_info,
- const DataReductionProxyConfig* data_reduction_proxy_config,
+ const DataReductionProxyConfig& data_reduction_proxy_config,
DataReductionProxyIOData* io_data,
net::ProxyInfo* result) {
- DCHECK(data_reduction_proxy_config);
DCHECK(result->is_empty() || result->is_direct() ||
- !data_reduction_proxy_config->IsDataReductionProxy(
+ !data_reduction_proxy_config.IsDataReductionProxy(
result->proxy_server(), NULL));
if (!util::EligibleForDataReductionProxy(*result, url, method))
@@ -306,12 +303,12 @@ void OnResolveProxyHandler(
// The |proxy_config| must be valid otherwise the proxy cannot be used.
DCHECK(proxy_config.is_valid() || !data_saver_proxy_used);
- if (data_reduction_proxy_config->enabled_by_user_and_reachable() &&
- url.SchemeIsHTTPOrHTTPS() && !url.SchemeIsCryptographic() &&
- !net::IsLocalhost(url.host()) &&
- (!proxy_config.is_valid() || data_saver_proxy_used)) {
- UMA_HISTOGRAM_BOOLEAN("DataReductionProxy.ConfigService.HTTPRequests",
- data_saver_proxy_used);
+ if (data_reduction_proxy_config.enabled_by_user_and_reachable() &&
+ url.SchemeIs(url::kHttpScheme) && !net::IsLocalhost(url.host_piece()) &&
+ !params::IsIncludedInHoldbackFieldTrial()) {
+ UMA_HISTOGRAM_BOOLEAN(
+ "DataReductionProxy.ConfigService.HTTPRequests",
+ !data_reduction_proxy_config.GetProxiesForHttp().empty());
}
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h
index 2b54b4672ec..d412dc3b1cc 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h
@@ -157,7 +157,7 @@ void OnResolveProxyHandler(
const std::string& method,
const net::ProxyConfig& proxy_config,
const net::ProxyRetryInfoMap& proxy_retry_info,
- const DataReductionProxyConfig* data_reduction_proxy_config,
+ const DataReductionProxyConfig& data_reduction_proxy_config,
DataReductionProxyIOData* io_data,
net::ProxyInfo* result);
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
index fb48f0e39bd..f7a2306fd34 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
@@ -772,7 +772,7 @@ TEST_F(DataReductionProxyDelegateTest, OnResolveProxyHandler) {
// Another proxy is used. It should be used afterwards.
result.Use(other_proxy_info);
OnResolveProxyHandler(url, "GET", data_reduction_proxy_config,
- empty_proxy_retry_info, config(), nullptr, &result);
+ empty_proxy_retry_info, *config(), nullptr, &result);
EXPECT_EQ(other_proxy_info.proxy_server(), result.proxy_server());
// A direct connection is used. The data reduction proxy should be used
@@ -781,7 +781,7 @@ TEST_F(DataReductionProxyDelegateTest, OnResolveProxyHandler) {
result.Use(direct_proxy_info);
net::ProxyConfig::ID prev_id = result.config_id();
OnResolveProxyHandler(url, "GET", data_reduction_proxy_config,
- empty_proxy_retry_info, config(), nullptr, &result);
+ empty_proxy_retry_info, *config(), nullptr, &result);
EXPECT_EQ(data_reduction_proxy_info.proxy_server(), result.proxy_server());
// Only the proxy list should be updated, not the proxy info.
EXPECT_EQ(result.config_id(), prev_id);
@@ -792,7 +792,7 @@ TEST_F(DataReductionProxyDelegateTest, OnResolveProxyHandler) {
prev_id = result.config_id();
OnResolveProxyHandler(
GURL("ws://echo.websocket.org/"), "GET", data_reduction_proxy_config,
- data_reduction_proxy_retry_info, config(), nullptr, &result);
+ data_reduction_proxy_retry_info, *config(), nullptr, &result);
EXPECT_TRUE(result.proxy_server().is_direct());
EXPECT_EQ(result.config_id(), prev_id);
@@ -800,30 +800,30 @@ TEST_F(DataReductionProxyDelegateTest, OnResolveProxyHandler) {
result.UseDirect();
OnResolveProxyHandler(GURL("wss://echo.websocket.org/"), "GET",
data_reduction_proxy_config, empty_proxy_retry_info,
- config(), nullptr, &result);
+ *config(), nullptr, &result);
EXPECT_TRUE(result.is_direct());
result.UseDirect();
OnResolveProxyHandler(GURL("wss://echo.websocket.org/"), "GET",
data_reduction_proxy_config, empty_proxy_retry_info,
- config(), nullptr, &result);
+ *config(), nullptr, &result);
EXPECT_TRUE(result.is_direct());
// POST methods go direct.
result.UseDirect();
OnResolveProxyHandler(url, "POST", data_reduction_proxy_config,
- empty_proxy_retry_info, config(), nullptr, &result);
+ empty_proxy_retry_info, *config(), nullptr, &result);
EXPECT_TRUE(result.is_direct());
// Without DataCompressionProxyCriticalBypass Finch trial set, the
// BYPASS_DATA_REDUCTION_PROXY load flag should be ignored.
result.UseDirect();
OnResolveProxyHandler(url, "GET", data_reduction_proxy_config,
- empty_proxy_retry_info, config(), nullptr, &result);
+ empty_proxy_retry_info, *config(), nullptr, &result);
EXPECT_FALSE(result.is_direct());
OnResolveProxyHandler(url, "GET", data_reduction_proxy_config,
- empty_proxy_retry_info, config(), nullptr,
+ empty_proxy_retry_info, *config(), nullptr,
&other_proxy_info);
EXPECT_FALSE(other_proxy_info.is_direct());
}
@@ -907,15 +907,14 @@ TEST_F(DataReductionProxyDelegateTest, HTTPRequests) {
net::ProxyInfo result;
result.Use(direct_proxy_info);
OnResolveProxyHandler(url, "GET", data_reduction_proxy_config,
- empty_proxy_retry_info, config(), nullptr, &result);
+ empty_proxy_retry_info, *config(), nullptr, &result);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.ConfigService.HTTPRequests",
test.expect_histogram ? 1 : 0);
if (test.expect_histogram) {
histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.ConfigService.HTTPRequests",
- test.use_direct_proxy ? 0 : 1, 1);
+ "DataReductionProxy.ConfigService.HTTPRequests", 1, 1);
}
}
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
index 70390e396ac..4d8f08897a2 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
@@ -14,6 +14,7 @@
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/test/histogram_tester.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
@@ -399,6 +400,64 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, RedirectWithoutRetry) {
EXPECT_EQ(1, delegate().received_redirect_count());
}
+// Test that data reduction proxy is byppassed if there is a URL redirect cycle.
+TEST_F(DataReductionProxyInterceptorEndToEndTest, URLRedirectCycle) {
+ base::HistogramTester histogram_tester;
+ MockRead redirect_mock_reads_1[] = {
+ MockRead("HTTP/1.1 302 Found\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Location: http://bar.com/\r\n\r\n"),
+ MockRead(""), MockRead(net::SYNCHRONOUS, net::OK),
+ };
+ net::StaticSocketDataProvider redirect_socket_data_provider_1(
+ redirect_mock_reads_1, arraysize(redirect_mock_reads_1), nullptr, 0);
+ mock_socket_factory()->AddSocketDataProvider(
+ &redirect_socket_data_provider_1);
+
+ MockRead redirect_mock_reads_2[] = {
+ MockRead("HTTP/1.1 302 Found\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Location: http://foo.com/\r\n\r\n"),
+ MockRead(""), MockRead(net::SYNCHRONOUS, net::OK),
+ };
+ net::StaticSocketDataProvider redirect_socket_data_provider_2(
+ redirect_mock_reads_2, arraysize(redirect_mock_reads_2), nullptr, 0);
+ mock_socket_factory()->AddSocketDataProvider(
+ &redirect_socket_data_provider_2);
+
+ // Redirect cycle.
+ MockRead redirect_mock_reads_3[] = {
+ MockRead("HTTP/1.1 302 Found\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Location: http://bar.com/\r\n\r\n"),
+ MockRead(""), MockRead(net::SYNCHRONOUS, net::OK),
+ };
+ net::StaticSocketDataProvider redirect_socket_data_provider_3(
+ redirect_mock_reads_3, arraysize(redirect_mock_reads_3), nullptr, 0);
+ mock_socket_factory()->AddSocketDataProvider(
+ &redirect_socket_data_provider_3);
+
+ // Data reduction proxy should be bypassed.
+ MockRead redirect_mock_reads_4[] = {
+ MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead(kBody.c_str()),
+ MockRead(net::SYNCHRONOUS, net::OK),
+ };
+ net::StaticSocketDataProvider redirect_socket_data_provider_4(
+ redirect_mock_reads_4, arraysize(redirect_mock_reads_4), nullptr, 0);
+ mock_socket_factory()->AddSocketDataProvider(
+ &redirect_socket_data_provider_4);
+
+ std::unique_ptr<net::URLRequest> request =
+ CreateAndExecuteRequest(GURL("http://foo.com"));
+
+ EXPECT_EQ(net::OK, delegate().request_status());
+ EXPECT_EQ(200, request->GetResponseCode());
+ EXPECT_EQ(kBody, delegate().data_received());
+ EXPECT_FALSE(request->was_fetched_via_proxy());
+ histogram_tester.ExpectTotalCount(
+ "DataReductionProxy.BypassedBytes.URLRedirectCycle", 1);
+}
+
TEST_F(DataReductionProxyInterceptorEndToEndTest, ResponseWithBypassAndRetry) {
// The first try gives a bypass.
MockRead initial_mock_reads[] = {
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc
index b9a4168edbc..cfe96f4bfc4 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc
@@ -36,7 +36,7 @@ DataReductionProxyRequestType GetDataReductionProxyRequestType(
// Data Reduction Proxy, since 304s aren't required to have a Via header even
// if they came through the Data Reduction Proxy.
if (request.response_headers() &&
- (HasDataReductionProxyViaHeader(request.response_headers(), nullptr) ||
+ (HasDataReductionProxyViaHeader(*request.response_headers(), nullptr) ||
(request.response_headers()->response_code() == net::HTTP_NOT_MODIFIED &&
config.WasDataReductionProxyUsed(&request, nullptr)))) {
return VIA_DATA_REDUCTION_PROXY;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
index 8bae820f90e..12d8b56770d 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -23,6 +23,7 @@
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_util.h"
#include "components/data_reduction_proxy/core/common/lofi_decider.h"
#include "net/base/load_flags.h"
+#include "net/base/mime_util.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/nqe/network_quality_estimator.h"
@@ -46,27 +47,31 @@ namespace {
// |freshness_lifetime| contains information on how long the resource will be
// fresh for and how long is the usability.
void RecordContentLengthHistograms(bool lofi_low_header_added,
+ bool is_https,
+ bool is_video,
int64_t received_content_length,
int64_t original_content_length,
const base::TimeDelta& freshness_lifetime) {
// Add the current resource to these histograms only when a valid
// X-Original-Content-Length header is present.
if (original_content_length >= 0) {
- UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthWithValidOCL",
- received_content_length);
- UMA_HISTOGRAM_COUNTS("Net.HttpOriginalContentLengthWithValidOCL",
- original_content_length);
- UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthDifferenceWithValidOCL",
- original_content_length - received_content_length);
+ UMA_HISTOGRAM_COUNTS_1M("Net.HttpContentLengthWithValidOCL",
+ received_content_length);
+ UMA_HISTOGRAM_COUNTS_1M("Net.HttpOriginalContentLengthWithValidOCL",
+ original_content_length);
+ UMA_HISTOGRAM_COUNTS_1M("Net.HttpContentLengthDifferenceWithValidOCL",
+ original_content_length - received_content_length);
// Populate Lo-Fi content length histograms.
if (lofi_low_header_added) {
- UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthWithValidOCL.LoFiOn",
- received_content_length);
- UMA_HISTOGRAM_COUNTS("Net.HttpOriginalContentLengthWithValidOCL.LoFiOn",
- original_content_length);
- UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthDifferenceWithValidOCL.LoFiOn",
- original_content_length - received_content_length);
+ UMA_HISTOGRAM_COUNTS_1M("Net.HttpContentLengthWithValidOCL.LoFiOn",
+ received_content_length);
+ UMA_HISTOGRAM_COUNTS_1M(
+ "Net.HttpOriginalContentLengthWithValidOCL.LoFiOn",
+ original_content_length);
+ UMA_HISTOGRAM_COUNTS_1M(
+ "Net.HttpContentLengthDifferenceWithValidOCL.LoFiOn",
+ original_content_length - received_content_length);
}
} else {
@@ -74,11 +79,22 @@ void RecordContentLengthHistograms(bool lofi_low_header_added,
// length if the X-Original-Content-Header is not present.
original_content_length = received_content_length;
}
- UMA_HISTOGRAM_COUNTS("Net.HttpContentLength", received_content_length);
- UMA_HISTOGRAM_COUNTS("Net.HttpOriginalContentLength",
- original_content_length);
- UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthDifference",
- original_content_length - received_content_length);
+ UMA_HISTOGRAM_COUNTS_1M("Net.HttpContentLength", received_content_length);
+ if (is_https) {
+ UMA_HISTOGRAM_COUNTS_1M("Net.HttpContentLength.Https",
+ received_content_length);
+ } else {
+ UMA_HISTOGRAM_COUNTS_1M("Net.HttpContentLength.Http",
+ received_content_length);
+ }
+ if (is_video) {
+ UMA_HISTOGRAM_COUNTS_1M("Net.HttpContentLength.Video",
+ received_content_length);
+ }
+ UMA_HISTOGRAM_COUNTS_1M("Net.HttpOriginalContentLength",
+ original_content_length);
+ UMA_HISTOGRAM_COUNTS_1M("Net.HttpContentLengthDifference",
+ original_content_length - received_content_length);
UMA_HISTOGRAM_CUSTOM_COUNTS("Net.HttpContentFreshnessLifetime",
freshness_lifetime.InSeconds(),
base::TimeDelta::FromHours(1).InSeconds(),
@@ -86,17 +102,17 @@ void RecordContentLengthHistograms(bool lofi_low_header_added,
100);
if (freshness_lifetime.InSeconds() <= 0)
return;
- UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthCacheable",
- received_content_length);
+ UMA_HISTOGRAM_COUNTS_1M("Net.HttpContentLengthCacheable",
+ received_content_length);
if (freshness_lifetime.InHours() < 4)
return;
- UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthCacheable4Hours",
- received_content_length);
+ UMA_HISTOGRAM_COUNTS_1M("Net.HttpContentLengthCacheable4Hours",
+ received_content_length);
if (freshness_lifetime.InHours() < 24)
return;
- UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthCacheable24Hours",
- received_content_length);
+ UMA_HISTOGRAM_COUNTS_1M("Net.HttpContentLengthCacheable24Hours",
+ received_content_length);
}
// Given a |request| that went through the Data Reduction Proxy, this function
@@ -113,6 +129,19 @@ int64_t EstimateOriginalReceivedBytes(const net::URLRequest& request) {
util::CalculateEffectiveOCL(request);
}
+// Verifies that the chrome proxy related request headers are set correctly.
+// |via_chrome_proxy| is true if the request is being fetched via Chrome Data
+// Saver proxy.
+void VerifyHttpRequestHeaders(bool via_chrome_proxy,
+ const net::HttpRequestHeaders& headers) {
+ if (via_chrome_proxy) {
+ DCHECK(headers.HasHeader(chrome_proxy_header()));
+ } else {
+ DCHECK(!headers.HasHeader(chrome_proxy_header()));
+ DCHECK(!headers.HasHeader(chrome_proxy_accept_transform_header()));
+ }
+}
+
} // namespace
DataReductionProxyNetworkDelegate::DataReductionProxyNetworkDelegate(
@@ -205,6 +234,17 @@ void DataReductionProxyNetworkDelegate::OnBeforeSendHeadersInternal(
DCHECK(data_reduction_proxy_config_);
DCHECK(request);
+ // If there was a redirect or request bypass, use the same page ID for both
+ // requests. As long as the session ID has not changed. Re-issued requests
+ // and client redirects will be assigned a new page ID as they are different
+ // URLRequests.
+ DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
+ base::Optional<uint64_t> page_id;
+ if (data && data->session_key() ==
+ data_reduction_proxy_request_options_->GetSecureSession()) {
+ page_id = data->page_id();
+ }
+
// Reset |request|'s DataReductionProxyData.
DataReductionProxyData::ClearData(request);
@@ -212,10 +252,10 @@ void DataReductionProxyNetworkDelegate::OnBeforeSendHeadersInternal(
if (!WasEligibleWithoutHoldback(*request, proxy_info, proxy_retry_info))
return;
// For the holdback field trial, still log UMA as if the proxy was used.
- DataReductionProxyData* data =
- DataReductionProxyData::GetDataAndCreateIfNecessary(request);
+ data = DataReductionProxyData::GetDataAndCreateIfNecessary(request);
if (data)
data->set_used_data_reduction_proxy(true);
+ VerifyHttpRequestHeaders(false, *headers);
return;
}
@@ -241,23 +281,26 @@ void DataReductionProxyNetworkDelegate::OnBeforeSendHeadersInternal(
// Chrome-Proxy-Accept-Transform header.
lofi_decider->RemoveAcceptTransformHeader(headers);
}
+ VerifyHttpRequestHeaders(false, *headers);
return;
}
// Retrieves DataReductionProxyData from a request, creating a new instance
// if needed.
- DataReductionProxyData* data =
- DataReductionProxyData::GetDataAndCreateIfNecessary(request);
+ data = DataReductionProxyData::GetDataAndCreateIfNecessary(request);
if (data) {
data->set_used_data_reduction_proxy(true);
- data->set_session_key(
- data_reduction_proxy_request_options_->GetSecureSession());
- data->set_request_url(request->url());
- if ((request->load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED) &&
- request->context()->network_quality_estimator()) {
- data->set_effective_connection_type(request->context()
- ->network_quality_estimator()
- ->GetEffectiveConnectionType());
+ // Only set GURL, NQE and session key string for main frame requests since
+ // they are not needed for sub-resources.
+ if (request->load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED) {
+ data->set_session_key(
+ data_reduction_proxy_request_options_->GetSecureSession());
+ data->set_request_url(request->url());
+ if (request->context()->network_quality_estimator()) {
+ data->set_effective_connection_type(request->context()
+ ->network_quality_estimator()
+ ->GetEffectiveConnectionType());
+ }
}
}
@@ -274,17 +317,46 @@ void DataReductionProxyNetworkDelegate::OnBeforeSendHeadersInternal(
}
MaybeAddBrotliToAcceptEncodingHeader(proxy_info, headers, *request);
- data_reduction_proxy_request_options_->AddRequestHeader(headers);
+ // Generate a page ID for main frame requests that don't already have one.
+ // TODO(ryansturm): remove LOAD_MAIN_FRAME_DEPRECATED from d_r_p.
+ // crbug.com/709621
+ if (request->load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED) {
+ if (!page_id) {
+ page_id = data_reduction_proxy_request_options_->GeneratePageId();
+ }
+ data->set_page_id(page_id.value());
+ }
+
+ data_reduction_proxy_request_options_->AddRequestHeader(headers, page_id);
+
if (lofi_decider)
lofi_decider->MaybeSetIgnorePreviewsBlacklistDirective(headers);
+ VerifyHttpRequestHeaders(true, *headers);
}
void DataReductionProxyNetworkDelegate::OnBeforeRedirectInternal(
net::URLRequest* request,
const GURL& new_location) {
// Since this is after a redirect response, reset |request|'s
- // DataReductionProxyData.
+ // DataReductionProxyData, but keep page ID and session.
+ // TODO(ryansturm): Change ClearData logic to have persistent and
+ // non-persistent (WRT redirects) data.
+ // crbug.com/709564
+ DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
+ base::Optional<uint64_t> page_id;
+ if (data && data->session_key() ==
+ data_reduction_proxy_request_options_->GetSecureSession()) {
+ page_id = data->page_id();
+ }
+
DataReductionProxyData::ClearData(request);
+
+ if (page_id) {
+ data = DataReductionProxyData::GetDataAndCreateIfNecessary(request);
+ data->set_page_id(page_id.value());
+ data->set_session_key(
+ data_reduction_proxy_request_options_->GetSecureSession());
+ }
}
void DataReductionProxyNetworkDelegate::OnCompletedInternal(
@@ -338,6 +410,25 @@ void DataReductionProxyNetworkDelegate::OnCompletedInternal(
RecordContentLength(*request, request_type, original_content_length);
}
+void DataReductionProxyNetworkDelegate::OnHeadersReceivedInternal(
+ net::URLRequest* request,
+ const net::CompletionCallback& callback,
+ const net::HttpResponseHeaders* original_response_headers,
+ scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
+ GURL* allowed_unsafe_redirect_url) {
+ if (!original_response_headers)
+ return;
+ if (IsEmptyImagePreview(*original_response_headers)) {
+ DataReductionProxyData* data =
+ DataReductionProxyData::GetDataAndCreateIfNecessary(request);
+ data->set_lofi_received(true);
+ } else if (IsLitePagePreview(*original_response_headers)) {
+ DataReductionProxyData* data =
+ DataReductionProxyData::GetDataAndCreateIfNecessary(request);
+ data->set_lite_page_received(true);
+ }
+}
+
void DataReductionProxyNetworkDelegate::CalculateAndRecordDataUsage(
const net::URLRequest& request,
DataReductionProxyRequestType request_type) {
@@ -395,14 +486,21 @@ void DataReductionProxyNetworkDelegate::RecordContentLength(
->GetFreshnessLifetimes(request.response_info().response_time)
.freshness;
+ bool is_https = request.url().SchemeIs("https");
+ bool is_video = false;
+ std::string mime_type;
+ if (request.response_headers()->GetMimeType(&mime_type)) {
+ is_video = net::MatchesMimeType("video/*", mime_type);
+ }
+
RecordContentLengthHistograms(
// |data_reduction_proxy_io_data_| can be NULL for Webview.
data_reduction_proxy_io_data_ &&
data_reduction_proxy_io_data_->IsEnabled() &&
data_reduction_proxy_io_data_->lofi_decider() &&
data_reduction_proxy_io_data_->lofi_decider()->IsUsingLoFi(request),
- request.received_response_content_length(), original_content_length,
- freshness_lifetime);
+ is_https, is_video, request.received_response_content_length(),
+ original_content_length, freshness_lifetime);
if (data_reduction_proxy_io_data_ && data_reduction_proxy_bypass_stats_) {
// Record BypassedBytes histograms for the request.
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
index f36cea458de..33c717f128e 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
@@ -115,6 +115,15 @@ class DataReductionProxyNetworkDelegate : public net::LayeredNetworkDelegate {
void OnCompletedInternal(net::URLRequest* request,
bool started) override;
+ // Checks if a LoFi or Lite Pages response was received and sets the state on
+ // DataReductionProxyData for |request|.
+ void OnHeadersReceivedInternal(
+ net::URLRequest* request,
+ const net::CompletionCallback& callback,
+ const net::HttpResponseHeaders* original_response_headers,
+ scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
+ GURL* allowed_unsafe_redirect_url) override;
+
// Calculates actual data usage that went over the network at the HTTP layer
// (e.g. not including network layer overhead) and estimates original data
// usage for |request|.
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
index 028c43e6088..5c3886d257a 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -12,11 +12,13 @@
#include <utility>
#include "base/command_line.h"
+#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial.h"
#include "base/numerics/safe_conversions.h"
+#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -57,6 +59,7 @@
#include "net/test/test_data_directory.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job_factory_impl.h"
+#include "net/url_request/url_request_status.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -69,6 +72,38 @@ using TestNetworkDelegate = net::NetworkDelegateImpl;
const char kOtherProxy[] = "testproxy:17";
const char kTestURL[] = "http://www.google.com/";
+const char kSecureTestURL[] = "https://www.google.com/";
+
+const std::string kReceivedValidOCLHistogramName =
+ "Net.HttpContentLengthWithValidOCL";
+const std::string kOriginalValidOCLHistogramName =
+ "Net.HttpOriginalContentLengthWithValidOCL";
+const std::string kDifferenceValidOCLHistogramName =
+ "Net.HttpContentLengthDifferenceWithValidOCL";
+
+// Lo-Fi histograms.
+const std::string kReceivedValidOCLLoFiOnHistogramName =
+ "Net.HttpContentLengthWithValidOCL.LoFiOn";
+const std::string kOriginalValidOCLLoFiOnHistogramName =
+ "Net.HttpOriginalContentLengthWithValidOCL.LoFiOn";
+const std::string kDifferenceValidOCLLoFiOnHistogramName =
+ "Net.HttpContentLengthDifferenceWithValidOCL.LoFiOn";
+
+const std::string kReceivedHistogramName = "Net.HttpContentLength";
+const std::string kReceivedInsecureHistogramName = "Net.HttpContentLength.Http";
+const std::string kReceivedSecureHistogramName = "Net.HttpContentLength.Https";
+const std::string kReceivedVideoHistogramName = "Net.HttpContentLength.Video";
+const std::string kOriginalHistogramName = "Net.HttpOriginalContentLength";
+const std::string kDifferenceHistogramName = "Net.HttpContentLengthDifference";
+const std::string kFreshnessLifetimeHistogramName =
+ "Net.HttpContentFreshnessLifetime";
+const std::string kCacheableHistogramName = "Net.HttpContentLengthCacheable";
+const std::string kCacheable4HoursHistogramName =
+ "Net.HttpContentLengthCacheable4Hours";
+const std::string kCacheable24HoursHistogramName =
+ "Net.HttpContentLengthCacheable24Hours";
+const int64_t kResponseContentLength = 100;
+const int64_t kOriginalContentLength = 200;
#if defined(OS_ANDROID)
const Client kClient = Client::CHROME_ANDROID;
@@ -177,29 +212,48 @@ class TestLoFiUIService : public LoFiUIService {
bool on_lofi_response_;
};
+enum ProxyTestConfig { USE_SECURE_PROXY, USE_INSECURE_PROXY, BYPASS_PROXY };
+
class DataReductionProxyNetworkDelegateTest : public testing::Test {
public:
DataReductionProxyNetworkDelegateTest()
- : context_(true), context_storage_(&context_) {}
-
- void Init(bool use_secure_proxy, bool enable_brotli_globally) {
- net::ProxyServer proxy_server =
- use_secure_proxy
- ? net::ProxyServer::FromURI("https://origin.net:443",
- net::ProxyServer::SCHEME_HTTPS)
- : net::ProxyServer::FromURI("http://origin.net:80",
- net::ProxyServer::SCHEME_HTTP);
+ : context_(true),
+ context_storage_(&context_),
+ ssl_socket_data_provider_(net::ASYNC, net::OK) {
+ ssl_socket_data_provider_.next_proto = net::kProtoHTTP11;
+ ssl_socket_data_provider_.cert = net::ImportCertFromFile(
+ net::GetTestCertsDirectory(), "unittest.selfsigned.der");
+ }
+ void Init(ProxyTestConfig proxy_config, bool enable_brotli_globally) {
+ net::ProxyServer proxy_server;
+ switch (proxy_config) {
+ case BYPASS_PROXY:
+ proxy_server = net::ProxyServer::Direct();
+ break;
+ case USE_SECURE_PROXY:
+ proxy_server = net::ProxyServer::FromURI(
+ "https://origin.net:443", net::ProxyServer::SCHEME_HTTPS);
+ break;
+ case USE_INSECURE_PROXY:
+ proxy_server = net::ProxyServer::FromURI("http://origin.net:80",
+ net::ProxyServer::SCHEME_HTTP);
+ break;
+ }
proxy_service_ =
net::ProxyService::CreateFixedFromPacResult(proxy_server.ToPacString());
context_.set_proxy_service(proxy_service_.get());
- test_context_ = (DataReductionProxyTestContext::Builder()
- .WithClient(kClient)
- .WithMockClientSocketFactory(&mock_socket_factory_)
- .WithURLRequestContext(&context_)
- .WithProxiesForHttp({DataReductionProxyServer(
- proxy_server, ProxyServer::UNSPECIFIED_TYPE)})
- .Build());
+ DataReductionProxyTestContext::Builder builder;
+ builder = builder.WithClient(kClient)
+ .WithMockClientSocketFactory(&mock_socket_factory_)
+ .WithURLRequestContext(&context_);
+
+ if (proxy_config != BYPASS_PROXY) {
+ builder = builder.WithProxiesForHttp({DataReductionProxyServer(
+ proxy_server, ProxyServer::UNSPECIFIED_TYPE)});
+ }
+
+ test_context_ = builder.Build();
context_.set_client_socket_factory(&mock_socket_factory_);
test_context_->AttachToURLRequestContext(&context_storage_);
@@ -213,6 +267,7 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
test_context_->io_data()->set_lofi_ui_service(std::move(lofi_ui_service));
context_.set_enable_brotli(enable_brotli_globally);
+ context_.set_network_quality_estimator(&test_network_quality_estimator_);
context_.Init();
test_context_->EnableDataReductionProxyWithSecureProxyCheckSuccess();
@@ -253,7 +308,8 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
const GURL& url,
net::HttpRequestHeaders* request_headers,
const std::string& response_headers,
- int64_t response_content_length) {
+ int64_t response_content_length,
+ int load_flags) {
const std::string response_body(
base::checked_cast<size_t>(response_content_length), ' ');
@@ -268,12 +324,31 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
context_.CreateRequest(url, net::IDLE, &delegate);
if (request_headers)
request->SetExtraRequestHeaders(*request_headers);
+ request->SetLoadFlags(request->load_flags() | load_flags);
request->Start();
base::RunLoop().RunUntilIdle();
return request;
}
+ // Reads brotli encoded content to |encoded_brotli_buffer_|.
+ void ReadBrotliFile() {
+ // Get the path of data directory.
+ const size_t kDefaultBufferSize = 4096;
+ base::FilePath data_dir;
+ PathService::Get(base::DIR_SOURCE_ROOT, &data_dir);
+ data_dir = data_dir.AppendASCII("net");
+ data_dir = data_dir.AppendASCII("data");
+ data_dir = data_dir.AppendASCII("filter_unittests");
+
+ // Read data from the encoded file into buffer.
+ base::FilePath encoded_file_path;
+ encoded_file_path = data_dir.AppendASCII("google.br");
+ ASSERT_TRUE(
+ base::ReadFileToString(encoded_file_path, &encoded_brotli_buffer_));
+ ASSERT_GE(kDefaultBufferSize, encoded_brotli_buffer_.size());
+ }
+
// Fetches a single URL request, verifies the correctness of Accept-Encoding
// header, and verifies that the response is cached only if |expect_cached|
// is set to true. Each line in |response_headers| should end with "\r\n" and
@@ -284,17 +359,21 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
const std::string& response_headers,
bool expect_cached,
bool expect_brotli) {
+ test_network_quality_estimator()->set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
GURL url(kTestURL);
- net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
int response_body_size = 140;
- const std::string response_body(
- base::checked_cast<size_t>(response_body_size), ' ');
+ std::string response_body;
+ if (expect_brotli && !expect_cached) {
+ response_body = encoded_brotli_buffer_;
+ response_body_size = response_body.size();
+ } else {
+ response_body =
+ std::string(base::checked_cast<size_t>(response_body_size), ' ');
+ }
- ssl_socket_data_provider.next_proto = net::kProtoHTTP11;
- ssl_socket_data_provider.cert = net::ImportCertFromFile(
- net::GetTestCertsDirectory(), "unittest.selfsigned.der");
- mock_socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
+ mock_socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider_);
net::MockRead reads[] = {net::MockRead(response_headers.c_str()),
net::MockRead(response_body.c_str()),
@@ -358,6 +437,8 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
request->Start();
base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0, request->status().ToNetError());
+
if (!expect_cached) {
EXPECT_EQ(response_body_size,
request->received_response_content_length());
@@ -367,6 +448,10 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
VerifyBrotliPresent(request.get(), expect_brotli);
} else {
EXPECT_TRUE(request->was_cached());
+ std::string content_encoding_value;
+ request->GetResponseHeaderByName("Content-Encoding",
+ &content_encoding_value);
+ EXPECT_EQ(expect_brotli, content_encoding_value == "br");
}
}
@@ -377,15 +462,93 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
EXPECT_TRUE(request_headers_sent.GetHeader("Accept-Encoding",
&accept_encoding_value));
EXPECT_NE(std::string::npos, accept_encoding_value.find("gzip"));
+
+ std::string content_encoding_value;
+ request->GetResponseHeaderByName("Content-Encoding",
+ &content_encoding_value);
+
if (expect_brotli) {
// Brotli should be the last entry in the Accept-Encoding header.
EXPECT_EQ(accept_encoding_value.length() - 2,
accept_encoding_value.find("br"));
+ EXPECT_EQ("br", content_encoding_value);
} else {
EXPECT_EQ(std::string::npos, accept_encoding_value.find("br"));
}
}
+ void FetchURLRequestAndVerifyPageIdDirective(const std::string& page_id_value,
+ bool redirect_once) {
+ std::string response_headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Length: 140\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "x-original-content-length: 200\r\n"
+ "Cache-Control: max-age=1200\r\n"
+ "Vary: accept-encoding\r\n\r\n";
+
+ GURL url(kTestURL);
+
+ int response_body_size = 140;
+ std::string response_body =
+ std::string(base::checked_cast<size_t>(response_body_size), ' ');
+
+ mock_socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider_);
+
+ net::MockRead redirect_reads[] = {
+ net::MockRead("HTTP/1.1 302 Redirect\r\n"),
+ net::MockRead("Location: http://www.google.com/\r\n"),
+ net::MockRead("Content-Length: 0\r\n\r\n"),
+ net::MockRead(net::SYNCHRONOUS, net::OK),
+ net::MockRead(response_headers.c_str()),
+ net::MockRead(response_body.c_str()),
+ net::MockRead(net::SYNCHRONOUS, net::OK)};
+
+ net::MockRead reads[] = {net::MockRead(response_headers.c_str()),
+ net::MockRead(response_body.c_str()),
+ net::MockRead(net::SYNCHRONOUS, net::OK)};
+
+ EXPECT_FALSE(
+ io_data()->test_request_options()->GetHeaderValueForTesting().empty());
+
+ std::string mock_write =
+ "GET http://www.google.com/ HTTP/1.1\r\nHost: "
+ "www.google.com\r\nProxy-Connection: "
+ "keep-alive\r\nUser-Agent:\r\nAccept-Encoding: gzip, "
+ "deflate\r\nAccept-Language: en-us,fr\r\n"
+ "Chrome-Proxy: " +
+ io_data()->test_request_options()->GetHeaderValueForTesting() +
+ (page_id_value.empty() ? "" : (", " + page_id_value)) + "\r\n\r\n";
+
+ net::MockWrite redirect_writes[] = {net::MockWrite(mock_write.c_str()),
+ net::MockWrite(mock_write.c_str())};
+
+ net::MockWrite writes[] = {net::MockWrite(mock_write.c_str())};
+
+ std::unique_ptr<net::StaticSocketDataProvider> socket;
+ if (!redirect_once) {
+ socket = base::MakeUnique<net::StaticSocketDataProvider>(
+ reads, arraysize(reads), writes, arraysize(writes));
+ } else {
+ socket = base::MakeUnique<net::StaticSocketDataProvider>(
+ redirect_reads, arraysize(redirect_reads), redirect_writes,
+ arraysize(redirect_writes));
+ }
+
+ mock_socket_factory_.AddSocketDataProvider(socket.get());
+
+ net::TestDelegate delegate;
+ std::unique_ptr<net::URLRequest> request =
+ context_.CreateRequest(url, net::IDLE, &delegate);
+ if (!page_id_value.empty()) {
+ request->SetLoadFlags(request->load_flags() |
+ net::LOAD_MAIN_FRAME_DEPRECATED);
+ }
+
+ request->Start();
+ base::RunLoop().RunUntilIdle();
+ }
+
void DelegateStageDone(int result) {}
void NotifyNetworkDelegate(net::URLRequest* request,
@@ -430,6 +593,14 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
TestLoFiDecider* lofi_decider() const { return lofi_decider_; }
+ net::TestNetworkQualityEstimator* test_network_quality_estimator() {
+ return &test_network_quality_estimator_;
+ }
+
+ net::SSLSocketDataProvider* ssl_socket_data_provider() {
+ return &ssl_socket_data_provider_;
+ }
+
private:
base::MessageLoopForIO message_loop_;
net::MockClientSocketFactory mock_socket_factory_;
@@ -440,12 +611,20 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
TestLoFiDecider* lofi_decider_;
TestLoFiUIService* lofi_ui_service_;
std::unique_ptr<DataReductionProxyTestContext> test_context_;
+ net::TestNetworkQualityEstimator test_network_quality_estimator_;
+
+ net::SSLSocketDataProvider ssl_socket_data_provider_;
+
+ std::unique_ptr<net::StaticSocketDataProvider> socket_;
+
+ // Encoded Brotli content read from a file. May be empty.
+ std::string encoded_brotli_buffer_;
};
TEST_F(DataReductionProxyNetworkDelegateTest, AuthenticationTest) {
- Init(false, false);
+ Init(USE_INSECURE_PROXY, false);
std::unique_ptr<net::URLRequest> fake_request(
- FetchURLRequest(GURL(kTestURL), nullptr, std::string(), 0));
+ FetchURLRequest(GURL(kTestURL), nullptr, std::string(), 0, 0));
net::ProxyInfo data_reduction_proxy_info;
net::ProxyRetryInfoMap proxy_retry_info;
@@ -454,6 +633,13 @@ TEST_F(DataReductionProxyNetworkDelegateTest, AuthenticationTest) {
data_reduction_proxy_info.UseNamedProxy(data_reduction_proxy);
net::HttpRequestHeaders headers;
+ // Call network delegate methods to ensure that appropriate chrome proxy
+ // headers get added/removed.
+ network_delegate()->NotifyBeforeStartTransaction(
+ fake_request.get(),
+ base::Bind(&DataReductionProxyNetworkDelegateTest::DelegateStageDone,
+ base::Unretained(this)),
+ &headers);
network_delegate()->NotifyBeforeSendHeaders(fake_request.get(),
data_reduction_proxy_info,
proxy_retry_info, &headers);
@@ -466,7 +652,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest, AuthenticationTest) {
}
TEST_F(DataReductionProxyNetworkDelegateTest, LoFiTransitions) {
- Init(false, false);
+ Init(USE_INSECURE_PROXY, false);
// Enable Lo-Fi.
const struct {
bool lofi_switch_enabled;
@@ -617,7 +803,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest, LoFiTransitions) {
}
TEST_F(DataReductionProxyNetworkDelegateTest, RequestDataConfigurations) {
- Init(false, false);
+ Init(USE_INSECURE_PROXY, false);
const struct {
bool lofi_on;
bool used_data_reduction_proxy;
@@ -655,10 +841,8 @@ TEST_F(DataReductionProxyNetworkDelegateTest, RequestDataConfigurations) {
net::HttpRequestHeaders headers;
net::ProxyRetryInfoMap proxy_retry_info;
- net::TestNetworkQualityEstimator test_network_quality_estimator;
- test_network_quality_estimator.set_effective_connection_type(
+ test_network_quality_estimator()->set_effective_connection_type(
net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
- context()->set_network_quality_estimator(&test_network_quality_estimator);
std::unique_ptr<net::URLRequest> request = context()->CreateRequest(
GURL(kTestURL), net::RequestPriority::IDLE, nullptr);
@@ -666,6 +850,14 @@ TEST_F(DataReductionProxyNetworkDelegateTest, RequestDataConfigurations) {
: 0);
lofi_decider()->SetIsUsingLoFi(test.lofi_on);
io_data()->request_options()->SetSecureSession("fake-session");
+
+ // Call network delegate methods to ensure that appropriate chrome proxy
+ // headers get added/removed.
+ network_delegate()->NotifyBeforeStartTransaction(
+ request.get(),
+ base::Bind(&DataReductionProxyNetworkDelegateTest::DelegateStageDone,
+ base::Unretained(this)),
+ &headers);
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
DataReductionProxyData* data =
@@ -678,8 +870,8 @@ TEST_F(DataReductionProxyNetworkDelegateTest, RequestDataConfigurations) {
: net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
data->effective_connection_type());
EXPECT_TRUE(data->used_data_reduction_proxy());
- EXPECT_EQ(GURL(kTestURL), data->request_url());
- EXPECT_EQ("fake-session", data->session_key());
+ EXPECT_EQ(test.main_frame ? GURL(kTestURL) : GURL(), data->request_url());
+ EXPECT_EQ(test.main_frame ? "fake-session" : "", data->session_key());
EXPECT_EQ(test.lofi_on, data->lofi_requested());
}
}
@@ -687,7 +879,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest, RequestDataConfigurations) {
TEST_F(DataReductionProxyNetworkDelegateTest,
RequestDataHoldbackConfigurations) {
- Init(false, false);
+ Init(USE_INSECURE_PROXY, false);
const struct {
bool data_reduction_proxy_enabled;
bool used_direct;
@@ -734,28 +926,35 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
}
TEST_F(DataReductionProxyNetworkDelegateTest, RedirectRequestDataCleared) {
- Init(false, false);
+ Init(USE_INSECURE_PROXY, false);
net::ProxyInfo data_reduction_proxy_info;
std::string data_reduction_proxy;
base::TrimString(params()->DefaultOrigin(), "/", &data_reduction_proxy);
data_reduction_proxy_info.UseNamedProxy(data_reduction_proxy);
// Main frame loaded. Lo-Fi should be used.
- net::HttpRequestHeaders headers;
+ net::HttpRequestHeaders headers_original;
net::ProxyRetryInfoMap proxy_retry_info;
- net::TestNetworkQualityEstimator test_network_quality_estimator;
- test_network_quality_estimator.set_effective_connection_type(
+ test_network_quality_estimator()->set_effective_connection_type(
net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
- context()->set_network_quality_estimator(&test_network_quality_estimator);
std::unique_ptr<net::URLRequest> request = context()->CreateRequest(
GURL(kTestURL), net::RequestPriority::IDLE, nullptr);
request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
lofi_decider()->SetIsUsingLoFi(true);
io_data()->request_options()->SetSecureSession("fake-session");
+
+ // Call network delegate methods to ensure that appropriate chrome proxy
+ // headers get added/removed.
+ network_delegate()->NotifyBeforeStartTransaction(
+ request.get(),
+ base::Bind(&DataReductionProxyNetworkDelegateTest::DelegateStageDone,
+ base::Unretained(this)),
+ &headers_original);
network_delegate()->NotifyBeforeSendHeaders(
- request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
+ request.get(), data_reduction_proxy_info, proxy_retry_info,
+ &headers_original);
DataReductionProxyData* data =
DataReductionProxyData::GetData(*request.get());
@@ -773,46 +972,28 @@ TEST_F(DataReductionProxyNetworkDelegateTest, RedirectRequestDataCleared) {
// DataReductionProxyData.
network_delegate()->NotifyBeforeRedirect(request.get(), GURL(kTestURL));
data = DataReductionProxyData::GetData(*request.get());
- EXPECT_FALSE(data);
+ EXPECT_FALSE(data && data->used_data_reduction_proxy());
// Call NotifyBeforeSendHeaders again with different proxy info to check that
- // new data isn't added.
+ // new data isn't added. Use a new set of headers since the redirected HTTP
+ // jobs do not reuse headers from the previous jobs. Also, call network
+ // delegate methods to ensure that appropriate chrome proxy headers get
+ // added/removed.
+ net::HttpRequestHeaders headers_redirect;
+ network_delegate()->NotifyBeforeStartTransaction(
+ request.get(),
+ base::Bind(&DataReductionProxyNetworkDelegateTest::DelegateStageDone,
+ base::Unretained(this)),
+ &headers_redirect);
network_delegate()->NotifyBeforeSendHeaders(
- request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
+ request.get(), data_reduction_proxy_info, proxy_retry_info,
+ &headers_redirect);
data = DataReductionProxyData::GetData(*request.get());
EXPECT_FALSE(data);
}
TEST_F(DataReductionProxyNetworkDelegateTest, NetHistograms) {
- Init(false, false);
- const std::string kReceivedValidOCLHistogramName =
- "Net.HttpContentLengthWithValidOCL";
- const std::string kOriginalValidOCLHistogramName =
- "Net.HttpOriginalContentLengthWithValidOCL";
- const std::string kDifferenceValidOCLHistogramName =
- "Net.HttpContentLengthDifferenceWithValidOCL";
-
- // Lo-Fi histograms.
- const std::string kReceivedValidOCLLoFiOnHistogramName =
- "Net.HttpContentLengthWithValidOCL.LoFiOn";
- const std::string kOriginalValidOCLLoFiOnHistogramName =
- "Net.HttpOriginalContentLengthWithValidOCL.LoFiOn";
- const std::string kDifferenceValidOCLLoFiOnHistogramName =
- "Net.HttpContentLengthDifferenceWithValidOCL.LoFiOn";
-
- const std::string kReceivedHistogramName = "Net.HttpContentLength";
- const std::string kOriginalHistogramName = "Net.HttpOriginalContentLength";
- const std::string kDifferenceHistogramName =
- "Net.HttpContentLengthDifference";
- const std::string kFreshnessLifetimeHistogramName =
- "Net.HttpContentFreshnessLifetime";
- const std::string kCacheableHistogramName = "Net.HttpContentLengthCacheable";
- const std::string kCacheable4HoursHistogramName =
- "Net.HttpContentLengthCacheable4Hours";
- const std::string kCacheable24HoursHistogramName =
- "Net.HttpContentLengthCacheable24Hours";
- const int64_t kResponseContentLength = 100;
- const int64_t kOriginalContentLength = 200;
+ Init(USE_INSECURE_PROXY, false);
base::HistogramTester histogram_tester;
@@ -825,7 +1006,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest, NetHistograms) {
base::Int64ToString(kOriginalContentLength) + "\r\n\r\n";
std::unique_ptr<net::URLRequest> fake_request(FetchURLRequest(
- GURL(kTestURL), nullptr, response_headers, kResponseContentLength));
+ GURL(kTestURL), nullptr, response_headers, kResponseContentLength, 0));
fake_request->SetLoadFlags(fake_request->load_flags() |
net::LOAD_MAIN_FRAME_DEPRECATED);
@@ -842,6 +1023,12 @@ TEST_F(DataReductionProxyNetworkDelegateTest, NetHistograms) {
kOriginalContentLength - kResponseContentLength, 1);
histogram_tester.ExpectUniqueSample(kReceivedHistogramName,
kResponseContentLength, 1);
+ histogram_tester.ExpectUniqueSample(kReceivedInsecureHistogramName,
+ kResponseContentLength, 1);
+ histogram_tester.ExpectTotalCount(kReceivedSecureHistogramName, 0);
+ histogram_tester.ExpectTotalCount(kReceivedVideoHistogramName, 0);
+ histogram_tester.ExpectUniqueSample(kReceivedInsecureHistogramName,
+ kResponseContentLength, 1);
histogram_tester.ExpectUniqueSample(kOriginalHistogramName,
kOriginalContentLength, 1);
histogram_tester.ExpectUniqueSample(
@@ -902,7 +1089,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest, NetHistograms) {
config()->ShouldEnableLoFi(*fake_request.get()));
fake_request = (FetchURLRequest(GURL(kTestURL), nullptr, response_headers,
- kResponseContentLength));
+ kResponseContentLength, 0));
fake_request->SetLoadFlags(fake_request->load_flags() |
net::LOAD_MAIN_FRAME_DEPRECATED);
@@ -932,8 +1119,57 @@ TEST_F(DataReductionProxyNetworkDelegateTest, NetHistograms) {
}
}
+TEST_F(DataReductionProxyNetworkDelegateTest, NetVideoHistograms) {
+ Init(USE_INSECURE_PROXY, false);
+
+ base::HistogramTester histogram_tester;
+
+ // Check video
+ std::string video_response_headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
+ "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
+ "Content-Type: video/mp4\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "x-original-content-length: " +
+ base::Int64ToString(kOriginalContentLength) + "\r\n\r\n";
+
+ FetchURLRequest(GURL(kTestURL), nullptr, video_response_headers,
+ kResponseContentLength, 0);
+
+ histogram_tester.ExpectUniqueSample(kReceivedInsecureHistogramName,
+ kResponseContentLength, 1);
+ histogram_tester.ExpectTotalCount(kReceivedSecureHistogramName, 0);
+ histogram_tester.ExpectUniqueSample(kReceivedVideoHistogramName,
+ kResponseContentLength, 1);
+}
+
+TEST_F(DataReductionProxyNetworkDelegateTest, NetSSLHistograms) {
+ Init(BYPASS_PROXY, false);
+
+ base::HistogramTester histogram_tester;
+
+ // Check https
+ std::string secure_response_headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
+ "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "x-original-content-length: " +
+ base::Int64ToString(kOriginalContentLength) + "\r\n\r\n";
+
+ mock_socket_factory()->AddSSLSocketDataProvider(ssl_socket_data_provider());
+ FetchURLRequest(GURL(kSecureTestURL), nullptr, secure_response_headers,
+ kResponseContentLength, 0);
+
+ histogram_tester.ExpectTotalCount(kReceivedInsecureHistogramName, 0);
+ histogram_tester.ExpectUniqueSample(kReceivedSecureHistogramName,
+ kResponseContentLength, 1);
+ histogram_tester.ExpectTotalCount(kReceivedVideoHistogramName, 0);
+}
+
TEST_F(DataReductionProxyNetworkDelegateTest, OnCompletedInternalLoFi) {
- Init(false, false);
+ Init(USE_INSECURE_PROXY, false);
// Enable Lo-Fi.
const struct {
bool lofi_response;
@@ -953,15 +1189,17 @@ TEST_F(DataReductionProxyNetworkDelegateTest, OnCompletedInternalLoFi) {
response_headers += "Chrome-Proxy-Content-Transform: empty-image\r\n";
response_headers += "\r\n";
- FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140);
-
+ auto request =
+ FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140, 0);
+ EXPECT_EQ(tests[i].lofi_response,
+ DataReductionProxyData::GetData(*request)->lofi_received());
VerifyDidNotifyLoFiResponse(tests[i].lofi_response);
}
}
TEST_F(DataReductionProxyNetworkDelegateTest,
TestLoFiTransformationTypeHistogram) {
- Init(false, false);
+ Init(USE_INSECURE_PROXY, false);
const char kLoFiTransformationTypeHistogram[] =
"DataReductionProxy.LoFi.TransformationType";
base::HistogramTester histogram_tester;
@@ -969,7 +1207,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
net::HttpRequestHeaders request_headers;
request_headers.SetHeader("chrome-proxy-accept-transform", "lite-page");
lofi_decider()->ignore_is_using_data_reduction_proxy_check();
- FetchURLRequest(GURL(kTestURL), &request_headers, std::string(), 140);
+ FetchURLRequest(GURL(kTestURL), &request_headers, std::string(), 140, 0);
histogram_tester.ExpectBucketCount(kLoFiTransformationTypeHistogram,
NO_TRANSFORMATION_LITE_PAGE_REQUESTED, 1);
@@ -982,7 +1220,9 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
"x-original-content-length: 200\r\n";
response_headers += "\r\n";
- FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140);
+ auto request =
+ FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140, 0);
+ EXPECT_TRUE(DataReductionProxyData::GetData(*request)->lite_page_received());
histogram_tester.ExpectBucketCount(kLoFiTransformationTypeHistogram,
LITE_PAGE, 1);
@@ -992,7 +1232,9 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
// disabled globally.
TEST_F(DataReductionProxyNetworkDelegateTest,
BrotliAdvertisement_BrotliDisabled) {
- Init(true /* use_secure_proxy */, false /* enable_brotli_globally */);
+ Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
+
+ ReadBrotliFile();
std::string response_headers =
"HTTP/1.1 200 OK\r\n"
@@ -1012,7 +1254,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
// is fetched from an insecure proxy.
TEST_F(DataReductionProxyNetworkDelegateTest,
BrotliAdvertisementInsecureProxy) {
- Init(false /* use_secure_proxy */, true /* enable_brotli_globally */);
+ Init(USE_INSECURE_PROXY, true /* enable_brotli_globally */);
std::string response_headers =
"HTTP/1.1 200 OK\r\n"
"Content-Length: 140\r\n"
@@ -1025,7 +1267,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
// Use secure sockets when fetching the request since Brotli is only enabled
// for secure connections.
std::unique_ptr<net::URLRequest> request(
- FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140));
+ FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140, 0));
EXPECT_EQ(140, request->received_response_content_length());
EXPECT_NE(0, request->GetTotalSentBytes());
EXPECT_NE(0, request->GetTotalReceivedBytes());
@@ -1038,7 +1280,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
// disabled via data reduction proxy field trial.
TEST_F(DataReductionProxyNetworkDelegateTest,
BrotliAdvertisementDisabledViaFieldTrial) {
- Init(true /* use_secure_proxy */, true /* enable_brotli_globally */);
+ Init(USE_SECURE_PROXY, true /* enable_brotli_globally */);
base::FieldTrialList field_trial_list(nullptr);
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
@@ -1060,14 +1302,14 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
// Test that Brotli is correctly added to the accept-encoding header when it is
// enabled globally.
TEST_F(DataReductionProxyNetworkDelegateTest, BrotliAdvertisement) {
- Init(true /* use_secure_proxy */, true /* enable_brotli_globally */);
+ Init(USE_SECURE_PROXY, true /* enable_brotli_globally */);
std::string response_headers =
"HTTP/1.1 200 OK\r\n"
- "Content-Length: 140\r\n"
"Via: 1.1 Chrome-Compression-Proxy\r\n"
"x-original-content-length: 200\r\n"
"Cache-Control: max-age=1200\r\n"
+ "Content-Encoding: br\r\n"
"Vary: accept-encoding\r\n";
response_headers += "\r\n";
@@ -1075,6 +1317,102 @@ TEST_F(DataReductionProxyNetworkDelegateTest, BrotliAdvertisement) {
FetchURLRequestAndVerifyBrotli(nullptr, response_headers, true, true);
}
+TEST_F(DataReductionProxyNetworkDelegateTest, IncrementingMainFramePageId) {
+ // This is unaffacted by brotil and insecure proxy.
+ Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
+
+ io_data()->request_options()->SetSecureSession("new-session");
+
+ FetchURLRequestAndVerifyPageIdDirective("pid=1", false);
+
+ FetchURLRequestAndVerifyPageIdDirective("pid=2", false);
+
+ FetchURLRequestAndVerifyPageIdDirective("pid=3", false);
+}
+
+TEST_F(DataReductionProxyNetworkDelegateTest, ResetSessionResetsId) {
+ // This is unaffacted by brotil and insecure proxy.
+ Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
+
+ io_data()->request_options()->SetSecureSession("new-session");
+
+ FetchURLRequestAndVerifyPageIdDirective("pid=1", false);
+
+ io_data()->request_options()->SetSecureSession("new-session-2");
+
+ FetchURLRequestAndVerifyPageIdDirective("pid=1", false);
+}
+
+TEST_F(DataReductionProxyNetworkDelegateTest, SubResourceNoPageId) {
+ // This is unaffacted by brotil and insecure proxy.
+ Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
+ io_data()->request_options()->SetSecureSession("new-session");
+ FetchURLRequestAndVerifyPageIdDirective(std::string(), false);
+}
+
+TEST_F(DataReductionProxyNetworkDelegateTest, RedirectSharePid) {
+ // This is unaffacted by brotil and insecure proxy.
+ Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
+
+ io_data()->request_options()->SetSecureSession("new-session");
+
+ FetchURLRequestAndVerifyPageIdDirective("pid=1", true);
+}
+
+TEST_F(DataReductionProxyNetworkDelegateTest,
+ SessionChangeResetsPageIDOnRedirect) {
+ // This test calls directly into network delegate as it is difficult to mock
+ // state changing in between redirects within an URLRequest's lifetime.
+
+ // This is unaffacted by brotil and insecure proxy.
+ Init(USE_INSECURE_PROXY, false /* enable_brotli_globally */);
+ net::ProxyInfo data_reduction_proxy_info;
+ std::string data_reduction_proxy;
+ base::TrimString(params()->DefaultOrigin(), "/", &data_reduction_proxy);
+ data_reduction_proxy_info.UseNamedProxy(data_reduction_proxy);
+
+ std::unique_ptr<net::URLRequest> request = context()->CreateRequest(
+ GURL(kTestURL), net::RequestPriority::IDLE, nullptr);
+ request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
+ io_data()->request_options()->SetSecureSession("fake-session");
+
+ net::HttpRequestHeaders headers;
+ net::ProxyRetryInfoMap proxy_retry_info;
+
+ // Send a request and verify the page ID is 1.
+ network_delegate()->NotifyBeforeSendHeaders(
+ request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
+ DataReductionProxyData* data =
+ DataReductionProxyData::GetData(*request.get());
+ EXPECT_TRUE(data_reduction_proxy_info.is_http());
+ EXPECT_EQ(1u, data->page_id().value());
+
+ // Send a second request and verify the page ID incremements.
+ request = context()->CreateRequest(GURL(kTestURL), net::RequestPriority::IDLE,
+ nullptr);
+ request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
+
+ network_delegate()->NotifyBeforeSendHeaders(
+ request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
+ data = DataReductionProxyData::GetData(*request.get());
+ EXPECT_EQ(2u, data->page_id().value());
+
+ // Verify that redirects are the same page ID.
+ network_delegate()->NotifyBeforeRedirect(request.get(), GURL(kTestURL));
+ network_delegate()->NotifyBeforeSendHeaders(
+ request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
+ data = DataReductionProxyData::GetData(*request.get());
+ EXPECT_EQ(2u, data->page_id().value());
+
+ // Verify that redirects into a new session get a new page ID.
+ network_delegate()->NotifyBeforeRedirect(request.get(), GURL(kTestURL));
+ io_data()->request_options()->SetSecureSession("new-session");
+ network_delegate()->NotifyBeforeSendHeaders(
+ request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
+ data = DataReductionProxyData::GetData(*request.get());
+ EXPECT_EQ(1u, data->page_id().value());
+}
+
} // namespace
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc
index 7b0d644f0b5..4d21e6666ed 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc
@@ -6,9 +6,11 @@
#include <stdint.h>
+#include "base/bind_helpers.h"
#include "base/metrics/histogram_macros.h"
#include "base/optional.h"
#include "base/rand_util.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h"
@@ -36,7 +38,8 @@ static const char kHistogramAttempted[] =
// timing and data reduction proxy state.
void AddDataToPageloadMetrics(const DataReductionProxyData& request_data,
const DataReductionProxyPageLoadTiming& timing,
- PageloadMetrics* request) {
+ PageloadMetrics* request,
+ bool opted_out) {
request->set_session_key(request_data.session_key());
// For the timing events, any of them could be zero. Fill the message as a
// best effort.
@@ -92,6 +95,32 @@ void AddDataToPageloadMetrics(const DataReductionProxyData& request_data,
request_data.effective_connection_type()));
request->set_compressed_page_size_bytes(timing.network_bytes);
request->set_original_page_size_bytes(timing.original_network_bytes);
+
+ if (request_data.page_id()) {
+ request->set_page_id(request_data.page_id().value());
+ }
+
+ bool was_preview_shown = false;
+ if (request_data.lofi_received()) {
+ request->set_previews_type(PageloadMetrics_PreviewsType_LOFI);
+ was_preview_shown = true;
+ } else if (request_data.lite_page_received()) {
+ request->set_previews_type(PageloadMetrics_PreviewsType_LITE_PAGE);
+ was_preview_shown = true;
+ } else {
+ request->set_previews_type(PageloadMetrics_PreviewsType_NONE);
+ }
+
+ if (!was_preview_shown || timing.app_background_occurred) {
+ request->set_previews_opt_out(PageloadMetrics_PreviewsOptOut_UNKNOWN);
+ return;
+ }
+
+ if (opted_out) {
+ request->set_previews_opt_out(PageloadMetrics_PreviewsOptOut_OPT_OUT);
+ return;
+ }
+ request->set_previews_opt_out(PageloadMetrics_PreviewsOptOut_NON_OPT_OUT);
}
// Adds |current_time| as the metrics sent time to |request_data|, and returns
@@ -115,6 +144,7 @@ DataReductionProxyPingbackClient::DataReductionProxyPingbackClient(
pingback_reporting_fraction_(0.0) {}
DataReductionProxyPingbackClient::~DataReductionProxyPingbackClient() {
+ DCHECK(opt_outs_.empty());
DCHECK(thread_checker_.CalledOnValidThread());
}
@@ -137,8 +167,18 @@ void DataReductionProxyPingbackClient::SendPingback(
UMA_HISTOGRAM_BOOLEAN(kHistogramAttempted, send_pingback);
if (!send_pingback)
return;
+
+ bool opted_out = false;
+ if (request_data.page_id()) {
+ auto opt_out = opt_outs_.find(NavigationID(request_data.page_id().value(),
+ request_data.session_key()));
+ opted_out = opt_out != opt_outs_.end();
+ if (opted_out)
+ opt_outs_.erase(opt_out);
+ }
+
PageloadMetrics* pageload_metrics = metrics_request_.add_pageloads();
- AddDataToPageloadMetrics(request_data, timing, pageload_metrics);
+ AddDataToPageloadMetrics(request_data, timing, pageload_metrics, opted_out);
if (current_fetcher_.get())
return;
DCHECK_EQ(1, metrics_request_.pageloads_size());
@@ -187,4 +227,26 @@ void DataReductionProxyPingbackClient::SetPingbackReportingFraction(
pingback_reporting_fraction_ = pingback_reporting_fraction;
}
+void DataReductionProxyPingbackClient::AddOptOut(
+ const NavigationID& navigation_id) {
+ opt_outs_.emplace(navigation_id);
+}
+
+void DataReductionProxyPingbackClient::ClearNavigationKeySync(
+ const NavigationID& navigation_id) {
+ opt_outs_.erase(navigation_id);
+}
+
+void DataReductionProxyPingbackClient::ClearNavigationKeyAsync(
+ const NavigationID& navigation_id) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&DataReductionProxyPingbackClient::ClearNavigationKeySync,
+ base::Unretained(this), navigation_id));
+}
+
+size_t DataReductionProxyPingbackClient::OptOutsSizeForTesting() const {
+ return opt_outs_.size();
+}
+
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h
index a91a44cf0d9..1f437b6a85c 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h
@@ -5,8 +5,12 @@
#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_PINGBACK_CLIENT_H_
#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_PINGBACK_CLIENT_H_
+#include <stdint.h>
+
#include <memory>
+#include <set>
#include <string>
+#include <utility>
#include "base/macros.h"
#include "base/threading/thread_checker.h"
@@ -27,6 +31,8 @@ namespace data_reduction_proxy {
class DataReductionProxyData;
struct DataReductionProxyPageLoadTiming;
+using NavigationID = std::pair<uint64_t, std::string>;
+
// Manages pingbacks about page load timing information to the data saver proxy
// server. This class is not thread safe.
class DataReductionProxyPingbackClient : public net::URLFetcherDelegate {
@@ -46,6 +52,17 @@ class DataReductionProxyPingbackClient : public net::URLFetcherDelegate {
// call to SendPingback.
void SetPingbackReportingFraction(float pingback_reporting_fraction);
+ // Adds an opt out for |tab_identifier_key| for a data saver |page_id|. An opt
+ // out occurs when users dismiss the preview in favor of the full page.
+ void AddOptOut(const NavigationID& navigation_id);
+
+ // Removes any stored data associated with |tab_identifier_key| in a task that
+ // runs later.
+ void ClearNavigationKeyAsync(const NavigationID& navigation_id);
+
+ // The total number of pending loads being tracked due to opt outs.
+ size_t OptOutsSizeForTesting() const;
+
protected:
// Generates a float in the range [0, 1). Virtualized in testing.
virtual float GenerateRandomFloat() const;
@@ -66,6 +83,9 @@ class DataReductionProxyPingbackClient : public net::URLFetcherDelegate {
// reset to an empty RecordPageloadMetricsRequest.
void CreateFetcherForDataAndStart();
+ // Removes any stored data associated with |tab_identifier_key|.
+ void ClearNavigationKeySync(const NavigationID& navigation_id);
+
net::URLRequestContextGetter* url_request_context_;
// The URL for the data saver proxy's ping back service.
@@ -80,6 +100,9 @@ class DataReductionProxyPingbackClient : public net::URLFetcherDelegate {
// The probability of sending a pingback to the server.
float pingback_reporting_fraction_;
+ // The map of tab identifier keys to page IDs.
+ std::set<NavigationID> opt_outs_;
+
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(DataReductionProxyPingbackClient);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc
index 70d0992d008..65c03f3309a 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc
@@ -6,6 +6,7 @@
#include <stdint.h>
+#include <list>
#include <memory>
#include <string>
@@ -13,6 +14,7 @@
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/optional.h"
+#include "base/run_loop.h"
#include "base/test/histogram_tester.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
@@ -86,25 +88,7 @@ class TestDataReductionProxyPingbackClient
class DataReductionProxyPingbackClientTest : public testing::Test {
public:
- DataReductionProxyPingbackClientTest()
- : timing_(
- base::Time::FromJsTime(1500) /* navigation_start */,
- base::Optional<base::TimeDelta>(
- base::TimeDelta::FromMilliseconds(1600)) /* response_start */,
- base::Optional<base::TimeDelta>(
- base::TimeDelta::FromMilliseconds(1700)) /* load_event_start */,
- base::Optional<base::TimeDelta>(base::TimeDelta::FromMilliseconds(
- 1800)) /* first_image_paint */,
- base::Optional<base::TimeDelta>(base::TimeDelta::FromMilliseconds(
- 1900)) /* first_contentful_paint */,
- base::Optional<base::TimeDelta>(base::TimeDelta::FromMilliseconds(
- 2000)) /* experimental_first_meaningful_paint */,
- base::Optional<base::TimeDelta>(base::TimeDelta::FromMilliseconds(
- 100)) /* parse_blocked_on_script_load_duration */,
- base::Optional<base::TimeDelta>(
- base::TimeDelta::FromMilliseconds(2000)) /* parse_stop */,
- kBytes /* network_bytes */,
- kBytesOriginal /* original_network_bytes */) {}
+ DataReductionProxyPingbackClientTest() {}
TestDataReductionProxyPingbackClient* pingback_client() const {
return pingback_client_.get();
@@ -116,31 +100,60 @@ class DataReductionProxyPingbackClientTest : public testing::Test {
pingback_client_ = base::WrapUnique<TestDataReductionProxyPingbackClient>(
new TestDataReductionProxyPingbackClient(
request_context_getter_.get()));
+ page_id_ = 0u;
}
- void CreateAndSendPingback() {
+ void CreateAndSendPingback(bool lofi_received,
+ bool lite_page_received,
+ bool app_background_occurred) {
+ timing_ = base::MakeUnique<DataReductionProxyPageLoadTiming>(
+ base::Time::FromJsTime(1500) /* navigation_start */,
+ base::Optional<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(1600)) /* response_start */,
+ base::Optional<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(1700)) /* load_event_start */,
+ base::Optional<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(1800)) /* first_image_paint */,
+ base::Optional<base::TimeDelta>(base::TimeDelta::FromMilliseconds(
+ 1900)) /* first_contentful_paint */,
+ base::Optional<base::TimeDelta>(base::TimeDelta::FromMilliseconds(
+ 2000)) /* experimental_first_meaningful_paint */,
+ base::Optional<base::TimeDelta>(base::TimeDelta::FromMilliseconds(
+ 100)) /* parse_blocked_on_script_load_duration */,
+ base::Optional<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(2000)) /* parse_stop */,
+ kBytes /* network_bytes */, kBytesOriginal /* original_network_bytes */,
+ app_background_occurred /* app_background_occurred */);
+
DataReductionProxyData request_data;
request_data.set_session_key(kSessionKey);
request_data.set_request_url(GURL(kFakeURL));
request_data.set_effective_connection_type(
net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
+ request_data.set_lofi_received(lofi_received);
+ request_data.set_lite_page_received(lite_page_received);
+ request_data.set_page_id(page_id_);
factory()->set_remove_fetcher_on_delete(true);
- pingback_client()->SendPingback(request_data, timing_);
+ pingback_client()->SendPingback(request_data, *timing_);
+ page_id_++;
}
net::TestURLFetcherFactory* factory() { return &factory_; }
- const DataReductionProxyPageLoadTiming& timing() { return timing_; }
+ const DataReductionProxyPageLoadTiming& timing() { return *timing_; }
const base::HistogramTester& histogram_tester() { return histogram_tester_; }
+ uint64_t page_id() const { return page_id_; }
+
private:
base::MessageLoopForIO message_loop_;
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
std::unique_ptr<TestDataReductionProxyPingbackClient> pingback_client_;
net::TestURLFetcherFactory factory_;
- DataReductionProxyPageLoadTiming timing_;
+ std::unique_ptr<DataReductionProxyPageLoadTiming> timing_;
base::HistogramTester histogram_tester_;
+ uint64_t page_id_;
};
TEST_F(DataReductionProxyPingbackClientTest, VerifyPingbackContent) {
@@ -150,7 +163,10 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyPingbackContent) {
pingback_client()->SetPingbackReportingFraction(1.0f);
base::Time current_time = base::Time::UnixEpoch();
pingback_client()->set_current_time(current_time);
- CreateAndSendPingback();
+ uint64_t data_page_id = page_id();
+ CreateAndSendPingback(false /* lofi_received */,
+ false /* lite_page_received */,
+ false /* app_background_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
@@ -189,6 +205,12 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyPingbackContent) {
EXPECT_EQ(kFakeURL, pageload_metrics.first_request_url());
EXPECT_EQ(kBytes, pageload_metrics.compressed_page_size_bytes());
EXPECT_EQ(kBytesOriginal, pageload_metrics.original_page_size_bytes());
+ EXPECT_EQ(data_page_id, pageload_metrics.page_id());
+
+ EXPECT_EQ(PageloadMetrics_PreviewsType_NONE,
+ pageload_metrics.previews_type());
+ EXPECT_EQ(PageloadMetrics_PreviewsOptOut_UNKNOWN,
+ pageload_metrics.previews_opt_out());
EXPECT_EQ(
PageloadMetrics_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_OFFLINE,
@@ -206,13 +228,22 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyTwoPingbacksBatchedContent) {
base::Time current_time = base::Time::UnixEpoch();
pingback_client()->set_current_time(current_time);
// First pingback
- CreateAndSendPingback();
+ CreateAndSendPingback(false /* lofi_received */,
+ false /* lite_page_received */,
+ false /* app_background_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
// Two more pingbacks batched together.
- CreateAndSendPingback();
+ std::list<uint64_t> page_ids;
+ page_ids.push_back(page_id());
+ CreateAndSendPingback(false /* lofi_received */,
+ false /* lite_page_received */,
+ false /* app_background_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 2);
- CreateAndSendPingback();
+ page_ids.push_back(page_id());
+ CreateAndSendPingback(false /* lofi_received */,
+ false /* lite_page_received */,
+ false /* app_background_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 3);
// Ignore the first pingback.
@@ -261,6 +292,8 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyTwoPingbacksBatchedContent) {
EXPECT_EQ(kFakeURL, pageload_metrics.first_request_url());
EXPECT_EQ(kBytes, pageload_metrics.compressed_page_size_bytes());
EXPECT_EQ(kBytesOriginal, pageload_metrics.original_page_size_bytes());
+ EXPECT_EQ(page_ids.front(), pageload_metrics.page_id());
+ page_ids.pop_front();
EXPECT_EQ(
PageloadMetrics_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_OFFLINE,
pageload_metrics.effective_connection_type());
@@ -276,9 +309,13 @@ TEST_F(DataReductionProxyPingbackClientTest, SendTwoPingbacks) {
EXPECT_FALSE(factory()->GetFetcherByID(0));
pingback_client()->OverrideRandom(true, 0.5f);
pingback_client()->SetPingbackReportingFraction(1.0f);
- CreateAndSendPingback();
+ CreateAndSendPingback(false /* lofi_received */,
+ false /* lite_page_received */,
+ false /* app_background_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
- CreateAndSendPingback();
+ CreateAndSendPingback(false /* lofi_received */,
+ false /* lite_page_received */,
+ false /* app_background_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 2);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
@@ -297,7 +334,9 @@ TEST_F(DataReductionProxyPingbackClientTest, NoPingbackSent) {
EXPECT_FALSE(factory()->GetFetcherByID(0));
pingback_client()->OverrideRandom(true, 0.5f);
pingback_client()->SetPingbackReportingFraction(0.0f);
- CreateAndSendPingback();
+ CreateAndSendPingback(false /* lofi_received */,
+ false /* lite_page_received */,
+ false /* app_background_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, false, 1);
histogram_tester().ExpectTotalCount(kHistogramSucceeded, 0);
EXPECT_FALSE(factory()->GetFetcherByID(0));
@@ -311,7 +350,9 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyReportingBehvaior) {
// pingback is created.
pingback_client()->SetPingbackReportingFraction(0.5f);
pingback_client()->OverrideRandom(true, 0.4f);
- CreateAndSendPingback();
+ CreateAndSendPingback(false /* lofi_received */,
+ false /* lite_page_received */,
+ false /* app_background_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
EXPECT_TRUE(test_fetcher);
@@ -321,7 +362,9 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyReportingBehvaior) {
// Verify that if the random number is greater than the reporting fraction,
// the pingback is not created.
pingback_client()->OverrideRandom(true, 0.6f);
- CreateAndSendPingback();
+ CreateAndSendPingback(false /* lofi_received */,
+ false /* lite_page_received */,
+ false /* app_background_occurred */);
histogram_tester().ExpectBucketCount(kHistogramAttempted, false, 1);
test_fetcher = factory()->GetFetcherByID(0);
EXPECT_FALSE(test_fetcher);
@@ -331,7 +374,9 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyReportingBehvaior) {
// and the random number is zero, no pingback is sent.
pingback_client()->SetPingbackReportingFraction(0.0f);
pingback_client()->OverrideRandom(true, 0.0f);
- CreateAndSendPingback();
+ CreateAndSendPingback(false /* lofi_received */,
+ false /* lite_page_received */,
+ false /* app_background_occurred */);
histogram_tester().ExpectBucketCount(kHistogramAttempted, false, 2);
test_fetcher = factory()->GetFetcherByID(0);
EXPECT_FALSE(test_fetcher);
@@ -341,7 +386,9 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyReportingBehvaior) {
data_reduction_proxy::switches::kEnableDataReductionProxyForcePingback);
pingback_client()->SetPingbackReportingFraction(0.0f);
pingback_client()->OverrideRandom(true, 1.0f);
- CreateAndSendPingback();
+ CreateAndSendPingback(false /* lofi_received */,
+ false /* lite_page_received */,
+ false /* app_background_occurred */);
histogram_tester().ExpectBucketCount(kHistogramAttempted, true, 2);
test_fetcher = factory()->GetFetcherByID(0);
EXPECT_TRUE(test_fetcher);
@@ -354,7 +401,9 @@ TEST_F(DataReductionProxyPingbackClientTest, FailedPingback) {
EXPECT_FALSE(factory()->GetFetcherByID(0));
pingback_client()->OverrideRandom(true, 0.5f);
pingback_client()->SetPingbackReportingFraction(1.0f);
- CreateAndSendPingback();
+ CreateAndSendPingback(false /* lofi_received */,
+ false /* lite_page_received */,
+ false /* app_background_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
EXPECT_TRUE(test_fetcher);
@@ -365,4 +414,166 @@ TEST_F(DataReductionProxyPingbackClientTest, FailedPingback) {
histogram_tester().ExpectUniqueSample(kHistogramSucceeded, false, 1);
}
+TEST_F(DataReductionProxyPingbackClientTest, VerifyLoFiContentNoOptOut) {
+ Init();
+ EXPECT_FALSE(factory()->GetFetcherByID(0));
+ pingback_client()->OverrideRandom(true, 0.5f);
+ pingback_client()->SetPingbackReportingFraction(1.0f);
+ base::Time current_time = base::Time::UnixEpoch();
+ pingback_client()->set_current_time(current_time);
+ CreateAndSendPingback(true /* lofi_received */,
+ false /* lite_page_received */,
+ false /* app_background_occurred */);
+ histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
+ net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
+ EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
+ RecordPageloadMetricsRequest batched_request;
+ batched_request.ParseFromString(test_fetcher->upload_data());
+ EXPECT_EQ(batched_request.pageloads_size(), 1);
+ PageloadMetrics pageload_metrics = batched_request.pageloads(0);
+ EXPECT_EQ(PageloadMetrics_PreviewsType_LOFI,
+ pageload_metrics.previews_type());
+ EXPECT_EQ(PageloadMetrics_PreviewsOptOut_NON_OPT_OUT,
+ pageload_metrics.previews_opt_out());
+
+ test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+ EXPECT_FALSE(factory()->GetFetcherByID(0));
+}
+
+TEST_F(DataReductionProxyPingbackClientTest, VerifyLoFiContentOptOut) {
+ Init();
+ EXPECT_FALSE(factory()->GetFetcherByID(0));
+ pingback_client()->OverrideRandom(true, 0.5f);
+ pingback_client()->SetPingbackReportingFraction(1.0f);
+ base::Time current_time = base::Time::UnixEpoch();
+ pingback_client()->set_current_time(current_time);
+ pingback_client()->AddOptOut(NavigationID(page_id(), kSessionKey));
+ CreateAndSendPingback(true /* lofi_received */,
+ false /* lite_page_received */,
+ false /* app_background_occurred */);
+ histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
+ net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
+ EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
+ RecordPageloadMetricsRequest batched_request;
+ batched_request.ParseFromString(test_fetcher->upload_data());
+ EXPECT_EQ(batched_request.pageloads_size(), 1);
+ PageloadMetrics pageload_metrics = batched_request.pageloads(0);
+ EXPECT_EQ(PageloadMetrics_PreviewsType_LOFI,
+ pageload_metrics.previews_type());
+ EXPECT_EQ(PageloadMetrics_PreviewsOptOut_OPT_OUT,
+ pageload_metrics.previews_opt_out());
+
+ test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+ EXPECT_FALSE(factory()->GetFetcherByID(0));
+}
+
+TEST_F(DataReductionProxyPingbackClientTest, VerifyLoFiContentBackground) {
+ Init();
+ EXPECT_FALSE(factory()->GetFetcherByID(0));
+ pingback_client()->OverrideRandom(true, 0.5f);
+ pingback_client()->SetPingbackReportingFraction(1.0f);
+ base::Time current_time = base::Time::UnixEpoch();
+ pingback_client()->set_current_time(current_time);
+ pingback_client()->AddOptOut(NavigationID(page_id(), kSessionKey));
+ CreateAndSendPingback(true /* lofi_received */,
+ false /* lite_page_received */,
+ true /* app_background_occurred */);
+ histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
+ net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
+ EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
+ RecordPageloadMetricsRequest batched_request;
+ batched_request.ParseFromString(test_fetcher->upload_data());
+ EXPECT_EQ(batched_request.pageloads_size(), 1);
+ PageloadMetrics pageload_metrics = batched_request.pageloads(0);
+ EXPECT_EQ(PageloadMetrics_PreviewsType_LOFI,
+ pageload_metrics.previews_type());
+ EXPECT_EQ(PageloadMetrics_PreviewsOptOut_UNKNOWN,
+ pageload_metrics.previews_opt_out());
+
+ test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+ EXPECT_FALSE(factory()->GetFetcherByID(0));
+}
+
+TEST_F(DataReductionProxyPingbackClientTest, VerifyLitePageContent) {
+ Init();
+ EXPECT_FALSE(factory()->GetFetcherByID(0));
+ pingback_client()->OverrideRandom(true, 0.5f);
+ pingback_client()->SetPingbackReportingFraction(1.0f);
+ base::Time current_time = base::Time::UnixEpoch();
+ pingback_client()->set_current_time(current_time);
+ pingback_client()->AddOptOut(NavigationID(page_id(), kSessionKey));
+ CreateAndSendPingback(false /* lofi_received */,
+ true /* lite_page_received */,
+ false /* app_background_occurred */);
+ histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
+ net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
+ EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
+ RecordPageloadMetricsRequest batched_request;
+ batched_request.ParseFromString(test_fetcher->upload_data());
+ EXPECT_EQ(batched_request.pageloads_size(), 1);
+ PageloadMetrics pageload_metrics = batched_request.pageloads(0);
+ EXPECT_EQ(PageloadMetrics_PreviewsType_LITE_PAGE,
+ pageload_metrics.previews_type());
+ EXPECT_EQ(PageloadMetrics_PreviewsOptOut_OPT_OUT,
+ pageload_metrics.previews_opt_out());
+
+ test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+ EXPECT_FALSE(factory()->GetFetcherByID(0));
+}
+
+TEST_F(DataReductionProxyPingbackClientTest, VerifyTwoLitePagePingbacks) {
+ Init();
+ EXPECT_FALSE(factory()->GetFetcherByID(0));
+ pingback_client()->OverrideRandom(true, 0.5f);
+ pingback_client()->SetPingbackReportingFraction(1.0f);
+ base::Time current_time = base::Time::UnixEpoch();
+ pingback_client()->set_current_time(current_time);
+ pingback_client()->AddOptOut(NavigationID(page_id(), kSessionKey));
+ CreateAndSendPingback(false /* lofi_received */,
+ true /* lite_page_received */,
+ false /* app_background_occurred */);
+ pingback_client()->AddOptOut(NavigationID(page_id(), kSessionKey));
+ CreateAndSendPingback(false /* lofi_received */,
+ true /* lite_page_received */,
+ false /* app_background_occurred */);
+ histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 2);
+ net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
+ EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
+ RecordPageloadMetricsRequest batched_request;
+ batched_request.ParseFromString(test_fetcher->upload_data());
+ EXPECT_EQ(batched_request.pageloads_size(), 1);
+ PageloadMetrics pageload_metrics = batched_request.pageloads(0);
+ EXPECT_EQ(PageloadMetrics_PreviewsType_LITE_PAGE,
+ pageload_metrics.previews_type());
+ EXPECT_EQ(PageloadMetrics_PreviewsOptOut_OPT_OUT,
+ pageload_metrics.previews_opt_out());
+ test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+ test_fetcher = factory()->GetFetcherByID(0);
+ EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
+ batched_request.ParseFromString(test_fetcher->upload_data());
+ EXPECT_EQ(batched_request.pageloads_size(), 1);
+ pageload_metrics = batched_request.pageloads(0);
+ EXPECT_EQ(PageloadMetrics_PreviewsType_LITE_PAGE,
+ pageload_metrics.previews_type());
+ EXPECT_EQ(PageloadMetrics_PreviewsOptOut_OPT_OUT,
+ pageload_metrics.previews_opt_out());
+ test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+ EXPECT_FALSE(factory()->GetFetcherByID(0));
+}
+
+TEST_F(DataReductionProxyPingbackClientTest, VerifyClearingPendingLoads) {
+ Init();
+ EXPECT_FALSE(factory()->GetFetcherByID(0));
+ pingback_client()->OverrideRandom(true, 0.5f);
+ pingback_client()->SetPingbackReportingFraction(1.0f);
+ base::Time current_time = base::Time::UnixEpoch();
+ pingback_client()->set_current_time(current_time);
+ pingback_client()->AddOptOut(NavigationID(page_id(), kSessionKey));
+ EXPECT_EQ(1u, pingback_client()->OptOutsSizeForTesting());
+ pingback_client()->ClearNavigationKeyAsync(
+ NavigationID(page_id(), kSessionKey));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0u, pingback_client()->OptOutsSizeForTesting());
+}
+
} // namespace data_reduction_proxy
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
index beabdfb174a..85671575bb3 100644
--- 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
@@ -39,8 +39,7 @@ class DataReductionProxyPrefsTest : public testing::Test {
PrefService* pref_service) {
ListPrefUpdate list(local_state_prefs(), pref_name);
for (int64_t i = 0; i < 10L; ++i) {
- list->Set(i, new base::StringValue(
- base::Int64ToString(i + starting_value)));
+ list->Set(i, new base::Value(base::Int64ToString(i + starting_value)));
}
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
index 3b66f062cfa..470a67597e5 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/single_thread_task_runner.h"
+#include "base/strings/safe_sprintf.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_tokenizer.h"
@@ -46,6 +47,7 @@ const char kBuildNumberHeaderOption[] = "b";
const char kPatchNumberHeaderOption[] = "p";
const char kClientHeaderOption[] = "c";
const char kExperimentsOption[] = "exp";
+const char kPageIdOption[] = "pid";
// The empty version for the authentication protocol. Currently used by
// Android webview.
@@ -74,7 +76,8 @@ DataReductionProxyRequestOptions::DataReductionProxyRequestOptions(
DataReductionProxyConfig* config)
: client_(util::GetStringForClient(client)),
use_assigned_credentials_(false),
- data_reduction_proxy_config_(config) {
+ data_reduction_proxy_config_(config),
+ current_page_id_(0u) {
DCHECK(data_reduction_proxy_config_);
util::GetChromiumBuildAndPatch(version, &build_, &patch_);
}
@@ -150,8 +153,10 @@ void DataReductionProxyRequestOptions::RandBytes(void* output,
}
void DataReductionProxyRequestOptions::AddRequestHeader(
- net::HttpRequestHeaders* request_headers) {
+ net::HttpRequestHeaders* request_headers,
+ base::Optional<uint64_t> page_id) {
DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!page_id || page_id.value() > 0u);
base::Time now = Now();
// Authorization credentials must be regenerated if they are expired.
if (!use_assigned_credentials_ && (now > credentials_expiration_time_))
@@ -164,6 +169,14 @@ void DataReductionProxyRequestOptions::AddRequestHeader(
header_value += ", ";
}
header_value += header_value_;
+
+ if (page_id) {
+ char page_id_buffer[16];
+ if (base::strings::SafeSPrintf(page_id_buffer, "%x", page_id.value()) > 0) {
+ header_value += ", " + FormatOption(kPageIdOption, page_id_buffer);
+ }
+ }
+
request_headers->SetHeader(kChromeProxyHeader, header_value);
}
@@ -209,6 +222,7 @@ void DataReductionProxyRequestOptions::SetSecureSession(
session_.clear();
credentials_.clear();
secure_session_ = secure_session;
+ ResetPageId();
// Force skipping of credential regeneration. It should be handled by the
// caller.
use_assigned_credentials_ = true;
@@ -298,4 +312,14 @@ std::string DataReductionProxyRequestOptions::GetSessionKeyFromRequestHeaders(
return "";
}
+uint64_t DataReductionProxyRequestOptions::GeneratePageId() {
+ // Caller should not depend on order.
+ return ++current_page_id_;
+}
+
+void DataReductionProxyRequestOptions::ResetPageId() {
+ // Caller should not depend on reset setting the page ID to 0.
+ current_page_id_ = 0;
+}
+
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h
index b18dee44472..08700fd2d18 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h
@@ -13,6 +13,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
@@ -56,8 +57,10 @@ class DataReductionProxyRequestOptions {
void Init();
// Adds a 'Chrome-Proxy' header to |request_headers| with the data reduction
- // proxy authentication credentials.
- void AddRequestHeader(net::HttpRequestHeaders* request_headers);
+ // proxy authentication credentials. |page_id| should only be non-empty for
+ // main frame requests.
+ void AddRequestHeader(net::HttpRequestHeaders* request_headers,
+ base::Optional<uint64_t> page_id);
// Stores the supplied key and sets up credentials suitable for authenticating
// with the data reduction proxy.
@@ -81,6 +84,9 @@ class DataReductionProxyRequestOptions {
std::string GetSessionKeyFromRequestHeaders(
const net::HttpRequestHeaders& request_headers) const;
+ // Creates and returns a new unique page ID (unique per session).
+ uint64_t GeneratePageId();
+
protected:
// Returns a UTF16 string that's the hash of the configured authentication
// |key| and |salt|. Returns an empty UTF16 string if no key is configured or
@@ -106,6 +112,11 @@ class DataReductionProxyRequestOptions {
FRIEND_TEST_ALL_PREFIXES(DataReductionProxyRequestOptionsTest,
AuthHashForSalt);
+ // Resets the page ID for a new session.
+ // TODO(ryansturm): Create a session object to store this and other data saver
+ // session info. crbug.com/709624
+ void ResetPageId();
+
// Updates the value of the experiments to be run and regenerate the header if
// necessary.
void UpdateExperiments();
@@ -152,6 +163,9 @@ class DataReductionProxyRequestOptions {
// Must outlive |this|.
DataReductionProxyConfig* data_reduction_proxy_config_;
+ // The page identifier that was last generated for data saver proxy server.
+ uint64_t current_page_id_;
+
// Enforce usage on the IO thread.
base::ThreadChecker thread_checker_;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
index 40cc55ec0df..1e58b8a5452 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
@@ -39,11 +39,15 @@ const char kExpectedBuild[] = "2";
const char kExpectedPatch[] = "3";
const char kExpectedCredentials[] = "96bd72ec4a050ba60981743d41787768";
const char kExpectedSession[] = "0-1633771873-1633771873-1633771873";
+const char kPageId[] = "1";
+const uint64_t kPageIdValue = 1;
const char kTestKey2[] = "test-key2";
const char kExpectedCredentials2[] = "c911fdb402f578787562cf7f00eda972";
const char kExpectedSession2[] = "0-1633771873-1633771873-1633771873";
const char kDataReductionProxyKey[] = "12345";
+const char kPageId2[] = "f";
+const uint64_t kPageIdValue2 = 15;
const char kSecureSession[] = "TestSecureSessionKey";
} // namespace
@@ -93,6 +97,7 @@ void SetHeaderExpectations(const std::string& session,
const std::string& client,
const std::string& build,
const std::string& patch,
+ const std::string& page_id,
const std::vector<std::string> experiments,
std::string* expected_header) {
std::vector<std::string> expected_options;
@@ -123,6 +128,10 @@ void SetHeaderExpectations(const std::string& session,
expected_options.push_back(
std::string(kExperimentsOption) + "=" + experiment);
}
+
+ EXPECT_FALSE(page_id.empty());
+ expected_options.push_back("pid=" + page_id);
+
if (!expected_options.empty())
*expected_header = base::JoinString(expected_options, ", ");
}
@@ -153,10 +162,11 @@ class DataReductionProxyRequestOptionsTest : public testing::Test {
return request_options_.get();
}
- void VerifyExpectedHeader(const std::string& expected_header) {
+ void VerifyExpectedHeader(const std::string& expected_header,
+ uint64_t page_id) {
test_context_->RunUntilIdle();
net::HttpRequestHeaders headers;
- request_options_->AddRequestHeader(&headers);
+ request_options_->AddRequestHeader(&headers, page_id);
if (expected_header.empty()) {
EXPECT_FALSE(headers.HasHeader(kChromeProxyHeader));
return;
@@ -184,13 +194,13 @@ TEST_F(DataReductionProxyRequestOptionsTest, AuthHashForSalt) {
TEST_F(DataReductionProxyRequestOptionsTest, AuthorizationOnIOThread) {
std::string expected_header;
SetHeaderExpectations(kExpectedSession2, kExpectedCredentials2, std::string(),
- kClientStr, kExpectedBuild, kExpectedPatch,
+ kClientStr, kExpectedBuild, kExpectedPatch, kPageId,
std::vector<std::string>(), &expected_header);
std::string expected_header2;
SetHeaderExpectations("86401-1633771873-1633771873-1633771873",
"d7c1c34ef6b90303b01c48a6c1db6419", std::string(),
- kClientStr, kExpectedBuild, kExpectedPatch,
+ kClientStr, kExpectedBuild, kExpectedPatch, kPageId2,
std::vector<std::string>(), &expected_header2);
CreateRequestOptions(kVersion);
@@ -200,40 +210,40 @@ TEST_F(DataReductionProxyRequestOptionsTest, AuthorizationOnIOThread) {
request_options()->SetKeyOnIO(kTestKey2);
// Write headers.
- VerifyExpectedHeader(expected_header);
+ VerifyExpectedHeader(expected_header, kPageIdValue);
// Fast forward 24 hours. The header should be the same.
request_options()->set_offset(base::TimeDelta::FromSeconds(24 * 60 * 60));
- VerifyExpectedHeader(expected_header);
+ VerifyExpectedHeader(expected_header, kPageIdValue);
// Fast forward one more second. The header should be new.
request_options()->set_offset(base::TimeDelta::FromSeconds(24 * 60 * 60 + 1));
- VerifyExpectedHeader(expected_header2);
+ VerifyExpectedHeader(expected_header2, kPageIdValue2);
}
TEST_F(DataReductionProxyRequestOptionsTest, AuthorizationIgnoresEmptyKey) {
std::string expected_header;
SetHeaderExpectations(kExpectedSession, kExpectedCredentials, std::string(),
- kClientStr, kExpectedBuild, kExpectedPatch,
+ kClientStr, kExpectedBuild, kExpectedPatch, kPageId,
std::vector<std::string>(), &expected_header);
CreateRequestOptions(kVersion);
- VerifyExpectedHeader(expected_header);
+ VerifyExpectedHeader(expected_header, kPageIdValue);
// Now set an empty key. The auth handler should ignore that, and the key
// remains |kTestKey|.
request_options()->SetKeyOnIO(std::string());
- VerifyExpectedHeader(expected_header);
+ VerifyExpectedHeader(expected_header, kPageIdValue);
}
TEST_F(DataReductionProxyRequestOptionsTest, SecureSession) {
std::string expected_header;
SetHeaderExpectations(std::string(), std::string(), kSecureSession,
- kClientStr, kExpectedBuild, kExpectedPatch,
+ kClientStr, kExpectedBuild, kExpectedPatch, kPageId,
std::vector<std::string>(), &expected_header);
CreateRequestOptions(kVersion);
request_options()->SetSecureSession(kSecureSession);
- VerifyExpectedHeader(expected_header);
+ VerifyExpectedHeader(expected_header, kPageIdValue);
}
TEST_F(DataReductionProxyRequestOptionsTest, ParseExperiments) {
@@ -245,11 +255,11 @@ TEST_F(DataReductionProxyRequestOptionsTest, ParseExperiments) {
expected_experiments.push_back("\"foo,bar\"");
std::string expected_header;
SetHeaderExpectations(kExpectedSession, kExpectedCredentials, std::string(),
- kClientStr, kExpectedBuild, kExpectedPatch,
+ kClientStr, kExpectedBuild, kExpectedPatch, kPageId,
expected_experiments, &expected_header);
CreateRequestOptions(kVersion);
- VerifyExpectedHeader(expected_header);
+ VerifyExpectedHeader(expected_header, kPageIdValue);
}
TEST_F(DataReductionProxyRequestOptionsTest, ParseExperimentsFromFieldTrial) {
@@ -312,11 +322,11 @@ TEST_F(DataReductionProxyRequestOptionsTest, ParseExperimentsFromFieldTrial) {
expected_experiments.push_back(test.expected_experiment);
SetHeaderExpectations(kExpectedSession, kExpectedCredentials, std::string(),
- kClientStr, kExpectedBuild, kExpectedPatch,
+ kClientStr, kExpectedBuild, kExpectedPatch, kPageId,
expected_experiments, &expected_header);
CreateRequestOptions(kVersion);
- VerifyExpectedHeader(expected_header);
+ VerifyExpectedHeader(expected_header, kPageIdValue);
}
}
@@ -356,4 +366,17 @@ TEST_F(DataReductionProxyRequestOptionsTest, GetSessionKeyFromRequestHeaders) {
}
}
+TEST_F(DataReductionProxyRequestOptionsTest, PageIdIncrementing) {
+ CreateRequestOptions(kVersion);
+ DCHECK_EQ(1u, request_options()->GeneratePageId());
+ DCHECK_EQ(2u, request_options()->GeneratePageId());
+ DCHECK_EQ(3u, request_options()->GeneratePageId());
+
+ request_options()->SetSecureSession("blah");
+
+ DCHECK_EQ(1u, request_options()->GeneratePageId());
+ DCHECK_EQ(2u, request_options()->GeneratePageId());
+ DCHECK_EQ(3u, request_options()->GeneratePageId());
+}
+
} // namespace data_reduction_proxy
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 6269291be06..b07e7dd8c8b 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
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
@@ -15,6 +16,7 @@
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.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"
@@ -103,6 +105,12 @@ void DataReductionProxySettings::InitDataReductionProxySettings(
UpdateConfigValues();
RecordDataReductionInit();
data_reduction_proxy_service_->InitializeLoFiPrefs();
+
+ if (base::FeatureList::IsEnabled(features::kDataReductionSiteBreakdown) &&
+ spdy_proxy_auth_enabled_.GetValue()) {
+ data_reduction_proxy_service_->compression_stats()
+ ->SetDataUsageReportingEnabled(true);
+ }
}
void DataReductionProxySettings::OnServiceInitialized() {
@@ -139,9 +147,14 @@ bool DataReductionProxySettings::IsDataReductionProxyManaged() {
void DataReductionProxySettings::SetDataReductionProxyEnabled(bool enabled) {
DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(data_reduction_proxy_service_->compression_stats());
if (spdy_proxy_auth_enabled_.GetValue() != enabled) {
spdy_proxy_auth_enabled_.SetValue(enabled);
OnProxyEnabledPrefChange();
+ if (base::FeatureList::IsEnabled(features::kDataReductionSiteBreakdown)) {
+ data_reduction_proxy_service_->compression_stats()
+ ->SetDataUsageReportingEnabled(enabled);
+ }
}
}
@@ -152,6 +165,13 @@ int64_t DataReductionProxySettings::GetDataReductionLastUpdateTime() {
data_reduction_proxy_service_->compression_stats()->GetLastUpdateTime();
}
+void DataReductionProxySettings::ClearDataSavingStatistics() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(data_reduction_proxy_service_->compression_stats());
+ data_reduction_proxy_service_->compression_stats()
+ ->ClearDataSavingStatistics();
+}
+
int64_t DataReductionProxySettings::GetTotalHttpContentLengthSaved() {
DCHECK(thread_checker_.CalledOnValidThread());
return data_reduction_proxy_service_->compression_stats()
@@ -391,15 +411,4 @@ void DataReductionProxySettings::GetContentLengths(
days, original_content_length, received_content_length, last_update_time);
}
-bool DataReductionProxySettings::UpdateDataSavings(
- const std::string& data_usage_host,
- int64_t data_used,
- int64_t original_size) {
- if (!IsDataReductionProxyEnabled())
- return false;
- data_reduction_proxy_service_->compression_stats()->UpdateDataSavings(
- data_usage_host, data_used, original_size);
- return true;
-}
-
} // 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 ea4bcb767e4..b329f5f1cb3 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
@@ -17,7 +17,6 @@
#include "base/threading/thread_checker.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service_observer.h"
-#include "components/data_reduction_proxy/core/common/data_savings_recorder.h"
#include "components/prefs/pref_member.h"
#include "url/gurl.h"
@@ -73,20 +72,14 @@ enum DataReductionSettingsEnabledAction {
// Central point for configuring the data reduction proxy.
// This object lives on the UI thread and all of its methods are expected to
// be called from there.
-class DataReductionProxySettings : public DataReductionProxyServiceObserver,
- public DataSavingsRecorder {
+class DataReductionProxySettings : public DataReductionProxyServiceObserver {
public:
- typedef base::Callback<bool(const std::string&, const std::string&)>
- SyntheticFieldTrialRegistrationCallback;
+ using SyntheticFieldTrialRegistrationCallback =
+ base::Callback<bool(base::StringPiece, base::StringPiece)>;
DataReductionProxySettings();
virtual ~DataReductionProxySettings();
- // DataSavingsRecorder implementation:
- bool UpdateDataSavings(const std::string& data_usage_host,
- int64_t data_used,
- int64_t original_size) override;
-
// Initializes the Data Reduction Proxy with the name of the preference that
// controls enabling it, profile prefs and a |DataReductionProxyIOData|. The
// caller must ensure that all parameters remain alive for the lifetime of
@@ -97,8 +90,6 @@ class DataReductionProxySettings : public DataReductionProxyServiceObserver,
DataReductionProxyIOData* io_data,
std::unique_ptr<DataReductionProxyService> data_reduction_proxy_service);
- base::WeakPtr<DataReductionProxyCompressionStats> compression_stats();
-
// Sets the |register_synthetic_field_trial_| callback and runs to register
// the DataReductionProxyEnabled and the DataReductionProxyLoFiEnabled
// synthetic field trial.
@@ -146,6 +137,9 @@ class DataReductionProxySettings : public DataReductionProxyServiceObserver,
// daily original and received content lengths.
int64_t GetDataReductionLastUpdateTime();
+ // Clears all data saving statistics.
+ void ClearDataSavingStatistics();
+
// 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();
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
index 744a0f3b939..90476c4db2b 100644
--- 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
@@ -62,9 +62,9 @@ void DataReductionProxySettingsTestBase::SetUp() {
prefs::kDailyHttpReceivedContentLength);
for (int64_t i = 0; i < kNumDaysInHistory; i++) {
original_update->Insert(
- 0, base::MakeUnique<base::StringValue>(base::Int64ToString(2 * i)));
+ 0, base::MakeUnique<base::Value>(base::Int64ToString(2 * i)));
received_update->Insert(
- 0, base::MakeUnique<base::StringValue>(base::Int64ToString(i)));
+ 0, base::MakeUnique<base::Value>(base::Int64ToString(i)));
}
last_update_time_ = base::Time::Now().LocalMidnight();
pref_service->SetInt64(prefs::kDailyHttpContentLengthLastUpdateDate,
@@ -124,7 +124,7 @@ void DataReductionProxySettingsTestBase::CheckOnPrefChange(
if (managed) {
test_context_->pref_service()->SetManagedPref(
test_context_->GetDataReductionProxyEnabledPrefName(),
- new base::Value(enabled));
+ base::MakeUnique<base::Value>(enabled));
} else {
test_context_->SetDataReductionProxyEnabled(enabled);
}
@@ -140,10 +140,9 @@ void DataReductionProxySettingsTestBase::InitDataReductionProxy(
test_context_->CreateDataReductionProxyService(settings_.get()));
settings_->data_reduction_proxy_service()->SetIOData(
test_context_->io_data()->GetWeakPtr());
- settings_->SetCallbackToRegisterSyntheticFieldTrial(
- base::Bind(&DataReductionProxySettingsTestBase::
- SyntheticFieldTrialRegistrationCallback,
- base::Unretained(this)));
+ settings_->SetCallbackToRegisterSyntheticFieldTrial(base::Bind(
+ &DataReductionProxySettingsTestBase::OnSyntheticFieldTrialRegistration,
+ base::Unretained(this)));
test_context_->RunUntilIdle();
}
@@ -154,4 +153,11 @@ void DataReductionProxySettingsTestBase::CheckDataReductionProxySyntheticTrial(
synthetic_field_trials_["SyntheticDataReductionProxySetting"]);
}
+bool DataReductionProxySettingsTestBase::OnSyntheticFieldTrialRegistration(
+ base::StringPiece trial_name,
+ base::StringPiece group_name) {
+ synthetic_field_trials_[trial_name.as_string()] = group_name.as_string();
+ 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
index 987de6337db..6846173a474 100644
--- 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
@@ -8,8 +8,10 @@
#include <map>
#include <memory>
#include <string>
+#include <utility>
#include "base/message_loop/message_loop.h"
+#include "base/strings/string_piece.h"
#include "base/time/clock.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
@@ -41,7 +43,6 @@ class DataReductionProxySettingsTestBase : public testing::Test {
static void AddTestProxyToCommandLine();
DataReductionProxySettingsTestBase();
- DataReductionProxySettingsTestBase(bool promo_allowed);
~DataReductionProxySettingsTestBase() override;
void AddProxyToCommandLine();
@@ -68,12 +69,10 @@ class DataReductionProxySettingsTestBase : public testing::Test {
void InitWithStatisticsPrefs();
void InitDataReductionProxy(bool enabled_at_startup);
void CheckDataReductionProxySyntheticTrial(bool enabled);
- bool SyntheticFieldTrialRegistrationCallback(const std::string& trial_name,
- const std::string& group_name) {
- synthetic_field_trials_[trial_name] = group_name;
- return true;
- }
+ bool OnSyntheticFieldTrialRegistration(base::StringPiece trial_name,
+ base::StringPiece group_name);
+ protected:
base::MessageLoopForIO message_loop_;
std::unique_ptr<DataReductionProxyTestContext> test_context_;
std::unique_ptr<DataReductionProxySettings> settings_;
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
index d2ef4375ad6..8af34b7db5c 100644
--- 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
@@ -66,17 +66,14 @@ TEST_F(DataReductionProxySettingsTest, TestIsProxyEnabledOrManaged) {
test_context_->config()->UpdateConfigForTesting(false, true);
EXPECT_FALSE(settings_->IsDataReductionProxyEnabled());
- EXPECT_FALSE(settings_->UpdateDataSavings(std::string(), 0, 0));
EXPECT_FALSE(settings_->IsDataReductionProxyManaged());
CheckOnPrefChange(true, true, false);
EXPECT_TRUE(settings_->IsDataReductionProxyEnabled());
- EXPECT_TRUE(settings_->UpdateDataSavings(std::string(), 0, 0));
EXPECT_FALSE(settings_->IsDataReductionProxyManaged());
CheckOnPrefChange(true, true, true);
EXPECT_TRUE(settings_->IsDataReductionProxyEnabled());
- EXPECT_TRUE(settings_->UpdateDataSavings(std::string(), 0, 0));
EXPECT_TRUE(settings_->IsDataReductionProxyManaged());
test_context_->RunUntilIdle();
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.cc
index c28f9e0fa55..f8483575138 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.cc
@@ -299,9 +299,8 @@ bool DataReductionProxyTamperDetection::ValidateViaHeader(
base::StringPiece fingerprint,
bool* has_chrome_proxy_via_header) const {
bool has_intermediary;
- *has_chrome_proxy_via_header = HasDataReductionProxyViaHeader(
- response_headers_,
- &has_intermediary);
+ *has_chrome_proxy_via_header =
+ HasDataReductionProxyViaHeader(*response_headers_, &has_intermediary);
if (*has_chrome_proxy_via_header)
return !has_intermediary;
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
index eb267fb172a..f5a610b1dfd 100644
--- 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
@@ -287,6 +287,12 @@ DataStore::Status TestDataStore::Delete(base::StringPiece key) {
return OK;
}
+DataStore::Status TestDataStore::RecreateDB() {
+ map_.clear();
+
+ return OK;
+}
+
DataReductionProxyTestContext::Builder::Builder()
: params_flags_(DataReductionProxyParams::kPromoAllowed),
params_definitions_(TestDataReductionProxyParams::HAS_EVERYTHING),
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
index e42557f3a0e..a6eb4039e03 100644
--- 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
@@ -261,6 +261,8 @@ class TestDataStore : public data_reduction_proxy::DataStore {
DataStore::Status Delete(base::StringPiece key) override;
+ DataStore::Status RecreateDB() override;
+
std::map<std::string, std::string>* map() { return &map_; }
private:
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_store.cc b/chromium/components/data_reduction_proxy/core/browser/data_store.cc
index eacf50ca185..782a1944b47 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_store.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_store.cc
@@ -28,4 +28,8 @@ 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
index 1c254c2f137..f275da781e2 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_store.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_store.h
@@ -36,6 +36,9 @@ class DataStore {
virtual Status Delete(base::StringPiece key);
+ // Deletes the LevelDB and recreates it.
+ virtual Status RecreateDB();
+
private:
DISALLOW_COPY_AND_ASSIGN(DataStore);
};
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
index 76903bee1df..3c7c180fe96 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc
@@ -117,7 +117,9 @@ DataStore::Status DataStoreImpl::OpenDB() {
leveldb::Options options;
options.create_if_missing = true;
options.paranoid_checks = true;
- options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
+ // 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();
leveldb::DB* dbptr = nullptr;
Status status =
@@ -144,14 +146,13 @@ DataStore::Status DataStoreImpl::OpenDB() {
return status;
}
-void DataStoreImpl::RecreateDB() {
+DataStore::Status DataStoreImpl::RecreateDB() {
DCHECK(sequence_checker_.CalledOnValidSequence());
- LOG(WARNING) << "Deleting corrupt Data Reduction Proxy LevelDB";
db_.reset(nullptr);
base::DeleteFile(profile_path_.Append(kDBName), true);
- OpenDB();
+ 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
index b7aeca2bbd2..950de079ae0 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_store_impl.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_store_impl.h
@@ -36,14 +36,14 @@ class DataStoreImpl : public DataStore {
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();
- // Deletes the LevelDB and recreates it. This method is called if any DB call
- // returns a |CORRUPTED| status.
- void RecreateDB();
-
// The underlying LevelDB used by this implementation.
std::unique_ptr<leveldb::DB> db_;
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
index 98bcbbd0ed4..41f5fb65332 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc
@@ -22,23 +22,23 @@
#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;
-// Time interval for each DataUsageBucket.
-const int kDataUsageBucketLengthInMinutes = 15;
-static_assert(kDataUsageBucketLengthInMinutes > 0,
+static_assert(data_reduction_proxy::kDataUsageBucketLengthInMinutes > 0,
"Length of time should be positive");
-static_assert(kMinutesInHour % kDataUsageBucketLengthInMinutes == 0,
+static_assert(kMinutesInHour %
+ data_reduction_proxy::kDataUsageBucketLengthInMinutes ==
+ 0,
"kDataUsageBucketLengthMins must be a factor of kMinsInHour");
-// Number of days for which to maintain data usage history.
-const int kDataUsageHistoryNumDays = 60;
-
// Total number of buckets persisted to DB.
const int kNumDataUsageBuckets =
kDataUsageHistoryNumDays * kMinutesInDay / kDataUsageBucketLengthInMinutes;
@@ -65,8 +65,6 @@ base::Time BucketLowerBoundary(base::Time time) {
} // namespace
-namespace data_reduction_proxy {
-
DataUsageStore::DataUsageStore(DataStore* db)
: db_(db), current_bucket_index_(-1) {
sequence_checker_.DetachFromSequence();
@@ -154,10 +152,16 @@ void DataUsageStore::StoreCurrentDataUsageBucket(
}
void DataUsageStore::DeleteHistoricalDataUsage() {
- for (int i = 0; i < kNumDataUsageBuckets; ++i)
- db_->Delete(DbKeyForBucketIndex(i));
+ 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_->Delete(kCurrentBucketIndexKey);
+ db_->RecreateDB();
}
void DataUsageStore::DeleteBrowsingHistory(const base::Time& start,
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
index c346408374b..9ef594a55bd 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_usage_store.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_usage_store.h
@@ -21,6 +21,12 @@ 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 {
diff --git a/chromium/components/data_reduction_proxy/core/common/BUILD.gn b/chromium/components/data_reduction_proxy/core/common/BUILD.gn
index ba5918c21ed..d4a8642349b 100644
--- a/chromium/components/data_reduction_proxy/core/common/BUILD.gn
+++ b/chromium/components/data_reduction_proxy/core/common/BUILD.gn
@@ -17,6 +17,8 @@ template("common_tmpl") {
"data_reduction_proxy_event_storage_delegate.h",
"data_reduction_proxy_event_store.cc",
"data_reduction_proxy_event_store.h",
+ "data_reduction_proxy_features.cc",
+ "data_reduction_proxy_features.h",
"data_reduction_proxy_headers.cc",
"data_reduction_proxy_headers.h",
"data_reduction_proxy_page_load_timing.cc",
@@ -31,7 +33,6 @@ template("common_tmpl") {
"data_reduction_proxy_switches.h",
"data_reduction_proxy_util.cc",
"data_reduction_proxy_util.h",
- "data_savings_recorder.h",
"lofi_decider.h",
"lofi_ui_service.h",
"resource_type_provider.h",
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_bypass_type_list.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_bypass_type_list.h
index 8010fbf87c2..0c67e60f5ec 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_bypass_type_list.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_bypass_type_list.h
@@ -45,5 +45,8 @@ BYPASS_EVENT_TYPE(STATUS_503_HTTP_SERVICE_UNAVAILABLE, 9)
// Bypass due to any network error.
BYPASS_EVENT_TYPE(NETWORK_ERROR, 10)
+// Bypass due to URL redirect cycle.
+BYPASS_EVENT_TYPE(URL_REDIRECT_CYCLE, 11)
+
// This must always be last.
-BYPASS_EVENT_TYPE(MAX, 11)
+BYPASS_EVENT_TYPE(MAX, 12)
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc
index 8f7db517adb..fd6ddc7bd21 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc
@@ -12,6 +12,7 @@
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
#include "base/values.h"
@@ -51,13 +52,13 @@ const StringToConstant kDataReductionProxyBypassActionTypeTable[] = {
};
std::string JoinListValueStrings(base::ListValue* list_value) {
- std::vector<std::string> values;
+ std::vector<base::StringPiece> values;
for (const auto& value : *list_value) {
- std::string value_string;
- if (!value->GetAsString(&value_string))
+ base::StringPiece value_string;
+ if (!value.GetAsString(&value_string))
return std::string();
- values.push_back(std::move(value_string));
+ values.push_back(value_string);
}
return base::JoinString(values, ";");
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
new file mode 100644
index 00000000000..6e09db8dc84
--- /dev/null
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
@@ -0,0 +1,20 @@
+// 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"
+
+namespace data_reduction_proxy {
+namespace features {
+
+// Enables the Data Reduction Proxy menu item in the main menu rather than under
+// Settings on Android.
+const base::Feature kDataReductionMainMenu{"DataReductionProxyMainMenu",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables the site breakdown on the Data Reduction Proxy settings page.
+const base::Feature kDataReductionSiteBreakdown{
+ "DataReductionProxySiteBreakdown", 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
new file mode 100644
index 00000000000..9913b055a51
--- /dev/null
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
@@ -0,0 +1,18 @@
+// 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 kDataReductionMainMenu;
+extern const base::Feature kDataReductionSiteBreakdown;
+
+} // 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
index 375416a081c..3a697aecaf8 100644
--- 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
@@ -20,6 +20,8 @@
#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 "net/url_request/url_request.h"
using base::StringPiece;
using base::TimeDelta;
@@ -40,6 +42,9 @@ const char kLitePageDirective[] = "lite-page";
const char kCompressedVideoDirective[] = "compressed-video";
const char kIdentityDirective[] = "identity";
+// The legacy Chrome-Proxy response header directive for LoFi images.
+const char kLegacyChromeProxyLoFiResponseDirective[] = "q=low";
+
const char kChromeProxyLitePageIngoreBlacklistDirective[] =
"exp=ignore_preview_blacklist";
@@ -80,29 +85,37 @@ bool StartsWithActionPrefix(base::StringPiece header_value,
// Returns true if the provided transform type is specified in the provided
// Chrome-Proxy-Content-Transform header value.
-bool IsPreviewTypeInHeaderValue(const std::string& header_value,
- const std::string& transform_type) {
- std::vector<std::string> tokens =
- base::SplitString(base::ToLowerASCII(header_value), ";",
- base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
- if (tokens.empty())
- return false;
- std::string header_transform_type;
- base::TrimWhitespaceASCII(tokens[0], base::TRIM_ALL, &header_transform_type);
- return header_transform_type == transform_type;
+bool IsPreviewTypeInHeaderValue(base::StringPiece header_value,
+ base::StringPiece transform_type) {
+ DCHECK_EQ(transform_type, base::ToLowerASCII(transform_type));
+
+ // The Chrome-Proxy-Content-Transform header consists of a single
+ // transformation type string followed by zero or more semicolon-delimited
+ // options, e.g. "empty-image", "empty-image;foo-option".
+ base::StringPiece token = base::TrimWhitespaceASCII(
+ header_value.substr(0, header_value.find(';')), base::TRIM_ALL);
+ return base::LowerCaseEqualsASCII(token, transform_type);
}
// Returns true if the provided transform type is specified in the
// Chrome-Proxy-Content-Transform-Header.
bool IsPreviewType(const net::HttpResponseHeaders& headers,
- const std::string& transform_type) {
- std::string header_value;
- if (!headers.GetNormalizedHeader(
- data_reduction_proxy::chrome_proxy_content_transform_header(),
- &header_value)) {
+ base::StringPiece transform_type) {
+ std::string value;
+ return headers.EnumerateHeader(nullptr, kChromeProxyContentTransformHeader,
+ &value) &&
+ IsPreviewTypeInHeaderValue(value, transform_type);
+}
+
+// Returns true if there is a cycle in |url_chain|.
+bool HasURLRedirectCycle(const std::vector<GURL>& url_chain) {
+ if (url_chain.size() <= 1)
return false;
- }
- return IsPreviewTypeInHeaderValue(header_value, transform_type);
+
+ // If the last entry occurs earlier in the |url_chain|, then very likely there
+ // is a redirect cycle.
+ return std::find(url_chain.rbegin() + 1, url_chain.rend(),
+ url_chain.back()) != url_chain.rend();
}
} // namespace
@@ -146,12 +159,27 @@ const char* if_heavy_qualifier() {
}
bool IsEmptyImagePreview(const net::HttpResponseHeaders& headers) {
- return IsPreviewType(headers, kEmptyImageDirective);
+ return IsPreviewType(headers, kEmptyImageDirective) ||
+ headers.HasHeaderValue(kChromeProxyHeader,
+ kLegacyChromeProxyLoFiResponseDirective);
}
-bool IsEmptyImagePreview(const std::string& content_transform_value) {
- return IsPreviewTypeInHeaderValue(content_transform_value,
- kEmptyImageDirective);
+bool IsEmptyImagePreview(const std::string& content_transform_value,
+ const std::string& chrome_proxy_value) {
+ if (IsPreviewTypeInHeaderValue(content_transform_value, kEmptyImageDirective))
+ return true;
+
+ // Look for "q=low" in the "Chrome-Proxy" response header.
+ net::HttpUtil::ValuesIterator values(chrome_proxy_value.begin(),
+ chrome_proxy_value.end(), ',');
+ while (values.GetNext()) {
+ base::StringPiece value(values.value_begin(), values.value_end());
+ if (base::LowerCaseEqualsASCII(value,
+ kLegacyChromeProxyLoFiResponseDirective)) {
+ return true;
+ }
+ }
+ return false;
}
bool IsLitePagePreview(const net::HttpResponseHeaders& headers) {
@@ -175,14 +203,13 @@ bool GetDataReductionProxyActionValue(const net::HttpResponseHeaders* headers,
return false;
}
-bool ParseHeadersAndSetBypassDuration(const net::HttpResponseHeaders* headers,
+bool ParseHeadersAndSetBypassDuration(const net::HttpResponseHeaders& headers,
base::StringPiece action_prefix,
base::TimeDelta* bypass_duration) {
- DCHECK(headers);
size_t iter = 0;
std::string value;
- while (headers->EnumerateHeader(&iter, kChromeProxyHeader, &value)) {
+ while (headers.EnumerateHeader(&iter, kChromeProxyHeader, &value)) {
if (StartsWithActionPrefix(value, action_prefix)) {
int64_t seconds;
if (!base::StringToInt64(
@@ -203,7 +230,7 @@ bool ParseHeadersAndSetBypassDuration(const net::HttpResponseHeaders* headers,
return false;
}
-bool ParseHeadersForBypassInfo(const net::HttpResponseHeaders* headers,
+bool ParseHeadersForBypassInfo(const net::HttpResponseHeaders& headers,
DataReductionProxyInfo* proxy_info) {
DCHECK(proxy_info);
@@ -240,8 +267,7 @@ bool ParseHeadersForBypassInfo(const net::HttpResponseHeaders* headers,
// reduction proxies. Unlike 'block', 'block-once' does not cause data
// reduction proxies to be bypassed for an extended period of time;
// 'block-once' only affects the retry of the current request.
- if (headers->HasHeaderValue(kChromeProxyHeader,
- kChromeProxyActionBlockOnce)) {
+ if (headers.HasHeaderValue(kChromeProxyHeader, kChromeProxyActionBlockOnce)) {
proxy_info->bypass_all = true;
proxy_info->mark_proxies_as_bad = false;
proxy_info->bypass_duration = TimeDelta();
@@ -252,7 +278,7 @@ bool ParseHeadersForBypassInfo(const net::HttpResponseHeaders* headers,
return false;
}
-bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers,
+bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders& headers,
bool* has_intermediary) {
static const size_t kVersionSize = 4;
static const char kDataReductionProxyViaValue[] = "Chrome-Compression-Proxy";
@@ -262,14 +288,14 @@ bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers,
// Case-sensitive comparison of |value|. Assumes the received protocol and the
// space following it are always |kVersionSize| characters. E.g.,
// 'Via: 1.1 Chrome-Compression-Proxy'
- while (headers->EnumerateHeader(&iter, "via", &value)) {
+ while (headers.EnumerateHeader(&iter, "via", &value)) {
if (base::StringPiece(value).substr(
kVersionSize, arraysize(kDataReductionProxyViaValue) - 1) ==
kDataReductionProxyViaValue) {
if (has_intermediary)
// We assume intermediary exists if there is another Via header after
// the data reduction proxy's Via header.
- *has_intermediary = !(headers->EnumerateHeader(&iter, "via", &value));
+ *has_intermediary = !(headers.EnumerateHeader(&iter, "via", &value));
return true;
}
}
@@ -278,9 +304,21 @@ bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers,
}
DataReductionProxyBypassType GetDataReductionProxyBypassType(
- const net::HttpResponseHeaders* headers,
+ const std::vector<GURL>& url_chain,
+ const net::HttpResponseHeaders& headers,
DataReductionProxyInfo* data_reduction_proxy_info) {
DCHECK(data_reduction_proxy_info);
+
+ bool has_via_header = HasDataReductionProxyViaHeader(headers, nullptr);
+
+ if (has_via_header && HasURLRedirectCycle(url_chain)) {
+ data_reduction_proxy_info->bypass_all = true;
+ data_reduction_proxy_info->mark_proxies_as_bad = false;
+ data_reduction_proxy_info->bypass_duration = base::TimeDelta();
+ data_reduction_proxy_info->bypass_action = BYPASS_ACTION_TYPE_BLOCK_ONCE;
+ return BYPASS_EVENT_TYPE_URL_REDIRECT_CYCLE;
+ }
+
if (ParseHeadersForBypassInfo(headers, data_reduction_proxy_info)) {
// A chrome-proxy response header is only present in a 502. For proper
// reporting, this check must come before the 5xx checks below.
@@ -302,20 +340,19 @@ DataReductionProxyBypassType GetDataReductionProxyBypassType(
data_reduction_proxy_info->bypass_duration = GetDefaultBypassDuration();
// Fall back if a 500, 502 or 503 is returned.
- if (headers->response_code() == net::HTTP_INTERNAL_SERVER_ERROR)
+ if (headers.response_code() == net::HTTP_INTERNAL_SERVER_ERROR)
return BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR;
- if (headers->response_code() == net::HTTP_BAD_GATEWAY)
+ if (headers.response_code() == net::HTTP_BAD_GATEWAY)
return BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY;
- if (headers->response_code() == net::HTTP_SERVICE_UNAVAILABLE)
+ if (headers.response_code() == net::HTTP_SERVICE_UNAVAILABLE)
return BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE;
// TODO(kundaji): Bypass if Proxy-Authenticate header value cannot be
// interpreted by data reduction proxy.
- if (headers->response_code() == net::HTTP_PROXY_AUTHENTICATION_REQUIRED &&
- !headers->HasHeader("Proxy-Authenticate")) {
+ if (headers.response_code() == net::HTTP_PROXY_AUTHENTICATION_REQUIRED &&
+ !headers.HasHeader("Proxy-Authenticate")) {
return BYPASS_EVENT_TYPE_MALFORMED_407;
}
- if (!HasDataReductionProxyViaHeader(headers, NULL) &&
- (headers->response_code() != net::HTTP_NOT_MODIFIED)) {
+ if (!has_via_header && (headers.response_code() != net::HTTP_NOT_MODIFIED)) {
// A Via header might not be present in a 304. Since the goal of a 304
// response is to minimize information transfer, a sender in general
// should not generate representation metadata other than Cache-Control,
@@ -323,8 +360,8 @@ DataReductionProxyBypassType GetDataReductionProxyBypassType(
// The proxy Via header might also not be present in a 4xx response.
// Separate this case from other responses that are missing the header.
- if (headers->response_code() >= net::HTTP_BAD_REQUEST &&
- headers->response_code() < net::HTTP_INTERNAL_SERVER_ERROR) {
+ if (headers.response_code() >= net::HTTP_BAD_REQUEST &&
+ headers.response_code() < net::HTTP_INTERNAL_SERVER_ERROR) {
// At this point, any 4xx response that is missing the via header
// indicates an issue that is scoped to only the current request, so only
// bypass the data reduction proxy for the current request.
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
index e86cb5af22a..e059d641d74 100644
--- 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
@@ -6,16 +6,17 @@
#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_HEADERS_H_
#include <string>
+#include <vector>
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "net/proxy/proxy_service.h"
-namespace net {
+class GURL;
+namespace net {
class HttpResponseHeaders;
-
} // namespace net
namespace data_reduction_proxy {
@@ -110,7 +111,8 @@ bool IsEmptyImagePreview(const net::HttpResponseHeaders& headers);
// Returns true if the provided value of the Chrome-Proxy-Content-Transform
// response header that is provided in |content_transform_value| indicates that
// an empty image has been provided.
-bool IsEmptyImagePreview(const std::string& content_transform_value);
+bool IsEmptyImagePreview(const std::string& content_transform_value,
+ const std::string& chrome_proxy_value);
// Returns true if the Chrome-Proxy-Content-Transform response header indicates
// that a lite page has been provided.
@@ -122,7 +124,7 @@ bool IsLitePagePreview(const net::HttpResponseHeaders& headers);
// (as specified in |ProxyList::UpdateRetryInfoOnFallback|) should be used.
// If all available data reduction proxies should by bypassed, |bypass_all| is
// set to true. |proxy_info| must be non-NULL.
-bool ParseHeadersForBypassInfo(const net::HttpResponseHeaders* headers,
+bool ParseHeadersForBypassInfo(const net::HttpResponseHeaders& headers,
DataReductionProxyInfo* proxy_info);
// Returns true if the response contains the data reduction proxy Via header
@@ -130,14 +132,15 @@ bool ParseHeadersForBypassInfo(const net::HttpResponseHeaders* headers,
// a Via header after the data reduction proxy, and to false otherwise. Used to
// check the integrity of data reduction proxy responses and whether there are
// other middleboxes between the data reduction proxy and the client.
-bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders* headers,
+bool HasDataReductionProxyViaHeader(const net::HttpResponseHeaders& headers,
bool* has_intermediary);
// Returns the reason why the Chrome proxy should be bypassed or not, and
// populates |proxy_info| with information on how long to bypass if
-// applicable.
+// applicable. |url_chain| is the chain of URLs traversed by the request.
DataReductionProxyBypassType GetDataReductionProxyBypassType(
- const net::HttpResponseHeaders* headers,
+ const std::vector<GURL>& url_chain,
+ const net::HttpResponseHeaders& headers,
DataReductionProxyInfo* proxy_info);
// Searches for the specified Chrome-Proxy action, and if present saves its
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc
index e2f88449332..2e10c016f9e 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc
@@ -18,6 +18,7 @@
#include "net/http/http_response_headers.h"
#include "net/proxy/proxy_service.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
namespace data_reduction_proxy {
@@ -76,6 +77,28 @@ TEST_F(DataReductionProxyHeadersTest, IsEmptyImagePreview) {
"Another-Header: empty-image\n",
false,
},
+ {
+ "HTTP/1.1 200 OK\n"
+ "Chrome-Proxy: q=low\n",
+ true,
+ },
+ {
+ "HTTP/1.1 200 OK\n"
+ "Chrome-Proxy: foo=bar, Q=LOW\n",
+ true,
+ },
+ {
+ "HTTP/1.1 200 OK\n"
+ "Chrome-Proxy-Content-Transform: q=low\n"
+ "Chrome-Proxy: empty-image\n",
+ false,
+ },
+ {
+ "HTTP/1.1 200 OK\n"
+ "Chrome-Proxy-Content-Transform: foo\n"
+ "Chrome-Proxy: q=low\n",
+ true,
+ },
};
for (size_t i = 0; i < arraysize(tests); ++i) {
std::string headers(tests[i].headers);
@@ -88,30 +111,30 @@ TEST_F(DataReductionProxyHeadersTest, IsEmptyImagePreview) {
TEST_F(DataReductionProxyHeadersTest, IsEmptyImagePreviewValue) {
const struct {
- const char* header;
+ const char* chrome_proxy_content_transform_header;
+ const char* chrome_proxy_header;
bool expected_result;
} tests[] = {
- {
- "foo", false,
- },
- {
- "", false,
- },
- {
- "empty-image", true,
- },
- {
- "empty-image;foo", true,
- },
- {
- "Empty-Image", true,
- },
- {
- "foo;empty-image", false,
- },
+ {"", "", false},
+ {"foo", "", false},
+ {"", "bar", false},
+ {"foo", "bar", false},
+ {"empty-image", "", true},
+ {"empty-image;foo", "", true},
+ {"Empty-Image", "", true},
+ {"foo;empty-image", "", false},
+ {"empty-image", "foo", true},
+ {"foo;empty-image", "bar", false},
+ {"", "q=low", true},
+ {"foo", "q=low", true},
+ {"foo", "bar, baz, Q=LOW ", true},
+ {"empty-image", "q=low", true},
};
- for (size_t i = 0; i < arraysize(tests); ++i)
- EXPECT_EQ(tests[i].expected_result, IsEmptyImagePreview(tests[i].header));
+ for (const auto& test : tests) {
+ EXPECT_EQ(test.expected_result,
+ IsEmptyImagePreview(test.chrome_proxy_content_transform_header,
+ test.chrome_proxy_header));
+ }
}
TEST_F(DataReductionProxyHeadersTest, IsLitePagePreview) {
@@ -497,9 +520,8 @@ TEST_F(DataReductionProxyHeadersTest, GetProxyBypassInfo) {
new net::HttpResponseHeaders(headers));
DataReductionProxyInfo data_reduction_proxy_info;
- EXPECT_EQ(
- tests[i].expected_result,
- ParseHeadersForBypassInfo(parsed.get(), &data_reduction_proxy_info));
+ EXPECT_EQ(tests[i].expected_result,
+ ParseHeadersForBypassInfo(*parsed, &data_reduction_proxy_info));
EXPECT_EQ(tests[i].expected_retry_delay,
data_reduction_proxy_info.bypass_duration.InSeconds());
EXPECT_EQ(tests[i].expected_bypass_all,
@@ -520,8 +542,7 @@ TEST_F(DataReductionProxyHeadersTest, ParseHeadersAndSetProxyInfo) {
new net::HttpResponseHeaders(headers));
DataReductionProxyInfo data_reduction_proxy_info;
- EXPECT_TRUE(
- ParseHeadersForBypassInfo(parsed.get(), &data_reduction_proxy_info));
+ EXPECT_TRUE(ParseHeadersForBypassInfo(*parsed, &data_reduction_proxy_info));
EXPECT_LE(60, data_reduction_proxy_info.bypass_duration.InSeconds());
EXPECT_GE(5 * 60, data_reduction_proxy_info.bypass_duration.InSeconds());
EXPECT_FALSE(data_reduction_proxy_info.bypass_all);
@@ -612,11 +633,11 @@ TEST_F(DataReductionProxyHeadersTest, HasDataReductionProxyViaHeader) {
bool has_chrome_proxy_via_header, has_intermediary;
if (tests[i].ignore_intermediary) {
has_chrome_proxy_via_header =
- HasDataReductionProxyViaHeader(parsed.get(), NULL);
+ HasDataReductionProxyViaHeader(*parsed, NULL);
}
else {
has_chrome_proxy_via_header =
- HasDataReductionProxyViaHeader(parsed.get(), &has_intermediary);
+ HasDataReductionProxyViaHeader(*parsed, &has_intermediary);
}
EXPECT_EQ(tests[i].expected_result, has_chrome_proxy_via_header);
if (has_chrome_proxy_via_header && !tests[i].ignore_intermediary) {
@@ -768,8 +789,87 @@ TEST_F(DataReductionProxyHeadersTest, GetDataReductionProxyBypassEventType) {
tests[i].in_tamper_detection_experiment ? "TamperDetection_Enabled"
: "TamperDetection_Disabled");
- EXPECT_EQ(tests[i].expected_result, GetDataReductionProxyBypassType(
- parsed.get(), &chrome_proxy_info));
+ EXPECT_EQ(tests[i].expected_result,
+ GetDataReductionProxyBypassType(std::vector<GURL>(), *parsed,
+ &chrome_proxy_info));
+ }
+}
+
+TEST_F(DataReductionProxyHeadersTest,
+ GetDataReductionProxyBypassEventTypeURLRedirectCycle) {
+ const struct {
+ const char* headers;
+ std::vector<GURL> url_chain;
+ DataReductionProxyBypassType expected_result;
+ } tests[] = {
+ {
+ "HTTP/1.1 200 OK\n"
+ "Via: 1.1 Chrome-Compression-Proxy\n",
+ std::vector<GURL>{GURL("http://google.com/1"),
+ GURL("http://google.com/2"),
+ GURL("http://google.com/1")},
+ BYPASS_EVENT_TYPE_URL_REDIRECT_CYCLE,
+ },
+ {
+ "HTTP/1.1 200 OK\n"
+ "Via: 1.1 Chrome-Compression-Proxy\n",
+ std::vector<GURL>{
+ GURL("http://google.com/1"), GURL("http://google.com/2"),
+ GURL("http://google.com/1"), GURL("http://google.com/2")},
+ BYPASS_EVENT_TYPE_URL_REDIRECT_CYCLE,
+ },
+ {
+ "HTTP/1.1 200 OK\n"
+ "Via: 1.1 Chrome-Compression-Proxy\n",
+ std::vector<GURL>{GURL("http://google.com/1")}, BYPASS_EVENT_TYPE_MAX,
+ },
+ {
+ "HTTP/1.1 200 OK\n"
+ "Via: 1.1 Chrome-Compression-Proxy\n",
+ std::vector<GURL>{GURL("http://google.com/1"),
+ GURL("http://google.com/2")},
+ BYPASS_EVENT_TYPE_MAX,
+ },
+ {
+ "HTTP/1.1 200 OK\n"
+ "Via: 1.1 Chrome-Compression-Proxy\n",
+ std::vector<GURL>{GURL("http://google.com/1"),
+ GURL("http://google.com/2"),
+ GURL("http://google.com/3")},
+ BYPASS_EVENT_TYPE_MAX,
+ },
+ {
+ "HTTP/1.1 200 OK\n"
+ "Via: 1.1 Chrome-Compression-Proxy\n",
+ std::vector<GURL>{
+ GURL("http://google.com/1"), GURL("http://google.com/2"),
+ GURL("http://google.com/3"), GURL("http://google.com/1")},
+ BYPASS_EVENT_TYPE_URL_REDIRECT_CYCLE,
+ },
+ {
+ "HTTP/1.1 200 OK\n"
+ "Via: 1.1 Chrome-Compression-Proxy\n",
+ std::vector<GURL>{
+ GURL("http://google.com/1"), GURL("http://google.com/2"),
+ GURL("http://google.com/1"), GURL("http://google.com/3")},
+ BYPASS_EVENT_TYPE_MAX,
+ },
+ {
+ "HTTP/1.1 200 OK\n"
+ "Via: 1.1 Chrome-Compression-Proxy\n",
+ std::vector<GURL>(), BYPASS_EVENT_TYPE_MAX,
+ }};
+
+ for (const auto& test : tests) {
+ std::string headers(test.headers);
+ HeadersToRaw(&headers);
+ scoped_refptr<net::HttpResponseHeaders> parsed(
+ new net::HttpResponseHeaders(headers));
+ DataReductionProxyInfo chrome_proxy_info;
+
+ EXPECT_EQ(test.expected_result,
+ GetDataReductionProxyBypassType(test.url_chain, *parsed,
+ &chrome_proxy_info));
}
}
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc
index 22a9b101b0b..13ff57d2f35 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc
@@ -17,7 +17,8 @@ DataReductionProxyPageLoadTiming::DataReductionProxyPageLoadTiming(
parse_blocked_on_script_load_duration,
const base::Optional<base::TimeDelta>& parse_stop,
int64_t network_bytes,
- int64_t original_network_bytes)
+ int64_t original_network_bytes,
+ bool app_background_occurred)
: navigation_start(navigation_start),
response_start(response_start),
load_event_start(load_event_start),
@@ -28,7 +29,8 @@ DataReductionProxyPageLoadTiming::DataReductionProxyPageLoadTiming(
parse_blocked_on_script_load_duration),
parse_stop(parse_stop),
network_bytes(network_bytes),
- original_network_bytes(original_network_bytes) {}
+ original_network_bytes(original_network_bytes),
+ app_background_occurred(app_background_occurred) {}
DataReductionProxyPageLoadTiming::DataReductionProxyPageLoadTiming(
const DataReductionProxyPageLoadTiming& other) = default;
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h
index a1224225e41..84e1357dae1 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h
@@ -26,7 +26,8 @@ struct DataReductionProxyPageLoadTiming {
parse_blocked_on_script_load_duration,
const base::Optional<base::TimeDelta>& parse_stop,
int64_t network_bytes,
- int64_t original_network_bytes);
+ int64_t original_network_bytes,
+ bool app_background_occurred);
DataReductionProxyPageLoadTiming(
const DataReductionProxyPageLoadTiming& other);
@@ -57,6 +58,8 @@ struct DataReductionProxyPageLoadTiming {
// The number of bytes that would have been served over the network if the
// user were not using data reduction proxy, not including headers.
const int64_t original_network_bytes;
+ // True when android app background occurred during the page load lifetime.
+ const bool app_background_occurred;
};
} // namespace data_reduction_proxy
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
index ac08fb10e9d..44bb16c9f56 100644
--- 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
@@ -237,6 +237,14 @@ bool IsIncludedInQuicFieldTrial() {
return true;
}
+bool IsQuicEnabledForNonCoreProxies() {
+ DCHECK(IsIncludedInQuicFieldTrial());
+ std::map<std::string, std::string> params;
+ variations::GetVariationParams(GetQuicFieldTrialName(), &params);
+ return GetStringValueForVariationParamWithDefaultValue(
+ params, "enable_quic_non_core_proxies", "false") == "true";
+}
+
const char* GetQuicFieldTrialName() {
return kQuicFieldTrial;
}
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
index 02b3d9cc19c..eab391b026e 100644
--- 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
@@ -122,6 +122,9 @@ bool WarnIfNoDataReductionProxy();
// proxy server as quic://proxy.googlezip.net.
bool IsIncludedInQuicFieldTrial();
+// Returns true if QUIC is enabled for non core data reduction proxies.
+bool IsQuicEnabledForNonCoreProxies();
+
const char* GetQuicFieldTrialName();
// Returns true if zero RTT for QUIC is enabled.
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
index 20de8115b95..b045ae0ddd9 100644
--- 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
@@ -456,6 +456,44 @@ TEST_F(DataReductionProxyParamsTest, QuicFieldTrial) {
}
}
+// Tests if the QUIC field trial |enable_quic_non_core_proxies| is set
+// correctly.
+TEST_F(DataReductionProxyParamsTest, QuicEnableNonCoreProxies) {
+ const struct {
+ std::string trial_group_name;
+ bool expected_enabled;
+ std::string enable_non_core_proxies;
+ bool expected_enable_non_core_proxies;
+ } tests[] = {
+ {"Enabled", true, "true", true},
+ {"Enabled", true, "false", false},
+ {"Enabled", true, std::string(), false},
+ {"Control", false, "true", false},
+ {"Disabled", false, "true", false},
+ };
+
+ for (const auto& test : tests) {
+ variations::testing::ClearAllVariationParams();
+ std::map<std::string, std::string> variation_params;
+ variation_params["enable_quic_non_core_proxies"] =
+ test.enable_non_core_proxies;
+
+ ASSERT_TRUE(variations::AssociateVariationParams(
+ params::GetQuicFieldTrialName(), test.trial_group_name,
+ variation_params));
+
+ base::FieldTrialList field_trial_list(nullptr);
+ base::FieldTrialList::CreateFieldTrial(params::GetQuicFieldTrialName(),
+ test.trial_group_name);
+
+ EXPECT_EQ(test.expected_enabled, params::IsIncludedInQuicFieldTrial());
+ if (params::IsIncludedInQuicFieldTrial()) {
+ EXPECT_EQ(test.expected_enable_non_core_proxies,
+ params::IsQuicEnabledForNonCoreProxies());
+ }
+ }
+}
+
TEST_F(DataReductionProxyParamsTest, HoldbackEnabledFieldTrial) {
const struct {
std::string trial_group_name;
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 8e2caccccc3..82dc96a2074 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
@@ -80,10 +80,6 @@ const char kEnableDataReductionProxyLitePage[] =
const char kEnableDataReductionProxyForcePingback[] =
"enable-data-reduction-proxy-force-pingback";
-// If set, enables use of QUIC with non core data reduction proxies.
-const char kDataReductionProxyEnableQuicOnNonCoreProxies[] =
- "data-reduction-proxy-enable-quic-on-non-core-proxies";
-
// Enables a 1 MB savings promo for the data reduction proxy.
const char kEnableDataReductionProxySavingsPromo[] =
"enable-data-reduction-proxy-savings-promo";
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 c3ab54b10b1..cbc063d6836 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
@@ -31,7 +31,6 @@ extern const char kEnableDataReductionProxyBypassWarning[];
extern const char kEnableDataReductionProxyCarrierTest[];
extern const char kEnableDataReductionProxyForcePingback[];
extern const char kEnableDataReductionProxyLitePage[];
-extern const char kDataReductionProxyEnableQuicOnNonCoreProxies[];
extern const char kEnableDataReductionProxySavingsPromo[];
} // namespace switches
diff --git a/chromium/components/data_reduction_proxy/core/common/data_savings_recorder.h b/chromium/components/data_reduction_proxy/core/common/data_savings_recorder.h
deleted file mode 100644
index a96cf5984be..00000000000
--- a/chromium/components/data_reduction_proxy/core/common/data_savings_recorder.h
+++ /dev/null
@@ -1,30 +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_REDUCTION_PROXY_CORE_COMMON_DATA_SAVINGS_RECORDER_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_SAVINGS_RECORDER_H_
-
-#include <stdint.h>
-
-#include <string>
-
-namespace data_reduction_proxy {
-
-// An interface that will record data savings based on the amount of data used,
-// the original size of the data, and the request type.
-class DataSavingsRecorder {
- public:
- // Records detailed data usage. Assumes |data_used| is recorded already by
- // previous handling of URLRequests. Also records daily data savings
- // statistics to prefs and reports data savings UMA. |data_used| and
- // |original_size| are measured in bytes.
- // Returns true if data savings was recorded.
- virtual bool UpdateDataSavings(const std::string& data_usage_host,
- int64_t data_used,
- int64_t original_size) = 0;
-};
-
-} // namespace data_reduction_proxy
-
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_SAVINGS_RECORDER_H_
diff --git a/chromium/components/data_reduction_proxy/proto/pageload_metrics.proto b/chromium/components/data_reduction_proxy/proto/pageload_metrics.proto
index ab567c1b11a..1725604afae 100644
--- a/chromium/components/data_reduction_proxy/proto/pageload_metrics.proto
+++ b/chromium/components/data_reduction_proxy/proto/pageload_metrics.proto
@@ -34,6 +34,26 @@ message PageloadMetrics {
EFFECTIVE_CONNECTION_TYPE_4G = 5;
};
+ // The various opt out states seen by server previews.
+ enum PreviewsOptOut {
+ // Set for non-previews navigations and app background navigations.
+ UNKNOWN = 0;
+ // Set for previews navigations that clicked "show original".
+ OPT_OUT = 1;
+ // Set for previews navigations that did not click "show original".
+ NON_OPT_OUT = 2;
+ }
+
+ // The various server previews that can be shown.
+ enum PreviewsType {
+ // No server preview was applied.
+ NONE = 0;
+ // Image placeholders were used on the page.
+ LOFI = 1;
+ // The main resource was a lite page.
+ LITE_PAGE = 2;
+ }
+
// The session key used to load the page.
optional string session_key = 1;
// The time at which the first request of the pageload was made, according to
@@ -72,4 +92,13 @@ message PageloadMetrics {
// Time to first meaningful paint. This measure is unstable and will change
// over time.
optional Duration experimental_time_to_first_meaningful_paint = 15;
+
+ // The unique identifier for the page load.
+ optional uint64 page_id = 16;
+
+ // The opt out state of the page load.
+ optional PreviewsOptOut previews_opt_out = 17;
+
+ // The previews type that was used on the page.
+ optional PreviewsType previews_type = 18;
}
diff --git a/chromium/components/data_usage/core/data_use_aggregator_unittest.cc b/chromium/components/data_usage/core/data_use_aggregator_unittest.cc
index a388729e376..8088c5318a1 100644
--- a/chromium/components/data_usage/core/data_use_aggregator_unittest.cc
+++ b/chromium/components/data_usage/core/data_use_aggregator_unittest.cc
@@ -25,6 +25,7 @@
#include "net/base/network_change_notifier.h"
#include "net/base/network_delegate_impl.h"
#include "net/socket/socket_test_util.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -278,8 +279,8 @@ class DataUseAggregatorTest : public testing::Test {
mock_socket_factory_->AddSocketDataProvider(&socket);
net::TestDelegate delegate;
- std::unique_ptr<net::URLRequest> request =
- context_->CreateRequest(url, net::IDLE, &delegate);
+ std::unique_ptr<net::URLRequest> request = context_->CreateRequest(
+ url, net::IDLE, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
request->set_first_party_for_cookies(first_party_for_cookies);
ReportingNetworkDelegate::DataUseContextMap data_use_context_map;
diff --git a/chromium/components/data_use_measurement/content/BUILD.gn b/chromium/components/data_use_measurement/content/BUILD.gn
index b9c18ae112e..58db8d3c329 100644
--- a/chromium/components/data_use_measurement/content/BUILD.gn
+++ b/chromium/components/data_use_measurement/content/BUILD.gn
@@ -12,5 +12,6 @@ static_library("content") {
"//content/public/browser",
"//content/public/common",
"//net:net",
+ "//ui/base",
]
}
diff --git a/chromium/components/data_use_measurement/content/DEPS b/chromium/components/data_use_measurement/content/DEPS
index 8dbf71c6590..ba4bf0ecc28 100644
--- a/chromium/components/data_use_measurement/content/DEPS
+++ b/chromium/components/data_use_measurement/content/DEPS
@@ -2,4 +2,5 @@ include_rules = [
"+content/public/browser",
"+content/public/common",
"+net",
+ "+ui/base",
]
diff --git a/chromium/components/data_use_measurement/content/content_url_request_classifier.cc b/chromium/components/data_use_measurement/content/content_url_request_classifier.cc
index 2c723b69684..d3354c45154 100644
--- a/chromium/components/data_use_measurement/content/content_url_request_classifier.cc
+++ b/chromium/components/data_use_measurement/content/content_url_request_classifier.cc
@@ -6,11 +6,39 @@
#include <string>
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
#include "base/strings/string_util.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/common/resource_type.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
+#include "ui/base/page_transition_types.h"
+
+namespace {
+
+// Data use broken by page transition type. This enum must remain synchronized
+// with the enum of the same name in metrics/histograms/histograms.xml. The enum
+// values have the same meaning as ui::PageTransition in
+// ui/base/page_transition_types.h. These values are written to logs. New enum
+// values can be added, but existing enums must never be renumbered or deleted
+// and reused.
+enum DataUsePageTransition {
+ LINK = 0,
+ TYPED = 1,
+ AUTO_BOOKMARK = 2,
+ SUBFRAME = 3, // AUTO_SUBFRAME and MANUAL_SUBFRAME transitions.
+ GENERATED = 4,
+ AUTO_TOPLEVEL = 5,
+ FORM_SUBMIT = 6,
+ RELOAD = 7,
+ KEYWORD = 8, // KEYWORD and KEYWORD_GENERATED transitions.
+ FORWARD_BACK = 9,
+ HOME_PAGE = 10,
+ TRANSITION_MAX = 11,
+};
+
+} // namespace
namespace data_use_measurement {
@@ -67,4 +95,73 @@ DataUseUserData::DataUseContentType ContentURLRequestClassifier::GetContentType(
return DataUseUserData::OTHER;
}
+void ContentURLRequestClassifier::RecordPageTransitionUMA(
+ uint64_t page_transition,
+ int64_t received_bytes) const {
+ DataUsePageTransition data_use_page_transition =
+ DataUsePageTransition::TRANSITION_MAX;
+ if (received_bytes <= 0)
+ return;
+
+ if (page_transition & ui::PAGE_TRANSITION_FORWARD_BACK) {
+ data_use_page_transition = DataUsePageTransition::FORWARD_BACK;
+ } else if (page_transition & ui::PAGE_TRANSITION_HOME_PAGE) {
+ data_use_page_transition = DataUsePageTransition::HOME_PAGE;
+ } else {
+ switch (page_transition & ui::PAGE_TRANSITION_CORE_MASK) {
+ case ui::PAGE_TRANSITION_LINK:
+ data_use_page_transition = DataUsePageTransition::LINK;
+ break;
+ case ui::PAGE_TRANSITION_TYPED:
+ data_use_page_transition = DataUsePageTransition::TYPED;
+ break;
+ case ui::PAGE_TRANSITION_AUTO_BOOKMARK:
+ data_use_page_transition = DataUsePageTransition::AUTO_BOOKMARK;
+ break;
+ case ui::PAGE_TRANSITION_AUTO_SUBFRAME:
+ case ui::PAGE_TRANSITION_MANUAL_SUBFRAME:
+ data_use_page_transition = DataUsePageTransition::SUBFRAME;
+ break;
+ case ui::PAGE_TRANSITION_GENERATED:
+ data_use_page_transition = DataUsePageTransition::GENERATED;
+ break;
+ case ui::PAGE_TRANSITION_AUTO_TOPLEVEL:
+ data_use_page_transition = DataUsePageTransition::AUTO_TOPLEVEL;
+ break;
+ case ui::PAGE_TRANSITION_FORM_SUBMIT:
+ data_use_page_transition = DataUsePageTransition::FORM_SUBMIT;
+ break;
+ case ui::PAGE_TRANSITION_RELOAD:
+ data_use_page_transition = DataUsePageTransition::RELOAD;
+ break;
+ case ui::PAGE_TRANSITION_KEYWORD:
+ case ui::PAGE_TRANSITION_KEYWORD_GENERATED:
+ data_use_page_transition = DataUsePageTransition::KEYWORD;
+ break;
+ default:
+ return;
+ }
+ }
+ DCHECK_NE(DataUsePageTransition::TRANSITION_MAX, data_use_page_transition);
+
+ // Use the more primitive STATIC_HISTOGRAM_POINTER_BLOCK macro because the
+ // simple UMA_HISTOGRAM_ENUMERATION macros don't expose 'AddCount'.
+ STATIC_HISTOGRAM_POINTER_BLOCK(
+ "DataUse.PageTransition.UserTraffic",
+ AddCount(data_use_page_transition, received_bytes),
+ base::LinearHistogram::FactoryGet(
+ "DataUse.PageTransition.UserTraffic", 1,
+ DataUsePageTransition::TRANSITION_MAX,
+ DataUsePageTransition::TRANSITION_MAX + 1,
+ base::HistogramBase::kUmaTargetedHistogramFlag));
+}
+
+bool ContentURLRequestClassifier::IsFavIconRequest(
+ const net::URLRequest& request) const {
+ const content::ResourceRequestInfo* request_info =
+ content::ResourceRequestInfo::ForRequest(&request);
+ return request_info && request_info->GetResourceType() ==
+ content::ResourceType::RESOURCE_TYPE_FAVICON;
+}
+
} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/content/content_url_request_classifier.h b/chromium/components/data_use_measurement/content/content_url_request_classifier.h
index 8b978fed773..0726bb967c2 100644
--- a/chromium/components/data_use_measurement/content/content_url_request_classifier.h
+++ b/chromium/components/data_use_measurement/content/content_url_request_classifier.h
@@ -17,12 +17,15 @@ namespace data_use_measurement {
bool IsUserRequest(const net::URLRequest& request);
class ContentURLRequestClassifier : public URLRequestClassifier {
- public:
+ private:
+ // UrlRequestClassifier:
bool IsUserRequest(const net::URLRequest& request) const override;
-
DataUseUserData::DataUseContentType GetContentType(
const net::URLRequest& request,
const net::HttpResponseHeaders& response_headers) const override;
+ void RecordPageTransitionUMA(uint64_t page_transition,
+ int64_t received_bytes) const override;
+ bool IsFavIconRequest(const net::URLRequest& request) const override;
};
} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/data_use_measurement.cc b/chromium/components/data_use_measurement/core/data_use_measurement.cc
index 3a803074015..fcebeb8d070 100644
--- a/chromium/components/data_use_measurement/core/data_use_measurement.cc
+++ b/chromium/components/data_use_measurement/core/data_use_measurement.cc
@@ -17,6 +17,7 @@
#include "net/base/network_change_notifier.h"
#include "net/base/upload_data_stream.h"
#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
#include "net/url_request/url_request.h"
#if defined(OS_ANDROID)
@@ -65,6 +66,17 @@ void IncrementLatencyHistogramByCount(const std::string& name,
}
#endif
+void RecordFavIconDataUse(const net::URLRequest& request) {
+ UMA_HISTOGRAM_COUNTS_100000(
+ "DataUse.FavIcon.Downstream",
+ request.was_cached() ? 0 : request.GetTotalReceivedBytes());
+ if (request.status().is_success() &&
+ request.GetResponseCode() != net::HTTP_OK) {
+ UMA_HISTOGRAM_COUNTS_100000("DataUse.FavIcon.Downstream.Non200Response",
+ request.GetTotalReceivedBytes());
+ }
+}
+
} // namespace
DataUseMeasurement::DataUseMeasurement(
@@ -132,6 +144,8 @@ void DataUseMeasurement::OnBeforeRedirect(const net::URLRequest& request,
// TODO(rajendrant): May not be needed when http://crbug/651957 is fixed.
UpdateDataUsePrefs(request);
ReportServicesMessageSizeUMA(request);
+ if (url_request_classifier_->IsFavIconRequest(request))
+ RecordFavIconDataUse(request);
}
void DataUseMeasurement::OnHeadersReceived(
@@ -169,9 +183,12 @@ void DataUseMeasurement::OnCompleted(const net::URLRequest& request,
// of redirected requests.
UpdateDataUsePrefs(request);
ReportServicesMessageSizeUMA(request);
+ RecordPageTransitionUMA(request);
#if defined(OS_ANDROID)
MaybeRecordNetworkBytesOS();
#endif
+ if (url_request_classifier_->IsFavIconRequest(request))
+ RecordFavIconDataUse(request);
}
void DataUseMeasurement::ReportDataUseUMA(const net::URLRequest& request,
@@ -381,6 +398,10 @@ void DataUseMeasurement::ReportDataUsageServices(
GetHistogramName("DataUse.MessageSize.AllServices", dir, app_state,
is_connection_cellular),
service, message_size);
+ if (app_state == DataUseUserData::BACKGROUND) {
+ IncreaseSparseHistogramByValue("DataUse.AllServices.Background", service,
+ message_size);
+ }
}
}
@@ -388,7 +409,7 @@ void DataUseMeasurement::RecordTabStateHistogram(
TrafficDirection dir,
DataUseUserData::AppState app_state,
bool is_tab_visible,
- int64_t bytes) {
+ int64_t bytes) const {
if (app_state == DataUseUserData::UNKNOWN)
return;
@@ -440,4 +461,16 @@ void DataUseMeasurement::RecordContentTypeHistogram(
}
}
+void DataUseMeasurement::RecordPageTransitionUMA(
+ const net::URLRequest& request) const {
+ if (!url_request_classifier_->IsUserRequest(request))
+ return;
+
+ const DataUseRecorder* recorder = ascriber_->GetDataUseRecorder(request);
+ if (recorder) {
+ url_request_classifier_->RecordPageTransitionUMA(
+ recorder->page_transition(), request.GetTotalReceivedBytes());
+ }
+}
+
} // 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
index a0e4298c94e..931d6f1033d 100644
--- a/chromium/components/data_use_measurement/core/data_use_measurement.h
+++ b/chromium/components/data_use_measurement/core/data_use_measurement.h
@@ -140,7 +140,10 @@ class DataUseMeasurement {
void RecordTabStateHistogram(TrafficDirection dir,
DataUseUserData::AppState app_state,
bool is_tab_visible,
- int64_t bytes);
+ int64_t bytes) const;
+
+ // Records data use histograms split on page tranition.
+ void RecordPageTransitionUMA(const net::URLRequest& request) const;
// Records data use histograms of user traffic and services traffic split on
// content type, AppState and TabState.
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
index 39429f95ad4..87ce637a5e4 100644
--- a/chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc
+++ b/chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc
@@ -19,6 +19,7 @@
#include "net/base/network_change_notifier.h"
#include "net/base/request_priority.h"
#include "net/socket/socket_test_util.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -55,6 +56,13 @@ class TestURLRequestClassifier : public base::SupportsUserData::Data,
content_type_ = content_type;
}
+ void RecordPageTransitionUMA(uint64_t page_transition,
+ int64_t received_bytes) const override {}
+
+ bool IsFavIconRequest(const net::URLRequest& request) const override {
+ return false;
+ }
+
private:
DataUseUserData::DataUseContentType content_type_;
};
@@ -126,8 +134,9 @@ class DataUseMeasurementTest : public testing::Test {
0);
socket_factory_->AddSocketDataProvider(&socket_data);
- std::unique_ptr<net::URLRequest> request(context_->CreateRequest(
- GURL("http://foo.com"), net::DEFAULT_PRIORITY, &test_delegate));
+ std::unique_ptr<net::URLRequest> request(
+ context_->CreateRequest(GURL("http://foo.com"), net::DEFAULT_PRIORITY,
+ &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
if (is_user_request == kUserRequest) {
TestURLRequestClassifier::MarkAsUserRequest(request.get());
} else {
diff --git a/chromium/components/data_use_measurement/core/data_use_network_delegate_unittest.cc b/chromium/components/data_use_measurement/core/data_use_network_delegate_unittest.cc
index 53d585b1230..1a259bb01a1 100644
--- a/chromium/components/data_use_measurement/core/data_use_network_delegate_unittest.cc
+++ b/chromium/components/data_use_measurement/core/data_use_network_delegate_unittest.cc
@@ -12,6 +12,7 @@
#include "components/data_use_measurement/core/url_request_classifier.h"
#include "components/metrics/data_use_tracker.h"
#include "net/socket/socket_test_util.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -39,6 +40,13 @@ class TestURLRequestClassifier : public base::SupportsUserData::Data,
const net::HttpResponseHeaders& response_headers) const override {
return DataUseUserData::OTHER;
}
+
+ void RecordPageTransitionUMA(uint64_t page_transition,
+ int64_t received_bytes) const override {}
+
+ bool IsFavIconRequest(const net::URLRequest& request) const override {
+ return false;
+ }
};
class TestDataUseAscriber : public DataUseAscriber {
@@ -94,8 +102,9 @@ std::unique_ptr<net::URLRequest> RequestURL(
socket_factory->AddSocketDataProvider(&response_socket_data_provider);
net::TestDelegate test_delegate;
test_delegate.set_quit_on_complete(true);
- std::unique_ptr<net::URLRequest> request(context->CreateRequest(
- GURL("http://example.com"), net::DEFAULT_PRIORITY, &test_delegate));
+ std::unique_ptr<net::URLRequest> request(
+ context->CreateRequest(GURL("http://example.com"), net::DEFAULT_PRIORITY,
+ &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
if (from_user) {
TestURLRequestClassifier::MarkAsUserRequest(request.get());
diff --git a/chromium/components/data_use_measurement/core/data_use_recorder.h b/chromium/components/data_use_measurement/core/data_use_recorder.h
index 8a26da67f02..7a279512f8f 100644
--- a/chromium/components/data_use_measurement/core/data_use_recorder.h
+++ b/chromium/components/data_use_measurement/core/data_use_recorder.h
@@ -43,6 +43,12 @@ class DataUseRecorder {
void set_is_visible(bool is_visible) { is_visible_ = is_visible; }
+ uint64_t page_transition() const { return page_transition_; }
+
+ void set_page_transition(uint64_t page_transition) {
+ page_transition_ = page_transition;
+ }
+
// Returns whether data use is complete and no additional data can be used
// by the entity tracked by this recorder. For example,
bool IsDataUseComplete();
@@ -98,6 +104,9 @@ class DataUseRecorder {
// Whether the entity that owns this data use is currently visible.
bool is_visible_;
+ // ui::PageTransition casted as a uint64_t.
+ uint64_t page_transition_;
+
DISALLOW_COPY_AND_ASSIGN(DataUseRecorder);
};
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
index de9cf6f6391..ebae0e3d205 100644
--- a/chromium/components/data_use_measurement/core/data_use_user_data.cc
+++ b/chromium/components/data_use_measurement/core/data_use_user_data.cc
@@ -126,6 +126,10 @@ std::string DataUseUserData::GetServiceNameAsString(ServiceName service_name) {
return "Doodle";
case UKM:
return "UKM";
+ case PAYMENTS:
+ return "Payments";
+ case LARGE_ICON_SERVICE:
+ return "LargeIconService";
}
return "INVALID";
}
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
index 4f8b4b91c01..584e7a52bd1 100644
--- a/chromium/components/data_use_measurement/core/data_use_user_data.h
+++ b/chromium/components/data_use_measurement/core/data_use_user_data.h
@@ -22,7 +22,8 @@ class DataUseUserData : public base::SupportsUserData::Data {
public:
// This enum should be synced with DataUseServices enum in histograms.xml.
// Please keep them synced after any updates. Also add service name to
- // GetServiceNameAsString function.
+ // GetServiceNameAsString function and the same service name to
+ // DataUse.Service.Types histogram suffixes in histograms.xml
enum ServiceName {
NOT_TAGGED,
SUGGESTIONS,
@@ -63,6 +64,8 @@ class DataUseUserData : public base::SupportsUserData::Data {
NTP_SNIPPETS_THUMBNAILS,
DOODLE,
UKM,
+ PAYMENTS,
+ LARGE_ICON_SERVICE,
};
// Data use broken by content type. This enum must remain synchronized
diff --git a/chromium/components/data_use_measurement/core/url_request_classifier.h b/chromium/components/data_use_measurement/core/url_request_classifier.h
index 00dc4108054..d8239b3f26b 100644
--- a/chromium/components/data_use_measurement/core/url_request_classifier.h
+++ b/chromium/components/data_use_measurement/core/url_request_classifier.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_DATA_USE_MEASUREMENT_CORE_URL_REQUEST_CLASSIFIER_H_
#define COMPONENTS_DATA_USE_MEASUREMENT_CORE_URL_REQUEST_CLASSIFIER_H_
+#include <stdint.h>
+
#include "components/data_use_measurement/core/data_use_user_data.h"
namespace net {
@@ -28,6 +30,13 @@ class URLRequestClassifier {
virtual DataUseUserData::DataUseContentType GetContentType(
const net::URLRequest& request,
const net::HttpResponseHeaders& response_headers) const = 0;
+
+ // Records the page transition histograms.
+ virtual void RecordPageTransitionUMA(uint64_t page_transition,
+ int64_t received_bytes) const = 0;
+
+ // Returns true if |request| is fetching a favicon.
+ virtual bool IsFavIconRequest(const net::URLRequest& request) const = 0;
};
} // namespace data_use_measurement
diff --git a/chromium/components/device_event_log/README.md b/chromium/components/device_event_log/README.md
new file mode 100644
index 00000000000..f899ee80f7d
--- /dev/null
+++ b/chromium/components/device_event_log/README.md
@@ -0,0 +1,49 @@
+# Device Event Log
+
+This directory contains code for logging device and system events.
+
+## Usage
+
+Use device event log macros to record events without contributing to noise in
+the chrome log.
+
+* Events are stored in a circular buffer (current limit is 4000).
+* Events can be viewed at chrome://device-log. Events can be filtered by type
+ and level.
+* Events show up in **feedback reports** under `device_event_log`.
+* Network events are separated out into a `network_event_log` section.
+* **ERROR** events will also be logged to the main chrome log.
+* All events can be logged to the main chrome log using vlog:
+ `--vmodule=device_event_log*=1`
+
+The events can also be queried for viewing in other informational pages, e.g:
+```
+device_event_log::GetAsString(device_event_log::OLDEST_FIRST, "json",
+ "bluetooth", device_event_log::LOG_LEVEL_DEBUG,
+ 1000);
+```
+
+## Examples
+
+Typical usage:
+
+```NET_LOG(EVENT) << "NetworkState Changed " << name << ": " << state;```
+
+```POWER_LOG(USER) << "Suspend requested";```
+
+```POWER_LOG(DEBUG) << "Sending suspend request to dbus object: " << path;```
+
+```BLUETOOTH_LOG(ERROR) << "Unrecognized DBus error " << error_name;```
+
+Advanced usage:
+
+```
+device_event_log::LogLevel log_level =
+ SuppressError(dbus_error_message) ? device_event_log::LOG_LEVEL_DEBUG
+ : device_event_log::LOG_LEVEL_ERROR;
+DEVICE_LOG(device_event_log::LOG_TYPE_NETWORK, log_level) << detail;
+```
+
+```
+USB_PLOG(DEBUG) << "Failed to set configuration " << configuration_value;
+```
diff --git a/chromium/components/device_event_log/device_event_log.h b/chromium/components/device_event_log/device_event_log.h
index 8383781f15b..133cf794b94 100644
--- a/chromium/components/device_event_log/device_event_log.h
+++ b/chromium/components/device_event_log/device_event_log.h
@@ -30,6 +30,8 @@
// Examples:
// NET_LOG(EVENT) << "NetworkState Changed " << name << ": " << state;
// POWER_LOG(USER) << "Suspend requested";
+//
+// See also the README.md in this directory.
#define NET_LOG(level) \
DEVICE_LOG(::device_event_log::LOG_TYPE_NETWORK, \
@@ -40,6 +42,9 @@
#define LOGIN_LOG(level) \
DEVICE_LOG(::device_event_log::LOG_TYPE_LOGIN, \
::device_event_log::LOG_LEVEL_##level)
+#define BLUETOOTH_LOG(level) \
+ DEVICE_LOG(::device_event_log::LOG_TYPE_BLUETOOTH, \
+ ::device_event_log::LOG_LEVEL_##level)
#define USB_LOG(level) \
DEVICE_LOG(::device_event_log::LOG_TYPE_USB, \
::device_event_log::LOG_LEVEL_##level)
@@ -52,6 +57,9 @@
#define HID_PLOG(level) \
DEVICE_PLOG(::device_event_log::LOG_TYPE_HID, \
::device_event_log::LOG_LEVEL_##level)
+#define MEMORY_LOG(level) \
+ DEVICE_LOG(::device_event_log::LOG_TYPE_MEMORY, \
+ ::device_event_log::LOG_LEVEL_##level)
// Generally prefer the above macros unless |type| or |level| is not constant.
@@ -76,22 +84,25 @@
namespace device_event_log {
-// Used to specify the type of event. NOTE: Be sure to update LogTypeFromString
-// and GetLogTypeString when adding entries to this enum. Also consider
-// updating chrome://device-log (see device_log_ui.cc).
+// Used to specify the type of event. Consider updating chrome://device-log
+// when adding new types (see device_log_ui.cc).
enum LogType {
// Shill / network configuration related events.
- LOG_TYPE_NETWORK,
+ LOG_TYPE_NETWORK = 0,
// Power manager related events.
- LOG_TYPE_POWER,
+ LOG_TYPE_POWER = 1,
// Login related events.
- LOG_TYPE_LOGIN,
+ LOG_TYPE_LOGIN = 2,
+ // Bluetooth device related events (i.e. device/bluetooth).
+ LOG_TYPE_BLUETOOTH = 3,
// USB device related events (i.e. device/usb).
- LOG_TYPE_USB,
+ LOG_TYPE_USB = 4,
// Human-interface device related events (i.e. device/hid).
- LOG_TYPE_HID,
- // Used internally
- LOG_TYPE_UNKNOWN
+ LOG_TYPE_HID = 5,
+ // Memory related events.
+ LOG_TYPE_MEMORY = 6,
+ // Used internally, must be the last type (may be changed).
+ LOG_TYPE_UNKNOWN = 7
};
// Used to specify the detail level for logging. In GetAsString, used to
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 eef301542cf..5ea67e9e20b 100644
--- a/chromium/components/device_event_log/device_event_log_impl.cc
+++ b/chromium/components/device_event_log/device_event_log_impl.cc
@@ -29,8 +29,10 @@ const char* kLogLevelName[] = {"Error", "User", "Event", "Debug"};
const char* kLogTypeNetworkDesc = "Network";
const char* kLogTypePowerDesc = "Power";
const char* kLogTypeLoginDesc = "Login";
+const char* kLogTypeBluetoothDesc = "Bluetooth";
const char* kLogTypeUsbDesc = "USB";
const char* kLogTypeHidDesc = "HID";
+const char* kLogTypeMemoryDesc = "Memory";
std::string GetLogTypeString(LogType type) {
switch (type) {
@@ -40,14 +42,31 @@ std::string GetLogTypeString(LogType type) {
return kLogTypePowerDesc;
case LOG_TYPE_LOGIN:
return kLogTypeLoginDesc;
+ case LOG_TYPE_BLUETOOTH:
+ return kLogTypeBluetoothDesc;
case LOG_TYPE_USB:
return kLogTypeUsbDesc;
case LOG_TYPE_HID:
return kLogTypeHidDesc;
- default:
- NOTREACHED();
- return "Unknown";
+ case LOG_TYPE_MEMORY:
+ return kLogTypeMemoryDesc;
+ case LOG_TYPE_UNKNOWN:
+ break;
+ }
+ NOTREACHED();
+ return "Unknown";
+}
+
+LogType GetLogTypeFromString(const std::string& desc) {
+ std::string desc_lc = base::ToLowerASCII(desc);
+ for (int i = 0; i < LOG_TYPE_UNKNOWN; ++i) {
+ auto type = static_cast<LogType>(i);
+ std::string log_desc_lc = base::ToLowerASCII(GetLogTypeString(type));
+ if (desc_lc == log_desc_lc)
+ return type;
}
+ NOTREACHED() << "Unrecogized LogType: " << desc;
+ return LOG_TYPE_UNKNOWN;
}
std::string DateAndTimeWithMicroseconds(const base::Time& time) {
@@ -185,18 +204,6 @@ void GetFormat(const std::string& format_string,
}
}
-LogType LogTypeFromString(const std::string& desc) {
- std::string desc_lc = base::ToLowerASCII(desc);
- if (desc_lc == "network")
- return LOG_TYPE_NETWORK;
- if (desc_lc == "power")
- return LOG_TYPE_POWER;
- if (desc_lc == "login")
- return LOG_TYPE_LOGIN;
- NOTREACHED() << "Unrecogized LogType: " << desc;
- return LOG_TYPE_UNKNOWN;
-}
-
void GetLogTypes(const std::string& types,
std::set<LogType>* include_types,
std::set<LogType>* exclude_types) {
@@ -204,11 +211,11 @@ void GetLogTypes(const std::string& types,
while (tokens.GetNext()) {
std::string tok(tokens.token());
if (tok.substr(0, 4) == "non-") {
- LogType type = LogTypeFromString(tok.substr(4));
+ LogType type = GetLogTypeFromString(tok.substr(4));
if (type != LOG_TYPE_UNKNOWN)
exclude_types->insert(type);
} else {
- LogType type = LogTypeFromString(tok);
+ LogType type = GetLogTypeFromString(tok);
if (type != LOG_TYPE_UNKNOWN)
include_types->insert(type);
}
diff --git a/chromium/components/display_compositor/BUILD.gn b/chromium/components/display_compositor/BUILD.gn
index e54fb14c292..41cc0497fc2 100644
--- a/chromium/components/display_compositor/BUILD.gn
+++ b/chromium/components/display_compositor/BUILD.gn
@@ -17,11 +17,8 @@ component("display_compositor") {
"gl_helper_readback_support.h",
"gl_helper_scaling.cc",
"gl_helper_scaling.h",
- "gpu_compositor_frame_sink.cc",
- "gpu_compositor_frame_sink.h",
- "gpu_compositor_frame_sink_delegate.h",
- "gpu_root_compositor_frame_sink.cc",
- "gpu_root_compositor_frame_sink.h",
+ "host_shared_bitmap_manager.cc",
+ "host_shared_bitmap_manager.h",
]
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
@@ -78,6 +75,7 @@ source_set("unit_tests") {
testonly = true
sources = [
"buffer_queue_unittest.cc",
+ "host_shared_bitmap_manager_unittest.cc",
]
if (!use_aura && !is_mac) {
diff --git a/chromium/components/display_compositor/DEPS b/chromium/components/display_compositor/DEPS
index eca1d9b8f16..5f7809be7ec 100644
--- a/chromium/components/display_compositor/DEPS
+++ b/chromium/components/display_compositor/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+cc/base",
"+cc/ipc",
"+cc/output",
+ "+cc/resources",
"+cc/surfaces",
"+cc/test",
"+gpu/GLES2",
@@ -10,6 +11,7 @@ include_rules = [
"+gpu/ipc",
"+gpu/ipc/common",
"+mojo/public/cpp/bindings",
+ "+mojo/public/cpp/system",
"+third_party/khronos/GLES2",
"+third_party/skia",
"+ui/display",
diff --git a/chromium/components/display_compositor/buffer_queue.cc b/chromium/components/display_compositor/buffer_queue.cc
index 60b50d7a8bb..092ae46771c 100644
--- a/chromium/components/display_compositor/buffer_queue.cc
+++ b/chromium/components/display_compositor/buffer_queue.cc
@@ -200,8 +200,9 @@ uint32_t BufferQueue::GetCurrentTextureId() const {
// Return in-flight or displayed surface texture if no surface is
// currently bound. This can happen when using overlays and surface
- // damage is empty.
- if (!in_flight_surfaces_.empty())
+ // damage is empty. Note: |in_flight_surfaces_| entries can be null
+ // as a result of calling FreeAllSurfaces().
+ if (!in_flight_surfaces_.empty() && in_flight_surfaces_.back())
return in_flight_surfaces_.back()->texture;
if (displayed_surface_)
return displayed_surface_->texture;
diff --git a/chromium/components/display_compositor/compositor_overlay_candidate_validator_android.cc b/chromium/components/display_compositor/compositor_overlay_candidate_validator_android.cc
index a42d0355a14..a75f5570e52 100644
--- a/chromium/components/display_compositor/compositor_overlay_candidate_validator_android.cc
+++ b/chromium/components/display_compositor/compositor_overlay_candidate_validator_android.cc
@@ -56,6 +56,10 @@ bool CompositorOverlayCandidateValidatorAndroid::AllowCALayerOverlays() {
return false;
}
+bool CompositorOverlayCandidateValidatorAndroid::AllowDCLayerOverlays() {
+ return false;
+}
+
// Overlays will still be allowed when software mirroring is enabled, even
// though they won't appear in the mirror.
void CompositorOverlayCandidateValidatorAndroid::SetSoftwareMirrorMode(
diff --git a/chromium/components/display_compositor/compositor_overlay_candidate_validator_android.h b/chromium/components/display_compositor/compositor_overlay_candidate_validator_android.h
index 0dd3becf66b..f98e2aad4d9 100644
--- a/chromium/components/display_compositor/compositor_overlay_candidate_validator_android.h
+++ b/chromium/components/display_compositor/compositor_overlay_candidate_validator_android.h
@@ -28,6 +28,7 @@ class DISPLAY_COMPOSITOR_EXPORT CompositorOverlayCandidateValidatorAndroid
void GetStrategies(cc::OverlayProcessor::StrategyList* strategies) override;
void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override;
bool AllowCALayerOverlays() override;
+ bool AllowDCLayerOverlays() override;
void SetSoftwareMirrorMode(bool enabled) override;
diff --git a/chromium/components/display_compositor/compositor_overlay_candidate_validator_mac.h b/chromium/components/display_compositor/compositor_overlay_candidate_validator_mac.h
index 8350584dd27..0ee60f5199b 100644
--- a/chromium/components/display_compositor/compositor_overlay_candidate_validator_mac.h
+++ b/chromium/components/display_compositor/compositor_overlay_candidate_validator_mac.h
@@ -22,6 +22,7 @@ class DISPLAY_COMPOSITOR_EXPORT CompositorOverlayCandidateValidatorMac
// cc::OverlayCandidateValidator implementation.
void GetStrategies(cc::OverlayProcessor::StrategyList* strategies) override;
bool AllowCALayerOverlays() override;
+ bool AllowDCLayerOverlays() override;
void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override;
// CompositorOverlayCandidateValidator implementation.
diff --git a/chromium/components/display_compositor/compositor_overlay_candidate_validator_mac.mm b/chromium/components/display_compositor/compositor_overlay_candidate_validator_mac.mm
index 7bf52fae066..336cc8fbdfd 100644
--- a/chromium/components/display_compositor/compositor_overlay_candidate_validator_mac.mm
+++ b/chromium/components/display_compositor/compositor_overlay_candidate_validator_mac.mm
@@ -22,6 +22,10 @@ bool CompositorOverlayCandidateValidatorMac::AllowCALayerOverlays() {
return !ca_layer_disabled_ && !software_mirror_active_;
}
+bool CompositorOverlayCandidateValidatorMac::AllowDCLayerOverlays() {
+ return false;
+}
+
void CompositorOverlayCandidateValidatorMac::CheckOverlaySupport(
cc::OverlayCandidateList* surfaces) {}
diff --git a/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.cc b/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.cc
index b9f0857f569..901076af3ba 100644
--- a/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.cc
+++ b/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.cc
@@ -29,18 +29,6 @@ std::unique_ptr<cc::OverlayProcessor::Strategy> MakeOverlayStrategy(
} // namespace
-static gfx::BufferFormat GetBufferFormat(cc::ResourceFormat overlay_format) {
- switch (overlay_format) {
- // TODO(dshwang): overlay video still uses RGBA_8888.
- case cc::RGBA_8888:
- case cc::BGRA_8888:
- return gfx::BufferFormat::BGRA_8888;
- default:
- NOTREACHED();
- return gfx::BufferFormat::BGRA_8888;
- }
-}
-
// |overlay_candidates| is an object used to answer questions about possible
// overlays configuarations.
// |strategies_string| is a comma-separated string containing all the overaly
@@ -90,6 +78,10 @@ bool CompositorOverlayCandidateValidatorOzone::AllowCALayerOverlays() {
return false;
}
+bool CompositorOverlayCandidateValidatorOzone::AllowDCLayerOverlays() {
+ return false;
+}
+
void CompositorOverlayCandidateValidatorOzone::CheckOverlaySupport(
cc::OverlayCandidateList* surfaces) {
// SW mirroring copies out of the framebuffer, so we can't remove any
@@ -107,7 +99,7 @@ void CompositorOverlayCandidateValidatorOzone::CheckOverlaySupport(
for (size_t i = 0; i < surfaces->size(); i++) {
ozone_surface_list.at(i).transform = surfaces->at(i).transform;
- ozone_surface_list.at(i).format = GetBufferFormat(surfaces->at(i).format);
+ ozone_surface_list.at(i).format = surfaces->at(i).format;
ozone_surface_list.at(i).display_rect = surfaces->at(i).display_rect;
ozone_surface_list.at(i).crop_rect = surfaces->at(i).uv_rect;
ozone_surface_list.at(i).quad_rect_in_target_space =
diff --git a/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.h b/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.h
index 19bc4ad1525..02c9b670382 100644
--- a/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.h
+++ b/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.h
@@ -30,6 +30,7 @@ class DISPLAY_COMPOSITOR_EXPORT CompositorOverlayCandidateValidatorOzone
// cc::OverlayCandidateValidator implementation.
void GetStrategies(cc::OverlayProcessor::StrategyList* strategies) override;
bool AllowCALayerOverlays() override;
+ bool AllowDCLayerOverlays() override;
void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override;
// CompositorOverlayCandidateValidator implementation.
diff --git a/chromium/components/display_compositor/compositor_overlay_candidate_validator_win.cc b/chromium/components/display_compositor/compositor_overlay_candidate_validator_win.cc
index 83936a9706f..74e704672de 100644
--- a/chromium/components/display_compositor/compositor_overlay_candidate_validator_win.cc
+++ b/chromium/components/display_compositor/compositor_overlay_candidate_validator_win.cc
@@ -4,12 +4,7 @@
#include "components/display_compositor/compositor_overlay_candidate_validator_win.h"
-#include <memory>
-
-#include "base/memory/ptr_util.h"
#include "cc/output/overlay_processor.h"
-#include "cc/output/overlay_strategy_underlay.h"
-#include "ui/gfx/geometry/rect_conversions.h"
namespace display_compositor {
@@ -21,23 +16,21 @@ CompositorOverlayCandidateValidatorWin::
void CompositorOverlayCandidateValidatorWin::GetStrategies(
cc::OverlayProcessor::StrategyList* strategies) {
- strategies->push_back(base::MakeUnique<cc::OverlayStrategyUnderlay>(this));
}
void CompositorOverlayCandidateValidatorWin::CheckOverlaySupport(
cc::OverlayCandidateList* candidates) {
- for (cc::OverlayCandidate& candidate : *candidates) {
- candidate.display_rect =
- gfx::RectF(gfx::ToEnclosingRect(candidate.display_rect));
- candidate.overlay_handled = true;
- candidate.plane_z_order = -1;
- }
+ NOTIMPLEMENTED();
}
bool CompositorOverlayCandidateValidatorWin::AllowCALayerOverlays() {
return false;
}
+bool CompositorOverlayCandidateValidatorWin::AllowDCLayerOverlays() {
+ return true;
+}
+
void CompositorOverlayCandidateValidatorWin::SetSoftwareMirrorMode(
bool enabled) {
// Software mirroring isn't supported on Windows.
diff --git a/chromium/components/display_compositor/compositor_overlay_candidate_validator_win.h b/chromium/components/display_compositor/compositor_overlay_candidate_validator_win.h
index 6b47b1ca3ae..18145f3d434 100644
--- a/chromium/components/display_compositor/compositor_overlay_candidate_validator_win.h
+++ b/chromium/components/display_compositor/compositor_overlay_candidate_validator_win.h
@@ -22,6 +22,7 @@ class DISPLAY_COMPOSITOR_EXPORT CompositorOverlayCandidateValidatorWin
void GetStrategies(cc::OverlayProcessor::StrategyList* strategies) override;
void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override;
bool AllowCALayerOverlays() override;
+ bool AllowDCLayerOverlays() override;
void SetSoftwareMirrorMode(bool enabled) override;
diff --git a/chromium/components/display_compositor/host_shared_bitmap_manager.cc b/chromium/components/display_compositor/host_shared_bitmap_manager.cc
new file mode 100644
index 00000000000..cd914f54084
--- /dev/null
+++ b/chromium/components/display_compositor/host_shared_bitmap_manager.cc
@@ -0,0 +1,264 @@
+// 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/display_compositor/host_shared_bitmap_manager.h"
+
+#include <stdint.h>
+
+#include <utility>
+
+#include "base/lazy_instance.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "build/build_config.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace display_compositor {
+
+class BitmapData : public base::RefCountedThreadSafe<BitmapData> {
+ public:
+ explicit BitmapData(size_t buffer_size) : buffer_size(buffer_size) {}
+ std::unique_ptr<base::SharedMemory> memory;
+ std::unique_ptr<uint8_t[]> pixels;
+ size_t buffer_size;
+
+ private:
+ friend class base::RefCountedThreadSafe<BitmapData>;
+ ~BitmapData() {}
+ DISALLOW_COPY_AND_ASSIGN(BitmapData);
+};
+
+namespace {
+
+class HostSharedBitmap : public cc::SharedBitmap {
+ public:
+ HostSharedBitmap(uint8_t* pixels,
+ scoped_refptr<BitmapData> bitmap_data,
+ const cc::SharedBitmapId& id,
+ HostSharedBitmapManager* manager)
+ : SharedBitmap(pixels, id),
+ bitmap_data_(bitmap_data),
+ manager_(manager) {}
+
+ ~HostSharedBitmap() override {
+ if (manager_)
+ manager_->FreeSharedMemoryFromMap(id());
+ }
+
+ private:
+ scoped_refptr<BitmapData> bitmap_data_;
+ HostSharedBitmapManager* manager_;
+};
+
+} // namespace
+
+base::LazyInstance<HostSharedBitmapManager>::DestructorAtExit
+ g_shared_memory_manager = LAZY_INSTANCE_INITIALIZER;
+
+HostSharedBitmapManagerClient::HostSharedBitmapManagerClient(
+ HostSharedBitmapManager* manager)
+ : manager_(manager), binding_(this) {}
+
+HostSharedBitmapManagerClient::~HostSharedBitmapManagerClient() {
+ for (const auto& id : owned_bitmaps_)
+ manager_->ChildDeletedSharedBitmap(id);
+}
+
+void HostSharedBitmapManagerClient::Bind(
+ cc::mojom::SharedBitmapManagerAssociatedRequest request) {
+ binding_.Bind(std::move(request));
+}
+
+void HostSharedBitmapManagerClient::DidAllocateSharedBitmap(
+ mojo::ScopedSharedBufferHandle buffer,
+ const cc::SharedBitmapId& id) {
+ base::SharedMemoryHandle memory_handle;
+ size_t size;
+ MojoResult result = mojo::UnwrapSharedMemoryHandle(
+ std::move(buffer), &memory_handle, &size, NULL);
+ DCHECK_EQ(result, MOJO_RESULT_OK);
+ this->ChildAllocatedSharedBitmap(size, memory_handle, id);
+}
+
+void HostSharedBitmapManagerClient::AllocateSharedBitmapForChild(
+ base::ProcessHandle process_handle,
+ size_t buffer_size,
+ const cc::SharedBitmapId& id,
+ base::SharedMemoryHandle* shared_memory_handle) {
+ manager_->AllocateSharedBitmapForChild(process_handle, buffer_size, id,
+ shared_memory_handle);
+ if (*shared_memory_handle != base::SharedMemory::NULLHandle()) {
+ base::AutoLock lock(lock_);
+ owned_bitmaps_.insert(id);
+ }
+}
+
+void HostSharedBitmapManagerClient::ChildAllocatedSharedBitmap(
+ size_t buffer_size,
+ const base::SharedMemoryHandle& handle,
+ const cc::SharedBitmapId& id) {
+ if (manager_->ChildAllocatedSharedBitmap(buffer_size, handle, id)) {
+ base::AutoLock lock(lock_);
+ owned_bitmaps_.insert(id);
+ }
+}
+
+void HostSharedBitmapManagerClient::DidDeleteSharedBitmap(
+ const cc::SharedBitmapId& id) {
+ manager_->ChildDeletedSharedBitmap(id);
+ {
+ base::AutoLock lock(lock_);
+ owned_bitmaps_.erase(id);
+ }
+}
+
+HostSharedBitmapManager::HostSharedBitmapManager() {}
+HostSharedBitmapManager::~HostSharedBitmapManager() {
+ DCHECK(handle_map_.empty());
+}
+
+HostSharedBitmapManager* HostSharedBitmapManager::current() {
+ return g_shared_memory_manager.Pointer();
+}
+
+std::unique_ptr<cc::SharedBitmap> HostSharedBitmapManager::AllocateSharedBitmap(
+ const gfx::Size& size) {
+ base::AutoLock lock(lock_);
+ size_t bitmap_size;
+ if (!cc::SharedBitmap::SizeInBytes(size, &bitmap_size))
+ return std::unique_ptr<cc::SharedBitmap>();
+
+ scoped_refptr<BitmapData> data(new BitmapData(bitmap_size));
+ // Bitmaps allocated in host don't need to be shared to other processes, so
+ // allocate them with new instead.
+ data->pixels = std::unique_ptr<uint8_t[]>(new uint8_t[bitmap_size]);
+
+ cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+ handle_map_[id] = data;
+ return base::MakeUnique<HostSharedBitmap>(data->pixels.get(), data, id, this);
+}
+
+std::unique_ptr<cc::SharedBitmap>
+HostSharedBitmapManager::GetSharedBitmapFromId(const gfx::Size& size,
+ const cc::SharedBitmapId& id) {
+ base::AutoLock lock(lock_);
+ BitmapMap::iterator it = handle_map_.find(id);
+ if (it == handle_map_.end())
+ return std::unique_ptr<cc::SharedBitmap>();
+
+ BitmapData* data = it->second.get();
+
+ size_t bitmap_size;
+ if (!cc::SharedBitmap::SizeInBytes(size, &bitmap_size) ||
+ bitmap_size > data->buffer_size)
+ return std::unique_ptr<cc::SharedBitmap>();
+
+ if (data->pixels) {
+ return base::MakeUnique<HostSharedBitmap>(data->pixels.get(), data, id,
+ nullptr);
+ }
+ if (!data->memory->memory()) {
+ return std::unique_ptr<cc::SharedBitmap>();
+ }
+
+ return base::MakeUnique<HostSharedBitmap>(
+ static_cast<uint8_t*>(data->memory->memory()), data, id, nullptr);
+}
+
+bool HostSharedBitmapManager::OnMemoryDump(
+ const base::trace_event::MemoryDumpArgs& args,
+ base::trace_event::ProcessMemoryDump* pmd) {
+ base::AutoLock lock(lock_);
+
+ for (const auto& bitmap : handle_map_) {
+ base::trace_event::MemoryAllocatorDump* dump =
+ pmd->CreateAllocatorDump(base::StringPrintf(
+ "sharedbitmap/%s",
+ base::HexEncode(bitmap.first.name, sizeof(bitmap.first.name))
+ .c_str()));
+ if (!dump)
+ return false;
+
+ dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ bitmap.second->buffer_size);
+
+ // Generate a global GUID used to share this allocation with renderer
+ // processes.
+ auto guid = cc::GetSharedBitmapGUIDForTracing(bitmap.first);
+ pmd->CreateSharedGlobalAllocatorDump(guid);
+ pmd->AddOwnershipEdge(dump->guid(), guid);
+ }
+
+ return true;
+}
+
+bool HostSharedBitmapManager::ChildAllocatedSharedBitmap(
+ size_t buffer_size,
+ const base::SharedMemoryHandle& handle,
+ const cc::SharedBitmapId& id) {
+ base::AutoLock lock(lock_);
+ if (handle_map_.find(id) != handle_map_.end())
+ return false;
+ scoped_refptr<BitmapData> data(new BitmapData(buffer_size));
+
+ handle_map_[id] = data;
+ data->memory = base::MakeUnique<base::SharedMemory>(handle, false);
+ data->memory->Map(data->buffer_size);
+ data->memory->Close();
+ return true;
+}
+
+void HostSharedBitmapManager::AllocateSharedBitmapForChild(
+ base::ProcessHandle process_handle,
+ size_t buffer_size,
+ const cc::SharedBitmapId& id,
+ base::SharedMemoryHandle* shared_memory_handle) {
+ base::AutoLock lock(lock_);
+ if (handle_map_.find(id) != handle_map_.end()) {
+ *shared_memory_handle = base::SharedMemory::NULLHandle();
+ return;
+ }
+ std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory);
+ if (!shared_memory->CreateAndMapAnonymous(buffer_size)) {
+ LOG(ERROR) << "Cannot create shared memory buffer";
+ *shared_memory_handle = base::SharedMemory::NULLHandle();
+ return;
+ }
+
+ scoped_refptr<BitmapData> data(new BitmapData(buffer_size));
+ data->memory = std::move(shared_memory);
+
+ handle_map_[id] = data;
+ if (!data->memory->ShareToProcess(process_handle, shared_memory_handle)) {
+ LOG(ERROR) << "Cannot share shared memory buffer";
+ *shared_memory_handle = base::SharedMemory::NULLHandle();
+ return;
+ }
+ data->memory->Close();
+}
+
+void HostSharedBitmapManager::ChildDeletedSharedBitmap(
+ const cc::SharedBitmapId& id) {
+ base::AutoLock lock(lock_);
+ handle_map_.erase(id);
+}
+
+size_t HostSharedBitmapManager::AllocatedBitmapCount() const {
+ base::AutoLock lock(lock_);
+ return handle_map_.size();
+}
+
+void HostSharedBitmapManager::FreeSharedMemoryFromMap(
+ const cc::SharedBitmapId& id) {
+ base::AutoLock lock(lock_);
+ handle_map_.erase(id);
+}
+
+} // namespace display_compositor
diff --git a/chromium/components/display_compositor/host_shared_bitmap_manager.h b/chromium/components/display_compositor/host_shared_bitmap_manager.h
new file mode 100644
index 00000000000..05706c33759
--- /dev/null
+++ b/chromium/components/display_compositor/host_shared_bitmap_manager.h
@@ -0,0 +1,121 @@
+// Copyright (c) 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.
+
+#ifndef COMPONENTS_DISPLAY_COMPOSITOR_HOST_SHARED_BITMAP_MANAGER_H_
+#define COMPONENTS_DISPLAY_COMPOSITOR_HOST_SHARED_BITMAP_MANAGER_H_
+
+#include <stddef.h>
+
+#include <map>
+#include <memory>
+#include <set>
+
+#include "base/containers/hash_tables.h"
+#include "base/hash.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
+#include "base/synchronization/lock.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "cc/ipc/shared_bitmap_manager.mojom.h"
+#include "cc/resources/shared_bitmap_manager.h"
+#include "components/display_compositor/display_compositor_export.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+
+namespace BASE_HASH_NAMESPACE {
+template <>
+struct hash<cc::SharedBitmapId> {
+ size_t operator()(const cc::SharedBitmapId& id) const {
+ return base::Hash(reinterpret_cast<const char*>(id.name), sizeof(id.name));
+ }
+};
+} // namespace BASE_HASH_NAMESPACE
+
+namespace display_compositor {
+class BitmapData;
+class HostSharedBitmapManager;
+
+class DISPLAY_COMPOSITOR_EXPORT HostSharedBitmapManagerClient
+ : NON_EXPORTED_BASE(public cc::mojom::SharedBitmapManager) {
+ public:
+ explicit HostSharedBitmapManagerClient(HostSharedBitmapManager* manager);
+
+ ~HostSharedBitmapManagerClient() override;
+
+ void Bind(cc::mojom::SharedBitmapManagerAssociatedRequest request);
+
+ // cc::mojom::SharedBitmapManager overrides:
+ void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
+ const cc::SharedBitmapId& id) override;
+ void DidDeleteSharedBitmap(const cc::SharedBitmapId& id) override;
+
+ void AllocateSharedBitmapForChild(
+ base::ProcessHandle process_handle,
+ size_t buffer_size,
+ const cc::SharedBitmapId& id,
+ base::SharedMemoryHandle* shared_memory_handle);
+ void ChildAllocatedSharedBitmap(size_t buffer_size,
+ const base::SharedMemoryHandle& handle,
+ const cc::SharedBitmapId& id);
+
+ private:
+ HostSharedBitmapManager* manager_;
+ mojo::AssociatedBinding<cc::mojom::SharedBitmapManager> binding_;
+
+ // Lock must be held around access to owned_bitmaps_.
+ base::Lock lock_;
+ base::hash_set<cc::SharedBitmapId> owned_bitmaps_;
+
+ DISALLOW_COPY_AND_ASSIGN(HostSharedBitmapManagerClient);
+};
+
+class DISPLAY_COMPOSITOR_EXPORT HostSharedBitmapManager
+ : public cc::SharedBitmapManager,
+ public base::trace_event::MemoryDumpProvider {
+ public:
+ HostSharedBitmapManager();
+ ~HostSharedBitmapManager() override;
+
+ static HostSharedBitmapManager* current();
+
+ // cc::SharedBitmapManager implementation.
+ std::unique_ptr<cc::SharedBitmap> AllocateSharedBitmap(
+ const gfx::Size& size) override;
+ std::unique_ptr<cc::SharedBitmap> GetSharedBitmapFromId(
+ const gfx::Size& size,
+ const cc::SharedBitmapId&) override;
+
+ // base::trace_event::MemoryDumpProvider implementation.
+ bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
+ base::trace_event::ProcessMemoryDump* pmd) override;
+
+ size_t AllocatedBitmapCount() const;
+
+ void FreeSharedMemoryFromMap(const cc::SharedBitmapId& id);
+
+ private:
+ friend class HostSharedBitmapManagerClient;
+
+ void AllocateSharedBitmapForChild(
+ base::ProcessHandle process_handle,
+ size_t buffer_size,
+ const cc::SharedBitmapId& id,
+ base::SharedMemoryHandle* shared_memory_handle);
+ bool ChildAllocatedSharedBitmap(size_t buffer_size,
+ const base::SharedMemoryHandle& handle,
+ const cc::SharedBitmapId& id);
+ void ChildDeletedSharedBitmap(const cc::SharedBitmapId& id);
+
+ mutable base::Lock lock_;
+
+ typedef base::hash_map<cc::SharedBitmapId, scoped_refptr<BitmapData>>
+ BitmapMap;
+ BitmapMap handle_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(HostSharedBitmapManager);
+};
+
+} // namespace display_compositor
+
+#endif // COMPONENTS_DISPLAY_COMPOSITOR_HOST_SHARED_BITMAP_MANAGER_H_
diff --git a/chromium/components/display_compositor/host_shared_bitmap_manager_unittest.cc b/chromium/components/display_compositor/host_shared_bitmap_manager_unittest.cc
new file mode 100644
index 00000000000..e3ea52419fa
--- /dev/null
+++ b/chromium/components/display_compositor/host_shared_bitmap_manager_unittest.cc
@@ -0,0 +1,165 @@
+// Copyright (c) 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 <stddef.h>
+#include <string.h>
+
+#include "components/display_compositor/host_shared_bitmap_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace display_compositor {
+namespace {
+
+class HostSharedBitmapManagerTest : public testing::Test {
+ protected:
+ void SetUp() override { manager_.reset(new HostSharedBitmapManager()); }
+ std::unique_ptr<HostSharedBitmapManager> manager_;
+};
+
+TEST_F(HostSharedBitmapManagerTest, TestCreate) {
+ gfx::Size bitmap_size(1, 1);
+ size_t size_in_bytes;
+ EXPECT_TRUE(cc::SharedBitmap::SizeInBytes(bitmap_size, &size_in_bytes));
+ std::unique_ptr<base::SharedMemory> bitmap(new base::SharedMemory());
+ bitmap->CreateAndMapAnonymous(size_in_bytes);
+ memset(bitmap->memory(), 0xff, size_in_bytes);
+ cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+
+ HostSharedBitmapManagerClient client(manager_.get());
+ base::SharedMemoryHandle handle;
+ bitmap->ShareToProcess(base::GetCurrentProcessHandle(), &handle);
+ client.ChildAllocatedSharedBitmap(size_in_bytes, handle, id);
+
+ std::unique_ptr<cc::SharedBitmap> large_bitmap;
+ large_bitmap = manager_->GetSharedBitmapFromId(gfx::Size(1024, 1024), id);
+ EXPECT_TRUE(large_bitmap.get() == NULL);
+
+ std::unique_ptr<cc::SharedBitmap> very_large_bitmap;
+ very_large_bitmap =
+ manager_->GetSharedBitmapFromId(gfx::Size(1, (1 << 30) | 1), id);
+ EXPECT_TRUE(very_large_bitmap.get() == NULL);
+
+ std::unique_ptr<cc::SharedBitmap> negative_size_bitmap;
+ negative_size_bitmap =
+ manager_->GetSharedBitmapFromId(gfx::Size(-1, 1024), id);
+ EXPECT_TRUE(negative_size_bitmap.get() == NULL);
+
+ cc::SharedBitmapId id2 = cc::SharedBitmap::GenerateId();
+ std::unique_ptr<cc::SharedBitmap> invalid_bitmap;
+ invalid_bitmap = manager_->GetSharedBitmapFromId(bitmap_size, id2);
+ EXPECT_TRUE(invalid_bitmap.get() == NULL);
+
+ std::unique_ptr<cc::SharedBitmap> shared_bitmap;
+ shared_bitmap = manager_->GetSharedBitmapFromId(bitmap_size, id);
+ ASSERT_TRUE(shared_bitmap.get() != NULL);
+ EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), 4), 0);
+
+ std::unique_ptr<cc::SharedBitmap> large_bitmap2;
+ large_bitmap2 = manager_->GetSharedBitmapFromId(gfx::Size(1024, 1024), id);
+ EXPECT_TRUE(large_bitmap2.get() == NULL);
+
+ std::unique_ptr<cc::SharedBitmap> shared_bitmap2;
+ shared_bitmap2 = manager_->GetSharedBitmapFromId(bitmap_size, id);
+ EXPECT_TRUE(shared_bitmap2->pixels() == shared_bitmap->pixels());
+ shared_bitmap2.reset();
+ EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes),
+ 0);
+
+ client.DidDeleteSharedBitmap(id);
+
+ memset(bitmap->memory(), 0, size_in_bytes);
+
+ EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes),
+ 0);
+ bitmap.reset();
+ shared_bitmap.reset();
+}
+
+TEST_F(HostSharedBitmapManagerTest, TestCreateForChild) {
+ gfx::Size bitmap_size(1, 1);
+ size_t size_in_bytes;
+ EXPECT_TRUE(cc::SharedBitmap::SizeInBytes(bitmap_size, &size_in_bytes));
+ cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+ HostSharedBitmapManagerClient client(manager_.get());
+ base::SharedMemoryHandle handle;
+ client.AllocateSharedBitmapForChild(base::GetCurrentProcessHandle(),
+ size_in_bytes, id, &handle);
+
+ EXPECT_TRUE(base::SharedMemory::IsHandleValid(handle));
+ std::unique_ptr<base::SharedMemory> bitmap(
+ new base::SharedMemory(handle, false));
+ EXPECT_TRUE(bitmap->Map(size_in_bytes));
+ memset(bitmap->memory(), 0xff, size_in_bytes);
+
+ std::unique_ptr<cc::SharedBitmap> shared_bitmap;
+ shared_bitmap = manager_->GetSharedBitmapFromId(bitmap_size, id);
+ EXPECT_TRUE(shared_bitmap);
+ EXPECT_TRUE(
+ memcmp(bitmap->memory(), shared_bitmap->pixels(), size_in_bytes) == 0);
+
+ client.DidDeleteSharedBitmap(id);
+}
+
+TEST_F(HostSharedBitmapManagerTest, RemoveProcess) {
+ gfx::Size bitmap_size(1, 1);
+ size_t size_in_bytes;
+ EXPECT_TRUE(cc::SharedBitmap::SizeInBytes(bitmap_size, &size_in_bytes));
+ std::unique_ptr<base::SharedMemory> bitmap(new base::SharedMemory());
+ bitmap->CreateAndMapAnonymous(size_in_bytes);
+ memset(bitmap->memory(), 0xff, size_in_bytes);
+ cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+
+ base::SharedMemoryHandle handle;
+ std::unique_ptr<HostSharedBitmapManagerClient> client(
+ new HostSharedBitmapManagerClient(manager_.get()));
+ bitmap->ShareToProcess(base::GetCurrentProcessHandle(), &handle);
+ client->ChildAllocatedSharedBitmap(size_in_bytes, handle, id);
+
+ std::unique_ptr<cc::SharedBitmap> shared_bitmap;
+ shared_bitmap = manager_->GetSharedBitmapFromId(bitmap_size, id);
+ ASSERT_TRUE(shared_bitmap.get() != NULL);
+
+ EXPECT_EQ(1u, manager_->AllocatedBitmapCount());
+ client.reset();
+ EXPECT_EQ(0u, manager_->AllocatedBitmapCount());
+
+ std::unique_ptr<cc::SharedBitmap> shared_bitmap2;
+ shared_bitmap2 = manager_->GetSharedBitmapFromId(bitmap_size, id);
+ EXPECT_TRUE(shared_bitmap2.get() == NULL);
+ EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes),
+ 0);
+
+ shared_bitmap.reset();
+}
+
+TEST_F(HostSharedBitmapManagerTest, AddDuplicate) {
+ gfx::Size bitmap_size(1, 1);
+ size_t size_in_bytes;
+ EXPECT_TRUE(cc::SharedBitmap::SizeInBytes(bitmap_size, &size_in_bytes));
+ std::unique_ptr<base::SharedMemory> bitmap(new base::SharedMemory());
+ bitmap->CreateAndMapAnonymous(size_in_bytes);
+ memset(bitmap->memory(), 0xff, size_in_bytes);
+ cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+ HostSharedBitmapManagerClient client(manager_.get());
+
+ base::SharedMemoryHandle handle;
+ bitmap->ShareToProcess(base::GetCurrentProcessHandle(), &handle);
+ client.ChildAllocatedSharedBitmap(size_in_bytes, handle, id);
+
+ std::unique_ptr<base::SharedMemory> bitmap2(new base::SharedMemory());
+ bitmap2->CreateAndMapAnonymous(size_in_bytes);
+ memset(bitmap2->memory(), 0x00, size_in_bytes);
+
+ client.ChildAllocatedSharedBitmap(size_in_bytes, bitmap2->handle(), id);
+
+ std::unique_ptr<cc::SharedBitmap> shared_bitmap;
+ shared_bitmap = manager_->GetSharedBitmapFromId(bitmap_size, id);
+ ASSERT_TRUE(shared_bitmap.get() != NULL);
+ EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes),
+ 0);
+ client.DidDeleteSharedBitmap(id);
+}
+
+} // namespace
+} // namespace display_compositor
diff --git a/chromium/components/display_compositor/yuv_readback_unittest.cc b/chromium/components/display_compositor/yuv_readback_unittest.cc
index fe595e3364a..bda67318c25 100644
--- a/chromium/components/display_compositor/yuv_readback_unittest.cc
+++ b/chromium/components/display_compositor/yuv_readback_unittest.cc
@@ -7,6 +7,7 @@
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/scoped_task_environment.h"
#include "base/test/test_suite.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
@@ -476,7 +477,7 @@ class YUVReadbackTest : public testing::Test {
gpu::gles2::GLES2Interface* gl_;
std::unique_ptr<display_compositor::GLHelper> helper_;
gl::DisableNullDrawGLBindings enable_pixel_output_;
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
};
TEST_F(YUVReadbackTest, YUVReadbackOptTest) {
diff --git a/chromium/components/dom_distiller/DEPS b/chromium/components/dom_distiller/DEPS
index 75e60801d90..35ae9ad146c 100644
--- a/chromium/components/dom_distiller/DEPS
+++ b/chromium/components/dom_distiller/DEPS
@@ -15,6 +15,7 @@ include_rules = [
"+third_party/re2",
"+net/base",
"+net/http",
+ "+net/traffic_annotation",
"+net/url_request",
"+ui/base/l10n",
"+ui/base/resource",
diff --git a/chromium/components/dom_distiller/content/browser/distillability_driver.cc b/chromium/components/dom_distiller/content/browser/distillability_driver.cc
index 8d5b06e6d6b..ce19a465041 100644
--- a/chromium/components/dom_distiller/content/browser/distillability_driver.cc
+++ b/chromium/components/dom_distiller/content/browser/distillability_driver.cc
@@ -91,7 +91,7 @@ void DistillabilityDriver::RenderFrameHostChanged(
void DistillabilityDriver::ReadyToCommitNavigation(
content::NavigationHandle* navigation_handle) {
- if (!navigation_handle->IsSamePage())
+ if (!navigation_handle->IsSameDocument())
SetupMojoService(navigation_handle->GetRenderFrameHost());
}
diff --git a/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc b/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc
index bcd09f2561a..79183c2e540 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc
+++ b/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc
@@ -7,9 +7,9 @@
#include <utility>
#include "base/memory/ptr_util.h"
+#include "base/metrics/user_metrics.h"
#include "components/dom_distiller/content/browser/distiller_ui_handle.h"
#include "components/dom_distiller/core/feedback_reporter.h"
-#include "content/public/browser/user_metrics.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
namespace dom_distiller {
@@ -22,27 +22,9 @@ DistillerJavaScriptServiceImpl::DistillerJavaScriptServiceImpl(
DistillerJavaScriptServiceImpl::~DistillerJavaScriptServiceImpl() {}
-void DistillerJavaScriptServiceImpl::HandleDistillerFeedbackCall(
- bool good) {
- FeedbackReporter::ReportQuality(good);
- if (good) {
- return;
- }
-
- // If feedback is bad try to start up external feedback.
- if (!distiller_ui_handle_) {
- return;
- }
- content::WebContents* contents =
- content::WebContents::FromRenderFrameHost(render_frame_host_);
- distiller_ui_handle_->ReportExternalFeedback(
- contents, contents->GetURL(), false);
- return;
-}
-
void DistillerJavaScriptServiceImpl::HandleDistillerClosePanelCall(
bool animate) {
- content::RecordAction(base::UserMetricsAction("DomDistiller_ViewOriginal"));
+ base::RecordAction(base::UserMetricsAction("DomDistiller_ViewOriginal"));
if (!distiller_ui_handle_) {
return;
}
diff --git a/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h b/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h
index e8ac057ee0b..829df278081 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h
+++ b/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h
@@ -22,9 +22,6 @@ class DistillerJavaScriptServiceImpl
// Mojo mojom::DistillerJavaScriptService implementation.
- // Send UMA feedback and start the external feedback reporter if one exists.
- void HandleDistillerFeedbackCall(bool good) override;
-
// Make a call into Android to close the overlay panel containing reader mode.
void HandleDistillerClosePanelCall(bool animate) override;
diff --git a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc
index f062063541a..0ac8f7c7b8e 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc
+++ b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/callback.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/utf_string_conversions.h"
#include "components/dom_distiller/content/browser/distiller_javascript_utils.h"
@@ -168,7 +169,7 @@ void DistillerPageWebContents::DidFailLoad(
content::WebContentsObserver::Observe(NULL);
DCHECK(state_ == LOADING_PAGE || state_ == EXECUTING_JAVASCRIPT);
state_ = PAGELOAD_FAILED;
- std::unique_ptr<base::Value> empty = base::Value::CreateNullValue();
+ auto empty = base::MakeUnique<base::Value>();
OnWebContentsDistillationDone(GURL(), base::TimeTicks(), empty.get());
}
}
diff --git a/chromium/components/dom_distiller/content/browser/distiller_ui_handle.h b/chromium/components/dom_distiller/content/browser/distiller_ui_handle.h
index d374859e829..d97384eafd5 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_ui_handle.h
+++ b/chromium/components/dom_distiller/content/browser/distiller_ui_handle.h
@@ -18,11 +18,6 @@ class DistillerUIHandle {
DistillerUIHandle() {}
virtual ~DistillerUIHandle() {}
- // Start an external form to record user feedback.
- virtual void ReportExternalFeedback(content::WebContents* web_contents,
- const GURL& url,
- const bool good) = 0;
-
// Open the UI settings for dom distiller.
virtual void OpenSettings(content::WebContents* web_contents) = 0;
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 aa6e2a89b01..c9273e10fc0 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
@@ -136,9 +136,9 @@ void DomDistillerViewerSource::RequestViewerHandle::DidFinishNavigation(
const GURL& navigation = navigation_handle->GetURL();
bool expected_main_view_request =
- navigation.SchemeIs(expected_scheme_.c_str()) &&
+ navigation.SchemeIs(expected_scheme_) &&
expected_request_path_ == navigation.query();
- if (navigation_handle->IsSamePage() || expected_main_view_request) {
+ if (navigation_handle->IsSameDocument() || expected_main_view_request) {
// In-page navigations, as well as the main view request can be ignored.
if (expected_main_view_request) {
content::RenderFrameHost* render_frame_host =
@@ -291,7 +291,7 @@ std::string DomDistillerViewerSource::GetMimeType(
bool DomDistillerViewerSource::ShouldServiceRequest(
const net::URLRequest* request) const {
- return request->url().SchemeIs(scheme_.c_str());
+ return request->url().SchemeIs(scheme_);
}
// TODO(nyquist): Start tracking requests using this method.
diff --git a/chromium/components/dom_distiller/content/browser/external_feedback_reporter.h b/chromium/components/dom_distiller/content/browser/external_feedback_reporter.h
deleted file mode 100644
index 90586c3600f..00000000000
--- a/chromium/components/dom_distiller/content/browser/external_feedback_reporter.h
+++ /dev/null
@@ -1,32 +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_DOM_DISTILLER_CONTENT_BROWSER_EXTERNAL_FEEDBACK_REPORTER_H_
-#define COMPONENTS_DOM_DISTILLER_CONTENT_BROWSER_EXTERNAL_FEEDBACK_REPORTER_H_
-
-#include "base/macros.h"
-#include "content/public/browser/web_contents.h"
-#include "url/gurl.h"
-
-namespace dom_distiller {
-
-// ExternalFeedbackReporter handles reporting distillation quality through an
-// external source.
-class ExternalFeedbackReporter {
- public:
- ExternalFeedbackReporter() {}
- virtual ~ExternalFeedbackReporter() {}
-
- // Start an external form to record user feedback.
- virtual void ReportExternalFeedback(content::WebContents* web_contents,
- const GURL& url,
- const bool good) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ExternalFeedbackReporter);
-};
-
-} // namespace dom_distiller
-
-#endif // COMPONENTS_DOM_DISTILLER_CONTENT_BROWSER_EXTERNAL_FEEDBACK_REPORTER_H_
diff --git a/chromium/components/dom_distiller/content/browser/web_contents_main_frame_observer.cc b/chromium/components/dom_distiller/content/browser/web_contents_main_frame_observer.cc
index 8e561a758ba..ac85891cb8e 100644
--- a/chromium/components/dom_distiller/content/browser/web_contents_main_frame_observer.cc
+++ b/chromium/components/dom_distiller/content/browser/web_contents_main_frame_observer.cc
@@ -35,7 +35,7 @@ void WebContentsMainFrameObserver::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
if (!navigation_handle->IsInMainFrame() ||
!navigation_handle->HasCommitted() ||
- navigation_handle->IsSamePage()) {
+ navigation_handle->IsSameDocument()) {
return;
}
diff --git a/chromium/components/dom_distiller/content/common/distiller_javascript_service.mojom b/chromium/components/dom_distiller/content/common/distiller_javascript_service.mojom
index d16d5d1c858..8589198d0ed 100644
--- a/chromium/components/dom_distiller/content/common/distiller_javascript_service.mojom
+++ b/chromium/components/dom_distiller/content/common/distiller_javascript_service.mojom
@@ -7,9 +7,6 @@ module dom_distiller.mojom;
// This service is implemented by the browser process and is used by the
// renderer when a distiller JavaScript function is called.
interface DistillerJavaScriptService {
- // Handle the "distiller.sendFeedback" function.
- HandleDistillerFeedbackCall(bool good);
-
// Handle closing the overlay panel that contains Reader Mode; the
// "distiller.close" function.
HandleDistillerClosePanelCall(bool animate);
diff --git a/chromium/components/dom_distiller/content/renderer/distillability_agent.cc b/chromium/components/dom_distiller/content/renderer/distillability_agent.cc
index e032b677b0d..4bee7c3e57f 100644
--- a/chromium/components/dom_distiller/content/renderer/distillability_agent.cc
+++ b/chromium/components/dom_distiller/content/renderer/distillability_agent.cc
@@ -77,28 +77,22 @@ bool IsDistillablePageAdaboost(WebDocument& doc,
const DistillablePageDetector* detector,
const DistillablePageDetector* long_page,
bool is_last) {
- WebDistillabilityFeatures features = doc.distillabilityFeatures();
- GURL parsed_url(doc.url());
+ WebDistillabilityFeatures features = doc.DistillabilityFeatures();
+ GURL parsed_url(doc.Url());
if (!parsed_url.is_valid()) {
return false;
}
std::vector<double> derived = CalculateDerivedFeatures(
- features.openGraph,
- parsed_url,
- features.elementCount,
- features.anchorCount,
- features.formCount,
- features.mozScore,
- features.mozScoreAllSqrt,
- features.mozScoreAllLinear
- );
+ features.open_graph, parsed_url, features.element_count,
+ features.anchor_count, features.form_count, features.moz_score,
+ features.moz_score_all_sqrt, features.moz_score_all_linear);
double score = detector->Score(derived) - detector->GetThreshold();
double long_score = long_page->Score(derived) - long_page->GetThreshold();
bool distillable = score > 0;
bool long_article = long_score > 0;
bool blacklisted = IsBlacklisted(parsed_url);
- if (!features.isMobileFriendly) {
+ if (!features.is_mobile_friendly) {
int score_int = std::round(score * 100);
if (score > 0) {
UMA_HISTOGRAM_COUNTS_1000("DomDistiller.DistillabilityScoreNMF.Positive",
@@ -122,8 +116,8 @@ bool IsDistillablePageAdaboost(WebDocument& doc,
}
}
- int bucket = static_cast<unsigned>(features.isMobileFriendly) |
- (static_cast<unsigned>(distillable) << 1);
+ int bucket = static_cast<unsigned>(features.is_mobile_friendly) |
+ (static_cast<unsigned>(distillable) << 1);
if (is_last) {
UMA_HISTOGRAM_ENUMERATION("DomDistiller.PageDistillableAfterLoading",
bucket, 4);
@@ -133,7 +127,7 @@ bool IsDistillablePageAdaboost(WebDocument& doc,
if (!distillable) {
UMA_HISTOGRAM_ENUMERATION("DomDistiller.DistillabilityRejection",
NOT_ARTICLE, REJECTION_BUCKET_BOUNDARY);
- } else if (features.isMobileFriendly) {
+ } else if (features.is_mobile_friendly) {
UMA_HISTOGRAM_ENUMERATION("DomDistiller.DistillabilityRejection",
MOBILE_FRIENDLY, REJECTION_BUCKET_BOUNDARY);
} else if (blacklisted) {
@@ -151,7 +145,7 @@ bool IsDistillablePageAdaboost(WebDocument& doc,
if (blacklisted) {
return false;
}
- if (features.isMobileFriendly) {
+ if (features.is_mobile_friendly) {
return false;
}
return distillable && long_article;
@@ -162,7 +156,7 @@ bool IsDistillablePage(WebDocument& doc, bool is_last) {
case DistillerHeuristicsType::ALWAYS_TRUE:
return true;
case DistillerHeuristicsType::OG_ARTICLE:
- return doc.distillabilityFeatures().openGraph;
+ return doc.DistillabilityFeatures().open_graph;
case DistillerHeuristicsType::ADABOOST_MODEL:
return IsDistillablePageAdaboost(doc,
DistillablePageDetector::GetNewModel(),
@@ -182,19 +176,21 @@ DistillabilityAgent::DistillabilityAgent(
void DistillabilityAgent::DidMeaningfulLayout(
WebMeaningfulLayout layout_type) {
- if (layout_type != WebMeaningfulLayout::FinishedParsing &&
- layout_type != WebMeaningfulLayout::FinishedLoading) {
+ if (layout_type != WebMeaningfulLayout::kFinishedParsing &&
+ layout_type != WebMeaningfulLayout::kFinishedLoading) {
return;
}
DCHECK(render_frame());
if (!render_frame()->IsMainFrame()) return;
DCHECK(render_frame()->GetWebFrame());
- WebDocument doc = render_frame()->GetWebFrame()->document();
- if (doc.isNull() || doc.body().isNull()) return;
- if (!url_utils::IsUrlDistillable(doc.url())) return;
+ WebDocument doc = render_frame()->GetWebFrame()->GetDocument();
+ if (doc.IsNull() || doc.Body().IsNull())
+ return;
+ if (!url_utils::IsUrlDistillable(doc.Url()))
+ return;
- bool is_loaded = layout_type == WebMeaningfulLayout::FinishedLoading;
+ bool is_loaded = layout_type == WebMeaningfulLayout::kFinishedLoading;
if (!NeedToUpdate(is_loaded)) return;
bool is_last = IsLast(is_loaded);
diff --git a/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc b/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc
index 7e5f90620ca..86dd5ccd925 100644
--- a/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc
+++ b/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc
@@ -29,7 +29,7 @@ DistillerNativeJavaScript::~DistillerNativeJavaScript() {}
void DistillerNativeJavaScript::AddJavaScriptObjectToFrame(
v8::Local<v8::Context> context) {
- v8::Isolate* isolate = blink::mainThreadIsolate();
+ v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
if (context.IsEmpty())
return;
@@ -45,12 +45,6 @@ void DistillerNativeJavaScript::AddJavaScriptObjectToFrame(
// wrapper function for binding. Note that calling distiller_js_service.get()
// does not transfer ownership of the interface.
BindFunctionToObject(
- distiller_obj, "sendFeedback",
- base::Bind(
- &mojom::DistillerJavaScriptService::HandleDistillerFeedbackCall,
- base::Unretained(distiller_js_service_.get())));
-
- BindFunctionToObject(
distiller_obj, "closePanel",
base::Bind(
&mojom::DistillerJavaScriptService::HandleDistillerClosePanelCall,
diff --git a/chromium/components/dom_distiller/core/BUILD.gn b/chromium/components/dom_distiller/core/BUILD.gn
index 49f014fb5a1..55652429d24 100644
--- a/chromium/components/dom_distiller/core/BUILD.gn
+++ b/chromium/components/dom_distiller/core/BUILD.gn
@@ -59,6 +59,7 @@ static_library("core") {
public_deps = [
"//components/dom_distiller/core/proto",
+ "//net",
"//third_party/dom_distiller_js:proto",
]
deps = [
@@ -71,7 +72,6 @@ static_library("core") {
"//components/strings",
"//components/sync",
"//components/variations",
- "//net",
"//skia",
"//third_party/re2",
"//ui/base",
diff --git a/chromium/components/dom_distiller/core/css/distilledpage.css b/chromium/components/dom_distiller/core/css/distilledpage.css
index a9b7529746c..9880e2cde5a 100644
--- a/chromium/components/dom_distiller/core/css/distilledpage.css
+++ b/chromium/components/dom_distiller/core/css/distilledpage.css
@@ -382,85 +382,10 @@ body .hidden {
display: none;
}
-/* Footer feedback form. */
-#contentWrap {
- display: flex;
- flex-direction: column;
- flex-grow: 1;
- overflow: auto;
- position: relative;
- z-index: 1;
-}
-
-.footerFeedback {
- display: flex;
- flex-direction: column;
- font-size: 14px;
- z-index: 2;
- background-color: #4285F4;
- color: #fff;
- width: 100%;
-}
-
-.feedbackContent {
- font-size: 14px;
- font-family: sans-serif;
- background-color: #4285F4;
- clear: both;
- padding: 14px;
-}
-
-#feedbackQuestion {
- font-size: 1.4em;
- font-weight: 700;
- text-align: center;
- width: 100%;
-}
-
-.feedbackButtonWrap {
- margin-top: 14px;
- text-align: center;
- width: 100%;
-}
-
-.feedbackButton {
- -webkit-user-select: none;
- background-color: #FFFFFF;
- border-radius: 3px;
- color: #4285F4;
- display: inline-block;
- font-weight: 900;
- height: 35px;
- margin: 0px 4% 0px 4%;
- padding-top: 8px;
- text-align: center;
- text-transform: uppercase;
- user-select: none;
- width: 40%;
-}
-
.clear {
clear: both;
}
-/* Feedback fade out */
-.fadeOut {
- animation-duration: 0.5s;
- animation-name: fadeOutAndSwipeAnimation;
-}
-
-@keyframes fadeOutAndSwipeAnimation {
- from {
- margin-left: 0%;
- opacity: 1;
- }
-
- to {
- margin-left: -100%;
- opacity: 0;
- }
-}
-
/* Iframe sizing. */
.youtubeContainer {
height: 0px;
diff --git a/chromium/components/dom_distiller/core/distiller_unittest.cc b/chromium/components/dom_distiller/core/distiller_unittest.cc
index b7eaf9b6004..1336d7ea940 100644
--- a/chromium/components/dom_distiller/core/distiller_unittest.cc
+++ b/chromium/components/dom_distiller/core/distiller_unittest.cc
@@ -17,6 +17,7 @@
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
@@ -533,7 +534,7 @@ TEST_F(DistillerTest, CheckMaxPageLimitExactLimit) {
TEST_F(DistillerTest, SinglePageDistillationFailure) {
base::MessageLoopForUI loop;
// To simulate failure return a null value.
- std::unique_ptr<base::Value> null_value = base::Value::CreateNullValue();
+ auto null_value = base::MakeUnique<base::Value>();
distiller_.reset(
new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
DistillPage(kURL, CreateMockDistillerPage(null_value.get(), GURL(kURL)));
@@ -555,7 +556,7 @@ TEST_F(DistillerTest, MultiplePagesDistillationFailure) {
distiller_data->distilled_values.begin() + failed_page_num);
distiller_data->distilled_values.insert(
distiller_data->distilled_values.begin() + failed_page_num,
- base::Value::CreateNullValue());
+ base::MakeUnique<base::Value>());
// Expect only calls till the failed page number.
distiller_.reset(
new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
diff --git a/chromium/components/dom_distiller/core/distiller_url_fetcher.cc b/chromium/components/dom_distiller/core/distiller_url_fetcher.cc
index 752c7ad77ae..696af4f95c2 100644
--- a/chromium/components/dom_distiller/core/distiller_url_fetcher.cc
+++ b/chromium/components/dom_distiller/core/distiller_url_fetcher.cc
@@ -6,6 +6,7 @@
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_context_getter.h"
@@ -47,8 +48,39 @@ void DistillerURLFetcher::FetchURL(const std::string& url,
std::unique_ptr<URLFetcher> DistillerURLFetcher::CreateURLFetcher(
net::URLRequestContextGetter* context_getter,
const std::string& url) {
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("dom_distiller", R"(
+ semantics {
+ sender: "DOM Distiller"
+ description:
+ "Chromium provides Mobile-friendly view on Android phones when the "
+ "web page contains an article, and is not mobile-friendly. If the "
+ "user enters Mobile-friendly view, the main content would be "
+ "extracted and reflowed in a simple layout for better readability. "
+ "On iOS, apps can add URLs to the Reading List in Chromium. When "
+ "opening the entries in the Reading List with no or limited "
+ "network, the simple layout would be shown. DOM distiller is the "
+ "backend service for Mobile-friendly view and Reading List."
+ trigger:
+ "When the user enters Mobile-friendly view on Android phones, or "
+ "adds entries to the Reading List on iOS. Note that Reading List "
+ "entries can be added from other apps."
+ data:
+ "URLs of the required website resources to fetch."
+ destination: WEBSITE
+ }
+ policy {
+ cookies_allowed: true
+ cookies_store: "user"
+ setting: "Users can enable or disable Mobile-friendly view by "
+ "toggling chrome://flags#reader-mode-heuristics in Chromium on "
+ "Android."
+ policy_exception_justification:
+ "Not implemented, considered not useful as no content is being "
+ "uploaded; this request merely downloads the resources on the web."
+ })");
std::unique_ptr<net::URLFetcher> fetcher =
- URLFetcher::Create(GURL(url), URLFetcher::GET, this);
+ URLFetcher::Create(GURL(url), URLFetcher::GET, this, traffic_annotation);
data_use_measurement::DataUseUserData::AttachToFetcher(
fetcher.get(), data_use_measurement::DataUseUserData::DOM_DISTILLER);
fetcher->SetRequestContext(context_getter);
diff --git a/chromium/components/dom_distiller/core/dom_distiller_request_view_base.cc b/chromium/components/dom_distiller/core/dom_distiller_request_view_base.cc
index 2d505d93f9a..bc717770c6a 100644
--- a/chromium/components/dom_distiller/core/dom_distiller_request_view_base.cc
+++ b/chromium/components/dom_distiller/core/dom_distiller_request_view_base.cc
@@ -56,10 +56,6 @@ void DomDistillerRequestViewBase::OnArticleReady(
SendJavaScript(viewer::GetSetTitleJs(article_proto->title()));
SendJavaScript(viewer::GetSetTextDirectionJs(text_direction));
SendJavaScript(viewer::GetUnsafeArticleContentJs(article_proto));
- // If any content was loaded, show the feedback form.
- if (ShouldShowFeedbackForm()) {
- SendJavaScript(viewer::GetShowFeedbackFormJs());
- }
} else {
// It's possible that we didn't get some incremental updates from the
// distiller. Ensure all remaining pages are flushed to the viewer.
@@ -91,10 +87,6 @@ void DomDistillerRequestViewBase::OnArticleUpdated(
// client.
SendJavaScript(viewer::GetSetTitleJs(page.title()));
SendJavaScript(viewer::GetSetTextDirectionJs(page.text_direction()));
- // If any content was loaded, show the feedback form.
- if (ShouldShowFeedbackForm()) {
- SendJavaScript(viewer::GetShowFeedbackFormJs());
- }
}
}
}
diff --git a/chromium/components/dom_distiller/core/experiments.cc b/chromium/components/dom_distiller/core/experiments.cc
index cc882d1f0fb..900daecd4b5 100644
--- a/chromium/components/dom_distiller/core/experiments.cc
+++ b/chromium/components/dom_distiller/core/experiments.cc
@@ -47,29 +47,4 @@ DistillerHeuristicsType GetDistillerHeuristicsType() {
}
return DistillerHeuristicsType::ADABOOST_MODEL;
}
-
-bool ShouldShowFeedbackForm() {
- const std::string group_name =
- base::FieldTrialList::FindFullName("ReaderModeUIFeedback");
- const std::string switch_value =
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kReaderModeFeedback);
- if (switch_value != "") {
- if (switch_value == switches::reader_mode_feedback::kOn) {
- return true;
- }
- if (switch_value == switches::reader_mode_feedback::kOff) {
- return false;
- }
- NOTREACHED() << "Invalid value for " << switches::kReaderModeFeedback;
- } else {
- if (group_name == "DoNotShow") {
- return false;
- }
- if (group_name == "Show") {
- return true;
- }
- }
- return false;
-}
}
diff --git a/chromium/components/dom_distiller/core/experiments.h b/chromium/components/dom_distiller/core/experiments.h
index 9d5187a3411..16edfcbee00 100644
--- a/chromium/components/dom_distiller/core/experiments.h
+++ b/chromium/components/dom_distiller/core/experiments.h
@@ -14,7 +14,6 @@ namespace dom_distiller {
};
DistillerHeuristicsType GetDistillerHeuristicsType();
- bool ShouldShowFeedbackForm();
}
#endif // COMPONENTS_DOM_DISTILLER_CORE_EXPERIMENTS_H_
diff --git a/chromium/components/dom_distiller/core/html/dom_distiller_viewer.html b/chromium/components/dom_distiller/core/html/dom_distiller_viewer.html
index 138eee0ccee..f67f4ed4d66 100644
--- a/chromium/components/dom_distiller/core/html/dom_distiller_viewer.html
+++ b/chromium/components/dom_distiller/core/html/dom_distiller_viewer.html
@@ -12,7 +12,6 @@ found in the LICENSE file.
<title>$1</title>
<!-- Placeholder for CSS. -->
$2
- <link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
</head>
<body class="$3">
<div id="contentWrap">
diff --git a/chromium/components/dom_distiller/core/javascript/dom_distiller_viewer.js b/chromium/components/dom_distiller/core/javascript/dom_distiller_viewer.js
index e325f3c0216..61ef521bcf2 100644
--- a/chromium/components/dom_distiller/core/javascript/dom_distiller_viewer.js
+++ b/chromium/components/dom_distiller/core/javascript/dom_distiller_viewer.js
@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// This variable will be changed by iOS scripts.
-var distiller_on_ios = false;
+// On iOS, |distiller_on_ios| was set to true before this script.
+var distiller_on_ios;
+if (typeof distiller_on_ios === 'undefined') {distiller_on_ios = false;}
function addToPage(html) {
var div = document.createElement('div');
@@ -111,22 +112,18 @@ function useFontScaling(scaling) {
pincher.useFontScaling(scaling);
}
-/**
- * Show the distiller feedback form.
- * @param questionText The i18n text for the feedback question.
- * @param yesText The i18n text for the feedback answer 'YES'.
- * @param noText The i18n text for the feedback answer 'NO'.
- */
-function showFeedbackForm(questionText, yesText, noText) {
- // If the distiller is running on iOS, do not show the feedback form. This
- // variable is set in distiller_viewer.cc before this function is run.
+function maybeSetWebFont() {
+ // On iOS, the web fonts block the rendering until the resources are
+ // fetched, which can take a long time on slow networks.
+ // In Blink, it times out after 3 seconds and uses fallback fonts.
+ // See crbug.com/711650
if (distiller_on_ios) return;
- document.getElementById('feedbackYes').innerText = yesText;
- document.getElementById('feedbackNo').innerText = noText;
- document.getElementById('feedbackQuestion').innerText = questionText;
-
- document.getElementById('feedbackContainer').classList.remove("hidden");
+ var e = document.createElement('link');
+ e.href = 'https://fonts.googleapis.com/css?family=Roboto';
+ e.rel = 'stylesheet';
+ e.type = 'text/css';
+ document.head.appendChild(e);
}
// Add a listener to the "View Original" link to report opt-outs.
@@ -137,42 +134,8 @@ document.getElementById('closeReaderView').addEventListener('click',
}
}, true);
-document.getElementById('feedbackYes').addEventListener('click', function(e) {
- if (distiller) {
- distiller.sendFeedback(true);
- }
- document.getElementById('feedbackContainer').className += " fadeOut";
-}, true);
-
-document.getElementById('feedbackNo').addEventListener('click', function(e) {
- if (distiller) {
- distiller.sendFeedback(false);
- }
- document.getElementById('feedbackContainer').className += " fadeOut";
-}, true);
-
-document.getElementById('feedbackContainer').addEventListener('animationend',
- function(e) {
- var feedbackContainer = document.getElementById('feedbackContainer');
- feedbackContainer.classList.remove("fadeOut");
- document.getElementById('contentWrap').style.paddingBottom =
- window.getComputedStyle(feedbackContainer).height;
- feedbackContainer.className += " hidden";
- setTimeout(function() {
- // Close the gap where the feedback form was.
- var contentWrap = document.getElementById('contentWrap');
- contentWrap.style.transition = '0.5s';
- contentWrap.style.paddingBottom = '';
- }, 0);
- }, true);
-
-document.getElementById('contentWrap').addEventListener('transitionend',
- function(e) {
- var contentWrap = document.getElementById('contentWrap');
- contentWrap.style.transition = '';
- }, true);
-
updateToolbarColor();
+maybeSetWebFont();
var pincher = (function() {
'use strict';
diff --git a/chromium/components/dom_distiller/core/javascript/domdistiller.js b/chromium/components/dom_distiller/core/javascript/domdistiller.js
index bbd2d00d569..6e9a417a3cf 100644
--- a/chromium/components/dom_distiller/core/javascript/domdistiller.js
+++ b/chromium/components/dom_distiller/core/javascript/domdistiller.js
@@ -8,7 +8,12 @@
try {
function initialize() {
// This include will be processed at build time by grit.
+ // Note: this <include> is not behind a single-line comment because the
+ // first line of the file is source code (so the first line would be
+ // skipped) instead of a licence header.
+ // clang-format off
<include src="../../../../third_party/dom_distiller_js/dist/js/domdistiller.js"/>
+ // clang-format on
}
window.setTimeout = function() {};
window.clearTimeout = function() {};
diff --git a/chromium/components/dom_distiller/core/page_features_unittest.cc b/chromium/components/dom_distiller/core/page_features_unittest.cc
index 6d0bea34b80..0bfeb142d69 100644
--- a/chromium/components/dom_distiller/core/page_features_unittest.cc
+++ b/chromium/components/dom_distiller/core/page_features_unittest.cc
@@ -75,7 +75,7 @@ TEST(DomDistillerPageFeaturesTest, TestCalculateDerivedFeatures) {
std::string stringified_json;
ASSERT_TRUE(base::JSONWriter::Write(*core_features, &stringified_json));
std::unique_ptr<base::Value> stringified_value(
- new base::StringValue(stringified_json));
+ new base::Value(stringified_json));
std::vector<double> derived(
CalculateDerivedFeaturesFromJSON(stringified_value.get()));
diff --git a/chromium/components/dom_distiller/core/viewer.cc b/chromium/components/dom_distiller/core/viewer.cc
index 524f50fdc40..66ce1429842 100644
--- a/chromium/components/dom_distiller/core/viewer.cc
+++ b/chromium/components/dom_distiller/core/viewer.cc
@@ -149,31 +149,12 @@ std::string ReplaceHtmlTemplateValues(
namespace viewer {
-const std::string GetShowFeedbackFormJs() {
- base::StringValue question_val(
- l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_QUALITY_QUESTION));
- base::StringValue no_val(
- l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_QUALITY_ANSWER_NO));
- base::StringValue yes_val(
- l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_QUALITY_ANSWER_YES));
-
- std::string question;
- std::string yes;
- std::string no;
-
- base::JSONWriter::Write(question_val, &question);
- base::JSONWriter::Write(yes_val, &yes);
- base::JSONWriter::Write(no_val, &no);
-
- return "showFeedbackForm(" + question + ", " + yes + ", " + no + ");";
-}
-
const std::string GetUnsafeIncrementalDistilledPageJs(
const DistilledPageProto* page_proto,
const bool is_last_page) {
std::string output(page_proto->html());
EnsureNonEmptyContent(&output);
- base::StringValue value(output);
+ base::Value value(output);
base::JSONWriter::Write(value, &output);
std::string page_update("addToPage(");
page_update += output + ");";
@@ -187,28 +168,25 @@ const std::string GetErrorPageJs() {
IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_TITLE));
std::string page_update(GetSetTitleJs(title));
- base::StringValue value(l10n_util::GetStringUTF8(
+ base::Value value(l10n_util::GetStringUTF8(
IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_CONTENT));
std::string output;
base::JSONWriter::Write(value, &output);
page_update += "addToPage(" + output + ");";
page_update += GetSetTextDirectionJs(std::string("auto"));
page_update += GetToggleLoadingIndicatorJs(true);
- if (ShouldShowFeedbackForm()) {
- page_update += GetShowFeedbackFormJs();
- }
return page_update;
}
const std::string GetSetTitleJs(std::string title) {
- base::StringValue value(title);
+ base::Value value(title);
std::string output;
base::JSONWriter::Write(value, &output);
return "setTitle(" + output + ");";
}
const std::string GetSetTextDirectionJs(const std::string& direction) {
- base::StringValue value(direction);
+ base::Value value(direction);
std::string output;
base::JSONWriter::Write(value, &output);
return "setTextDirection(" + output + ");";
@@ -240,7 +218,7 @@ const std::string GetUnsafeArticleContentJs(
std::string output(unsafe_output_stream.str());
EnsureNonEmptyContent(&output);
- base::JSONWriter::Write(base::StringValue(output), &output);
+ base::JSONWriter::Write(base::Value(output), &output);
std::string page_update("addToPage(");
page_update += output + ");";
return page_update + GetToggleLoadingIndicatorJs(true);
diff --git a/chromium/components/dom_distiller/core/viewer.h b/chromium/components/dom_distiller/core/viewer.h
index 3f924da6b85..950c9dbabf6 100644
--- a/chromium/components/dom_distiller/core/viewer.h
+++ b/chromium/components/dom_distiller/core/viewer.h
@@ -23,9 +23,6 @@ class ViewRequestDelegate;
namespace viewer {
-// Returns the JavaScript to show the feedback footer for a distilled page.
-const std::string GetShowFeedbackFormJs();
-
// Returns an HTML template page based on the given |page_proto| which provides
// basic information about the page (i.e. title, text direction, etc.). This is
// supposed to be displayed to the end user. The returned HTML should be
diff --git a/chromium/components/dom_distiller/ios/distiller_page_ios.mm b/chromium/components/dom_distiller/ios/distiller_page_ios.mm
index 4773be550d6..1b19a6fde56 100644
--- a/chromium/components/dom_distiller/ios/distiller_page_ios.mm
+++ b/chromium/components/dom_distiller/ios/distiller_page_ios.mm
@@ -50,7 +50,7 @@ std::unique_ptr<base::Value> ValueResultFromScriptResult(id wk_result,
CFTypeID result_type = CFGetTypeID(wk_result);
if (result_type == CFStringGetTypeID()) {
- result.reset(new base::StringValue(base::SysNSStringToUTF16(wk_result)));
+ result.reset(new base::Value(base::SysNSStringToUTF16(wk_result)));
DCHECK(result->IsType(base::Value::Type::STRING));
} else if (result_type == CFNumberGetTypeID()) {
// Different implementation is here.
@@ -66,7 +66,7 @@ std::unique_ptr<base::Value> ValueResultFromScriptResult(id wk_result,
result.reset(new base::Value(static_cast<bool>([wk_result boolValue])));
DCHECK(result->IsType(base::Value::Type::BOOLEAN));
} else if (result_type == CFNullGetTypeID()) {
- result = base::Value::CreateNullValue();
+ result = base::MakeUnique<base::Value>();
DCHECK(result->IsType(base::Value::Type::NONE));
} else if (result_type == CFDictionaryGetTypeID()) {
std::unique_ptr<base::DictionaryValue> dictionary =
@@ -232,7 +232,7 @@ void DistillerPageIOS::OnLoadURLDone(
}
void DistillerPageIOS::HandleJavaScriptResult(id result) {
- std::unique_ptr<base::Value> resultValue = base::Value::CreateNullValue();
+ auto resultValue = base::MakeUnique<base::Value>();
if (result) {
resultValue = ValueResultFromScriptResult(result);
}
diff --git a/chromium/components/domain_reliability/OWNERS b/chromium/components/domain_reliability/OWNERS
index e6a2f014455..c6f3da30e81 100644
--- a/chromium/components/domain_reliability/OWNERS
+++ b/chromium/components/domain_reliability/OWNERS
@@ -4,3 +4,5 @@ juliatuttle@chromium.org
per-file quic_error_mapping*=rch@chromium.org
per-file quic_error_mapping*=zhongyi@chromium.org
+
+# COMPONENT: Internals>Network
diff --git a/chromium/components/domain_reliability/quic_error_mapping.cc b/chromium/components/domain_reliability/quic_error_mapping.cc
index 7a370264553..56d3c76591a 100644
--- a/chromium/components/domain_reliability/quic_error_mapping.cc
+++ b/chromium/components/domain_reliability/quic_error_mapping.cc
@@ -12,247 +12,244 @@ const struct QuicErrorMapping {
net::QuicErrorCode quic_error;
const char* beacon_quic_error;
} kQuicErrorMap[] = {
- // Connection has reached an invalid state.
- { net::QUIC_INTERNAL_ERROR, "quic.internal_error" },
- // There were data frames after the a fin or reset.
- { net::QUIC_STREAM_DATA_AFTER_TERMINATION,
- "quic.stream_data.after_termination" },
- // Control frame is malformed.
- { net::QUIC_INVALID_PACKET_HEADER, "quic.invalid.packet_header" },
- // Frame data is malformed.
- { net::QUIC_INVALID_FRAME_DATA, "quic.invalid_frame_data" },
- // The packet contained no payload.
- { net::QUIC_MISSING_PAYLOAD, "quic.missing.payload" },
- // FEC data is malformed.
- { net::QUIC_INVALID_FEC_DATA, "quic.invalid.fec_data" },
- // STREAM frame data is malformed.
- { net::QUIC_INVALID_STREAM_DATA, "quic.invalid.stream_data" },
- // STREAM frame data is not encrypted.
- { net::QUIC_UNENCRYPTED_STREAM_DATA, "quic.unencrypted.stream_data" },
- // Attempt to send unencrypted STREAM frame.
- { net::QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA,
- "quic.attempt.to.unencrypted.stream.data" },
- // Received a frame which is likely the result of memory corruption.
- { net::QUIC_MAYBE_CORRUPTED_MEMORY, "quic.maybe.corrupted.momery" },
- // FEC frame data is not encrypted.
- { net::QUIC_UNENCRYPTED_FEC_DATA, "quic.unencrypted.fec.data" },
- // RST_STREAM frame data is malformed.
- { net::QUIC_INVALID_RST_STREAM_DATA, "quic.invalid.rst_stream_data" },
- // CONNECTION_CLOSE frame data is malformed.
- { net::QUIC_INVALID_CONNECTION_CLOSE_DATA,
- "quic.invalid.connection_close_data" },
- // GOAWAY frame data is malformed.
- { net::QUIC_INVALID_GOAWAY_DATA, "quic.invalid.goaway_data" },
- // WINDOW_UPDATE frame data is malformed.
- { net::QUIC_INVALID_WINDOW_UPDATE_DATA, "quic.invalid.window_update_data" },
- // BLOCKED frame data is malformed.
- { net::QUIC_INVALID_BLOCKED_DATA, "quic.invalid.blocked_data" },
- // STOP_WAITING frame data is malformed.
- { net::QUIC_INVALID_STOP_WAITING_DATA, "quic.invalid.stop_waiting_data" },
- // PATH_CLOSE frame data is malformed.
- { net::QUIC_INVALID_PATH_CLOSE_DATA, "quic.invalid_path_close_data" },
- // ACK frame data is malformed.
- { net::QUIC_INVALID_ACK_DATA, "quic.invalid.ack_data" },
+ // Connection has reached an invalid state.
+ {net::QUIC_INTERNAL_ERROR, "quic.internal_error"},
+ // There were data frames after the a fin or reset.
+ {net::QUIC_STREAM_DATA_AFTER_TERMINATION,
+ "quic.stream_data.after_termination"},
+ // Control frame is malformed.
+ {net::QUIC_INVALID_PACKET_HEADER, "quic.invalid.packet_header"},
+ // Frame data is malformed.
+ {net::QUIC_INVALID_FRAME_DATA, "quic.invalid_frame_data"},
+ // The packet contained no payload.
+ {net::QUIC_MISSING_PAYLOAD, "quic.missing.payload"},
+ // FEC data is malformed.
+ {net::QUIC_INVALID_FEC_DATA, "quic.invalid.fec_data"},
+ // STREAM frame data is malformed.
+ {net::QUIC_INVALID_STREAM_DATA, "quic.invalid.stream_data"},
+ // STREAM frame data is not encrypted.
+ {net::QUIC_UNENCRYPTED_STREAM_DATA, "quic.unencrypted.stream_data"},
+ // Attempt to send unencrypted STREAM frame.
+ {net::QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA,
+ "quic.attempt.to.unencrypted.stream.data"},
+ // Received a frame which is likely the result of memory corruption.
+ {net::QUIC_MAYBE_CORRUPTED_MEMORY, "quic.maybe.corrupted.momery"},
+ // FEC frame data is not encrypted.
+ {net::QUIC_UNENCRYPTED_FEC_DATA, "quic.unencrypted.fec.data"},
+ // RST_STREAM frame data is malformed.
+ {net::QUIC_INVALID_RST_STREAM_DATA, "quic.invalid.rst_stream_data"},
+ // CONNECTION_CLOSE frame data is malformed.
+ {net::QUIC_INVALID_CONNECTION_CLOSE_DATA,
+ "quic.invalid.connection_close_data"},
+ // GOAWAY frame data is malformed.
+ {net::QUIC_INVALID_GOAWAY_DATA, "quic.invalid.goaway_data"},
+ // WINDOW_UPDATE frame data is malformed.
+ {net::QUIC_INVALID_WINDOW_UPDATE_DATA, "quic.invalid.window_update_data"},
+ // BLOCKED frame data is malformed.
+ {net::QUIC_INVALID_BLOCKED_DATA, "quic.invalid.blocked_data"},
+ // STOP_WAITING frame data is malformed.
+ {net::QUIC_INVALID_STOP_WAITING_DATA, "quic.invalid.stop_waiting_data"},
+ // PATH_CLOSE frame data is malformed.
+ {net::QUIC_INVALID_PATH_CLOSE_DATA, "quic.invalid_path_close_data"},
+ // ACK frame data is malformed.
+ {net::QUIC_INVALID_ACK_DATA, "quic.invalid.ack_data"},
- // Version negotiation packet is malformed.
- { net::QUIC_INVALID_VERSION_NEGOTIATION_PACKET,
- "quic_invalid_version_negotiation_packet" },
- // Public RST packet is malformed.
- { net::QUIC_INVALID_PUBLIC_RST_PACKET, "quic.invalid.public_rst_packet" },
+ // Version negotiation packet is malformed.
+ {net::QUIC_INVALID_VERSION_NEGOTIATION_PACKET,
+ "quic_invalid_version_negotiation_packet"},
+ // Public RST packet is malformed.
+ {net::QUIC_INVALID_PUBLIC_RST_PACKET, "quic.invalid.public_rst_packet"},
- // There was an error decrypting.
- { net::QUIC_DECRYPTION_FAILURE, "quic.decryption.failure" },
- // There was an error encrypting.
- { net::QUIC_ENCRYPTION_FAILURE, "quic.encryption.failure" },
- // The packet exceeded kMaxPacketSize.
- { net::QUIC_PACKET_TOO_LARGE, "quic.packet.too_large" },
- // The peer is going away. May be a client or server.
- { net::QUIC_PEER_GOING_AWAY, "quic.peer_going_away" },
- // A stream ID was invalid.
- { net::QUIC_INVALID_STREAM_ID, "quic.invalid_stream_id" },
- // A priority was invalid.
- { net::QUIC_INVALID_PRIORITY, "quic.invalid_priority" },
- // Too many streams already open.
- { net::QUIC_TOO_MANY_OPEN_STREAMS, "quic.too_many_open_streams" },
- // The peer created too many available streams.
- { net::QUIC_TOO_MANY_AVAILABLE_STREAMS, "quic.too_many_available_streams" },
- // Received public reset for this connection.
- { net::QUIC_PUBLIC_RESET, "quic.public_reset" },
- // Invalid protocol version.
- { net::QUIC_INVALID_VERSION, "quic.invalid_version" },
+ // There was an error decrypting.
+ {net::QUIC_DECRYPTION_FAILURE, "quic.decryption.failure"},
+ // There was an error encrypting.
+ {net::QUIC_ENCRYPTION_FAILURE, "quic.encryption.failure"},
+ // The packet exceeded kMaxPacketSize.
+ {net::QUIC_PACKET_TOO_LARGE, "quic.packet.too_large"},
+ // The peer is going away. May be a client or server.
+ {net::QUIC_PEER_GOING_AWAY, "quic.peer_going_away"},
+ // A stream ID was invalid.
+ {net::QUIC_INVALID_STREAM_ID, "quic.invalid_stream_id"},
+ // A priority was invalid.
+ {net::QUIC_INVALID_PRIORITY, "quic.invalid_priority"},
+ // Too many streams already open.
+ {net::QUIC_TOO_MANY_OPEN_STREAMS, "quic.too_many_open_streams"},
+ // The peer created too many available streams.
+ {net::QUIC_TOO_MANY_AVAILABLE_STREAMS, "quic.too_many_available_streams"},
+ // Received public reset for this connection.
+ {net::QUIC_PUBLIC_RESET, "quic.public_reset"},
+ // Invalid protocol version.
+ {net::QUIC_INVALID_VERSION, "quic.invalid_version"},
- // The Header ID for a stream was too far from the previous.
- { net::QUIC_INVALID_HEADER_ID, "quic.invalid_header_id" },
- // Negotiable parameter received during handshake had invalid value.
- { net::QUIC_INVALID_NEGOTIATED_VALUE, "quic.invalid_negotiated_value" },
- // There was an error decompressing data.
- { net::QUIC_DECOMPRESSION_FAILURE, "quic.decompression_failure" },
- // We hit our prenegotiated (or default) timeout
- { net::QUIC_NETWORK_IDLE_TIMEOUT, "quic.connection.idle_time_out" },
- // We hit our overall connection timeout
- { net::QUIC_HANDSHAKE_TIMEOUT,
- "quic.connection.handshake_timed_out" },
- // There was an error encountered migrating addresses.
- { net::QUIC_ERROR_MIGRATING_ADDRESS, "quic.error_migrating_address" },
- // There was an error encountered migrating port only.
- { net::QUIC_ERROR_MIGRATING_PORT, "quic.error_migrating_port" },
- // There was an error while writing to the socket.
- { net::QUIC_PACKET_WRITE_ERROR, "quic.packet.write_error" },
- // There was an error while reading from the socket.
- { net::QUIC_PACKET_READ_ERROR, "quic.packet.read_error" },
- // We received a STREAM_FRAME with no data and no fin flag set.
- { net::QUIC_EMPTY_STREAM_FRAME_NO_FIN, "quic.empty_stream_frame_no_fin" },
- // We received invalid data on the headers stream.
- { net::QUIC_INVALID_HEADERS_STREAM_DATA, "quic.invalid_headers_stream_data" },
- // The peer received too much data, violating flow control.
- { net::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
- "quic.flow_control.received_too_much_data" },
- // The peer sent too much data, violating flow control.
- { net::QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA,
- "quic.flow_control.sent_too_much_data" },
- // The peer received an invalid flow control window.
- { net::QUIC_FLOW_CONTROL_INVALID_WINDOW, "quic.flow_control.invalid_window" },
- // The connection has been IP pooled into an existing connection.
- { net::QUIC_CONNECTION_IP_POOLED, "quic.connection.ip_pooled" },
- // The connection has too many outstanding sent packets.
- { net::QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS,
- "quic.too_many_outstanding_sent_packets" },
- // The connection has too many outstanding received packets.
- { net::QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS,
- "quic.too_many_outstanding_received_packets" },
- // The quic connection job to load server config is cancelled.
- { net::QUIC_CONNECTION_CANCELLED, "quic.connection.cancelled" },
- // Disabled QUIC because of high packet loss rate.
- { net::QUIC_BAD_PACKET_LOSS_RATE, "quic.bad_packet_loss_rate" },
- // Disabled QUIC because of too many PUBLIC_RESETs post handshake.
- { net::QUIC_PUBLIC_RESETS_POST_HANDSHAKE,
- "quic.public_resets_post_handshake" },
- // Disabled QUIC because of too many timeouts with streams open.
- { net::QUIC_TIMEOUTS_WITH_OPEN_STREAMS, "quic.timeouts_with_open_streams" },
- // Closed because we failed to serialize a packet.
- { net::QUIC_FAILED_TO_SERIALIZE_PACKET, "quic.failed_to_serialize_packet" },
- // QUIC timed out after too many RTOs.
- { net::QUIC_TOO_MANY_RTOS, "quic.too_many_rtos" },
- // Crypto errors.
+ // The Header ID for a stream was too far from the previous.
+ {net::QUIC_INVALID_HEADER_ID, "quic.invalid_header_id"},
+ // Negotiable parameter received during handshake had invalid value.
+ {net::QUIC_INVALID_NEGOTIATED_VALUE, "quic.invalid_negotiated_value"},
+ // There was an error decompressing data.
+ {net::QUIC_DECOMPRESSION_FAILURE, "quic.decompression_failure"},
+ // We hit our prenegotiated (or default) timeout
+ {net::QUIC_NETWORK_IDLE_TIMEOUT, "quic.connection.idle_time_out"},
+ // We hit our overall connection timeout
+ {net::QUIC_HANDSHAKE_TIMEOUT, "quic.connection.handshake_timed_out"},
+ // There was an error encountered migrating addresses.
+ {net::QUIC_ERROR_MIGRATING_ADDRESS, "quic.error_migrating_address"},
+ // There was an error encountered migrating port only.
+ {net::QUIC_ERROR_MIGRATING_PORT, "quic.error_migrating_port"},
+ // There was an error while writing to the socket.
+ {net::QUIC_PACKET_WRITE_ERROR, "quic.packet.write_error"},
+ // There was an error while reading from the socket.
+ {net::QUIC_PACKET_READ_ERROR, "quic.packet.read_error"},
+ // We received a STREAM_FRAME with no data and no fin flag set.
+ {net::QUIC_EMPTY_STREAM_FRAME_NO_FIN, "quic.empty_stream_frame_no_fin"},
+ // We received invalid data on the headers stream.
+ {net::QUIC_INVALID_HEADERS_STREAM_DATA, "quic.invalid_headers_stream_data"},
+ // The peer received too much data, violating flow control.
+ {net::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
+ "quic.flow_control.received_too_much_data"},
+ // The peer sent too much data, violating flow control.
+ {net::QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA,
+ "quic.flow_control.sent_too_much_data"},
+ // The peer received an invalid flow control window.
+ {net::QUIC_FLOW_CONTROL_INVALID_WINDOW, "quic.flow_control.invalid_window"},
+ // The connection has been IP pooled into an existing connection.
+ {net::QUIC_CONNECTION_IP_POOLED, "quic.connection.ip_pooled"},
+ // The connection has too many outstanding sent packets.
+ {net::QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS,
+ "quic.too_many_outstanding_sent_packets"},
+ // The connection has too many outstanding received packets.
+ {net::QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS,
+ "quic.too_many_outstanding_received_packets"},
+ // The quic connection job to load server config is cancelled.
+ {net::QUIC_CONNECTION_CANCELLED, "quic.connection.cancelled"},
+ // Disabled QUIC because of high packet loss rate.
+ {net::QUIC_BAD_PACKET_LOSS_RATE, "quic.bad_packet_loss_rate"},
+ // Disabled QUIC because of too many PUBLIC_RESETs post handshake.
+ {net::QUIC_PUBLIC_RESETS_POST_HANDSHAKE,
+ "quic.public_resets_post_handshake"},
+ // Disabled QUIC because of too many timeouts with streams open.
+ {net::QUIC_TIMEOUTS_WITH_OPEN_STREAMS, "quic.timeouts_with_open_streams"},
+ // Closed because we failed to serialize a packet.
+ {net::QUIC_FAILED_TO_SERIALIZE_PACKET, "quic.failed_to_serialize_packet"},
+ // QUIC timed out after too many RTOs.
+ {net::QUIC_TOO_MANY_RTOS, "quic.too_many_rtos"},
+ // Crypto errors.
- // Hanshake failed.
- { net::QUIC_HANDSHAKE_FAILED, "quic.handshake_failed" },
- // Handshake message contained out of order tags.
- { net::QUIC_CRYPTO_TAGS_OUT_OF_ORDER, "quic.crypto.tags_out_of_order" },
- // Handshake message contained too many entries.
- { net::QUIC_CRYPTO_TOO_MANY_ENTRIES, "quic.crypto.too_many_entries" },
- // Handshake message contained an invalid value length.
- { net::QUIC_CRYPTO_INVALID_VALUE_LENGTH, "quic.crypto.invalid_value_length" },
- // A crypto message was received after the handshake was complete.
- { net::QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
- "quic.crypto_message_after_handshake_complete" },
- // A crypto message was received with an illegal message tag.
- { net::QUIC_INVALID_CRYPTO_MESSAGE_TYPE, "quic.invalid_crypto_message_type" },
- // A crypto message was received with an illegal parameter.
- { net::QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
- "quic.invalid_crypto_message_parameter" },
- // An invalid channel id signature was supplied.
- { net::QUIC_INVALID_CHANNEL_ID_SIGNATURE,
- "quic.invalid_channel_id_signature" },
- // A crypto message was received with a mandatory parameter missing.
- { net::QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
- "quic.crypto_message.parameter_not_found" },
- // A crypto message was received with a parameter that has no overlap
- // with the local parameter.
- { net::QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP,
- "quic.crypto_message.parameter_no_overlap" },
- // A crypto message was received that contained a parameter with too few
- // values.
- { net::QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND,
- "quic_crypto_message_index_not_found" },
- // A demand for an unsupport proof type was received.
- { net::QUIC_UNSUPPORTED_PROOF_DEMAND, "quic.unsupported_proof_demand" },
- // An internal error occured in crypto processing.
- { net::QUIC_CRYPTO_INTERNAL_ERROR, "quic.crypto.internal_error" },
- // A crypto handshake message specified an unsupported version.
- { net::QUIC_CRYPTO_VERSION_NOT_SUPPORTED,
- "quic.crypto.version_not_supported" },
- // A crypto handshake message resulted in a stateless reject.
- { net::QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT,
- "quic.crypto.handshake_stateless_reject" },
- // There was no intersection between the crypto primitives supported by the
- // peer and ourselves.
- { net::QUIC_CRYPTO_NO_SUPPORT, "quic.crypto.no_support" },
- // The server rejected our client hello messages too many times.
- { net::QUIC_CRYPTO_TOO_MANY_REJECTS, "quic.crypto.too_many_rejects" },
- // The client rejected the server's certificate chain or signature.
- { net::QUIC_PROOF_INVALID, "quic.proof_invalid" },
- // A crypto message was received with a duplicate tag.
- { net::QUIC_CRYPTO_DUPLICATE_TAG, "quic.crypto.duplicate_tag" },
- // A crypto message was received with the wrong encryption level (i.e. it
- // should have been encrypted but was not.)
- { net::QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
- "quic.crypto.encryption_level_incorrect" },
- // The server config for a server has expired.
- { net::QUIC_CRYPTO_SERVER_CONFIG_EXPIRED,
- "quic.crypto.server_config_expired" },
- // We failed to setup the symmetric keys for a connection.
- { net::QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
- "quic.crypto.symmetric_key_setup_failed" },
- // A handshake message arrived, but we are still validating the
- // previous handshake message.
- { net::QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO,
- "quic.crypto_message_while_validating_client_hello" },
- // A server config update arrived before the handshake is complete.
- { net::QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE,
- "quic.crypto.update_before_handshake_complete" },
- // CHLO cannot fit in one packet.
- { net::QUIC_CRYPTO_CHLO_TOO_LARGE,
- "quic.crypto.chlo_too_large" },
- // This connection involved a version negotiation which appears to have been
- // tampered with.
- { net::QUIC_VERSION_NEGOTIATION_MISMATCH,
- "quic.version_negotiation_mismatch" },
+ // Hanshake failed.
+ {net::QUIC_HANDSHAKE_FAILED, "quic.handshake_failed"},
+ // Handshake message contained out of order tags.
+ {net::QUIC_CRYPTO_TAGS_OUT_OF_ORDER, "quic.crypto.tags_out_of_order"},
+ // Handshake message contained too many entries.
+ {net::QUIC_CRYPTO_TOO_MANY_ENTRIES, "quic.crypto.too_many_entries"},
+ // Handshake message contained an invalid value length.
+ {net::QUIC_CRYPTO_INVALID_VALUE_LENGTH, "quic.crypto.invalid_value_length"},
+ // A crypto message was received after the handshake was complete.
+ {net::QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
+ "quic.crypto_message_after_handshake_complete"},
+ // A crypto message was received with an illegal message tag.
+ {net::QUIC_INVALID_CRYPTO_MESSAGE_TYPE, "quic.invalid_crypto_message_type"},
+ // A crypto message was received with an illegal parameter.
+ {net::QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
+ "quic.invalid_crypto_message_parameter"},
+ // An invalid channel id signature was supplied.
+ {net::QUIC_INVALID_CHANNEL_ID_SIGNATURE,
+ "quic.invalid_channel_id_signature"},
+ // A crypto message was received with a mandatory parameter missing.
+ {net::QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
+ "quic.crypto_message.parameter_not_found"},
+ // A crypto message was received with a parameter that has no overlap
+ // with the local parameter.
+ {net::QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP,
+ "quic.crypto_message.parameter_no_overlap"},
+ // A crypto message was received that contained a parameter with too few
+ // values.
+ {net::QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND,
+ "quic_crypto_message_index_not_found"},
+ // A demand for an unsupport proof type was received.
+ {net::QUIC_UNSUPPORTED_PROOF_DEMAND, "quic.unsupported_proof_demand"},
+ // An internal error occured in crypto processing.
+ {net::QUIC_CRYPTO_INTERNAL_ERROR, "quic.crypto.internal_error"},
+ // A crypto handshake message specified an unsupported version.
+ {net::QUIC_CRYPTO_VERSION_NOT_SUPPORTED,
+ "quic.crypto.version_not_supported"},
+ // A crypto handshake message resulted in a stateless reject.
+ {net::QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT,
+ "quic.crypto.handshake_stateless_reject"},
+ // There was no intersection between the crypto primitives supported by the
+ // peer and ourselves.
+ {net::QUIC_CRYPTO_NO_SUPPORT, "quic.crypto.no_support"},
+ // The server rejected our client hello messages too many times.
+ {net::QUIC_CRYPTO_TOO_MANY_REJECTS, "quic.crypto.too_many_rejects"},
+ // The client rejected the server's certificate chain or signature.
+ {net::QUIC_PROOF_INVALID, "quic.proof_invalid"},
+ // A crypto message was received with a duplicate tag.
+ {net::QUIC_CRYPTO_DUPLICATE_TAG, "quic.crypto.duplicate_tag"},
+ // A crypto message was received with the wrong encryption level (i.e. it
+ // should have been encrypted but was not.)
+ {net::QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
+ "quic.crypto.encryption_level_incorrect"},
+ // The server config for a server has expired.
+ {net::QUIC_CRYPTO_SERVER_CONFIG_EXPIRED,
+ "quic.crypto.server_config_expired"},
+ // We failed to setup the symmetric keys for a connection.
+ {net::QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
+ "quic.crypto.symmetric_key_setup_failed"},
+ // A handshake message arrived, but we are still validating the
+ // previous handshake message.
+ {net::QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO,
+ "quic.crypto_message_while_validating_client_hello"},
+ // A server config update arrived before the handshake is complete.
+ {net::QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE,
+ "quic.crypto.update_before_handshake_complete"},
+ // CHLO cannot fit in one packet.
+ {net::QUIC_CRYPTO_CHLO_TOO_LARGE, "quic.crypto.chlo_too_large"},
+ // This connection involved a version negotiation which appears to have been
+ // tampered with.
+ {net::QUIC_VERSION_NEGOTIATION_MISMATCH,
+ "quic.version_negotiation_mismatch"},
- // Multipath is not enabled, but a packet with multipath flag on is received.
- { net::QUIC_BAD_MULTIPATH_FLAG, "quic.bad_multipath_flag" },
- // A path is supposed to exist but does not.
- { net::QUIC_MULTIPATH_PATH_DOES_NOT_EXIST,
- "quic.quic_multipath_path_does_not_exist" },
- // A path is supposed to be active but is not.
- { net::QUIC_MULTIPATH_PATH_NOT_ACTIVE,
- "quic.quic_multipath_path_not_active" },
+ // Multipath is not enabled, but a packet with multipath flag on is
+ // received.
+ {net::QUIC_BAD_MULTIPATH_FLAG, "quic.bad_multipath_flag"},
+ // A path is supposed to exist but does not.
+ {net::QUIC_MULTIPATH_PATH_DOES_NOT_EXIST,
+ "quic.quic_multipath_path_does_not_exist"},
+ // A path is supposed to be active but is not.
+ {net::QUIC_MULTIPATH_PATH_NOT_ACTIVE,
+ "quic.quic_multipath_path_not_active"},
- // Network change and connection migration errors.
+ // Network change and connection migration errors.
- // IP address changed causing connection close.
- { net::QUIC_IP_ADDRESS_CHANGED, "quic.ip_address_changed" },
- // Network changed, but connection had no migratable streams.
- { net::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
- "quic.connection_migration_no_migratable_streams" },
- // Connection changed networks too many times.
- { net::QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES,
- "quic.connection_migration_too_many_changes" },
- // Connection migration was attempted, but there was no new network to
- // migrate to.
- { net::QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK,
- "quic.connection_migration_no_new_network" },
- // Network changed, but connection had one or more non-migratable streams.
- { net::QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM,
- "quic.connection_migration_non_migratable_stream" },
- // Stream frame overlaps with buffered data.
- { net::QUIC_OVERLAPPING_STREAM_DATA,
- "quic.overlapping_stream_data" },
- // Stream frames arrived too discontiguously so that stream sequencer buffer
- // has too many gaps.
- { net::QUIC_TOO_MANY_FRAME_GAPS,
- "quic.too_many_frame_gaps" },
- // Sequencer buffer get into weird state where continuing read/write
- // will lead to crash.
- { net::QUIC_STREAM_SEQUENCER_INVALID_STATE,
- "quic.stream_sequencer_invalid_state" },
- // Connection closed because of server hits max number of sessions allowed.
- { net::QUIC_TOO_MANY_SESSIONS_ON_SERVER,
- "quic.too_many_sessions_on_server" },
+ // IP address changed causing connection close.
+ {net::QUIC_IP_ADDRESS_CHANGED, "quic.ip_address_changed"},
+ // Network changed, but connection had no migratable streams.
+ {net::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
+ "quic.connection_migration_no_migratable_streams"},
+ // Connection changed networks too many times.
+ {net::QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES,
+ "quic.connection_migration_too_many_changes"},
+ // Connection migration was attempted, but there was no new network to
+ // migrate to.
+ {net::QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK,
+ "quic.connection_migration_no_new_network"},
+ // Network changed, but connection had one or more non-migratable streams.
+ {net::QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM,
+ "quic.connection_migration_non_migratable_stream"},
+ // Stream frame overlaps with buffered data.
+ {net::QUIC_OVERLAPPING_STREAM_DATA, "quic.overlapping_stream_data"},
+ // Stream frames arrived too discontiguously so that stream sequencer buffer
+ // has too many gaps.
+ {net::QUIC_TOO_MANY_FRAME_GAPS, "quic.too_many_frame_gaps"},
+ // Sequencer buffer get into weird state where continuing read/write
+ // will lead to crash.
+ {net::QUIC_STREAM_SEQUENCER_INVALID_STATE,
+ "quic.stream_sequencer_invalid_state"},
+ // Connection closed because of server hits max number of sessions allowed.
+ {net::QUIC_TOO_MANY_SESSIONS_ON_SERVER, "quic.too_many_sessions_on_server"},
+ // There was an error decompressing data.
+ {net::QUIC_DECOMPRESSION_FAILURE, "quic.decompression_failure"},
- // No error. Used as bound while iterating.
- { net::QUIC_LAST_ERROR, "quic.last_error"}
-};
+ // No error. Used as bound while iterating.
+ {net::QUIC_LAST_ERROR, "quic.last_error"}};
// Must be updated any time a net::QuicErrorCode is deprecated in
// net/quic/core/quic_packets.h.
diff --git a/chromium/components/doodle/BUILD.gn b/chromium/components/doodle/BUILD.gn
index 1eec0e37198..e53b617ee7c 100644
--- a/chromium/components/doodle/BUILD.gn
+++ b/chromium/components/doodle/BUILD.gn
@@ -11,12 +11,16 @@ static_library("doodle") {
"doodle_service.h",
"doodle_types.cc",
"doodle_types.h",
+ "pref_names.cc",
+ "pref_names.h",
]
deps = [
"//base",
"//components/data_use_measurement/core",
"//components/google/core/browser",
+ "//components/keyed_service/core",
+ "//components/prefs",
"//net",
]
}
@@ -26,11 +30,13 @@ source_set("unit_tests") {
sources = [
"doodle_fetcher_impl_unittest.cc",
"doodle_service_unittest.cc",
+ "doodle_types_unittest.cc",
]
deps = [
":doodle",
"//components/google/core/browser",
+ "//components/prefs:test_support",
"//net:test_support",
"//ui/base",
]
diff --git a/chromium/components/doodle/DEPS b/chromium/components/doodle/DEPS
index 3115564367a..b41c6c92580 100644
--- a/chromium/components/doodle/DEPS
+++ b/chromium/components/doodle/DEPS
@@ -1,7 +1,10 @@
include_rules = [
"+components/data_use_measurement/core",
"+components/google/core/browser",
+ "+components/keyed_service/core",
+ "+components/prefs",
"+net/base",
"+net/http/http_status_code.h",
+ "+net/traffic_annotation",
"+net/url_request",
]
diff --git a/chromium/components/doodle/doodle_fetcher.h b/chromium/components/doodle/doodle_fetcher.h
index f5ef780410c..e7a5d2636b9 100644
--- a/chromium/components/doodle/doodle_fetcher.h
+++ b/chromium/components/doodle/doodle_fetcher.h
@@ -9,6 +9,10 @@
#include "base/optional.h"
#include "components/doodle/doodle_types.h"
+namespace base {
+class TimeDelta;
+}
+
namespace doodle {
// Interface for fetching the current doodle from the network.
@@ -19,9 +23,11 @@ namespace doodle {
class DoodleFetcher {
public:
// Callback that is invoked when the fetching is done.
- // |doodle_config| will only contain a value if |state| is AVAILABLE.
+ // |time_to_live| will only be meaningful, and |doodle_config| will only
+ // contain a value, if |state| is AVAILABLE.
using FinishedCallback = base::OnceCallback<void(
DoodleState state,
+ base::TimeDelta time_to_live,
const base::Optional<DoodleConfig>& doodle_config)>;
virtual ~DoodleFetcher() = default;
diff --git a/chromium/components/doodle/doodle_fetcher_impl.cc b/chromium/components/doodle/doodle_fetcher_impl.cc
index f7954a411d0..b1c8188b88c 100644
--- a/chromium/components/doodle/doodle_fetcher_impl.cc
+++ b/chromium/components/doodle/doodle_fetcher_impl.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "base/values.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
@@ -14,6 +14,7 @@
#include "components/google/core/browser/google_util.h"
#include "net/base/load_flags.h"
#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h"
using net::URLFetcher;
@@ -22,9 +23,10 @@ namespace doodle {
namespace {
-const double kMaxTimeToLiveMS = 30.0 * 24 * 60 * 60 * 1000; // 30 days
-
-const char kDoodleConfigPath[] = "/async/ddljson";
+// "/async/ddljson" is the base API path. "ntp:1" identifies this request as
+// being for a New Tab page. The "graybg:" param specifies whether the doodle
+// will be displayed on a gray background.
+const char kDoodleConfigPathFormat[] = "/async/ddljson?async=ntp:1,graybg:%d";
std::string StripSafetyPreamble(const std::string& json) {
// The response may start with )]}'. Ignore this.
@@ -38,47 +40,31 @@ std::string StripSafetyPreamble(const std::string& json) {
return json_sp.as_string();
}
-DoodleType ParseDoodleType(const base::DictionaryValue& ddljson) {
- std::string type_str;
- ddljson.GetString("doodle_type", &type_str);
- if (type_str == "SIMPLE") {
- return DoodleType::SIMPLE;
- }
- if (type_str == "RANDOM") {
- return DoodleType::RANDOM;
- }
- if (type_str == "VIDEO") {
- return DoodleType::VIDEO;
- }
- if (type_str == "INTERACTIVE") {
- return DoodleType::INTERACTIVE;
- }
- if (type_str == "INLINE_INTERACTIVE") {
- return DoodleType::INLINE_INTERACTIVE;
- }
- if (type_str == "SLIDESHOW") {
- return DoodleType::SLIDESHOW;
+GURL BuildDoodleURL(const GURL& base_url,
+ bool gray_background,
+ const base::Optional<std::string>& override_url) {
+ std::string path =
+ base::StringPrintf(kDoodleConfigPathFormat, gray_background ? 1 : 0);
+ if (override_url.has_value()) {
+ // The override URL may or may not be relative to the base URL.
+ path = *override_url;
}
- return DoodleType::UNKNOWN;
+ return base_url.Resolve(path);
}
} // namespace
-DoodleImage::DoodleImage()
- : height(0), width(0), is_animated_gif(false), is_cta(false) {}
-DoodleImage::~DoodleImage() = default;
-
-DoodleConfig::DoodleConfig() : doodle_type(DoodleType::UNKNOWN) {}
-DoodleConfig::DoodleConfig(const DoodleConfig& config) = default;
-DoodleConfig::~DoodleConfig() = default;
-
DoodleFetcherImpl::DoodleFetcherImpl(
scoped_refptr<net::URLRequestContextGetter> download_context,
GoogleURLTracker* google_url_tracker,
- const ParseJSONCallback& json_parsing_callback)
+ const ParseJSONCallback& json_parsing_callback,
+ bool gray_background,
+ const base::Optional<std::string>& override_url)
: download_context_(download_context),
- json_parsing_callback_(json_parsing_callback),
google_url_tracker_(google_url_tracker),
+ json_parsing_callback_(json_parsing_callback),
+ gray_background_(gray_background),
+ override_url_(override_url),
weak_ptr_factory_(this) {
DCHECK(google_url_tracker_);
}
@@ -92,8 +78,30 @@ void DoodleFetcherImpl::FetchDoodle(FinishedCallback callback) {
}
DCHECK(!fetcher_.get());
callbacks_.push_back(std::move(callback));
- fetcher_ = URLFetcher::Create(GetGoogleBaseUrl().Resolve(kDoodleConfigPath),
- URLFetcher::GET, this);
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("doodle_fetcher", R"(
+ semantics {
+ sender: "Doodle Fetcher"
+ description:
+ "Retrieves metadata (image URL, clickthrough URL etc) for any "
+ "currently running Doodle."
+ trigger:
+ "Displaying the new tab page on Android."
+ data: "None."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "Choosing a non-Google search engine in Chromium settings under "
+ "'Search Engine' will disable this feature."
+ policy_exception_justification:
+ "Not implemented, considered not useful as it does not upload any "
+ "data."
+ })");
+ fetcher_ = URLFetcher::Create(
+ BuildDoodleURL(GetGoogleBaseUrl(), gray_background_, override_url_),
+ URLFetcher::GET, this, traffic_annotation);
fetcher_->SetRequestContext(download_context_.get());
fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
net::LOAD_DO_NOT_SAVE_COOKIES |
@@ -112,7 +120,8 @@ void DoodleFetcherImpl::OnURLFetchComplete(const URLFetcher* source) {
if (!(source->GetStatus().is_success() &&
source->GetResponseCode() == net::HTTP_OK &&
source->GetResponseAsString(&json_string))) {
- RespondToAllCallbacks(DoodleState::DOWNLOAD_ERROR, base::nullopt);
+ RespondToAllCallbacks(DoodleState::DOWNLOAD_ERROR, base::TimeDelta(),
+ base::nullopt);
return;
}
@@ -128,108 +137,61 @@ void DoodleFetcherImpl::OnJsonParsed(std::unique_ptr<base::Value> json) {
base::DictionaryValue::From(std::move(json));
if (!config.get()) {
DLOG(WARNING) << "Doodle JSON is not valid.";
- RespondToAllCallbacks(DoodleState::PARSING_ERROR, base::nullopt);
+ RespondToAllCallbacks(DoodleState::PARSING_ERROR, base::TimeDelta(),
+ base::nullopt);
return;
}
const base::DictionaryValue* ddljson = nullptr;
if (!config->GetDictionary("ddljson", &ddljson)) {
DLOG(WARNING) << "Doodle JSON response did not contain 'ddljson' key.";
- RespondToAllCallbacks(DoodleState::PARSING_ERROR, base::nullopt);
+ RespondToAllCallbacks(DoodleState::PARSING_ERROR, base::TimeDelta(),
+ base::nullopt);
return;
}
- base::Optional<DoodleConfig> doodle = ParseDoodle(*ddljson);
+ base::TimeDelta time_to_live;
+ base::Optional<DoodleConfig> doodle =
+ ParseDoodleConfigAndTimeToLive(*ddljson, &time_to_live);
if (!doodle.has_value()) {
- RespondToAllCallbacks(DoodleState::NO_DOODLE, base::nullopt);
+ RespondToAllCallbacks(DoodleState::NO_DOODLE, base::TimeDelta(),
+ base::nullopt);
return;
}
- RespondToAllCallbacks(DoodleState::AVAILABLE, std::move(doodle));
+ RespondToAllCallbacks(DoodleState::AVAILABLE, time_to_live,
+ std::move(doodle));
}
void DoodleFetcherImpl::OnJsonParseFailed(const std::string& error_message) {
DLOG(WARNING) << "JSON parsing failed: " << error_message;
- RespondToAllCallbacks(DoodleState::PARSING_ERROR, base::nullopt);
+ RespondToAllCallbacks(DoodleState::PARSING_ERROR, base::TimeDelta(),
+ base::nullopt);
}
-base::Optional<DoodleConfig> DoodleFetcherImpl::ParseDoodle(
- const base::DictionaryValue& ddljson) const {
- DoodleConfig doodle;
- // The |large_image| field is required (it's the "default" representation for
- // the doodle).
- if (!ParseImage(ddljson, "large_image", &doodle.large_image)) {
- return base::nullopt;
- }
- ParseImage(ddljson, "transparent_large_image",
- &doodle.transparent_large_image);
- ParseImage(ddljson, "large_cta_image", &doodle.large_cta_image);
- ParseBaseInformation(ddljson, &doodle);
- return doodle;
-}
-
-bool DoodleFetcherImpl::ParseImage(const base::DictionaryValue& image_parent,
- const std::string& image_name,
- DoodleImage* image) const {
- DCHECK(image);
- const base::DictionaryValue* image_dict = nullptr;
- if (!image_parent.GetDictionary(image_name, &image_dict)) {
- return false;
- }
- image->url = ParseRelativeUrl(*image_dict, "url");
- if (!image->url.is_valid()) {
- DLOG(WARNING) << "Image URL for \"" << image_name << "\" is invalid.";
- return false;
- }
- image_dict->GetInteger("height", &image->height);
- image_dict->GetInteger("width", &image->width);
- image_dict->GetBoolean("is_animated_gif", &image->is_animated_gif);
- image_dict->GetBoolean("is_cta", &image->is_cta);
- return true;
-}
-
-void DoodleFetcherImpl::ParseBaseInformation(
+base::Optional<DoodleConfig> DoodleFetcherImpl::ParseDoodleConfigAndTimeToLive(
const base::DictionaryValue& ddljson,
- DoodleConfig* config) const {
- config->search_url = ParseRelativeUrl(ddljson, "search_url");
- config->target_url = ParseRelativeUrl(ddljson, "target_url");
- config->fullpage_interactive_url =
- ParseRelativeUrl(ddljson, "fullpage_interactive_url");
-
- config->doodle_type = ParseDoodleType(ddljson);
- ddljson.GetString("alt_text", &config->alt_text);
- ddljson.GetString("interactive_html", &config->interactive_html);
+ base::TimeDelta* time_to_live) const {
+ base::Optional<DoodleConfig> doodle =
+ DoodleConfig::FromDictionary(ddljson, GetGoogleBaseUrl());
// The JSON doesn't guarantee the number to fit into an int.
- double ttl = 0; // Expires immediately if the parameter is missing.
- if (!ddljson.GetDouble("time_to_live_ms", &ttl) || ttl < 0) {
+ double ttl_ms = 0; // Expires immediately if the parameter is missing.
+ if (!ddljson.GetDouble("time_to_live_ms", &ttl_ms) || ttl_ms < 0) {
DLOG(WARNING) << "No valid Doodle TTL present in ddljson!";
- ttl = 0;
- }
- // TODO(treib,fhorschig): Move this logic into the service.
- if (ttl > kMaxTimeToLiveMS) {
- ttl = kMaxTimeToLiveMS;
- DLOG(WARNING) << "Clamping Doodle TTL to 30 days!";
+ ttl_ms = 0;
}
- config->time_to_live = base::TimeDelta::FromMillisecondsD(ttl);
-}
+ *time_to_live = base::TimeDelta::FromMillisecondsD(ttl_ms);
-GURL DoodleFetcherImpl::ParseRelativeUrl(
- const base::DictionaryValue& dict_value,
- const std::string& key) const {
- std::string str_url;
- dict_value.GetString(key, &str_url);
- if (str_url.empty()) {
- return GURL();
- }
- return GetGoogleBaseUrl().Resolve(str_url);
+ return doodle;
}
void DoodleFetcherImpl::RespondToAllCallbacks(
DoodleState state,
+ base::TimeDelta time_to_live,
const base::Optional<DoodleConfig>& config) {
for (auto& callback : callbacks_) {
- std::move(callback).Run(state, config);
+ std::move(callback).Run(state, time_to_live, config);
}
callbacks_.clear();
}
diff --git a/chromium/components/doodle/doodle_fetcher_impl.h b/chromium/components/doodle/doodle_fetcher_impl.h
index 3f3eb19aeaa..07f4f0129eb 100644
--- a/chromium/components/doodle/doodle_fetcher_impl.h
+++ b/chromium/components/doodle/doodle_fetcher_impl.h
@@ -25,6 +25,7 @@ class GoogleURLTracker;
namespace base {
class DictionaryValue;
+class TimeDelta;
class Value;
}
@@ -44,7 +45,9 @@ class DoodleFetcherImpl : public DoodleFetcher, public net::URLFetcherDelegate {
DoodleFetcherImpl(
scoped_refptr<net::URLRequestContextGetter> download_context,
GoogleURLTracker* google_url_tracker,
- const ParseJSONCallback& json_parsing_callback);
+ const ParseJSONCallback& json_parsing_callback,
+ bool gray_background,
+ const base::Optional<std::string>& override_url);
~DoodleFetcherImpl() override;
// Fetches a doodle asynchronously. The |callback| is called with a
@@ -62,18 +65,14 @@ class DoodleFetcherImpl : public DoodleFetcher, public net::URLFetcherDelegate {
// ParseJSONCallback Failure callback
void OnJsonParseFailed(const std::string& error_message);
- base::Optional<DoodleConfig> ParseDoodle(
- const base::DictionaryValue& ddljson) const;
- bool ParseImage(const base::DictionaryValue& image_dict,
- const std::string& image_name,
- DoodleImage* image) const;
- void ParseBaseInformation(const base::DictionaryValue& ddljson,
- DoodleConfig* config) const;
- GURL ParseRelativeUrl(const base::DictionaryValue& dict_value,
- const std::string& key) const;
+ base::Optional<DoodleConfig> ParseDoodleConfigAndTimeToLive(
+ const base::DictionaryValue& ddljson,
+ base::TimeDelta* time_to_live) const;
void RespondToAllCallbacks(DoodleState state,
+ base::TimeDelta time_to_live,
const base::Optional<DoodleConfig>& config);
+
GURL GetGoogleBaseUrl() const;
// Returns whether a fetch is still in progress. A fetch begins when a
@@ -82,8 +81,10 @@ class DoodleFetcherImpl : public DoodleFetcher, public net::URLFetcherDelegate {
// Parameters set from constructor.
scoped_refptr<net::URLRequestContextGetter> const download_context_;
- ParseJSONCallback json_parsing_callback_;
GoogleURLTracker* google_url_tracker_;
+ ParseJSONCallback json_parsing_callback_;
+ const bool gray_background_;
+ const base::Optional<std::string> override_url_;
std::vector<FinishedCallback> callbacks_;
std::unique_ptr<net::URLFetcher> fetcher_;
diff --git a/chromium/components/doodle/doodle_fetcher_impl_unittest.cc b/chromium/components/doodle/doodle_fetcher_impl_unittest.cc
index 785936d596f..8bdb1fb126c 100644
--- a/chromium/components/doodle/doodle_fetcher_impl_unittest.cc
+++ b/chromium/components/doodle/doodle_fetcher_impl_unittest.cc
@@ -4,6 +4,7 @@
#include "components/doodle/doodle_fetcher_impl.h"
+#include <memory>
#include <string>
#include <utility>
@@ -12,6 +13,8 @@
#include "base/json/json_reader.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
+#include "base/test/mock_callback.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "components/google/core/browser/google_switches.h"
#include "components/google/core/browser/google_url_tracker.h"
@@ -22,13 +25,17 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using testing::_;
+using testing::DoAll;
using testing::Eq;
+using testing::SaveArg;
namespace doodle {
namespace {
-const char kDoodleConfigPath[] = "/async/ddljson";
+const char kDoodleConfigPath[] = "/async/ddljson?async=ntp:1,graybg:1";
+const char kDoodleConfigPathNoGrayBg[] = "/async/ddljson?async=ntp:1,graybg:0";
// Required to instantiate a GoogleUrlTracker in UNIT_TEST_MODE.
class GoogleURLTrackerClientStub : public GoogleURLTrackerClient {
@@ -46,12 +53,6 @@ class GoogleURLTrackerClientStub : public GoogleURLTrackerClient {
DISALLOW_COPY_AND_ASSIGN(GoogleURLTrackerClientStub);
};
-std::string Resolve(const std::string& relative_url) {
- return GURL(GoogleURLTracker::kDefaultGoogleHomepage)
- .Resolve(relative_url)
- .spec();
-}
-
void ParseJson(
const std::string& json,
const base::Callback<void(std::unique_ptr<base::Value> json)>& success,
@@ -67,23 +68,21 @@ void ParseJson(
} // namespace
-class DoodleFetcherImplTest : public testing::Test {
+class DoodleFetcherImplTestBase : public testing::Test {
public:
- DoodleFetcherImplTest()
- : url_(GURL(GoogleURLTracker::kDefaultGoogleHomepage)),
- google_url_tracker_(base::MakeUnique<GoogleURLTrackerClientStub>(),
+ DoodleFetcherImplTestBase(bool gray_background,
+ const base::Optional<std::string>& override_url)
+ : google_url_tracker_(base::MakeUnique<GoogleURLTrackerClientStub>(),
GoogleURLTracker::UNIT_TEST_MODE),
doodle_fetcher_(
new net::TestURLRequestContextGetter(message_loop_.task_runner()),
&google_url_tracker_,
- base::Bind(ParseJson)) {}
+ base::Bind(ParseJson),
+ gray_background,
+ override_url) {}
void RespondWithData(const std::string& data) {
- RespondToFetcherWithData(GetRunningFetcher(), data);
- }
-
- void RespondToFetcherWithData(net::TestURLFetcher* url_fetcher,
- const std::string& data) {
+ net::TestURLFetcher* url_fetcher = GetRunningFetcher();
url_fetcher->set_status(net::URLRequestStatus());
url_fetcher->set_response_code(net::HTTP_OK);
url_fetcher->SetResponseString(data);
@@ -106,40 +105,36 @@ class DoodleFetcherImplTest : public testing::Test {
return url_fetcher;
}
- DoodleFetcherImpl::FinishedCallback CreateResponseSavingCallback(
- DoodleState* state_out,
- base::Optional<DoodleConfig>* config_out) {
- return base::BindOnce(
- [](DoodleState* state_out, base::Optional<DoodleConfig>* config_out,
- DoodleState state, const base::Optional<DoodleConfig>& config) {
- if (state_out) {
- *state_out = state;
- }
- if (config_out) {
- *config_out = config;
- }
- },
- state_out, config_out);
- }
-
DoodleFetcherImpl* doodle_fetcher() { return &doodle_fetcher_; }
GURL GetGoogleBaseURL() { return google_url_tracker_.google_url(); }
+ GURL Resolve(const std::string& relative_url) {
+ return GetGoogleBaseURL().Resolve(relative_url);
+ }
+
private:
base::MessageLoop message_loop_;
- GURL url_;
net::TestURLFetcherFactory url_fetcher_factory_;
GoogleURLTracker google_url_tracker_;
DoodleFetcherImpl doodle_fetcher_;
};
+class DoodleFetcherImplTest : public DoodleFetcherImplTestBase {
+ public:
+ DoodleFetcherImplTest()
+ : DoodleFetcherImplTestBase(/*gray_background=*/true,
+ /*override_url=*/base::nullopt) {}
+};
+
TEST_F(DoodleFetcherImplTest, ReturnsFromFetchWithoutError) {
- DoodleState state(DoodleState::NO_DOODLE);
- base::Optional<DoodleConfig> response;
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(&state, &response));
+ DoodleState state = DoodleState::NO_DOODLE;
+ base::Optional<DoodleConfig> response;
+ EXPECT_CALL(callback, Run(_, _, _))
+ .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<2>(&response)));
RespondWithData(R"json({"ddljson": {
"time_to_live_ms":55000,
"large_image": {"url":"/logos/doodles/2015/some.gif"}
@@ -150,11 +145,13 @@ TEST_F(DoodleFetcherImplTest, ReturnsFromFetchWithoutError) {
}
TEST_F(DoodleFetcherImplTest, ReturnsFrom404FetchWithError) {
- DoodleState state(DoodleState::NO_DOODLE);
- base::Optional<DoodleConfig> response;
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(&state, &response));
+ DoodleState state = DoodleState::NO_DOODLE;
+ base::Optional<DoodleConfig> response;
+ EXPECT_CALL(callback, Run(_, _, _))
+ .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<2>(&response)));
RespondWithError(net::ERR_FILE_NOT_FOUND);
EXPECT_THAT(state, Eq(DoodleState::DOWNLOAD_ERROR));
@@ -162,11 +159,13 @@ TEST_F(DoodleFetcherImplTest, ReturnsFrom404FetchWithError) {
}
TEST_F(DoodleFetcherImplTest, ReturnsErrorForInvalidJson) {
- DoodleState state(DoodleState::NO_DOODLE);
- base::Optional<DoodleConfig> response;
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(&state, &response));
+ DoodleState state = DoodleState::NO_DOODLE;
+ base::Optional<DoodleConfig> response;
+ EXPECT_CALL(callback, Run(_, _, _))
+ .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<2>(&response)));
RespondWithData("}");
EXPECT_THAT(state, Eq(DoodleState::PARSING_ERROR));
@@ -174,11 +173,13 @@ TEST_F(DoodleFetcherImplTest, ReturnsErrorForInvalidJson) {
}
TEST_F(DoodleFetcherImplTest, ReturnsErrorForIncompleteJson) {
- DoodleState state(DoodleState::NO_DOODLE);
- base::Optional<DoodleConfig> response;
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(&state, &response));
+ DoodleState state = DoodleState::NO_DOODLE;
+ base::Optional<DoodleConfig> response;
+ EXPECT_CALL(callback, Run(_, _, _))
+ .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<2>(&response)));
RespondWithData("{}");
EXPECT_THAT(state, Eq(DoodleState::PARSING_ERROR));
@@ -186,17 +187,20 @@ TEST_F(DoodleFetcherImplTest, ReturnsErrorForIncompleteJson) {
}
TEST_F(DoodleFetcherImplTest, ResponseContainsValidBaseInformation) {
- DoodleState state(DoodleState::NO_DOODLE);
- base::Optional<DoodleConfig> response;
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(&state, &response));
+ DoodleState state = DoodleState::NO_DOODLE;
+ base::TimeDelta time_to_live;
+ base::Optional<DoodleConfig> response;
+ EXPECT_CALL(callback, Run(_, _, _))
+ .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<1>(&time_to_live),
+ SaveArg<2>(&response)));
RespondWithData(R"json()]}'{
"ddljson": {
"alt_text":"Mouseover Text",
"doodle_type":"SIMPLE",
"interactive_html":"\u003cstyle\u003e\u003c\/style\u003e",
- "search_url":"/search?q\u003dtest",
"target_url":"/search?q\u003dtest\u0026sa\u003dX\u0026ved\u003d0ahUKEw",
"time_to_live_ms":55000,
"large_image": {
@@ -208,9 +212,6 @@ TEST_F(DoodleFetcherImplTest, ResponseContainsValidBaseInformation) {
ASSERT_TRUE(response.has_value());
DoodleConfig config = response.value();
- EXPECT_TRUE(config.search_url.is_valid());
- EXPECT_THAT(config.search_url, Eq(Resolve("/search?q\u003dtest")));
- EXPECT_TRUE(config.fullpage_interactive_url.is_empty());
EXPECT_TRUE(config.target_url.is_valid());
EXPECT_THAT(config.target_url,
Eq(Resolve("/search?q\u003dtest\u0026sa\u003dX\u0026ved\u003d"
@@ -220,67 +221,59 @@ TEST_F(DoodleFetcherImplTest, ResponseContainsValidBaseInformation) {
EXPECT_THAT(config.interactive_html,
Eq("\u003cstyle\u003e\u003c/style\u003e"));
- EXPECT_THAT(config.time_to_live,
- Eq(base::TimeDelta::FromMilliseconds(55000)));
-}
-
-TEST_F(DoodleFetcherImplTest, DoodleExpiresWithinThirtyDaysForTooLargeTTL) {
- DoodleState state(DoodleState::NO_DOODLE);
- base::Optional<DoodleConfig> response;
-
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(&state, &response));
- RespondWithData(R"json({"ddljson": {
- "time_to_live_ms":5184000000,
- "large_image": {"url":"/logos/doodles/2015/some.gif"}
- }})json"); // 60 days
+ EXPECT_FALSE(config.large_cta_image.has_value());
+ EXPECT_FALSE(config.transparent_large_image.has_value());
- EXPECT_THAT(state, Eq(DoodleState::AVAILABLE));
- ASSERT_TRUE(response.has_value());
- EXPECT_THAT(response.value().time_to_live,
- Eq(base::TimeDelta::FromMilliseconds(30ul * 24 * 60 * 60 *
- 1000))); // 30 days
+ EXPECT_THAT(time_to_live, Eq(base::TimeDelta::FromMilliseconds(55000)));
}
TEST_F(DoodleFetcherImplTest, DoodleExpiresImmediatelyWithNegativeTTL) {
- DoodleState state(DoodleState::NO_DOODLE);
- base::Optional<DoodleConfig> response;
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(&state, &response));
+ DoodleState state = DoodleState::NO_DOODLE;
+ base::TimeDelta time_to_live;
+ base::Optional<DoodleConfig> response;
+ EXPECT_CALL(callback, Run(_, _, _))
+ .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<1>(&time_to_live),
+ SaveArg<2>(&response)));
RespondWithData(R"json({"ddljson": {
"time_to_live_ms":-1,
"large_image": {"url":"/logos/doodles/2015/some.gif"}
}})json");
EXPECT_THAT(state, Eq(DoodleState::AVAILABLE));
- ASSERT_TRUE(response.has_value());
- EXPECT_THAT(response.value().time_to_live,
- Eq(base::TimeDelta::FromMilliseconds(0)));
+ EXPECT_TRUE(response.has_value());
+ EXPECT_THAT(time_to_live, Eq(base::TimeDelta::FromMilliseconds(0)));
}
TEST_F(DoodleFetcherImplTest, DoodleExpiresImmediatelyWithoutValidTTL) {
- DoodleState state(DoodleState::NO_DOODLE);
- base::Optional<DoodleConfig> response;
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(&state, &response));
+ DoodleState state = DoodleState::NO_DOODLE;
+ base::TimeDelta time_to_live;
+ base::Optional<DoodleConfig> response;
+ EXPECT_CALL(callback, Run(_, _, _))
+ .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<1>(&time_to_live),
+ SaveArg<2>(&response)));
RespondWithData(R"json({"ddljson": {
"large_image": {"url":"/logos/doodles/2015/some.gif"}
}})json");
EXPECT_THAT(state, Eq(DoodleState::AVAILABLE));
- ASSERT_TRUE(response.has_value());
- EXPECT_THAT(response.value().time_to_live,
- Eq(base::TimeDelta::FromMilliseconds(0)));
+ EXPECT_TRUE(response.has_value());
+ EXPECT_THAT(time_to_live, Eq(base::TimeDelta::FromMilliseconds(0)));
}
TEST_F(DoodleFetcherImplTest, ReturnsNoDoodleForMissingLargeImageUrl) {
- DoodleState state(DoodleState::AVAILABLE);
- base::Optional<DoodleConfig> response;
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(&state, &response));
+ DoodleState state = DoodleState::AVAILABLE;
+ base::Optional<DoodleConfig> response;
+ EXPECT_CALL(callback, Run(_, _, _))
+ .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<2>(&response)));
RespondWithData(R"json({"ddljson": {
"time_to_live_ms":55000,
"large_image": {}
@@ -291,11 +284,13 @@ TEST_F(DoodleFetcherImplTest, ReturnsNoDoodleForMissingLargeImageUrl) {
}
TEST_F(DoodleFetcherImplTest, EmptyResponsesCausesNoDoodleState) {
- DoodleState state(DoodleState::AVAILABLE);
- base::Optional<DoodleConfig> response;
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(&state, &response));
+ DoodleState state = DoodleState::AVAILABLE;
+ base::Optional<DoodleConfig> response;
+ EXPECT_CALL(callback, Run(_, _, _))
+ .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<2>(&response)));
RespondWithData("{\"ddljson\":{}}");
EXPECT_THAT(state, Eq(DoodleState::NO_DOODLE));
@@ -303,11 +298,13 @@ TEST_F(DoodleFetcherImplTest, EmptyResponsesCausesNoDoodleState) {
}
TEST_F(DoodleFetcherImplTest, ResponseContainsExactlyTheSampleImages) {
- DoodleState state(DoodleState::NO_DOODLE);
- base::Optional<DoodleConfig> response;
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(&state, &response));
+ DoodleState state = DoodleState::NO_DOODLE;
+ base::Optional<DoodleConfig> response;
+ EXPECT_CALL(callback, Run(_, _, _))
+ .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<2>(&response)));
RespondWithData(R"json()]}'{
"ddljson": {
"time_to_live_ms":55000,
@@ -338,17 +335,8 @@ TEST_F(DoodleFetcherImplTest, ResponseContainsExactlyTheSampleImages) {
ASSERT_TRUE(response.has_value());
DoodleConfig config = response.value();
- EXPECT_TRUE(config.transparent_large_image.url.is_valid());
- EXPECT_THAT(config.transparent_large_image.url.spec(),
- Eq(Resolve("/logos/doodles/2015/new-years-eve-2015-5985438795"
- "8251-thp.png")));
- EXPECT_THAT(config.transparent_large_image.width, Eq(510));
- EXPECT_THAT(config.transparent_large_image.height, Eq(225));
- EXPECT_FALSE(config.transparent_large_image.is_animated_gif);
- EXPECT_FALSE(config.transparent_large_image.is_cta);
-
EXPECT_TRUE(config.large_image.url.is_valid());
- EXPECT_THAT(config.large_image.url.spec(),
+ EXPECT_THAT(config.large_image.url,
Eq(Resolve("/logos/doodles/2015/new-years-eve-2015-5985438795"
"8251-hp.gif")));
EXPECT_THAT(config.large_image.width, Eq(489));
@@ -356,33 +344,50 @@ TEST_F(DoodleFetcherImplTest, ResponseContainsExactlyTheSampleImages) {
EXPECT_TRUE(config.large_image.is_animated_gif);
EXPECT_FALSE(config.large_image.is_cta);
- EXPECT_TRUE(config.large_cta_image.url.is_valid());
- EXPECT_THAT(config.large_cta_image.url.spec(),
+ ASSERT_TRUE(config.transparent_large_image.has_value());
+ EXPECT_TRUE(config.transparent_large_image->url.is_valid());
+ EXPECT_THAT(config.transparent_large_image->url,
+ Eq(Resolve("/logos/doodles/2015/new-years-eve-2015-5985438795"
+ "8251-thp.png")));
+ EXPECT_THAT(config.transparent_large_image->width, Eq(510));
+ EXPECT_THAT(config.transparent_large_image->height, Eq(225));
+ EXPECT_FALSE(config.transparent_large_image->is_animated_gif);
+ EXPECT_FALSE(config.transparent_large_image->is_cta);
+
+ ASSERT_TRUE(config.large_cta_image.has_value());
+ EXPECT_TRUE(config.large_cta_image->url.is_valid());
+ EXPECT_THAT(config.large_cta_image->url,
Eq(Resolve("/logos/doodles/2015/new-years-eve-2015-5985438795"
"8251-cta.gif")));
- EXPECT_THAT(config.large_cta_image.width, Eq(489));
- EXPECT_THAT(config.large_cta_image.height, Eq(225));
- EXPECT_TRUE(config.large_cta_image.is_animated_gif);
- EXPECT_TRUE(config.large_cta_image.is_cta);
+ EXPECT_THAT(config.large_cta_image->width, Eq(489));
+ EXPECT_THAT(config.large_cta_image->height, Eq(225));
+ EXPECT_TRUE(config.large_cta_image->is_animated_gif);
+ EXPECT_TRUE(config.large_cta_image->is_cta);
}
TEST_F(DoodleFetcherImplTest, RespondsToMultipleRequestsWithSameFetcher) {
- DoodleState state1(DoodleState::NO_DOODLE);
- DoodleState state2(DoodleState::NO_DOODLE);
- base::Optional<DoodleConfig> response1;
- base::Optional<DoodleConfig> response2;
-
// Trigger two requests.
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(&state1, &response1));
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback1;
+ doodle_fetcher()->FetchDoodle(callback1.Get());
net::URLFetcher* first_created_fetcher = GetRunningFetcher();
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(&state2, &response2));
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback2;
+ doodle_fetcher()->FetchDoodle(callback2.Get());
net::URLFetcher* second_created_fetcher = GetRunningFetcher();
// Expect that only one fetcher handles both requests.
EXPECT_THAT(first_created_fetcher, Eq(second_created_fetcher));
+ // But both callbacks should get called.
+ DoodleState state1 = DoodleState::NO_DOODLE;
+ DoodleState state2 = DoodleState::NO_DOODLE;
+ base::Optional<DoodleConfig> response1;
+ base::Optional<DoodleConfig> response2;
+
+ EXPECT_CALL(callback1, Run(_, _, _))
+ .WillOnce(DoAll(SaveArg<0>(&state1), SaveArg<2>(&response1)));
+ EXPECT_CALL(callback2, Run(_, _, _))
+ .WillOnce(DoAll(SaveArg<0>(&state2), SaveArg<2>(&response2)));
+
RespondWithData(R"json({"ddljson": {
"time_to_live_ms":55000,
"large_image": {"url":"/logos/doodles/2015/some.gif"}
@@ -396,22 +401,72 @@ TEST_F(DoodleFetcherImplTest, RespondsToMultipleRequestsWithSameFetcher) {
}
TEST_F(DoodleFetcherImplTest, ReceivesBaseUrlFromTracker) {
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(/*state=*/nullptr, /*response=*/nullptr));
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
+ // TODO(treib,fhorschig): This doesn't really test anything useful, since the
+ // Google base URL is the default anyway. Find a way to set the base URL in
+ // the tracker.
EXPECT_THAT(GetRunningFetcher()->GetOriginalURL(),
- Eq(GetGoogleBaseURL().Resolve(kDoodleConfigPath)));
+ Eq(Resolve(kDoodleConfigPath)));
}
TEST_F(DoodleFetcherImplTest, OverridesBaseUrlWithCommandLineArgument) {
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kGoogleBaseURL, "http://www.google.kz");
- doodle_fetcher()->FetchDoodle(
- CreateResponseSavingCallback(/*state=*/nullptr, /*response=*/nullptr));
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
EXPECT_THAT(GetRunningFetcher()->GetOriginalURL(),
Eq(GURL("http://www.google.kz").Resolve(kDoodleConfigPath)));
}
+class DoodleFetcherImplNoGrayBgTest : public DoodleFetcherImplTestBase {
+ public:
+ DoodleFetcherImplNoGrayBgTest()
+ : DoodleFetcherImplTestBase(/*gray_background=*/false,
+ /*override_url=*/base::nullopt) {}
+};
+
+TEST_F(DoodleFetcherImplNoGrayBgTest, PassesNoGrayBgParam) {
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
+
+ EXPECT_THAT(GetRunningFetcher()->GetOriginalURL(),
+ Eq(Resolve(kDoodleConfigPathNoGrayBg)));
+}
+
+class DoodleFetcherImplRelativeOverrideUrlTest
+ : public DoodleFetcherImplTestBase {
+ public:
+ DoodleFetcherImplRelativeOverrideUrlTest()
+ : DoodleFetcherImplTestBase(/*gray_background=*/false,
+ /*override_url=*/std::string("/different")) {}
+};
+
+TEST_F(DoodleFetcherImplRelativeOverrideUrlTest, OverridesWithRelativeUrl) {
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
+
+ EXPECT_THAT(GetRunningFetcher()->GetOriginalURL(), Eq(Resolve("/different")));
+}
+
+class DoodleFetcherImplAbsoluteOverrideUrlTest
+ : public DoodleFetcherImplTestBase {
+ public:
+ DoodleFetcherImplAbsoluteOverrideUrlTest()
+ : DoodleFetcherImplTestBase(
+ /*gray_background=*/false,
+ /*override_url=*/std::string("http://host.com/ddl")) {}
+};
+
+TEST_F(DoodleFetcherImplAbsoluteOverrideUrlTest, OverridesWithAbsoluteUrl) {
+ base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
+ doodle_fetcher()->FetchDoodle(callback.Get());
+
+ EXPECT_THAT(GetRunningFetcher()->GetOriginalURL(),
+ Eq(GURL("http://host.com/ddl")));
+}
+
} // namespace doodle
diff --git a/chromium/components/doodle/doodle_service.cc b/chromium/components/doodle/doodle_service.cc
index fee586c6be9..cd4b053edf1 100644
--- a/chromium/components/doodle/doodle_service.cc
+++ b/chromium/components/doodle/doodle_service.cc
@@ -7,16 +7,71 @@
#include <utility>
#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/values.h"
+#include "components/doodle/pref_names.h"
+#include "components/prefs/pref_registry.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
namespace doodle {
-DoodleService::DoodleService(std::unique_ptr<DoodleFetcher> fetcher)
- : fetcher_(std::move(fetcher)) {
+namespace {
+
+// The maximum time-to-live we'll accept; any larger values will be clamped to
+// this one. This is a last resort in case the server sends bad data.
+const int64_t kMaxTimeToLiveSecs = 30 * 24 * 60 * 60; // 30 days
+
+// The default value for DoodleService::min_refresh_interval_.
+const int64_t kDefaultMinRefreshIntervalSecs = 15 * 60; // 15 minutes
+
+} // namespace
+
+// static
+void DoodleService::RegisterProfilePrefs(PrefRegistrySimple* pref_registry) {
+ pref_registry->RegisterDictionaryPref(
+ prefs::kCachedConfig, base::MakeUnique<base::DictionaryValue>(),
+ PrefRegistry::LOSSY_PREF);
+ pref_registry->RegisterInt64Pref(prefs::kCachedConfigExpiry, 0,
+ PrefRegistry::LOSSY_PREF);
+}
+
+DoodleService::DoodleService(
+ PrefService* pref_service,
+ std::unique_ptr<DoodleFetcher> fetcher,
+ std::unique_ptr<base::OneShotTimer> expiry_timer,
+ std::unique_ptr<base::Clock> clock,
+ std::unique_ptr<base::TickClock> tick_clock,
+ base::Optional<base::TimeDelta> override_min_refresh_interval)
+ : pref_service_(pref_service),
+ fetcher_(std::move(fetcher)),
+ expiry_timer_(std::move(expiry_timer)),
+ clock_(std::move(clock)),
+ tick_clock_(std::move(tick_clock)),
+ min_refresh_interval_(
+ override_min_refresh_interval.has_value()
+ ? override_min_refresh_interval.value()
+ : base::TimeDelta::FromSeconds(kDefaultMinRefreshIntervalSecs)) {
+ DCHECK(pref_service_);
DCHECK(fetcher_);
+ DCHECK(expiry_timer_);
+ DCHECK(clock_);
+ DCHECK(tick_clock_);
+
+ base::Time expiry_date = base::Time::FromInternalValue(
+ pref_service_->GetInt64(prefs::kCachedConfigExpiry));
+ base::Optional<DoodleConfig> config = DoodleConfig::FromDictionary(
+ *pref_service_->GetDictionary(prefs::kCachedConfig), base::nullopt);
+ DoodleState state =
+ config.has_value() ? DoodleState::AVAILABLE : DoodleState::NO_DOODLE;
+ HandleNewConfig(state, expiry_date - clock_->Now(), config);
}
DoodleService::~DoodleService() = default;
+void DoodleService::Shutdown() {}
+
void DoodleService::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
@@ -26,37 +81,162 @@ void DoodleService::RemoveObserver(Observer* observer) {
}
void DoodleService::Refresh() {
- fetcher_->FetchDoodle(
- base::BindOnce(&DoodleService::DoodleFetched, base::Unretained(this)));
+ base::TimeTicks now_ticks = tick_clock_->NowTicks();
+ // Check if we have passed the minimum refresh interval.
+ base::TimeDelta time_since_fetch = now_ticks - last_successful_fetch_;
+ if (time_since_fetch < min_refresh_interval_) {
+ RecordDownloadMetrics(OUTCOME_REFRESH_INTERVAL_NOT_PASSED,
+ base::TimeDelta());
+ return;
+ }
+ fetcher_->FetchDoodle(base::BindOnce(&DoodleService::DoodleFetched,
+ base::Unretained(this), now_ticks));
+}
+
+// static
+bool DoodleService::DownloadOutcomeIsSuccess(DownloadOutcome outcome) {
+ switch (outcome) {
+ case OUTCOME_NEW_DOODLE:
+ case OUTCOME_REVALIDATED_DOODLE:
+ case OUTCOME_CHANGED_DOODLE:
+ case OUTCOME_NO_DOODLE:
+ return true;
+ case OUTCOME_EXPIRED:
+ case OUTCOME_DOWNLOAD_ERROR:
+ case OUTCOME_PARSING_ERROR:
+ case OUTCOME_REFRESH_INTERVAL_NOT_PASSED:
+ return false;
+ case OUTCOME_COUNT:
+ NOTREACHED();
+ }
+ return false;
+}
+
+// static
+void DoodleService::RecordDownloadMetrics(DownloadOutcome outcome,
+ base::TimeDelta download_time) {
+ UMA_HISTOGRAM_ENUMERATION("Doodle.ConfigDownloadOutcome", outcome,
+ OUTCOME_COUNT);
+
+ if (DownloadOutcomeIsSuccess(outcome)) {
+ UMA_HISTOGRAM_MEDIUM_TIMES("Doodle.ConfigDownloadTime", download_time);
+ }
+}
+
+// static
+DoodleService::DownloadOutcome DoodleService::DetermineDownloadOutcome(
+ const base::Optional<DoodleConfig>& old_config,
+ const base::Optional<DoodleConfig>& new_config,
+ DoodleState state,
+ bool expired) {
+ // First, handle error cases: *_ERROR or EXPIRED override other outcomes.
+ switch (state) {
+ case DoodleState::AVAILABLE:
+ if (expired) {
+ return OUTCOME_EXPIRED;
+ }
+ break;
+
+ case DoodleState::NO_DOODLE:
+ break;
+
+ case DoodleState::DOWNLOAD_ERROR:
+ return OUTCOME_DOWNLOAD_ERROR;
+
+ case DoodleState::PARSING_ERROR:
+ return OUTCOME_PARSING_ERROR;
+ }
+
+ if (!new_config.has_value()) {
+ return OUTCOME_NO_DOODLE;
+ }
+ if (!old_config.has_value()) {
+ return OUTCOME_NEW_DOODLE;
+ }
+ if (old_config.value() != new_config.value()) {
+ return OUTCOME_CHANGED_DOODLE;
+ }
+ return OUTCOME_REVALIDATED_DOODLE;
}
void DoodleService::DoodleFetched(
+ base::TimeTicks start_time,
DoodleState state,
+ base::TimeDelta time_to_live,
const base::Optional<DoodleConfig>& doodle_config) {
- if (!cached_config_.has_value() && !doodle_config.has_value()) {
- // There was no config before and we didn't get a new one, so there's
- // nothing to do.
- return;
+ base::TimeTicks now_ticks = tick_clock_->NowTicks();
+ DownloadOutcome outcome = HandleNewConfig(state, time_to_live, doodle_config);
+ if (DownloadOutcomeIsSuccess(outcome)) {
+ last_successful_fetch_ = now_ticks;
}
+ base::TimeDelta download_time = now_ticks - start_time;
+ RecordDownloadMetrics(outcome, download_time);
+}
- bool notify = false;
- if (cached_config_.has_value() != doodle_config.has_value()) {
- // We got a new config, or an existing one went away.
- notify = true;
- } else {
- // There was a config both before and after the update. Notify observers
- // only if something relevant changed.
- notify = !cached_config_.value().IsEquivalent(doodle_config.value());
+DoodleService::DownloadOutcome DoodleService::HandleNewConfig(
+ DoodleState state,
+ base::TimeDelta time_to_live,
+ const base::Optional<DoodleConfig>& doodle_config) {
+ // Clamp the time-to-live to some reasonable maximum.
+ if (time_to_live.InSeconds() > kMaxTimeToLiveSecs) {
+ time_to_live = base::TimeDelta::FromSeconds(kMaxTimeToLiveSecs);
+ DLOG(WARNING) << "Clamping TTL to " << kMaxTimeToLiveSecs << " seconds!";
}
- // In any case, update the cache.
- cached_config_ = doodle_config;
+ // Handle the case where the new config is already expired.
+ bool expired = time_to_live <= base::TimeDelta();
+ const base::Optional<DoodleConfig>& new_config =
+ expired ? base::nullopt : doodle_config;
+
+ // Determine the download outcome *before* updating the cached config.
+ DownloadOutcome outcome =
+ DetermineDownloadOutcome(cached_config_, new_config, state, expired);
+
+ // If the config changed, update our cache and notify observers.
+ // Note that this checks both for existence changes as well as changes of the
+ // configs themselves.
+ if (cached_config_ != new_config) {
+ UpdateCachedConfig(time_to_live, new_config);
- if (notify) {
for (auto& observer : observers_) {
observer.OnDoodleConfigUpdated(cached_config_);
}
}
+
+ // Even if the configs are identical, the time-to-live might have changed.
+ // (Re-)schedule the cache expiry.
+ if (cached_config_.has_value()) {
+ expiry_timer_->Start(
+ FROM_HERE, time_to_live,
+ base::Bind(&DoodleService::DoodleExpired, base::Unretained(this)));
+ } else {
+ expiry_timer_->Stop();
+ }
+
+ return outcome;
+}
+
+void DoodleService::UpdateCachedConfig(
+ base::TimeDelta time_to_live,
+ const base::Optional<DoodleConfig>& new_config) {
+ DCHECK(cached_config_ != new_config);
+
+ cached_config_ = new_config;
+
+ if (cached_config_.has_value()) {
+ pref_service_->Set(prefs::kCachedConfig, *cached_config_->ToDictionary());
+ base::Time expiry_date = clock_->Now() + time_to_live;
+ pref_service_->SetInt64(prefs::kCachedConfigExpiry,
+ expiry_date.ToInternalValue());
+ } else {
+ pref_service_->ClearPref(prefs::kCachedConfig);
+ pref_service_->ClearPref(prefs::kCachedConfigExpiry);
+ }
+}
+
+void DoodleService::DoodleExpired() {
+ DCHECK(cached_config_.has_value());
+ HandleNewConfig(DoodleState::NO_DOODLE, base::TimeDelta(), base::nullopt);
}
} // namespace doodle
diff --git a/chromium/components/doodle/doodle_service.h b/chromium/components/doodle/doodle_service.h
index 09e1ae1f950..e4a9792a991 100644
--- a/chromium/components/doodle/doodle_service.h
+++ b/chromium/components/doodle/doodle_service.h
@@ -10,20 +10,40 @@
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/optional.h"
+#include "base/time/clock.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
#include "components/doodle/doodle_fetcher.h"
#include "components/doodle/doodle_types.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+class PrefRegistrySimple;
+class PrefService;
namespace doodle {
-class DoodleService {
+class DoodleService : public KeyedService {
public:
class Observer {
public:
virtual void OnDoodleConfigUpdated(const base::Optional<DoodleConfig>&) = 0;
};
- DoodleService(std::unique_ptr<DoodleFetcher> fetcher);
- ~DoodleService();
+ static void RegisterProfilePrefs(PrefRegistrySimple* pref_registry);
+
+ // All pointer parameters must be non-null. If |min_refresh_interval| doesn't
+ // have a value, the default value is used.
+ DoodleService(PrefService* pref_service,
+ std::unique_ptr<DoodleFetcher> fetcher,
+ std::unique_ptr<base::OneShotTimer> expiry_timer,
+ std::unique_ptr<base::Clock> clock,
+ std::unique_ptr<base::TickClock> tick_clock,
+ base::Optional<base::TimeDelta> override_min_refresh_interval);
+ ~DoodleService() override;
+
+ // KeyedService implementation.
+ void Shutdown() override;
// Returns the current (cached) config, if any.
const base::Optional<DoodleConfig>& config() const { return cached_config_; }
@@ -42,15 +62,67 @@ class DoodleService {
void Refresh();
private:
- void DoodleFetched(DoodleState state,
+ // Note: Keep in sync with the corresponding enum in histograms.xml. Never
+ // remove values, and only insert new values at the end.
+ enum DownloadOutcome {
+ OUTCOME_NEW_DOODLE = 0,
+ OUTCOME_REVALIDATED_DOODLE = 1,
+ OUTCOME_CHANGED_DOODLE = 2,
+ OUTCOME_NO_DOODLE = 3,
+ OUTCOME_EXPIRED = 4,
+ OUTCOME_DOWNLOAD_ERROR = 5,
+ OUTCOME_PARSING_ERROR = 6,
+ OUTCOME_REFRESH_INTERVAL_NOT_PASSED = 7,
+ // Insert new values here!
+ OUTCOME_COUNT = 8
+ };
+
+ static bool DownloadOutcomeIsSuccess(DownloadOutcome outcome);
+ static void RecordDownloadMetrics(DownloadOutcome outcome,
+ base::TimeDelta download_time);
+
+ static DownloadOutcome DetermineDownloadOutcome(
+ const base::Optional<DoodleConfig>& old_config,
+ const base::Optional<DoodleConfig>& new_config,
+ DoodleState state,
+ bool expired);
+
+ // Callback for the fetcher.
+ void DoodleFetched(base::TimeTicks start_time,
+ DoodleState state,
+ base::TimeDelta time_to_live,
const base::Optional<DoodleConfig>& doodle_config);
+ DownloadOutcome HandleNewConfig(
+ DoodleState state,
+ base::TimeDelta time_to_live,
+ const base::Optional<DoodleConfig>& doodle_config);
+
+ void UpdateCachedConfig(base::TimeDelta time_to_live,
+ const base::Optional<DoodleConfig>& new_config);
+
+ // Callback for the expiry timer.
+ void DoodleExpired();
+
+ PrefService* pref_service_;
+
// The fetcher for getting fresh DoodleConfigs from the network.
std::unique_ptr<DoodleFetcher> fetcher_;
+ std::unique_ptr<base::OneShotTimer> expiry_timer_;
+ std::unique_ptr<base::Clock> clock_;
+ std::unique_ptr<base::TickClock> tick_clock_;
+
+ // The minimum interval between server fetches. After a successful fetch,
+ // refresh requests are ignored for this period.
+ const base::TimeDelta min_refresh_interval_;
+
// The result of the last network fetch.
base::Optional<DoodleConfig> cached_config_;
+ // The time of the most recent successful fetch.
+ base::TimeTicks last_successful_fetch_;
+
// The list of observers to be notified when the DoodleConfig changes.
base::ObserverList<Observer> observers_;
diff --git a/chromium/components/doodle/doodle_service_unittest.cc b/chromium/components/doodle/doodle_service_unittest.cc
index 48b3a10cade..8f6fc7e1011 100644
--- a/chromium/components/doodle/doodle_service_unittest.cc
+++ b/chromium/components/doodle/doodle_service_unittest.cc
@@ -10,6 +10,13 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/test/histogram_tester.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/prefs/testing_pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -32,9 +39,10 @@ class FakeDoodleFetcher : public DoodleFetcher {
size_t num_pending_callbacks() const { return callbacks_.size(); }
void ServeAllCallbacks(DoodleState state,
+ base::TimeDelta time_to_live,
const base::Optional<DoodleConfig>& config) {
for (auto& callback : callbacks_) {
- std::move(callback).Run(state, config);
+ std::move(callback).Run(state, time_to_live, config);
}
callbacks_.clear();
}
@@ -49,28 +57,66 @@ class MockDoodleObserver : public DoodleService::Observer {
void(const base::Optional<DoodleConfig>&));
};
-} // namespace
-
-// Equality operator for DoodleConfigs, for use by testing::Eq.
-// Note: This must be outside of the anonymous namespace.
-bool operator==(const DoodleConfig& lhs, const DoodleConfig& rhs) {
- return lhs.IsEquivalent(rhs);
+DoodleConfig CreateConfig(DoodleType type) {
+ return DoodleConfig(type, DoodleImage(GURL("https://doodle.com/image.jpg")));
}
+} // namespace
+
class DoodleServiceTest : public testing::Test {
public:
- DoodleServiceTest() : fetcher_(nullptr) {
+ DoodleServiceTest()
+ : task_runner_(new base::TestMockTimeTaskRunner()),
+ task_runner_handle_(task_runner_),
+ tick_clock_(task_runner_->GetMockTickClock()),
+ fetcher_(nullptr),
+ expiry_timer_(nullptr) {
+ DoodleService::RegisterProfilePrefs(pref_service_.registry());
+
+ task_runner_->FastForwardBy(base::TimeDelta::FromHours(12345));
+
+ // Set the minimum refresh interval to 0 by default, so tests don't have to
+ // worry about it. The tests that care set it explicitly.
+ RecreateServiceWithZeroRefreshInterval();
+ }
+
+ void DestroyService() { service_ = nullptr; }
+
+ void RecreateServiceWithZeroRefreshInterval() {
+ RecreateService(/*min_refresh_interval=*/base::TimeDelta());
+ }
+
+ void RecreateService(base::Optional<base::TimeDelta> refresh_interval) {
+ auto expiry_timer = base::MakeUnique<base::OneShotTimer>(tick_clock_.get());
+ expiry_timer->SetTaskRunner(task_runner_);
+ expiry_timer_ = expiry_timer.get();
+
auto fetcher = base::MakeUnique<FakeDoodleFetcher>();
fetcher_ = fetcher.get();
- service_ = base::MakeUnique<DoodleService>(std::move(fetcher));
+
+ service_ = base::MakeUnique<DoodleService>(
+ &pref_service_, std::move(fetcher), std::move(expiry_timer),
+ task_runner_->GetMockClock(), task_runner_->GetMockTickClock(),
+ refresh_interval);
}
DoodleService* service() { return service_.get(); }
FakeDoodleFetcher* fetcher() { return fetcher_; }
+ base::TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); }
+
private:
+ TestingPrefServiceSimple pref_service_;
+
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+ base::ThreadTaskRunnerHandle task_runner_handle_;
+ std::unique_ptr<base::TickClock> tick_clock_;
+
std::unique_ptr<DoodleService> service_;
+
+ // Weak, owned by the service.
FakeDoodleFetcher* fetcher_;
+ base::OneShotTimer* expiry_timer_;
};
TEST_F(DoodleServiceTest, FetchesConfigOnRefresh) {
@@ -82,9 +128,9 @@ TEST_F(DoodleServiceTest, FetchesConfigOnRefresh) {
EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u));
// Serve it (with an arbitrary config).
- DoodleConfig config;
- config.doodle_type = DoodleType::SIMPLE;
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, config);
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
// The config should be available.
EXPECT_THAT(service()->config(), Eq(config));
@@ -95,15 +141,103 @@ TEST_F(DoodleServiceTest, FetchesConfigOnRefresh) {
EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u));
// Serve it with a different config.
- DoodleConfig other_config;
- other_config.doodle_type = DoodleType::SLIDESHOW;
- DCHECK(!config.IsEquivalent(other_config));
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, other_config);
+ DoodleConfig other_config = CreateConfig(DoodleType::SLIDESHOW);
+ DCHECK(config != other_config);
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), other_config);
// The config should have been updated.
EXPECT_THAT(service()->config(), Eq(other_config));
}
+TEST_F(DoodleServiceTest, PersistsConfig) {
+ // Load some doodle config.
+ service()->Refresh();
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ config.large_image.url = GURL("https://doodle.com/doodle.jpg");
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
+ ASSERT_THAT(service()->config(), Eq(config));
+
+ // Re-create the service. It should have persisted the config, and load it
+ // again automatically.
+ RecreateServiceWithZeroRefreshInterval();
+ EXPECT_THAT(service()->config(), Eq(config));
+}
+
+TEST_F(DoodleServiceTest, PersistsExpiryDate) {
+ // Load some doodle config.
+ service()->Refresh();
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ config.large_image.url = GURL("https://doodle.com/doodle.jpg");
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
+ ASSERT_THAT(service()->config(), Eq(config));
+
+ // Destroy the service, and let some time pass.
+ DestroyService();
+ task_runner()->FastForwardBy(base::TimeDelta::FromMinutes(15));
+
+ // Remove the abandoned expiry task from the task runner.
+ ASSERT_THAT(task_runner()->GetPendingTaskCount(), Eq(1u));
+ task_runner()->ClearPendingTasks();
+
+ // Re-create the service. The persisted config should have been loaded again.
+ RecreateServiceWithZeroRefreshInterval();
+ EXPECT_THAT(service()->config(), Eq(config));
+
+ // Its time-to-live should have been updated.
+ EXPECT_THAT(task_runner()->GetPendingTaskCount(), Eq(1u));
+ EXPECT_THAT(task_runner()->NextPendingTaskDelay(),
+ Eq(base::TimeDelta::FromMinutes(45)));
+}
+
+TEST_F(DoodleServiceTest, PersistedConfigExpires) {
+ // Load some doodle config.
+ service()->Refresh();
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ config.large_image.url = GURL("https://doodle.com/doodle.jpg");
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
+ ASSERT_THAT(service()->config(), Eq(config));
+
+ // Destroy the service, and let enough time pass so that the config expires.
+ DestroyService();
+ task_runner()->FastForwardBy(base::TimeDelta::FromHours(1));
+
+ // Re-create the service. The persisted config should have been discarded
+ // because it is expired.
+ RecreateServiceWithZeroRefreshInterval();
+ EXPECT_THAT(service()->config(), Eq(base::nullopt));
+}
+
+TEST_F(DoodleServiceTest, RespectsMinRefreshInterval) {
+ // Create a service with the default refresh interval.
+ RecreateService(/*min_refresh_interval=*/base::nullopt);
+
+ // Load some doodle config.
+ service()->Refresh();
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ config.large_image.url = GURL("https://doodle.com/doodle.jpg");
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
+ ASSERT_THAT(service()->config(), Eq(config));
+
+ // Let some time pass (less than the refresh interval).
+ task_runner()->FastForwardBy(base::TimeDelta::FromMinutes(10));
+
+ // Request a refresh. This should get ignored.
+ service()->Refresh();
+ EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(0u));
+
+ // Let more time pass, so we get past the refresh interval.
+ task_runner()->FastForwardBy(base::TimeDelta::FromMinutes(6));
+
+ // Now the refresh request should be honored again.
+ service()->Refresh();
+ EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u));
+}
+
TEST_F(DoodleServiceTest, CallsObserverOnConfigReceived) {
StrictMock<MockDoodleObserver> observer;
service()->AddObserver(&observer);
@@ -116,10 +250,10 @@ TEST_F(DoodleServiceTest, CallsObserverOnConfigReceived) {
ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(1u));
// Serve it (with an arbitrary config). The observer should get notified.
- DoodleConfig config;
- config.doodle_type = DoodleType::SIMPLE;
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(config)));
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, config);
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
// Remove the observer before the service gets destroyed.
service()->RemoveObserver(&observer);
@@ -128,9 +262,9 @@ TEST_F(DoodleServiceTest, CallsObserverOnConfigReceived) {
TEST_F(DoodleServiceTest, CallsObserverOnConfigRemoved) {
// Load some doodle config.
service()->Refresh();
- DoodleConfig config;
- config.doodle_type = DoodleType::SIMPLE;
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, config);
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
ASSERT_THAT(service()->config(), Eq(config));
// Register an observer and request a refresh.
@@ -142,7 +276,8 @@ TEST_F(DoodleServiceTest, CallsObserverOnConfigRemoved) {
// Serve the request with an empty doodle config. The observer should get
// notified.
EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(base::nullopt)));
- fetcher()->ServeAllCallbacks(DoodleState::NO_DOODLE, base::nullopt);
+ fetcher()->ServeAllCallbacks(DoodleState::NO_DOODLE, base::TimeDelta(),
+ base::nullopt);
// Remove the observer before the service gets destroyed.
service()->RemoveObserver(&observer);
@@ -151,9 +286,9 @@ TEST_F(DoodleServiceTest, CallsObserverOnConfigRemoved) {
TEST_F(DoodleServiceTest, CallsObserverOnConfigUpdated) {
// Load some doodle config.
service()->Refresh();
- DoodleConfig config;
- config.doodle_type = DoodleType::SIMPLE;
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, config);
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
ASSERT_THAT(service()->config(), Eq(config));
// Register an observer and request a refresh.
@@ -164,22 +299,22 @@ TEST_F(DoodleServiceTest, CallsObserverOnConfigUpdated) {
// Serve the request with a different doodle config. The observer should get
// notified.
- DoodleConfig other_config;
- other_config.doodle_type = DoodleType::SLIDESHOW;
- DCHECK(!config.IsEquivalent(other_config));
+ DoodleConfig other_config = CreateConfig(DoodleType::SLIDESHOW);
+ DCHECK(config != other_config);
EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(other_config)));
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, other_config);
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), other_config);
// Remove the observer before the service gets destroyed.
service()->RemoveObserver(&observer);
}
-TEST_F(DoodleServiceTest, DoesNotCallObserverWhenConfigEquivalent) {
+TEST_F(DoodleServiceTest, DoesNotCallObserverIfConfigEquivalent) {
// Load some doodle config.
service()->Refresh();
- DoodleConfig config;
- config.doodle_type = DoodleType::SIMPLE;
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, config);
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
ASSERT_THAT(service()->config(), Eq(config));
// Register an observer and request a refresh.
@@ -190,13 +325,214 @@ TEST_F(DoodleServiceTest, DoesNotCallObserverWhenConfigEquivalent) {
// Serve the request with an equivalent doodle config. The observer should
// *not* get notified.
- DoodleConfig equivalent_config;
- equivalent_config.doodle_type = DoodleType::SIMPLE;
- DCHECK(config.IsEquivalent(equivalent_config));
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, equivalent_config);
+ DoodleConfig equivalent_config = CreateConfig(DoodleType::SIMPLE);
+ DCHECK(config == equivalent_config);
+ fetcher()->ServeAllCallbacks(
+ DoodleState::AVAILABLE, base::TimeDelta::FromHours(1), equivalent_config);
// Remove the observer before the service gets destroyed.
service()->RemoveObserver(&observer);
}
+TEST_F(DoodleServiceTest, CallsObserverWhenConfigExpires) {
+ // Load some doodle config.
+ service()->Refresh();
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
+ ASSERT_THAT(service()->config(), Eq(config));
+
+ // Make sure the task arrived at the timer's task runner.
+ EXPECT_THAT(task_runner()->GetPendingTaskCount(), Eq(1u));
+ EXPECT_THAT(task_runner()->NextPendingTaskDelay(),
+ Eq(base::TimeDelta::FromHours(1)));
+
+ // Register an observer.
+ StrictMock<MockDoodleObserver> observer;
+ service()->AddObserver(&observer);
+
+ // Fast-forward time so that the expiry task will run. The observer should get
+ // notified that there's no config anymore.
+ EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(base::nullopt)));
+ task_runner()->FastForwardBy(base::TimeDelta::FromHours(1));
+
+ // Remove the observer before the service gets destroyed.
+ service()->RemoveObserver(&observer);
+}
+
+TEST_F(DoodleServiceTest, DisregardsAlreadyExpiredConfigs) {
+ StrictMock<MockDoodleObserver> observer;
+ service()->AddObserver(&observer);
+
+ ASSERT_THAT(service()->config(), Eq(base::nullopt));
+
+ // Load an already-expired config. This should have no effect; in particular
+ // no call to the observer.
+ service()->Refresh();
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromSeconds(0), config);
+ EXPECT_THAT(service()->config(), Eq(base::nullopt));
+
+ // Load a doodle config as usual. Nothing to see here.
+ service()->Refresh();
+ EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(config)));
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
+ ASSERT_THAT(service()->config(), Eq(config));
+
+ // Now load an expired config again. The cached one should go away.
+ service()->Refresh();
+ EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(base::nullopt)));
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromSeconds(0), config);
+
+ // Remove the observer before the service gets destroyed.
+ service()->RemoveObserver(&observer);
+}
+
+TEST_F(DoodleServiceTest, ClampsTimeToLive) {
+ // Load a config with an excessive time-to-live.
+ service()->Refresh();
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromDays(100), config);
+ ASSERT_THAT(service()->config(), Eq(config));
+
+ // The time-to-live should have been clamped to a reasonable maximum.
+ ASSERT_THAT(task_runner()->GetPendingTaskCount(), Eq(1u));
+ EXPECT_THAT(task_runner()->NextPendingTaskDelay(),
+ Eq(base::TimeDelta::FromDays(30)));
+}
+
+TEST_F(DoodleServiceTest, RecordsMetricsForSuccessfulDownload) {
+ base::HistogramTester histograms;
+
+ // Load a doodle config as usual, but let it take some time.
+ service()->Refresh();
+ task_runner()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
+ ASSERT_THAT(service()->config(), Eq(config));
+
+ // Metrics should have been recorded.
+ histograms.ExpectUniqueSample("Doodle.ConfigDownloadOutcome",
+ 0, // OUTCOME_NEW_DOODLE
+ 1);
+ histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 1);
+ histograms.ExpectTimeBucketCount("Doodle.ConfigDownloadTime",
+ base::TimeDelta::FromSeconds(5), 1);
+}
+
+TEST_F(DoodleServiceTest, RecordsMetricsForEmptyDownload) {
+ base::HistogramTester histograms;
+
+ // Send a "no doodle" response after some time.
+ service()->Refresh();
+ task_runner()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+ fetcher()->ServeAllCallbacks(DoodleState::NO_DOODLE, base::TimeDelta(),
+ base::nullopt);
+ ASSERT_THAT(service()->config(), Eq(base::nullopt));
+
+ // Metrics should have been recorded.
+ histograms.ExpectUniqueSample("Doodle.ConfigDownloadOutcome",
+ 3, // OUTCOME_NO_DOODLE
+ 1);
+ histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 1);
+ histograms.ExpectTimeBucketCount("Doodle.ConfigDownloadTime",
+ base::TimeDelta::FromSeconds(5), 1);
+}
+
+TEST_F(DoodleServiceTest, RecordsMetricsForFailedDownload) {
+ base::HistogramTester histograms;
+
+ // Let the download fail after some time.
+ service()->Refresh();
+ task_runner()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+ fetcher()->ServeAllCallbacks(DoodleState::DOWNLOAD_ERROR, base::TimeDelta(),
+ base::nullopt);
+ ASSERT_THAT(service()->config(), Eq(base::nullopt));
+
+ // The outcome should have been recorded, but not the time - we only record
+ // that for successful downloads.
+ histograms.ExpectUniqueSample("Doodle.ConfigDownloadOutcome",
+ 5, // OUTCOME_DOWNLOAD_ERROR
+ 1);
+ histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 0);
+}
+
+TEST_F(DoodleServiceTest, RecordsMetricsForEarlyRefreshRequest) {
+ // Create a service with some refresh interval.
+ RecreateService(/*min_refresh_interval=*/base::TimeDelta::FromMinutes(10));
+
+ // Load a doodle config as usual.
+ service()->Refresh();
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
+ ASSERT_THAT(service()->config(), Eq(config));
+
+ base::HistogramTester histograms;
+
+ // Request a refresh before the min refresh interval has passed.
+ task_runner()->FastForwardBy(base::TimeDelta::FromMinutes(5));
+ service()->Refresh();
+
+ // This should not have resulted in a request.
+ ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(0u));
+
+ // The outcome should still have been recorded, but not the time - we only
+ // record that for successful downloads.
+ histograms.ExpectUniqueSample("Doodle.ConfigDownloadOutcome",
+ 7, // OUTCOME_REFRESH_INTERVAL_NOT_PASSED
+ 1);
+ histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 0);
+}
+
+TEST_F(DoodleServiceTest, DoesNotRecordMetricsAtStartup) {
+ // Creating the service should not emit any histogram samples.
+ base::HistogramTester histograms;
+ RecreateServiceWithZeroRefreshInterval();
+ ASSERT_THAT(service()->config(), Eq(base::nullopt));
+ histograms.ExpectTotalCount("Doodle.ConfigDownloadOutcome", 0);
+ histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 0);
+}
+
+TEST_F(DoodleServiceTest, DoesNotRecordMetricsAtStartupWithConfig) {
+ // Load a doodle config as usual.
+ service()->Refresh();
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
+ ASSERT_THAT(service()->config(), Eq(config));
+
+ // Recreating the service should not emit any histogram samples, even though
+ // a config gets loaded.
+ base::HistogramTester histograms;
+ RecreateServiceWithZeroRefreshInterval();
+ ASSERT_THAT(service()->config(), Eq(config));
+ histograms.ExpectTotalCount("Doodle.ConfigDownloadOutcome", 0);
+ histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 0);
+}
+
+TEST_F(DoodleServiceTest, DoesNotRecordMetricsWhenConfigExpires) {
+ // Load some doodle config.
+ service()->Refresh();
+ DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
+ fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
+ base::TimeDelta::FromHours(1), config);
+ ASSERT_THAT(service()->config(), Eq(config));
+
+ base::HistogramTester histograms;
+
+ // Fast-forward time so that the config expires.
+ task_runner()->FastForwardBy(base::TimeDelta::FromHours(1));
+ ASSERT_THAT(service()->config(), Eq(base::nullopt));
+
+ // This should not have resulted in any metrics being emitted.
+ histograms.ExpectTotalCount("Doodle.ConfigDownloadOutcome", 0);
+ histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 0);
+}
+
} // namespace doodle
diff --git a/chromium/components/doodle/doodle_types.cc b/chromium/components/doodle/doodle_types.cc
index 7468d2b8f87..3ba743f4149 100644
--- a/chromium/components/doodle/doodle_types.cc
+++ b/chromium/components/doodle/doodle_types.cc
@@ -4,8 +4,148 @@
#include "components/doodle/doodle_types.h"
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+
namespace doodle {
+namespace {
+
+// String representations for the DoodleType enum.
+const char kDoodleTypeUnknown[] = "UNKNOWN";
+const char kDoodleTypeSimple[] = "SIMPLE";
+const char kDoodleTypeRandom[] = "RANDOM";
+const char kDoodleTypeVideo[] = "VIDEO";
+const char kDoodleTypeInteractive[] = "INTERACTIVE";
+const char kDoodleTypeInlineInteractive[] = "INLINE_INTERACTIVE";
+const char kDoodleTypeSlideshow[] = "SLIDESHOW";
+
+// JSON keys for DoodleImage fields.
+const char kKeyUrl[] = "url";
+const char kKeyHeight[] = "height";
+const char kKeyWidth[] = "width";
+const char kKeyIsAnimatedGif[] = "is_animated_gif";
+const char kKeyIsCta[] = "is_cta";
+
+// JSON keys for DoodleConfig fields.
+const char kKeyDoodleType[] = "doodle_type";
+const char kKeyAltText[] = "alt_text";
+const char kKeyInteractiveHtml[] = "interactive_html";
+const char kKeyTargetUrl[] = "target_url";
+const char kKeyLargeImage[] = "large_image";
+const char kKeyLargeCtaImage[] = "large_cta_image";
+const char kKeyTransparentLargeImage[] = "transparent_large_image";
+
+std::string DoodleTypeToString(DoodleType type) {
+ switch (type) {
+ case DoodleType::UNKNOWN:
+ return kDoodleTypeUnknown;
+ case DoodleType::SIMPLE:
+ return kDoodleTypeSimple;
+ case DoodleType::RANDOM:
+ return kDoodleTypeRandom;
+ case DoodleType::VIDEO:
+ return kDoodleTypeVideo;
+ case DoodleType::INTERACTIVE:
+ return kDoodleTypeInteractive;
+ case DoodleType::INLINE_INTERACTIVE:
+ return kDoodleTypeInlineInteractive;
+ case DoodleType::SLIDESHOW:
+ return kDoodleTypeSlideshow;
+ }
+ NOTREACHED();
+ return std::string();
+}
+
+DoodleType DoodleTypeFromString(const std::string& type_str) {
+ if (type_str == kDoodleTypeSimple) {
+ return DoodleType::SIMPLE;
+ }
+ if (type_str == kDoodleTypeRandom) {
+ return DoodleType::RANDOM;
+ }
+ if (type_str == kDoodleTypeVideo) {
+ return DoodleType::VIDEO;
+ }
+ if (type_str == kDoodleTypeInteractive) {
+ return DoodleType::INTERACTIVE;
+ }
+ if (type_str == kDoodleTypeInlineInteractive) {
+ return DoodleType::INLINE_INTERACTIVE;
+ }
+ if (type_str == kDoodleTypeSlideshow) {
+ return DoodleType::SLIDESHOW;
+ }
+ return DoodleType::UNKNOWN;
+}
+
+GURL ResolvePossiblyRelativeUrl(const std::string& url_str,
+ const base::Optional<GURL>& base_url) {
+ if (!base_url.has_value()) {
+ return GURL(url_str);
+ }
+ return base_url->Resolve(url_str);
+}
+
+GURL ParseUrl(const base::DictionaryValue& parent_dict,
+ const std::string& key,
+ const base::Optional<GURL>& base_url) {
+ std::string url_str;
+ if (!parent_dict.GetString(key, &url_str) || url_str.empty()) {
+ return GURL();
+ }
+ return ResolvePossiblyRelativeUrl(url_str, base_url);
+}
+
+base::Optional<DoodleImage> ParseImage(const base::DictionaryValue& parent_dict,
+ const std::string& key,
+ const base::Optional<GURL>& base_url) {
+ const base::DictionaryValue* image_dict = nullptr;
+ if (!parent_dict.GetDictionary(key, &image_dict)) {
+ return base::nullopt;
+ }
+ return DoodleImage::FromDictionary(*image_dict, base_url);
+}
+
+} // namespace
+
+// static
+base::Optional<DoodleImage> DoodleImage::FromDictionary(
+ const base::DictionaryValue& dict,
+ const base::Optional<GURL>& base_url) {
+ // The URL is the only required field.
+ GURL url = ParseUrl(dict, kKeyUrl, base_url);
+ if (!url.is_valid()) {
+ return base::nullopt;
+ }
+
+ DoodleImage image(url);
+
+ dict.GetInteger(kKeyHeight, &image.height);
+ dict.GetInteger(kKeyWidth, &image.width);
+ dict.GetBoolean(kKeyIsAnimatedGif, &image.is_animated_gif);
+ dict.GetBoolean(kKeyIsCta, &image.is_cta);
+
+ return image;
+}
+
+DoodleImage::DoodleImage(const GURL& url)
+ : url(url), height(0), width(0), is_animated_gif(false), is_cta(false) {
+ DCHECK(url.is_valid());
+}
+
+DoodleImage::~DoodleImage() = default;
+
+std::unique_ptr<base::DictionaryValue> DoodleImage::ToDictionary() const {
+ auto dict = base::MakeUnique<base::DictionaryValue>();
+ dict->SetString(kKeyUrl, url.spec());
+ dict->SetInteger(kKeyHeight, height);
+ dict->SetInteger(kKeyWidth, width);
+ dict->SetBoolean(kKeyIsAnimatedGif, is_animated_gif);
+ dict->SetBoolean(kKeyIsCta, is_cta);
+ return dict;
+}
+
bool DoodleImage::operator==(const DoodleImage& other) const {
return url == other.url && height == other.height && width == other.width &&
is_animated_gif == other.is_animated_gif && is_cta == other.is_cta;
@@ -15,17 +155,69 @@ bool DoodleImage::operator!=(const DoodleImage& other) const {
return !(*this == other);
}
-bool DoodleConfig::IsEquivalent(const DoodleConfig& other) const {
- // Note: This compares all fields except for |time_to_live|, which by
- // definition isn't constant over time, and shouldn't be in DoodleConfig in
- // the first place.
+DoodleConfig::DoodleConfig(DoodleType doodle_type,
+ const DoodleImage& large_image)
+ : doodle_type(doodle_type), large_image(large_image) {}
+DoodleConfig::DoodleConfig(const DoodleConfig& config) = default;
+DoodleConfig::~DoodleConfig() = default;
+
+// static
+base::Optional<DoodleConfig> DoodleConfig::FromDictionary(
+ const base::DictionaryValue& dict,
+ const base::Optional<GURL>& base_url) {
+ // The |large_image| field is required (it's the "default" representation for
+ // the doodle).
+ base::Optional<DoodleImage> large_image =
+ ParseImage(dict, kKeyLargeImage, base_url);
+ if (!large_image.has_value()) {
+ return base::nullopt;
+ }
+
+ std::string type_str;
+ dict.GetString(kKeyDoodleType, &type_str);
+
+ DoodleConfig doodle(DoodleTypeFromString(type_str), large_image.value());
+
+ dict.GetString(kKeyAltText, &doodle.alt_text);
+
+ dict.GetString(kKeyInteractiveHtml, &doodle.interactive_html);
+
+ doodle.target_url = ParseUrl(dict, kKeyTargetUrl, base_url);
+
+ doodle.large_cta_image = ParseImage(dict, kKeyLargeCtaImage, base_url);
+ doodle.transparent_large_image =
+ ParseImage(dict, kKeyTransparentLargeImage, base_url);
+
+ return doodle;
+}
+
+std::unique_ptr<base::DictionaryValue> DoodleConfig::ToDictionary() const {
+ auto dict = base::MakeUnique<base::DictionaryValue>();
+ dict->SetString(kKeyDoodleType, DoodleTypeToString(doodle_type));
+ dict->SetString(kKeyAltText, alt_text);
+ dict->SetString(kKeyInteractiveHtml, interactive_html);
+ dict->SetString(kKeyTargetUrl, target_url.spec());
+ dict->Set(kKeyLargeImage, large_image.ToDictionary());
+ if (large_cta_image.has_value()) {
+ dict->Set(kKeyLargeCtaImage, large_cta_image->ToDictionary());
+ }
+ if (transparent_large_image.has_value()) {
+ dict->Set(kKeyTransparentLargeImage,
+ transparent_large_image->ToDictionary());
+ }
+ return dict;
+}
+
+bool DoodleConfig::operator==(const DoodleConfig& other) const {
return doodle_type == other.doodle_type && alt_text == other.alt_text &&
interactive_html == other.interactive_html &&
- search_url == other.search_url && target_url == other.target_url &&
- fullpage_interactive_url == other.fullpage_interactive_url &&
large_image == other.large_image &&
large_cta_image == other.large_cta_image &&
transparent_large_image == other.transparent_large_image;
}
+bool DoodleConfig::operator!=(const DoodleConfig& other) const {
+ return !(*this == other);
+}
+
} // namespace doodle
diff --git a/chromium/components/doodle/doodle_types.h b/chromium/components/doodle/doodle_types.h
index 1317c80ccd4..66aa2c533c6 100644
--- a/chromium/components/doodle/doodle_types.h
+++ b/chromium/components/doodle/doodle_types.h
@@ -5,9 +5,16 @@
#ifndef COMPONENTS_DOODLE_DOODLE_TYPES_H_
#define COMPONENTS_DOODLE_DOODLE_TYPES_H_
-#include "base/time/time.h"
+#include <memory>
+#include <string>
+
+#include "base/optional.h"
#include "url/gurl.h"
+namespace base {
+class DictionaryValue;
+}
+
namespace doodle {
enum class DoodleState {
@@ -27,12 +34,17 @@ enum class DoodleType {
SLIDESHOW,
};
-// Information about a Doodle image. If the image is invalid, the |url| will be
-// empty and invalid. By default the dimensions are 0.
+// Information about a Doodle image. By default the dimensions are 0.
struct DoodleImage {
- DoodleImage();
+ DoodleImage(const GURL& url);
~DoodleImage();
+ static base::Optional<DoodleImage> FromDictionary(
+ const base::DictionaryValue& dict,
+ const base::Optional<GURL>& base_url);
+
+ std::unique_ptr<base::DictionaryValue> ToDictionary() const;
+
bool operator==(const DoodleImage& other) const;
bool operator!=(const DoodleImage& other) const;
@@ -48,28 +60,28 @@ struct DoodleImage {
// All information about a current doodle that can be fetched from the remote
// end. By default, all URLs are empty and therefore invalid.
struct DoodleConfig {
- DoodleConfig();
+ DoodleConfig(DoodleType doodle_type, const DoodleImage& large_image);
DoodleConfig(const DoodleConfig& config); // = default;
~DoodleConfig();
- // Checks whether this config is "equivalent" to the other. This compares all
- // fields for equality, except for |expiry_date|.
- bool IsEquivalent(const DoodleConfig& other) const;
+ static base::Optional<DoodleConfig> FromDictionary(
+ const base::DictionaryValue& dict,
+ const base::Optional<GURL>& base_url);
+
+ std::unique_ptr<base::DictionaryValue> ToDictionary() const;
+
+ bool operator==(const DoodleConfig& other) const;
+ bool operator!=(const DoodleConfig& other) const;
DoodleType doodle_type;
std::string alt_text;
std::string interactive_html;
- GURL search_url;
GURL target_url;
- GURL fullpage_interactive_url;
DoodleImage large_image;
- DoodleImage large_cta_image;
- DoodleImage transparent_large_image;
-
- // TODO(treib,fhorschig): Don't expose this? Clients don't care about it.
- base::TimeDelta time_to_live;
+ base::Optional<DoodleImage> large_cta_image;
+ base::Optional<DoodleImage> transparent_large_image;
// Copying and assignment allowed.
};
diff --git a/chromium/components/doodle/doodle_types_unittest.cc b/chromium/components/doodle/doodle_types_unittest.cc
new file mode 100644
index 00000000000..91e2f749b4b
--- /dev/null
+++ b/chromium/components/doodle/doodle_types_unittest.cc
@@ -0,0 +1,259 @@
+// 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/doodle/doodle_types.h"
+
+#include <memory>
+#include <string>
+
+#include "base/json/json_reader.h"
+#include "base/optional.h"
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using testing::Eq;
+
+namespace doodle {
+
+namespace {
+
+// Parses the given |json| string into a base::DictionaryValue and creates a
+// DoodleImage out of that. |json| must be a valid json string.
+base::Optional<DoodleImage> DoodleImageFromJson(
+ const std::string& json,
+ const base::Optional<GURL>& base_url) {
+ std::unique_ptr<base::DictionaryValue> value =
+ base::DictionaryValue::From(base::JSONReader::Read(json));
+ DCHECK(value);
+ return DoodleImage::FromDictionary(*value, base_url);
+}
+
+// Parses the given |json| string into a base::DictionaryValue and creates a
+// DoodleConfig out of that. |json| must be a valid json string.
+base::Optional<DoodleConfig> DoodleConfigFromJson(
+ const std::string& json,
+ const base::Optional<GURL>& base_url) {
+ std::unique_ptr<base::DictionaryValue> value =
+ base::DictionaryValue::From(base::JSONReader::Read(json));
+ DCHECK(value);
+ return DoodleConfig::FromDictionary(*value, base_url);
+}
+
+} // namespace
+
+TEST(DoodleImageTest, ParsesMinimalImage) {
+ std::string json = R"json({
+ "url":"https://www.doodle.com/doodle"
+ })json";
+ base::Optional<DoodleImage> image = DoodleImageFromJson(json, base::nullopt);
+ ASSERT_TRUE(image.has_value());
+ EXPECT_THAT(image->url, Eq(GURL("https://www.doodle.com/doodle")));
+ EXPECT_THAT(image->height, Eq(0));
+ EXPECT_THAT(image->width, Eq(0));
+ EXPECT_THAT(image->is_animated_gif, Eq(false));
+ EXPECT_THAT(image->is_cta, Eq(false));
+}
+
+TEST(DoodleImageTest, ParsesFullImage) {
+ std::string json = R"json({
+ "url":"https://www.doodle.com/doodle",
+ "height":100,
+ "width":50,
+ "is_animated_gif":true,
+ "is_cta":true
+ })json";
+ base::Optional<DoodleImage> image = DoodleImageFromJson(json, base::nullopt);
+ ASSERT_TRUE(image.has_value());
+ EXPECT_THAT(image->url, Eq(GURL("https://www.doodle.com/doodle")));
+ EXPECT_THAT(image->height, Eq(100));
+ EXPECT_THAT(image->width, Eq(50));
+ EXPECT_THAT(image->is_animated_gif, Eq(true));
+ EXPECT_THAT(image->is_cta, Eq(true));
+}
+
+TEST(DoodleImageTest, ResolvesRelativeUrl) {
+ std::string json = R"json({
+ "url":"/the_doodle_path"
+ })json";
+ base::Optional<DoodleImage> image =
+ DoodleImageFromJson(json, GURL("https://doodle.dood/"));
+ ASSERT_TRUE(image.has_value());
+ EXPECT_THAT(image->url, Eq(GURL("https://doodle.dood/the_doodle_path")));
+}
+
+TEST(DoodleImageTest, DoesNotResolveAbsoluteUrl) {
+ std::string json = R"json({
+ "url":"https://www.doodle.com/the_doodle_path"
+ })json";
+ base::Optional<DoodleImage> image =
+ DoodleImageFromJson(json, GURL("https://other.com/"));
+ ASSERT_TRUE(image.has_value());
+ EXPECT_THAT(image->url, Eq(GURL("https://www.doodle.com/the_doodle_path")));
+}
+
+TEST(DoodleImageTest, RequiresUrl) {
+ std::string json = R"json({
+ "height":100,
+ "width":50,
+ "is_animated_gif":true,
+ "is_cta":true
+ })json";
+ base::Optional<DoodleImage> image = DoodleImageFromJson(json, base::nullopt);
+ EXPECT_FALSE(image.has_value());
+}
+
+TEST(DoodleImageTest, HandlesInvalidUrl) {
+ std::string json = R"json({
+ "url":"not_a_url"
+ })json";
+ base::Optional<DoodleImage> image = DoodleImageFromJson(json, base::nullopt);
+ // The URL is required, and invalid should be treated like missing.
+ EXPECT_FALSE(image.has_value());
+}
+
+TEST(DoodleImageTest, PreservesFieldsOverRoundtrip) {
+ // Set all fields to non-default values.
+ DoodleImage image(GURL("https://www.doodle.com/doodle"));
+ image.height = 100;
+ image.width = 50;
+ image.is_animated_gif = true;
+ image.is_cta = true;
+
+ // Convert to a dictionary and back.
+ base::Optional<DoodleImage> after_roundtrip =
+ DoodleImage::FromDictionary(*image.ToDictionary(), base::nullopt);
+
+ // Make sure everything survived.
+ ASSERT_TRUE(after_roundtrip.has_value());
+ EXPECT_THAT(*after_roundtrip, Eq(image));
+}
+
+TEST(DoodleConfigTest, ParsesMinimalConfig) {
+ std::string json = R"json({
+ "large_image":{"url":"https://doodle.com/img.jpg"}
+ })json";
+ base::Optional<DoodleConfig> config =
+ DoodleConfigFromJson(json, base::nullopt);
+ ASSERT_TRUE(config.has_value());
+ EXPECT_THAT(config->doodle_type, Eq(DoodleType::UNKNOWN));
+ EXPECT_THAT(config->alt_text, Eq(std::string()));
+ EXPECT_THAT(config->interactive_html, Eq(std::string()));
+ EXPECT_THAT(config->target_url, Eq(GURL()));
+ EXPECT_FALSE(config->large_cta_image.has_value());
+ EXPECT_FALSE(config->transparent_large_image.has_value());
+}
+
+TEST(DoodleConfigTest, ParsesFullConfig) {
+ std::string json = R"json({
+ "doodle_type":"SLIDESHOW",
+ "alt_text":"some text",
+ "interactive_html":"<div id='dood'></div>",
+ "target_url":"https://doodle.com/target",
+ "large_image":{"url":"https://doodle.com/img.jpg"},
+ "large_cta_image":{"url":"https://doodle.com/cta.jpg"},
+ "transparent_large_image":{"url":"https://doodle.com/transparent.jpg"}
+ })json";
+ base::Optional<DoodleConfig> config =
+ DoodleConfigFromJson(json, base::nullopt);
+ ASSERT_TRUE(config.has_value());
+ EXPECT_THAT(config->doodle_type, Eq(DoodleType::SLIDESHOW));
+ EXPECT_THAT(config->alt_text, Eq("some text"));
+ EXPECT_THAT(config->interactive_html, Eq("<div id='dood'></div>"));
+ EXPECT_THAT(config->target_url, Eq(GURL("https://doodle.com/target")));
+ EXPECT_THAT(config->large_image.url, Eq(GURL("https://doodle.com/img.jpg")));
+ ASSERT_TRUE(config->large_cta_image.has_value());
+ EXPECT_THAT(config->large_cta_image->url,
+ Eq(GURL("https://doodle.com/cta.jpg")));
+ ASSERT_TRUE(config->transparent_large_image.has_value());
+ EXPECT_THAT(config->transparent_large_image->url,
+ Eq(GURL("https://doodle.com/transparent.jpg")));
+}
+
+TEST(DoodleConfigTest, RequiresLargeImage) {
+ std::string json = R"json({
+ "doodle_type":"SLIDESHOW",
+ "alt_text":"some text",
+ "interactive_html":"<div id='dood'></div>",
+ "target_url":"https://doodle.com/target",
+ "large_cta_image":{"url":"https://doodle.com/cta.jpg"},
+ "transparent_large_image":{"url":"https://doodle.com/transparent.jpg"}
+ })json";
+ base::Optional<DoodleConfig> config =
+ DoodleConfigFromJson(json, base::nullopt);
+ EXPECT_FALSE(config.has_value());
+}
+
+TEST(DoodleConfigTest, RequiresValidLargeImage) {
+ std::string json = R"json({
+ "doodle_type":"SLIDESHOW",
+ "alt_text":"some text",
+ "interactive_html":"<div id='dood'></div>",
+ "target_url":"https://doodle.com/target",
+ "large_image":{"no_url":"asdf"},
+ "large_cta_image":{"url":"https://doodle.com/cta.jpg"},
+ "transparent_large_image":{"url":"https://doodle.com/transparent.jpg"}
+ })json";
+ base::Optional<DoodleConfig> config =
+ DoodleConfigFromJson(json, base::nullopt);
+ EXPECT_FALSE(config.has_value());
+}
+
+TEST(DoodleConfigTest, ResolvesRelativeUrls) {
+ std::string json = R"json({
+ "target_url":"/target",
+ "large_image":{"url":"/large.jpg"},
+ "large_cta_image":{"url":"/cta.jpg"},
+ "transparent_large_image":{"url":"/transparent.jpg"}
+ })json";
+ base::Optional<DoodleConfig> config =
+ DoodleConfigFromJson(json, GURL("https://doodle.com/"));
+ ASSERT_TRUE(config.has_value());
+ EXPECT_THAT(config->target_url, Eq(GURL("https://doodle.com/target")));
+ EXPECT_THAT(config->large_image.url,
+ Eq(GURL("https://doodle.com/large.jpg")));
+ ASSERT_TRUE(config->large_cta_image.has_value());
+ EXPECT_THAT(config->large_cta_image->url,
+ Eq(GURL("https://doodle.com/cta.jpg")));
+ ASSERT_TRUE(config->transparent_large_image.has_value());
+ EXPECT_THAT(config->transparent_large_image->url,
+ Eq(GURL("https://doodle.com/transparent.jpg")));
+}
+
+TEST(DoodleConfigTest, HandlesInvalidUrls) {
+ std::string json = R"json({
+ "target_url":"not_a_url",
+ "large_image":{"url":"https://doodle.com/img.jpg"}
+ })json";
+ base::Optional<DoodleConfig> config =
+ DoodleConfigFromJson(json, base::nullopt);
+ // All the URLs are optional, so invalid ones shouldn't matter.
+ ASSERT_TRUE(config.has_value());
+ EXPECT_TRUE(config->target_url.is_empty());
+}
+
+TEST(DoodleConfigTest, PreservesFieldsOverRoundtrip) {
+ // Set all fields to non-default values.
+ DoodleConfig config(DoodleType::SLIDESHOW,
+ DoodleImage(GURL("https://www.doodle.com/img.jpg")));
+ config.alt_text = "some text";
+ config.interactive_html = "<div id='dood'></div>";
+ config.target_url = GURL("https://doodle.com/target");
+ config.large_cta_image = DoodleImage(GURL("https://www.doodle.com/cta.jpg"));
+ config.transparent_large_image =
+ DoodleImage(GURL("https://www.doodle.com/transparent.jpg"));
+
+ // Convert to a dictionary and back.
+ // Note: The different |base_url| should make no difference, since all
+ // persisted URLs are absolute already.
+ base::Optional<DoodleConfig> after_roundtrip = DoodleConfig::FromDictionary(
+ *config.ToDictionary(), GURL("https://other.com"));
+
+ // Make sure everything survived.
+ ASSERT_TRUE(after_roundtrip.has_value());
+ EXPECT_THAT(*after_roundtrip, Eq(config));
+}
+
+} // namespace doodle
diff --git a/chromium/components/doodle/pref_names.cc b/chromium/components/doodle/pref_names.cc
new file mode 100644
index 00000000000..17ff266090e
--- /dev/null
+++ b/chromium/components/doodle/pref_names.cc
@@ -0,0 +1,14 @@
+// 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/doodle/pref_names.h"
+
+namespace doodle {
+namespace prefs {
+
+const char kCachedConfig[] = "doodle.cached_config";
+const char kCachedConfigExpiry[] = "doodle.cached_config_expiry";
+
+} // namespace prefs
+} // namespace doodle
diff --git a/chromium/components/doodle/pref_names.h b/chromium/components/doodle/pref_names.h
new file mode 100644
index 00000000000..20d7b061a1a
--- /dev/null
+++ b/chromium/components/doodle/pref_names.h
@@ -0,0 +1,17 @@
+// 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_DOODLE_PREF_NAMES_H_
+#define COMPONENTS_DOODLE_PREF_NAMES_H_
+
+namespace doodle {
+namespace prefs {
+
+extern const char kCachedConfig[];
+extern const char kCachedConfigExpiry[];
+
+} // namespace prefs
+} // namespace doodle
+
+#endif // COMPONENTS_DOODLE_PREF_NAMES_H_
diff --git a/chromium/components/error_page/OWNERS b/chromium/components/error_page/OWNERS
index 2b70a4c33b6..bebb2c48565 100644
--- a/chromium/components/error_page/OWNERS
+++ b/chromium/components/error_page/OWNERS
@@ -3,4 +3,6 @@ juliatuttle@chromium.org
# If changing network error strings, please visit go/chrome-neterror-strings
# (Google internal) or contact edwardjung@chromium.org and rachelis@chromium.org
-per-file error_page_strings.grdp=edwardjung@chromium.org \ No newline at end of file
+per-file error_page_strings.grdp=edwardjung@chromium.org
+
+# COMPONENT: Internals>Network
diff --git a/chromium/components/error_page/common/localized_error.cc b/chromium/components/error_page/common/localized_error.cc
index 5192a110541..32cb9e9b40b 100644
--- a/chromium/components/error_page/common/localized_error.cc
+++ b/chromium/components/error_page/common/localized_error.cc
@@ -248,6 +248,12 @@ const LocalizedErrorMap net_error_options[] = {
SUGGEST_CONTACT_ADMINISTRATOR,
SHOW_NO_BUTTONS,
},
+ {net::ERR_SSL_VERSION_INTERFERENCE,
+ IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
+ IDS_ERRORPAGES_SUMMARY_CONNECTION_FAILED,
+ SUGGEST_CHECK_CONNECTION | SUGGEST_FIREWALL_CONFIG | SUGGEST_PROXY_CONFIG,
+ SHOW_BUTTON_RELOAD,
+ },
{net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY,
IDS_ERRORPAGES_HEADING_INSECURE_CONNECTION,
IDS_ERRORPAGES_SUMMARY_SSL_SECURITY_ERROR,
@@ -757,6 +763,9 @@ base::DictionaryValue* AddSuggestionDetailDictionaryToList(
l10n_util::GetStringUTF16(body_message_id));
}
list->Append(base::WrapUnique(suggestion_list_item));
+ // |suggestion_list_item| is invalidated at this point, so it needs to be
+ // reset.
+ list->GetDictionary(list->GetSize() - 1, &suggestion_list_item);
return suggestion_list_item;
}
diff --git a/chromium/components/error_page/renderer/net_error_helper_core.cc b/chromium/components/error_page/renderer/net_error_helper_core.cc
index e9c1eef43d7..287cd84def6 100644
--- a/chromium/components/error_page/renderer/net_error_helper_core.cc
+++ b/chromium/components/error_page/renderer/net_error_helper_core.cc
@@ -129,7 +129,7 @@ base::TimeDelta GetAutoReloadTime(size_t reload_count) {
// Returns whether |error| is a DNS-related error (and therefore whether
// the tab helper should start a DNS probe after receiving it).
bool IsBlinkDnsError(const blink::WebURLError& error) {
- return (error.domain.utf8() == net::kErrorDomain) &&
+ return (error.domain.Utf8() == net::kErrorDomain) &&
net::IsDnsError(error.reason);
}
@@ -163,11 +163,11 @@ bool ShouldUseFixUrlServiceForError(const blink::WebURLError& error,
error_param->clear();
// Don't use the correction service for HTTPS (for privacy reasons).
- GURL unreachable_url(error.unreachableURL);
+ GURL unreachable_url(error.unreachable_url);
if (GURL(unreachable_url).SchemeIsCryptographic())
return false;
- std::string domain = error.domain.utf8();
+ std::string domain = error.domain.Utf8();
if (domain == url::kHttpScheme && error.reason == 404) {
*error_param = "http404";
return true;
@@ -230,7 +230,7 @@ std::string CreateFixUrlRequestBody(
// TODO(mmenke): Investigate open sourcing the relevant protocol buffers and
// using those directly instead.
std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
- params->SetString("urlQuery", PrepareUrlForUpload(error.unreachableURL));
+ params->SetString("urlQuery", PrepareUrlForUpload(error.unreachable_url));
return CreateRequestBody("linkdoctor.fixurl.fixurl", error_param,
correction_params, std::move(params));
}
@@ -247,7 +247,7 @@ std::string CreateClickTrackingUrlRequestBody(
std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
params->SetString("originalUrlQuery",
- PrepareUrlForUpload(error.unreachableURL));
+ PrepareUrlForUpload(error.unreachable_url));
params->SetString("clickedUrlCorrection", correction.url_correction);
params->SetString("clickType", correction.click_type);
@@ -297,7 +297,7 @@ std::unique_ptr<ErrorPageParams> CreateErrorPageParams(
// Version of URL for display in suggestions. It has to be sanitized first
// because any received suggestions will be relative to the sanitized URL.
base::string16 original_url_for_display =
- FormatURLForDisplay(SanitizeURL(GURL(error.unreachableURL)), is_rtl);
+ FormatURLForDisplay(SanitizeURL(GURL(error.unreachable_url)), is_rtl);
std::unique_ptr<ErrorPageParams> params(new ErrorPageParams());
params->override_suggestions.reset(new base::ListValue());
@@ -368,7 +368,7 @@ std::unique_ptr<ErrorPageParams> CreateErrorPageParams(
}
void ReportAutoReloadSuccess(const blink::WebURLError& error, size_t count) {
- if (error.domain.utf8() != net::kErrorDomain)
+ if (error.domain.Utf8() != net::kErrorDomain)
return;
UMA_HISTOGRAM_SPARSE_SLOWLY("Net.AutoReload.ErrorAtSuccess", -error.reason);
UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtSuccess",
@@ -380,7 +380,7 @@ void ReportAutoReloadSuccess(const blink::WebURLError& error, size_t count) {
}
void ReportAutoReloadFailure(const blink::WebURLError& error, size_t count) {
- if (error.domain.utf8() != net::kErrorDomain)
+ if (error.domain.Utf8() != net::kErrorDomain)
return;
UMA_HISTOGRAM_SPARSE_SLOWLY("Net.AutoReload.ErrorAtStop", -error.reason);
UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtStop",
@@ -483,8 +483,8 @@ NetErrorHelperCore::NavigationCorrectionParams::~NavigationCorrectionParams() {
bool NetErrorHelperCore::IsReloadableError(
const NetErrorHelperCore::ErrorPageInfo& info) {
- GURL url = info.error.unreachableURL;
- return info.error.domain.utf8() == net::kErrorDomain &&
+ GURL url = info.error.unreachable_url;
+ return info.error.domain.Utf8() == net::kErrorDomain &&
info.error.reason != net::ERR_ABORTED &&
// For now, net::ERR_UNKNOWN_URL_SCHEME is only being displayed on
// Chrome for Android.
@@ -605,8 +605,8 @@ void NetErrorHelperCore::OnCommitLoad(FrameType frame_type, const GURL& url) {
// result is from the page reload button.
if (committed_error_page_info_ && pending_error_page_info_ &&
navigation_from_button_ != NO_BUTTON &&
- committed_error_page_info_->error.unreachableURL ==
- pending_error_page_info_->error.unreachableURL) {
+ committed_error_page_info_->error.unreachable_url ==
+ pending_error_page_info_->error.unreachable_url) {
DCHECK(navigation_from_button_ == RELOAD_BUTTON ||
navigation_from_button_ == SHOW_SAVED_COPY_BUTTON);
RecordEvent(navigation_from_button_ == RELOAD_BUTTON ?
@@ -618,7 +618,7 @@ void NetErrorHelperCore::OnCommitLoad(FrameType frame_type, const GURL& url) {
if (committed_error_page_info_ && !pending_error_page_info_ &&
committed_error_page_info_->auto_reload_triggered) {
const blink::WebURLError& error = committed_error_page_info_->error;
- const GURL& error_url = error.unreachableURL;
+ const GURL& error_url = error.unreachable_url;
if (url == error_url)
ReportAutoReloadSuccess(error, auto_reload_count_);
else if (url != content::kUnreachableWebDataURL)
@@ -853,7 +853,7 @@ void NetErrorHelperCore::OnNavigationCorrectionsFetched(
// double page load by just updating the error page, like DNS
// probes do.
delegate_->LoadErrorPage(error_html,
- pending_error_page_info_->error.unreachableURL);
+ pending_error_page_info_->error.unreachable_url);
}
blink::WebURLError NetErrorHelperCore::GetUpdatedError(
@@ -865,10 +865,10 @@ blink::WebURLError NetErrorHelperCore::GetUpdatedError(
}
blink::WebURLError updated_error;
- updated_error.domain = blink::WebString::fromUTF8(kDnsProbeErrorDomain);
+ updated_error.domain = blink::WebString::FromUTF8(kDnsProbeErrorDomain);
updated_error.reason = last_probe_status_;
- updated_error.unreachableURL = error.unreachableURL;
- updated_error.staleCopyInCache = error.staleCopyInCache;
+ updated_error.unreachable_url = error.unreachable_url;
+ updated_error.stale_copy_in_cache = error.stale_copy_in_cache;
return updated_error;
}
@@ -989,7 +989,7 @@ void NetErrorHelperCore::ExecuteButtonPress(Button button) {
RecordEvent(NETWORK_ERROR_PAGE_BOTH_BUTTONS_SHOWN_SAVED_COPY_CLICKED);
}
delegate_->LoadPageFromCache(
- committed_error_page_info_->error.unreachableURL);
+ committed_error_page_info_->error.unreachable_url);
return;
case MORE_BUTTON:
// Visual effects on page are handled in Javascript code.
@@ -1004,7 +1004,7 @@ void NetErrorHelperCore::ExecuteButtonPress(Button button) {
case DIAGNOSE_ERROR:
RecordEvent(NETWORK_ERROR_DIAGNOSE_BUTTON_CLICKED);
delegate_->DiagnoseError(
- committed_error_page_info_->error.unreachableURL);
+ committed_error_page_info_->error.unreachable_url);
return;
case DOWNLOAD_BUTTON:
RecordEvent(NETWORK_ERROR_PAGE_DOWNLOAD_BUTTON_CLICKED);
diff --git a/chromium/components/error_page/renderer/net_error_helper_core_unittest.cc b/chromium/components/error_page/renderer/net_error_helper_core_unittest.cc
index db07d6862e2..f67d1cd4991 100644
--- a/chromium/components/error_page/renderer/net_error_helper_core_unittest.cc
+++ b/chromium/components/error_page/renderer/net_error_helper_core_unittest.cc
@@ -114,23 +114,23 @@ testing::AssertionResult StringValueEquals(
// error page for that error.
std::string ErrorToString(const WebURLError& error, bool is_failed_post) {
return base::StringPrintf("(%s, %s, %i, %s)",
- error.unreachableURL.string().utf8().c_str(),
- error.domain.utf8().c_str(), error.reason,
+ error.unreachable_url.GetString().Utf8().c_str(),
+ error.domain.Utf8().c_str(), error.reason,
is_failed_post ? "POST" : "NOT POST");
}
WebURLError ProbeError(DnsProbeStatus status) {
WebURLError error;
- error.unreachableURL = GURL(kFailedUrl);
- error.domain = blink::WebString::fromUTF8(kDnsProbeErrorDomain);
+ error.unreachable_url = GURL(kFailedUrl);
+ error.domain = blink::WebString::FromUTF8(kDnsProbeErrorDomain);
error.reason = status;
return error;
}
WebURLError NetErrorForURL(net::Error net_error, const GURL& url) {
WebURLError error;
- error.unreachableURL = url;
- error.domain = blink::WebString::fromUTF8(net::kErrorDomain);
+ error.unreachable_url = url;
+ error.domain = blink::WebString::FromUTF8(net::kErrorDomain);
error.reason = net_error;
return error;
}
@@ -1176,13 +1176,13 @@ TEST_F(NetErrorHelperCoreTest, NoCorrectionsForHttps) {
// The HTTPS page fails to load.
std::string html;
blink::WebURLError error = NetError(net::ERR_NAME_NOT_RESOLVED);
- error.unreachableURL = GURL(kFailedHttpsUrl);
+ error.unreachable_url = GURL(kFailedHttpsUrl);
core()->GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, error,
false /* is_failed_post */,
false /* is_ignoring_cache */, &html);
blink::WebURLError probe_error = ProbeError(DNS_PROBE_POSSIBLE);
- probe_error.unreachableURL = GURL(kFailedHttpsUrl);
+ probe_error.unreachable_url = GURL(kFailedHttpsUrl);
EXPECT_EQ(ErrorToString(probe_error, false), html);
EXPECT_FALSE(is_url_being_fetched());
EXPECT_FALSE(last_error_page_params());
@@ -1203,7 +1203,7 @@ TEST_F(NetErrorHelperCoreTest, NoCorrectionsForHttps) {
EXPECT_FALSE(last_error_page_params());
blink::WebURLError final_probe_error =
ProbeError(DNS_PROBE_FINISHED_NXDOMAIN);
- final_probe_error.unreachableURL = GURL(kFailedHttpsUrl);
+ final_probe_error.unreachable_url = GURL(kFailedHttpsUrl);
EXPECT_EQ(ErrorToString(final_probe_error, false), last_error_html());
}
diff --git a/chromium/components/exo/BUILD.gn b/chromium/components/exo/BUILD.gn
index e91c8e0417a..3edaf861812 100644
--- a/chromium/components/exo/BUILD.gn
+++ b/chromium/components/exo/BUILD.gn
@@ -93,7 +93,6 @@ source_set("test_support") {
deps = [
":exo",
"//ash/public/cpp:ash_public_cpp",
- "//ash/test:ash_with_aura_test_support",
"//ash/test:test_support_without_content",
"//base",
"//gpu",
@@ -131,6 +130,7 @@ source_set("unit_tests") {
"//base",
"//base/test:test_support",
"//cc",
+ "//cc:test_support",
"//cc/surfaces:surfaces",
"//components/user_manager",
"//device/gamepad:test_helpers",
@@ -162,7 +162,7 @@ test("exo_unittests") {
deps = [
":unit_tests",
- "//ash/test:ash_with_aura_test_support",
+ "//ash/public/cpp:ash_public_cpp",
"//ash/test:test_support_without_content",
"//base",
"//base/test:test_support",
@@ -171,6 +171,7 @@ test("exo_unittests") {
"//testing/gtest",
"//ui/aura",
"//ui/base",
+ "//ui/compositor:test_support",
"//ui/gl:test_support",
]
diff --git a/chromium/components/exo/buffer.cc b/chromium/components/exo/buffer.cc
index d9f29ec71e9..0588175c463 100644
--- a/chromium/components/exo/buffer.cc
+++ b/chromium/components/exo/buffer.cc
@@ -53,6 +53,7 @@ GLenum GLInternalFormat(gfx::BufferFormat format) {
GL_RGBA, // RGBA_8888
GL_RGB, // BGRX_8888
GL_BGRA_EXT, // BGRA_8888
+ GL_RGBA, // RGBA_F16
GL_RGB_YCRCB_420_CHROMIUM, // YVU_420
GL_RGB_YCBCR_420V_CHROMIUM, // YUV_420_BIPLANAR
GL_RGB_YCBCR_422_CHROMIUM, // UYVY_422
@@ -457,6 +458,7 @@ bool Buffer::ProduceTransferableResource(
resource->mailbox_holder = gpu::MailboxHolder(contents_texture->mailbox(),
sync_token, texture_target_);
resource->is_overlay_candidate = is_overlay_candidate_;
+ resource->buffer_format = gpu_memory_buffer_->GetFormat();
// The contents texture will be released when no longer used by the
// compositor.
diff --git a/chromium/components/exo/compositor_frame_sink.cc b/chromium/components/exo/compositor_frame_sink.cc
index 895d513fa98..cee2955b41b 100644
--- a/chromium/components/exo/compositor_frame_sink.cc
+++ b/chromium/components/exo/compositor_frame_sink.cc
@@ -18,12 +18,13 @@ namespace exo {
CompositorFrameSink::CompositorFrameSink(const cc::FrameSinkId& frame_sink_id,
cc::SurfaceManager* surface_manager,
CompositorFrameSinkHolder* client)
- : support_(this,
- surface_manager,
- frame_sink_id,
- false /* is_root */,
- true /* handles_frame_sink_id_invalidation */,
- true /* needs_sync_points */),
+ : support_(cc::CompositorFrameSinkSupport::Create(
+ this,
+ surface_manager,
+ frame_sink_id,
+ false /* is_root */,
+ true /* handles_frame_sink_id_invalidation */,
+ true /* needs_sync_points */)),
client_(client) {}
CompositorFrameSink::~CompositorFrameSink() {}
@@ -32,24 +33,30 @@ CompositorFrameSink::~CompositorFrameSink() {}
// cc::mojom::MojoCompositorFrameSink overrides:
void CompositorFrameSink::SetNeedsBeginFrame(bool needs_begin_frame) {
- support_.SetNeedsBeginFrame(needs_begin_frame);
+ support_->SetNeedsBeginFrame(needs_begin_frame);
}
void CompositorFrameSink::SubmitCompositorFrame(
const cc::LocalSurfaceId& local_surface_id,
cc::CompositorFrame frame) {
- support_.SubmitCompositorFrame(local_surface_id, std::move(frame));
+ support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
+}
+
+void CompositorFrameSink::BeginFrameDidNotSwap(
+ const cc::BeginFrameAck& begin_frame_ack) {
+ support_->BeginFrameDidNotSwap(begin_frame_ack);
}
void CompositorFrameSink::EvictFrame() {
- support_.EvictFrame();
+ support_->EvictFrame();
}
////////////////////////////////////////////////////////////////////////////////
// cc::CompositorFrameSinkSupportClient overrides:
-void CompositorFrameSink::DidReceiveCompositorFrameAck() {
- client_->DidReceiveCompositorFrameAck();
+void CompositorFrameSink::DidReceiveCompositorFrameAck(
+ const cc::ReturnedResourceArray& resources) {
+ client_->DidReceiveCompositorFrameAck(resources);
}
void CompositorFrameSink::OnBeginFrame(const cc::BeginFrameArgs& args) {
@@ -61,10 +68,4 @@ void CompositorFrameSink::ReclaimResources(
client_->ReclaimResources(resources);
}
-void CompositorFrameSink::WillDrawSurface(
- const cc::LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) {
- client_->WillDrawSurface(local_surface_id, damage_rect);
-}
-
} // namespace exo
diff --git a/chromium/components/exo/compositor_frame_sink.h b/chromium/components/exo/compositor_frame_sink.h
index 3bfc7dd212b..7da2b6b2a38 100644
--- a/chromium/components/exo/compositor_frame_sink.h
+++ b/chromium/components/exo/compositor_frame_sink.h
@@ -29,17 +29,19 @@ class CompositorFrameSink : public cc::CompositorFrameSinkSupportClient,
void SetNeedsBeginFrame(bool needs_begin_frame) override;
void SubmitCompositorFrame(const cc::LocalSurfaceId& local_surface_id,
cc::CompositorFrame frame) override;
+ void BeginFrameDidNotSwap(const cc::BeginFrameAck& begin_frame_ack) override;
void EvictFrame() override;
// Overridden from cc::CompositorFrameSinkSupportClient:
- void DidReceiveCompositorFrameAck() override;
+ void DidReceiveCompositorFrameAck(
+ const cc::ReturnedResourceArray& resources) override;
void OnBeginFrame(const cc::BeginFrameArgs& args) override;
void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) override;
+ const gfx::Rect& damage_rect) override {}
private:
- cc::CompositorFrameSinkSupport support_;
+ std::unique_ptr<cc::CompositorFrameSinkSupport> support_;
CompositorFrameSinkHolder* const client_;
DISALLOW_COPY_AND_ASSIGN(CompositorFrameSink);
diff --git a/chromium/components/exo/compositor_frame_sink_holder.cc b/chromium/components/exo/compositor_frame_sink_holder.cc
index 3d55a7d68b1..b516b842a52 100644
--- a/chromium/components/exo/compositor_frame_sink_holder.cc
+++ b/chromium/components/exo/compositor_frame_sink_holder.cc
@@ -22,6 +22,7 @@ CompositorFrameSinkHolder::CompositorFrameSinkHolder(
begin_frame_source_(base::MakeUnique<cc::ExternalBeginFrameSource>(this)),
weak_factory_(this) {
surface_->AddSurfaceObserver(this);
+ surface_->SetBeginFrameSource(begin_frame_source_.get());
}
bool CompositorFrameSinkHolder::HasReleaseCallbackForResource(
@@ -36,23 +37,17 @@ void CompositorFrameSinkHolder::SetResourceReleaseCallback(
release_callbacks_[id] = callback;
}
-void CompositorFrameSinkHolder::SetNeedsBeginFrame(bool needs_begin_frame) {
- needs_begin_frame_ = needs_begin_frame;
- OnNeedsBeginFrames(needs_begin_frame);
-}
-
////////////////////////////////////////////////////////////////////////////////
// cc::mojom::MojoCompositorFrameSinkClient overrides:
-void CompositorFrameSinkHolder::DidReceiveCompositorFrameAck() {
- // TODO(staraz): Implement this
+void CompositorFrameSinkHolder::DidReceiveCompositorFrameAck(
+ const cc::ReturnedResourceArray& resources) {
+ ReclaimResources(resources);
+ if (surface_)
+ surface_->DidReceiveCompositorFrameAck();
}
void CompositorFrameSinkHolder::OnBeginFrame(const cc::BeginFrameArgs& args) {
- // TODO(eseckler): Hook up |surface_| to the ExternalBeginFrameSource.
- if (surface_)
- surface_->BeginFrame(args.frame_time);
-
begin_frame_source_->OnBeginFrame(args);
}
@@ -68,34 +63,17 @@ void CompositorFrameSinkHolder::ReclaimResources(
}
}
-void CompositorFrameSinkHolder::WillDrawSurface(
- const cc::LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) {
- if (surface_)
- surface_->WillDraw();
-
- UpdateNeedsBeginFrame();
-}
-
////////////////////////////////////////////////////////////////////////////////
-// cc::BeginFrameObserver overrides:
-
-const cc::BeginFrameArgs& CompositorFrameSinkHolder::LastUsedBeginFrameArgs()
- const {
- return last_begin_frame_args_;
-}
-
-void CompositorFrameSinkHolder::OnBeginFrameSourcePausedChanged(bool paused) {}
-
-////////////////////////////////////////////////////////////////////////////////
-// cc::ExternalBeginFrameSouceClient overrides:
+// cc::ExternalBeginFrameSourceClient overrides:
void CompositorFrameSinkHolder::OnNeedsBeginFrames(bool needs_begin_frames) {
frame_sink_->SetNeedsBeginFrame(needs_begin_frames);
}
void CompositorFrameSinkHolder::OnDidFinishFrame(const cc::BeginFrameAck& ack) {
- // TODO(eseckler): Pass on the ack to frame_sink_.
+ // If there was damage, the submitted CompositorFrame includes the ack.
+ if (!ack.has_damage)
+ frame_sink_->BeginFrameDidNotSwap(ack);
}
////////////////////////////////////////////////////////////////////////////////
@@ -114,16 +92,4 @@ CompositorFrameSinkHolder::~CompositorFrameSinkHolder() {
surface_->RemoveSurfaceObserver(this);
}
-void CompositorFrameSinkHolder::UpdateNeedsBeginFrame() {
- if (!begin_frame_source_)
- return;
-
- bool needs_begin_frame = surface_ && surface_->NeedsBeginFrame();
- if (needs_begin_frame == needs_begin_frame_)
- return;
-
- needs_begin_frame_ = needs_begin_frame;
- OnNeedsBeginFrames(needs_begin_frame_);
-}
-
} // namespace exo
diff --git a/chromium/components/exo/compositor_frame_sink_holder.h b/chromium/components/exo/compositor_frame_sink_holder.h
index 4f3b0a21d89..a469929e4b7 100644
--- a/chromium/components/exo/compositor_frame_sink_holder.h
+++ b/chromium/components/exo/compositor_frame_sink_holder.h
@@ -28,7 +28,6 @@ class CompositorFrameSinkHolder
: public base::RefCounted<CompositorFrameSinkHolder>,
public cc::ExternalBeginFrameSourceClient,
public cc::mojom::MojoCompositorFrameSinkClient,
- public cc::BeginFrameObserver,
public SurfaceObserver {
public:
CompositorFrameSinkHolder(Surface* surface,
@@ -45,18 +44,11 @@ class CompositorFrameSinkHolder
return weak_factory_.GetWeakPtr();
}
- void SetNeedsBeginFrame(bool needs_begin_frame);
-
// Overridden from cc::mojom::MojoCompositorFrameSinkClient:
- void DidReceiveCompositorFrameAck() override;
+ void DidReceiveCompositorFrameAck(
+ const cc::ReturnedResourceArray& resources) override;
void OnBeginFrame(const cc::BeginFrameArgs& args) override;
void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
- void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) override;
-
- // Overridden from cc::BeginFrameObserver:
- const cc::BeginFrameArgs& LastUsedBeginFrameArgs() const override;
- void OnBeginFrameSourcePausedChanged(bool paused) override;
// Overridden from cc::ExternalBeginFrameSourceClient:
void OnNeedsBeginFrames(bool needs_begin_frames) override;
@@ -70,18 +62,13 @@ class CompositorFrameSinkHolder
~CompositorFrameSinkHolder() override;
- void UpdateNeedsBeginFrame();
-
// A collection of callbacks used to release resources.
using ResourceReleaseCallbackMap = std::map<int, cc::ReleaseCallback>;
ResourceReleaseCallbackMap release_callbacks_;
Surface* surface_;
std::unique_ptr<CompositorFrameSink> frame_sink_;
-
std::unique_ptr<cc::ExternalBeginFrameSource> begin_frame_source_;
- bool needs_begin_frame_ = false;
- cc::BeginFrameArgs last_begin_frame_args_;
base::WeakPtrFactory<CompositorFrameSinkHolder> weak_factory_;
diff --git a/chromium/components/exo/display.cc b/chromium/components/exo/display.cc
index 44b975a2425..7e38bb47686 100644
--- a/chromium/components/exo/display.cc
+++ b/chromium/components/exo/display.cc
@@ -24,7 +24,7 @@
#if defined(USE_OZONE)
#include <GLES2/gl2extchromium.h>
#include "components/exo/buffer.h"
-#include "gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.h"
+#include "gpu/ipc/client/gpu_memory_buffer_impl_native_pixmap.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "ui/ozone/public/ozone_switches.h"
@@ -45,7 +45,7 @@ const gfx::BufferFormat kOverlayFormats[] = {
const gfx::BufferFormat kOverlayFormatsForDrmAtomic[] = {
gfx::BufferFormat::RGBX_8888, gfx::BufferFormat::RGBA_8888,
- gfx::BufferFormat::BGR_565};
+ gfx::BufferFormat::BGR_565, gfx::BufferFormat::YUV_420_BIPLANAR};
#endif
} // namespace
@@ -101,7 +101,7 @@ std::unique_ptr<Buffer> Display::CreateLinuxDMABufBuffer(
size.ToString());
gfx::GpuMemoryBufferHandle handle;
- handle.type = gfx::OZONE_NATIVE_PIXMAP;
+ handle.type = gfx::NATIVE_PIXMAP;
for (auto& fd : fds)
handle.native_pixmap_handle.fds.emplace_back(std::move(fd));
@@ -109,7 +109,7 @@ std::unique_ptr<Buffer> Display::CreateLinuxDMABufBuffer(
handle.native_pixmap_handle.planes.push_back(plane);
std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
- gpu::GpuMemoryBufferImplOzoneNativePixmap::CreateFromHandle(
+ gpu::GpuMemoryBufferImplNativePixmap::CreateFromHandle(
handle, size, format, gfx::BufferUsage::GPU_READ,
gpu::GpuMemoryBufferImpl::DestructionCallback());
if (!gpu_memory_buffer) {
@@ -179,7 +179,6 @@ std::unique_ptr<ShellSurface> Display::CreatePopupShellSurface(
std::unique_ptr<ShellSurface> Display::CreateRemoteShellSurface(
Surface* surface,
- const gfx::Point& origin,
int container) {
TRACE_EVENT2("exo", "Display::CreateRemoteShellSurface", "surface",
surface->AsTracedValue(), "container", container);
@@ -193,7 +192,7 @@ std::unique_ptr<ShellSurface> Display::CreateRemoteShellSurface(
bool can_minimize = container != ash::kShellWindowId_SystemModalContainer;
return base::MakeUnique<ShellSurface>(
- surface, nullptr, ShellSurface::BoundsMode::CLIENT, origin,
+ surface, nullptr, ShellSurface::BoundsMode::CLIENT, gfx::Point(),
true /* activatable */, can_minimize, container);
}
diff --git a/chromium/components/exo/display.h b/chromium/components/exo/display.h
index 7e9ee4ed681..780f4040bb2 100644
--- a/chromium/components/exo/display.h
+++ b/chromium/components/exo/display.h
@@ -76,7 +76,6 @@ class Display {
// Creates a remote shell surface for an existing surface using |container|.
std::unique_ptr<ShellSurface> CreateRemoteShellSurface(
Surface* surface,
- const gfx::Point& origin,
int container);
// Creates a sub-surface for an existing surface. The sub-surface will be
diff --git a/chromium/components/exo/display_unittest.cc b/chromium/components/exo/display_unittest.cc
index a9a4f0edbfe..a9036a4115d 100644
--- a/chromium/components/exo/display_unittest.cc
+++ b/chromium/components/exo/display_unittest.cc
@@ -13,7 +13,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#if defined(USE_OZONE)
-#include "ui/ozone/public/native_pixmap.h"
+#include "ui/gfx/native_pixmap.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/surface_factory_ozone.h"
#endif
@@ -61,7 +61,7 @@ TEST_F(DisplayTest, DISABLED_CreateLinuxDMABufBuffer) {
std::unique_ptr<Display> display(new Display);
// Creating a prime buffer from a native pixmap handle should succeed.
- scoped_refptr<ui::NativePixmap> pixmap =
+ scoped_refptr<gfx::NativePixmap> pixmap =
ui::OzonePlatform::GetInstance()
->GetSurfaceFactoryOzone()
->CreateNativePixmap(gfx::kNullAcceleratedWidget, buffer_size,
@@ -147,13 +147,12 @@ TEST_F(DisplayTest, CreateRemoteShellSurface) {
// Create a remote shell surface for surface1.
std::unique_ptr<ShellSurface> shell_surface1 =
display->CreateRemoteShellSurface(
- surface1.get(), gfx::Point(),
- ash::kShellWindowId_SystemModalContainer);
+ surface1.get(), ash::kShellWindowId_SystemModalContainer);
EXPECT_TRUE(shell_surface1);
// Create a remote shell surface for surface2.
std::unique_ptr<ShellSurface> shell_surface2 =
- display->CreateRemoteShellSurface(surface2.get(), gfx::Point(),
+ display->CreateRemoteShellSurface(surface2.get(),
ash::kShellWindowId_DefaultContainer);
EXPECT_TRUE(shell_surface2);
}
diff --git a/chromium/components/exo/gaming_seat.cc b/chromium/components/exo/gaming_seat.cc
index 67d9c25ac22..eed466c7bf5 100644
--- a/chromium/components/exo/gaming_seat.cc
+++ b/chromium/components/exo/gaming_seat.cc
@@ -124,7 +124,7 @@ class GamingSeat::ThreadSafeGamepadChangeFetcher
fetcher_->GetGamepadData(
false /* No hardware changed notification from the system */);
- for (size_t i = 0; i < blink::WebGamepads::itemsLengthCap; ++i) {
+ for (size_t i = 0; i < blink::WebGamepads::kItemsLengthCap; ++i) {
device::PadState& pad_state = pad_states_.get()[i];
// After querying the gamepad clear the state if it did not have it's
@@ -216,7 +216,7 @@ GamingSeat::~GamingSeat() {
gamepad_change_fetcher_->EnablePolling(false);
delegate_->OnGamingSeatDestroying(this);
- for (size_t i = 0; i < blink::WebGamepads::itemsLengthCap; ++i) {
+ for (size_t i = 0; i < blink::WebGamepads::kItemsLengthCap; ++i) {
if (gamepad_delegates_[i]) {
gamepad_delegates_[i]->OnRemoved();
}
@@ -279,7 +279,7 @@ void GamingSeat::ProcessGamepadChanges(int index,
// Notify delegate of updated axes.
for (size_t axis = 0;
- axis < std::max(pad_state.axesLength, new_pad.axesLength); ++axis) {
+ axis < std::max(pad_state.axes_length, new_pad.axes_length); ++axis) {
if (!GamepadButtonValuesAreEqual(new_pad.axes[axis],
pad_state.axes[axis])) {
send_frame = true;
@@ -289,7 +289,7 @@ void GamingSeat::ProcessGamepadChanges(int index,
// Notify delegate of updated buttons.
for (size_t button_id = 0;
- button_id < std::max(pad_state.buttonsLength, new_pad.buttonsLength);
+ button_id < std::max(pad_state.buttons_length, new_pad.buttons_length);
++button_id) {
auto button = pad_state.buttons[button_id];
auto new_button = new_pad.buttons[button_id];
diff --git a/chromium/components/exo/gaming_seat.h b/chromium/components/exo/gaming_seat.h
index cc7aa9a0c57..d8fcf119a2f 100644
--- a/chromium/components/exo/gaming_seat.h
+++ b/chromium/components/exo/gaming_seat.h
@@ -60,7 +60,7 @@ class GamingSeat : public WMHelper::FocusObserver {
GamingSeatDelegate* const delegate_;
// The delegate instances that all other events are dispatched to.
- GamepadDelegate* gamepad_delegates_[blink::WebGamepads::itemsLengthCap];
+ GamepadDelegate* gamepad_delegates_[blink::WebGamepads::kItemsLengthCap];
// The current state of the gamepad represented by this instance.
blink::WebGamepads pad_state_;
diff --git a/chromium/components/exo/gaming_seat_unittest.cc b/chromium/components/exo/gaming_seat_unittest.cc
index fb22d28290a..8b94ca0a5f1 100644
--- a/chromium/components/exo/gaming_seat_unittest.cc
+++ b/chromium/components/exo/gaming_seat_unittest.cc
@@ -197,7 +197,7 @@ TEST_F(GamingSeatTest, OnAxis) {
axis_moved.items[0].timestamp = 1;
axis_moved.items[2].connected = true;
axis_moved.items[2].timestamp = 2;
- axis_moved.items[2].axesLength = 1;
+ axis_moved.items[2].axes_length = 1;
axis_moved.items[2].axes[0] = 1.0;
EXPECT_CALL(gamepad_delegate2, OnAxis(0, 1.0)).Times(1);
@@ -205,7 +205,7 @@ TEST_F(GamingSeatTest, OnAxis) {
SetDataAndPostToDelegate(axis_moved);
axis_moved.items[0].timestamp = 2;
- axis_moved.items[0].axesLength = 1;
+ axis_moved.items[0].axes_length = 1;
axis_moved.items[0].axes[0] = 2.0;
EXPECT_CALL(gamepad_delegate0, OnAxis(0, 2.0)).Times(1);
@@ -257,7 +257,7 @@ TEST_F(GamingSeatTest, OnButton) {
axis_moved.items[2].connected = true;
axis_moved.items[2].timestamp = 2;
- axis_moved.items[2].buttonsLength = 1;
+ axis_moved.items[2].buttons_length = 1;
axis_moved.items[2].buttons[0].pressed = true;
axis_moved.items[2].buttons[0].value = 1.0;
@@ -266,7 +266,7 @@ TEST_F(GamingSeatTest, OnButton) {
SetDataAndPostToDelegate(axis_moved);
axis_moved.items[0].timestamp = 2;
- axis_moved.items[0].buttonsLength = 1;
+ axis_moved.items[0].buttons_length = 1;
axis_moved.items[0].buttons[0].pressed = true;
axis_moved.items[0].buttons[0].value = 2.0;
diff --git a/chromium/components/exo/pointer.cc b/chromium/components/exo/pointer.cc
index 1697f5c34dc..1cc32a42637 100644
--- a/chromium/components/exo/pointer.cc
+++ b/chromium/components/exo/pointer.cc
@@ -89,9 +89,8 @@ void Pointer::SetCursor(Surface* surface, const gfx::Point& hotspot) {
}
if (surface_) {
surface_->window()->SetTransform(gfx::Transform());
- WMHelper::GetInstance()
- ->GetContainer(ash::kShellWindowId_MouseCursorContainer)
- ->RemoveChild(surface_->window());
+ if (surface_->window()->parent())
+ surface_->window()->parent()->RemoveChild(surface_->window());
surface_->SetSurfaceDelegate(nullptr);
surface_->RemoveSurfaceObserver(this);
}
@@ -119,7 +118,7 @@ void Pointer::SetCursor(Surface* surface, const gfx::Point& hotspot) {
if (!cursor_changed)
return;
- // If |surface_| is set then ascynchrounsly capture a snapshot of cursor,
+ // If |surface_| is set then asynchronously capture a snapshot of cursor,
// otherwise cancel pending capture and immediately set the cursor to "none".
if (surface_) {
CaptureCursor();
@@ -140,9 +139,6 @@ gfx::NativeCursor Pointer::GetCursor() {
void Pointer::OnMouseEvent(ui::MouseEvent* event) {
Surface* target = GetEffectiveTargetForEvent(event);
- if (event->flags() & ui::EF_TOUCH_ACCESSIBILITY)
- return;
-
// If target is different than the current pointer focus then we need to
// generate enter and leave events.
if (target != focus_) {
@@ -169,7 +165,10 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) {
delegate_->OnPointerFrame();
}
- if (focus_ && event->IsMouseEvent() && event->type() != ui::ET_MOUSE_EXITED) {
+ if (!focus_)
+ return;
+
+ if (event->IsMouseEvent() && event->type() != ui::ET_MOUSE_EXITED) {
// Generate motion event if location changed. We need to check location
// here as mouse movement can generate both "moved" and "entered" events
// but OnPointerMotion should only be called if location changed since
@@ -183,44 +182,52 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) {
switch (event->type()) {
case ui::ET_MOUSE_PRESSED:
- case ui::ET_MOUSE_RELEASED:
- if (focus_) {
- delegate_->OnPointerButton(event->time_stamp(),
- event->changed_button_flags(),
- event->type() == ui::ET_MOUSE_PRESSED);
- delegate_->OnPointerFrame();
- }
+ case ui::ET_MOUSE_RELEASED: {
+ delegate_->OnPointerButton(event->time_stamp(),
+ event->changed_button_flags(),
+ event->type() == ui::ET_MOUSE_PRESSED);
+ delegate_->OnPointerFrame();
break;
- case ui::ET_SCROLL:
- if (focus_) {
- ui::ScrollEvent* scroll_event = static_cast<ui::ScrollEvent*>(event);
- delegate_->OnPointerScroll(
- event->time_stamp(),
- gfx::Vector2dF(scroll_event->x_offset(), scroll_event->y_offset()),
- false);
- delegate_->OnPointerFrame();
- }
+ }
+ case ui::ET_SCROLL: {
+ ui::ScrollEvent* scroll_event = static_cast<ui::ScrollEvent*>(event);
+ delegate_->OnPointerScroll(
+ event->time_stamp(),
+ gfx::Vector2dF(scroll_event->x_offset(), scroll_event->y_offset()),
+ false);
+ delegate_->OnPointerFrame();
break;
- case ui::ET_MOUSEWHEEL:
- if (focus_) {
- delegate_->OnPointerScroll(
- event->time_stamp(),
- static_cast<ui::MouseWheelEvent*>(event)->offset(), true);
- delegate_->OnPointerFrame();
- }
+ }
+ case ui::ET_MOUSEWHEEL: {
+ delegate_->OnPointerScroll(
+ event->time_stamp(),
+ static_cast<ui::MouseWheelEvent*>(event)->offset(), true);
+ delegate_->OnPointerFrame();
break;
- case ui::ET_SCROLL_FLING_START:
- if (focus_) {
- delegate_->OnPointerScrollStop(event->time_stamp());
- delegate_->OnPointerFrame();
- }
+ }
+ case ui::ET_SCROLL_FLING_START: {
+ // Fling start in chrome signals the lifting of fingers after scrolling.
+ // In wayland terms this signals the end of a scroll sequence.
+ delegate_->OnPointerScrollStop(event->time_stamp());
+ delegate_->OnPointerFrame();
break;
- case ui::ET_SCROLL_FLING_CANCEL:
- if (focus_) {
- delegate_->OnPointerScrollCancel(event->time_stamp());
+ }
+ case ui::ET_SCROLL_FLING_CANCEL: {
+ // Fling cancel is generated very generously at every touch of the
+ // touchpad. Since it's not directly supported by the delegate, we do not
+ // want limit this event to only right after a fling start has been
+ // generated to prevent erronous behavior.
+ if (last_event_type_ == ui::ET_SCROLL_FLING_START) {
+ // We emulate fling cancel by starting a new scroll sequence that
+ // scrolls by 0 pixels, effectively stopping any kinetic scroll motion.
+ delegate_->OnPointerScroll(event->time_stamp(), gfx::Vector2dF(),
+ false);
+ delegate_->OnPointerFrame();
+ delegate_->OnPointerScrollStop(event->time_stamp());
delegate_->OnPointerFrame();
}
break;
+ }
case ui::ET_MOUSE_MOVED:
case ui::ET_MOUSE_DRAGGED:
case ui::ET_MOUSE_ENTERED:
@@ -232,14 +239,17 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) {
break;
}
- if (focus_)
- UpdateCursorScale();
+ last_event_type_ = event->type();
+ UpdateCursorScale();
}
void Pointer::OnScrollEvent(ui::ScrollEvent* event) {
OnMouseEvent(event);
}
+////////////////////////////////////////////////////////////////////////////////
+// WMHelper::CursorObserver overrides:
+
void Pointer::OnCursorSetChanged(ui::CursorSetType cursor_set) {
if (focus_)
UpdateCursorScale();
@@ -324,6 +334,7 @@ void Pointer::UpdateCursorScale() {
void Pointer::CaptureCursor() {
DCHECK(surface_);
+ DCHECK(focus_);
// Set UI scale before submitting capture request.
surface_->window()->layer()->SetTransform(
diff --git a/chromium/components/exo/pointer.h b/chromium/components/exo/pointer.h
index 67a12efedb1..07cf6bdc026 100644
--- a/chromium/components/exo/pointer.h
+++ b/chromium/components/exo/pointer.h
@@ -14,6 +14,7 @@
#include "components/exo/surface_observer.h"
#include "components/exo/wm_helper.h"
#include "ui/base/cursor/cursor.h"
+#include "ui/events/event_constants.h"
#include "ui/events/event_handler.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_f.h"
@@ -107,6 +108,9 @@ class Pointer : public ui::EventHandler,
// Source used for cursor capture copy output requests.
const base::UnguessableToken cursor_capture_source_id_;
+ // Last received event type.
+ ui::EventType last_event_type_ = ui::ET_UNKNOWN;
+
// Weak pointer factory used for cursor capture callbacks.
base::WeakPtrFactory<Pointer> cursor_capture_weak_ptr_factory_;
diff --git a/chromium/components/exo/pointer_delegate.h b/chromium/components/exo/pointer_delegate.h
index 7e4e4fa2350..cbfc718fff8 100644
--- a/chromium/components/exo/pointer_delegate.h
+++ b/chromium/components/exo/pointer_delegate.h
@@ -56,9 +56,6 @@ class PointerDelegate {
const gfx::Vector2dF& offset,
bool discrete) = 0;
- // Called when a current kinetic scroll should be canceled.
- virtual void OnPointerScrollCancel(base::TimeTicks time_stamp) = 0;
-
// Called when pointer scroll has stopped and a fling is happening (e.g.
// lifting the fingers from the touchpad after scrolling quickly)
virtual void OnPointerScrollStop(base::TimeTicks time_stamp) = 0;
diff --git a/chromium/components/exo/pointer_unittest.cc b/chromium/components/exo/pointer_unittest.cc
index f49513864ca..0a6118b36de 100644
--- a/chromium/components/exo/pointer_unittest.cc
+++ b/chromium/components/exo/pointer_unittest.cc
@@ -2,13 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ash/common/wm/window_positioning_utils.h"
-#include "ash/common/wm_shell.h"
-#include "ash/common/wm_window.h"
+#include "components/exo/pointer.h"
+
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
+#include "ash/shell_port.h"
+#include "ash/wm/window_positioning_utils.h"
+#include "ash/wm_window.h"
#include "components/exo/buffer.h"
-#include "components/exo/pointer.h"
#include "components/exo/pointer_delegate.h"
#include "components/exo/shell_surface.h"
#include "components/exo/surface.h"
@@ -36,7 +37,6 @@ class MockPointerDelegate : public PointerDelegate {
MOCK_METHOD3(OnPointerButton, void(base::TimeTicks, int, bool));
MOCK_METHOD3(OnPointerScroll,
void(base::TimeTicks, const gfx::Vector2dF&, bool));
- MOCK_METHOD1(OnPointerScrollCancel, void(base::TimeTicks));
MOCK_METHOD1(OnPointerScrollStop, void(base::TimeTicks));
MOCK_METHOD0(OnPointerFrame, void());
};
@@ -244,7 +244,7 @@ TEST_F(PointerTest, OnPointerScroll) {
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
- EXPECT_CALL(delegate, OnPointerFrame()).Times(4);
+ EXPECT_CALL(delegate, OnPointerFrame()).Times(3);
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(location);
@@ -253,7 +253,6 @@ TEST_F(PointerTest, OnPointerScroll) {
// Expect fling stop followed by scroll and scroll stop.
testing::InSequence sequence;
- EXPECT_CALL(delegate, OnPointerScrollCancel(testing::_));
EXPECT_CALL(delegate,
OnPointerScroll(testing::_, gfx::Vector2dF(1.2, 1.2), false));
EXPECT_CALL(delegate, OnPointerScrollStop(testing::_));
@@ -319,7 +318,7 @@ TEST_F(PointerTest, IgnorePointerEventDuringModal) {
// Make the window modal.
shell_surface2->SetSystemModal(true);
- EXPECT_TRUE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+ EXPECT_TRUE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
EXPECT_CALL(delegate, OnPointerFrame()).Times(testing::AnyNumber());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
@@ -351,7 +350,6 @@ TEST_F(PointerTest, IgnorePointerEventDuringModal) {
{
testing::InSequence sequence;
- EXPECT_CALL(delegate, OnPointerScrollCancel(testing::_));
EXPECT_CALL(delegate,
OnPointerScroll(testing::_, gfx::Vector2dF(1.2, 1.2), false));
EXPECT_CALL(delegate, OnPointerScrollStop(testing::_));
@@ -392,7 +390,6 @@ TEST_F(PointerTest, IgnorePointerEventDuringModal) {
{
testing::InSequence sequence;
- EXPECT_CALL(delegate, OnPointerScrollCancel(testing::_)).Times(0);
EXPECT_CALL(delegate,
OnPointerScroll(testing::_, gfx::Vector2dF(1.2, 1.2), false))
.Times(0);
@@ -408,7 +405,7 @@ TEST_F(PointerTest, IgnorePointerEventDuringModal) {
// Make the window non-modal.
shell_surface2->SetSystemModal(false);
- EXPECT_FALSE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+ EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
// Check if pointer events on non-modal window are registered.
{
@@ -434,7 +431,6 @@ TEST_F(PointerTest, IgnorePointerEventDuringModal) {
{
testing::InSequence sequence;
- EXPECT_CALL(delegate, OnPointerScrollCancel(testing::_));
EXPECT_CALL(delegate,
OnPointerScroll(testing::_, gfx::Vector2dF(1.2, 1.2), false));
EXPECT_CALL(delegate, OnPointerScrollStop(testing::_));
diff --git a/chromium/components/exo/shell_surface.cc b/chromium/components/exo/shell_surface.cc
index 57460ab9654..48a58e7c211 100644
--- a/chromium/components/exo/shell_surface.cc
+++ b/chromium/components/exo/shell_surface.cc
@@ -6,14 +6,18 @@
#include <algorithm>
-#include "ash/common/frame/custom_frame_view_ash.h"
-#include "ash/common/shelf/wm_shelf.h"
-#include "ash/common/wm/window_resizer.h"
-#include "ash/common/wm/window_state.h"
-#include "ash/common/wm_window.h"
+#include "ash/frame/custom_frame_view_ash.h"
#include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/cpp/window_properties.h"
+#include "ash/public/interfaces/window_pin_type.mojom.h"
+#include "ash/shelf/wm_shelf.h"
+#include "ash/shell_port.h"
+#include "ash/wm/drag_window_resizer.h"
+#include "ash/wm/window_resizer.h"
+#include "ash/wm/window_state.h"
#include "ash/wm/window_state_aura.h"
#include "ash/wm/window_util.h"
+#include "ash/wm_window.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
@@ -29,6 +33,8 @@
#include "ui/aura/window_tree_host.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/class_property.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
#include "ui/gfx/path.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/coordinate_conversion.h"
@@ -143,6 +149,25 @@ class CustomWindowTargeter : public aura::WindowTargeter {
DISALLOW_COPY_AND_ASSIGN(CustomWindowTargeter);
};
+// Minimal WindowResizer that unlike DefaultWindowResizer does not handle
+// dragging and resizing windows.
+class CustomWindowResizer : public ash::WindowResizer {
+ public:
+ explicit CustomWindowResizer(ash::wm::WindowState* window_state)
+ : WindowResizer(window_state) {
+ ash::ShellPort::Get()->LockCursor();
+ }
+ ~CustomWindowResizer() override { ash::ShellPort::Get()->UnlockCursor(); }
+
+ // Overridden from ash::WindowResizer:
+ void Drag(const gfx::Point& location, int event_flags) override {}
+ void CompleteDrag() override {}
+ void RevertDrag() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CustomWindowResizer);
+};
+
class ShellSurfaceWidget : public views::Widget {
public:
explicit ShellSurfaceWidget(ShellSurface* shell_surface)
@@ -299,11 +324,14 @@ ShellSurface::ShellSurface(Surface* surface,
surface_(surface),
parent_(parent ? parent->GetWidget()->GetNativeWindow() : nullptr),
bounds_mode_(bounds_mode),
+ primary_display_id_(
+ display::Screen::GetScreen()->GetPrimaryDisplay().id()),
origin_(origin),
activatable_(activatable),
can_minimize_(can_minimize),
container_(container) {
WMHelper::GetInstance()->AddActivationObserver(this);
+ WMHelper::GetInstance()->AddDisplayConfigurationObserver(this);
surface_->SetSurfaceDelegate(this);
surface_->AddSurfaceObserver(this);
surface_->window()->Show();
@@ -336,6 +364,7 @@ ShellSurface::~ShellSurface() {
widget_->CloseNow();
}
WMHelper::GetInstance()->RemoveActivationObserver(this);
+ WMHelper::GetInstance()->RemoveDisplayConfigurationObserver(this);
if (parent_)
parent_->RemoveObserver(this);
if (surface_) {
@@ -453,9 +482,9 @@ void ShellSurface::SetFullscreen(bool fullscreen) {
widget_->SetFullscreen(fullscreen);
}
-void ShellSurface::SetPinned(bool pinned, bool trusted) {
- TRACE_EVENT2("exo", "ShellSurface::SetPinned", "pinned", pinned, "trusted",
- trusted);
+void ShellSurface::SetPinned(ash::mojom::WindowPinType type) {
+ TRACE_EVENT1("exo", "ShellSurface::SetPinned", "type",
+ static_cast<int>(type));
if (!widget_)
CreateShellSurfaceWidget(ui::SHOW_STATE_NORMAL);
@@ -463,16 +492,7 @@ void ShellSurface::SetPinned(bool pinned, bool trusted) {
// Note: This will ask client to configure its surface even if pinned
// state doesn't change.
ScopedConfigure scoped_configure(this, true);
- if (pinned) {
- ash::wm::PinWindow(widget_->GetNativeWindow(), trusted);
- } else {
- // At the moment, we cannot just unpin the window state, due to ash
- // implementation. Instead, we call Restore() to unpin, if it is Pinned
- // state. In this implementation, we may loose the previous state,
- // if the previous state is fullscreen, etc.
- if (ash::wm::GetWindowState(widget_->GetNativeWindow())->IsPinned())
- widget_->Restore();
- }
+ widget_->GetNativeWindow()->SetProperty(ash::kWindowPinTypeKey, type);
}
void ShellSurface::SetSystemUiVisibility(bool autohide) {
@@ -548,9 +568,9 @@ void ShellSurface::Move() {
switch (bounds_mode_) {
case BoundsMode::SHELL:
+ case BoundsMode::CLIENT:
AttemptToStartDrag(HTCAPTION);
return;
- case BoundsMode::CLIENT:
case BoundsMode::FIXED:
return;
}
@@ -650,29 +670,7 @@ void ShellSurface::SetTopInset(int height) {
void ShellSurface::SetOrigin(const gfx::Point& origin) {
TRACE_EVENT1("exo", "ShellSurface::SetOrigin", "origin", origin.ToString());
- if (origin == origin_)
- return;
-
- if (bounds_mode_ != BoundsMode::CLIENT) {
- origin_ = origin;
- return;
- }
-
- // If the origin changed, give the client a chance to adjust window positions
- // before switching to the new coordinate system. Retain the old origin by
- // reverting the origin delta until the next configure is acknowledged.
- gfx::Vector2d delta = origin - origin_;
- origin_offset_ -= delta;
- pending_origin_offset_accumulator_ += delta;
-
origin_ = origin;
-
- if (widget_) {
- UpdateWidgetBounds();
- UpdateShadow();
- }
-
- Configure();
}
void ShellSurface::SetActivatable(bool activatable) {
@@ -924,6 +922,11 @@ void ShellSurface::OnPreWindowStateTypeChange(
ash::wm::WindowState* window_state,
ash::wm::WindowStateType old_type) {
ash::wm::WindowStateType new_type = window_state->GetStateType();
+ if (old_type == ash::wm::WINDOW_STATE_TYPE_MINIMIZED ||
+ new_type == ash::wm::WINDOW_STATE_TYPE_MINIMIZED) {
+ return;
+ }
+
if (ash::wm::IsMaximizedOrFullscreenOrPinnedWindowStateType(old_type) ||
ash::wm::IsMaximizedOrFullscreenOrPinnedWindowStateType(new_type)) {
// When transitioning in/out of maximized or fullscreen mode we need to
@@ -931,9 +934,8 @@ void ShellSurface::OnPreWindowStateTypeChange(
// cross-fade animations. The configure callback provides a mechanism for
// the client to inform us that a frame has taken the state change into
// account and without this cross-fade animations are unreliable.
-
- // TODO(domlaskowski): For shell surfaces whose bounds are controlled by the
- // client, the configure callback does not yet support window state changes.
+ // TODO(domlaskowski): For BoundsMode::CLIENT, the configure callback does
+ // not yet support window state changes. See crbug.com/699746.
if (configure_callback_.is_null() || bounds_mode_ == BoundsMode::CLIENT)
scoped_animations_disabled_.reset(new ScopedAnimationsDisabled(this));
}
@@ -966,8 +968,8 @@ void ShellSurface::OnPostWindowStateTypeChange(
void ShellSurface::OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) {
- // TODO(domlaskowski): For shell surfaces whose bounds are controlled by the
- // client, the configure callback does not yet support resizing.
+ // TODO(domlaskowski): For BoundsMode::CLIENT, the configure callback does not
+ // yet support resizing. See crbug.com/699746.
if (bounds_mode_ == BoundsMode::CLIENT)
return;
@@ -1032,6 +1034,39 @@ void ShellSurface::OnAccessibilityModeChanged() {
}
////////////////////////////////////////////////////////////////////////////////
+// WMHelper::DisplayConfigurationObserver overrides:
+
+void ShellSurface::OnDisplayConfigurationChanged() {
+ if (bounds_mode_ != BoundsMode::CLIENT)
+ return;
+
+ const display::Screen* screen = display::Screen::GetScreen();
+ int64_t primary_display_id = screen->GetPrimaryDisplay().id();
+ if (primary_display_id == primary_display_id_)
+ return;
+
+ display::Display old_primary_display;
+ if (screen->GetDisplayWithDisplayId(primary_display_id_,
+ &old_primary_display)) {
+ // Give the client a chance to adjust window positions before switching to
+ // the new coordinate system. Retain the old origin by reverting the origin
+ // delta until the next configure is acknowledged.
+ gfx::Vector2d delta = gfx::Point() - old_primary_display.bounds().origin();
+ origin_offset_ -= delta;
+ pending_origin_offset_accumulator_ += delta;
+
+ if (widget_) {
+ UpdateWidgetBounds();
+ UpdateShadow();
+ }
+
+ Configure();
+ }
+
+ primary_display_id_ = primary_display_id;
+}
+
+////////////////////////////////////////////////////////////////////////////////
// ui::EventHandler overrides:
void ShellSurface::OnKeyEvent(ui::KeyEvent* event) {
@@ -1040,6 +1075,9 @@ void ShellSurface::OnKeyEvent(ui::KeyEvent* event) {
return;
}
+ // TODO(domlaskowski): For BoundsMode::CLIENT, synchronize the revert with the
+ // client, instead of having the client destroy the window on VKEY_ESCAPE. See
+ // crbug.com/699746.
if (event->type() == ui::ET_KEY_PRESSED &&
event->key_code() == ui::VKEY_ESCAPE) {
EndDrag(true /* revert */);
@@ -1069,6 +1107,9 @@ void ShellSurface::OnMouseEvent(ui::MouseEvent* event) {
switch (event->type()) {
case ui::ET_MOUSE_DRAGGED: {
+ if (bounds_mode_ == BoundsMode::CLIENT)
+ break;
+
gfx::Point location(event->location());
aura::Window::ConvertPointToTarget(widget_->GetNativeWindow(),
widget_->GetNativeWindow()->parent(),
@@ -1221,11 +1262,11 @@ void ShellSurface::Configure() {
serial = configure_callback_.Run(
non_client_view->frame_view()->GetBoundsForClientView().size(),
ash::wm::GetWindowState(widget_->GetNativeWindow())->GetStateType(),
- IsResizing(), widget_->IsActive(), origin_);
+ IsResizing(), widget_->IsActive(), origin_offset);
} else {
serial = configure_callback_.Run(gfx::Size(),
ash::wm::WINDOW_STATE_TYPE_NORMAL, false,
- false, origin_);
+ false, origin_offset);
}
}
@@ -1243,6 +1284,22 @@ void ShellSurface::Configure() {
<< pending_configs_.size();
}
+aura::Window* ShellSurface::GetDragWindow() const {
+ switch (bounds_mode_) {
+ case BoundsMode::SHELL:
+ return widget_->GetNativeWindow();
+
+ case BoundsMode::CLIENT:
+ return surface_ ? surface_->window() : nullptr;
+
+ case BoundsMode::FIXED:
+ return nullptr;
+ }
+
+ NOTREACHED();
+ return nullptr;
+}
+
void ShellSurface::AttemptToStartDrag(int component) {
DCHECK(widget_);
@@ -1250,69 +1307,82 @@ void ShellSurface::AttemptToStartDrag(int component) {
if (resizer_)
return;
- if (widget_->GetNativeWindow()->HasCapture())
+ aura::Window* window = GetDragWindow();
+ if (!window || window->HasCapture())
return;
- aura::Window* root_window = widget_->GetNativeWindow()->GetRootWindow();
- gfx::Point drag_location =
- root_window->GetHost()->dispatcher()->GetLastMouseLocationInRoot();
- aura::Window::ConvertPointToTarget(
- root_window, widget_->GetNativeWindow()->parent(), &drag_location);
+ if (bounds_mode_ == BoundsMode::SHELL) {
+ // Set the cursor before calling CreateWindowResizer(), as that will
+ // eventually call LockCursor() and prevent the cursor from changing.
+ aura::client::CursorClient* cursor_client =
+ aura::client::GetCursorClient(window->GetRootWindow());
+ if (!cursor_client)
+ return;
- // Set the cursor before calling CreateWindowResizer(), as that will
- // eventually call LockCursor() and prevent the cursor from changing.
- aura::client::CursorClient* cursor_client =
- aura::client::GetCursorClient(root_window);
- DCHECK(cursor_client);
+ switch (component) {
+ case HTCAPTION:
+ cursor_client->SetCursor(ui::kCursorPointer);
+ break;
+ case HTTOP:
+ cursor_client->SetCursor(ui::kCursorNorthResize);
+ break;
+ case HTTOPRIGHT:
+ cursor_client->SetCursor(ui::kCursorNorthEastResize);
+ break;
+ case HTRIGHT:
+ cursor_client->SetCursor(ui::kCursorEastResize);
+ break;
+ case HTBOTTOMRIGHT:
+ cursor_client->SetCursor(ui::kCursorSouthEastResize);
+ break;
+ case HTBOTTOM:
+ cursor_client->SetCursor(ui::kCursorSouthResize);
+ break;
+ case HTBOTTOMLEFT:
+ cursor_client->SetCursor(ui::kCursorSouthWestResize);
+ break;
+ case HTLEFT:
+ cursor_client->SetCursor(ui::kCursorWestResize);
+ break;
+ case HTTOPLEFT:
+ cursor_client->SetCursor(ui::kCursorNorthWestResize);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
- switch (component) {
- case HTCAPTION:
- cursor_client->SetCursor(ui::kCursorPointer);
- break;
- case HTTOP:
- cursor_client->SetCursor(ui::kCursorNorthResize);
- break;
- case HTTOPRIGHT:
- cursor_client->SetCursor(ui::kCursorNorthEastResize);
- break;
- case HTRIGHT:
- cursor_client->SetCursor(ui::kCursorEastResize);
- break;
- case HTBOTTOMRIGHT:
- cursor_client->SetCursor(ui::kCursorSouthEastResize);
- break;
- case HTBOTTOM:
- cursor_client->SetCursor(ui::kCursorSouthResize);
- break;
- case HTBOTTOMLEFT:
- cursor_client->SetCursor(ui::kCursorSouthWestResize);
- break;
- case HTLEFT:
- cursor_client->SetCursor(ui::kCursorWestResize);
- break;
- case HTTOPLEFT:
- cursor_client->SetCursor(ui::kCursorNorthWestResize);
- break;
- default:
- NOTREACHED();
- break;
- }
+ resizer_ = ash::CreateWindowResizer(ash::WmWindow::Get(window),
+ GetMouseLocation(), component,
+ aura::client::WINDOW_MOVE_SOURCE_MOUSE);
+ if (!resizer_)
+ return;
- resizer_ = ash::CreateWindowResizer(
- ash::WmWindow::Get(widget_->GetNativeWindow()), drag_location, component,
- aura::client::WINDOW_MOVE_SOURCE_MOUSE);
- if (!resizer_)
- return;
+ // Apply pending origin offsets and resize direction before starting a
+ // new resize operation. These can still be pending if the client has
+ // acknowledged the configure request but not yet called Commit().
+ origin_offset_ += pending_origin_offset_;
+ pending_origin_offset_ = gfx::Vector2d();
+ resize_component_ = pending_resize_component_;
+ } else {
+ DCHECK(bounds_mode_ == BoundsMode::CLIENT);
- // Apply pending origin offsets and resize direction before starting a new
- // resize operation. These can still be pending if the client has acknowledged
- // the configure request but not yet called Commit().
- origin_offset_ += pending_origin_offset_;
- pending_origin_offset_ = gfx::Vector2d();
- resize_component_ = pending_resize_component_;
+ ash::wm::WindowState* window_state =
+ ash::wm::GetWindowState(widget_->GetNativeWindow());
+ DCHECK(!window_state->drag_details());
+ DCHECK(component == HTCAPTION);
+ window_state->CreateDragDetails(GetMouseLocation(), component,
+ aura::client::WINDOW_MOVE_SOURCE_MOUSE);
+
+ // Chained with a CustomWindowResizer, DragWindowResizer does not handle
+ // dragging. It only renders phantom windows and moves the window to the
+ // target root window when dragging ends.
+ resizer_.reset(ash::DragWindowResizer::Create(
+ new CustomWindowResizer(window_state), window_state));
+ }
WMHelper::GetInstance()->AddPreTargetHandler(this);
- widget_->GetNativeWindow()->SetCapture();
+ window->SetCapture();
// Notify client that resizing state has changed.
if (IsResizing())
@@ -1323,6 +1393,10 @@ void ShellSurface::EndDrag(bool revert) {
DCHECK(widget_);
DCHECK(resizer_);
+ aura::Window* window = GetDragWindow();
+ DCHECK(window);
+ DCHECK(window->HasCapture());
+
bool was_resizing = IsResizing();
if (revert)
@@ -1331,7 +1405,7 @@ void ShellSurface::EndDrag(bool revert) {
resizer_->CompleteDrag();
WMHelper::GetInstance()->RemovePreTargetHandler(this);
- widget_->GetNativeWindow()->ReleaseCapture();
+ window->ReleaseCapture();
resizer_.reset();
// Notify client that resizing state has changed.
@@ -1444,8 +1518,34 @@ void ShellSurface::UpdateWidgetBounds() {
// should not result in a configure request.
DCHECK(!ignore_window_bounds_changes_);
ignore_window_bounds_changes_ = true;
- if (widget_->GetWindowBoundsInScreen() != new_widget_bounds)
- widget_->SetBounds(new_widget_bounds);
+ const gfx::Rect widget_bounds = widget_->GetWindowBoundsInScreen();
+ if (widget_bounds != new_widget_bounds) {
+ if (bounds_mode_ != BoundsMode::CLIENT || !resizer_) {
+ // TODO(domlaskowski): Use screen coordinates once multi-display support
+ // lands in ARC. See crbug.com/718627.
+ widget_->GetNativeWindow()->SetBounds(new_widget_bounds);
+ UpdateSurfaceBounds();
+ } else {
+ // TODO(domlaskowski): Synchronize window state transitions with the
+ // client, and abort client-side dragging on transition to fullscreen. See
+ // crbug.com/699746.
+ DLOG_IF(ERROR, widget_bounds.size() != new_widget_bounds.size())
+ << "Window size changed during client-driven drag";
+
+ // Convert from screen to display coordinates.
+ gfx::Point origin = new_widget_bounds.origin();
+ wm::ConvertPointFromScreen(widget_->GetNativeWindow()->parent(), &origin);
+ new_widget_bounds.set_origin(origin);
+
+ // Move the window relative to the current display.
+ widget_->GetNativeWindow()->SetBounds(new_widget_bounds);
+ UpdateSurfaceBounds();
+
+ // Render phantom windows when beyond the current display.
+ resizer_->Drag(GetMouseLocation(), 0);
+ }
+ }
+
ignore_window_bounds_changes_ = false;
}
@@ -1482,7 +1582,7 @@ void ShellSurface::UpdateShadow() {
if (shadow_underlay_)
shadow_underlay_->Hide();
} else {
- wm::SetShadowElevation(window, wm::ShadowElevation::MEDIUM);
+ wm::SetShadowElevation(window, wm::ShadowElevation::DEFAULT);
gfx::Rect shadow_content_bounds =
gfx::ScaleToEnclosedRect(shadow_content_bounds_, 1.f / scale_);
@@ -1622,4 +1722,13 @@ void ShellSurface::UpdateShadow() {
}
}
+gfx::Point ShellSurface::GetMouseLocation() const {
+ aura::Window* const root_window = widget_->GetNativeWindow()->GetRootWindow();
+ gfx::Point location =
+ root_window->GetHost()->dispatcher()->GetLastMouseLocationInRoot();
+ aura::Window::ConvertPointToTarget(
+ root_window, widget_->GetNativeWindow()->parent(), &location);
+ return location;
+}
+
} // namespace exo
diff --git a/chromium/components/exo/shell_surface.h b/chromium/components/exo/shell_surface.h
index 0bf2b7e916f..536f41763d5 100644
--- a/chromium/components/exo/shell_surface.h
+++ b/chromium/components/exo/shell_surface.h
@@ -5,11 +5,12 @@
#ifndef COMPONENTS_EXO_SHELL_SURFACE_H_
#define COMPONENTS_EXO_SHELL_SURFACE_H_
+#include <cstdint>
#include <deque>
#include <memory>
#include <string>
-#include "ash/common/wm/window_state_observer.h"
+#include "ash/wm/window_state_observer.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "components/exo/surface_delegate.h"
@@ -24,6 +25,9 @@
namespace ash {
class WindowResizer;
+namespace mojom {
+enum class WindowPinType;
+}
}
namespace base {
@@ -45,7 +49,8 @@ class ShellSurface : public SurfaceDelegate,
public ash::wm::WindowStateObserver,
public aura::WindowObserver,
public WMHelper::ActivationObserver,
- public WMHelper::AccessibilityObserver {
+ public WMHelper::AccessibilityObserver,
+ public WMHelper::DisplayConfigurationObserver {
public:
enum class BoundsMode { SHELL, CLIENT, FIXED };
@@ -98,7 +103,7 @@ class ShellSurface : public SurfaceDelegate,
ash::wm::WindowStateType state_type,
bool resizing,
bool activated,
- const gfx::Point& origin)>;
+ const gfx::Vector2d& origin_offset)>;
void set_configure_callback(const ConfigureCallback& configure_callback) {
configure_callback_ = configure_callback;
}
@@ -127,8 +132,8 @@ class ShellSurface : public SurfaceDelegate,
// Set fullscreen state for shell surface.
void SetFullscreen(bool fullscreen);
- // Pins the shell surface. |trusted| flag is ignored when |pinned| is false.
- void SetPinned(bool pinned, bool trusted);
+ // Pins the shell surface.
+ void SetPinned(ash::mojom::WindowPinType type);
// Sets whether or not the shell surface should autohide the system UI.
void SetSystemUiVisibility(bool autohide);
@@ -258,6 +263,9 @@ class ShellSurface : public SurfaceDelegate,
// Overridden from WMHelper::AccessibilityObserver:
void OnAccessibilityModeChanged() override;
+ // Overridden from WMHelper::DisplayConfigurationObserver:
+ void OnDisplayConfigurationChanged() override;
+
// Overridden from ui::EventHandler:
void OnKeyEvent(ui::KeyEvent* event) override;
void OnMouseEvent(ui::MouseEvent* event) override;
@@ -288,6 +296,9 @@ class ShellSurface : public SurfaceDelegate,
// Asks the client to configure its surface.
void Configure();
+ // Returns the window that has capture during dragging.
+ aura::Window* GetDragWindow() const;
+
// Attempt to start a drag operation. The type of drag operation to start is
// determined by |component|.
void AttemptToStartDrag(int component);
@@ -318,10 +329,14 @@ class ShellSurface : public SurfaceDelegate,
// Applies |system_modal_| to |widget_|.
void UpdateSystemModal();
+ // In the coordinate system of the parent root window.
+ gfx::Point GetMouseLocation() const;
+
views::Widget* widget_ = nullptr;
Surface* surface_;
aura::Window* parent_;
const BoundsMode bounds_mode_;
+ int64_t primary_display_id_;
gfx::Point origin_;
bool activatable_ = true;
const bool can_minimize_;
diff --git a/chromium/components/exo/shell_surface_unittest.cc b/chromium/components/exo/shell_surface_unittest.cc
index b8dbca007cd..d92a731337d 100644
--- a/chromium/components/exo/shell_surface_unittest.cc
+++ b/chromium/components/exo/shell_surface_unittest.cc
@@ -2,18 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ash/common/accessibility_delegate.h"
-#include "ash/common/wm/window_state.h"
-#include "ash/common/wm/wm_event.h"
-#include "ash/common/wm_shell.h"
-#include "ash/common/wm_window.h"
+#include "components/exo/shell_surface.h"
+
+#include "ash/accessibility_delegate.h"
#include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/cpp/window_properties.h"
+#include "ash/public/interfaces/window_pin_type.mojom.h"
+#include "ash/shell.h"
+#include "ash/shell_port.h"
+#include "ash/wm/window_state.h"
#include "ash/wm/window_state_aura.h"
+#include "ash/wm/wm_event.h"
+#include "ash/wm_window.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "components/exo/buffer.h"
#include "components/exo/display.h"
-#include "components/exo/shell_surface.h"
#include "components/exo/sub_surface.h"
#include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h"
@@ -42,7 +46,7 @@ uint32_t ConfigureFullscreen(uint32_t serial,
ash::wm::WindowStateType state_type,
bool resizing,
bool activated,
- const gfx::Point& origin) {
+ const gfx::Vector2d& origin_offset) {
EXPECT_EQ(ash::wm::WINDOW_STATE_TYPE_FULLSCREEN, state_type);
return serial;
}
@@ -51,6 +55,13 @@ wm::ShadowElevation GetShadowElevation(aura::Window* window) {
return window->GetProperty(wm::kShadowElevationKey);
}
+bool IsWidgetPinned(views::Widget* widget) {
+ ash::mojom::WindowPinType type =
+ widget->GetNativeWindow()->GetProperty(ash::kWindowPinTypeKey);
+ return type == ash::mojom::WindowPinType::PINNED ||
+ type == ash::mojom::WindowPinType::TRUSTED_PINNED;
+}
+
TEST_F(ShellSurfaceTest, AcknowledgeConfigure) {
gfx::Size buffer_size(32, 32);
std::unique_ptr<Buffer> buffer(
@@ -185,25 +196,17 @@ TEST_F(ShellSurfaceTest, SetPinned) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
- shell_surface->SetPinned(true, /* trusted */ true);
- EXPECT_TRUE(
- ash::wm::GetWindowState(shell_surface->GetWidget()->GetNativeWindow())
- ->IsPinned());
+ shell_surface->SetPinned(ash::mojom::WindowPinType::TRUSTED_PINNED);
+ EXPECT_TRUE(IsWidgetPinned(shell_surface->GetWidget()));
- shell_surface->SetPinned(false, /* trusted */ true);
- EXPECT_FALSE(
- ash::wm::GetWindowState(shell_surface->GetWidget()->GetNativeWindow())
- ->IsPinned());
+ shell_surface->SetPinned(ash::mojom::WindowPinType::NONE);
+ EXPECT_FALSE(IsWidgetPinned(shell_surface->GetWidget()));
- shell_surface->SetPinned(true, /* trusted */ false);
- EXPECT_TRUE(
- ash::wm::GetWindowState(shell_surface->GetWidget()->GetNativeWindow())
- ->IsPinned());
+ shell_surface->SetPinned(ash::mojom::WindowPinType::PINNED);
+ EXPECT_TRUE(IsWidgetPinned(shell_surface->GetWidget()));
- shell_surface->SetPinned(false, /* trusted */ false);
- EXPECT_FALSE(
- ash::wm::GetWindowState(shell_surface->GetWidget()->GetNativeWindow())
- ->IsPinned());
+ shell_surface->SetPinned(ash::mojom::WindowPinType::NONE);
+ EXPECT_FALSE(IsWidgetPinned(shell_surface->GetWidget()));
}
TEST_F(ShellSurfaceTest, SetSystemUiVisibility) {
@@ -389,7 +392,7 @@ uint32_t Configure(gfx::Size* suggested_size,
ash::wm::WindowStateType state_type,
bool resizing,
bool activated,
- const gfx::Point& origin) {
+ const gfx::Vector2d& origin_offset) {
*suggested_size = size;
*has_state_type = state_type;
*is_resizing = resizing;
@@ -454,7 +457,7 @@ TEST_F(ShellSurfaceTest, ModalWindow) {
surface->SetInputRegion(SkRegion());
surface->Commit();
- EXPECT_FALSE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+ EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
// Creating a surface without input region should not make it modal.
std::unique_ptr<Display> display(new Display);
@@ -468,26 +471,26 @@ TEST_F(ShellSurfaceTest, ModalWindow) {
surface->SetSubSurfacePosition(child.get(), gfx::Point(10, 10));
child->Commit();
surface->Commit();
- EXPECT_FALSE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+ EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
// Making the surface opaque shouldn't make it modal either.
child->SetBlendMode(SkBlendMode::kSrc);
child->Commit();
surface->Commit();
- EXPECT_FALSE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+ EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
// Setting input regions won't make it modal either.
surface->SetInputRegion(
SkRegion(gfx::RectToSkIRect(gfx::Rect(10, 10, 100, 100))));
surface->Commit();
- EXPECT_FALSE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+ EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
// Only SetSystemModal changes modality.
shell_surface->SetSystemModal(true);
- EXPECT_TRUE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+ EXPECT_TRUE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
shell_surface->SetSystemModal(false);
- EXPECT_FALSE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+ EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
}
TEST_F(ShellSurfaceTest, ModalWindowSetSystemModalBeforeCommit) {
@@ -510,12 +513,12 @@ TEST_F(ShellSurfaceTest, ModalWindowSetSystemModalBeforeCommit) {
// It is expected that modal window is shown.
EXPECT_TRUE(shell_surface->GetWidget());
- EXPECT_TRUE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+ EXPECT_TRUE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
// Now widget is created and setting modal state should be applied
// immediately.
shell_surface->SetSystemModal(false);
- EXPECT_FALSE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+ EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
}
TEST_F(ShellSurfaceTest, PopupWindow) {
@@ -621,7 +624,7 @@ TEST_F(ShellSurfaceTest, SurfaceShadow) {
shell_surface->SetRectangularSurfaceShadow(gfx::Rect(10, 10, 100, 100));
surface->Commit();
- EXPECT_EQ(wm::ShadowElevation::MEDIUM, GetShadowElevation(window));
+ EXPECT_EQ(wm::ShadowElevation::DEFAULT, GetShadowElevation(window));
EXPECT_TRUE(shadow->layer()->visible());
// For surface shadow, the underlay is placed at the bottom of shell surfaces.
@@ -698,7 +701,7 @@ TEST_F(ShellSurfaceTest, NonSurfaceShadow) {
shell_surface->SetRectangularShadowEnabled(true);
surface->Commit();
- EXPECT_EQ(wm::ShadowElevation::MEDIUM, GetShadowElevation(window));
+ EXPECT_EQ(wm::ShadowElevation::DEFAULT, GetShadowElevation(window));
EXPECT_TRUE(shadow->layer()->visible());
// For no surface shadow, both of underlay and overlay should be stacked
@@ -744,7 +747,7 @@ TEST_F(ShellSurfaceTest, ShadowWithStateChange) {
shell_surface->SetRectangularSurfaceShadow(shadow_bounds);
surface->Commit();
- EXPECT_EQ(wm::ShadowElevation::MEDIUM, GetShadowElevation(window));
+ EXPECT_EQ(wm::ShadowElevation::DEFAULT, GetShadowElevation(window));
// Shadow overlay bounds.
EXPECT_TRUE(shadow->layer()->visible());
@@ -978,7 +981,7 @@ TEST_F(ShellSurfaceTest, SpokenFeedbackFullscreenBackground) {
EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(shell_window, ev_out));
// Enable spoken feedback.
- ash::WmShell::Get()->accessibility_delegate()->ToggleSpokenFeedback(
+ ash::Shell::Get()->accessibility_delegate()->ToggleSpokenFeedback(
ash::A11Y_NOTIFICATION_NONE);
shell_surface.OnAccessibilityModeChanged();
@@ -1015,7 +1018,7 @@ TEST_F(ShellSurfaceTest, SpokenFeedbackFullscreenBackground) {
EXPECT_EQ(shadow_bounds, shell_surface.shadow_underlay()->bounds());
// Disable spoken feedback. Shadow underlay is restored.
- ash::WmShell::Get()->accessibility_delegate()->ToggleSpokenFeedback(
+ ash::Shell::Get()->accessibility_delegate()->ToggleSpokenFeedback(
ash::A11Y_NOTIFICATION_NONE);
shell_surface.OnAccessibilityModeChanged();
shell_surface2.OnAccessibilityModeChanged();
diff --git a/chromium/components/exo/surface.cc b/chromium/components/exo/surface.cc
index b3ef1ceaf03..ab863b1e3ef 100644
--- a/chromium/components/exo/surface.cc
+++ b/chromium/components/exo/surface.cc
@@ -432,6 +432,13 @@ void Surface::Commit() {
CheckIfSurfaceHierarchyNeedsCommitToNewSurfaces();
CommitSurfaceHierarchy();
}
+
+ if (begin_frame_source_ && current_begin_frame_ack_.sequence_number !=
+ cc::BeginFrameArgs::kInvalidFrameNumber) {
+ begin_frame_source_->DidFinishFrame(this, current_begin_frame_ack_);
+ current_begin_frame_ack_.sequence_number =
+ cc::BeginFrameArgs::kInvalidFrameNumber;
+ }
}
void Surface::CommitSurfaceHierarchy() {
@@ -457,6 +464,13 @@ void Surface::CommitSurfaceHierarchy() {
local_surface_id_ = id_allocator_.GenerateId();
}
+ // Move pending frame callbacks to the end of frame_callbacks_.
+ frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_);
+
+ // Move pending presentation callbacks to the end of presentation_callbacks_.
+ presentation_callbacks_.splice(presentation_callbacks_.end(),
+ pending_presentation_callbacks_);
+
UpdateSurface(false);
if (old_local_surface_id != local_surface_id_) {
@@ -485,13 +499,6 @@ void Surface::CommitSurfaceHierarchy() {
compositor_frame_sink_holder_->HasReleaseCallbackForResource(
current_resource_.id));
- // Move pending frame callbacks to the end of frame_callbacks_.
- frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_);
-
- // Move pending presentation callbacks to the end of presentation_callbacks_.
- presentation_callbacks_.splice(presentation_callbacks_.end(),
- pending_presentation_callbacks_);
-
// Synchronize window hierarchy. This will position and update the stacking
// order of all sub-surfaces after committing all pending state of sub-surface
// descendants.
@@ -598,22 +605,47 @@ std::unique_ptr<base::trace_event::TracedValue> Surface::AsTracedValue() const {
return value;
}
-void Surface::WillDraw() {
+void Surface::DidReceiveCompositorFrameAck() {
active_frame_callbacks_.splice(active_frame_callbacks_.end(),
frame_callbacks_);
swapping_presentation_callbacks_.splice(
swapping_presentation_callbacks_.end(), presentation_callbacks_);
+ UpdateNeedsBeginFrame();
}
-bool Surface::NeedsBeginFrame() const {
- return !active_frame_callbacks_.empty();
+void Surface::SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) {
+ if (needs_begin_frame_) {
+ DCHECK(begin_frame_source_);
+ begin_frame_source_->RemoveObserver(this);
+ needs_begin_frame_ = false;
+ }
+ begin_frame_source_ = begin_frame_source;
+ UpdateNeedsBeginFrame();
+}
+
+void Surface::UpdateNeedsBeginFrame() {
+ if (!begin_frame_source_)
+ return;
+
+ bool needs_begin_frame = !active_frame_callbacks_.empty();
+ if (needs_begin_frame == needs_begin_frame_)
+ return;
+
+ needs_begin_frame_ = needs_begin_frame;
+ if (needs_begin_frame_)
+ begin_frame_source_->AddObserver(this);
+ else
+ begin_frame_source_->RemoveObserver(this);
}
-void Surface::BeginFrame(base::TimeTicks frame_time) {
+bool Surface::OnBeginFrameDerivedImpl(const cc::BeginFrameArgs& args) {
+ current_begin_frame_ack_ = cc::BeginFrameAck(
+ args.source_id, args.sequence_number, args.sequence_number, false);
while (!active_frame_callbacks_.empty()) {
- active_frame_callbacks_.front().Run(frame_time);
+ active_frame_callbacks_.front().Run(args.frame_time);
active_frame_callbacks_.pop_front();
}
+ return true;
}
void Surface::CheckIfSurfaceHierarchyNeedsCommitToNewSurfaces() {
@@ -783,17 +815,22 @@ void Surface::UpdateSurface(bool full_damage) {
1.f / scaled_buffer_size.height());
}
- // pending_damage_ is in Surface coordinates.
- gfx::Rect damage_rect = full_damage
- ? gfx::Rect(contents_surface_size)
- : gfx::SkIRectToRect(pending_damage_.getBounds());
+ gfx::Rect damage_rect;
+ gfx::Rect output_rect = gfx::Rect(contents_surface_size);
+ if (full_damage) {
+ damage_rect = output_rect;
+ } else {
+ // pending_damage_ is in Surface coordinates.
+ damage_rect = gfx::SkIRectToRect(pending_damage_.getBounds());
+ damage_rect.Intersect(output_rect);
+ }
const int kRenderPassId = 1;
std::unique_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create();
- render_pass->SetNew(kRenderPassId, gfx::Rect(contents_surface_size),
- damage_rect, gfx::Transform());
+ render_pass->SetNew(kRenderPassId, output_rect, damage_rect,
+ gfx::Transform());
- gfx::Rect quad_rect = gfx::Rect(contents_surface_size);
+ gfx::Rect quad_rect = output_rect;
cc::SharedQuadState* quad_state =
render_pass->CreateAndAppendSharedQuadState();
quad_state->quad_layer_bounds = contents_surface_size;
@@ -801,6 +838,16 @@ void Surface::UpdateSurface(bool full_damage) {
quad_state->opacity = state_.alpha;
cc::CompositorFrame frame;
+ // If we commit while we don't have an active BeginFrame, we acknowledge a
+ // manual one.
+ if (current_begin_frame_ack_.sequence_number ==
+ cc::BeginFrameArgs::kInvalidFrameNumber) {
+ current_begin_frame_ack_ = cc::BeginFrameAck::CreateManualAckWithDamage();
+ } else {
+ current_begin_frame_ack_.has_damage = true;
+ }
+ frame.metadata.begin_frame_ack = current_begin_frame_ack_;
+
if (current_resource_.id) {
// Texture quad is only needed if buffer is not fully transparent.
if (state_.alpha) {
diff --git a/chromium/components/exo/surface.h b/chromium/components/exo/surface.h
index ecda81291a8..9c633b63691 100644
--- a/chromium/components/exo/surface.h
+++ b/chromium/components/exo/surface.h
@@ -15,6 +15,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
+#include "cc/output/begin_frame_args.h"
#include "cc/resources/transferable_resource.h"
#include "cc/scheduler/begin_frame_source.h"
#include "cc/surfaces/local_surface_id_allocator.h"
@@ -62,7 +63,8 @@ using CursorProvider = Pointer;
class Surface : public ui::ContextFactoryObserver,
public aura::WindowObserver,
public ui::PropertyHandler,
- public ui::CompositorVSyncManager::Observer {
+ public ui::CompositorVSyncManager::Observer,
+ public cc::BeginFrameObserverBase {
public:
using PropertyDeallocator = void (*)(int64_t value);
@@ -189,15 +191,12 @@ class Surface : public ui::ContextFactoryObserver,
// Returns a trace value representing the state of the surface.
std::unique_ptr<base::trace_event::TracedValue> AsTracedValue() const;
- // Call this to indicate that surface is being scheduled for a draw.
- void WillDraw();
+ // Call this to indicate that the previous CompositorFrame is processed and
+ // the surface is being scheduled for a draw.
+ void DidReceiveCompositorFrameAck();
- // Returns true when there's an active frame callback that requires a
- // BeginFrame() call.
- bool NeedsBeginFrame() const;
-
- // Call this to indicate that it's a good time to start producing a new frame.
- void BeginFrame(base::TimeTicks frame_time);
+ // Called when the begin frame source has changed.
+ void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source);
// Check whether this Surface and its children need to create new cc::Surface
// IDs for their contents next time they get new buffer contents.
@@ -222,6 +221,10 @@ class Surface : public ui::ContextFactoryObserver,
return pending_damage_.contains(gfx::RectToSkIRect(damage));
}
+ // Overridden from cc::BeginFrameObserverBase:
+ bool OnBeginFrameDerivedImpl(const cc::BeginFrameArgs& args) override;
+ void OnBeginFrameSourcePausedChanged(bool paused) override {}
+
private:
struct State {
State();
@@ -282,6 +285,9 @@ class Surface : public ui::ContextFactoryObserver,
// current_resource_.
void UpdateSurface(bool full_damage);
+ // Adds/Removes begin frame observer based on state.
+ void UpdateNeedsBeginFrame();
+
// This returns true when the surface has some contents assigned to it.
bool has_contents() const { return !!current_buffer_.buffer(); }
@@ -389,6 +395,11 @@ class Surface : public ui::ContextFactoryObserver,
// references to surfaces.
scoped_refptr<cc::SurfaceReferenceFactory> surface_reference_factory_;
+ // The begin frame source being observed.
+ cc::BeginFrameSource* begin_frame_source_ = nullptr;
+ bool needs_begin_frame_ = false;
+ cc::BeginFrameAck current_begin_frame_ack_;
+
DISALLOW_COPY_AND_ASSIGN(Surface);
};
diff --git a/chromium/components/exo/surface_unittest.cc b/chromium/components/exo/surface_unittest.cc
index dc67d757874..1eb280384a9 100644
--- a/chromium/components/exo/surface_unittest.cc
+++ b/chromium/components/exo/surface_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 "cc/surfaces/surface.h"
#include "base/bind.h"
#include "cc/output/compositor_frame.h"
#include "cc/quads/texture_draw_quad.h"
-#include "cc/surfaces/surface.h"
#include "cc/surfaces/surface_manager.h"
+#include "cc/test/begin_frame_args_test.h"
+#include "cc/test/fake_external_begin_frame_source.h"
#include "components/exo/buffer.h"
#include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h"
@@ -75,6 +77,10 @@ TEST_F(SurfaceTest, Damage) {
EXPECT_TRUE(surface->HasPendingDamageForTesting(gfx::Rect(0, 0, 10, 10)));
EXPECT_TRUE(surface->HasPendingDamageForTesting(gfx::Rect(10, 10, 10, 10)));
EXPECT_FALSE(surface->HasPendingDamageForTesting(gfx::Rect(5, 5, 10, 10)));
+
+ // Check that damage larger than contents is handled correctly at commit.
+ surface->Damage(gfx::Rect(gfx::ScaleToCeiledSize(buffer_size, 2.0f)));
+ surface->Commit();
}
void SetFrameTime(base::TimeTicks* result, base::TimeTicks frame_time) {
@@ -307,5 +313,42 @@ TEST_F(SurfaceTest, Commit) {
surface->Commit();
}
+TEST_F(SurfaceTest, SendsBeginFrameAcks) {
+ cc::FakeExternalBeginFrameSource source(0.f, false);
+ gfx::Size buffer_size(1, 1);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ std::unique_ptr<Surface> surface(new Surface);
+ surface->SetBeginFrameSource(&source);
+ surface->Attach(buffer.get());
+
+ // Request a frame callback so that Surface now needs BeginFrames.
+ base::TimeTicks frame_time;
+ surface->RequestFrameCallback(
+ base::Bind(&SetFrameTime, base::Unretained(&frame_time)));
+ surface->Commit(); // Move callback from pending callbacks to current ones.
+ RunAllPendingInMessageLoop();
+
+ // Surface should add itself as observer during
+ // DidReceiveCompositorFrameAck().
+ surface->DidReceiveCompositorFrameAck();
+ EXPECT_EQ(1u, source.num_observers());
+
+ cc::BeginFrameArgs args(source.CreateBeginFrameArgs(BEGINFRAME_FROM_HERE));
+ args.frame_time = base::TimeTicks::FromInternalValue(100);
+ source.TestOnBeginFrame(args); // Runs the frame callback.
+ EXPECT_EQ(args.frame_time, frame_time);
+
+ surface->Commit(); // Acknowledges the BeginFrame.
+ RunAllPendingInMessageLoop();
+
+ cc::BeginFrameAck expected_ack(args.source_id, args.sequence_number,
+ args.sequence_number, true);
+ EXPECT_EQ(expected_ack, source.LastAckForObserver(surface.get()));
+
+ const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
+ EXPECT_EQ(expected_ack, frame.metadata.begin_frame_ack);
+}
+
} // namespace
} // namespace exo
diff --git a/chromium/components/exo/touch_unittest.cc b/chromium/components/exo/touch_unittest.cc
index 1384229ac62..665b2701c4e 100644
--- a/chromium/components/exo/touch_unittest.cc
+++ b/chromium/components/exo/touch_unittest.cc
@@ -2,18 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ash/common/wm/window_positioner.h"
-#include "ash/common/wm/window_positioning_utils.h"
-#include "ash/common/wm_shell.h"
-#include "ash/common/wm_window.h"
+#include "components/exo/touch.h"
+
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
+#include "ash/shell_port.h"
+#include "ash/wm/window_positioner.h"
+#include "ash/wm/window_positioning_utils.h"
+#include "ash/wm_window.h"
#include "components/exo/buffer.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/touch.h"
#include "components/exo/touch_delegate.h"
#include "components/exo/touch_stylus_delegate.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -210,8 +211,9 @@ TEST_F(TouchTest, OnTouchCancel) {
// One touch point being canceled is enough for OnTouchCancel to be called.
EXPECT_CALL(delegate, OnTouchCancel());
EXPECT_CALL(delegate, OnTouchFrame());
- ui::TouchEvent cancel_event(ui::ET_TOUCH_CANCELLED, gfx::Point(), 1,
- ui::EventTimeForNow());
+ ui::TouchEvent cancel_event(
+ ui::ET_TOUCH_CANCELLED, gfx::Point(), ui::EventTimeForNow(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1));
generator.Dispatch(&cancel_event);
EXPECT_CALL(delegate, OnTouchDestroying(touch.get()));
@@ -229,7 +231,7 @@ TEST_F(TouchTest, IgnoreTouchEventDuringModal) {
// Make the window modal.
modal.shell_surface()->SetSystemModal(true);
- EXPECT_TRUE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+ EXPECT_TRUE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
EXPECT_CALL(delegate, OnTouchShape(testing::_, testing::_, testing::_))
.Times(testing::AnyNumber());
EXPECT_CALL(delegate, CanAcceptTouchEventsForSurface(window.surface()))
@@ -269,7 +271,7 @@ TEST_F(TouchTest, IgnoreTouchEventDuringModal) {
// Make the window non-modal.
modal.shell_surface()->SetSystemModal(false);
- EXPECT_FALSE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+ EXPECT_FALSE(ash::ShellPort::Get()->IsSystemModalWindowOpen());
// Check if touch events on non-modal window are registered.
{
diff --git a/chromium/components/exo/wayland/BUILD.gn b/chromium/components/exo/wayland/BUILD.gn
index 02d12269a08..2b0910474fa 100644
--- a/chromium/components/exo/wayland/BUILD.gn
+++ b/chromium/components/exo/wayland/BUILD.gn
@@ -107,7 +107,10 @@ source_set("client_lib") {
"//ui/gl:gl_config",
]
defines = [ "OZONE_PLATFORM_GBM" ]
- deps += [ "//third_party/minigbm" ]
+ deps += [
+ "//third_party/minigbm",
+ "//ui/ozone",
+ ]
}
}
diff --git a/chromium/components/exo/wayland/clients/client_base.cc b/chromium/components/exo/wayland/clients/client_base.cc
index d423ac4f770..8c17ba56ed5 100644
--- a/chromium/components/exo/wayland/clients/client_base.cc
+++ b/chromium/components/exo/wayland/clients/client_base.cc
@@ -33,6 +33,8 @@
#include <drm_fourcc.h>
#include <gbm.h>
#include <xf86drm.h>
+
+#include "ui/ozone/public/ozone_platform.h" // nogncheck
#endif
namespace exo {
@@ -126,21 +128,25 @@ const GrGLInterface* GrGLCreateNativeInterface() {
return eglGetProcAddress(name);
});
}
+
+zwp_linux_buffer_params_v1_listener g_params_listener = {
+ LinuxBufferParamsCreated, LinuxBufferParamsFailed};
#endif
wl_registry_listener g_registry_listener = {RegistryHandler, RegistryRemover};
wl_buffer_listener g_buffer_listener = {BufferRelease};
-zwp_linux_buffer_params_v1_listener g_params_listener = {
- LinuxBufferParamsCreated, LinuxBufferParamsFailed};
-
} // namespace
////////////////////////////////////////////////////////////////////////////////
// ClientBase::InitParams, public:
-ClientBase::InitParams::InitParams() {}
+ClientBase::InitParams::InitParams() {
+#if defined(OZONE_PLATFORM_GBM)
+ drm_format = DRM_FORMAT_ABGR8888;
+#endif
+}
ClientBase::InitParams::~InitParams() {}
@@ -269,6 +275,9 @@ bool ClientBase::Init(const InitParams& params) {
return false;
}
+ ui::OzonePlatform::InitParams params;
+ params.single_process = true;
+ ui::OzonePlatform::InitializeForGPU(params);
bool gl_initialized = gl::init::InitializeGLOneOff();
DCHECK(gl_initialized);
gl_surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size());
@@ -366,8 +375,8 @@ ClientBase::~ClientBase() {}
std::unique_ptr<ClientBase::Buffer> ClientBase::CreateBuffer(
int32_t drm_format) {
-#if defined(OZONE_PLATFORM_GBM)
std::unique_ptr<Buffer> buffer(new Buffer());
+#if defined(OZONE_PLATFORM_GBM)
if (device_) {
buffer->bo.reset(gbm_bo_create(device_.get(), width_, height_, drm_format,
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING));
diff --git a/chromium/components/exo/wayland/clients/client_base.h b/chromium/components/exo/wayland/clients/client_base.h
index ce10e447217..be00a8c4bcf 100644
--- a/chromium/components/exo/wayland/clients/client_base.h
+++ b/chromium/components/exo/wayland/clients/client_base.h
@@ -5,8 +5,6 @@
#ifndef COMPONENTS_EXO_WAYLAND_CLIENTS_CLIENT_BASE_H_
#define COMPONENTS_EXO_WAYLAND_CLIENTS_CLIENT_BASE_H_
-#include <drm_fourcc.h>
-
#include <memory>
#include <string>
#include <vector>
@@ -44,7 +42,7 @@ class ClientBase {
bool transparent_background = false;
bool use_drm = false;
std::string use_drm_value;
- int32_t drm_format = DRM_FORMAT_ABGR8888;
+ int32_t drm_format = 0;
};
struct Globals {
diff --git a/chromium/components/exo/wayland/clients/yuv.cc b/chromium/components/exo/wayland/clients/yuv.cc
index 0f6cebc6b81..2c33be576fd 100644
--- a/chromium/components/exo/wayland/clients/yuv.cc
+++ b/chromium/components/exo/wayland/clients/yuv.cc
@@ -38,8 +38,9 @@ bool YuvClient::WriteSolidColor(gbm_bo* bo, SkColor color) {
base::ScopedFD fd(gbm_bo_get_plane_fd(bo, i));
uint32_t stride = gbm_bo_get_plane_stride(bo, i);
uint32_t offset = gbm_bo_get_plane_offset(bo, i);
- void* void_data = mmap(nullptr, gbm_bo_get_plane_size(bo, i) + offset,
- (PROT_READ | PROT_WRITE), MAP_SHARED, fd.get(), 0);
+ uint32_t map_size = gbm_bo_get_plane_size(bo, i) + offset;
+ void* void_data = mmap(nullptr, map_size, (PROT_READ | PROT_WRITE),
+ MAP_SHARED, fd.get(), 0);
if (void_data == MAP_FAILED) {
LOG(ERROR) << "Failed mmap().";
return false;
@@ -66,6 +67,11 @@ bool YuvClient::WriteSolidColor(gbm_bo* bo, SkColor color) {
}
}
}
+ int ret = munmap(void_data, map_size);
+ if (ret) {
+ LOG(ERROR) << "Failed munmap().";
+ return false;
+ }
}
return true;
}
diff --git a/chromium/components/exo/wayland/server.cc b/chromium/components/exo/wayland/server.cc
index 0faf554a77f..45295ff70a5 100644
--- a/chromium/components/exo/wayland/server.cc
+++ b/chromium/components/exo/wayland/server.cc
@@ -31,6 +31,7 @@
#include <utility>
#include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/interfaces/window_pin_type.mojom.h"
#include "ash/shell.h"
#include "base/bind.h"
#include "base/cancelable_callback.h"
@@ -158,8 +159,9 @@ DEFINE_UI_CLASS_PROPERTY_KEY(bool, kSurfaceHasSecurityKey, false);
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kSurfaceHasBlendingKey, false);
// A property key containing a boolean set to true whether the current
-// OnWindowActivated invocation should be ignored.
-DEFINE_UI_CLASS_PROPERTY_KEY(bool, kIgnoreWindowActivated, false);
+// OnWindowActivated invocation should be ignored. The defualt is true
+// to ignore the activation event originated by creation.
+DEFINE_UI_CLASS_PROPERTY_KEY(bool, kIgnoreWindowActivated, true);
wl_resource* GetSurfaceResource(Surface* surface) {
return surface->GetProperty(kSurfaceResourceKey);
@@ -1012,7 +1014,7 @@ uint32_t HandleShellSurfaceConfigureCallback(
ash::wm::WindowStateType state_type,
bool resizing,
bool activated,
- const gfx::Point& origin) {
+ const gfx::Vector2d& origin_offset) {
wl_shell_surface_send_configure(resource, WL_SHELL_SURFACE_RESIZE_NONE,
size.width(), size.height());
wl_client_flush(wl_resource_get_client(resource));
@@ -1538,7 +1540,7 @@ uint32_t HandleXdgToplevelV6ConfigureCallback(
ash::wm::WindowStateType state_type,
bool resizing,
bool activated,
- const gfx::Point& origin) {
+ const gfx::Vector2d& origin_offset) {
wl_array states;
wl_array_init(&states);
if (state_type == ash::wm::WINDOW_STATE_TYPE_MAXIMIZED)
@@ -1676,7 +1678,7 @@ uint32_t HandleXdgSurfaceV5ConfigureCallback(
ash::wm::WindowStateType state_type,
bool resizing,
bool activated,
- const gfx::Point& origin) {
+ const gfx::Vector2d& origin_offset) {
wl_array states;
wl_array_init(&states);
if (state_type == ash::wm::WINDOW_STATE_TYPE_MAXIMIZED)
@@ -1935,8 +1937,8 @@ void remote_surface_activate(wl_client* client,
// Activation on Aura is synchronous, so activation callbacks will be called
// before the flag is reset.
window->SetProperty(kIgnoreWindowActivated, true);
- GetUserDataAs<ShellSurface>(resource)->Activate();
- window->ClearProperty(kIgnoreWindowActivated);
+ shell_surface->Activate();
+ window->SetProperty(kIgnoreWindowActivated, false);
}
void remote_surface_maximize(wl_client* client, wl_resource* resource) {
@@ -1962,11 +1964,14 @@ void remote_surface_unfullscreen(wl_client* client, wl_resource* resource) {
void remote_surface_pin(wl_client* client,
wl_resource* resource,
int32_t trusted) {
- GetUserDataAs<ShellSurface>(resource)->SetPinned(true, trusted);
+ GetUserDataAs<ShellSurface>(resource)->SetPinned(
+ trusted ? ash::mojom::WindowPinType::TRUSTED_PINNED
+ : ash::mojom::WindowPinType::PINNED);
}
void remote_surface_unpin(wl_client* client, wl_resource* resource) {
- GetUserDataAs<ShellSurface>(resource)->SetPinned(false, /* trusted */ false);
+ GetUserDataAs<ShellSurface>(resource)->SetPinned(
+ ash::mojom::WindowPinType::NONE);
}
void remote_surface_set_system_modal(wl_client* client, wl_resource* resource) {
@@ -2003,7 +2008,7 @@ void remote_surface_ack_configure(wl_client* client,
}
void remote_surface_move(wl_client* client, wl_resource* resource) {
- NOTIMPLEMENTED();
+ GetUserDataAs<ShellSurface>(resource)->Move();
}
const struct zcr_remote_surface_v1_interface remote_surface_implementation = {
@@ -2078,7 +2083,7 @@ class WaylandRemoteShell : public WMHelper::MaximizeModeObserver,
std::unique_ptr<ShellSurface> CreateShellSurface(Surface* surface,
int container) {
- return display_->CreateRemoteShellSurface(surface, gfx::Point(), container);
+ return display_->CreateRemoteShellSurface(surface, container);
}
std::unique_ptr<NotificationSurface> CreateNotificationSurface(
@@ -2088,9 +2093,20 @@ class WaylandRemoteShell : public WMHelper::MaximizeModeObserver,
}
// Overridden from display::DisplayObserver:
+ void OnDisplayAdded(const display::Display& new_display) override {
+ if (IsMultiDisplaySupported())
+ ScheduleSendDisplayMetrics(0);
+ }
+
+ void OnDisplayRemoved(const display::Display& old_display) override {
+ if (IsMultiDisplaySupported())
+ ScheduleSendDisplayMetrics(0);
+ }
+
void OnDisplayMetricsChanged(const display::Display& display,
uint32_t changed_metrics) override {
- if (display::Screen::GetScreen()->GetPrimaryDisplay().id() != display.id())
+ if (!IsMultiDisplaySupported() &&
+ display::Screen::GetScreen()->GetPrimaryDisplay().id() != display.id())
return;
// No need to update when a primary display has changed without bounds
@@ -2121,8 +2137,11 @@ class WaylandRemoteShell : public WMHelper::MaximizeModeObserver,
// already activated on the client side, so do not notify about the
// activation. It means that zcr_remote_shell_v1_send_activated is used
// only to notify about activations originating in Aura.
- if (gained_active && gained_active->GetProperty(kIgnoreWindowActivated))
+ if (gained_active && ShellSurface::GetMainSurface(gained_active) &&
+ gained_active->GetProperty(kIgnoreWindowActivated)) {
+ gained_active->SetProperty(kIgnoreWindowActivated, false);
return;
+ }
SendActivated(gained_active, lost_active);
}
@@ -2142,9 +2161,27 @@ class WaylandRemoteShell : public WMHelper::MaximizeModeObserver,
needs_send_display_metrics_ = false;
const display::Screen* screen = display::Screen::GetScreen();
- const display::Display primary_display = screen->GetPrimaryDisplay();
- const gfx::Insets& work_area_insets = primary_display.GetWorkAreaInsets();
+ if (IsMultiDisplaySupported()) {
+ for (const auto& display : screen->GetAllDisplays()) {
+ const gfx::Rect& bounds = display.bounds();
+ const gfx::Insets& insets = display.GetWorkAreaInsets();
+
+ zcr_remote_shell_v1_send_workspace(
+ remote_shell_resource_,
+ static_cast<uint32_t>(display.id() >> 32),
+ static_cast<uint32_t>(display.id()),
+ bounds.x(), bounds.y(), bounds.width(), bounds.height(),
+ insets.left(), insets.top(), insets.right(), insets.bottom(),
+ OutputTransform(display.rotation()),
+ wl_fixed_from_double(display.device_scale_factor()));
+ }
+
+ zcr_remote_shell_v1_send_configure(remote_shell_resource_, layout_mode_);
+ }
+
+ display::Display primary_display = screen->GetPrimaryDisplay();
+ const gfx::Insets& insets = primary_display.GetWorkAreaInsets();
zcr_remote_shell_v1_send_configuration_changed(
remote_shell_resource_,
@@ -2152,8 +2189,8 @@ class WaylandRemoteShell : public WMHelper::MaximizeModeObserver,
primary_display.size().height(),
OutputTransform(primary_display.rotation()),
wl_fixed_from_double(primary_display.device_scale_factor()),
- work_area_insets.left(), work_area_insets.top(),
- work_area_insets.right(), work_area_insets.bottom(), layout_mode_);
+ insets.left(), insets.top(), insets.right(), insets.bottom(),
+ layout_mode_);
wl_client_flush(wl_resource_get_client(remote_shell_resource_));
}
@@ -2263,12 +2300,14 @@ uint32_t HandleRemoteSurfaceConfigureCallback(
ash::wm::WindowStateType state_type,
bool resizing,
bool activated,
- const gfx::Point& origin) {
+ const gfx::Vector2d& origin_offset) {
wl_array states;
wl_array_init(&states);
uint32_t serial = wl_display_next_serial(
wl_client_get_display(wl_resource_get_client(resource)));
- zcr_remote_surface_v1_send_configure(resource, origin.x(), origin.y(),
+ zcr_remote_surface_v1_send_configure(resource,
+ origin_offset.x(),
+ origin_offset.y(),
&states, serial);
wl_client_flush(wl_resource_get_client(resource));
wl_array_release(&states);
@@ -2614,12 +2653,6 @@ class WaylandPointerDelegate : public PointerDelegate {
WL_POINTER_AXIS_VERTICAL_SCROLL,
wl_fixed_from_double(-y_value));
}
- void OnPointerScrollCancel(base::TimeTicks time_stamp) override {
- // Wayland doesn't know the concept of a canceling kinetic scrolling.
- // But we can send a 0 distance scroll to emulate this behavior.
- OnPointerScroll(time_stamp, gfx::Vector2dF(0, 0), false);
- OnPointerScrollStop(time_stamp);
- }
void OnPointerScrollStop(base::TimeTicks time_stamp) override {
if (wl_resource_get_version(pointer_resource_) >=
WL_POINTER_AXIS_STOP_SINCE_VERSION) {
diff --git a/chromium/components/exo/wm_helper.cc b/chromium/components/exo/wm_helper.cc
index 009d4cc8838..7f0cfcffe72 100644
--- a/chromium/components/exo/wm_helper.cc
+++ b/chromium/components/exo/wm_helper.cc
@@ -79,6 +79,16 @@ void WMHelper::RemoveInputDeviceEventObserver(
input_device_event_observers_.RemoveObserver(observer);
}
+void WMHelper::AddDisplayConfigurationObserver(
+ DisplayConfigurationObserver* observer) {
+ display_config_observers_.AddObserver(observer);
+}
+
+void WMHelper::RemoveDisplayConfigurationObserver(
+ DisplayConfigurationObserver* observer) {
+ display_config_observers_.RemoveObserver(observer);
+}
+
void WMHelper::NotifyWindowActivated(aura::Window* gained_active,
aura::Window* lost_active) {
for (ActivationObserver& observer : activation_observers_)
@@ -126,4 +136,9 @@ void WMHelper::NotifyKeyboardDeviceConfigurationChanged() {
observer.OnKeyboardDeviceConfigurationChanged();
}
+void WMHelper::NotifyDisplayConfigurationChanged() {
+ for (DisplayConfigurationObserver& observer : display_config_observers_)
+ observer.OnDisplayConfigurationChanged();
+}
+
} // namespace exo
diff --git a/chromium/components/exo/wm_helper.h b/chromium/components/exo/wm_helper.h
index 9ce432b862d..ad0aeb6ac5a 100644
--- a/chromium/components/exo/wm_helper.h
+++ b/chromium/components/exo/wm_helper.h
@@ -79,6 +79,14 @@ class WMHelper {
virtual ~InputDeviceEventObserver() {}
};
+ class DisplayConfigurationObserver {
+ public:
+ virtual void OnDisplayConfigurationChanged() = 0;
+
+ protected:
+ virtual ~DisplayConfigurationObserver() {}
+ };
+
virtual ~WMHelper();
static void SetInstance(WMHelper* helper);
@@ -96,6 +104,9 @@ class WMHelper {
void RemoveAccessibilityObserver(AccessibilityObserver* observer);
void AddInputDeviceEventObserver(InputDeviceEventObserver* observer);
void RemoveInputDeviceEventObserver(InputDeviceEventObserver* observer);
+ void AddDisplayConfigurationObserver(DisplayConfigurationObserver* observer);
+ void RemoveDisplayConfigurationObserver(
+ DisplayConfigurationObserver* observer);
virtual const display::ManagedDisplayInfo GetDisplayInfo(
int64_t display_id) const = 0;
@@ -126,6 +137,7 @@ class WMHelper {
void NotifyMaximizeModeEnded();
void NotifyAccessibilityModeChanged();
void NotifyKeyboardDeviceConfigurationChanged();
+ void NotifyDisplayConfigurationChanged();
private:
base::ObserverList<ActivationObserver> activation_observers_;
@@ -134,6 +146,7 @@ class WMHelper {
base::ObserverList<MaximizeModeObserver> maximize_mode_observers_;
base::ObserverList<AccessibilityObserver> accessibility_observers_;
base::ObserverList<InputDeviceEventObserver> input_device_event_observers_;
+ base::ObserverList<DisplayConfigurationObserver> display_config_observers_;
DISALLOW_COPY_AND_ASSIGN(WMHelper);
};
diff --git a/chromium/components/exo/wm_helper_ash.cc b/chromium/components/exo/wm_helper_ash.cc
index 413eeb8e6a6..3fbec935039 100644
--- a/chromium/components/exo/wm_helper_ash.cc
+++ b/chromium/components/exo/wm_helper_ash.cc
@@ -4,11 +4,12 @@
#include "components/exo/wm_helper_ash.h"
-#include "ash/common/accessibility_delegate.h"
-#include "ash/common/system/tray/system_tray_notifier.h"
-#include "ash/common/wm/maximize_mode/maximize_mode_controller.h"
-#include "ash/common/wm_shell.h"
+#include "ash/accessibility_delegate.h"
+#include "ash/public/cpp/config.h"
#include "ash/shell.h"
+#include "ash/shell_port.h"
+#include "ash/system/tray/system_tray_notifier.h"
+#include "ash/wm/maximize_mode/maximize_mode_controller.h"
#include "base/memory/singleton.h"
#include "ui/aura/client/focus_client.h"
#include "ui/display/manager/display_manager.h"
@@ -21,13 +22,19 @@ namespace exo {
// WMHelperAsh, public:
WMHelperAsh::WMHelperAsh() {
- ash::WmShell::Get()->AddShellObserver(this);
- ash::Shell::GetInstance()->activation_client()->AddObserver(this);
+ ash::Shell::Get()->AddShellObserver(this);
+ ash::Shell::Get()->activation_client()->AddObserver(this);
+ // TODO(crbug.com/631103): Mushrome doesn't have a cursor manager yet.
+ if (ash::ShellPort::Get()->GetAshConfig() != ash::Config::MUS)
+ ash::Shell::Get()->cursor_manager()->AddObserver(this);
+ ash::ShellPort::Get()->AddDisplayObserver(this);
aura::client::FocusClient* focus_client =
aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
focus_client->AddObserver(this);
- ui::DeviceDataManager::GetInstance()->AddObserver(this);
- ash::WmShell::Get()->system_tray_notifier()->AddAccessibilityObserver(this);
+ // TODO(crbug.com/709225): Mushrome doesn't have a DeviceDataManager.
+ if (ash::ShellPort::Get()->GetAshConfig() != ash::Config::MUS)
+ ui::DeviceDataManager::GetInstance()->AddObserver(this);
+ ash::Shell::Get()->system_tray_notifier()->AddAccessibilityObserver(this);
}
WMHelperAsh::~WMHelperAsh() {
@@ -36,11 +43,16 @@ WMHelperAsh::~WMHelperAsh() {
aura::client::FocusClient* focus_client =
aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
focus_client->RemoveObserver(this);
- ash::Shell::GetInstance()->activation_client()->RemoveObserver(this);
- ash::WmShell::Get()->RemoveShellObserver(this);
- ui::DeviceDataManager::GetInstance()->RemoveObserver(this);
- ash::WmShell::Get()->system_tray_notifier()->RemoveAccessibilityObserver(
- this);
+ ash::ShellPort::Get()->RemoveDisplayObserver(this);
+ // TODO(crbug.com/631103): Mushrome doesn't have a cursor manager yet.
+ if (ash::ShellPort::Get()->GetAshConfig() != ash::Config::MUS)
+ ash::Shell::Get()->cursor_manager()->RemoveObserver(this);
+ ash::Shell::Get()->activation_client()->RemoveObserver(this);
+ ash::Shell::Get()->RemoveShellObserver(this);
+ // TODO(crbug.com/709225): Mushrome doesn't have a DeviceDataManager.
+ if (ash::ShellPort::Get()->GetAshConfig() != ash::Config::MUS)
+ ui::DeviceDataManager::GetInstance()->RemoveObserver(this);
+ ash::Shell::Get()->system_tray_notifier()->RemoveAccessibilityObserver(this);
}
////////////////////////////////////////////////////////////////////////////////
@@ -48,17 +60,18 @@ WMHelperAsh::~WMHelperAsh() {
const display::ManagedDisplayInfo WMHelperAsh::GetDisplayInfo(
int64_t display_id) const {
- return ash::Shell::GetInstance()->display_manager()->GetDisplayInfo(
- display_id);
+ return ash::Shell::Get()->display_manager()->GetDisplayInfo(display_id);
}
aura::Window* WMHelperAsh::GetContainer(int container_id) {
- return ash::Shell::GetContainer(ash::Shell::GetTargetRootWindow(),
+ // TODO(domlaskowski): Use target root window once multi-display support lands
+ // in ARC. See crbug.com/718627.
+ return ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
container_id);
}
aura::Window* WMHelperAsh::GetActiveWindow() const {
- return ash::Shell::GetInstance()->activation_client()->GetActiveWindow();
+ return ash::Shell::Get()->activation_client()->GetActiveWindow();
}
aura::Window* WMHelperAsh::GetFocusedWindow() const {
@@ -68,43 +81,44 @@ aura::Window* WMHelperAsh::GetFocusedWindow() const {
}
ui::CursorSetType WMHelperAsh::GetCursorSet() const {
- return ash::Shell::GetInstance()->cursor_manager()->GetCursorSet();
+ // TODO(crbug.com/631103): Mushrome doesn't have a cursor manager yet.
+ if (ash::ShellPort::Get()->GetAshConfig() == ash::Config::MUS)
+ return ui::CURSOR_SET_NORMAL;
+ return ash::Shell::Get()->cursor_manager()->GetCursorSet();
}
void WMHelperAsh::AddPreTargetHandler(ui::EventHandler* handler) {
- ash::Shell::GetInstance()->AddPreTargetHandler(handler);
+ ash::Shell::Get()->AddPreTargetHandler(handler);
}
void WMHelperAsh::PrependPreTargetHandler(ui::EventHandler* handler) {
- ash::Shell::GetInstance()->PrependPreTargetHandler(handler);
+ ash::Shell::Get()->PrependPreTargetHandler(handler);
}
void WMHelperAsh::RemovePreTargetHandler(ui::EventHandler* handler) {
- ash::Shell::GetInstance()->RemovePreTargetHandler(handler);
+ ash::Shell::Get()->RemovePreTargetHandler(handler);
}
void WMHelperAsh::AddPostTargetHandler(ui::EventHandler* handler) {
- ash::Shell::GetInstance()->AddPostTargetHandler(handler);
+ ash::Shell::Get()->AddPostTargetHandler(handler);
}
void WMHelperAsh::RemovePostTargetHandler(ui::EventHandler* handler) {
- ash::Shell::GetInstance()->RemovePostTargetHandler(handler);
+ ash::Shell::Get()->RemovePostTargetHandler(handler);
}
bool WMHelperAsh::IsMaximizeModeWindowManagerEnabled() const {
- return ash::WmShell::Get()
+ return ash::Shell::Get()
->maximize_mode_controller()
->IsMaximizeModeWindowManagerEnabled();
}
bool WMHelperAsh::IsSpokenFeedbackEnabled() const {
- return ash::WmShell::Get()
- ->accessibility_delegate()
- ->IsSpokenFeedbackEnabled();
+ return ash::Shell::Get()->accessibility_delegate()->IsSpokenFeedbackEnabled();
}
void WMHelperAsh::PlayEarcon(int sound_key) const {
- return ash::WmShell::Get()->accessibility_delegate()->PlayEarcon(sound_key);
+ return ash::Shell::Get()->accessibility_delegate()->PlayEarcon(sound_key);
}
void WMHelperAsh::OnWindowActivated(
@@ -144,6 +158,10 @@ void WMHelperAsh::OnMaximizeModeEnded() {
NotifyMaximizeModeEnded();
}
+void WMHelperAsh::OnDisplayConfigurationChanged() {
+ NotifyDisplayConfigurationChanged();
+}
+
void WMHelperAsh::OnKeyboardDeviceConfigurationChanged() {
NotifyKeyboardDeviceConfigurationChanged();
}
diff --git a/chromium/components/exo/wm_helper_ash.h b/chromium/components/exo/wm_helper_ash.h
index b41e750bb0c..dc39a292e3b 100644
--- a/chromium/components/exo/wm_helper_ash.h
+++ b/chromium/components/exo/wm_helper_ash.h
@@ -5,8 +5,9 @@
#ifndef COMPONENTS_EXO_WM_HELPER_ASH_H_
#define COMPONENTS_EXO_WM_HELPER_ASH_H_
-#include "ash/common/shell_observer.h"
-#include "ash/common/system/accessibility_observer.h"
+#include "ash/shell_observer.h"
+#include "ash/system/accessibility_observer.h"
+#include "ash/wm_display_observer.h"
#include "base/macros.h"
#include "components/exo/wm_helper.h"
#include "ui/aura/client/cursor_client_observer.h"
@@ -23,12 +24,13 @@ class WMHelperAsh : public WMHelper,
public aura::client::CursorClientObserver,
public ash::AccessibilityObserver,
public ash::ShellObserver,
+ public ash::WmDisplayObserver,
public ui::InputDeviceEventObserver {
public:
WMHelperAsh();
~WMHelperAsh() override;
- // Overriden from WMHelper:
+ // Overridden from WMHelper:
const display::ManagedDisplayInfo GetDisplayInfo(
int64_t display_id) const override;
aura::Window* GetContainer(int container_id) override;
@@ -44,17 +46,17 @@ class WMHelperAsh : public WMHelper,
bool IsSpokenFeedbackEnabled() const override;
void PlayEarcon(int sound_key) const override;
- // Overriden from aura::client::ActivationChangeObserver:
+ // Overridden from aura::client::ActivationChangeObserver:
void OnWindowActivated(
aura::client::ActivationChangeObserver::ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) override;
- // Overriden from aura::client::FocusChangeObserver:
+ // Overridden from aura::client::FocusChangeObserver:
void OnWindowFocused(aura::Window* gained_focus,
aura::Window* lost_focus) override;
- // Overriden from aura::client::CursorClientObserver:
+ // Overridden from aura::client::CursorClientObserver:
void OnCursorVisibilityChanged(bool is_visible) override;
void OnCursorSetChanged(ui::CursorSetType cursor_set) override;
@@ -62,12 +64,15 @@ class WMHelperAsh : public WMHelper,
void OnAccessibilityModeChanged(
ash::AccessibilityNotificationVisibility notify) override;
- // Overriden from ash::ShellObserver:
+ // Overridden from ash::ShellObserver:
void OnMaximizeModeStarted() override;
void OnMaximizeModeEnding() override;
void OnMaximizeModeEnded() override;
- // Overriden from ui::InputDeviceEventObserver:
+ // Overridden from ash::WmDisplayObserver:
+ void OnDisplayConfigurationChanged() override;
+
+ // Overridden from ui::InputDeviceEventObserver:
void OnKeyboardDeviceConfigurationChanged() override;
private:
diff --git a/chromium/components/exo/wm_helper_mus.cc b/chromium/components/exo/wm_helper_mus.cc
index 07a60cfdce7..a13d09ff997 100644
--- a/chromium/components/exo/wm_helper_mus.cc
+++ b/chromium/components/exo/wm_helper_mus.cc
@@ -6,8 +6,11 @@
#include "ui/aura/client/focus_client.h"
#include "ui/aura/env.h"
+#include "ui/aura/mus/focus_synchronizer.h"
+#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/window.h"
#include "ui/display/manager/managed_display_info.h"
+#include "ui/views/mus/mus_client.h"
#include "ui/wm/public/activation_client.h"
namespace exo {
@@ -15,16 +18,20 @@ namespace exo {
// WMHelperMus, public:
WMHelperMus::WMHelperMus() {
- aura::Env* env = aura::Env::GetInstance();
- SetActiveFocusClient(env->active_focus_client(),
- env->active_focus_client_root());
- env->AddObserver(this);
+ aura::FocusSynchronizer* focus_synchronizer =
+ views::MusClient::Get()->window_tree_client()->focus_synchronizer();
+ SetActiveFocusClient(focus_synchronizer->active_focus_client(),
+ focus_synchronizer->active_focus_client_root());
+ focus_synchronizer->AddObserver(this);
}
WMHelperMus::~WMHelperMus() {
if (active_focus_client_)
active_focus_client_->RemoveObserver(this);
- aura::Env::GetInstance()->RemoveObserver(this);
+ views::MusClient::Get()
+ ->window_tree_client()
+ ->focus_synchronizer()
+ ->RemoveObserver(this);
}
////////////////////////////////////////////////////////////////////////////////
@@ -88,12 +95,10 @@ void WMHelperMus::PlayEarcon(int sound_key) const {
NOTIMPLEMENTED();
}
-void WMHelperMus::OnWindowInitialized(aura::Window* window) {}
-
void WMHelperMus::OnActiveFocusClientChanged(
aura::client::FocusClient* focus_client,
- aura::Window* window) {
- SetActiveFocusClient(focus_client, window);
+ aura::Window* focus_client_root) {
+ SetActiveFocusClient(focus_client, focus_client_root);
}
void WMHelperMus::OnWindowFocused(aura::Window* gained_focus,
diff --git a/chromium/components/exo/wm_helper_mus.h b/chromium/components/exo/wm_helper_mus.h
index f1fb4cc7392..c1d955834e7 100644
--- a/chromium/components/exo/wm_helper_mus.h
+++ b/chromium/components/exo/wm_helper_mus.h
@@ -8,7 +8,7 @@
#include "base/macros.h"
#include "components/exo/wm_helper.h"
#include "ui/aura/client/focus_change_observer.h"
-#include "ui/aura/env_observer.h"
+#include "ui/aura/mus/focus_synchronizer_observer.h"
#include "ui/events/devices/input_device_event_observer.h"
namespace aura {
@@ -20,15 +20,16 @@ class ActivationClient;
namespace exo {
// A helper class for accessing WindowManager related features.
+// This is only used for mash. Mushrome uses WMHelperAsh.
class WMHelperMus : public WMHelper,
public ui::InputDeviceEventObserver,
- public aura::EnvObserver,
+ public aura::FocusSynchronizerObserver,
public aura::client::FocusChangeObserver {
public:
WMHelperMus();
~WMHelperMus() override;
- // Overriden from WMHelper:
+ // Overridden from WMHelper:
const display::ManagedDisplayInfo GetDisplayInfo(
int64_t display_id) const override;
aura::Window* GetContainer(int container_id) override;
@@ -44,16 +45,15 @@ class WMHelperMus : public WMHelper,
bool IsSpokenFeedbackEnabled() const override;
void PlayEarcon(int sound_key) const override;
- // Overriden from aura::EnvObserver:
- void OnWindowInitialized(aura::Window* window) override;
+ // Overridden from aura::FocusSynchronizerObserver:
void OnActiveFocusClientChanged(aura::client::FocusClient* focus_client,
- aura::Window* window) override;
+ aura::Window* focus_client_root) override;
- // Overriden from ui::client::FocusChangeObserver:
+ // Overridden from ui::client::FocusChangeObserver:
void OnWindowFocused(aura::Window* gained_focus,
aura::Window* lost_focus) override;
- // Overriden from ui::InputDeviceEventObserver:
+ // Overridden from ui::InputDeviceEventObserver:
void OnKeyboardDeviceConfigurationChanged() override;
private:
diff --git a/chromium/components/favicon/content/content_favicon_driver.cc b/chromium/components/favicon/content/content_favicon_driver.cc
index cf9bba46bd0..d6bbcac5d8f 100644
--- a/chromium/components/favicon/content/content_favicon_driver.cc
+++ b/chromium/components/favicon/content/content_favicon_driver.cc
@@ -109,11 +109,6 @@ ContentFaviconDriver::~ContentFaviconDriver() {
int ContentFaviconDriver::DownloadImage(const GURL& url,
int max_image_size,
ImageDownloadCallback callback) {
- if (WasUnableToDownloadFavicon(url)) {
- DVLOG(1) << "Skip Failed FavIcon: " << url;
- return 0;
- }
-
bool bypass_cache = (bypass_cache_page_url_ == GetActiveURL());
bypass_cache_page_url_ = GURL();
diff --git a/chromium/components/favicon/content/content_favicon_driver_unittest.cc b/chromium/components/favicon/content/content_favicon_driver_unittest.cc
index 73769c5f2f2..5439aee3d76 100644
--- a/chromium/components/favicon/content/content_favicon_driver_unittest.cc
+++ b/chromium/components/favicon/content/content_favicon_driver_unittest.cc
@@ -72,62 +72,46 @@ class ContentFaviconDriverTest : public content::RenderViewHostTestHarness {
testing::NiceMock<MockFaviconService> favicon_service_;
};
-// Test that UnableToDownloadFavicon() is not called as a result of a favicon
-// download with 200 status.
-TEST_F(ContentFaviconDriverTest, ShouldNotCallUnableToDownloadFaviconFor200) {
- EXPECT_CALL(favicon_service_, UnableToDownloadFavicon(kIconURL)).Times(0);
+// Test that a download is initiated when there isn't a favicon in the database
+// for either the page URL or the icon URL.
+TEST_F(ContentFaviconDriverTest, ShouldCauseImageDownload) {
// Mimic a page load.
TestFetchFaviconForPage(
kPageURL,
{content::FaviconURL(kIconURL, content::FaviconURL::FAVICON,
kEmptyIconSizes)});
- // Completing the download should not cause a call to
- // UnableToDownloadFavicon().
EXPECT_TRUE(web_contents_tester()->TestDidDownloadImage(
kIconURL, 200, kEmptyIcons, kEmptyIconSizes));
}
-// Test that UnableToDownloadFavicon() is called as a result of a favicon
-// download with 404 status.
-TEST_F(ContentFaviconDriverTest, ShouldCallUnableToDownloadFaviconFor404) {
- EXPECT_CALL(favicon_service_, UnableToDownloadFavicon(kIconURL));
- // Mimic a page load.
- TestFetchFaviconForPage(
- kPageURL,
- {content::FaviconURL(kIconURL, content::FaviconURL::FAVICON,
- kEmptyIconSizes)});
- // Mimic the completion of an image download.
- EXPECT_TRUE(web_contents_tester()->TestDidDownloadImage(
- kIconURL, 404, kEmptyIcons, kEmptyIconSizes));
-}
-
-// Test that UnableToDownloadFavicon() is not called as a result of a favicon
-// download with 503 status.
-TEST_F(ContentFaviconDriverTest, ShouldNotCallUnableToDownloadFaviconFor503) {
- EXPECT_CALL(favicon_service_, UnableToDownloadFavicon(kIconURL)).Times(0);
+// Test that Favicon is not requested repeatedly during the same session if
+// the favicon is known to be unavailable (e.g. due to HTTP 404 status).
+TEST_F(ContentFaviconDriverTest, ShouldNotRequestRepeatedlyIfUnavailable) {
+ ON_CALL(favicon_service_, WasUnableToDownloadFavicon(kIconURL))
+ .WillByDefault(Return(true));
// Mimic a page load.
TestFetchFaviconForPage(
kPageURL,
{content::FaviconURL(kIconURL, content::FaviconURL::FAVICON,
kEmptyIconSizes)});
- // Completing the download should not cause a call to
- // UnableToDownloadFavicon().
- EXPECT_TRUE(web_contents_tester()->TestDidDownloadImage(
- kIconURL, 503, kEmptyIcons, kEmptyIconSizes));
+ // Verify that no download request is pending for the image.
+ EXPECT_FALSE(web_contents_tester()->HasPendingDownloadImage(kIconURL));
}
-// Test that Favicon is not requested repeatedly during the same session if
-// the favicon is known to be unavailable (e.g. due to HTTP 404 status).
-TEST_F(ContentFaviconDriverTest, ShouldNotRequestRepeatedlyIfUnavailable) {
+TEST_F(ContentFaviconDriverTest, ShouldDownloadSecondIfFirstUnavailable) {
+ const GURL kOtherIconURL = GURL("http://www.google.com/other-favicon.ico");
ON_CALL(favicon_service_, WasUnableToDownloadFavicon(kIconURL))
.WillByDefault(Return(true));
// Mimic a page load.
TestFetchFaviconForPage(
kPageURL,
{content::FaviconURL(kIconURL, content::FaviconURL::FAVICON,
+ kEmptyIconSizes),
+ content::FaviconURL(kOtherIconURL, content::FaviconURL::FAVICON,
kEmptyIconSizes)});
- // Verify that no download request is pending for the image.
+ // Verify a download request is pending for the second image.
EXPECT_FALSE(web_contents_tester()->HasPendingDownloadImage(kIconURL));
+ EXPECT_TRUE(web_contents_tester()->HasPendingDownloadImage(kOtherIconURL));
}
// Test that ContentFaviconDriver ignores updated favicon URLs if there is no
diff --git a/chromium/components/favicon/core/BUILD.gn b/chromium/components/favicon/core/BUILD.gn
index 7d8c060d96a..09b113a7f80 100644
--- a/chromium/components/favicon/core/BUILD.gn
+++ b/chromium/components/favicon/core/BUILD.gn
@@ -30,8 +30,10 @@ static_library("core") {
"//base",
"//base:i18n",
"//components/bookmarks/browser",
+ "//components/data_use_measurement/core",
"//components/favicon_base",
"//components/history/core/browser",
+ "//components/image_fetcher/core",
"//components/keyed_service/core",
"//net:net",
"//skia",
@@ -40,6 +42,7 @@ static_library("core") {
"//url",
]
if (!is_ios) {
+ deps += [ "//cc/paint" ]
sources += [
"fallback_icon_client.h",
"fallback_icon_service.cc",
@@ -60,10 +63,12 @@ source_set("unit_tests") {
deps = [
":core",
"//base",
+ "//base/test:test_support",
"//components/favicon/core/test:test_support",
"//components/favicon_base",
"//components/history/core/browser:browser",
"//components/history/core/test:test",
+ "//components/image_fetcher/core",
"//skia",
"//testing/gmock",
"//testing/gtest",
diff --git a/chromium/components/favicon/core/DEPS b/chromium/components/favicon/core/DEPS
index 01613b3e140..47c9ad06444 100644
--- a/chromium/components/favicon/core/DEPS
+++ b/chromium/components/favicon/core/DEPS
@@ -1,7 +1,10 @@
include_rules = [
+ "+cc/paint",
"+components/bookmarks/browser",
+ "+components/data_use_measurement/core",
"+components/history/core/browser",
"+components/history/core/test",
+ "+components/image_fetcher/core",
"+components/keyed_service/core",
"+net/base",
"+skia",
diff --git a/chromium/components/favicon/core/fallback_icon_service.cc b/chromium/components/favicon/core/fallback_icon_service.cc
index 5164f97aa14..291e1fac8a9 100644
--- a/chromium/components/favicon/core/fallback_icon_service.cc
+++ b/chromium/components/favicon/core/fallback_icon_service.cc
@@ -8,6 +8,7 @@
#include <algorithm>
+#include "cc/paint/skia_paint_canvas.h"
#include "components/favicon/core/fallback_icon_client.h"
#include "components/favicon/core/fallback_url_util.h"
#include "components/favicon_base/fallback_icon_style.h"
@@ -40,14 +41,16 @@ std::vector<unsigned char> FallbackIconService::RenderFallbackIconBitmap(
int size,
const favicon_base::FallbackIconStyle& style) {
int size_to_use = std::min(kMaxFallbackFaviconSize, size);
- gfx::Canvas canvas(gfx::Size(size_to_use, size_to_use), 1.0f, false);
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(size_to_use, size_to_use, false);
+ cc::SkiaPaintCanvas paint_canvas(bitmap);
+ gfx::Canvas canvas(&paint_canvas, 1.f);
+
DrawFallbackIcon(icon_url, size_to_use, style, &canvas);
std::vector<unsigned char> bitmap_data;
- if (!gfx::PNGCodec::EncodeBGRASkBitmap(canvas.ExtractImageRep().sk_bitmap(),
- false, &bitmap_data)) {
+ if (!gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &bitmap_data))
bitmap_data.clear();
- }
return bitmap_data;
}
diff --git a/chromium/components/favicon/core/favicon_driver_impl.cc b/chromium/components/favicon/core/favicon_driver_impl.cc
index 453c96b02e0..f77d11b54a5 100644
--- a/chromium/components/favicon/core/favicon_driver_impl.cc
+++ b/chromium/components/favicon/core/favicon_driver_impl.cc
@@ -5,6 +5,7 @@
#include "components/favicon/core/favicon_driver_impl.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
@@ -52,13 +53,17 @@ FaviconDriverImpl::FaviconDriverImpl(FaviconService* favicon_service,
: favicon_service_(favicon_service),
history_service_(history_service),
bookmark_model_(bookmark_model) {
- favicon_handler_.reset(new FaviconHandler(
- favicon_service_, this, kEnableTouchIcon
- ? FaviconDriverObserver::NON_TOUCH_LARGEST
- : FaviconDriverObserver::NON_TOUCH_16_DIP));
+ if (!favicon_service_)
+ return;
+
if (kEnableTouchIcon) {
- touch_icon_handler_.reset(new FaviconHandler(
+ handlers_.push_back(base::MakeUnique<FaviconHandler>(
+ favicon_service_, this, FaviconDriverObserver::NON_TOUCH_LARGEST));
+ handlers_.push_back(base::MakeUnique<FaviconHandler>(
favicon_service_, this, FaviconDriverObserver::TOUCH_LARGEST));
+ } else {
+ handlers_.push_back(base::MakeUnique<FaviconHandler>(
+ favicon_service_, this, FaviconDriverObserver::NON_TOUCH_16_DIP));
}
}
@@ -66,9 +71,8 @@ FaviconDriverImpl::~FaviconDriverImpl() {
}
void FaviconDriverImpl::FetchFavicon(const GURL& url) {
- favicon_handler_->FetchFavicon(url);
- if (touch_icon_handler_.get())
- touch_icon_handler_->FetchFavicon(url);
+ for (const std::unique_ptr<FaviconHandler>& handler : handlers_)
+ handler->FetchFavicon(url);
}
bool FaviconDriverImpl::IsBookmarked(const GURL& url) {
@@ -76,17 +80,13 @@ bool FaviconDriverImpl::IsBookmarked(const GURL& url) {
}
bool FaviconDriverImpl::HasPendingTasksForTest() {
- if (favicon_handler_->HasPendingTasksForTest())
- return true;
- if (touch_icon_handler_ && touch_icon_handler_->HasPendingTasksForTest())
- return true;
+ for (const std::unique_ptr<FaviconHandler>& handler : handlers_) {
+ if (handler->HasPendingTasksForTest())
+ return true;
+ }
return false;
}
-bool FaviconDriverImpl::WasUnableToDownloadFavicon(const GURL& url) {
- return favicon_service_ && favicon_service_->WasUnableToDownloadFavicon(url);
-}
-
void FaviconDriverImpl::SetFaviconOutOfDateForPage(const GURL& url,
bool force_reload) {
if (favicon_service_) {
@@ -101,9 +101,8 @@ void FaviconDriverImpl::OnUpdateFaviconURL(
const std::vector<FaviconURL>& candidates) {
DCHECK(!candidates.empty());
RecordCandidateMetrics(candidates);
- favicon_handler_->OnUpdateFaviconURL(page_url, candidates);
- if (touch_icon_handler_.get())
- touch_icon_handler_->OnUpdateFaviconURL(page_url, candidates);
+ for (const std::unique_ptr<FaviconHandler>& handler : handlers_)
+ handler->OnUpdateFaviconURL(page_url, candidates);
}
} // namespace favicon
diff --git a/chromium/components/favicon/core/favicon_driver_impl.h b/chromium/components/favicon/core/favicon_driver_impl.h
index 7d33c3ef936..2faa6f3fa9b 100644
--- a/chromium/components/favicon/core/favicon_driver_impl.h
+++ b/chromium/components/favicon/core/favicon_driver_impl.h
@@ -53,9 +53,6 @@ class FaviconDriverImpl : public FaviconDriver,
bookmarks::BookmarkModel* bookmark_model);
~FaviconDriverImpl() override;
- // Returns whether downloading favicon for |url| previously failed.
- bool WasUnableToDownloadFavicon(const GURL& url);
-
// Informs FaviconService that the favicon for |url| is out of date. If
// |force_reload| is true, then discard information about favicon download
// failures.
@@ -78,9 +75,7 @@ class FaviconDriverImpl : public FaviconDriver,
bookmarks::BookmarkModel* bookmark_model_;
// FaviconHandlers used to download the different kind of favicons.
- // |touch_icon_handler_| may be null depending on the platform and variations.
- std::unique_ptr<FaviconHandler> favicon_handler_;
- std::unique_ptr<FaviconHandler> touch_icon_handler_;
+ std::vector<std::unique_ptr<FaviconHandler>> handlers_;
DISALLOW_COPY_AND_ASSIGN(FaviconDriverImpl);
};
diff --git a/chromium/components/favicon/core/favicon_handler.cc b/chromium/components/favicon/core/favicon_handler.cc
index adbb5df8e2a..738fa28cd48 100644
--- a/chromium/components/favicon/core/favicon_handler.cc
+++ b/chromium/components/favicon/core/favicon_handler.cc
@@ -6,11 +6,13 @@
#include <algorithm>
#include <cmath>
+#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/memory/ref_counted_memory.h"
+#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
#include "components/favicon/core/favicon_service.h"
#include "components/favicon_base/favicon_util.h"
@@ -23,29 +25,24 @@
namespace favicon {
namespace {
+const int kNonTouchLargestIconSize = 192;
+
// Size (along each axis) of a touch icon. This currently corresponds to
// the apple touch icon for iPad.
const int kTouchIconSize = 144;
-bool DoUrlAndIconMatch(const FaviconURL& favicon_url,
- const GURL& url,
- favicon_base::IconType icon_type) {
- return favicon_url.icon_url == url && favicon_url.icon_type == icon_type;
-}
-
// Returns true if all of the icon URLs and icon types in |bitmap_results| are
-// identical and if they match the icon URL and icon type in |favicon_url|.
-// Returns false if |bitmap_results| is empty.
+// identical and if they match |icon_url| and |icon_type|. Returns false if
+// |bitmap_results| is empty.
bool DoUrlsAndIconsMatch(
- const FaviconURL& favicon_url,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) {
if (bitmap_results.empty())
return false;
- const favicon_base::IconType icon_type = favicon_url.icon_type;
-
for (const auto& bitmap_result : bitmap_results) {
- if (favicon_url.icon_url != bitmap_result.icon_url ||
+ if (icon_url != bitmap_result.icon_url ||
icon_type != bitmap_result.icon_type) {
return false;
}
@@ -63,6 +60,36 @@ bool IsValid(const favicon_base::FaviconRawBitmapResult& bitmap_result) {
return bitmap_result.is_valid();
}
+void RecordDownloadAttemptsForHandlerType(
+ FaviconDriverObserver::NotificationIconType handler_type,
+ int attempts) {
+ // If not at least one attempts was recorded or more than 15 attempts were
+ // registered, something went wrong. Underflows are stored in bucket 0 and
+ // overflows in bucket 16.
+ attempts = std::max(0, std::min(attempts, 16));
+ switch (handler_type) {
+ case FaviconDriverObserver::NON_TOUCH_16_DIP:
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Favicons.DownloadAttempts.Favicons",
+ attempts);
+ return;
+ case FaviconDriverObserver::NON_TOUCH_LARGEST:
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Favicons.DownloadAttempts.LargeIcons",
+ attempts);
+ return;
+ case FaviconDriverObserver::TOUCH_LARGEST:
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Favicons.DownloadAttempts.TouchIcons",
+ attempts);
+ return;
+ }
+ NOTREACHED();
+}
+
+void RecordDownloadOutcome(FaviconHandler::DownloadOutcome outcome) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Favicons.DownloadOutcome", outcome,
+ FaviconHandler::DownloadOutcome::DOWNLOAD_OUTCOME_COUNT);
+}
+
// Returns true if |bitmap_results| is non-empty and:
// - At least one of the bitmaps in |bitmap_results| is expired
// OR
@@ -113,100 +140,47 @@ bool HasValidResult(
bitmap_results.end();
}
-// Returns the index of the entry with the largest area.
-int GetLargestSizeIndex(const std::vector<gfx::Size>& sizes) {
- DCHECK(!sizes.empty());
- size_t ret = 0;
- for (size_t i = 1; i < sizes.size(); ++i) {
- if (sizes[ret].GetArea() < sizes[i].GetArea())
- ret = i;
- }
- return static_cast<int>(ret);
-}
-
-// Return the index of a size which is same as the given |size|, -1 returned if
-// there is no such bitmap.
-int GetIndexBySize(const std::vector<gfx::Size>& sizes,
- const gfx::Size& size) {
- DCHECK(!sizes.empty());
- std::vector<gfx::Size>::const_iterator i =
- std::find(sizes.begin(), sizes.end(), size);
- if (i == sizes.end())
- return -1;
-
- return static_cast<int>(i - sizes.begin());
-}
-
-// Compare function used for std::stable_sort to sort as descend.
-bool CompareIconSize(const FaviconURL& b1, const FaviconURL& b2) {
- int area1 = 0;
- if (!b1.icon_sizes.empty())
- area1 = b1.icon_sizes.front().GetArea();
-
- int area2 = 0;
- if (!b2.icon_sizes.empty())
- area2 = b2.icon_sizes.front().GetArea();
-
- return area1 > area2;
-}
-
-// Sorts the entries in |image_urls| by icon size in descending order.
-// Discards all but the largest size for each FaviconURL.
-void SortAndPruneImageUrls(std::vector<FaviconURL>* image_urls) {
- // Not using const-reference since the loop mutates FaviconURL::icon_sizes.
- for (FaviconURL& image_url : *image_urls) {
- if (image_url.icon_sizes.empty())
- continue;
-
- gfx::Size largest =
- image_url.icon_sizes[GetLargestSizeIndex(image_url.icon_sizes)];
- image_url.icon_sizes.clear();
- image_url.icon_sizes.push_back(largest);
+std::vector<int> GetDesiredPixelSizes(
+ FaviconDriverObserver::NotificationIconType handler_type) {
+ switch (handler_type) {
+ case FaviconDriverObserver::NON_TOUCH_16_DIP: {
+ std::vector<int> pixel_sizes;
+ for (float scale_factor : favicon_base::GetFaviconScales()) {
+ pixel_sizes.push_back(
+ static_cast<int>(ceil(scale_factor * gfx::kFaviconSize)));
+ }
+ return pixel_sizes;
+ }
+ case FaviconDriverObserver::NON_TOUCH_LARGEST:
+ return std::vector<int>(1U, kNonTouchLargestIconSize);
+ case FaviconDriverObserver::TOUCH_LARGEST:
+ return std::vector<int>(1U, kTouchIconSize);
}
- std::stable_sort(image_urls->begin(), image_urls->end(), CompareIconSize);
-}
-
-// Checks whether two FaviconURLs are equal ignoring the icon sizes.
-bool FaviconURLsEqualIgnoringSizes(const FaviconURL& u1, const FaviconURL& u2) {
- return u1.icon_type == u2.icon_type && u1.icon_url == u2.icon_url;
+ NOTREACHED();
+ return std::vector<int>();
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
-FaviconHandler::DownloadRequest::DownloadRequest()
- : icon_type(favicon_base::INVALID_ICON) {
-}
-
-FaviconHandler::DownloadRequest::~DownloadRequest() {
-}
-
-FaviconHandler::DownloadRequest::DownloadRequest(
- const GURL& image_url,
- favicon_base::IconType icon_type)
- : image_url(image_url), icon_type(icon_type) {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-FaviconHandler::FaviconCandidate::FaviconCandidate()
- : score(0), icon_type(favicon_base::INVALID_ICON) {
-}
-
-FaviconHandler::FaviconCandidate::~FaviconCandidate() {
+// static
+FaviconHandler::FaviconCandidate
+FaviconHandler::FaviconCandidate::FromFaviconURL(
+ const favicon::FaviconURL& favicon_url,
+ const std::vector<int>& desired_pixel_sizes) {
+ FaviconCandidate candidate;
+ candidate.icon_url = favicon_url.icon_url;
+ candidate.icon_type = favicon_url.icon_type;
+ // TODO(crbug.com/705900): For candidates without explicit size information,
+ // sizes could be inferred for the most common cases. Namely, .ico files tend
+ // to contain the 16x16 bitmap, which would allow to improve the
+ // prioritization on desktop.
+ SelectFaviconFrameIndices(favicon_url.icon_sizes, desired_pixel_sizes,
+ /*best_indices=*/nullptr, &candidate.score);
+ return candidate;
}
-FaviconHandler::FaviconCandidate::FaviconCandidate(
- const GURL& image_url,
- const gfx::Image& image,
- float score,
- favicon_base::IconType icon_type)
- : image_url(image_url),
- image(image),
- score(score),
- icon_type(icon_type) {}
-
////////////////////////////////////////////////////////////////////////////////
FaviconHandler::FaviconHandler(
@@ -224,8 +198,8 @@ FaviconHandler::FaviconHandler(
notification_icon_type_(favicon_base::INVALID_ICON),
service_(service),
delegate_(delegate),
- current_candidate_index_(0u),
- weak_ptr_factory_(this) {
+ num_download_requests_(0),
+ current_candidate_index_(0u) {
DCHECK(delegate_);
}
@@ -253,75 +227,54 @@ void FaviconHandler::FetchFavicon(const GURL& url) {
initial_history_result_expired_or_incomplete_ = false;
redownload_icons_ = false;
got_favicon_from_history_ = false;
- download_requests_.clear();
- image_urls_.clear();
+ download_request_.Cancel();
+ candidates_.clear();
notification_icon_url_ = GURL();
notification_icon_type_ = favicon_base::INVALID_ICON;
+ num_download_requests_ = 0;
current_candidate_index_ = 0u;
- best_favicon_candidate_ = FaviconCandidate();
+ best_favicon_ = DownloadedFavicon();
// Request the favicon from the history service. In parallel to this the
// renderer is going to notify us (well WebContents) when the favicon url is
// available.
- GetFaviconForURLFromFaviconService(
- url_, icon_types_,
+ service_->GetFaviconForPageURL(
+ url_, icon_types_, preferred_icon_size(),
base::Bind(&FaviconHandler::OnFaviconDataForInitialURLFromFaviconService,
base::Unretained(this)),
&cancelable_task_tracker_);
}
-bool FaviconHandler::UpdateFaviconCandidate(const GURL& image_url,
- const gfx::Image& image,
- float score,
- favicon_base::IconType icon_type) {
- bool replace_best_favicon_candidate = false;
- bool exact_match = false;
- if (download_largest_icon_) {
- replace_best_favicon_candidate =
- image.Size().GetArea() >
- best_favicon_candidate_.image.Size().GetArea();
-
- gfx::Size largest = best_favicon_candidate_.image.Size();
- if (replace_best_favicon_candidate)
- largest = image.Size();
+bool FaviconHandler::UpdateFaviconCandidate(
+ const DownloadedFavicon& downloaded_favicon) {
+ if (downloaded_favicon.candidate.score > best_favicon_.candidate.score)
+ best_favicon_ = downloaded_favicon;
- // The size of the downloaded icon may not match the declared size. Stop
- // downloading if:
+ if (download_largest_icon_) {
+ // The size of the downloaded icon may not match the declared size. It's
+ // important to stop downloading if:
// - current candidate is only candidate.
- // - next candidate doesn't have sizes attributes, in this case, the rest
- // candidates don't have sizes attribute either, stop downloading now,
- // otherwise, all favicon without sizes attribute are downloaded.
- // - next candidate has sizes attribute and it is not larger than largest,
- // - current candidate is maximal one we want.
- const int maximal_size = GetMaximalIconSize(icon_type);
- if (current_candidate_index_ + 1 >= image_urls_.size()) {
- exact_match = true;
- } else {
- FaviconURL next_image_url = image_urls_[current_candidate_index_ + 1];
- exact_match = next_image_url.icon_sizes.empty() ||
- next_image_url.icon_sizes[0].GetArea() <= largest.GetArea() ||
- (image.Size().width() == maximal_size &&
- image.Size().height() == maximal_size);
- }
+ // - next candidate has sizes attribute and it is not better than the best
+ // one observed so far, which means any following candidate should also
+ // be worse or equal too.
+ // - next candidate doesn't have sizes attributes, which means further
+ // candidates don't have sizes attribute either (because the score lowest
+ // and hence get sorted last during prioritization). We stop immediately
+ // to avoid downloading them all, although we don't have the certainty
+ // that no better favicon is among them.
+ return current_candidate_index_ + 1 >= candidates_.size() ||
+ candidates_[current_candidate_index_ + 1].score <=
+ best_favicon_.candidate.score;
} else {
- exact_match = score == 1 || preferred_icon_size() == 0;
- replace_best_favicon_candidate =
- exact_match ||
- best_favicon_candidate_.icon_type == favicon_base::INVALID_ICON ||
- score > best_favicon_candidate_.score;
- }
- if (replace_best_favicon_candidate) {
- best_favicon_candidate_ =
- FaviconCandidate(image_url, image, score, icon_type);
+ return best_favicon_.candidate.score == 1;
}
- return exact_match;
}
void FaviconHandler::SetFavicon(const GURL& icon_url,
const gfx::Image& image,
favicon_base::IconType icon_type) {
if (ShouldSaveFavicon())
- SetHistoryFavicons(url_, icon_url, icon_type, image);
+ service_->SetFavicons(url_, icon_url, icon_type, image);
NotifyFaviconUpdated(icon_url, icon_type, image);
}
@@ -367,27 +320,30 @@ void FaviconHandler::OnUpdateFaviconURL(
if (page_url != url_)
return;
- std::vector<FaviconURL> pruned_candidates;
+ std::vector<FaviconCandidate> sorted_candidates;
+ const std::vector<int> desired_pixel_sizes =
+ GetDesiredPixelSizes(handler_type_);
for (const FaviconURL& candidate : candidates) {
- if (!candidate.icon_url.is_empty() && (candidate.icon_type & icon_types_))
- pruned_candidates.push_back(candidate);
+ if (!candidate.icon_url.is_empty() && (candidate.icon_type & icon_types_)) {
+ sorted_candidates.push_back(
+ FaviconCandidate::FromFaviconURL(candidate, desired_pixel_sizes));
+ }
}
- if (download_largest_icon_)
- SortAndPruneImageUrls(&pruned_candidates);
+ std::stable_sort(sorted_candidates.begin(), sorted_candidates.end(),
+ &FaviconCandidate::CompareScore);
- // Ignore FaviconURL::icon_sizes because FaviconURL::icon_sizes is not stored
- // in the history database.
- if (image_urls_.size() == pruned_candidates.size() &&
- std::equal(pruned_candidates.begin(), pruned_candidates.end(),
- image_urls_.begin(), FaviconURLsEqualIgnoringSizes)) {
+ if (candidates_.size() == sorted_candidates.size() &&
+ std::equal(sorted_candidates.begin(), sorted_candidates.end(),
+ candidates_.begin())) {
return;
}
- download_requests_.clear();
- image_urls_ = pruned_candidates;
+ download_request_.Cancel();
+ candidates_ = std::move(sorted_candidates);
+ num_download_requests_ = 0;
current_candidate_index_ = 0u;
- best_favicon_candidate_ = FaviconCandidate();
+ best_favicon_ = DownloadedFavicon();
// TODO(davemoore) Should clear on empty url. Currently we ignore it.
// This appears to be what FF does as well.
@@ -395,10 +351,19 @@ void FaviconHandler::OnUpdateFaviconURL(
OnGotInitialHistoryDataAndIconURLCandidates();
}
+// static
+int FaviconHandler::GetMaximalIconSize(
+ FaviconDriverObserver::NotificationIconType handler_type) {
+ int max_size = 0;
+ for (int size : GetDesiredPixelSizes(handler_type))
+ max_size = std::max(max_size, size);
+ return max_size;
+}
+
void FaviconHandler::OnGotInitialHistoryDataAndIconURLCandidates() {
if (!initial_history_result_expired_or_incomplete_ &&
- DoUrlAndIconMatch(*current_candidate(), notification_icon_url_,
- notification_icon_type_)) {
+ current_candidate()->icon_url == notification_icon_url_ &&
+ current_candidate()->icon_type == notification_icon_type_) {
// - The data from history is valid and not expired.
// - The icon URL of the history data matches one of the page's icon URLs.
// - The icon URL of the history data matches the icon URL of the last
@@ -414,51 +379,34 @@ void FaviconHandler::OnGotInitialHistoryDataAndIconURLCandidates() {
}
void FaviconHandler::OnDidDownloadFavicon(
+ favicon_base::IconType icon_type,
int id,
int http_status_code,
const GURL& image_url,
const std::vector<SkBitmap>& bitmaps,
const std::vector<gfx::Size>& original_bitmap_sizes) {
+ // Mark download as finished.
+ download_request_.Cancel();
+
if (bitmaps.empty() && http_status_code == 404) {
DVLOG(1) << "Failed to Download Favicon:" << image_url;
- if (service_)
- service_->UnableToDownloadFavicon(image_url);
- }
-
- DownloadRequests::iterator i = download_requests_.find(id);
- if (i == download_requests_.end()) {
- // Currently WebContents notifies us of ANY downloads so that it is
- // possible to get here.
- return;
- }
-
- DownloadRequest download_request = i->second;
- download_requests_.erase(i);
-
- if (!current_candidate() ||
- !DoUrlAndIconMatch(*current_candidate(),
- image_url,
- download_request.icon_type)) {
- return;
+ RecordDownloadOutcome(DownloadOutcome::FAILED);
+ service_->UnableToDownloadFavicon(image_url);
}
bool request_next_icon = true;
if (!bitmaps.empty()) {
+ RecordDownloadOutcome(DownloadOutcome::SUCCEEDED);
float score = 0.0f;
gfx::ImageSkia image_skia;
if (download_largest_icon_) {
- int index = -1;
- // Use the largest bitmap if FaviconURL doesn't have sizes attribute.
- if (current_candidate()->icon_sizes.empty()) {
- index = GetLargestSizeIndex(original_bitmap_sizes);
- } else {
- index = GetIndexBySize(original_bitmap_sizes,
- current_candidate()->icon_sizes[0]);
- // Find largest bitmap if there is no one exactly matched.
- if (index == -1)
- index = GetLargestSizeIndex(original_bitmap_sizes);
- }
- image_skia = gfx::ImageSkia(gfx::ImageSkiaRep(bitmaps[index], 1));
+ std::vector<size_t> best_indices;
+ SelectFaviconFrameIndices(original_bitmap_sizes,
+ GetDesiredPixelSizes(handler_type_),
+ &best_indices, &score);
+ DCHECK_EQ(1U, best_indices.size());
+ image_skia =
+ gfx::ImageSkia::CreateFrom1xBitmap(bitmaps[best_indices.front()]);
} else {
image_skia = CreateFaviconImageSkia(bitmaps,
original_bitmap_sizes,
@@ -467,84 +415,48 @@ void FaviconHandler::OnDidDownloadFavicon(
}
if (!image_skia.isNull()) {
- gfx::Image image(image_skia);
// The downloaded icon is still valid when there is no FaviconURL update
// during the downloading.
- request_next_icon = !UpdateFaviconCandidate(image_url, image, score,
- download_request.icon_type);
+ DownloadedFavicon downloaded_favicon;
+ downloaded_favicon.image = gfx::Image(image_skia);
+ downloaded_favicon.candidate.icon_url = image_url;
+ downloaded_favicon.candidate.icon_type = icon_type;
+ downloaded_favicon.candidate.score = score;
+ request_next_icon = !UpdateFaviconCandidate(downloaded_favicon);
}
}
- if (request_next_icon && current_candidate_index_ + 1 < image_urls_.size()) {
+ if (request_next_icon && current_candidate_index_ + 1 < candidates_.size()) {
// Process the next candidate.
++current_candidate_index_;
DownloadCurrentCandidateOrAskFaviconService();
} else {
+ // OnDidDownloadFavicon() can only be called after requesting a download, so
+ // |num_download_requests_| can never be 0.
+ RecordDownloadAttemptsForHandlerType(handler_type_, num_download_requests_);
// We have either found the ideal candidate or run out of candidates.
- if (best_favicon_candidate_.icon_type != favicon_base::INVALID_ICON) {
+ if (best_favicon_.candidate.icon_type != favicon_base::INVALID_ICON) {
// No more icons to request, set the favicon from the candidate.
- SetFavicon(best_favicon_candidate_.image_url,
- best_favicon_candidate_.image,
- best_favicon_candidate_.icon_type);
+ SetFavicon(best_favicon_.candidate.icon_url, best_favicon_.image,
+ best_favicon_.candidate.icon_type);
}
// Clear download related state.
- download_requests_.clear();
- current_candidate_index_ = image_urls_.size();
- best_favicon_candidate_ = FaviconCandidate();
- }
-}
-
-bool FaviconHandler::HasPendingTasksForTest() {
- return !download_requests_.empty() ||
- cancelable_task_tracker_.HasTrackedTasks();
-}
-
-void FaviconHandler::UpdateFaviconMappingAndFetch(
- const GURL& page_url,
- const GURL& icon_url,
- favicon_base::IconType icon_type,
- const favicon_base::FaviconResultsCallback& callback,
- base::CancelableTaskTracker* tracker) {
- // TODO(pkotwicz): pass in all of |image_urls_| to
- // UpdateFaviconMappingsAndFetch().
- if (service_) {
- std::vector<GURL> icon_urls;
- icon_urls.push_back(icon_url);
- service_->UpdateFaviconMappingsAndFetch(page_url, icon_urls, icon_type,
- preferred_icon_size(), callback,
- tracker);
+ current_candidate_index_ = candidates_.size();
+ num_download_requests_ = 0;
+ best_favicon_ = DownloadedFavicon();
}
}
-void FaviconHandler::GetFaviconFromFaviconService(
- const GURL& icon_url,
- favicon_base::IconType icon_type,
- const favicon_base::FaviconResultsCallback& callback,
- base::CancelableTaskTracker* tracker) {
- if (service_) {
- service_->GetFavicon(icon_url, icon_type, preferred_icon_size(), callback,
- tracker);
- }
-}
-
-void FaviconHandler::GetFaviconForURLFromFaviconService(
- const GURL& page_url,
- int icon_types,
- const favicon_base::FaviconResultsCallback& callback,
- base::CancelableTaskTracker* tracker) {
- if (service_) {
- service_->GetFaviconForPageURL(page_url, icon_types, preferred_icon_size(),
- callback, tracker);
- }
+const std::vector<GURL> FaviconHandler::GetIconURLs() const {
+ std::vector<GURL> icon_urls;
+ for (const FaviconCandidate& candidate : candidates_)
+ icon_urls.push_back(candidate.icon_url);
+ return icon_urls;
}
-void FaviconHandler::SetHistoryFavicons(const GURL& page_url,
- const GURL& icon_url,
- favicon_base::IconType icon_type,
- const gfx::Image& image) {
- if (service_) {
- service_->SetFavicons(page_url, icon_url, icon_type, image);
- }
+bool FaviconHandler::HasPendingTasksForTest() {
+ return !download_request_.IsCancelled() ||
+ cancelable_task_tracker_.HasTrackedTasks();
}
bool FaviconHandler::ShouldSaveFavicon() {
@@ -555,24 +467,6 @@ bool FaviconHandler::ShouldSaveFavicon() {
return delegate_->IsBookmarked(url_);
}
-int FaviconHandler::GetMaximalIconSize(favicon_base::IconType icon_type) {
- switch (icon_type) {
- case favicon_base::FAVICON:
-#if defined(OS_ANDROID)
- return 192;
-#else
- return gfx::ImageSkia::GetMaxSupportedScale() * gfx::kFaviconSize;
-#endif
- case favicon_base::TOUCH_ICON:
- case favicon_base::TOUCH_PRECOMPOSED_ICON:
- return kTouchIconSize;
- case favicon_base::INVALID_ICON:
- return 0;
- }
- NOTREACHED();
- return 0;
-}
-
void FaviconHandler::OnFaviconDataForInitialURLFromFaviconService(
const std::vector<favicon_base::FaviconRawBitmapResult>&
favicon_bitmap_results) {
@@ -585,9 +479,10 @@ void FaviconHandler::OnFaviconDataForInitialURLFromFaviconService(
redownload_icons_ = initial_history_result_expired_or_incomplete_ &&
!favicon_bitmap_results.empty();
- if (has_valid_result &&
- (!current_candidate() ||
- DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results))) {
+ if (has_valid_result && (!current_candidate() ||
+ DoUrlsAndIconsMatch(current_candidate()->icon_url,
+ current_candidate()->icon_type,
+ favicon_bitmap_results))) {
// The db knows the favicon (although it may be out of date) and the entry
// doesn't have an icon. Set the favicon now, and if the favicon turns out
// to be expired (or the wrong url) we'll fetch later on. This way the
@@ -611,8 +506,8 @@ void FaviconHandler::DownloadCurrentCandidateOrAskFaviconService() {
// favicon for another page that shares the same favicon. Ask for the
// favicon given the favicon URL.
if (delegate_->IsOffTheRecord()) {
- GetFaviconFromFaviconService(
- icon_url, icon_type,
+ service_->GetFavicon(
+ icon_url, icon_type, preferred_icon_size(),
base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)),
&cancelable_task_tracker_);
} else {
@@ -621,8 +516,10 @@ void FaviconHandler::DownloadCurrentCandidateOrAskFaviconService() {
// 2. If the favicon exists in the database, this updates the database to
// include the mapping between the page url and the favicon url.
// This is asynchronous. The history service will call back when done.
- UpdateFaviconMappingAndFetch(
- url_, icon_url, icon_type,
+ // TODO(pkotwicz): pass in all of |image_urls_| to
+ // UpdateFaviconMappingsAndFetch().
+ service_->UpdateFaviconMappingsAndFetch(
+ url_, {icon_url}, icon_type, preferred_icon_size(),
base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)),
&cancelable_task_tracker_);
}
@@ -646,8 +543,9 @@ void FaviconHandler::OnFaviconData(const std::vector<
}
if (!current_candidate() ||
- (has_results &&
- !DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results))) {
+ (has_results && !DoUrlsAndIconsMatch(current_candidate()->icon_url,
+ current_candidate()->icon_type,
+ favicon_bitmap_results))) {
// The icon URLs have been updated since the favicon data was requested.
return;
}
@@ -655,31 +553,33 @@ void FaviconHandler::OnFaviconData(const std::vector<
if (has_expired_or_incomplete_result) {
ScheduleDownload(current_candidate()->icon_url,
current_candidate()->icon_type);
+ } else if (num_download_requests_ > 0) {
+ RecordDownloadAttemptsForHandlerType(handler_type_, num_download_requests_);
}
}
void FaviconHandler::ScheduleDownload(const GURL& image_url,
favicon_base::IconType icon_type) {
DCHECK(image_url.is_valid());
+ // Note that CancelableCallback starts cancelled.
+ DCHECK(download_request_.IsCancelled()) << "More than one ongoing download";
+ if (service_->WasUnableToDownloadFavicon(image_url)) {
+ DVLOG(1) << "Skip Failed FavIcon: " << image_url;
+ RecordDownloadOutcome(DownloadOutcome::SKIPPED);
+ OnDidDownloadFavicon(icon_type, 0, 0, image_url, std::vector<SkBitmap>(),
+ std::vector<gfx::Size>());
+ return;
+ }
+ ++num_download_requests_;
+ download_request_.Reset(base::Bind(&FaviconHandler::OnDidDownloadFavicon,
+ base::Unretained(this), icon_type));
// A max bitmap size is specified to avoid receiving huge bitmaps in
// OnDidDownloadFavicon(). See FaviconDriver::StartDownload()
// for more details about the max bitmap size.
const int download_id =
- delegate_->DownloadImage(image_url, GetMaximalIconSize(icon_type),
- base::Bind(&FaviconHandler::OnDidDownloadFavicon,
- weak_ptr_factory_.GetWeakPtr()));
-
- // Download ids should be unique.
- DCHECK(download_requests_.find(download_id) == download_requests_.end());
- download_requests_[download_id] = DownloadRequest(image_url, icon_type);
-
- if (download_id == 0) {
- // If DownloadFavicon() did not start a download, it returns a download id
- // of 0. We still need to call OnDidDownloadFavicon() because the method is
- // responsible for initiating the data request for the next candidate.
- OnDidDownloadFavicon(download_id, 0, image_url, std::vector<SkBitmap>(),
- std::vector<gfx::Size>());
- }
+ delegate_->DownloadImage(image_url, GetMaximalIconSize(handler_type_),
+ download_request_.callback());
+ DCHECK_NE(download_id, 0);
}
} // namespace favicon
diff --git a/chromium/components/favicon/core/favicon_handler.h b/chromium/components/favicon/core/favicon_handler.h
index e7a13bbb8d0..30c0b1df498 100644
--- a/chromium/components/favicon/core/favicon_handler.h
+++ b/chromium/components/favicon/core/favicon_handler.h
@@ -7,13 +7,12 @@
#include <stddef.h>
-#include <map>
#include <vector>
#include "base/callback_forward.h"
+#include "base/cancelable_callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
#include "base/task/cancelable_task_tracker.h"
#include "components/favicon/core/favicon_driver_observer.h"
#include "components/favicon/core/favicon_url.h"
@@ -27,7 +26,6 @@ class SkBitmap;
namespace favicon {
class FaviconService;
-class TestFaviconHandler;
// FaviconHandler works with FaviconDriver to fetch the specific type of
// favicon.
@@ -77,6 +75,19 @@ class TestFaviconHandler;
class FaviconHandler {
public:
+ // Outcome of a favicon download.
+ // Recorded as Favicons.DownloadOutcome and public for testing.
+ //
+ // These values must stay in sync with the FaviconDownloadStatus enum
+ // in histograms.xml and should be treated as append-only, since it backs an
+ // UMA histogram..
+ enum class DownloadOutcome {
+ SUCCEEDED = 0,
+ FAILED = 1,
+ SKIPPED = 2,
+ DOWNLOAD_OUTCOME_COUNT = 3
+ };
+
class Delegate {
public:
// Mimics WebContents::ImageDownloadCallback.
@@ -117,11 +128,11 @@ class FaviconHandler {
const gfx::Image& image) = 0;
};
- // |delegate| must not be nullptr and must outlive this class.
+ // |service| and |delegate| must not be nullptr and must outlive this class.
FaviconHandler(FaviconService* service,
Delegate* delegate,
FaviconDriverObserver::NotificationIconType handler_type);
- virtual ~FaviconHandler();
+ ~FaviconHandler();
// Initiates loading the favicon for the specified url.
void FetchFavicon(const GURL& url);
@@ -132,85 +143,50 @@ class FaviconHandler {
const std::vector<favicon::FaviconURL>& candidates);
// For testing.
- const std::vector<favicon::FaviconURL>& image_urls() const {
- return image_urls_;
- }
+ const std::vector<GURL> GetIconURLs() const;
// Returns whether the handler is waiting for a download to complete or for
// data from the FaviconService. Reserved for testing.
bool HasPendingTasksForTest();
- protected:
- // These virtual methods make FaviconHandler testable and are overridden by
- // TestFaviconHandler.
-
- // Ask the favicon from history
- virtual void UpdateFaviconMappingAndFetch(
- const GURL& page_url,
- const GURL& icon_url,
- favicon_base::IconType icon_type,
- const favicon_base::FaviconResultsCallback& callback,
- base::CancelableTaskTracker* tracker);
-
- virtual void GetFaviconFromFaviconService(
- const GURL& icon_url,
- favicon_base::IconType icon_type,
- const favicon_base::FaviconResultsCallback& callback,
- base::CancelableTaskTracker* tracker);
-
- virtual void GetFaviconForURLFromFaviconService(
- const GURL& page_url,
- int icon_types,
- const favicon_base::FaviconResultsCallback& callback,
- base::CancelableTaskTracker* tracker);
-
- virtual void SetHistoryFavicons(const GURL& page_url,
- const GURL& icon_url,
- favicon_base::IconType icon_type,
- const gfx::Image& image);
-
- // Returns true if the favicon should be saved.
- virtual bool ShouldSaveFavicon();
+ // Get the maximal icon size in pixels for a handler of type |handler_type|.
+ static int GetMaximalIconSize(
+ FaviconDriverObserver::NotificationIconType handler_type);
private:
- // For testing:
- friend class TestFaviconHandler;
-
- // Represents an in progress download of an image from the renderer.
- struct DownloadRequest {
- DownloadRequest();
- ~DownloadRequest();
-
- DownloadRequest(const GURL& image_url, favicon_base::IconType icon_type);
-
- GURL image_url;
- favicon_base::IconType icon_type;
- };
-
// Used to track a candidate for the favicon.
struct FaviconCandidate {
- FaviconCandidate();
- ~FaviconCandidate();
-
- FaviconCandidate(const GURL& image_url,
- const gfx::Image& image,
- float score,
- favicon_base::IconType icon_type);
+ // Builds a scored candidate by selecting the best bitmap sizes.
+ static FaviconCandidate FromFaviconURL(
+ const favicon::FaviconURL& favicon_url,
+ const std::vector<int>& desired_pixel_sizes);
+
+ friend bool operator==(const FaviconCandidate& lhs,
+ const FaviconCandidate& rhs) {
+ return lhs.icon_url == rhs.icon_url && lhs.icon_type == rhs.icon_type &&
+ lhs.score == rhs.score;
+ }
+
+ // Compare function used for std::stable_sort to sort in descending order.
+ static bool CompareScore(const FaviconCandidate& lhs,
+ const FaviconCandidate& rhs) {
+ return lhs.score > rhs.score;
+ }
+
+ GURL icon_url;
+ favicon_base::IconType icon_type = favicon_base::INVALID_ICON;
+ float score = 0;
+ };
- GURL image_url;
+ struct DownloadedFavicon {
+ FaviconCandidate candidate;
gfx::Image image;
- float score;
- favicon_base::IconType icon_type;
};
// Returns the bit mask of favicon_base::IconType based on the handler's type.
static int GetIconTypesFromHandlerType(
FaviconDriverObserver::NotificationIconType handler_type);
- // Get the maximal icon size in pixels for a icon of type |icon_type| for the
- // current platform.
- static int GetMaximalIconSize(favicon_base::IconType icon_type);
-
// Called when the history request for favicon data mapped to |url_| has
// completed and the renderer has told us the icon URLs used by |url_|
void OnGotInitialHistoryDataAndIconURLCandidates();
@@ -236,17 +212,18 @@ class FaviconHandler {
// Triggered when a download of an image has finished.
void OnDidDownloadFavicon(
+ favicon_base::IconType icon_type,
int id,
int http_status_code,
const GURL& image_url,
const std::vector<SkBitmap>& bitmaps,
const std::vector<gfx::Size>& original_bitmap_sizes);
- // Updates |favicon_candidate_| and returns true if it is an exact match.
- bool UpdateFaviconCandidate(const GURL& image_url,
- const gfx::Image& image,
- float score,
- favicon_base::IconType icon_type);
+ bool ShouldSaveFavicon();
+
+ // Updates |best_favicon_| and returns true if it was considered a satisfying
+ // image (e.g. exact size match).
+ bool UpdateFaviconCandidate(const DownloadedFavicon& downloaded_favicon);
// Sets the image data for the favicon.
void SetFavicon(const GURL& icon_url,
@@ -266,9 +243,9 @@ class FaviconHandler {
const gfx::Image& image);
// Return the current candidate if any.
- favicon::FaviconURL* current_candidate() {
- return current_candidate_index_ < image_urls_.size()
- ? &image_urls_[current_candidate_index_]
+ const FaviconCandidate* current_candidate() const {
+ return current_candidate_index_ < candidates_.size()
+ ? &candidates_[current_candidate_index_]
: nullptr;
}
@@ -302,8 +279,8 @@ class FaviconHandler {
bool redownload_icons_;
// Requests to the renderer to download favicons.
- typedef std::map<int, DownloadRequest> DownloadRequests;
- DownloadRequests download_requests_;
+ base::CancelableCallback<Delegate::ImageDownloadCallback::RunType>
+ download_request_;
// The combination of the supported icon types.
const int icon_types_;
@@ -312,7 +289,7 @@ class FaviconHandler {
const bool download_largest_icon_;
// The prioritized favicon candidates from the page back from the renderer.
- std::vector<favicon::FaviconURL> image_urls_;
+ std::vector<FaviconCandidate> candidates_;
// The icon URL and the icon type of the favicon in the most recent
// FaviconDriver::OnFaviconAvailable() notification.
@@ -326,17 +303,19 @@ class FaviconHandler {
// This handler's delegate.
Delegate* delegate_;
+ // Captures the number of download requests that were initiated for the
+ // current url_.
+ int num_download_requests_;
+
// The index of the favicon URL in |image_urls_| which is currently being
// requested from history or downloaded.
size_t current_candidate_index_;
// Best image we've seen so far. As images are downloaded from the page they
- // are stored here. When there is an exact match, or no more images are
- // available the favicon service and the current page are updated (assuming
- // the image is for a favicon).
- FaviconCandidate best_favicon_candidate_;
-
- base::WeakPtrFactory<FaviconHandler> weak_ptr_factory_;
+ // are stored here. When a satisfying icon is found (as defined in
+ // UpdateFaviconCandidate()), the favicon service and the delegate are
+ // notified.
+ DownloadedFavicon best_favicon_;
DISALLOW_COPY_AND_ASSIGN(FaviconHandler);
};
diff --git a/chromium/components/favicon/core/favicon_handler_unittest.cc b/chromium/components/favicon/core/favicon_handler_unittest.cc
index f4370bc599b..4a997f38247 100644
--- a/chromium/components/favicon/core/favicon_handler_unittest.cc
+++ b/chromium/components/favicon/core/favicon_handler_unittest.cc
@@ -6,12 +6,20 @@
#include <stddef.h>
+#include <map>
#include <memory>
#include <set>
#include <vector>
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/histogram_tester.h"
#include "components/favicon/core/favicon_driver.h"
+#include "components/favicon/core/test/mock_favicon_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/layout.h"
@@ -22,1201 +30,826 @@
namespace favicon {
namespace {
-// Fill the given bmp with valid png data.
-void FillDataToBitmap(int w, int h, SkBitmap* bmp) {
- bmp->allocN32Pixels(w, h);
+using favicon_base::FAVICON;
+using favicon_base::FaviconRawBitmapResult;
+using favicon_base::TOUCH_ICON;
+using favicon_base::TOUCH_PRECOMPOSED_ICON;
+using testing::Assign;
+using testing::ElementsAre;
+using testing::InSequence;
+using testing::Invoke;
+using testing::IsEmpty;
+using testing::Return;
+using testing::_;
+
+using DownloadOutcome = FaviconHandler::DownloadOutcome;
+using IntVector = std::vector<int>;
+using URLVector = std::vector<GURL>;
+using BitmapVector = std::vector<SkBitmap>;
+using SizeVector = std::vector<gfx::Size>;
+
+MATCHER_P2(ImageSizeIs, width, height, "") {
+ *result_listener << "where size is " << arg.Width() << "x" << arg.Height();
+ return arg.Size() == gfx::Size(width, height);
+}
+
+// Fill the given bmp with some test data.
+SkBitmap CreateBitmapWithEdgeSize(int size) {
+ SkBitmap bmp;
+ bmp.allocN32Pixels(size, size);
unsigned char* src_data =
- reinterpret_cast<unsigned char*>(bmp->getAddr32(0, 0));
- for (int i = 0; i < w * h; i++) {
+ reinterpret_cast<unsigned char*>(bmp.getAddr32(0, 0));
+ for (int i = 0; i < size * size; i++) {
src_data[i * 4 + 0] = static_cast<unsigned char>(i % 255);
src_data[i * 4 + 1] = static_cast<unsigned char>(i % 255);
src_data[i * 4 + 2] = static_cast<unsigned char>(i % 255);
src_data[i * 4 + 3] = static_cast<unsigned char>(i % 255);
}
+ return bmp;
}
// Fill the given data buffer with valid png data.
-void FillBitmap(int w, int h, std::vector<unsigned char>* output) {
- SkBitmap bitmap;
- FillDataToBitmap(w, h, &bitmap);
- gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, output);
+std::vector<unsigned char> FillBitmapWithEdgeSize(int size) {
+ SkBitmap bitmap = CreateBitmapWithEdgeSize(size);
+ std::vector<unsigned char> output;
+ gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &output);
+ return output;
}
-void SetFaviconRawBitmapResult(
+std::vector<FaviconRawBitmapResult> CreateRawBitmapResult(
const GURL& icon_url,
- favicon_base::IconType icon_type,
- bool expired,
- std::vector<favicon_base::FaviconRawBitmapResult>* favicon_bitmap_results) {
+ favicon_base::IconType icon_type = FAVICON,
+ bool expired = false,
+ int edge_size = gfx::kFaviconSize) {
scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes());
- FillBitmap(gfx::kFaviconSize, gfx::kFaviconSize, &data->data());
- favicon_base::FaviconRawBitmapResult bitmap_result;
+ data->data() = FillBitmapWithEdgeSize(edge_size);
+ FaviconRawBitmapResult bitmap_result;
bitmap_result.expired = expired;
bitmap_result.bitmap_data = data;
// Use a pixel size other than (0,0) as (0,0) has a special meaning.
- bitmap_result.pixel_size = gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize);
+ bitmap_result.pixel_size = gfx::Size(edge_size, edge_size);
bitmap_result.icon_type = icon_type;
bitmap_result.icon_url = icon_url;
-
- favicon_bitmap_results->push_back(bitmap_result);
+ return {bitmap_result};
}
-void SetFaviconRawBitmapResult(
- const GURL& icon_url,
- std::vector<favicon_base::FaviconRawBitmapResult>* favicon_bitmap_results) {
- SetFaviconRawBitmapResult(icon_url,
- favicon_base::FAVICON,
- false /* expired */,
- favicon_bitmap_results);
-}
-
-// This class is used to save the download request for verifying with test case.
-class DownloadHandler {
+// Fake that implements the calls to FaviconHandler::Delegate's DownloadImage(),
+// delegated to this class through MockDelegate.
+class FakeImageDownloader {
public:
- DownloadHandler() : callback_invoked_(false) {}
- ~DownloadHandler() {}
-
- void Reset() {
- download_.reset();
- callback_invoked_ = false;
- // Does not affect |should_fail_download_icon_urls_| and
- // |failed_download_icon_urls_|.
+ struct Response {
+ int http_status_code = 404;
+ BitmapVector bitmaps;
+ SizeVector original_bitmap_sizes;
+ };
+
+ FakeImageDownloader() : next_download_id_(1) {}
+
+ // Implementation of FaviconHalder::Delegate's DownloadImage(). If a given
+ // URL is not known (i.e. not previously added via Add()), it produces 404s.
+ int DownloadImage(const GURL& url,
+ int max_image_size,
+ FaviconHandler::Delegate::ImageDownloadCallback callback) {
+ downloads_.push_back(url);
+
+ const Response& response = responses_[url];
+ int download_id = next_download_id_++;
+ base::Closure bound_callback =
+ base::Bind(callback, download_id, response.http_status_code, url,
+ response.bitmaps, response.original_bitmap_sizes);
+ if (url == manual_callback_url_)
+ manual_callback_ = bound_callback;
+ else
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, bound_callback);
+ return download_id;
}
- // Make downloads for any of |icon_urls| fail.
- void FailDownloadForIconURLs(const std::set<GURL>& icon_urls) {
- should_fail_download_icon_urls_ = icon_urls;
+ void Add(const GURL& icon_url, const IntVector& sizes) {
+ AddWithOriginalSizes(icon_url, sizes, sizes);
}
- // Returns whether a download for |icon_url| did fail.
- bool DidFailDownloadForIconURL(const GURL& icon_url) const {
- return failed_download_icon_urls_.count(icon_url);
+ void AddWithOriginalSizes(const GURL& icon_url,
+ const IntVector& sizes,
+ const IntVector& original_sizes) {
+ DCHECK_EQ(sizes.size(), original_sizes.size());
+ Response response;
+ response.http_status_code = 200;
+ for (int size : sizes) {
+ response.original_bitmap_sizes.push_back(gfx::Size(size, size));
+ response.bitmaps.push_back(CreateBitmapWithEdgeSize(size));
+ }
+ responses_[icon_url] = response;
}
- void AddDownload(int download_id,
- const GURL& image_url,
- const std::vector<int>& image_sizes,
- int max_image_size,
- FaviconHandler::Delegate::ImageDownloadCallback callback) {
- download_.reset(new Download(download_id, image_url, image_sizes,
- max_image_size, callback));
+ void AddError(const GURL& icon_url, int http_status_code) {
+ Response response;
+ response.http_status_code = http_status_code;
+ responses_[icon_url] = response;
+ }
+
+ // Disables automatic callback for |url|. This is useful for emulating a
+ // download taking a long time. The callback for DownloadImage() will be
+ // stored in |manual_callback_|.
+ void SetRunCallbackManuallyForUrl(const GURL& url) {
+ manual_callback_url_ = url;
+ }
+
+ // Returns whether an ongoing download exists for a url previously selected
+ // via SetRunCallbackManuallyForUrl().
+ bool HasPendingManualCallback() { return !manual_callback_.is_null(); }
+
+ // Triggers the response for a download previously selected for manual
+ // triggering via SetRunCallbackManuallyForUrl().
+ bool RunCallbackManually() {
+ if (!HasPendingManualCallback())
+ return false;
+ manual_callback_.Run();
+ manual_callback_.Reset();
+ return true;
}
- void InvokeCallback();
+ // Returns pending and completed download URLs.
+ const URLVector& downloads() const { return downloads_; }
- bool HasDownload() const { return download_.get(); }
- const GURL& GetImageUrl() const { return download_->image_url; }
- void SetImageSizes(const std::vector<int>& sizes) {
- download_->image_sizes = sizes; }
+ void ClearDownloads() { downloads_.clear(); }
private:
- struct Download {
- Download(int id,
- GURL url,
- const std::vector<int>& sizes,
- int max_size,
- FaviconHandler::Delegate::ImageDownloadCallback callback)
- : download_id(id),
- image_url(url),
- image_sizes(sizes),
- max_image_size(max_size),
- callback(callback) {}
- ~Download() {}
- int download_id;
- GURL image_url;
- std::vector<int> image_sizes;
- int max_image_size;
- FaviconHandler::Delegate::ImageDownloadCallback callback;
- };
+ int next_download_id_;
+
+ // Pending and completed download URLs.
+ URLVector downloads_;
- std::unique_ptr<Download> download_;
- bool callback_invoked_;
+ // URL to disable automatic callbacks for.
+ GURL manual_callback_url_;
- // The icon URLs for which the download should fail.
- std::set<GURL> should_fail_download_icon_urls_;
+ // Callback for DownloadImage() request for |manual_callback_url_|.
+ base::Closure manual_callback_;
- // The icon URLs for which the download did fail. This should be a subset of
- // |should_fail_download_icon_urls_|.
- std::set<GURL> failed_download_icon_urls_;
+ // Registered responses.
+ std::map<GURL, Response> responses_;
- DISALLOW_COPY_AND_ASSIGN(DownloadHandler);
+ DISALLOW_COPY_AND_ASSIGN(FakeImageDownloader);
};
-// This class is used to save the history request for verifying with test case.
-// It also will be used to simulate the history response.
-class HistoryRequestHandler {
+class MockDelegate : public FaviconHandler::Delegate {
public:
- HistoryRequestHandler(const GURL& page_url,
- const GURL& icon_url,
- int icon_type,
- const favicon_base::FaviconResultsCallback& callback)
- : page_url_(page_url),
- icon_url_(icon_url),
- icon_type_(icon_type),
- callback_(callback) {
- }
-
- HistoryRequestHandler(const GURL& page_url,
- const GURL& icon_url,
- int icon_type,
- const std::vector<unsigned char>& bitmap_data,
- const gfx::Size& size)
- : page_url_(page_url),
- icon_url_(icon_url),
- icon_type_(icon_type),
- bitmap_data_(bitmap_data),
- size_(size) {
+ MockDelegate() {
+ // Delegate image downloading to FakeImageDownloader.
+ ON_CALL(*this, DownloadImage(_, _, _))
+ .WillByDefault(
+ Invoke(&fake_downloader_, &FakeImageDownloader::DownloadImage));
}
- ~HistoryRequestHandler() {}
- void InvokeCallback();
-
- const GURL page_url_;
- const GURL icon_url_;
- const int icon_type_;
- const std::vector<unsigned char> bitmap_data_;
- const gfx::Size size_;
- std::vector<favicon_base::FaviconRawBitmapResult> history_results_;
- favicon_base::FaviconResultsCallback callback_;
+ MOCK_METHOD3(DownloadImage,
+ int(const GURL& url,
+ int max_image_size,
+ ImageDownloadCallback callback));
+ MOCK_METHOD0(IsOffTheRecord, bool());
+ MOCK_METHOD1(IsBookmarked, bool(const GURL& url));
+ MOCK_METHOD5(OnFaviconUpdated,
+ void(const GURL& page_url,
+ FaviconDriverObserver::NotificationIconType type,
+ const GURL& icon_url,
+ bool icon_url_changed,
+ const gfx::Image& image));
+
+ FakeImageDownloader& fake_downloader() { return fake_downloader_; }
+
+ // Convenience getter for test readability. Returns pending and completed
+ // download URLs.
+ const URLVector& downloads() const { return fake_downloader_.downloads(); }
private:
- DISALLOW_COPY_AND_ASSIGN(HistoryRequestHandler);
+ FakeImageDownloader fake_downloader_;
};
-class TestDelegate : public FaviconHandler::Delegate {
+// FakeFaviconService mimics a FaviconService backend that allows setting up
+// test data stored via Store(). If Store() has not been called for a
+// particular URL, the callback is called with empty database results.
+class FakeFaviconService {
public:
- TestDelegate() : num_notifications_(0), download_id_(0) {}
-
- int DownloadImage(const GURL& image_url,
- int max_bitmap_size,
- ImageDownloadCallback callback) override {
- // Do not do a download if downloading |image_url| failed previously. This
- // emulates the behavior of FaviconDriver::DownloadImage()
- if (download_handler_.DidFailDownloadForIconURL(image_url)) {
- download_handler_.AddDownload(download_id_, image_url, std::vector<int>(),
- 0, callback);
- return 0;
- }
-
- download_id_++;
- std::vector<int> sizes;
- sizes.push_back(0);
- download_handler_.AddDownload(download_id_, image_url, sizes,
- max_bitmap_size, callback);
- return download_id_;
+ FakeFaviconService() = default;
+
+ // Stores favicon with bitmap data in |results| at |page_url| and |icon_url|.
+ void Store(const GURL& page_url,
+ const GURL& icon_url,
+ const std::vector<favicon_base::FaviconRawBitmapResult>& result) {
+ results_[icon_url] = result;
+ results_[page_url] = result;
}
- bool IsOffTheRecord() override { return false; }
+ // Returns pending and completed database request URLs.
+ const URLVector& db_requests() const { return db_requests_; }
- bool IsBookmarked(const GURL& url) override { return false; }
+ void ClearDbRequests() { db_requests_.clear(); }
- void OnFaviconUpdated(
- const GURL& page_url,
- FaviconDriverObserver::NotificationIconType notification_icon_type,
+ base::CancelableTaskTracker::TaskId GetFavicon(
const GURL& icon_url,
- bool icon_url_changed,
- const gfx::Image& image) override {
- ++num_notifications_;
- icon_url_ = icon_url;
- image_ = image;
+ favicon_base::IconType icon_type,
+ int desired_size_in_dip,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ return GetFaviconForPageOrIconURL(icon_url, callback, tracker);
}
- DownloadHandler* download_handler() { return &download_handler_; }
- const GURL& icon_url() const { return icon_url_; }
- const gfx::Image& image() const { return image_; }
- size_t num_notifications() const { return num_notifications_; }
- void ResetNumNotifications() { num_notifications_ = 0; }
+ base::CancelableTaskTracker::TaskId GetFaviconForPageURL(
+ const GURL& page_url,
+ int icon_types,
+ int desired_size_in_dip,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ return GetFaviconForPageOrIconURL(page_url, callback, tracker);
+ }
+
+ base::CancelableTaskTracker::TaskId UpdateFaviconMappingsAndFetch(
+ const GURL& page_url,
+ const std::vector<GURL>& icon_urls,
+ int icon_types,
+ int desired_size_in_dip,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ CHECK_EQ(1U, icon_urls.size()) << "Multi-icon lookup not implemented";
+ return GetFaviconForPageOrIconURL(icon_urls.front(), callback, tracker);
+ }
private:
- GURL icon_url_;
- gfx::Image image_;
- size_t num_notifications_;
+ base::CancelableTaskTracker::TaskId GetFaviconForPageOrIconURL(
+ const GURL& page_or_icon_url,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ db_requests_.push_back(page_or_icon_url);
- // The unique id of a download request. It will be returned to a
- // FaviconHandler.
- int download_id_;
+ return tracker->PostTask(base::ThreadTaskRunnerHandle::Get().get(),
+ FROM_HERE,
+ base::Bind(callback, results_[page_or_icon_url]));
+ }
- DownloadHandler download_handler_;
+ std::map<GURL, std::vector<favicon_base::FaviconRawBitmapResult>> results_;
+ URLVector db_requests_;
- DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+ DISALLOW_COPY_AND_ASSIGN(FakeFaviconService);
};
-} // namespace
-
-// This class is used to catch the FaviconHandler's download and history
-// request, and also provide the methods to access the FaviconHandler
-// internals.
-class TestFaviconHandler : public FaviconHandler {
+// MockFaviconService subclass that delegates DB reads to FakeFaviconService.
+class MockFaviconServiceWithFake : public MockFaviconService {
public:
- static int GetMaximalIconSize(favicon_base::IconType icon_type) {
- return FaviconHandler::GetMaximalIconSize(icon_type);
+ MockFaviconServiceWithFake() {
+ // Delegate the various methods that read from the DB.
+ ON_CALL(*this, GetFavicon(_, _, _, _, _))
+ .WillByDefault(Invoke(&fake_, &FakeFaviconService::GetFavicon));
+ ON_CALL(*this, GetFaviconForPageURL(_, _, _, _, _))
+ .WillByDefault(
+ Invoke(&fake_, &FakeFaviconService::GetFaviconForPageURL));
+ ON_CALL(*this, UpdateFaviconMappingsAndFetch(_, _, _, _, _, _))
+ .WillByDefault(
+ Invoke(&fake_, &FakeFaviconService::UpdateFaviconMappingsAndFetch));
}
- TestFaviconHandler(FaviconHandler::Delegate* delegate,
- FaviconDriverObserver::NotificationIconType handler_type)
- : FaviconHandler(nullptr, delegate, handler_type) {}
-
- ~TestFaviconHandler() override {}
+ FakeFaviconService* fake() { return &fake_; }
- HistoryRequestHandler* history_handler() {
- return history_handler_.get();
- }
+ private:
+ FakeFaviconService fake_;
- // This method will take the ownership of the given handler.
- void set_history_handler(HistoryRequestHandler* handler) {
- history_handler_.reset(handler);
- }
+ DISALLOW_COPY_AND_ASSIGN(MockFaviconServiceWithFake);
+};
- FaviconURL* current_candidate() {
- return FaviconHandler::current_candidate();
- }
+class FaviconHandlerTest : public testing::Test {
+ protected:
+ const std::vector<gfx::Size> kEmptySizes;
- size_t current_candidate_index() const {
- return current_candidate_index_;
- }
+ // Some known icons for which download will succeed.
+ const GURL kPageURL = GURL("http://www.google.com");
+ const GURL kIconURL10x10 = GURL("http://www.google.com/favicon10x10");
+ const GURL kIconURL12x12 = GURL("http://www.google.com/favicon12x12");
+ const GURL kIconURL16x16 = GURL("http://www.google.com/favicon16x16");
+ const GURL kIconURL64x64 = GURL("http://www.google.com/favicon64x64");
- const FaviconCandidate& best_favicon_candidate() {
- return best_favicon_candidate_;
- }
+ FaviconHandlerTest() {
+ // Register various known icon URLs.
+ delegate_.fake_downloader().Add(kIconURL10x10, IntVector{10});
+ delegate_.fake_downloader().Add(kIconURL12x12, IntVector{12});
+ delegate_.fake_downloader().Add(kIconURL16x16, IntVector{16});
+ delegate_.fake_downloader().Add(kIconURL64x64, IntVector{64});
- protected:
- void UpdateFaviconMappingAndFetch(
- const GURL& page_url,
- const GURL& icon_url,
- favicon_base::IconType icon_type,
- const favicon_base::FaviconResultsCallback& callback,
- base::CancelableTaskTracker* tracker) override {
- history_handler_.reset(new HistoryRequestHandler(page_url, icon_url,
- icon_type, callback));
+ // The score computed by SelectFaviconFrames() is dependent on the supported
+ // scale factors of the platform. It is used for determining the goodness of
+ // a downloaded bitmap in FaviconHandler::OnDidDownloadFavicon().
+ // Force the values of the scale factors so that the tests produce the same
+ // results on all platforms.
+ scoped_set_supported_scale_factors_.reset(
+ new ui::test::ScopedSetSupportedScaleFactors({ui::SCALE_FACTOR_100P}));
}
- void GetFaviconFromFaviconService(
- const GURL& icon_url,
- favicon_base::IconType icon_type,
- const favicon_base::FaviconResultsCallback& callback,
- base::CancelableTaskTracker* tracker) override {
- history_handler_.reset(new HistoryRequestHandler(GURL(), icon_url,
- icon_type, callback));
+ bool VerifyAndClearExpectations() {
+ base::RunLoop().RunUntilIdle();
+ favicon_service_.fake()->ClearDbRequests();
+ delegate_.fake_downloader().ClearDownloads();
+ return testing::Mock::VerifyAndClearExpectations(&favicon_service_) &&
+ testing::Mock::VerifyAndClearExpectations(&delegate_);
}
- void GetFaviconForURLFromFaviconService(
- const GURL& page_url,
- int icon_types,
- const favicon_base::FaviconResultsCallback& callback,
- base::CancelableTaskTracker* tracker) override {
- history_handler_.reset(new HistoryRequestHandler(page_url, GURL(),
- icon_types, callback));
+ // Creates a new handler and feeds in the page URL and the candidates.
+ // Returns the handler in case tests want to exercise further steps.
+ std::unique_ptr<FaviconHandler> RunHandlerWithCandidates(
+ FaviconDriverObserver::NotificationIconType handler_type,
+ const std::vector<favicon::FaviconURL>& candidates) {
+ auto handler = base::MakeUnique<FaviconHandler>(&favicon_service_,
+ &delegate_, handler_type);
+ handler->FetchFavicon(kPageURL);
+ // The first RunUntilIdle() causes the FaviconService lookups be faster than
+ // OnUpdateFaviconURL(), which is the most likely scenario.
+ base::RunLoop().RunUntilIdle();
+ handler->OnUpdateFaviconURL(kPageURL, candidates);
+ base::RunLoop().RunUntilIdle();
+ return handler;
}
- void SetHistoryFavicons(const GURL& page_url,
- const GURL& icon_url,
- favicon_base::IconType icon_type,
- const gfx::Image& image) override {
- scoped_refptr<base::RefCountedMemory> bytes = image.As1xPNGBytes();
- std::vector<unsigned char> bitmap_data(bytes->front(),
- bytes->front() + bytes->size());
- history_handler_.reset(new HistoryRequestHandler(
- page_url, icon_url, icon_type, bitmap_data, image.Size()));
+ // Same as above, but for the simplest case where all types are FAVICON and
+ // no sizes are provided, using a FaviconHandler of type NON_TOUCH_16_DIP.
+ std::unique_ptr<FaviconHandler> RunHandlerWithSimpleFaviconCandidates(
+ const std::vector<GURL>& urls) {
+ std::vector<favicon::FaviconURL> candidates;
+ for (const GURL& url : urls) {
+ candidates.emplace_back(url, FAVICON, kEmptySizes);
+ }
+ return RunHandlerWithCandidates(FaviconDriverObserver::NON_TOUCH_16_DIP,
+ candidates);
}
- bool ShouldSaveFavicon() override { return true; }
-
- GURL page_url_;
-
- private:
- std::unique_ptr<HistoryRequestHandler> history_handler_;
-
- DISALLOW_COPY_AND_ASSIGN(TestFaviconHandler);
+ base::MessageLoopForUI message_loop_;
+ std::unique_ptr<ui::test::ScopedSetSupportedScaleFactors>
+ scoped_set_supported_scale_factors_;
+ testing::NiceMock<MockFaviconServiceWithFake> favicon_service_;
+ testing::NiceMock<MockDelegate> delegate_;
};
-namespace {
+TEST_F(FaviconHandlerTest, GetFaviconFromHistory) {
+ base::HistogramTester histogram_tester;
+ const GURL kIconURL("http://www.google.com/favicon");
+
+ favicon_service_.fake()->Store(kPageURL, kIconURL,
+ CreateRawBitmapResult(kIconURL));
+
+ EXPECT_CALL(delegate_, OnFaviconUpdated(
+ kPageURL, FaviconDriverObserver::NON_TOUCH_16_DIP,
+ kIconURL, /*icon_url_changed=*/true, _));
+
+ RunHandlerWithSimpleFaviconCandidates({kIconURL});
+ EXPECT_THAT(delegate_.downloads(), IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.LargeIcons"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.Favicons"),
+ IsEmpty());
+}
-void HistoryRequestHandler::InvokeCallback() {
- if (!callback_.is_null()) {
- callback_.Run(history_results_);
- }
+// Test that UpdateFaviconsAndFetch() is called with the appropriate parameters
+// when there is data in the database for neither the page URL nor the icon URL.
+TEST_F(FaviconHandlerTest, UpdateFaviconMappingsAndFetch) {
+ EXPECT_CALL(favicon_service_, UpdateFaviconMappingsAndFetch(
+ kPageURL, URLVector{kIconURL16x16}, FAVICON,
+ /*desired_size_in_dip=*/16, _, _));
+
+ RunHandlerWithSimpleFaviconCandidates({kIconURL16x16});
}
-void DownloadHandler::InvokeCallback() {
- if (callback_invoked_)
- return;
-
- std::vector<gfx::Size> original_bitmap_sizes;
- std::vector<SkBitmap> bitmaps;
- if (should_fail_download_icon_urls_.count(download_->image_url)) {
- failed_download_icon_urls_.insert(download_->image_url);
- } else {
- for (std::vector<int>::const_iterator i = download_->image_sizes.begin();
- i != download_->image_sizes.end(); ++i) {
- int original_size = (*i > 0) ? *i : gfx::kFaviconSize;
- int downloaded_size = original_size;
- if (download_->max_image_size != 0 &&
- downloaded_size > download_->max_image_size) {
- downloaded_size = download_->max_image_size;
- }
- SkBitmap bitmap;
- FillDataToBitmap(downloaded_size, downloaded_size, &bitmap);
- bitmaps.push_back(bitmap);
- original_bitmap_sizes.push_back(gfx::Size(original_size, original_size));
- }
- }
- download_->callback.Run(download_->download_id,
- /*=status_code=*/200, download_->image_url, bitmaps,
- original_bitmap_sizes);
- callback_invoked_ = true;
+// Test that the FaviconHandler process finishes when:
+// - There is data in the database for neither the page URL nor the icon URL.
+// AND
+// - FaviconService::GetFaviconForPageURL() callback returns before
+// FaviconHandler::OnUpdateFaviconURL() is called.
+TEST_F(FaviconHandlerTest, DownloadUnknownFaviconIfCandidatesSlower) {
+ EXPECT_CALL(favicon_service_, SetFavicons(kPageURL, kIconURL16x16, FAVICON,
+ ImageSizeIs(16, 16)));
+ EXPECT_CALL(delegate_, OnFaviconUpdated(
+ kPageURL, FaviconDriverObserver::NON_TOUCH_16_DIP,
+ kIconURL16x16, /*icon_url_changed=*/true, _));
+
+ FaviconHandler handler(&favicon_service_, &delegate_,
+ FaviconDriverObserver::NON_TOUCH_16_DIP);
+ handler.FetchFavicon(kPageURL);
+ // Causes FaviconService lookups be faster than OnUpdateFaviconURL().
+ base::RunLoop().RunUntilIdle();
+ handler.OnUpdateFaviconURL(kPageURL,
+ {FaviconURL(kIconURL16x16, FAVICON, kEmptySizes)});
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(kIconURL16x16));
+ EXPECT_THAT(favicon_service_.fake()->db_requests(),
+ ElementsAre(kPageURL, kIconURL16x16));
}
-class FaviconHandlerTest : public testing::Test {
- protected:
- FaviconHandlerTest() {
- }
+// Test that the FaviconHandler process finishes when:
+// - There is data in the database for neither the page URL nor the icon URL.
+// AND
+// - FaviconService::GetFaviconForPageURL() callback returns after
+// FaviconHandler::OnUpdateFaviconURL() is called.
+TEST_F(FaviconHandlerTest, DownloadUnknownFaviconIfCandidatesFaster) {
+ EXPECT_CALL(favicon_service_, SetFavicons(kPageURL, kIconURL16x16, FAVICON,
+ ImageSizeIs(16, 16)));
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, kIconURL16x16, _, _));
+
+ FaviconHandler handler(&favicon_service_, &delegate_,
+ FaviconDriverObserver::NON_TOUCH_16_DIP);
+ handler.FetchFavicon(kPageURL);
+ ASSERT_THAT(favicon_service_.fake()->db_requests(), ElementsAre(kPageURL));
+
+ // Feed in favicons without processing posted tasks (RunUntilIdle()).
+ handler.OnUpdateFaviconURL(kPageURL,
+ {FaviconURL(kIconURL16x16, FAVICON, kEmptySizes)});
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(kIconURL16x16));
+}
- ~FaviconHandlerTest() override {}
+// Test that the FaviconHandler process does not save anything to the database
+// for incognito tabs.
+TEST_F(FaviconHandlerTest, DownloadUnknownFaviconInIncognito) {
+ ON_CALL(delegate_, IsOffTheRecord()).WillByDefault(Return(true));
- // Simulates requesting a favicon for |page_url| given:
- // - We have not previously cached anything in history for |page_url| or for
- // any of |candidates|.
- // - The page provides favicons at |candidate_icons|.
- // - The favicons at |candidate_icons| have edge pixel sizes of
- // |candidate_icon_sizes|.
- void DownloadTillDoneIgnoringHistory(
- TestDelegate* delegate,
- TestFaviconHandler* favicon_handler,
- const GURL& page_url,
- const std::vector<FaviconURL>& candidate_icons,
- const int* candidate_icon_sizes) {
- size_t old_num_notifications = delegate->num_notifications();
-
- UpdateFaviconURL(delegate, favicon_handler, page_url, candidate_icons);
- EXPECT_EQ(candidate_icons.size(), favicon_handler->image_urls().size());
-
- DownloadHandler* download_handler = delegate->download_handler();
- for (size_t i = 0; i < candidate_icons.size(); ++i) {
- favicon_handler->history_handler()->history_results_.clear();
- favicon_handler->history_handler()->InvokeCallback();
- ASSERT_TRUE(download_handler->HasDownload());
- EXPECT_EQ(download_handler->GetImageUrl(),
- candidate_icons[i].icon_url);
- std::vector<int> sizes;
- sizes.push_back(candidate_icon_sizes[i]);
- download_handler->SetImageSizes(sizes);
- download_handler->InvokeCallback();
-
- download_handler->Reset();
-
- if (delegate->num_notifications() > old_num_notifications)
- return;
- }
- }
+ // No writes expected.
+ EXPECT_CALL(favicon_service_, UpdateFaviconMappingsAndFetch(_, _, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(favicon_service_, SetFavicons(_, _, _, _)).Times(0);
- void UpdateFaviconURL(TestDelegate* delegate,
- TestFaviconHandler* favicon_handler,
- const GURL& page_url,
- const std::vector<FaviconURL>& candidate_icons) {
- delegate->ResetNumNotifications();
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, kIconURL16x16, _, _));
- favicon_handler->FetchFavicon(page_url);
- favicon_handler->history_handler()->InvokeCallback();
+ RunHandlerWithSimpleFaviconCandidates({kIconURL16x16});
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(kIconURL16x16));
+ EXPECT_THAT(favicon_service_.fake()->db_requests(),
+ ElementsAre(kPageURL, kIconURL16x16));
+}
- favicon_handler->OnUpdateFaviconURL(page_url, candidate_icons);
- }
+// Test that the FaviconHandler saves a favicon if the page is bookmarked, even
+// in incognito.
+TEST_F(FaviconHandlerTest, DownloadBookmarkedFaviconInIncognito) {
+ ON_CALL(delegate_, IsOffTheRecord()).WillByDefault(Return(true));
+ ON_CALL(delegate_, IsBookmarked(kPageURL)).WillByDefault(Return(true));
- void SetUp() override {
- // The score computed by SelectFaviconFrames() is dependent on the supported
- // scale factors of the platform. It is used for determining the goodness of
- // a downloaded bitmap in FaviconHandler::OnDidDownloadFavicon().
- // Force the values of the scale factors so that the tests produce the same
- // results on all platforms.
- std::vector<ui::ScaleFactor> scale_factors;
- scale_factors.push_back(ui::SCALE_FACTOR_100P);
- scoped_set_supported_scale_factors_.reset(
- new ui::test::ScopedSetSupportedScaleFactors(scale_factors));
- testing::Test::SetUp();
- }
+ EXPECT_CALL(favicon_service_, UpdateFaviconMappingsAndFetch(_, _, _, _, _, _))
+ .Times(0);
- std::unique_ptr<ui::test::ScopedSetSupportedScaleFactors>
- scoped_set_supported_scale_factors_;
-};
+ EXPECT_CALL(favicon_service_, SetFavicons(_, kIconURL16x16, _, _));
-TEST_F(FaviconHandlerTest, GetFaviconFromHistory) {
- const GURL page_url("http://www.google.com");
- const GURL icon_url("http://www.google.com/favicon");
-
- TestDelegate delegate;
- TestFaviconHandler helper(&delegate, FaviconDriverObserver::NON_TOUCH_16_DIP);
-
- helper.FetchFavicon(page_url);
- HistoryRequestHandler* history_handler = helper.history_handler();
- // Ensure the data given to history is correct.
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(page_url, history_handler->page_url_);
- EXPECT_EQ(GURL(), history_handler->icon_url_);
- EXPECT_EQ(favicon_base::FAVICON, history_handler->icon_type_);
-
- SetFaviconRawBitmapResult(icon_url, &history_handler->history_results_);
-
- // Send history response.
- history_handler->InvokeCallback();
- // Verify FaviconHandler status
- EXPECT_EQ(1u, delegate.num_notifications());
- EXPECT_EQ(icon_url, delegate.icon_url());
-
- // Simulates update favicon url.
- std::vector<FaviconURL> urls;
- urls.push_back(
- FaviconURL(icon_url, favicon_base::FAVICON, std::vector<gfx::Size>()));
- helper.OnUpdateFaviconURL(page_url, urls);
-
- // Verify FaviconHandler status
- EXPECT_EQ(1u, helper.image_urls().size());
- ASSERT_TRUE(helper.current_candidate());
- ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
- ASSERT_EQ(favicon_base::FAVICON, helper.current_candidate()->icon_type);
-
- // Favicon shouldn't request to download icon.
- EXPECT_FALSE(delegate.download_handler()->HasDownload());
+ RunHandlerWithSimpleFaviconCandidates({kIconURL16x16});
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(kIconURL16x16));
}
-TEST_F(FaviconHandlerTest, DownloadFavicon) {
- const GURL page_url("http://www.google.com");
- const GURL icon_url("http://www.google.com/favicon");
-
- TestDelegate delegate;
- TestFaviconHandler helper(&delegate, FaviconDriverObserver::NON_TOUCH_16_DIP);
-
- helper.FetchFavicon(page_url);
- HistoryRequestHandler* history_handler = helper.history_handler();
- // Ensure the data given to history is correct.
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(page_url, history_handler->page_url_);
- EXPECT_EQ(GURL(), history_handler->icon_url_);
- EXPECT_EQ(favicon_base::FAVICON, history_handler->icon_type_);
-
- // Set icon data expired
- SetFaviconRawBitmapResult(icon_url,
- favicon_base::FAVICON,
- true /* expired */,
- &history_handler->history_results_);
- // Send history response.
- history_handler->InvokeCallback();
- // Verify FaviconHandler status
- EXPECT_EQ(1u, delegate.num_notifications());
- EXPECT_EQ(icon_url, delegate.icon_url());
-
- // Simulates update favicon url.
- std::vector<FaviconURL> urls;
- urls.push_back(
- FaviconURL(icon_url, favicon_base::FAVICON, std::vector<gfx::Size>()));
- helper.OnUpdateFaviconURL(page_url, urls);
-
- // Verify FaviconHandler status
- EXPECT_EQ(1u, helper.image_urls().size());
- ASSERT_TRUE(helper.current_candidate());
- ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
- ASSERT_EQ(favicon_base::FAVICON, helper.current_candidate()->icon_type);
-
- // Favicon should request to download icon now.
- DownloadHandler* download_handler = delegate.download_handler();
- EXPECT_TRUE(download_handler->HasDownload());
-
- // Verify the download request.
- EXPECT_EQ(icon_url, download_handler->GetImageUrl());
-
- // Reset the history_handler to verify whether favicon is set.
- helper.set_history_handler(nullptr);
-
- // Smulates download done.
- download_handler->InvokeCallback();
-
- // New icon should be saved to history backend and navigation entry.
- history_handler = helper.history_handler();
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(icon_url, history_handler->icon_url_);
- EXPECT_EQ(favicon_base::FAVICON, history_handler->icon_type_);
- EXPECT_LT(0U, history_handler->bitmap_data_.size());
- EXPECT_EQ(page_url, history_handler->page_url_);
-
- // Verify NavigationEntry.
- EXPECT_EQ(2u, delegate.num_notifications());
- EXPECT_EQ(icon_url, delegate.icon_url());
- EXPECT_FALSE(delegate.image().IsEmpty());
- EXPECT_EQ(gfx::kFaviconSize, delegate.image().Width());
+// Test that the icon is redownloaded if the icon cached for the page URL
+// expired.
+TEST_F(FaviconHandlerTest, RedownloadExpiredPageUrlFavicon) {
+ favicon_service_.fake()->Store(
+ kPageURL, kIconURL16x16,
+ CreateRawBitmapResult(kIconURL16x16, FAVICON, /*expired=*/true));
+
+ // TODO(crbug.com/700811): It would be nice if we could check whether the two
+ // OnFaviconUpdated() calls are called with different gfx::Images (as opposed
+ // to calling OnFaviconUpdated() with the expired gfx::Image both times).
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, kIconURL16x16, _, _)).Times(2);
+ EXPECT_CALL(favicon_service_, SetFavicons(_, kIconURL16x16, _, _));
+
+ RunHandlerWithSimpleFaviconCandidates({kIconURL16x16});
+ // We know from the |kPageUrl| database request that |kIconURL16x16| has
+ // expired. A second request for |kIconURL16x16| should not have been made
+ // because it is redundant.
+ EXPECT_THAT(favicon_service_.fake()->db_requests(), ElementsAre(kPageURL));
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(kIconURL16x16));
}
+// Test that FaviconHandler requests the new data when:
+// - There is valid data in the database for the page URL.
+// AND
+// - The icon URL used by the page has changed.
+// AND
+// - There is no data in database for the new icon URL.
TEST_F(FaviconHandlerTest, UpdateAndDownloadFavicon) {
- const GURL page_url("http://www.google.com");
- const GURL icon_url("http://www.google.com/favicon");
- const GURL new_icon_url("http://www.google.com/new_favicon");
-
- TestDelegate delegate;
- TestFaviconHandler helper(&delegate, FaviconDriverObserver::NON_TOUCH_16_DIP);
-
- helper.FetchFavicon(page_url);
- HistoryRequestHandler* history_handler = helper.history_handler();
- // Ensure the data given to history is correct.
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(page_url, history_handler->page_url_);
- EXPECT_EQ(GURL(), history_handler->icon_url_);
- EXPECT_EQ(favicon_base::FAVICON, history_handler->icon_type_);
-
- // Set valid icon data.
- SetFaviconRawBitmapResult(icon_url, &history_handler->history_results_);
-
- // Send history response.
- history_handler->InvokeCallback();
- // Verify FaviconHandler status.
- EXPECT_EQ(1u, delegate.num_notifications());
- EXPECT_EQ(icon_url, delegate.icon_url());
-
- // Reset the history_handler to verify whether new icon is requested from
- // history.
- helper.set_history_handler(nullptr);
-
- // Simulates update with the different favicon url.
- std::vector<FaviconURL> urls;
- urls.push_back(FaviconURL(
- new_icon_url, favicon_base::FAVICON, std::vector<gfx::Size>()));
- helper.OnUpdateFaviconURL(page_url, urls);
-
- // Verify FaviconHandler status.
- EXPECT_EQ(1u, helper.image_urls().size());
- ASSERT_TRUE(helper.current_candidate());
- ASSERT_EQ(new_icon_url, helper.current_candidate()->icon_url);
- ASSERT_EQ(favicon_base::FAVICON, helper.current_candidate()->icon_type);
-
- // Favicon should be requested from history.
- history_handler = helper.history_handler();
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(new_icon_url, history_handler->icon_url_);
- EXPECT_EQ(favicon_base::FAVICON, history_handler->icon_type_);
- EXPECT_EQ(page_url, history_handler->page_url_);
-
- // Simulate not find icon.
- history_handler->history_results_.clear();
- history_handler->InvokeCallback();
-
- // Favicon should request to download icon now.
- DownloadHandler* download_handler = delegate.download_handler();
- EXPECT_TRUE(download_handler->HasDownload());
-
- // Verify the download request.
- EXPECT_EQ(new_icon_url, download_handler->GetImageUrl());
-
- // Reset the history_handler to verify whether favicon is set.
- helper.set_history_handler(nullptr);
-
- // Smulates download done.
- download_handler->InvokeCallback();
-
- // New icon should be saved to history backend and navigation entry.
- history_handler = helper.history_handler();
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(new_icon_url, history_handler->icon_url_);
- EXPECT_EQ(favicon_base::FAVICON, history_handler->icon_type_);
- EXPECT_LT(0U, history_handler->bitmap_data_.size());
- EXPECT_EQ(page_url, history_handler->page_url_);
-
- // Verify NavigationEntry.
- EXPECT_EQ(2u, delegate.num_notifications());
- EXPECT_EQ(new_icon_url, delegate.icon_url());
- EXPECT_FALSE(delegate.image().IsEmpty());
- EXPECT_EQ(gfx::kFaviconSize, delegate.image().Width());
-}
+ const GURL kOldIconURL("http://www.google.com/old_favicon");
+ const GURL kNewIconURL = kIconURL16x16;
-TEST_F(FaviconHandlerTest, FaviconInHistoryInvalid) {
- const GURL page_url("http://www.google.com");
- const GURL icon_url("http://www.google.com/favicon");
+ favicon_service_.fake()->Store(kPageURL, kOldIconURL,
+ CreateRawBitmapResult(kOldIconURL));
- TestDelegate delegate;
- TestFaviconHandler helper(&delegate, FaviconDriverObserver::NON_TOUCH_16_DIP);
+ InSequence seq;
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, kOldIconURL, _, _));
+ EXPECT_CALL(favicon_service_, SetFavicons(_, kNewIconURL, _, _));
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, kNewIconURL, _, _));
- helper.FetchFavicon(page_url);
- HistoryRequestHandler* history_handler = helper.history_handler();
- // Ensure the data given to history is correct.
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(page_url, history_handler->page_url_);
- EXPECT_EQ(GURL(), history_handler->icon_url_);
- EXPECT_EQ(favicon_base::FAVICON, history_handler->icon_type_);
+ RunHandlerWithSimpleFaviconCandidates({kNewIconURL});
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(kNewIconURL));
+}
+// If there is data for the page URL in history which is invalid, test that:
+// - The invalid data is not sent to the UI.
+// - The icon is redownloaded.
+TEST_F(FaviconHandlerTest, FaviconInHistoryInvalid) {
// Set non empty but invalid data.
- favicon_base::FaviconRawBitmapResult bitmap_result;
- bitmap_result.expired = false;
+ std::vector<FaviconRawBitmapResult> bitmap_result =
+ CreateRawBitmapResult(kIconURL16x16);
// Empty bitmap data is invalid.
- bitmap_result.bitmap_data = new base::RefCountedBytes();
- bitmap_result.pixel_size = gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize);
- bitmap_result.icon_type = favicon_base::FAVICON;
- bitmap_result.icon_url = icon_url;
- history_handler->history_results_.clear();
- history_handler->history_results_.push_back(bitmap_result);
-
- // Send history response.
- history_handler->InvokeCallback();
- // The NavigationEntry should not be set yet as the history data is invalid.
- EXPECT_EQ(0u, delegate.num_notifications());
- EXPECT_EQ(GURL(), delegate.icon_url());
-
- // Reset the history_handler to verify whether new icon is requested from
- // history.
- helper.set_history_handler(nullptr);
-
- // Simulates update with matching favicon URL.
- std::vector<FaviconURL> urls;
- urls.push_back(
- FaviconURL(icon_url, favicon_base::FAVICON, std::vector<gfx::Size>()));
- helper.OnUpdateFaviconURL(page_url, urls);
-
- // A download for the favicon should be requested, and we should not do
- // another history request.
- DownloadHandler* download_handler = delegate.download_handler();
- EXPECT_TRUE(download_handler->HasDownload());
- EXPECT_EQ(nullptr, helper.history_handler());
-
- // Verify the download request.
- EXPECT_EQ(icon_url, download_handler->GetImageUrl());
-
- // Simulates download done.
- download_handler->InvokeCallback();
-
- // New icon should be saved to history backend and navigation entry.
- history_handler = helper.history_handler();
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(icon_url, history_handler->icon_url_);
- EXPECT_EQ(favicon_base::FAVICON, history_handler->icon_type_);
- EXPECT_LT(0U, history_handler->bitmap_data_.size());
- EXPECT_EQ(page_url, history_handler->page_url_);
-
- // Verify NavigationEntry.
- EXPECT_EQ(1u, delegate.num_notifications());
- EXPECT_EQ(icon_url, delegate.icon_url());
- EXPECT_FALSE(delegate.image().IsEmpty());
- EXPECT_EQ(gfx::kFaviconSize, delegate.image().Width());
+ bitmap_result[0].bitmap_data = new base::RefCountedBytes();
+
+ favicon_service_.fake()->Store(kPageURL, kIconURL16x16, bitmap_result);
+
+ // TODO(crbug.com/700811): It would be nice if we could check the image
+ // being published to rule out invalid data.
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, kIconURL16x16, _, _));
+
+ RunHandlerWithSimpleFaviconCandidates({kIconURL16x16});
+
+ EXPECT_THAT(favicon_service_.fake()->db_requests(), ElementsAre(kPageURL));
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(kIconURL16x16));
}
+// Test that no downloads are done if a user visits a page which changed its
+// favicon URL to a favicon URL which is already cached in the database.
TEST_F(FaviconHandlerTest, UpdateFavicon) {
- const GURL page_url("http://www.google.com");
- const GURL icon_url("http://www.google.com/favicon");
- const GURL new_icon_url("http://www.google.com/new_favicon");
-
- TestDelegate delegate;
- TestFaviconHandler helper(&delegate, FaviconDriverObserver::NON_TOUCH_16_DIP);
-
- helper.FetchFavicon(page_url);
- HistoryRequestHandler* history_handler = helper.history_handler();
- // Ensure the data given to history is correct.
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(page_url, history_handler->page_url_);
- EXPECT_EQ(GURL(), history_handler->icon_url_);
- EXPECT_EQ(favicon_base::FAVICON, history_handler->icon_type_);
-
- SetFaviconRawBitmapResult(icon_url, &history_handler->history_results_);
-
- // Send history response.
- history_handler->InvokeCallback();
- // Verify FaviconHandler status.
- EXPECT_EQ(1u, delegate.num_notifications());
- EXPECT_EQ(icon_url, delegate.icon_url());
-
- // Reset the history_handler to verify whether new icon is requested from
- // history.
- helper.set_history_handler(nullptr);
-
- // Simulates update with the different favicon url.
- std::vector<FaviconURL> urls;
- urls.push_back(FaviconURL(
- new_icon_url, favicon_base::FAVICON, std::vector<gfx::Size>()));
- helper.OnUpdateFaviconURL(page_url, urls);
-
- // Verify FaviconHandler status.
- EXPECT_EQ(1u, helper.image_urls().size());
- ASSERT_TRUE(helper.current_candidate());
- ASSERT_EQ(new_icon_url, helper.current_candidate()->icon_url);
- ASSERT_EQ(favicon_base::FAVICON, helper.current_candidate()->icon_type);
-
- // Favicon should be requested from history.
- history_handler = helper.history_handler();
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(new_icon_url, history_handler->icon_url_);
- EXPECT_EQ(favicon_base::FAVICON, history_handler->icon_type_);
- EXPECT_EQ(page_url, history_handler->page_url_);
-
- // Simulate find icon.
- SetFaviconRawBitmapResult(new_icon_url, &history_handler->history_results_);
- history_handler->InvokeCallback();
-
- // Shouldn't request download favicon
- EXPECT_FALSE(delegate.download_handler()->HasDownload());
-
- // Verify the favicon status.
- EXPECT_EQ(2u, delegate.num_notifications());
- EXPECT_EQ(new_icon_url, delegate.icon_url());
- EXPECT_FALSE(delegate.image().IsEmpty());
+ const GURL kSomePreviousPageURL("https://www.google.com/previous");
+ const GURL kIconURL("http://www.google.com/favicon");
+ const GURL kNewIconURL("http://www.google.com/new_favicon");
+
+ favicon_service_.fake()->Store(kPageURL, kIconURL,
+ CreateRawBitmapResult(kIconURL));
+ favicon_service_.fake()->Store(kSomePreviousPageURL, kNewIconURL,
+ CreateRawBitmapResult(kNewIconURL));
+
+ EXPECT_CALL(favicon_service_, SetFavicons(_, _, _, _)).Times(0);
+
+ InSequence seq;
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, kIconURL, _, _));
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, kNewIconURL, _, _));
+
+ RunHandlerWithSimpleFaviconCandidates({kNewIconURL});
+ EXPECT_THAT(favicon_service_.fake()->db_requests(),
+ ElementsAre(kPageURL, kNewIconURL));
+ EXPECT_THAT(delegate_.downloads(), IsEmpty());
}
TEST_F(FaviconHandlerTest, Download2ndFaviconURLCandidate) {
- const GURL page_url("http://www.google.com");
- const GURL icon_url("http://www.google.com/favicon");
- const GURL new_icon_url("http://www.google.com/new_favicon");
-
- TestDelegate delegate;
- TestFaviconHandler helper(&delegate, FaviconDriverObserver::TOUCH_LARGEST);
- std::set<GURL> fail_downloads;
- fail_downloads.insert(icon_url);
- delegate.download_handler()->FailDownloadForIconURLs(fail_downloads);
-
- helper.FetchFavicon(page_url);
- HistoryRequestHandler* history_handler = helper.history_handler();
- // Ensure the data given to history is correct.
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(page_url, history_handler->page_url_);
- EXPECT_EQ(GURL(), history_handler->icon_url_);
- EXPECT_EQ(favicon_base::TOUCH_PRECOMPOSED_ICON | favicon_base::TOUCH_ICON,
- history_handler->icon_type_);
-
- // Icon not found.
- history_handler->history_results_.clear();
- // Send history response.
- history_handler->InvokeCallback();
- // Verify FaviconHandler status.
- EXPECT_EQ(0u, delegate.num_notifications());
- EXPECT_EQ(GURL(), delegate.icon_url());
-
- // Reset the history_handler to verify whether new icon is requested from
- // history.
- helper.set_history_handler(nullptr);
-
- // Simulates update with the different favicon url.
- std::vector<FaviconURL> urls;
- urls.push_back(FaviconURL(icon_url,
- favicon_base::TOUCH_PRECOMPOSED_ICON,
- std::vector<gfx::Size>()));
- urls.push_back(FaviconURL(
- new_icon_url, favicon_base::TOUCH_ICON, std::vector<gfx::Size>()));
- urls.push_back(FaviconURL(
- new_icon_url, favicon_base::FAVICON, std::vector<gfx::Size>()));
- helper.OnUpdateFaviconURL(page_url, urls);
-
- // Verify FaviconHandler status.
- EXPECT_EQ(2u, helper.image_urls().size());
- EXPECT_EQ(0u, helper.current_candidate_index());
- ASSERT_TRUE(helper.current_candidate());
- ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
- ASSERT_EQ(favicon_base::TOUCH_PRECOMPOSED_ICON,
- helper.current_candidate()->icon_type);
-
- // Favicon should be requested from history.
- history_handler = helper.history_handler();
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(icon_url, history_handler->icon_url_);
- EXPECT_EQ(favicon_base::TOUCH_PRECOMPOSED_ICON, history_handler->icon_type_);
- EXPECT_EQ(page_url, history_handler->page_url_);
-
- // Simulate not find icon.
- history_handler->history_results_.clear();
- history_handler->InvokeCallback();
-
- // Should request download favicon.
- DownloadHandler* download_handler = delegate.download_handler();
- EXPECT_TRUE(download_handler->HasDownload());
-
- // Verify the download request.
- EXPECT_EQ(icon_url, download_handler->GetImageUrl());
-
- // Reset the history_handler to verify whether favicon is request from
- // history.
- helper.set_history_handler(nullptr);
- download_handler->InvokeCallback();
-
- // Left 1 url.
- EXPECT_EQ(1u, helper.current_candidate_index());
- ASSERT_TRUE(helper.current_candidate());
- EXPECT_EQ(new_icon_url, helper.current_candidate()->icon_url);
- EXPECT_EQ(favicon_base::TOUCH_ICON, helper.current_candidate()->icon_type);
-
- // Favicon should be requested from history.
- history_handler = helper.history_handler();
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(new_icon_url, history_handler->icon_url_);
- EXPECT_EQ(favicon_base::TOUCH_ICON, history_handler->icon_type_);
- EXPECT_EQ(page_url, history_handler->page_url_);
-
- // Reset download handler
- download_handler->Reset();
-
- // Simulates getting a expired icon from history.
- SetFaviconRawBitmapResult(new_icon_url,
- favicon_base::TOUCH_ICON,
- true /* expired */,
- &history_handler->history_results_);
- history_handler->InvokeCallback();
-
- // Verify the download request.
- EXPECT_TRUE(delegate.download_handler()->HasDownload());
- EXPECT_EQ(new_icon_url, download_handler->GetImageUrl());
-
- helper.set_history_handler(nullptr);
-
- // Simulates icon being downloaded.
- download_handler->InvokeCallback();
-
- // New icon should be saved to history backend.
- history_handler = helper.history_handler();
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(new_icon_url, history_handler->icon_url_);
- EXPECT_EQ(favicon_base::TOUCH_ICON, history_handler->icon_type_);
- EXPECT_LT(0U, history_handler->bitmap_data_.size());
- EXPECT_EQ(page_url, history_handler->page_url_);
+ const GURL kIconURLReturning500("http://www.google.com/500.png");
+
+ delegate_.fake_downloader().AddError(kIconURLReturning500, 500);
+
+ favicon_service_.fake()->Store(
+ kPageURL, kIconURL64x64,
+ CreateRawBitmapResult(kIconURL64x64, TOUCH_ICON,
+ /*expired=*/true));
+
+ EXPECT_CALL(delegate_,
+ OnFaviconUpdated(kPageURL, FaviconDriverObserver::TOUCH_LARGEST,
+ kIconURL64x64, /*icon_url_changed=*/true, _));
+ EXPECT_CALL(delegate_,
+ OnFaviconUpdated(kPageURL, FaviconDriverObserver::TOUCH_LARGEST,
+ kIconURL64x64, /*icon_url_changed=*/false, _));
+
+ RunHandlerWithCandidates(
+ FaviconDriverObserver::TOUCH_LARGEST,
+ {
+ FaviconURL(kIconURLReturning500, TOUCH_PRECOMPOSED_ICON, kEmptySizes),
+ FaviconURL(kIconURL64x64, TOUCH_ICON, kEmptySizes),
+ });
+ // First download fails, second succeeds.
+ EXPECT_THAT(delegate_.downloads(),
+ ElementsAre(kIconURLReturning500, kIconURL64x64));
}
+// Test that download data for icon URLs other than the current favicon
+// candidate URLs is ignored. This test tests the scenario where a download is
+// in flight when FaviconHandler::OnUpdateFaviconURL() is called.
+// TODO(mastiz): Make this test deal with FaviconURLs of type
+// favicon_base::FAVICON and add new ones like OnlyDownloadMatchingIconType and
+// CallSetFaviconsWithCorrectIconType.
TEST_F(FaviconHandlerTest, UpdateDuringDownloading) {
- const GURL page_url("http://www.google.com");
- const GURL icon_url("http://www.google.com/favicon");
- const GURL new_icon_url("http://www.google.com/new_favicon");
-
- TestDelegate delegate;
- TestFaviconHandler helper(&delegate, FaviconDriverObserver::TOUCH_LARGEST);
-
- helper.FetchFavicon(page_url);
- HistoryRequestHandler* history_handler = helper.history_handler();
- // Ensure the data given to history is correct.
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(page_url, history_handler->page_url_);
- EXPECT_EQ(GURL(), history_handler->icon_url_);
- EXPECT_EQ(favicon_base::TOUCH_PRECOMPOSED_ICON | favicon_base::TOUCH_ICON,
- history_handler->icon_type_);
-
- // Icon not found.
- history_handler->history_results_.clear();
- // Send history response.
- history_handler->InvokeCallback();
- // Verify FaviconHandler status.
- EXPECT_EQ(0u, delegate.num_notifications());
- EXPECT_EQ(GURL(), delegate.icon_url());
-
- // Reset the history_handler to verify whether new icon is requested from
- // history.
- helper.set_history_handler(nullptr);
-
- // Simulates update with the different favicon url.
- std::vector<FaviconURL> urls;
- urls.push_back(FaviconURL(icon_url,
- favicon_base::TOUCH_PRECOMPOSED_ICON,
- std::vector<gfx::Size>()));
- urls.push_back(FaviconURL(
- new_icon_url, favicon_base::TOUCH_ICON, std::vector<gfx::Size>()));
- urls.push_back(FaviconURL(
- new_icon_url, favicon_base::FAVICON, std::vector<gfx::Size>()));
- helper.OnUpdateFaviconURL(page_url, urls);
-
- // Verify FaviconHandler status.
- EXPECT_EQ(2u, helper.image_urls().size());
- ASSERT_EQ(0u, helper.current_candidate_index());
- ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
- ASSERT_EQ(favicon_base::TOUCH_PRECOMPOSED_ICON,
- helper.current_candidate()->icon_type);
-
- // Favicon should be requested from history.
- history_handler = helper.history_handler();
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(icon_url, history_handler->icon_url_);
- EXPECT_EQ(favicon_base::TOUCH_PRECOMPOSED_ICON, history_handler->icon_type_);
- EXPECT_EQ(page_url, history_handler->page_url_);
-
- // Simulate not find icon.
- history_handler->history_results_.clear();
- history_handler->InvokeCallback();
-
- // Should request download favicon.
- DownloadHandler* download_handler = delegate.download_handler();
- EXPECT_TRUE(download_handler->HasDownload());
-
- // Verify the download request.
- EXPECT_EQ(icon_url, download_handler->GetImageUrl());
-
- // Reset the history_handler to verify whether favicon is request from
- // history.
- helper.set_history_handler(nullptr);
- const GURL latest_icon_url("http://www.google.com/latest_favicon");
- std::vector<FaviconURL> latest_urls;
- latest_urls.push_back(FaviconURL(
- latest_icon_url, favicon_base::TOUCH_ICON, std::vector<gfx::Size>()));
- helper.OnUpdateFaviconURL(page_url, latest_urls);
-
- EXPECT_EQ(1u, helper.image_urls().size());
- EXPECT_EQ(0u, helper.current_candidate_index());
- EXPECT_EQ(latest_icon_url, helper.current_candidate()->icon_url);
- EXPECT_EQ(favicon_base::TOUCH_ICON, helper.current_candidate()->icon_type);
-
- // Whether new icon is requested from history
- history_handler = helper.history_handler();
- ASSERT_TRUE(history_handler);
- EXPECT_EQ(latest_icon_url, history_handler->icon_url_);
- EXPECT_EQ(favicon_base::TOUCH_ICON, history_handler->icon_type_);
- EXPECT_EQ(page_url, history_handler->page_url_);
-
- // Reset the history_handler to verify whether favicon is request from
- // history.
- // Save the callback for late use.
- favicon_base::FaviconResultsCallback callback = history_handler->callback_;
- helper.set_history_handler(nullptr);
-
- // Simulates download succeed.
- download_handler->InvokeCallback();
- // The downloaded icon should be thrown away as there is favicon update.
- EXPECT_FALSE(helper.history_handler());
-
- download_handler->Reset();
-
- // Simulates getting the icon from history.
- std::unique_ptr<HistoryRequestHandler> handler;
- handler.reset(new HistoryRequestHandler(
- page_url, latest_icon_url, favicon_base::TOUCH_ICON, callback));
- SetFaviconRawBitmapResult(latest_icon_url,
- favicon_base::TOUCH_ICON,
- false /* expired */,
- &handler->history_results_);
- handler->InvokeCallback();
-
- // No download request.
- EXPECT_FALSE(download_handler->HasDownload());
+ const GURL kIconURL1("http://www.google.com/favicon");
+ const GURL kIconURL2 = kIconURL16x16;
+ const GURL kIconURL3 = kIconURL64x64;
+
+ // Defer the download completion such that RunUntilIdle() doesn't complete
+ // the download.
+ delegate_.fake_downloader().SetRunCallbackManuallyForUrl(kIconURL1);
+
+ delegate_.fake_downloader().Add(kIconURL1, IntVector{16});
+ delegate_.fake_downloader().Add(kIconURL3, IntVector{64});
+
+ std::unique_ptr<FaviconHandler> handler =
+ RunHandlerWithSimpleFaviconCandidates({kIconURL1, kIconURL2});
+
+ ASSERT_TRUE(VerifyAndClearExpectations());
+ ASSERT_TRUE(delegate_.fake_downloader().HasPendingManualCallback());
+
+ // Favicon update should invalidate the ongoing download.
+ EXPECT_CALL(favicon_service_, SetFavicons(_, kIconURL3, _, _));
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, kIconURL3, _, _));
+
+ handler->OnUpdateFaviconURL(kPageURL,
+ {FaviconURL(kIconURL3, FAVICON, kEmptySizes)});
+
+ // Finalizes download, which should be thrown away as the favicon URLs were
+ // updated.
+ EXPECT_TRUE(delegate_.fake_downloader().RunCallbackManually());
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_THAT(favicon_service_.fake()->db_requests(), ElementsAre(kIconURL3));
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(kIconURL3));
}
// Test that sending an icon URL update identical to the previous icon URL
// update is a no-op.
-TEST_F(FaviconHandlerTest, UpdateSameIconURLs) {
- const GURL page_url("http://www.google.com");
- const GURL icon_url1("http://www.google.com/favicon1");
- const GURL icon_url2("http://www.google.com/favicon2");
- std::vector<FaviconURL> favicon_urls;
- favicon_urls.push_back(FaviconURL(GURL("http://www.google.com/favicon1"),
- favicon_base::FAVICON,
- std::vector<gfx::Size>()));
- favicon_urls.push_back(FaviconURL(GURL("http://www.google.com/favicon2"),
- favicon_base::FAVICON,
- std::vector<gfx::Size>()));
-
- TestDelegate delegate;
- TestFaviconHandler helper(&delegate, FaviconDriverObserver::NON_TOUCH_16_DIP);
-
- // Initiate a request for favicon data for |page_url|. History does not know
- // about the page URL or the icon URLs.
- helper.FetchFavicon(page_url);
- helper.history_handler()->InvokeCallback();
- helper.set_history_handler(nullptr);
-
- // Got icon URLs.
- helper.OnUpdateFaviconURL(page_url, favicon_urls);
-
- // There should be an ongoing history request for |icon_url1|.
- ASSERT_EQ(2u, helper.image_urls().size());
- ASSERT_EQ(0u, helper.current_candidate_index());
- HistoryRequestHandler* history_handler = helper.history_handler();
- ASSERT_TRUE(history_handler);
-
- // Calling OnUpdateFaviconURL() with the same icon URLs should have no effect.
- helper.OnUpdateFaviconURL(page_url, favicon_urls);
- EXPECT_EQ(history_handler, helper.history_handler());
-
- // Complete history request for |icon_url1| and do download.
- helper.history_handler()->InvokeCallback();
- helper.set_history_handler(nullptr);
- delegate.download_handler()->SetImageSizes(std::vector<int>(1u, 10));
- delegate.download_handler()->InvokeCallback();
- delegate.download_handler()->Reset();
-
- // There should now be an ongoing history request for |icon_url2|.
- ASSERT_EQ(1u, helper.current_candidate_index());
- history_handler = helper.history_handler();
- ASSERT_TRUE(history_handler);
-
- // Calling OnUpdateFaviconURL() with the same icon URLs should have no effect.
- helper.OnUpdateFaviconURL(page_url, favicon_urls);
- EXPECT_EQ(history_handler, helper.history_handler());
+TEST_F(FaviconHandlerTest, UpdateSameIconURLsWhileProcessingShouldBeNoop) {
+ const GURL kSlowLoadingIconURL("http://www.google.com/slow_favicon");
+
+ const std::vector<FaviconURL> favicon_urls = {
+ FaviconURL(kIconURL64x64, FAVICON, kEmptySizes),
+ FaviconURL(kSlowLoadingIconURL, FAVICON, kEmptySizes),
+ };
+
+ // Defer the download completion such that RunUntilIdle() doesn't complete
+ // the download.
+ delegate_.fake_downloader().SetRunCallbackManuallyForUrl(kSlowLoadingIconURL);
+ delegate_.fake_downloader().Add(kSlowLoadingIconURL, IntVector{16});
+
+ std::unique_ptr<FaviconHandler> handler = RunHandlerWithCandidates(
+ FaviconDriverObserver::NON_TOUCH_16_DIP, favicon_urls);
+
+ ASSERT_THAT(favicon_service_.fake()->db_requests(),
+ ElementsAre(kPageURL, kIconURL64x64, kSlowLoadingIconURL));
+ ASSERT_TRUE(VerifyAndClearExpectations());
+ ASSERT_TRUE(delegate_.fake_downloader().HasPendingManualCallback());
+
+ // Calling OnUpdateFaviconURL() with the same icon URLs should have no effect,
+ // despite the ongoing download.
+ handler->OnUpdateFaviconURL(kPageURL, favicon_urls);
+ base::RunLoop().RunUntilIdle();
+
+ // Complete the download.
+ EXPECT_CALL(favicon_service_, SetFavicons(_, _, _, _));
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, _, _, _));
+ EXPECT_TRUE(delegate_.fake_downloader().RunCallbackManually());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_THAT(delegate_.downloads(), IsEmpty());
+}
+
+// Test that calling OnUpdateFaviconUrl() with the same icon URLs as before is a
+// no-op. This is important because OnUpdateFaviconUrl() is called when the page
+// finishes loading. This can occur several times for pages with iframes.
+TEST_F(FaviconHandlerTest, UpdateSameIconURLsAfterFinishedShouldBeNoop) {
+ const std::vector<FaviconURL> favicon_urls = {
+ FaviconURL(kIconURL10x10, FAVICON, kEmptySizes),
+ FaviconURL(kIconURL16x16, FAVICON, kEmptySizes),
+ };
+
+ std::unique_ptr<FaviconHandler> handler = RunHandlerWithCandidates(
+ FaviconDriverObserver::NON_TOUCH_16_DIP, favicon_urls);
+
+ ASSERT_TRUE(VerifyAndClearExpectations());
+
+ // Calling OnUpdateFaviconURL() with identical data should be a no-op.
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(favicon_service_, SetFavicons(_, _, _, _)).Times(0);
+
+ handler->OnUpdateFaviconURL(kPageURL, favicon_urls);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_THAT(favicon_service_.fake()->db_requests(), IsEmpty());
+ EXPECT_THAT(delegate_.downloads(), IsEmpty());
}
// Fixes crbug.com/544560
+// Tests that Delegate::OnFaviconUpdated() is called if:
+// - The best icon on the initial page is not the last icon.
+// - All of the initial page's icons are downloaded.
+// AND
+// - JavaScript modifies the page's <link rel="icon"> tags to contain only the
+// last icon.
TEST_F(FaviconHandlerTest,
OnFaviconAvailableNotificationSentAfterIconURLChange) {
- const GURL kPageURL("http://www.page_which_animates_favicon.com");
- const GURL kIconURL1("http://wwww.page_which_animates_favicon.com/frame1.png");
- const GURL kIconURL2("http://wwww.page_which_animates_favicon.com/frame2.png");
-
- TestDelegate delegate;
- TestFaviconHandler helper(&delegate, FaviconDriverObserver::NON_TOUCH_16_DIP);
-
- // Initial state:
- // - The database does not know about |kPageURL|.
- // - The page uses |kIconURL1| and |kIconURL2|.
- // - The database knows about both |kIconURL1| and |kIconURl2|. Both icons
- // are expired in the database.
- helper.FetchFavicon(kPageURL);
- ASSERT_TRUE(helper.history_handler());
- helper.history_handler()->InvokeCallback();
- {
- std::vector<FaviconURL> icon_urls;
- icon_urls.push_back(
- FaviconURL(kIconURL1, favicon_base::FAVICON, std::vector<gfx::Size>()));
- icon_urls.push_back(
- FaviconURL(kIconURL2, favicon_base::FAVICON, std::vector<gfx::Size>()));
- helper.OnUpdateFaviconURL(kPageURL, icon_urls);
- }
-
- // FaviconHandler should request from history and download |kIconURL1| and
- // |kIconURL2|. |kIconURL1| is the better match. A
- // FaviconDriver::OnFaviconUpdated() notification should be sent for
- // |kIconURL1|.
- ASSERT_EQ(0u, delegate.num_notifications());
- ASSERT_TRUE(helper.history_handler());
- SetFaviconRawBitmapResult(kIconURL1,
- favicon_base::FAVICON,
- true /* expired */,
- &helper.history_handler()->history_results_);
- helper.history_handler()->InvokeCallback();
- helper.set_history_handler(nullptr);
- ASSERT_TRUE(delegate.download_handler()->HasDownload());
- delegate.download_handler()->SetImageSizes(std::vector<int>(1u, 15));
- delegate.download_handler()->InvokeCallback();
- delegate.download_handler()->Reset();
-
- ASSERT_TRUE(helper.history_handler());
- helper.history_handler()->InvokeCallback();
- SetFaviconRawBitmapResult(kIconURL2,
- favicon_base::FAVICON,
- true /* expired */,
- &helper.history_handler()->history_results_);
- helper.history_handler()->InvokeCallback();
- helper.set_history_handler(nullptr);
- ASSERT_TRUE(delegate.download_handler()->HasDownload());
- delegate.download_handler()->SetImageSizes(std::vector<int>(1u, 10));
- delegate.download_handler()->InvokeCallback();
- delegate.download_handler()->Reset();
-
- ASSERT_LT(0u, delegate.num_notifications());
- ASSERT_EQ(kIconURL1, delegate.icon_url());
-
- // Clear the history handler because SetHistoryFavicons() sets it.
- helper.set_history_handler(nullptr);
+ const GURL kIconURL1(
+ "http://wwww.page_which_animates_favicon.com/frame1.png");
+ const GURL kIconURL2(
+ "http://wwww.page_which_animates_favicon.com/frame2.png");
+
+ // |kIconURL1| is the better match.
+ delegate_.fake_downloader().Add(kIconURL1, IntVector{15});
+ delegate_.fake_downloader().Add(kIconURL2, IntVector{10});
+
+ // Two FaviconDriver::OnFaviconUpdated() notifications should be sent for
+ // |kIconURL1|, one before and one after the download.
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, kIconURL1, _, _));
+
+ std::unique_ptr<FaviconHandler> handler =
+ RunHandlerWithSimpleFaviconCandidates({kIconURL1, kIconURL2});
+
+ // Both |kIconURL1| and |kIconURL2| should have been requested from the
+ // database and downloaded. |kIconURL2| should have been fetched from the
+ // database and downloaded last.
+ ASSERT_THAT(delegate_.downloads(), ElementsAre(kIconURL1, kIconURL2));
+ ASSERT_THAT(favicon_service_.fake()->db_requests(),
+ ElementsAre(kPageURL, kIconURL1, kIconURL2));
+ ASSERT_TRUE(VerifyAndClearExpectations());
// Simulate the page changing it's icon URL to just |kIconURL2| via
// Javascript.
- helper.OnUpdateFaviconURL(
- kPageURL,
- std::vector<FaviconURL>(1u, FaviconURL(kIconURL2, favicon_base::FAVICON,
- std::vector<gfx::Size>())));
-
- // FaviconHandler should request from history and download |kIconURL2|. A
- // FaviconDriver::OnFaviconUpdated() notification should be sent for
- // |kIconURL2|.
- delegate.ResetNumNotifications();
- ASSERT_TRUE(helper.history_handler());
- SetFaviconRawBitmapResult(kIconURL2,
- favicon_base::FAVICON,
- true /* expired */,
- &helper.history_handler()->history_results_);
- helper.history_handler()->InvokeCallback();
- helper.set_history_handler(nullptr);
- ASSERT_TRUE(delegate.download_handler()->HasDownload());
- delegate.download_handler()->InvokeCallback();
- delegate.download_handler()->Reset();
- ASSERT_LT(0u, delegate.num_notifications());
- EXPECT_EQ(kIconURL2, delegate.icon_url());
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, kIconURL2, _, _));
+ handler->OnUpdateFaviconURL(kPageURL,
+ {FaviconURL(kIconURL2, FAVICON, kEmptySizes)});
+ base::RunLoop().RunUntilIdle();
}
// Test the favicon which is selected when the web page provides several
// favicons and none of the favicons are cached in history.
// The goal of this test is to be more of an integration test than
// SelectFaviconFramesTest.*.
-TEST_F(FaviconHandlerTest, MultipleFavicons) {
- const GURL kPageURL("http://www.google.com");
- const FaviconURL kSourceIconURLs[] = {
- FaviconURL(GURL("http://www.google.com/a"),
- favicon_base::FAVICON,
- std::vector<gfx::Size>()),
- FaviconURL(GURL("http://www.google.com/b"),
- favicon_base::FAVICON,
- std::vector<gfx::Size>()),
- FaviconURL(GURL("http://www.google.com/c"),
- favicon_base::FAVICON,
- std::vector<gfx::Size>()),
- FaviconURL(GURL("http://www.google.com/d"),
- favicon_base::FAVICON,
- std::vector<gfx::Size>()),
- FaviconURL(GURL("http://www.google.com/e"),
- favicon_base::FAVICON,
- std::vector<gfx::Size>())};
-
- // Set the supported scale factors to 1x and 2x. This affects the behavior of
- // SelectFaviconFrames().
- std::vector<ui::ScaleFactor> scale_factors;
- scale_factors.push_back(ui::SCALE_FACTOR_100P);
- scale_factors.push_back(ui::SCALE_FACTOR_200P);
- ui::test::ScopedSetSupportedScaleFactors scoped_supported(scale_factors);
-
- // 1) Test that if there are several single resolution favicons to choose from
- // that the largest exact match is chosen.
- TestDelegate delegate1;
- TestFaviconHandler handler1(&delegate1,
- FaviconDriverObserver::NON_TOUCH_16_DIP);
-
- const int kSizes1[] = { 16, 24, 32, 48, 256 };
- std::vector<FaviconURL> urls1(kSourceIconURLs,
- kSourceIconURLs + arraysize(kSizes1));
- DownloadTillDoneIgnoringHistory(&delegate1, &handler1, kPageURL, urls1,
- kSizes1);
-
- EXPECT_EQ(nullptr, handler1.current_candidate());
- EXPECT_EQ(1u, delegate1.num_notifications());
- EXPECT_FALSE(delegate1.image().IsEmpty());
- EXPECT_EQ(gfx::kFaviconSize, delegate1.image().Width());
-
- size_t expected_index = 2u;
- EXPECT_EQ(32, kSizes1[expected_index]);
- EXPECT_EQ(kSourceIconURLs[expected_index].icon_url, delegate1.icon_url());
-
- // 2) Test that if there are several single resolution favicons to choose
- // from, the exact match is preferred even if it results in upsampling.
- TestDelegate delegate2;
- TestFaviconHandler handler2(&delegate2,
- FaviconDriverObserver::NON_TOUCH_16_DIP);
-
- const int kSizes2[] = { 16, 24, 48, 256 };
- std::vector<FaviconURL> urls2(kSourceIconURLs,
- kSourceIconURLs + arraysize(kSizes2));
- DownloadTillDoneIgnoringHistory(&delegate2, &handler2, kPageURL, urls2,
- kSizes2);
- EXPECT_EQ(1u, delegate2.num_notifications());
- expected_index = 0u;
- EXPECT_EQ(16, kSizes2[expected_index]);
- EXPECT_EQ(kSourceIconURLs[expected_index].icon_url, delegate2.icon_url());
-
- // 3) Test that favicons which need to be upsampled a little or downsampled
- // a little are preferred over huge favicons.
- TestDelegate delegate3;
- TestFaviconHandler handler3(&delegate3,
- FaviconDriverObserver::NON_TOUCH_16_DIP);
-
- const int kSizes3[] = { 256, 48 };
- std::vector<FaviconURL> urls3(kSourceIconURLs,
- kSourceIconURLs + arraysize(kSizes3));
- DownloadTillDoneIgnoringHistory(&delegate3, &handler3, kPageURL, urls3,
- kSizes3);
- EXPECT_EQ(1u, delegate3.num_notifications());
- expected_index = 1u;
- EXPECT_EQ(48, kSizes3[expected_index]);
- EXPECT_EQ(kSourceIconURLs[expected_index].icon_url, delegate3.icon_url());
-
- TestDelegate delegate4;
- TestFaviconHandler handler4(&delegate4,
- FaviconDriverObserver::NON_TOUCH_16_DIP);
-
- const int kSizes4[] = { 17, 256 };
- std::vector<FaviconURL> urls4(kSourceIconURLs,
- kSourceIconURLs + arraysize(kSizes4));
- DownloadTillDoneIgnoringHistory(&delegate4, &handler4, kPageURL, urls4,
- kSizes4);
- EXPECT_EQ(1u, delegate4.num_notifications());
- expected_index = 0u;
- EXPECT_EQ(17, kSizes4[expected_index]);
- EXPECT_EQ(kSourceIconURLs[expected_index].icon_url, delegate4.icon_url());
+class FaviconHandlerMultipleFaviconsTest : public FaviconHandlerTest {
+ protected:
+ FaviconHandlerMultipleFaviconsTest() {
+ // Set the supported scale factors to 1x and 2x. This affects the behavior
+ // of SelectFaviconFrames().
+ scoped_set_supported_scale_factors_.reset(); // Need to delete first.
+ scoped_set_supported_scale_factors_.reset(
+ new ui::test::ScopedSetSupportedScaleFactors(
+ {ui::SCALE_FACTOR_100P, ui::SCALE_FACTOR_200P}));
+ }
+
+ // Simulates requesting a favicon for |page_url| given:
+ // - We have not previously cached anything in history for |page_url| or for
+ // any of candidates.
+ // - The page provides favicons with edge pixel sizes of
+ // |candidate_icon_sizes|.
+ // - Candidates are assumed of type FAVICON and the URLs are generated
+ // internally for testing purposes.
+ //
+ // Returns the chosen size among |candidate_icon_sizes| or -1 if none was
+ // chosen.
+ int DownloadTillDoneIgnoringHistory(const IntVector& candidate_icon_sizes) {
+ std::vector<FaviconURL> candidate_icons;
+ int chosen_icon_size = -1;
+
+ for (int icon_size : candidate_icon_sizes) {
+ const GURL icon_url(base::StringPrintf(
+ "https://www.google.com/generated/%dx%d", icon_size, icon_size));
+ // Set up 200 responses for all images, and the corresponding size.
+ delegate_.fake_downloader().Add(icon_url, IntVector{icon_size});
+ // Create test candidates of type FAVICON and a fake URL.
+ candidate_icons.emplace_back(icon_url, FAVICON, kEmptySizes);
+
+ ON_CALL(delegate_, OnFaviconUpdated(_, _, icon_url, _, _))
+ .WillByDefault(Assign(&chosen_icon_size, icon_size));
+ }
+
+ RunHandlerWithCandidates(FaviconDriverObserver::NON_TOUCH_16_DIP,
+ candidate_icons);
+ return chosen_icon_size;
+ }
+};
+
+// Tests that running FaviconHandler
+// - On an OS which supports the 1x and 2x scale factor
+// - On a page with <link rel="icon"> tags with no "sizes" information.
+// Selects the largest exact match. Note that a 32x32 PNG image is not a "true
+// exact match" on an OS which supports an 1x and 2x. A "true exact match" is
+// a .ico file with 16x16 and 32x32 bitmaps.
+TEST_F(FaviconHandlerMultipleFaviconsTest, ChooseLargestExactMatch) {
+ EXPECT_EQ(32,
+ DownloadTillDoneIgnoringHistory(IntVector{16, 24, 32, 48, 256}));
+}
+
+// Test that if there are several single resolution favicons to choose
+// from, the exact match is preferred even if it results in upsampling.
+TEST_F(FaviconHandlerMultipleFaviconsTest, ChooseExactMatchDespiteUpsampling) {
+ EXPECT_EQ(16, DownloadTillDoneIgnoringHistory(IntVector{16, 24, 48, 256}));
+}
+
+// Test that favicons which need to be upsampled a little or downsampled
+// a little are preferred over huge favicons.
+TEST_F(FaviconHandlerMultipleFaviconsTest,
+ ChooseMinorDownsamplingOverHugeIcon) {
+ EXPECT_EQ(48, DownloadTillDoneIgnoringHistory(IntVector{256, 48}));
+}
+
+TEST_F(FaviconHandlerMultipleFaviconsTest, ChooseMinorUpsamplingOverHugeIcon) {
+ EXPECT_EQ(17, DownloadTillDoneIgnoringHistory(IntVector{17, 256}));
+}
+
+TEST_F(FaviconHandlerTest, Report404) {
+ const GURL k404IconURL("http://www.google.com/404.png");
+
+ EXPECT_CALL(favicon_service_, UnableToDownloadFavicon(k404IconURL));
+
+ RunHandlerWithSimpleFaviconCandidates({k404IconURL});
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(k404IconURL));
+}
+
+// Test that WasUnableToDownloadFavicon() is not called if a download returns
+// HTTP status 503.
+TEST_F(FaviconHandlerTest, NotReport503) {
+ const GURL k503IconURL("http://www.google.com/503.png");
+
+ delegate_.fake_downloader().AddError(k503IconURL, 503);
+
+ EXPECT_CALL(favicon_service_, UnableToDownloadFavicon(_)).Times(0);
+
+ RunHandlerWithSimpleFaviconCandidates({k503IconURL});
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(k503IconURL));
}
// Test that the best favicon is selected when:
@@ -1224,51 +857,32 @@ TEST_F(FaviconHandlerTest, MultipleFavicons) {
// - Downloading one of the page's icon URLs previously returned a 404.
// - None of the favicons are cached in the Favicons database.
TEST_F(FaviconHandlerTest, MultipleFavicons404) {
- const GURL kPageURL("http://www.google.com");
const GURL k404IconURL("http://www.google.com/404.png");
- const FaviconURL k404FaviconURL(
- k404IconURL, favicon_base::FAVICON, std::vector<gfx::Size>());
- const FaviconURL kFaviconURLs[] = {
- FaviconURL(GURL("http://www.google.com/a"),
- favicon_base::FAVICON,
- std::vector<gfx::Size>()),
- k404FaviconURL,
- FaviconURL(GURL("http://www.google.com/c"),
- favicon_base::FAVICON,
- std::vector<gfx::Size>()),
- };
- TestDelegate delegate;
- TestFaviconHandler handler(&delegate,
- FaviconDriverObserver::NON_TOUCH_16_DIP);
- DownloadHandler* download_handler = delegate.download_handler();
-
- std::set<GURL> k404URLs;
- k404URLs.insert(k404IconURL);
- download_handler->FailDownloadForIconURLs(k404URLs);
-
- // Make the initial download for |k404IconURL| fail.
- const int kSizes1[] = { 0 };
- std::vector<FaviconURL> urls1(1u, k404FaviconURL);
- DownloadTillDoneIgnoringHistory(&delegate, &handler, kPageURL, urls1,
- kSizes1);
- EXPECT_TRUE(download_handler->DidFailDownloadForIconURL(k404IconURL));
-
- // Do a fetch now that the initial download for |k404IconURL| has failed. The
- // behavior is different because OnDidDownloadFavicon() is invoked
- // synchronously from DownloadFavicon().
- const int kSizes2[] = { 10, 0, 16 };
- std::vector<FaviconURL> urls2(kFaviconURLs,
- kFaviconURLs + arraysize(kFaviconURLs));
- DownloadTillDoneIgnoringHistory(&delegate, &handler, kPageURL, urls2,
- kSizes2);
-
- EXPECT_EQ(nullptr, handler.current_candidate());
- EXPECT_EQ(1u, delegate.num_notifications());
- EXPECT_FALSE(delegate.image().IsEmpty());
- int expected_index = 2u;
- EXPECT_EQ(16, kSizes2[expected_index]);
- EXPECT_EQ(kFaviconURLs[expected_index].icon_url, delegate.icon_url());
+ ON_CALL(favicon_service_, WasUnableToDownloadFavicon(k404IconURL))
+ .WillByDefault(Return(true));
+
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, kIconURL64x64, _, _));
+ RunHandlerWithSimpleFaviconCandidates({k404IconURL, kIconURL64x64});
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(kIconURL64x64));
+}
+
+// Test that the best favicon is selected when:
+// - The page provides several favicons.
+// - Downloading the last page icon URL previously returned a 404.
+// - None of the favicons are cached in the Favicons database.
+// - All of the icons are downloaded because none of the icons have the ideal
+// size.
+// - The 404 icon is last.
+TEST_F(FaviconHandlerTest, MultipleFaviconsLast404) {
+ const GURL k404IconURL("http://www.google.com/404.png");
+
+ ON_CALL(favicon_service_, WasUnableToDownloadFavicon(k404IconURL))
+ .WillByDefault(Return(true));
+
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, kIconURL64x64, _, _));
+ RunHandlerWithSimpleFaviconCandidates({kIconURL64x64, k404IconURL});
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(kIconURL64x64));
}
// Test that no favicon is selected when:
@@ -1276,402 +890,306 @@ TEST_F(FaviconHandlerTest, MultipleFavicons404) {
// - Downloading the page's icons has previously returned a 404.
// - None of the favicons are cached in the Favicons database.
TEST_F(FaviconHandlerTest, MultipleFaviconsAll404) {
- const GURL kPageURL("http://www.google.com");
- const GURL k404IconURL1("http://www.google.com/4041.png");
- const GURL k404IconURL2("http://www.google.com/4042.png");
- const FaviconURL kFaviconURLs[] = {
- FaviconURL(k404IconURL1,
- favicon_base::FAVICON,
- std::vector<gfx::Size>()),
- FaviconURL(k404IconURL2,
- favicon_base::FAVICON,
- std::vector<gfx::Size>()),
- };
+ const GURL k404IconURL1("http://www.google.com/a/404.png");
+ const GURL k404IconURL2("http://www.google.com/b/404.png");
- TestDelegate delegate;
- TestFaviconHandler handler(&delegate,
- FaviconDriverObserver::NON_TOUCH_16_DIP);
- DownloadHandler* download_handler = delegate.download_handler();
-
- std::set<GURL> k404URLs;
- k404URLs.insert(k404IconURL1);
- k404URLs.insert(k404IconURL2);
- download_handler->FailDownloadForIconURLs(k404URLs);
-
- // Make the initial downloads for |kFaviconURLs| fail.
- for (const FaviconURL& favicon_url : kFaviconURLs) {
- const int kSizes[] = { 0 };
- std::vector<FaviconURL> urls(1u, favicon_url);
- DownloadTillDoneIgnoringHistory(&delegate, &handler, kPageURL, urls,
- kSizes);
- }
- EXPECT_TRUE(download_handler->DidFailDownloadForIconURL(k404IconURL1));
- EXPECT_TRUE(download_handler->DidFailDownloadForIconURL(k404IconURL2));
-
- // Do a fetch now that the initial downloads for |kFaviconURLs| have failed.
- // The behavior is different because OnDidDownloadFavicon() is invoked
- // synchronously from DownloadFavicon().
- const int kSizes[] = { 0, 0 };
- std::vector<FaviconURL> urls(kFaviconURLs,
- kFaviconURLs + arraysize(kFaviconURLs));
- DownloadTillDoneIgnoringHistory(&delegate, &handler, kPageURL, urls, kSizes);
-
- EXPECT_EQ(nullptr, handler.current_candidate());
- EXPECT_EQ(0u, delegate.num_notifications());
- EXPECT_TRUE(delegate.image().IsEmpty());
+ ON_CALL(favicon_service_, WasUnableToDownloadFavicon(k404IconURL1))
+ .WillByDefault(Return(true));
+ ON_CALL(favicon_service_, WasUnableToDownloadFavicon(k404IconURL2))
+ .WillByDefault(Return(true));
+
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, _, _, _)).Times(0);
+ RunHandlerWithSimpleFaviconCandidates({k404IconURL1, k404IconURL2});
+ EXPECT_THAT(delegate_.downloads(), IsEmpty());
}
// Test that no favicon is selected when the page's only icon uses an invalid
// URL syntax.
TEST_F(FaviconHandlerTest, FaviconInvalidURL) {
- const GURL kPageURL("http://www.google.com");
const GURL kInvalidFormatURL("invalid");
ASSERT_TRUE(kInvalidFormatURL.is_empty());
- FaviconURL favicon_url(kInvalidFormatURL, favicon_base::FAVICON,
- std::vector<gfx::Size>());
+ EXPECT_CALL(delegate_, OnFaviconUpdated(_, _, _, _, _)).Times(0);
- TestDelegate delegate;
- TestFaviconHandler handler(&delegate,
- FaviconDriverObserver::NON_TOUCH_16_DIP);
- UpdateFaviconURL(&delegate, &handler, kPageURL,
- std::vector<FaviconURL>(1u, favicon_url));
- EXPECT_EQ(0u, handler.image_urls().size());
+ RunHandlerWithSimpleFaviconCandidates({kInvalidFormatURL});
+ EXPECT_THAT(delegate_.downloads(), IsEmpty());
}
TEST_F(FaviconHandlerTest, TestSortFavicon) {
- const GURL kPageURL("http://www.google.com");
- std::vector<gfx::Size> icon1;
- icon1.push_back(gfx::Size(1024, 1024));
- icon1.push_back(gfx::Size(512, 512));
-
- std::vector<gfx::Size> icon2;
- icon2.push_back(gfx::Size(15, 15));
- icon2.push_back(gfx::Size(16, 16));
-
- std::vector<gfx::Size> icon3;
- icon3.push_back(gfx::Size(16, 16));
- icon3.push_back(gfx::Size(14, 14));
-
- const FaviconURL kSourceIconURLs[] = {
- FaviconURL(GURL("http://www.google.com/a"), favicon_base::FAVICON, icon1),
- FaviconURL(GURL("http://www.google.com/b"), favicon_base::FAVICON, icon2),
- FaviconURL(GURL("http://www.google.com/c"), favicon_base::FAVICON, icon3),
- FaviconURL(GURL("http://www.google.com/d"),
- favicon_base::FAVICON,
- std::vector<gfx::Size>()),
- FaviconURL(GURL("http://www.google.com/e"),
- favicon_base::FAVICON,
- std::vector<gfx::Size>())};
-
- TestDelegate delegate1;
- TestFaviconHandler handler1(&delegate1,
- FaviconDriverObserver::NON_TOUCH_LARGEST);
- std::vector<FaviconURL> urls1(kSourceIconURLs,
- kSourceIconURLs + arraysize(kSourceIconURLs));
- UpdateFaviconURL(&delegate1, &handler1, kPageURL, urls1);
-
- struct ExpectedResult {
- // The favicon's index in kSourceIconURLs.
- size_t favicon_index;
- // Width of largest bitmap.
- int width;
- } results[] = {
- // First is icon1, though its size larger than maximal.
- {0, 1024},
- // Second is icon2
- // The 16x16 is largest.
- {1, 16},
- // Third is icon3 though it has same size as icon2.
- // The 16x16 is largest.
- {2, 16},
- // The rest of bitmaps come in order, there is no sizes attribute.
- {3, -1},
- {4, -1},
- };
- const std::vector<FaviconURL>& icons = handler1.image_urls();
- ASSERT_EQ(5u, icons.size());
- for (size_t i = 0; i < icons.size(); ++i) {
- EXPECT_EQ(kSourceIconURLs[results[i].favicon_index].icon_url,
- icons[i].icon_url);
- if (results[i].width != -1)
- EXPECT_EQ(results[i].width, icons[i].icon_sizes[0].width());
- }
+ // Names represent the bitmap sizes per icon.
+ const GURL kIconURL1_17("http://www.google.com/a");
+ const GURL kIconURL1024_512("http://www.google.com/b");
+ const GURL kIconURL16_14("http://www.google.com/c");
+ const GURL kIconURLWithoutSize1("http://www.google.com/d");
+ const GURL kIconURLWithoutSize2("http://www.google.com/e");
+
+ const std::vector<favicon::FaviconURL> kSourceIconURLs{
+ FaviconURL(kIconURL1_17, FAVICON, {gfx::Size(1, 1), gfx::Size(17, 17)}),
+ FaviconURL(kIconURL1024_512, FAVICON,
+ {gfx::Size(1024, 1024), gfx::Size(512, 512)}),
+ FaviconURL(kIconURL16_14, FAVICON,
+ {gfx::Size(16, 16), gfx::Size(14, 14)}),
+ FaviconURL(kIconURLWithoutSize1, FAVICON, kEmptySizes),
+ FaviconURL(kIconURLWithoutSize2, FAVICON, kEmptySizes)};
+
+ std::unique_ptr<FaviconHandler> handler = RunHandlerWithCandidates(
+ FaviconDriverObserver::NON_TOUCH_LARGEST, kSourceIconURLs);
+
+ EXPECT_THAT(
+ handler->GetIconURLs(),
+ ElementsAre(
+ // The 512x512 bitmap is the best match for the desired size.
+ kIconURL1024_512, kIconURL1_17, kIconURL16_14,
+ // The rest of bitmaps come in order, there is no "sizes" attribute.
+ kIconURLWithoutSize1, kIconURLWithoutSize2));
}
TEST_F(FaviconHandlerTest, TestDownloadLargestFavicon) {
- const GURL kPageURL("http://www.google.com");
- std::vector<gfx::Size> icon1;
- icon1.push_back(gfx::Size(1024, 1024));
- icon1.push_back(gfx::Size(512, 512));
-
- std::vector<gfx::Size> icon2;
- icon2.push_back(gfx::Size(15, 15));
- icon2.push_back(gfx::Size(14, 14));
-
- std::vector<gfx::Size> icon3;
- icon3.push_back(gfx::Size(16, 16));
- icon3.push_back(gfx::Size(512, 512));
-
- const FaviconURL kSourceIconURLs[] = {
- FaviconURL(
- GURL("http://www.google.com/a"), favicon_base::FAVICON, icon1),
- FaviconURL(
- GURL("http://www.google.com/b"), favicon_base::FAVICON, icon2),
- FaviconURL(
- GURL("http://www.google.com/c"), favicon_base::FAVICON, icon3),
- FaviconURL(GURL("http://www.google.com/d"),
- favicon_base::FAVICON,
- std::vector<gfx::Size>()),
- FaviconURL(GURL("http://www.google.com/e"),
- favicon_base::FAVICON,
- std::vector<gfx::Size>())};
-
- TestDelegate delegate1;
- TestFaviconHandler handler1(&delegate1,
- FaviconDriverObserver::NON_TOUCH_LARGEST);
-
- std::set<GURL> fail_icon_urls;
- for (size_t i = 0; i < arraysize(kSourceIconURLs); ++i) {
- fail_icon_urls.insert(kSourceIconURLs[i].icon_url);
- }
- delegate1.download_handler()->FailDownloadForIconURLs(fail_icon_urls);
-
- std::vector<FaviconURL> urls1(kSourceIconURLs,
- kSourceIconURLs + arraysize(kSourceIconURLs));
- UpdateFaviconURL(&delegate1, &handler1, kPageURL, urls1);
-
- // Simulate the download failed, to check whether the icons were requested
- // to download according their size.
- struct ExpectedResult {
- // The favicon's index in kSourceIconURLs.
- size_t favicon_index;
- // Width of largest bitmap.
- int width;
- } results[] = {
- {0, 1024},
- {2, 512},
- {1, 15},
- // The rest of bitmaps come in order.
- {3, -1},
- {4, -1},
- };
+ // Names represent the bitmap sizes per icon.
+ const GURL kIconURL1024_512("http://www.google.com/a");
+ const GURL kIconURL15_14("http://www.google.com/b");
+ const GURL kIconURL16_512("http://www.google.com/c");
+ const GURL kIconURLWithoutSize1("http://www.google.com/d");
+ const GURL kIconURLWithoutSize2("http://www.google.com/e");
+
+ RunHandlerWithCandidates(
+ FaviconDriverObserver::NON_TOUCH_LARGEST,
+ {FaviconURL(kIconURL1024_512, FAVICON,
+ {gfx::Size(1024, 1024), gfx::Size(512, 512)}),
+ FaviconURL(kIconURL15_14, FAVICON,
+ {gfx::Size(15, 15), gfx::Size(14, 14)}),
+ FaviconURL(kIconURL16_512, FAVICON,
+ {gfx::Size(16, 16), gfx::Size(512, 512)}),
+ FaviconURL(kIconURLWithoutSize1, FAVICON, kEmptySizes),
+ FaviconURL(kIconURLWithoutSize2, FAVICON, kEmptySizes)});
+
+ // Icon URLs are not registered and hence 404s will be produced, which
+ // allows checking whether the icons were requested according to their size.
+ // The favicons should have been requested in decreasing order of their sizes.
+ // Favicons without any <link sizes=""> attribute should have been downloaded
+ // last.
+ EXPECT_THAT(delegate_.downloads(),
+ ElementsAre(kIconURL1024_512, kIconURL16_512, kIconURL15_14,
+ kIconURLWithoutSize1, kIconURLWithoutSize2));
+}
- for (int i = 0; i < 5; ++i) {
- EXPECT_EQ(kSourceIconURLs[results[i].favicon_index].icon_url,
- handler1.current_candidate()->icon_url);
- if (results[i].width != -1) {
- EXPECT_EQ(results[i].width, handler1.current_candidate()->
- icon_sizes[0].width());
- }
+TEST_F(FaviconHandlerTest, TestSelectLargestFavicon) {
+ const GURL kIconURL1("http://www.google.com/b");
+ const GURL kIconURL2("http://www.google.com/c");
- // Simulate no favicon from history.
- handler1.history_handler()->history_results_.clear();
- handler1.history_handler()->InvokeCallback();
+ delegate_.fake_downloader().Add(kIconURL1, IntVector{15});
+ delegate_.fake_downloader().Add(kIconURL2, IntVector{14, 16});
- // Verify download request
- ASSERT_TRUE(delegate1.download_handler()->HasDownload());
- EXPECT_EQ(kSourceIconURLs[results[i].favicon_index].icon_url,
- delegate1.download_handler()->GetImageUrl());
+ // Verify NotifyFaviconAvailable().
+ EXPECT_CALL(delegate_,
+ OnFaviconUpdated(_, FaviconDriverObserver::NON_TOUCH_LARGEST,
+ kIconURL2, _, _));
- delegate1.download_handler()->InvokeCallback();
- delegate1.download_handler()->Reset();
- }
-}
+ RunHandlerWithCandidates(
+ FaviconDriverObserver::NON_TOUCH_LARGEST,
+ {FaviconURL(kIconURL1, FAVICON, {gfx::Size(15, 15)}),
+ FaviconURL(kIconURL2, FAVICON, {gfx::Size(14, 14), gfx::Size(16, 16)})});
-TEST_F(FaviconHandlerTest, TestSelectLargestFavicon) {
- const GURL kPageURL("http://www.google.com");
-
- std::vector<gfx::Size> one_icon;
- one_icon.push_back(gfx::Size(15, 15));
-
- std::vector<gfx::Size> two_icons;
- two_icons.push_back(gfx::Size(14, 14));
- two_icons.push_back(gfx::Size(16, 16));
-
- const FaviconURL kSourceIconURLs[] = {
- FaviconURL(
- GURL("http://www.google.com/b"), favicon_base::FAVICON, one_icon),
- FaviconURL(
- GURL("http://www.google.com/c"), favicon_base::FAVICON, two_icons)};
-
- TestDelegate delegate1;
- TestFaviconHandler handler1(&delegate1,
- FaviconDriverObserver::NON_TOUCH_LARGEST);
- std::vector<FaviconURL> urls1(kSourceIconURLs,
- kSourceIconURLs + arraysize(kSourceIconURLs));
- UpdateFaviconURL(&delegate1, &handler1, kPageURL, urls1);
-
- ASSERT_EQ(2u, handler1.image_urls().size());
-
- // Index of largest favicon in kSourceIconURLs.
- size_t i = 1;
- // The largest bitmap's index in Favicon .
- int b = 1;
-
- // Verify the icon_bitmaps_ was initialized correctly.
- EXPECT_EQ(kSourceIconURLs[i].icon_url,
- handler1.current_candidate()->icon_url);
- EXPECT_EQ(kSourceIconURLs[i].icon_sizes[b],
- handler1.current_candidate()->icon_sizes[0]);
-
- // Simulate no favicon from history.
- handler1.history_handler()->history_results_.clear();
- handler1.history_handler()->InvokeCallback();
-
- // Verify download request
- ASSERT_TRUE(delegate1.download_handler()->HasDownload());
- EXPECT_EQ(kSourceIconURLs[i].icon_url,
- delegate1.download_handler()->GetImageUrl());
-
- // Give the correct download result.
- std::vector<int> sizes;
- for (std::vector<gfx::Size>::const_iterator j =
- kSourceIconURLs[i].icon_sizes.begin();
- j != kSourceIconURLs[i].icon_sizes.end(); ++j)
- sizes.push_back(j->width());
-
- delegate1.download_handler()->SetImageSizes(sizes);
- delegate1.download_handler()->InvokeCallback();
-
- // Verify the largest bitmap has been saved into history.
- EXPECT_EQ(kSourceIconURLs[i].icon_url, handler1.history_handler()->icon_url_);
- EXPECT_EQ(kSourceIconURLs[i].icon_sizes[b],
- handler1.history_handler()->size_);
- // Verify NotifyFaviconAvailable().
- EXPECT_EQ(1u, delegate1.num_notifications());
- EXPECT_EQ(kSourceIconURLs[i].icon_url, delegate1.icon_url());
- EXPECT_EQ(kSourceIconURLs[i].icon_sizes[b], delegate1.image().Size());
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(kIconURL2));
}
TEST_F(FaviconHandlerTest, TestFaviconWasScaledAfterDownload) {
- const GURL kPageURL("http://www.google.com");
- const int kMaximalSize =
- TestFaviconHandler::GetMaximalIconSize(favicon_base::FAVICON);
-
- std::vector<gfx::Size> icon1;
- icon1.push_back(gfx::Size(kMaximalSize + 1, kMaximalSize + 1));
-
- std::vector<gfx::Size> icon2;
- icon2.push_back(gfx::Size(kMaximalSize + 2, kMaximalSize + 2));
-
- const FaviconURL kSourceIconURLs[] = {
- FaviconURL(
- GURL("http://www.google.com/b"), favicon_base::FAVICON, icon1),
- FaviconURL(
- GURL("http://www.google.com/c"), favicon_base::FAVICON, icon2)};
-
- TestDelegate delegate1;
- TestFaviconHandler handler1(&delegate1,
- FaviconDriverObserver::NON_TOUCH_LARGEST);
- std::vector<FaviconURL> urls1(kSourceIconURLs,
- kSourceIconURLs + arraysize(kSourceIconURLs));
- UpdateFaviconURL(&delegate1, &handler1, kPageURL, urls1);
-
- ASSERT_EQ(2u, handler1.image_urls().size());
-
- // Index of largest favicon in kSourceIconURLs.
- size_t i = 1;
- // The largest bitmap's index in Favicon .
- int b = 0;
-
- // Verify the icon_bitmaps_ was initialized correctly.
- EXPECT_EQ(kSourceIconURLs[i].icon_url,
- handler1.current_candidate()->icon_url);
- EXPECT_EQ(kSourceIconURLs[i].icon_sizes[b],
- handler1.current_candidate()->icon_sizes[0]);
-
- // Simulate no favicon from history.
- handler1.history_handler()->history_results_.clear();
- handler1.history_handler()->InvokeCallback();
-
- // Verify download request
- ASSERT_TRUE(delegate1.download_handler()->HasDownload());
- EXPECT_EQ(kSourceIconURLs[i].icon_url,
- delegate1.download_handler()->GetImageUrl());
-
- // Give the scaled download bitmap.
- std::vector<int> sizes;
- sizes.push_back(kMaximalSize);
-
- delegate1.download_handler()->SetImageSizes(sizes);
- delegate1.download_handler()->InvokeCallback();
-
- // Verify the largest bitmap has been saved into history though it was
- // scaled down to maximal size and smaller than icon1 now.
- EXPECT_EQ(kSourceIconURLs[i].icon_url, handler1.history_handler()->icon_url_);
- EXPECT_EQ(gfx::Size(kMaximalSize, kMaximalSize),
- handler1.history_handler()->size_);
+ const int kMaximalSize = FaviconHandler::GetMaximalIconSize(
+ FaviconDriverObserver::NON_TOUCH_LARGEST);
+
+ const GURL kIconURL1("http://www.google.com/b");
+ const GURL kIconURL2("http://www.google.com/c");
+
+ const int kOriginalSize1 = kMaximalSize + 1;
+ const int kOriginalSize2 = kMaximalSize + 2;
+
+ delegate_.fake_downloader().AddWithOriginalSizes(
+ kIconURL1, IntVector{kMaximalSize}, IntVector{kOriginalSize1});
+ delegate_.fake_downloader().AddWithOriginalSizes(
+ kIconURL2, IntVector{kMaximalSize}, IntVector{kOriginalSize2});
+
+ // Verify the best bitmap was selected (although smaller than |kIconURL2|)
+ // and that it was scaled down to |kMaximalSize|.
+ EXPECT_CALL(delegate_,
+ OnFaviconUpdated(_, _, kIconURL1, _,
+ ImageSizeIs(kMaximalSize, kMaximalSize)));
+
+ RunHandlerWithCandidates(
+ FaviconDriverObserver::NON_TOUCH_LARGEST,
+ {FaviconURL(kIconURL1, FAVICON,
+ SizeVector{gfx::Size(kOriginalSize1, kOriginalSize1)}),
+ FaviconURL(kIconURL2, FAVICON,
+ SizeVector{gfx::Size(kOriginalSize2, kOriginalSize2)})});
+
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(kIconURL1));
}
+// Test that if several icons are downloaded because the icons are smaller than
+// expected that OnFaviconUpdated() is called with the largest downloaded
+// bitmap.
TEST_F(FaviconHandlerTest, TestKeepDownloadedLargestFavicon) {
- const GURL kPageURL("http://www.google.com");
-
- std::vector<gfx::Size> icon1;
- icon1.push_back(gfx::Size(16, 16));
- const int actual_size1 = 10;
-
- std::vector<gfx::Size> icon2;
- icon2.push_back(gfx::Size(15, 15));
- const int actual_size2 = 12;
-
- const FaviconURL kSourceIconURLs[] = {
- FaviconURL(GURL("http://www.google.com/b"), favicon_base::FAVICON, icon1),
- FaviconURL(GURL("http://www.google.com/c"), favicon_base::FAVICON, icon2),
- FaviconURL(GURL("http://www.google.com/d"),
- favicon_base::FAVICON,
- std::vector<gfx::Size>())};
-
- TestDelegate delegate1;
- TestFaviconHandler handler1(&delegate1,
- FaviconDriverObserver::NON_TOUCH_LARGEST);
- std::vector<FaviconURL> urls1(kSourceIconURLs,
- kSourceIconURLs + arraysize(kSourceIconURLs));
- UpdateFaviconURL(&delegate1, &handler1, kPageURL, urls1);
- ASSERT_EQ(3u, handler1.image_urls().size());
-
- // Simulate no favicon from history.
- handler1.history_handler()->history_results_.clear();
- handler1.history_handler()->InvokeCallback();
-
- // Verify the first icon was request to download
- ASSERT_TRUE(delegate1.download_handler()->HasDownload());
- EXPECT_EQ(kSourceIconURLs[0].icon_url,
- delegate1.download_handler()->GetImageUrl());
-
- // Give the incorrect size.
- std::vector<int> sizes;
- sizes.push_back(actual_size1);
- delegate1.download_handler()->SetImageSizes(sizes);
- delegate1.download_handler()->InvokeCallback();
- delegate1.download_handler()->Reset();
-
- // Simulate no favicon from history.
- handler1.history_handler()->history_results_.clear();
- handler1.history_handler()->InvokeCallback();
-
- // Verify the 2nd icon was request to download
- ASSERT_TRUE(delegate1.download_handler()->HasDownload());
- EXPECT_EQ(kSourceIconURLs[1].icon_url,
- delegate1.download_handler()->GetImageUrl());
-
- // Very the best candidate is icon1
- EXPECT_EQ(kSourceIconURLs[0].icon_url,
- handler1.best_favicon_candidate().image_url);
- EXPECT_EQ(gfx::Size(actual_size1, actual_size1),
- handler1.best_favicon_candidate().image.Size());
-
- // Give the incorrect size.
- sizes.clear();
- sizes.push_back(actual_size2);
- delegate1.download_handler()->SetImageSizes(sizes);
- delegate1.download_handler()->InvokeCallback();
- delegate1.download_handler()->Reset();
-
- // Verify icon2 has been saved into history.
- EXPECT_EQ(kSourceIconURLs[1].icon_url, handler1.history_handler()->icon_url_);
- EXPECT_EQ(gfx::Size(actual_size2, actual_size2),
- handler1.history_handler()->size_);
+ EXPECT_CALL(delegate_,
+ OnFaviconUpdated(_, _, kIconURL12x12, _, ImageSizeIs(12, 12)));
+
+ RunHandlerWithCandidates(
+ FaviconDriverObserver::NON_TOUCH_LARGEST,
+ {FaviconURL(kIconURL10x10, FAVICON, SizeVector{gfx::Size(16, 16)}),
+ FaviconURL(kIconURL12x12, FAVICON, SizeVector{gfx::Size(15, 15)}),
+ FaviconURL(kIconURL16x16, FAVICON, kEmptySizes)});
+}
+
+TEST_F(FaviconHandlerTest, TestRecordMultipleDownloadAttempts) {
+ base::HistogramTester histogram_tester;
+
+ // Try to download the three failing icons and end up logging three attempts.
+ RunHandlerWithCandidates(
+ FaviconDriverObserver::NON_TOUCH_LARGEST,
+ {FaviconURL(GURL("http://www.google.com/a"), FAVICON, kEmptySizes),
+ FaviconURL(GURL("http://www.google.com/b"), FAVICON, kEmptySizes),
+ FaviconURL(GURL("http://www.google.com/c"), FAVICON, kEmptySizes)});
+
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.LargeIcons"),
+ ElementsAre(base::Bucket(/*sample=*/3, /*expected_count=*/1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.Favicons"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.TouchIcons"),
+ IsEmpty());
+}
+
+TEST_F(FaviconHandlerTest, TestRecordSingleFaviconDownloadAttempt) {
+ base::HistogramTester histogram_tester;
+
+ RunHandlerWithSimpleFaviconCandidates({kIconURL16x16});
+
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.Favicons"),
+ ElementsAre(base::Bucket(/*sample=*/1, /*expected_count=*/1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.LargeIcons"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.TouchIcons"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadOutcome"),
+ ElementsAre(base::Bucket(static_cast<int>(DownloadOutcome::SUCCEEDED),
+ /*expected_count=*/1)));
+}
+
+TEST_F(FaviconHandlerTest, TestRecordSingleLargeIconDownloadAttempt) {
+ base::HistogramTester histogram_tester;
+
+ RunHandlerWithCandidates(FaviconDriverObserver::NON_TOUCH_LARGEST,
+ {FaviconURL(kIconURL64x64, FAVICON, kEmptySizes)});
+
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.Favicons"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.LargeIcons"),
+ ElementsAre(base::Bucket(/*sample=*/1, /*expected_count=*/1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.TouchIcons"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadOutcome"),
+ ElementsAre(base::Bucket(static_cast<int>(DownloadOutcome::SUCCEEDED),
+ /*expected_count=*/1)));
+}
+
+TEST_F(FaviconHandlerTest, TestRecordSingleTouchIconDownloadAttempt) {
+ base::HistogramTester histogram_tester;
+ RunHandlerWithCandidates(
+ FaviconDriverObserver::TOUCH_LARGEST,
+ {FaviconURL(kIconURL64x64, TOUCH_ICON, kEmptySizes)});
+
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.LargeIcons"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.Favicons"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.TouchIcons"),
+ ElementsAre(base::Bucket(/*sample=*/1, /*expected_count=*/1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadOutcome"),
+ ElementsAre(base::Bucket(static_cast<int>(DownloadOutcome::SUCCEEDED),
+ /*expected_count=*/1)));
+}
+
+TEST_F(FaviconHandlerTest, TestRecordDownloadAttemptsFinishedByCache) {
+ const GURL kIconURL1024x1024("http://www.google.com/a-404-ing-icon");
+ base::HistogramTester histogram_tester;
+ favicon_service_.fake()->Store(
+ GURL("http://so.de"), kIconURL64x64,
+ CreateRawBitmapResult(kIconURL64x64, FAVICON, /*expired=*/false, 64));
+
+ RunHandlerWithCandidates(
+ FaviconDriverObserver::NON_TOUCH_LARGEST,
+ {FaviconURL(kIconURL1024x1024, FAVICON, {gfx::Size(1024, 1024)}),
+ FaviconURL(kIconURL12x12, FAVICON, {gfx::Size(12, 12)}),
+ FaviconURL(kIconURL64x64, FAVICON, {gfx::Size(64, 64)})});
+
+ // Should try only the first (receive 404) and get second icon from cache.
+ EXPECT_THAT(delegate_.downloads(), ElementsAre(kIconURL1024x1024));
+
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.LargeIcons"),
+ ElementsAre(base::Bucket(/*sample=*/1, /*expected_count=*/1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.Favicons"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.TouchIcons"),
+ IsEmpty());
+}
+
+TEST_F(FaviconHandlerTest, TestRecordSingleDownloadAttemptForRefreshingIcons) {
+ base::HistogramTester histogram_tester;
+ favicon_service_.fake()->Store(
+ GURL("http://www.google.com/ps"), kIconURL16x16,
+ CreateRawBitmapResult(kIconURL16x16, FAVICON, /*expired=*/true));
+
+ RunHandlerWithSimpleFaviconCandidates({kIconURL16x16});
+
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadAttempts.Favicons"),
+ ElementsAre(base::Bucket(/*sample=*/1, /*expected_count=*/1)));
+}
+
+TEST_F(FaviconHandlerTest, TestRecordFailingDownloadAttempt) {
+ base::HistogramTester histogram_tester;
+ const GURL k404IconURL("http://www.google.com/404.png");
+
+ delegate_.fake_downloader().AddError(k404IconURL, 404);
+
+ EXPECT_CALL(favicon_service_, UnableToDownloadFavicon(k404IconURL));
+
+ RunHandlerWithSimpleFaviconCandidates({k404IconURL});
+
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadOutcome"),
+ ElementsAre(base::Bucket(static_cast<int>(DownloadOutcome::FAILED),
+ /*expected_count=*/1)));
+}
+
+TEST_F(FaviconHandlerTest, TestRecordSkippedDownloadForKnownFailingUrl) {
+ base::HistogramTester histogram_tester;
+ const GURL k404IconURL("http://www.google.com/404.png");
+
+ ON_CALL(favicon_service_, WasUnableToDownloadFavicon(k404IconURL))
+ .WillByDefault(Return(true));
+
+ RunHandlerWithSimpleFaviconCandidates({k404IconURL});
+
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Favicons.DownloadOutcome"),
+ ElementsAre(base::Bucket(static_cast<int>(DownloadOutcome::SKIPPED),
+ /*expected_count=*/1)));
}
} // namespace
diff --git a/chromium/components/favicon/core/favicon_service.h b/chromium/components/favicon/core/favicon_service.h
index 10a8174747e..8ac749f8419 100644
--- a/chromium/components/favicon/core/favicon_service.h
+++ b/chromium/components/favicon/core/favicon_service.h
@@ -189,6 +189,20 @@ class FaviconService : public KeyedService {
favicon_base::IconType icon_type,
const gfx::Image& image) = 0;
+ // Same as SetFavicons() with three differences:
+ // 1) It will be a no-op if there is an existing cached favicon for *any* type
+ // for |page_url|.
+ // 2) If |icon_url| is known to the database, |bitmaps| will be ignored (i.e.
+ // the icon won't be overwritten) but the mappings from |page_url| to
+ // |icon_url| will be stored (conditioned to point 1 above).
+ // 3) If |icon_url| is stored, it will be marked as expired.
+ // The callback will receive whether the write actually happened.
+ virtual void SetLastResortFavicons(const GURL& page_url,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const gfx::Image& image,
+ base::Callback<void(bool)> callback) = 0;
+
// Avoid repeated requests to download missing favicon.
virtual void UnableToDownloadFavicon(const GURL& icon_url) = 0;
virtual bool WasUnableToDownloadFavicon(const GURL& icon_url) const = 0;
diff --git a/chromium/components/favicon/core/favicon_service_impl.cc b/chromium/components/favicon/core/favicon_service_impl.cc
index a57c99e9ce2..98557b24766 100644
--- a/chromium/components/favicon/core/favicon_service_impl.cc
+++ b/chromium/components/favicon/core/favicon_service_impl.cc
@@ -36,6 +36,23 @@ std::vector<int> GetPixelSizesForFaviconScales(int size_in_dip) {
return sizes_in_pixel;
}
+std::vector<SkBitmap> ExtractSkBitmapsToStore(const gfx::Image& image) {
+ gfx::ImageSkia image_skia = image.AsImageSkia();
+ image_skia.EnsureRepsForSupportedScales();
+ const std::vector<gfx::ImageSkiaRep>& image_reps = image_skia.image_reps();
+ std::vector<SkBitmap> bitmaps;
+ const std::vector<float> favicon_scales = favicon_base::GetFaviconScales();
+ for (size_t i = 0; i < image_reps.size(); ++i) {
+ // Don't save if the scale isn't one of supported favicon scales.
+ if (std::find(favicon_scales.begin(), favicon_scales.end(),
+ image_reps[i].scale()) == favicon_scales.end()) {
+ continue;
+ }
+ bitmaps.push_back(image_reps[i].sk_bitmap());
+ }
+ return bitmaps;
+}
+
} // namespace
FaviconServiceImpl::FaviconServiceImpl(
@@ -215,20 +232,18 @@ void FaviconServiceImpl::SetFavicons(const GURL& page_url,
const GURL& icon_url,
favicon_base::IconType icon_type,
const gfx::Image& image) {
- gfx::ImageSkia image_skia = image.AsImageSkia();
- image_skia.EnsureRepsForSupportedScales();
- const std::vector<gfx::ImageSkiaRep>& image_reps = image_skia.image_reps();
- std::vector<SkBitmap> bitmaps;
- const std::vector<float> favicon_scales = favicon_base::GetFaviconScales();
- for (size_t i = 0; i < image_reps.size(); ++i) {
- // Don't save if the scale isn't one of supported favicon scales.
- if (std::find(favicon_scales.begin(), favicon_scales.end(),
- image_reps[i].scale()) == favicon_scales.end()) {
- continue;
- }
- bitmaps.push_back(image_reps[i].sk_bitmap());
- }
- history_service_->SetFavicons(page_url, icon_type, icon_url, bitmaps);
+ history_service_->SetFavicons(page_url, icon_type, icon_url,
+ ExtractSkBitmapsToStore(image));
+}
+
+void FaviconServiceImpl::SetLastResortFavicons(
+ const GURL& page_url,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const gfx::Image& image,
+ base::Callback<void(bool)> callback) {
+ history_service_->SetLastResortFavicons(
+ page_url, icon_type, icon_url, ExtractSkBitmapsToStore(image), callback);
}
void FaviconServiceImpl::UnableToDownloadFavicon(const GURL& icon_url) {
diff --git a/chromium/components/favicon/core/favicon_service_impl.h b/chromium/components/favicon/core/favicon_service_impl.h
index ea030b260f1..d7e5c308823 100644
--- a/chromium/components/favicon/core/favicon_service_impl.h
+++ b/chromium/components/favicon/core/favicon_service_impl.h
@@ -102,6 +102,11 @@ class FaviconServiceImpl : public FaviconService {
const GURL& icon_url,
favicon_base::IconType icon_type,
const gfx::Image& image) override;
+ void SetLastResortFavicons(const GURL& page_url,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const gfx::Image& image,
+ base::Callback<void(bool)> callback) override;
void UnableToDownloadFavicon(const GURL& icon_url) override;
bool WasUnableToDownloadFavicon(const GURL& icon_url) const override;
void ClearUnableToDownloadFavicons() override;
diff --git a/chromium/components/favicon/core/large_icon_service.cc b/chromium/components/favicon/core/large_icon_service.cc
index fa42fe4d8f5..bf94e5b38ea 100644
--- a/chromium/components/favicon/core/large_icon_service.cc
+++ b/chromium/components/favicon/core/large_icon_service.cc
@@ -7,28 +7,149 @@
#include <memory>
#include "base/bind.h"
+#include "base/feature_list.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/stringprintf.h"
#include "base/task_runner.h"
#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/favicon/core/favicon_service.h"
#include "components/favicon_base/fallback_icon_style.h"
#include "components/favicon_base/favicon_types.h"
+#include "components/favicon_base/favicon_util.h"
+#include "components/image_fetcher/core/request_metadata.h"
#include "skia/ext/image_operations.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/geometry/size.h"
+#include "url/url_canon.h"
+namespace favicon {
namespace {
+// This feature is only used for accessing field trial parameters, not for
+// switching on/off the code.
+const base::Feature kLargeIconServiceFetchingFeature{
+ "LargeIconServiceFetching", base::FEATURE_ENABLED_BY_DEFAULT};
+
+const char kGoogleServerV2RequestFormat[] =
+ "https://t0.gstatic.com/faviconV2?"
+ "client=chrome&drop_404_icon=true&size=32&min_size=%d&max_size=64&"
+ "fallback_opts=TYPE,SIZE,URL&url=%s";
+const char kGoogleServerV2RequestFormatParam[] = "request_format";
+
+GURL TrimPageUrlForGoogleServer(const GURL& page_url) {
+ if (!page_url.SchemeIsHTTPOrHTTPS() || page_url.HostIsIPAddress())
+ return GURL();
+
+ url::Replacements<char> replacements;
+ replacements.ClearUsername();
+ replacements.ClearPassword();
+ replacements.ClearQuery();
+ replacements.ClearRef();
+ return page_url.ReplaceComponents(replacements);
+}
+
+GURL GetRequestUrlForGoogleServerV2(const GURL& page_url,
+ int min_source_size_in_pixel) {
+ std::string url_format = base::GetFieldTrialParamValueByFeature(
+ kLargeIconServiceFetchingFeature, kGoogleServerV2RequestFormatParam);
+
+ return GURL(base::StringPrintf(
+ url_format.empty() ? kGoogleServerV2RequestFormat : url_format.c_str(),
+ min_source_size_in_pixel, page_url.spec().c_str()));
+}
+
+bool IsDbResultAdequate(const favicon_base::FaviconRawBitmapResult& db_result,
+ int min_source_size) {
+ return db_result.is_valid() &&
+ db_result.pixel_size.width() == db_result.pixel_size.height() &&
+ db_result.pixel_size.width() >= min_source_size;
+}
+
+// Wraps the PNG data in |db_result| in a gfx::Image. If |desired_size| is not
+// 0, the image gets decoded and resized to |desired_size| (in px). Must run on
+// a background thread in production.
+gfx::Image ResizeLargeIconOnBackgroundThread(
+ const favicon_base::FaviconRawBitmapResult& db_result,
+ int desired_size) {
+ gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(
+ db_result.bitmap_data->front(), db_result.bitmap_data->size());
+
+ if (desired_size == 0 || db_result.pixel_size.width() == desired_size) {
+ return image;
+ }
+
+ SkBitmap resized = skia::ImageOperations::Resize(
+ image.AsBitmap(), skia::ImageOperations::RESIZE_LANCZOS3, desired_size,
+ desired_size);
+ return gfx::Image::CreateFrom1xBitmap(resized);
+}
+
+// Processes the |db_result| and writes the result into |raw_result| if
+// |raw_result| is not nullptr or to |bitmap|, otherwise. If |db_result| is not
+// valid or is smaller than |min_source_size|, the resulting fallback style is
+// written into |fallback_icon_style|.
+void ProcessIconOnBackgroundThread(
+ const favicon_base::FaviconRawBitmapResult& db_result,
+ int min_source_size,
+ int desired_size,
+ favicon_base::FaviconRawBitmapResult* raw_result,
+ SkBitmap* bitmap,
+ favicon_base::FallbackIconStyle* fallback_icon_style) {
+ if (IsDbResultAdequate(db_result, min_source_size)) {
+ gfx::Image image;
+ image = ResizeLargeIconOnBackgroundThread(db_result, desired_size);
+
+ if (!image.IsEmpty()) {
+ if (raw_result) {
+ *raw_result = db_result;
+ if (desired_size != 0)
+ raw_result->pixel_size = gfx::Size(desired_size, desired_size);
+ raw_result->bitmap_data = image.As1xPNGBytes();
+ }
+ if (bitmap) {
+ *bitmap = image.AsBitmap();
+ }
+ return;
+ }
+ }
+
+ if (!fallback_icon_style)
+ return;
+
+ *fallback_icon_style = favicon_base::FallbackIconStyle();
+ int fallback_icon_size = 0;
+ if (db_result.is_valid()) {
+ favicon_base::SetDominantColorAsBackground(db_result.bitmap_data,
+ fallback_icon_style);
+ // The size must be positive, we cap to 128 to avoid the sparse histogram
+ // to explode (having too many different values, server-side). Size 128
+ // already indicates that there is a problem in the code, 128 px _should_ be
+ // enough in all current UI surfaces.
+ fallback_icon_size = db_result.pixel_size.width();
+ DCHECK_GT(fallback_icon_size, 0);
+ fallback_icon_size = std::min(fallback_icon_size, 128);
+ }
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Favicons.LargeIconService.FallbackSize",
+ fallback_icon_size);
+}
+
// Processes the bitmap data returned from the FaviconService as part of a
// LargeIconService request.
class LargeIconWorker : public base::RefCountedThreadSafe<LargeIconWorker> {
public:
+ // Exactly one of the callbacks is expected to be non-null.
LargeIconWorker(int min_source_size_in_pixel,
int desired_size_in_pixel,
- favicon_base::LargeIconCallback callback,
+ favicon_base::LargeIconCallback raw_bitmap_callback,
+ favicon_base::LargeIconImageCallback image_callback,
scoped_refptr<base::TaskRunner> background_task_runner,
base::CancelableTaskTracker* tracker);
@@ -37,39 +158,27 @@ class LargeIconWorker : public base::RefCountedThreadSafe<LargeIconWorker> {
// ProcessIconOnBackgroundThread() so we do not perform complex image
// operations on the UI thread.
void OnIconLookupComplete(
- const favicon_base::FaviconRawBitmapResult& bitmap_result);
+ const favicon_base::FaviconRawBitmapResult& db_result);
private:
friend class base::RefCountedThreadSafe<LargeIconWorker>;
~LargeIconWorker();
- // Must run on a background thread in production.
- // Tries to resize |bitmap_result_| and pass the output to |callback_|. If
- // that does not work, computes the icon fallback style and uses it to
- // invoke |callback_|. This must be run on a background thread because image
- // resizing and dominant color extraction can be expensive.
- void ProcessIconOnBackgroundThread();
-
- // Must run on a background thread in production.
- // If |bitmap_result_| is square and large enough (>= |min_source_in_pixel_|),
- // resizes it to |desired_size_in_pixel_| (but if |desired_size_in_pixel_| is
- // 0 then don't resize). If successful, stores the resulting bitmap data
- // into |resized_bitmap_result| and returns true.
- bool ResizeLargeIconOnBackgroundThreadIfValid(
- favicon_base::FaviconRawBitmapResult* resized_bitmap_result);
-
// Must run on the owner (UI) thread in production.
// Invoked when ProcessIconOnBackgroundThread() is done.
void OnIconProcessingComplete();
int min_source_size_in_pixel_;
int desired_size_in_pixel_;
- favicon_base::LargeIconCallback callback_;
+ favicon_base::LargeIconCallback raw_bitmap_callback_;
+ favicon_base::LargeIconImageCallback image_callback_;
scoped_refptr<base::TaskRunner> background_task_runner_;
base::CancelableTaskTracker* tracker_;
- favicon_base::FaviconRawBitmapResult bitmap_result_;
- std::unique_ptr<favicon_base::LargeIconResult> result_;
+
+ favicon_base::FaviconRawBitmapResult raw_bitmap_result_;
+ SkBitmap bitmap_result_;
+ std::unique_ptr<favicon_base::FallbackIconStyle> fallback_icon_style_;
DISALLOW_COPY_AND_ASSIGN(LargeIconWorker);
};
@@ -77,98 +186,104 @@ class LargeIconWorker : public base::RefCountedThreadSafe<LargeIconWorker> {
LargeIconWorker::LargeIconWorker(
int min_source_size_in_pixel,
int desired_size_in_pixel,
- favicon_base::LargeIconCallback callback,
+ favicon_base::LargeIconCallback raw_bitmap_callback,
+ favicon_base::LargeIconImageCallback image_callback,
scoped_refptr<base::TaskRunner> background_task_runner,
base::CancelableTaskTracker* tracker)
: min_source_size_in_pixel_(min_source_size_in_pixel),
desired_size_in_pixel_(desired_size_in_pixel),
- callback_(callback),
+ raw_bitmap_callback_(raw_bitmap_callback),
+ image_callback_(image_callback),
background_task_runner_(background_task_runner),
- tracker_(tracker) {
-}
+ tracker_(tracker),
+ fallback_icon_style_(
+ base::MakeUnique<favicon_base::FallbackIconStyle>()) {}
LargeIconWorker::~LargeIconWorker() {
}
void LargeIconWorker::OnIconLookupComplete(
- const favicon_base::FaviconRawBitmapResult& bitmap_result) {
- bitmap_result_ = bitmap_result;
+ const favicon_base::FaviconRawBitmapResult& db_result) {
tracker_->PostTaskAndReply(
background_task_runner_.get(), FROM_HERE,
- base::Bind(&LargeIconWorker::ProcessIconOnBackgroundThread, this),
+ base::Bind(&ProcessIconOnBackgroundThread, db_result,
+ min_source_size_in_pixel_, desired_size_in_pixel_,
+ raw_bitmap_callback_ ? &raw_bitmap_result_ : nullptr,
+ image_callback_ ? &bitmap_result_ : nullptr,
+ fallback_icon_style_.get()),
base::Bind(&LargeIconWorker::OnIconProcessingComplete, this));
}
-void LargeIconWorker::ProcessIconOnBackgroundThread() {
- favicon_base::FaviconRawBitmapResult resized_bitmap_result;
- if (ResizeLargeIconOnBackgroundThreadIfValid(&resized_bitmap_result)) {
- result_.reset(
- new favicon_base::LargeIconResult(resized_bitmap_result));
- } else {
- // Failed to resize |bitmap_result_|, so compute fallback icon style.
- std::unique_ptr<favicon_base::FallbackIconStyle> fallback_icon_style(
- new favicon_base::FallbackIconStyle());
- if (bitmap_result_.is_valid()) {
- favicon_base::SetDominantColorAsBackground(
- bitmap_result_.bitmap_data, fallback_icon_style.get());
+void LargeIconWorker::OnIconProcessingComplete() {
+ // If |raw_bitmap_callback_| is provided, return the raw result.
+ if (raw_bitmap_callback_) {
+ if (raw_bitmap_result_.is_valid()) {
+ raw_bitmap_callback_.Run(
+ favicon_base::LargeIconResult(raw_bitmap_result_));
+ return;
}
- result_.reset(
- new favicon_base::LargeIconResult(fallback_icon_style.release()));
+ raw_bitmap_callback_.Run(
+ favicon_base::LargeIconResult(fallback_icon_style_.release()));
+ return;
}
-}
-
-bool LargeIconWorker::ResizeLargeIconOnBackgroundThreadIfValid(
- favicon_base::FaviconRawBitmapResult* resized_bitmap_result) {
- // Require bitmap to be valid and square.
- if (!bitmap_result_.is_valid() ||
- bitmap_result_.pixel_size.width() != bitmap_result_.pixel_size.height())
- return false;
- // Require bitmap to be large enough. It's square, so just check width.
- if (bitmap_result_.pixel_size.width() < min_source_size_in_pixel_)
- return false;
-
- *resized_bitmap_result = bitmap_result_;
-
- // Special case: Can use |bitmap_result_| as is.
- if (desired_size_in_pixel_ == 0 ||
- bitmap_result_.pixel_size.width() == desired_size_in_pixel_)
- return true;
+ if (!bitmap_result_.isNull()) {
+ image_callback_.Run(favicon_base::LargeIconImageResult(
+ gfx::Image::CreateFrom1xBitmap(bitmap_result_)));
+ return;
+ }
+ image_callback_.Run(
+ favicon_base::LargeIconImageResult(fallback_icon_style_.release()));
+}
- // Resize bitmap: decode PNG, resize, and re-encode PNG.
- SkBitmap decoded_bitmap;
- if (!gfx::PNGCodec::Decode(bitmap_result_.bitmap_data->front(),
- bitmap_result_.bitmap_data->size(), &decoded_bitmap))
- return false;
+void ReportDownloadedSize(int size) {
+ UMA_HISTOGRAM_COUNTS_1000("Favicons.LargeIconService.DownloadedSize", size);
+}
- SkBitmap resized_bitmap = skia::ImageOperations::Resize(
- decoded_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
- desired_size_in_pixel_, desired_size_in_pixel_);
+void OnFetchIconFromGoogleServerComplete(
+ FaviconService* favicon_service,
+ const GURL& page_url,
+ const base::Callback<void(bool success)>& callback,
+ const std::string& server_request_url,
+ const gfx::Image& image,
+ const image_fetcher::RequestMetadata& metadata) {
+ if (image.IsEmpty()) {
+ DLOG(WARNING) << "large icon server fetch empty " << server_request_url;
+ favicon_service->UnableToDownloadFavicon(GURL(server_request_url));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(callback, false));
+ ReportDownloadedSize(0);
+ return;
+ }
- std::vector<unsigned char> bitmap_data;
- if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_bitmap, false, &bitmap_data))
- return false;
+ ReportDownloadedSize(image.Width());
- resized_bitmap_result->pixel_size =
- gfx::Size(desired_size_in_pixel_, desired_size_in_pixel_);
- resized_bitmap_result->bitmap_data =
- base::RefCountedBytes::TakeVector(&bitmap_data);
- return true;
-}
+ // If given, use the original favicon URL from Content-Location http header.
+ // Otherwise, use the request URL as fallback.
+ std::string original_icon_url = metadata.content_location_header;
+ if (original_icon_url.empty()) {
+ original_icon_url = server_request_url;
+ }
-void LargeIconWorker::OnIconProcessingComplete() {
- callback_.Run(*result_);
+ // Write fetched icons to FaviconService's cache, but only if no icon was
+ // available (clients are encouraged to do this in advance, but meanwhile
+ // something else could've been written). By marking the icons initially
+ // expired (out-of-date), they will be refetched when we visit the original
+ // page any time in the future.
+ favicon_service->SetLastResortFavicons(page_url, GURL(original_icon_url),
+ favicon_base::IconType::TOUCH_ICON,
+ image, callback);
}
} // namespace
-namespace favicon {
-
LargeIconService::LargeIconService(
FaviconService* favicon_service,
- const scoped_refptr<base::TaskRunner>& background_task_runner)
+ const scoped_refptr<base::TaskRunner>& background_task_runner,
+ std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher)
: favicon_service_(favicon_service),
- background_task_runner_(background_task_runner) {
+ background_task_runner_(background_task_runner),
+ image_fetcher_(std::move(image_fetcher)) {
large_icon_types_.push_back(favicon_base::IconType::FAVICON);
large_icon_types_.push_back(favicon_base::IconType::TOUCH_ICON);
large_icon_types_.push_back(favicon_base::IconType::TOUCH_PRECOMPOSED_ICON);
@@ -178,18 +293,72 @@ LargeIconService::~LargeIconService() {
}
base::CancelableTaskTracker::TaskId
- LargeIconService::GetLargeIconOrFallbackStyle(
+LargeIconService::GetLargeIconOrFallbackStyle(
+ const GURL& page_url,
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel,
+ const favicon_base::LargeIconCallback& raw_bitmap_callback,
+ base::CancelableTaskTracker* tracker) {
+ return GetLargeIconOrFallbackStyleImpl(
+ page_url, min_source_size_in_pixel, desired_size_in_pixel,
+ raw_bitmap_callback, favicon_base::LargeIconImageCallback(), tracker);
+}
+
+base::CancelableTaskTracker::TaskId
+LargeIconService::GetLargeIconImageOrFallbackStyle(
+ const GURL& page_url,
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel,
+ const favicon_base::LargeIconImageCallback& image_callback,
+ base::CancelableTaskTracker* tracker) {
+ return GetLargeIconOrFallbackStyleImpl(
+ page_url, min_source_size_in_pixel, desired_size_in_pixel,
+ favicon_base::LargeIconCallback(), image_callback, tracker);
+}
+
+void LargeIconService::
+ GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
const GURL& page_url,
int min_source_size_in_pixel,
- int desired_size_in_pixel,
- const favicon_base::LargeIconCallback& callback,
- base::CancelableTaskTracker* tracker) {
+ const base::Callback<void(bool success)>& callback) {
+ DCHECK_LE(0, min_source_size_in_pixel);
+
+ const GURL trimmed_page_url = TrimPageUrlForGoogleServer(page_url);
+ const GURL server_request_url = GetRequestUrlForGoogleServerV2(
+ trimmed_page_url, min_source_size_in_pixel);
+
+ // Do not download if the URL is invalid after trimming, or there is a
+ // previous cache miss recorded for |server_request_url|.
+ if (!server_request_url.is_valid() || !trimmed_page_url.is_valid() ||
+ !image_fetcher_ ||
+ favicon_service_->WasUnableToDownloadFavicon(server_request_url)) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(callback, false));
+ return;
+ }
+
+ image_fetcher_->SetDataUseServiceName(
+ data_use_measurement::DataUseUserData::LARGE_ICON_SERVICE);
+ image_fetcher_->StartOrQueueNetworkRequest(
+ server_request_url.spec(), server_request_url,
+ base::Bind(&OnFetchIconFromGoogleServerComplete, favicon_service_,
+ page_url, callback));
+}
+
+base::CancelableTaskTracker::TaskId
+LargeIconService::GetLargeIconOrFallbackStyleImpl(
+ const GURL& page_url,
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel,
+ const favicon_base::LargeIconCallback& raw_bitmap_callback,
+ const favicon_base::LargeIconImageCallback& image_callback,
+ base::CancelableTaskTracker* tracker) {
DCHECK_LE(1, min_source_size_in_pixel);
DCHECK_LE(0, desired_size_in_pixel);
- scoped_refptr<LargeIconWorker> worker =
- new LargeIconWorker(min_source_size_in_pixel, desired_size_in_pixel,
- callback, background_task_runner_, tracker);
+ scoped_refptr<LargeIconWorker> worker = new LargeIconWorker(
+ min_source_size_in_pixel, desired_size_in_pixel, raw_bitmap_callback,
+ image_callback, background_task_runner_, tracker);
// TODO(beaudoin): For now this is just a wrapper around
// GetLargestRawFaviconForPageURL. Add the logic required to select the best
@@ -197,8 +366,7 @@ base::CancelableTaskTracker::TaskId
// a large icon is known but its bitmap is not available.
return favicon_service_->GetLargestRawFaviconForPageURL(
page_url, large_icon_types_, min_source_size_in_pixel,
- base::Bind(&LargeIconWorker::OnIconLookupComplete, worker),
- tracker);
+ base::Bind(&LargeIconWorker::OnIconLookupComplete, worker), tracker);
}
} // namespace favicon
diff --git a/chromium/components/favicon/core/large_icon_service.h b/chromium/components/favicon/core/large_icon_service.h
index 73a2698448c..7207e605ac3 100644
--- a/chromium/components/favicon/core/large_icon_service.h
+++ b/chromium/components/favicon/core/large_icon_service.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/task/cancelable_task_tracker.h"
#include "components/favicon_base/favicon_callback.h"
+#include "components/image_fetcher/core/image_fetcher.h"
#include "components/keyed_service/core/keyed_service.h"
class GURL;
@@ -18,6 +19,10 @@ namespace base {
class TaskRunner;
}
+namespace image_fetcher {
+class ImageFetcher;
+}
+
namespace favicon {
class FaviconService;
@@ -28,7 +33,8 @@ class LargeIconService : public KeyedService {
public:
LargeIconService(
FaviconService* favicon_service,
- const scoped_refptr<base::TaskRunner>& background_task_runner);
+ const scoped_refptr<base::TaskRunner>& background_task_runner,
+ std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher);
~LargeIconService() override;
// Requests the best large icon for the page at |page_url|.
@@ -42,14 +48,52 @@ class LargeIconService : public KeyedService {
// - Returns the default fallback icon style.
// For cases 2 and 3, this function returns the style of the fallback icon
// instead of rendering an icon so clients can render the icon themselves.
+ // TODO(jkrcal): Rename to GetLargeIconRawBitmapOrFallbackStyle.
base::CancelableTaskTracker::TaskId GetLargeIconOrFallbackStyle(
- const GURL& page_url,
- int min_source_size_in_pixel,
- int desired_size_in_pixel,
- const favicon_base::LargeIconCallback& callback,
- base::CancelableTaskTracker* tracker);
+ const GURL& page_url,
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel,
+ const favicon_base::LargeIconCallback& callback,
+ base::CancelableTaskTracker* tracker);
+
+ // Behaves the same as GetLargeIconOrFallbackStyle(), only returns the large
+ // icon (if available) decoded.
+ base::CancelableTaskTracker::TaskId GetLargeIconImageOrFallbackStyle(
+ const GURL& page_url,
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel,
+ const favicon_base::LargeIconImageCallback& callback,
+ base::CancelableTaskTracker* tracker);
+
+ // Fetches the best large icon for the page at |page_url| from a Google
+ // favicon server and stores the result in the FaviconService database
+ // (implemented in HistoryService). The write will be a no-op if the local
+ // favicon database contains an icon for |page_url|, so clients are
+ // encouraged to use GetLargeIconOrFallbackStyle() first.
+ //
+ // A minimum size |min_source_size_in_pixel| can be specified as a constraint.
+ //
+ // The callback is triggered when the operation finishes, where |success|
+ // tells whether the fetch actually managed to database a new icon in the
+ // FaviconService.
+ //
+ // WARNING: This function will share the |page_url| with a Google server. This
+ // Can be used only for urls that are not privacy sensitive or for users that
+ // sync their history with Google servers.
+ void GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
+ const GURL& page_url,
+ int min_source_size_in_pixel,
+ const base::Callback<void(bool success)>& callback);
private:
+ base::CancelableTaskTracker::TaskId GetLargeIconOrFallbackStyleImpl(
+ const GURL& page_url,
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel,
+ const favicon_base::LargeIconCallback& raw_bitmap_callback,
+ const favicon_base::LargeIconImageCallback& image_callback,
+ base::CancelableTaskTracker* tracker);
+
FaviconService* favicon_service_;
scoped_refptr<base::TaskRunner> background_task_runner_;
@@ -58,6 +102,8 @@ class LargeIconService : public KeyedService {
// request.
std::vector<int> large_icon_types_;
+ std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher_;
+
DISALLOW_COPY_AND_ASSIGN(LargeIconService);
};
diff --git a/chromium/components/favicon/core/large_icon_service_unittest.cc b/chromium/components/favicon/core/large_icon_service_unittest.cc
index 7e0b7dce22f..ef463077010 100644
--- a/chromium/components/favicon/core/large_icon_service_unittest.cc
+++ b/chromium/components/favicon/core/large_icon_service_unittest.cc
@@ -9,15 +9,20 @@
#include "base/bind.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted_memory.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/task/cancelable_task_tracker.h"
+#include "base/test/histogram_tester.h"
+#include "base/test/mock_callback.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/favicon/core/favicon_client.h"
#include "components/favicon/core/test/mock_favicon_service.h"
#include "components/favicon_base/fallback_icon_style.h"
#include "components/favicon_base/favicon_types.h"
+#include "components/image_fetcher/core/image_fetcher.h"
+#include "components/image_fetcher/core/request_metadata.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -25,19 +30,49 @@
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia.h"
#include "url/gurl.h"
namespace favicon {
namespace {
+using testing::IsEmpty;
+using testing::IsNull;
+using testing::Eq;
+using testing::NiceMock;
+using testing::Return;
+using testing::SaveArg;
using testing::_;
const char kDummyUrl[] = "http://www.example.com";
const char kDummyIconUrl[] = "http://www.example.com/touch_icon.png";
const SkColor kTestColor = SK_ColorRED;
-favicon_base::FaviconRawBitmapResult CreateTestBitmap(
- int w, int h, SkColor color) {
+ACTION_P(PostFetchReply, p0) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(arg2, arg0, p0, image_fetcher::RequestMetadata()));
+}
+
+ACTION_P2(PostFetchReplyWithMetadata, p0, p1) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(arg2, arg0, p0, p1));
+}
+
+ACTION_P(PostBoolReply, p0) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(arg4, p0));
+}
+
+SkBitmap CreateTestSkBitmap(int w, int h, SkColor color) {
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(w, h);
+ bitmap.eraseColor(color);
+ return bitmap;
+}
+
+favicon_base::FaviconRawBitmapResult CreateTestBitmapResult(int w,
+ int h,
+ SkColor color) {
favicon_base::FaviconRawBitmapResult result;
result.expired = false;
@@ -56,172 +91,362 @@ favicon_base::FaviconRawBitmapResult CreateTestBitmap(
return result;
}
+bool HasBackgroundColor(
+ const favicon_base::FallbackIconStyle& fallback_icon_style,
+ SkColor color) {
+ return !fallback_icon_style.is_default_background_color &&
+ fallback_icon_style.background_color == color;
+}
+
+class MockImageFetcher : public image_fetcher::ImageFetcher {
+ public:
+ MOCK_METHOD1(SetImageFetcherDelegate,
+ void(image_fetcher::ImageFetcherDelegate* delegate));
+ MOCK_METHOD1(SetDataUseServiceName,
+ void(image_fetcher::ImageFetcher::DataUseServiceName name));
+ MOCK_METHOD1(SetImageDownloadLimit,
+ void(base::Optional<int64_t> max_download_bytes));
+ MOCK_METHOD1(SetDesiredImageFrameSize, void(const gfx::Size& size));
+ MOCK_METHOD3(StartOrQueueNetworkRequest,
+ void(const std::string&,
+ const GURL&,
+ const ImageFetcherCallback&));
+ MOCK_METHOD0(GetImageDecoder, image_fetcher::ImageDecoder*());
+};
+
class LargeIconServiceTest : public testing::Test {
public:
LargeIconServiceTest()
- : large_icon_service_(&mock_favicon_service_,
- base::ThreadTaskRunnerHandle::Get()),
- is_callback_invoked_(false) {}
+ : mock_image_fetcher_(new NiceMock<MockImageFetcher>()),
+ large_icon_service_(&mock_favicon_service_,
+ base::ThreadTaskRunnerHandle::Get(),
+ base::WrapUnique(mock_image_fetcher_)) {}
- ~LargeIconServiceTest() override {
- }
+ ~LargeIconServiceTest() override {}
+
+ protected:
+ base::MessageLoopForIO loop_;
+
+ NiceMock<MockImageFetcher>* mock_image_fetcher_;
+ testing::NiceMock<MockFaviconService> mock_favicon_service_;
+ LargeIconService large_icon_service_;
+ base::HistogramTester histogram_tester_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LargeIconServiceTest);
+};
+
+TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServer) {
+ const GURL kExpectedServerUrl(
+ "https://t0.gstatic.com/faviconV2?client=chrome&drop_404_icon=true"
+ "&size=32&min_size=42&max_size=64&fallback_opts=TYPE,SIZE,URL"
+ "&url=http://www.example.com/");
+
+ EXPECT_CALL(mock_favicon_service_, UnableToDownloadFavicon(_)).Times(0);
+
+ base::MockCallback<base::Callback<void(bool success)>> callback;
+ EXPECT_CALL(*mock_image_fetcher_,
+ StartOrQueueNetworkRequest(_, kExpectedServerUrl, _))
+ .WillOnce(PostFetchReply(gfx::Image::CreateFrom1xBitmap(
+ CreateTestSkBitmap(64, 64, kTestColor))));
+ EXPECT_CALL(mock_favicon_service_,
+ SetLastResortFavicons(GURL(kDummyUrl), kExpectedServerUrl,
+ favicon_base::IconType::TOUCH_ICON, _, _))
+ .WillOnce(PostBoolReply(true));
+
+ large_icon_service_
+ .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
+ GURL(kDummyUrl), /*min_source_size_in_pixel=*/42, callback.Get());
+
+ EXPECT_CALL(callback, Run(true));
+ base::RunLoop().RunUntilIdle();
+ histogram_tester_.ExpectUniqueSample(
+ "Favicons.LargeIconService.DownloadedSize", 64, /*expected_count=*/1);
+}
+
+TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServerWithOriginalUrl) {
+ const GURL kExpectedServerUrl(
+ "https://t0.gstatic.com/faviconV2?client=chrome&drop_404_icon=true"
+ "&size=32&min_size=42&max_size=64&fallback_opts=TYPE,SIZE,URL"
+ "&url=http://www.example.com/");
+ const GURL kExpectedOriginalUrl("http://www.example.com/favicon.png");
+
+ image_fetcher::RequestMetadata expected_metadata;
+ expected_metadata.content_location_header = kExpectedOriginalUrl.spec();
+ EXPECT_CALL(*mock_image_fetcher_,
+ StartOrQueueNetworkRequest(_, kExpectedServerUrl, _))
+ .WillOnce(PostFetchReplyWithMetadata(
+ gfx::Image::CreateFrom1xBitmap(
+ CreateTestSkBitmap(64, 64, kTestColor)),
+ expected_metadata));
+ EXPECT_CALL(mock_favicon_service_,
+ SetLastResortFavicons(GURL(kDummyUrl), kExpectedOriginalUrl,
+ favicon_base::IconType::TOUCH_ICON, _, _))
+ .WillOnce(PostBoolReply(true));
+
+ base::MockCallback<base::Callback<void(bool success)>> callback;
+ large_icon_service_
+ .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
+ GURL(kDummyUrl), /*min_source_size_in_pixel=*/42, callback.Get());
+
+ EXPECT_CALL(callback, Run(true));
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(LargeIconServiceTest, ShouldTrimQueryParametersForGoogleServer) {
+ const GURL kDummyUrlWithQuery("http://www.example.com?foo=1");
+ const GURL kExpectedServerUrl(
+ "https://t0.gstatic.com/faviconV2?client=chrome&drop_404_icon=true"
+ "&size=32&min_size=42&max_size=64&fallback_opts=TYPE,SIZE,URL"
+ "&url=http://www.example.com/");
+
+ EXPECT_CALL(*mock_image_fetcher_,
+ StartOrQueueNetworkRequest(_, kExpectedServerUrl, _))
+ .WillOnce(PostFetchReply(gfx::Image::CreateFrom1xBitmap(
+ CreateTestSkBitmap(64, 64, kTestColor))));
+ // Verify that the non-trimmed page URL is used when writing to the database.
+ EXPECT_CALL(mock_favicon_service_,
+ SetLastResortFavicons(_, kExpectedServerUrl, _, _, _));
+
+ large_icon_service_
+ .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
+ GURL(kDummyUrlWithQuery), /*min_source_size_in_pixel=*/42,
+ base::Callback<void(bool success)>());
+
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(LargeIconServiceTest, ShouldNotQueryGoogleServerIfInvalidScheme) {
+ const GURL kDummyFtpUrl("ftp://www.example.com");
+
+ EXPECT_CALL(*mock_image_fetcher_, StartOrQueueNetworkRequest(_, _, _))
+ .Times(0);
- void ResultCallback(const favicon_base::LargeIconResult& result) {
- is_callback_invoked_ = true;
+ base::MockCallback<base::Callback<void(bool success)>> callback;
- // Checking presence and absence of results.
- EXPECT_EQ(expected_bitmap_.is_valid(), result.bitmap.is_valid());
- EXPECT_EQ(expected_fallback_icon_style_ != nullptr,
- result.fallback_icon_style != nullptr);
+ large_icon_service_
+ .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
+ GURL(kDummyFtpUrl), /*min_source_size_in_pixel=*/42, callback.Get());
- if (expected_bitmap_.is_valid()) {
- EXPECT_EQ(expected_bitmap_.pixel_size, result.bitmap.pixel_size);
- // Not actually checking bitmap content.
+ EXPECT_CALL(callback, Run(false));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_THAT(histogram_tester_.GetAllSamples(
+ "Favicons.LargeIconService.DownloadedSize"),
+ IsEmpty());
+}
+
+TEST_F(LargeIconServiceTest, ShouldReportUnavailableIfFetchFromServerFails) {
+ const GURL kDummyUrlWithQuery("http://www.example.com?foo=1");
+ const GURL kExpectedServerUrl(
+ "https://t0.gstatic.com/faviconV2?client=chrome&drop_404_icon=true"
+ "&size=32&min_size=42&max_size=64&fallback_opts=TYPE,SIZE,URL"
+ "&url=http://www.example.com/");
+
+ EXPECT_CALL(mock_favicon_service_, SetLastResortFavicons(_, _, _, _, _))
+ .Times(0);
+
+ base::MockCallback<base::Callback<void(bool success)>> callback;
+ EXPECT_CALL(*mock_image_fetcher_,
+ StartOrQueueNetworkRequest(_, kExpectedServerUrl, _))
+ .WillOnce(PostFetchReply(gfx::Image()));
+ EXPECT_CALL(mock_favicon_service_,
+ UnableToDownloadFavicon(kExpectedServerUrl));
+
+ large_icon_service_
+ .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
+ kDummyUrlWithQuery, /*min_source_size_in_pixel=*/42, callback.Get());
+
+ EXPECT_CALL(callback, Run(false));
+ base::RunLoop().RunUntilIdle();
+ // Verify that download failure gets recorded.
+ histogram_tester_.ExpectUniqueSample(
+ "Favicons.LargeIconService.DownloadedSize", 0, /*expected_count=*/1);
+}
+
+TEST_F(LargeIconServiceTest, ShouldNotGetFromGoogleServerIfUnavailable) {
+ ON_CALL(
+ mock_favicon_service_,
+ WasUnableToDownloadFavicon(GURL(
+ "https://t0.gstatic.com/faviconV2?client=chrome&drop_404_icon=true"
+ "&size=32&min_size=42&max_size=64&fallback_opts=TYPE,SIZE,URL"
+ "&url=http://www.example.com/")))
+ .WillByDefault(Return(true));
+
+ EXPECT_CALL(mock_favicon_service_, UnableToDownloadFavicon(_)).Times(0);
+ EXPECT_CALL(*mock_image_fetcher_, StartOrQueueNetworkRequest(_, _, _))
+ .Times(0);
+ EXPECT_CALL(mock_favicon_service_, SetLastResortFavicons(_, _, _, _, _))
+ .Times(0);
+
+ base::MockCallback<base::Callback<void(bool success)>> callback;
+ large_icon_service_
+ .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
+ GURL(kDummyUrl), /*min_source_size_in_pixel=*/42, callback.Get());
+
+ EXPECT_CALL(callback, Run(false));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_THAT(histogram_tester_.GetAllSamples(
+ "Favicons.LargeIconService.DownloadedSize"),
+ IsEmpty());
+}
+
+class LargeIconServiceGetterTest : public LargeIconServiceTest,
+ public ::testing::WithParamInterface<bool> {
+ public:
+ LargeIconServiceGetterTest() : LargeIconServiceTest() {}
+ ~LargeIconServiceGetterTest() override {}
+
+ void GetLargeIconOrFallbackStyleAndWaitForCallback(
+ const GURL& page_url,
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel) {
+ // Switch over testing two analogous functions based on the bool param.
+ if (GetParam()) {
+ large_icon_service_.GetLargeIconOrFallbackStyle(
+ page_url, min_source_size_in_pixel, desired_size_in_pixel,
+ base::Bind(&LargeIconServiceGetterTest::RawBitmapResultCallback,
+ base::Unretained(this)),
+ &cancelable_task_tracker_);
+ } else {
+ large_icon_service_.GetLargeIconImageOrFallbackStyle(
+ page_url, min_source_size_in_pixel, desired_size_in_pixel,
+ base::Bind(&LargeIconServiceGetterTest::ImageResultCallback,
+ base::Unretained(this)),
+ &cancelable_task_tracker_);
+ }
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void RawBitmapResultCallback(const favicon_base::LargeIconResult& result) {
+ if (result.bitmap.is_valid()) {
+ returned_bitmap_size_ =
+ base::MakeUnique<gfx::Size>(result.bitmap.pixel_size);
+ }
+ StoreFallbackStyle(result.fallback_icon_style.get());
+ }
+
+ void ImageResultCallback(const favicon_base::LargeIconImageResult& result) {
+ if (!result.image.IsEmpty()) {
+ returned_bitmap_size_ =
+ base::MakeUnique<gfx::Size>(result.image.ToImageSkia()->size());
}
- if (expected_fallback_icon_style_.get()) {
- EXPECT_EQ(*expected_fallback_icon_style_,
- *result.fallback_icon_style);
+ StoreFallbackStyle(result.fallback_icon_style.get());
+ }
+
+ void StoreFallbackStyle(
+ const favicon_base::FallbackIconStyle* fallback_style) {
+ if (fallback_style) {
+ returned_fallback_style_ =
+ base::MakeUnique<favicon_base::FallbackIconStyle>(*fallback_style);
}
}
void InjectMockResult(
const GURL& page_url,
const favicon_base::FaviconRawBitmapResult& mock_result) {
- EXPECT_CALL(mock_favicon_service_,
- GetLargestRawFaviconForPageURL(page_url, _, _, _, _))
- .WillOnce(PostReply<5>(mock_result));
+ ON_CALL(mock_favicon_service_,
+ GetLargestRawFaviconForPageURL(page_url, _, _, _, _))
+ .WillByDefault(PostReply<5>(mock_result));
}
protected:
- base::MessageLoopForIO loop_;
-
- testing::StrictMock<MockFaviconService> mock_favicon_service_;
- LargeIconService large_icon_service_;
base::CancelableTaskTracker cancelable_task_tracker_;
- favicon_base::FaviconRawBitmapResult expected_bitmap_;
- std::unique_ptr<favicon_base::FallbackIconStyle>
- expected_fallback_icon_style_;
-
- bool is_callback_invoked_;
+ std::unique_ptr<favicon_base::FallbackIconStyle> returned_fallback_style_;
+ std::unique_ptr<gfx::Size> returned_bitmap_size_;
private:
- DISALLOW_COPY_AND_ASSIGN(LargeIconServiceTest);
+ DISALLOW_COPY_AND_ASSIGN(LargeIconServiceGetterTest);
};
-TEST_F(LargeIconServiceTest, SameSize) {
- InjectMockResult(GURL(kDummyUrl), CreateTestBitmap(24, 24, kTestColor));
- expected_bitmap_ = CreateTestBitmap(24, 24, kTestColor);
- large_icon_service_.GetLargeIconOrFallbackStyle(
+TEST_P(LargeIconServiceGetterTest, SameSize) {
+ InjectMockResult(GURL(kDummyUrl), CreateTestBitmapResult(24, 24, kTestColor));
+ GetLargeIconOrFallbackStyleAndWaitForCallback(
GURL(kDummyUrl),
- 24, // |min_source_size_in_pixel|
- 24, // |desired_size_in_pixel|
- base::Bind(&LargeIconServiceTest::ResultCallback, base::Unretained(this)),
- &cancelable_task_tracker_);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(is_callback_invoked_);
+ 24, // |min_source_size_in_pixel|
+ 24); // |desired_size_in_pixel|
+ EXPECT_EQ(gfx::Size(24, 24), *returned_bitmap_size_);
+ EXPECT_EQ(nullptr, returned_fallback_style_);
}
-TEST_F(LargeIconServiceTest, ScaleDown) {
- InjectMockResult(GURL(kDummyUrl), CreateTestBitmap(32, 32, kTestColor));
- expected_bitmap_ = CreateTestBitmap(24, 24, kTestColor);
- large_icon_service_.GetLargeIconOrFallbackStyle(
- GURL(kDummyUrl), 24, 24,
- base::Bind(&LargeIconServiceTest::ResultCallback, base::Unretained(this)),
- &cancelable_task_tracker_);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(is_callback_invoked_);
+TEST_P(LargeIconServiceGetterTest, ScaleDown) {
+ InjectMockResult(GURL(kDummyUrl), CreateTestBitmapResult(32, 32, kTestColor));
+ GetLargeIconOrFallbackStyleAndWaitForCallback(GURL(kDummyUrl), 24, 24);
+ EXPECT_EQ(gfx::Size(24, 24), *returned_bitmap_size_);
+ EXPECT_EQ(nullptr, returned_fallback_style_);
}
-TEST_F(LargeIconServiceTest, ScaleUp) {
- InjectMockResult(GURL(kDummyUrl), CreateTestBitmap(16, 16, kTestColor));
- expected_bitmap_ = CreateTestBitmap(24, 24, kTestColor);
- large_icon_service_.GetLargeIconOrFallbackStyle(
+TEST_P(LargeIconServiceGetterTest, ScaleUp) {
+ InjectMockResult(GURL(kDummyUrl), CreateTestBitmapResult(16, 16, kTestColor));
+ GetLargeIconOrFallbackStyleAndWaitForCallback(
GURL(kDummyUrl),
14, // Lowered requirement so stored bitmap is admitted.
- 24,
- base::Bind(&LargeIconServiceTest::ResultCallback, base::Unretained(this)),
- &cancelable_task_tracker_);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(is_callback_invoked_);
+ 24);
+ EXPECT_EQ(gfx::Size(24, 24), *returned_bitmap_size_);
+ EXPECT_EQ(nullptr, returned_fallback_style_);
}
// |desired_size_in_pixel| == 0 means retrieve original image without scaling.
-TEST_F(LargeIconServiceTest, NoScale) {
- InjectMockResult(GURL(kDummyUrl), CreateTestBitmap(24, 24, kTestColor));
- expected_bitmap_ = CreateTestBitmap(24, 24, kTestColor);
- large_icon_service_.GetLargeIconOrFallbackStyle(
- GURL(kDummyUrl), 16, 0,
- base::Bind(&LargeIconServiceTest::ResultCallback, base::Unretained(this)),
- &cancelable_task_tracker_);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(is_callback_invoked_);
-}
-
-TEST_F(LargeIconServiceTest, FallbackSinceIconTooSmall) {
- InjectMockResult(GURL(kDummyUrl), CreateTestBitmap(16, 16, kTestColor));
- expected_fallback_icon_style_.reset(new favicon_base::FallbackIconStyle);
- expected_fallback_icon_style_->background_color = kTestColor;
- expected_fallback_icon_style_->is_default_background_color = false;
- large_icon_service_.GetLargeIconOrFallbackStyle(
- GURL(kDummyUrl), 24, 24,
- base::Bind(&LargeIconServiceTest::ResultCallback, base::Unretained(this)),
- &cancelable_task_tracker_);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(is_callback_invoked_);
-}
-
-TEST_F(LargeIconServiceTest, FallbackSinceIconNotSquare) {
- InjectMockResult(GURL(kDummyUrl), CreateTestBitmap(24, 32, kTestColor));
- expected_fallback_icon_style_.reset(new favicon_base::FallbackIconStyle);
- expected_fallback_icon_style_->background_color = kTestColor;
- expected_fallback_icon_style_->is_default_background_color = false;
- large_icon_service_.GetLargeIconOrFallbackStyle(
- GURL(kDummyUrl), 24, 24,
- base::Bind(&LargeIconServiceTest::ResultCallback, base::Unretained(this)),
- &cancelable_task_tracker_);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(is_callback_invoked_);
+TEST_P(LargeIconServiceGetterTest, NoScale) {
+ InjectMockResult(GURL(kDummyUrl), CreateTestBitmapResult(24, 24, kTestColor));
+ GetLargeIconOrFallbackStyleAndWaitForCallback(GURL(kDummyUrl), 16, 0);
+ EXPECT_EQ(gfx::Size(24, 24), *returned_bitmap_size_);
+ EXPECT_EQ(nullptr, returned_fallback_style_);
}
-TEST_F(LargeIconServiceTest, FallbackSinceIconMissing) {
+TEST_P(LargeIconServiceGetterTest, FallbackSinceIconTooSmall) {
+ InjectMockResult(GURL(kDummyUrl), CreateTestBitmapResult(16, 16, kTestColor));
+ GetLargeIconOrFallbackStyleAndWaitForCallback(GURL(kDummyUrl), 24, 24);
+ EXPECT_EQ(nullptr, returned_bitmap_size_);
+ EXPECT_TRUE(HasBackgroundColor(*returned_fallback_style_, kTestColor));
+ histogram_tester_.ExpectUniqueSample("Favicons.LargeIconService.FallbackSize",
+ 16, /*expected_count=*/1);
+}
+
+TEST_P(LargeIconServiceGetterTest, FallbackSinceIconNotSquare) {
+ InjectMockResult(GURL(kDummyUrl), CreateTestBitmapResult(24, 32, kTestColor));
+ GetLargeIconOrFallbackStyleAndWaitForCallback(GURL(kDummyUrl), 24, 24);
+ EXPECT_EQ(nullptr, returned_bitmap_size_);
+ EXPECT_TRUE(HasBackgroundColor(*returned_fallback_style_, kTestColor));
+ histogram_tester_.ExpectUniqueSample("Favicons.LargeIconService.FallbackSize",
+ 24, /*expected_count=*/1);
+}
+
+TEST_P(LargeIconServiceGetterTest, FallbackSinceIconMissing) {
InjectMockResult(GURL(kDummyUrl), favicon_base::FaviconRawBitmapResult());
- // Expect default fallback style, including background.
- expected_fallback_icon_style_.reset(new favicon_base::FallbackIconStyle);
- large_icon_service_.GetLargeIconOrFallbackStyle(
- GURL(kDummyUrl), 24, 24,
- base::Bind(&LargeIconServiceTest::ResultCallback, base::Unretained(this)),
- &cancelable_task_tracker_);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(is_callback_invoked_);
+ GetLargeIconOrFallbackStyleAndWaitForCallback(GURL(kDummyUrl), 24, 24);
+ EXPECT_EQ(nullptr, returned_bitmap_size_);
+ EXPECT_TRUE(returned_fallback_style_->is_default_background_color);
+ histogram_tester_.ExpectUniqueSample("Favicons.LargeIconService.FallbackSize",
+ 0, /*expected_count=*/1);
}
-TEST_F(LargeIconServiceTest, FallbackSinceIconMissingNoScale) {
+TEST_P(LargeIconServiceGetterTest, FallbackSinceIconMissingNoScale) {
InjectMockResult(GURL(kDummyUrl), favicon_base::FaviconRawBitmapResult());
- // Expect default fallback style, including background.
- expected_fallback_icon_style_.reset(new favicon_base::FallbackIconStyle);
- large_icon_service_.GetLargeIconOrFallbackStyle(
- GURL(kDummyUrl), 24, 0,
- base::Bind(&LargeIconServiceTest::ResultCallback, base::Unretained(this)),
- &cancelable_task_tracker_);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(is_callback_invoked_);
+ GetLargeIconOrFallbackStyleAndWaitForCallback(GURL(kDummyUrl), 24, 0);
+ EXPECT_EQ(nullptr, returned_bitmap_size_);
+ EXPECT_TRUE(returned_fallback_style_->is_default_background_color);
+ histogram_tester_.ExpectUniqueSample("Favicons.LargeIconService.FallbackSize",
+ 0, /*expected_count=*/1);
}
// Oddball case where we demand a high resolution icon to scale down. Generates
// fallback even though an icon with the final size is available.
-TEST_F(LargeIconServiceTest, FallbackSinceTooPicky) {
- InjectMockResult(GURL(kDummyUrl), CreateTestBitmap(24, 24, kTestColor));
- expected_fallback_icon_style_.reset(new favicon_base::FallbackIconStyle);
- expected_fallback_icon_style_->background_color = kTestColor;
- expected_fallback_icon_style_->is_default_background_color = false;
- large_icon_service_.GetLargeIconOrFallbackStyle(
- GURL(kDummyUrl), 32, 24,
- base::Bind(&LargeIconServiceTest::ResultCallback, base::Unretained(this)),
- &cancelable_task_tracker_);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(is_callback_invoked_);
+TEST_P(LargeIconServiceGetterTest, FallbackSinceTooPicky) {
+ InjectMockResult(GURL(kDummyUrl), CreateTestBitmapResult(24, 24, kTestColor));
+ GetLargeIconOrFallbackStyleAndWaitForCallback(GURL(kDummyUrl), 32, 24);
+ EXPECT_EQ(nullptr, returned_bitmap_size_);
+ EXPECT_TRUE(HasBackgroundColor(*returned_fallback_style_, kTestColor));
+ histogram_tester_.ExpectUniqueSample("Favicons.LargeIconService.FallbackSize",
+ 24, /*expected_count=*/1);
}
+// Every test will appear with suffix /0 (param false) and /1 (param true), e.g.
+// LargeIconServiceGetterTest.FallbackSinceTooPicky/0: get image.
+// LargeIconServiceGetterTest.FallbackSinceTooPicky/1: get raw bitmap.
+INSTANTIATE_TEST_CASE_P(, // Empty instatiation name.
+ LargeIconServiceGetterTest,
+ ::testing::Values(false, true));
+
} // namespace
} // namespace favicon
diff --git a/chromium/components/favicon/ios/web_favicon_driver.mm b/chromium/components/favicon/ios/web_favicon_driver.mm
index 9e1b7e3dc00..500a5f4c435 100644
--- a/chromium/components/favicon/ios/web_favicon_driver.mm
+++ b/chromium/components/favicon/ios/web_favicon_driver.mm
@@ -70,11 +70,6 @@ GURL WebFaviconDriver::GetActiveURL() {
int WebFaviconDriver::DownloadImage(const GURL& url,
int max_image_size,
ImageDownloadCallback callback) {
- if (WasUnableToDownloadFavicon(url)) {
- DVLOG(1) << "Skip Failed FavIcon: " << url;
- return 0;
- }
-
static int downloaded_image_count = 0;
int local_download_id = ++downloaded_image_count;
@@ -82,8 +77,8 @@ int WebFaviconDriver::DownloadImage(const GURL& url,
image_fetcher::IOSImageDataFetcherCallback local_callback =
^(NSData* data, const image_fetcher::RequestMetadata& metadata) {
- if (metadata.response_code ==
- image_fetcher::ImageDataFetcher::RESPONSE_CODE_INVALID)
+ if (metadata.http_response_code ==
+ image_fetcher::RequestMetadata::RESPONSE_CODE_INVALID)
return;
std::vector<SkBitmap> frames;
@@ -94,7 +89,7 @@ int WebFaviconDriver::DownloadImage(const GURL& url,
sizes.push_back(gfx::Size(frame.width(), frame.height()));
}
}
- callback.Run(local_download_id, metadata.response_code, local_url,
+ callback.Run(local_download_id, metadata.http_response_code, local_url,
frames, sizes);
};
image_fetcher_.FetchImageDataWebpDecoded(url, local_callback);
diff --git a/chromium/components/favicon_base/favicon_callback.h b/chromium/components/favicon_base/favicon_callback.h
index 96029f1c409..28ad5b3206d 100644
--- a/chromium/components/favicon_base/favicon_callback.h
+++ b/chromium/components/favicon_base/favicon_callback.h
@@ -14,6 +14,7 @@ namespace favicon_base {
struct FaviconRawBitmapResult;
struct FaviconImageResult;
struct LargeIconResult;
+struct LargeIconImageResult;
// Callback for functions that can be used to return a |gfx::Image| and the
// |GURL| it is loaded from. They are returned as a |FaviconImageResult| object.
@@ -33,8 +34,16 @@ typedef base::Callback<void(const std::vector<FaviconRawBitmapResult>&)>
// Callback for functions returning data for a large icon. |LargeIconResult|
// will contain either the raw bitmap for a large icon or the style of the
// fallback to use if a sufficiently large icon could not be found.
+// TODO(jkrcal): Rename LargeIcon* to LargeIconRawBitmap*.
typedef base::Callback<void(const LargeIconResult&)> LargeIconCallback;
+// Callback for functions returning decoded data for a large icon.
+// |LargeIconImageResult| will contain either the decoded image of a large
+// icon or the style of the fallback to use if a sufficiently large icon could
+// not be found.
+typedef base::Callback<void(const LargeIconImageResult&)>
+ LargeIconImageCallback;
+
} // namespace favicon_base
#endif // COMPONENTS_FAVICON_BASE_FAVICON_CALLBACK_H_
diff --git a/chromium/components/favicon_base/favicon_types.cc b/chromium/components/favicon_base/favicon_types.cc
index 8699c4387f4..b03f0ecd4ae 100644
--- a/chromium/components/favicon_base/favicon_types.cc
+++ b/chromium/components/favicon_base/favicon_types.cc
@@ -38,4 +38,16 @@ LargeIconResult::LargeIconResult(FallbackIconStyle* fallback_icon_style_in)
LargeIconResult::~LargeIconResult() {}
+// --------------------------------------------------------
+// LargeIconImageResult
+
+LargeIconImageResult::LargeIconImageResult(const gfx::Image& image_in)
+ : image(image_in) {}
+
+LargeIconImageResult::LargeIconImageResult(
+ FallbackIconStyle* fallback_icon_style_in)
+ : fallback_icon_style(fallback_icon_style_in) {}
+
+LargeIconImageResult::~LargeIconImageResult() {}
+
} // namespace favicon_base
diff --git a/chromium/components/favicon_base/favicon_types.h b/chromium/components/favicon_base/favicon_types.h
index 6a399cefe0e..47c63aeb6fa 100644
--- a/chromium/components/favicon_base/favicon_types.h
+++ b/chromium/components/favicon_base/favicon_types.h
@@ -99,6 +99,26 @@ struct LargeIconResult {
std::unique_ptr<FallbackIconStyle> fallback_icon_style;
};
+// Result returned by LargeIconService::GetLargeIconImageOrFallbackStyle().
+// Contains either the gfx::Image if the favicon database has a sufficiently
+// large favicon bitmap and the style of the fallback icon otherwise.
+struct LargeIconImageResult {
+ explicit LargeIconImageResult(const gfx::Image& image_in);
+
+ // Takes ownership of |fallback_icon_style_in|.
+ explicit LargeIconImageResult(FallbackIconStyle* fallback_icon_style_in);
+
+ ~LargeIconImageResult();
+
+ // The image from the favicon database if the database has a sufficiently
+ // large one.
+ gfx::Image image;
+
+ // The fallback icon style if a sufficiently large icon isn't available. This
+ // uses the dominant color of a smaller icon as the background if available.
+ std::unique_ptr<FallbackIconStyle> fallback_icon_style;
+};
+
} // namespace favicon_base
#endif // COMPONENTS_FAVICON_BASE_FAVICON_TYPES_H_
diff --git a/chromium/components/favicon_base/select_favicon_frames.cc b/chromium/components/favicon_base/select_favicon_frames.cc
index 82b44baa6f6..8bc63e8d0ec 100644
--- a/chromium/components/favicon_base/select_favicon_frames.cc
+++ b/chromium/components/favicon_base/select_favicon_frames.cc
@@ -265,6 +265,9 @@ void SelectFaviconFrameIndices(const std::vector<gfx::Size>& frame_pixel_sizes,
GetCandidateIndicesWithBestScores(
frame_pixel_sizes, desired_sizes, match_score, &results);
+ if (!best_indices)
+ return;
+
std::set<size_t> already_added;
for (size_t i = 0; i < results.size(); ++i) {
size_t index = results[i].index;
diff --git a/chromium/components/feature_engagement_tracker/BUILD.gn b/chromium/components/feature_engagement_tracker/BUILD.gn
new file mode 100644
index 00000000000..454c5105ea7
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/BUILD.gn
@@ -0,0 +1,35 @@
+# 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) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+
+group("feature_engagement_tracker") {
+ public_deps = [
+ "//components/feature_engagement_tracker/public",
+ ]
+
+ deps = [
+ "//components/feature_engagement_tracker/internal",
+ ]
+}
+
+group("unit_tests") {
+ testonly = true
+
+ deps = [
+ "//components/feature_engagement_tracker/internal:unit_tests",
+ ]
+}
+
+if (is_android) {
+ java_group("feature_engagement_tracker_java") {
+ deps = [
+ "//components/feature_engagement_tracker/internal:internal_java",
+ "//components/feature_engagement_tracker/public:public_java",
+ ]
+ }
+}
diff --git a/chromium/components/feature_engagement_tracker/DEPS b/chromium/components/feature_engagement_tracker/DEPS
new file mode 100644
index 00000000000..1347398646b
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "-content",
+ "+jni",
+ "+components/keyed_service",
+]
diff --git a/chromium/components/feature_engagement_tracker/OWNERS b/chromium/components/feature_engagement_tracker/OWNERS
new file mode 100644
index 00000000000..6768d1d71d0
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/OWNERS
@@ -0,0 +1,2 @@
+dtrainor@chromium.org
+nyquist@chromium.org
diff --git a/chromium/components/feature_engagement_tracker/README.md b/chromium/components/feature_engagement_tracker/README.md
new file mode 100644
index 00000000000..d55b95aa074
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/README.md
@@ -0,0 +1,14 @@
+# Feature Engagement Tracker
+
+The Feature Engagement Tracker provides a client-side backend for displaying
+feature enlightenment or in-product help (IPH) with a clean and easy to use API
+to be consumed by the UI frontend. The backend behaves as a black box and takes
+input about user behavior. Whenever the frontend gives a trigger signal that
+in-product help could be displayed, the backend will provide an answer to
+whether it is appropriate to show it or not.
+
+The frontend only needs to deal with user interactions and how to display the
+feature enlightenment or in-product help itself.
+
+The backend is feature agnostic and have no special logic for any specific
+features, but instead provides a generic API.
diff --git a/chromium/components/feature_engagement_tracker/internal/BUILD.gn b/chromium/components/feature_engagement_tracker/internal/BUILD.gn
new file mode 100644
index 00000000000..00badef306e
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/BUILD.gn
@@ -0,0 +1,103 @@
+# 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) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+
+static_library("internal") {
+ visibility = [
+ ":*",
+ "//components/feature_engagement_tracker",
+ ]
+
+ sources = [
+ "condition_validator.h",
+ "configuration.cc",
+ "configuration.h",
+ "editable_configuration.cc",
+ "editable_configuration.h",
+ "feature_constants.cc",
+ "feature_engagement_tracker_impl.cc",
+ "feature_engagement_tracker_impl.h",
+ "feature_list.cc",
+ "feature_list.h",
+ "in_memory_store.cc",
+ "in_memory_store.h",
+ "model.h",
+ "model_impl.cc",
+ "model_impl.h",
+ "never_condition_validator.cc",
+ "never_condition_validator.h",
+ "once_condition_validator.cc",
+ "once_condition_validator.h",
+ "single_invalid_configuration.cc",
+ "single_invalid_configuration.h",
+ "store.h",
+ ]
+
+ public_deps = [
+ "//components/feature_engagement_tracker/internal/proto",
+ ]
+
+ deps = [
+ "//base",
+ "//components/feature_engagement_tracker/public",
+ "//components/keyed_service/core",
+ ]
+
+ if (is_android) {
+ sources += [
+ "android/feature_engagement_tracker_impl_android.cc",
+ "android/feature_engagement_tracker_impl_android.h",
+ "android/feature_engagement_tracker_jni_registrar.cc",
+ ]
+
+ deps += [ ":jni_headers" ]
+ }
+}
+
+source_set("unit_tests") {
+ testonly = true
+
+ visibility = [ "//components/feature_engagement_tracker:unit_tests" ]
+
+ sources = [
+ "editable_configuration_unittest.cc",
+ "feature_engagement_tracker_impl_unittest.cc",
+ "in_memory_store_unittest.cc",
+ "model_impl_unittest.cc",
+ "never_condition_validator_unittest.cc",
+ "once_condition_validator_unittest.cc",
+ "single_invalid_configuration_unittest.cc",
+ ]
+
+ deps = [
+ ":internal",
+ "//base/test:test_support",
+ "//testing/gtest",
+ ]
+}
+
+if (is_android) {
+ android_library("internal_java") {
+ visibility = [ "//components/feature_engagement_tracker:feature_engagement_tracker_java" ]
+
+ java_files = [ "android/java/src/org/chromium/components/feature_engagement_tracker/internal/FeatureEngagementTrackerImpl.java" ]
+
+ deps = [
+ "//base:base_java",
+ "//components/feature_engagement_tracker/public:public_java",
+ ]
+ }
+
+ generate_jni("jni_headers") {
+ visibility = [ ":*" ]
+ sources = [
+ "android/java/src/org/chromium/components/feature_engagement_tracker/internal/FeatureEngagementTrackerImpl.java",
+ ]
+ jni_package = "components/feature_engagement_tracker/internal"
+ }
+}
diff --git a/chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc b/chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc
new file mode 100644
index 00000000000..9d8a362b803
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc
@@ -0,0 +1,131 @@
+// 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/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h"
+
+#include <vector>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/feature_list.h"
+#include "components/feature_engagement_tracker/internal/feature_list.h"
+#include "components/feature_engagement_tracker/public/feature_engagement_tracker.h"
+#include "jni/FeatureEngagementTrackerImpl_jni.h"
+
+namespace feature_engagement_tracker {
+
+namespace {
+
+const char kFeatureEngagementTrackerImplAndroidKey[] =
+ "feature_engagement_tracker_impl_android";
+
+// Create mapping from feature name to base::Feature.
+FeatureEngagementTrackerImplAndroid::FeatureMap CreateMapFromNameToFeature(
+ FeatureVector features) {
+ FeatureEngagementTrackerImplAndroid::FeatureMap feature_map;
+ for (auto it = features.begin(); it != features.end(); ++it) {
+ feature_map[(*it)->name] = *it;
+ }
+ return feature_map;
+}
+
+FeatureEngagementTrackerImplAndroid* FromFeatureEngagementTrackerImpl(
+ FeatureEngagementTracker* feature_engagement_tracker) {
+ FeatureEngagementTrackerImpl* impl =
+ static_cast<FeatureEngagementTrackerImpl*>(feature_engagement_tracker);
+ FeatureEngagementTrackerImplAndroid* impl_android =
+ static_cast<FeatureEngagementTrackerImplAndroid*>(
+ impl->GetUserData(kFeatureEngagementTrackerImplAndroidKey));
+ if (!impl_android) {
+ impl_android =
+ new FeatureEngagementTrackerImplAndroid(impl, GetAllFeatures());
+ impl->SetUserData(kFeatureEngagementTrackerImplAndroidKey, impl_android);
+ }
+ return impl_android;
+}
+
+} // namespace
+
+// static
+bool FeatureEngagementTrackerImplAndroid::RegisterJni(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+// static
+FeatureEngagementTrackerImplAndroid*
+FeatureEngagementTrackerImplAndroid::FromJavaObject(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj) {
+ return reinterpret_cast<FeatureEngagementTrackerImplAndroid*>(
+ Java_FeatureEngagementTrackerImpl_getNativePtr(env, jobj));
+}
+
+// This function is declared in
+// //components/feature_engagement_tracker/public/feature_engagement_tracker.h
+// and should be linked in to any binary using
+// FeatureEngagementTracker::GetJavaObject.
+// static
+base::android::ScopedJavaLocalRef<jobject>
+FeatureEngagementTracker::GetJavaObject(
+ FeatureEngagementTracker* feature_engagement_tracker) {
+ return FromFeatureEngagementTrackerImpl(feature_engagement_tracker)
+ ->GetJavaObject();
+}
+
+FeatureEngagementTrackerImplAndroid::FeatureEngagementTrackerImplAndroid(
+ FeatureEngagementTrackerImpl* feature_engagement_tracker_impl,
+ FeatureVector features)
+ : features_(CreateMapFromNameToFeature(features)),
+ feature_engagement_tracker_impl_(feature_engagement_tracker_impl) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+
+ java_obj_.Reset(env, Java_FeatureEngagementTrackerImpl_create(
+ env, reinterpret_cast<intptr_t>(this))
+ .obj());
+}
+
+FeatureEngagementTrackerImplAndroid::~FeatureEngagementTrackerImplAndroid() {
+ Java_FeatureEngagementTrackerImpl_clearNativePtr(
+ base::android::AttachCurrentThread(), java_obj_);
+}
+
+base::android::ScopedJavaLocalRef<jobject>
+FeatureEngagementTrackerImplAndroid::GetJavaObject() {
+ return base::android::ScopedJavaLocalRef<jobject>(java_obj_);
+}
+
+void FeatureEngagementTrackerImplAndroid::NotifyEvent(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& jevent) {
+ std::string event = ConvertJavaStringToUTF8(env, jevent);
+ feature_engagement_tracker_impl_->NotifyEvent(event);
+}
+
+bool FeatureEngagementTrackerImplAndroid::ShouldTriggerHelpUI(
+ 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 feature_engagement_tracker_impl_->ShouldTriggerHelpUI(
+ *features_[feature]);
+}
+
+void FeatureEngagementTrackerImplAndroid::Dismissed(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj) {
+ feature_engagement_tracker_impl_->Dismissed();
+}
+
+void FeatureEngagementTrackerImplAndroid::AddOnInitializedCallback(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jobject>& j_callback_obj) {
+ // TODO(nyquist): Implement support for the wrapped base::Callback.
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h b/chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h
new file mode 100644
index 00000000000..1234ae82724
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h
@@ -0,0 +1,79 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_ANDROID_FEATURE_ENGAGEMENT_TRACKER_IMPL_ANDROID_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_ANDROID_FEATURE_ENGAGEMENT_TRACKER_IMPL_ANDROID_H_
+
+#include <string>
+#include <unordered_map>
+
+#include "base/android/callback_android.h"
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/macros.h"
+#include "base/supports_user_data.h"
+#include "components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h"
+#include "components/feature_engagement_tracker/internal/feature_list.h"
+
+namespace base {
+struct Feature;
+} // namespace base
+
+namespace feature_engagement_tracker {
+
+// JNI bridge between FeatureEngagementTrackerImpl in Java and C++. See the
+// public API of FeatureEngagementTracker for documentation for all methods.
+class FeatureEngagementTrackerImplAndroid
+ : public base::SupportsUserData::Data {
+ public:
+ using FeatureMap = std::unordered_map<std::string, const base::Feature*>;
+ static bool RegisterJni(JNIEnv* env);
+ static FeatureEngagementTrackerImplAndroid* FromJavaObject(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj);
+
+ FeatureEngagementTrackerImplAndroid(
+ FeatureEngagementTrackerImpl* feature_engagement_tracker_impl,
+ FeatureVector features);
+ ~FeatureEngagementTrackerImplAndroid() override;
+
+ base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
+
+ FeatureEngagementTrackerImpl* feature_engagement_tracker_impl() {
+ return feature_engagement_tracker_impl_;
+ }
+
+ // FeatureEngagementTracker JNI bridge implementation.
+ virtual void NotifyEvent(JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& jevent);
+ virtual bool ShouldTriggerHelpUI(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& jfeature);
+ virtual void Dismissed(JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj);
+ virtual void AddOnInitializedCallback(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jobject>& j_callback_obj);
+
+ private:
+ // A map from the feature name to the base::Feature, to ensure that the Java
+ // version of the API can use the string name. If base::Feature becomes a Java
+ // class as well, we should remove this mapping.
+ FeatureMap features_;
+
+ // The FeatureEngagementTrackerImpl this is a JNI bridge for.
+ FeatureEngagementTrackerImpl* feature_engagement_tracker_impl_;
+
+ // The Java-side of this JNI bridge.
+ base::android::ScopedJavaGlobalRef<jobject> java_obj_;
+
+ DISALLOW_COPY_AND_ASSIGN(FeatureEngagementTrackerImplAndroid);
+};
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_ANDROID_FEATURE_ENGAGEMENT_TRACKER_IMPL_ANDROID_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/condition_validator.h b/chromium/components/feature_engagement_tracker/internal/condition_validator.h
new file mode 100644
index 00000000000..295a6a08af6
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/condition_validator.h
@@ -0,0 +1,36 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CONDITION_VALIDATOR_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CONDITION_VALIDATOR_H_
+
+#include "base/macros.h"
+#include "components/feature_engagement_tracker/internal/model.h"
+
+namespace base {
+struct Feature;
+} // namespace base
+
+namespace feature_engagement_tracker {
+
+// A ConditionValidator checks the requred conditions for a given feature,
+// and checks if all conditions are met.
+class ConditionValidator {
+ public:
+ virtual ~ConditionValidator() = default;
+
+ // Returns true iff all conditions for the given feature have been met.
+ virtual bool MeetsConditions(const base::Feature& feature,
+ const Model& model) = 0;
+
+ protected:
+ ConditionValidator() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConditionValidator);
+};
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CONDITION_VALIDATOR_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/configuration.cc b/chromium/components/feature_engagement_tracker/internal/configuration.cc
new file mode 100644
index 00000000000..6e7b904bf20
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/configuration.cc
@@ -0,0 +1,20 @@
+// 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/feature_engagement_tracker/internal/configuration.h"
+
+#include <string>
+
+namespace feature_engagement_tracker {
+
+FeatureConfig::FeatureConfig() : valid(false) {}
+
+FeatureConfig::~FeatureConfig() = default;
+
+bool operator==(const FeatureConfig& lhs, const FeatureConfig& rhs) {
+ return lhs.valid == rhs.valid &&
+ lhs.feature_used_event == rhs.feature_used_event;
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/configuration.h b/chromium/components/feature_engagement_tracker/internal/configuration.h
new file mode 100644
index 00000000000..2e470cb7446
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/configuration.h
@@ -0,0 +1,59 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CONFIGURATION_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CONFIGURATION_H_
+
+#include <map>
+#include <string>
+
+#include "base/macros.h"
+
+namespace base {
+struct Feature;
+}
+
+namespace feature_engagement_tracker {
+
+// A FeatureConfig contains all the configuration for a given feature.
+struct FeatureConfig {
+ public:
+ FeatureConfig();
+ ~FeatureConfig();
+
+ // Whether the configuration has been successfully parsed.
+ bool valid;
+
+ // The identifier for a particular event that will be searched for when
+ // counting how many times a particular feature has been used.
+ std::string feature_used_event;
+};
+
+bool operator==(const FeatureConfig& lhs, const FeatureConfig& rhs);
+
+// A Configuration contains the current set of runtime configurations.
+// It is up to each implementation of Configuration to provide a way to
+// register features and their configurations.
+class Configuration {
+ public:
+ // Convenience alias for typical implementatinos of Configuration.
+ using ConfigMap = std::map<const base::Feature*, FeatureConfig>;
+
+ virtual ~Configuration() = default;
+
+ // Returns the FeatureConfig for the given |feature|. The |feature| must
+ // be registered with the Configuration instance.
+ virtual const FeatureConfig& GetFeatureConfig(
+ const base::Feature& feature) const = 0;
+
+ protected:
+ Configuration() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Configuration);
+};
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CONFIGURATION_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/editable_configuration.cc b/chromium/components/feature_engagement_tracker/internal/editable_configuration.cc
new file mode 100644
index 00000000000..f7a4cba5c5c
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/editable_configuration.cc
@@ -0,0 +1,31 @@
+// 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/feature_engagement_tracker/internal/editable_configuration.h"
+
+#include <map>
+
+#include "base/logging.h"
+#include "components/feature_engagement_tracker/internal/configuration.h"
+
+namespace feature_engagement_tracker {
+
+EditableConfiguration::EditableConfiguration() = default;
+
+EditableConfiguration::~EditableConfiguration() = default;
+
+void EditableConfiguration::SetConfiguration(
+ const base::Feature* feature,
+ const FeatureConfig& feature_config) {
+ configs_[feature] = feature_config;
+}
+
+const FeatureConfig& EditableConfiguration::GetFeatureConfig(
+ const base::Feature& feature) const {
+ auto it = configs_.find(&feature);
+ DCHECK(it != configs_.end());
+ return it->second;
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/editable_configuration.h b/chromium/components/feature_engagement_tracker/internal/editable_configuration.h
new file mode 100644
index 00000000000..2e01b72118f
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/editable_configuration.h
@@ -0,0 +1,43 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_EDITABLE_CONFIGURATION_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_EDITABLE_CONFIGURATION_H_
+
+#include "base/macros.h"
+#include "components/feature_engagement_tracker/internal/configuration.h"
+
+namespace base {
+struct Feature;
+} // namespace base
+
+namespace feature_engagement_tracker {
+
+// An EditableConfiguration provides a configuration that can be configured
+// by calling SetConfiguration(...) for each feature, which makes it well
+// suited for simple setup and tests.
+class EditableConfiguration : public Configuration {
+ public:
+ EditableConfiguration();
+ ~EditableConfiguration() override;
+
+ // Configuration implementaiton.
+ const FeatureConfig& GetFeatureConfig(
+ const base::Feature& feature) const override;
+
+ // Adds a new FeatureConfig to the current configurations. If it already
+ // exists, the contents are replaced.
+ void SetConfiguration(const base::Feature* feature,
+ const FeatureConfig& feature_config);
+
+ private:
+ // The current configurations.
+ ConfigMap configs_;
+
+ DISALLOW_COPY_AND_ASSIGN(EditableConfiguration);
+};
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_EDITABLE_CONFIGURATION_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/editable_configuration_unittest.cc b/chromium/components/feature_engagement_tracker/internal/editable_configuration_unittest.cc
new file mode 100644
index 00000000000..896e0381734
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/editable_configuration_unittest.cc
@@ -0,0 +1,86 @@
+// 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/feature_engagement_tracker/internal/editable_configuration.h"
+
+#include <string>
+
+#include "base/feature_list.h"
+#include "base/metrics/field_trial.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/feature_engagement_tracker/internal/configuration.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feature_engagement_tracker {
+
+namespace {
+
+const base::Feature kTestFeatureFoo{"test_foo",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kTestFeatureBar{"test_bar",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+class EditableConfigurationTest : public ::testing::Test {
+ public:
+ FeatureConfig CreateFeatureConfig(const std::string& feature_used_event,
+ bool valid) {
+ FeatureConfig feature_config;
+ feature_config.valid = valid;
+ feature_config.feature_used_event = feature_used_event;
+ return feature_config;
+ }
+
+ protected:
+ base::test::ScopedFeatureList scoped_feature_list_;
+ EditableConfiguration configuration_;
+};
+
+} // namespace
+
+TEST_F(EditableConfigurationTest, SingleConfigAddAndGet) {
+ scoped_feature_list_.InitWithFeatures({kTestFeatureFoo}, {});
+
+ FeatureConfig foo_config = CreateFeatureConfig("foo", true);
+ configuration_.SetConfiguration(&kTestFeatureFoo, foo_config);
+ const FeatureConfig& foo_config_result =
+ configuration_.GetFeatureConfig(kTestFeatureFoo);
+
+ EXPECT_EQ(foo_config, foo_config_result);
+}
+
+TEST_F(EditableConfigurationTest, TwoConfigAddAndGet) {
+ scoped_feature_list_.InitWithFeatures({kTestFeatureFoo, kTestFeatureBar}, {});
+
+ FeatureConfig foo_config = CreateFeatureConfig("foo", true);
+ configuration_.SetConfiguration(&kTestFeatureFoo, foo_config);
+ FeatureConfig bar_config = CreateFeatureConfig("bar", true);
+ configuration_.SetConfiguration(&kTestFeatureBar, bar_config);
+
+ const FeatureConfig& foo_config_result =
+ configuration_.GetFeatureConfig(kTestFeatureFoo);
+ const FeatureConfig& bar_config_result =
+ configuration_.GetFeatureConfig(kTestFeatureBar);
+
+ EXPECT_EQ(foo_config, foo_config_result);
+ EXPECT_EQ(bar_config, bar_config_result);
+}
+
+TEST_F(EditableConfigurationTest, ConfigShouldBeEditable) {
+ scoped_feature_list_.InitWithFeatures({kTestFeatureFoo}, {});
+
+ FeatureConfig valid_foo_config = CreateFeatureConfig("foo", true);
+ configuration_.SetConfiguration(&kTestFeatureFoo, valid_foo_config);
+
+ const FeatureConfig& valid_foo_config_result =
+ configuration_.GetFeatureConfig(kTestFeatureFoo);
+ EXPECT_EQ(valid_foo_config, valid_foo_config_result);
+
+ FeatureConfig invalid_foo_config = CreateFeatureConfig("foo2", false);
+ configuration_.SetConfiguration(&kTestFeatureFoo, invalid_foo_config);
+ const FeatureConfig& invalid_foo_config_result =
+ configuration_.GetFeatureConfig(kTestFeatureFoo);
+ EXPECT_EQ(invalid_foo_config, invalid_foo_config_result);
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_constants.cc b/chromium/components/feature_engagement_tracker/internal/feature_constants.cc
new file mode 100644
index 00000000000..570ff1077d5
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/feature_constants.cc
@@ -0,0 +1,17 @@
+/// 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/feature_engagement_tracker/public/feature_constants.h"
+
+#include "base/feature_list.h"
+
+namespace feature_engagement_tracker {
+
+const base::Feature kIPHDemoMode{"IPH_DemoMode",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kIPHDummyFeature{"IPH_DummyFeature",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc b/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc
new file mode 100644
index 00000000000..24c499d8545
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc
@@ -0,0 +1,108 @@
+// 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/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h"
+
+#include "base/bind.h"
+#include "base/feature_list.h"
+#include "base/memory/ptr_util.h"
+#include "components/feature_engagement_tracker/internal/editable_configuration.h"
+#include "components/feature_engagement_tracker/internal/feature_list.h"
+#include "components/feature_engagement_tracker/internal/in_memory_store.h"
+#include "components/feature_engagement_tracker/internal/model_impl.h"
+#include "components/feature_engagement_tracker/internal/never_condition_validator.h"
+#include "components/feature_engagement_tracker/internal/once_condition_validator.h"
+#include "components/feature_engagement_tracker/internal/single_invalid_configuration.h"
+#include "components/feature_engagement_tracker/public/feature_constants.h"
+
+namespace feature_engagement_tracker {
+
+namespace {
+
+// Creates a FeatureEngagementTrackerImpl that is usable for a demo mode.
+std::unique_ptr<FeatureEngagementTracker>
+CreateDemoModeFeatureEngagementTracker() {
+ std::unique_ptr<EditableConfiguration> configuration =
+ base::MakeUnique<EditableConfiguration>();
+
+ // Create valid configurations for all features to ensure that the
+ // OnceConditionValidator acknowledges that thet meet conditions once.
+ std::vector<const base::Feature*> features = GetAllFeatures();
+ for (auto* feature : features) {
+ FeatureConfig feature_config;
+ feature_config.valid = true;
+ configuration->SetConfiguration(feature, feature_config);
+ }
+
+ return base::MakeUnique<FeatureEngagementTrackerImpl>(
+ base::MakeUnique<InMemoryStore>(), std::move(configuration),
+ base::MakeUnique<OnceConditionValidator>());
+}
+
+} // namespace
+
+// This method is declared in //components/feature_engagement_tracker/public/
+// feature_engagement_tracker.h
+// and should be linked in to any binary using FeatureEngagementTracker::Create.
+// static
+FeatureEngagementTracker* FeatureEngagementTracker::Create(
+ const base::FilePath& storage_dir,
+ const scoped_refptr<base::SequencedTaskRunner>& background__task_runner) {
+ if (base::FeatureList::IsEnabled(kIPHDemoMode))
+ return CreateDemoModeFeatureEngagementTracker().release();
+
+ std::unique_ptr<Store> store = base::MakeUnique<InMemoryStore>();
+ // TODO(nyquist): Create FinchConfiguration to parse configuration.
+ std::unique_ptr<Configuration> configuration =
+ base::MakeUnique<SingleInvalidConfiguration>();
+ std::unique_ptr<ConditionValidator> validator =
+ base::MakeUnique<NeverConditionValidator>();
+
+ return new FeatureEngagementTrackerImpl(
+ std::move(store), std::move(configuration), std::move(validator));
+}
+
+FeatureEngagementTrackerImpl::FeatureEngagementTrackerImpl(
+ std::unique_ptr<Store> store,
+ std::unique_ptr<Configuration> configuration,
+ std::unique_ptr<ConditionValidator> condition_validator)
+ : condition_validator_(std::move(condition_validator)),
+ weak_ptr_factory_(this) {
+ model_ =
+ base::MakeUnique<ModelImpl>(std::move(store), std::move(configuration));
+ model_->Initialize(
+ base::Bind(&FeatureEngagementTrackerImpl::OnModelInitializationFinished,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+FeatureEngagementTrackerImpl::~FeatureEngagementTrackerImpl() = default;
+
+void FeatureEngagementTrackerImpl::NotifyEvent(const std::string& event) {
+ // TODO(nyquist): Track this event.
+}
+
+bool FeatureEngagementTrackerImpl::ShouldTriggerHelpUI(
+ const base::Feature& feature) {
+ // TODO(nyquist): Track this event.
+ bool result = condition_validator_->MeetsConditions(feature, *model_);
+ if (result)
+ model_->SetIsCurrentlyShowing(true);
+ return result;
+}
+
+void FeatureEngagementTrackerImpl::Dismissed() {
+ // TODO(nyquist): Track this event.
+ model_->SetIsCurrentlyShowing(false);
+}
+
+void FeatureEngagementTrackerImpl::AddOnInitializedCallback(
+ OnInitializedCallback callback) {
+ // TODO(nyquist): Add support for this.
+}
+
+void FeatureEngagementTrackerImpl::OnModelInitializationFinished(bool result) {
+ // TODO(nyquist): Ensure that all OnInitializedCallbacks are invoked.
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h b/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h
new file mode 100644
index 00000000000..b008894138e
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h
@@ -0,0 +1,56 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_ENGAGEMENT_TRACKER_IMPL_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_ENGAGEMENT_TRACKER_IMPL_H_
+
+#include <string>
+#include <vector>
+
+#include "base/feature_list.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/supports_user_data.h"
+#include "components/feature_engagement_tracker/internal/condition_validator.h"
+#include "components/feature_engagement_tracker/internal/model.h"
+#include "components/feature_engagement_tracker/public/feature_engagement_tracker.h"
+
+namespace feature_engagement_tracker {
+class Store;
+
+// The internal implementation of the FeatureEngagementTracker.
+class FeatureEngagementTrackerImpl : public FeatureEngagementTracker,
+ public base::SupportsUserData {
+ public:
+ FeatureEngagementTrackerImpl(
+ std::unique_ptr<Store> store,
+ std::unique_ptr<Configuration> configuration,
+ std::unique_ptr<ConditionValidator> condition_validator);
+ ~FeatureEngagementTrackerImpl() override;
+
+ // FeatureEngagementTracker implementation.
+ void NotifyEvent(const std::string& event) override;
+ bool ShouldTriggerHelpUI(const base::Feature& feature) override;
+ void Dismissed() override;
+ void AddOnInitializedCallback(OnInitializedCallback callback) override;
+
+ private:
+ // Invoked by the Model when it has been initialized.
+ void OnModelInitializationFinished(bool result);
+
+ // The current model.
+ std::unique_ptr<Model> model_;
+
+ // The ConditionValidator provides functionality for knowing when to trigger
+ // help UI.
+ std::unique_ptr<ConditionValidator> condition_validator_;
+
+ base::WeakPtrFactory<FeatureEngagementTrackerImpl> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FeatureEngagementTrackerImpl);
+};
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_ENGAGEMENT_TRACKER_IMPL_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc b/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc
new file mode 100644
index 00000000000..daa58c307fa
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc
@@ -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.
+
+#include "components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h"
+
+#include <memory>
+
+#include "base/feature_list.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/field_trial.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/feature_engagement_tracker/internal/editable_configuration.h"
+#include "components/feature_engagement_tracker/internal/in_memory_store.h"
+#include "components/feature_engagement_tracker/internal/once_condition_validator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feature_engagement_tracker {
+
+namespace {
+const base::Feature kTestFeatureFoo{"test_foo",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kTestFeatureBar{"test_bar",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kTestFeatureQux{"test_qux",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+void RegisterFeatureConfig(EditableConfiguration* configuration,
+ const base::Feature& feature,
+ bool valid) {
+ FeatureConfig config;
+ config.valid = valid;
+ config.feature_used_event = feature.name;
+ configuration->SetConfiguration(&feature, config);
+}
+
+class FeatureEngagementTrackerImplTest : public ::testing::Test {
+ public:
+ FeatureEngagementTrackerImplTest() {
+ std::unique_ptr<Store> store = base::MakeUnique<InMemoryStore>();
+ std::unique_ptr<EditableConfiguration> configuration =
+ base::MakeUnique<EditableConfiguration>();
+ std::unique_ptr<ConditionValidator> validator =
+ base::MakeUnique<OnceConditionValidator>();
+
+ RegisterFeatureConfig(configuration.get(), kTestFeatureFoo, true);
+ RegisterFeatureConfig(configuration.get(), kTestFeatureBar, true);
+ RegisterFeatureConfig(configuration.get(), kTestFeatureQux, false);
+
+ scoped_feature_list_.InitWithFeatures(
+ {kTestFeatureFoo, kTestFeatureBar, kTestFeatureQux}, {});
+
+ tracker_.reset(new FeatureEngagementTrackerImpl(
+ std::move(store), std::move(configuration), std::move(validator)));
+ // Ensure all initialization is finished.
+ base::RunLoop().RunUntilIdle();
+ }
+
+ protected:
+ base::MessageLoop message_loop_;
+ std::unique_ptr<FeatureEngagementTrackerImpl> tracker_;
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+} // namespace
+
+TEST_F(FeatureEngagementTrackerImplTest, TestTriggering) {
+ // The first time a feature triggers it should be shown.
+ EXPECT_TRUE(tracker_->ShouldTriggerHelpUI(kTestFeatureFoo));
+ EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureFoo));
+ EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureQux));
+
+ // While in-product help is currently showing, no other features should be
+ // shown.
+ EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureBar));
+ EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureQux));
+
+ // After dismissing the current in-product help, that feature can not be shown
+ // again, but a different feature should.
+ tracker_->Dismissed();
+ EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureFoo));
+ EXPECT_TRUE(tracker_->ShouldTriggerHelpUI(kTestFeatureBar));
+ EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureQux));
+
+ // After dismissing the second registered feature, no more in-product help
+ // should be shown, since kTestFeatureQux is invalid.
+ tracker_->Dismissed();
+ EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureFoo));
+ EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureBar));
+ EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureQux));
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_list.cc b/chromium/components/feature_engagement_tracker/internal/feature_list.cc
new file mode 100644
index 00000000000..ebdef0a0cf3
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/feature_list.cc
@@ -0,0 +1,23 @@
+/// 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/feature_engagement_tracker/internal/feature_list.h"
+
+#include "base/feature_list.h"
+#include "components/feature_engagement_tracker/public/feature_constants.h"
+
+namespace feature_engagement_tracker {
+
+namespace {
+
+const base::Feature* kAllFeatures[] = {&kIPHDummyFeature};
+
+} // namespace
+
+std::vector<const base::Feature*> GetAllFeatures() {
+ return std::vector<const base::Feature*>(
+ kAllFeatures, kAllFeatures + arraysize(kAllFeatures));
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_list.h b/chromium/components/feature_engagement_tracker/internal/feature_list.h
new file mode 100644
index 00000000000..ba4a5786239
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/feature_list.h
@@ -0,0 +1,20 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_LIST_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_LIST_H_
+
+#include <vector>
+
+#include "base/feature_list.h"
+
+namespace feature_engagement_tracker {
+using FeatureVector = std::vector<const base::Feature*>;
+
+// Returns all the features that are in use for engagement tracking.
+FeatureVector GetAllFeatures();
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_LIST_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/in_memory_store.cc b/chromium/components/feature_engagement_tracker/internal/in_memory_store.cc
new file mode 100644
index 00000000000..0c9fa6e4c5b
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/in_memory_store.cc
@@ -0,0 +1,46 @@
+// 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/feature_engagement_tracker/internal/in_memory_store.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/feature_list.h"
+#include "base/memory/ptr_util.h"
+#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/feature_engagement_tracker/internal/store.h"
+
+namespace feature_engagement_tracker {
+
+InMemoryStore::InMemoryStore(std::unique_ptr<std::vector<Event>> events)
+ : Store(), events_(std::move(events)), ready_(false) {}
+
+InMemoryStore::InMemoryStore()
+ : InMemoryStore(base::MakeUnique<std::vector<Event>>()) {}
+
+InMemoryStore::~InMemoryStore() = default;
+
+void InMemoryStore::Load(const OnLoadedCallback& callback) {
+ HandleLoadResult(callback, true);
+}
+
+bool InMemoryStore::IsReady() const {
+ return ready_;
+}
+
+void InMemoryStore::WriteEvent(const Event& event) {
+ // Intentionally ignore all writes.
+}
+
+void InMemoryStore::HandleLoadResult(const OnLoadedCallback& callback,
+ bool success) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, success, base::Passed(&events_)));
+ ready_ = success;
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/in_memory_store.h b/chromium/components/feature_engagement_tracker/internal/in_memory_store.h
new file mode 100644
index 00000000000..939037c64b8
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/in_memory_store.h
@@ -0,0 +1,47 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_IN_MEMORY_STORE_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_IN_MEMORY_STORE_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "components/feature_engagement_tracker/internal/store.h"
+
+namespace feature_engagement_tracker {
+// An InMemoryStore provides a DB layer that stores all data in-memory.
+// All data is made available to this class during construction, and can be
+// loaded once by a caller. All calls to WriteEvent(...) are ignored.
+class InMemoryStore : public Store {
+ public:
+ explicit InMemoryStore(std::unique_ptr<std::vector<Event>> events);
+ InMemoryStore();
+ ~InMemoryStore() override;
+
+ // Store implementation.
+ void Load(const OnLoadedCallback& callback) override;
+ bool IsReady() const override;
+ void WriteEvent(const Event& event) override;
+
+ protected:
+ // Posts the result of loading and sets up the ready state.
+ // Protected and virtual for testing.
+ virtual void HandleLoadResult(const OnLoadedCallback& callback, bool success);
+
+ private:
+ // All events that this in-memory store was constructed with. This will be
+ // reset when Load(...) is called.
+ std::unique_ptr<std::vector<Event>> events_;
+
+ // Whether the store is ready or not. It is true after Load(...) has been
+ // invoked.
+ bool ready_;
+
+ DISALLOW_COPY_AND_ASSIGN(InMemoryStore);
+};
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_IN_MEMORY_STORE_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/in_memory_store_unittest.cc b/chromium/components/feature_engagement_tracker/internal/in_memory_store_unittest.cc
new file mode 100644
index 00000000000..be3f0ad2910
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/in_memory_store_unittest.cc
@@ -0,0 +1,69 @@
+// 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/feature_engagement_tracker/internal/in_memory_store.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feature_engagement_tracker {
+
+namespace {
+
+class InMemoryStoreTest : public ::testing::Test {
+ public:
+ InMemoryStoreTest()
+ : load_callback_has_been_invoked_(false), last_result_(false) {}
+
+ void LoadCallback(bool success, std::unique_ptr<std::vector<Event>> events) {
+ load_callback_has_been_invoked_ = true;
+ last_result_ = success;
+ loaded_events_.reset(events.release());
+ }
+
+ protected:
+ bool load_callback_has_been_invoked_;
+ bool last_result_;
+ std::unique_ptr<std::vector<Event>> loaded_events_;
+ base::MessageLoop message_loop_;
+};
+} // namespace
+
+TEST_F(InMemoryStoreTest, LoadShouldProvideEventsAsCallback) {
+ std::unique_ptr<std::vector<Event>> events =
+ base::MakeUnique<std::vector<Event>>();
+ Event foo;
+ Event bar;
+ events->push_back(foo);
+ events->push_back(bar);
+
+ // Create a new store and verify it's not ready yet.
+ InMemoryStore store(std::move(events));
+ EXPECT_FALSE(store.IsReady());
+
+ // Load the data and ensure the callback is not immediately invoked, since the
+ // result should be posted.
+ store.Load(
+ base::Bind(&InMemoryStoreTest::LoadCallback, base::Unretained(this)));
+ EXPECT_FALSE(load_callback_has_been_invoked_);
+
+ // Run the message loop until it's idle to finish to ensure the result is
+ // available.
+ base::RunLoop().RunUntilIdle();
+
+ // The two events should have been loaded, and the store should be ready.
+ EXPECT_TRUE(load_callback_has_been_invoked_);
+ EXPECT_TRUE(store.IsReady());
+ EXPECT_EQ(2u, loaded_events_->size());
+ EXPECT_TRUE(last_result_);
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/model.h b/chromium/components/feature_engagement_tracker/internal/model.h
new file mode 100644
index 00000000000..3011066367e
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/model.h
@@ -0,0 +1,67 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_H_
+
+#include <map>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "components/feature_engagement_tracker/internal/configuration.h"
+
+namespace base {
+struct Feature;
+} // namespace base
+
+namespace feature_engagement_tracker {
+class Event;
+
+// A Model provides all necessary runtime state.
+class Model {
+ public:
+ // Callback for when model initialization has finished. The bool argument
+ // denotes whether the model was successfully initialized.
+ using OnModelInitializationFinished = base::Callback<void(bool)>;
+
+ virtual ~Model() = default;
+
+ // Initialize the model, including all underlying sub systems. When all
+ // required operations have been finished, a callback is posted.
+ virtual void Initialize(const OnModelInitializationFinished& callback) = 0;
+
+ // Returns whether the model is ready, i.e. whether it has been fully
+ // initialized.
+ virtual bool IsReady() const = 0;
+
+ // Returns the FeatureConfig for the given |feature|.
+ virtual const FeatureConfig& GetFeatureConfig(
+ const base::Feature& feature) const = 0;
+
+ // Update the state of whether any in-product help is currently showing.
+ virtual void SetIsCurrentlyShowing(bool is_showing) = 0;
+
+ // Returns whether any in-product help is currently showing.
+ virtual bool IsCurrentlyShowing() const = 0;
+
+ // Retrieves the Event object for the event with the given name. If the event
+ // is not found, an empty event will be returned. Calling this before the
+ // Model has finished initializing will result in undefined behavior.
+ virtual const Event& GetEvent(const std::string& event_name) = 0;
+
+ // Increments the counter for today for how many times the event has happened.
+ // If the event has never happened before, the Event object will be created.
+ virtual void IncrementEvent(const std::string& event_name) = 0;
+
+ protected:
+ Model() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Model);
+};
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/model_impl.cc b/chromium/components/feature_engagement_tracker/internal/model_impl.cc
new file mode 100644
index 00000000000..26d6e21fc3d
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/model_impl.cc
@@ -0,0 +1,120 @@
+// 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/feature_engagement_tracker/internal/model_impl.h"
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/feature_engagement_tracker/internal/configuration.h"
+#include "components/feature_engagement_tracker/internal/model.h"
+#include "components/feature_engagement_tracker/internal/store.h"
+
+namespace feature_engagement_tracker {
+
+ModelImpl::ModelImpl(std::unique_ptr<Store> store,
+ std::unique_ptr<Configuration> configuration)
+ : Model(),
+ store_(std::move(store)),
+ configuration_(std::move(configuration)),
+ ready_(false),
+ currently_showing_(false),
+ weak_factory_(this) {}
+
+ModelImpl::~ModelImpl() = default;
+
+void ModelImpl::Initialize(const OnModelInitializationFinished& callback) {
+ store_->Load(base::Bind(&ModelImpl::OnStoreLoaded, weak_factory_.GetWeakPtr(),
+ callback));
+}
+
+bool ModelImpl::IsReady() const {
+ return ready_;
+}
+
+const FeatureConfig& ModelImpl::GetFeatureConfig(
+ const base::Feature& feature) const {
+ return configuration_->GetFeatureConfig(feature);
+}
+
+void ModelImpl::SetIsCurrentlyShowing(bool is_showing) {
+ currently_showing_ = is_showing;
+}
+
+bool ModelImpl::IsCurrentlyShowing() const {
+ return currently_showing_;
+}
+
+const Event& ModelImpl::GetEvent(const std::string& event_name) {
+ return GetNonConstEvent(event_name);
+}
+
+void ModelImpl::IncrementEvent(const std::string& event_name) {
+ // TODO(nyquist): Add support for pending events, and also add UMA.
+ DCHECK(ready_);
+
+ Event& event = GetNonConstEvent(event_name);
+ uint32_t current_day = GetCurrentDay();
+ for (int i = 0; i < event.events_size(); ++i) {
+ Event_Count* event_count = event.mutable_events(i);
+ DCHECK(event_count->has_day());
+ DCHECK(event_count->has_count());
+ if (event_count->day() == current_day) {
+ event_count->set_count(event_count->count() + 1);
+ store_->WriteEvent(event);
+ return;
+ }
+ }
+
+ // Day not found for event, adding new day with a count of 1.
+ Event_Count* event_count = event.add_events();
+ event_count->set_day(current_day);
+ event_count->set_count(1u);
+ store_->WriteEvent(event);
+}
+
+uint32_t ModelImpl::GetCurrentDay() {
+ // TODO(nyquist): Implement this according to specification.
+ return 1u;
+}
+
+void ModelImpl::OnStoreLoaded(const OnModelInitializationFinished& callback,
+ bool success,
+ std::unique_ptr<std::vector<Event>> events) {
+ if (!success) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(callback, false));
+ return;
+ }
+
+ for (auto& event : *events) {
+ DCHECK_NE("", event.name());
+ events_[event.name()] = event;
+ }
+
+ // TODO(nyquist): Clear expired data.
+
+ ready_ = true;
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(callback, true));
+}
+
+Event& ModelImpl::GetNonConstEvent(const std::string& event_name) {
+ if (events_.find(event_name) == events_.end()) {
+ // Event does not exist yet, so create it.
+ events_[event_name].set_name(event_name);
+ store_->WriteEvent(events_[event_name]);
+ }
+ return events_[event_name];
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/model_impl.h b/chromium/components/feature_engagement_tracker/internal/model_impl.h
new file mode 100644
index 00000000000..ff456e13ee0
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/model_impl.h
@@ -0,0 +1,80 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_IMPL_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_IMPL_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/feature_engagement_tracker/internal/configuration.h"
+#include "components/feature_engagement_tracker/internal/model.h"
+#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
+
+namespace base {
+struct Feature;
+}
+
+namespace feature_engagement_tracker {
+class Store;
+
+// A ModelImpl provides the default implementation of the Model.
+class ModelImpl : public Model {
+ public:
+ ModelImpl(std::unique_ptr<Store> store,
+ std::unique_ptr<Configuration> configuration);
+ ~ModelImpl() override;
+
+ // Model implementation.
+ void Initialize(const OnModelInitializationFinished& callback) override;
+ bool IsReady() const override;
+ const FeatureConfig& GetFeatureConfig(
+ const base::Feature& feature) const override;
+ void SetIsCurrentlyShowing(bool is_showing) override;
+ bool IsCurrentlyShowing() const override;
+ const Event& GetEvent(const std::string& event_name) override;
+ void IncrementEvent(const std::string& event_name) override;
+
+ protected:
+ // Returns the number of days since epoch (1970-01-01) in the local timezone.
+ // Protected and virtual for testing.
+ virtual uint32_t GetCurrentDay();
+
+ private:
+ // Callback for loading the underlying store.
+ void OnStoreLoaded(const OnModelInitializationFinished& callback,
+ bool success,
+ std::unique_ptr<std::vector<Event>> events);
+
+ // Internal version for getting the non-const version of a stored Event.
+ // Creates the event if it is not already stored.
+ Event& GetNonConstEvent(const std::string& event_name);
+
+ // The underlying store for all events.
+ std::unique_ptr<Store> store_;
+
+ // The current configuration for all features.
+ std::unique_ptr<Configuration> configuration_;
+
+ // An in-memory representation of all events.
+ std::map<std::string, Event> events_;
+
+ // Whether the model has been fully initialized.
+ bool ready_;
+
+ // Whether the model is currently showing an in-product help.
+ bool currently_showing_;
+
+ base::WeakPtrFactory<ModelImpl> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ModelImpl);
+};
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_IMPL_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/model_impl_unittest.cc b/chromium/components/feature_engagement_tracker/internal/model_impl_unittest.cc
new file mode 100644
index 00000000000..ef57d2a5758
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/model_impl_unittest.cc
@@ -0,0 +1,385 @@
+// 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/feature_engagement_tracker/internal/model_impl.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/feature_list.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/field_trial.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/feature_engagement_tracker/internal/editable_configuration.h"
+#include "components/feature_engagement_tracker/internal/in_memory_store.h"
+#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feature_engagement_tracker {
+
+namespace {
+const base::Feature kTestFeatureFoo{"test_foo",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kTestFeatureBar{"test_bar",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+void RegisterFeatureConfig(EditableConfiguration* configuration,
+ const base::Feature& feature,
+ bool valid) {
+ FeatureConfig config;
+ config.valid = valid;
+ config.feature_used_event = feature.name;
+ configuration->SetConfiguration(&feature, config);
+}
+
+void SetEventCountForDay(Event* event, uint32_t day, uint32_t count) {
+ Event_Count* event_count = event->add_events();
+ event_count->set_day(day);
+ event_count->set_count(count);
+}
+
+// Verifies that the given |event| contains a |day| with the correct |count|,
+// and that the day only exists a single time.
+void VerifyEventCount(const Event& event, uint32_t day, uint32_t count) {
+ bool found_day = false;
+ for (int i = 0; i < event.events_size(); ++i) {
+ Event_Count event_count = event.events(i);
+ if (event_count.day() == day) {
+ EXPECT_FALSE(found_day);
+ found_day = true;
+ EXPECT_EQ(count, event_count.count());
+ }
+ }
+ EXPECT_TRUE(found_day);
+}
+
+// Verifies that the event |a| and |b| contain the exact same data.
+void VerifyEqual(const Event& a, const Event& b) {
+ EXPECT_EQ(a.name(), b.name());
+ EXPECT_EQ(a.events_size(), b.events_size());
+ for (int i = 0; i < a.events_size(); ++i) {
+ VerifyEventCount(b, a.events(i).day(), a.events(i).count());
+ }
+}
+
+// A test-only implementation of InMemoryStore that tracks calls to
+// WriteEvent(...).
+class TestInMemoryStore : public InMemoryStore {
+ public:
+ explicit TestInMemoryStore(std::unique_ptr<std::vector<Event>> events,
+ bool load_should_succeed)
+ : InMemoryStore(std::move(events)),
+ load_should_succeed_(load_should_succeed) {}
+
+ void Load(const OnLoadedCallback& callback) override {
+ HandleLoadResult(callback, load_should_succeed_);
+ }
+
+ void WriteEvent(const Event& event) override { last_written_event_ = event; }
+
+ Event GetLastWrittenEvent() { return last_written_event_; }
+
+ private:
+ // Temporary store the last written event.
+ Event last_written_event_;
+
+ // Denotes whether the call to Load(...) should succeed or not. This impacts
+ // both the ready-state and the result for the OnLoadedCallback.
+ bool load_should_succeed_;
+};
+
+// Creates a TestInMemoryStore containing three hard coded events.
+std::unique_ptr<TestInMemoryStore> CreatePrefilledStore() {
+ std::unique_ptr<std::vector<Event>> events =
+ base::MakeUnique<std::vector<Event>>();
+
+ Event foo;
+ foo.set_name("foo");
+ SetEventCountForDay(&foo, 1, 1);
+ events->push_back(foo);
+
+ Event bar;
+ bar.set_name("bar");
+ SetEventCountForDay(&bar, 1, 3);
+ SetEventCountForDay(&bar, 2, 3);
+ SetEventCountForDay(&bar, 5, 5);
+ events->push_back(bar);
+
+ Event qux;
+ qux.set_name("qux");
+ SetEventCountForDay(&qux, 1, 5);
+ SetEventCountForDay(&qux, 2, 1);
+ SetEventCountForDay(&qux, 3, 2);
+ events->push_back(qux);
+
+ return base::MakeUnique<TestInMemoryStore>(std::move(events), true);
+}
+
+// A test-only implementation of ModelImpl to be able to change the current
+// day while a test is running.
+class TestModelImpl : public ModelImpl {
+ public:
+ TestModelImpl(std::unique_ptr<Store> store,
+ std::unique_ptr<Configuration> configuration)
+ : ModelImpl(std::move(store), std::move(configuration)),
+ current_day_(0) {}
+ ~TestModelImpl() override {}
+
+ uint32_t GetCurrentDay() override { return current_day_; }
+
+ void SetCurrentDay(uint32_t current_day) { current_day_ = current_day; }
+
+ private:
+ uint32_t current_day_;
+};
+
+class ModelImplTest : public ::testing::Test {
+ public:
+ ModelImplTest()
+ : got_initialize_callback_(false), initialize_callback_result_(false) {}
+
+ void SetUp() override {
+ std::unique_ptr<EditableConfiguration> configuration =
+ base::MakeUnique<EditableConfiguration>();
+
+ RegisterFeatureConfig(configuration.get(), kTestFeatureFoo, true);
+ RegisterFeatureConfig(configuration.get(), kTestFeatureBar, true);
+
+ scoped_feature_list_.InitWithFeatures({kTestFeatureFoo, kTestFeatureBar},
+ {});
+
+ std::unique_ptr<TestInMemoryStore> store = CreateStore();
+ store_ = store.get();
+
+ model_.reset(new TestModelImpl(std::move(store), std::move(configuration)));
+ }
+
+ virtual std::unique_ptr<TestInMemoryStore> CreateStore() {
+ return CreatePrefilledStore();
+ }
+
+ void OnModelInitializationFinished(bool success) {
+ got_initialize_callback_ = true;
+ initialize_callback_result_ = success;
+ }
+
+ protected:
+ std::unique_ptr<TestModelImpl> model_;
+ TestInMemoryStore* store_;
+ bool got_initialize_callback_;
+ bool initialize_callback_result_;
+
+ private:
+ base::MessageLoop message_loop_;
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+class LoadFailingModelImplTest : public ModelImplTest {
+ public:
+ LoadFailingModelImplTest() : ModelImplTest() {}
+
+ std::unique_ptr<TestInMemoryStore> CreateStore() override {
+ return base::MakeUnique<TestInMemoryStore>(
+ base::MakeUnique<std::vector<Event>>(), false);
+ }
+};
+
+} // namespace
+
+TEST_F(ModelImplTest, InitializeShouldLoadEntries) {
+ model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(model_->IsReady());
+ EXPECT_TRUE(got_initialize_callback_);
+ EXPECT_TRUE(initialize_callback_result_);
+
+ // Verify that all the data matches what was put into the store in
+ // CreateStore().
+ Event foo_event = model_->GetEvent("foo");
+ EXPECT_EQ("foo", foo_event.name());
+ EXPECT_EQ(1, foo_event.events_size());
+ VerifyEventCount(foo_event, 1u, 1u);
+
+ Event bar_event = model_->GetEvent("bar");
+ EXPECT_EQ("bar", bar_event.name());
+ EXPECT_EQ(3, bar_event.events_size());
+ VerifyEventCount(bar_event, 1u, 3u);
+ VerifyEventCount(bar_event, 2u, 3u);
+ VerifyEventCount(bar_event, 5u, 5u);
+
+ Event qux_event = model_->GetEvent("qux");
+ EXPECT_EQ("qux", qux_event.name());
+ EXPECT_EQ(3, qux_event.events_size());
+ VerifyEventCount(qux_event, 1u, 5u);
+ VerifyEventCount(qux_event, 2u, 1u);
+ VerifyEventCount(qux_event, 3u, 2u);
+}
+
+TEST_F(ModelImplTest, RetrievingNewEventsShouldYieldEmpty) {
+ model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(model_->IsReady());
+
+ Event no_event = model_->GetEvent("no");
+ EXPECT_EQ("no", no_event.name());
+ EXPECT_EQ(0, no_event.events_size());
+ VerifyEqual(no_event, store_->GetLastWrittenEvent());
+}
+
+TEST_F(ModelImplTest, IncrementingNonExistingEvent) {
+ model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(model_->IsReady());
+
+ model_->SetCurrentDay(1u);
+
+ // Incrementing the event should work even if it does not exist.
+ model_->IncrementEvent("nonexisting");
+ Event event1 = model_->GetEvent("nonexisting");
+ EXPECT_EQ("nonexisting", event1.name());
+ EXPECT_EQ(1, event1.events_size());
+ VerifyEventCount(event1, 1u, 1u);
+ VerifyEqual(event1, store_->GetLastWrittenEvent());
+
+ // Incrementing the event after it has been initialized to 1, it should now
+ // have a count of 2 for the given day.
+ model_->IncrementEvent("nonexisting");
+ Event event2 = model_->GetEvent("nonexisting");
+ Event_Count event2_count = event2.events(0);
+ EXPECT_EQ(1, event2.events_size());
+ VerifyEventCount(event2, 1u, 2u);
+ VerifyEqual(event2, store_->GetLastWrittenEvent());
+}
+
+TEST_F(ModelImplTest, IncrementingNonExistingEventMultipleDays) {
+ model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(model_->IsReady());
+
+ model_->SetCurrentDay(1u);
+ model_->IncrementEvent("nonexisting");
+ model_->SetCurrentDay(2u);
+ model_->IncrementEvent("nonexisting");
+ model_->IncrementEvent("nonexisting");
+ model_->SetCurrentDay(3u);
+ model_->IncrementEvent("nonexisting");
+ Event event = model_->GetEvent("nonexisting");
+ EXPECT_EQ(3, event.events_size());
+ VerifyEventCount(event, 1u, 1u);
+ VerifyEventCount(event, 2u, 2u);
+ VerifyEventCount(event, 3u, 1u);
+ VerifyEqual(event, store_->GetLastWrittenEvent());
+}
+
+TEST_F(ModelImplTest, IncrementingSingleDayExistingEvent) {
+ model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(model_->IsReady());
+
+ model_->SetCurrentDay(1u);
+
+ // |foo| is inserted into the store with a count of 1 at day 1.
+ Event foo_event = model_->GetEvent("foo");
+ EXPECT_EQ("foo", foo_event.name());
+ EXPECT_EQ(1, foo_event.events_size());
+ VerifyEventCount(foo_event, 1u, 1u);
+
+ // Incrementing |foo| should change count to 2.
+ model_->IncrementEvent("foo");
+ Event foo_event2 = model_->GetEvent("foo");
+ EXPECT_EQ(1, foo_event2.events_size());
+ VerifyEventCount(foo_event2, 1u, 2u);
+ VerifyEqual(foo_event2, store_->GetLastWrittenEvent());
+}
+
+TEST_F(ModelImplTest, IncrementingSingleDayExistingEventTwice) {
+ model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(model_->IsReady());
+
+ model_->SetCurrentDay(1u);
+
+ // |foo| is inserted into the store with a count of 1 at day 1, so
+ // incrementing twice should lead to 3.
+ model_->IncrementEvent("foo");
+ model_->IncrementEvent("foo");
+ Event foo_event = model_->GetEvent("foo");
+ EXPECT_EQ(1, foo_event.events_size());
+ VerifyEventCount(foo_event, 1u, 3u);
+ VerifyEqual(foo_event, store_->GetLastWrittenEvent());
+}
+
+TEST_F(ModelImplTest, IncrementingExistingMultiDayEvent) {
+ model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(model_->IsReady());
+
+ // |bar| is inserted into the store with a count of 3 at day 2. Incrementing
+ // that day should lead to a count of 4.
+ model_->SetCurrentDay(2u);
+ Event bar_event = model_->GetEvent("bar");
+ VerifyEventCount(bar_event, 2u, 3u);
+ model_->IncrementEvent("bar");
+ Event bar_event2 = model_->GetEvent("bar");
+ VerifyEventCount(bar_event2, 2u, 4u);
+ VerifyEqual(bar_event2, store_->GetLastWrittenEvent());
+}
+
+TEST_F(ModelImplTest, IncrementingExistingMultiDayEventNewDay) {
+ model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(model_->IsReady());
+
+ // |bar| does not contain entries for day 10, so incrementing should create
+ // the day.
+ model_->SetCurrentDay(10u);
+ model_->IncrementEvent("bar");
+ Event bar_event = model_->GetEvent("bar");
+ VerifyEventCount(bar_event, 10u, 1u);
+ VerifyEqual(bar_event, store_->GetLastWrittenEvent());
+ model_->IncrementEvent("bar");
+ Event bar_event2 = model_->GetEvent("bar");
+ VerifyEventCount(bar_event2, 10u, 2u);
+ VerifyEqual(bar_event2, store_->GetLastWrittenEvent());
+}
+
+TEST_F(ModelImplTest, ShowState) {
+ model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(model_->IsReady());
+
+ EXPECT_FALSE(model_->IsCurrentlyShowing());
+
+ model_->SetIsCurrentlyShowing(false);
+ EXPECT_FALSE(model_->IsCurrentlyShowing());
+
+ model_->SetIsCurrentlyShowing(true);
+ EXPECT_TRUE(model_->IsCurrentlyShowing());
+
+ model_->SetIsCurrentlyShowing(false);
+ EXPECT_FALSE(model_->IsCurrentlyShowing());
+}
+
+TEST_F(LoadFailingModelImplTest, FailedInitializeInformsCaller) {
+ model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(model_->IsReady());
+ EXPECT_TRUE(got_initialize_callback_);
+ EXPECT_FALSE(initialize_callback_result_);
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/never_condition_validator.cc b/chromium/components/feature_engagement_tracker/internal/never_condition_validator.cc
new file mode 100644
index 00000000000..317c66c0618
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/never_condition_validator.cc
@@ -0,0 +1,20 @@
+// 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/feature_engagement_tracker/internal/never_condition_validator.h"
+
+#include "components/feature_engagement_tracker/internal/model.h"
+
+namespace feature_engagement_tracker {
+
+NeverConditionValidator::NeverConditionValidator() = default;
+
+NeverConditionValidator::~NeverConditionValidator() = default;
+
+bool NeverConditionValidator::MeetsConditions(const base::Feature& feature,
+ const Model& model) {
+ return false;
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/never_condition_validator.h b/chromium/components/feature_engagement_tracker/internal/never_condition_validator.h
new file mode 100644
index 00000000000..b9fca6483ad
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/never_condition_validator.h
@@ -0,0 +1,37 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_NEVER_CONDITION_VALIDATOR_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_NEVER_CONDITION_VALIDATOR_H_
+
+#include <unordered_set>
+
+#include "base/macros.h"
+#include "components/feature_engagement_tracker/internal/condition_validator.h"
+#include "components/feature_engagement_tracker/internal/model.h"
+
+namespace base {
+struct Feature;
+} // namespace base
+
+namespace feature_engagement_tracker {
+
+// An ConditionValidator that never acknowledges that a feature has met its
+// conditions.
+class NeverConditionValidator : public ConditionValidator {
+ public:
+ NeverConditionValidator();
+ ~NeverConditionValidator() override;
+
+ // ConditionValidator implementation.
+ bool MeetsConditions(const base::Feature& feature,
+ const Model& model) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NeverConditionValidator);
+};
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_NEVER_CONDITION_VALIDATOR_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/never_condition_validator_unittest.cc b/chromium/components/feature_engagement_tracker/internal/never_condition_validator_unittest.cc
new file mode 100644
index 00000000000..d39f1220af2
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/never_condition_validator_unittest.cc
@@ -0,0 +1,78 @@
+// 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/feature_engagement_tracker/internal/never_condition_validator.h"
+
+#include "base/feature_list.h"
+#include "base/metrics/field_trial.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/feature_engagement_tracker/internal/model.h"
+#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feature_engagement_tracker {
+
+namespace {
+
+const base::Feature kTestFeatureFoo{"test_foo",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kTestFeatureBar{"test_bar",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// A Model that is always postive to show in-product help.
+class TestModel : public Model {
+ public:
+ TestModel() {
+ feature_config_.valid = true;
+ feature_config_.feature_used_event = "foobar";
+ }
+
+ void Initialize(const OnModelInitializationFinished& callback) override {}
+
+ bool IsReady() const override { return true; }
+
+ const FeatureConfig& GetFeatureConfig(
+ const base::Feature& feature) const override {
+ return feature_config_;
+ }
+
+ void SetIsCurrentlyShowing(bool is_showing) override {}
+
+ bool IsCurrentlyShowing() const override { return false; }
+
+ const Event& GetEvent(const std::string& event_name) override {
+ return empty_event_;
+ }
+
+ void IncrementEvent(const std::string& event_name) override {}
+
+ private:
+ FeatureConfig feature_config_;
+ Event empty_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestModel);
+};
+
+class NeverConditionValidatorTest : public ::testing::Test {
+ public:
+ NeverConditionValidatorTest() = default;
+
+ protected:
+ base::test::ScopedFeatureList scoped_feature_list_;
+ TestModel model_;
+ NeverConditionValidator validator_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NeverConditionValidatorTest);
+};
+
+} // namespace
+
+TEST_F(NeverConditionValidatorTest, ShouldNeverMeetConditions) {
+ scoped_feature_list_.InitWithFeatures({kTestFeatureFoo, kTestFeatureBar}, {});
+ EXPECT_FALSE(validator_.MeetsConditions(kTestFeatureFoo, model_));
+ EXPECT_FALSE(validator_.MeetsConditions(kTestFeatureBar, model_));
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/once_condition_validator.cc b/chromium/components/feature_engagement_tracker/internal/once_condition_validator.cc
new file mode 100644
index 00000000000..1240766927b
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/once_condition_validator.cc
@@ -0,0 +1,37 @@
+// 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/feature_engagement_tracker/internal/once_condition_validator.h"
+
+#include "base/feature_list.h"
+#include "components/feature_engagement_tracker/internal/configuration.h"
+#include "components/feature_engagement_tracker/internal/model.h"
+
+namespace feature_engagement_tracker {
+
+OnceConditionValidator::OnceConditionValidator() = default;
+
+OnceConditionValidator::~OnceConditionValidator() = default;
+
+bool OnceConditionValidator::MeetsConditions(const base::Feature& feature,
+ const Model& model) {
+ if (!model.IsReady())
+ return false;
+
+ if (model.IsCurrentlyShowing())
+ return false;
+
+ const FeatureConfig& config = model.GetFeatureConfig(feature);
+ if (!config.valid)
+ return false;
+
+ if (shown_features_.find(&feature) == shown_features_.end()) {
+ shown_features_.insert(&feature);
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/once_condition_validator.h b/chromium/components/feature_engagement_tracker/internal/once_condition_validator.h
new file mode 100644
index 00000000000..83b265edf51
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/once_condition_validator.h
@@ -0,0 +1,51 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_ONCE_CONDITION_VALIDATOR_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_ONCE_CONDITION_VALIDATOR_H_
+
+#include <unordered_set>
+
+#include "base/macros.h"
+#include "components/feature_engagement_tracker/internal/condition_validator.h"
+#include "components/feature_engagement_tracker/internal/model.h"
+
+namespace base {
+struct Feature;
+} // namespace base
+
+namespace feature_engagement_tracker {
+
+// An ConditionValidator that will ensure that each base::Feature will meet
+// conditions maximum one time for any given session.
+// It has the following requirements:
+// - The Model is ready.
+// - No other in-product help is currently showing.
+// - FeatureConfig for the feature is valid.
+// - This is the first time the given base::Feature meets all above stated
+// conditions.
+//
+// NOTE: This ConditionValidator fully ignores whether the base::Feature is
+// enabled or not and any other configuration specified in the FeatureConfig.
+// In practice this leads this ConditionValidator to be well suited for a
+// demonstration mode of in-product help.
+class OnceConditionValidator : public ConditionValidator {
+ public:
+ OnceConditionValidator();
+ ~OnceConditionValidator() override;
+
+ // ConditionValidator implementation.
+ bool MeetsConditions(const base::Feature& feature,
+ const Model& model) override;
+
+ private:
+ // Contains all features that have met conditions within the current session.
+ std::unordered_set<const base::Feature*> shown_features_;
+
+ DISALLOW_COPY_AND_ASSIGN(OnceConditionValidator);
+};
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_ONCE_CONDITION_VALIDATOR_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/once_condition_validator_unittest.cc b/chromium/components/feature_engagement_tracker/internal/once_condition_validator_unittest.cc
new file mode 100644
index 00000000000..c8ee8c7b333
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/once_condition_validator_unittest.cc
@@ -0,0 +1,163 @@
+// 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/feature_engagement_tracker/internal/once_condition_validator.h"
+
+#include <string>
+
+#include "base/feature_list.h"
+#include "base/metrics/field_trial.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/feature_engagement_tracker/internal/editable_configuration.h"
+#include "components/feature_engagement_tracker/internal/model.h"
+#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feature_engagement_tracker {
+
+namespace {
+
+const base::Feature kTestFeatureFoo{"test_foo",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kTestFeatureBar{"test_bar",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// A Model that is easily configurable at runtime.
+class TestModel : public Model {
+ public:
+ TestModel() : ready_(false), is_showing_(false) {}
+
+ void Initialize(const OnModelInitializationFinished& callback) override {}
+
+ bool IsReady() const override { return ready_; }
+
+ void SetIsReady(bool ready) { ready_ = ready; }
+
+ const FeatureConfig& GetFeatureConfig(
+ const base::Feature& feature) const override {
+ return configuration_.GetFeatureConfig(feature);
+ }
+
+ void SetIsCurrentlyShowing(bool is_showing) override {
+ is_showing_ = is_showing;
+ }
+
+ bool IsCurrentlyShowing() const override { return is_showing_; }
+
+ EditableConfiguration& GetConfiguration() { return configuration_; }
+
+ const Event& GetEvent(const std::string& event_name) override {
+ return empty_event_;
+ }
+
+ void IncrementEvent(const std::string& event_name) override {}
+
+ private:
+ EditableConfiguration configuration_;
+ Event empty_event_;
+ bool ready_;
+ bool is_showing_;
+};
+
+class OnceConditionValidatorTest : public ::testing::Test {
+ public:
+ OnceConditionValidatorTest() {
+ // By default, model should be ready.
+ model_.SetIsReady(true);
+ }
+
+ void AddFeature(const base::Feature& feature, bool valid) {
+ FeatureConfig feature_config;
+ feature_config.valid = valid;
+ model_.GetConfiguration().SetConfiguration(&feature, feature_config);
+ }
+
+ protected:
+ base::test::ScopedFeatureList scoped_feature_list_;
+ TestModel model_;
+ OnceConditionValidator validator_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OnceConditionValidatorTest);
+};
+
+} // namespace
+
+TEST_F(OnceConditionValidatorTest, EnabledFeatureShouldTriggerOnce) {
+ scoped_feature_list_.InitWithFeatures({kTestFeatureFoo}, {});
+
+ // Initialize validator with one enabled and valid feature.
+ AddFeature(kTestFeatureFoo, true);
+
+ // Only the first call to MeetsConditions() should lead to enlightenment.
+ EXPECT_TRUE(validator_.MeetsConditions(kTestFeatureFoo, model_));
+ EXPECT_FALSE(validator_.MeetsConditions(kTestFeatureFoo, model_));
+}
+
+TEST_F(OnceConditionValidatorTest,
+ BothEnabledAndDisabledFeaturesShouldTrigger) {
+ scoped_feature_list_.InitWithFeatures({kTestFeatureFoo}, {kTestFeatureBar});
+
+ // Initialize validator with one enabled and one disabled feature, both valid.
+ AddFeature(kTestFeatureFoo, true);
+ AddFeature(kTestFeatureBar, true);
+
+ // Only the kTestFeatureFoo feature should lead to enlightenment, since
+ // kTestFeatureBar is disabled. Ordering disabled feature first to ensure this
+ // captures a different behavior than the
+ // OnlyOneFeatureShouldTriggerPerSession test below.
+ EXPECT_TRUE(validator_.MeetsConditions(kTestFeatureBar, model_));
+ EXPECT_TRUE(validator_.MeetsConditions(kTestFeatureFoo, model_));
+}
+
+TEST_F(OnceConditionValidatorTest, StillTriggerWhenAllFeaturesDisabled) {
+ scoped_feature_list_.InitWithFeatures({}, {kTestFeatureFoo, kTestFeatureBar});
+
+ // Initialize validator with two enabled features, both valid.
+ AddFeature(kTestFeatureFoo, true);
+ AddFeature(kTestFeatureBar, true);
+
+ // No features should get to show enlightenment.
+ EXPECT_TRUE(validator_.MeetsConditions(kTestFeatureFoo, model_));
+ EXPECT_TRUE(validator_.MeetsConditions(kTestFeatureBar, model_));
+}
+
+TEST_F(OnceConditionValidatorTest, OnlyTriggerWhenModelIsReady) {
+ scoped_feature_list_.InitWithFeatures({kTestFeatureFoo}, {});
+
+ // Initialize validator with a single valid feature.
+ AddFeature(kTestFeatureFoo, true);
+
+ model_.SetIsReady(false);
+ EXPECT_FALSE(validator_.MeetsConditions(kTestFeatureFoo, model_));
+
+ model_.SetIsReady(true);
+ EXPECT_TRUE(validator_.MeetsConditions(kTestFeatureFoo, model_));
+}
+
+TEST_F(OnceConditionValidatorTest, OnlyTriggerIfNothingElseIsShowing) {
+ scoped_feature_list_.InitWithFeatures({kTestFeatureFoo}, {});
+
+ // Initialize validator with a single valid feature.
+ AddFeature(kTestFeatureFoo, true);
+
+ model_.SetIsCurrentlyShowing(true);
+ EXPECT_FALSE(validator_.MeetsConditions(kTestFeatureFoo, model_));
+
+ model_.SetIsCurrentlyShowing(false);
+ EXPECT_TRUE(validator_.MeetsConditions(kTestFeatureFoo, model_));
+}
+
+TEST_F(OnceConditionValidatorTest, DoNotTriggerForInvalidConfig) {
+ scoped_feature_list_.InitWithFeatures({kTestFeatureFoo}, {});
+
+ AddFeature(kTestFeatureFoo, false);
+ EXPECT_FALSE(validator_.MeetsConditions(kTestFeatureFoo, model_));
+
+ // Override config to be valid.
+ AddFeature(kTestFeatureFoo, true);
+ EXPECT_TRUE(validator_.MeetsConditions(kTestFeatureFoo, model_));
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/proto/BUILD.gn b/chromium/components/feature_engagement_tracker/internal/proto/BUILD.gn
new file mode 100644
index 00000000000..686f184a97f
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/proto/BUILD.gn
@@ -0,0 +1,11 @@
+# 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("//third_party/protobuf/proto_library.gni")
+
+proto_library("proto") {
+ sources = [
+ "event.proto",
+ ]
+}
diff --git a/chromium/components/feature_engagement_tracker/internal/proto/event.proto b/chromium/components/feature_engagement_tracker/internal/proto/event.proto
new file mode 100644
index 00000000000..9b619a23a78
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/proto/event.proto
@@ -0,0 +1,27 @@
+// 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.
+//
+// FeatureEngagementTracker content.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package feature_engagement_tracker;
+
+// Event stores state for a specific event a count per day it has happened.
+message Event {
+ // Count stores a pair of a day and how many times something happened that
+ // day.
+ message Count {
+ optional uint32 day = 1;
+ optional uint32 count = 2;
+ }
+
+ // The descriptive name of the event.
+ optional string name = 1;
+
+ // The number of this event that happened per day.
+ repeated Count events = 2;
+}
diff --git a/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration.cc b/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration.cc
new file mode 100644
index 00000000000..ed20e661431
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration.cc
@@ -0,0 +1,23 @@
+// 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/feature_engagement_tracker/internal/single_invalid_configuration.h"
+
+#include "components/feature_engagement_tracker/internal/configuration.h"
+
+namespace feature_engagement_tracker {
+
+SingleInvalidConfiguration::SingleInvalidConfiguration() {
+ invalid_feature_config_.valid = false;
+ invalid_feature_config_.feature_used_event = "nothing_to_see_here";
+};
+
+SingleInvalidConfiguration::~SingleInvalidConfiguration() = default;
+
+const FeatureConfig& SingleInvalidConfiguration::GetFeatureConfig(
+ const base::Feature& feature) const {
+ return invalid_feature_config_;
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration.h b/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration.h
new file mode 100644
index 00000000000..449cee97bbe
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration.h
@@ -0,0 +1,39 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_SINGLE_INVALID_CONFIGURATION_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_SINGLE_INVALID_CONFIGURATION_H_
+
+#include <unordered_set>
+
+#include "base/macros.h"
+#include "components/feature_engagement_tracker/internal/configuration.h"
+
+namespace base {
+struct Feature;
+} // namespace base
+
+namespace feature_engagement_tracker {
+
+// An Configuration that always returns the same single invalid configuration,
+// regardless of which feature.
+class SingleInvalidConfiguration : public Configuration {
+ public:
+ SingleInvalidConfiguration();
+ ~SingleInvalidConfiguration() override;
+
+ // Configuration implementation.
+ const FeatureConfig& GetFeatureConfig(
+ const base::Feature& feature) const override;
+
+ private:
+ // The invalid configuration to always return.
+ FeatureConfig invalid_feature_config_;
+
+ DISALLOW_COPY_AND_ASSIGN(SingleInvalidConfiguration);
+};
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_SINGLE_INVALID_CONFIGURATION_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration_unittest.cc b/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration_unittest.cc
new file mode 100644
index 00000000000..d4c2666b563
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration_unittest.cc
@@ -0,0 +1,46 @@
+// 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/feature_engagement_tracker/internal/single_invalid_configuration.h"
+
+#include "base/feature_list.h"
+#include "base/metrics/field_trial.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/feature_engagement_tracker/internal/configuration.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feature_engagement_tracker {
+
+namespace {
+
+const base::Feature kTestFeatureFoo{"test_foo",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kTestFeatureBar{"test_bar",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+class SingleInvalidConfigurationTest : public ::testing::Test {
+ public:
+ SingleInvalidConfigurationTest() = default;
+
+ protected:
+ base::test::ScopedFeatureList scoped_feature_list_;
+ SingleInvalidConfiguration configuration_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SingleInvalidConfigurationTest);
+};
+
+} // namespace
+
+TEST_F(SingleInvalidConfigurationTest, AllConfigurationsAreInvalid) {
+ scoped_feature_list_.InitWithFeatures({kTestFeatureFoo, kTestFeatureBar}, {});
+
+ FeatureConfig foo_config = configuration_.GetFeatureConfig(kTestFeatureFoo);
+ EXPECT_FALSE(foo_config.valid);
+
+ FeatureConfig bar_config = configuration_.GetFeatureConfig(kTestFeatureBar);
+ EXPECT_FALSE(bar_config.valid);
+}
+
+} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/store.h b/chromium/components/feature_engagement_tracker/internal/store.h
new file mode 100644
index 00000000000..cef9b460a21
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/internal/store.h
@@ -0,0 +1,44 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_STORE_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_STORE_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
+
+namespace feature_engagement_tracker {
+
+// Store represents the storage engine behind the FeatureEngagementTracker.
+class Store {
+ public:
+ // TODO(nyquist): Add vector of all events to result callback.
+ using OnLoadedCallback =
+ base::Callback<void(bool success, std::unique_ptr<std::vector<Event>>)>;
+
+ virtual ~Store() = default;
+
+ // Loads the database from storage and asynchronously posts the result back
+ // on the caller's thread.
+ // Ownership of the loaded data is given to the caller.
+ virtual void Load(const OnLoadedCallback& callback) = 0;
+
+ // Returns whether the database is ready, i.e. whether it has been fully
+ // loaded.
+ virtual bool IsReady() const = 0;
+
+ // Stores the given event to persistent storage.
+ virtual void WriteEvent(const Event& event) = 0;
+
+ protected:
+ Store() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Store);
+};
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_STORE_H_
diff --git a/chromium/components/feature_engagement_tracker/public/BUILD.gn b/chromium/components/feature_engagement_tracker/public/BUILD.gn
new file mode 100644
index 00000000000..62a0f4ae869
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/public/BUILD.gn
@@ -0,0 +1,38 @@
+# 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) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+
+source_set("public") {
+ sources = [
+ "feature_constants.h",
+ "feature_engagement_tracker.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/keyed_service/core",
+ ]
+
+ if (is_android) {
+ sources += [ "android/feature_engagement_tracker_jni_registrar.h" ]
+ }
+}
+
+if (is_android) {
+ android_library("public_java") {
+ java_files = [
+ "android/java/src/org/chromium/components/feature_engagement_tracker/FeatureConstants.java",
+ "android/java/src/org/chromium/components/feature_engagement_tracker/FeatureEngagementTracker.java",
+ ]
+
+ deps = [
+ "//base:base_java",
+ "//third_party/android_tools:android_support_annotations_java",
+ ]
+ }
+}
diff --git a/chromium/components/feature_engagement_tracker/public/feature_constants.h b/chromium/components/feature_engagement_tracker/public/feature_constants.h
new file mode 100644
index 00000000000..c26608a4247
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/public/feature_constants.h
@@ -0,0 +1,23 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_CONSTANTS_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_CONSTANTS_H_
+
+#include "base/feature_list.h"
+
+namespace feature_engagement_tracker {
+
+// A feature for enabling a demonstration mode for In-Product Help.
+extern const base::Feature kIPHDemoMode;
+
+// All the features declared below should also be declared in the Java
+// version: org.chromium.components.feature_engagement_tracker.FeatureConstants.
+
+// A dummy feature until real features start using the backend.
+extern const base::Feature kIPHDummyFeature;
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_CONSTANTS_H_
diff --git a/chromium/components/feature_engagement_tracker/public/feature_engagement_tracker.h b/chromium/components/feature_engagement_tracker/public/feature_engagement_tracker.h
new file mode 100644
index 00000000000..b151dda4e70
--- /dev/null
+++ b/chromium/components/feature_engagement_tracker/public/feature_engagement_tracker.h
@@ -0,0 +1,77 @@
+// 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_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_ENGAGEMENT_TRACKER_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_ENGAGEMENT_TRACKER_H_
+
+#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"
+#include "base/sequenced_task_runner.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/jni_android.h"
+#endif // defined(OS_ANDROID)
+
+namespace feature_engagement_tracker {
+
+// The FeatureEngagementTracker provides a backend for displaying feature
+// enlightenment or in-product help (IPH) with a clean and easy to use API to be
+// consumed by the UI frontend. The backend behaves as a black box and takes
+// input about user behavior. Whenever the frontend gives a trigger signal that
+// IPH could be displayed, the backend will provide an answer to whether it is
+// appropriate to show it or not.
+class FeatureEngagementTracker : public KeyedService {
+ public:
+#if defined(OS_ANDROID)
+ // Returns a Java object of the type FeatureEngagementTracker for the given
+ // FeatureEngagementTracker.
+ static base::android::ScopedJavaLocalRef<jobject> GetJavaObject(
+ FeatureEngagementTracker* feature_engagement_tracker);
+#endif // defined(OS_ANDROID)
+
+ // Invoked when the tracker has been initialized. The |success| parameter
+ // indicates that the initialization was a success and it it ready to receive
+ // calls.
+ using OnInitializedCallback = base::Callback<void(bool success)>;
+
+ // The |storage_dir| is the path to where all local storage will be.
+ // The |bakground_task_runner| will be used for all disk reads and writes.
+ static FeatureEngagementTracker* Create(
+ const base::FilePath& storage_dir,
+ const scoped_refptr<base::SequencedTaskRunner>& background_task_runner);
+
+ // Must be called whenever an event happens.
+ virtual void NotifyEvent(const std::string& event) = 0;
+
+ // This function must be called whenever the triggering condition for a
+ // specific feature happens. Returns true iff the display of the in-product
+ // 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;
+
+ // Must be called after display of feature enlightenment finishes.
+ virtual void Dismissed() = 0;
+
+ // For features that trigger on startup, they register a callback to ensure
+ // that they are told when the tracker has been initialized.
+ virtual void AddOnInitializedCallback(OnInitializedCallback callback) = 0;
+
+ protected:
+ FeatureEngagementTracker() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FeatureEngagementTracker);
+};
+
+} // namespace feature_engagement_tracker
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_ENGAGEMENT_TRACKER_H_
diff --git a/chromium/components/feedback/DEPS b/chromium/components/feedback/DEPS
index 754fa046d27..2d72d2013c1 100644
--- a/chromium/components/feedback/DEPS
+++ b/chromium/components/feedback/DEPS
@@ -9,6 +9,7 @@ include_rules = [
"+content/public/browser",
"+content/public/test",
"+net/base",
+ "+net/traffic_annotation",
"+net/url_request",
"+third_party/re2",
"+third_party/zlib/google",
diff --git a/chromium/components/feedback/OWNERS b/chromium/components/feedback/OWNERS
index e89629f3c57..8b11b5345db 100644
--- a/chromium/components/feedback/OWNERS
+++ b/chromium/components/feedback/OWNERS
@@ -1,6 +1,8 @@
afakhry@chromium.org
bsimonnet@chromium.org
-steel@chromium.org
+rkc@chromium.org
zork@chromium.org
per-file anonymizer_tool*=battre@chromium.org
+
+# COMPONENT: Platform>Apps>Feedback
diff --git a/chromium/components/feedback/feedback_data_unittest.cc b/chromium/components/feedback/feedback_data_unittest.cc
index c41e0724080..d6e353b398e 100644
--- a/chromium/components/feedback/feedback_data_unittest.cc
+++ b/chromium/components/feedback/feedback_data_unittest.cc
@@ -9,7 +9,6 @@
#include <utility>
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "components/feedback/feedback_uploader.h"
#include "components/feedback/feedback_uploader_factory.h"
@@ -18,6 +17,7 @@
#include "components/user_prefs/user_prefs.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -58,8 +58,7 @@ class FeedbackDataTest : public testing::Test {
FeedbackDataTest()
: context_(new content::TestBrowserContext()),
prefs_(new TestingPrefServiceSimple()),
- data_(new FeedbackData()),
- ui_thread_(content::BrowserThread::UI, &message_loop_) {
+ data_(new FeedbackData()) {
user_prefs::UserPrefs::Set(context_.get(), prefs_.get());
data_->set_context(context_.get());
data_->set_send_report_callback(base::Bind(
@@ -95,8 +94,7 @@ class FeedbackDataTest : public testing::Test {
std::unique_ptr<content::TestBrowserContext> context_;
std::unique_ptr<PrefService> prefs_;
scoped_refptr<FeedbackData> data_;
- base::MessageLoop message_loop_;
- content::TestBrowserThread ui_thread_;
+ content::TestBrowserThreadBundle test_browser_thread_bundle_;
};
TEST_F(FeedbackDataTest, ReportSending) {
diff --git a/chromium/components/feedback/feedback_uploader_chrome.cc b/chromium/components/feedback/feedback_uploader_chrome.cc
index 0b18305d920..fe99da76a8c 100644
--- a/chromium/components/feedback/feedback_uploader_chrome.cc
+++ b/chromium/components/feedback/feedback_uploader_chrome.cc
@@ -20,6 +20,7 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "net/base/load_flags.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h"
#include "url/gurl.h"
@@ -47,14 +48,45 @@ FeedbackUploaderChrome::FeedbackUploaderChrome(
void FeedbackUploaderChrome::DispatchReport(const std::string& data) {
GURL post_url(url_);
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("chrome_feedback_report_app", R"(
+ semantics {
+ sender: "Chrome Feedback Report App"
+ description:
+ "Users can press Alt+Shift+i to report a bug or a feedback in "
+ "general. Along with the free-form text they entered, system logs "
+ "that helps in diagnosis of the issue are sent to Google. This "
+ "service uploads the report to Google Feedback server."
+ trigger:
+ "When user chooses to send a feedback to Google."
+ data:
+ "The free-form text that user has entered and useful debugging "
+ "logs (UI logs, Chrome logs, kernel logs, auto update engine logs, "
+ "ARC++ logs, etc.). The logs are anonymized to remove any "
+ "user-private data. The user can view the system information "
+ "before sending, and choose to send the feedback report without "
+ "system information and the logs (unchecking 'Send system "
+ "information' prevents sending logs as well), the screenshot, or "
+ "even his/her email address."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "This feature cannot be disabled by settings and is only activated "
+ "by direct user request."
+ policy_exception_justification: "Not implemented."
+ })");
// Note: FeedbackUploaderDelegate deletes itself and the fetcher.
net::URLFetcher* fetcher =
net::URLFetcher::Create(
post_url, net::URLFetcher::POST,
new FeedbackUploaderDelegate(
- data, base::Bind(&FeedbackUploaderChrome::UpdateUploadTimer,
- AsWeakPtr()),
- base::Bind(&FeedbackUploaderChrome::RetryReport, AsWeakPtr())))
+ data,
+ base::Bind(&FeedbackUploaderChrome::UpdateUploadTimer,
+ AsWeakPtr()),
+ base::Bind(&FeedbackUploaderChrome::RetryReport, AsWeakPtr())),
+ traffic_annotation)
.release();
data_use_measurement::DataUseUserData::AttachToFetcher(
fetcher, data_use_measurement::DataUseUserData::FEEDBACK_UPLOADER);
diff --git a/chromium/components/feedback/feedback_uploader_unittest.cc b/chromium/components/feedback/feedback_uploader_unittest.cc
index 17a6ec5b935..76201f3b32f 100644
--- a/chromium/components/feedback/feedback_uploader_unittest.cc
+++ b/chromium/components/feedback/feedback_uploader_unittest.cc
@@ -11,7 +11,6 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "build/build_config.h"
@@ -20,7 +19,7 @@
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/test/test_browser_context.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -47,8 +46,7 @@ namespace feedback {
class FeedbackUploaderTest : public testing::Test {
protected:
FeedbackUploaderTest()
- : ui_thread_(content::BrowserThread::UI, &message_loop_),
- context_(new content::TestBrowserContext()),
+ : context_(new content::TestBrowserContext()),
prefs_(new sync_preferences::TestingPrefServiceSyncable()),
dispatched_reports_count_(0),
expected_reports_(0) {
@@ -105,9 +103,8 @@ class FeedbackUploaderTest : public testing::Test {
run_loop_->Run();
}
- base::MessageLoop message_loop_;
+ content::TestBrowserThreadBundle test_browser_thread_bundle_;
std::unique_ptr<base::RunLoop> run_loop_;
- content::TestBrowserThread ui_thread_;
std::unique_ptr<content::TestBrowserContext> context_;
std::unique_ptr<PrefService> prefs_;
diff --git a/chromium/components/filesystem/file_system_app.cc b/chromium/components/filesystem/file_system_app.cc
index dd1d24b0108..c54639cea37 100644
--- a/chromium/components/filesystem/file_system_app.cc
+++ b/chromium/components/filesystem/file_system_app.cc
@@ -11,7 +11,6 @@
#include "base/files/file_util.h"
#include "base/memory/ptr_util.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/service_manager/public/cpp/connection.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/interface_registry.h"
#include "services/service_manager/public/cpp/service_context.h"
@@ -39,7 +38,9 @@ const char kUserDataDir[] = "user-data-dir";
} // namespace filesystem
-FileSystemApp::FileSystemApp() : lock_table_(new LockTable) {}
+FileSystemApp::FileSystemApp() : lock_table_(new LockTable) {
+ registry_.AddInterface<mojom::FileSystem>(this);
+}
FileSystemApp::~FileSystemApp() {}
@@ -47,10 +48,12 @@ void FileSystemApp::OnStart() {
tracing_.Initialize(context()->connector(), context()->identity().name());
}
-bool FileSystemApp::OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) {
- registry->AddInterface<mojom::FileSystem>(this);
- return true;
+void FileSystemApp::OnBindInterface(
+ const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
}
// |InterfaceFactory<Files>| implementation:
diff --git a/chromium/components/filesystem/file_system_app.h b/chromium/components/filesystem/file_system_app.h
index b3f399d8df0..7035393eda1 100644
--- a/chromium/components/filesystem/file_system_app.h
+++ b/chromium/components/filesystem/file_system_app.h
@@ -10,6 +10,7 @@
#include "components/filesystem/file_system_impl.h"
#include "components/filesystem/lock_table.h"
#include "components/filesystem/public/interfaces/file_system.mojom.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/interface_factory.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/tracing/public/cpp/provider.h"
@@ -29,8 +30,9 @@ class FileSystemApp
// |service_manager::Service| override:
void OnStart() override;
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
// |InterfaceFactory<Files>| implementation:
void Create(const service_manager::Identity& remote_identity,
@@ -38,6 +40,8 @@ class FileSystemApp
tracing::Provider tracing_;
+ service_manager::BinderRegistry registry_;
+
scoped_refptr<LockTable> lock_table_;
DISALLOW_COPY_AND_ASSIGN(FileSystemApp);
diff --git a/chromium/components/flags_ui/OWNERS b/chromium/components/flags_ui/OWNERS
index 61dccf7dc22..506ff92d665 100644
--- a/chromium/components/flags_ui/OWNERS
+++ b/chromium/components/flags_ui/OWNERS
@@ -1,3 +1,5 @@
file://ui/webui/OWNERS
asvitkine@chromium.org
+
+# COMPONENT: UI>Browser>WebUI
diff --git a/chromium/components/flags_ui/feature_entry.cc b/chromium/components/flags_ui/feature_entry.cc
index cca7419aabe..d51dd48c380 100644
--- a/chromium/components/flags_ui/feature_entry.cc
+++ b/chromium/components/flags_ui/feature_entry.cc
@@ -7,16 +7,20 @@
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
namespace flags_ui {
+const char kGenericExperimentChoiceDefault[] = "Default";
+const char kGenericExperimentChoiceEnabled[] = "Enabled";
+const char kGenericExperimentChoiceDisabled[] = "Disabled";
+const char kGenericExperimentChoiceAutomatic[] = "Automatic";
+
std::string FeatureEntry::NameForOption(int index) const {
DCHECK(type == FeatureEntry::MULTI_VALUE ||
type == FeatureEntry::ENABLE_DISABLE_VALUE ||
type == FeatureEntry::FEATURE_VALUE ||
- type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE);
+ type == FeatureEntry::FEATURE_WITH_PARAMS_VALUE);
DCHECK_LT(index, num_options);
return std::string(internal_name) + testing::kMultiSeparator +
base::IntToString(index);
@@ -26,37 +30,37 @@ base::string16 FeatureEntry::DescriptionForOption(int index) const {
DCHECK(type == FeatureEntry::MULTI_VALUE ||
type == FeatureEntry::ENABLE_DISABLE_VALUE ||
type == FeatureEntry::FEATURE_VALUE ||
- type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE);
+ type == FeatureEntry::FEATURE_WITH_PARAMS_VALUE);
DCHECK_LT(index, num_options);
- int description_id;
+ const char* description = nullptr;
if (type == FeatureEntry::ENABLE_DISABLE_VALUE ||
type == FeatureEntry::FEATURE_VALUE) {
- const int kEnableDisableDescriptionIds[] = {
- IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT,
- IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
- IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
+ const char* kEnableDisableDescriptions[] = {
+ kGenericExperimentChoiceDefault, kGenericExperimentChoiceEnabled,
+ kGenericExperimentChoiceDisabled,
};
- description_id = kEnableDisableDescriptionIds[index];
- } else if (type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE) {
+ description = kEnableDisableDescriptions[index];
+ } else if (type == FeatureEntry::FEATURE_WITH_PARAMS_VALUE) {
if (index == 0) {
- description_id = IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT;
+ description = kGenericExperimentChoiceDefault;
} else if (index == 1) {
- description_id = IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED;
+ description = kGenericExperimentChoiceEnabled;
} else if (index < num_options - 1) {
// First two options do not have variations params.
int variation_index = index - 2;
- return l10n_util::GetStringUTF16(IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED) +
+ return base::ASCIIToUTF16(
+ base::StringPiece(kGenericExperimentChoiceEnabled)) +
base::ASCIIToUTF16(" ") +
base::ASCIIToUTF16(
feature_variations[variation_index].description_text);
} else {
DCHECK_EQ(num_options - 1, index);
- description_id = IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED;
+ description = kGenericExperimentChoiceDisabled;
}
} else {
- description_id = choices[index].description_id;
+ description = choices[index].description;
}
- return l10n_util::GetStringUTF16(description_id);
+ return base::ASCIIToUTF16(base::StringPiece(description));
}
const FeatureEntry::Choice& FeatureEntry::ChoiceForOption(int index) const {
@@ -68,7 +72,7 @@ const FeatureEntry::Choice& FeatureEntry::ChoiceForOption(int index) const {
FeatureEntry::FeatureState FeatureEntry::StateForOption(int index) const {
DCHECK(type == FeatureEntry::FEATURE_VALUE ||
- type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE);
+ type == FeatureEntry::FEATURE_WITH_PARAMS_VALUE);
DCHECK_LT(index, num_options);
if (index == 0)
@@ -82,10 +86,10 @@ FeatureEntry::FeatureState FeatureEntry::StateForOption(int index) const {
const FeatureEntry::FeatureVariation* FeatureEntry::VariationForOption(
int index) const {
DCHECK(type == FeatureEntry::FEATURE_VALUE ||
- type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE);
+ type == FeatureEntry::FEATURE_WITH_PARAMS_VALUE);
DCHECK_LT(index, num_options);
- if (type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE && index > 1 &&
+ if (type == FeatureEntry::FEATURE_WITH_PARAMS_VALUE && index > 1 &&
index < num_options - 1) {
// We have no variations for FEATURE_VALUE type. Option at |index|
// corresponds to variation at |index| - 2 as the list starts with "Default"
diff --git a/chromium/components/flags_ui/feature_entry.h b/chromium/components/flags_ui/feature_entry.h
index 86e14c7a298..64283844bc5 100644
--- a/chromium/components/flags_ui/feature_entry.h
+++ b/chromium/components/flags_ui/feature_entry.h
@@ -15,6 +15,12 @@ struct Feature;
namespace flags_ui {
+// Generic experiment choice option names.
+extern const char kGenericExperimentChoiceDefault[];
+extern const char kGenericExperimentChoiceEnabled[];
+extern const char kGenericExperimentChoiceDisabled[];
+extern const char kGenericExperimentChoiceAutomatic[];
+
// FeatureEntry is used to describe an experimental feature.
//
// Note that features should eventually be either turned on by default with no
@@ -59,14 +65,14 @@ struct FeatureEntry {
FEATURE_VALUE,
// Corresponds to a base::Feature and additional options [O_1, ..., O_n]
- // that specify variation parameters. Each of the options can specify a set
- // of variation parameters. The entry will have n+3 states: Default,
- // Enabled, Enabled V_1, ..., Enabled: V_n, Disabled. When set to Default,
- // the normal default values of the feature and of the parameters are used
- // (possibly passed from the server in a trial config). When set to Enabled,
- // the feature is overriden to be enabled and empty set of parameters is
- // used boiling down to the default behavior in the code.
- FEATURE_WITH_VARIATIONS_VALUE,
+ // that specify field trial params. Each of the options can specify a set
+ // of field trial params. The entry will have n+3 states: Default, Enabled,
+ // Enabled V_1, ..., Enabled: V_n, Disabled. When set to Default, the normal
+ // default values of the feature and of the parameters are used (possibly
+ // passed from the server in a trial config). When set to Enabled, the
+ // feature is overriden to be enabled and empty set of parameters is used
+ // boiling down to the default behavior in the code.
+ FEATURE_WITH_PARAMS_VALUE,
};
// Describes state of a feature.
@@ -82,8 +88,8 @@ struct FeatureEntry {
// Used for MULTI_VALUE types to describe one of the possible values the user
// can select.
struct Choice {
- // ID of the message containing the choice name.
- int description_id;
+ // The message containing the choice name.
+ const char* description;
// Command line switch and value to enabled for this choice.
const char* command_line_switch;
@@ -120,11 +126,11 @@ struct FeatureEntry {
// name of existing flags.
const char* internal_name;
- // String id of the message containing the feature's name.
- int visible_name_id;
+ // The feature's name.
+ const char* visible_name;
- // String id of the message containing the feature's description.
- int visible_description_id;
+ // The feature's description.
+ const char* visible_description;
// The platforms the feature is available on.
// Needs to be more than a compile-time #ifdef because of profile sync.
diff --git a/chromium/components/flags_ui/feature_entry_macros.h b/chromium/components/flags_ui/feature_entry_macros.h
index 530fbc595b5..e474374de19 100644
--- a/chromium/components/flags_ui/feature_entry_macros.h
+++ b/chromium/components/flags_ui/feature_entry_macros.h
@@ -32,10 +32,9 @@
#define FEATURE_VALUE_TYPE(feature) \
flags_ui::FeatureEntry::FEATURE_VALUE, nullptr, nullptr, nullptr, nullptr, \
&feature, 3, nullptr, nullptr, nullptr
-// TODO(jkrcal): Rename FEATURE_WITH_VARIATIONS* to FEATURE_WITH_PARAMS*.
-#define FEATURE_WITH_VARIATIONS_VALUE_TYPE(feature, feature_variations, \
- feature_trial) \
- flags_ui::FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE, nullptr, nullptr, \
+#define FEATURE_WITH_PARAMS_VALUE_TYPE(feature, feature_variations, \
+ feature_trial) \
+ flags_ui::FeatureEntry::FEATURE_WITH_PARAMS_VALUE, nullptr, nullptr, \
nullptr, nullptr, &feature, 3 + arraysize(feature_variations), nullptr, \
feature_variations, feature_trial
diff --git a/chromium/components/flags_ui/flags_state.cc b/chromium/components/flags_ui/flags_state.cc
index f0c754a9fcf..d89c3629c35 100644
--- a/chromium/components/flags_ui/flags_state.cc
+++ b/chromium/components/flags_ui/flags_state.cc
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "base/metrics/field_trial.h"
#include "base/stl_util.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
@@ -105,7 +106,7 @@ void AddInternalName(const FeatureEntry& e, std::set<std::string>* names) {
case FeatureEntry::MULTI_VALUE:
case FeatureEntry::ENABLE_DISABLE_VALUE:
case FeatureEntry::FEATURE_VALUE:
- case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
+ case FeatureEntry::FEATURE_WITH_PARAMS_VALUE:
for (int i = 0; i < e.num_options; ++i)
names->insert(e.NameForOption(i));
break;
@@ -140,7 +141,7 @@ bool ValidateFeatureEntry(const FeatureEntry& e) {
DCHECK(!e.choices);
DCHECK(e.feature);
return true;
- case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
+ case FeatureEntry::FEATURE_WITH_PARAMS_VALUE:
DCHECK_GT(e.num_options, 2);
DCHECK(!e.choices);
DCHECK(e.feature);
@@ -162,7 +163,7 @@ bool IsDefaultValue(const FeatureEntry& entry,
case FeatureEntry::MULTI_VALUE:
case FeatureEntry::ENABLE_DISABLE_VALUE:
case FeatureEntry::FEATURE_VALUE:
- case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
+ case FeatureEntry::FEATURE_WITH_PARAMS_VALUE:
for (int i = 0; i < entry.num_options; ++i) {
if (enabled_entries.count(entry.NameForOption(i)) > 0)
return false;
@@ -179,7 +180,7 @@ base::Value* CreateOptionsData(const FeatureEntry& entry,
DCHECK(entry.type == FeatureEntry::MULTI_VALUE ||
entry.type == FeatureEntry::ENABLE_DISABLE_VALUE ||
entry.type == FeatureEntry::FEATURE_VALUE ||
- entry.type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE);
+ entry.type == FeatureEntry::FEATURE_WITH_PARAMS_VALUE);
base::ListValue* result = new base::ListValue;
for (int i = 0; i < entry.num_options; ++i) {
std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue);
@@ -389,13 +390,13 @@ void FlagsState::RemoveFlagsSwitches(
const std::string& existing_value_utf8 = existing_value;
#endif
- std::vector<std::string> features =
+ std::vector<base::StringPiece> features =
base::FeatureList::SplitFeatureListString(existing_value_utf8);
- std::vector<std::string> remaining_features;
+ std::vector<base::StringPiece> remaining_features;
// For any featrue name in |features| that is not in |switch_added_values| -
// i.e. it wasn't added by about_flags code, add it to |remaining_features|.
- for (const std::string& feature : features) {
- if (!base::ContainsKey(switch_added_values, feature))
+ for (const auto& feature : features) {
+ if (!base::ContainsKey(switch_added_values, feature.as_string()))
remaining_features.push_back(feature);
}
@@ -440,7 +441,7 @@ std::vector<std::string> FlagsState::RegisterAllFeatureVariationParameters(
// First collect all the data for each trial.
for (size_t i = 0; i < num_feature_entries_; ++i) {
const FeatureEntry& e = feature_entries_[i];
- if (e.type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE) {
+ if (e.type == FeatureEntry::FEATURE_WITH_PARAMS_VALUE) {
for (int j = 0; j < e.num_options; ++j) {
if (e.StateForOption(j) == FeatureEntry::FeatureState::ENABLED &&
enabled_entries.count(e.NameForOption(j))) {
@@ -510,9 +511,9 @@ void FlagsState::GetFlagFeatureEntries(
std::unique_ptr<base::DictionaryValue> data(new base::DictionaryValue());
data->SetString("internal_name", entry.internal_name);
- data->SetString("name", l10n_util::GetStringUTF16(entry.visible_name_id));
+ data->SetString("name", base::StringPiece(entry.visible_name));
data->SetString("description",
- l10n_util::GetStringUTF16(entry.visible_description_id));
+ base::StringPiece(entry.visible_description));
base::ListValue* supported_platforms = new base::ListValue();
AddOsStrings(entry.supported_platforms, supported_platforms);
@@ -533,7 +534,7 @@ void FlagsState::GetFlagFeatureEntries(
case FeatureEntry::MULTI_VALUE:
case FeatureEntry::ENABLE_DISABLE_VALUE:
case FeatureEntry::FEATURE_VALUE:
- case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
+ case FeatureEntry::FEATURE_WITH_PARAMS_VALUE:
data->Set("options", CreateOptionsData(entry, enabled_entries));
break;
}
@@ -683,7 +684,7 @@ void FlagsState::MergeFeatureCommandLineSwitch(
base::CommandLine* command_line) {
std::string original_switch_value =
command_line->GetSwitchValueASCII(switch_name);
- std::vector<std::string> features =
+ std::vector<base::StringPiece> features =
base::FeatureList::SplitFeatureListString(original_switch_value);
// Only add features that don't already exist in the lists.
// Note: The base::ContainsValue() call results in O(n^2) performance, but in
@@ -783,7 +784,7 @@ void FlagsState::GenerateFlagsToSwitchesMapping(
e.disable_command_line_value, name_to_switch_map);
break;
case FeatureEntry::FEATURE_VALUE:
- case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
+ case FeatureEntry::FEATURE_WITH_PARAMS_VALUE:
for (int j = 0; j < e.num_options; ++j) {
FeatureEntry::FeatureState state = e.StateForOption(j);
if (state == FeatureEntry::FeatureState::DEFAULT) {
diff --git a/chromium/components/flags_ui/flags_state_unittest.cc b/chromium/components/flags_ui/flags_state_unittest.cc
index 658f021a739..6b396e116b5 100644
--- a/chromium/components/flags_ui/flags_state_unittest.cc
+++ b/chromium/components/flags_ui/flags_state_unittest.cc
@@ -83,10 +83,8 @@ const FeatureEntry::FeatureVariation kTestVariations1[] = {
const FeatureEntry::FeatureVariation kTestVariations2[] = {
{"dummy description 2", kTestVariationOther2, 1, nullptr}};
-// Those have to be valid ids for the translation system but the value are
-// never used, so pick one at random from the current component.
-const int kDummyNameId = IDS_FLAGS_UI_WARNING_HEADER;
-const int kDummyDescriptionId = IDS_FLAGS_UI_WARNING_TEXT;
+const char* kDummyName = nullptr;
+const char* kDummyDescription = nullptr;
bool SkipFeatureEntry(const FeatureEntry& feature_entry) {
return false;
@@ -95,52 +93,52 @@ bool SkipFeatureEntry(const FeatureEntry& feature_entry) {
} // namespace
const FeatureEntry::Choice kMultiChoices[] = {
- {kDummyDescriptionId, "", ""},
- {kDummyDescriptionId, kMultiSwitch1, ""},
- {kDummyDescriptionId, kMultiSwitch2, kValueForMultiSwitch2},
+ {kDummyDescription, "", ""},
+ {kDummyDescription, kMultiSwitch1, ""},
+ {kDummyDescription, kMultiSwitch2, kValueForMultiSwitch2},
};
// The entries that are set for these tests. The 3rd entry is not supported on
// the current platform, all others are.
static FeatureEntry kEntries[] = {
- {kFlags1, kDummyNameId, kDummyDescriptionId,
+ {kFlags1, kDummyName, kDummyDescription,
0, // Ends up being mapped to the current platform.
FeatureEntry::SINGLE_VALUE, kSwitch1, "", nullptr, nullptr, nullptr, 0,
nullptr, nullptr, nullptr},
- {kFlags2, kDummyNameId, kDummyDescriptionId,
+ {kFlags2, kDummyName, kDummyDescription,
0, // Ends up being mapped to the current platform.
FeatureEntry::SINGLE_VALUE, kSwitch2, kValueForSwitch2, nullptr, nullptr,
nullptr, 0, nullptr, nullptr, nullptr},
- {kFlags3, kDummyNameId, kDummyDescriptionId,
+ {kFlags3, kDummyName, kDummyDescription,
0, // This ends up enabling for an OS other than the current.
FeatureEntry::SINGLE_VALUE, kSwitch3, "", nullptr, nullptr, nullptr, 0,
nullptr, nullptr, nullptr},
- {kFlags4, kDummyNameId, kDummyDescriptionId,
+ {kFlags4, kDummyName, kDummyDescription,
0, // Ends up being mapped to the current platform.
FeatureEntry::MULTI_VALUE, "", "", "", "", nullptr,
arraysize(kMultiChoices), kMultiChoices, nullptr, nullptr},
- {kFlags5, kDummyNameId, kDummyDescriptionId,
+ {kFlags5, kDummyName, kDummyDescription,
0, // Ends up being mapped to the current platform.
FeatureEntry::ENABLE_DISABLE_VALUE, kSwitch1, kEnableDisableValue1,
kSwitch2, kEnableDisableValue2, nullptr, 3, nullptr, nullptr, nullptr},
- {kFlags6, kDummyNameId, kDummyDescriptionId, 0,
+ {kFlags6, kDummyName, kDummyDescription, 0,
FeatureEntry::SINGLE_DISABLE_VALUE, kSwitch6, "", nullptr, nullptr,
nullptr, 0, nullptr, nullptr, nullptr},
- {kFlags7, kDummyNameId, kDummyDescriptionId,
+ {kFlags7, kDummyName, kDummyDescription,
0, // Ends up being mapped to the current platform.
FeatureEntry::FEATURE_VALUE, nullptr, nullptr, nullptr, nullptr,
&kTestFeature1, 3, nullptr, nullptr, nullptr},
- {kFlags8, kDummyNameId, kDummyDescriptionId,
+ {kFlags8, kDummyName, kDummyDescription,
0, // Ends up being mapped to the current platform.
- FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE, nullptr, nullptr, nullptr,
+ FeatureEntry::FEATURE_WITH_PARAMS_VALUE, nullptr, nullptr, nullptr,
nullptr, &kTestFeature1, 4, nullptr, kTestVariations1, kTestTrial},
- {kFlags9, kDummyNameId, kDummyDescriptionId,
+ {kFlags9, kDummyName, kDummyDescription,
0, // Ends up being mapped to the current platform.
- FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE, nullptr, nullptr, nullptr,
+ FeatureEntry::FEATURE_WITH_PARAMS_VALUE, nullptr, nullptr, nullptr,
nullptr, &kTestFeature1, 4, nullptr, kTestVariations1, kTestTrial},
- {kFlags10, kDummyNameId, kDummyDescriptionId,
+ {kFlags10, kDummyName, kDummyDescription,
0, // Ends up being mapped to the current platform.
- FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE, nullptr, nullptr, nullptr,
+ FeatureEntry::FEATURE_WITH_PARAMS_VALUE, nullptr, nullptr, nullptr,
nullptr, &kTestFeature2, 4, nullptr, kTestVariations2, kTestTrial},
};
diff --git a/chromium/components/flags_ui/pref_service_flags_storage.cc b/chromium/components/flags_ui/pref_service_flags_storage.cc
index 3c6ddc4dd77..2153c1bf6be 100644
--- a/chromium/components/flags_ui/pref_service_flags_storage.cc
+++ b/chromium/components/flags_ui/pref_service_flags_storage.cc
@@ -26,7 +26,7 @@ std::set<std::string> PrefServiceFlagsStorage::GetFlags() {
for (base::ListValue::const_iterator it = enabled_experiments->begin();
it != enabled_experiments->end(); ++it) {
std::string experiment_name;
- if (!(*it)->GetAsString(&experiment_name)) {
+ if (!it->GetAsString(&experiment_name)) {
LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments;
continue;
}
diff --git a/chromium/components/flags_ui_strings.grdp b/chromium/components/flags_ui_strings.grdp
index cc86c24d08f..3fbc8f3e325 100644
--- a/chromium/components/flags_ui_strings.grdp
+++ b/chromium/components/flags_ui_strings.grdp
@@ -46,18 +46,6 @@
Flags that apply system-wide can only be set by the owner: <ph name="OWNER_EMAIL">$1<ex>owner@example.com</ex></ph>.
</message>
</if>
- <message name="IDS_GENERIC_EXPERIMENT_CHOICE_AUTOMATIC" desc="Generic 'Automatic' experiment choice option name.">
- Automatic
- </message>
- <message name="IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT" desc="Generic 'Default' experiment choice option name. E.G. shown in multi value options in about:flags.">
- Default
- </message>
- <message name="IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED" desc="Generic 'Enabled' experiment choice option name. E.G. shown in multi value options in about:flags.">
- Enabled
- </message>
- <message name="IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED" desc="Generic 'Disabled' experiment choice option name. E.G. shown in multi value options in about:flags.">
- Disabled
- </message>
<if expr="is_ios">
<message name="IDS_FLAGS_UI_ALTERNATIVES_UI_TABLE_TITLE" desc="Title for the features table on the about:ui_alternatives page.">
UI Alternatives
diff --git a/chromium/components/font_service/font_service_app.cc b/chromium/components/font_service/font_service_app.cc
index 78f6d4a336b..5dfe5f919ee 100644
--- a/chromium/components/font_service/font_service_app.cc
+++ b/chromium/components/font_service/font_service_app.cc
@@ -9,8 +9,6 @@
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "mojo/public/cpp/system/platform_handle.h"
-#include "services/service_manager/public/cpp/connection.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
#include "services/service_manager/public/cpp/service_context.h"
static_assert(
@@ -41,7 +39,9 @@ base::File GetFileForPath(const base::FilePath& path) {
namespace font_service {
-FontServiceApp::FontServiceApp() {}
+FontServiceApp::FontServiceApp() {
+ registry_.AddInterface(this);
+}
FontServiceApp::~FontServiceApp() {}
@@ -49,10 +49,12 @@ void FontServiceApp::OnStart() {
tracing_.Initialize(context()->connector(), context()->identity().name());
}
-bool FontServiceApp::OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) {
- registry->AddInterface(this);
- return true;
+void FontServiceApp::OnBindInterface(
+ const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
}
void FontServiceApp::Create(
diff --git a/chromium/components/font_service/font_service_app.h b/chromium/components/font_service/font_service_app.h
index 39f2d33db95..ddad2541748 100644
--- a/chromium/components/font_service/font_service_app.h
+++ b/chromium/components/font_service/font_service_app.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "components/font_service/public/interfaces/font_service.mojom.h"
#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/interface_factory.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/tracing/public/cpp/provider.h"
@@ -29,8 +30,9 @@ class FontServiceApp
private:
// service_manager::Service:
void OnStart() override;
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
// service_manager::InterfaceFactory<mojom::FontService>:
void Create(const service_manager::Identity& remote_identity,
@@ -45,6 +47,7 @@ class FontServiceApp
int FindOrAddPath(const SkString& path);
+ service_manager::BinderRegistry registry_;
mojo::BindingSet<mojom::FontService> bindings_;
tracing::Provider tracing_;
diff --git a/chromium/components/google/core/browser/BUILD.gn b/chromium/components/google/core/browser/BUILD.gn
index 67f502e105c..96ada900a71 100644
--- a/chromium/components/google/core/browser/BUILD.gn
+++ b/chromium/components/google/core/browser/BUILD.gn
@@ -17,16 +17,19 @@ static_library("browser") {
"google_util.h",
]
- deps = [
+ public_deps = [
"//base",
- "//components/data_use_measurement/core",
"//components/keyed_service/core",
+ "//net",
+ "//url",
+ ]
+
+ deps = [
+ "//components/data_use_measurement/core",
"//components/pref_registry",
"//components/prefs",
"//components/strings",
"//components/url_formatter",
- "//net",
- "//url",
]
}
diff --git a/chromium/components/google/core/browser/google_url_tracker.cc b/chromium/components/google/core/browser/google_url_tracker.cc
index 0e10272068f..e16f3277604 100644
--- a/chromium/components/google/core/browser/google_url_tracker.cc
+++ b/chromium/components/google/core/browser/google_url_tracker.cc
@@ -20,6 +20,7 @@
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "net/base/load_flags.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_status.h"
@@ -73,14 +74,9 @@ void GoogleURLTracker::RegisterProfilePrefs(
registry->RegisterStringPref(prefs::kLastPromptedGoogleURL, std::string());
}
-void GoogleURLTracker::RequestServerCheck(bool force) {
- // If this instance already has a fetcher, SetNeedToFetch() is unnecessary,
- // and changing |already_fetched_| is wrong.
- if (!fetcher_) {
- if (force)
- already_fetched_ = false;
+void GoogleURLTracker::RequestServerCheck() {
+ if (!fetcher_)
SetNeedToFetch();
- }
}
std::unique_ptr<GoogleURLTracker::Subscription>
@@ -166,8 +162,40 @@ void GoogleURLTracker::StartFetchIfDesirable() {
return;
already_fetched_ = true;
- fetcher_ = net::URLFetcher::Create(fetcher_id_, GURL(kSearchDomainCheckURL),
- net::URLFetcher::GET, this);
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("google_url_tracker", R"(
+ semantics {
+ sender: "Google URL Tracker"
+ description:
+ "When the user's default search engine is Google, or Google "
+ "services are used to resolve navigation errors, the browser needs "
+ "to know the ideal origin for requests to Google services. In "
+ "these cases the browser makes a request to a global Google "
+ "service that returns this origin, potentially taking into account "
+ "the user's cookies or IP address."
+ trigger: "Browser startup or network change."
+ data: "None."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: true
+ cookies_store: "user"
+ setting:
+ "To disable this check, users can change the default search engine "
+ "to something other than Google, and disable 'Use a web service to "
+ "help resolve navigation errors' in Chromium's settings under "
+ "Privacy.\nAlternately, running Chromium with "
+ "--google-base-url=\"https://www.google.com/\" will disable this, "
+ "and force Chromium to use the specified URL for Google service "
+ "requests.\nFinally, running Chromium with "
+ "--disable-background-networking will disable this, as well as "
+ "various other features that make network requests automatically."
+ policy_exception_justification:
+ "Not implemented."
+ })");
+ fetcher_ =
+ net::URLFetcher::Create(fetcher_id_, GURL(kSearchDomainCheckURL),
+ net::URLFetcher::GET, this, traffic_annotation);
data_use_measurement::DataUseUserData::AttachToFetcher(
fetcher_.get(),
data_use_measurement::DataUseUserData::GOOGLE_URL_TRACKER);
diff --git a/chromium/components/google/core/browser/google_url_tracker.h b/chromium/components/google/core/browser/google_url_tracker.h
index 27496a6af79..5d0ba62a4e3 100644
--- a/chromium/components/google/core/browser/google_url_tracker.h
+++ b/chromium/components/google/core/browser/google_url_tracker.h
@@ -65,13 +65,11 @@ class GoogleURLTracker
const GURL& google_url() const { return google_url_; }
// Requests that the tracker perform a server check to update the Google URL
- // as necessary. If |force| is false, this will happen at most once per
- // network change, not sooner than five seconds after startup (checks
- // requested before that time will occur then; checks requested afterwards
- // will occur immediately, if no other checks have been made during this run).
- // If |force| is true, and the tracker has already performed any requested
- // check, it will check again.
- void RequestServerCheck(bool force);
+ // as necessary. This will happen at most once per network change, not sooner
+ // than five seconds after startup (checks requested before that time will
+ // occur then; checks requested afterwards will occur immediately, if no other
+ // checks have been made during this run).
+ void RequestServerCheck();
std::unique_ptr<Subscription> RegisterCallback(
const OnGoogleURLUpdatedCallback& cb);
diff --git a/chromium/components/google/core/browser/google_url_tracker_unittest.cc b/chromium/components/google/core/browser/google_url_tracker_unittest.cc
index f6c325a00f8..eed326c70f8 100644
--- a/chromium/components/google/core/browser/google_url_tracker_unittest.cc
+++ b/chromium/components/google/core/browser/google_url_tracker_unittest.cc
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/google/core/browser/google_pref_names.h"
#include "components/google/core/browser/google_url_tracker_client.h"
@@ -132,7 +133,7 @@ class GoogleURLTrackerTest : public testing::Test {
void clear_listener_notified() { listener_.clear_notified(); }
private:
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
TestingPrefServiceSimple prefs_;
// Creating this allows us to call
diff --git a/chromium/components/guest_view/browser/guest_view_base.cc b/chromium/components/guest_view/browser/guest_view_base.cc
index 606a47060b4..4a260c65b66 100644
--- a/chromium/components/guest_view/browser/guest_view_base.cc
+++ b/chromium/components/guest_view/browser/guest_view_base.cc
@@ -39,8 +39,8 @@ namespace guest_view {
namespace {
using WebContentsGuestViewMap = std::map<const WebContents*, GuestViewBase*>;
-static base::LazyInstance<WebContentsGuestViewMap> webcontents_guestview_map =
- LAZY_INSTANCE_INITIALIZER;
+static base::LazyInstance<WebContentsGuestViewMap>::DestructorAtExit
+ webcontents_guestview_map = LAZY_INSTANCE_INITIALIZER;
} // namespace
@@ -75,7 +75,7 @@ class GuestViewBase::OwnerContentsObserver : public WebContentsObserver {
// If the embedder navigates to a different page then destroy the guest.
if (!navigation_handle->IsInMainFrame() ||
!navigation_handle->HasCommitted() ||
- navigation_handle->IsSamePage()) {
+ navigation_handle->IsSameDocument()) {
return;
}
@@ -139,7 +139,7 @@ class GuestViewBase::OwnerContentsObserver : public WebContentsObserver {
if (destroyed_)
return;
destroyed_ = true;
- guest_->Destroy();
+ guest_->Destroy(true);
}
DISALLOW_COPY_AND_ASSIGN(OwnerContentsObserver);
@@ -161,7 +161,7 @@ class GuestViewBase::OpenerLifetimeObserver : public WebContentsObserver {
return;
// If the opener is destroyed then destroy the guest.
- guest_->Destroy();
+ guest_->Destroy(true);
}
private:
@@ -442,7 +442,7 @@ void GuestViewBase::DidDetach() {
element_instance_id_));
element_instance_id_ = kInstanceIDNone;
if (!CanRunInDetachedState())
- Destroy();
+ Destroy(true);
}
bool GuestViewBase::HandleFindForEmbedder(
@@ -477,7 +477,7 @@ const GURL& GuestViewBase::GetOwnerSiteURL() const {
return owner_web_contents()->GetLastCommittedURL();
}
-void GuestViewBase::Destroy() {
+void GuestViewBase::Destroy(bool also_delete) {
if (is_being_destroyed_)
return;
@@ -510,7 +510,8 @@ void GuestViewBase::Destroy() {
RemoveGuest(guest_instance_id_);
pending_events_.clear();
- delete web_contents();
+ if (also_delete)
+ delete web_contents();
}
void GuestViewBase::SetAttachParams(const base::DictionaryValue& params) {
@@ -598,6 +599,8 @@ void GuestViewBase::RenderViewReady() {
}
void GuestViewBase::WebContentsDestroyed() {
+ Destroy(false);
+
// Let the derived class know that its WebContents is in the process of
// being destroyed. web_contents() is still valid at this point.
// TODO(fsamuel): This allows for reentrant code into WebContents during
@@ -695,9 +698,9 @@ bool GuestViewBase::ShouldFocusPageAfterCrash() {
bool GuestViewBase::PreHandleGestureEvent(WebContents* source,
const blink::WebGestureEvent& event) {
- return event.type() == blink::WebGestureEvent::GesturePinchBegin ||
- event.type() == blink::WebGestureEvent::GesturePinchUpdate ||
- event.type() == blink::WebGestureEvent::GesturePinchEnd;
+ return event.GetType() == blink::WebGestureEvent::kGesturePinchBegin ||
+ event.GetType() == blink::WebGestureEvent::kGesturePinchUpdate ||
+ event.GetType() == blink::WebGestureEvent::kGesturePinchEnd;
}
void GuestViewBase::UpdatePreferredSize(WebContents* target_web_contents,
diff --git a/chromium/components/guest_view/browser/guest_view_base.h b/chromium/components/guest_view/browser/guest_view_base.h
index 42e3734eff9..c900a11b01f 100644
--- a/chromium/components/guest_view/browser/guest_view_base.h
+++ b/chromium/components/guest_view/browser/guest_view_base.h
@@ -192,7 +192,7 @@ class GuestViewBase : public content::BrowserPluginGuestDelegate,
int proxy_routing_id() const { return guest_proxy_routing_id_; }
// Destroy this guest.
- void Destroy();
+ void Destroy(bool also_delete);
// Saves the attach state of the custom element hosting this GuestView.
void SetAttachParams(const base::DictionaryValue& params);
@@ -451,7 +451,8 @@ class GuestViewBase : public content::BrowserPluginGuestDelegate,
std::unique_ptr<base::DictionaryValue> attach_params_;
// This observer ensures that this guest self-destructs if the embedder goes
- // away.
+ // away. It also tracks when the embedder's fullscreen is toggled or when its
+ // page scale factor changes so the guest can change itself accordingly.
std::unique_ptr<OwnerContentsObserver> owner_contents_observer_;
// This observer ensures that if the guest is unattached and its opener goes
diff --git a/chromium/components/guest_view/browser/guest_view_manager.cc b/chromium/components/guest_view/browser/guest_view_manager.cc
index 315ea635bfd..1c68e13912c 100644
--- a/chromium/components/guest_view/browser/guest_view_manager.cc
+++ b/chromium/components/guest_view/browser/guest_view_manager.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/macros.h"
+#include "base/metrics/user_metrics.h"
#include "base/strings/stringprintf.h"
#include "components/guest_view/browser/guest_view_base.h"
#include "components/guest_view/browser/guest_view_manager_delegate.h"
@@ -17,7 +18,6 @@
#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 "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/child_process_host.h"
#include "content/public/common/result_codes.h"
@@ -129,7 +129,7 @@ void GuestViewManager::AttachGuest(int embedder_process_id,
auto* old_guest_view =
GuestViewBase::From(embedder_process_id, old_guest_instance_id);
- old_guest_view->Destroy();
+ old_guest_view->Destroy(true);
}
instance_id_map_[key] = guest_instance_id;
reverse_instance_id_map_[guest_instance_id] = key;
@@ -411,8 +411,7 @@ bool GuestViewManager::CanEmbedderAccessInstanceIDMaybeKill(
if (!CanEmbedderAccessInstanceID(embedder_render_process_id,
guest_instance_id)) {
// The embedder process is trying to access a guest it does not own.
- content::RecordAction(
- base::UserMetricsAction("BadMessageTerminate_BPGM"));
+ base::RecordAction(base::UserMetricsAction("BadMessageTerminate_BPGM"));
content::RenderProcessHost::FromID(embedder_render_process_id)
->Shutdown(content::RESULT_CODE_KILLED_BAD_MESSAGE, false);
return false;
diff --git a/chromium/components/guest_view/renderer/BUILD.gn b/chromium/components/guest_view/renderer/BUILD.gn
index df68a0ed028..c78feedc49e 100644
--- a/chromium/components/guest_view/renderer/BUILD.gn
+++ b/chromium/components/guest_view/renderer/BUILD.gn
@@ -21,8 +21,11 @@ static_library("renderer") {
"//components/guest_view/common",
"//content/public/common",
"//content/public/renderer",
- "//ipc",
"//third_party/WebKit/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 890fb3628c6..cc01a13e096 100644
--- a/chromium/components/guest_view/renderer/guest_view_container.cc
+++ b/chromium/components/guest_view/renderer/guest_view_container.cc
@@ -18,8 +18,8 @@
namespace {
using GuestViewContainerMap = std::map<int, guest_view::GuestViewContainer*>;
-static base::LazyInstance<GuestViewContainerMap> g_guest_view_container_map =
- LAZY_INSTANCE_INITIALIZER;
+static base::LazyInstance<GuestViewContainerMap>::DestructorAtExit
+ g_guest_view_container_map = LAZY_INSTANCE_INITIALIZER;
} // namespace
diff --git a/chromium/components/guest_view/renderer/guest_view_request.cc b/chromium/components/guest_view/renderer/guest_view_request.cc
index 1d26c3f4462..ea96bc9b3c7 100644
--- a/chromium/components/guest_view/renderer/guest_view_request.cc
+++ b/chromium/components/guest_view/renderer/guest_view_request.cc
@@ -90,15 +90,14 @@ void GuestViewAttachRequest::HandleResponse(const IPC::Message& message) {
return;
v8::HandleScope handle_scope(isolate());
- blink::WebFrame* frame = guest_proxy_render_view->GetWebView()->mainFrame();
+ blink::WebFrame* frame = guest_proxy_render_view->GetWebView()->MainFrame();
// TODO(lazyboy,nasko): The WebLocalFrame branch is not used when running
// on top of out-of-process iframes. Remove it once the code is converted.
v8::Local<v8::Value> window;
- if (frame->isWebLocalFrame()) {
- window = frame->mainWorldScriptContext()->Global();
+ if (frame->IsWebLocalFrame()) {
+ window = frame->MainWorldScriptContext()->Global();
} else {
- window =
- frame->toWebRemoteFrame()->deprecatedMainWorldScriptContext()->Global();
+ window = frame->ToWebRemoteFrame()->GlobalProxy();
}
const int argc = 1;
diff --git a/chromium/components/history/core/browser/BUILD.gn b/chromium/components/history/core/browser/BUILD.gn
index 3e89493c14b..e60183b62e9 100644
--- a/chromium/components/history/core/browser/BUILD.gn
+++ b/chromium/components/history/core/browser/BUILD.gn
@@ -66,6 +66,10 @@ static_library("browser") {
"top_sites_observer.h",
"typed_url_data_type_controller.cc",
"typed_url_data_type_controller.h",
+ "typed_url_sync_bridge.cc",
+ "typed_url_sync_bridge.h",
+ "typed_url_sync_metadata_database.cc",
+ "typed_url_sync_metadata_database.h",
"typed_url_syncable_service.cc",
"typed_url_syncable_service.h",
"url_database.cc",
@@ -88,6 +92,7 @@ static_library("browser") {
]
public_deps = [
+ "//components/sync/protocol",
"//skia",
]
@@ -187,6 +192,7 @@ source_set("unit_tests") {
"history_backend_db_unittest.cc",
"history_backend_unittest.cc",
"history_database_unittest.cc",
+ "history_model_worker_unittest.cc",
"history_querying_unittest.cc",
"history_service_unittest.cc",
"history_types_unittest.cc",
@@ -194,6 +200,7 @@ source_set("unit_tests") {
"top_sites_cache_unittest.cc",
"top_sites_database_unittest.cc",
"top_sites_impl_unittest.cc",
+ "typed_url_sync_metadata_database_unittest.cc",
"typed_url_syncable_service_unittest.cc",
"url_database_unittest.cc",
"url_utils_unittest.cc",
diff --git a/chromium/components/history/core/browser/download_database.cc b/chromium/components/history/core/browser/download_database.cc
index e82f3947ed5..01bb312ad7c 100644
--- a/chromium/components/history/core/browser/download_database.cc
+++ b/chromium/components/history/core/browser/download_database.cc
@@ -273,6 +273,14 @@ bool DownloadDatabase::MigrateDownloadSiteInstanceUrl() {
return EnsureColumnExists("site_url", "VARCHAR NOT NULL DEFAULT ''");
}
+bool DownloadDatabase::MigrateDownloadLastAccessTime() {
+ return EnsureColumnExists("last_access_time", "INTEGER NOT NULL DEFAULT 0");
+}
+
+bool DownloadDatabase::MigrateDownloadTransient() {
+ return EnsureColumnExists("transient", "INTEGER NOT NULL DEFAULT 0");
+}
+
bool DownloadDatabase::InitDownloadTable() {
const char kSchema[] =
"CREATE TABLE downloads ("
@@ -290,6 +298,8 @@ bool DownloadDatabase::InitDownloadTable() {
"end_time INTEGER NOT NULL," // When the download completed.
"opened INTEGER NOT NULL," // 1 if it has ever been opened
// else 0
+ "last_access_time INTEGER NOT NULL," // The last time it was accessed.
+ "transient INTEGER NOT NULL," // 1 if it is transient, else 0.
"referrer VARCHAR NOT NULL," // HTTP Referrer
"site_url VARCHAR NOT NULL," // Site URL for initiating site
// instance.
@@ -380,9 +390,10 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) {
SQL_FROM_HERE,
"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, referrer, "
- "site_url, tab_url, tab_referrer_url, http_method, by_ext_id, "
- "by_ext_name, etag, last_modified FROM downloads ORDER BY start_time"));
+ "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 downloads ORDER BY start_time"));
while (statement_main.Step()) {
std::unique_ptr<DownloadRow> info(new DownloadRow());
@@ -414,6 +425,9 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) {
info->end_time =
base::Time::FromInternalValue(statement_main.ColumnInt64(column++));
info->opened = statement_main.ColumnInt(column++) != 0;
+ info->last_access_time =
+ base::Time::FromInternalValue(statement_main.ColumnInt64(column++));
+ info->transient = statement_main.ColumnInt(column++) != 0;
info->referrer_url = GURL(statement_main.ColumnString(column++));
info->site_url = GURL(statement_main.ColumnString(column++));
info->tab_url = GURL(statement_main.ColumnString(column++));
@@ -531,8 +545,8 @@ bool DownloadDatabase::UpdateDownload(const DownloadRow& data) {
"mime_type=?, original_mime_type=?, "
"received_bytes=?, state=?, "
"danger_type=?, interrupt_reason=?, hash=?, end_time=?, total_bytes=?, "
- "opened=?, by_ext_id=?, by_ext_name=?, etag=?, last_modified=? "
- "WHERE id=?"));
+ "opened=?, last_access_time=?, transient=?, by_ext_id=?, by_ext_name=?, "
+ "etag=?, last_modified=? WHERE id=?"));
int column = 0;
BindFilePath(statement, data.current_path, column++);
BindFilePath(statement, data.target_path, column++);
@@ -547,6 +561,8 @@ bool DownloadDatabase::UpdateDownload(const DownloadRow& data) {
statement.BindInt64(column++, data.end_time.ToInternalValue());
statement.BindInt64(column++, data.total_bytes);
statement.BindInt(column++, (data.opened ? 1 : 0));
+ statement.BindInt64(column++, data.last_access_time.ToInternalValue());
+ statement.BindInt(column++, (data.transient ? 1 : 0));
statement.BindString(column++, data.by_ext_id);
statement.BindString(column++, data.by_ext_name);
statement.BindString(column++, data.etag);
@@ -604,12 +620,13 @@ bool DownloadDatabase::CreateDownload(const DownloadRow& info) {
"INSERT INTO downloads "
"(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, referrer, "
- " site_url, tab_url, tab_referrer_url, http_method, "
+ " 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) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
" ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
- " ?, ?, ?, ?)"));
+ " ?, ?, ?, ?, ?, ?)"));
int column = 0;
statement_insert.BindInt(column++, DownloadIdToInt(info.id));
@@ -629,6 +646,9 @@ bool DownloadDatabase::CreateDownload(const DownloadRow& info) {
statement_insert.BindBlob(column++, info.hash.data(), info.hash.size());
statement_insert.BindInt64(column++, info.end_time.ToInternalValue());
statement_insert.BindInt(column++, info.opened ? 1 : 0);
+ statement_insert.BindInt64(column++,
+ info.last_access_time.ToInternalValue());
+ 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.tab_url.spec());
diff --git a/chromium/components/history/core/browser/download_database.h b/chromium/components/history/core/browser/download_database.h
index 931ad5c03c6..7a80f69eb00 100644
--- a/chromium/components/history/core/browser/download_database.h
+++ b/chromium/components/history/core/browser/download_database.h
@@ -93,6 +93,12 @@ class DownloadDatabase {
// table.
bool MigrateDownloadSiteInstanceUrl();
+ // Returns true if able to add last_access_time column to the download table.
+ bool MigrateDownloadLastAccessTime();
+
+ // Returns true if able to add transient column to the download table.
+ bool MigrateDownloadTransient();
+
// Creates the downloads table if needed.
bool InitDownloadTable();
diff --git a/chromium/components/history/core/browser/download_row.cc b/chromium/components/history/core/browser/download_row.cc
index a377766a5f2..c8a8afc9248 100644
--- a/chromium/components/history/core/browser/download_row.cc
+++ b/chromium/components/history/core/browser/download_row.cc
@@ -15,7 +15,8 @@ DownloadRow::DownloadRow()
danger_type(DownloadDangerType::NOT_DANGEROUS),
interrupt_reason(0),
id(kInvalidDownloadId),
- opened(false) {
+ opened(false),
+ transient(false) {
// |interrupt_reason| is left undefined by this constructor as the value
// has no meaning unless |state| is equal to kStateInterrupted.
}
@@ -31,8 +32,8 @@ DownloadRow::DownloadRow(
const std::string& http_method,
const std::string& mime_type,
const std::string& original_mime_type,
- const base::Time& start,
- const base::Time& end,
+ base::Time start,
+ base::Time end,
const std::string& etag,
const std::string& last_modified,
int64_t received,
@@ -44,6 +45,8 @@ DownloadRow::DownloadRow(
DownloadId id,
const std::string& guid,
bool download_opened,
+ base::Time last_access,
+ bool transient,
const std::string& ext_id,
const std::string& ext_name,
const std::vector<DownloadSliceInfo>& download_slice_info)
@@ -70,6 +73,8 @@ DownloadRow::DownloadRow(
id(id),
guid(guid),
opened(download_opened),
+ last_access_time(last_access),
+ transient(transient),
by_ext_id(ext_id),
by_ext_name(ext_name),
download_slice_info(download_slice_info) {}
@@ -92,7 +97,9 @@ bool DownloadRow::operator==(const DownloadRow& rhs) const {
danger_type == rhs.danger_type &&
interrupt_reason == rhs.interrupt_reason && hash == rhs.hash &&
id == rhs.id && guid == rhs.guid && opened == rhs.opened &&
- by_ext_id == rhs.by_ext_id && by_ext_name == rhs.by_ext_name &&
+ last_access_time == rhs.last_access_time &&
+ transient == rhs.transient && by_ext_id == rhs.by_ext_id &&
+ by_ext_name == rhs.by_ext_name &&
download_slice_info == rhs.download_slice_info;
}
diff --git a/chromium/components/history/core/browser/download_row.h b/chromium/components/history/core/browser/download_row.h
index 1c47635aeed..d6320407a58 100644
--- a/chromium/components/history/core/browser/download_row.h
+++ b/chromium/components/history/core/browser/download_row.h
@@ -33,8 +33,8 @@ struct DownloadRow {
const std::string& http_method,
const std::string& mime_type,
const std::string& original_mime_type,
- const base::Time& start,
- const base::Time& end,
+ base::Time start,
+ base::Time end,
const std::string& etag,
const std::string& last_modified,
int64_t received,
@@ -46,6 +46,8 @@ struct DownloadRow {
DownloadId id,
const std::string& guid,
bool download_opened,
+ base::Time last_access,
+ bool transient,
const std::string& ext_id,
const std::string& ext_name,
const std::vector<DownloadSliceInfo>& download_slice_info);
@@ -134,6 +136,13 @@ struct DownloadRow {
// Whether this download has ever been opened from the browser.
bool opened;
+ // The time when the download was last accessed.
+ base::Time last_access_time;
+
+ // Whether this download is transient. Transient items are cleaned up after
+ // completion and not shown in the UI.
+ bool transient;
+
// The id and name of the extension that created this download.
std::string by_ext_id;
std::string by_ext_name;
diff --git a/chromium/components/history/core/browser/history_backend.cc b/chromium/components/history/core/browser/history_backend.cc
index 62187120cff..dd82dc44197 100644
--- a/chromium/components/history/core/browser/history_backend.cc
+++ b/chromium/components/history/core/browser/history_backend.cc
@@ -15,6 +15,8 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
+#include "base/debug/dump_without_crashing.h"
+#include "base/feature_list.h"
#include "base/files/file_enumerator.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
@@ -39,8 +41,10 @@
#include "components/history/core/browser/in_memory_history_backend.h"
#include "components/history/core/browser/keyword_search_term.h"
#include "components/history/core/browser/page_usage_data.h"
+#include "components/history/core/browser/typed_url_sync_bridge.h"
#include "components/history/core/browser/typed_url_syncable_service.h"
#include "components/history/core/browser/url_utils.h"
+#include "components/sync/driver/sync_driver_switches.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "sql/error_delegate_util.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -52,9 +56,11 @@
#include "base/ios/scoped_critical_action.h"
#endif
+using base::debug::DumpWithoutCrashing;
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
+using syncer::ModelTypeChangeProcessor;
/* The HistoryBackend consists of two components:
@@ -211,7 +217,18 @@ void HistoryBackend::Init(
if (!force_fail)
InitImpl(history_database_params);
delegate_->DBLoaded();
- typed_url_syncable_service_.reset(new TypedUrlSyncableService(this));
+ if (base::FeatureList::IsEnabled(switches::kSyncUSSTypedURL)) {
+ typed_url_sync_bridge_ = base::MakeUnique<TypedURLSyncBridge>(
+ this,
+ base::BindRepeating(
+ &ModelTypeChangeProcessor::Create,
+ // TODO(gangwu): use ReportUnrecoverableError before launch.
+ base::BindRepeating(base::IgnoreResult(&DumpWithoutCrashing))));
+ } else {
+ typed_url_syncable_service_ =
+ base::MakeUnique<TypedUrlSyncableService>(this);
+ }
+
memory_pressure_listener_.reset(new base::MemoryPressureListener(
base::Bind(&HistoryBackend::OnMemoryPressure, base::Unretained(this))));
}
@@ -372,6 +389,19 @@ void HistoryBackend::UpdateVisitDuration(VisitID visit_id, const Time end_ts) {
}
}
+bool HistoryBackend::IsUntypedIntranetHost(const GURL& url) {
+ if (!url.SchemeIs(url::kHttpScheme) && !url.SchemeIs(url::kHttpsScheme) &&
+ !url.SchemeIs(url::kFtpScheme))
+ return false;
+
+ const std::string host = url.host();
+ const size_t registry_length =
+ net::registry_controlled_domains::GetCanonicalHostRegistryLength(
+ host, net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
+ net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
+ return (registry_length == 0) && !db_->IsTypedHost(host);
+}
+
TopHostsList HistoryBackend::TopHosts(size_t num_hosts) const {
if (!db_)
return TopHostsList();
@@ -450,21 +480,13 @@ void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
!ui::PageTransitionCoreTypeIs(request_transition,
ui::PAGE_TRANSITION_TYPED) &&
!is_keyword_generated) {
- const GURL& origin_url(has_redirects ? request.redirects[0] : request.url);
- if (origin_url.SchemeIs(url::kHttpScheme) ||
- origin_url.SchemeIs(url::kHttpsScheme) ||
- origin_url.SchemeIs(url::kFtpScheme)) {
- std::string host(origin_url.host());
- size_t registry_length =
- net::registry_controlled_domains::GetCanonicalHostRegistryLength(
- host,
- net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
- net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
- if (registry_length == 0 && !db_->IsTypedHost(host)) {
- request_transition = ui::PageTransitionFromInt(
- ui::PAGE_TRANSITION_TYPED |
- ui::PageTransitionGetQualifier(request_transition));
- }
+ // Check both the start and end of a redirect chain, since the user will
+ // consider both to have been "navigated to".
+ if (IsUntypedIntranetHost(request.url) ||
+ (has_redirects && IsUntypedIntranetHost(request.redirects[0]))) {
+ request_transition = ui::PageTransitionFromInt(
+ ui::PAGE_TRANSITION_TYPED |
+ ui::PageTransitionGetQualifier(request_transition));
}
}
@@ -629,6 +651,9 @@ void HistoryBackend::InitImpl(
bool kill_db = scheduled_kill_db_;
if (kill_db)
KillHistoryDatabase();
+
+ // The frequency of this UMA will indicate how often history
+ // initialization fails.
UMA_HISTOGRAM_BOOLEAN("History.AttemptedToFixProfileError", kill_db);
} // Falls through.
case sql::INIT_TOO_NEW: {
@@ -726,8 +751,8 @@ void HistoryBackend::CloseAllDatabases() {
void HistoryBackend::RecordTopHostsMetrics(const GURL& url) {
// Convert index from 0-based to 1-based.
- UMA_HISTOGRAM_ENUMERATION("History.TopHostsVisitsByRank",
- HostRankIfAvailable(url) + 1, kMaxTopHosts + 2);
+ UMA_HISTOGRAM_EXACT_LINEAR("History.TopHostsVisitsByRank",
+ HostRankIfAvailable(url) + 1, kMaxTopHosts + 2);
}
std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
@@ -783,7 +808,7 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
NOTREACHED() << "Adding URL failed.";
return std::make_pair(0, 0);
}
- url_info.id_ = url_id;
+ url_info.set_id(url_id);
}
// Add the visit with the time to the database.
@@ -1031,6 +1056,10 @@ TypedUrlSyncableService* HistoryBackend::GetTypedUrlSyncableService() const {
return typed_url_syncable_service_.get();
}
+TypedURLSyncBridge* HistoryBackend::GetTypedURLSyncBridge() const {
+ return typed_url_sync_bridge_.get();
+}
+
// Statistics ------------------------------------------------------------------
HistoryCountResult HistoryBackend::GetHistoryCount(const Time& begin_time,
@@ -1703,38 +1732,26 @@ void HistoryBackend::SetFavicons(const GURL& page_url,
favicon_base::IconType icon_type,
const GURL& icon_url,
const std::vector<SkBitmap>& bitmaps) {
- if (!thumbnail_db_ || !db_)
- return;
-
- DCHECK_GE(kMaxFaviconBitmapsPerIconURL, bitmaps.size());
-
- favicon_base::FaviconID icon_id =
- thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, nullptr);
-
- bool favicon_created = false;
- if (!icon_id) {
- icon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
- favicon_created = true;
- }
-
- bool favicon_data_modified = SetFaviconBitmaps(icon_id, bitmaps);
+ SetFaviconsImpl(page_url, icon_type, icon_url, bitmaps,
+ /*bitmaps_are_expired=*/false);
+}
- std::vector<favicon_base::FaviconID> icon_ids(1u, icon_id);
- bool mapping_changed =
- SetFaviconMappingsForPageAndRedirects(page_url, icon_type, icon_ids);
+bool HistoryBackend::SetLastResortFavicons(
+ const GURL& page_url,
+ favicon_base::IconType icon_type,
+ const GURL& icon_url,
+ const std::vector<SkBitmap>& bitmaps) {
+ if (!thumbnail_db_ || !db_)
+ return false;
- if (mapping_changed) {
- // Notify the UI that this function changed an icon mapping.
- SendFaviconChangedNotificationForPageAndRedirects(page_url);
+ // Verify there's no known data for the page URL.
+ if (thumbnail_db_->GetIconMappingsForPageURL(page_url,
+ /*mapping_data=*/nullptr)) {
+ return false;
}
- if (favicon_data_modified && !favicon_created) {
- // If there was a favicon at |icon_url| prior to SetFavicons() being called,
- // there may be page URLs which also use the favicon at |icon_url|. Notify
- // the UI that the favicon has changed for |icon_url|.
- SendFaviconChangedNotificationForIconURL(icon_url);
- }
- ScheduleCommit();
+ return SetFaviconsImpl(page_url, icon_type, icon_url, bitmaps,
+ /*bitmaps_are_expired=*/true);
}
void HistoryBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) {
@@ -1812,6 +1829,51 @@ void HistoryBackend::SetImportedFavicons(
}
}
+bool HistoryBackend::SetFaviconsImpl(const GURL& page_url,
+ favicon_base::IconType icon_type,
+ const GURL& icon_url,
+ const std::vector<SkBitmap>& bitmaps,
+ bool bitmaps_are_expired) {
+ if (!thumbnail_db_ || !db_)
+ return false;
+
+ DCHECK_GE(kMaxFaviconBitmapsPerIconURL, bitmaps.size());
+
+ favicon_base::FaviconID icon_id =
+ thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type, nullptr);
+
+ bool favicon_created = false;
+ if (!icon_id) {
+ icon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
+ favicon_created = true;
+ }
+
+ bool favicon_data_modified = false;
+ if (favicon_created || !bitmaps_are_expired)
+ favicon_data_modified = SetFaviconBitmaps(icon_id, bitmaps);
+
+ if (favicon_created && bitmaps_are_expired)
+ thumbnail_db_->SetFaviconOutOfDate(icon_id);
+
+ std::vector<favicon_base::FaviconID> icon_ids(1u, icon_id);
+ bool mapping_changed =
+ SetFaviconMappingsForPageAndRedirects(page_url, icon_type, icon_ids);
+
+ if (mapping_changed) {
+ // Notify the UI that this function changed an icon mapping.
+ SendFaviconChangedNotificationForPageAndRedirects(page_url);
+ }
+
+ if (favicon_data_modified && !favicon_created) {
+ // If there was a favicon at |icon_url| prior to SetFavicons() being called,
+ // there may be page URLs which also use the favicon at |icon_url|. Notify
+ // the UI that the favicon has changed for |icon_url|.
+ SendFaviconChangedNotificationForIconURL(icon_url);
+ }
+ ScheduleCommit();
+ return favicon_data_modified;
+}
+
void HistoryBackend::UpdateFaviconMappingsAndFetchImpl(
const GURL* page_url,
const std::vector<GURL>& icon_urls,
diff --git a/chromium/components/history/core/browser/history_backend.h b/chromium/components/history/core/browser/history_backend.h
index 2a62a79decc..f96d2182c87 100644
--- a/chromium/components/history/core/browser/history_backend.h
+++ b/chromium/components/history/core/browser/history_backend.h
@@ -53,6 +53,7 @@ struct HistoryDatabaseParams;
class HistoryDBTask;
class InMemoryHistoryBackend;
class TypedUrlSyncableService;
+class TypedURLSyncBridge;
class HistoryBackendHelper;
class URLDatabase;
@@ -325,6 +326,11 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
const GURL& icon_url,
const std::vector<SkBitmap>& bitmaps);
+ bool SetLastResortFavicons(const GURL& page_url,
+ favicon_base::IconType icon_type,
+ const GURL& icon_url,
+ const std::vector<SkBitmap>& bitmaps);
+
void SetFaviconsOutOfDateForPage(const GURL& page_url);
void SetImportedFavicons(
@@ -395,6 +401,10 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// is owned by |this| object.
virtual TypedUrlSyncableService* GetTypedUrlSyncableService() const;
+ // Returns the sync bridge for syncing typed urls. The returned service
+ // is owned by |this| object.
+ TypedURLSyncBridge* GetTypedURLSyncBridge() const;
+
// Deleting ------------------------------------------------------------------
virtual void DeleteURLs(const std::vector<GURL>& urls);
@@ -514,6 +524,11 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, SetFaviconsReplaceBitmapData);
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest,
SetFaviconsSameFaviconURLForTwoPages);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, SetLastResortFaviconsForEmptyDB);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest,
+ SetLastResortFaviconsForPageInDB);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest,
+ SetLastResortFaviconsForIconInDB);
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest,
UpdateFaviconMappingsAndFetchNoChange);
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, MergeFaviconPageURLNotInDB);
@@ -606,9 +621,12 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// at |cur_visit|.
void GetRedirectsToSpecificVisit(VisitID cur_visit, RedirectList* redirects);
- // Update the visit_duration information in visits table.
+ // Updates the visit_duration information in visits table.
void UpdateVisitDuration(VisitID visit_id, const base::Time end_ts);
+ // Returns whether |url| is on an untyped intranet host.
+ bool IsUntypedIntranetHost(const GURL& url);
+
// Querying ------------------------------------------------------------------
// Backends for QueryHistory. *Basic() handles queries that are not
@@ -656,6 +674,16 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// Favicons ------------------------------------------------------------------
+ // If |bitmaps_are_expired| is true, the icon for |icon_url| will be modified
+ // only if it's not present in the database. In that case, it will be
+ // initially set as expired. Returns whether the new bitmaps were actually
+ // written.
+ bool SetFaviconsImpl(const GURL& page_url,
+ favicon_base::IconType icon_type,
+ const GURL& icon_url,
+ const std::vector<SkBitmap>& bitmaps,
+ bool bitmaps_are_expired);
+
// Used by both UpdateFaviconMappingsAndFetch and GetFavicons.
// If |page_url| is non-null, the icon urls for |page_url| (and all
// redirects) are set to the subset of |icon_urls| for which icons are
@@ -886,10 +914,12 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// List of observers
base::ObserverList<HistoryBackendObserver> observers_;
- // Used to manage syncing of the typed urls datatype. This will be null before
- // Init is called. Defined after observers_ because it unregisters itself as
- // observer during destruction.
+ // Used to manage syncing of the typed urls datatype. They will be null before
+ // Init is called, and only one will be instantiated after Init is called
+ // depending on switches::kSyncUSSTypedURL. Defined after observers_ because
+ // it unregisters itself as observer during destruction.
std::unique_ptr<TypedUrlSyncableService> typed_url_syncable_service_;
+ std::unique_ptr<TypedURLSyncBridge> typed_url_sync_bridge_;
DISALLOW_COPY_AND_ASSIGN(HistoryBackend);
};
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 2fbd5d028a5..939e1c874d8 100644
--- a/chromium/components/history/core/browser/history_backend_db_unittest.cc
+++ b/chromium/components/history/core/browser/history_backend_db_unittest.cc
@@ -765,6 +765,44 @@ TEST_F(HistoryBackendDBTest, MigrateDownloadsSlicesTable) {
}
}
+// Tests that last access time and transient is automatically added when
+// migrating to version 36.
+TEST_F(HistoryBackendDBTest, MigrateDownloadsLastAccessTimeAndTransient) {
+ ASSERT_NO_FATAL_FAILURE(CreateDBVersion(32));
+ {
+ sql::Connection db;
+ ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
+ }
+
+ // Re-open the db using the HistoryDatabase, which should migrate to the
+ // current version.
+ CreateBackendAndDatabase();
+ DeleteBackend();
+ {
+ // Re-open the db for manual manipulation.
+ sql::Connection db;
+ ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
+ // The version should have been updated.
+ int cur_version = HistoryDatabase::GetCurrentVersion();
+ ASSERT_LE(35, 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));
+ }
+ {
+ // The downloads table should have last_access_time and transient
+ // initialized to zero.
+ sql::Statement s(db.GetUniqueStatement(
+ "SELECT last_access_time, transient from downloads"));
+ EXPECT_TRUE(s.Step());
+ EXPECT_EQ(base::Time(), base::Time::FromInternalValue(s.ColumnInt64(0)));
+ EXPECT_EQ(0, s.ColumnInt(1));
+ }
+ }
+}
+
TEST_F(HistoryBackendDBTest, DownloadCreateAndQuery) {
CreateBackendAndDatabase();
@@ -777,6 +815,7 @@ TEST_F(HistoryBackendDBTest, DownloadCreateAndQuery) {
base::Time start_time(base::Time::Now());
base::Time end_time(start_time + base::TimeDelta::FromHours(1));
+ base::Time last_access_time;
DownloadRow download_A(
base::FilePath(FILE_PATH_LITERAL("/path/1")),
@@ -787,14 +826,15 @@ TEST_F(HistoryBackendDBTest, DownloadCreateAndQuery) {
"original/mime-type", start_time, end_time, "etag1", "last_modified_1",
100, 1000, DownloadState::INTERRUPTED, DownloadDangerType::NOT_DANGEROUS,
kTestDownloadInterruptReasonCrash, "hash-value1", 1,
- "FE672168-26EF-4275-A149-FEC25F6A75F9", false, "extension-id",
- "extension-name", std::vector<DownloadSliceInfo>());
+ "FE672168-26EF-4275-A149-FEC25F6A75F9", false, last_access_time, true,
+ "extension-id", "extension-name", std::vector<DownloadSliceInfo>());
ASSERT_TRUE(db_->CreateDownload(download_A));
url_chain.push_back(GURL("http://example.com/d"));
base::Time start_time2(start_time + base::TimeDelta::FromHours(10));
base::Time end_time2(end_time + base::TimeDelta::FromHours(10));
+ base::Time last_access_time2(start_time2 + base::TimeDelta::FromHours(5));
DownloadRow download_B(
base::FilePath(FILE_PATH_LITERAL("/path/3")),
@@ -805,8 +845,8 @@ TEST_F(HistoryBackendDBTest, DownloadCreateAndQuery) {
"original/mime-type2", start_time2, end_time2, "etag2", "last_modified_2",
1001, 1001, DownloadState::COMPLETE, DownloadDangerType::DANGEROUS_FILE,
kTestDownloadInterruptReasonNone, std::string(), 2,
- "b70f3869-7d75-4878-acb4-4caf7026d12b", false, "extension-id",
- "extension-name", std::vector<DownloadSliceInfo>());
+ "b70f3869-7d75-4878-acb4-4caf7026d12b", false, last_access_time2, true,
+ "extension-id", "extension-name", std::vector<DownloadSliceInfo>());
ASSERT_TRUE(db_->CreateDownload(download_B));
EXPECT_EQ(2u, db_->CountDownloads());
@@ -835,6 +875,7 @@ TEST_F(HistoryBackendDBTest, DownloadCreateAndUpdate_VolatileFields) {
base::Time start_time(base::Time::Now());
base::Time end_time(start_time + base::TimeDelta::FromHours(1));
+ base::Time last_access_time(start_time + base::TimeDelta::FromHours(5));
DownloadRow download(
base::FilePath(FILE_PATH_LITERAL("/path/1")),
@@ -845,7 +886,8 @@ TEST_F(HistoryBackendDBTest, DownloadCreateAndUpdate_VolatileFields) {
"original/mime-type", start_time, end_time, "etag1", "last_modified_1",
100, 1000, DownloadState::INTERRUPTED, DownloadDangerType::NOT_DANGEROUS,
3, "some-hash-value", 1, "FE672168-26EF-4275-A149-FEC25F6A75F9", false,
- "extension-id", "extension-name", std::vector<DownloadSliceInfo>());
+ last_access_time, false, "extension-id", "extension-name",
+ std::vector<DownloadSliceInfo>());
db_->CreateDownload(download);
download.current_path =
@@ -861,6 +903,7 @@ TEST_F(HistoryBackendDBTest, DownloadCreateAndUpdate_VolatileFields) {
download.total_bytes += 1;
download.hash = "some-other-hash";
download.opened = !download.opened;
+ download.transient = !download.transient;
download.by_ext_id = "by-new-extension-id";
download.by_ext_name = "by-new-extension-name";
download.etag = "new-etag";
@@ -960,8 +1003,8 @@ TEST_F(HistoryBackendDBTest, DownloadNukeRecordsMissingURLs) {
"application/octet-stream", now, now, std::string(), std::string(), 0,
512, DownloadState::COMPLETE, DownloadDangerType::NOT_DANGEROUS,
kTestDownloadInterruptReasonNone, std::string(), 1,
- "05AF6C8E-E4E0-45D7-B5CE-BC99F7019918", 0, "by_ext_id", "by_ext_name",
- std::vector<DownloadSliceInfo>());
+ "05AF6C8E-E4E0-45D7-B5CE-BC99F7019918", 0, now, false, "by_ext_id",
+ "by_ext_name", std::vector<DownloadSliceInfo>());
// Creating records without any urls should fail.
EXPECT_FALSE(db_->CreateDownload(download));
@@ -1079,6 +1122,7 @@ TEST_F(HistoryBackendDBTest, CreateAndUpdateDownloadingSlice) {
slice_info.push_back(DownloadSliceInfo(id, 500, received));
base::Time start_time(base::Time::Now());
base::Time end_time(start_time + base::TimeDelta::FromHours(1));
+ base::Time last_access_time(start_time + base::TimeDelta::FromHours(5));
DownloadRow download(
base::FilePath(FILE_PATH_LITERAL("/path/1")),
@@ -1089,8 +1133,8 @@ TEST_F(HistoryBackendDBTest, CreateAndUpdateDownloadingSlice) {
"original/mime-type", start_time, end_time, "etag1", "last_modified_1",
received, 1500, DownloadState::INTERRUPTED,
DownloadDangerType::NOT_DANGEROUS, kTestDownloadInterruptReasonCrash,
- "hash-value1", id, "FE672168-26EF-4275-A149-FEC25F6A75F9",
- false, "extension-id", "extension-name", slice_info);
+ "hash-value1", id, "FE672168-26EF-4275-A149-FEC25F6A75F9", false,
+ last_access_time, false, "extension-id", "extension-name", slice_info);
ASSERT_TRUE(db_->CreateDownload(download));
std::vector<DownloadRow> results;
db_->QueryDownloads(&results);
@@ -1115,17 +1159,18 @@ TEST_F(HistoryBackendDBTest, UpdateDownloadWithNewSlice) {
DownloadId id = 1;
base::Time start_time(base::Time::Now());
base::Time end_time(start_time + base::TimeDelta::FromHours(1));
+ base::Time last_access_time(start_time + base::TimeDelta::FromHours(5));
DownloadRow download(
base::FilePath(FILE_PATH_LITERAL("/path/1")),
base::FilePath(FILE_PATH_LITERAL("/path/2")), url_chain,
GURL("http://example.com/referrer"), GURL("http://example.com"),
GURL("http://example.com/tab-url"),
GURL("http://example.com/tab-referrer"), "GET", "mime/type",
- "original/mime-type", start_time, end_time, "etag1", "last_modified_1",
- 0, 1500, DownloadState::INTERRUPTED, DownloadDangerType::NOT_DANGEROUS,
+ "original/mime-type", start_time, end_time, "etag1", "last_modified_1", 0,
+ 1500, DownloadState::INTERRUPTED, DownloadDangerType::NOT_DANGEROUS,
kTestDownloadInterruptReasonCrash, "hash-value1", id,
- "FE672168-26EF-4275-A149-FEC25F6A75F9", false, "extension-id",
- "extension-name", std::vector<DownloadSliceInfo>());
+ "FE672168-26EF-4275-A149-FEC25F6A75F9", false, last_access_time, true,
+ "extension-id", "extension-name", std::vector<DownloadSliceInfo>());
ASSERT_TRUE(db_->CreateDownload(download));
// Add a new slice and call UpdateDownload().
@@ -1153,6 +1198,7 @@ TEST_F(HistoryBackendDBTest, DownloadSliceDeletedIfEmpty) {
slice_info.push_back(DownloadSliceInfo(id, 1500, 0));
base::Time start_time(base::Time::Now());
base::Time end_time(start_time + base::TimeDelta::FromHours(1));
+ base::Time last_access_time(start_time + base::TimeDelta::FromHours(5));
DownloadRow download(
base::FilePath(FILE_PATH_LITERAL("/path/1")),
@@ -1163,8 +1209,8 @@ TEST_F(HistoryBackendDBTest, DownloadSliceDeletedIfEmpty) {
"original/mime-type", start_time, end_time, "etag1", "last_modified_1",
received, 1500, DownloadState::INTERRUPTED,
DownloadDangerType::NOT_DANGEROUS, kTestDownloadInterruptReasonCrash,
- "hash-value1", id, "FE672168-26EF-4275-A149-FEC25F6A75F9",
- false, "extension-id", "extension-name", slice_info);
+ "hash-value1", id, "FE672168-26EF-4275-A149-FEC25F6A75F9", false,
+ last_access_time, true, "extension-id", "extension-name", slice_info);
ASSERT_TRUE(db_->CreateDownload(download));
std::vector<DownloadRow> results;
db_->QueryDownloads(&results);
diff --git a/chromium/components/history/core/browser/history_backend_unittest.cc b/chromium/components/history/core/browser/history_backend_unittest.cc
index b89d0a76ecc..16455290909 100644
--- a/chromium/components/history/core/browser/history_backend_unittest.cc
+++ b/chromium/components/history/core/browser/history_backend_unittest.cc
@@ -30,6 +30,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/histogram_tester.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "components/favicon_base/favicon_usage_data.h"
@@ -282,7 +283,7 @@ class HistoryBackendTestBase : public testing::Test {
URLsModifiedList urls_modified_notifications_;
URLsDeletedList urls_deleted_notifications_;
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
base::FilePath test_dir_;
DISALLOW_COPY_AND_ASSIGN(HistoryBackendTestBase);
@@ -1964,6 +1965,7 @@ TEST_F(HistoryBackendTest, SetFaviconsReplaceBitmapData) {
GetOnlyFaviconBitmap(original_favicon_id, &original_favicon_bitmap));
EXPECT_TRUE(
BitmapColorEqual(SK_ColorBLUE, original_favicon_bitmap.bitmap_data));
+ EXPECT_NE(base::Time(), original_favicon_bitmap.last_updated);
// Call SetFavicons() with completely identical data.
bitmaps[0] = CreateBitmap(SK_ColorBLUE, kSmallEdgeSize);
@@ -1978,6 +1980,7 @@ TEST_F(HistoryBackendTest, SetFaviconsReplaceBitmapData) {
GetOnlyFaviconBitmap(updated_favicon_id, &updated_favicon_bitmap));
EXPECT_TRUE(
BitmapColorEqual(SK_ColorBLUE, updated_favicon_bitmap.bitmap_data));
+ EXPECT_NE(base::Time(), updated_favicon_bitmap.last_updated);
// Call SetFavicons() with a different bitmap of the same size.
bitmaps[0] = CreateBitmap(SK_ColorWHITE, kSmallEdgeSize);
@@ -2068,6 +2071,96 @@ TEST_F(HistoryBackendTest, SetFaviconsSameFaviconURLForTwoPages) {
EXPECT_EQ(2u, favicon_bitmaps.size());
}
+// Tests calling SetLastResortFavicons(). Neither |page_url| nor |icon_url| are
+// known to the database.
+TEST_F(HistoryBackendTest, SetLastResortFaviconsForEmptyDB) {
+ GURL page_url("http://www.google.com");
+ GURL icon_url("http:/www.google.com/favicon.ico");
+
+ std::vector<SkBitmap> bitmaps;
+ bitmaps.push_back(CreateBitmap(SK_ColorRED, kSmallEdgeSize));
+
+ // Call SetLastResortFavicons() with a different icon URL and bitmap data.
+ EXPECT_TRUE(backend_->SetLastResortFavicons(page_url, favicon_base::FAVICON,
+ icon_url, bitmaps));
+
+ favicon_base::FaviconID favicon_id =
+ backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
+ icon_url, favicon_base::FAVICON, NULL);
+ EXPECT_NE(0, favicon_id);
+
+ FaviconBitmap favicon_bitmap;
+ ASSERT_TRUE(GetOnlyFaviconBitmap(favicon_id, &favicon_bitmap));
+ // The original bitmap should have been retrieved.
+ EXPECT_TRUE(BitmapColorEqual(SK_ColorRED, favicon_bitmap.bitmap_data));
+ // The favicon should not be marked as expired.
+ EXPECT_EQ(base::Time(), favicon_bitmap.last_updated);
+}
+
+// Tests calling SetLastResortFavicons(). |page_url| is known to the database
+// but |icon_url| is not (the second should be irrelevant though).
+TEST_F(HistoryBackendTest, SetLastResortFaviconsForPageInDB) {
+ GURL page_url("http://www.google.com");
+ GURL icon_url1("http:/www.google.com/favicon1.ico");
+ GURL icon_url2("http:/www.google.com/favicon2.ico");
+ std::vector<SkBitmap> bitmaps;
+ bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize));
+
+ // Add bitmap to the database.
+ backend_->SetFavicons(page_url, favicon_base::FAVICON, icon_url1, bitmaps);
+ favicon_base::FaviconID original_favicon_id =
+ backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
+ icon_url1, favicon_base::FAVICON, NULL);
+ ASSERT_NE(0, original_favicon_id);
+
+ // Call SetLastResortFavicons() with a different icon URL and bitmap data.
+ bitmaps[0] = CreateBitmap(SK_ColorWHITE, kSmallEdgeSize);
+ EXPECT_FALSE(backend_->SetLastResortFavicons(page_url, favicon_base::FAVICON,
+ icon_url2, bitmaps));
+ EXPECT_EQ(0, backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
+ icon_url2, favicon_base::FAVICON, NULL));
+
+ FaviconBitmap favicon_bitmap;
+ ASSERT_TRUE(GetOnlyFaviconBitmap(original_favicon_id, &favicon_bitmap));
+ // The original bitmap should have been retrieved.
+ EXPECT_TRUE(BitmapColorEqual(SK_ColorBLUE, favicon_bitmap.bitmap_data));
+ // The favicon should not be marked as expired.
+ EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
+}
+
+// Tests calling SetLastResortFavicons(). |page_url| is not known to the
+// database but |icon_url| is.
+TEST_F(HistoryBackendTest, SetLastResortFaviconsForIconInDB) {
+ const GURL old_page_url("http://www.google.com/old");
+ const GURL page_url("http://www.google.com/");
+ const GURL icon_url("http://www.google.com/icon");
+ std::vector<SkBitmap> bitmaps;
+ bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize));
+
+ // Add bitmap to the database.
+ backend_->SetFavicons(old_page_url, favicon_base::FAVICON, icon_url, bitmaps);
+ favicon_base::FaviconID original_favicon_id =
+ backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
+ icon_url, favicon_base::FAVICON, NULL);
+ ASSERT_NE(0, original_favicon_id);
+
+ // Call SetLastResortFavicons() with a different bitmap.
+ bitmaps[0] = CreateBitmap(SK_ColorWHITE, kSmallEdgeSize);
+ EXPECT_FALSE(backend_->SetLastResortFavicons(page_url, favicon_base::FAVICON,
+ icon_url, bitmaps));
+
+ EXPECT_EQ(original_favicon_id,
+ backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
+ icon_url, favicon_base::FAVICON, NULL));
+
+ FaviconBitmap favicon_bitmap;
+ ASSERT_TRUE(GetOnlyFaviconBitmap(original_favicon_id, &favicon_bitmap));
+ // The original bitmap should have been retrieved.
+ EXPECT_TRUE(BitmapColorEqual(SK_ColorBLUE, favicon_bitmap.bitmap_data));
+ // The favicon should not be marked as expired.
+ EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
+}
+
// Test repeatedly calling MergeFavicon(). |page_url| is initially not known
// to the database.
TEST_F(HistoryBackendTest, MergeFaviconPageURLNotInDB) {
@@ -3582,10 +3675,13 @@ TEST_F(HistoryBackendTest, DeleteFTSIndexDatabases) {
// Setup dummy index database files.
const char* data = "Dummy";
const size_t data_len = 5;
- ASSERT_TRUE(base::WriteFile(db1, data, data_len));
- ASSERT_TRUE(base::WriteFile(db1_journal, data, data_len));
- ASSERT_TRUE(base::WriteFile(db1_wal, data, data_len));
- ASSERT_TRUE(base::WriteFile(db2_actual, data, data_len));
+ ASSERT_EQ(static_cast<int>(data_len), base::WriteFile(db1, data, data_len));
+ ASSERT_EQ(static_cast<int>(data_len),
+ base::WriteFile(db1_journal, data, data_len));
+ ASSERT_EQ(static_cast<int>(data_len),
+ 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)
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 2768a8bc916..59dcff235b9 100644
--- a/chromium/components/history/core/browser/history_database.cc
+++ b/chromium/components/history/core/browser/history_database.cc
@@ -22,6 +22,7 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/history/core/browser/url_utils.h"
+#include "sql/meta_table.h"
#include "sql/statement.h"
#include "sql/transaction.h"
@@ -36,11 +37,42 @@ 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 = 33;
+const int kCurrentVersionNumber = 36;
const int kCompatibleVersionNumber = 16;
const char kEarlyExpirationThresholdKey[] = "early_expiration_threshold";
const int kMaxHostsInMemory = 10000;
+// Logs a migration failure to UMA and logging. The return value will be
+// what to return from ::Init (to simplify the call sites). Migration failures
+// are almost always fatal since the database can be in an inconsistent state.
+sql::InitStatus LogMigrationFailure(int from_version) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("History.MigrateFailureFromVersion",
+ from_version);
+ LOG(ERROR) << "History failed to migrate from version " << from_version
+ << ". History will be disabled.";
+ return sql::INIT_FAILURE;
+}
+
+// Reasons for initialization to fail. These are logged to UMA. It corresponds
+// to the HistoryInitStep enum in enums.xml.
+//
+// DO NOT CHANGE THE VALUES. Leave holes if anything is removed and add only
+// to the end.
+enum class InitStep {
+ OPEN = 0,
+ TRANSACTION_BEGIN = 1,
+ META_TABLE_INIT = 2,
+ CREATE_TABLES = 3,
+ VERSION = 4,
+ COMMIT = 5,
+};
+
+sql::InitStatus LogInitFailure(InitStep what) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("History.InitializationFailureStep",
+ static_cast<int>(what));
+ return sql::INIT_FAILURE;
+}
+
} // namespace
HistoryDatabase::HistoryDatabase(
@@ -73,13 +105,13 @@ sql::InitStatus HistoryDatabase::Init(const base::FilePath& history_name) {
// mode to start out for the in-memory backend to read the data).
if (!db_.Open(history_name))
- return sql::INIT_FAILURE;
+ return LogInitFailure(InitStep::OPEN);
// Wrap the rest of init in a tranaction. This will prevent the database from
// getting corrupted if we crash in the middle of initialization or migration.
sql::Transaction committer(&db_);
if (!committer.Begin())
- return sql::INIT_FAILURE;
+ return LogInitFailure(InitStep::TRANSACTION_BEGIN);
#if defined(OS_MACOSX) && !defined(OS_IOS)
// Exclude the history file from backups.
@@ -93,11 +125,11 @@ sql::InitStatus HistoryDatabase::Init(const base::FilePath& history_name) {
// NOTE: If you add something here, also add it to
// RecreateAllButStarAndURLTables.
if (!meta_table_.Init(&db_, GetCurrentVersion(), kCompatibleVersionNumber))
- return sql::INIT_FAILURE;
+ return LogInitFailure(InitStep::META_TABLE_INIT);
if (!CreateURLTable(false) || !InitVisitTable() ||
!InitKeywordSearchTermsTable() || !InitDownloadTable() ||
- !InitSegmentTables())
- return sql::INIT_FAILURE;
+ !InitSegmentTables() || !InitSyncTable())
+ return LogInitFailure(InitStep::CREATE_TABLES);
CreateMainURLIndex();
CreateKeywordSearchTermsIndices();
@@ -106,10 +138,14 @@ sql::InitStatus HistoryDatabase::Init(const base::FilePath& history_name) {
// Version check.
sql::InitStatus version_status = EnsureCurrentVersion();
- if (version_status != sql::INIT_OK)
+ if (version_status != sql::INIT_OK) {
+ LogInitFailure(InitStep::VERSION);
return version_status;
+ }
- return committer.Commit() ? sql::INIT_OK : sql::INIT_FAILURE;
+ if (!committer.Commit())
+ return LogInitFailure(InitStep::COMMIT);
+ return sql::INIT_OK;
}
void HistoryDatabase::ComputeDatabaseMetrics(
@@ -364,6 +400,10 @@ sql::Connection& HistoryDatabase::GetDB() {
return db_;
}
+sql::MetaTable& HistoryDatabase::GetMetaTable() {
+ return meta_table_;
+}
+
// Migration -------------------------------------------------------------------
sql::InitStatus HistoryDatabase::EnsureCurrentVersion() {
@@ -378,10 +418,8 @@ sql::InitStatus HistoryDatabase::EnsureCurrentVersion() {
// Put migration code here
if (cur_version == 15) {
- if (!db_.Execute("DROP TABLE starred") || !DropStarredIDFromURLs()) {
- LOG(WARNING) << "Unable to update history database to version 16.";
- return sql::INIT_FAILURE;
- }
+ if (!db_.Execute("DROP TABLE starred") || !DropStarredIDFromURLs())
+ return LogMigrationFailure(15);
++cur_version;
meta_table_.SetVersionNumber(cur_version);
meta_table_.SetCompatibleVersionNumber(
@@ -425,10 +463,8 @@ sql::InitStatus HistoryDatabase::EnsureCurrentVersion() {
if (cur_version == 20) {
// This is the version prior to adding the visit_duration field in visits
// database. We need to migrate the database.
- if (!MigrateVisitsWithoutDuration()) {
- LOG(WARNING) << "Unable to update history database to version 21.";
- return sql::INIT_FAILURE;
- }
+ if (!MigrateVisitsWithoutDuration())
+ return LogMigrationFailure(20);
++cur_version;
meta_table_.SetVersionNumber(cur_version);
}
@@ -436,102 +472,79 @@ 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 (!MigrateToVersion22()) {
- LOG(WARNING) << "Unable to migrate the android_urls table to version 22";
- }
+ if (!MigrateToVersion22())
+ return LogMigrationFailure(21);
#endif
++cur_version;
meta_table_.SetVersionNumber(cur_version);
}
if (cur_version == 22) {
- if (!MigrateDownloadsState()) {
- LOG(WARNING) << "Unable to fix invalid downloads state values";
- // Invalid state values may cause crashes.
- return sql::INIT_FAILURE;
- }
+ if (!MigrateDownloadsState())
+ return LogMigrationFailure(22);
cur_version++;
meta_table_.SetVersionNumber(cur_version);
}
if (cur_version == 23) {
- if (!MigrateDownloadsReasonPathsAndDangerType()) {
- LOG(WARNING) << "Unable to upgrade download interrupt reason and paths";
- // Invalid state values may cause crashes.
- return sql::INIT_FAILURE;
- }
+ if (!MigrateDownloadsReasonPathsAndDangerType())
+ return LogMigrationFailure(23);
cur_version++;
meta_table_.SetVersionNumber(cur_version);
}
if (cur_version == 24) {
- if (!MigratePresentationIndex()) {
- LOG(WARNING) << "Unable to migrate history to version 25";
- return sql::INIT_FAILURE;
- }
+ if (!MigratePresentationIndex())
+ return LogMigrationFailure(24);
cur_version++;
meta_table_.SetVersionNumber(cur_version);
}
if (cur_version == 25) {
- if (!MigrateReferrer()) {
- LOG(WARNING) << "Unable to migrate history to version 26";
- return sql::INIT_FAILURE;
- }
+ if (!MigrateReferrer())
+ return LogMigrationFailure(25);
cur_version++;
meta_table_.SetVersionNumber(cur_version);
}
if (cur_version == 26) {
- if (!MigrateDownloadedByExtension()) {
- LOG(WARNING) << "Unable to migrate history to version 27";
- return sql::INIT_FAILURE;
- }
+ if (!MigrateDownloadedByExtension())
+ return LogMigrationFailure(26);
cur_version++;
meta_table_.SetVersionNumber(cur_version);
}
if (cur_version == 27) {
- if (!MigrateDownloadValidators()) {
- LOG(WARNING) << "Unable to migrate history to version 28";
- return sql::INIT_FAILURE;
- }
+ if (!MigrateDownloadValidators())
+ return LogMigrationFailure(27);
cur_version++;
meta_table_.SetVersionNumber(cur_version);
}
if (cur_version == 28) {
- if (!MigrateMimeType()) {
- LOG(WARNING) << "Unable to migrate history to version 29";
- return sql::INIT_FAILURE;
- }
+ if (!MigrateMimeType())
+ return LogMigrationFailure(28);
cur_version++;
meta_table_.SetVersionNumber(cur_version);
}
if (cur_version == 29) {
- if (!MigrateHashHttpMethodAndGenerateGuids()) {
- LOG(WARNING) << "Unable to migrate history to version 30";
- return sql::INIT_FAILURE;
- }
+ if (!MigrateHashHttpMethodAndGenerateGuids())
+ return LogMigrationFailure(29);
cur_version++;
meta_table_.SetVersionNumber(cur_version);
}
if (cur_version == 30) {
- if (!MigrateDownloadTabUrl()) {
- LOG(WARNING) << "Unable to migrate history to version 31";
- return sql::INIT_FAILURE;
- }
+ if (!MigrateDownloadTabUrl())
+ return LogMigrationFailure(30);
cur_version++;
meta_table_.SetVersionNumber(cur_version);
}
if (cur_version == 31) {
- if (!MigrateDownloadSiteInstanceUrl()) {
- LOG(WARNING) << "Unable to migrate history to version 32";
- return sql::INIT_FAILURE;
- }
+ if (!MigrateDownloadSiteInstanceUrl())
+ return LogMigrationFailure(31);
cur_version++;
meta_table_.SetVersionNumber(cur_version);
}
@@ -542,6 +555,58 @@ sql::InitStatus HistoryDatabase::EnsureCurrentVersion() {
meta_table_.SetVersionNumber(cur_version);
}
+ if (cur_version == 33) {
+ if (!MigrateDownloadLastAccessTime())
+ return LogMigrationFailure(33);
+ cur_version++;
+ meta_table_.SetVersionNumber(cur_version);
+ }
+
+ if (cur_version == 34) {
+ /*
+ This code is commented out because we suspect the additional disk storage
+ requirements of duplicating the URL table to update the schema cause
+ some devices to run out of storage. Errors during initialization are
+ very disruptive to the user experience.
+
+ TODO(https://crbug.com/736136) figure out how to update users to use
+ AUTOINCREMENT.
+
+ // AUTOINCREMENT is added to urls table PRIMARY KEY(id), need to recreate a
+ // new table and copy all contents over. favicon_id is removed from urls
+ // table since we never use it. Also typed_url_sync_metadata and
+ // autofill_model_type_state tables are introduced, no migration needed for
+ // those two tables.
+ if (!RecreateURLTableWithAllContents())
+ return LogMigrationFailure(34);
+ */
+ cur_version++;
+ meta_table_.SetVersionNumber(cur_version);
+ }
+
+ if (cur_version == 35) {
+ if (!MigrateDownloadTransient())
+ return LogMigrationFailure(35);
+ cur_version++;
+ meta_table_.SetVersionNumber(cur_version);
+ }
+
+ // ========================= ^^ new migration code goes here ^^
+ // ADDING NEW MIGRATION CODE
+ // =========================
+ //
+ // Add new migration code above here. It's important to use as little space
+ // as possible during migration. Many phones are very near their storage
+ // limit, so anything that recreates or duplicates large history tables can
+ // easily push them over that limit.
+ //
+ // When failures happen during initialization, history is not loaded. This
+ // causes all components related to the history database file to fail
+ // completely, including autocomplete and downloads. Devices near their
+ // storage limit are likely to fail doing some update later, but those
+ // operations will then just be skipped which is not nearly as disruptive.
+ // See https://crbug.com/734194.
+
// When the version is too old, we just try to continue anyway, there should
// not be a released product that makes a database too old for us to handle.
LOG_IF(WARNING, cur_version < GetCurrentVersion()) <<
diff --git a/chromium/components/history/core/browser/history_database.h b/chromium/components/history/core/browser/history_database.h
index 9a26ae98194..dc9989d60ae 100644
--- a/chromium/components/history/core/browser/history_database.h
+++ b/chromium/components/history/core/browser/history_database.h
@@ -13,6 +13,7 @@
#include "build/build_config.h"
#include "components/history/core/browser/download_database.h"
#include "components/history/core/browser/history_types.h"
+#include "components/history/core/browser/typed_url_sync_metadata_database.h"
#include "components/history/core/browser/url_database.h"
#include "components/history/core/browser/visit_database.h"
#include "components/history/core/browser/visitsegment_database.h"
@@ -45,6 +46,7 @@ class HistoryDatabase : public DownloadDatabase,
public AndroidURLsDatabase,
public AndroidCacheDatabase,
#endif
+ public TypedURLSyncMetadataDatabase,
public URLDatabase,
public VisitDatabase,
public VisitSegmentDatabase {
@@ -169,9 +171,13 @@ class HistoryDatabase : public DownloadDatabase,
#endif
friend class ::InMemoryURLIndexTest;
- // Overridden from URLDatabase:
+ // Overridden from URLDatabase, DownloadDatabase, VisitDatabase,
+ // VisitSegmentDatabase and TypedURLSyncMetadataDatabase.
sql::Connection& GetDB() override;
+ // Overridden from TypedURLSyncMetadataDatabase.
+ sql::MetaTable& GetMetaTable() override;
+
// Migration -----------------------------------------------------------------
// Makes sure the version is up to date, updating if necessary. If the
diff --git a/chromium/components/history/core/browser/history_model_worker.cc b/chromium/components/history/core/browser/history_model_worker.cc
index 72b843dc9ff..ad3f9911e7a 100644
--- a/chromium/components/history/core/browser/history_model_worker.cc
+++ b/chromium/components/history/core/browser/history_model_worker.cc
@@ -6,30 +6,19 @@
#include <utility>
-#include "base/synchronization/waitable_event.h"
+#include "base/memory/ptr_util.h"
#include "components/history/core/browser/history_db_task.h"
#include "components/history/core/browser/history_service.h"
-#include "components/sync/base/scoped_event_signal.h"
namespace browser_sync {
class WorkerTask : public history::HistoryDBTask {
public:
- WorkerTask(const syncer::WorkCallback& work,
- syncer::ScopedEventSignal scoped_event_signal,
- syncer::SyncerError* error)
- : work_(work),
- scoped_event_signal_(std::move(scoped_event_signal)),
- error_(error) {}
+ WorkerTask(base::OnceClosure work) : work_(std::move(work)) {}
bool RunOnDBThread(history::HistoryBackend* backend,
history::HistoryDatabase* db) override {
- // Signal the completion event at the end of this scope.
- auto scoped_event_signal = std::move(scoped_event_signal_);
-
- // Run the task.
- *error_ = work_.Run();
-
+ std::move(work_).Run();
return true;
}
@@ -37,34 +26,12 @@ class WorkerTask : public history::HistoryDBTask {
// any code asynchronously on the main thread after completion.
void DoneRunOnMainThread() override {}
- protected:
- ~WorkerTask() override {
- // The event in |scoped_event_signal_| is signaled at the end of this
- // scope if this is destroyed before RunOnDBThread runs.
- }
-
- syncer::WorkCallback work_;
- syncer::ScopedEventSignal scoped_event_signal_;
- syncer::SyncerError* error_;
-};
-
-class AddDBThreadObserverTask : public history::HistoryDBTask {
- public:
- explicit AddDBThreadObserverTask(base::Closure register_callback)
- : register_callback_(register_callback) {}
-
- bool RunOnDBThread(history::HistoryBackend* backend,
- history::HistoryDatabase* db) override {
- register_callback_.Run();
- return true;
- }
-
- void DoneRunOnMainThread() override {}
-
private:
- ~AddDBThreadObserverTask() override {}
+ // A OnceClosure is deleted right after it runs. This is important to unblock
+ // DoWorkAndWaitUntilDone() right after the task runs.
+ base::OnceClosure work_;
- base::Closure register_callback_;
+ DISALLOW_COPY_AND_ASSIGN(WorkerTask);
};
namespace {
@@ -73,18 +40,11 @@ namespace {
// thread.
void PostWorkerTask(
const base::WeakPtr<history::HistoryService>& history_service,
- const syncer::WorkCallback& work,
- syncer::ScopedEventSignal scoped_event_signal,
- base::CancelableTaskTracker* cancelable_tracker,
- syncer::SyncerError* error) {
+ base::OnceClosure work,
+ base::CancelableTaskTracker* cancelable_tracker) {
if (history_service.get()) {
- std::unique_ptr<history::HistoryDBTask> task(
- new WorkerTask(work, std::move(scoped_event_signal), error));
- history_service->ScheduleDBTask(std::move(task), cancelable_tracker);
- } else {
- *error = syncer::CANNOT_DO_WORK;
- // The event in |scoped_event_signal| is signaled at the end of this
- // scope.
+ history_service->ScheduleDBTask(
+ base::MakeUnique<WorkerTask>(std::move(work)), cancelable_tracker);
}
}
@@ -99,27 +59,6 @@ HistoryModelWorker::HistoryModelWorker(
cancelable_tracker_.reset(new base::CancelableTaskTracker);
}
-syncer::SyncerError HistoryModelWorker::DoWorkAndWaitUntilDoneImpl(
- const syncer::WorkCallback& work) {
- syncer::SyncerError error = syncer::UNSET;
-
- // Signaled after the task runs or when it is abandoned.
- base::WaitableEvent work_done_or_abandoned(
- base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- if (ui_thread_->PostTask(FROM_HERE,
- base::Bind(&PostWorkerTask, history_service_, work,
- base::Passed(syncer::ScopedEventSignal(
- &work_done_or_abandoned)),
- cancelable_tracker_.get(), &error))) {
- work_done_or_abandoned.Wait();
- } else {
- error = syncer::CANNOT_DO_WORK;
- }
- return error;
-}
-
syncer::ModelSafeGroup HistoryModelWorker::GetModelSafeGroup() {
return syncer::GROUP_HISTORY;
}
@@ -138,4 +77,10 @@ HistoryModelWorker::~HistoryModelWorker() {
ui_thread_->DeleteSoon(FROM_HERE, cancelable_tracker_.release());
}
+void HistoryModelWorker::ScheduleWork(base::OnceClosure work) {
+ ui_thread_->PostTask(FROM_HERE, base::Bind(&PostWorkerTask, history_service_,
+ base::Passed(std::move(work)),
+ cancelable_tracker_.get()));
+}
+
} // namespace browser_sync
diff --git a/chromium/components/history/core/browser/history_model_worker.h b/chromium/components/history/core/browser/history_model_worker.h
index 6421c64d3a1..f72b00afbc5 100644
--- a/chromium/components/history/core/browser/history_model_worker.h
+++ b/chromium/components/history/core/browser/history_model_worker.h
@@ -32,13 +32,11 @@ class HistoryModelWorker : public syncer::ModelSafeWorker {
syncer::ModelSafeGroup GetModelSafeGroup() override;
bool IsOnModelThread() override;
- protected:
- syncer::SyncerError DoWorkAndWaitUntilDoneImpl(
- const syncer::WorkCallback& work) override;
-
private:
~HistoryModelWorker() override;
+ void ScheduleWork(base::OnceClosure work) override;
+
const base::WeakPtr<history::HistoryService> history_service_;
// A reference to the UI thread's task runner.
diff --git a/chromium/components/history/core/browser/history_model_worker_unittest.cc b/chromium/components/history/core/browser/history_model_worker_unittest.cc
new file mode 100644
index 00000000000..1877558782c
--- /dev/null
+++ b/chromium/components/history/core/browser/history_model_worker_unittest.cc
@@ -0,0 +1,227 @@
+// 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/history/core/browser/history_model_worker.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/atomic_flag.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "components/history/core/browser/history_db_task.h"
+#include "components/history/core/browser/history_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace browser_sync {
+namespace {
+
+class HistoryServiceMock : public history::HistoryService {
+ public:
+ HistoryServiceMock(scoped_refptr<base::SingleThreadTaskRunner> history_thread)
+ : history_thread_(std::move(history_thread)) {}
+
+ base::CancelableTaskTracker::TaskId ScheduleDBTask(
+ std::unique_ptr<history::HistoryDBTask> task,
+ base::CancelableTaskTracker* tracker) override {
+ history::HistoryDBTask* task_raw = task.get();
+ history_thread_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(base::IgnoreResult(&history::HistoryDBTask::RunOnDBThread),
+ base::Unretained(task_raw), nullptr, nullptr),
+ base::Bind(&history::HistoryDBTask::DoneRunOnMainThread,
+ base::Passed(std::move(task))));
+ return base::CancelableTaskTracker::kBadTaskId; // Unused.
+ }
+
+ private:
+ const scoped_refptr<base::SingleThreadTaskRunner> history_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(HistoryServiceMock);
+};
+
+syncer::WorkCallback ClosureToWorkCallback(base::Closure work) {
+ return base::Bind(
+ [](base::Closure work) {
+ work.Run();
+ return syncer::SYNCER_OK;
+ },
+ std::move(work));
+}
+
+class HistoryModelWorkerTest : public testing::Test {
+ public:
+ HistoryModelWorkerTest()
+ : sync_thread_("SyncThreadForTest"),
+ history_service_(history_thread_),
+ history_service_factory_(&history_service_) {
+ sync_thread_.Start();
+ worker_ = new HistoryModelWorker(history_service_factory_.GetWeakPtr(),
+ ui_thread_);
+ }
+
+ ~HistoryModelWorkerTest() override {
+ // HistoryModelWorker posts a cleanup task to the UI thread in its
+ // destructor. Run it to prevent a leak.
+ worker_ = nullptr;
+ ui_thread_->RunUntilIdle();
+ }
+
+ protected:
+ void DoWorkAndWaitUntilDoneOnSyncThread(base::Closure work) {
+ sync_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ base::IgnoreResult(&HistoryModelWorker::DoWorkAndWaitUntilDone),
+ worker_, base::Passed(ClosureToWorkCallback(work))));
+ sync_thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&base::AtomicFlag::Set,
+ base::Unretained(&sync_thread_unblocked_)));
+ }
+
+ const scoped_refptr<base::TestSimpleTaskRunner> ui_thread_ =
+ new base::TestSimpleTaskRunner();
+ scoped_refptr<base::TestSimpleTaskRunner> history_thread_ =
+ new base::TestSimpleTaskRunner();
+ base::AtomicFlag sync_thread_unblocked_;
+ base::Thread sync_thread_;
+ HistoryServiceMock history_service_;
+ scoped_refptr<HistoryModelWorker> worker_;
+
+ private:
+ base::WeakPtrFactory<HistoryServiceMock> history_service_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(HistoryModelWorkerTest);
+};
+
+} // namespace
+
+TEST_F(HistoryModelWorkerTest, DoWorkAndWaitUntilDone) {
+ bool did_work = false;
+ DoWorkAndWaitUntilDoneOnSyncThread(base::Bind(
+ [](bool* did_work) { *did_work = true; }, base::Unretained(&did_work)));
+
+ EXPECT_FALSE(did_work);
+ EXPECT_FALSE(sync_thread_unblocked_.IsSet());
+
+ // Wait for a task to be posted to the UI thread and run it. Expect this task
+ // to post another task to the history DB thread and run it.
+ while (!ui_thread_->HasPendingTask())
+ base::PlatformThread::YieldCurrentThread();
+ ui_thread_->RunUntilIdle();
+ EXPECT_TRUE(history_thread_->HasPendingTask());
+ history_thread_->RunUntilIdle();
+
+ EXPECT_TRUE(did_work);
+
+ sync_thread_.Stop();
+ EXPECT_TRUE(sync_thread_unblocked_.IsSet());
+}
+
+TEST_F(HistoryModelWorkerTest, DoWorkAndWaitUntilDoneRequestStopBeforeRunWork) {
+ bool did_work = false;
+ DoWorkAndWaitUntilDoneOnSyncThread(base::Bind(
+ [](bool* did_work) { *did_work = true; }, base::Unretained(&did_work)));
+
+ EXPECT_FALSE(did_work);
+ EXPECT_FALSE(sync_thread_unblocked_.IsSet());
+
+ // Wait for a task to be posted to the UI thread and run it.
+ while (!ui_thread_->HasPendingTask())
+ base::PlatformThread::YieldCurrentThread();
+ ui_thread_->RunUntilIdle();
+
+ // Stop the worker.
+ worker_->RequestStop();
+
+ // The WorkCallback should not run on the history DB thread.
+ EXPECT_TRUE(history_thread_->HasPendingTask());
+ history_thread_->RunUntilIdle();
+ EXPECT_FALSE(did_work);
+
+ sync_thread_.Stop();
+ EXPECT_TRUE(sync_thread_unblocked_.IsSet());
+}
+
+TEST_F(HistoryModelWorkerTest,
+ DoWorkAndWaitUntilDoneRequestStopBeforeUITaskRun) {
+ bool did_work = false;
+ DoWorkAndWaitUntilDoneOnSyncThread(base::Bind(
+ [](bool* did_work) { *did_work = true; }, base::Unretained(&did_work)));
+
+ EXPECT_FALSE(did_work);
+ EXPECT_FALSE(sync_thread_unblocked_.IsSet());
+
+ // Wait for a task to be posted to the UI thread.
+ while (!ui_thread_->HasPendingTask())
+ base::PlatformThread::YieldCurrentThread();
+
+ // Stop the worker.
+ worker_->RequestStop();
+
+ // Stopping the worker should unblock the sync thread.
+ sync_thread_.Stop();
+ EXPECT_TRUE(sync_thread_unblocked_.IsSet());
+}
+
+TEST_F(HistoryModelWorkerTest, DoWorkAndWaitUntilDoneDeleteWorkBeforeRun) {
+ bool did_work = false;
+ DoWorkAndWaitUntilDoneOnSyncThread(base::Bind(
+ [](bool* did_work) { *did_work = true; }, base::Unretained(&did_work)));
+
+ EXPECT_FALSE(did_work);
+ EXPECT_FALSE(sync_thread_unblocked_.IsSet());
+
+ // Wait for a task to be posted to the UI thread. Delete it before it can run.
+ while (!ui_thread_->HasPendingTask())
+ base::PlatformThread::YieldCurrentThread();
+ ui_thread_->ClearPendingTasks();
+
+ EXPECT_FALSE(did_work);
+
+ // Deleting the task should have unblocked the sync thread.
+ sync_thread_.Stop();
+ EXPECT_TRUE(sync_thread_unblocked_.IsSet());
+}
+
+TEST_F(HistoryModelWorkerTest, DoWorkAndWaitUntilDoneRequestStopDuringRunWork) {
+ bool did_work = false;
+ DoWorkAndWaitUntilDoneOnSyncThread(base::Bind(
+ [](scoped_refptr<HistoryModelWorker> worker,
+ base::AtomicFlag* sync_thread_unblocked, bool* did_work) {
+ worker->RequestStop();
+ base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
+
+ // The sync thread should not be unblocked while a WorkCallback is
+ // running.
+ EXPECT_FALSE(sync_thread_unblocked->IsSet());
+
+ *did_work = true;
+ },
+ worker_, base::Unretained(&sync_thread_unblocked_),
+ base::Unretained(&did_work)));
+ EXPECT_FALSE(did_work);
+ EXPECT_FALSE(sync_thread_unblocked_.IsSet());
+
+ // Wait for a task to be posted to the UI thread and run it.
+ while (!ui_thread_->HasPendingTask())
+ base::PlatformThread::YieldCurrentThread();
+ ui_thread_->RunUntilIdle();
+
+ // Expect a task to be posted to the history DB thread. Run it.
+ EXPECT_TRUE(history_thread_->HasPendingTask());
+ history_thread_->RunUntilIdle();
+ EXPECT_TRUE(did_work);
+
+ sync_thread_.Stop();
+ EXPECT_TRUE(sync_thread_unblocked_.IsSet());
+}
+
+} // namespace browser_sync
diff --git a/chromium/components/history/core/browser/history_service.cc b/chromium/components/history/core/browser/history_service.cc
index 081e5cdd08c..b9ebe00521a 100644
--- a/chromium/components/history/core/browser/history_service.cc
+++ b/chromium/components/history/core/browser/history_service.cc
@@ -234,6 +234,10 @@ URLDatabase* HistoryService::InMemoryDatabase() {
return in_memory_backend_ ? in_memory_backend_->db() : nullptr;
}
+TypedURLSyncBridge* HistoryService::GetTypedURLSyncBridge() const {
+ return history_backend_->GetTypedURLSyncBridge();
+}
+
TypedUrlSyncableService* HistoryService::GetTypedUrlSyncableService() const {
return history_backend_->GetTypedUrlSyncableService();
}
@@ -621,6 +625,24 @@ void HistoryService::SetFavicons(const GURL& page_url,
page_url, icon_type, icon_url, bitmaps));
}
+void HistoryService::SetLastResortFavicons(
+ const GURL& page_url,
+ favicon_base::IconType icon_type,
+ const GURL& icon_url,
+ const std::vector<SkBitmap>& bitmaps,
+ base::Callback<void(bool)> callback) {
+ DCHECK(backend_task_runner_) << "History service being called after cleanup";
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (history_client_ && !history_client_->CanAddURL(page_url))
+ return;
+
+ PostTaskAndReplyWithResult(
+ backend_task_runner_.get(), FROM_HERE,
+ base::Bind(&HistoryBackend::SetLastResortFavicons, history_backend_,
+ page_url, icon_type, icon_url, bitmaps),
+ callback);
+}
+
void HistoryService::SetFaviconsOutOfDateForPage(const GURL& page_url) {
DCHECK(backend_task_runner_) << "History service being called after cleanup";
DCHECK(thread_checker_.CalledOnValidThread());
@@ -915,11 +937,11 @@ void HistoryService::ScheduleAutocomplete(
}
void HistoryService::ScheduleTask(SchedulePriority priority,
- const base::Closure& task) {
+ base::OnceClosure task) {
DCHECK(thread_checker_.CalledOnValidThread());
CHECK(backend_task_runner_);
// TODO(brettw): Do prioritization.
- backend_task_runner_->PostTask(FROM_HERE, task);
+ backend_task_runner_->PostTask(FROM_HERE, std::move(task));
}
base::WeakPtr<HistoryService> HistoryService::AsWeakPtr() {
diff --git a/chromium/components/history/core/browser/history_service.h b/chromium/components/history/core/browser/history_service.h
index dd6b19aa490..c89868c9b4f 100644
--- a/chromium/components/history/core/browser/history_service.h
+++ b/chromium/components/history/core/browser/history_service.h
@@ -33,6 +33,7 @@
#include "components/history/core/browser/delete_directive_handler.h"
#include "components/history/core/browser/history_types.h"
#include "components/history/core/browser/keyword_id.h"
+#include "components/history/core/browser/typed_url_sync_bridge.h"
#include "components/history/core/browser/typed_url_syncable_service.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/sync/model/syncable_service.h"
@@ -129,6 +130,11 @@ class HistoryService : public syncer::SyncableService, public KeyedService {
// They return false if database is not available (e.g. not loaded yet) or the
// URL does not exist.
+ // Returns a pointer to the TypedURLSyncBridge owned by HistoryBackend.
+ // This method should only be called from the history thread, because the
+ // returned bridge is intended to be accessed only via the history thread.
+ TypedURLSyncBridge* GetTypedURLSyncBridge() const;
+
// Returns a pointer to the TypedUrlSyncableService owned by HistoryBackend.
// This method should only be called from the history thread, because the
// returned service is intended to be accessed only via the history thread.
@@ -761,6 +767,20 @@ class HistoryService : public syncer::SyncableService, public KeyedService {
const GURL& icon_url,
const std::vector<SkBitmap>& bitmaps);
+ // Same as SetFavicons with three differences:
+ // 1) It will be a no-op if there is an existing cached favicon for *any* type
+ // for |page_url|.
+ // 2) If |icon_url| is known to the database, |bitmaps| will be ignored (i.e.
+ // the icon won't be overwritten) but the mappings from |page_url| to
+ // |icon_url| will be stored (conditioned to point 1 above).
+ // 3) If |icon_url| is stored, it will be marked as expired.
+ // The callback will receive whether the write actually happened.
+ void SetLastResortFavicons(const GURL& page_url,
+ favicon_base::IconType icon_type,
+ const GURL& icon_url,
+ const std::vector<SkBitmap>& bitmaps,
+ base::Callback<void(bool)> callback);
+
// Used by the FaviconService to mark the favicon for the page as being out
// of date.
void SetFaviconsOutOfDateForPage(const GURL& page_url);
@@ -781,7 +801,7 @@ class HistoryService : public syncer::SyncableService, public KeyedService {
// Call to schedule a given task for running on the history thread with the
// specified priority. The task will have ownership taken.
- void ScheduleTask(SchedulePriority priority, const base::Closure& task);
+ void ScheduleTask(SchedulePriority priority, base::OnceClosure task);
// Called when the favicons for the given page URLs (e.g.
// http://www.google.com) and the given icon URL (e.g.
diff --git a/chromium/components/history/core/browser/history_service_unittest.cc b/chromium/components/history/core/browser/history_service_unittest.cc
index 170ff0ee0a3..b26d83adbbb 100644
--- a/chromium/components/history/core/browser/history_service_unittest.cc
+++ b/chromium/components/history/core/browser/history_service_unittest.cc
@@ -204,13 +204,8 @@ TEST_F(HistoryServiceTest, AddPage) {
TEST_F(HistoryServiceTest, AddRedirect) {
ASSERT_TRUE(history_service_.get());
- const char* first_sequence[] = {
- "http://first.page.com/",
- "http://second.page.com/"};
- int first_count = arraysize(first_sequence);
- history::RedirectList first_redirects;
- for (int i = 0; i < first_count; i++)
- first_redirects.push_back(GURL(first_sequence[i]));
+ history::RedirectList first_redirects = {GURL("http://first.page.com/"),
+ GURL("http://second.page.com/")};
// Add the sequence of pages as a server with no referrer. Note that we need
// to have a non-NULL page ID scope.
@@ -252,9 +247,8 @@ TEST_F(HistoryServiceTest, AddRedirect) {
// Now add a client redirect from that second visit to a third, client
// redirects are tracked by the RenderView prior to updating history,
// so we pass in a CLIENT_REDIRECT qualifier to mock that behavior.
- history::RedirectList second_redirects;
- second_redirects.push_back(first_redirects[1]);
- second_redirects.push_back(GURL("http://last.page.com/"));
+ history::RedirectList second_redirects = {first_redirects[1],
+ GURL("http://last.page.com/")};
history_service_->AddPage(second_redirects[1], base::Time::Now(),
reinterpret_cast<ContextID>(1), 1,
second_redirects[0], second_redirects,
@@ -364,6 +358,48 @@ TEST_F(HistoryServiceTest, MakeIntranetURLsTyped) {
ASSERT_EQ(2U, query_url_visits_.size());
EXPECT_TRUE(ui::PageTransitionCoreTypeIs(query_url_visits_[1].transition,
ui::PAGE_TRANSITION_LINK));
+
+ // A redirect chain with an intranet URL at the head should be promoted.
+ history::RedirectList redirects1 = {GURL("http://intranet1/path"),
+ GURL("http://second1.com/"),
+ GURL("http://third1.com/")};
+ history_service_->AddPage(redirects1.back(), base::Time::Now(), NULL, 0,
+ GURL(), redirects1, ui::PAGE_TRANSITION_LINK,
+ history::SOURCE_BROWSED, false);
+ EXPECT_TRUE(QueryURL(history_service_.get(), redirects1.front()));
+ EXPECT_EQ(1, query_url_row_.visit_count());
+ EXPECT_EQ(1, query_url_row_.typed_count());
+ ASSERT_EQ(1U, query_url_visits_.size());
+ EXPECT_TRUE(ui::PageTransitionCoreTypeIs(query_url_visits_[0].transition,
+ ui::PAGE_TRANSITION_TYPED));
+
+ // As should one with an intranet URL at the tail.
+ history::RedirectList redirects2 = {GURL("http://first2.com/"),
+ GURL("http://second2.com/"),
+ GURL("http://intranet2/path")};
+ history_service_->AddPage(redirects2.back(), base::Time::Now(), NULL, 0,
+ GURL(), redirects2, ui::PAGE_TRANSITION_LINK,
+ history::SOURCE_BROWSED, false);
+ EXPECT_TRUE(QueryURL(history_service_.get(), redirects2.back()));
+ EXPECT_EQ(1, query_url_row_.visit_count());
+ EXPECT_EQ(0, query_url_row_.typed_count());
+ ASSERT_EQ(1U, query_url_visits_.size());
+ EXPECT_TRUE(ui::PageTransitionCoreTypeIs(query_url_visits_[0].transition,
+ ui::PAGE_TRANSITION_TYPED));
+
+ // But not one with an intranet URL in the middle.
+ history::RedirectList redirects3 = {GURL("http://first3.com/"),
+ GURL("http://intranet3/path"),
+ GURL("http://third3.com/")};
+ history_service_->AddPage(redirects3.back(), base::Time::Now(), NULL, 0,
+ GURL(), redirects3, ui::PAGE_TRANSITION_LINK,
+ history::SOURCE_BROWSED, false);
+ EXPECT_TRUE(QueryURL(history_service_.get(), redirects3[1]));
+ EXPECT_EQ(1, query_url_row_.visit_count());
+ EXPECT_EQ(0, query_url_row_.typed_count());
+ ASSERT_EQ(1U, query_url_visits_.size());
+ EXPECT_TRUE(ui::PageTransitionCoreTypeIs(query_url_visits_[0].transition,
+ ui::PAGE_TRANSITION_LINK));
}
TEST_F(HistoryServiceTest, Typed) {
@@ -532,12 +568,8 @@ TEST_F(HistoryServiceTest, MostVisitedURLs) {
EXPECT_EQ(url2, most_visited_urls_[1].url);
EXPECT_EQ(url0, most_visited_urls_[2].url);
- // Redirects
- history::RedirectList redirects;
- redirects.push_back(url3);
- redirects.push_back(url4);
-
// Visit url4 using redirects.
+ history::RedirectList redirects = {url3, url4};
history_service_->AddPage(
url4, base::Time::Now(), context_id, 0, GURL(),
redirects, ui::PAGE_TRANSITION_TYPED,
diff --git a/chromium/components/history/core/browser/history_types.cc b/chromium/components/history/core/browser/history_types.cc
index c6d3edacac1..93a242a2f0c 100644
--- a/chromium/components/history/core/browser/history_types.cc
+++ b/chromium/components/history/core/browser/history_types.cc
@@ -14,26 +14,18 @@ namespace history {
// VisitRow --------------------------------------------------------------------
-VisitRow::VisitRow()
- : visit_id(0),
- url_id(0),
- referring_visit(0),
- transition(ui::PAGE_TRANSITION_LINK),
- segment_id(0) {
-}
+VisitRow::VisitRow() {}
VisitRow::VisitRow(URLID arg_url_id,
base::Time arg_visit_time,
VisitID arg_referring_visit,
ui::PageTransition arg_transition,
SegmentID arg_segment_id)
- : visit_id(0),
- url_id(arg_url_id),
+ : url_id(arg_url_id),
visit_time(arg_visit_time),
referring_visit(arg_referring_visit),
transition(arg_transition),
- segment_id(arg_segment_id) {
-}
+ segment_id(arg_segment_id) {}
VisitRow::~VisitRow() {
}
@@ -99,9 +91,8 @@ void QueryResults::DeleteRange(size_t begin, size_t end) {
results_.erase(results_.begin() + begin, results_.begin() + end + 1);
// Delete the indicies referencing the deleted entries.
- for (std::set<GURL>::const_iterator url = urls_modified.begin();
- url != urls_modified.end(); ++url) {
- URLToResultIndices::iterator found = url_to_results_.find(*url);
+ for (const auto& url : urls_modified) {
+ URLToResultIndices::iterator found = url_to_results_.find(url);
if (found == url_to_results_.end()) {
NOTREACHED();
continue;
@@ -154,10 +145,7 @@ void QueryResults::AdjustResultMap(size_t begin, size_t end, ptrdiff_t delta) {
// QueryOptions ----------------------------------------------------------------
-QueryOptions::QueryOptions()
- : max_count(0),
- duplicate_policy(QueryOptions::REMOVE_ALL_DUPLICATES),
- matching_algorithm(query_parser::MatchingAlgorithm::DEFAULT) {}
+QueryOptions::QueryOptions() {}
void QueryOptions::SetRecentDayRange(int days_ago) {
end_time = base::Time::Now();
@@ -179,8 +167,7 @@ int QueryOptions::EffectiveMaxCount() const {
// QueryURLResult -------------------------------------------------------------
-QueryURLResult::QueryURLResult() : success(false) {
-}
+QueryURLResult::QueryURLResult() {}
QueryURLResult::~QueryURLResult() {
}
@@ -190,26 +177,27 @@ QueryURLResult::~QueryURLResult() {
MostVisitedURL::MostVisitedURL() {}
MostVisitedURL::MostVisitedURL(const GURL& url,
- const base::string16& title)
- : url(url),
- title(title) {
-}
-
-MostVisitedURL::MostVisitedURL(const GURL& url,
const base::string16& title,
- const base::Time& last_forced_time)
- : url(url),
- title(title),
- last_forced_time(last_forced_time) {
-}
+ base::Time last_forced_time)
+ : url(url), title(title), last_forced_time(last_forced_time) {}
MostVisitedURL::MostVisitedURL(const MostVisitedURL& other) = default;
+// TODO(bug 706963) this should be implemented as "= default" when Android
+// toolchain is updated.
+MostVisitedURL::MostVisitedURL(MostVisitedURL&& other) noexcept
+ : url(std::move(other.url)),
+ title(std::move(other.title)),
+ last_forced_time(other.last_forced_time),
+ redirects(std::move(other.redirects)) {}
+
MostVisitedURL::~MostVisitedURL() {}
+MostVisitedURL& MostVisitedURL::operator=(const MostVisitedURL&) = default;
+
// FilteredURL -----------------------------------------------------------------
-FilteredURL::FilteredURL() : score(0.0) {}
+FilteredURL::FilteredURL() {}
FilteredURL::FilteredURL(const PageUsageData& page_data)
: url(page_data.GetURL()),
@@ -217,15 +205,13 @@ FilteredURL::FilteredURL(const PageUsageData& page_data)
score(page_data.GetScore()) {
}
+FilteredURL::FilteredURL(FilteredURL&& other) noexcept = default;
+
FilteredURL::~FilteredURL() {}
// FilteredURL::ExtendedInfo ---------------------------------------------------
-FilteredURL::ExtendedInfo::ExtendedInfo()
- : total_visits(0),
- visits(0),
- duration_opened(0) {
-}
+FilteredURL::ExtendedInfo::ExtendedInfo() = default;
// Images ---------------------------------------------------------------------
@@ -299,31 +285,27 @@ MostVisitedThumbnails::~MostVisitedThumbnails() {}
// IconMapping ----------------------------------------------------------------
-IconMapping::IconMapping()
- : mapping_id(0), icon_id(0), icon_type(favicon_base::INVALID_ICON) {}
+IconMapping::IconMapping() {}
+IconMapping::IconMapping(const IconMapping&) = default;
+IconMapping::IconMapping(IconMapping&&) noexcept = default;
IconMapping::~IconMapping() {}
+IconMapping& IconMapping::operator=(const IconMapping&) = default;
+
// FaviconBitmapIDSize ---------------------------------------------------------
-FaviconBitmapIDSize::FaviconBitmapIDSize()
- : bitmap_id(0) {
-}
+FaviconBitmapIDSize::FaviconBitmapIDSize() {}
-FaviconBitmapIDSize::~FaviconBitmapIDSize() {
-}
+FaviconBitmapIDSize::~FaviconBitmapIDSize() {}
// FaviconBitmap --------------------------------------------------------------
-FaviconBitmap::FaviconBitmap()
- : bitmap_id(0),
- icon_id(0) {
-}
+FaviconBitmap::FaviconBitmap() {}
FaviconBitmap::FaviconBitmap(const FaviconBitmap& other) = default;
-FaviconBitmap::~FaviconBitmap() {
-}
+FaviconBitmap::~FaviconBitmap() {}
// ExpireHistoryArgs ----------------------------------------------------------
diff --git a/chromium/components/history/core/browser/history_types.h b/chromium/components/history/core/browser/history_types.h
index e560ed7c020..9189b068c5a 100644
--- a/chromium/components/history/core/browser/history_types.h
+++ b/chromium/components/history/core/browser/history_types.h
@@ -78,23 +78,23 @@ class VisitRow {
~VisitRow();
// ID of this row (visit ID, used a a referrer for other visits).
- VisitID visit_id;
+ VisitID visit_id = 0;
// Row ID into the URL table of the URL that this page is.
- URLID url_id;
+ URLID url_id = 0;
base::Time visit_time;
// Indicates another visit that was the referring page for this one.
// 0 indicates no referrer.
- VisitID referring_visit;
+ VisitID referring_visit = 0;
// A combination of bits from PageTransition.
- ui::PageTransition transition;
+ ui::PageTransition transition = ui::PAGE_TRANSITION_LINK;
// The segment id (see visitsegment_database.*).
// If 0, the segment id is null in the table.
- SegmentID segment_id;
+ SegmentID segment_id = 0;
// Record how much time a user has this visit starting from the user
// opened this visit to the user closed or ended this visit.
@@ -103,7 +103,7 @@ class VisitRow {
base::TimeDelta visit_duration;
// Compares two visits based on dates, for sorting.
- bool operator<(const VisitRow& other) {
+ bool operator<(const VisitRow& other) const {
return visit_time < other.visit_time;
}
@@ -123,7 +123,7 @@ typedef std::pair<base::Time, ui::PageTransition> VisitInfo;
// views are only interested in the time, and not the other information
// associated with a VisitRow.
struct PageVisit {
- URLID page_id;
+ URLID page_id = 0;
base::Time visit_time;
};
@@ -205,7 +205,7 @@ class QueryResults {
// time an entry with that URL appears. Normally, each URL will have one or
// very few indices after it, so we optimize this to use statically allocated
// memory when possible.
- typedef std::map<GURL, base::StackVector<size_t, 4> > URLToResultIndices;
+ typedef std::map<GURL, base::StackVector<size_t, 4>> URLToResultIndices;
// Inserts an entry into the |url_to_results_| map saying that the given URL
// is at the given index in the results_.
@@ -251,8 +251,8 @@ struct QueryOptions {
// The maximum number of results to return. The results will be sorted with
// the most recent first, so older results may not be returned if there is not
- // enough room. When 0, this will return everything (the default).
- int max_count;
+ // enough room. When 0, this will return everything.
+ int max_count = 0;
enum DuplicateHandling {
// Omit visits for which there is a more recent visit to the same URL.
@@ -269,11 +269,12 @@ struct QueryOptions {
};
// Allows the caller to specify how duplicate URLs in the result set should
- // be handled. The default is REMOVE_DUPLICATES.
- DuplicateHandling duplicate_policy;
+ // be handled.
+ DuplicateHandling duplicate_policy = REMOVE_ALL_DUPLICATES;
// Allows the caller to specify the matching algorithm for text queries.
- query_parser::MatchingAlgorithm matching_algorithm;
+ query_parser::MatchingAlgorithm matching_algorithm =
+ query_parser::MatchingAlgorithm::DEFAULT;
// Helpers to get the effective parameters values, since a value of 0 means
// "unspecified".
@@ -291,7 +292,7 @@ struct QueryURLResult {
// Indicates whether the call to HistoryBackend::QueryURL was successfull
// or not. If false, then both |row| and |visits| fields are undefined.
- bool success;
+ bool success = false;
URLRow row;
VisitVector visits;
};
@@ -304,8 +305,8 @@ struct VisibleVisitCountToHostResult {
// Indicates whether the call to HistoryBackend::GetVisibleVisitCountToHost
// was successful or not. If false, then both |count| and |first_visit| are
// undefined.
- bool success;
- int count;
+ bool success = false;
+ int count = 0;
base::Time first_visit;
};
@@ -314,11 +315,11 @@ struct VisibleVisitCountToHostResult {
// Holds the per-URL information of the most visited query.
struct MostVisitedURL {
MostVisitedURL();
- MostVisitedURL(const GURL& url, const base::string16& title);
MostVisitedURL(const GURL& url,
const base::string16& title,
- const base::Time& last_forced_time);
+ base::Time last_forced_time = base::Time());
MostVisitedURL(const MostVisitedURL& other);
+ MostVisitedURL(MostVisitedURL&& other) noexcept;
~MostVisitedURL();
GURL url;
@@ -331,6 +332,8 @@ struct MostVisitedURL {
RedirectList redirects;
+ MostVisitedURL& operator=(const MostVisitedURL&);
+
bool operator==(const MostVisitedURL& other) const {
return url == other.url;
}
@@ -343,22 +346,23 @@ struct FilteredURL {
struct ExtendedInfo {
ExtendedInfo();
// The absolute number of visits.
- unsigned int total_visits;
+ unsigned int total_visits = 0;
// The number of visits, as seen by the Most Visited NTP pane.
- unsigned int visits;
+ unsigned int visits = 0;
// The total number of seconds that the page was open.
- int64_t duration_opened;
+ int64_t duration_opened = 0;
// The time when the page was last visited.
base::Time last_visit_time;
};
FilteredURL();
explicit FilteredURL(const PageUsageData& data);
+ FilteredURL(FilteredURL&& other) noexcept;
~FilteredURL();
GURL url;
base::string16 title;
- double score;
+ double score = 0.0;
ExtendedInfo extended_info;
};
@@ -437,7 +441,7 @@ struct TopSitesDelta {
MostVisitedURLWithRankList moved;
};
-typedef std::map<GURL, scoped_refptr<base::RefCountedBytes> > URLToThumbnailMap;
+typedef std::map<GURL, scoped_refptr<base::RefCountedBytes>> URLToThumbnailMap;
// Used when migrating most visited thumbnails out of history and into topsites.
struct ThumbnailMigration {
@@ -479,8 +483,8 @@ typedef std::map<GURL, std::pair<int, base::Time>> OriginCountAndLastVisitMap;
struct HistoryCountResult {
// Indicates whether the call to HistoryBackend::GetHistoryCount was
// successful or not. If false, then |count| is undefined.
- bool success;
- int count;
+ bool success = false;
+ int count = 0;
};
// Favicons -------------------------------------------------------------------
@@ -488,22 +492,26 @@ struct HistoryCountResult {
// Used for the mapping between the page and icon.
struct IconMapping {
IconMapping();
+ IconMapping(const IconMapping&);
+ IconMapping(IconMapping&&) noexcept;
~IconMapping();
+ IconMapping& operator=(const IconMapping&);
+
// The unique id of the mapping.
- IconMappingID mapping_id;
+ IconMappingID mapping_id = 0;
// The url of a web page.
GURL page_url;
// The unique id of the icon.
- favicon_base::FaviconID icon_id;
+ favicon_base::FaviconID icon_id = 0;
// The url of the icon.
GURL icon_url;
// The type of icon.
- favicon_base::IconType icon_type;
+ favicon_base::IconType icon_type = favicon_base::INVALID_ICON;
};
// Defines a favicon bitmap and its associated pixel size.
@@ -512,7 +520,7 @@ struct FaviconBitmapIDSize {
~FaviconBitmapIDSize();
// The unique id of the favicon bitmap.
- FaviconBitmapID bitmap_id;
+ FaviconBitmapID bitmap_id = 0;
// The pixel dimensions of the associated bitmap.
gfx::Size pixel_size;
@@ -525,10 +533,10 @@ struct FaviconBitmap {
~FaviconBitmap();
// The unique id of the bitmap.
- FaviconBitmapID bitmap_id;
+ FaviconBitmapID bitmap_id = 0;
// The id of the favicon to which the bitmap belongs to.
- favicon_base::FaviconID icon_id;
+ favicon_base::FaviconID icon_id = 0;
// Time at which |bitmap_data| was last updated.
base::Time last_updated;
diff --git a/chromium/components/history/core/browser/in_memory_database.cc b/chromium/components/history/core/browser/in_memory_database.cc
index b99e202f21d..3ae5f679041 100644
--- a/chromium/components/history/core/browser/in_memory_database.cc
+++ b/chromium/components/history/core/browser/in_memory_database.cc
@@ -79,8 +79,23 @@ bool InMemoryDatabase::InitFromDisk(const base::FilePath& history_name) {
// Copy URL data to memory.
base::TimeTicks begin_load = base::TimeTicks::Now();
+
+ // Need to explicitly specify the column names here since databases on disk
+ // may or may not have a favicon_id column, but the in-memory one will never
+ // have it. Therefore, the columns aren't guaranteed to match.
+ //
+ // TODO(https://crbug.com/736136) Once we can guarantee that the favicon_id
+ // column doesn't exist with migration code, this can be replaced with the
+ // simpler:
+ // "INSERT INTO urls SELECT * FROM history.urls WHERE typed_count > 0"
+ // which does not require us to keep the list of columns in sync. However,
+ // we may still want to keep the explicit columns as a safety measure.
if (!db_.Execute(
- "INSERT INTO urls SELECT * FROM history.urls WHERE typed_count > 0")) {
+ "INSERT INTO urls "
+ "(id, url, title, visit_count, typed_count, last_visit_time, hidden) "
+ "SELECT "
+ "id, url, title, visit_count, typed_count, last_visit_time, hidden "
+ "FROM history.urls WHERE typed_count > 0")) {
// Unable to get data from the history database. This is OK, the file may
// just not exist yet.
}
@@ -102,11 +117,10 @@ bool InMemoryDatabase::InitFromDisk(const base::FilePath& history_name) {
// Insert keyword search related URLs.
begin_load = base::TimeTicks::Now();
- if (!db_.Execute(
- "INSERT OR IGNORE INTO urls SELECT u.id, u.url, u.title, u.visit_count, "
- "u.typed_count, u.last_visit_time, u.hidden, u.favicon_id "
- "FROM history.urls u JOIN history.keyword_search_terms kst "
- "WHERE u.typed_count = 0 AND u.id = kst.url_id")) {
+ if (!db_.Execute("INSERT OR IGNORE INTO urls SELECT u.id, u.url, u.title, "
+ "u.visit_count, u.typed_count, u.last_visit_time, u.hidden "
+ "FROM history.urls u JOIN history.keyword_search_terms kst "
+ "WHERE u.typed_count = 0 AND u.id = kst.url_id")) {
// Unable to get data from the history database. This is OK, the file may
// just not exist yet.
}
diff --git a/chromium/components/history/core/browser/thumbnail_database.cc b/chromium/components/history/core/browser/thumbnail_database.cc
index f476c6e0db1..d9bc22defb1 100644
--- a/chromium/components/history/core/browser/thumbnail_database.cc
+++ b/chromium/components/history/core/browser/thumbnail_database.cc
@@ -82,9 +82,9 @@ namespace {
// fatal (in fact, very old data may be expired immediately at startup
// anyhow).
-// Version 8: ???????? by rogerm@chromium.org on 2015-??-??
+// Version 8: 982ef2c1/r323176 by rogerm@chromium.org on 2015-03-31
// Version 7: 911a634d/r209424 by qsr@chromium.org on 2013-07-01
-// Version 6: 610f923b/r152367 by pkotwicz@chromium.org on 2012-08-20
+// Version 6: 610f923b/r152367 by pkotwicz@chromium.org on 2012-08-20 (depr.)
// Version 5: e2ee8ae9/r105004 by groby@chromium.org on 2011-10-12 (deprecated)
// Version 4: 5f104d76/r77288 by sky@chromium.org on 2011-03-08 (deprecated)
// Version 3: 09911bf3/r15 by initial.commit on 2008-07-26 (deprecated)
@@ -94,7 +94,7 @@ namespace {
// the new version and a test to verify that Init() works with it.
const int kCurrentVersionNumber = 8;
const int kCompatibleVersionNumber = 8;
-const int kDeprecatedVersionNumber = 5; // and earlier.
+const int kDeprecatedVersionNumber = 6; // and earlier.
void FillIconMapping(const sql::Statement& statement,
const GURL& page_url,
@@ -146,8 +146,7 @@ void GenerateDiagnostics(sql::Connection* db,
}
// NOTE(shess): Schema modifications must consider initial creation in
-// |InitImpl()|, recovery in |RecoverDatabaseOrRaze()|, and history pruning in
-// |RetainDataForPageUrls()|.
+// |InitImpl()| and history pruning in |RetainDataForPageUrls()|.
bool InitTables(sql::Connection* db) {
const char kIconMappingSql[] =
"CREATE TABLE IF NOT EXISTS icon_mapping"
@@ -190,8 +189,7 @@ bool InitTables(sql::Connection* db) {
}
// NOTE(shess): Schema modifications must consider initial creation in
-// |InitImpl()|, recovery in |RecoverDatabaseOrRaze()|, and history pruning in
-// |RetainDataForPageUrls()|.
+// |InitImpl()| and history pruning in |RetainDataForPageUrls()|.
bool InitIndices(sql::Connection* db) {
const char kIconMappingUrlIndexSql[] =
"CREATE INDEX IF NOT EXISTS icon_mapping_page_url_idx"
@@ -218,199 +216,6 @@ bool InitIndices(sql::Connection* db) {
return true;
}
-enum RecoveryEventType {
- RECOVERY_EVENT_RECOVERED = 0,
- RECOVERY_EVENT_FAILED_SCOPER,
- RECOVERY_EVENT_FAILED_META_VERSION_ERROR, // obsolete
- RECOVERY_EVENT_FAILED_META_VERSION_NONE, // obsolete
- RECOVERY_EVENT_FAILED_META_WRONG_VERSION6, // obsolete
- RECOVERY_EVENT_FAILED_META_WRONG_VERSION5, // obsolete
- RECOVERY_EVENT_FAILED_META_WRONG_VERSION,
- RECOVERY_EVENT_FAILED_RECOVER_META, // obsolete
- RECOVERY_EVENT_FAILED_META_INSERT, // obsolete
- RECOVERY_EVENT_FAILED_INIT,
- RECOVERY_EVENT_FAILED_RECOVER_FAVICONS, // obsolete
- RECOVERY_EVENT_FAILED_FAVICONS_INSERT, // obsolete
- RECOVERY_EVENT_FAILED_RECOVER_FAVICON_BITMAPS, // obsolete
- RECOVERY_EVENT_FAILED_FAVICON_BITMAPS_INSERT, // obsolete
- RECOVERY_EVENT_FAILED_RECOVER_ICON_MAPPING, // obsolete
- RECOVERY_EVENT_FAILED_ICON_MAPPING_INSERT, // obsolete
- RECOVERY_EVENT_RECOVERED_VERSION6, // obsolete
- RECOVERY_EVENT_FAILED_META_INIT,
- RECOVERY_EVENT_FAILED_META_VERSION,
- RECOVERY_EVENT_DEPRECATED,
- RECOVERY_EVENT_FAILED_V5_INITSCHEMA, // obsolete
- RECOVERY_EVENT_FAILED_V5_AUTORECOVER_FAVICONS, // obsolete
- RECOVERY_EVENT_FAILED_V5_AUTORECOVER_ICON_MAPPING, // obsolete
- RECOVERY_EVENT_RECOVERED_VERSION5, // obsolete
- RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICONS,
- RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICON_BITMAPS,
- RECOVERY_EVENT_FAILED_AUTORECOVER_ICON_MAPPING,
- RECOVERY_EVENT_FAILED_COMMIT,
-
- // Always keep this at the end.
- RECOVERY_EVENT_MAX,
-};
-
-void RecordRecoveryEvent(RecoveryEventType recovery_event) {
- UMA_HISTOGRAM_ENUMERATION("History.FaviconsRecovery",
- recovery_event, RECOVERY_EVENT_MAX);
-}
-
-// Recover the database to the extent possible, razing it if recovery
-// is not possible.
-// TODO(shess): This is mostly just a safe proof of concept. In the
-// real world, this database is probably not worthwhile recovering, as
-// opposed to just razing it and starting over whenever corruption is
-// detected. So this database is a good test subject.
-void RecoverDatabaseOrRaze(sql::Connection* db, const base::FilePath& db_path) {
- // NOTE(shess): This code is currently specific to the version
- // number. I am working on simplifying things to loosen the
- // dependency, meanwhile contact me if you need to bump the version.
- DCHECK_EQ(8, kCurrentVersionNumber);
-
- // TODO(shess): Reset back after?
- db->reset_error_callback();
-
- // For histogram purposes.
- size_t favicons_rows_recovered = 0;
- size_t favicon_bitmaps_rows_recovered = 0;
- size_t icon_mapping_rows_recovered = 0;
- int64_t original_size = 0;
- base::GetFileSize(db_path, &original_size);
-
- std::unique_ptr<sql::Recovery> recovery = sql::Recovery::Begin(db, db_path);
- if (!recovery) {
- // TODO(shess): Unable to create recovery connection. This
- // implies something substantial is wrong. At this point |db| has
- // been poisoned so there is nothing really to do.
- //
- // Possible responses are unclear. If the failure relates to a
- // problem somehow specific to the temporary file used to back the
- // database, then an in-memory database could possibly be used.
- // This could potentially allow recovering the main database, and
- // might be simple to implement w/in Begin().
- RecordRecoveryEvent(RECOVERY_EVENT_FAILED_SCOPER);
- return;
- }
-
- // Setup the meta recovery table and fetch the version number from
- // the corrupt database.
- int version = 0;
- if (!recovery->SetupMeta() || !recovery->GetMetaVersionNumber(&version)) {
- // TODO(shess): Prior histograms indicate all failures are in
- // creating the recover virtual table for corrupt.meta. The table
- // may not exist, or the database may be too far gone. Either
- // way, unclear how to resolve.
- sql::Recovery::Rollback(std::move(recovery));
- RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_VERSION);
- return;
- }
-
- // This code may be able to fetch version information that the regular
- // deprecation path cannot.
- // NOTE(shess,rogerm): v6 is not currently deprecated in the normal Init()
- // path, but is deprecated in the recovery path in the interest of keeping
- // the code simple. http://crbug.com/327485 for numbers.
- DCHECK_LE(kDeprecatedVersionNumber, 6);
- if (version <= 6) {
- sql::Recovery::Unrecoverable(std::move(recovery));
- RecordRecoveryEvent(RECOVERY_EVENT_DEPRECATED);
- return;
- }
-
- // Earlier versions have been handled or deprecated.
- if (version < 7) {
- sql::Recovery::Unrecoverable(std::move(recovery));
- RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_WRONG_VERSION);
- return;
- }
-
- // Recover to current schema version.
- sql::MetaTable recover_meta_table;
- if (!recover_meta_table.Init(recovery->db(), kCurrentVersionNumber,
- kCompatibleVersionNumber)) {
- sql::Recovery::Rollback(std::move(recovery));
- RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_INIT);
- return;
- }
-
- // Create a fresh version of the database. The recovery code uses
- // conflict-resolution to handle duplicates, so the indices are
- // necessary.
- if (!InitTables(recovery->db()) || !InitIndices(recovery->db())) {
- // TODO(shess): Unable to create the new schema in the new
- // database. The new database should be a temporary file, so
- // being unable to work with it is pretty unclear.
- //
- // What are the potential responses, even? The recovery database
- // could be opened as in-memory. If the temp database had a
- // filesystem problem and the temp filesystem differs from the
- // main database, then that could fix it.
- sql::Recovery::Rollback(std::move(recovery));
- RecordRecoveryEvent(RECOVERY_EVENT_FAILED_INIT);
- return;
- }
-
- if (!recovery->AutoRecoverTable("favicons", &favicons_rows_recovered)) {
- sql::Recovery::Rollback(std::move(recovery));
- RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICONS);
- return;
- }
- if (!recovery->AutoRecoverTable("favicon_bitmaps",
- &favicon_bitmaps_rows_recovered)) {
- sql::Recovery::Rollback(std::move(recovery));
- RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICON_BITMAPS);
- return;
- }
- if (!recovery->AutoRecoverTable("icon_mapping",
- &icon_mapping_rows_recovered)) {
- sql::Recovery::Rollback(std::move(recovery));
- RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER_ICON_MAPPING);
- return;
- }
-
- // TODO(shess): Is it possible/likely to have broken foreign-key
- // issues with the tables?
- // - icon_mapping.icon_id maps to no favicons.id
- // - favicon_bitmaps.icon_id maps to no favicons.id
- // - favicons.id is referenced by no icon_mapping.icon_id
- // - favicons.id is referenced by no favicon_bitmaps.icon_id
- // This step is possibly not worth the effort necessary to develop
- // and sequence the statements, as it is basically a form of garbage
- // collection.
-
- if (!sql::Recovery::Recovered(std::move(recovery))) {
- RecordRecoveryEvent(RECOVERY_EVENT_FAILED_COMMIT);
- return;
- }
-
- // Track the size of the recovered database relative to the size of
- // the input database. The size should almost always be smaller,
- // unless the input database was empty to start with. If the
- // percentage results are very low, something is awry.
- int64_t final_size = 0;
- if (original_size > 0 &&
- base::GetFileSize(db_path, &final_size) &&
- final_size > 0) {
- int percentage = static_cast<int>(original_size * 100 / final_size);
- UMA_HISTOGRAM_PERCENTAGE("History.FaviconsRecoveredPercentage",
- std::max(100, percentage));
- }
-
- // Using 10,000 because these cases mostly care about "none
- // recovered" and "lots recovered". More than 10,000 rows recovered
- // probably means there's something wrong with the profile.
- UMA_HISTOGRAM_COUNTS_10000("History.FaviconsRecoveredRowsFavicons",
- static_cast<int>(favicons_rows_recovered));
- UMA_HISTOGRAM_COUNTS_10000("History.FaviconsRecoveredRowsFaviconBitmaps",
- static_cast<int>(favicon_bitmaps_rows_recovered));
- UMA_HISTOGRAM_COUNTS_10000("History.FaviconsRecoveredRowsIconMapping",
- static_cast<int>(icon_mapping_rows_recovered));
-
- RecordRecoveryEvent(RECOVERY_EVENT_RECOVERED);
-}
-
void DatabaseErrorCallback(sql::Connection* db,
const base::FilePath& db_path,
HistoryBackendClient* backend_client,
@@ -425,11 +230,36 @@ void DatabaseErrorCallback(sql::Connection* db,
}
// Attempt to recover corrupt databases.
- int error = (extended_error & 0xFF);
- if (error == SQLITE_CORRUPT ||
- error == SQLITE_CANTOPEN ||
- error == SQLITE_NOTADB) {
- RecoverDatabaseOrRaze(db, db_path);
+ if (sql::Recovery::ShouldRecover(extended_error)) {
+ // NOTE(shess): This approach is valid as of version 8. When bumping the
+ // version, it will PROBABLY remain valid, but consider whether any schema
+ // changes might break automated recovery.
+ DCHECK_EQ(8, kCurrentVersionNumber);
+
+ // Prevent reentrant calls.
+ db->reset_error_callback();
+
+ // TODO(shess): Is it possible/likely to have broken foreign-key
+ // issues with the tables?
+ // - icon_mapping.icon_id maps to no favicons.id
+ // - favicon_bitmaps.icon_id maps to no favicons.id
+ // - favicons.id is referenced by no icon_mapping.icon_id
+ // - favicons.id is referenced by no favicon_bitmaps.icon_id
+ // This step is possibly not worth the effort necessary to develop
+ // and sequence the statements, as it is basically a form of garbage
+ // collection.
+
+ // After this call, the |db| handle is poisoned so that future calls will
+ // return errors until the handle is re-opened.
+ sql::Recovery::RecoverDatabaseWithMetaVersion(db, db_path);
+
+ // The DLOG(FATAL) below is intended to draw immediate attention to errors
+ // in newly-written code. Database corruption is generally a result of OS
+ // 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::Connection::IsExpectedSqliteError(extended_error));
+ return;
}
// The default handling is to assert on debug and to ignore on release.
diff --git a/chromium/components/history/core/browser/thumbnail_database_unittest.cc b/chromium/components/history/core/browser/thumbnail_database_unittest.cc
index 61873b37978..b20bbaf3f78 100644
--- a/chromium/components/history/core/browser/thumbnail_database_unittest.cc
+++ b/chromium/components/history/core/browser/thumbnail_database_unittest.cc
@@ -636,34 +636,8 @@ TEST_F(ThumbnailDatabaseTest, Version6) {
ASSERT_TRUE(db.get() != NULL);
VerifyTablesAndColumns(&db->db_);
- EXPECT_TRUE(CheckPageHasIcon(db.get(),
- kPageUrl1,
- favicon_base::FAVICON,
- kIconUrl1,
- kLargeSize,
- sizeof(kBlob1),
- kBlob1));
- EXPECT_TRUE(CheckPageHasIcon(db.get(),
- kPageUrl2,
- favicon_base::FAVICON,
- kIconUrl2,
- kLargeSize,
- sizeof(kBlob2),
- kBlob2));
- EXPECT_TRUE(CheckPageHasIcon(db.get(),
- kPageUrl3,
- favicon_base::FAVICON,
- kIconUrl1,
- kLargeSize,
- sizeof(kBlob1),
- kBlob1));
- EXPECT_TRUE(CheckPageHasIcon(db.get(),
- kPageUrl3,
- favicon_base::TOUCH_ICON,
- kIconUrl3,
- kLargeSize,
- sizeof(kBlob2),
- kBlob2));
+ // Version 6 is deprecated, the data should all be gone.
+ VerifyDatabaseEmpty(&db->db_);
}
// Test loading version 7 database.
diff --git a/chromium/components/history/core/browser/top_sites_database.cc b/chromium/components/history/core/browser/top_sites_database.cc
index 7e9fc819a0a..435930053a2 100644
--- a/chromium/components/history/core/browser/top_sites_database.cc
+++ b/chromium/components/history/core/browser/top_sites_database.cc
@@ -12,6 +12,7 @@
#include "base/files/file_util.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "components/history/core/browser/history_types.h"
@@ -57,16 +58,13 @@ namespace {
// anyhow).
// Version 3: b6d6a783/r231648 by beaudoin@chromium.org on 2013-10-29
-// Version 2: eb0b24e6/r87284 by satorux@chromium.org on 2011-05-31
+// Version 2: eb0b24e6/r87284 by satorux@chromium.org on 2011-05-31 (deprecated)
// Version 1: 809cc4d8/r64072 by sky@chromium.org on 2010-10-27 (deprecated)
// NOTE(shess): When changing the version, add a new golden file for
// the new version and a test to verify that Init() works with it.
-// NOTE(shess): RecoverDatabaseOrRaze() depends on the specific
-// version number. The code is subtle and in development, contact me
-// if the necessary changes are not obvious.
static const int kVersionNumber = 3;
-static const int kDeprecatedVersionNumber = 1; // and earlier.
+static const int kDeprecatedVersionNumber = 2; // and earlier.
bool InitTables(sql::Connection* db) {
const char kThumbnailsSql[] =
@@ -87,9 +85,9 @@ bool InitTables(sql::Connection* db) {
// Encodes redirects into a string.
std::string GetRedirects(const MostVisitedURL& url) {
- std::vector<std::string> redirects;
- for (size_t i = 0; i < url.redirects.size(); i++)
- redirects.push_back(url.redirects[i].spec());
+ std::vector<base::StringPiece> redirects;
+ for (const auto& redirect : url.redirects)
+ redirects.push_back(redirect.spec());
return base::JoinString(redirects, " ");
}
@@ -107,9 +105,8 @@ void SetRedirects(const std::string& redirects, MostVisitedURL* url) {
// Track various failure (and success) cases in recovery code.
//
// TODO(shess): The recovery code is complete, but by nature runs in challenging
-// circumstances, so initially the default error response is to leave the
-// existing database in place. This histogram is intended to expose the
-// failures seen in the fleet. Frequent failure cases can be explored more
+// circumstances, so errors will happen. This histogram is intended to expose
+// the failures seen in the fleet. Frequent failure cases can be explored more
// deeply to see if the complexity to fix them is warranted. Infrequent failure
// cases can be resolved by marking the database unrecoverable (which will
// delete the data).
@@ -125,12 +122,12 @@ enum RecoveryEventType {
// Sqlite.RecoveryEvent can usually be used to get more detail about the
// specific failure (see sql/recovery.cc).
- RECOVERY_EVENT_FAILED_SCOPER,
+ OBSOLETE_RECOVERY_EVENT_FAILED_SCOPER,
RECOVERY_EVENT_FAILED_META_VERSION,
RECOVERY_EVENT_FAILED_META_WRONG_VERSION,
- RECOVERY_EVENT_FAILED_META_INIT,
- RECOVERY_EVENT_FAILED_SCHEMA_INIT,
- RECOVERY_EVENT_FAILED_AUTORECOVER_THUMBNAILS,
+ OBSOLETE_RECOVERY_EVENT_FAILED_META_INIT,
+ OBSOLETE_RECOVERY_EVENT_FAILED_SCHEMA_INIT,
+ OBSOLETE_RECOVERY_EVENT_FAILED_AUTORECOVER_THUMBNAILS,
RECOVERY_EVENT_FAILED_COMMIT,
// Track invariants resolved by FixThumbnailsTable().
@@ -138,6 +135,9 @@ enum RecoveryEventType {
RECOVERY_EVENT_INVARIANT_REDIRECT,
RECOVERY_EVENT_INVARIANT_CONTIGUOUS,
+ // Track automated full-database recovery.
+ RECOVERY_EVENT_FAILED_AUTORECOVER,
+
// Always keep this at the end.
RECOVERY_EVENT_MAX,
};
@@ -202,89 +202,48 @@ void FixThumbnailsTable(sql::Connection* db) {
RecordRecoveryEvent(RECOVERY_EVENT_INVARIANT_CONTIGUOUS);
}
-// Recover the database to the extent possible, razing it if recovery is not
-// possible.
-void RecoverDatabaseOrRaze(sql::Connection* db, const base::FilePath& db_path) {
+// Recover the database to the extent possible, then fixup any broken
+// constraints.
+void RecoverAndFixup(sql::Connection* db, const base::FilePath& db_path) {
// NOTE(shess): If the version changes, review this code.
DCHECK_EQ(3, kVersionNumber);
- // It is almost certain that some operation against |db| will fail, prevent
- // reentry.
- db->reset_error_callback();
-
- // For generating histogram stats.
- size_t thumbnails_recovered = 0;
- int64_t original_size = 0;
- base::GetFileSize(db_path, &original_size);
-
- std::unique_ptr<sql::Recovery> recovery = sql::Recovery::Begin(db, db_path);
+ std::unique_ptr<sql::Recovery> recovery =
+ sql::Recovery::BeginRecoverDatabase(db, db_path);
if (!recovery) {
- RecordRecoveryEvent(RECOVERY_EVENT_FAILED_SCOPER);
+ RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER);
return;
}
- // Setup the meta recovery table and fetch the version number from the corrupt
- // database.
+ // If the [meta] table does not exist, or the [version] key cannot be found,
+ // then the schema is indeterminate. The only plausible approach would be to
+ // validate that the schema contains all of the tables and indices and columns
+ // expected, but that complexity may not be warranted, this case has only been
+ // seen for a few thousand database files.
int version = 0;
if (!recovery->SetupMeta() || !recovery->GetMetaVersionNumber(&version)) {
- // TODO(shess): Prior histograms indicate all failures are in creating the
- // recover virtual table for corrupt.meta. The table may not exist, or the
- // database may be too far gone. Either way, unclear how to resolve.
- sql::Recovery::Rollback(std::move(recovery));
+ sql::Recovery::Unrecoverable(std::move(recovery));
RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_VERSION);
return;
}
- // This code runs in a context which may be able to read version information
- // that the regular deprecation path cannot. The effect of this code will be
- // to raze the database.
+ // In this case the next open will clear the database anyhow.
if (version <= kDeprecatedVersionNumber) {
sql::Recovery::Unrecoverable(std::move(recovery));
RecordRecoveryEvent(RECOVERY_EVENT_DEPRECATED);
return;
}
- // TODO(shess): Earlier versions have been deprecated, later versions should
- // be impossible. Unrecoverable() seems like a feasible response if this is
- // infrequent enough.
- if (version != 2 && version != 3) {
+ // TODO(shess): Consider marking corrupt databases from the future
+ // Unrecoverable(), since this histogram value has never been seen. OTOH,
+ // this may be too risky, because if future code was correlated with
+ // corruption then rollback would be a sensible response.
+ if (version > kVersionNumber) {
RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_WRONG_VERSION);
sql::Recovery::Rollback(std::move(recovery));
return;
}
- // Both v2 and v3 recover to current schema version.
- sql::MetaTable recover_meta_table;
- if (!recover_meta_table.Init(recovery->db(), kVersionNumber,
- kVersionNumber)) {
- sql::Recovery::Rollback(std::move(recovery));
- RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_INIT);
- return;
- }
-
- // Create a fresh version of the schema. The recovery code uses
- // conflict-resolution to handle duplicates, so any indices are necessary.
- if (!InitTables(recovery->db())) {
- // TODO(shess): Unable to create the new schema in the new database. The
- // new database should be a temporary file, so being unable to work with it
- // is pretty unclear.
- //
- // What are the potential responses, even? The recovery database could be
- // opened as in-memory. If the temp database had a filesystem problem and
- // the temp filesystem differs from the main database, then that could fix
- // it.
- sql::Recovery::Rollback(std::move(recovery));
- RecordRecoveryEvent(RECOVERY_EVENT_FAILED_SCHEMA_INIT);
- return;
- }
-
- // In the v2 case the missing column will get default values.
- if (!recovery->AutoRecoverTable("thumbnails", &thumbnails_recovered)) {
- sql::Recovery::Rollback(std::move(recovery));
- RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER_THUMBNAILS);
- return;
- }
-
// TODO(shess): Inline this?
FixThumbnailsTable(recovery->db());
@@ -296,23 +255,6 @@ void RecoverDatabaseOrRaze(sql::Connection* db, const base::FilePath& db_path) {
return;
}
- // Track the size of the recovered database relative to the size of the input
- // database. The size should almost always be smaller, unless the input
- // database was empty to start with. If the percentage results are very low,
- // something is awry.
- int64_t final_size = 0;
- if (original_size > 0 && base::GetFileSize(db_path, &final_size) &&
- final_size > 0) {
- UMA_HISTOGRAM_PERCENTAGE("History.TopSitesRecoveredPercentage",
- final_size * 100 / original_size);
- }
-
- // Using 10,000 because these cases mostly care about "none recovered" and
- // "lots recovered". More than 10,000 rows recovered probably means there's
- // something wrong with the profile.
- UMA_HISTOGRAM_COUNTS_10000("History.TopSitesRecoveredRowsThumbnails",
- static_cast<int>(thumbnails_recovered));
-
RecordRecoveryEvent(RECOVERY_EVENT_RECOVERED);
}
@@ -324,11 +266,21 @@ void DatabaseErrorCallback(sql::Connection* db,
// be the history thread, but at this level I can't see how to reach that.
// Attempt to recover corrupt databases.
- int error = (extended_error & 0xFF);
- if (error == SQLITE_CORRUPT ||
- error == SQLITE_CANTOPEN ||
- error == SQLITE_NOTADB) {
- RecoverDatabaseOrRaze(db, db_path);
+ if (sql::Recovery::ShouldRecover(extended_error)) {
+ // Prevent reentrant calls.
+ db->reset_error_callback();
+
+ // After this call, the |db| handle is poisoned so that future calls will
+ // return errors until the handle is re-opened.
+ RecoverAndFixup(db, db_path);
+
+ // The DLOG(FATAL) below is intended to draw immediate attention to errors
+ // in newly-written code. Database corruption is generally a result of OS
+ // 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::Connection::IsExpectedSqliteError(extended_error));
+ return;
}
// TODO(shess): This database's error histograms look like:
diff --git a/chromium/components/history/core/browser/top_sites_database_unittest.cc b/chromium/components/history/core/browser/top_sites_database_unittest.cc
index 289b9830404..29683551742 100644
--- a/chromium/components/history/core/browser/top_sites_database_unittest.cc
+++ b/chromium/components/history/core/browser/top_sites_database_unittest.cc
@@ -86,31 +86,15 @@ TEST_F(TopSitesDatabaseTest, Version1) {
VerifyDatabaseEmpty(db.db_.get());
}
+// Version 2 is deprecated, the resulting schema should be current,
+// with no data.
TEST_F(TopSitesDatabaseTest, Version2) {
ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v2.sql"));
TopSitesDatabase db;
ASSERT_TRUE(db.Init(file_name_));
-
VerifyTablesAndColumns(db.db_.get());
-
- // Basic operational check.
- MostVisitedURLList urls;
- std::map<GURL, Images> thumbnails;
- db.GetPageThumbnails(&urls, &thumbnails);
- ASSERT_EQ(3u, urls.size());
- ASSERT_EQ(3u, thumbnails.size());
- EXPECT_EQ(kUrl0, urls[0].url); // [0] because of url_rank.
- // kGoogleThumbnail includes nul terminator.
- ASSERT_EQ(sizeof(kGoogleThumbnail) - 1,
- thumbnails[urls[0].url].thumbnail->size());
- EXPECT_TRUE(!memcmp(thumbnails[urls[0].url].thumbnail->front(),
- kGoogleThumbnail, sizeof(kGoogleThumbnail) - 1));
-
- ASSERT_TRUE(db.RemoveURL(urls[1]));
- db.GetPageThumbnails(&urls, &thumbnails);
- ASSERT_EQ(2u, urls.size());
- ASSERT_EQ(2u, thumbnails.size());
+ VerifyDatabaseEmpty(db.db_.get());
}
TEST_F(TopSitesDatabaseTest, Version3) {
@@ -198,29 +182,15 @@ TEST_F(TopSitesDatabaseTest, Recovery2) {
ASSERT_TRUE(expecter.SawExpectedErrors());
}
- // Corruption should be detected and recovered during Init(). After recovery,
- // the Version2 checks should work.
+ // Corruption should be detected and recovered during Init().
{
sql::test::ScopedErrorExpecter expecter;
expecter.ExpectError(SQLITE_CORRUPT);
TopSitesDatabase db;
ASSERT_TRUE(db.Init(file_name_));
-
VerifyTablesAndColumns(db.db_.get());
-
- // Basic operational check.
- MostVisitedURLList urls;
- std::map<GURL, Images> thumbnails;
- db.GetPageThumbnails(&urls, &thumbnails);
- ASSERT_EQ(3u, urls.size());
- ASSERT_EQ(3u, thumbnails.size());
- EXPECT_EQ(kUrl0, urls[0].url); // [0] because of url_rank.
- // kGoogleThumbnail includes nul terminator.
- ASSERT_EQ(sizeof(kGoogleThumbnail) - 1,
- thumbnails[urls[0].url].thumbnail->size());
- EXPECT_TRUE(!memcmp(thumbnails[urls[0].url].thumbnail->front(),
- kGoogleThumbnail, sizeof(kGoogleThumbnail) - 1));
+ VerifyDatabaseEmpty(db.db_.get());
ASSERT_TRUE(expecter.SawExpectedErrors());
}
diff --git a/chromium/components/history/core/browser/top_sites_impl.cc b/chromium/components/history/core/browser/top_sites_impl.cc
index b9ae71596b5..72378e2940c 100644
--- a/chromium/components/history/core/browser/top_sites_impl.cc
+++ b/chromium/components/history/core/browser/top_sites_impl.cc
@@ -14,6 +14,7 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/md5.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted_memory.h"
#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
@@ -291,7 +292,7 @@ bool TopSitesImpl::HasBlacklistedItems() const {
void TopSitesImpl::AddBlacklistedURL(const GURL& url) {
DCHECK(thread_checker_.CalledOnValidThread());
- std::unique_ptr<base::Value> dummy = base::Value::CreateNullValue();
+ auto dummy = base::MakeUnique<base::Value>();
{
DictionaryPrefUpdate update(pref_service_, kMostVisitedURLsBlacklist);
base::DictionaryValue* blacklist = update.Get();
diff --git a/chromium/components/history/core/browser/top_sites_impl_unittest.cc b/chromium/components/history/core/browser/top_sites_impl_unittest.cc
index f5042274a36..aaacb7352af 100644
--- a/chromium/components/history/core/browser/top_sites_impl_unittest.cc
+++ b/chromium/components/history/core/browser/top_sites_impl_unittest.cc
@@ -31,10 +31,13 @@
#include "components/history/core/test/wait_top_sites_loaded_observer.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 "third_party/skia/include/core/SkBitmap.h"
#include "url/gurl.h"
+using testing::ContainerEq;
+
namespace history {
namespace {
@@ -636,6 +639,42 @@ TEST_F(TopSitesImplTest, GetMostVisited) {
ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
}
+// Tests GetMostVisitedURLs with a redirect.
+TEST_F(TopSitesImplTest, GetMostVisitedWithRedirect) {
+ GURL bare("http://cnn.com/");
+ GURL www("https://www.cnn.com/");
+ GURL edition("https://edition.cnn.com/");
+
+ AddPageToHistory(edition, base::ASCIIToUTF16("CNN"),
+ history::RedirectList{bare, www, edition},
+ base::Time::Now());
+ AddPageToHistory(edition);
+
+ StartQueryForMostVisited();
+ WaitForHistory();
+
+ TopSitesQuerier querier;
+ querier.QueryTopSites(top_sites(), false);
+
+ ASSERT_EQ(1, querier.number_of_callbacks());
+
+ // This behavior is not desirable: even though edition.cnn.com is in the list
+ // of top sites, and the the bare URL cnn.com is just a redirect to it, we're
+ // returning both. Even worse, the NTP will show the same title, icon, and
+ // thumbnail for the site, so to the user it looks like we just have the same
+ // thing twice. (https://crbug.com/567132)
+ std::vector<GURL> expected_urls = {bare, edition}; // should be {edition}.
+
+ for (const auto& prepopulated : GetPrepopulatedPages()) {
+ expected_urls.push_back(prepopulated.most_visited.url);
+ }
+ std::vector<GURL> actual_urls;
+ for (const auto& actual : querier.urls()) {
+ actual_urls.push_back(actual.url);
+ }
+ EXPECT_THAT(actual_urls, ContainerEq(expected_urls));
+}
+
// Makes sure changes done to top sites get mirrored to the db.
TEST_F(TopSitesImplTest, SaveToDB) {
MostVisitedURL url;
diff --git a/chromium/components/history/core/browser/typed_url_sync_bridge.cc b/chromium/components/history/core/browser/typed_url_sync_bridge.cc
new file mode 100644
index 00000000000..55712c82cb7
--- /dev/null
+++ b/chromium/components/history/core/browser/typed_url_sync_bridge.cc
@@ -0,0 +1,103 @@
+// 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/history/core/browser/typed_url_sync_bridge.h"
+
+namespace history {
+
+TypedURLSyncBridge::TypedURLSyncBridge(
+ HistoryBackend* history_backend,
+ const ChangeProcessorFactory& change_processor_factory)
+ : ModelTypeSyncBridge(change_processor_factory, syncer::TYPED_URLS),
+ history_backend_(history_backend) {
+ DCHECK(history_backend_);
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ NOTIMPLEMENTED();
+}
+
+TypedURLSyncBridge::~TypedURLSyncBridge() {
+ // TODO(gangwu): unregister as HistoryBackendObserver, can use ScopedObserver
+ // to do it.
+}
+
+std::unique_ptr<syncer::MetadataChangeList>
+TypedURLSyncBridge::CreateMetadataChangeList() {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ NOTIMPLEMENTED();
+ return {};
+}
+
+base::Optional<syncer::ModelError> TypedURLSyncBridge::MergeSyncData(
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+ syncer::EntityDataMap entity_data_map) {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ NOTIMPLEMENTED();
+ return {};
+}
+
+base::Optional<syncer::ModelError> TypedURLSyncBridge::ApplySyncChanges(
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+ syncer::EntityChangeList entity_changes) {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ NOTIMPLEMENTED();
+ return {};
+}
+
+void TypedURLSyncBridge::GetData(StorageKeyList storage_keys,
+ DataCallback callback) {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ NOTIMPLEMENTED();
+}
+
+void TypedURLSyncBridge::GetAllData(DataCallback callback) {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ NOTIMPLEMENTED();
+}
+
+// Must be exactly the value of GURL::spec() for backwards comparability with
+// 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 syncer::EntityData& entity_data) {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ NOTIMPLEMENTED();
+ return std::string();
+}
+
+// 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 syncer::EntityData& entity_data) {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ NOTIMPLEMENTED();
+ return std::string();
+}
+
+void TypedURLSyncBridge::OnURLVisited(history::HistoryBackend* history_backend,
+ ui::PageTransition transition,
+ const history::URLRow& row,
+ const history::RedirectList& redirects,
+ base::Time visit_time) {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ NOTIMPLEMENTED();
+}
+
+void TypedURLSyncBridge::OnURLsModified(
+ history::HistoryBackend* history_backend,
+ const history::URLRows& changed_urls) {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ NOTIMPLEMENTED();
+}
+
+void TypedURLSyncBridge::OnURLsDeleted(history::HistoryBackend* history_backend,
+ bool all_history,
+ bool expired,
+ const history::URLRows& deleted_rows,
+ const std::set<GURL>& favicon_urls) {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ NOTIMPLEMENTED();
+}
+
+} // namespace history
diff --git a/chromium/components/history/core/browser/typed_url_sync_bridge.h b/chromium/components/history/core/browser/typed_url_sync_bridge.h
new file mode 100644
index 00000000000..9dd05415a35
--- /dev/null
+++ b/chromium/components/history/core/browser/typed_url_sync_bridge.h
@@ -0,0 +1,63 @@
+// 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_HISTORY_CORE_BROWSER_TYPED_URL_SYNC_BRIDGE_H_
+#define COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_SYNC_BRIDGE_H_
+
+#include "components/history/core/browser/history_backend_observer.h"
+#include "components/sync/model/metadata_change_list.h"
+#include "components/sync/model/model_type_sync_bridge.h"
+#include "components/sync/model/sync_error.h"
+
+namespace history {
+
+class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
+ public history::HistoryBackendObserver {
+ public:
+ TypedURLSyncBridge(HistoryBackend* history_backend,
+ const ChangeProcessorFactory& change_processor_factory);
+ ~TypedURLSyncBridge() override;
+
+ // syncer::ModelTypeService implementation.
+ std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList()
+ override;
+ base::Optional<syncer::ModelError> MergeSyncData(
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+ syncer::EntityDataMap entity_data_map) override;
+ base::Optional<syncer::ModelError> ApplySyncChanges(
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+ syncer::EntityChangeList entity_changes) override;
+ void GetData(StorageKeyList storage_keys, DataCallback callback) override;
+ void GetAllData(DataCallback callback) override;
+ std::string GetClientTag(const syncer::EntityData& entity_data) override;
+ std::string GetStorageKey(const syncer::EntityData& entity_data) override;
+
+ // history::HistoryBackendObserver:
+ void OnURLVisited(history::HistoryBackend* history_backend,
+ ui::PageTransition transition,
+ const history::URLRow& row,
+ const history::RedirectList& redirects,
+ base::Time visit_time) override;
+ void OnURLsModified(history::HistoryBackend* history_backend,
+ const history::URLRows& changed_urls) override;
+ void OnURLsDeleted(history::HistoryBackend* history_backend,
+ bool all_history,
+ bool expired,
+ const history::URLRows& deleted_rows,
+ const std::set<GURL>& favicon_urls) override;
+
+ private:
+ // The backend we're syncing local changes from and sync changes to.
+ HistoryBackend* const history_backend_;
+
+ // Since HistoryBackend use SequencedTaskRunner, so should use SequenceChecker
+ // here.
+ base::SequenceChecker sequence_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(TypedURLSyncBridge);
+};
+
+} // namespace history
+
+#endif // COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_SYNC_BRIDGE_H_
diff --git a/chromium/components/history/core/browser/typed_url_sync_metadata_database.cc b/chromium/components/history/core/browser/typed_url_sync_metadata_database.cc
new file mode 100644
index 00000000000..6cc6d157746
--- /dev/null
+++ b/chromium/components/history/core/browser/typed_url_sync_metadata_database.cc
@@ -0,0 +1,136 @@
+// 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/history/core/browser/typed_url_sync_metadata_database.h"
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "sql/statement.h"
+
+namespace history {
+
+namespace {
+
+// Key in sql::MetaTable, the value will be Serialization of sync
+// ModelTypeState, which is for tracking sync state of typed url datatype.
+const char kTypedURLModelTypeStateKey[] = "typed_url_model_type_state";
+
+} // namespace
+
+// Description of database table:
+//
+// typed_url_sync_metadata
+// storage_key the rowid of an entry in urls table, used by service to
+// look up native data with sync metadata records.
+// value Serialize sync EntityMetadata, which is for tracking sync
+// state of each typed url.
+
+TypedURLSyncMetadataDatabase::TypedURLSyncMetadataDatabase() {}
+
+TypedURLSyncMetadataDatabase::~TypedURLSyncMetadataDatabase() {}
+
+bool TypedURLSyncMetadataDatabase::GetAllSyncMetadata(
+ syncer::MetadataBatch* metadata_batch) {
+ DCHECK(metadata_batch);
+ if (!GetAllSyncEntityMetadata(metadata_batch)) {
+ return false;
+ }
+
+ sync_pb::ModelTypeState model_type_state;
+ if (GetModelTypeState(&model_type_state)) {
+ metadata_batch->SetModelTypeState(model_type_state);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool TypedURLSyncMetadataDatabase::UpdateSyncMetadata(
+ const std::string& storage_key,
+ const sync_pb::EntityMetadata& metadata) {
+ int64_t storage_key_int = 0;
+ if (!base::StringToInt64(storage_key, &storage_key_int)) {
+ return false;
+ }
+ sql::Statement s(GetDB().GetUniqueStatement(
+ "INSERT OR REPLACE INTO typed_url_sync_metadata "
+ "(storage_key, value) VALUES(?, ?)"));
+ s.BindInt64(0, storage_key_int);
+ s.BindString(1, metadata.SerializeAsString());
+
+ return s.Run();
+}
+
+bool TypedURLSyncMetadataDatabase::ClearSyncMetadata(
+ const std::string& storage_key) {
+ int64_t storage_key_int = 0;
+ if (!base::StringToInt64(storage_key, &storage_key_int)) {
+ return false;
+ }
+ sql::Statement s(GetDB().GetUniqueStatement(
+ "DELETE FROM typed_url_sync_metadata WHERE storage_key=?"));
+ s.BindInt64(0, storage_key_int);
+
+ return s.Run();
+}
+
+bool TypedURLSyncMetadataDatabase::UpdateModelTypeState(
+ const sync_pb::ModelTypeState& model_type_state) {
+ DCHECK_GT(GetMetaTable().GetVersionNumber(), 0);
+
+ std::string serialized_state = model_type_state.SerializeAsString();
+ return GetMetaTable().SetValue(kTypedURLModelTypeStateKey, serialized_state);
+}
+
+bool TypedURLSyncMetadataDatabase::ClearModelTypeState() {
+ DCHECK_GT(GetMetaTable().GetVersionNumber(), 0);
+ return GetMetaTable().DeleteKey(kTypedURLModelTypeStateKey);
+}
+
+bool TypedURLSyncMetadataDatabase::InitSyncTable() {
+ if (!GetDB().DoesTableExist("typed_url_sync_metadata")) {
+ if (!GetDB().Execute("CREATE TABLE typed_url_sync_metadata ("
+ "storage_key INTEGER PRIMARY KEY NOT NULL,"
+ "value BLOB)")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool TypedURLSyncMetadataDatabase::GetAllSyncEntityMetadata(
+ syncer::MetadataBatch* metadata_batch) {
+ DCHECK(metadata_batch);
+ sql::Statement s(GetDB().GetUniqueStatement(
+ "SELECT storage_key, value FROM typed_url_sync_metadata"));
+
+ while (s.Step()) {
+ std::string storage_key = base::Int64ToString(s.ColumnInt64(0));
+ std::string serialized_metadata = s.ColumnString(1);
+ sync_pb::EntityMetadata entity_metadata;
+ if (entity_metadata.ParseFromString(serialized_metadata)) {
+ metadata_batch->AddMetadata(storage_key, entity_metadata);
+ } else {
+ DLOG(WARNING) << "Failed to deserialize TYPED_URLS model type "
+ "sync_pb::EntityMetadata.";
+ return false;
+ }
+ }
+ return true;
+}
+
+bool TypedURLSyncMetadataDatabase::GetModelTypeState(
+ sync_pb::ModelTypeState* state) {
+ DCHECK_GT(GetMetaTable().GetVersionNumber(), 0);
+ std::string serialized_state;
+ if (!GetMetaTable().GetValue(kTypedURLModelTypeStateKey, &serialized_state)) {
+ return true;
+ }
+
+ return state->ParseFromString(serialized_state);
+}
+
+} // namespace history
diff --git a/chromium/components/history/core/browser/typed_url_sync_metadata_database.h b/chromium/components/history/core/browser/typed_url_sync_metadata_database.h
new file mode 100644
index 00000000000..0b687539c28
--- /dev/null
+++ b/chromium/components/history/core/browser/typed_url_sync_metadata_database.h
@@ -0,0 +1,74 @@
+// 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_HISTORY_CORE_BROWSER_TYPED_URL_SYNC_METADATA_DATABASE_H_
+#define COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_SYNC_METADATA_DATABASE_H_
+
+#include "base/macros.h"
+#include "components/sync/base/model_type.h"
+#include "components/sync/model/metadata_batch.h"
+#include "sql/meta_table.h"
+
+namespace sql {
+class Connection;
+}
+
+namespace history {
+
+// A sync metadata database needs to maintain two tables: entity metadata table
+// and datatype state table. Entity metadata table contains metadata(sync
+// states) for each url. Datatype state table contains the state of typed url
+// datatype.
+class TypedURLSyncMetadataDatabase {
+ public:
+ // Must call InitVisitTable() before using to make sure the database is
+ // initialized.
+ TypedURLSyncMetadataDatabase();
+ virtual ~TypedURLSyncMetadataDatabase();
+
+ // Read all the stored metadata for typed URL and fill |metadata_batch|
+ // with it.
+ bool GetAllSyncMetadata(syncer::MetadataBatch* metadata_batch);
+
+ // Update the metadata row for typed URL, keyed by |storage_key|, to
+ // contain the contents of |metadata|.
+ bool UpdateSyncMetadata(const std::string& storage_key,
+ const sync_pb::EntityMetadata& metadata);
+
+ // Remove the metadata row of typed URL keyed by |storage_key|.
+ bool ClearSyncMetadata(const std::string& storage_key);
+
+ // Update the stored sync state for the typed URL.
+ bool UpdateModelTypeState(const sync_pb::ModelTypeState& model_type_state);
+
+ // Clear the stored sync state for typed URL.
+ bool ClearModelTypeState();
+
+ protected:
+ // Returns the database for the functions in this interface.
+ virtual sql::Connection& GetDB() = 0;
+
+ // Returns MetaTable, so this sync can store ModelTypeState in MetaTable.
+ // Check if GetMetaTable().GetVersionNumber() is greater than 0 to make sure
+ // MetaTable is initialed.
+ virtual sql::MetaTable& GetMetaTable() = 0;
+
+ // Called by the derived classes on initialization to make sure the tables
+ // and indices are properly set up. Must be called before anything else.
+ bool InitSyncTable();
+
+ private:
+ // Read all sync_pb::EntityMetadata for typed URL and fill
+ // |metadata_records| with it.
+ bool GetAllSyncEntityMetadata(syncer::MetadataBatch* metadata_batch);
+
+ // Read sync_pb::ModelTypeState for typed URL and fill |state| with it.
+ bool GetModelTypeState(sync_pb::ModelTypeState* state);
+
+ DISALLOW_COPY_AND_ASSIGN(TypedURLSyncMetadataDatabase);
+};
+
+} // namespace history
+
+#endif // COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_SYNC_METADATA_DATABASE_H_
diff --git a/chromium/components/history/core/browser/typed_url_sync_metadata_database_unittest.cc b/chromium/components/history/core/browser/typed_url_sync_metadata_database_unittest.cc
new file mode 100644
index 00000000000..31810c615ea
--- /dev/null
+++ b/chromium/components/history/core/browser/typed_url_sync_metadata_database_unittest.cc
@@ -0,0 +1,143 @@
+// 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/history/core/browser/typed_url_sync_metadata_database.h"
+
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "components/sync/protocol/model_type_state.pb.h"
+#include "sql/statement.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using sync_pb::EntityMetadata;
+using sync_pb::ModelTypeState;
+using syncer::EntityMetadataMap;
+using syncer::MetadataBatch;
+
+namespace history {
+
+class TypedURLSyncMetadataDatabaseTest : public testing::Test,
+ public TypedURLSyncMetadataDatabase {
+ public:
+ TypedURLSyncMetadataDatabaseTest() {}
+ ~TypedURLSyncMetadataDatabaseTest() override {}
+
+ protected:
+ sql::Connection& GetDB() override { return db_; }
+
+ void SetUp() override {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ base::FilePath db_file =
+ temp_dir_.GetPath().AppendASCII("TypedURLSyncMetadataDatabaseTest.db");
+
+ EXPECT_TRUE(db_.Open(db_file));
+
+ // Initialize the tables for this test.
+ InitSyncTable();
+
+ GetMetaTable().Init(&db_, 1, 1);
+ }
+ void TearDown() override { db_.Close(); }
+
+ sql::MetaTable& GetMetaTable() override { return meta_table_; }
+
+ base::ScopedTempDir temp_dir_;
+ sql::Connection db_;
+ sql::MetaTable meta_table_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TypedURLSyncMetadataDatabaseTest);
+};
+
+TEST_F(TypedURLSyncMetadataDatabaseTest, TypedURLNoMetadata) {
+ MetadataBatch metadata_batch;
+ EXPECT_TRUE(GetAllSyncMetadata(&metadata_batch));
+ EXPECT_EQ(0u, metadata_batch.TakeAllMetadata().size());
+ EXPECT_EQ(ModelTypeState().SerializeAsString(),
+ metadata_batch.GetModelTypeState().SerializeAsString());
+}
+
+TEST_F(TypedURLSyncMetadataDatabaseTest, TypedURLGetAllSyncMetadata) {
+ EntityMetadata metadata;
+ std::string storage_key = "1";
+ std::string storage_key2 = "2";
+ metadata.set_sequence_number(1);
+
+ EXPECT_TRUE(UpdateSyncMetadata(storage_key, metadata));
+
+ ModelTypeState model_type_state;
+ model_type_state.set_initial_sync_done(true);
+
+ EXPECT_TRUE(UpdateModelTypeState(model_type_state));
+
+ metadata.set_sequence_number(2);
+ EXPECT_TRUE(UpdateSyncMetadata(storage_key2, metadata));
+
+ MetadataBatch metadata_batch;
+ EXPECT_TRUE(GetAllSyncMetadata(&metadata_batch));
+
+ EXPECT_TRUE(metadata_batch.GetModelTypeState().initial_sync_done());
+
+ EntityMetadataMap metadata_records = metadata_batch.TakeAllMetadata();
+
+ EXPECT_EQ(metadata_records.size(), 2u);
+ EXPECT_EQ(metadata_records[storage_key].sequence_number(), 1);
+ EXPECT_EQ(metadata_records[storage_key2].sequence_number(), 2);
+
+ // Now check that a model type state update replaces the old value
+ model_type_state.set_initial_sync_done(false);
+ EXPECT_TRUE(UpdateModelTypeState(model_type_state));
+
+ EXPECT_TRUE(GetAllSyncMetadata(&metadata_batch));
+ EXPECT_FALSE(metadata_batch.GetModelTypeState().initial_sync_done());
+}
+
+TEST_F(TypedURLSyncMetadataDatabaseTest, TypedURLWriteThenDeleteSyncMetadata) {
+ EntityMetadata metadata;
+ MetadataBatch metadata_batch;
+ std::string storage_key = "1";
+ ModelTypeState model_type_state;
+
+ model_type_state.set_initial_sync_done(true);
+
+ metadata.set_client_tag_hash("client_hash");
+
+ // Write the data into the store.
+ EXPECT_TRUE(UpdateSyncMetadata(storage_key, metadata));
+ EXPECT_TRUE(UpdateModelTypeState(model_type_state));
+ // Delete the data we just wrote.
+ EXPECT_TRUE(ClearSyncMetadata(storage_key));
+ // It shouldn't be there any more.
+ EXPECT_TRUE(GetAllSyncMetadata(&metadata_batch));
+
+ EntityMetadataMap metadata_records = metadata_batch.TakeAllMetadata();
+ EXPECT_EQ(metadata_records.size(), 0u);
+
+ // Now delete the model type state.
+ EXPECT_TRUE(ClearModelTypeState());
+ EXPECT_TRUE(GetAllSyncMetadata(&metadata_batch));
+ EXPECT_EQ(ModelTypeState().SerializeAsString(),
+ metadata_batch.GetModelTypeState().SerializeAsString());
+}
+
+TEST_F(TypedURLSyncMetadataDatabaseTest, TypedURLCorruptSyncMetadata) {
+ MetadataBatch metadata_batch;
+ sql::Statement s(GetDB().GetUniqueStatement(
+ "INSERT OR REPLACE INTO typed_url_sync_metadata "
+ "(storage_key, value) VALUES(?, ?)"));
+ s.BindInt64(0, 1);
+ s.BindString(1, "unparseable");
+ EXPECT_TRUE(s.Run());
+
+ EXPECT_FALSE(GetAllSyncMetadata(&metadata_batch));
+}
+
+TEST_F(TypedURLSyncMetadataDatabaseTest, TypedURLCorruptModelTypeState) {
+ MetadataBatch metadata_batch;
+ GetMetaTable().SetValue("typed_url_model_type_state", "unparseable");
+
+ EXPECT_FALSE(GetAllSyncMetadata(&metadata_batch));
+}
+
+} // namespace history
diff --git a/chromium/components/history/core/browser/typed_url_syncable_service.cc b/chromium/components/history/core/browser/typed_url_syncable_service.cc
index deaf6b27d76..3f357843574 100644
--- a/chromium/components/history/core/browser/typed_url_syncable_service.cc
+++ b/chromium/components/history/core/browser/typed_url_syncable_service.cc
@@ -187,9 +187,6 @@ syncer::SyncMergeResult TypedUrlSyncableService::MergeDataAndStartSyncing(
std::string tag = i->first.spec();
AddTypedUrlToChangeList(i->second.first, i->second.second,
visit_vectors[i->first], tag, &new_changes);
-
- // Add url to cache of sync state, if not already cached
- synced_typed_urls_.insert(i->first);
}
// Send history changes to the sync server
@@ -429,10 +426,6 @@ void TypedUrlSyncableService::CreateOrUpdateUrl(
// Add a new entry to |loaded_data|, and set the iterator to it.
history::VisitVector untyped_visits;
if (!FixupURLAndGetVisits(&untyped_url, &untyped_visits)) {
- // Couldn't load the visits for this URL due to some kind of DB error.
- // Don't bother writing this URL to the history DB (if we ignore the
- // error and continue, we might end up duplicating existing visits).
- DLOG(ERROR) << "Could not load visits for url: " << untyped_url.url();
return;
}
(*visit_vectors)[untyped_url.url()] = untyped_visits;
@@ -807,18 +800,9 @@ bool TypedUrlSyncableService::CreateOrUpdateSyncNode(
// Get the visits for this node.
VisitVector visit_vector;
if (!FixupURLAndGetVisits(&url, &visit_vector)) {
- DLOG(ERROR) << "Could not load visits for url: " << url.url();
return false;
}
- if (std::find_if(visit_vector.begin(), visit_vector.end(),
- [](const history::VisitRow& visit) {
- return ui::PageTransitionCoreTypeIs(
- visit.transition, ui::PAGE_TRANSITION_TYPED);
- }) == visit_vector.end())
- // This URL has no TYPED visits, don't sync it
- return false;
-
DCHECK(!visit_vector.empty());
std::string title = url.url().spec();
@@ -829,9 +813,6 @@ bool TypedUrlSyncableService::CreateOrUpdateSyncNode(
? syncer::SyncChange::ACTION_UPDATE
: syncer::SyncChange::ACTION_ADD;
- // Ensure cache of server state is up to date.
- synced_typed_urls_.insert(url.url());
-
AddTypedUrlToChangeList(change_type, url, visit_vector, title, changes);
return true;
@@ -850,7 +831,13 @@ void TypedUrlSyncableService::AddTypedUrlToChangeList(
if (change_type == syncer::SyncChange::ACTION_DELETE) {
typed_url->set_url(tag);
} else {
- WriteToTypedUrlSpecifics(row, visits, typed_url);
+ if (!WriteToTypedUrlSpecifics(row, visits, typed_url)) {
+ // Cannot write to specifics, ex. no TYPED visits.
+ return;
+ }
+
+ // Ensure cache of server state is up to date.
+ synced_typed_urls_.insert(row.url());
}
change_list->push_back(syncer::SyncChange(
@@ -858,7 +845,7 @@ void TypedUrlSyncableService::AddTypedUrlToChangeList(
syncer::SyncData::CreateLocalData(tag, title, entity_specifics)));
}
-void TypedUrlSyncableService::WriteToTypedUrlSpecifics(
+bool TypedUrlSyncableService::WriteToTypedUrlSpecifics(
const URLRow& url,
const VisitVector& visits,
sync_pb::TypedUrlSpecifics* typed_url) {
@@ -876,6 +863,15 @@ void TypedUrlSyncableService::WriteToTypedUrlSpecifics(
bool only_typed = false;
int skip_count = 0;
+ if (std::find_if(visits.begin(), visits.end(),
+ [](const history::VisitRow& visit) {
+ return ui::PageTransitionCoreTypeIs(
+ visit.transition, ui::PAGE_TRANSITION_TYPED);
+ }) == visits.end()) {
+ // This URL has no TYPED visits, don't sync it
+ return false;
+ }
+
if (visits.size() > static_cast<size_t>(kMaxTypedUrlVisits)) {
int typed_count = 0;
int total = 0;
@@ -893,6 +889,7 @@ void TypedUrlSyncableService::WriteToTypedUrlSpecifics(
++typed_count;
}
}
+
// We should have at least one typed visit. This can sometimes happen if
// the history DB has an inaccurate count for some reason (there's been
// bugs in the history code in the past which has left users in the wild
@@ -935,18 +932,11 @@ void TypedUrlSyncableService::WriteToTypedUrlSpecifics(
}
DCHECK_EQ(skip_count, 0);
- if (typed_url->visits_size() == 0) {
- // If we get here, it's because we don't actually have any TYPED visits
- // even though the visit's typed_count > 0 (corrupted typed_count). So
- // let's go ahead and add a RELOAD visit at the most recent visit since
- // it's not legal to have an empty visit array (yet another workaround
- // for http://crbug.com/84258).
- typed_url->add_visits(url.last_visit().ToInternalValue());
- typed_url->add_visit_transitions(ui::PAGE_TRANSITION_RELOAD);
- }
CHECK_GT(typed_url->visits_size(), 0);
CHECK_LE(typed_url->visits_size(), kMaxTypedUrlVisits);
CHECK_EQ(typed_url->visits_size(), typed_url->visit_transitions_size());
+
+ return true;
}
// static
@@ -972,6 +962,10 @@ bool TypedUrlSyncableService::FixupURLAndGetVisits(URLRow* url,
if (!history_backend_->GetMostRecentVisitsForURL(url->id(), kMaxVisitsToFetch,
visits)) {
++num_db_errors_;
+ // Couldn't load the visits for this URL due to some kind of DB error.
+ // Don't bother writing this URL to the history DB (if we ignore the
+ // error and continue, we might end up duplicating existing visits).
+ DLOG(ERROR) << "Could not load visits for url: " << url->url();
return false;
}
@@ -1003,6 +997,29 @@ bool TypedUrlSyncableService::FixupURLAndGetVisits(URLRow* url,
// crashes/bugs can cause them to mismatch), so just set it here.
url->set_last_visit(visits->back().visit_time);
DCHECK(CheckVisitOrdering(*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) {
+ base::Time time = visit.visit_time;
+ if (history_backend_->IsExpiredVisitTime(time)) {
+ ++num_expired_visits;
+ } else {
+ break;
+ }
+ }
+ if (num_expired_visits != 0) {
+ if (num_expired_visits == visits->size()) {
+ DVLOG(1) << "All visits are expired for url: " << url->url();
+ visits->clear();
+ return false;
+ }
+ visits->erase(visits->begin(), visits->begin() + num_expired_visits);
+ }
+ DCHECK(CheckVisitOrdering(*visits));
+
return true;
}
@@ -1019,10 +1036,6 @@ void TypedUrlSyncableService::UpdateFromSyncDB(
// This URL already exists locally - fetch the visits so we can
// merge them below.
if (!FixupURLAndGetVisits(&new_url, &existing_visits)) {
- // Couldn't load the visits for this URL due to some kind of DB error.
- // Don't bother writing this URL to the history DB (if we ignore the
- // error and continue, we might end up duplicating existing visits).
- DLOG(ERROR) << "Could not load visits for url: " << new_url.url();
return;
}
}
diff --git a/chromium/components/history/core/browser/typed_url_syncable_service.h b/chromium/components/history/core/browser/typed_url_syncable_service.h
index 838e83efc6d..39f2fd53da9 100644
--- a/chromium/components/history/core/browser/typed_url_syncable_service.h
+++ b/chromium/components/history/core/browser/typed_url_syncable_service.h
@@ -71,11 +71,12 @@ class TypedUrlSyncableService : public syncer::SyncableService,
// Returns the percentage of DB accesses that have resulted in an error.
int GetErrorPercentage() const;
- // Converts the passed URL information to a TypedUrlSpecifics structure for
- // writing to the sync DB.
- static void WriteToTypedUrlSpecifics(const URLRow& url,
+ // 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);
+ sync_pb::TypedUrlSpecifics* specifics)
+ WARN_UNUSED_RESULT;
private:
friend class TypedUrlSyncableServiceTest;
@@ -183,9 +184,12 @@ class TypedUrlSyncableService : public syncer::SyncableService,
// function compensates for the fact that the history DB has rather poor data
// integrity (duplicate visits, visit timestamps that don't match the
// last_visit timestamp, huge data sets that exhaust memory when fetched,
- // etc) by modifying the passed |url| object and |visits| vector.
- // Returns false if we could not fetch the visits for the passed URL, and
- // tracks DB error statistics internally for reporting via UMA.
+ // expired visits that are not deleted by |ExpireHistoryBackend|, etc) by
+ // modifying the passed |url| object and |visits| vector.
+ // Returns false in two cases.
+ // 1. we could not fetch the visits for the passed URL, and tracks DB error
+ // statistics internally for reporting via UMA.
+ // 2. All the visits are expired.
virtual bool FixupURLAndGetVisits(URLRow* url, VisitVector* visits);
// Given a typed URL in the sync DB, looks for an existing entry in the
diff --git a/chromium/components/history/core/browser/typed_url_syncable_service_unittest.cc b/chromium/components/history/core/browser/typed_url_syncable_service_unittest.cc
index 749938ca5a7..936739677d4 100644
--- a/chromium/components/history/core/browser/typed_url_syncable_service_unittest.cc
+++ b/chromium/components/history/core/browser/typed_url_syncable_service_unittest.cc
@@ -262,7 +262,7 @@ class TypedUrlSyncableServiceTest : public testing::Test {
void AddObserver();
// Fills |specifics| with the sync data for |url| and |visits|.
- static void WriteToTypedUrlSpecifics(const URLRow& url,
+ static bool WriteToTypedUrlSpecifics(const URLRow& url,
const VisitVector& visits,
sync_pb::TypedUrlSpecifics* specifics);
@@ -389,11 +389,12 @@ void TypedUrlSyncableServiceTest::AddObserver() {
}
// Static.
-void TypedUrlSyncableServiceTest::WriteToTypedUrlSpecifics(
+bool TypedUrlSyncableServiceTest::WriteToTypedUrlSpecifics(
const URLRow& url,
const VisitVector& visits,
sync_pb::TypedUrlSpecifics* specifics) {
- TypedUrlSyncableService::WriteToTypedUrlSpecifics(url, visits, specifics);
+ return TypedUrlSyncableService::WriteToTypedUrlSpecifics(url, visits,
+ specifics);
}
// Static.
@@ -900,6 +901,28 @@ TEST_F(TypedUrlSyncableServiceTest, MergeUrlNoChange) {
EXPECT_EQ(sync_state.count(row.url()), 1U);
}
+// Add a corupted typed url locally, has typed url count 1, but no real typed
+// url visit. Starting sync should not pick up this url.
+TEST_F(TypedUrlSyncableServiceTest, MergeUrlNoTypedUrl) {
+ // Add a url to backend.
+ VisitVector visits;
+ URLRow row = MakeTypedUrlRow(kURL, kTitle, 0, 3, false, &visits);
+
+ // Mark typed_count to 1 even when there is no typed url visit.
+ row.set_typed_count(1);
+ fake_history_backend_->SetVisitsForUrl(row, visits);
+
+ StartSyncing(syncer::SyncDataList());
+ syncer::SyncChangeList& changes = fake_change_processor_->changes();
+ EXPECT_TRUE(changes.empty());
+
+ // Check that the local cache was is still correct.
+ std::set<GURL> sync_state;
+ GetSyncedUrls(&sync_state);
+ EXPECT_TRUE(sync_state.empty());
+ EXPECT_EQ(sync_state.count(row.url()), 0U);
+}
+
// Starting sync with no sync data should just push the local url to sync.
TEST_F(TypedUrlSyncableServiceTest, MergeUrlEmptySync) {
// Add a url to backend.
@@ -1414,21 +1437,15 @@ TEST_F(TypedUrlSyncableServiceTest, TooManyTypedVisits) {
}
}
-// Create a typed url without visit, check WriteToTypedUrlSpecifics will create
-// a RELOAD visit for it.
+// Create a typed url without visit, check WriteToTypedUrlSpecifics will return
+// false for it.
TEST_F(TypedUrlSyncableServiceTest, NoTypedVisits) {
history::VisitVector visits;
history::URLRow url(MakeTypedUrlRow(kURL, kTitle, 0, 1000, false, &visits));
sync_pb::TypedUrlSpecifics typed_url;
- WriteToTypedUrlSpecifics(url, visits, &typed_url);
- // URLs with no typed URL visits should be translated to a URL with one
- // reload visit.
- EXPECT_EQ(1, typed_url.visits_size());
- EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
-
- EXPECT_EQ(1000, typed_url.visits(0));
- EXPECT_EQ(static_cast<int32_t>(ui::PAGE_TRANSITION_RELOAD),
- typed_url.visit_transitions(0));
+ EXPECT_FALSE(WriteToTypedUrlSpecifics(url, visits, &typed_url));
+ // URLs with no typed URL visits should not been written to specifics.
+ EXPECT_EQ(0, typed_url.visits_size());
}
TEST_F(TypedUrlSyncableServiceTest, MergeUrls) {
@@ -1550,4 +1567,50 @@ TEST_F(TypedUrlSyncableServiceTest, MergeUrlsAfterExpiration) {
EXPECT_EQ(4U, history_visits[2].visit_time.ToInternalValue());
}
+// Create a local typed URL with one expired TYPED visit,
+// MergeDataAndStartSyncing should not pass it to sync. And then add a non
+// expired visit, OnURLsModified should only send the non expired visit to sync.
+TEST_F(TypedUrlSyncableServiceTest, LocalExpiredTypedUrlDoNotSync) {
+ URLRow row;
+ URLRows changed_urls;
+ VisitVector visits;
+
+ // Add an expired typed URL to local.
+ row = MakeTypedUrlRow(kURL, kTitle, 1, kExpiredVisit, false, &visits);
+ fake_history_backend_->SetVisitsForUrl(row, visits);
+
+ StartSyncing(syncer::SyncDataList());
+
+ // Check change processor did not receive expired typed URL.
+ syncer::SyncChangeList& changes = fake_change_processor_->changes();
+ ASSERT_EQ(0U, changes.size());
+
+ // Add a non expired typed URL to local.
+ row = MakeTypedUrlRow(kURL, kTitle, 2, 1, false, &visits);
+ fake_history_backend_->SetVisitsForUrl(row, visits);
+
+ changed_urls.push_back(row);
+ // Notify typed url sync service of the update.
+ typed_url_sync_service_->OnURLsModified(fake_history_backend_.get(),
+ changed_urls);
+
+ // Check change processor did not receive expired typed URL.
+ ASSERT_EQ(1U, changes.size());
+ ASSERT_TRUE(changes[0].IsValid());
+ EXPECT_EQ(syncer::TYPED_URLS, changes[0].sync_data().GetDataType());
+ EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[0].change_type());
+
+ // Get typed url specifics. Verify only a non-expired visit received.
+ sync_pb::TypedUrlSpecifics url_specifics =
+ changes[0].sync_data().GetSpecifics().typed_url();
+
+ EXPECT_TRUE(URLsEqual(row, url_specifics));
+ ASSERT_EQ(1, url_specifics.visits_size());
+ ASSERT_EQ(static_cast<const int>(visits.size() - 1),
+ url_specifics.visits_size());
+ EXPECT_EQ(visits[1].visit_time.ToInternalValue(), url_specifics.visits(0));
+ EXPECT_EQ(static_cast<const int>(visits[1].transition),
+ url_specifics.visit_transitions(0));
+}
+
} // namespace history
diff --git a/chromium/components/history/core/browser/url_database.cc b/chromium/components/history/core/browser/url_database.cc
index 37d2830b4a9..4a976a94aa3 100644
--- a/chromium/components/history/core/browser/url_database.cc
+++ b/chromium/components/history/core/browser/url_database.cc
@@ -62,13 +62,13 @@ std::string URLDatabase::GURLToDatabaseURL(const GURL& gurl) {
// kURLRowFields.
void URLDatabase::FillURLRow(sql::Statement& s, URLRow* i) {
DCHECK(i);
- i->id_ = s.ColumnInt64(0);
- i->url_ = GURL(s.ColumnString(1));
- i->title_ = s.ColumnString16(2);
- i->visit_count_ = s.ColumnInt(3);
- i->typed_count_ = s.ColumnInt(4);
- i->last_visit_ = base::Time::FromInternalValue(s.ColumnInt64(5));
- i->hidden_ = s.ColumnInt(6) != 0;
+ i->set_id(s.ColumnInt64(0));
+ i->set_url(GURL(s.ColumnString(1)));
+ i->set_title(s.ColumnString16(2));
+ i->set_visit_count(s.ColumnInt(3));
+ i->set_typed_count(s.ColumnInt(4));
+ i->set_last_visit(base::Time::FromInternalValue(s.ColumnInt64(5)));
+ i->set_hidden(s.ColumnInt(6) != 0);
}
bool URLDatabase::GetURLRow(URLID url_id, URLRow* info) {
@@ -568,26 +568,7 @@ bool URLDatabase::DropStarredIDFromURLs() {
if (!GetDB().DoesColumnExist("urls", "starred_id"))
return true; // urls is already updated, no need to continue.
- // Create a temporary table to contain the new URLs table.
- if (!CreateTemporaryURLTable()) {
- NOTREACHED();
- return false;
- }
-
- // Copy the contents.
- if (!GetDB().Execute(
- "INSERT INTO temp_urls (id, url, title, visit_count, typed_count, "
- "last_visit_time, hidden, favicon_id) "
- "SELECT id, url, title, visit_count, typed_count, last_visit_time, "
- "hidden, favicon_id FROM urls")) {
- NOTREACHED() << GetDB().GetErrorMessage();
- return false;
- }
-
- // Rename/commit the tmp table.
- CommitTemporaryURLTable();
-
- return true;
+ return RecreateURLTableWithAllContents();
}
bool URLDatabase::CreateURLTable(bool is_temporary) {
@@ -600,15 +581,34 @@ bool URLDatabase::CreateURLTable(bool is_temporary) {
std::string sql;
sql.append("CREATE TABLE ");
sql.append(name);
- sql.append("("
- "id INTEGER PRIMARY KEY,"
+ sql.append(
+ "("
+ // The id uses AUTOINCREMENT is for sync propose. Sync uses this |id| as
+ // an unique key to identify the URLs. If here did not use AUTOINCREMENT,
+ // and Sync was not working somehow, a ROWID could be deleted and re-used
+ // 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,"
"visit_count INTEGER DEFAULT 0 NOT NULL,"
"typed_count INTEGER DEFAULT 0 NOT NULL,"
"last_visit_time INTEGER NOT NULL,"
- "hidden INTEGER DEFAULT 0 NOT NULL,"
- "favicon_id INTEGER DEFAULT 0 NOT NULL)"); // favicon_id is not used now.
+ "hidden INTEGER DEFAULT 0 NOT NULL)");
+ // IMPORTANT: If you change the colums, also update in_memory_database.cc
+ // where the values are copied (InitFromDisk).
return GetDB().Execute(sql.c_str());
}
@@ -618,6 +618,29 @@ bool URLDatabase::CreateMainURLIndex() {
"CREATE INDEX IF NOT EXISTS urls_url_index ON urls (url)");
}
+bool URLDatabase::RecreateURLTableWithAllContents() {
+ // Create a temporary table to contain the new URLs table.
+ if (!CreateTemporaryURLTable()) {
+ NOTREACHED();
+ return false;
+ }
+
+ // Copy the contents.
+ if (!GetDB().Execute(
+ "INSERT INTO temp_urls (id, url, title, visit_count, typed_count, "
+ "last_visit_time, hidden) "
+ "SELECT id, url, title, visit_count, typed_count, last_visit_time, "
+ "hidden FROM urls")) {
+ NOTREACHED() << GetDB().GetErrorMessage();
+ return false;
+ }
+
+ // Rename/commit the tmp table.
+ CommitTemporaryURLTable();
+
+ return true;
+}
+
const int kLowQualityMatchTypedLimit = 1;
const int kLowQualityMatchVisitLimit = 4;
const int kLowQualityMatchAgeLimitInDays = 3;
diff --git a/chromium/components/history/core/browser/url_database.h b/chromium/components/history/core/browser/url_database.h
index 8e7acbb92cf..1b8a5d71ee6 100644
--- a/chromium/components/history/core/browser/url_database.h
+++ b/chromium/components/history/core/browser/url_database.h
@@ -266,6 +266,9 @@ class URLDatabase {
// Creates the index over URLs so we can quickly look up based on URL.
bool CreateMainURLIndex();
+ // Recreate URL table, and keep all existing contents.
+ bool RecreateURLTableWithAllContents();
+
// Ensures the keyword search terms table exists.
bool InitKeywordSearchTermsTable();
diff --git a/chromium/components/history/core/browser/url_database_unittest.cc b/chromium/components/history/core/browser/url_database_unittest.cc
index fe60fcc55c2..c9466aed55d 100644
--- a/chromium/components/history/core/browser/url_database_unittest.cc
+++ b/chromium/components/history/core/browser/url_database_unittest.cc
@@ -38,6 +38,25 @@ class URLDatabaseTest : public testing::Test,
URLDatabaseTest() {
}
+ void CreateVersion33URLTable() {
+ EXPECT_TRUE(GetDB().Execute("DROP TABLE urls"));
+
+ std::string sql;
+ // create a version 33 urls table
+ sql.append(
+ "CREATE TABLE urls ("
+ "id INTEGER PRIMARY KEY,"
+ "url LONGVARCHAR,"
+ "title LONGVARCHAR,"
+ "visit_count INTEGER DEFAULT 0 NOT NULL,"
+ "typed_count INTEGER DEFAULT 0 NOT NULL,"
+ "last_visit_time INTEGER NOT NULL,"
+ "hidden INTEGER DEFAULT 0 NOT NULL,"
+ "favicon_id INTEGER DEFAULT 0 NOT NULL)"); // favicon_id is not used
+ // now.
+ EXPECT_TRUE(GetDB().Execute(sql.c_str()));
+ }
+
protected:
// Provided for URL/VisitDatabase.
sql::Connection& GetDB() override { return db_; }
@@ -328,4 +347,98 @@ TEST_F(URLDatabaseTest, GetAndDeleteKeywordSearchTermByTerm) {
EXPECT_TRUE(rows.empty());
}
+// Test for migration of update URL table, verify AUTOINCREMENT is working
+// properly.
+TEST_F(URLDatabaseTest, MigrationURLTableForAddingAUTOINCREMENT) {
+ CreateVersion33URLTable();
+ // First, add two URLs.
+ const GURL url1("http://www.google.com/");
+ URLRow url_info1(url1);
+ url_info1.set_title(base::UTF8ToUTF16("Google"));
+ url_info1.set_visit_count(4);
+ url_info1.set_typed_count(2);
+ url_info1.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
+ url_info1.set_hidden(false);
+ URLID id1_initially = AddURL(url_info1);
+ EXPECT_TRUE(id1_initially);
+
+ const GURL url2("http://mail.google.com/");
+ URLRow url_info2(url2);
+ url_info2.set_title(base::UTF8ToUTF16("Google Mail"));
+ url_info2.set_visit_count(3);
+ url_info2.set_typed_count(0);
+ url_info2.set_last_visit(Time::Now() - TimeDelta::FromDays(2));
+ url_info2.set_hidden(true);
+ EXPECT_TRUE(AddURL(url_info2));
+
+ // Verify both are added.
+ URLRow info1;
+ EXPECT_TRUE(GetRowForURL(url1, &info1));
+ EXPECT_TRUE(IsURLRowEqual(url_info1, info1));
+ URLRow info2;
+ EXPECT_TRUE(GetRowForURL(url2, &info2));
+ EXPECT_TRUE(IsURLRowEqual(url_info2, info2));
+
+ // Delete second URL, and add a new URL, verify id got re-used.
+ EXPECT_TRUE(DeleteURLRow(info2.id()));
+
+ const GURL url3("http://maps.google.com/");
+ URLRow url_info3(url3);
+ url_info3.set_title(base::UTF8ToUTF16("Google Maps"));
+ url_info3.set_visit_count(7);
+ url_info3.set_typed_count(6);
+ url_info3.set_last_visit(Time::Now() - TimeDelta::FromDays(3));
+ url_info3.set_hidden(false);
+ EXPECT_TRUE(AddURL(url_info3));
+
+ URLRow info3;
+ EXPECT_TRUE(GetRowForURL(url3, &info3));
+ EXPECT_TRUE(IsURLRowEqual(url_info3, info3));
+ // Verify the id re-used.
+ EXPECT_EQ(info2.id(), info3.id());
+
+ // Upgrade urls table.
+ RecreateURLTableWithAllContents();
+
+ // Verify all data keeped.
+ EXPECT_TRUE(GetRowForURL(url1, &info1));
+ EXPECT_TRUE(IsURLRowEqual(url_info1, info1));
+ EXPECT_FALSE(GetRowForURL(url2, &info2));
+ EXPECT_TRUE(GetRowForURL(url3, &info3));
+ EXPECT_TRUE(IsURLRowEqual(url_info3, info3));
+
+ // Add a new URL
+ const GURL url4("http://plus.google.com/");
+ URLRow url_info4(url4);
+ url_info4.set_title(base::UTF8ToUTF16("Google Plus"));
+ url_info4.set_visit_count(4);
+ url_info4.set_typed_count(3);
+ url_info4.set_last_visit(Time::Now() - TimeDelta::FromDays(4));
+ url_info4.set_hidden(false);
+ EXPECT_TRUE(AddURL(url_info4));
+
+ // Verify The URL are added.
+ URLRow info4;
+ EXPECT_TRUE(GetRowForURL(url4, &info4));
+ EXPECT_TRUE(IsURLRowEqual(url_info4, info4));
+
+ // Delete the newest URL, and add a new URL, verify id is not re-used.
+ EXPECT_TRUE(DeleteURLRow(info4.id()));
+
+ const GURL url5("http://docs.google.com/");
+ URLRow url_info5(url5);
+ url_info5.set_title(base::UTF8ToUTF16("Google Docs"));
+ url_info5.set_visit_count(9);
+ url_info5.set_typed_count(2);
+ url_info5.set_last_visit(Time::Now() - TimeDelta::FromDays(5));
+ url_info5.set_hidden(false);
+ EXPECT_TRUE(AddURL(url_info5));
+
+ URLRow info5;
+ EXPECT_TRUE(GetRowForURL(url5, &info5));
+ EXPECT_TRUE(IsURLRowEqual(url_info5, info5));
+ // Verify the id is not re-used.
+ EXPECT_NE(info4.id(), info5.id());
+}
+
} // namespace history
diff --git a/chromium/components/history/core/browser/url_row.cc b/chromium/components/history/core/browser/url_row.cc
index 096672d5180..130442d6eeb 100644
--- a/chromium/components/history/core/browser/url_row.cc
+++ b/chromium/components/history/core/browser/url_row.cc
@@ -9,38 +9,30 @@
namespace history {
URLRow::URLRow() {
- Initialize();
}
URLRow::URLRow(const GURL& url) : url_(url) {
- // Initialize will not set the URL, so our initialization above will stay.
- Initialize();
}
-URLRow::URLRow(const GURL& url, URLID id) : url_(url) {
- // Initialize will not set the URL, so our initialization above will stay.
- Initialize();
- // Initialize will zero the id_, so set it here.
- id_ = id;
-}
+URLRow::URLRow(const GURL& url, URLID id) : id_(id), url_(url) {}
URLRow::URLRow(const URLRow& other) = default;
+// TODO(bug 706963) this should be implemented as "= default" when Android
+// toolchain is updated.
+URLRow::URLRow(URLRow&& other) noexcept
+ : id_(other.id_),
+ url_(std::move(other.url_)),
+ title_(std::move(other.title_)),
+ visit_count_(other.visit_count_),
+ typed_count_(other.typed_count_),
+ last_visit_(other.last_visit_),
+ hidden_(other.hidden_) {}
+
URLRow::~URLRow() {
}
-URLRow& URLRow::operator=(const URLRow& other) {
- if (this == &other)
- return *this;
- id_ = other.id_;
- url_ = other.url_;
- title_ = other.title_;
- visit_count_ = other.visit_count_;
- typed_count_ = other.typed_count_;
- last_visit_ = other.last_visit_;
- hidden_ = other.hidden_;
- return *this;
-}
+URLRow& URLRow::operator=(const URLRow& other) = default;
void URLRow::Swap(URLRow* other) {
std::swap(id_, other->id_);
@@ -52,40 +44,29 @@ void URLRow::Swap(URLRow* other) {
std::swap(hidden_, other->hidden_);
}
-void URLRow::Initialize() {
- id_ = 0;
- visit_count_ = 0;
- typed_count_ = 0;
- last_visit_ = base::Time();
- hidden_ = false;
-}
-
-
-URLResult::URLResult()
- : blocked_visit_(false) {
-}
+URLResult::URLResult() {}
URLResult::URLResult(const GURL& url, base::Time visit_time)
- : URLRow(url),
- visit_time_(visit_time),
- blocked_visit_(false) {
-}
+ : URLRow(url), visit_time_(visit_time) {}
-URLResult::URLResult(const GURL& url,
- const query_parser::Snippet::MatchPositions& title_matches)
- : URLRow(url) {
- title_match_positions_ = title_matches;
-}
-URLResult::URLResult(const URLRow& url_row)
- : URLRow(url_row),
- blocked_visit_(false) {
-}
+URLResult::URLResult(const URLRow& url_row) : URLRow(url_row) {}
URLResult::URLResult(const URLResult& other) = default;
+// TODO(bug 706963) this should be implemented as "= default" when Android
+// toolchain is updated.
+URLResult::URLResult(URLResult&& other) noexcept
+ : URLRow(std::move(other)),
+ visit_time_(other.visit_time_),
+ snippet_(std::move(other.snippet_)),
+ title_match_positions_(std::move(other.title_match_positions_)),
+ blocked_visit_(other.blocked_visit_) {}
+
URLResult::~URLResult() {
}
+URLResult& URLResult::operator=(const URLResult&) = default;
+
void URLResult::SwapResult(URLResult* other) {
URLRow::Swap(other);
std::swap(visit_time_, other->visit_time_);
diff --git a/chromium/components/history/core/browser/url_row.h b/chromium/components/history/core/browser/url_row.h
index c333c31a44a..64f00dabec0 100644
--- a/chromium/components/history/core/browser/url_row.h
+++ b/chromium/components/history/core/browser/url_row.h
@@ -18,16 +18,6 @@ typedef int64_t URLID;
// Holds all information globally associated with one URL (one row in the
// URL table).
-//
-// This keeps track of dirty bits, which are currently unused:
-//
-// TODO(brettw) the dirty bits are broken in a number of respects. First, the
-// database will want to update them on a const object, so they need to be
-// mutable.
-//
-// Second, there is a problem copying. If you make a copy of this structure
-// (as we allow since we put this into vectors in various places) then the
-// dirty bits will not be in sync for these copies.
class URLRow {
public:
URLRow();
@@ -39,6 +29,7 @@ class URLRow {
URLRow(const GURL& url, URLID id);
URLRow(const URLRow& other);
+ URLRow(URLRow&&) noexcept;
virtual ~URLRow();
URLRow& operator=(const URLRow& other);
@@ -51,6 +42,7 @@ class URLRow {
// row.
void set_id(URLID id) { id_ = id; }
+ void set_url(const GURL& url) { url_ = url; }
const GURL& url() const { return url_; }
const base::string16& title() const {
@@ -121,19 +113,10 @@ class URLRow {
void Swap(URLRow* other);
private:
- // This class writes directly into this structure and clears our dirty bits
- // when reading out of the DB.
- friend class URLDatabase;
- friend class HistoryBackend;
-
- // Initializes all values that need initialization to their defaults.
- // This excludes objects which autoinitialize such as strings.
- void Initialize();
-
// The row ID of this URL from the history database. This is immutable except
// when retrieving the row from the database or when determining if the URL
// referenced by the URLRow already exists in the database.
- URLID id_;
+ URLID id_ = 0;
// The URL of this row. Immutable except for the database which sets it
// when it pulls them out. If clients want to change it, they must use
@@ -143,10 +126,10 @@ class URLRow {
base::string16 title_;
// Total number of times this URL has been visited.
- int visit_count_;
+ int visit_count_ = 0;
// Number of times this URL has been manually entered in the URL bar.
- int typed_count_;
+ int typed_count_ = 0;
// The date of the last visit of this URL, which saves us from having to
// loop up in the visit table for things like autocomplete and expiration.
@@ -154,7 +137,7 @@ class URLRow {
// Indicates this entry should now be shown in typical UI or queries, this
// is usually for subframes.
- bool hidden_;
+ bool hidden_ = false;
// We support the implicit copy constuctor and operator=.
};
@@ -165,14 +148,13 @@ class URLResult : public URLRow {
public:
URLResult();
URLResult(const GURL& url, base::Time visit_time);
- // Constructor that create a URLResult from the specified URL and title match
- // positions from title_matches.
- URLResult(const GURL& url,
- const query_parser::Snippet::MatchPositions& title_matches);
- explicit URLResult(const URLRow& url_row);
+ URLResult(const URLRow& url_row);
URLResult(const URLResult& other);
+ URLResult(URLResult&&) noexcept;
~URLResult() override;
+ URLResult& operator=(const URLResult&);
+
base::Time visit_time() const { return visit_time_; }
void set_visit_time(base::Time visit_time) { visit_time_ = visit_time; }
@@ -205,7 +187,7 @@ class URLResult : public URLRow {
query_parser::Snippet::MatchPositions title_match_positions_;
// Whether a managed user was blocked when attempting to visit this URL.
- bool blocked_visit_;
+ bool blocked_visit_ = false;
// We support the implicit copy constructor and operator=.
};
diff --git a/chromium/components/history/core/browser/web_history_service_unittest.cc b/chromium/components/history/core/browser/web_history_service_unittest.cc
index 6a62a10c83a..7d528f3bcf3 100644
--- a/chromium/components/history/core/browser/web_history_service_unittest.cc
+++ b/chromium/components/history/core/browser/web_history_service_unittest.cc
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
@@ -231,7 +232,7 @@ class WebHistoryServiceTest : public testing::Test {
}
private:
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
FakeProfileOAuth2TokenService token_service_;
AccountTrackerService account_tracker_;
TestSigninClient signin_client_;
diff --git a/chromium/components/image_fetcher/BUILD.gn b/chromium/components/image_fetcher/core/BUILD.gn
index f911424ac1d..19d9cd4a7bd 100644
--- a/chromium/components/image_fetcher/BUILD.gn
+++ b/chromium/components/image_fetcher/core/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.
-static_library("image_fetcher") {
+static_library("core") {
sources = [
"image_data_fetcher.cc",
"image_data_fetcher.h",
@@ -31,7 +31,7 @@ source_set("unit_tests") {
"request_metadata_unittest.cc",
]
deps = [
- ":image_fetcher",
+ ":core",
"//net",
"//net:test_support",
"//testing/gmock",
diff --git a/chromium/components/image_fetcher/image_data_fetcher.cc b/chromium/components/image_fetcher/core/image_data_fetcher.cc
index 204fa95d7e8..3eac4508d21 100644
--- a/chromium/components/image_fetcher/image_data_fetcher.cc
+++ b/chromium/components/image_fetcher/core/image_data_fetcher.cc
@@ -2,19 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/image_fetcher/image_data_fetcher.h"
+#include "components/image_fetcher/core/image_data_fetcher.h"
+
+#include <utility>
#include "net/base/load_flags.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_status.h"
#include "url/gurl.h"
using data_use_measurement::DataUseUserData;
+namespace {
+
+const char kContentLocationHeader[] = "Content-Location";
+
+} // namespace
+
namespace image_fetcher {
// An active image URL fetcher request. The struct contains the related requests
@@ -22,8 +29,7 @@ namespace image_fetcher {
struct ImageDataFetcher::ImageDataFetcherRequest {
ImageDataFetcherRequest(const ImageDataFetcherCallback& callback,
std::unique_ptr<net::URLFetcher> url_fetcher)
- : callback(callback),
- url_fetcher(std::move(url_fetcher)) {}
+ : callback(callback), url_fetcher(std::move(url_fetcher)) {}
~ImageDataFetcherRequest() {}
@@ -47,6 +53,11 @@ void ImageDataFetcher::SetDataUseServiceName(
data_use_service_name_ = data_use_service_name;
}
+void ImageDataFetcher::SetImageDownloadLimit(
+ base::Optional<int64_t> max_download_bytes) {
+ max_download_bytes_ = max_download_bytes;
+}
+
void ImageDataFetcher::FetchImageData(
const GURL& image_url,
const ImageDataFetcherCallback& callback) {
@@ -70,32 +81,63 @@ void ImageDataFetcher::FetchImageData(
request->url_fetcher->SetRequestContext(url_request_context_getter_.get());
request->url_fetcher->SetReferrer(referrer);
request->url_fetcher->SetReferrerPolicy(referrer_policy);
+ request->url_fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DO_NOT_SAVE_COOKIES |
+ net::LOAD_DO_NOT_SEND_AUTH_DATA);
request->url_fetcher->Start();
pending_requests_[request->url_fetcher.get()] = std::move(request);
}
void ImageDataFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
- auto request_iter = pending_requests_.find(source);
- DCHECK(request_iter != pending_requests_.end());
-
+ DCHECK(pending_requests_.find(source) != pending_requests_.end());
bool success = source->GetStatus().status() == net::URLRequestStatus::SUCCESS;
RequestMetadata metadata;
- metadata.response_code = RESPONSE_CODE_INVALID;
if (success && source->GetResponseHeaders()) {
source->GetResponseHeaders()->GetMimeType(&metadata.mime_type);
- metadata.response_code = source->GetResponseHeaders()->response_code();
- success &= (metadata.response_code == net::HTTP_OK);
+ metadata.http_response_code = source->GetResponseHeaders()->response_code();
+ // Just read the first value-pair for this header (not caring about |iter|).
+ source->GetResponseHeaders()->EnumerateHeader(
+ /*iter=*/nullptr, kContentLocationHeader,
+ &metadata.content_location_header);
+ success &= (metadata.http_response_code == net::HTTP_OK);
}
+ metadata.from_http_cache = source->WasCached();
std::string image_data;
if (success) {
source->GetResponseAsString(&image_data);
}
- request_iter->second->callback.Run(image_data, metadata);
+ FinishRequest(source, metadata, image_data);
+}
+
+void ImageDataFetcher::OnURLFetchDownloadProgress(
+ const net::URLFetcher* source,
+ int64_t current,
+ int64_t total,
+ int64_t current_network_bytes) {
+ if (!max_download_bytes_.has_value()) {
+ return;
+ }
+ if (total <= max_download_bytes_.value() &&
+ current <= max_download_bytes_.value()) {
+ return;
+ }
+ DCHECK(pending_requests_.find(source) != pending_requests_.end());
+ DLOG(WARNING) << "Image data exceeded download size limit.";
+ RequestMetadata metadata;
+ metadata.http_response_code = net::URLFetcher::RESPONSE_CODE_INVALID;
- // Remove the finished request.
+ FinishRequest(source, metadata, /*image_data=*/std::string());
+}
+
+void ImageDataFetcher::FinishRequest(const net::URLFetcher* source,
+ const RequestMetadata& metadata,
+ const std::string& image_data) {
+ auto request_iter = pending_requests_.find(source);
+ DCHECK(request_iter != pending_requests_.end());
+ request_iter->second->callback.Run(image_data, metadata);
pending_requests_.erase(request_iter);
}
diff --git a/chromium/components/image_fetcher/image_data_fetcher.h b/chromium/components/image_fetcher/core/image_data_fetcher.h
index d05ec3d4bb5..169ad54d2ce 100644
--- a/chromium/components/image_fetcher/image_data_fetcher.h
+++ b/chromium/components/image_fetcher/core/image_data_fetcher.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_IMAGE_FETCHER_IMAGE_DATA_FETCHER_H_
-#define COMPONENTS_IMAGE_FETCHER_IMAGE_DATA_FETCHER_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_DATA_FETCHER_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_DATA_FETCHER_H_
#include <map>
#include <memory>
@@ -12,9 +12,9 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/optional.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "components/image_fetcher/request_metadata.h"
-#include "net/url_request/url_fetcher.h"
+#include "components/image_fetcher/core/request_metadata.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request.h"
#include "url/gurl.h"
@@ -28,14 +28,10 @@ namespace image_fetcher {
class ImageDataFetcher : public net::URLFetcherDelegate {
public:
- // Impossible http response code. Used to signal that no http response code
- // was received.
- enum ResponseCode {
- RESPONSE_CODE_INVALID = net::URLFetcher::RESPONSE_CODE_INVALID
- };
-
// Callback with the |image_data|. If an error prevented a http response,
// |request_metadata.response_code| will be RESPONSE_CODE_INVALID.
+ // TODO(treib): Pass |image_data| out by value, or use RefCountedBytes, to
+ // avoid copying.
using ImageDataFetcherCallback =
base::Callback<void(const std::string& image_data,
const RequestMetadata& request_metadata)>;
@@ -49,6 +45,10 @@ class ImageDataFetcher : public net::URLFetcherDelegate {
// Sets a service name against which to track data usage.
void SetDataUseServiceName(DataUseServiceName data_use_service_name);
+ // Sets an upper limit for image downloads.
+ // Already running downloads are affected.
+ void SetImageDownloadLimit(base::Optional<int64_t> max_download_bytes);
+
// Fetches the raw image bytes from the given |image_url| and calls the given
// |callback|. The callback is run even if fetching the URL fails. In case
// of an error an empty string is passed to the callback.
@@ -64,8 +64,16 @@ class ImageDataFetcher : public net::URLFetcherDelegate {
private:
struct ImageDataFetcherRequest;
- // Method inherited from URLFetcherDelegate
+ // Methods inherited from URLFetcherDelegate
void OnURLFetchComplete(const net::URLFetcher* source) override;
+ void OnURLFetchDownloadProgress(const net::URLFetcher* source,
+ int64_t current,
+ int64_t total,
+ int64_t current_network_bytes) override;
+
+ void FinishRequest(const net::URLFetcher* source,
+ const RequestMetadata& metadata,
+ const std::string& image_data);
// All active image url requests.
std::map<const net::URLFetcher*, std::unique_ptr<ImageDataFetcherRequest>>
@@ -82,9 +90,12 @@ class ImageDataFetcher : public net::URLFetcherDelegate {
// is not used.
int next_url_fetcher_id_;
+ // Upper limit for the number of bytes to download per image.
+ base::Optional<int64_t> max_download_bytes_;
+
DISALLOW_COPY_AND_ASSIGN(ImageDataFetcher);
};
} // namespace image_fetcher
-#endif // COMPONENTS_IMAGE_FETCHER_IMAGE_DATA_FETCHER_H_
+#endif // COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_DATA_FETCHER_H_
diff --git a/chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc b/chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc
new file mode 100644
index 00000000000..de47936940e
--- /dev/null
+++ b/chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc
@@ -0,0 +1,297 @@
+// 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/image_fetcher/core/image_data_fetcher.h"
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_request_status.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kImageURL[] = "http://www.example.com/image";
+const char kURLResponseData[] = "EncodedImageData";
+
+} // namespace
+
+namespace image_fetcher {
+
+class ImageDataFetcherTest : public testing::Test {
+ public:
+ ImageDataFetcherTest()
+ : test_request_context_getter_(
+ new net::TestURLRequestContextGetter(message_loop_.task_runner())),
+ image_data_fetcher_(test_request_context_getter_.get()) {}
+ ~ImageDataFetcherTest() override {}
+
+ MOCK_METHOD2(OnImageDataFetched,
+ void(const std::string&, const RequestMetadata&));
+
+ MOCK_METHOD2(OnImageDataFetchedFailedRequest,
+ void(const std::string&, const RequestMetadata&));
+
+ MOCK_METHOD2(OnImageDataFetchedMultipleRequests,
+ void(const std::string&, const RequestMetadata&));
+
+ protected:
+ base::MessageLoop message_loop_;
+
+ scoped_refptr<net::URLRequestContextGetter> test_request_context_getter_;
+
+ ImageDataFetcher image_data_fetcher_;
+
+ net::TestURLFetcherFactory fetcher_factory_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ImageDataFetcherTest);
+};
+
+TEST_F(ImageDataFetcherTest, FetchImageData) {
+ image_data_fetcher_.FetchImageData(
+ GURL(kImageURL), base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
+ base::Unretained(this)));
+
+ RequestMetadata expected_metadata;
+ expected_metadata.mime_type = std::string("image/png");
+ expected_metadata.http_response_code = net::HTTP_OK;
+ EXPECT_CALL(*this, OnImageDataFetched(std::string(kURLResponseData),
+ expected_metadata));
+
+ // Get and configure the TestURLFetcher.
+ net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_NE(nullptr, test_url_fetcher);
+ EXPECT_TRUE(test_url_fetcher->GetLoadFlags() & net::LOAD_DO_NOT_SEND_COOKIES);
+ EXPECT_TRUE(test_url_fetcher->GetLoadFlags() & net::LOAD_DO_NOT_SAVE_COOKIES);
+ EXPECT_TRUE(test_url_fetcher->GetLoadFlags() &
+ net::LOAD_DO_NOT_SEND_AUTH_DATA);
+ test_url_fetcher->set_status(
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
+ test_url_fetcher->SetResponseString(kURLResponseData);
+ test_url_fetcher->set_response_code(net::HTTP_OK);
+
+ std::string raw_header =
+ "HTTP/1.1 200 OK\n"
+ "Content-type: image/png\n\n";
+ std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(raw_header));
+ test_url_fetcher->set_response_headers(headers);
+
+ // Call the URLFetcher delegate to continue the test.
+ test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
+}
+
+TEST_F(ImageDataFetcherTest, FetchImageData_FromCache) {
+ image_data_fetcher_.FetchImageData(
+ GURL(kImageURL), base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
+ base::Unretained(this)));
+
+ RequestMetadata expected_metadata;
+ expected_metadata.mime_type = std::string("image/png");
+ expected_metadata.http_response_code = net::HTTP_OK;
+ expected_metadata.from_http_cache = true;
+ EXPECT_CALL(*this, OnImageDataFetched(std::string(kURLResponseData),
+ expected_metadata));
+
+ // Get and configure the TestURLFetcher.
+ net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_NE(nullptr, test_url_fetcher);
+ test_url_fetcher->set_status(
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
+ test_url_fetcher->SetResponseString(kURLResponseData);
+ test_url_fetcher->set_response_code(net::HTTP_OK);
+ test_url_fetcher->set_was_cached(true);
+
+ std::string raw_header =
+ "HTTP/1.1 200 OK\n"
+ "Content-type: image/png\n\n";
+ std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(raw_header));
+ test_url_fetcher->set_response_headers(headers);
+
+ // Call the URLFetcher delegate to continue the test.
+ test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
+}
+
+TEST_F(ImageDataFetcherTest, FetchImageData_NotFound) {
+ image_data_fetcher_.FetchImageData(
+ GURL(kImageURL), base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
+ base::Unretained(this)));
+
+ RequestMetadata expected_metadata;
+ expected_metadata.mime_type = std::string("image/png");
+ expected_metadata.http_response_code = net::HTTP_NOT_FOUND;
+ // For 404, expect an empty result even though correct image data is sent.
+ EXPECT_CALL(*this, OnImageDataFetched(std::string(), expected_metadata));
+
+ // Get and configure the TestURLFetcher.
+ net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_NE(nullptr, test_url_fetcher);
+ test_url_fetcher->set_status(
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
+ test_url_fetcher->SetResponseString(kURLResponseData);
+
+ std::string raw_header =
+ "HTTP/1.1 404 Not Found\n"
+ "Content-type: image/png\n\n";
+ std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(raw_header));
+ test_url_fetcher->set_response_headers(headers);
+
+ // Call the URLFetcher delegate to continue the test.
+ test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
+}
+
+TEST_F(ImageDataFetcherTest, FetchImageData_WithContentLocation) {
+ image_data_fetcher_.FetchImageData(
+ GURL(kImageURL), base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
+ base::Unretained(this)));
+
+ RequestMetadata expected_metadata;
+ expected_metadata.mime_type = std::string("image/png");
+ expected_metadata.http_response_code = net::HTTP_NOT_FOUND;
+ expected_metadata.content_location_header = "http://test-location/image.png";
+ // For 404, expect an empty result even though correct image data is sent.
+ EXPECT_CALL(*this, OnImageDataFetched(std::string(), expected_metadata));
+
+ // Get and configure the TestURLFetcher.
+ net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_NE(nullptr, test_url_fetcher);
+ test_url_fetcher->set_status(
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
+ test_url_fetcher->SetResponseString(kURLResponseData);
+
+ std::string raw_header =
+ "HTTP/1.1 404 Not Found\n"
+ "Content-type: image/png\n"
+ "Content-location: http://test-location/image.png\n\n";
+ std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(raw_header));
+ test_url_fetcher->set_response_headers(headers);
+
+ // Call the URLFetcher delegate to continue the test.
+ test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
+}
+
+TEST_F(ImageDataFetcherTest, FetchImageData_FailedRequest) {
+ image_data_fetcher_.FetchImageData(
+ GURL(kImageURL),
+ base::Bind(&ImageDataFetcherTest::OnImageDataFetchedFailedRequest,
+ base::Unretained(this)));
+
+ RequestMetadata expected_metadata;
+ expected_metadata.http_response_code = net::URLFetcher::RESPONSE_CODE_INVALID;
+ EXPECT_CALL(
+ *this, OnImageDataFetchedFailedRequest(std::string(), expected_metadata));
+
+ // Get and configure the TestURLFetcher.
+ net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_NE(nullptr, test_url_fetcher);
+ test_url_fetcher->set_status(net::URLRequestStatus(
+ net::URLRequestStatus::FAILED, net::ERR_INVALID_URL));
+
+ // Call the URLFetcher delegate to continue the test.
+ test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
+}
+
+TEST_F(ImageDataFetcherTest, FetchImageData_MultipleRequests) {
+ ImageDataFetcher::ImageDataFetcherCallback callback =
+ base::Bind(&ImageDataFetcherTest::OnImageDataFetchedMultipleRequests,
+ base::Unretained(this));
+ EXPECT_CALL(*this, OnImageDataFetchedMultipleRequests(testing::_, testing::_))
+ .Times(2);
+
+ image_data_fetcher_.FetchImageData(GURL(kImageURL), callback);
+ image_data_fetcher_.FetchImageData(GURL(kImageURL), callback);
+
+ // Multiple calls to FetchImageData for the same URL will result in
+ // multiple URLFetchers being created.
+ net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_NE(nullptr, test_url_fetcher);
+ test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
+
+ test_url_fetcher = fetcher_factory_.GetFetcherByID(1);
+ ASSERT_NE(nullptr, test_url_fetcher);
+ test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
+}
+
+TEST_F(ImageDataFetcherTest, FetchImageData_CancelFetchIfImageExceedsMaxSize) {
+ // In order to know whether the fetcher was canceled, it must notify about its
+ // deletion.
+ fetcher_factory_.set_remove_fetcher_on_delete(true);
+
+ const int64_t kMaxDownloadBytes = 1024 * 1024;
+ image_data_fetcher_.SetImageDownloadLimit(kMaxDownloadBytes);
+ image_data_fetcher_.FetchImageData(
+ GURL(kImageURL), base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
+ base::Unretained(this)));
+
+ // Fetching an oversized image will behave like any other failed request.
+ // There will be exactly one call to OnImageDataFetched containing a response
+ // code that would be impossible for a completed fetch.
+ RequestMetadata expected_metadata;
+ expected_metadata.http_response_code = net::URLFetcher::RESPONSE_CODE_INVALID;
+ EXPECT_CALL(*this, OnImageDataFetched(std::string(), expected_metadata));
+
+ // Get and configure the TestURLFetcher.
+ net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_NE(nullptr, test_url_fetcher);
+
+ // Create a completely valid response that is never used. This is to make sure
+ // that the answer isn't accidentally invalid but intentionally.
+ test_url_fetcher->set_status(
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
+ test_url_fetcher->SetResponseString(kURLResponseData);
+ test_url_fetcher->set_response_code(net::HTTP_OK);
+ std::string raw_header =
+ "HTTP/1.1 200 OK\n"
+ "Content-type: image/png\n\n";
+ std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(raw_header));
+ test_url_fetcher->set_response_headers(headers);
+
+ test_url_fetcher->delegate()->OnURLFetchDownloadProgress(
+ test_url_fetcher,
+ /*current=*/0, // Bytes received up to the call.
+ /*total=*/-1, // not determined
+ /*current_network_bytes=*/0); // not relevant
+ // The URL fetch should be running ...
+ ASSERT_NE(nullptr, fetcher_factory_.GetFetcherByID(0));
+
+ test_url_fetcher->delegate()->OnURLFetchDownloadProgress(
+ test_url_fetcher,
+ 768 * 1024, // Current bytes are not exeeding the limit.
+ /*total=*/-1, /*current_network_bytes=*/0);
+ // ... and running ...
+ ASSERT_NE(nullptr, fetcher_factory_.GetFetcherByID(0));
+
+ test_url_fetcher->delegate()->OnURLFetchDownloadProgress(
+ test_url_fetcher, kMaxDownloadBytes, // Still not exeeding the limit.
+ /*total=*/-1, /*current_network_bytes=*/0);
+ // ... and running ...
+ ASSERT_NE(nullptr, fetcher_factory_.GetFetcherByID(0));
+
+ test_url_fetcher->delegate()->OnURLFetchDownloadProgress(
+ test_url_fetcher, kMaxDownloadBytes + 1, // Limits are exceeded.
+ /*total=*/-1, /*current_network_bytes=*/0);
+ // ... and be canceled.
+ EXPECT_EQ(nullptr, fetcher_factory_.GetFetcherByID(0));
+}
+
+} // namespace image_fetcher
diff --git a/chromium/components/image_fetcher/image_decoder.h b/chromium/components/image_fetcher/core/image_decoder.h
index b5589f17b4a..5f03db12d4c 100644
--- a/chromium/components/image_fetcher/image_decoder.h
+++ b/chromium/components/image_fetcher/core/image_decoder.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_IMAGE_FETCHER_IMAGE_DECODER_H_
-#define COMPONENTS_IMAGE_FETCHER_IMAGE_DECODER_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_DECODER_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_DECODER_H_
#include <string>
@@ -43,4 +43,4 @@ class ImageDecoder {
} // namespace image_fetcher
-#endif // COMPONENTS_IMAGE_FETCHER_IMAGE_DECODER_H_
+#endif // COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_DECODER_H_
diff --git a/chromium/components/image_fetcher/image_fetcher.h b/chromium/components/image_fetcher/core/image_fetcher.h
index 3626c3af704..0284aee9f25 100644
--- a/chromium/components/image_fetcher/image_fetcher.h
+++ b/chromium/components/image_fetcher/core/image_fetcher.h
@@ -2,15 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_H_
-#define COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_H_
#include <string>
#include "base/callback.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "components/image_fetcher/image_fetcher_delegate.h"
+#include "components/image_fetcher/core/image_fetcher_delegate.h"
#include "url/gurl.h"
namespace gfx {
@@ -20,6 +21,10 @@ class Size;
namespace image_fetcher {
+class ImageDecoder;
+
+struct RequestMetadata;
+
// A class used to fetch server images. It can be called from any thread and the
// callback will be called on the thread which initiated the fetch.
class ImageFetcher {
@@ -27,6 +32,11 @@ class ImageFetcher {
ImageFetcher() {}
virtual ~ImageFetcher() {}
+ using ImageFetcherCallback =
+ base::Callback<void(const std::string& id,
+ const gfx::Image& image,
+ const RequestMetadata& metadata)>;
+
using DataUseServiceName = data_use_measurement::DataUseUserData::ServiceName;
virtual void SetImageFetcherDelegate(ImageFetcherDelegate* delegate) = 0;
@@ -35,6 +45,12 @@ class ImageFetcher {
virtual void SetDataUseServiceName(
DataUseServiceName data_use_service_name) = 0;
+ // Sets an upper limit for image downloads that is by default disabled.
+ // Setting |max_download_bytes| to a negative value will disable the limit.
+ // Already running downloads are immediately affected.
+ virtual void SetImageDownloadLimit(
+ base::Optional<int64_t> max_download_bytes) = 0;
+
// Sets the desired size for images with multiple frames (like .ico files).
// By default, the image fetcher choses smaller images. Override to choose a
// frame with a size as close as possible to |size| (trying to take one in
@@ -48,10 +64,9 @@ class ImageFetcher {
virtual void StartOrQueueNetworkRequest(
const std::string& id,
const GURL& image_url,
- base::Callback<void(const std::string&, const gfx::Image&)> callback) = 0;
+ const ImageFetcherCallback& callback) = 0;
- // TODO(treib,markusheintz): Now that iOS uses the same ImageFetcherImpl (see
- // crbug.com/689020), add a getter for the ImageDecoder here.
+ virtual ImageDecoder* GetImageDecoder() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(ImageFetcher);
@@ -59,4 +74,4 @@ class ImageFetcher {
} // namespace image_fetcher
-#endif // COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_H_
+#endif // COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_H_
diff --git a/chromium/components/image_fetcher/image_fetcher_delegate.h b/chromium/components/image_fetcher/core/image_fetcher_delegate.h
index 38d66b29543..fd9c362fcb9 100644
--- a/chromium/components/image_fetcher/image_fetcher_delegate.h
+++ b/chromium/components/image_fetcher/core/image_fetcher_delegate.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_IMAGE_FETCHER_IMAGE_FETCHER_DELEGATE_H_
-#define COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_DELEGATE_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_DELEGATE_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_DELEGATE_H_
#include <string>
@@ -24,13 +24,12 @@ class ImageFetcherDelegate {
// stores (generally compressed) image data owned by the caller, and can be
// empty if the fetch failed.
virtual void OnImageDataFetched(const std::string& id,
- const std::string& data) {};
+ const std::string& data) {}
// Called when an image was fetched and decoded. |id| is an identifier for the
// fetch (as passed to ImageFetcher::StartOrQueueNetworkRequest); |image|
// stores image data owned by the caller, and can be an empty gfx::Image.
- virtual void OnImageFetched(const std::string& id,
- const gfx::Image& image) {};
+ virtual void OnImageFetched(const std::string& id, const gfx::Image& image) {}
protected:
virtual ~ImageFetcherDelegate() {}
@@ -40,4 +39,4 @@ class ImageFetcherDelegate {
} // namespace image_fetcher
-#endif // COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_DELEGATE_H_
+#endif // COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_DELEGATE_H_
diff --git a/chromium/components/image_fetcher/image_fetcher_impl.cc b/chromium/components/image_fetcher/core/image_fetcher_impl.cc
index f65155c65e7..567928c9a6d 100644
--- a/chromium/components/image_fetcher/image_fetcher_impl.cc
+++ b/chromium/components/image_fetcher/core/image_fetcher_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/image_fetcher/image_fetcher_impl.h"
+#include "components/image_fetcher/core/image_fetcher_impl.h"
#include <string>
@@ -15,10 +15,10 @@ namespace image_fetcher {
ImageFetcherImpl::ImageFetcherImpl(
std::unique_ptr<ImageDecoder> image_decoder,
net::URLRequestContextGetter* url_request_context)
- : delegate_(nullptr), url_request_context_(url_request_context),
+ : delegate_(nullptr),
+ url_request_context_(url_request_context),
image_decoder_(std::move(image_decoder)),
- image_data_fetcher_(new ImageDataFetcher(url_request_context_.get())) {
-}
+ image_data_fetcher_(new ImageDataFetcher(url_request_context_.get())) {}
ImageFetcherImpl::~ImageFetcherImpl() {}
@@ -27,7 +27,7 @@ ImageFetcherImpl::ImageRequest::ImageRequest() {}
ImageFetcherImpl::ImageRequest::ImageRequest(const ImageRequest& other) =
default;
-ImageFetcherImpl::ImageRequest::~ImageRequest() { }
+ImageFetcherImpl::ImageRequest::~ImageRequest() {}
void ImageFetcherImpl::SetImageFetcherDelegate(ImageFetcherDelegate* delegate) {
DCHECK(delegate);
@@ -43,10 +43,15 @@ void ImageFetcherImpl::SetDesiredImageFrameSize(const gfx::Size& size) {
desired_image_frame_size_ = size;
}
+void ImageFetcherImpl::SetImageDownloadLimit(
+ base::Optional<int64_t> max_download_bytes) {
+ image_data_fetcher_->SetImageDownloadLimit(max_download_bytes);
+}
+
void ImageFetcherImpl::StartOrQueueNetworkRequest(
const std::string& id,
const GURL& image_url,
- base::Callback<void(const std::string&, const gfx::Image&)> callback) {
+ const ImageFetcherCallback& callback) {
// Before starting to fetch the image. Look for a request in progress for
// |image_url|, and queue if appropriate.
ImageRequestMap::iterator it = pending_net_requests_.find(image_url);
@@ -57,9 +62,8 @@ void ImageFetcherImpl::StartOrQueueNetworkRequest(
pending_net_requests_[image_url].swap(&request);
image_data_fetcher_->FetchImageData(
- image_url,
- base::Bind(&ImageFetcherImpl::OnImageURLFetched,
- base::Unretained(this), image_url));
+ image_url, base::Bind(&ImageFetcherImpl::OnImageURLFetched,
+ base::Unretained(this), image_url));
} else {
// Request in progress. Register as an interested callback.
it->second.callbacks.push_back(callback);
@@ -76,12 +80,14 @@ void ImageFetcherImpl::OnImageURLFetched(const GURL& image_url,
delegate_->OnImageDataFetched(it->second.id, image_data);
}
- image_decoder_->DecodeImage(image_data, desired_image_frame_size_,
- base::Bind(&ImageFetcherImpl::OnImageDecoded,
- base::Unretained(this), image_url));
+ image_decoder_->DecodeImage(
+ image_data, desired_image_frame_size_,
+ base::Bind(&ImageFetcherImpl::OnImageDecoded, base::Unretained(this),
+ image_url, metadata));
}
void ImageFetcherImpl::OnImageDecoded(const GURL& image_url,
+ const RequestMetadata& metadata,
const gfx::Image& image) {
// Get request for the given image_url from the request queue.
ImageRequestMap::iterator image_iter = pending_net_requests_.find(image_url);
@@ -90,7 +96,7 @@ void ImageFetcherImpl::OnImageDecoded(const GURL& image_url,
// Run all callbacks
for (const auto& callback : request->callbacks) {
- callback.Run(request->id, image);
+ callback.Run(request->id, image, metadata);
}
// Inform the ImageFetcherDelegate.
@@ -102,4 +108,8 @@ void ImageFetcherImpl::OnImageDecoded(const GURL& image_url,
pending_net_requests_.erase(image_iter);
}
+ImageDecoder* ImageFetcherImpl::GetImageDecoder() {
+ return image_decoder_.get();
+}
+
} // namespace image_fetcher
diff --git a/chromium/components/image_fetcher/image_fetcher_impl.h b/chromium/components/image_fetcher/core/image_fetcher_impl.h
index 16b348f854e..697217c7f79 100644
--- a/chromium/components/image_fetcher/image_fetcher_impl.h
+++ b/chromium/components/image_fetcher/core/image_fetcher_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_IMAGE_FETCHER_IMAGE_FETCHER_IMPL_H_
-#define COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_IMPL_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_IMPL_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_IMPL_H_
#include <map>
#include <memory>
@@ -13,9 +13,9 @@
#include "base/callback.h"
#include "base/macros.h"
-#include "components/image_fetcher/image_data_fetcher.h"
-#include "components/image_fetcher/image_decoder.h"
-#include "components/image_fetcher/image_fetcher.h"
+#include "components/image_fetcher/core/image_data_fetcher.h"
+#include "components/image_fetcher/core/image_decoder.h"
+#include "components/image_fetcher/core/image_fetcher.h"
#include "ui/gfx/geometry/size.h"
#include "url/gurl.h"
@@ -32,9 +32,8 @@ namespace image_fetcher {
// The standard (non-test) implementation of ImageFetcher.
class ImageFetcherImpl : public image_fetcher::ImageFetcher {
public:
- ImageFetcherImpl(
- std::unique_ptr<ImageDecoder> image_decoder,
- net::URLRequestContextGetter* url_request_context);
+ ImageFetcherImpl(std::unique_ptr<ImageDecoder> image_decoder,
+ net::URLRequestContextGetter* url_request_context);
~ImageFetcherImpl() override;
// Sets the |delegate| of the ImageFetcherImpl. The |delegate| has to be alive
@@ -47,16 +46,17 @@ class ImageFetcherImpl : public image_fetcher::ImageFetcher {
void SetDesiredImageFrameSize(const gfx::Size& size) override;
+ void SetImageDownloadLimit(
+ base::Optional<int64_t> max_download_bytes) override;
+
void StartOrQueueNetworkRequest(
const std::string& id,
const GURL& image_url,
- base::Callback<void(const std::string&, const gfx::Image&)> callback)
- override;
+ const ImageFetcherCallback& callback) override;
- private:
- using CallbackVector =
- std::vector<base::Callback<void(const std::string&, const gfx::Image&)>>;
+ ImageDecoder* GetImageDecoder() override;
+ private:
// State related to an image fetch (id, pending callbacks).
struct ImageRequest {
ImageRequest();
@@ -71,7 +71,7 @@ class ImageFetcherImpl : public image_fetcher::ImageFetcher {
std::string id;
// Queue for pending callbacks, which may accumulate while the request is in
// flight.
- CallbackVector callbacks;
+ std::vector<ImageFetcherCallback> callbacks;
};
using ImageRequestMap = std::map<const GURL, ImageRequest>;
@@ -84,7 +84,9 @@ class ImageFetcherImpl : public image_fetcher::ImageFetcher {
// Processes image decoded events. This is the continuation method used for
// creating callbacks that are passed to the ImageDecoder.
- void OnImageDecoded(const GURL& image_url, const gfx::Image& image);
+ void OnImageDecoded(const GURL& image_url,
+ const RequestMetadata& metadata,
+ const gfx::Image& image);
ImageFetcherDelegate* delegate_;
@@ -105,4 +107,4 @@ class ImageFetcherImpl : public image_fetcher::ImageFetcher {
} // namespace image_fetcher
-#endif // COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_IMPL_H_
+#endif // COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_IMPL_H_
diff --git a/chromium/components/image_fetcher/request_metadata.cc b/chromium/components/image_fetcher/core/request_metadata.cc
index 172dc5c2ab1..13ffadaa357 100644
--- a/chromium/components/image_fetcher/request_metadata.cc
+++ b/chromium/components/image_fetcher/core/request_metadata.cc
@@ -2,13 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/image_fetcher/request_metadata.h"
+#include "components/image_fetcher/core/request_metadata.h"
namespace image_fetcher {
+RequestMetadata::RequestMetadata()
+ : http_response_code(RESPONSE_CODE_INVALID), from_http_cache(false) {}
+
bool operator==(const RequestMetadata& lhs, const RequestMetadata& rhs) {
return lhs.mime_type == rhs.mime_type &&
- lhs.response_code == rhs.response_code;
+ lhs.http_response_code == rhs.http_response_code &&
+ lhs.from_http_cache == rhs.from_http_cache &&
+ lhs.content_location_header == rhs.content_location_header;
}
bool operator!=(const RequestMetadata& lhs, const RequestMetadata& rhs) {
diff --git a/chromium/components/image_fetcher/core/request_metadata.h b/chromium/components/image_fetcher/core/request_metadata.h
new file mode 100644
index 00000000000..630ffc6956c
--- /dev/null
+++ b/chromium/components/image_fetcher/core/request_metadata.h
@@ -0,0 +1,35 @@
+// 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_IMAGE_FETCHER_CORE_REQUEST_METADATA_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_REQUEST_METADATA_H_
+
+#include <string>
+
+#include "net/url_request/url_fetcher.h"
+
+namespace image_fetcher {
+
+// Metadata for a URL request.
+struct RequestMetadata {
+ // Impossible http response code. Used to signal that no http response code
+ // was received.
+ enum ResponseCode {
+ RESPONSE_CODE_INVALID = net::URLFetcher::RESPONSE_CODE_INVALID
+ };
+
+ RequestMetadata();
+
+ std::string mime_type;
+ int http_response_code;
+ bool from_http_cache;
+ std::string content_location_header;
+};
+
+bool operator==(const RequestMetadata& lhs, const RequestMetadata& rhs);
+bool operator!=(const RequestMetadata& lhs, const RequestMetadata& rhs);
+
+} // namespace image_fetcher
+
+#endif // COMPONENTS_IMAGE_FETCHER_CORE_REQUEST_METADATA_H_
diff --git a/chromium/components/image_fetcher/core/request_metadata_unittest.cc b/chromium/components/image_fetcher/core/request_metadata_unittest.cc
new file mode 100644
index 00000000000..ea0d00f4e5c
--- /dev/null
+++ b/chromium/components/image_fetcher/core/request_metadata_unittest.cc
@@ -0,0 +1,57 @@
+// 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/image_fetcher/core/request_metadata.h"
+
+#include "base/memory/ref_counted.h"
+#include "net/http/http_response_headers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace image_fetcher {
+
+TEST(RequestMetadataTest, Equality) {
+ RequestMetadata rhs;
+ RequestMetadata lhs;
+ rhs.mime_type = "testMimeType";
+ lhs.mime_type = "testMimeType";
+ rhs.http_response_code = 1;
+ lhs.http_response_code = 1;
+ rhs.from_http_cache = true;
+ lhs.from_http_cache = true;
+ lhs.content_location_header = "http://test-location.com/image.png";
+ rhs.content_location_header = "http://test-location.com/image.png";
+
+ EXPECT_EQ(rhs, lhs);
+}
+
+TEST(RequestMetadataTest, NoEquality) {
+ RequestMetadata rhs;
+ RequestMetadata lhs;
+ rhs.mime_type = "testMimeType";
+ lhs.mime_type = "testMimeType";
+ rhs.http_response_code = 1;
+ lhs.http_response_code = 1;
+ rhs.from_http_cache = true;
+ lhs.from_http_cache = true;
+ lhs.content_location_header = "http://test-location.com/image.png";
+ rhs.content_location_header = "http://test-location.com/image.png";
+
+ lhs.mime_type = "testOtherMimeType";
+ EXPECT_NE(rhs, lhs);
+ lhs.mime_type = "testMimeType";
+
+ lhs.http_response_code = 2;
+ EXPECT_NE(rhs, lhs);
+ lhs.http_response_code = 1;
+
+ lhs.from_http_cache = false;
+ EXPECT_NE(rhs, lhs);
+ lhs.from_http_cache = true;
+
+ lhs.content_location_header = "http://other.test-location.com/image.png";
+ EXPECT_NE(rhs, lhs);
+ lhs.content_location_header = "http://test-location.com/image.png";
+}
+
+} // namespace image_fetcher
diff --git a/chromium/components/image_fetcher/image_data_fetcher_unittest.cc b/chromium/components/image_fetcher/image_data_fetcher_unittest.cc
deleted file mode 100644
index 15039781fb4..00000000000
--- a/chromium/components/image_fetcher/image_data_fetcher_unittest.cc
+++ /dev/null
@@ -1,167 +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/image_fetcher/image_data_fetcher.h"
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_status_code.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_status.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-const char kImageURL[] = "http://www.example.com/image";
-const char kURLResponseData[] = "EncodedImageData";
-
-} // namespace
-
-namespace image_fetcher {
-
-class ImageDataFetcherTest : public testing::Test {
- public:
- ImageDataFetcherTest()
- : test_request_context_getter_(
- new net::TestURLRequestContextGetter(message_loop_.task_runner())),
- image_data_fetcher_(test_request_context_getter_.get()) {}
- ~ImageDataFetcherTest() override {}
-
- MOCK_METHOD2(OnImageDataFetched,
- void(const std::string&, const RequestMetadata&));
-
- MOCK_METHOD2(OnImageDataFetchedFailedRequest,
- void(const std::string&, const RequestMetadata&));
-
- MOCK_METHOD2(OnImageDataFetchedMultipleRequests,
- void(const std::string&, const RequestMetadata&));
-
- protected:
- base::MessageLoop message_loop_;
-
- scoped_refptr<net::URLRequestContextGetter> test_request_context_getter_;
-
- ImageDataFetcher image_data_fetcher_;
-
- net::TestURLFetcherFactory fetcher_factory_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ImageDataFetcherTest);
-};
-
-TEST_F(ImageDataFetcherTest, FetchImageData) {
- image_data_fetcher_.FetchImageData(
- GURL(kImageURL),
- base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
- base::Unretained(this)));
-
- RequestMetadata expected_metadata;
- expected_metadata.mime_type = std::string("image/png");
- expected_metadata.response_code = net::HTTP_OK;
- EXPECT_CALL(*this, OnImageDataFetched(std::string(kURLResponseData),
- expected_metadata));
-
- // Get and configure the TestURLFetcher.
- net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
- ASSERT_NE(nullptr, test_url_fetcher);
- test_url_fetcher->set_status(
- net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
- test_url_fetcher->SetResponseString(kURLResponseData);
- test_url_fetcher->set_response_code(net::HTTP_OK);
-
- std::string raw_header =
- "HTTP/1.1 200 OK\n"
- "Content-type: image/png\n\n";
- std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
- scoped_refptr<net::HttpResponseHeaders> headers(
- new net::HttpResponseHeaders(raw_header));
-
- test_url_fetcher->set_response_headers(headers);
-
- // Call the URLFetcher delegate to continue the test.
- test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
-}
-
-TEST_F(ImageDataFetcherTest, FetchImageData_NotFound) {
- image_data_fetcher_.FetchImageData(
- GURL(kImageURL), base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
- base::Unretained(this)));
-
- RequestMetadata expected_metadata;
- expected_metadata.mime_type = std::string("image/png");
- expected_metadata.response_code = net::HTTP_NOT_FOUND;
- // For 404, expect an empty result even though correct image data is sent.
- EXPECT_CALL(*this, OnImageDataFetched(std::string(), expected_metadata));
-
- // Get and configure the TestURLFetcher.
- net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
- ASSERT_NE(nullptr, test_url_fetcher);
- test_url_fetcher->set_status(
- net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
- test_url_fetcher->SetResponseString(kURLResponseData);
-
- std::string raw_header =
- "HTTP/1.1 404 Not Found\n"
- "Content-type: image/png\n\n";
- std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
- scoped_refptr<net::HttpResponseHeaders> headers(
- new net::HttpResponseHeaders(raw_header));
-
- test_url_fetcher->set_response_headers(headers);
-
- // Call the URLFetcher delegate to continue the test.
- test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
-}
-
-TEST_F(ImageDataFetcherTest, FetchImageData_FailedRequest) {
- image_data_fetcher_.FetchImageData(
- GURL(kImageURL),
- base::Bind(&ImageDataFetcherTest::OnImageDataFetchedFailedRequest,
- base::Unretained(this)));
-
- RequestMetadata expected_metadata;
- expected_metadata.response_code = net::URLFetcher::RESPONSE_CODE_INVALID;
- EXPECT_CALL(
- *this, OnImageDataFetchedFailedRequest(std::string(), expected_metadata));
-
- // Get and configure the TestURLFetcher.
- net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
- ASSERT_NE(nullptr, test_url_fetcher);
- test_url_fetcher->set_status(
- net::URLRequestStatus(net::URLRequestStatus::FAILED,
- net::ERR_INVALID_URL));
-
- // Call the URLFetcher delegate to continue the test.
- test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
-}
-
-TEST_F(ImageDataFetcherTest, FetchImageData_MultipleRequests) {
- ImageDataFetcher::ImageDataFetcherCallback callback =
- base::Bind(&ImageDataFetcherTest::OnImageDataFetchedMultipleRequests,
- base::Unretained(this));
- EXPECT_CALL(*this, OnImageDataFetchedMultipleRequests(testing::_, testing::_))
- .Times(2);
-
- image_data_fetcher_.FetchImageData(GURL(kImageURL), callback);
- image_data_fetcher_.FetchImageData(GURL(kImageURL), callback);
-
- // Multiple calls to FetchImageData for the same URL will result in
- // multiple URLFetchers being created.
- net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
- ASSERT_NE(nullptr, test_url_fetcher);
- test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
-
- test_url_fetcher = fetcher_factory_.GetFetcherByID(1);
- ASSERT_NE(nullptr, test_url_fetcher);
- test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
-}
-
-} // namespace image_fetcher
diff --git a/chromium/components/image_fetcher/ios/BUILD.gn b/chromium/components/image_fetcher/ios/BUILD.gn
index 88d514b151f..9ad5c7edc70 100644
--- a/chromium/components/image_fetcher/ios/BUILD.gn
+++ b/chromium/components/image_fetcher/ios/BUILD.gn
@@ -6,14 +6,18 @@ source_set("ios") {
sources = [
"ios_image_data_fetcher_wrapper.h",
"ios_image_data_fetcher_wrapper.mm",
+ "ios_image_decoder_impl.h",
+ "ios_image_decoder_impl.mm",
"webp_decoder.h",
"webp_decoder.mm",
]
deps = [
"//base",
- "//components/image_fetcher",
+ "//components/image_fetcher/core",
+ "//ios/web",
"//net",
"//third_party/libwebp:libwebp_dec",
+ "//ui/gfx",
]
configs += [ "//build/config/compiler:enable_arc" ]
}
@@ -22,6 +26,7 @@ source_set("unit_tests") {
testonly = true
sources = [
"ios_image_data_fetcher_wrapper_unittest.mm",
+ "ios_image_decoder_impl_unittest.mm",
"webp_decoder_unittest.mm",
]
deps = [
@@ -32,6 +37,7 @@ source_set("unit_tests") {
"//net:test_support",
"//testing/gmock",
"//testing/gtest",
+ "//ui/gfx",
]
configs += [ "//build/config/compiler:enable_arc" ]
}
diff --git a/chromium/components/image_fetcher/ios/DEPS b/chromium/components/image_fetcher/ios/DEPS
index d2f380fdf1b..dc46f3b0b57 100644
--- a/chromium/components/image_fetcher/ios/DEPS
+++ b/chromium/components/image_fetcher/ios/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+ios/web/public",
+ "+ui/gfx",
# Only WebP decoding is allowed (no encoding).
"+third_party/libwebp/webp/decode.h",
diff --git a/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h b/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h
index 4b6e0b67ef1..57806b0adba 100644
--- a/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h
+++ b/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h
@@ -9,7 +9,7 @@
#include "base/memory/ref_counted.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "components/image_fetcher/image_data_fetcher.h"
+#include "components/image_fetcher/core/image_data_fetcher.h"
namespace base {
class TaskRunner;
diff --git a/chromium/components/image_fetcher/ios/ios_image_decoder_impl.h b/chromium/components/image_fetcher/ios/ios_image_decoder_impl.h
new file mode 100644
index 00000000000..2bb5db145d5
--- /dev/null
+++ b/chromium/components/image_fetcher/ios/ios_image_decoder_impl.h
@@ -0,0 +1,23 @@
+// 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_IMAGE_FETCHER_IOS_IMAGE_DECODER_IMPL_H_
+#define COMPONENTS_IMAGE_FETCHER_IOS_IMAGE_DECODER_IMPL_H_
+
+#include "base/memory/ref_counted.h"
+#include "components/image_fetcher/core/image_decoder.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace image_fetcher {
+
+// Factory for iOS specific implementation of ImageDecoder.
+std::unique_ptr<ImageDecoder> CreateIOSImageDecoder(
+ scoped_refptr<base::TaskRunner> task_runner);
+
+} // namespace image_fetcher
+
+#endif // COMPONENTS_IMAGE_FETCHER_IOS_IMAGE_DECODER_IMPL_H_
diff --git a/chromium/components/image_fetcher/ios/ios_image_decoder_impl.mm b/chromium/components/image_fetcher/ios/ios_image_decoder_impl.mm
new file mode 100644
index 00000000000..ba32199f114
--- /dev/null
+++ b/chromium/components/image_fetcher/ios/ios_image_decoder_impl.mm
@@ -0,0 +1,106 @@
+// 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/image_fetcher/ios/ios_image_decoder_impl.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/callback.h"
+#import "base/mac/bind_objc_block.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#import "components/image_fetcher/ios/webp_decoder.h"
+#include "ios/web/public/web_thread.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace image_fetcher {
+
+class IOSImageDecoderImpl : public ImageDecoder {
+ public:
+ explicit IOSImageDecoderImpl(scoped_refptr<base::TaskRunner> task_runner);
+ ~IOSImageDecoderImpl() override;
+
+ // Note, that |desired_image_frame_size| is not supported
+ // (http://crbug/697596).
+ void DecodeImage(const std::string& image_data,
+ const gfx::Size& desired_image_frame_size,
+ const ImageDecodedCallback& callback) override;
+
+ private:
+ void CreateUIImageAndRunCallback(const ImageDecodedCallback& callback,
+ NSData* image_data);
+
+ // The task runner used to decode images if necessary.
+ const scoped_refptr<base::TaskRunner> task_runner_;
+
+ // The WeakPtrFactory is used to cancel callbacks if ImageFetcher is
+ // destroyed during WebP decoding.
+ base::WeakPtrFactory<IOSImageDecoderImpl> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(IOSImageDecoderImpl);
+};
+
+IOSImageDecoderImpl::IOSImageDecoderImpl(
+ scoped_refptr<base::TaskRunner> task_runner)
+ : task_runner_(std::move(task_runner)), weak_factory_(this) {
+ DCHECK(task_runner_.get());
+}
+
+IOSImageDecoderImpl::~IOSImageDecoderImpl() {}
+
+void IOSImageDecoderImpl::DecodeImage(const std::string& image_data,
+ const gfx::Size& desired_image_frame_size,
+ const ImageDecodedCallback& callback) {
+ // Convert the |image_data| std::string to an NSData buffer.
+ // The data is copied as it may have to outlive the caller in
+ // PostTaskAndReplyWithResult.
+ NSData* data =
+ [NSData dataWithBytes:image_data.data() length:image_data.size()];
+
+ // The WebP image format is not supported by iOS natively. Therefore WebP
+ // images need to be decoded explicitly,
+ if (webp_transcode::WebpDecoder::IsWebpImage(image_data)) {
+ base::PostTaskAndReplyWithResult(
+ task_runner_.get(), FROM_HERE, base::BindBlockArc(^NSData*() {
+ return webp_transcode::WebpDecoder::DecodeWebpImage(data);
+ }),
+ base::Bind(&IOSImageDecoderImpl::CreateUIImageAndRunCallback,
+ weak_factory_.GetWeakPtr(), callback));
+ } else {
+ CreateUIImageAndRunCallback(callback, data);
+ }
+}
+
+void IOSImageDecoderImpl::CreateUIImageAndRunCallback(
+ const ImageDecodedCallback& callback,
+ NSData* image_data) {
+ // Decode the image data using UIImage.
+ if (image_data) {
+ // "Most likely" always returns 1x images.
+ UIImage* ui_image = [UIImage imageWithData:image_data scale:1];
+ if (ui_image) {
+ // This constructor does not retain the image, but expects to take the
+ // ownership, therefore, |ui_image| is retained here, but not released
+ // afterwards.
+ gfx::Image gfx_image(ui_image, base::scoped_policy::RETAIN);
+ callback.Run(gfx_image);
+ return;
+ }
+ }
+ gfx::Image empty_image;
+ callback.Run(empty_image);
+}
+
+std::unique_ptr<ImageDecoder> CreateIOSImageDecoder(
+ scoped_refptr<base::TaskRunner> task_runner) {
+ return base::MakeUnique<IOSImageDecoderImpl>(std::move(task_runner));
+}
+
+} // namespace image_fetcher
diff --git a/chromium/components/image_fetcher/ios/ios_image_decoder_impl_unittest.mm b/chromium/components/image_fetcher/ios/ios_image_decoder_impl_unittest.mm
new file mode 100644
index 00000000000..b83a127b3aa
--- /dev/null
+++ b/chromium/components/image_fetcher/ios/ios_image_decoder_impl_unittest.mm
@@ -0,0 +1,112 @@
+// Copyright 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.
+
+#include "components/image_fetcher/ios/ios_image_decoder_impl.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+static unsigned char kJPGImage[] = {
+ 255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 1, 0,
+ 72, 0, 72, 0, 0, 255, 254, 0, 19, 67, 114, 101, 97, 116, 101,
+ 100, 32, 119, 105, 116, 104, 32, 71, 73, 77, 80, 255, 219, 0, 67,
+ 0, 5, 3, 4, 4, 4, 3, 5, 4, 4, 4, 5, 5, 5, 6,
+ 7, 12, 8, 7, 7, 7, 7, 15, 11, 11, 9, 12, 17, 15, 18,
+ 18, 17, 15, 17, 17, 19, 22, 28, 23, 19, 20, 26, 21, 17, 17,
+ 24, 33, 24, 26, 29, 29, 31, 31, 31, 19, 23, 34, 36, 34, 30,
+ 36, 28, 30, 31, 30, 255, 219, 0, 67, 1, 5, 5, 5, 7, 6,
+ 7, 14, 8, 8, 14, 30, 20, 17, 20, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 255,
+ 192, 0, 17, 8, 0, 1, 0, 1, 3, 1, 34, 0, 2, 17, 1,
+ 3, 17, 1, 255, 196, 0, 21, 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 255, 196, 0, 20,
+ 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 255, 196, 0, 20, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 196, 0, 20, 17,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 255, 218, 0, 12, 3, 1, 0, 2, 17, 3, 17, 0, 63,
+ 0, 178, 192, 7, 255, 217};
+
+static unsigned char kWEBPImage[] = {
+ 82, 73, 70, 70, 74, 0, 0, 0, 87, 69, 66, 80, 86, 80, 56, 88, 10,
+ 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 76, 80, 72,
+ 12, 0, 0, 0, 1, 7, 16, 17, 253, 15, 68, 68, 255, 3, 0, 0, 86,
+ 80, 56, 32, 24, 0, 0, 0, 48, 1, 0, 157, 1, 42, 1, 0, 1, 0,
+ 3, 0, 52, 37, 164, 0, 3, 112, 0, 254, 251, 253, 80, 0};
+
+} // namespace
+
+namespace image_fetcher {
+
+class IOSImageDecoderImplTest : public PlatformTest {
+ public:
+ void OnImageDecoded(const gfx::Image& image) { decoded_image_ = image; }
+
+ protected:
+ IOSImageDecoderImplTest()
+ : pool_(new base::SequencedWorkerPool(2,
+ "TestPool",
+ base::TaskPriority::USER_VISIBLE)) {
+ ios_image_decoder_impl_ = CreateIOSImageDecoder(pool_);
+ }
+
+ ~IOSImageDecoderImplTest() override { pool_->Shutdown(); }
+
+ base::MessageLoop loop_;
+ scoped_refptr<base::SequencedWorkerPool> pool_;
+ std::unique_ptr<ImageDecoder> ios_image_decoder_impl_;
+
+ gfx::Image decoded_image_;
+};
+
+TEST_F(IOSImageDecoderImplTest, JPGImage) {
+ ASSERT_TRUE(decoded_image_.IsEmpty());
+
+ std::string image_data =
+ std::string(reinterpret_cast<char*>(kJPGImage), sizeof(kJPGImage));
+ ios_image_decoder_impl_->DecodeImage(
+ image_data, gfx::Size(),
+ base::Bind(&IOSImageDecoderImplTest::OnImageDecoded,
+ base::Unretained(this)));
+
+ pool_->FlushForTesting();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(decoded_image_.IsEmpty());
+}
+
+TEST_F(IOSImageDecoderImplTest, WebpImage) {
+ ASSERT_TRUE(decoded_image_.IsEmpty());
+
+ std::string image_data =
+ std::string(reinterpret_cast<char*>(kWEBPImage), sizeof(kWEBPImage));
+ ios_image_decoder_impl_->DecodeImage(
+ image_data, gfx::Size(),
+ base::Bind(&IOSImageDecoderImplTest::OnImageDecoded,
+ base::Unretained(this)));
+
+ pool_->FlushForTesting();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(decoded_image_.IsEmpty());
+}
+
+} // namespace image_fetcher
diff --git a/chromium/components/image_fetcher/request_metadata.h b/chromium/components/image_fetcher/request_metadata.h
deleted file mode 100644
index 6b41e2d3c31..00000000000
--- a/chromium/components/image_fetcher/request_metadata.h
+++ /dev/null
@@ -1,24 +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_IMAGE_FETCHER_REQUEST_METADATA_H_
-#define COMPONENTS_IMAGE_FETCHER_REQUEST_METADATA_H_
-
-#include <string>
-
-namespace image_fetcher {
-
-// Metadata for a URL request.
-struct RequestMetadata {
- std::string mime_type;
- // HTTP response code.
- int response_code;
-};
-
-bool operator==(const RequestMetadata& lhs, const RequestMetadata& rhs);
-bool operator!=(const RequestMetadata& lhs, const RequestMetadata& rhs);
-
-} // namespace image_fetcher
-
-#endif // COMPONENTS_IMAGE_FETCHER_REQUEST_METADATA_H_
diff --git a/chromium/components/image_fetcher/request_metadata_unittest.cc b/chromium/components/image_fetcher/request_metadata_unittest.cc
deleted file mode 100644
index ba87ba08d8f..00000000000
--- a/chromium/components/image_fetcher/request_metadata_unittest.cc
+++ /dev/null
@@ -1,39 +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/image_fetcher/request_metadata.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace image_fetcher {
-
-TEST(RequestMetadataTest, Equality) {
- RequestMetadata rhs;
- RequestMetadata lhs;
- rhs.mime_type = "testMimeType";
- lhs.mime_type = "testMimeType";
- rhs.response_code = 1;
- lhs.response_code = 1;
-
- EXPECT_EQ(rhs, lhs);
-}
-
-TEST(RequestMetadataTest, NoEquality) {
- RequestMetadata rhs;
- RequestMetadata lhs;
- rhs.mime_type = "testMimeType";
- lhs.mime_type = "testMimeType";
- rhs.response_code = 1;
- lhs.response_code = 1;
-
- lhs.mime_type = "testOtherMimeType";
- EXPECT_NE(rhs, lhs);
- lhs.mime_type = "testMimeType";
-
- lhs.response_code = 2;
- EXPECT_NE(rhs, lhs);
- lhs.response_code = 1;
-}
-
-} // namespace image_fetcher
diff --git a/chromium/components/infobars/core/BUILD.gn b/chromium/components/infobars/core/BUILD.gn
index 4b5bf24eb66..103e359078f 100644
--- a/chromium/components/infobars/core/BUILD.gn
+++ b/chromium/components/infobars/core/BUILD.gn
@@ -34,6 +34,7 @@ static_library("core") {
"//base",
"//ui/base",
"//ui/gfx",
+ "//ui/gfx/animation",
"//ui/strings",
"//url",
]
diff --git a/chromium/components/infobars/core/infobar_delegate.cc b/chromium/components/infobars/core/infobar_delegate.cc
index 9f597fa1cfe..c3c0c97baf1 100644
--- a/chromium/components/infobars/core/infobar_delegate.cc
+++ b/chromium/components/infobars/core/infobar_delegate.cc
@@ -131,11 +131,6 @@ InfoBarDelegate::AsMediaStreamInfoBarDelegateAndroid() {
return nullptr;
}
-MediaThrottleInfoBarDelegate*
- InfoBarDelegate::AsMediaThrottleInfoBarDelegate() {
- return nullptr;
-}
-
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 1396e1673b5..c041844b9d4 100644
--- a/chromium/components/infobars/core/infobar_delegate.h
+++ b/chromium/components/infobars/core/infobar_delegate.h
@@ -23,7 +23,6 @@ class ThreeDAPIInfoBarDelegate;
#if defined(OS_ANDROID)
class MediaStreamInfoBarDelegateAndroid;
-class MediaThrottleInfoBarDelegate;
namespace offline_pages {
class OfflinePageInfoBarDelegate;
@@ -119,7 +118,7 @@ class InfoBarDelegate {
GOOGLE_API_KEYS_INFOBAR_DELEGATE = 45,
OBSOLETE_SYSTEM_INFOBAR_DELEGATE = 46,
SESSION_CRASHED_INFOBAR_DELEGATE = 47,
- WEBSITE_SETTINGS_INFOBAR_DELEGATE = 48,
+ PAGE_INFO_INFOBAR_DELEGATE = 48,
AUTOFILL_CC_INFOBAR_DELEGATE = 49,
TRANSLATE_INFOBAR_DELEGATE = 50,
IOS_CHROME_SAVE_PASSWORD_INFOBAR_DELEGATE = 51,
@@ -229,7 +228,6 @@ class InfoBarDelegate {
#if defined(OS_ANDROID)
virtual MediaStreamInfoBarDelegateAndroid*
AsMediaStreamInfoBarDelegateAndroid();
- virtual MediaThrottleInfoBarDelegate* AsMediaThrottleInfoBarDelegate();
virtual offline_pages::OfflinePageInfoBarDelegate*
AsOfflinePageInfoBarDelegate();
#endif
diff --git a/chromium/components/json_schema/json_schema_validator_unittest_base.cc b/chromium/components/json_schema/json_schema_validator_unittest_base.cc
index eb60ebb289f..d96544c31d2 100644
--- a/chromium/components/json_schema/json_schema_validator_unittest_base.cc
+++ b/chromium/components/json_schema/json_schema_validator_unittest_base.cc
@@ -123,18 +123,16 @@ void JSONSchemaValidatorTestBase::TestStringPattern() {
schema->SetString(schema::kPattern, "foo+");
ExpectValid(TEST_SOURCE,
- std::unique_ptr<base::Value>(new base::StringValue("foo")).get(),
+ std::unique_ptr<base::Value>(new base::Value("foo")).get(),
schema.get(), NULL);
- ExpectValid(
- TEST_SOURCE,
- std::unique_ptr<base::Value>(new base::StringValue("foooooo")).get(),
- schema.get(), NULL);
- ExpectNotValid(
- TEST_SOURCE,
- std::unique_ptr<base::Value>(new base::StringValue("bar")).get(),
- schema.get(), NULL, std::string(),
- JSONSchemaValidator::FormatErrorMessage(
- JSONSchemaValidator::kStringPattern, "foo+"));
+ ExpectValid(TEST_SOURCE,
+ std::unique_ptr<base::Value>(new base::Value("foooooo")).get(),
+ schema.get(), NULL);
+ ExpectNotValid(TEST_SOURCE,
+ std::unique_ptr<base::Value>(new base::Value("bar")).get(),
+ schema.get(), NULL, std::string(),
+ JSONSchemaValidator::FormatErrorMessage(
+ JSONSchemaValidator::kStringPattern, "foo+"));
}
void JSONSchemaValidatorTestBase::TestEnum() {
@@ -142,7 +140,7 @@ void JSONSchemaValidatorTestBase::TestEnum() {
LoadDictionary("enum_schema.json"));
ExpectValid(TEST_SOURCE,
- std::unique_ptr<base::Value>(new base::StringValue("foo")).get(),
+ std::unique_ptr<base::Value>(new base::Value("foo")).get(),
schema.get(), NULL);
ExpectValid(TEST_SOURCE,
std::unique_ptr<base::Value>(new base::Value(42)).get(),
@@ -152,10 +150,9 @@ void JSONSchemaValidatorTestBase::TestEnum() {
schema.get(), NULL);
ExpectNotValid(
- TEST_SOURCE,
- std::unique_ptr<base::Value>(new base::StringValue("42")).get(),
+ TEST_SOURCE, std::unique_ptr<base::Value>(new base::Value("42")).get(),
schema.get(), NULL, std::string(), JSONSchemaValidator::kInvalidEnum);
- ExpectNotValid(TEST_SOURCE, base::Value::CreateNullValue().get(),
+ ExpectNotValid(TEST_SOURCE, base::MakeUnique<base::Value>().get(),
schema.get(), NULL, std::string(),
JSONSchemaValidator::kInvalidEnum);
}
@@ -164,7 +161,7 @@ void JSONSchemaValidatorTestBase::TestChoices() {
std::unique_ptr<base::DictionaryValue> schema(
LoadDictionary("choices_schema.json"));
- ExpectValid(TEST_SOURCE, base::Value::CreateNullValue().get(), schema.get(),
+ ExpectValid(TEST_SOURCE, base::MakeUnique<base::Value>().get(), schema.get(),
NULL);
ExpectValid(TEST_SOURCE,
std::unique_ptr<base::Value>(new base::Value(42)).get(),
@@ -175,8 +172,7 @@ void JSONSchemaValidatorTestBase::TestChoices() {
ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
ExpectNotValid(
- TEST_SOURCE,
- std::unique_ptr<base::Value>(new base::StringValue("foo")).get(),
+ TEST_SOURCE, std::unique_ptr<base::Value>(new base::Value("foo")).get(),
schema.get(), NULL, std::string(), JSONSchemaValidator::kInvalidChoice);
ExpectNotValid(
TEST_SOURCE, std::unique_ptr<base::Value>(new base::ListValue()).get(),
@@ -290,7 +286,7 @@ void JSONSchemaValidatorTestBase::TestObject() {
ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
instance->Remove("bar", NULL);
ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
- instance->Set("bar", base::Value::CreateNullValue());
+ instance->Set("bar", base::MakeUnique<base::Value>());
ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL,
"bar", JSONSchemaValidator::FormatErrorMessage(
JSONSchemaValidator::kInvalidType,
@@ -413,7 +409,7 @@ void JSONSchemaValidatorTestBase::TestArrayTuple() {
base::DictionaryValue* additional_properties = new base::DictionaryValue();
additional_properties->SetString(schema::kType, schema::kAny);
schema->Set(schema::kAdditionalProperties, additional_properties);
- instance->Set(0, new base::StringValue("42"));
+ instance->Set(0, new base::Value("42"));
instance->AppendString("anything");
ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
instance->Set(2, new base::ListValue());
@@ -437,7 +433,7 @@ void JSONSchemaValidatorTestBase::TestArrayTuple() {
ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
// TODO(aa): I think this is inconsistent with the handling of NULL+optional
// for objects.
- instance->Set(0, base::Value::CreateNullValue());
+ instance->Set(0, base::MakeUnique<base::Value>());
ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
instance->Set(0, new base::Value(42));
ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "0",
@@ -497,22 +493,21 @@ void JSONSchemaValidatorTestBase::TestString() {
schema->SetInteger(schema::kMaxLength, 10);
ExpectValid(TEST_SOURCE,
- std::unique_ptr<base::Value>(new base::StringValue("x")).get(),
+ std::unique_ptr<base::Value>(new base::Value("x")).get(),
+ schema.get(), NULL);
+ ExpectValid(TEST_SOURCE,
+ std::unique_ptr<base::Value>(new base::Value("xxxxxxxxxx")).get(),
schema.get(), NULL);
- ExpectValid(
- TEST_SOURCE,
- std::unique_ptr<base::Value>(new base::StringValue("xxxxxxxxxx")).get(),
- schema.get(), NULL);
ExpectNotValid(
TEST_SOURCE,
- std::unique_ptr<base::Value>(new base::StringValue(std::string())).get(),
+ std::unique_ptr<base::Value>(new base::Value(std::string())).get(),
schema.get(), NULL, std::string(),
JSONSchemaValidator::FormatErrorMessage(
JSONSchemaValidator::kStringMinLength, "1"));
ExpectNotValid(
TEST_SOURCE,
- std::unique_ptr<base::Value>(new base::StringValue("xxxxxxxxxxx")).get(),
+ std::unique_ptr<base::Value>(new base::Value("xxxxxxxxxxx")).get(),
schema.get(), NULL, std::string(),
JSONSchemaValidator::FormatErrorMessage(
JSONSchemaValidator::kStringMaxLength, "10"));
@@ -597,10 +592,9 @@ void JSONSchemaValidatorTestBase::TestTypeClassifier() {
new base::Value(pow(-2.0, DBL_MANT_DIG) * 2))
.get()));
- EXPECT_EQ(
- std::string(schema::kString),
- JSONSchemaValidator::GetJSONSchemaType(
- std::unique_ptr<base::Value>(new base::StringValue("foo")).get()));
+ EXPECT_EQ(std::string(schema::kString),
+ JSONSchemaValidator::GetJSONSchemaType(
+ std::unique_ptr<base::Value>(new base::Value("foo")).get()));
EXPECT_EQ(std::string(schema::kArray),
JSONSchemaValidator::GetJSONSchemaType(
std::unique_ptr<base::Value>(new base::ListValue()).get()));
@@ -610,7 +604,7 @@ void JSONSchemaValidatorTestBase::TestTypeClassifier() {
std::unique_ptr<base::Value>(new base::DictionaryValue()).get()));
EXPECT_EQ(std::string(schema::kNull),
JSONSchemaValidator::GetJSONSchemaType(
- base::Value::CreateNullValue().get()));
+ base::MakeUnique<base::Value>().get()));
}
void JSONSchemaValidatorTestBase::TestTypes() {
@@ -628,10 +622,9 @@ void JSONSchemaValidatorTestBase::TestTypes() {
schema.get(), NULL);
schema->SetString(schema::kType, schema::kString);
- ExpectValid(
- TEST_SOURCE,
- std::unique_ptr<base::Value>(new base::StringValue("foobar")).get(),
- schema.get(), NULL);
+ ExpectValid(TEST_SOURCE,
+ std::unique_ptr<base::Value>(new base::Value("foobar")).get(),
+ schema.get(), NULL);
schema->SetString(schema::kType, schema::kNumber);
ExpectValid(TEST_SOURCE,
@@ -677,7 +670,7 @@ void JSONSchemaValidatorTestBase::TestTypes() {
schema.get(), NULL);
schema->SetString(schema::kType, schema::kNull);
- ExpectValid(TEST_SOURCE, base::Value::CreateNullValue().get(), schema.get(),
+ ExpectValid(TEST_SOURCE, base::MakeUnique<base::Value>().get(), schema.get(),
NULL);
// not valid
@@ -690,7 +683,7 @@ void JSONSchemaValidatorTestBase::TestTypes() {
schema->SetString(schema::kType, schema::kObject);
ExpectNotValid(
- TEST_SOURCE, base::Value::CreateNullValue().get(), schema.get(), NULL,
+ TEST_SOURCE, base::MakeUnique<base::Value>().get(), schema.get(), NULL,
std::string(),
JSONSchemaValidator::FormatErrorMessage(JSONSchemaValidator::kInvalidType,
schema::kObject, schema::kNull));
@@ -712,8 +705,7 @@ void JSONSchemaValidatorTestBase::TestTypes() {
schema->SetString(schema::kType, schema::kNumber);
ExpectNotValid(
- TEST_SOURCE,
- std::unique_ptr<base::Value>(new base::StringValue("42")).get(),
+ TEST_SOURCE, std::unique_ptr<base::Value>(new base::Value("42")).get(),
schema.get(), NULL, std::string(),
JSONSchemaValidator::FormatErrorMessage(
JSONSchemaValidator::kInvalidType, schema::kNumber, schema::kString));
diff --git a/chromium/components/keyed_service/content/browser_context_dependency_manager.cc b/chromium/components/keyed_service/content/browser_context_dependency_manager.cc
index 2e441d99e43..fe134b96490 100644
--- a/chromium/components/keyed_service/content/browser_context_dependency_manager.cc
+++ b/chromium/components/keyed_service/content/browser_context_dependency_manager.cc
@@ -60,17 +60,15 @@ BrowserContextDependencyManager::
return will_create_browser_context_services_callbacks_.Add(callback);
}
-#ifndef NDEBUG
void BrowserContextDependencyManager::AssertBrowserContextWasntDestroyed(
- content::BrowserContext* context) {
+ content::BrowserContext* context) const {
DependencyManager::AssertContextWasntDestroyed(context);
}
-void BrowserContextDependencyManager::MarkBrowserContextLiveForTesting(
+void BrowserContextDependencyManager::MarkBrowserContextLive(
content::BrowserContext* context) {
- DependencyManager::MarkContextLiveForTesting(context);
+ DependencyManager::MarkContextLive(context);
}
-#endif // NDEBUG
// static
BrowserContextDependencyManager*
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 551a8229c02..0a6eb603e1e 100644
--- a/chromium/components/keyed_service/content/browser_context_dependency_manager.h
+++ b/chromium/components/keyed_service/content/browser_context_dependency_manager.h
@@ -68,19 +68,18 @@ class KEYED_SERVICE_EXPORT BrowserContextDependencyManager
RegisterWillCreateBrowserContextServicesCallbackForTesting(
const base::Callback<void(content::BrowserContext*)>& callback);
-#ifndef NDEBUG
- // Debugging assertion called as part of GetServiceForBrowserContext in debug
- // mode. This will NOTREACHED() whenever the user is trying to access a stale
- // BrowserContext*.
- void AssertBrowserContextWasntDestroyed(content::BrowserContext* context);
+ // Runtime assertion called as a part of GetServiceForBrowserContext() to
+ // check if |context| is considered stale. This will NOTREACHED() or
+ // base::debug::DumpWithoutCrashing() depending on the DCHECK_IS_ON() value.
+ void AssertBrowserContextWasntDestroyed(
+ content::BrowserContext* context) const;
// Marks |context| as live (i.e., not stale). This method can be called as a
// safeguard against |AssertBrowserContextWasntDestroyed()| checks going off
- // due to |context| aliasing a BrowserContext instance from a prior test
- // (i.e., 0xWhatever might be created, be destroyed, and then a new
- // BrowserContext object might be created at 0xWhatever).
- void MarkBrowserContextLiveForTesting(content::BrowserContext* context);
-#endif // NDEBUG
+ // due to |context| aliasing a BrowserContext instance from a prior
+ // construction (i.e., 0xWhatever might be created, be destroyed, and then a
+ // new BrowserContext object might be created at 0xWhatever).
+ void MarkBrowserContextLive(content::BrowserContext* context);
static BrowserContextDependencyManager* GetInstance();
diff --git a/chromium/components/keyed_service/content/browser_context_keyed_base_factory.cc b/chromium/components/keyed_service/content/browser_context_keyed_base_factory.cc
index fe461ffb8f0..7c2d8b797c5 100644
--- a/chromium/components/keyed_service/content/browser_context_keyed_base_factory.cc
+++ b/chromium/components/keyed_service/content/browser_context_keyed_base_factory.cc
@@ -18,12 +18,9 @@ BrowserContextKeyedBaseFactory::~BrowserContextKeyedBaseFactory() {
content::BrowserContext* BrowserContextKeyedBaseFactory::GetBrowserContextToUse(
content::BrowserContext* context) const {
+ // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse().
DCHECK(CalledOnValidThread());
-#ifndef NDEBUG
- AssertContextWasntDestroyed(context);
-#endif
-
// Safe default for the Incognito mode: no service.
if (context->IsOffTheRecord())
return NULL;
@@ -52,6 +49,7 @@ void BrowserContextKeyedBaseFactory::BrowserContextDestroyed(
base::SupportsUserData* BrowserContextKeyedBaseFactory::GetContextToUse(
base::SupportsUserData* context) const {
+ AssertContextWasntDestroyed(context);
return GetBrowserContextToUse(static_cast<content::BrowserContext*>(context));
}
diff --git a/chromium/components/keyed_service/content/browser_context_keyed_service_factory.cc b/chromium/components/keyed_service/content/browser_context_keyed_service_factory.cc
index f008d176167..38f6ca6158a 100644
--- a/chromium/components/keyed_service/content/browser_context_keyed_service_factory.cc
+++ b/chromium/components/keyed_service/content/browser_context_keyed_service_factory.cc
@@ -48,12 +48,9 @@ KeyedService* BrowserContextKeyedServiceFactory::GetServiceForBrowserContext(
content::BrowserContext*
BrowserContextKeyedServiceFactory::GetBrowserContextToUse(
content::BrowserContext* context) const {
+ // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse().
DCHECK(CalledOnValidThread());
-#ifndef NDEBUG
- AssertContextWasntDestroyed(context);
-#endif
-
// Safe default for Incognito mode: no service.
if (context->IsOffTheRecord())
return nullptr;
@@ -102,6 +99,7 @@ bool BrowserContextKeyedServiceFactory::IsOffTheRecord(
base::SupportsUserData* BrowserContextKeyedServiceFactory::GetContextToUse(
base::SupportsUserData* context) const {
+ AssertContextWasntDestroyed(context);
return GetBrowserContextToUse(static_cast<content::BrowserContext*>(context));
}
diff --git a/chromium/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc b/chromium/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc
index 03c99158b48..7778de8abee 100644
--- a/chromium/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc
+++ b/chromium/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc
@@ -49,12 +49,9 @@ RefcountedBrowserContextKeyedServiceFactory::GetServiceForBrowserContext(
content::BrowserContext*
RefcountedBrowserContextKeyedServiceFactory::GetBrowserContextToUse(
content::BrowserContext* context) const {
+ // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse().
DCHECK(CalledOnValidThread());
-#ifndef NDEBUG
- AssertContextWasntDestroyed(context);
-#endif
-
// Safe default for Incognito mode: no service.
if (context->IsOffTheRecord())
return nullptr;
@@ -97,6 +94,7 @@ bool RefcountedBrowserContextKeyedServiceFactory::IsOffTheRecord(
base::SupportsUserData*
RefcountedBrowserContextKeyedServiceFactory::GetContextToUse(
base::SupportsUserData* context) const {
+ AssertContextWasntDestroyed(context);
return GetBrowserContextToUse(static_cast<content::BrowserContext*>(context));
}
diff --git a/chromium/components/keyed_service/core/dependency_manager.cc b/chromium/components/keyed_service/core/dependency_manager.cc
index 3cc264beddd..093f40a82cf 100644
--- a/chromium/components/keyed_service/core/dependency_manager.cc
+++ b/chromium/components/keyed_service/core/dependency_manager.cc
@@ -5,6 +5,7 @@
#include "components/keyed_service/core/dependency_manager.h"
#include "base/bind.h"
+#include "base/debug/dump_without_crashing.h"
#include "base/logging.h"
#include "base/supports_user_data.h"
#include "components/keyed_service/core/keyed_service_base_factory.h"
@@ -50,9 +51,7 @@ void DependencyManager::RegisterPrefsForServices(
void DependencyManager::CreateContextServices(base::SupportsUserData* context,
bool is_testing_context) {
-#ifndef NDEBUG
- MarkContextLiveForTesting(context);
-#endif
+ MarkContextLive(context);
std::vector<DependencyNode*> construction_order;
if (!dependency_graph_.GetConstructionOrder(&construction_order)) {
@@ -92,10 +91,8 @@ void DependencyManager::DestroyContextServices(
factory->ContextShutdown(context);
}
-#ifndef NDEBUG
// The context is now dead to the rest of the program.
dead_context_pointers_.insert(context);
-#endif
for (auto* dependency_node : destruction_order) {
KeyedServiceBaseFactory* factory =
@@ -104,22 +101,26 @@ void DependencyManager::DestroyContextServices(
}
}
-#ifndef NDEBUG
void DependencyManager::AssertContextWasntDestroyed(
- base::SupportsUserData* context) {
+ base::SupportsUserData* 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(). "
<< "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()
}
}
-void DependencyManager::MarkContextLiveForTesting(
- base::SupportsUserData* context) {
+void DependencyManager::MarkContextLive(base::SupportsUserData* context) {
dead_context_pointers_.erase(context);
}
+#ifndef NDEBUG
namespace {
std::string KeyedServiceBaseFactoryGetNodeName(DependencyNode* node) {
diff --git a/chromium/components/keyed_service/core/dependency_manager.h b/chromium/components/keyed_service/core/dependency_manager.h
index 06e535737b5..32c1f646447 100644
--- a/chromium/components/keyed_service/core/dependency_manager.h
+++ b/chromium/components/keyed_service/core/dependency_manager.h
@@ -5,15 +5,12 @@
#ifndef COMPONENTS_KEYED_SERVICE_CORE_DEPENDENCY_MANAGER_H_
#define COMPONENTS_KEYED_SERVICE_CORE_DEPENDENCY_MANAGER_H_
+#include <set>
#include <string>
#include "components/keyed_service/core/dependency_graph.h"
#include "components/keyed_service/core/keyed_service_export.h"
-#ifndef NDEBUG
-#include <set>
-#endif
-
class KeyedServiceBaseFactory;
namespace base {
@@ -65,18 +62,19 @@ class KEYED_SERVICE_EXPORT DependencyManager {
// with it.
void DestroyContextServices(base::SupportsUserData* context);
-#ifndef NDEBUG
- // Debugging assertion called as part of GetServiceForContext() in debug
- // mode. This will NOTREACHED() whenever the |context| is considered stale.
- void AssertContextWasntDestroyed(base::SupportsUserData* 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.
+ void AssertContextWasntDestroyed(base::SupportsUserData* context) const;
// Marks |context| as live (i.e., not stale). This method can be called as a
// safeguard against |AssertContextWasntDestroyed()| checks going off due to
- // |context| aliasing am instance from a prior test (i.e., 0xWhatever might
- // be created, be destroyed, and then a new object might be created at
+ // |context| aliasing an instance from a prior construction (i.e., 0xWhatever
+ // might be created, be destroyed, and then a new object might be created at
// 0xWhatever).
- void MarkContextLiveForTesting(base::SupportsUserData* context);
+ void MarkContextLive(base::SupportsUserData* context);
+#ifndef NDEBUG
// Dumps service dependency graph as a Graphviz dot file |dot_file| with a
// title |top_level_name|. Helper for |DumpContextDependencies|.
void DumpDependenciesAsGraphviz(const std::string& top_level_name,
@@ -94,13 +92,11 @@ class KEYED_SERVICE_EXPORT DependencyManager {
DependencyGraph dependency_graph_;
-#ifndef NDEBUG
// A list of context objects that have gone through the Shutdown() phase.
// These pointers are most likely invalid, but we keep track of their
// locations in memory so we can nicely assert if we're asked to do anything
// with them.
std::set<base::SupportsUserData*> dead_context_pointers_;
-#endif // NDEBUG
};
#endif // COMPONENTS_KEYED_SERVICE_CORE_DEPENDENCY_MANAGER_H_
diff --git a/chromium/components/keyed_service/core/keyed_service_base_factory.cc b/chromium/components/keyed_service/core/keyed_service_base_factory.cc
index 9f0991d7d61..48643305759 100644
--- a/chromium/components/keyed_service/core/keyed_service_base_factory.cc
+++ b/chromium/components/keyed_service/core/keyed_service_base_factory.cc
@@ -79,19 +79,18 @@ KeyedServiceBaseFactory::GetAssociatedPrefRegistry(
return registry;
}
-#ifndef NDEBUG
void KeyedServiceBaseFactory::AssertContextWasntDestroyed(
base::SupportsUserData* context) const {
- DCHECK(CalledOnValidThread());
+ // TODO(crbug.com/701326): We should DCHECK(CalledOnValidThread()) here, but
+ // currently some code doesn't do service getting on the main thread.
+ // This needs to be fixed and DCHECK should be restored here.
dependency_manager_->AssertContextWasntDestroyed(context);
}
-void KeyedServiceBaseFactory::MarkContextLiveForTesting(
- base::SupportsUserData* context) {
+void KeyedServiceBaseFactory::MarkContextLive(base::SupportsUserData* context) {
DCHECK(CalledOnValidThread());
- dependency_manager_->MarkContextLiveForTesting(context);
+ dependency_manager_->MarkContextLive(context);
}
-#endif
bool KeyedServiceBaseFactory::ServiceIsCreatedWithContext() const {
return false;
diff --git a/chromium/components/keyed_service/core/keyed_service_base_factory.h b/chromium/components/keyed_service/core/keyed_service_base_factory.h
index 9e41dcf961d..ea9223b0af3 100644
--- a/chromium/components/keyed_service/core/keyed_service_base_factory.h
+++ b/chromium/components/keyed_service/core/keyed_service_base_factory.h
@@ -54,18 +54,16 @@ class KEYED_SERVICE_EXPORT KeyedServiceBaseFactory
// created by factories.
void DependsOn(KeyedServiceBaseFactory* rhs);
-#ifndef NDEBUG
- // Debugging assertion that will NOTREACHED() is |context| is considered
- // stale. Should be used by subclasses when accessing |context|.
+ // Runtime assertion to check if |context| is considered stale. Should be used
+ // by subclasses when accessing |context|.
void AssertContextWasntDestroyed(base::SupportsUserData* context) const;
// Marks |context| as live (i.e., not stale). This method can be called as a
// safeguard against |AssertContextWasntDestroyed()| checks going off due to
- // |context| aliasing am instance from a prior test (i.e., 0xWhatever might
- // be created, be destroyed, and then a new object might be created at
+ // |context| aliasing an instance from a prior construction (i.e., 0xWhatever
+ // might be created, be destroyed, and then a new object might be created at
// 0xWhatever).
- void MarkContextLiveForTesting(base::SupportsUserData* context);
-#endif
+ void MarkContextLive(base::SupportsUserData* context);
// Calls RegisterProfilePrefs() after doing house keeping required to work
// alongside RegisterUserPrefsOnContextForTest().
diff --git a/chromium/components/keyed_service/core/keyed_service_factory.cc b/chromium/components/keyed_service/core/keyed_service_factory.cc
index 938ddc5d41b..e93b14219e1 100644
--- a/chromium/components/keyed_service/core/keyed_service_factory.cc
+++ b/chromium/components/keyed_service/core/keyed_service_factory.cc
@@ -30,13 +30,11 @@ void KeyedServiceFactory::SetTestingFactory(
// destruction.
bool add_context = ArePreferencesSetOn(context);
-#ifndef NDEBUG
// Ensure that |context| is not marked as stale (e.g., due to it aliasing an
// instance that was destroyed in an earlier test) in order to avoid accesses
// to |context| in |BrowserContextShutdown| from causing
// |AssertBrowserContextWasntDestroyed| to raise an error.
- MarkContextLiveForTesting(context);
-#endif
+ MarkContextLive(context);
// We have to go through the shutdown and destroy mechanisms because there
// are unit tests that create a service on a context and then change the
diff --git a/chromium/components/keyed_service/core/refcounted_keyed_service_factory.cc b/chromium/components/keyed_service/core/refcounted_keyed_service_factory.cc
index 7c44c2ce389..7afecda34f6 100644
--- a/chromium/components/keyed_service/core/refcounted_keyed_service_factory.cc
+++ b/chromium/components/keyed_service/core/refcounted_keyed_service_factory.cc
@@ -28,6 +28,12 @@ void RefcountedKeyedServiceFactory::SetTestingFactory(
// destruction.
bool add_context = ArePreferencesSetOn(context);
+ // Ensure that |context| is not marked as stale (e.g., due to it aliasing an
+ // instance that was destroyed in an earlier test) in order to avoid accesses
+ // to |context| in |ContextShutdown| from causing
+ // |AssertBrowserContextWasntDestroyed| to raise an error.
+ MarkContextLive(context);
+
// We have to go through the shutdown and destroy mechanisms because there
// are unit tests that create a service on a context and then change the
// testing service mid-test.
diff --git a/chromium/components/keyed_service/ios/browser_state_context_converter.cc b/chromium/components/keyed_service/ios/browser_state_context_converter.cc
deleted file mode 100644
index 608bb559b5e..00000000000
--- a/chromium/components/keyed_service/ios/browser_state_context_converter.cc
+++ /dev/null
@@ -1,28 +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/keyed_service/ios/browser_state_context_converter.h"
-
-namespace {
-
-// Global BrowserStateContextConverter* instance, may be null.
-BrowserStateContextConverter* g_browser_state_context_converter = nullptr;
-
-} // namespace
-
-// static
-void BrowserStateContextConverter::SetInstance(
- BrowserStateContextConverter* instance) {
- g_browser_state_context_converter = instance;
-}
-
-BrowserStateContextConverter* BrowserStateContextConverter::GetInstance() {
- return g_browser_state_context_converter;
-}
-
-BrowserStateContextConverter::BrowserStateContextConverter() {
-}
-
-BrowserStateContextConverter::~BrowserStateContextConverter() {
-}
diff --git a/chromium/components/keyed_service/ios/browser_state_context_converter.h b/chromium/components/keyed_service/ios/browser_state_context_converter.h
deleted file mode 100644
index 7af647d4f41..00000000000
--- a/chromium/components/keyed_service/ios/browser_state_context_converter.h
+++ /dev/null
@@ -1,55 +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_KEYED_SERVICE_IOS_BROWSER_STATE_CONTEXT_CONVERTER_H_
-#define COMPONENTS_KEYED_SERVICE_IOS_BROWSER_STATE_CONTEXT_CONVERTER_H_
-
-#include "base/macros.h"
-
-namespace base {
-class SupportsUserData;
-}
-
-// BrowserStateContextConverter does safe conversion of base::SupportsUserData*
-// to web::BrowserState* or content::BrowserContext*.
-//
-// iOS code is still using BrowserContextKeyedServiceFactory and until the
-// conversion is complete — http://crbug.com/478763 — there is need to have
-// mixed dependency between BCKSF and BSKSF.
-//
-// The implementation has BrowserStateKeyedServiceFactory supporting a
-// BrowserContextDependencyManager as DependencyManager. Thus the context
-// parameter passed to the BrowserStateKeyedServiceFactory can either be
-// content::BrowserContext if the method is invoked by DependencyManager
-// or web::BrowserState if the method is invoked via the type-safe public
-// API.
-//
-// The public API of BrowserStateKeyedServiceFactory is type-safe (all
-// public method receive web::BrowserState for context object), so only
-// methods that take a base::SupportsUserData need to discriminate
-// between the two objects.
-class BrowserStateContextConverter {
- public:
- // Sets/Gets the global BrowserStateContextConverter instance. May return null
- // when mixed dependencies are disabled.
- static void SetInstance(BrowserStateContextConverter* instance);
- static BrowserStateContextConverter* GetInstance();
-
- // Converts |context| to a web::BrowserState* and returns it casted as a
- // base::SupportsUserData*.
- virtual base::SupportsUserData* GetBrowserStateForContext(
- base::SupportsUserData* context) = 0;
- // Converts |context| to a content::BrowserContext* and returns it casted as a
- // base::SupportsUserData*.
- virtual base::SupportsUserData* GetBrowserContextForContext(
- base::SupportsUserData* context) = 0;
-
- protected:
- BrowserStateContextConverter();
- virtual ~BrowserStateContextConverter();
-
- DISALLOW_COPY_AND_ASSIGN(BrowserStateContextConverter);
-};
-
-#endif // COMPONENTS_KEYED_SERVICE_IOS_BROWSER_STATE_CONTEXT_CONVERTER_H_
diff --git a/chromium/components/keyed_service/ios/browser_state_dependency_manager.cc b/chromium/components/keyed_service/ios/browser_state_dependency_manager.cc
index fb313ae3d99..7dcc8d9a720 100644
--- a/chromium/components/keyed_service/ios/browser_state_dependency_manager.cc
+++ b/chromium/components/keyed_service/ios/browser_state_dependency_manager.cc
@@ -34,17 +34,15 @@ void BrowserStateDependencyManager::DestroyBrowserStateServices(
DependencyManager::DestroyContextServices(context);
}
-#ifndef NDEBUG
void BrowserStateDependencyManager::AssertBrowserStateWasntDestroyed(
- web::BrowserState* context) {
+ web::BrowserState* context) const {
DependencyManager::AssertContextWasntDestroyed(context);
}
-void BrowserStateDependencyManager::MarkBrowserStateLiveForTesting(
+void BrowserStateDependencyManager::MarkBrowserStateLive(
web::BrowserState* context) {
- DependencyManager::MarkContextLiveForTesting(context);
+ DependencyManager::MarkContextLive(context);
}
-#endif // NDEBUG
BrowserStateDependencyManager::BrowserStateDependencyManager() {
}
diff --git a/chromium/components/keyed_service/ios/browser_state_dependency_manager.h b/chromium/components/keyed_service/ios/browser_state_dependency_manager.h
index 649f16f2376..927f9a4e443 100644
--- a/chromium/components/keyed_service/ios/browser_state_dependency_manager.h
+++ b/chromium/components/keyed_service/ios/browser_state_dependency_manager.h
@@ -56,19 +56,17 @@ class KEYED_SERVICE_EXPORT BrowserStateDependencyManager
// associated with it.
void DestroyBrowserStateServices(web::BrowserState* context);
-#ifndef NDEBUG
- // Debugging assertion called as part of GetServiceForBrowserState in debug
- // mode. This will NOTREACHED() whenever the user is trying to access a stale
- // BrowserState*.
- void AssertBrowserStateWasntDestroyed(web::BrowserState* context);
+ // Runtime assertion called as a part of GetServiceForBrowserState() to check
+ // if |context| is considered stale. This will NOTREACHED() or
+ // base::debug::DumpWithoutCrashing() depending on the DCHECK_IS_ON() value.
+ void AssertBrowserStateWasntDestroyed(web::BrowserState* context) const;
// Marks |context| as live (i.e., not stale). This method can be called as a
// safeguard against |AssertBrowserStateWasntDestroyed()| checks going off
- // due to |context| aliasing a BrowserState instance from a prior test
+ // due to |context| aliasing a BrowserState instance from a prior construction
// (i.e., 0xWhatever might be created, be destroyed, and then a new
// BrowserState object might be created at 0xWhatever).
- void MarkBrowserStateLiveForTesting(web::BrowserState* context);
-#endif // NDEBUG
+ void MarkBrowserStateLive(web::BrowserState* context);
private:
friend struct base::DefaultSingletonTraits<BrowserStateDependencyManager>;
diff --git a/chromium/components/keyed_service/ios/browser_state_keyed_service_factory.cc b/chromium/components/keyed_service/ios/browser_state_keyed_service_factory.cc
index a981c3d83db..105e6992ce4 100644
--- a/chromium/components/keyed_service/ios/browser_state_keyed_service_factory.cc
+++ b/chromium/components/keyed_service/ios/browser_state_keyed_service_factory.cc
@@ -42,12 +42,9 @@ KeyedService* BrowserStateKeyedServiceFactory::GetServiceForBrowserState(
web::BrowserState* BrowserStateKeyedServiceFactory::GetBrowserStateToUse(
web::BrowserState* context) const {
+ // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse().
DCHECK(CalledOnValidThread());
-#ifndef NDEBUG
- AssertContextWasntDestroyed(context);
-#endif
-
// Safe default for Incognito mode: no service.
if (context->IsOffTheRecord())
return nullptr;
@@ -86,6 +83,7 @@ bool BrowserStateKeyedServiceFactory::IsOffTheRecord(
base::SupportsUserData* BrowserStateKeyedServiceFactory::GetContextToUse(
base::SupportsUserData* context) const {
+ AssertContextWasntDestroyed(context);
return GetBrowserStateToUse(static_cast<web::BrowserState*>(context));
}
diff --git a/chromium/components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.cc b/chromium/components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.cc
index a1cb827db05..a9abd88e526 100644
--- a/chromium/components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.cc
+++ b/chromium/components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.cc
@@ -49,12 +49,9 @@ RefcountedBrowserStateKeyedServiceFactory::GetServiceForBrowserState(
web::BrowserState*
RefcountedBrowserStateKeyedServiceFactory::GetBrowserStateToUse(
web::BrowserState* context) const {
+ // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse().
DCHECK(CalledOnValidThread());
-#ifndef NDEBUG
- AssertContextWasntDestroyed(context);
-#endif
-
// Safe default for Incognito mode: no service.
if (context->IsOffTheRecord())
return nullptr;
@@ -96,6 +93,7 @@ bool RefcountedBrowserStateKeyedServiceFactory::IsOffTheRecord(
base::SupportsUserData*
RefcountedBrowserStateKeyedServiceFactory::GetContextToUse(
base::SupportsUserData* context) const {
+ AssertContextWasntDestroyed(context);
return GetBrowserStateToUse(static_cast<web::BrowserState*>(context));
}
diff --git a/chromium/components/leveldb/env_mojo.cc b/chromium/components/leveldb/env_mojo.cc
index 82af93a9970..4f82181a5a3 100644
--- a/chromium/components/leveldb/env_mojo.cc
+++ b/chromium/components/leveldb/env_mojo.cc
@@ -9,8 +9,10 @@
#include <memory>
#include "base/strings/string_util.h"
+#include "base/task_scheduler/post_task.h"
#include "base/trace_event/trace_event.h"
#include "third_party/leveldatabase/chromium_logger.h"
+#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
namespace leveldb {
@@ -215,12 +217,32 @@ class MojoWritableFile : public leveldb::WritableFile {
DISALLOW_COPY_AND_ASSIGN(MojoWritableFile);
};
+class Thread : public base::PlatformThread::Delegate {
+ public:
+ Thread(void (*function)(void* arg), void* arg)
+ : function_(function), arg_(arg) {
+ base::PlatformThreadHandle handle;
+ bool success = base::PlatformThread::Create(0, this, &handle);
+ DCHECK(success);
+ }
+ ~Thread() override {}
+ void ThreadMain() override {
+ (*function_)(arg_);
+ delete this;
+ }
+
+ private:
+ void (*function_)(void* arg);
+ void* arg_;
+
+ DISALLOW_COPY_AND_ASSIGN(Thread);
+};
+
} // namespace
-MojoEnv::MojoEnv(const std::string& name,
- scoped_refptr<LevelDBMojoProxy> file_thread,
+MojoEnv::MojoEnv(scoped_refptr<LevelDBMojoProxy> file_thread,
LevelDBMojoProxy::OpaqueDir* dir)
- : ChromiumEnv(name), thread_(file_thread), dir_(dir) {}
+ : thread_(file_thread), dir_(dir) {}
MojoEnv::~MojoEnv() {
thread_->UnregisterDirectory(dir_);
@@ -249,7 +271,7 @@ Status MojoEnv::NewRandomAccessFile(const std::string& fname,
if (!f.IsValid()) {
*result = nullptr;
base::File::Error error_code = f.error_details();
- return MakeIOError(fname, FileErrorString(error_code),
+ return MakeIOError(fname, base::File::ErrorToString(error_code),
leveldb_env::kNewRandomAccessFile, error_code);
}
@@ -381,4 +403,21 @@ Status MojoEnv::NewLogger(const std::string& fname, Logger** result) {
}
}
+uint64_t MojoEnv::NowMicros() {
+ return base::TimeTicks::Now().ToInternalValue();
+}
+
+void MojoEnv::SleepForMicroseconds(int micros) {
+ // Round up to the next millisecond.
+ base::PlatformThread::Sleep(base::TimeDelta::FromMicroseconds(micros));
+}
+
+void MojoEnv::Schedule(void (*function)(void* arg), void* arg) {
+ base::PostTask(FROM_HERE, base::Bind(function, arg));
+}
+
+void MojoEnv::StartThread(void (*function)(void* arg), void* arg) {
+ new Thread(function, arg); // Will self-delete.
+}
+
} // namespace leveldb
diff --git a/chromium/components/leveldb/env_mojo.h b/chromium/components/leveldb/env_mojo.h
index d7848033243..8af9ef4aebc 100644
--- a/chromium/components/leveldb/env_mojo.h
+++ b/chromium/components/leveldb/env_mojo.h
@@ -7,7 +7,6 @@
#include "components/filesystem/public/interfaces/directory.mojom.h"
#include "components/leveldb/leveldb_mojo_proxy.h"
-#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/src/include/leveldb/env.h"
namespace leveldb {
@@ -17,14 +16,13 @@ namespace leveldb {
// synchronous and block on responses from the filesystem service. That's fine
// since, for the most part, they merely open files or check for a file's
// existence.
-class MojoEnv : public leveldb_env::ChromiumEnv {
+class MojoEnv : public leveldb::Env {
public:
- MojoEnv(const std::string& name,
- scoped_refptr<LevelDBMojoProxy> file_thread,
+ MojoEnv(scoped_refptr<LevelDBMojoProxy> file_thread,
LevelDBMojoProxy::OpaqueDir* dir);
~MojoEnv() override;
- // Overridden from leveldb_env::EnvChromium:
+ // Overridden from leveldb::Env:
Status NewSequentialFile(const std::string& fname,
SequentialFile** result) override;
Status NewRandomAccessFile(const std::string& fname,
@@ -46,8 +44,10 @@ class MojoEnv : public leveldb_env::ChromiumEnv {
Status GetTestDirectory(std::string* path) override;
Status NewLogger(const std::string& fname, Logger** result) override;
- // For reference, we specifically don't override Schedule(), StartThread(),
- // NowMicros() or SleepForMicroseconds() and use the EnvChromium versions.
+ uint64_t NowMicros() override;
+ void SleepForMicroseconds(int micros) override;
+ void Schedule(void (*function)(void* arg), void* arg) override;
+ void StartThread(void (*function)(void* arg), void* arg) override;
private:
scoped_refptr<LevelDBMojoProxy> thread_;
diff --git a/chromium/components/leveldb/leveldb_app.cc b/chromium/components/leveldb/leveldb_app.cc
index cb15293d59e..93086f77aa5 100644
--- a/chromium/components/leveldb/leveldb_app.cc
+++ b/chromium/components/leveldb/leveldb_app.cc
@@ -5,12 +5,13 @@
#include "components/leveldb/leveldb_app.h"
#include "components/leveldb/leveldb_service_impl.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
#include "services/service_manager/public/cpp/service_context.h"
namespace leveldb {
-LevelDBApp::LevelDBApp() : file_thread_("LevelDBFile") {}
+LevelDBApp::LevelDBApp() : file_thread_("LevelDBFile") {
+ registry_.AddInterface<mojom::LevelDBService>(this);
+}
LevelDBApp::~LevelDBApp() {}
@@ -18,10 +19,12 @@ void LevelDBApp::OnStart() {
tracing_.Initialize(context()->connector(), context()->identity().name());
}
-bool LevelDBApp::OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) {
- registry->AddInterface<mojom::LevelDBService>(this);
- return true;
+void LevelDBApp::OnBindInterface(
+ const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
}
void LevelDBApp::Create(const service_manager::Identity& remote_identity,
diff --git a/chromium/components/leveldb/leveldb_app.h b/chromium/components/leveldb/leveldb_app.h
index b69efe83a5c..1898f525984 100644
--- a/chromium/components/leveldb/leveldb_app.h
+++ b/chromium/components/leveldb/leveldb_app.h
@@ -10,6 +10,7 @@
#include "base/threading/thread.h"
#include "components/leveldb/public/interfaces/leveldb.mojom.h"
#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/interface_factory.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/tracing/public/cpp/provider.h"
@@ -26,8 +27,9 @@ class LevelDBApp
private:
// |Service| override:
void OnStart() override;
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
// |InterfaceFactory<mojom::LevelDBService>| implementation:
void Create(const service_manager::Identity& remote_identity,
@@ -35,6 +37,7 @@ class LevelDBApp
tracing::Provider tracing_;
std::unique_ptr<mojom::LevelDBService> service_;
+ service_manager::BinderRegistry registry_;
mojo::BindingSet<mojom::LevelDBService> bindings_;
base::Thread file_thread_;
diff --git a/chromium/components/leveldb/leveldb_service_impl.cc b/chromium/components/leveldb/leveldb_service_impl.cc
index e3fd368af17..2f754112c52 100644
--- a/chromium/components/leveldb/leveldb_service_impl.cc
+++ b/chromium/components/leveldb/leveldb_service_impl.cc
@@ -22,15 +22,10 @@ namespace leveldb {
LevelDBServiceImpl::LevelDBServiceImpl(
scoped_refptr<base::SingleThreadTaskRunner> file_task_runner)
- : thread_(new LevelDBMojoProxy(std::move(file_task_runner))),
- environment_name_("LevelDBEnv") {}
+ : thread_(new LevelDBMojoProxy(std::move(file_task_runner))) {}
LevelDBServiceImpl::~LevelDBServiceImpl() {}
-void LevelDBServiceImpl::SetEnvironmentName(const std::string& name) {
- environment_name_ = name;
-}
-
void LevelDBServiceImpl::Open(
filesystem::mojom::DirectoryPtr directory,
const std::string& dbname,
@@ -60,8 +55,7 @@ void LevelDBServiceImpl::OpenWithOptions(
LevelDBMojoProxy::OpaqueDir* dir =
thread_->RegisterDirectory(std::move(directory));
- std::unique_ptr<MojoEnv> env_mojo(
- new MojoEnv(environment_name_, thread_, dir));
+ std::unique_ptr<MojoEnv> env_mojo(new MojoEnv(thread_, dir));
options.env = env_mojo.get();
leveldb::DB* db = nullptr;
@@ -107,8 +101,7 @@ void LevelDBServiceImpl::Destroy(filesystem::mojom::DirectoryPtr directory,
// Register our directory with the file thread.
LevelDBMojoProxy::OpaqueDir* dir =
thread_->RegisterDirectory(std::move(directory));
- std::unique_ptr<MojoEnv> env_mojo(
- new MojoEnv(environment_name_, thread_, dir));
+ std::unique_ptr<MojoEnv> env_mojo(new MojoEnv(thread_, dir));
options.env = env_mojo.get();
callback.Run(LeveldbStatusToError(leveldb::DestroyDB(dbname, options)));
}
diff --git a/chromium/components/leveldb/leveldb_service_impl.h b/chromium/components/leveldb/leveldb_service_impl.h
index aca402228a5..3cc1210d2c1 100644
--- a/chromium/components/leveldb/leveldb_service_impl.h
+++ b/chromium/components/leveldb/leveldb_service_impl.h
@@ -23,7 +23,6 @@ class LevelDBServiceImpl : public mojom::LevelDBService {
~LevelDBServiceImpl() override;
// Overridden from LevelDBService:
- void SetEnvironmentName(const std::string& name) override;
void Open(filesystem::mojom::DirectoryPtr directory,
const std::string& dbname,
leveldb::mojom::LevelDBDatabaseAssociatedRequest database,
@@ -46,8 +45,6 @@ class LevelDBServiceImpl : public mojom::LevelDBService {
// and receive mojo message calls.
scoped_refptr<LevelDBMojoProxy> thread_;
- std::string environment_name_;
-
DISALLOW_COPY_AND_ASSIGN(LevelDBServiceImpl);
};
diff --git a/chromium/components/leveldb/public/interfaces/leveldb.mojom b/chromium/components/leveldb/public/interfaces/leveldb.mojom
index 68062c0c322..11e56709553 100644
--- a/chromium/components/leveldb/public/interfaces/leveldb.mojom
+++ b/chromium/components/leveldb/public/interfaces/leveldb.mojom
@@ -62,11 +62,6 @@ struct OpenOptions {
// Service which hands out databases.
interface LevelDBService {
- // Sets the name of the environment to a custom value. This is used for any
- // databases opened after calling this method to name UMA histograms and to
- // name the background thread that might get started.
- SetEnvironmentName(string name);
-
// Open the database with the specified "name" in the specified "directory".
// Fails if the database doesn't already exist.
Open(filesystem.mojom.Directory directory,
diff --git a/chromium/components/login/BUILD.gn b/chromium/components/login/BUILD.gn
index 22249304a8c..00c322080b1 100644
--- a/chromium/components/login/BUILD.gn
+++ b/chromium/components/login/BUILD.gn
@@ -10,6 +10,8 @@ component("login") {
"localized_values_builder.h",
"screens/screen_context.cc",
"screens/screen_context.h",
+ "secure_module_util_chromeos.cc",
+ "secure_module_util_chromeos.h",
]
defines = [ "LOGIN_IMPLEMENTATION" ]
diff --git a/chromium/components/login/base_screen_handler_utils.cc b/chromium/components/login/base_screen_handler_utils.cc
index 89c2cf40716..fe1851bdffc 100644
--- a/chromium/components/login/base_screen_handler_utils.cc
+++ b/chromium/components/login/base_screen_handler_utils.cc
@@ -84,16 +84,16 @@ base::Value MakeValue(double v) {
return base::Value(v);
}
-base::StringValue MakeValue(const std::string& v) {
- return base::StringValue(v);
+base::Value MakeValue(const std::string& v) {
+ return base::Value(v);
}
-base::StringValue MakeValue(const base::string16& v) {
- return base::StringValue(v);
+base::Value MakeValue(const base::string16& v) {
+ return base::Value(v);
}
-base::StringValue MakeValue(const AccountId& v) {
- return base::StringValue(v.Serialize());
+base::Value MakeValue(const AccountId& v) {
+ return base::Value(v.Serialize());
}
ParsedValueContainer<AccountId>::ParsedValueContainer() {
diff --git a/chromium/components/login/base_screen_handler_utils.h b/chromium/components/login/base_screen_handler_utils.h
index e6a6e645edd..fbb74d35d0f 100644
--- a/chromium/components/login/base_screen_handler_utils.h
+++ b/chromium/components/login/base_screen_handler_utils.h
@@ -56,9 +56,9 @@ inline bool GetArg(const base::ListValue* args, size_t index, T* out_value) {
base::Value LOGIN_EXPORT MakeValue(bool v);
base::Value LOGIN_EXPORT MakeValue(int v);
base::Value LOGIN_EXPORT MakeValue(double v);
-base::StringValue LOGIN_EXPORT MakeValue(const std::string& v);
-base::StringValue LOGIN_EXPORT MakeValue(const base::string16& v);
-base::StringValue LOGIN_EXPORT MakeValue(const AccountId& v);
+base::Value LOGIN_EXPORT MakeValue(const std::string& v);
+base::Value LOGIN_EXPORT MakeValue(const base::string16& v);
+base::Value LOGIN_EXPORT MakeValue(const AccountId& v);
template <typename T>
inline const T& MakeValue(const T& v) {
diff --git a/chromium/components/login/screens/screen_context.cc b/chromium/components/login/screens/screen_context.cc
index 4021855c257..5e170b682d8 100644
--- a/chromium/components/login/screens/screen_context.cc
+++ b/chromium/components/login/screens/screen_context.cc
@@ -44,11 +44,11 @@ bool ScreenContext::SetDouble(const KeyType& key, double value) {
}
bool ScreenContext::SetString(const KeyType& key, const std::string& value) {
- return Set(key, new base::StringValue(value));
+ return Set(key, new base::Value(value));
}
bool ScreenContext::SetString(const KeyType& key, const base::string16& value) {
- return Set(key, new base::StringValue(value));
+ return Set(key, new base::Value(value));
}
bool ScreenContext::SetStringList(const KeyType& key, const StringList& value) {
diff --git a/chromium/components/login/secure_module_util_chromeos.cc b/chromium/components/login/secure_module_util_chromeos.cc
new file mode 100644
index 00000000000..9e9d57a2f4d
--- /dev/null
+++ b/chromium/components/login/secure_module_util_chromeos.cc
@@ -0,0 +1,50 @@
+// 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/login/secure_module_util_chromeos.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/task_scheduler/post_task.h"
+
+namespace login {
+
+namespace {
+
+// If either of these two files exist, then we are using Cr50 and not using TPM.
+constexpr char kCr50UsedIndicatorFile1[] =
+ "/opt/google/cr50/firmware/cr50.bin.prod";
+constexpr char kCr50UsedIndicatorFile2[] = "/etc/init/cr50-update.conf";
+
+SecureModuleUsed g_secure_module_used = SecureModuleUsed::UNQUERIED;
+
+SecureModuleUsed GetSecureModuleInfoFromFilesAndCacheIt() {
+ if (base::PathExists(base::FilePath(kCr50UsedIndicatorFile1)) ||
+ base::PathExists(base::FilePath(kCr50UsedIndicatorFile2))) {
+ g_secure_module_used = SecureModuleUsed::CR50;
+ } else {
+ g_secure_module_used = SecureModuleUsed::TPM;
+ }
+ return g_secure_module_used;
+}
+
+} // namespace
+
+void GetSecureModuleUsed(GetSecureModuleUsedCallback callback) {
+ if (g_secure_module_used != SecureModuleUsed::UNQUERIED) {
+ base::ResetAndReturn(&callback).Run(g_secure_module_used);
+ return;
+ }
+
+ base::PostTaskWithTraitsAndReplyWithResult(
+ FROM_HERE,
+ base::TaskTraits().MayBlock().WithPriority(
+ base::TaskPriority::BACKGROUND),
+ base::BindOnce(&GetSecureModuleInfoFromFilesAndCacheIt),
+ std::move(callback));
+}
+
+} // namespace login
diff --git a/chromium/components/login/secure_module_util_chromeos.h b/chromium/components/login/secure_module_util_chromeos.h
new file mode 100644
index 00000000000..424e2bb412f
--- /dev/null
+++ b/chromium/components/login/secure_module_util_chromeos.h
@@ -0,0 +1,29 @@
+// 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_LOGIN_SECURE_MODULE_UTIL_H_
+#define COMPONENTS_LOGIN_SECURE_MODULE_UTIL_H_
+
+#include "base/callback.h"
+#include "components/login/login_export.h"
+
+namespace login {
+
+enum class SecureModuleUsed {
+ UNQUERIED,
+ CR50,
+ TPM,
+};
+
+// Receives one argument which contains the type of secure module we are using.
+using GetSecureModuleUsedCallback =
+ base::OnceCallback<void(SecureModuleUsed secure_module)>;
+
+// Gets the secure module by checking for certain files on the filesystem or in
+// the cache. |callback| is called with type of secure module we are using.
+void LOGIN_EXPORT GetSecureModuleUsed(GetSecureModuleUsedCallback callback);
+
+} // namespace login
+
+#endif // COMPONENTS_LOGIN_SECURE_MODULE_UTIL_H_
diff --git a/chromium/components/memory_pressure/direct_memory_pressure_calculator_win.cc b/chromium/components/memory_pressure/direct_memory_pressure_calculator_win.cc
index f393b7cf54f..48ae41e6477 100644
--- a/chromium/components/memory_pressure/direct_memory_pressure_calculator_win.cc
+++ b/chromium/components/memory_pressure/direct_memory_pressure_calculator_win.cc
@@ -65,7 +65,7 @@ DirectMemoryPressureCalculator::CalculateCurrentPressureLevel() {
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
// How much system memory is actively available for use right now, in MBs.
- int phys_free = mem_info.free / kKBperMB;
+ int phys_free = mem_info.avail_phys / kKBperMB;
// TODO(chrisha): This should eventually care about address space pressure,
// but the browser process (where this is running) effectively never runs out
diff --git a/chromium/components/memory_pressure/direct_memory_pressure_calculator_win_unittest.cc b/chromium/components/memory_pressure/direct_memory_pressure_calculator_win_unittest.cc
index c7c48e6f199..a8f0ec5aafc 100644
--- a/chromium/components/memory_pressure/direct_memory_pressure_calculator_win_unittest.cc
+++ b/chromium/components/memory_pressure/direct_memory_pressure_calculator_win_unittest.cc
@@ -59,8 +59,8 @@ class TestDirectMemoryPressureCalculator
// |total| is set in the constructor and not modified.
// Set the amount of free memory.
- mem_info_.free = phys_left_mb * kKBperMB;
- DCHECK_LT(mem_info_.free, mem_info_.total);
+ mem_info_.avail_phys = phys_left_mb * kKBperMB;
+ DCHECK_LT(mem_info_.avail_phys, mem_info_.total);
}
void SetNone() { SetMemoryFree(moderate_threshold_mb() + 1); }
diff --git a/chromium/components/memory_pressure/memory_pressure_monitor_unittest.cc b/chromium/components/memory_pressure/memory_pressure_monitor_unittest.cc
index 139c19e1e0b..ac608bf7923 100644
--- a/chromium/components/memory_pressure/memory_pressure_monitor_unittest.cc
+++ b/chromium/components/memory_pressure/memory_pressure_monitor_unittest.cc
@@ -5,6 +5,7 @@
#include "components/memory_pressure/memory_pressure_monitor.h"
#include <memory>
+#include <utility>
#include "base/bind.h"
#include "base/task_runner.h"
@@ -35,10 +36,8 @@ using testing::_;
// counting confuses gmock.
class LenientMockTaskRunner {
public:
- MOCK_METHOD3(PostDelayedTask,
- bool(const tracked_objects::Location&,
- const base::Closure&,
- base::TimeDelta));
+ MOCK_METHOD2(PostDelayedTask,
+ bool(const tracked_objects::Location&, base::TimeDelta));
};
using MockTaskRunner = testing::StrictMock<LenientMockTaskRunner>;
@@ -49,9 +48,9 @@ class TaskRunnerProxy : public base::TaskRunner {
explicit TaskRunnerProxy(MockTaskRunner* mock) : mock_(mock) {}
bool RunsTasksOnCurrentThread() const override { return true; }
bool PostDelayedTask(const tracked_objects::Location& location,
- const base::Closure& closure,
+ base::OnceClosure closure,
base::TimeDelta delta) override {
- return mock_->PostDelayedTask(location, closure, delta);
+ return mock_->PostDelayedTask(location, delta);
}
private:
@@ -169,7 +168,7 @@ class MemoryPressureMonitorTest : public testing::Test {
// Sets expectations for tasks scheduled via |mock_task_runner_|.
void ExpectTaskPosted(int delay_ms) {
base::TimeDelta delay = base::TimeDelta::FromMilliseconds(delay_ms);
- EXPECT_CALL(mock_task_runner_, PostDelayedTask(_, _, delay))
+ EXPECT_CALL(mock_task_runner_, PostDelayedTask(_, delay))
.WillOnce(testing::Return(true));
}
diff --git a/chromium/components/metrics/BUILD.gn b/chromium/components/metrics/BUILD.gn
index 35b57624c6f..3852c12e5dd 100644
--- a/chromium/components/metrics/BUILD.gn
+++ b/chromium/components/metrics/BUILD.gn
@@ -35,6 +35,8 @@ static_library("metrics") {
"file_metrics_provider.h",
"histogram_encoder.cc",
"histogram_encoder.h",
+ "log_decoder.cc",
+ "log_decoder.h",
"log_store.h",
"machine_id_provider.h",
"machine_id_provider_stub.cc",
@@ -45,7 +47,6 @@ static_library("metrics") {
"metrics_log_manager.h",
"metrics_log_store.cc",
"metrics_log_store.h",
- "metrics_log_uploader.cc",
"metrics_log_uploader.h",
"metrics_pref_names.cc",
"metrics_pref_names.h",
@@ -53,8 +54,8 @@ static_library("metrics") {
"metrics_provider.h",
"metrics_reporting_default_state.cc",
"metrics_reporting_default_state.h",
- "metrics_reporting_scheduler.cc",
- "metrics_reporting_scheduler.h",
+ "metrics_reporting_service.cc",
+ "metrics_reporting_service.h",
"metrics_rotation_scheduler.cc",
"metrics_rotation_scheduler.h",
"metrics_scheduler.cc",
@@ -76,6 +77,8 @@ static_library("metrics") {
"persisted_logs_metrics.h",
"persisted_logs_metrics_impl.cc",
"persisted_logs_metrics_impl.h",
+ "reporting_service.cc",
+ "reporting_service.h",
"stability_metrics_helper.cc",
"stability_metrics_helper.h",
"stability_metrics_provider.cc",
@@ -325,7 +328,6 @@ source_set("unit_tests") {
"metrics_log_manager_unittest.cc",
"metrics_log_store_unittest.cc",
"metrics_log_unittest.cc",
- "metrics_reporting_scheduler_unittest.cc",
"metrics_service_unittest.cc",
"metrics_state_manager_unittest.cc",
"net/net_metrics_log_uploader_unittest.cc",
diff --git a/chromium/components/metrics/OWNERS b/chromium/components/metrics/OWNERS
index 236892ba623..3b1e0686f43 100644
--- a/chromium/components/metrics/OWNERS
+++ b/chromium/components/metrics/OWNERS
@@ -3,3 +3,5 @@ holte@chromium.org
isherman@chromium.org
mpearson@chromium.org
rkaplow@chromium.org
+
+# COMPONENT: Internals>Metrics
diff --git a/chromium/components/metrics/data_use_tracker.cc b/chromium/components/metrics/data_use_tracker.cc
index 6081facf5d6..94c50146bd1 100644
--- a/chromium/components/metrics/data_use_tracker.cc
+++ b/chromium/components/metrics/data_use_tracker.cc
@@ -54,7 +54,8 @@ void DataUseTracker::UpdateMetricsUsagePrefs(const std::string& service_name,
return;
UpdateUsagePref(prefs::kUserCellDataUse, message_size);
- if (service_name == "UMA")
+ // TODO(holte): Consider adding seperate tracking for UKM.
+ if (service_name == "UMA" || service_name == "UKM")
UpdateUsagePref(prefs::kUmaCellDataUse, message_size);
}
diff --git a/chromium/components/metrics/data_use_tracker_unittest.cc b/chromium/components/metrics/data_use_tracker_unittest.cc
index 3e3e73c268b..a271b5d4d25 100644
--- a/chromium/components/metrics/data_use_tracker_unittest.cc
+++ b/chromium/components/metrics/data_use_tracker_unittest.cc
@@ -21,10 +21,7 @@ const char kExpiredDateStr2[] = "2016-03-01";
class TestDataUsePrefService : public TestingPrefServiceSimple {
public:
- TestDataUsePrefService() {
- registry()->RegisterDictionaryPref(metrics::prefs::kUserCellDataUse);
- registry()->RegisterDictionaryPref(metrics::prefs::kUmaCellDataUse);
- }
+ TestDataUsePrefService() { DataUseTracker::RegisterPrefs(registry()); }
void ClearDataUsePrefs() {
ClearPref(metrics::prefs::kUserCellDataUse);
diff --git a/chromium/components/metrics/file_metrics_provider.cc b/chromium/components/metrics/file_metrics_provider.cc
index 27ba40b865d..d9a6a042c23 100644
--- a/chromium/components/metrics/file_metrics_provider.cc
+++ b/chromium/components/metrics/file_metrics_provider.cc
@@ -140,8 +140,10 @@ void FileMetricsProvider::RegisterSource(const base::FilePath& path,
source->prefs_key = prefs_key.as_string();
switch (source->type) {
- case SOURCE_HISTOGRAMS_ATOMIC_FILE:
case SOURCE_HISTOGRAMS_ACTIVE_FILE:
+ DCHECK(prefs_key.empty());
+ // fall through
+ case SOURCE_HISTOGRAMS_ATOMIC_FILE:
source->path = path;
break;
case SOURCE_HISTOGRAMS_ATOMIC_DIR:
@@ -334,10 +336,18 @@ FileMetricsProvider::AccessResult FileMetricsProvider::CheckAndMapMetricSource(
return ACCESS_RESULT_INVALID_CONTENTS;
}
- // Create an allocator for the mapped file. Ownership passes to the allocator.
- source->allocator.reset(new base::PersistentHistogramAllocator(
+ // Map the file and validate it.
+ std::unique_ptr<base::PersistentMemoryAllocator> memory_allocator =
base::MakeUnique<base::FilePersistentMemoryAllocator>(
- std::move(mapped), 0, 0, base::StringPiece(), read_only)));
+ std::move(mapped), 0, 0, base::StringPiece(), read_only);
+ if (memory_allocator->GetMemoryState() ==
+ base::PersistentMemoryAllocator::MEMORY_DELETED) {
+ return ACCESS_RESULT_MEMORY_DELETED;
+ }
+
+ // Create an allocator for the mapped file. Ownership passes to the allocator.
+ source->allocator = base::MakeUnique<base::PersistentHistogramAllocator>(
+ std::move(memory_allocator));
return ACCESS_RESULT_SUCCESS;
}
diff --git a/chromium/components/metrics/file_metrics_provider.h b/chromium/components/metrics/file_metrics_provider.h
index 080a8211dd2..43d4d304dea 100644
--- a/chromium/components/metrics/file_metrics_provider.h
+++ b/chromium/components/metrics/file_metrics_provider.h
@@ -90,8 +90,9 @@ class FileMetricsProvider : public MetricsProvider,
// within that directory are used. Because some metadata may need to persist
// across process restarts, preferences entries are used based on the
// |prefs_key| name. Call RegisterPrefs() with the same name to create the
- // necessary keys in advance. Set |prefs_key| empty if no persistence is
- // required.
+ // necessary keys in advance. Set |prefs_key| empty (nullptr will work) if
+ // no persistence is required. ACTIVE files shouldn't have a pref key as
+ // they update internal state about what has been previously sent.
void RegisterSource(const base::FilePath& path,
SourceType type,
SourceAssociation source_association,
@@ -129,6 +130,9 @@ class FileMetricsProvider : public MetricsProvider,
// File could not be opened.
ACCESS_RESULT_NO_OPEN,
+ // File contents were internally deleted.
+ ACCESS_RESULT_MEMORY_DELETED,
+
ACCESS_RESULT_MAX
};
diff --git a/chromium/components/metrics/file_metrics_provider_unittest.cc b/chromium/components/metrics/file_metrics_provider_unittest.cc
index 11977099c3e..9781cea05a3 100644
--- a/chromium/components/metrics/file_metrics_provider_unittest.cc
+++ b/chromium/components/metrics/file_metrics_provider_unittest.cc
@@ -372,10 +372,9 @@ TEST_P(FileMetricsProviderTest, AccessReadWriteMetrics) {
base::GlobalHistogramAllocator::ReleaseForTesting();
// Register the file and allow the "checker" task to run.
- provider()->RegisterSource(metrics_file(),
- FileMetricsProvider::SOURCE_HISTOGRAMS_ACTIVE_FILE,
- FileMetricsProvider::ASSOCIATE_CURRENT_RUN,
- kMetricsName);
+ provider()->RegisterSource(
+ metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ACTIVE_FILE,
+ FileMetricsProvider::ASSOCIATE_CURRENT_RUN, nullptr);
// Record embedded snapshots via snapshot-manager.
OnDidCreateMetricsLog();
diff --git a/chromium/components/metrics/leak_detector/leak_detector.h b/chromium/components/metrics/leak_detector/leak_detector.h
index de5d40f900e..fb208990f39 100644
--- a/chromium/components/metrics/leak_detector/leak_detector.h
+++ b/chromium/components/metrics/leak_detector/leak_detector.h
@@ -23,7 +23,7 @@
namespace base {
template <typename T>
-struct DefaultLazyInstanceTraits;
+struct LazyInstanceTraitsBase;
}
namespace metrics {
@@ -86,7 +86,7 @@ class LeakDetector {
void RemoveObserver(Observer* observer);
private:
- friend base::DefaultLazyInstanceTraits<LeakDetector>;
+ friend base::LazyInstanceTraitsBase<LeakDetector>;
FRIEND_TEST_ALL_PREFIXES(LeakDetectorTest, NotifyObservers);
// Keep these private, as this class is meant to be initialized only through
diff --git a/chromium/components/metrics/log_decoder.cc b/chromium/components/metrics/log_decoder.cc
new file mode 100644
index 00000000000..1754c2717df
--- /dev/null
+++ b/chromium/components/metrics/log_decoder.cc
@@ -0,0 +1,16 @@
+// 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/metrics/log_decoder.h"
+
+#include "third_party/zlib/google/compression_utils.h"
+
+namespace metrics {
+
+bool DecodeLogData(const std::string& compressed_log_data,
+ std::string* log_data) {
+ return compression::GzipUncompress(compressed_log_data, log_data);
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/log_decoder.h b/chromium/components/metrics/log_decoder.h
new file mode 100644
index 00000000000..c85037f932c
--- /dev/null
+++ b/chromium/components/metrics/log_decoder.h
@@ -0,0 +1,21 @@
+// 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_METRICS_LOG_DECODER_H_
+#define COMPONENTS_METRICS_LOG_DECODER_H_
+
+#include <string>
+
+namespace metrics {
+
+// Other modules can call this function instead of directly calling gzip. This
+// prevents other modules from having to depend on zlib, or being aware of
+// metrics' use of gzip compression, which is a metrics implementation detail.
+// Returns true on success, false on failure.
+bool DecodeLogData(const std::string& compressed_log_data,
+ std::string* log_data);
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_LOG_DECODER_H_
diff --git a/chromium/components/metrics/metrics_log.cc b/chromium/components/metrics/metrics_log.cc
index ac35ce396a3..42331e3f15b 100644
--- a/chromium/components/metrics/metrics_log.cc
+++ b/chromium/components/metrics/metrics_log.cc
@@ -151,12 +151,7 @@ void MetricsLog::RecordCoreSystemProfile(MetricsServiceClient* client,
metrics::SystemProfileProto::Hardware* hardware =
system_profile->mutable_hardware();
-#if !defined(OS_IOS)
- // On iOS, OperatingSystemArchitecture() returns values like iPad4,4 which is
- // not the actual CPU architecture. Don't set it until the API is fixed. See
- // crbug.com/370104 for details.
hardware->set_cpu_architecture(base::SysInfo::OperatingSystemArchitecture());
-#endif
hardware->set_system_ram_mb(base::SysInfo::AmountOfPhysicalMemoryMB());
hardware->set_hardware_class(base::SysInfo::HardwareModelName());
#if defined(OS_WIN)
diff --git a/chromium/components/metrics/metrics_log_unittest.cc b/chromium/components/metrics/metrics_log_unittest.cc
index f1a7792f85d..63152c68ea9 100644
--- a/chromium/components/metrics/metrics_log_unittest.cc
+++ b/chromium/components/metrics/metrics_log_unittest.cc
@@ -196,9 +196,7 @@ TEST_F(MetricsLogTest, BasicRecord) {
#endif
metrics::SystemProfileProto::Hardware* hardware =
system_profile->mutable_hardware();
-#if !defined(OS_IOS)
hardware->set_cpu_architecture(base::SysInfo::OperatingSystemArchitecture());
-#endif
hardware->set_system_ram_mb(base::SysInfo::AmountOfPhysicalMemoryMB());
hardware->set_hardware_class(base::SysInfo::HardwareModelName());
#if defined(OS_WIN)
diff --git a/chromium/components/metrics/metrics_log_uploader.cc b/chromium/components/metrics/metrics_log_uploader.cc
deleted file mode 100644
index 0d67ced66c6..00000000000
--- a/chromium/components/metrics/metrics_log_uploader.cc
+++ /dev/null
@@ -1,22 +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/metrics/metrics_log_uploader.h"
-
-namespace metrics {
-
-MetricsLogUploader::MetricsLogUploader(
- const std::string& server_url,
- const std::string& mime_type,
- MetricServiceType service_type,
- const base::Callback<void(int)>& on_upload_complete)
- : server_url_(server_url),
- mime_type_(mime_type),
- service_type_(service_type),
- on_upload_complete_(on_upload_complete) {}
-
-MetricsLogUploader::~MetricsLogUploader() {
-}
-
-} // namespace metrics
diff --git a/chromium/components/metrics/metrics_log_uploader.h b/chromium/components/metrics/metrics_log_uploader.h
index bcc46626ad5..3fe7f5e3f5c 100644
--- a/chromium/components/metrics/metrics_log_uploader.h
+++ b/chromium/components/metrics/metrics_log_uploader.h
@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "base/strings/string_piece.h"
namespace metrics {
@@ -16,6 +17,10 @@ namespace metrics {
// of MetricsService.
class MetricsLogUploader {
public:
+ // Type for OnUploadComplete callbacks. These callbacks will receive two
+ // parameters: A response code and an net error code.
+ typedef base::Callback<void(int, int)> UploadCallback;
+
// Possible service types. This should correspond to a type from
// DataUseUserData.
enum MetricServiceType {
@@ -23,34 +28,13 @@ class MetricsLogUploader {
UKM,
};
- // Constructs the uploader that will upload logs to the specified |server_url|
- // with the given |mime_type|. The |service_type| marks which service the
- // data usage should be attributed to. The |on_upload_complete| callback will
- // be called with the HTTP response code of the upload or with -1 on an error.
- MetricsLogUploader(const std::string& server_url,
- const std::string& mime_type,
- MetricServiceType service_type,
- const base::Callback<void(int)>& on_upload_complete);
- virtual ~MetricsLogUploader();
+ virtual ~MetricsLogUploader() {}
// Uploads a log with the specified |compressed_log_data| and |log_hash|.
// |log_hash| is expected to be the hex-encoded SHA1 hash of the log data
// before compression.
virtual void UploadLog(const std::string& compressed_log_data,
const std::string& log_hash) = 0;
-
- protected:
- const std::string server_url_;
- const std::string mime_type_;
-
- // Which service type this uploads for. This is used for bandwidth
- // attribution.
- const MetricServiceType service_type_;
-
- const base::Callback<void(int)> on_upload_complete_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MetricsLogUploader);
};
} // namespace metrics
diff --git a/chromium/components/metrics/metrics_pref_names.cc b/chromium/components/metrics/metrics_pref_names.cc
index ea3fd3892ae..dbec00a0384 100644
--- a/chromium/components/metrics/metrics_pref_names.cc
+++ b/chromium/components/metrics/metrics_pref_names.cc
@@ -190,6 +190,10 @@ const char kUninstallMetricsPageLoadCount[] =
"uninstall_metrics.page_load_count";
const char kUninstallMetricsUptimeSec[] = "uninstall_metrics.uptime_sec";
+// Dictionary for measuring cellular data used by UKM service during last 7
+// days.
+const char kUkmCellDataUse[] = "user_experience_metrics.ukm_cell_datause";
+
// Dictionary for measuring cellular data used by UMA service during last 7
// days.
const char kUmaCellDataUse[] = "user_experience_metrics.uma_cell_datause";
diff --git a/chromium/components/metrics/metrics_pref_names.h b/chromium/components/metrics/metrics_pref_names.h
index a9188028bdf..5332512238b 100644
--- a/chromium/components/metrics/metrics_pref_names.h
+++ b/chromium/components/metrics/metrics_pref_names.h
@@ -65,6 +65,7 @@ extern const char kUninstallMetricsPageLoadCount[];
extern const char kUninstallMetricsUptimeSec[];
// For measuring data use for throttling UMA log uploads on cellular.
+extern const char kUkmCellDataUse[];
extern const char kUmaCellDataUse[];
extern const char kUserCellDataUse[];
diff --git a/chromium/components/metrics/metrics_reporting_scheduler.cc b/chromium/components/metrics/metrics_reporting_scheduler.cc
deleted file mode 100644
index 625d546fea2..00000000000
--- a/chromium/components/metrics/metrics_reporting_scheduler.cc
+++ /dev/null
@@ -1,175 +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/metrics/metrics_reporting_scheduler.h"
-
-#include <stdint.h>
-
-#include "base/compiler_specific.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/string_number_conversions.h"
-#include "build/build_config.h"
-#include "components/variations/variations_associated_data.h"
-
-using base::TimeDelta;
-
-namespace metrics {
-
-namespace {
-
-// The delay, in seconds, after startup before sending the first log message.
-#if defined(OS_ANDROID) || defined(OS_IOS)
-// Sessions are more likely to be short on a mobile device, so handle the
-// initial log quickly.
-const int kInitialUploadIntervalSeconds = 15;
-#else
-const int kInitialUploadIntervalSeconds = 60;
-#endif
-
-// The delay, in seconds, between uploading when there are queued logs from
-// previous sessions to send.
-#if defined(OS_ANDROID) || defined(OS_IOS)
-// Sending in a burst is better on a mobile device, since keeping the radio on
-// is very expensive.
-const int kUnsentLogsIntervalSeconds = 3;
-#else
-const int kUnsentLogsIntervalSeconds = 15;
-#endif
-
-// When uploading metrics to the server fails, we progressively wait longer and
-// longer before sending the next log. This backoff process helps reduce load
-// on a server that is having issues.
-// The following is the multiplier we use to expand that inter-log duration.
-const double kBackoffMultiplier = 1.1;
-
-// The maximum backoff multiplier.
-const int kMaxBackoffMultiplier = 10;
-
-} // anonymous namespace
-
-MetricsReportingScheduler::MetricsReportingScheduler(
- const base::Closure& upload_callback,
- const base::Callback<base::TimeDelta(void)>& upload_interval_callback)
- : upload_callback_(upload_callback),
- upload_interval_(TimeDelta::FromSeconds(kInitialUploadIntervalSeconds)),
- running_(false),
- callback_pending_(false),
- init_task_complete_(false),
- waiting_for_init_task_complete_(false),
- upload_interval_callback_(upload_interval_callback) {
-}
-
-MetricsReportingScheduler::~MetricsReportingScheduler() {}
-
-void MetricsReportingScheduler::Start() {
- running_ = true;
- ScheduleNextUpload();
-}
-
-void MetricsReportingScheduler::Stop() {
- running_ = false;
- if (upload_timer_.IsRunning())
- upload_timer_.Stop();
-}
-
-// Callback from MetricsService when the startup init task has completed.
-void MetricsReportingScheduler::InitTaskComplete() {
- DCHECK(!init_task_complete_);
- init_task_complete_ = true;
- if (waiting_for_init_task_complete_) {
- waiting_for_init_task_complete_ = false;
- TriggerUpload();
- } else {
- LogMetricsInitSequence(INIT_TASK_COMPLETED_FIRST);
- }
-}
-
-void MetricsReportingScheduler::UploadFinished(bool server_is_healthy,
- bool more_logs_remaining) {
- DCHECK(callback_pending_);
- callback_pending_ = false;
- // If the server is having issues, back off. Otherwise, reset to default
- // (unless there are more logs to send, in which case the next upload should
- // happen sooner).
- if (!server_is_healthy) {
- BackOffUploadInterval();
- } else if (more_logs_remaining) {
- upload_interval_ = TimeDelta::FromSeconds(kUnsentLogsIntervalSeconds);
- } else {
- upload_interval_ = GetStandardUploadInterval();
- last_upload_finish_time_ = base::TimeTicks::Now();
- }
-
- if (running_)
- ScheduleNextUpload();
-}
-
-void MetricsReportingScheduler::UploadCancelled() {
- DCHECK(callback_pending_);
- callback_pending_ = false;
- if (running_)
- ScheduleNextUpload();
-}
-
-void MetricsReportingScheduler::SetUploadIntervalForTesting(
- base::TimeDelta interval) {
- upload_interval_ = interval;
-}
-
-void MetricsReportingScheduler::LogMetricsInitSequence(InitSequence sequence) {
- UMA_HISTOGRAM_ENUMERATION("UMA.InitSequence", sequence,
- INIT_SEQUENCE_ENUM_SIZE);
-}
-
-void MetricsReportingScheduler::LogActualUploadInterval(TimeDelta interval) {
- UMA_HISTOGRAM_CUSTOM_COUNTS("UMA.ActualLogUploadInterval",
- interval.InMinutes(),
- 1,
- base::TimeDelta::FromHours(12).InMinutes(),
- 50);
-}
-
-void MetricsReportingScheduler::TriggerUpload() {
- // If the timer fired before the init task has completed, don't trigger the
- // upload yet - wait for the init task to complete and do it then.
- if (!init_task_complete_) {
- LogMetricsInitSequence(TIMER_FIRED_FIRST);
- waiting_for_init_task_complete_ = true;
- return;
- }
-
- if (!last_upload_finish_time_.is_null()) {
- LogActualUploadInterval(base::TimeTicks::Now() - last_upload_finish_time_);
- last_upload_finish_time_ = base::TimeTicks();
- }
-
- callback_pending_ = true;
- upload_callback_.Run();
-}
-
-void MetricsReportingScheduler::ScheduleNextUpload() {
- DCHECK(running_);
- if (upload_timer_.IsRunning() || callback_pending_)
- return;
-
- upload_timer_.Start(FROM_HERE, upload_interval_, this,
- &MetricsReportingScheduler::TriggerUpload);
-}
-
-void MetricsReportingScheduler::BackOffUploadInterval() {
- DCHECK_GT(kBackoffMultiplier, 1.0);
- upload_interval_ = TimeDelta::FromMicroseconds(static_cast<int64_t>(
- kBackoffMultiplier * upload_interval_.InMicroseconds()));
-
- TimeDelta max_interval = kMaxBackoffMultiplier * GetStandardUploadInterval();
- if (upload_interval_ > max_interval || upload_interval_.InSeconds() < 0) {
- upload_interval_ = max_interval;
- }
-}
-
-base::TimeDelta MetricsReportingScheduler::GetStandardUploadInterval() {
- return upload_interval_callback_.Run();
-}
-
-} // namespace metrics
diff --git a/chromium/components/metrics/metrics_reporting_scheduler.h b/chromium/components/metrics/metrics_reporting_scheduler.h
deleted file mode 100644
index e2a84634592..00000000000
--- a/chromium/components/metrics/metrics_reporting_scheduler.h
+++ /dev/null
@@ -1,113 +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_METRICS_METRICS_REPORTING_SCHEDULER_H_
-#define COMPONENTS_METRICS_METRICS_REPORTING_SCHEDULER_H_
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "components/metrics/net/network_metrics_provider.h"
-
-namespace metrics {
-
-// Scheduler task to drive a MetricsService object's uploading.
-// TODO(holte): Remove this once we've switched to split schedulers.
-class MetricsReportingScheduler {
- public:
- // Creates MetricsServiceScheduler object with the given |upload_callback|
- // callback to call when uploading should happen and
- // |upload_interval_callback| to determine the interval between uploads
- // in steady state.
- MetricsReportingScheduler(
- const base::Closure& upload_callback,
- const base::Callback<base::TimeDelta(void)>& upload_interval_callback);
- virtual ~MetricsReportingScheduler();
-
- // Starts scheduling uploads. This in a no-op if the scheduler is already
- // running, so it is safe to call more than once.
- void Start();
-
- // Stops scheduling uploads.
- void Stop();
-
- // Callback from MetricsService when the startup init task has completed.
- void InitTaskComplete();
-
- // Callback from MetricsService when a triggered upload finishes.
- void UploadFinished(bool server_is_healthy, bool more_logs_remaining);
-
- // Callback from MetricsService when a triggered upload is cancelled by the
- // MetricsService.
- void UploadCancelled();
-
- // Sets the upload interval to a specific value, exposed for unit tests.
- void SetUploadIntervalForTesting(base::TimeDelta interval);
-
- protected:
- enum InitSequence {
- TIMER_FIRED_FIRST,
- INIT_TASK_COMPLETED_FIRST,
- INIT_SEQUENCE_ENUM_SIZE,
- };
-
- private:
- // Record the init sequence order histogram.
- virtual void LogMetricsInitSequence(InitSequence sequence);
-
- // Record the upload interval time.
- virtual void LogActualUploadInterval(base::TimeDelta interval);
-
- // Timer callback indicating it's time for the MetricsService to upload
- // metrics.
- void TriggerUpload();
-
- // Schedules a future call to TriggerUpload if one isn't already pending.
- void ScheduleNextUpload();
-
- // Increases the upload interval each time it's called, to handle the case
- // where the server is having issues.
- void BackOffUploadInterval();
-
- // Returns upload interval to use in steady state.
- base::TimeDelta GetStandardUploadInterval();
-
- // The MetricsService method to call when uploading should happen.
- const base::Closure upload_callback_;
-
- base::OneShotTimer upload_timer_;
-
- // The interval between being told an upload is done and starting the next
- // upload.
- base::TimeDelta upload_interval_;
-
- // The tick count of the last time log upload has been finished and null if no
- // upload has been done yet.
- base::TimeTicks last_upload_finish_time_;
-
- // Indicates that the scheduler is running (i.e., that Start has been called
- // more recently than Stop).
- bool running_;
-
- // Indicates that the last triggered upload hasn't resolved yet.
- bool callback_pending_;
-
- // Whether the InitTaskComplete() callback has been called.
- bool init_task_complete_;
-
- // Whether the initial scheduled upload timer has fired before the init task
- // has been completed.
- bool waiting_for_init_task_complete_;
-
- // Callback function used to get the standard upload time.
- base::Callback<base::TimeDelta(void)> upload_interval_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(MetricsReportingScheduler);
-};
-
-} // namespace metrics
-
-#endif // COMPONENTS_METRICS_METRICS_REPORTING_SCHEDULER_H_
diff --git a/chromium/components/metrics/metrics_reporting_scheduler_unittest.cc b/chromium/components/metrics/metrics_reporting_scheduler_unittest.cc
deleted file mode 100644
index f5b9b5b0180..00000000000
--- a/chromium/components/metrics/metrics_reporting_scheduler_unittest.cc
+++ /dev/null
@@ -1,71 +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/metrics/metrics_reporting_scheduler.h"
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace metrics {
-
-class MetricsReportingSchedulerTest : public testing::Test {
- public:
- MetricsReportingSchedulerTest() : callback_call_count_(0) {}
- ~MetricsReportingSchedulerTest() override {}
-
- base::Closure GetCallback() {
- return base::Bind(&MetricsReportingSchedulerTest::SchedulerCallback,
- base::Unretained(this));
- }
-
- base::Callback<base::TimeDelta(void)> GetConnectionCallback() {
- return base::Bind(&MetricsReportingSchedulerTest::GetStandardUploadInterval,
- base::Unretained(this));
- }
-
- int callback_call_count() const { return callback_call_count_; }
-
- private:
- void SchedulerCallback() {
- ++callback_call_count_;
- }
-
- base::TimeDelta GetStandardUploadInterval() {
- return base::TimeDelta::FromMinutes(5);
- }
-
- int callback_call_count_;
-
- base::MessageLoopForUI message_loop_;
-
- DISALLOW_COPY_AND_ASSIGN(MetricsReportingSchedulerTest);
-};
-
-
-TEST_F(MetricsReportingSchedulerTest, InitTaskCompleteBeforeTimer) {
- MetricsReportingScheduler scheduler(GetCallback(), GetConnectionCallback());
- scheduler.SetUploadIntervalForTesting(base::TimeDelta());
- scheduler.InitTaskComplete();
- scheduler.Start();
- EXPECT_EQ(0, callback_call_count());
-
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, callback_call_count());
-}
-
-TEST_F(MetricsReportingSchedulerTest, InitTaskCompleteAfterTimer) {
- MetricsReportingScheduler scheduler(GetCallback(), GetConnectionCallback());
- scheduler.SetUploadIntervalForTesting(base::TimeDelta());
- scheduler.Start();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0, callback_call_count());
-
- scheduler.InitTaskComplete();
- EXPECT_EQ(1, callback_call_count());
-}
-
-} // namespace metrics
diff --git a/chromium/components/metrics/metrics_reporting_service.cc b/chromium/components/metrics/metrics_reporting_service.cc
new file mode 100644
index 00000000000..9e0e46a6aa8
--- /dev/null
+++ b/chromium/components/metrics/metrics_reporting_service.cc
@@ -0,0 +1,86 @@
+// 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.
+
+// ReportingService specialized to report UMA metrics.
+
+#include "components/metrics/metrics_reporting_service.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/metrics/histogram_macros.h"
+#include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/persisted_logs_metrics_impl.h"
+#include "components/metrics/url_constants.h"
+#include "components/prefs/pref_registry_simple.h"
+
+namespace metrics {
+
+namespace {
+
+// If an upload fails, and the transmission was over this byte count, 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.
+const size_t kUploadLogAvoidRetransmitSize = 100 * 1024;
+
+} // namespace
+
+// static
+void MetricsReportingService::RegisterPrefs(PrefRegistrySimple* registry) {
+ ReportingService::RegisterPrefs(registry);
+ MetricsLogStore::RegisterPrefs(registry);
+}
+
+MetricsReportingService::MetricsReportingService(MetricsServiceClient* client,
+ PrefService* local_state)
+ : ReportingService(client, local_state, kUploadLogAvoidRetransmitSize),
+ metrics_log_store_(local_state, kUploadLogAvoidRetransmitSize) {}
+
+MetricsReportingService::~MetricsReportingService() {}
+
+LogStore* MetricsReportingService::log_store() {
+ return &metrics_log_store_;
+}
+
+std::string MetricsReportingService::GetUploadUrl() const {
+ return client()->GetMetricsServerUrl();
+}
+
+base::StringPiece MetricsReportingService::upload_mime_type() const {
+ return kDefaultMetricsMimeType;
+}
+
+MetricsLogUploader::MetricServiceType MetricsReportingService::service_type()
+ const {
+ return MetricsLogUploader::UMA;
+}
+
+void MetricsReportingService::LogActualUploadInterval(
+ base::TimeDelta interval) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS("UMA.ActualLogUploadInterval",
+ interval.InMinutes(), 1,
+ base::TimeDelta::FromHours(12).InMinutes(), 50);
+}
+
+void MetricsReportingService::LogCellularConstraint(bool upload_canceled) {
+ UMA_HISTOGRAM_BOOLEAN("UMA.LogUpload.Canceled.CellularConstraint",
+ upload_canceled);
+}
+
+void MetricsReportingService::LogResponseOrErrorCode(int response_code,
+ int error_code) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("UMA.LogUpload.ResponseOrErrorCode",
+ response_code >= 0 ? response_code : error_code);
+}
+
+void MetricsReportingService::LogSuccess(size_t log_size) {
+ UMA_HISTOGRAM_COUNTS_10000("UMA.LogSize.OnSuccess", log_size / 1024);
+}
+
+void MetricsReportingService::LogLargeRejection(size_t log_size) {
+ UMA_HISTOGRAM_COUNTS_1M("UMA.Large Rejected Log was Discarded",
+ static_cast<int>(log_size));
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/metrics_reporting_service.h b/chromium/components/metrics/metrics_reporting_service.h
new file mode 100644
index 00000000000..07ff67ad81b
--- /dev/null
+++ b/chromium/components/metrics/metrics_reporting_service.h
@@ -0,0 +1,65 @@
+// 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.
+
+// This file defines a service that sends metrics logs to a server.
+
+#ifndef COMPONENTS_METRICS_METRICS_REPORTING_SERVICE_H_
+#define COMPONENTS_METRICS_METRICS_REPORTING_SERVICE_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "components/metrics/metrics_log_store.h"
+#include "components/metrics/reporting_service.h"
+
+class PrefService;
+class PrefRegistrySimple;
+
+namespace metrics {
+
+class MetricsServiceClient;
+
+// MetricsReportingService is concrete implementation of ReportingService for
+// UMA logs. It uses a MetricsLogStore as its LogStore, reports to the UMA
+// endpoint, and logs some histograms with the UMA prefix.
+class MetricsReportingService : public ReportingService {
+ public:
+ // Creates a ReportingService with the given |client|, |local_state|.
+ // Does not take ownership of the parameters; instead it stores a weak
+ // pointer to each. Caller should ensure that the parameters are valid for
+ // the lifetime of this class.
+ MetricsReportingService(MetricsServiceClient* client,
+ PrefService* local_state);
+ ~MetricsReportingService() override;
+
+ MetricsLogStore* metrics_log_store() { return &metrics_log_store_; }
+ const MetricsLogStore* metrics_log_store() const {
+ return &metrics_log_store_;
+ }
+
+ // Registers local state prefs used by this class.
+ static void RegisterPrefs(PrefRegistrySimple* registry);
+
+ private:
+ // ReportingService:
+ LogStore* log_store() override;
+ std::string GetUploadUrl() const override;
+ base::StringPiece upload_mime_type() const override;
+ MetricsLogUploader::MetricServiceType service_type() const override;
+ void LogActualUploadInterval(base::TimeDelta interval) override;
+ void LogCellularConstraint(bool upload_canceled) override;
+ void LogResponseOrErrorCode(int response_code, int error_code) override;
+ void LogSuccess(size_t log_size) override;
+ void LogLargeRejection(size_t log_size) override;
+
+ MetricsLogStore metrics_log_store_;
+
+ DISALLOW_COPY_AND_ASSIGN(MetricsReportingService);
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_METRICS_REPORTING_SERVICE_H_
diff --git a/chromium/components/metrics/metrics_service.cc b/chromium/components/metrics/metrics_service.cc
index c3155e46480..529af17d829 100644
--- a/chromium/components/metrics/metrics_service.cc
+++ b/chromium/components/metrics/metrics_service.cc
@@ -131,7 +131,6 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/feature_list.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_base.h"
@@ -141,23 +140,18 @@
#include "base/metrics/sparse_histogram.h"
#include "base/metrics/statistics_recorder.h"
#include "base/single_thread_task_runner.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/tracked_objects.h"
#include "build/build_config.h"
-#include "components/metrics/data_use_tracker.h"
#include "components/metrics/environment_recorder.h"
#include "components/metrics/metrics_log.h"
#include "components/metrics/metrics_log_manager.h"
#include "components/metrics/metrics_log_uploader.h"
#include "components/metrics/metrics_pref_names.h"
-#include "components/metrics/metrics_reporting_scheduler.h"
#include "components/metrics/metrics_rotation_scheduler.h"
#include "components/metrics/metrics_service_client.h"
#include "components/metrics/metrics_state_manager.h"
-#include "components/metrics/metrics_upload_scheduler.h"
#include "components/metrics/stability_metrics_provider.h"
#include "components/metrics/url_constants.h"
#include "components/prefs/pref_registry_simple.h"
@@ -188,33 +182,6 @@ const int kInitializationDelaySeconds = 30;
// The maximum number of events in a log uploaded to the UMA server.
const int kEventLimit = 2400;
-// If an upload fails, and the transmission was over this byte count, 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.
-const size_t kUploadLogAvoidRetransmitSize = 100 * 1024;
-
-enum ResponseStatus {
- UNKNOWN_FAILURE,
- SUCCESS,
- BAD_REQUEST, // Invalid syntax or log too large.
- NO_RESPONSE,
- NUM_RESPONSE_STATUSES
-};
-
-ResponseStatus ResponseCodeToStatus(int response_code) {
- switch (response_code) {
- case -1:
- return NO_RESPONSE;
- case 200:
- return SUCCESS;
- case 400:
- return BAD_REQUEST;
- default:
- return UNKNOWN_FAILURE;
- }
-}
-
#if defined(OS_ANDROID) || defined(OS_IOS)
void MarkAppCleanShutdownAndCommit(CleanExitBeacon* clean_exit_beacon,
PrefService* local_state) {
@@ -237,16 +204,13 @@ void MetricsService::RegisterPrefs(PrefRegistrySimple* registry) {
MetricsStateManager::RegisterPrefs(registry);
MetricsLog::RegisterPrefs(registry);
StabilityMetricsProvider::RegisterPrefs(registry);
- DataUseTracker::RegisterPrefs(registry);
ExecutionPhaseManager::RegisterPrefs(registry);
+ MetricsReportingService::RegisterPrefs(registry);
registry->RegisterInt64Pref(prefs::kInstallDate, 0);
registry->RegisterIntegerPref(prefs::kMetricsSessionID, -1);
- registry->RegisterListPref(prefs::kMetricsInitialLogs);
- registry->RegisterListPref(prefs::kMetricsOngoingLogs);
-
registry->RegisterInt64Pref(prefs::kUninstallLaunchCount, 0);
registry->RegisterInt64Pref(prefs::kUninstallMetricsUptimeSec, 0);
}
@@ -254,20 +218,17 @@ void MetricsService::RegisterPrefs(PrefRegistrySimple* registry) {
MetricsService::MetricsService(MetricsStateManager* state_manager,
MetricsServiceClient* client,
PrefService* local_state)
- : log_store_(local_state, kUploadLogAvoidRetransmitSize),
+ : reporting_service_(client, local_state),
histogram_snapshot_manager_(this),
state_manager_(state_manager),
client_(client),
local_state_(local_state),
clean_exit_beacon_(client->GetRegistryBackupKey(), local_state),
recording_state_(UNSET),
- reporting_active_(false),
test_mode_active_(false),
state_(INITIALIZED),
- log_upload_in_progress_(false),
idle_since_last_transmission_(false),
session_id_(-1),
- data_use_tracker_(DataUseTracker::Create(local_state_)),
self_ptr_factory_(this) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(state_manager_);
@@ -288,6 +249,7 @@ MetricsService::~MetricsService() {
}
void MetricsService::InitializeMetricsRecordingState() {
+ reporting_service_.Initialize();
InitializeMetricsState();
base::Closure upload_callback =
@@ -300,9 +262,6 @@ void MetricsService::InitializeMetricsRecordingState() {
// MetricsRotationScheduler is tied to the lifetime of |this|.
base::Bind(&MetricsServiceClient::GetStandardUploadInterval,
base::Unretained(client_))));
- base::Closure send_next_log_callback =
- base::Bind(&MetricsService::SendNextLog, self_ptr_factory_.GetWeakPtr());
- upload_scheduler_.reset(new MetricsUploadScheduler(send_next_log_callback));
for (auto& provider : metrics_providers_)
provider->Init();
@@ -327,14 +286,14 @@ void MetricsService::Stop() {
}
void MetricsService::EnableReporting() {
- if (reporting_active_)
+ if (reporting_service_.reporting_active())
return;
- reporting_active_ = true;
+ reporting_service_.EnableReporting();
StartSchedulerIfNecessary();
}
void MetricsService::DisableReporting() {
- reporting_active_ = false;
+ reporting_service_.DisableReporting();
}
std::string MetricsService::GetClientId() {
@@ -396,7 +355,11 @@ bool MetricsService::recording_active() const {
bool MetricsService::reporting_active() const {
DCHECK(thread_checker_.CalledOnValidThread());
- return reporting_active_;
+ return reporting_service_.reporting_active();
+}
+
+bool MetricsService::has_unsent_logs() const {
+ return reporting_service_.metrics_log_store()->has_unsent_logs();
}
void MetricsService::RecordDelta(const base::HistogramBase& histogram,
@@ -447,7 +410,7 @@ void MetricsService::RecordCompletedSessionEnd() {
#if defined(OS_ANDROID) || defined(OS_IOS)
void MetricsService::OnAppEnterBackground() {
rotation_scheduler_->Stop();
- upload_scheduler_->Stop();
+ reporting_service_.Stop();
MarkAppCleanShutdownAndCommit(&clean_exit_beacon_, local_state_);
@@ -503,18 +466,15 @@ void MetricsService::ClearSavedStabilityMetrics() {
}
void MetricsService::PushExternalLog(const std::string& log) {
- log_store_.StoreLog(log, MetricsLog::ONGOING_LOG);
+ log_store()->StoreLog(log, MetricsLog::ONGOING_LOG);
}
void MetricsService::UpdateMetricsUsagePrefs(const std::string& service_name,
int message_size,
bool is_cellular) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (data_use_tracker_) {
- data_use_tracker_->UpdateMetricsUsagePrefs(service_name,
- message_size,
- is_cellular);
- }
+ reporting_service_.UpdateMetricsUsagePrefs(service_name, message_size,
+ is_cellular);
}
//------------------------------------------------------------------------------
@@ -538,8 +498,6 @@ void MetricsService::InitializeMetricsState() {
version_changed = true;
}
- log_store_.LoadPersistedUnsentLogs();
-
session_id_ = local_state_->GetInteger(prefs::kMetricsSessionID);
StabilityMetricsProvider provider(local_state_);
@@ -721,7 +679,7 @@ void MetricsService::CloseCurrentLog() {
current_log->RecordGeneralMetrics(metrics_providers_);
RecordCurrentHistograms();
DVLOG(1) << "Generated an ongoing log.";
- log_manager_.FinishCurrentLog(&log_store_);
+ log_manager_.FinishCurrentLog(log_store());
}
void MetricsService::PushPendingLogsToPersistentStorage() {
@@ -729,7 +687,7 @@ void MetricsService::PushPendingLogsToPersistentStorage() {
return; // We didn't and still don't have time to get plugin list etc.
CloseCurrentLog();
- log_store_.PersistUnsentLogs();
+ log_store()->PersistUnsentLogs();
}
//------------------------------------------------------------------------------
@@ -746,7 +704,7 @@ void MetricsService::StartSchedulerIfNecessary() {
if (recording_active() &&
(reporting_active() || state_ < SENDING_LOGS)) {
rotation_scheduler_->Start();
- upload_scheduler_->Start();
+ reporting_service_.Start();
}
}
@@ -771,8 +729,8 @@ void MetricsService::StartScheduledUpload() {
// If there are unsent logs, send the next one. If not, start the asynchronous
// process of finalizing the current log for upload.
- if (state_ == SENDING_LOGS && log_store_.has_unsent_logs()) {
- upload_scheduler_->Start();
+ if (state_ == SENDING_LOGS && has_unsent_logs()) {
+ reporting_service_.Start();
rotation_scheduler_->RotationFinished();
} else {
// There are no logs left to send, so start creating a new one.
@@ -798,43 +756,9 @@ void MetricsService::OnFinalLogInfoCollectionDone() {
CloseCurrentLog();
OpenNewLog();
}
- HandleIdleSinceLastTransmission(true);
- upload_scheduler_->Start();
+ reporting_service_.Start();
rotation_scheduler_->RotationFinished();
-}
-
-void MetricsService::SendNextLog() {
- DVLOG(1) << "SendNextLog";
- if (!reporting_active()) {
- upload_scheduler_->StopAndUploadCancelled();
- return;
- }
- if (!log_store_.has_unsent_logs()) {
- // Should only get here if serializing the log failed somehow.
- upload_scheduler_->Stop();
- // Reset backoff interval
- upload_scheduler_->UploadFinished(true);
- return;
- }
- if (!log_store_.has_staged_log())
- log_store_.StageNextLog();
-
- // Proceed to stage the log for upload if log size satisfies cellular log
- // upload constrains.
- bool upload_canceled = false;
- bool is_cellular_logic = client_->IsUMACellularUploadLogicEnabled();
- if (is_cellular_logic && data_use_tracker_ &&
- !data_use_tracker_->ShouldUploadLogOnCellular(
- log_store_.staged_log_hash().size())) {
- upload_scheduler_->UploadOverDataUsageCap();
- upload_canceled = true;
- } else {
- SendStagedLog();
- }
- if (is_cellular_logic) {
- UMA_HISTOGRAM_BOOLEAN("UMA.LogUpload.Canceled.CellularConstraint",
- upload_canceled);
- }
+ HandleIdleSinceLastTransmission(true);
}
bool MetricsService::ProvidersHaveInitialStabilityMetrics() {
@@ -879,12 +803,12 @@ bool MetricsService::PrepareInitialStabilityLog(
// stability stats from a previous session only.
DVLOG(1) << "Generated an stability log.";
- log_manager_.FinishCurrentLog(&log_store_);
+ log_manager_.FinishCurrentLog(log_store());
log_manager_.ResumePausedLog();
// Store unsent logs, including the stability log that was just saved, so
// that they're not lost in case of a crash before upload time.
- log_store_.PersistUnsentLogs();
+ log_store()->PersistUnsentLogs();
return true;
}
@@ -911,79 +835,16 @@ void MetricsService::PrepareInitialMetricsLog() {
RecordCurrentHistograms();
DVLOG(1) << "Generated an initial log.";
- log_manager_.FinishCurrentLog(&log_store_);
+ log_manager_.FinishCurrentLog(log_store());
log_manager_.ResumePausedLog();
// Store unsent logs, including the initial log that was just saved, so
// that they're not lost in case of a crash before upload time.
- log_store_.PersistUnsentLogs();
+ log_store()->PersistUnsentLogs();
state_ = SENDING_LOGS;
}
-void MetricsService::SendStagedLog() {
- DCHECK(log_store_.has_staged_log());
- if (!log_store_.has_staged_log())
- return;
-
- DCHECK(!log_upload_in_progress_);
- log_upload_in_progress_ = true;
-
- if (!log_uploader_) {
- log_uploader_ = client_->CreateUploader(
- client_->GetMetricsServerUrl(), metrics::kDefaultMetricsMimeType,
- metrics::MetricsLogUploader::UMA,
- base::Bind(&MetricsService::OnLogUploadComplete,
- self_ptr_factory_.GetWeakPtr()));
- }
- const std::string hash = base::HexEncode(log_store_.staged_log_hash().data(),
- log_store_.staged_log_hash().size());
- log_uploader_->UploadLog(log_store_.staged_log(), hash);
-}
-
-
-void MetricsService::OnLogUploadComplete(int response_code) {
- DVLOG(1) << "OnLogUploadComplete:" << response_code;
- DCHECK(log_upload_in_progress_);
- log_upload_in_progress_ = false;
-
- // Log a histogram to track response success vs. failure rates.
- UMA_HISTOGRAM_ENUMERATION("UMA.UploadResponseStatus.Protobuf",
- ResponseCodeToStatus(response_code),
- NUM_RESPONSE_STATUSES);
-
- bool upload_succeeded = response_code == 200;
-
- // Provide boolean for error recovery (allow us to ignore response_code).
- bool discard_log = false;
- const size_t log_size = log_store_.staged_log().length();
- if (upload_succeeded) {
- UMA_HISTOGRAM_COUNTS_10000("UMA.LogSize.OnSuccess", log_size / 1024);
- } else if (log_size > kUploadLogAvoidRetransmitSize) {
- UMA_HISTOGRAM_COUNTS("UMA.Large Rejected Log was Discarded",
- static_cast<int>(log_size));
- discard_log = true;
- } else if (response_code == 400) {
- // Bad syntax. Retransmission won't work.
- discard_log = true;
- }
-
- if (upload_succeeded || discard_log) {
- log_store_.DiscardStagedLog();
- // Store the updated list to disk now that the removed log is uploaded.
- log_store_.PersistUnsentLogs();
- }
-
- // Error 400 indicates a problem with the log, not with the server, so
- // don't consider that a sign that the server is in trouble.
- bool server_is_healthy = upload_succeeded || response_code == 400;
- if (!log_store_.has_unsent_logs()) {
- DVLOG(1) << "Stopping upload_scheduler_";
- upload_scheduler_->Stop();
- }
- upload_scheduler_->UploadFinished(server_is_healthy);
-}
-
void MetricsService::IncrementLongPrefsValue(const char* path) {
int64_t value = local_state_->GetInt64(path);
local_state_->SetInt64(path, value + 1);
diff --git a/chromium/components/metrics/metrics_service.h b/chromium/components/metrics/metrics_service.h
index 574e7be724a..12c86aa1fba 100644
--- a/chromium/components/metrics/metrics_service.h
+++ b/chromium/components/metrics/metrics_service.h
@@ -27,12 +27,12 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/metrics/clean_exit_beacon.h"
-#include "components/metrics/data_use_tracker.h"
#include "components/metrics/execution_phase.h"
#include "components/metrics/metrics_log.h"
#include "components/metrics/metrics_log_manager.h"
#include "components/metrics/metrics_log_store.h"
#include "components/metrics/metrics_provider.h"
+#include "components/metrics/metrics_reporting_service.h"
#include "components/metrics/net/network_metrics_provider.h"
#include "components/variations/synthetic_trials.h"
@@ -50,9 +50,7 @@ struct ActiveGroupId;
namespace metrics {
-class MetricsLogUploader;
class MetricsRotationScheduler;
-class MetricsUploadScheduler;
class MetricsServiceAccessor;
class MetricsServiceClient;
class MetricsStateManager;
@@ -110,8 +108,7 @@ class MetricsService : public base::HistogramFlattener {
// Returns true if the last session exited cleanly.
bool WasLastShutdownClean() const;
- // At startup, prefs needs to be called with a list of all the pref names and
- // types we'll be using.
+ // Registers local state prefs used by this class.
static void RegisterPrefs(PrefRegistrySimple* registry);
// HistogramFlattener:
@@ -159,6 +156,7 @@ class MetricsService : public base::HistogramFlattener {
bool recording_active() const;
bool reporting_active() const;
+ bool has_unsent_logs() const;
// Redundant test to ensure that we are notified of a clean exit.
// This value should be true when process has completed shutdown.
@@ -200,7 +198,9 @@ class MetricsService : public base::HistogramFlattener {
protected:
// Exposed for testing.
MetricsLogManager* log_manager() { return &log_manager_; }
- MetricsLogStore* log_store() { return &log_store_; }
+ MetricsLogStore* log_store() {
+ return reporting_service_.metrics_log_store();
+ }
private:
friend class MetricsServiceAccessor;
@@ -307,10 +307,6 @@ class MetricsService : public base::HistogramFlattener {
// complete.
void OnFinalLogInfoCollectionDone();
- // If recording is enabled, begins uploading the next completed log from
- // the log manager, staging it if necessary.
- void SendNextLog();
-
// Returns true if any of the registered metrics providers have critical
// stability metrics to report in an initial stability log.
bool ProvidersHaveInitialStabilityMetrics();
@@ -327,12 +323,6 @@ class MetricsService : public base::HistogramFlattener {
// profiler data, as well as incremental stability-related metrics.
void PrepareInitialMetricsLog();
- // Uploads the currently staged log (which must be non-null).
- void SendStagedLog();
-
- // Called after transmission completes (either successfully or with failure).
- void OnLogUploadComplete(int response_code);
-
// Reads, increments and then sets the specified long preference that is
// stored as a string.
void IncrementLongPrefsValue(const char* path);
@@ -362,12 +352,12 @@ class MetricsService : public base::HistogramFlattener {
// i.e., histograms with the |kUmaStabilityHistogramFlag| flag set.
void RecordCurrentStabilityHistograms();
+ // Sub-service for uploading logs.
+ MetricsReportingService reporting_service_;
+
// Manager for the various in-flight logs.
MetricsLogManager log_manager_;
- // Store of logs ready to be uploaded.
- MetricsLogStore log_store_;
-
// |histogram_snapshot_manager_| prepares histogram deltas for transmission.
base::HistogramSnapshotManager histogram_snapshot_manager_;
@@ -392,7 +382,6 @@ class MetricsService : public base::HistogramFlattener {
// These should not be set directly, but by calling SetRecording and
// SetReporting.
RecordingState recording_state_;
- bool reporting_active_;
// Indicate whether test mode is enabled, where the initial log should never
// be cut, and logs are neither persisted nor uploaded.
@@ -407,12 +396,6 @@ class MetricsService : public base::HistogramFlattener {
// initial stability log may be sent before this.
std::unique_ptr<MetricsLog> initial_metrics_log_;
- // Instance of the helper class for uploading logs.
- std::unique_ptr<MetricsLogUploader> log_uploader_;
-
- // Whether there is a current log upload in progress.
- bool log_upload_in_progress_;
-
// Whether the MetricsService object has received any notifications since
// the last time a transmission was sent.
bool idle_since_last_transmission_;
@@ -422,8 +405,6 @@ class MetricsService : public base::HistogramFlattener {
// The scheduler for determining when log rotations should happen.
std::unique_ptr<MetricsRotationScheduler> rotation_scheduler_;
- // The scheduler for determining when uploads should happen.
- std::unique_ptr<MetricsUploadScheduler> upload_scheduler_;
// Stores the time of the first call to |GetUptimes()|.
base::TimeTicks first_updated_time_;
@@ -449,9 +430,6 @@ class MetricsService : public base::HistogramFlattener {
FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest,
RegisterSyntheticMultiGroupFieldTrial);
- // Pointer used for obtaining data use pref updater callback on above layers.
- std::unique_ptr<DataUseTracker> data_use_tracker_;
-
base::ThreadChecker thread_checker_;
// Weak pointers factory used to post task on different threads. All weak
diff --git a/chromium/components/metrics/metrics_service_accessor.cc b/chromium/components/metrics/metrics_service_accessor.cc
index 786895b40a1..29b67bd9118 100644
--- a/chromium/components/metrics/metrics_service_accessor.cc
+++ b/chromium/components/metrics/metrics_service_accessor.cc
@@ -32,8 +32,8 @@ bool MetricsServiceAccessor::IsMetricsReportingEnabled(
// static
bool MetricsServiceAccessor::RegisterSyntheticFieldTrial(
MetricsService* metrics_service,
- const std::string& trial_name,
- const std::string& group_name) {
+ base::StringPiece trial_name,
+ base::StringPiece group_name) {
return RegisterSyntheticFieldTrialWithNameAndGroupHash(
metrics_service, HashName(trial_name), HashName(group_name));
}
@@ -41,7 +41,7 @@ bool MetricsServiceAccessor::RegisterSyntheticFieldTrial(
// static
bool MetricsServiceAccessor::RegisterSyntheticMultiGroupFieldTrial(
MetricsService* metrics_service,
- const std::string& trial_name,
+ base::StringPiece trial_name,
const std::vector<uint32_t>& group_name_hashes) {
if (!metrics_service)
return false;
@@ -55,7 +55,7 @@ bool MetricsServiceAccessor::RegisterSyntheticMultiGroupFieldTrial(
bool MetricsServiceAccessor::RegisterSyntheticFieldTrialWithNameHash(
MetricsService* metrics_service,
uint32_t trial_name_hash,
- const std::string& group_name) {
+ base::StringPiece group_name) {
return RegisterSyntheticFieldTrialWithNameAndGroupHash(
metrics_service, trial_name_hash, HashName(group_name));
}
diff --git a/chromium/components/metrics/metrics_service_accessor.h b/chromium/components/metrics/metrics_service_accessor.h
index c4b5e62f195..7e1a107778b 100644
--- a/chromium/components/metrics/metrics_service_accessor.h
+++ b/chromium/components/metrics/metrics_service_accessor.h
@@ -6,10 +6,10 @@
#define COMPONENTS_METRICS_METRICS_SERVICE_ACCESSOR_H_
#include <stdint.h>
-#include <string>
#include <vector>
#include "base/macros.h"
+#include "base/strings/string_piece.h"
class PrefService;
@@ -38,8 +38,8 @@ class MetricsServiceAccessor {
// See the comment on MetricsService::RegisterSyntheticFieldTrial() for
// details.
static bool RegisterSyntheticFieldTrial(MetricsService* metrics_service,
- const std::string& trial_name,
- const std::string& group_name);
+ base::StringPiece trial_name,
+ base::StringPiece group_name);
// Registers a field trial name and set of groups with |metrics_service| (if
// not null), to be used to annotate a UMA report with a particular
@@ -48,7 +48,7 @@ class MetricsServiceAccessor {
// for details.
static bool RegisterSyntheticMultiGroupFieldTrial(
MetricsService* metrics_service,
- const std::string& trial_name,
+ base::StringPiece trial_name,
const std::vector<uint32_t>& group_name_hashes);
// Same as RegisterSyntheticFieldTrial above, but takes in the trial name as a
@@ -56,7 +56,7 @@ class MetricsServiceAccessor {
static bool RegisterSyntheticFieldTrialWithNameHash(
MetricsService* metrics_service,
uint32_t trial_name_hash,
- const std::string& group_name);
+ base::StringPiece group_name);
// Same as RegisterSyntheticFieldTrial above, but takes in the trial and group
// names as hashes rather than computing those hashes from the strings.
diff --git a/chromium/components/metrics/metrics_service_client.cc b/chromium/components/metrics/metrics_service_client.cc
index 5b6427734db..8a204b3e190 100644
--- a/chromium/components/metrics/metrics_service_client.cc
+++ b/chromium/components/metrics/metrics_service_client.cc
@@ -4,10 +4,23 @@
#include "components/metrics/metrics_service_client.h"
+#include "base/feature_list.h"
#include "components/metrics/url_constants.h"
namespace metrics {
+namespace {
+
+#if defined(OS_ANDROID) || defined(OS_IOS)
+const base::Feature kNewMetricsUrlFeature{"NewMetricsUrl",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#else
+const base::Feature kNewMetricsUrlFeature{"NewMetricsUrl",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+} // namespace
+
MetricsServiceClient::MetricsServiceClient() : update_running_services_() {}
MetricsServiceClient::~MetricsServiceClient() {}
@@ -33,7 +46,9 @@ bool MetricsServiceClient::IsUMACellularUploadLogicEnabled() {
}
std::string MetricsServiceClient::GetMetricsServerUrl() {
- return metrics::kDefaultMetricsServerUrl;
+ return base::FeatureList::IsEnabled(kNewMetricsUrlFeature)
+ ? kNewMetricsServerUrl
+ : kOldMetricsServerUrl;
}
bool MetricsServiceClient::IsHistorySyncEnabledOnAllProfiles() {
diff --git a/chromium/components/metrics/metrics_service_client.h b/chromium/components/metrics/metrics_service_client.h
index 0c5f6935dda..569e121c636 100644
--- a/chromium/components/metrics/metrics_service_client.h
+++ b/chromium/components/metrics/metrics_service_client.h
@@ -94,10 +94,10 @@ class MetricsServiceClient {
// Creates a MetricsLogUploader with the specified parameters (see comments on
// MetricsLogUploader for details).
virtual std::unique_ptr<MetricsLogUploader> CreateUploader(
- const std::string& server_url,
- const std::string& mime_type,
+ base::StringPiece server_url,
+ base::StringPiece mime_type,
metrics::MetricsLogUploader::MetricServiceType service_type,
- const base::Callback<void(int)>& on_upload_complete) = 0;
+ const MetricsLogUploader::UploadCallback& on_upload_complete) = 0;
// Returns the standard interval between upload attempts.
virtual base::TimeDelta GetStandardUploadInterval() = 0;
diff --git a/chromium/components/metrics/metrics_service_unittest.cc b/chromium/components/metrics/metrics_service_unittest.cc
index 5cc3c159f20..c4ccac83619 100644
--- a/chromium/components/metrics/metrics_service_unittest.cc
+++ b/chromium/components/metrics/metrics_service_unittest.cc
@@ -189,8 +189,7 @@ TEST_F(MetricsServiceTest, InitialStabilityLogAfterCleanShutDown) {
service.InitializeMetricsRecordingState();
// No initial stability log should be generated.
- EXPECT_FALSE(service.log_store()->has_unsent_logs());
- EXPECT_FALSE(service.log_store()->has_staged_log());
+ EXPECT_FALSE(service.has_unsent_logs());
// Ensure that HasInitialStabilityMetrics() is always called on providers,
// for consistency, even if other conditions already indicate their presence.
diff --git a/chromium/components/metrics/metrics_state_manager.cc b/chromium/components/metrics/metrics_state_manager.cc
index 4cae20d3ae7..83d62b5f4f8 100644
--- a/chromium/components/metrics/metrics_state_manager.cc
+++ b/chromium/components/metrics/metrics_state_manager.cc
@@ -92,16 +92,10 @@ void MetricsStateManager::ForceClientIdCreation() {
client_id_.swap(client_id_from_prefs);
}
- if (!client_id_.empty()) {
- // It is technically sufficient to only save a backup of the client id when
- // it is initially generated below, but since the backup was only introduced
- // in M38, seed it explicitly from here for some time.
- BackUpCurrentClientInfo();
+ if (!client_id_.empty())
return;
- }
- const std::unique_ptr<ClientInfo> client_info_backup =
- LoadClientInfoAndMaybeMigrate();
+ const std::unique_ptr<ClientInfo> client_info_backup = LoadClientInfo();
if (client_info_backup) {
client_id_ = client_info_backup->client_id;
@@ -233,36 +227,12 @@ void MetricsStateManager::BackUpCurrentClientInfo() {
store_client_info_.Run(client_info);
}
-std::unique_ptr<ClientInfo>
-MetricsStateManager::LoadClientInfoAndMaybeMigrate() {
+std::unique_ptr<ClientInfo> MetricsStateManager::LoadClientInfo() {
std::unique_ptr<ClientInfo> client_info = load_client_info_.Run();
- // Prior to 2014-07, the client ID was stripped of its dashes before being
- // saved. Migrate back to a proper GUID if this is the case. This migration
- // code can be removed in M41+.
- const size_t kGUIDLengthWithoutDashes = 32U;
- if (client_info &&
- client_info->client_id.length() == kGUIDLengthWithoutDashes) {
- DCHECK(client_info->client_id.find('-') == std::string::npos);
-
- std::string client_id_with_dashes;
- client_id_with_dashes.reserve(kGUIDLengthWithoutDashes + 4U);
- std::string::const_iterator client_id_it = client_info->client_id.begin();
- for (size_t i = 0; i < kGUIDLengthWithoutDashes + 4U; ++i) {
- if (i == 8U || i == 13U || i == 18U || i == 23U) {
- client_id_with_dashes.push_back('-');
- } else {
- client_id_with_dashes.push_back(*client_id_it);
- ++client_id_it;
- }
- }
- DCHECK(client_id_it == client_info->client_id.end());
- client_info->client_id.assign(client_id_with_dashes);
- }
-
- // The GUID retrieved (and possibly fixed above) should be valid unless
- // retrieval failed. If not, return nullptr. This will result in a new GUID
- // being generated by the calling function ForceClientIdCreation().
+ // The GUID retrieved should be valid unless retrieval failed.
+ // If not, return nullptr. This will result in a new GUID being generated by
+ // the calling function ForceClientIdCreation().
if (client_info && !base::IsValidGUID(client_info->client_id))
return nullptr;
diff --git a/chromium/components/metrics/metrics_state_manager.h b/chromium/components/metrics/metrics_state_manager.h
index afa146b98c0..ca60fd41930 100644
--- a/chromium/components/metrics/metrics_state_manager.h
+++ b/chromium/components/metrics/metrics_state_manager.h
@@ -118,9 +118,8 @@ class MetricsStateManager {
// Backs up the current client info via |store_client_info_|.
void BackUpCurrentClientInfo();
- // Loads the client info via |load_client_info_| and potentially migrates it
- // before returning it if it comes back in its old form.
- std::unique_ptr<ClientInfo> LoadClientInfoAndMaybeMigrate();
+ // Loads the client info via |load_client_info_|.
+ std::unique_ptr<ClientInfo> LoadClientInfo();
// Returns the low entropy source for this client. This is a random value
// that is non-identifying amongst browser clients. This method will
diff --git a/chromium/components/metrics/metrics_state_manager_unittest.cc b/chromium/components/metrics/metrics_state_manager_unittest.cc
index bbef26b167a..a55c2fa9f03 100644
--- a/chromium/components/metrics/metrics_state_manager_unittest.cc
+++ b/chromium/components/metrics/metrics_state_manager_unittest.cc
@@ -28,7 +28,8 @@ namespace metrics {
class MetricsStateManagerTest : public testing::Test {
public:
MetricsStateManagerTest()
- : enabled_state_provider_(new TestEnabledStateProvider(false, false)) {
+ : test_begin_time_(base::Time::Now().ToTimeT()),
+ enabled_state_provider_(new TestEnabledStateProvider(false, false)) {
MetricsService::RegisterPrefs(prefs_.registry());
}
@@ -47,6 +48,21 @@ class MetricsStateManagerTest : public testing::Test {
enabled_state_provider_->set_enabled(true);
}
+ void SetClientInfoPrefs(const ClientInfo& client_info) {
+ prefs_.SetString(prefs::kMetricsClientID, client_info.client_id);
+ prefs_.SetInt64(prefs::kInstallDate, client_info.installation_date);
+ prefs_.SetInt64(prefs::kMetricsReportingEnabledTimestamp,
+ client_info.reporting_enabled_date);
+ }
+
+ void SetFakeClientInfoBackup(const ClientInfo& client_info) {
+ fake_client_info_backup_.reset(new ClientInfo);
+ fake_client_info_backup_->client_id = client_info.client_id;
+ fake_client_info_backup_->installation_date = client_info.installation_date;
+ fake_client_info_backup_->reporting_enabled_date =
+ client_info.reporting_enabled_date;
+ }
+
protected:
TestingPrefServiceSimple prefs_;
@@ -58,6 +74,8 @@ class MetricsStateManagerTest : public testing::Test {
// MetricsStateManager.
std::unique_ptr<ClientInfo> fake_client_info_backup_;
+ const int64_t test_begin_time_;
+
private:
// Stores the |client_info| in |stored_client_info_backup_| for verification
// by the tests later.
@@ -222,11 +240,6 @@ TEST_F(MetricsStateManagerTest, ForceClientIdCreation) {
const int64_t kFakeInstallationDate = 12345;
prefs_.SetInt64(prefs::kInstallDate, kFakeInstallationDate);
- const int64_t test_begin_time = base::Time::Now().ToTimeT();
-
- // Holds ClientInfo from previous scoped test for extra checks.
- std::unique_ptr<ClientInfo> previous_client_info;
-
{
std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
@@ -241,7 +254,7 @@ TEST_F(MetricsStateManagerTest, ForceClientIdCreation) {
state_manager->ForceClientIdCreation();
EXPECT_NE(std::string(), state_manager->client_id());
EXPECT_GE(prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp),
- test_begin_time);
+ test_begin_time_);
ASSERT_TRUE(stored_client_info_backup_);
EXPECT_EQ(state_manager->client_id(),
@@ -250,70 +263,82 @@ TEST_F(MetricsStateManagerTest, ForceClientIdCreation) {
stored_client_info_backup_->installation_date);
EXPECT_EQ(prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp),
stored_client_info_backup_->reporting_enabled_date);
-
- previous_client_info = std::move(stored_client_info_backup_);
}
+}
- EnableMetricsReporting();
+TEST_F(MetricsStateManagerTest, LoadPrefs) {
+ ClientInfo client_info;
+ client_info.client_id = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF";
+ client_info.installation_date = 1112;
+ client_info.reporting_enabled_date = 2223;
+ SetClientInfoPrefs(client_info);
+ EnableMetricsReporting();
{
+ EXPECT_FALSE(fake_client_info_backup_);
EXPECT_FALSE(stored_client_info_backup_);
std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
// client_id should be auto-obtained from the constructor when metrics
// reporting is enabled.
- EXPECT_EQ(previous_client_info->client_id, state_manager->client_id());
+ EXPECT_EQ(client_info.client_id, state_manager->client_id());
- // The backup should also be refreshed when the client id re-initialized.
- ASSERT_TRUE(stored_client_info_backup_);
- EXPECT_EQ(previous_client_info->client_id,
- stored_client_info_backup_->client_id);
- EXPECT_EQ(kFakeInstallationDate,
- stored_client_info_backup_->installation_date);
- EXPECT_EQ(previous_client_info->reporting_enabled_date,
- stored_client_info_backup_->reporting_enabled_date);
+ // The backup should not be modified.
+ ASSERT_FALSE(stored_client_info_backup_);
// Re-forcing client id creation shouldn't cause another backup and
// shouldn't affect the existing client id.
- stored_client_info_backup_.reset();
state_manager->ForceClientIdCreation();
EXPECT_FALSE(stored_client_info_backup_);
- EXPECT_EQ(previous_client_info->client_id, state_manager->client_id());
+ EXPECT_EQ(client_info.client_id, state_manager->client_id());
}
+}
- const int64_t kBackupInstallationDate = 1111;
- const int64_t kBackupReportingEnabledDate = 2222;
- const char kBackupClientId[] = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE";
- fake_client_info_backup_.reset(new ClientInfo);
- fake_client_info_backup_->client_id = kBackupClientId;
- fake_client_info_backup_->installation_date = kBackupInstallationDate;
- fake_client_info_backup_->reporting_enabled_date =
- kBackupReportingEnabledDate;
+TEST_F(MetricsStateManagerTest, PreferPrefs) {
+ ClientInfo client_info;
+ client_info.client_id = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF";
+ client_info.installation_date = 1112;
+ client_info.reporting_enabled_date = 2223;
+ SetClientInfoPrefs(client_info);
+ ClientInfo client_info2;
+ client_info2.client_id = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE";
+ client_info2.installation_date = 1111;
+ client_info2.reporting_enabled_date = 2222;
+ SetFakeClientInfoBackup(client_info2);
+
+ EnableMetricsReporting();
{
- // The existence of a backup should result in the same behaviour as
- // before if we already have a client id.
+ // The backup should be ignored if we already have a client id.
EXPECT_FALSE(stored_client_info_backup_);
std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
- EXPECT_EQ(previous_client_info->client_id, state_manager->client_id());
+ EXPECT_EQ(client_info.client_id, state_manager->client_id());
- // The backup should also be refreshed when the client id re-initialized.
- ASSERT_TRUE(stored_client_info_backup_);
- EXPECT_EQ(previous_client_info->client_id,
- stored_client_info_backup_->client_id);
- EXPECT_EQ(kFakeInstallationDate,
- stored_client_info_backup_->installation_date);
- EXPECT_EQ(previous_client_info->reporting_enabled_date,
- stored_client_info_backup_->reporting_enabled_date);
- stored_client_info_backup_.reset();
+ // The backup should not be modified.
+ ASSERT_FALSE(stored_client_info_backup_);
}
+}
+
+TEST_F(MetricsStateManagerTest, RestoreBackup) {
+ ClientInfo client_info;
+ client_info.client_id = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF";
+ client_info.installation_date = 1112;
+ client_info.reporting_enabled_date = 2223;
+ SetClientInfoPrefs(client_info);
+
+ ClientInfo client_info2;
+ client_info2.client_id = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE";
+ client_info2.installation_date = 1111;
+ client_info2.reporting_enabled_date = 2222;
+ SetFakeClientInfoBackup(client_info2);
prefs_.ClearPref(prefs::kMetricsClientID);
prefs_.ClearPref(prefs::kMetricsReportingEnabledTimestamp);
+ EnableMetricsReporting();
{
// The backup should kick in if the client id has gone missing. It should
// replace remaining and missing dates as well.
@@ -321,62 +346,46 @@ TEST_F(MetricsStateManagerTest, ForceClientIdCreation) {
EXPECT_FALSE(stored_client_info_backup_);
std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
- EXPECT_EQ(kBackupClientId, state_manager->client_id());
- EXPECT_EQ(kBackupInstallationDate, prefs_.GetInt64(prefs::kInstallDate));
- EXPECT_EQ(kBackupReportingEnabledDate,
+ EXPECT_EQ(client_info2.client_id, state_manager->client_id());
+ EXPECT_EQ(client_info2.installation_date,
+ prefs_.GetInt64(prefs::kInstallDate));
+ EXPECT_EQ(client_info2.reporting_enabled_date,
prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp));
EXPECT_TRUE(stored_client_info_backup_);
- stored_client_info_backup_.reset();
}
+}
- const char kNoDashesBackupClientId[] = "AAAAAAAABBBBCCCCDDDDEEEEEEEEEEEE";
- fake_client_info_backup_.reset(new ClientInfo);
- fake_client_info_backup_->client_id = kNoDashesBackupClientId;
-
- prefs_.ClearPref(prefs::kInstallDate);
- prefs_.ClearPref(prefs::kMetricsClientID);
- prefs_.ClearPref(prefs::kMetricsReportingEnabledTimestamp);
-
- {
- // When running the backup from old-style client ids, dashes should be
- // re-added. And missing dates in backup should be replaced by Time::Now().
-
- EXPECT_FALSE(stored_client_info_backup_);
-
- std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
- EXPECT_EQ(kBackupClientId, state_manager->client_id());
- EXPECT_GE(prefs_.GetInt64(prefs::kInstallDate), test_begin_time);
- EXPECT_GE(prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp),
- test_begin_time);
+TEST_F(MetricsStateManagerTest, ResetBackup) {
+ ClientInfo client_info;
+ client_info.client_id = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE";
+ client_info.installation_date = 1111;
+ client_info.reporting_enabled_date = 2222;
- EXPECT_TRUE(stored_client_info_backup_);
- previous_client_info = std::move(stored_client_info_backup_);
- }
+ SetFakeClientInfoBackup(client_info);
+ SetClientInfoPrefs(client_info);
prefs_.SetBoolean(prefs::kMetricsResetIds, true);
+ EnableMetricsReporting();
{
// Upon request to reset metrics ids, the existing backup should not be
// restored.
- EXPECT_FALSE(stored_client_info_backup_);
-
std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
// A brand new client id should have been generated.
EXPECT_NE(std::string(), state_manager->client_id());
- EXPECT_NE(previous_client_info->client_id, state_manager->client_id());
+ EXPECT_NE(client_info.client_id, state_manager->client_id());
+ EXPECT_TRUE(stored_client_info_backup_);
// The installation date should not have been affected.
- EXPECT_EQ(previous_client_info->installation_date,
+ EXPECT_EQ(client_info.installation_date,
prefs_.GetInt64(prefs::kInstallDate));
// The metrics-reporting-enabled date will be reset to Now().
EXPECT_GE(prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp),
- previous_client_info->reporting_enabled_date);
-
- stored_client_info_backup_.reset();
+ test_begin_time_);
}
}
diff --git a/chromium/components/metrics/metrics_upload_scheduler.cc b/chromium/components/metrics/metrics_upload_scheduler.cc
index 11adf9ed9a2..22e1f2d72d8 100644
--- a/chromium/components/metrics/metrics_upload_scheduler.cc
+++ b/chromium/components/metrics/metrics_upload_scheduler.cc
@@ -104,18 +104,4 @@ void MetricsUploadScheduler::UploadOverDataUsageCap() {
TaskDone(base::TimeDelta::FromMinutes(kOverDataUsageIntervalMinutes));
}
-void MetricsUploadScheduler::LogActualUploadInterval(base::TimeDelta interval) {
- UMA_HISTOGRAM_CUSTOM_COUNTS("UMA.ActualLogUploadInterval",
- interval.InMinutes(), 1,
- base::TimeDelta::FromHours(12).InMinutes(), 50);
-}
-
-void MetricsUploadScheduler::TriggerTask() {
- if (!last_upload_finish_time_.is_null()) {
- LogActualUploadInterval(base::TimeTicks::Now() - last_upload_finish_time_);
- last_upload_finish_time_ = base::TimeTicks();
- }
- MetricsScheduler::TriggerTask();
-}
-
} // namespace metrics
diff --git a/chromium/components/metrics/metrics_upload_scheduler.h b/chromium/components/metrics/metrics_upload_scheduler.h
index ffa5f81a477..b1fa958e8a0 100644
--- a/chromium/components/metrics/metrics_upload_scheduler.h
+++ b/chromium/components/metrics/metrics_upload_scheduler.h
@@ -15,7 +15,7 @@ namespace metrics {
extern const base::Feature kUploadSchedulerFeature;
-// Scheduler task to drive a MetricsService object's uploading.
+// Scheduler task to drive a ReportingService object's uploading.
class MetricsUploadScheduler : public MetricsScheduler {
public:
// Creates MetricsUploadScheduler object with the given |upload_callback|
@@ -36,16 +36,6 @@ class MetricsUploadScheduler : public MetricsScheduler {
void UploadOverDataUsageCap();
private:
- // Record the upload interval time.
- virtual void LogActualUploadInterval(base::TimeDelta interval);
-
- // MetricsScheduler:
- void TriggerTask() override;
-
- // The tick count of the last time log upload has been finished and null if no
- // upload has been done yet.
- base::TimeTicks last_upload_finish_time_;
-
// Time to wait between uploads on success.
const base::TimeDelta unsent_logs_interval_;
diff --git a/chromium/components/metrics/net/net_metrics_log_uploader.cc b/chromium/components/metrics/net/net_metrics_log_uploader.cc
index 0064177a58c..e7dac872d37 100644
--- a/chromium/components/metrics/net/net_metrics_log_uploader.cc
+++ b/chromium/components/metrics/net/net_metrics_log_uploader.cc
@@ -8,22 +8,106 @@
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/metrics/metrics_log_uploader.h"
#include "net/base/load_flags.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h"
#include "url/gurl.h"
+namespace {
+
+net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotation(
+ const metrics::MetricsLogUploader::MetricServiceType& service_type) {
+ // The code in this function should remain so that we won't need a default
+ // case that does not have meaningful annotation.
+ if (service_type == metrics::MetricsLogUploader::UMA) {
+ return net::DefineNetworkTrafficAnnotation("metrics_report_uma", R"(
+ semantics {
+ sender: "Metrics UMA Log Uploader"
+ description:
+ "Report of usage statistics and crash-related data about Chromium. "
+ "Usage statistics contain information such as preferences, button "
+ "clicks, and memory usage and do not include web page URLs or "
+ "personal information. See more at "
+ "https://www.google.com/chrome/browser/privacy/ under 'Usage "
+ "statistics and crash reports'. Usage statistics are tied to a "
+ "pseudonymous machine identifier and not to your email address."
+ trigger:
+ "Reports are automatically generated on startup and at intervals "
+ "while Chromium is running."
+ data:
+ "A protocol buffer with usage statistics and crash related data."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "Users can enable or disable this feature by disabling "
+ "'Automatically send usage statistics and crash reports to Google' "
+ "in Chromium's settings under Advanced Settings, Privacy. The "
+ "feature is enabled by default."
+ chrome_policy {
+ MetricsReportingEnabled {
+ policy_options {mode: MANDATORY}
+ MetricsReportingEnabled: false
+ }
+ }
+ })");
+ } else {
+ DCHECK_EQ(service_type, metrics::MetricsLogUploader::UKM);
+ return net::DefineNetworkTrafficAnnotation("metrics_report_ukm", R"(
+ semantics {
+ sender: "Metrics UKM Log Uploader"
+ description:
+ "Report of usage statistics that are keyed by URLs to Chromium, "
+ "sent only if the profile has History Sync. This includes "
+ "information about the web pages you visit and your usage of them, "
+ "such as page load speed. This will also include URLs and "
+ "statistics related to downloaded files. If Extension Sync is "
+ "enabled, these statistics will also include information about "
+ "the extensions that have been installed from Chrome Web Store. "
+ "Google only stores usage statistics associated with published "
+ "extensions, and URLs that are known by Google’s search index. "
+ "Usage statistics are tied to a pseudonymous machine identifier "
+ "and not to your email address."
+ trigger:
+ "Reports are automatically generated on startup and at intervals "
+ "while Chromium is running with Sync enabled."
+ data:
+ "A protocol buffer with usage statistics and associated URLs."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "Users can enable or disable this feature by disabling "
+ "'Automatically send usage statistics and crash reports to Google' "
+ "in Chromium's settings under Advanced Settings, Privacy. This is "
+ "only enabled if all active profiles have History/Extension Sync "
+ "enabled without a Sync passphrase."
+ chrome_policy {
+ MetricsReportingEnabled {
+ policy_options {mode: MANDATORY}
+ MetricsReportingEnabled: false
+ }
+ }
+ })");
+ }
+}
+
+} // namespace
+
namespace metrics {
NetMetricsLogUploader::NetMetricsLogUploader(
net::URLRequestContextGetter* request_context_getter,
- const std::string& server_url,
- const std::string& mime_type,
+ base::StringPiece server_url,
+ base::StringPiece mime_type,
MetricsLogUploader::MetricServiceType service_type,
- const base::Callback<void(int)>& on_upload_complete)
- : MetricsLogUploader(server_url,
- mime_type,
- service_type,
- on_upload_complete),
- request_context_getter_(request_context_getter) {}
+ const MetricsLogUploader::UploadCallback& on_upload_complete)
+ : request_context_getter_(request_context_getter),
+ server_url_(server_url),
+ mime_type_(mime_type.data(), mime_type.size()),
+ service_type_(service_type),
+ on_upload_complete_(on_upload_complete) {}
NetMetricsLogUploader::~NetMetricsLogUploader() {
}
@@ -31,7 +115,8 @@ NetMetricsLogUploader::~NetMetricsLogUploader() {
void NetMetricsLogUploader::UploadLog(const std::string& compressed_log_data,
const std::string& log_hash) {
current_fetch_ =
- net::URLFetcher::Create(GURL(server_url_), net::URLFetcher::POST, this);
+ net::URLFetcher::Create(GURL(server_url_), net::URLFetcher::POST, this,
+ GetNetworkTrafficAnnotation(service_type_));
auto service = data_use_measurement::DataUseUserData::UMA;
@@ -70,8 +155,13 @@ void NetMetricsLogUploader::OnURLFetchComplete(const net::URLFetcher* source) {
int response_code = source->GetResponseCode();
if (response_code == net::URLFetcher::RESPONSE_CODE_INVALID)
response_code = -1;
+ int error_code = 0;
+ const net::URLRequestStatus& request_status = source->GetStatus();
+ if (request_status.status() != net::URLRequestStatus::SUCCESS) {
+ error_code = request_status.error();
+ }
current_fetch_.reset();
- on_upload_complete_.Run(response_code);
+ on_upload_complete_.Run(response_code, error_code);
}
} // namespace metrics
diff --git a/chromium/components/metrics/net/net_metrics_log_uploader.h b/chromium/components/metrics/net/net_metrics_log_uploader.h
index b81d1665dff..96e648ed744 100644
--- a/chromium/components/metrics/net/net_metrics_log_uploader.h
+++ b/chromium/components/metrics/net/net_metrics_log_uploader.h
@@ -9,8 +9,10 @@
#include <string>
#include "base/macros.h"
+#include "base/strings/string_piece.h"
#include "components/metrics/metrics_log_uploader.h"
#include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
namespace net {
class URLFetcher;
@@ -23,15 +25,18 @@ namespace metrics {
class NetMetricsLogUploader : public MetricsLogUploader,
public net::URLFetcherDelegate {
public:
- // Constructs a NetMetricsLogUploader with the specified request context and
- // other params (see comments on MetricsLogUploader for details). The caller
- // must ensure that |request_context_getter| remains valid for the lifetime
- // of this class.
- NetMetricsLogUploader(net::URLRequestContextGetter* request_context_getter,
- const std::string& server_url,
- const std::string& mime_type,
- MetricsLogUploader::MetricServiceType service_type,
- const base::Callback<void(int)>& on_upload_complete);
+ // Constructs a NetMetricsLogUploader which uploads data to |server_url| with
+ // the specified |mime_type|. The |service_type| marks which service the
+ // data usage should be attributed to. The |on_upload_complete| callback will
+ // be called with the HTTP response code of the upload or with -1 on an error.
+ // The caller must ensure that |request_context_getter| remains valid for the
+ // lifetime of this class.
+ NetMetricsLogUploader(
+ net::URLRequestContextGetter* request_context_getter,
+ base::StringPiece server_url,
+ base::StringPiece mime_type,
+ MetricsLogUploader::MetricServiceType service_type,
+ const MetricsLogUploader::UploadCallback& on_upload_complete);
~NetMetricsLogUploader() override;
// MetricsLogUploader:
@@ -45,6 +50,11 @@ class NetMetricsLogUploader : public MetricsLogUploader,
// The request context for fetches done using the network stack.
net::URLRequestContextGetter* const request_context_getter_;
+ const GURL server_url_;
+ const std::string mime_type_;
+ const MetricsLogUploader::MetricServiceType service_type_;
+ const MetricsLogUploader::UploadCallback on_upload_complete_;
+
// The outstanding transmission appears as a URL Fetch operation.
std::unique_ptr<net::URLFetcher> current_fetch_;
diff --git a/chromium/components/metrics/net/net_metrics_log_uploader_unittest.cc b/chromium/components/metrics/net/net_metrics_log_uploader_unittest.cc
index 14258f71b20..70d94fd7033 100644
--- a/chromium/components/metrics/net/net_metrics_log_uploader_unittest.cc
+++ b/chromium/components/metrics/net/net_metrics_log_uploader_unittest.cc
@@ -24,7 +24,7 @@ class NetMetricsLogUploaderTest : public testing::Test {
uploader_->UploadLog("initial_dummy_data", "initial_dummy_hash");
}
- void OnUploadCompleteReuseUploader(int response_code) {
+ void OnUploadCompleteReuseUploader(int response_code, int error_code) {
++on_upload_complete_count_;
if (on_upload_complete_count_ == 1)
uploader_->UploadLog("dummy_data", "dummy_hash");
diff --git a/chromium/components/metrics/net/network_metrics_provider.cc b/chromium/components/metrics/net/network_metrics_provider.cc
index bf565300894..cd2f4f5b0f3 100644
--- a/chromium/components/metrics/net/network_metrics_provider.cc
+++ b/chromium/components/metrics/net/network_metrics_provider.cc
@@ -18,6 +18,7 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/task_runner_util.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "net/base/net_errors.h"
#include "net/nqe/network_quality_estimator.h"
diff --git a/chromium/components/metrics/proto/cast_logs.proto b/chromium/components/metrics/proto/cast_logs.proto
index 4c624e4bbbf..4bea0fdf75a 100644
--- a/chromium/components/metrics/proto/cast_logs.proto
+++ b/chromium/components/metrics/proto/cast_logs.proto
@@ -25,6 +25,7 @@ message CastLogsProto {
CAST_PRODUCT_TYPE_TV = 2;
CAST_PRODUCT_TYPE_AUDIO = 3;
CAST_PRODUCT_TYPE_ANDROID_TV = 4;
+ CAST_PRODUCT_TYPE_ASSISTANT = 5;
}
optional CastProductType type = 1;
diff --git a/chromium/components/metrics/proto/omnibox_event.proto b/chromium/components/metrics/proto/omnibox_event.proto
index 0410d6cc0ed..1998a08fb21 100644
--- a/chromium/components/metrics/proto/omnibox_event.proto
+++ b/chromium/components/metrics/proto/omnibox_event.proto
@@ -177,7 +177,7 @@ message OmniboxEventProto {
}
// The result set displayed on the completion popup
- // Next tag: 7
+ // Next tag: 8
message Suggestion {
// Where does this result come from?
optional ProviderType provider = 1;
@@ -196,6 +196,14 @@ message OmniboxEventProto {
HISTORY_KEYWORD = 5; // A past page whose keyword contains the
// input
NAVSUGGEST = 6; // A suggested URL
+ //
+ // result_subtype_identifier is currently used
+ // for contextual zero-suggest suggestions
+ // provided by the experimental service (note
+ // that not all NAVSUUGGEST suggestions come
+ // from the experimental service).
+ // For subtype definitions, please contact
+ // gcomanici@chromium.org.
SEARCH_WHAT_YOU_TYPED = 7; // The input as a search query (with the
// default engine)
SEARCH_HISTORY = 8; // A past search (with the default engine)
@@ -253,6 +261,12 @@ message OmniboxEventProto {
// Whether this item is disabled in the UI (not clickable).
optional bool is_disabled = 6;
+
+ // Used to identify the specific source / type for suggestions by the
+ // suggest server. The meaning of individual values is determined by the
+ // provider of each suggestion type and is different for every suggestion
+ // type. See enum ResultType above for more details.
+ optional int32 result_subtype_identifier = 7;
}
repeated Suggestion suggestion = 9;
diff --git a/chromium/components/metrics/proto/translate_event.proto b/chromium/components/metrics/proto/translate_event.proto
index 94ae6ecb2ff..ad19742cfd4 100644
--- a/chromium/components/metrics/proto/translate_event.proto
+++ b/chromium/components/metrics/proto/translate_event.proto
@@ -131,6 +131,9 @@ message TranslateEventProto {
WEB_CONTENTS_NOT_ACTIVE = 22;
// The translate UI was not shown because the user is editing a form field.
EDITABLE_FIELD_IS_ACTIVE = 23;
+ // The translate UI was not shown because the language is in the user's User
+ // Language Profile.
+ LANGUAGE_IN_ULP = 24;
}
// Event received from translate UI.
diff --git a/chromium/components/metrics/reporting_service.cc b/chromium/components/metrics/reporting_service.cc
new file mode 100644
index 00000000000..14e4d9b9ced
--- /dev/null
+++ b/chromium/components/metrics/reporting_service.cc
@@ -0,0 +1,202 @@
+// 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.
+
+// ReportingService handles uploading serialized logs to a server.
+
+#include "components/metrics/reporting_service.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/metrics/data_use_tracker.h"
+#include "components/metrics/log_store.h"
+#include "components/metrics/metrics_log_uploader.h"
+#include "components/metrics/metrics_service_client.h"
+#include "components/metrics/metrics_upload_scheduler.h"
+
+namespace metrics {
+
+// static
+void ReportingService::RegisterPrefs(PrefRegistrySimple* registry) {
+ DataUseTracker::RegisterPrefs(registry);
+}
+
+ReportingService::ReportingService(MetricsServiceClient* client,
+ PrefService* local_state,
+ size_t max_retransmit_size)
+ : client_(client),
+ max_retransmit_size_(max_retransmit_size),
+ reporting_active_(false),
+ log_upload_in_progress_(false),
+ data_use_tracker_(DataUseTracker::Create(local_state)),
+ self_ptr_factory_(this) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(client_);
+ DCHECK(local_state);
+}
+
+ReportingService::~ReportingService() {
+ DisableReporting();
+}
+
+void ReportingService::Initialize() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!upload_scheduler_);
+ log_store()->LoadPersistedUnsentLogs();
+ base::Closure send_next_log_callback = base::Bind(
+ &ReportingService::SendNextLog, self_ptr_factory_.GetWeakPtr());
+ upload_scheduler_.reset(new MetricsUploadScheduler(send_next_log_callback));
+}
+
+void ReportingService::Start() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (reporting_active_)
+ upload_scheduler_->Start();
+}
+
+void ReportingService::Stop() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (upload_scheduler_)
+ upload_scheduler_->Stop();
+}
+
+void ReportingService::EnableReporting() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (reporting_active_)
+ return;
+ reporting_active_ = true;
+ Start();
+}
+
+void ReportingService::DisableReporting() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ reporting_active_ = false;
+ Stop();
+}
+
+bool ReportingService::reporting_active() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return reporting_active_;
+}
+
+void ReportingService::UpdateMetricsUsagePrefs(const std::string& service_name,
+ int message_size,
+ bool is_cellular) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (data_use_tracker_) {
+ data_use_tracker_->UpdateMetricsUsagePrefs(service_name, message_size,
+ is_cellular);
+ }
+}
+
+//------------------------------------------------------------------------------
+// private methods
+//------------------------------------------------------------------------------
+
+void ReportingService::SendNextLog() {
+ DVLOG(1) << "SendNextLog";
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!last_upload_finish_time_.is_null()) {
+ LogActualUploadInterval(base::TimeTicks::Now() - last_upload_finish_time_);
+ last_upload_finish_time_ = base::TimeTicks();
+ }
+ if (!reporting_active()) {
+ upload_scheduler_->StopAndUploadCancelled();
+ return;
+ }
+ if (!log_store()->has_unsent_logs()) {
+ // Should only get here if serializing the log failed somehow.
+ upload_scheduler_->Stop();
+ // Reset backoff interval
+ upload_scheduler_->UploadFinished(true);
+ return;
+ }
+ if (!log_store()->has_staged_log())
+ log_store()->StageNextLog();
+
+ // Proceed to stage the log for upload if log size satisfies cellular log
+ // upload constrains.
+ bool upload_canceled = false;
+ bool is_cellular_logic = client_->IsUMACellularUploadLogicEnabled();
+ if (is_cellular_logic && data_use_tracker_ &&
+ !data_use_tracker_->ShouldUploadLogOnCellular(
+ log_store()->staged_log_hash().size())) {
+ upload_scheduler_->UploadOverDataUsageCap();
+ upload_canceled = true;
+ } else {
+ SendStagedLog();
+ }
+ if (is_cellular_logic) {
+ LogCellularConstraint(upload_canceled);
+ }
+}
+
+void ReportingService::SendStagedLog() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(log_store()->has_staged_log());
+ if (!log_store()->has_staged_log())
+ return;
+
+ DCHECK(!log_upload_in_progress_);
+ log_upload_in_progress_ = true;
+
+ if (!log_uploader_) {
+ log_uploader_ = client_->CreateUploader(
+ GetUploadUrl(), upload_mime_type(), service_type(),
+ base::Bind(&ReportingService::OnLogUploadComplete,
+ self_ptr_factory_.GetWeakPtr()));
+ }
+
+ const std::string hash =
+ base::HexEncode(log_store()->staged_log_hash().data(),
+ log_store()->staged_log_hash().size());
+ log_uploader_->UploadLog(log_store()->staged_log(), hash);
+}
+
+void ReportingService::OnLogUploadComplete(int response_code, int error_code) {
+ DVLOG(1) << "OnLogUploadComplete:" << response_code;
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(log_upload_in_progress_);
+ log_upload_in_progress_ = false;
+
+ // Log a histogram to track response success vs. failure rates.
+ LogResponseOrErrorCode(response_code, error_code);
+
+ bool upload_succeeded = response_code == 200;
+
+ // Staged log could have been removed already (such as by Purge() in some
+ // implementations), otherwise we may remove it here.
+ if (log_store()->has_staged_log()) {
+ // Provide boolean for error recovery (allow us to ignore response_code).
+ bool discard_log = false;
+ const size_t log_size = log_store()->staged_log().length();
+ if (upload_succeeded) {
+ LogSuccess(log_size);
+ } else if (log_size > max_retransmit_size_) {
+ LogLargeRejection(log_size);
+ discard_log = true;
+ } else if (response_code == 400) {
+ // Bad syntax. Retransmission won't work.
+ discard_log = true;
+ }
+
+ if (upload_succeeded || discard_log) {
+ log_store()->DiscardStagedLog();
+ // Store the updated list to disk now that the removed log is uploaded.
+ log_store()->PersistUnsentLogs();
+ }
+ }
+
+ // Error 400 indicates a problem with the log, not with the server, so
+ // don't consider that a sign that the server is in trouble.
+ bool server_is_healthy = upload_succeeded || response_code == 400;
+ if (!log_store()->has_unsent_logs()) {
+ DVLOG(1) << "Stopping upload_scheduler_.";
+ upload_scheduler_->Stop();
+ }
+ upload_scheduler_->UploadFinished(server_is_healthy);
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/reporting_service.h b/chromium/components/metrics/reporting_service.h
new file mode 100644
index 00000000000..017bcc2a577
--- /dev/null
+++ b/chromium/components/metrics/reporting_service.h
@@ -0,0 +1,146 @@
+// 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.
+
+// This file defines a service that sends metrics logs to a server.
+
+#ifndef COMPONENTS_METRICS_REPORTING_SERVICE_H_
+#define COMPONENTS_METRICS_REPORTING_SERVICE_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "components/metrics/data_use_tracker.h"
+#include "components/metrics/metrics_log_uploader.h"
+
+class PrefService;
+class PrefRegistrySimple;
+
+namespace metrics {
+
+class LogStore;
+class MetricsUploadScheduler;
+class MetricsServiceClient;
+
+// ReportingService is an abstract class which uploads serialized logs from a
+// LogStore to a remote server. A concrete implementation of this class must
+// provide the specific LogStore and parameters for the MetricsLogUploader, and
+// can also implement hooks to record histograms based on certain events that
+// occur while attempting to upload logs.
+class ReportingService {
+ public:
+ // Creates a ReportingService with the given |client|, |local_state|, and
+ // |max_retransmit_size|. Does not take ownership of the parameters; instead
+ // it stores a weak pointer to each. Caller should ensure that the parameters
+ // are valid for the lifetime of this class.
+ ReportingService(MetricsServiceClient* client,
+ PrefService* local_state,
+ size_t max_retransmit_size);
+ virtual ~ReportingService();
+
+ // Completes setup tasks that can't be done at construction time.
+ // Loads persisted logs and creates the MetricsUploadScheduler.
+ void Initialize();
+
+ // Starts the metrics reporting system.
+ // Should be called when metrics enabled or new logs are created.
+ // When the service is already running, this is a safe no-op.
+ void Start();
+
+ // Shuts down the metrics system. Should be called at shutdown, or if metrics
+ // are turned off.
+ void Stop();
+
+ // Enable/disable transmission of accumulated logs and crash reports (dumps).
+ // Calling Start() automatically enables reporting, but sending is
+ // asyncronous so this can be called immediately after Start() to prevent
+ // any uploading.
+ void EnableReporting();
+ void DisableReporting();
+
+ // True iff reporting is currently enabled.
+ bool reporting_active() const;
+
+ // Updates data usage tracking prefs with the specified values.
+ void UpdateMetricsUsagePrefs(const std::string& service_name,
+ int message_size,
+ bool is_cellular);
+
+ // Registers local state prefs used by this class. This should only be called
+ // once.
+ static void RegisterPrefs(PrefRegistrySimple* registry);
+
+ protected:
+ MetricsServiceClient* client() const { return client_; };
+
+ private:
+ // Retrieves the log store backing this service.
+ virtual LogStore* log_store() = 0;
+
+ // Getters for MetricsLogUploader parameters.
+ virtual std::string GetUploadUrl() const = 0;
+ virtual base::StringPiece upload_mime_type() const = 0;
+ virtual MetricsLogUploader::MetricServiceType service_type() const = 0;
+
+ // Methods for recording data to histograms.
+ virtual void LogActualUploadInterval(base::TimeDelta interval) {}
+ virtual void LogCellularConstraint(bool upload_canceled) {}
+ virtual void LogResponseOrErrorCode(int response_code, int error_code) {}
+ virtual void LogSuccess(size_t log_size) {}
+ virtual void LogLargeRejection(size_t log_size) {}
+
+ // If recording is enabled, begins uploading the next completed log from
+ // the log manager, staging it if necessary.
+ void SendNextLog();
+
+ // Uploads the currently staged log (which must be non-null).
+ void SendStagedLog();
+
+ // Called after transmission completes (either successfully or with failure).
+ void OnLogUploadComplete(int response_code, int error_code);
+
+ // Used to interact with the embedder. Weak pointer; must outlive |this|
+ // instance.
+ MetricsServiceClient* const client_;
+
+ // Largest log size to attempt to retransmit.
+ size_t max_retransmit_size_;
+
+ // Indicate whether recording and reporting are currently happening.
+ // These should not be set directly, but by calling SetRecording and
+ // SetReporting.
+ bool reporting_active_;
+
+ // Instance of the helper class for uploading logs.
+ std::unique_ptr<MetricsLogUploader> log_uploader_;
+
+ // Whether there is a current log upload in progress.
+ bool log_upload_in_progress_;
+
+ // The scheduler for determining when uploads should happen.
+ std::unique_ptr<MetricsUploadScheduler> upload_scheduler_;
+
+ // Pointer used for obtaining data use pref updater callback on above layers.
+ std::unique_ptr<DataUseTracker> data_use_tracker_;
+
+ // The tick count of the last time log upload has been finished and null if no
+ // upload has been done yet.
+ base::TimeTicks last_upload_finish_time_;
+
+ base::ThreadChecker thread_checker_;
+
+ // Weak pointers factory used to post task on different threads. All weak
+ // pointers managed by this factory have the same lifetime as
+ // ReportingService.
+ base::WeakPtrFactory<ReportingService> self_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReportingService);
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_REPORTING_SERVICE_H_
diff --git a/chromium/components/metrics/stability_metrics_helper.cc b/chromium/components/metrics/stability_metrics_helper.cc
index 8c33f7773e5..f6254872b03 100644
--- a/chromium/components/metrics/stability_metrics_helper.cc
+++ b/chromium/components/metrics/stability_metrics_helper.cc
@@ -11,6 +11,7 @@
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
+#include "base/metrics/user_metrics.h"
#include "build/build_config.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/proto/system_profile.pb.h"
diff --git a/chromium/components/metrics/stability_metrics_helper.h b/chromium/components/metrics/stability_metrics_helper.h
index 87f8f400f19..bc9aaed0659 100644
--- a/chromium/components/metrics/stability_metrics_helper.h
+++ b/chromium/components/metrics/stability_metrics_helper.h
@@ -6,7 +6,6 @@
#define COMPONENTS_METRICS_STABILITY_METRICS_HELPER_H_
#include "base/macros.h"
-#include "base/metrics/user_metrics.h"
#include "base/process/kill.h"
class PrefRegistrySimple;
diff --git a/chromium/components/metrics/test_metrics_log_uploader.cc b/chromium/components/metrics/test_metrics_log_uploader.cc
index 9c701cce963..0eff63fd939 100644
--- a/chromium/components/metrics/test_metrics_log_uploader.cc
+++ b/chromium/components/metrics/test_metrics_log_uploader.cc
@@ -8,22 +8,15 @@
namespace metrics {
TestMetricsLogUploader::TestMetricsLogUploader(
- const std::string& server_url,
- const std::string& mime_type,
- MetricsLogUploader::MetricServiceType service_type,
- const base::Callback<void(int)>& on_upload_complete)
- : MetricsLogUploader(server_url,
- mime_type,
- service_type,
- on_upload_complete),
- is_uploading_(false) {}
+ const MetricsLogUploader::UploadCallback& on_upload_complete)
+ : on_upload_complete_(on_upload_complete), is_uploading_(false) {}
TestMetricsLogUploader::~TestMetricsLogUploader() = default;
void TestMetricsLogUploader::CompleteUpload(int response_code) {
DCHECK(is_uploading_);
is_uploading_ = false;
- on_upload_complete_.Run(response_code);
+ on_upload_complete_.Run(response_code, 0);
}
void TestMetricsLogUploader::UploadLog(const std::string& compressed_log_data,
diff --git a/chromium/components/metrics/test_metrics_log_uploader.h b/chromium/components/metrics/test_metrics_log_uploader.h
index 196370a4198..5730ee59036 100644
--- a/chromium/components/metrics/test_metrics_log_uploader.h
+++ b/chromium/components/metrics/test_metrics_log_uploader.h
@@ -11,10 +11,8 @@ namespace metrics {
class TestMetricsLogUploader : public MetricsLogUploader {
public:
- TestMetricsLogUploader(const std::string& server_url,
- const std::string& mime_type,
- MetricsLogUploader::MetricServiceType service_type,
- const base::Callback<void(int)>& on_upload_complete);
+ explicit TestMetricsLogUploader(
+ const MetricsLogUploader::UploadCallback& on_upload_complete);
~TestMetricsLogUploader() override;
// Mark the current upload complete with the given response code.
@@ -28,6 +26,7 @@ class TestMetricsLogUploader : public MetricsLogUploader {
void UploadLog(const std::string& compressed_log_data,
const std::string& log_hash) override;
+ const MetricsLogUploader::UploadCallback on_upload_complete_;
bool is_uploading_;
DISALLOW_COPY_AND_ASSIGN(TestMetricsLogUploader);
diff --git a/chromium/components/metrics/test_metrics_service_client.cc b/chromium/components/metrics/test_metrics_service_client.cc
index b68bef847f5..27a822b1674 100644
--- a/chromium/components/metrics/test_metrics_service_client.cc
+++ b/chromium/components/metrics/test_metrics_service_client.cc
@@ -65,12 +65,11 @@ void TestMetricsServiceClient::CollectFinalMetricsForLog(
}
std::unique_ptr<MetricsLogUploader> TestMetricsServiceClient::CreateUploader(
- const std::string& server_url,
- const std::string& mime_type,
+ base::StringPiece server_url,
+ base::StringPiece mime_type,
MetricsLogUploader::MetricServiceType service_type,
- const base::Callback<void(int)>& on_upload_complete) {
- uploader_ = new TestMetricsLogUploader(server_url, mime_type, service_type,
- on_upload_complete);
+ const MetricsLogUploader::UploadCallback& on_upload_complete) {
+ uploader_ = new TestMetricsLogUploader(on_upload_complete);
return std::unique_ptr<MetricsLogUploader>(uploader_);
}
diff --git a/chromium/components/metrics/test_metrics_service_client.h b/chromium/components/metrics/test_metrics_service_client.h
index 8d77e52a288..40342777964 100644
--- a/chromium/components/metrics/test_metrics_service_client.h
+++ b/chromium/components/metrics/test_metrics_service_client.h
@@ -37,10 +37,10 @@ class TestMetricsServiceClient : public MetricsServiceClient {
const base::Closure& done_callback) override;
void CollectFinalMetricsForLog(const base::Closure& done_callback) override;
std::unique_ptr<MetricsLogUploader> CreateUploader(
- const std::string& server_url,
- const std::string& mime_type,
+ base::StringPiece server_url,
+ base::StringPiece mime_type,
MetricsLogUploader::MetricServiceType service_type,
- const base::Callback<void(int)>& on_upload_complete) override;
+ const MetricsLogUploader::UploadCallback& on_upload_complete) override;
base::TimeDelta GetStandardUploadInterval() override;
bool IsReportingPolicyManaged() override;
EnableMetricsDefault GetMetricsReportingDefaultState() override;
diff --git a/chromium/components/metrics/url_constants.cc b/chromium/components/metrics/url_constants.cc
index 4a744d56aff..6b285923ff0 100644
--- a/chromium/components/metrics/url_constants.cc
+++ b/chromium/components/metrics/url_constants.cc
@@ -4,16 +4,12 @@
#include "components/metrics/url_constants.h"
-#include "build/build_config.h"
-
namespace metrics {
-#if defined(OS_ANDROID) || defined(OS_IOS)
-const char kDefaultMetricsServerUrl[] =
+const char kNewMetricsServerUrl[] =
"https://clientservices.googleapis.com/uma/v2";
-#else
-const char kDefaultMetricsServerUrl[] = "https://clients4.google.com/uma/v2";
-#endif
+
+const char kOldMetricsServerUrl[] = "https://clients4.google.com/uma/v2";
const char kDefaultMetricsMimeType[] = "application/vnd.chrome.uma";
diff --git a/chromium/components/metrics/url_constants.h b/chromium/components/metrics/url_constants.h
index b52ddef2ed9..cb1ba6bcbce 100644
--- a/chromium/components/metrics/url_constants.h
+++ b/chromium/components/metrics/url_constants.h
@@ -7,8 +7,11 @@
namespace metrics {
-// The default metrics server's URL.
-extern const char kDefaultMetricsServerUrl[];
+// The new metrics server's URL.
+extern const char kNewMetricsServerUrl[];
+
+// The old metrics server's URL.
+extern const char kOldMetricsServerUrl[];
// The default MIME type for the uploaded metrics data.
extern const char kDefaultMetricsMimeType[];
diff --git a/chromium/components/metrics_services_manager/OWNERS b/chromium/components/metrics_services_manager/OWNERS
index 236892ba623..3b1e0686f43 100644
--- a/chromium/components/metrics_services_manager/OWNERS
+++ b/chromium/components/metrics_services_manager/OWNERS
@@ -3,3 +3,5 @@ holte@chromium.org
isherman@chromium.org
mpearson@chromium.org
rkaplow@chromium.org
+
+# COMPONENT: Internals>Metrics
diff --git a/chromium/components/metrics_services_manager/metrics_services_manager.cc b/chromium/components/metrics_services_manager/metrics_services_manager.cc
index 7b87f884a91..5987635fbac 100644
--- a/chromium/components/metrics_services_manager/metrics_services_manager.cc
+++ b/chromium/components/metrics_services_manager/metrics_services_manager.cc
@@ -105,8 +105,7 @@ void MetricsServicesManager::UpdateRunningServices() {
if (client_->OnlyDoMetricsRecording()) {
metrics->StartRecordingForTests();
- GetRapporServiceImpl()->Update(
- rappor::UMA_RAPPOR_GROUP | rappor::SAFEBROWSING_RAPPOR_GROUP, false);
+ GetRapporServiceImpl()->Update(true, false);
return;
}
@@ -125,22 +124,7 @@ void MetricsServicesManager::UpdateRunningServices() {
UpdateUkmService();
- int recording_groups = 0;
-#if defined(GOOGLE_CHROME_BUILD)
- if (may_record_)
- recording_groups |= rappor::UMA_RAPPOR_GROUP;
-
- // NOTE: It is safe to use a raw pointer to |this| because this object owns
- // |client_|, and the contract of
- // MetricsServicesManagerClient::IsSafeBrowsingEnabled() states that the
- // callback passed in must not be used beyond the lifetime of the client
- // instance.
- base::Closure on_safe_browsing_update_callback = base::Bind(
- &MetricsServicesManager::UpdateRunningServices, base::Unretained(this));
- if (client_->IsSafeBrowsingEnabled(on_safe_browsing_update_callback))
- recording_groups |= rappor::SAFEBROWSING_RAPPOR_GROUP;
-#endif // defined(GOOGLE_CHROME_BUILD)
- GetRapporServiceImpl()->Update(recording_groups, may_upload_);
+ GetRapporServiceImpl()->Update(may_record_, may_upload_);
}
void MetricsServicesManager::UpdateUkmService() {
diff --git a/chromium/components/metrics_services_manager/metrics_services_manager_client.h b/chromium/components/metrics_services_manager/metrics_services_manager_client.h
index b53d39dbc55..1490ff984f8 100644
--- a/chromium/components/metrics_services_manager/metrics_services_manager_client.h
+++ b/chromium/components/metrics_services_manager/metrics_services_manager_client.h
@@ -48,14 +48,6 @@ class MetricsServicesManagerClient {
// operate.
virtual net::URLRequestContextGetter* GetURLRequestContext() = 0;
- // Returns whether safe browsing is enabled. If relevant in the embedder's
- // context, |on_update_callback| will be set up to be called when the state of
- // safe browsing changes. |on_update_callback| is guaranteed to be valid for
- // the lifetime of this client instance, but should not be used beyond this
- // instance being destroyed.
- virtual bool IsSafeBrowsingEnabled(
- const base::Closure& on_update_callback) = 0;
-
// Returns whether metrics reporting is enabled.
virtual bool IsMetricsReportingEnabled() = 0;
diff --git a/chromium/components/mime_util/mime_util.cc b/chromium/components/mime_util/mime_util.cc
index 5f4cf3ffbe4..5539c83cfac 100644
--- a/chromium/components/mime_util/mime_util.cc
+++ b/chromium/components/mime_util/mime_util.cc
@@ -112,7 +112,7 @@ class MimeUtil {
bool IsSupportedMimeType(const std::string& mime_type) const;
private:
- friend struct base::DefaultLazyInstanceTraits<MimeUtil>;
+ friend struct base::LazyInstanceTraitsBase<MimeUtil>;
using MimeTypes = base::hash_set<std::string>;
diff --git a/chromium/components/minidump_uploader/BUILD.gn b/chromium/components/minidump_uploader/BUILD.gn
index fd469b7b99e..c017ccd3abe 100644
--- a/chromium/components/minidump_uploader/BUILD.gn
+++ b/chromium/components/minidump_uploader/BUILD.gn
@@ -20,6 +20,7 @@ android_library("minidump_uploader_java") {
"android/java/src/org/chromium/components/minidump_uploader/util/CrashReportingPermissionManager.java",
"android/java/src/org/chromium/components/minidump_uploader/util/HttpURLConnectionFactory.java",
"android/java/src/org/chromium/components/minidump_uploader/util/HttpURLConnectionFactoryImpl.java",
+ "android/java/src/org/chromium/components/minidump_uploader/util/NetworkPermissionUtil.java",
]
}
diff --git a/chromium/components/minidump_uploader/OWNERS b/chromium/components/minidump_uploader/OWNERS
index 79f0e9b58df..af66982db09 100644
--- a/chromium/components/minidump_uploader/OWNERS
+++ b/chromium/components/minidump_uploader/OWNERS
@@ -3,3 +3,5 @@ mariakhomenko@chromium.org
# Crash uploading mechanism
isherman@chromium.org
+
+# COMPONENT: Internals>CrashReporting
diff --git a/chromium/components/nacl/broker/BUILD.gn b/chromium/components/nacl/broker/BUILD.gn
index 252ab4da2cb..bf0bf3a4d48 100644
--- a/chromium/components/nacl/broker/BUILD.gn
+++ b/chromium/components/nacl/broker/BUILD.gn
@@ -166,6 +166,7 @@ if (current_cpu == "x86") {
"//components/flags_ui:switches",
"//components/policy:generated",
"//content/public/common:static_switches",
+ "//gpu/config:crash_keys",
"//ipc",
]
}
diff --git a/chromium/components/nacl/browser/BUILD.gn b/chromium/components/nacl/browser/BUILD.gn
index 5307b79ceec..a9bfe4d9917 100644
--- a/chromium/components/nacl/browser/BUILD.gn
+++ b/chromium/components/nacl/browser/BUILD.gn
@@ -38,7 +38,6 @@ static_library("browser") {
"//components/url_formatter",
"//content/public/browser",
"//content/public/common",
- "//ipc",
"//mojo/edk/system",
"//native_client/src/trusted/service_runtime:sel_main_chrome",
"//net",
@@ -47,6 +46,10 @@ static_library("browser") {
"//ppapi/shared_impl",
]
+ public_deps = [
+ "//ipc",
+ ]
+
data_deps = []
if (is_linux) {
@@ -80,6 +83,7 @@ source_set("unit_tests") {
"pnacl_host_unittest.cc",
"pnacl_translation_cache_unittest.cc",
"test_nacl_browser_delegate.cc",
+ "test_nacl_browser_delegate.h",
]
deps = [
diff --git a/chromium/components/nacl/common/BUILD.gn b/chromium/components/nacl/common/BUILD.gn
index 8859d086d4d..7f2e1f24381 100644
--- a/chromium/components/nacl/common/BUILD.gn
+++ b/chromium/components/nacl/common/BUILD.gn
@@ -28,6 +28,7 @@ if (enable_nacl) {
public_deps = [
":minimal_content_dummy",
":switches",
+ "//ipc",
]
deps = [
@@ -35,7 +36,6 @@ if (enable_nacl) {
"//base",
"//base:base_static",
"//content/public/common:service_names",
- "//ipc",
"//mojo/edk/system",
"//services/service_manager/public/cpp",
]
@@ -75,12 +75,12 @@ if (enable_nacl) {
":minimal",
":mojo_bindings",
":switches",
+ "//ipc",
]
deps = [
"//base",
"//content/public/common",
- "//ipc",
"//url",
]
diff --git a/chromium/components/nacl/loader/sandbox_linux/BUILD.gn b/chromium/components/nacl/loader/sandbox_linux/BUILD.gn
index 8f61844d0bc..96dc1dbdcec 100644
--- a/chromium/components/nacl/loader/sandbox_linux/BUILD.gn
+++ b/chromium/components/nacl/loader/sandbox_linux/BUILD.gn
@@ -11,6 +11,7 @@ assert(enable_nacl)
source_set("sandbox_linux") {
sources = [
"nacl_bpf_sandbox_linux.cc",
+ "nacl_bpf_sandbox_linux.h",
"nacl_sandbox_linux.cc",
]
diff --git a/chromium/components/nacl/renderer/plugin/BUILD.gn b/chromium/components/nacl/renderer/plugin/BUILD.gn
index a0025956c75..d9957ccb682 100644
--- a/chromium/components/nacl/renderer/plugin/BUILD.gn
+++ b/chromium/components/nacl/renderer/plugin/BUILD.gn
@@ -5,13 +5,22 @@
static_library("nacl_trusted_plugin") {
sources = [
"module_ppapi.cc",
+ "module_ppapi.h",
"nacl_subprocess.cc",
+ "nacl_subprocess.h",
"plugin.cc",
+ "plugin.h",
+ "plugin_error.h",
"pnacl_coordinator.cc",
+ "pnacl_coordinator.h",
"pnacl_resources.cc",
+ "pnacl_resources.h",
"pnacl_translate_thread.cc",
+ "pnacl_translate_thread.h",
"ppapi_entrypoints.cc",
+ "ppapi_entrypoints.h",
"service_runtime.cc",
+ "service_runtime.h",
]
deps = [
diff --git a/chromium/components/navigation_interception/intercept_navigation_throttle.cc b/chromium/components/navigation_interception/intercept_navigation_throttle.cc
index 84292c9f8bb..c66a302286e 100644
--- a/chromium/components/navigation_interception/intercept_navigation_throttle.cc
+++ b/chromium/components/navigation_interception/intercept_navigation_throttle.cc
@@ -69,7 +69,8 @@ InterceptNavigationThrottle::CheckIfShouldIgnoreNavigation(bool is_redirect) {
navigation_handle()->GetURL(), navigation_handle()->GetReferrer(),
navigation_handle()->HasUserGesture(), navigation_handle()->IsPost(),
navigation_handle()->GetPageTransition(), is_redirect,
- navigation_handle()->IsExternalProtocol(), true);
+ navigation_handle()->IsExternalProtocol(), true,
+ navigation_handle()->GetBaseURLForDataURL());
if (run_callback_synchronously_) {
bool should_ignore_navigation = should_ignore_callback_.Run(
diff --git a/chromium/components/navigation_interception/navigation_params.cc b/chromium/components/navigation_interception/navigation_params.cc
index 54288f76c72..fe654e6d556 100644
--- a/chromium/components/navigation_interception/navigation_params.cc
+++ b/chromium/components/navigation_interception/navigation_params.cc
@@ -6,10 +6,6 @@
namespace navigation_interception {
-NavigationParams::NavigationParams(const NavigationParams& other) {
- Assign(other);
-}
-
NavigationParams::NavigationParams(const GURL& url,
const content::Referrer& referrer,
bool has_user_gesture,
@@ -17,7 +13,8 @@ NavigationParams::NavigationParams(const GURL& url,
ui::PageTransition transition_type,
bool is_redirect,
bool is_external_protocol,
- bool is_main_frame)
+ bool is_main_frame,
+ const GURL& base_url_for_data_url)
: url_(url),
referrer_(referrer),
has_user_gesture_(has_user_gesture),
@@ -25,23 +22,10 @@ NavigationParams::NavigationParams(const GURL& url,
transition_type_(transition_type),
is_redirect_(is_redirect),
is_external_protocol_(is_external_protocol),
- is_main_frame_(is_main_frame) {
-}
-
-void NavigationParams::operator=(const NavigationParams& rhs) {
- Assign(rhs);
-}
+ is_main_frame_(is_main_frame),
+ base_url_for_data_url_(base_url_for_data_url) {}
-void NavigationParams::Assign(const NavigationParams& other) {
- url_ = other.url();
- referrer_ = other.referrer();
- has_user_gesture_ = other.has_user_gesture();
- is_post_ = other.is_post();
- transition_type_ = other.transition_type();
- is_redirect_ = other.is_redirect();
- is_external_protocol_ = other.is_external_protocol();
- is_main_frame_ = other.is_main_frame();
-}
+NavigationParams::NavigationParams(const NavigationParams&) = default;
} // namespace navigation_interception
diff --git a/chromium/components/navigation_interception/navigation_params.h b/chromium/components/navigation_interception/navigation_params.h
index 3417816590e..20bc7f19711 100644
--- a/chromium/components/navigation_interception/navigation_params.h
+++ b/chromium/components/navigation_interception/navigation_params.h
@@ -21,9 +21,10 @@ class NavigationParams {
ui::PageTransition page_transition_type,
bool is_redirect,
bool is_external_protocol,
- bool is_main_frame);
- NavigationParams(const NavigationParams& other);
- void operator=(const NavigationParams& rhs);
+ bool is_main_frame,
+ const GURL& base_url_for_data_url);
+ NavigationParams(const NavigationParams&);
+ NavigationParams& operator=(const NavigationParams&) = delete;
const GURL& url() const { return url_; }
GURL& url() { return url_; }
@@ -34,9 +35,9 @@ class NavigationParams {
bool is_redirect() const { return is_redirect_; }
bool is_external_protocol() const { return is_external_protocol_; }
bool is_main_frame() const { return is_main_frame_; }
+ const GURL& base_url_for_data_url() const { return base_url_for_data_url_; }
private:
- void Assign(const NavigationParams& other);
GURL url_;
content::Referrer referrer_;
@@ -46,6 +47,7 @@ class NavigationParams {
bool is_redirect_;
bool is_external_protocol_;
bool is_main_frame_;
+ GURL base_url_for_data_url_;
};
} // namespace navigation_interception
diff --git a/chromium/components/navigation_interception/navigation_params_android.cc b/chromium/components/navigation_interception/navigation_params_android.cc
index e459d36273a..a5d6dcf0d32 100644
--- a/chromium/components/navigation_interception/navigation_params_android.cc
+++ b/chromium/components/navigation_interception/navigation_params_android.cc
@@ -16,8 +16,11 @@ base::android::ScopedJavaLocalRef<jobject> CreateJavaNavigationParams(
JNIEnv* env,
const NavigationParams& params,
bool has_user_gesture_carryover) {
+ const GURL& url = params.base_url_for_data_url().is_empty()
+ ? params.url()
+ : params.base_url_for_data_url();
ScopedJavaLocalRef<jstring> jstring_url =
- ConvertUTF8ToJavaString(env, params.url().spec());
+ ConvertUTF8ToJavaString(env, url.possibly_invalid_spec());
ScopedJavaLocalRef<jstring> jstring_referrer =
ConvertUTF8ToJavaString(env, params.referrer().url.spec());
diff --git a/chromium/components/navigation_metrics/BUILD.gn b/chromium/components/navigation_metrics/BUILD.gn
index df986e8a8f2..231ff611a2d 100644
--- a/chromium/components/navigation_metrics/BUILD.gn
+++ b/chromium/components/navigation_metrics/BUILD.gn
@@ -16,3 +16,16 @@ static_library("navigation_metrics") {
"//url",
]
}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "navigation_metrics_unittest.cc",
+ ]
+ deps = [
+ ":navigation_metrics",
+ "//base/test:test_support",
+ "//testing/gtest",
+ "//url",
+ ]
+}
diff --git a/chromium/components/navigation_metrics/OWNERS b/chromium/components/navigation_metrics/OWNERS
index b88d8719e8f..e9db99ed04e 100644
--- a/chromium/components/navigation_metrics/OWNERS
+++ b/chromium/components/navigation_metrics/OWNERS
@@ -1,2 +1,4 @@
cbentzel@chromium.org
davidben@chromium.org
+
+# COMPONENT: Internals>Network
diff --git a/chromium/components/navigation_metrics/navigation_metrics.cc b/chromium/components/navigation_metrics/navigation_metrics.cc
index 8958e6d69fa..bf7d81bbee2 100644
--- a/chromium/components/navigation_metrics/navigation_metrics.cc
+++ b/chromium/components/navigation_metrics/navigation_metrics.cc
@@ -76,6 +76,15 @@ void RecordMainFrameNavigation(const GURL& url,
UMA_HISTOGRAM_ENUMERATION("Navigation.MainFrameSchemeDifferentPage", scheme,
SCHEME_MAX);
}
+
+ if (is_off_the_record) {
+ UMA_HISTOGRAM_ENUMERATION("Navigation.MainFrameSchemeOTR", scheme,
+ SCHEME_MAX);
+ if (!is_in_page) {
+ UMA_HISTOGRAM_ENUMERATION("Navigation.MainFrameSchemeDifferentPageOTR",
+ scheme, SCHEME_MAX);
+ }
+ }
}
} // namespace navigation_metrics
diff --git a/chromium/components/navigation_metrics/navigation_metrics_unittest.cc b/chromium/components/navigation_metrics/navigation_metrics_unittest.cc
new file mode 100644
index 00000000000..fc3ac335ba3
--- /dev/null
+++ b/chromium/components/navigation_metrics/navigation_metrics_unittest.cc
@@ -0,0 +1,77 @@
+// 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/navigation_metrics/navigation_metrics.h"
+
+#include "base/test/histogram_tester.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace {
+const char* const kTestUrl = "http://www.example.com";
+const char* const kMainFrameScheme = "Navigation.MainFrameScheme";
+const char* const kMainFrameSchemeDifferentPage =
+ "Navigation.MainFrameSchemeDifferentPage";
+const char* const kMainFrameSchemeOTR = "Navigation.MainFrameSchemeOTR";
+const char* const kMainFrameSchemeDifferentPageOTR =
+ "Navigation.MainFrameSchemeDifferentPageOTR";
+
+} // namespace
+
+namespace navigation_metrics {
+
+TEST(NavigationMetrics, MainFrameSchemeDifferentDocument) {
+ base::HistogramTester test;
+
+ RecordMainFrameNavigation(GURL(kTestUrl), false, false, false);
+
+ test.ExpectTotalCount(kMainFrameScheme, 1);
+ test.ExpectUniqueSample(kMainFrameScheme, 1 /* http */, 1);
+ test.ExpectTotalCount(kMainFrameSchemeDifferentPage, 1);
+ test.ExpectUniqueSample(kMainFrameSchemeDifferentPage, 1 /* http */, 1);
+ test.ExpectTotalCount(kMainFrameSchemeOTR, 0);
+ test.ExpectTotalCount(kMainFrameSchemeDifferentPageOTR, 0);
+}
+
+TEST(NavigationMetrics, MainFrameSchemeSameDocument) {
+ base::HistogramTester test;
+
+ RecordMainFrameNavigation(GURL(kTestUrl), true, false, false);
+
+ test.ExpectTotalCount(kMainFrameScheme, 1);
+ test.ExpectUniqueSample(kMainFrameScheme, 1 /* http */, 1);
+ test.ExpectTotalCount(kMainFrameSchemeDifferentPage, 0);
+ test.ExpectTotalCount(kMainFrameSchemeOTR, 0);
+ test.ExpectTotalCount(kMainFrameSchemeDifferentPageOTR, 0);
+}
+
+TEST(NavigationMetrics, MainFrameSchemeDifferentDocumentOTR) {
+ base::HistogramTester test;
+
+ RecordMainFrameNavigation(GURL(kTestUrl), false, true, false);
+
+ test.ExpectTotalCount(kMainFrameScheme, 1);
+ test.ExpectUniqueSample(kMainFrameScheme, 1 /* http */, 1);
+ test.ExpectTotalCount(kMainFrameSchemeDifferentPage, 1);
+ test.ExpectUniqueSample(kMainFrameSchemeDifferentPage, 1 /* http */, 1);
+ test.ExpectTotalCount(kMainFrameSchemeOTR, 1);
+ test.ExpectUniqueSample(kMainFrameSchemeOTR, 1 /* http */, 1);
+ test.ExpectTotalCount(kMainFrameSchemeDifferentPageOTR, 1);
+ test.ExpectUniqueSample(kMainFrameSchemeDifferentPageOTR, 1 /* http */, 1);
+}
+
+TEST(NavigationMetrics, MainFrameSchemeSameDocumentOTR) {
+ base::HistogramTester test;
+
+ RecordMainFrameNavigation(GURL(kTestUrl), true, true, false);
+
+ test.ExpectTotalCount(kMainFrameScheme, 1);
+ test.ExpectUniqueSample(kMainFrameScheme, 1 /* http */, 1);
+ test.ExpectTotalCount(kMainFrameSchemeDifferentPage, 0);
+ test.ExpectTotalCount(kMainFrameSchemeOTR, 1);
+ test.ExpectUniqueSample(kMainFrameSchemeOTR, 1 /* http */, 1);
+ test.ExpectTotalCount(kMainFrameSchemeDifferentPageOTR, 0);
+}
+
+} // namespace navigation_metrics
diff --git a/chromium/components/net_log/net_log_file_writer_unittest.cc b/chromium/components/net_log/net_log_file_writer_unittest.cc
index af2b4e0ae7d..bfae99d6b39 100644
--- a/chromium/components/net_log/net_log_file_writer_unittest.cc
+++ b/chromium/components/net_log/net_log_file_writer_unittest.cc
@@ -27,6 +27,7 @@
#include "net/http/http_network_session.h"
#include "net/log/net_log_capture_mode.h"
#include "net/log/net_log_event_type.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -191,7 +192,8 @@ void SetUpTestContextGetterWithRequest(
context->set_net_log(net_log);
context->Init();
- *request = context->CreateRequest(url, net::IDLE, delegate);
+ *request = context->CreateRequest(url, net::IDLE, delegate,
+ TRAFFIC_ANNOTATION_FOR_TESTS);
(*request)->Start();
*context_getter = new net::TestURLRequestContextGetter(
diff --git a/chromium/components/net_log/resources/net_export.css b/chromium/components/net_log/resources/net_export.css
index 0fae6394a3d..8d7783039a8 100644
--- a/chromium/components/net_log/resources/net_export.css
+++ b/chromium/components/net_log/resources/net_export.css
@@ -16,6 +16,12 @@ button {
width: 200px;
}
+button:disabled > .export-view-logging-enabled,
+button:enabled > .export-view-logging-disabled
+{
+ display: none;
+}
+
.radio-button-div {
margin: 7px auto;
}
diff --git a/chromium/components/net_log/resources/net_export.html b/chromium/components/net_log/resources/net_export.html
index b3904fff13a..48d13725070 100644
--- a/chromium/components/net_log/resources/net_export.html
+++ b/chromium/components/net_log/resources/net_export.html
@@ -16,43 +16,56 @@
<script src="chrome://net-export/net_export.js"></script>
<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
<link rel="stylesheet" href="net_export.css">
+<title>Network Log Export</title>
</head>
<body>
<h2>Network Log Export</h2>
<div id="net-export-main">
<div>
<button id="export-view-start-data" disabled>
- Start Logging to Disk
- <div class="warning" id="export-view-deletes-log-text" hidden>
- Deletes old log
- </div>
+ <span class="export-view-logging-enabled">Start Logging to Disk</span>
+ <span class="export-view-logging-disabled">Logging to Disk...</span>
+ <if expr="is_ios or is_android">
+ <div class="warning" id="export-view-mobile-deletes-log-text" hidden>
+ Deletes old log
+ </div>
+ </if>
</button>
</div>
<div>
<button id="export-view-stop-data" disabled>Stop Logging</button>
</div>
<div>
- <button id="export-view-send-data" disabled>
- Email Log
- <div class="warning" id="export-view-private-data-text" hidden>
- Log contains private information
- </div>
- <div class="warning" id="export-view-send-old-log-text" hidden>
- Log file from previous session
- </div>
- </button>
+ <if expr="is_ios or is_android">
+ <button id="export-view-mobile-send-data" disabled>
+ Email Log
+ <div class="warning" id="export-view-mobile-private-data-text" hidden>
+ Log contains private information
+ </div>
+ <div class="warning" id="export-view-mobile-send-old-log-text" hidden>
+ Log file from previous session
+ </div>
+ </button>
+ </if>
</div>
<p>
<b>INSTRUCTIONS</b>: Start logging, reproduce the problem,
- and then stop logging. Make sure to send the email before
- starting to log again. Otherwise, the log will be deleted.
+ and then stop logging.
+
+ <if expr="is_ios or is_android">
+ Once logging has stopped, click the "Email Log" button to save the
+ file. Starting a new log will overwrite the old one.
+ </if>
+
+ <if expr="not(is_ios or is_android)">
+ Once logging has stopped, attach the log file to the bug report.
+ </if>
</p>
<p>
<!-- TODO(rayraymond): Change link to that of new standalone webapp.
See http://crbug.com/472699 -->
- Logs can be loaded in
- <a href="chrome://net-internals" target="_blank">net-internals</a>
- of desktop Chrome.
+ Log files can be loaded using
+ <a href="chrome://net-internals#import" target="_blank">net-internals</a>.
</p>
<p>
<b><span class="warning">WARNING</span></b>: Logs contain a list of sites
diff --git a/chromium/components/net_log/resources/net_export.js b/chromium/components/net_log/resources/net_export.js
index b13b90d4859..3ea73c575b6 100644
--- a/chromium/components/net_log/resources/net_export.js
+++ b/chromium/components/net_log/resources/net_export.js
@@ -26,7 +26,8 @@ var NetExportView = (function() {
function NetExportView() {
$('export-view-start-data').onclick = this.onStartData_.bind(this);
$('export-view-stop-data').onclick = this.onStopData_.bind(this);
- $('export-view-send-data').onclick = this.onSendData_.bind(this);
+ if (this.useMobileUI_())
+ $('export-view-mobile-send-data').onclick = this.onSendData_.bind(this);
// Tell NetExportMessageHandler to notify the UI of future state changes
// from this point on (through onExportNetLogInfoChanged()).
@@ -64,13 +65,6 @@ var NetExportView = (function() {
* the file where NetLog data is collected.
*/
onExportNetLogInfoChanged: function(exportNetLogInfo) {
- if (!exportNetLogInfo.useMobileUI) {
- document.getElementById('export-view-send-data').style.display =
- "none";
- document.getElementById('export-view-deletes-log-text').style.display =
- "none";
- }
-
if (exportNetLogInfo.file) {
var message = '';
if (exportNetLogInfo.state == 'LOGGING')
@@ -89,9 +83,12 @@ var NetExportView = (function() {
controls[i].disabled = true;
}
- $('export-view-deletes-log-text').hidden = true;
- $('export-view-private-data-text').hidden = true;
- $('export-view-send-old-log-text').hidden = true;
+ if (this.useMobileUI_()) {
+ $('export-view-mobile-deletes-log-text').hidden = true;
+ $('export-view-mobile-private-data-text').hidden = true;
+ $('export-view-mobile-send-old-log-text').hidden = true;
+ }
+
if (exportNetLogInfo.state == 'NOT_LOGGING') {
// Allow making a new log.
$('export-view-strip-private-data-button').disabled = false;
@@ -99,14 +96,15 @@ var NetExportView = (function() {
$('export-view-log-bytes-button').disabled = false;
$('export-view-start-data').disabled = false;
- // If there's an existing log, allow sending it.
- if (!!exportNetLogInfo.logExists) {
- $('export-view-deletes-log-text').hidden = false;
- $('export-view-send-data').disabled = false;
+ // If there's a pre-existing log, allow sending it (this only
+ // applies to the mobile UI).
+ if (this.useMobileUI_() && exportNetLogInfo.logExists) {
+ $('export-view-mobile-deletes-log-text').hidden = false;
+ $('export-view-mobile-send-data').disabled = false;
if (!exportNetLogInfo.logCaptureModeKnown) {
- $('export-view-send-old-log-text').hidden = false;
+ $('export-view-mobile-send-old-log-text').hidden = false;
} else if (exportNetLogInfo.captureMode != 'STRIP_PRIVATE_DATA') {
- $('export-view-private-data-text').hidden = false;
+ $('export-view-mobile-private-data-text').hidden = false;
}
}
} else if (exportNetLogInfo.state == 'LOGGING') {
@@ -121,6 +119,14 @@ var NetExportView = (function() {
$('export-view-file-path-text').textContent =
'Unable to initialize NetLog data file.';
}
+ },
+
+ /*
+ * Returns true if the UI is being displayed for mobile, otherwise false
+ * for desktop. This is controlled by the HTML template.
+ */
+ useMobileUI_: function() {
+ return !!document.getElementById('export-view-mobile-send-data');
}
};
diff --git a/chromium/components/neterror/OWNERS b/chromium/components/neterror/OWNERS
index 9f303e4e6fc..0dd67b9f8ba 100644
--- a/chromium/components/neterror/OWNERS
+++ b/chromium/components/neterror/OWNERS
@@ -1,4 +1,6 @@
jar@chromium.org
mmenke@chromium.org
juliatuttle@chromium.org
-edwardjung@chromium.org \ No newline at end of file
+edwardjung@chromium.org
+
+# COMPONENT: Internals>Network
diff --git a/chromium/components/neterror/resources/neterror.css b/chromium/components/neterror/resources/neterror.css
index f83710b2616..4649cd82bbb 100644
--- a/chromium/components/neterror/resources/neterror.css
+++ b/chromium/components/neterror/resources/neterror.css
@@ -397,6 +397,7 @@ html[subframe] body {
}
.offline .runner-container {
+ direction: ltr;
height: 150px;
max-width: 600px;
overflow: hidden;
diff --git a/chromium/components/neterror/resources/offline.js b/chromium/components/neterror/resources/offline.js
index 79ffa5c4da8..ed3582f278d 100644
--- a/chromium/components/neterror/resources/offline.js
+++ b/chromium/components/neterror/resources/offline.js
@@ -20,7 +20,6 @@ function Runner(outerContainerId, opt_config) {
this.outerContainerEl = document.querySelector(outerContainerId);
this.containerEl = null;
this.snackbarEl = null;
- this.detailsButton = this.outerContainerEl.querySelector('#details-button');
this.config = opt_config || Runner.config;
@@ -661,9 +660,11 @@ Runner.prototype = {
e.preventDefault();
}
- if (e.target != this.detailsButton) {
- if (!this.crashed && (Runner.keycodes.JUMP[e.keyCode] ||
- e.type == Runner.events.TOUCHSTART)) {
+ if (!this.crashed && !this.paused) {
+ if (Runner.keycodes.JUMP[e.keyCode] ||
+ e.type == Runner.events.TOUCHSTART) {
+ e.preventDefault();
+ // Starting the game for the first time.
if (!this.playing) {
this.loadSounds();
this.playing = true;
@@ -672,28 +673,24 @@ Runner.prototype = {
errorPageController.trackEasterEgg();
}
}
- // Play sound effect and jump on starting the game for the first time.
+ // Start jump.
if (!this.tRex.jumping && !this.tRex.ducking) {
this.playSound(this.soundFx.BUTTON_PRESS);
this.tRex.startJump(this.currentSpeed);
}
+ } else if (this.playing && Runner.keycodes.DUCK[e.keyCode]) {
+ e.preventDefault();
+ if (this.tRex.jumping) {
+ // Speed drop, activated only when jump key is not pressed.
+ this.tRex.setSpeedDrop();
+ } else if (!this.tRex.jumping && !this.tRex.ducking) {
+ // Duck.
+ this.tRex.setDuck(true);
+ }
}
-
- if (this.crashed && e.type == Runner.events.TOUCHSTART &&
- e.currentTarget == this.containerEl) {
- this.restart();
- }
- }
-
- if (this.playing && !this.crashed && Runner.keycodes.DUCK[e.keyCode]) {
- e.preventDefault();
- if (this.tRex.jumping) {
- // Speed drop, activated only when jump key is not pressed.
- this.tRex.setSpeedDrop();
- } else if (!this.tRex.jumping && !this.tRex.ducking) {
- // Duck.
- this.tRex.setDuck(true);
- }
+ } else if (this.crashed && e.type == Runner.events.TOUCHSTART &&
+ e.currentTarget == this.containerEl) {
+ this.restart();
}
},
@@ -812,6 +809,7 @@ Runner.prototype = {
this.playCount++;
this.runningTime = 0;
this.playing = true;
+ this.paused = false;
this.crashed = false;
this.distanceRan = 0;
this.setSpeed(this.config.SPEED);
diff --git a/chromium/components/network_hints/common/BUILD.gn b/chromium/components/network_hints/common/BUILD.gn
index 9cba7b7192b..b8ade78addb 100644
--- a/chromium/components/network_hints/common/BUILD.gn
+++ b/chromium/components/network_hints/common/BUILD.gn
@@ -15,8 +15,11 @@ static_library("common") {
deps = [
"//base",
"//content/public/common",
- "//ipc",
"//ui/accessibility",
"//url",
]
+
+ public_deps = [
+ "//ipc",
+ ]
}
diff --git a/chromium/components/network_hints/common/network_hints_messages.h b/chromium/components/network_hints/common/network_hints_messages.h
index bc4d163a4d1..82fce8f0f93 100644
--- a/chromium/components/network_hints/common/network_hints_messages.h
+++ b/chromium/components/network_hints/common/network_hints_messages.h
@@ -9,7 +9,6 @@
#include "components/network_hints/common/network_hints_common.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_message_utils.h"
-#include "third_party/WebKit/public/platform/WebNavigationHintType.h"
#include "url/ipc/url_param_traits.h"
// Singly-included section for custom IPC traits.
@@ -34,9 +33,6 @@ struct ParamTraits<network_hints::LookupRequest> {
#define IPC_MESSAGE_START NetworkHintsMsgStart
-IPC_ENUM_TRAITS_MAX_VALUE(blink::WebNavigationHintType,
- blink::WebNavigationHintType::Last)
-
//-----------------------------------------------------------------------------
// Host messages
// These are messages sent from the renderer process to the browser process.
@@ -52,8 +48,3 @@ IPC_MESSAGE_CONTROL3(NetworkHintsMsg_Preconnect,
GURL /* preconnect target url */,
bool /* Does connection have its credentials flag set */,
int /* number of connections */)
-
-// Request to trigger possible optimizations for navigation.
-IPC_MESSAGE_CONTROL2(NetworkHintsMsg_NavigationHint,
- GURL /* document url */,
- blink::WebNavigationHintType /* navigation hint type */)
diff --git a/chromium/components/network_hints/renderer/prescient_networking_dispatcher.cc b/chromium/components/network_hints/renderer/prescient_networking_dispatcher.cc
index 7284bc2f5bb..4ae1e1a943a 100644
--- a/chromium/components/network_hints/renderer/prescient_networking_dispatcher.cc
+++ b/chromium/components/network_hints/renderer/prescient_networking_dispatcher.cc
@@ -5,10 +5,6 @@
#include "components/network_hints/renderer/prescient_networking_dispatcher.h"
#include "base/logging.h"
-#include "components/network_hints/common/network_hints_messages.h"
-#include "content/public/renderer/render_thread.h"
-
-using content::RenderThread;
namespace network_hints {
@@ -18,28 +14,20 @@ PrescientNetworkingDispatcher::PrescientNetworkingDispatcher() {
PrescientNetworkingDispatcher::~PrescientNetworkingDispatcher() {
}
-void PrescientNetworkingDispatcher::prefetchDNS(
+void PrescientNetworkingDispatcher::PrefetchDNS(
const blink::WebString& hostname) {
- VLOG(2) << "Prefetch DNS: " << hostname.utf8();
- if (hostname.isEmpty())
+ VLOG(2) << "Prefetch DNS: " << hostname.Utf8();
+ if (hostname.IsEmpty())
return;
- std::string hostname_utf8 = hostname.utf8();
+ std::string hostname_utf8 = hostname.Utf8();
dns_prefetch_.Resolve(hostname_utf8.data(), hostname_utf8.length());
}
-void PrescientNetworkingDispatcher::preconnect(const blink::WebURL& url,
+void PrescientNetworkingDispatcher::Preconnect(const blink::WebURL& url,
bool allow_credentials) {
- VLOG(2) << "Preconnect: " << url.string().utf8();
+ VLOG(2) << "Preconnect: " << url.GetString().Utf8();
preconnect_.Preconnect(url, allow_credentials);
}
-void PrescientNetworkingDispatcher::sendNavigationHint(
- const blink::WebURL& url,
- blink::WebNavigationHintType type) {
- if (!url.isValid())
- return;
- RenderThread::Get()->Send(new NetworkHintsMsg_NavigationHint(url, type));
-}
-
} // namespace network_hints
diff --git a/chromium/components/network_hints/renderer/prescient_networking_dispatcher.h b/chromium/components/network_hints/renderer/prescient_networking_dispatcher.h
index c7f68ec4374..4991aae0ec8 100644
--- a/chromium/components/network_hints/renderer/prescient_networking_dispatcher.h
+++ b/chromium/components/network_hints/renderer/prescient_networking_dispatcher.h
@@ -10,10 +10,6 @@
#include "components/network_hints/renderer/renderer_preconnect.h"
#include "third_party/WebKit/public/platform/WebPrescientNetworking.h"
-namespace blink {
-enum class WebNavigationHintType;
-}
-
namespace network_hints {
// The main entry point from blink for sending DNS prefetch requests to the
@@ -23,11 +19,9 @@ class PrescientNetworkingDispatcher : public blink::WebPrescientNetworking {
PrescientNetworkingDispatcher();
~PrescientNetworkingDispatcher() override;
- void prefetchDNS(const blink::WebString& hostname) override;
- void preconnect(const blink::WebURL& url,
+ void PrefetchDNS(const blink::WebString& hostname) override;
+ void Preconnect(const blink::WebURL& url,
const bool allow_credentials) override;
- void sendNavigationHint(const blink::WebURL& url,
- blink::WebNavigationHintType type) override;
private:
network_hints::RendererDnsPrefetch dns_prefetch_;
diff --git a/chromium/components/network_session_configurator/network_session_configurator.cc b/chromium/components/network_session_configurator/network_session_configurator.cc
index 91a2b15ab08..00ab3d3c34f 100644
--- a/chromium/components/network_session_configurator/network_session_configurator.cc
+++ b/chromium/components/network_session_configurator/network_session_configurator.cc
@@ -107,11 +107,19 @@ bool ShouldEnableQuic(base::StringPiece quic_trial_group,
"true");
}
-bool ShouldDisableQuicWhenConnectionTimesOutWithOpenStreams(
+bool ShouldMarkQuicBrokenWhenNetworkBlackholes(
const VariationParameters& quic_trial_params) {
return base::LowerCaseEqualsASCII(
GetVariationParam(quic_trial_params,
- "disable_quic_on_timeout_with_open_streams"),
+ "mark_quic_broken_when_network_blackholes"),
+ "true");
+}
+
+bool ShouldRetryWithoutAltSvcOnQuicErrors(
+ const VariationParameters& quic_trial_params) {
+ return base::LowerCaseEqualsASCII(
+ GetVariationParam(quic_trial_params,
+ "retry_without_alt_svc_on_quic_errors"),
"true");
}
@@ -333,9 +341,10 @@ void ConfigureQuicParams(base::StringPiece quic_trial_group,
params->enable_quic = ShouldEnableQuic(
quic_trial_group, quic_trial_params, is_quic_force_disabled,
is_quic_force_enabled);
- params->disable_quic_on_timeout_with_open_streams =
- ShouldDisableQuicWhenConnectionTimesOutWithOpenStreams(quic_trial_params);
-
+ params->mark_quic_broken_when_network_blackholes =
+ ShouldMarkQuicBrokenWhenNetworkBlackholes(quic_trial_params);
+ params->retry_without_alt_svc_on_quic_errors =
+ ShouldRetryWithoutAltSvcOnQuicErrors(quic_trial_params);
params->enable_quic_alternative_service_with_different_host =
ShouldQuicEnableAlternativeServicesForDifferentHost(quic_trial_params);
diff --git a/chromium/components/network_session_configurator/network_session_configurator_unittest.cc b/chromium/components/network_session_configurator/network_session_configurator_unittest.cc
index 1832dfddce5..799f9ca4023 100644
--- a/chromium/components/network_session_configurator/network_session_configurator_unittest.cc
+++ b/chromium/components/network_session_configurator/network_session_configurator_unittest.cc
@@ -67,7 +67,8 @@ TEST_F(NetworkSessionConfiguratorTest, EnableQuicFromFieldTrialGroup) {
ParseFieldTrials();
EXPECT_TRUE(params_.enable_quic);
- EXPECT_FALSE(params_.disable_quic_on_timeout_with_open_streams);
+ EXPECT_FALSE(params_.mark_quic_broken_when_network_blackholes);
+ EXPECT_FALSE(params_.retry_without_alt_svc_on_quic_errors);
EXPECT_EQ(1350u, params_.quic_max_packet_length);
EXPECT_EQ(net::QuicTagVector(), params_.quic_connection_options);
EXPECT_FALSE(params_.quic_always_require_handshake_confirmation);
@@ -122,15 +123,26 @@ TEST_F(NetworkSessionConfiguratorTest, EnableQuicForDataReductionProxy) {
}
TEST_F(NetworkSessionConfiguratorTest,
- DisableQuicWhenConnectionTimesOutWithOpenStreamsFromFieldTrialParams) {
+ MarkQuicBrokenWhenNetworkBlackholesFromFieldTrialParams) {
std::map<std::string, std::string> field_trial_params;
- field_trial_params["disable_quic_on_timeout_with_open_streams"] = "true";
+ field_trial_params["mark_quic_broken_when_network_blackholes"] = "true";
variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
ParseFieldTrials();
- EXPECT_TRUE(params_.disable_quic_on_timeout_with_open_streams);
+ EXPECT_TRUE(params_.mark_quic_broken_when_network_blackholes);
+}
+
+TEST_F(NetworkSessionConfiguratorTest, RetryWithoutAltSvcOnQuicErrors) {
+ std::map<std::string, std::string> field_trial_params;
+ field_trial_params["retry_without_alt_svc_on_quic_errors"] = "true";
+ variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
+ base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
+
+ ParseFieldTrials();
+
+ EXPECT_TRUE(params_.retry_without_alt_svc_on_quic_errors);
}
TEST_F(NetworkSessionConfiguratorTest,
diff --git a/chromium/components/network_time/network_time_tracker.cc b/chromium/components/network_time/network_time_tracker.cc
index 10cd0912517..b5d8ccb8538 100644
--- a/chromium/components/network_time/network_time_tracker.cc
+++ b/chromium/components/network_time/network_time_tracker.cc
@@ -11,6 +11,7 @@
#include "base/i18n/time_formatting.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/rand_util.h"
@@ -28,6 +29,7 @@
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_response_writer.h"
#include "net/url_request/url_request_context_getter.h"
@@ -188,7 +190,7 @@ void RecordFetchValidHistogram(bool valid) {
// static
void NetworkTimeTracker::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(prefs::kNetworkTimeMapping,
- new base::DictionaryValue());
+ base::MakeUnique<base::DictionaryValue>());
}
NetworkTimeTracker::NetworkTimeTracker(
@@ -459,8 +461,28 @@ void NetworkTimeTracker::CheckTime() {
replacements.SetQueryStr(query_string);
url = url.ReplaceComponents(replacements);
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("network_time_component", R"(
+ semantics {
+ sender: "Network Time Component"
+ description:
+ "Sends a request to a Google server to retrieve the current "
+ "timestamp."
+ trigger:
+ "A request can be sent to retrieve the current time when the user "
+ "encounters an SSL date error, or in the background if Chromium "
+ "determines that it doesn't have an accurate timestamp."
+ data: "None"
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting: "This feature cannot be disabled by settings."
+ policy_exception_justification: "Not implemented."
+ })");
// This cancels any outstanding fetch.
- time_fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
+ time_fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this,
+ traffic_annotation);
if (!time_fetcher_) {
DVLOG(1) << "tried to make fetch happen; failed";
return;
diff --git a/chromium/components/new_or_sad_tab_strings.grdp b/chromium/components/new_or_sad_tab_strings.grdp
index 696464b8db6..03b87efbe7a 100644
--- a/chromium/components/new_or_sad_tab_strings.grdp
+++ b/chromium/components/new_or_sad_tab_strings.grdp
@@ -143,20 +143,26 @@
<!-- Incognito Tab redesign strings -->
<!-- TODO(msramek): Merge with the above section once this is fully launched. -->
- <message name="IDS_NEW_TAB_OTR_TITLE" desc="Title of the Incognito new tab page." formatter_data="android_java">
+ <message name="IDS_NEW_TAB_OTR_TITLE" desc="Title of the Incognito new tab page. The Incognito mode provides private browsing experience by hiding browsing activity from other people using the same device. However, it does not make the user completely invisible or anonymous; please don't translate it as such." formatter_data="android_java" translateable="false">
You’ve gone incognito
</message>
- <message name="IDS_NEW_TAB_OTR_SUBTITLE" 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 device." formatter_data="android_java">
- Now you can browse in private, and other people who use this device won’t see your activity.
- </message>
- <message name="IDS_NEW_TAB_OTR_DISCLAIMER" desc="A disclaimer on the Incognito new tab page, explaining to the user that downloaded files and added bookmarks will be persisted even after the Incognito session is closed." formatter_data="android_java">
- Downloaded files and bookmarks will be kept.
- </message>
- <message name="IDS_NEW_TAB_OTR_NOT_SAVED_BULLET_POINTS" desc="Bullet points listing data that are not saved in the Incognito mode. The '#' character in this text represents a bullet point. Please keep it unchanged and do not add additional spaces around it. The text between the pair of '|' characters will be highlighted." formatter_data="android_java">
- This information |won’t be saved|:#Your browsing history#Your searches#Cookie data
- </message>
- <message name="IDS_NEW_TAB_OTR_VISIBLE" desc="Bullet points listing entities that might be able to see the user's Incognito activity. The '#' character in this text represents a bullet point. Please keep it unchanged and do not add additional spaces around it. The text between the pair of '|' characters will be highlighted." formatter_data="android_java">
- Your activity |might still be visible| to:#Websites you visit#Your employer#Your internet service provider
+ <message name="IDS_NEW_TAB_OTR_SUBTITLE" 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" translateable="false">
+ Now you can browse privately, and other people who use this device won’t see your activity. However, downloads and bookmarks 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.)." formatter_data="android_java" translateable="false">
+ 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="END_LIST">&lt;/ul&gt;</ph>
+ </message>
+ <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" translateable="false">
+ 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>
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Websites you visit
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Your employer or school
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Your internet service provider
+ <ph name="END_LIST">&lt;/ul&gt;</ph>
</message>
</grit-part>
diff --git a/chromium/components/ntp_snippets/BUILD.gn b/chromium/components/ntp_snippets/BUILD.gn
index 15a008ba016..0cf1874adc8 100644
--- a/chromium/components/ntp_snippets/BUILD.gn
+++ b/chromium/components/ntp_snippets/BUILD.gn
@@ -47,6 +47,10 @@ static_library("ntp_snippets") {
"pref_names.h",
"pref_util.cc",
"pref_util.h",
+ "reading_list/reading_list_distillation_state_util.cc",
+ "reading_list/reading_list_distillation_state_util.h",
+ "reading_list/reading_list_suggestions_provider.cc",
+ "reading_list/reading_list_suggestions_provider.h",
"remote/json_request.cc",
"remote/json_request.h",
"remote/persistent_scheduler.h",
@@ -61,14 +65,14 @@ static_library("ntp_snippets") {
"remote/remote_suggestions_provider_impl.cc",
"remote/remote_suggestions_provider_impl.h",
"remote/remote_suggestions_scheduler.h",
+ "remote/remote_suggestions_scheduler_impl.cc",
+ "remote/remote_suggestions_scheduler_impl.h",
"remote/remote_suggestions_status_service.cc",
"remote/remote_suggestions_status_service.h",
"remote/request_params.cc",
"remote/request_params.h",
"remote/request_throttler.cc",
"remote/request_throttler.h",
- "remote/scheduling_remote_suggestions_provider.cc",
- "remote/scheduling_remote_suggestions_provider.h",
"sessions/foreign_sessions_suggestions_provider.cc",
"sessions/foreign_sessions_suggestions_provider.h",
"sessions/tab_delegate_sync_adapter.cc",
@@ -99,20 +103,25 @@ static_library("ntp_snippets") {
deps = [
"//components/bookmarks/browser",
"//components/data_use_measurement/core",
+ "//components/favicon/core",
+ "//components/favicon_base",
"//components/history/core/browser",
- "//components/image_fetcher",
+ "//components/image_fetcher/core",
"//components/metrics",
"//components/ntp_snippets/remote/proto",
"//components/offline_pages/core",
"//components/offline_pages/core/downloads:offline_pages_ui_adapter",
"//components/offline_pages/core/recent_tabs",
"//components/physical_web/data_source",
+ "//components/reading_list/core",
"//components/sessions",
"//components/strings",
"//components/sync_sessions",
"//components/translate/core/browser",
+ "//components/url_formatter",
"//components/variations",
"//components/variations/net",
+ "//components/web_resource",
"//third_party/icu/",
"//ui/gfx",
]
@@ -124,6 +133,7 @@ if (is_android) {
"category.h",
"category_info.h",
"category_status.h",
+ "content_suggestions_service.cc",
]
}
}
@@ -140,18 +150,20 @@ source_set("unit_tests") {
"content_suggestions_service_unittest.cc",
"offline_pages/recent_tab_suggestions_provider_unittest.cc",
"physical_web_pages/physical_web_page_suggestions_provider_unittest.cc",
+ "reading_list/reading_list_suggestions_provider_unittest.cc",
"remote/json_request_unittest.cc",
"remote/remote_suggestion_unittest.cc",
"remote/remote_suggestions_database_unittest.cc",
"remote/remote_suggestions_fetcher_unittest.cc",
"remote/remote_suggestions_provider_impl_unittest.cc",
+ "remote/remote_suggestions_scheduler_impl_unittest.cc",
"remote/remote_suggestions_status_service_unittest.cc",
"remote/request_throttler_unittest.cc",
- "remote/scheduling_remote_suggestions_provider_unittest.cc",
"remote/test_utils.cc",
"remote/test_utils.h",
"sessions/foreign_sessions_suggestions_provider_unittest.cc",
"sessions/tab_delegate_sync_adapter_unittest.cc",
+ "user_classifier_unittest.cc",
]
deps = [
@@ -161,7 +173,7 @@ source_set("unit_tests") {
"//base/test:test_support",
"//components/bookmarks/browser",
"//components/bookmarks/test",
- "//components/image_fetcher",
+ "//components/image_fetcher/core",
"//components/leveldb_proto:test_support",
"//components/ntp_snippets/remote/proto",
"//components/offline_pages/core",
@@ -170,6 +182,7 @@ source_set("unit_tests") {
"//components/offline_pages/core/downloads:offline_pages_ui_adapter",
"//components/offline_pages/core/recent_tabs",
"//components/physical_web/data_source:test_support",
+ "//components/reading_list/core",
"//components/sessions",
"//components/sessions:test_support",
"//components/signin/core/browser:test_support",
@@ -178,6 +191,7 @@ source_set("unit_tests") {
"//components/sync:test_support_driver",
"//components/sync_sessions",
"//components/variations:test_support",
+ "//components/web_resource:web_resource",
"//net:test_support",
"//testing/gtest",
"//third_party/icu/",
diff --git a/chromium/components/ntp_snippets/DEPS b/chromium/components/ntp_snippets/DEPS
index 390ae748d82..777f897e174 100644
--- a/chromium/components/ntp_snippets/DEPS
+++ b/chromium/components/ntp_snippets/DEPS
@@ -1,17 +1,22 @@
include_rules = [
"+components/data_use_measurement/core",
+ "+components/favicon/core",
+ "+components/favicon_base",
"+components/history/core",
"+components/image_fetcher",
"+components/keyed_service/core",
"+components/leveldb_proto",
"+components/metrics",
"+components/prefs",
+ "+components/reading_list",
"+components/signin",
"+components/strings/grit/components_strings.h",
"+components/sync/driver",
"+components/translate/core/browser",
+ "+components/url_formatter",
"+components/variations",
"+components/version_info",
+ "+components/web_resource",
"+grit/components_strings.h",
"+net/base",
"+net/http",
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc b/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc
index 21ecd8112fc..c26887102cb 100644
--- a/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc
@@ -11,6 +11,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "components/bookmarks/browser/bookmark_model.h"
@@ -29,9 +30,8 @@ struct RecentBookmark {
base::Time last_visited;
};
-const char* kBookmarksURLBlacklist[] = {"chrome://newtab/",
- "chrome-native://newtab/",
- "chrome://bookmarks/"};
+const char* kBookmarksURLBlacklist[] = {
+ "chrome://newtab/", "chrome-native://newtab/", "chrome://bookmarks/"};
const char kBookmarkLastVisitDateOnMobileKey[] = "last_visited";
const char kBookmarkLastVisitDateOnDesktopKey[] = "last_visited_desktop";
@@ -106,10 +106,11 @@ void UpdateBookmarkOnURLVisitedInMainFrame(BookmarkModel* bookmark_model,
// If there are bookmarks for |url|, set their last visit date to now.
std::string now = FormatLastVisitDate(base::Time::Now());
for (const BookmarkNode* node : bookmarks_for_url) {
- bookmark_model->SetNodeMetaInfo(
- node, is_mobile_platform ? kBookmarkLastVisitDateOnMobileKey
- : kBookmarkLastVisitDateOnDesktopKey,
- now);
+ bookmark_model->SetNodeMetaInfo(node,
+ is_mobile_platform
+ ? kBookmarkLastVisitDateOnMobileKey
+ : kBookmarkLastVisitDateOnDesktopKey,
+ now);
// If the bookmark has been dismissed from NTP before, a new visit overrides
// such a dismissal.
bookmark_model->DeleteNodeMetaInfo(node, kBookmarkDismissedFromNTP);
@@ -243,22 +244,19 @@ std::vector<const BookmarkNode*> GetDismissedBookmarksForDebugging(
bookmark_model->GetBookmarks(&bookmarks);
// Remove the bookmark URLs which have at least one non-dismissed bookmark.
- bookmarks.erase(
- std::remove_if(
- bookmarks.begin(), bookmarks.end(),
- [&bookmark_model](const BookmarkModel::URLAndTitle& bookmark) {
- std::vector<const BookmarkNode*> bookmarks_for_url;
- bookmark_model->GetNodesByURL(bookmark.url, &bookmarks_for_url);
- DCHECK(!bookmarks_for_url.empty());
-
- for (const BookmarkNode* node : bookmarks_for_url) {
- if (!IsDismissedFromNTPForBookmark(*node)) {
- return true;
- }
- }
- return false;
- }),
- bookmarks.end());
+ base::EraseIf(
+ bookmarks, [&bookmark_model](const BookmarkModel::URLAndTitle& bookmark) {
+ std::vector<const BookmarkNode*> bookmarks_for_url;
+ bookmark_model->GetNodesByURL(bookmark.url, &bookmarks_for_url);
+ DCHECK(!bookmarks_for_url.empty());
+
+ for (const BookmarkNode* node : bookmarks_for_url) {
+ if (!IsDismissedFromNTPForBookmark(*node)) {
+ return true;
+ }
+ }
+ return false;
+ });
// Insert into |result|.
std::vector<const BookmarkNode*> result;
@@ -306,7 +304,7 @@ void RemoveLastVisitedDatesBetween(const base::Time& begin,
ClearLastVisitedMetadataIfBetween(bookmark_model, *bookmark, begin, end,
kBookmarkLastVisitDateOnMobileKey);
ClearLastVisitedMetadataIfBetween(bookmark_model, *bookmark, begin, end,
- kBookmarkLastVisitDateOnDesktopKey);
+ kBookmarkLastVisitDateOnDesktopKey);
}
}
}
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils_unittest.cc b/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils_unittest.cc
index 6f0652717f9..cacb077e328 100644
--- a/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils_unittest.cc
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils_unittest.cc
@@ -161,7 +161,7 @@ TEST_F(GetRecentlyVisitedBookmarksTest, ShouldReturnNotMoreThanMaxCount) {
namespace {
base::Callback<bool(const GURL& url)> DeleteAllFilter() {
- return base::Bind([] (const GURL& url) { return true; });
+ return base::Bind([](const GURL& url) { return true; });
}
base::Callback<bool(const GURL& url)> DeleteOneURLFilter(
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
index b236af719a5..436e8bcee05 100644
--- a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
@@ -110,8 +110,7 @@ CategoryInfo BookmarkSuggestionsProvider::GetCategoryInfo(Category category) {
return CategoryInfo(
l10n_util::GetStringUTF16(IDS_NTP_BOOKMARK_SUGGESTIONS_SECTION_HEADER),
ContentSuggestionsCardLayout::MINIMAL_CARD,
- /*has_fetch_action=*/false,
- /*has_view_all_action=*/true,
+ ContentSuggestionsAdditionalAction::VIEW_ALL,
/*show_if_empty=*/false,
l10n_util::GetStringUTF16(IDS_NTP_BOOKMARK_SUGGESTIONS_SECTION_EMPTY));
}
@@ -231,11 +230,11 @@ void BookmarkSuggestionsProvider::BookmarkMetaInfoChanged(
}
void BookmarkSuggestionsProvider::BookmarkNodeRemoved(
- bookmarks::BookmarkModel* model,
- const bookmarks::BookmarkNode* parent,
- int old_index,
- const bookmarks::BookmarkNode* node,
- const std::set<GURL>& no_longer_bookmarked) {
+ bookmarks::BookmarkModel* model,
+ const bookmarks::BookmarkNode* parent,
+ int old_index,
+ const bookmarks::BookmarkNode* node,
+ const std::set<GURL>& no_longer_bookmarked) {
base::Time time;
if (GetLastVisitDateForNTPBookmark(
*node, consider_bookmark_visits_from_desktop_, &time) &&
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
index 19d30bbe2aa..64cd6e25d1a 100644
--- a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
@@ -68,12 +68,11 @@ class BookmarkSuggestionsProvider : public ContentSuggestionsProvider,
void BookmarkNodeAdded(bookmarks::BookmarkModel* model,
const bookmarks::BookmarkNode* parent,
int index) override;
- void BookmarkNodeRemoved(
- bookmarks::BookmarkModel* model,
- const bookmarks::BookmarkNode* parent,
- int old_index,
- const bookmarks::BookmarkNode* node,
- const std::set<GURL>& no_longer_bookmarked) override;
+ void BookmarkNodeRemoved(bookmarks::BookmarkModel* model,
+ const bookmarks::BookmarkNode* parent,
+ int old_index,
+ const bookmarks::BookmarkNode* node,
+ const std::set<GURL>& no_longer_bookmarked) override;
void BookmarkNodeChanged(bookmarks::BookmarkModel* model,
const bookmarks::BookmarkNode* node) override {}
void BookmarkNodeFaviconChanged(
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider_unittest.cc b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider_unittest.cc
index 4c0cda9054a..92682d579b7 100644
--- a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider_unittest.cc
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider_unittest.cc
@@ -38,9 +38,10 @@ class BookmarkSuggestionsProviderTest : public ::testing::Test {
public:
BookmarkSuggestionsProviderTest()
: model_(bookmarks::TestBookmarkClient::CreateModel()) {
- EXPECT_CALL(observer_, OnNewSuggestions(_, Category::FromKnownCategory(
- KnownCategories::BOOKMARKS),
- IsEmpty()))
+ EXPECT_CALL(observer_,
+ OnNewSuggestions(
+ _, Category::FromKnownCategory(KnownCategories::BOOKMARKS),
+ IsEmpty()))
.RetiresOnSaturation();
EXPECT_CALL(observer_,
OnCategoryStatusChanged(
@@ -64,8 +65,7 @@ class BookmarkSuggestionsProviderTest : public ::testing::Test {
std::unique_ptr<BookmarkSuggestionsProvider> provider_;
};
-TEST_F(BookmarkSuggestionsProviderTest,
- ShouldProvideBookmarkSuggestions) {
+TEST_F(BookmarkSuggestionsProviderTest, ShouldProvideBookmarkSuggestions) {
GURL url("http://my-new-bookmarked.url");
// Note, this update to the model does not trigger OnNewSuggestions() on the
// observer as the provider realizes no new nodes were added.
@@ -125,12 +125,13 @@ TEST_F(BookmarkSuggestionsProviderTest,
EXPECT_THAT(IsDismissedFromNTPForBookmark(*dismissed_node), Eq(true));
// Clear history and make sure the suggestions actually get removed.
- EXPECT_CALL(observer_, OnNewSuggestions(_, Category::FromKnownCategory(
- KnownCategories::BOOKMARKS),
- IsEmpty()));
+ EXPECT_CALL(observer_,
+ OnNewSuggestions(
+ _, Category::FromKnownCategory(KnownCategories::BOOKMARKS),
+ IsEmpty()));
static_cast<ContentSuggestionsProvider*>(provider_.get())
->ClearHistory(base::Time(), base::Time::Max(),
- base::Bind([] (const GURL& url) { return true; }));
+ base::Bind([](const GURL& url) { return true; }));
// Verify the dismissed marker is gone.
EXPECT_THAT(IsDismissedFromNTPForBookmark(*dismissed_node), Eq(false));
@@ -143,4 +144,3 @@ TEST_F(BookmarkSuggestionsProviderTest,
} // namespace
} // namespace ntp_snippets
-
diff --git a/chromium/components/ntp_snippets/category.cc b/chromium/components/ntp_snippets/category.cc
index 0a3fc04b3be..1ef1bed9385 100644
--- a/chromium/components/ntp_snippets/category.cc
+++ b/chromium/components/ntp_snippets/category.cc
@@ -22,9 +22,10 @@ Category Category::FromRemoteCategory(int remote_category) {
// static
Category Category::FromIDValue(int id) {
- DCHECK(IsValidIDValue(id)) << id << " is not a valid category ID. This may "
- "have been caused by removal of a local "
- "KnownCategory.";
+ DCHECK(IsValidIDValue(id)) << id
+ << " is not a valid category ID. This may have "
+ "been caused by removal of a local "
+ "KnownCategory.";
return Category(id);
}
diff --git a/chromium/components/ntp_snippets/category.h b/chromium/components/ntp_snippets/category.h
index d3859fba5a2..97abf753c9b 100644
--- a/chromium/components/ntp_snippets/category.h
+++ b/chromium/components/ntp_snippets/category.h
@@ -34,6 +34,9 @@ enum class KnownCategories {
// Pages recently browsed to on other devices.
FOREIGN_TABS,
+ // Pages from the user reading list.
+ READING_LIST,
+
// ****************** INSERT NEW LOCAL CATEGORIES HERE! ******************
// Existing categories are persisted and they must never be removed. This may
// happen implicitly, e.g. when an older version without some local category
diff --git a/chromium/components/ntp_snippets/category_info.cc b/chromium/components/ntp_snippets/category_info.cc
index e8b32ea52a1..51346473b3c 100644
--- a/chromium/components/ntp_snippets/category_info.cc
+++ b/chromium/components/ntp_snippets/category_info.cc
@@ -8,14 +8,12 @@ namespace ntp_snippets {
CategoryInfo::CategoryInfo(const base::string16& title,
ContentSuggestionsCardLayout card_layout,
- bool has_fetch_action,
- bool has_view_all_action,
+ ContentSuggestionsAdditionalAction additional_action,
bool show_if_empty,
const base::string16& no_suggestions_message)
: title_(title),
card_layout_(card_layout),
- has_fetch_action_(has_fetch_action),
- has_view_all_action_(has_view_all_action),
+ additional_action_(additional_action),
show_if_empty_(show_if_empty),
no_suggestions_message_(no_suggestions_message) {}
diff --git a/chromium/components/ntp_snippets/category_info.h b/chromium/components/ntp_snippets/category_info.h
index a85e867a232..88d01bba5f1 100644
--- a/chromium/components/ntp_snippets/category_info.h
+++ b/chromium/components/ntp_snippets/category_info.h
@@ -20,13 +20,26 @@ enum class ContentSuggestionsCardLayout {
MINIMAL_CARD
};
+// On Android builds, a Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.suggestions
+enum class ContentSuggestionsAdditionalAction {
+ // No additional action available.
+ NONE,
+
+ // More suggestions can be fetched using the Fetch methods with this category.
+ FETCH,
+
+ // Open a new surface dedicated to the content related to this category. The
+ // UI has to choose which surface to open.
+ VIEW_ALL
+};
+
// Contains static meta information about a Category.
class CategoryInfo {
public:
CategoryInfo(const base::string16& title,
ContentSuggestionsCardLayout card_layout,
- bool has_fetch_action,
- bool has_view_all_action,
+ ContentSuggestionsAdditionalAction additional_action,
bool show_if_empty,
const base::string16& no_suggestions_message);
CategoryInfo() = delete;
@@ -42,13 +55,10 @@ class CategoryInfo {
// Layout of the cards to be used to display suggestions in this category.
ContentSuggestionsCardLayout card_layout() const { return card_layout_; }
- // Whether the category supports a "Fetch" action, that triggers fetching more
- // suggestions for the category.
- bool has_fetch_action() const { return has_fetch_action_; }
-
- // Whether the category supports a "ViewAll" action, that triggers displaying
- // all the content related to the current categories.
- bool has_view_all_action() const { return has_view_all_action_; }
+ // Supported action for the category.
+ ContentSuggestionsAdditionalAction additional_action() const {
+ return additional_action_;
+ }
// Whether this category should be shown if it offers no suggestions.
bool show_if_empty() const { return show_if_empty_; }
@@ -64,9 +74,7 @@ class CategoryInfo {
base::string16 title_;
ContentSuggestionsCardLayout card_layout_;
- // Supported actions for the category.
- bool has_fetch_action_;
- bool has_view_all_action_;
+ ContentSuggestionsAdditionalAction additional_action_;
// Whether to show the category if a fetch returns no suggestions.
bool show_if_empty_;
diff --git a/chromium/components/ntp_snippets/category_rankers/category_ranker.h b/chromium/components/ntp_snippets/category_rankers/category_ranker.h
index c403625e616..aa19c57d668 100644
--- a/chromium/components/ntp_snippets/category_rankers/category_ranker.h
+++ b/chromium/components/ntp_snippets/category_rankers/category_ranker.h
@@ -10,9 +10,6 @@
namespace ntp_snippets {
-// TODO(vitaliii): Ensure that changes in the order are propagated to the UI.
-// (crbug.com/673743)
-
// Orders categories.
// The order may be dynamic and change at any time.
class CategoryRanker {
@@ -32,6 +29,16 @@ class CategoryRanker {
// known categories, otherwise nothing is changed.
virtual void AppendCategoryIfNecessary(Category category) = 0;
+ // If |category_to_insert| has not been added previously, it is added before
+ // |anchor|, otherwise nothing is changed.
+ virtual void InsertCategoryBeforeIfNecessary(Category category_to_insert,
+ Category anchor) = 0;
+
+ // If |category_to_insert| has not been added previously, it is added after
+ // |anchor|, otherwise nothing is changed.
+ virtual void InsertCategoryAfterIfNecessary(Category category_to_insert,
+ Category anchor) = 0;
+
// Feedback data from the user to update the ranking.
// Called whenever a suggestion is opened by the user.
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 653a68f9ac2..62e2ad711b5 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
@@ -246,9 +246,24 @@ void ClickBasedCategoryRanker::AppendCategoryIfNecessary(Category category) {
if (!ContainsCategory(category)) {
ordered_categories_.push_back(RankedCategory(
category, /*clicks=*/0, /*last_dismissed=*/base::Time()));
+ StoreOrderToPrefs(ordered_categories_);
}
}
+void ClickBasedCategoryRanker::InsertCategoryBeforeIfNecessary(
+ Category category_to_insert,
+ Category anchor) {
+ InsertCategoryRelativeToIfNecessary(category_to_insert, anchor,
+ /*after=*/false);
+}
+
+void ClickBasedCategoryRanker::InsertCategoryAfterIfNecessary(
+ Category category_to_insert,
+ Category anchor) {
+ InsertCategoryRelativeToIfNecessary(category_to_insert, anchor,
+ /*after=*/true);
+}
+
void ClickBasedCategoryRanker::OnSuggestionOpened(Category category) {
if (!ContainsCategory(category)) {
LOG(DFATAL) << "The category with ID " << category.id()
@@ -384,8 +399,8 @@ void ClickBasedCategoryRanker::AppendKnownCategory(
KnownCategories known_category) {
Category category = Category::FromKnownCategory(known_category);
DCHECK(!ContainsCategory(category));
- ordered_categories_.push_back(RankedCategory(
- category, /*clicks=*/0, /*last_dismissed=*/base::Time()));
+ ordered_categories_.push_back(
+ RankedCategory(category, /*clicks=*/0, /*last_dismissed=*/base::Time()));
}
namespace {
@@ -413,9 +428,9 @@ bool ClickBasedCategoryRanker::ReadOrderFromPrefs(
return false;
}
- for (const std::unique_ptr<base::Value>& value : *list) {
- base::DictionaryValue* dictionary;
- if (!value->GetAsDictionary(&dictionary)) {
+ for (const base::Value& value : *list) {
+ const base::DictionaryValue* dictionary;
+ if (!value.GetAsDictionary(&dictionary)) {
LOG(DFATAL) << "Failed to parse category data from prefs param "
<< prefs::kClickBasedCategoryRankerOrderWithClicks
<< " into dictionary.";
@@ -470,6 +485,23 @@ bool ClickBasedCategoryRanker::ContainsCategory(Category category) const {
return false;
}
+void ClickBasedCategoryRanker::InsertCategoryRelativeToIfNecessary(
+ Category category_to_insert,
+ Category anchor,
+ bool after) {
+ DCHECK(ContainsCategory(anchor));
+ if (ContainsCategory(category_to_insert)) {
+ return;
+ }
+
+ std::vector<RankedCategory>::iterator anchor_it = FindCategory(anchor);
+ ordered_categories_.insert(anchor_it + (after ? 1 : 0),
+ RankedCategory(category_to_insert,
+ /*clicks=*/anchor_it->clicks,
+ /*last_dismissed=*/base::Time()));
+ StoreOrderToPrefs(ordered_categories_);
+}
+
base::Time ClickBasedCategoryRanker::ReadLastDecayTimeFromPrefs() const {
return base::Time::FromInternalValue(
pref_service_->GetInt64(prefs::kClickBasedCategoryRankerLastDecayTime));
diff --git a/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.h b/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.h
index 0042ffe36d4..06bd846107f 100644
--- a/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.h
+++ b/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.h
@@ -24,8 +24,8 @@ namespace ntp_snippets {
// to the top. The new remote categories must be registered using
// AppendCategoryIfNecessary. All other categories must be hardcoded in the
// initial order. The order and category usage data are persisted in prefs and
-// reloaded on startup. TODO(crbug.com/675929): Remove unused categories from
-// prefs.
+// reloaded on startup.
+// TODO(crbug.com/675929): Remove unused categories from prefs.
class ClickBasedCategoryRanker : public CategoryRanker {
public:
explicit ClickBasedCategoryRanker(PrefService* pref_service,
@@ -36,6 +36,10 @@ class ClickBasedCategoryRanker : public CategoryRanker {
bool Compare(Category left, Category right) const override;
void ClearHistory(base::Time begin, base::Time end) override;
void AppendCategoryIfNecessary(Category category) override;
+ void InsertCategoryBeforeIfNecessary(Category category_to_insert,
+ Category anchor) override;
+ void InsertCategoryAfterIfNecessary(Category category_to_insert,
+ Category anchor) override;
void OnSuggestionOpened(Category category) override;
void OnCategoryDismissed(Category category) override;
@@ -76,6 +80,9 @@ class ClickBasedCategoryRanker : public CategoryRanker {
void StoreOrderToPrefs(const std::vector<RankedCategory>& ordered_categories);
std::vector<RankedCategory>::iterator FindCategory(Category category);
bool ContainsCategory(Category category) const;
+ void InsertCategoryRelativeToIfNecessary(Category category_to_insert,
+ Category anchor,
+ bool after);
base::Time ReadLastDecayTimeFromPrefs() const;
void StoreLastDecayTimeToPrefs(base::Time last_decay_time);
diff --git a/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc b/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc
index 172789bfa10..c7dcc4e84a5 100644
--- a/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc
+++ b/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc
@@ -84,7 +84,7 @@ class ClickBasedCategoryRankerTest : public testing::Test {
void SetDismissedCategoryPenaltyVariationParam(int value) {
variation_params_manager_.SetVariationParamsWithFeatureAssociations(
- ntp_snippets::kStudyName,
+ kCategoryRanker.name,
{{"click_based_category_ranker-dismissed_category_penalty",
base::IntToString(value)}},
{kCategoryRanker.name});
@@ -92,12 +92,21 @@ class ClickBasedCategoryRankerTest : public testing::Test {
void SetPromotedCategoryVariationParam(int value) {
variation_params_manager_.SetVariationParamsWithFeatureAssociations(
- ntp_snippets::kStudyName,
+ kCategoryRanker.name,
{{"click_based_category_ranker-promoted_category",
base::IntToString(value)}},
{kCategoryRanker.name});
}
+ std::vector<Category> ConvertKnownCategories(
+ std::vector<KnownCategories> known_categories) {
+ std::vector<Category> converted;
+ for (auto known : known_categories) {
+ converted.push_back(Category::FromKnownCategory(known));
+ }
+ return converted;
+ }
+
ClickBasedCategoryRanker* ranker() { return ranker_.get(); }
private:
@@ -746,4 +755,229 @@ TEST_F(ClickBasedCategoryRankerTest,
IsEmpty());
}
+TEST_F(ClickBasedCategoryRankerTest,
+ ShouldInsertCategoryBeforeSelectedCategory) {
+ std::vector<KnownCategories> default_order =
+ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder();
+ Category first = Category::FromKnownCategory(default_order[0]);
+ Category second = Category::FromKnownCategory(default_order[1]);
+
+ ASSERT_TRUE(CompareCategories(first, second));
+
+ Category inserted = GetUnusedRemoteCategory();
+
+ ranker()->InsertCategoryBeforeIfNecessary(inserted, second);
+ EXPECT_TRUE(CompareCategories(first, inserted));
+ EXPECT_TRUE(CompareCategories(inserted, second));
+}
+
+TEST_F(ClickBasedCategoryRankerTest,
+ ShouldInsertMultipleCategoriesBeforeSelectedCategory) {
+ std::vector<KnownCategories> default_order =
+ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder();
+ Category first = Category::FromKnownCategory(default_order[0]);
+ Category second = Category::FromKnownCategory(default_order[1]);
+
+ ASSERT_TRUE(CompareCategories(first, second));
+
+ Category first_inserted = GetUnusedRemoteCategory();
+ Category second_inserted = GetUnusedRemoteCategory();
+
+ ranker()->InsertCategoryBeforeIfNecessary(first_inserted, second);
+ ranker()->InsertCategoryBeforeIfNecessary(second_inserted, second);
+ EXPECT_TRUE(CompareCategories(first, first_inserted));
+ EXPECT_TRUE(CompareCategories(first_inserted, second_inserted));
+ EXPECT_TRUE(CompareCategories(second_inserted, second));
+}
+
+TEST_F(ClickBasedCategoryRankerTest, ShouldInsertCategoryBeforeFirstCategory) {
+ std::vector<KnownCategories> default_order =
+ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder();
+ Category first = Category::FromKnownCategory(default_order[0]);
+ Category inserted = GetUnusedRemoteCategory();
+
+ ranker()->InsertCategoryBeforeIfNecessary(inserted, first);
+ EXPECT_TRUE(CompareCategories(inserted, first));
+}
+
+TEST_F(ClickBasedCategoryRankerTest, ShouldInsertCategoryBeforeRemoteCategory) {
+ std::vector<KnownCategories> default_order =
+ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder();
+ Category remote = AddUnusedRemoteCategory();
+ Category inserted = GetUnusedRemoteCategory();
+
+ ranker()->InsertCategoryBeforeIfNecessary(inserted, remote);
+ EXPECT_TRUE(CompareCategories(inserted, remote));
+}
+
+TEST_F(ClickBasedCategoryRankerTest,
+ ShouldNotChangeRemainingOrderWhenInsertingBeforeCategory) {
+ std::vector<KnownCategories> default_order =
+ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder();
+ Category anchor = Category::FromKnownCategory(default_order[2]);
+ Category inserted = GetUnusedRemoteCategory();
+
+ ranker()->InsertCategoryBeforeIfNecessary(inserted, anchor);
+ std::vector<Category> converted_categories =
+ ConvertKnownCategories(default_order);
+ for (size_t i = 0; i + 1 < converted_categories.size(); ++i) {
+ EXPECT_TRUE(CompareCategories(converted_categories[i],
+ converted_categories[i + 1]));
+ }
+}
+
+TEST_F(ClickBasedCategoryRankerTest,
+ ShouldInsertCategoriesBeforeAndAfterSameCategory) {
+ std::vector<KnownCategories> default_order =
+ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder();
+ Category first = Category::FromKnownCategory(default_order[0]);
+ Category second = Category::FromKnownCategory(default_order[1]);
+ Category third = Category::FromKnownCategory(default_order[2]);
+ ASSERT_TRUE(CompareCategories(first, second));
+ ASSERT_TRUE(CompareCategories(second, third));
+
+ Category first_before = GetUnusedRemoteCategory();
+ ranker()->InsertCategoryBeforeIfNecessary(first_before, second);
+
+ Category first_after = GetUnusedRemoteCategory();
+ ranker()->InsertCategoryAfterIfNecessary(first_after, second);
+
+ Category second_before = GetUnusedRemoteCategory();
+ ranker()->InsertCategoryBeforeIfNecessary(second_before, second);
+
+ Category second_after = GetUnusedRemoteCategory();
+ ranker()->InsertCategoryAfterIfNecessary(second_after, second);
+
+ EXPECT_TRUE(CompareCategories(first_before, second_before));
+ EXPECT_TRUE(CompareCategories(second_before, second));
+ EXPECT_TRUE(CompareCategories(second, second_after));
+ EXPECT_TRUE(CompareCategories(second_after, first_after));
+ EXPECT_TRUE(CompareCategories(first_after, third));
+}
+
+TEST_F(ClickBasedCategoryRankerTest,
+ ShouldInsertCategoriesBeforeAndAfterDifferentCategories) {
+ std::vector<KnownCategories> default_order =
+ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder();
+ Category first = Category::FromKnownCategory(default_order[0]);
+ Category second = Category::FromKnownCategory(default_order[1]);
+ ASSERT_TRUE(CompareCategories(first, second));
+
+ Category first_before = GetUnusedRemoteCategory();
+ ranker()->InsertCategoryBeforeIfNecessary(first_before, second);
+
+ Category first_after = GetUnusedRemoteCategory();
+ ranker()->InsertCategoryAfterIfNecessary(first_after, first);
+
+ Category second_before = GetUnusedRemoteCategory();
+ ranker()->InsertCategoryBeforeIfNecessary(second_before, second);
+
+ Category second_after = GetUnusedRemoteCategory();
+ ranker()->InsertCategoryAfterIfNecessary(second_after, first);
+
+ EXPECT_TRUE(CompareCategories(first, second_after));
+ EXPECT_TRUE(CompareCategories(second_after, first_after));
+ EXPECT_TRUE(CompareCategories(first_after, first_before));
+ EXPECT_TRUE(CompareCategories(first_before, second_before));
+ EXPECT_TRUE(CompareCategories(second_before, second));
+}
+
+TEST_F(ClickBasedCategoryRankerTest,
+ ShouldNotEmitNewIndexWhenCategoryInserted) {
+ base::HistogramTester histogram_tester;
+
+ std::vector<KnownCategories> default_order =
+ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder();
+ Category first = Category::FromKnownCategory(default_order[0]);
+
+ ASSERT_THAT(histogram_tester.GetAllSamples(kHistogramMovedUpCategoryNewIndex),
+ IsEmpty());
+
+ Category before = GetUnusedRemoteCategory();
+ ranker()->InsertCategoryBeforeIfNecessary(before, first);
+
+ Category after = GetUnusedRemoteCategory();
+ ranker()->InsertCategoryAfterIfNecessary(after, first);
+
+ EXPECT_THAT(histogram_tester.GetAllSamples(kHistogramMovedUpCategoryNewIndex),
+ IsEmpty());
+}
+
+// TODO(vitaliii): Reuse these tests for ConstantCategoryRanker.
+TEST_F(ClickBasedCategoryRankerTest,
+ ShouldInsertCategoryAfterSelectedCategory) {
+ std::vector<KnownCategories> default_order =
+ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder();
+ Category first = Category::FromKnownCategory(default_order[0]);
+ Category second = Category::FromKnownCategory(default_order[1]);
+
+ ASSERT_TRUE(CompareCategories(first, second));
+
+ Category inserted = GetUnusedRemoteCategory();
+
+ ranker()->InsertCategoryAfterIfNecessary(inserted, first);
+ EXPECT_TRUE(CompareCategories(first, inserted));
+ EXPECT_TRUE(CompareCategories(inserted, second));
+}
+
+TEST_F(ClickBasedCategoryRankerTest,
+ ShouldInsertMultipleCategoriesAfterSelectedCategory) {
+ std::vector<KnownCategories> default_order =
+ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder();
+ Category first = Category::FromKnownCategory(default_order[0]);
+ Category second = Category::FromKnownCategory(default_order[1]);
+
+ ASSERT_TRUE(CompareCategories(first, second));
+
+ Category first_inserted = GetUnusedRemoteCategory();
+ Category second_inserted = GetUnusedRemoteCategory();
+
+ ranker()->InsertCategoryAfterIfNecessary(first_inserted, first);
+ ranker()->InsertCategoryAfterIfNecessary(second_inserted, first);
+ EXPECT_TRUE(CompareCategories(first, second_inserted));
+ EXPECT_TRUE(CompareCategories(second_inserted, first_inserted));
+ EXPECT_TRUE(CompareCategories(first_inserted, second));
+}
+
+TEST_F(ClickBasedCategoryRankerTest, ShouldInsertCategoryAfterLastCategory) {
+ Category last = AddUnusedRemoteCategory();
+ Category inserted = GetUnusedRemoteCategory();
+
+ ranker()->InsertCategoryAfterIfNecessary(inserted, last);
+ EXPECT_TRUE(CompareCategories(last, inserted));
+}
+
+TEST_F(ClickBasedCategoryRankerTest,
+ ShouldNotChangeRemainingOrderWhenInsertingAfterCategory) {
+ std::vector<KnownCategories> default_order =
+ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder();
+ Category anchor = Category::FromKnownCategory(default_order[2]);
+ Category inserted = GetUnusedRemoteCategory();
+
+ ranker()->InsertCategoryAfterIfNecessary(inserted, anchor);
+ std::vector<Category> converted_categories =
+ ConvertKnownCategories(default_order);
+ for (size_t i = 0; i + 1 < converted_categories.size(); ++i) {
+ EXPECT_TRUE(CompareCategories(converted_categories[i],
+ converted_categories[i + 1]));
+ }
+}
+
+TEST_F(ClickBasedCategoryRankerTest,
+ ShouldAssignScoreToInsertedCategoriesBasedOnAnchor) {
+ Category anchor = AddUnusedRemoteCategory();
+ NotifyOnSuggestionOpened(/*times=*/25, anchor);
+
+ Category inserted_before = GetUnusedRemoteCategory();
+ ranker()->InsertCategoryBeforeIfNecessary(inserted_before, anchor);
+
+ Category inserted_after = GetUnusedRemoteCategory();
+ ranker()->InsertCategoryAfterIfNecessary(inserted_after, anchor);
+
+ Category tester = AddUnusedRemoteCategory();
+ NotifyOnSuggestionOpened(/*times=*/20, tester);
+ EXPECT_TRUE(CompareCategories(inserted_before, tester));
+ EXPECT_TRUE(CompareCategories(inserted_after, tester));
+}
+
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc b/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc
index 8ba04ab61db..828cd317e5d 100644
--- a/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc
+++ b/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc
@@ -57,6 +57,24 @@ void ConstantCategoryRanker::AppendCategoryIfNecessary(Category category) {
}
}
+void ConstantCategoryRanker::InsertCategoryBeforeIfNecessary(
+ Category category_to_insert,
+ Category anchor) {
+ // TODO(vitaliii): Implement.
+ LOG(DFATAL) << "Not implemented, use ClickBasedCategoryRanker instead for "
+ "inserting categories relative to other categories.";
+ AppendCategoryIfNecessary(category_to_insert);
+}
+
+void ConstantCategoryRanker::InsertCategoryAfterIfNecessary(
+ Category category_to_insert,
+ Category anchor) {
+ // TODO(vitaliii): Implement.
+ LOG(DFATAL) << "Not implemented, use ClickBasedCategoryRanker instead for "
+ "inserting categories relative to other categories.";
+ AppendCategoryIfNecessary(category_to_insert);
+}
+
void ConstantCategoryRanker::OnSuggestionOpened(Category category) {
// Ignored. The order is constant.
}
@@ -73,6 +91,7 @@ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder() {
switch (choice) {
case CategoryOrderChoice::GENERAL:
categories.push_back(KnownCategories::PHYSICAL_WEB_PAGES);
+ categories.push_back(KnownCategories::READING_LIST);
categories.push_back(KnownCategories::DOWNLOADS);
categories.push_back(KnownCategories::RECENT_TABS);
categories.push_back(KnownCategories::FOREIGN_TABS);
@@ -81,6 +100,7 @@ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder() {
break;
case CategoryOrderChoice::EMERGING_MARKETS_ORIENTED:
categories.push_back(KnownCategories::ARTICLES);
+ categories.push_back(KnownCategories::READING_LIST);
categories.push_back(KnownCategories::DOWNLOADS);
categories.push_back(KnownCategories::BOOKMARKS);
@@ -91,7 +111,7 @@ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder() {
}
static_assert(
- static_cast<size_t>(KnownCategories::LOCAL_CATEGORIES_COUNT) == 5,
+ static_cast<size_t>(KnownCategories::LOCAL_CATEGORIES_COUNT) == 6,
"All local KnownCategories must be present in all orders.");
// Other remote categories will be ordered after these depending on when
diff --git a/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.h b/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.h
index 67786b208b3..8e4417e859a 100644
--- a/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.h
+++ b/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.h
@@ -27,6 +27,10 @@ class ConstantCategoryRanker : public CategoryRanker {
bool Compare(Category left, Category right) const override;
void ClearHistory(base::Time begin, base::Time end) override;
void AppendCategoryIfNecessary(Category category) override;
+ void InsertCategoryBeforeIfNecessary(Category category_to_insert,
+ Category anchor) override;
+ void InsertCategoryAfterIfNecessary(Category category_to_insert,
+ Category anchor) override;
void OnSuggestionOpened(Category category) override;
void OnCategoryDismissed(Category category) override;
diff --git a/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.cc b/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.cc
index 4c34840a61c..94739a7b525 100644
--- a/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.cc
+++ b/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.cc
@@ -30,6 +30,18 @@ void FakeCategoryRanker::AppendCategoryIfNecessary(Category category) {
// Ignored.
}
+void FakeCategoryRanker::InsertCategoryBeforeIfNecessary(
+ Category category_to_insert,
+ Category anchor) {
+ // Ignored.
+}
+
+void FakeCategoryRanker::InsertCategoryAfterIfNecessary(
+ Category category_to_insert,
+ Category anchor) {
+ // Ignored.
+}
+
void FakeCategoryRanker::OnSuggestionOpened(Category category) {
// Ignored.
}
diff --git a/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.h b/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.h
index 314f0f238ea..9b5e37659ff 100644
--- a/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.h
+++ b/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.h
@@ -27,6 +27,10 @@ class FakeCategoryRanker : public CategoryRanker {
bool Compare(Category left, Category right) const override;
void ClearHistory(base::Time begin, base::Time end) override;
void AppendCategoryIfNecessary(Category category) override;
+ void InsertCategoryBeforeIfNecessary(Category category_to_insert,
+ Category anchor) override;
+ void InsertCategoryAfterIfNecessary(Category category_to_insert,
+ Category anchor) override;
void OnSuggestionOpened(Category category) override;
void OnCategoryDismissed(Category category) override;
diff --git a/chromium/components/ntp_snippets/category_rankers/mock_category_ranker.h b/chromium/components/ntp_snippets/category_rankers/mock_category_ranker.h
index 5ec50ca7b32..2238aeea7e7 100644
--- a/chromium/components/ntp_snippets/category_rankers/mock_category_ranker.h
+++ b/chromium/components/ntp_snippets/category_rankers/mock_category_ranker.h
@@ -20,6 +20,10 @@ class MockCategoryRanker : public CategoryRanker {
MOCK_CONST_METHOD2(Compare, bool(Category left, Category right));
MOCK_METHOD2(ClearHistory, void(base::Time begin, base::Time end));
MOCK_METHOD1(AppendCategoryIfNecessary, void(Category category));
+ MOCK_METHOD2(InsertCategoryBeforeIfNecessary,
+ void(Category category_to_insert, Category anchor));
+ MOCK_METHOD2(InsertCategoryAfterIfNecessary,
+ void(Category category_to_insert, Category anchor));
MOCK_METHOD1(OnSuggestionOpened, void(Category category));
MOCK_METHOD1(OnCategoryDismissed, void(Category Category));
};
diff --git a/chromium/components/ntp_snippets/category_status.h b/chromium/components/ntp_snippets/category_status.h
index 2f6c7cdfbd9..9b9e8abb05e 100644
--- a/chromium/components/ntp_snippets/category_status.h
+++ b/chromium/components/ntp_snippets/category_status.h
@@ -28,14 +28,13 @@ enum class CategoryStatus {
// of the service configuration.
ALL_SUGGESTIONS_EXPLICITLY_DISABLED,
// Content suggestions from a specific category have been disabled as part of
- // the service configuration.
+ // the service configuration. Any suggestions from this category should be
+ // removed from the UI immediately.
CATEGORY_EXPLICITLY_DISABLED,
- // Content suggestions are not available because the user is not signed in.
- SIGNED_OUT,
-
// Content suggestions are not available because an error occurred when
- // loading or updating them.
+ // loading or updating them. Any suggestions from this category should be
+ // removed from the UI immediately.
LOADING_ERROR
};
diff --git a/chromium/components/ntp_snippets/content_suggestion.cc b/chromium/components/ntp_snippets/content_suggestion.cc
index 3b007a4f1c2..a26bfa1e255 100644
--- a/chromium/components/ntp_snippets/content_suggestion.cc
+++ b/chromium/components/ntp_snippets/content_suggestion.cc
@@ -10,6 +10,9 @@ namespace ntp_snippets {
DownloadSuggestionExtra::DownloadSuggestionExtra() = default;
+DownloadSuggestionExtra::DownloadSuggestionExtra(
+ const DownloadSuggestionExtra& other) = default;
+
DownloadSuggestionExtra::~DownloadSuggestionExtra() = default;
bool ContentSuggestion::ID::operator==(const ID& rhs) const {
@@ -40,6 +43,11 @@ std::ostream& operator<<(std::ostream& os, const ContentSuggestion::ID& id) {
return os;
}
+// static
+GURL ContentSuggestion::GetFaviconDomain(const GURL& favicon_url) {
+ return favicon_url.GetWithEmptyPath();
+}
+
void ContentSuggestion::set_download_suggestion_extra(
std::unique_ptr<DownloadSuggestionExtra> download_suggestion_extra) {
DCHECK(id_.category().IsKnownCategory(KnownCategories::DOWNLOADS));
@@ -52,6 +60,12 @@ void ContentSuggestion::set_recent_tab_suggestion_extra(
recent_tab_suggestion_extra_ = std::move(recent_tab_suggestion_extra);
}
+void ContentSuggestion::set_reading_list_suggestion_extra(
+ std::unique_ptr<ReadingListSuggestionExtra> reading_list_suggestion_extra) {
+ DCHECK(id_.category().IsKnownCategory(KnownCategories::READING_LIST));
+ reading_list_suggestion_extra_ = std::move(reading_list_suggestion_extra);
+}
+
void ContentSuggestion::set_notification_extra(
std::unique_ptr<NotificationExtra> notification_extra) {
notification_extra_ = std::move(notification_extra);
diff --git a/chromium/components/ntp_snippets/content_suggestion.h b/chromium/components/ntp_snippets/content_suggestion.h
index ea17274c45f..5bc647e4cda 100644
--- a/chromium/components/ntp_snippets/content_suggestion.h
+++ b/chromium/components/ntp_snippets/content_suggestion.h
@@ -21,8 +21,11 @@ namespace ntp_snippets {
// download suggestions.
struct DownloadSuggestionExtra {
DownloadSuggestionExtra();
+ DownloadSuggestionExtra(const DownloadSuggestionExtra&);
~DownloadSuggestionExtra();
+ // The GUID for the downloaded file.
+ std::string download_guid;
// The file path of the downloaded file once download completes.
base::FilePath target_file_path;
// The effective MIME type of downloaded content.
@@ -43,6 +46,21 @@ struct RecentTabSuggestionExtra {
int64_t offline_page_id = 0;
};
+// ReadingListSuggestionExtra contains additional data which is only available
+// for Reading List suggestions.
+struct ReadingListSuggestionExtra {
+ // State of the distillation a suggestion. This is the meaningful extract of
+ // ReadingListEntry::DistillationState for the suggestions. It is duplicated
+ // here to avoid a dependence on ReadingList.
+ enum class ReadingListSuggestionDistilledState { PENDING, SUCCESS, FAILURE };
+
+ // State of the distillation of the suggestion.
+ ReadingListSuggestionDistilledState distilled_state =
+ ReadingListSuggestionDistilledState::PENDING;
+ // URL of the page whose favicon should be displayed for this suggestion.
+ GURL favicon_page_url;
+};
+
// Contains additional data for notification-worthy suggestions.
struct NotificationExtra {
// Deadline for showing notification. If the deadline is past, the
@@ -94,6 +112,19 @@ class ContentSuggestion {
// This may be an AMP URL.
const GURL& url() const { return url_; }
+ // The URL of the page that links to a favicon that represents the suggestion.
+ // Path is trimmed for the URL because the current favicon server backend
+ // prefers it this way.
+ GURL url_with_favicon() const {
+ return url_with_favicon_.is_valid() ? GetFaviconDomain(url_with_favicon_)
+ : GetFaviconDomain(url_);
+ }
+ void set_url_with_favicon(const GURL& url_with_favicon) {
+ url_with_favicon_ = url_with_favicon;
+ }
+
+ static GURL GetFaviconDomain(const GURL& favicon_url);
+
// Title of the suggestion.
const base::string16& title() const { return title_; }
void set_title(const base::string16& title) { title_ = title; }
@@ -141,6 +172,15 @@ class ContentSuggestion {
void set_recent_tab_suggestion_extra(
std::unique_ptr<RecentTabSuggestionExtra> recent_tab_suggestion_extra);
+ // Extra information for reading list suggestions. Only available for
+ // KnownCategories::READING_LIST suggestions.
+ ReadingListSuggestionExtra* reading_list_suggestion_extra() const {
+ return reading_list_suggestion_extra_.get();
+ }
+ void set_reading_list_suggestion_extra(
+ std::unique_ptr<ReadingListSuggestionExtra>
+ reading_list_suggestion_extra);
+
// Extra information for notifications. When absent, no notification should be
// sent for this suggestion. When present, a notification should be sent,
// unless other factors disallow it (examples: the extra parameters say to;
@@ -159,6 +199,7 @@ class ContentSuggestion {
private:
ID id_;
GURL url_;
+ GURL url_with_favicon_;
base::string16 title_;
base::string16 snippet_text_;
base::Time publish_date_;
@@ -166,6 +207,7 @@ class ContentSuggestion {
float score_;
std::unique_ptr<DownloadSuggestionExtra> download_suggestion_extra_;
std::unique_ptr<RecentTabSuggestionExtra> recent_tab_suggestion_extra_;
+ std::unique_ptr<ReadingListSuggestionExtra> reading_list_suggestion_extra_;
std::unique_ptr<NotificationExtra> notification_extra_;
// The time when the remote suggestion was fetched from the server. This field
diff --git a/chromium/components/ntp_snippets/content_suggestions_metrics.cc b/chromium/components/ntp_snippets/content_suggestions_metrics.cc
index a88d5d1a1f1..5d2d4afe9af 100644
--- a/chromium/components/ntp_snippets/content_suggestions_metrics.cc
+++ b/chromium/components/ntp_snippets/content_suggestions_metrics.cc
@@ -13,7 +13,6 @@
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/strings/stringprintf.h"
-#include "base/template_util.h"
namespace ntp_snippets {
namespace metrics {
@@ -76,14 +75,15 @@ enum HistogramCategories {
PHYSICAL_WEB_PAGES,
FOREIGN_TABS,
ARTICLES,
+ READING_LIST,
// Insert new values here!
COUNT
};
HistogramCategories GetHistogramCategory(Category category) {
static_assert(
- std::is_same<decltype(category.id()), typename base::underlying_type<
- KnownCategories>::type>::value,
+ std::is_same<decltype(category.id()),
+ typename std::underlying_type<KnownCategories>::type>::value,
"KnownCategories must have the same underlying type as category.id()");
// Note: Since the underlying type of KnownCategories is int, it's legal to
// cast from int to KnownCategories, even if the given value isn't listed in
@@ -103,6 +103,8 @@ HistogramCategories GetHistogramCategory(Category category) {
return HistogramCategories::FOREIGN_TABS;
case KnownCategories::ARTICLES:
return HistogramCategories::ARTICLES;
+ case KnownCategories::READING_LIST:
+ return HistogramCategories::READING_LIST;
case KnownCategories::LOCAL_CATEGORIES_COUNT:
case KnownCategories::REMOTE_CATEGORIES_OFFSET:
NOTREACHED();
@@ -131,6 +133,8 @@ std::string GetCategorySuffix(Category category) {
return "Articles";
case HistogramCategories::EXPERIMENTAL:
return "Experimental";
+ case HistogramCategories::READING_LIST:
+ return "ReadingList";
case HistogramCategories::COUNT:
NOTREACHED();
break;
@@ -357,5 +361,10 @@ void OnCategoryDismissed(Category category) {
HistogramCategories::COUNT);
}
+void RecordRemoteSuggestionsProviderState(bool enabled) {
+ UMA_HISTOGRAM_BOOLEAN(
+ "NewTabPage.ContentSuggestions.Preferences.RemoteSuggestions", enabled);
+}
+
} // namespace metrics
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/content_suggestions_metrics.h b/chromium/components/ntp_snippets/content_suggestions_metrics.h
index d004c45694a..a2f04e5668d 100644
--- a/chromium/components/ntp_snippets/content_suggestions_metrics.h
+++ b/chromium/components/ntp_snippets/content_suggestions_metrics.h
@@ -58,6 +58,8 @@ void OnMoreButtonClicked(Category category, int position);
void OnCategoryDismissed(Category category);
+void RecordRemoteSuggestionsProviderState(bool enabled);
+
} // namespace metrics
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/content_suggestions_provider.h b/chromium/components/ntp_snippets/content_suggestions_provider.h
index dea83e7cc5b..8c485dfd5a0 100644
--- a/chromium/components/ntp_snippets/content_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/content_suggestions_provider.h
@@ -151,6 +151,7 @@ class ContentSuggestionsProvider {
ContentSuggestionsProvider(Observer* observer);
Observer* observer() const { return observer_; }
+
private:
Observer* observer_;
};
diff --git a/chromium/components/ntp_snippets/content_suggestions_service.cc b/chromium/components/ntp_snippets/content_suggestions_service.cc
index 48098c7afe3..de7ab3ff14f 100644
--- a/chromium/components/ntp_snippets/content_suggestions_service.cc
+++ b/chromium/components/ntp_snippets/content_suggestions_service.cc
@@ -11,29 +11,61 @@
#include "base/bind.h"
#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/default_clock.h"
#include "base/values.h"
+#include "components/favicon/core/large_icon_service.h"
+#include "components/favicon_base/fallback_icon_style.h"
+#include "components/favicon_base/favicon_types.h"
#include "components/ntp_snippets/pref_names.h"
+#include "components/ntp_snippets/remote/remote_suggestions_provider.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "ui/gfx/image/image.h"
namespace ntp_snippets {
+namespace {
+
+// Enumeration listing all possible outcomes for fetch attempts of favicons for
+// content suggestions. Used for UMA histograms, so do not change existing
+// values. Insert new values at the end, and update the histogram definition.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp.snippets
+enum class FaviconFetchResult {
+ SUCCESS_CACHED = 0,
+ SUCCESS_FETCHED = 1,
+ FAILURE = 2,
+ COUNT = 3
+};
+
+void RecordFaviconFetchResult(FaviconFetchResult result) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "NewTabPage.ContentSuggestions.ArticleFaviconFetchResult", result,
+ FaviconFetchResult::COUNT);
+}
+
+} // namespace
+
ContentSuggestionsService::ContentSuggestionsService(
State state,
SigninManagerBase* signin_manager,
history::HistoryService* history_service,
+ favicon::LargeIconService* large_icon_service,
PrefService* pref_service,
- std::unique_ptr<CategoryRanker> category_ranker)
+ std::unique_ptr<CategoryRanker> category_ranker,
+ std::unique_ptr<UserClassifier> user_classifier,
+ std::unique_ptr<RemoteSuggestionsScheduler> remote_suggestions_scheduler)
: state_(state),
signin_observer_(this),
history_service_observer_(this),
remote_suggestions_provider_(nullptr),
- remote_suggestions_scheduler_(nullptr),
+ large_icon_service_(large_icon_service),
pref_service_(pref_service),
- user_classifier_(pref_service),
+ remote_suggestions_scheduler_(std::move(remote_suggestions_scheduler)),
+ user_classifier_(std::move(user_classifier)),
category_ranker_(std::move(category_ranker)) {
// Can be null in tests.
if (signin_manager) {
@@ -123,6 +155,115 @@ void ContentSuggestionsService::FetchSuggestionImage(
suggestion_id, callback);
}
+// TODO(jkrcal): Split the favicon fetching into a separate class.
+void ContentSuggestionsService::FetchSuggestionFavicon(
+ const ContentSuggestion::ID& suggestion_id,
+ int minimum_size_in_pixel,
+ int desired_size_in_pixel,
+ const ImageFetchedCallback& callback) {
+ const GURL& domain_with_favicon = GetFaviconDomain(suggestion_id);
+ if (!domain_with_favicon.is_valid() || !large_icon_service_) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, gfx::Image()));
+ RecordFaviconFetchResult(FaviconFetchResult::FAILURE);
+ return;
+ }
+
+ // TODO(jkrcal): Create a general wrapper function in LargeIconService that
+ // does handle the get-from-cache-and-fallback-to-google-server functionality
+ // in one shot (for all clients that do not need to react in between).
+ large_icon_service_->GetLargeIconImageOrFallbackStyle(
+ domain_with_favicon, minimum_size_in_pixel, desired_size_in_pixel,
+ base::Bind(&ContentSuggestionsService::OnGetFaviconFromCacheFinished,
+ base::Unretained(this), domain_with_favicon,
+ minimum_size_in_pixel, desired_size_in_pixel, callback,
+ /*continue_to_google_server=*/true),
+ &favicons_task_tracker_);
+}
+
+GURL ContentSuggestionsService::GetFaviconDomain(
+ const ContentSuggestion::ID& suggestion_id) {
+ const std::vector<ContentSuggestion>& suggestions =
+ suggestions_by_category_[suggestion_id.category()];
+ auto position =
+ std::find_if(suggestions.begin(), suggestions.end(),
+ [&suggestion_id](const ContentSuggestion& suggestion) {
+ return suggestion_id == suggestion.id();
+ });
+ if (position != suggestions.end()) {
+ return position->url_with_favicon();
+ }
+
+ // Look up the URL in the archive of |remote_suggestions_provider_|.
+ // TODO(jkrcal): Fix how Fetch more works or find other ways to remove this
+ // hack. crbug.com/714031
+ if (providers_by_category_[suggestion_id.category()] ==
+ remote_suggestions_provider_) {
+ return remote_suggestions_provider_->GetUrlWithFavicon(suggestion_id);
+ }
+ return GURL();
+}
+
+void ContentSuggestionsService::OnGetFaviconFromCacheFinished(
+ const GURL& publisher_url,
+ int minimum_size_in_pixel,
+ int desired_size_in_pixel,
+ const ImageFetchedCallback& callback,
+ bool continue_to_google_server,
+ const favicon_base::LargeIconImageResult& result) {
+ if (!result.image.IsEmpty()) {
+ callback.Run(result.image);
+ // The icon is from cache if we haven't gone to Google server yet. The icon
+ // is freshly fetched, otherwise.
+ RecordFaviconFetchResult(continue_to_google_server
+ ? FaviconFetchResult::SUCCESS_CACHED
+ : FaviconFetchResult::SUCCESS_FETCHED);
+ return;
+ }
+
+ if (!continue_to_google_server ||
+ (result.fallback_icon_style &&
+ !result.fallback_icon_style->is_default_background_color)) {
+ // We cannot download from the server if there is some small icon in the
+ // cache (resulting in non-default background color) or if we already did
+ // so.
+ callback.Run(gfx::Image());
+ RecordFaviconFetchResult(FaviconFetchResult::FAILURE);
+ return;
+ }
+
+ // Try to fetch the favicon from a Google favicon server.
+ large_icon_service_
+ ->GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
+ publisher_url, minimum_size_in_pixel,
+ base::Bind(
+ &ContentSuggestionsService::OnGetFaviconFromGoogleServerFinished,
+ base::Unretained(this), publisher_url, minimum_size_in_pixel,
+ desired_size_in_pixel, callback));
+}
+
+void ContentSuggestionsService::OnGetFaviconFromGoogleServerFinished(
+ const GURL& publisher_url,
+ int minimum_size_in_pixel,
+ int desired_size_in_pixel,
+ const ImageFetchedCallback& callback,
+ bool success) {
+ if (!success) {
+ callback.Run(gfx::Image());
+ RecordFaviconFetchResult(FaviconFetchResult::FAILURE);
+ return;
+ }
+
+ // Get the freshly downloaded icon from the cache.
+ large_icon_service_->GetLargeIconImageOrFallbackStyle(
+ publisher_url, minimum_size_in_pixel, desired_size_in_pixel,
+ base::Bind(&ContentSuggestionsService::OnGetFaviconFromCacheFinished,
+ base::Unretained(this), publisher_url, minimum_size_in_pixel,
+ desired_size_in_pixel, callback,
+ /*continue_to_google_server=*/false),
+ &favicons_task_tracker_);
+}
+
void ContentSuggestionsService::ClearHistory(
base::Time begin,
base::Time end,
@@ -250,6 +391,22 @@ void ContentSuggestionsService::ReloadSuggestions() {
}
}
+void ContentSuggestionsService::SetRemoteSuggestionsEnabled(bool enabled) {
+ pref_service_->SetBoolean(prefs::kEnableSnippets, enabled);
+}
+
+bool ContentSuggestionsService::AreRemoteSuggestionsEnabled() const {
+ return pref_service_->GetBoolean(prefs::kEnableSnippets);
+}
+
+bool ContentSuggestionsService::AreRemoteSuggestionsManaged() const {
+ return pref_service_->IsManagedPreference(prefs::kEnableSnippets);
+}
+
+bool ContentSuggestionsService::AreRemoteSuggestionsManagedByCustodian() const {
+ return pref_service_->IsPreferenceManagedByCustodian(prefs::kEnableSnippets);
+}
+
////////////////////////////////////////////////////////////////////////////////
// Private methods
@@ -360,11 +517,10 @@ void ContentSuggestionsService::OnURLsDeleted(
for (const history::URLRow& row : deleted_rows) {
deleted_urls.insert(row.url());
}
- base::Callback<bool(const GURL& url)> filter = base::Bind(
- [](const std::set<GURL>& set, const GURL& url) {
- return set.count(url) != 0;
- },
- deleted_urls);
+ base::Callback<bool(const GURL& url)> filter =
+ base::Bind([](const std::set<GURL>& set,
+ const GURL& url) { return set.count(url) != 0; },
+ deleted_urls);
// We usually don't have any time-related information (the URLRow objects
// usually don't provide a |last_visit()| timestamp. Hence we simply clear
// the whole history for the selected URLs.
@@ -494,10 +650,10 @@ void ContentSuggestionsService::RestoreDismissedCategoriesFromPrefs() {
const base::ListValue* list =
pref_service_->GetList(prefs::kDismissedCategories);
- for (const std::unique_ptr<base::Value>& entry : *list) {
+ for (const base::Value& entry : *list) {
int id = 0;
- if (!entry->GetAsInteger(&id)) {
- DLOG(WARNING) << "Invalid category pref value: " << *entry;
+ if (!entry.GetAsInteger(&id)) {
+ DLOG(WARNING) << "Invalid category pref value: " << entry;
continue;
}
diff --git a/chromium/components/ntp_snippets/content_suggestions_service.h b/chromium/components/ntp_snippets/content_suggestions_service.h
index c3b44676c7f..308e4dbe69d 100644
--- a/chromium/components/ntp_snippets/content_suggestions_service.h
+++ b/chromium/components/ntp_snippets/content_suggestions_service.h
@@ -15,6 +15,7 @@
#include "base/observer_list.h"
#include "base/optional.h"
#include "base/scoped_observer.h"
+#include "base/task/cancelable_task_tracker.h"
#include "base/time/time.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/history_service_observer.h"
@@ -24,16 +25,24 @@
#include "components/ntp_snippets/category_rankers/category_ranker.h"
#include "components/ntp_snippets/category_status.h"
#include "components/ntp_snippets/content_suggestions_provider.h"
+#include "components/ntp_snippets/remote/remote_suggestions_scheduler.h"
#include "components/ntp_snippets/user_classifier.h"
#include "components/signin/core/browser/signin_manager.h"
class PrefService;
class PrefRegistrySimple;
+namespace favicon {
+class LargeIconService;
+} // namespace favicon
+
+namespace favicon_base {
+struct LargeIconImageResult;
+} // namespace favicon_base
+
namespace ntp_snippets {
class RemoteSuggestionsProvider;
-class RemoteSuggestionsScheduler;
// Retrieves suggestions from a number of ContentSuggestionsProviders and serves
// them grouped into categories. There can be at most one provider per category.
@@ -50,11 +59,10 @@ class ContentSuggestionsService : public KeyedService,
// data is then available through |GetSuggestionsForCategory(category)|.
virtual void OnNewSuggestions(Category category) = 0;
- // Fired when the status of a suggestions category changed. When the status
- // changes to an unavailable status, the suggestions of the respective
- // category have been invalidated, which means that they must no longer be
- // displayed to the user. The UI must immediately clear any suggestions of
- // that category.
+ // Fired when the status of a suggestions category changed. Note that for
+ // some status changes, the UI must update immediately (e.g. to remove
+ // invalidated suggestions). See comments on the individual CategoryStatus
+ // values for details.
virtual void OnCategoryStatusChanged(Category category,
CategoryStatus new_status) = 0;
@@ -87,11 +95,18 @@ class ContentSuggestionsService : public KeyedService,
DISABLED,
};
- ContentSuggestionsService(State state,
- SigninManagerBase* signin_manager,
- history::HistoryService* history_service,
- PrefService* pref_service,
- std::unique_ptr<CategoryRanker> category_ranker);
+ ContentSuggestionsService(
+ State state,
+ SigninManagerBase* signin_manager, // Can be nullptr in unittests.
+ history::HistoryService* history_service, // Can be nullptr in unittests.
+ // Can be nullptr in unittests.
+ favicon::LargeIconService* large_icon_service,
+ PrefService* pref_service,
+ std::unique_ptr<CategoryRanker> category_ranker,
+ std::unique_ptr<UserClassifier> user_classifier,
+ std::unique_ptr<RemoteSuggestionsScheduler>
+ remote_suggestions_scheduler // Can be nullptr in unittests.
+ );
~ContentSuggestionsService() override;
// Inherited from KeyedService.
@@ -125,6 +140,16 @@ class ContentSuggestionsService : public KeyedService,
void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
const ImageFetchedCallback& callback);
+ // Fetches the favicon from local cache (if larger than or equal to
+ // |minimum_size_in_pixel|) or from Google server (if there is no icon in the
+ // cache) and returns the results in the callback. If that suggestion doesn't
+ // exist or the fetch fails, the callback gets an empty image. The callback
+ // will not be called synchronously.
+ void FetchSuggestionFavicon(const ContentSuggestion::ID& suggestion_id,
+ int minimum_size_in_pixel,
+ int desired_size_in_pixel,
+ const ImageFetchedCallback& callback);
+
// Dismisses the suggestion with the given |suggestion_id|, if it exists.
// This will not trigger an update through the observers (i.e. providers must
// not call |Observer::OnNewSuggestions|).
@@ -206,6 +231,19 @@ class ContentSuggestionsService : public KeyedService,
// supports it).
void ClearDismissedSuggestionsForDebugging(Category category);
+ // Enables or disables the remote suggestions provider.
+ void SetRemoteSuggestionsEnabled(bool enabled);
+
+ // Returns true if the remote suggestions provider is enabled.
+ bool AreRemoteSuggestionsEnabled() const;
+
+ // Returns true if the remote provider is managed by an adminstrator's policy.
+ bool AreRemoteSuggestionsManaged() const;
+
+ // Returns true if the remote provider is managed by the guardian/parent of a
+ // child account.
+ bool AreRemoteSuggestionsManagedByCustodian() const;
+
// The reference to the RemoteSuggestionsProvider provider should
// only be set by the factory and only used for debugging.
// TODO(jkrcal) The way we deal with the circular dependency feels wrong.
@@ -222,18 +260,17 @@ class ContentSuggestionsService : public KeyedService,
return remote_suggestions_provider_;
}
- // The reference to RemoteSuggestionsScheduler should only be set by the
- // factory. The interface is suited for informing about external events that
- // have influence on scheduling remote fetches.
- void set_remote_suggestions_scheduler(
- ntp_snippets::RemoteSuggestionsScheduler* remote_suggestions_scheduler) {
- remote_suggestions_scheduler_ = remote_suggestions_scheduler;
- }
+ // The interface is suited for informing about external events that have
+ // influence on scheduling remote fetches. Can be nullptr in tests.
RemoteSuggestionsScheduler* remote_suggestions_scheduler() {
- return remote_suggestions_scheduler_;
+ return remote_suggestions_scheduler_.get();
}
- UserClassifier* user_classifier() { return &user_classifier_; }
+ // Can be nullptr in tests.
+ // TODO(jkrcal): The getter is only used from the bridge and from
+ // snippets-internals. Can we get rid of it with the metrics refactoring?
+ UserClassifier* user_classifier() { return user_classifier_.get(); }
+
CategoryRanker* category_ranker() { return category_ranker_.get(); }
private:
@@ -291,6 +328,23 @@ class ContentSuggestionsService : public KeyedService,
void RestoreDismissedCategoriesFromPrefs();
void StoreDismissedCategoriesToPrefs();
+ // Get the domain of the suggestion suitable for fetching the favicon.
+ GURL GetFaviconDomain(const ContentSuggestion::ID& suggestion_id);
+ // Callbacks for fetching favicons.
+ void OnGetFaviconFromCacheFinished(
+ const GURL& publisher_url,
+ int minimum_size_in_pixel,
+ int desired_size_in_pixel,
+ const ImageFetchedCallback& callback,
+ bool continue_to_google_server,
+ const favicon_base::LargeIconImageResult& result);
+ void OnGetFaviconFromGoogleServerFinished(
+ const GURL& publisher_url,
+ int minimum_size_in_pixel,
+ int desired_size_in_pixel,
+ const ImageFetchedCallback& callback,
+ bool success);
+
// Whether the content suggestions feature is enabled.
State state_;
@@ -336,18 +390,23 @@ class ContentSuggestionsService : public KeyedService,
const std::vector<ContentSuggestion> no_suggestions_;
+ base::CancelableTaskTracker favicons_task_tracker_;
+
// Keep a direct reference to this special provider to redirect debugging
// calls to it. If the RemoteSuggestionsProvider is loaded, it is also present
// in |providers_|, otherwise this is a nullptr.
RemoteSuggestionsProvider* remote_suggestions_provider_;
- // Interface for informing about external events that have influence on
- // scheduling remote fetches. Not owned.
- RemoteSuggestionsScheduler* remote_suggestions_scheduler_;
+ favicon::LargeIconService* large_icon_service_;
PrefService* pref_service_;
- UserClassifier user_classifier_;
+ // Interface for informing about external events that have influence on
+ // scheduling remote fetches.
+ std::unique_ptr<RemoteSuggestionsScheduler> remote_suggestions_scheduler_;
+
+ // Classifies the user on the basis of long-term user interactions.
+ std::unique_ptr<UserClassifier> user_classifier_;
// Provides order for categories.
std::unique_ptr<CategoryRanker> category_ranker_;
diff --git a/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc b/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc
index 0ada9202443..9bd9fe94a85 100644
--- a/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc
+++ b/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc
@@ -14,6 +14,7 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
+#include "base/time/default_clock.h"
#include "components/ntp_snippets/category_info.h"
#include "components/ntp_snippets/category_rankers/constant_category_ranker.h"
#include "components/ntp_snippets/category_rankers/fake_category_ranker.h"
@@ -22,6 +23,7 @@
#include "components/ntp_snippets/content_suggestion.h"
#include "components/ntp_snippets/content_suggestions_provider.h"
#include "components/ntp_snippets/mock_content_suggestions_provider.h"
+#include "components/ntp_snippets/remote/remote_suggestions_provider_impl.h"
#include "components/ntp_snippets/user_classifier.h"
#include "components/prefs/testing_pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -140,15 +142,24 @@ class ContentSuggestionsServiceTest : public testing::Test {
protected:
void RegisterPrefs() {
ContentSuggestionsService::RegisterProfilePrefs(pref_service_->registry());
+ RemoteSuggestionsProviderImpl::RegisterProfilePrefs(
+ pref_service_->registry());
UserClassifier::RegisterProfilePrefs(pref_service_->registry());
}
void CreateContentSuggestionsService(
ContentSuggestionsService::State enabled) {
ASSERT_FALSE(service_);
+
+ // TODO(jkrcal): Replace by a mock.
+ auto user_classifier = base::MakeUnique<UserClassifier>(
+ pref_service_.get(), base::MakeUnique<base::DefaultClock>());
+
service_ = base::MakeUnique<ContentSuggestionsService>(
enabled, /*signin_manager=*/nullptr, /*history_service=*/nullptr,
- pref_service_.get(), std::move(category_ranker_));
+ /*large_icon_service=*/nullptr, pref_service_.get(),
+ std::move(category_ranker_), std::move(user_classifier),
+ /*scheduler=*/nullptr);
}
void ResetService() {
@@ -433,8 +444,7 @@ TEST_F(ContentSuggestionsServiceTest, ShouldReturnCategoryInfo) {
const CategoryInfo& actual = result.value();
EXPECT_THAT(expected.title(), Eq(actual.title()));
EXPECT_THAT(expected.card_layout(), Eq(actual.card_layout()));
- EXPECT_THAT(expected.has_fetch_action(), Eq(actual.has_fetch_action()));
- EXPECT_THAT(expected.has_view_all_action(), Eq(actual.has_view_all_action()));
+ EXPECT_THAT(expected.additional_action(), Eq(actual.additional_action()));
}
TEST_F(ContentSuggestionsServiceTest,
diff --git a/chromium/components/ntp_snippets/features.cc b/chromium/components/ntp_snippets/features.cc
index d9066dc23be..0b90a4271f1 100644
--- a/chromium/components/ntp_snippets/features.cc
+++ b/chromium/components/ntp_snippets/features.cc
@@ -22,14 +22,8 @@ const base::Feature kBookmarkSuggestionsFeature{
const base::Feature kRecentOfflineTabSuggestionsFeature{
"NTPOfflinePageSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kSaveToOfflineFeature{
- "NTPSaveToOffline", base::FEATURE_ENABLED_BY_DEFAULT};
-
-const base::Feature kOfflineBadgeFeature{
- "NTPOfflineBadge", base::FEATURE_ENABLED_BY_DEFAULT};
-
-const base::Feature kIncreasedVisibility{
- "NTPSnippetsIncreasedVisibility", base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kIncreasedVisibility{"NTPSnippetsIncreasedVisibility",
+ base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kPhysicalWebPageSuggestionsFeature{
"NTPPhysicalWebPageSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -43,6 +37,10 @@ const base::Feature kPreferAmpUrlsFeature{"NTPPreferAmpUrls",
const base::Feature kCategoryRanker{"ContentSuggestionsCategoryRanker",
base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kPublisherFaviconsFromNewServerFeature{
+ "ContentSuggestionsFaviconsFromNewServer",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
const char kCategoryRankerParameter[] = "category_ranker";
const char kCategoryRankerConstantRanker[] = "constant";
const char kCategoryRankerClickBasedRanker[] = "click_based";
diff --git a/chromium/components/ntp_snippets/features.h b/chromium/components/ntp_snippets/features.h
index c70e278e7df..8832aed5502 100644
--- a/chromium/components/ntp_snippets/features.h
+++ b/chromium/components/ntp_snippets/features.h
@@ -24,14 +24,7 @@ extern const base::Feature kArticleSuggestionsFeature;
extern const base::Feature kBookmarkSuggestionsFeature;
extern const base::Feature kRecentOfflineTabSuggestionsFeature;
extern const base::Feature kPhysicalWebPageSuggestionsFeature;
-extern const base::Feature kForeignSessionsSuggestionsFeature;;
-
-// Feature to allow the 'save to offline' option to appear in the snippets
-// context menu.
-extern const base::Feature kSaveToOfflineFeature;
-
-// Feature to allow offline badges to appear on snippets.
-extern const base::Feature kOfflineBadgeFeature;
+extern const base::Feature kForeignSessionsSuggestionsFeature;
// Feature to allow UI as specified here: https://crbug.com/660837.
extern const base::Feature kIncreasedVisibility;
@@ -42,6 +35,9 @@ extern const base::Feature kPreferAmpUrlsFeature;
// Feature to choose a category ranker.
extern const base::Feature kCategoryRanker;
+// Feature to allow the new Google favicon server for fetching publisher icons.
+extern const base::Feature kPublisherFaviconsFromNewServerFeature;
+
// Parameter and its values for the kCategoryRanker feature flag.
extern const char kCategoryRankerParameter[];
extern const char kCategoryRankerConstantRanker[];
diff --git a/chromium/components/ntp_snippets/mock_content_suggestions_provider.cc b/chromium/components/ntp_snippets/mock_content_suggestions_provider.cc
index 007ecb16242..5e0bbfad778 100644
--- a/chromium/components/ntp_snippets/mock_content_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/mock_content_suggestions_provider.cc
@@ -38,8 +38,7 @@ CategoryInfo MockContentSuggestionsProvider::GetCategoryInfo(
Category category) {
return CategoryInfo(base::ASCIIToUTF16("Section title"),
ContentSuggestionsCardLayout::FULL_CARD,
- /*has_fetch_action=*/true,
- /*has_view_all_action=*/true,
+ ContentSuggestionsAdditionalAction::FETCH,
/*show_if_empty=*/false,
base::ASCIIToUTF16("No suggestions message"));
}
diff --git a/chromium/components/ntp_snippets/ntp_snippets_constants.cc b/chromium/components/ntp_snippets/ntp_snippets_constants.cc
index daaa006011c..82304939470 100644
--- a/chromium/components/ntp_snippets/ntp_snippets_constants.cc
+++ b/chromium/components/ntp_snippets/ntp_snippets_constants.cc
@@ -6,19 +6,16 @@
namespace ntp_snippets {
-// Also defined in SnippetArticleViewHolder.java
-const char kStudyName[] = "NTPSnippets";
-
const base::FilePath::CharType kDatabaseFolder[] =
FILE_PATH_LITERAL("NTPSnippets");
-const char kChromeReaderServer[] =
- "https://chromereader-pa.googleapis.com/v1/fetch";
const char kContentSuggestionsServer[] =
"https://chromecontentsuggestions-pa.googleapis.com/v1/suggestions/fetch";
const char kContentSuggestionsStagingServer[] =
- "https://staging-chromecontentsuggestions-pa.googleapis.com/v1/suggestions/fetch";
+ "https://staging-chromecontentsuggestions-pa.googleapis.com/v1/suggestions/"
+ "fetch";
const char kContentSuggestionsAlphaServer[] =
- "https://alpha-chromecontentsuggestions-pa.sandbox.googleapis.com/v1/suggestions/fetch";
+ "https://alpha-chromecontentsuggestions-pa.sandbox.googleapis.com/v1/"
+ "suggestions/fetch";
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/ntp_snippets_constants.h b/chromium/components/ntp_snippets/ntp_snippets_constants.h
index 5f805d11a58..aff5c3720d4 100644
--- a/chromium/components/ntp_snippets/ntp_snippets_constants.h
+++ b/chromium/components/ntp_snippets/ntp_snippets_constants.h
@@ -9,16 +9,12 @@
namespace ntp_snippets {
-// Name of the variation parameters study to configure NTP snippets.
-extern const char kStudyName[];
-
// Name of the folder where the snippets database should be stored. This is only
// the name of the folder, not a full path - it must be appended to e.g. the
// profile path.
extern const base::FilePath::CharType kDatabaseFolder[];
// Server endpoints for fetching snippets.
-extern const char kChromeReaderServer[]; // old endpoint
extern const char kContentSuggestionsServer[]; // used on stable/beta
extern const char kContentSuggestionsStagingServer[]; // used on dev/canary
extern const char kContentSuggestionsAlphaServer[]; // for testing
diff --git a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
index 49c08a12b04..43be2a4daa6 100644
--- a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
@@ -94,8 +94,7 @@ CategoryInfo RecentTabSuggestionsProvider::GetCategoryInfo(Category category) {
return CategoryInfo(
l10n_util::GetStringUTF16(IDS_NTP_RECENT_TAB_SUGGESTIONS_SECTION_HEADER),
ContentSuggestionsCardLayout::MINIMAL_CARD,
- /*has_fetch_action=*/false,
- /*has_view_all_action=*/false,
+ ContentSuggestionsAdditionalAction::NONE,
/*show_if_empty=*/false,
l10n_util::GetStringUTF16(IDS_NTP_RECENT_TAB_SUGGESTIONS_SECTION_EMPTY));
}
diff --git a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc
index 0fecc96e67b..7d8489ca0e0 100644
--- a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc
+++ b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc
@@ -165,14 +165,12 @@ TEST_F(RecentTabSuggestionsProviderTest, ShouldConvertToSuggestions) {
EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(2);
EXPECT_CALL(
*observer(),
- OnNewSuggestions(_, recent_tabs_category(),
- UnorderedElementsAre(
- Property(&ContentSuggestion::url,
- GURL("http://dummy.com/1")),
- Property(&ContentSuggestion::url,
- GURL("http://dummy.com/2")),
- Property(&ContentSuggestion::url,
- GURL("http://dummy.com/3")))));
+ OnNewSuggestions(
+ _, recent_tabs_category(),
+ UnorderedElementsAre(
+ Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
+ Property(&ContentSuggestion::url, GURL("http://dummy.com/2")),
+ Property(&ContentSuggestion::url, GURL("http://dummy.com/3")))));
auto recent_tabs_list = CreateDummyRecentTabs({1, 2, 3});
for (OfflinePageItem& recent_tab : recent_tabs_list) {
@@ -212,21 +210,17 @@ TEST_F(RecentTabSuggestionsProviderTest, ShouldSortByCreationTime) {
*observer(),
OnNewSuggestions(
_, recent_tabs_category(),
- ElementsAre(Property(&ContentSuggestion::url,
- GURL("http://dummy.com/3")),
- Property(&ContentSuggestion::url,
- GURL("http://dummy.com/1")),
- Property(&ContentSuggestion::url,
- GURL("http://dummy.com/2")))));
+ ElementsAre(
+ Property(&ContentSuggestion::url, GURL("http://dummy.com/3")),
+ Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
+ Property(&ContentSuggestion::url, GURL("http://dummy.com/2")))));
AddTabAndOfflinePageToModel(CreateDummyRecentTab(3, tomorrow));
}
TEST_F(RecentTabSuggestionsProviderTest, ShouldDeliverCorrectCategoryInfo) {
- EXPECT_FALSE(
- provider()->GetCategoryInfo(recent_tabs_category()).has_fetch_action());
- EXPECT_FALSE(provider()
- ->GetCategoryInfo(recent_tabs_category())
- .has_view_all_action());
+ EXPECT_EQ(
+ ContentSuggestionsAdditionalAction::NONE,
+ provider()->GetCategoryInfo(recent_tabs_category()).additional_action());
}
// TODO(vitaliii): Break this test into multiple tests. Currently if it fails,
@@ -263,10 +257,9 @@ TEST_F(RecentTabSuggestionsProviderTest, ShouldDismiss) {
base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
EXPECT_THAT(
dismissed_suggestions,
- UnorderedElementsAre(Property(&ContentSuggestion::url,
- GURL("http://dummy.com/2")),
- Property(&ContentSuggestion::url,
- GURL("http://dummy.com/3"))));
+ UnorderedElementsAre(
+ Property(&ContentSuggestion::url, GURL("http://dummy.com/2")),
+ Property(&ContentSuggestion::url, GURL("http://dummy.com/3"))));
// Clear dismissed suggestions.
provider()->ClearDismissedSuggestionsForDebugging(recent_tabs_category());
diff --git a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
index 7dc4615aa43..b8382c0caa0 100644
--- a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
@@ -50,8 +50,7 @@ bool CompareByDistance(const physical_web::Metadata& left,
return left.distance_estimate < right.distance_estimate;
}
-void FilterOutByGroupId(
- physical_web::MetadataList& page_metadata_list) {
+void FilterOutByGroupId(physical_web::MetadataList& page_metadata_list) {
// |std::unique| only removes duplicates that immediately follow each other.
// Thus, first, we have to sort by group_id and distance and only then remove
// duplicates.
@@ -69,18 +68,17 @@ void FilterOutByGroupId(
// Each empty group_id must be treated as unique, so we do not apply
// std::unique to them at all.
- auto nonempty_group_id_begin = std::find_if(
- page_metadata_list.begin(), page_metadata_list.end(),
- [](const physical_web::Metadata& page) {
- return !page.group_id.empty();
- });
-
- auto new_end = std::unique(
- nonempty_group_id_begin, page_metadata_list.end(),
- [](const physical_web::Metadata& left,
- const physical_web::Metadata& right) {
- return left.group_id == right.group_id;
- });
+ auto nonempty_group_id_begin =
+ std::find_if(page_metadata_list.begin(), page_metadata_list.end(),
+ [](const physical_web::Metadata& page) {
+ return !page.group_id.empty();
+ });
+
+ auto new_end = std::unique(nonempty_group_id_begin, page_metadata_list.end(),
+ [](const physical_web::Metadata& left,
+ const physical_web::Metadata& right) {
+ return left.group_id == right.group_id;
+ });
page_metadata_list.erase(new_end, page_metadata_list.end());
}
@@ -98,7 +96,8 @@ PhysicalWebPageSuggestionsProvider::PhysicalWebPageSuggestionsProvider(
physical_web_data_source_(physical_web_data_source),
pref_service_(pref_service) {
observer->OnCategoryStatusChanged(this, provided_category_, category_status_);
- physical_web_data_source_->RegisterListener(this);
+ physical_web_data_source_->RegisterListener(
+ this, physical_web::BACKGROUND_INTERMITTENT);
// TODO(vitaliii): Rewrite initial fetch once crbug.com/667754 is resolved.
FetchPhysicalWebPages();
}
@@ -117,8 +116,7 @@ CategoryInfo PhysicalWebPageSuggestionsProvider::GetCategoryInfo(
return CategoryInfo(l10n_util::GetStringUTF16(
IDS_NTP_PHYSICAL_WEB_PAGE_SUGGESTIONS_SECTION_HEADER),
ContentSuggestionsCardLayout::FULL_CARD,
- /*has_fetch_action=*/false,
- /*has_view_all_action=*/false,
+ ContentSuggestionsAdditionalAction::NONE,
/*show_if_empty=*/false,
l10n_util::GetStringUTF16(
IDS_NTP_PHYSICAL_WEB_PAGE_SUGGESTIONS_SECTION_EMPTY));
diff --git a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider_unittest.cc b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider_unittest.cc
index 696cebb50a2..588eed81e30 100644
--- a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider_unittest.cc
+++ b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider_unittest.cc
@@ -360,8 +360,7 @@ TEST_F(PhysicalWebPageSuggestionsProviderTest,
provider()->DismissSuggestion(GetDummySuggestionId(1));
provider()->DismissSuggestion(GetDummySuggestionId(2));
- physical_web_data_source()->SetMetadataList(
- CreateDummyPhysicalWebPages({2}));
+ physical_web_data_source()->SetMetadataList(CreateDummyPhysicalWebPages({2}));
FireUrlLost("https://resolved_url.com/1");
physical_web_data_source()->SetMetadataList(
diff --git a/chromium/components/ntp_snippets/pref_names.cc b/chromium/components/ntp_snippets/pref_names.cc
index cd03e327107..fb5582a6725 100644
--- a/chromium/components/ntp_snippets/pref_names.cc
+++ b/chromium/components/ntp_snippets/pref_names.cc
@@ -11,14 +11,13 @@ const char kEnableSnippets[] = "ntp_snippets.enable";
const char kRemoteSuggestionCategories[] = "ntp_snippets.remote_categories";
-const char kSnippetLastFetchAttempt[] =
- "ntp_snippets.last_fetch_attempt";
+const char kSnippetLastFetchAttempt[] = "ntp_snippets.last_fetch_attempt";
-const char kSnippetSoftFetchingIntervalOnUsageEvent[] =
- "ntp_snippets.soft_fetching_interval_on_usage_event";
+const char kSnippetSoftFetchingIntervalWifi[] =
+ "ntp_snippets.soft_fetching_interval_wifi";
-const char kSnippetSoftFetchingIntervalOnNtpOpened[] =
- "ntp_snippets.soft_fetching_interval_on_ntp_opened";
+const char kSnippetSoftFetchingIntervalFallback[] =
+ "ntp_snippets.soft_fetching_interval_fallback";
const char kSnippetPersistentFetchingIntervalWifi[] =
"ntp_snippets.fetching_interval_wifi";
diff --git a/chromium/components/ntp_snippets/pref_names.h b/chromium/components/ntp_snippets/pref_names.h
index ee604861932..9826eb9e9ca 100644
--- a/chromium/components/ntp_snippets/pref_names.h
+++ b/chromium/components/ntp_snippets/pref_names.h
@@ -20,11 +20,12 @@ extern const char kRemoteSuggestionCategories[];
extern const char kSnippetLastFetchAttempt[];
// The pref name for the currently applied minimal interval between two
// successive soft background fetches that react to user activity (such as
-// opening Chrome).
-extern const char kSnippetSoftFetchingIntervalOnUsageEvent[];
+// opening Chrome) when there is a WiFi connectivity.
+extern const char kSnippetSoftFetchingIntervalWifi[];
// The pref name for the currently applied minimal interval between two
-// successive soft brackground fetches when the New Tab Page is opened.
-extern const char kSnippetSoftFetchingIntervalOnNtpOpened[];
+// successive soft background fetches that react to user activity (such as
+// opening Chrome) when there is no WiFi connectivity.
+extern const char kSnippetSoftFetchingIntervalFallback[];
// The pref name for the currently-scheduled background fetching interval when
// there is WiFi connectivity.
diff --git a/chromium/components/ntp_snippets/pref_util.cc b/chromium/components/ntp_snippets/pref_util.cc
index a6288f92535..3973cda1b1d 100644
--- a/chromium/components/ntp_snippets/pref_util.cc
+++ b/chromium/components/ntp_snippets/pref_util.cc
@@ -16,9 +16,9 @@ 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 std::unique_ptr<base::Value>& value : *list) {
+ for (const base::Value& value : *list) {
std::string dismissed_id;
- bool success = value->GetAsString(&dismissed_id);
+ bool success = value.GetAsString(&dismissed_id);
DCHECK(success) << "Failed to parse dismissed id from prefs param "
<< pref_name << " into string.";
dismissed_ids.insert(dismissed_id);
diff --git a/chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.cc b/chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.cc
new file mode 100644
index 00000000000..e7361ad1300
--- /dev/null
+++ b/chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.cc
@@ -0,0 +1,50 @@
+// 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/ntp_snippets/reading_list/reading_list_distillation_state_util.h"
+
+#include "base/logging.h"
+
+namespace ntp_snippets {
+
+ReadingListEntry::DistillationState ReadingListStateFromSuggestionState(
+ ReadingListSuggestionExtra::ReadingListSuggestionDistilledState
+ distilled_state) {
+ switch (distilled_state) {
+ case ReadingListSuggestionExtra::ReadingListSuggestionDistilledState::
+ PENDING:
+ return ReadingListEntry::WAITING;
+ case ReadingListSuggestionExtra::ReadingListSuggestionDistilledState::
+ SUCCESS:
+ return ReadingListEntry::PROCESSED;
+ case ReadingListSuggestionExtra::ReadingListSuggestionDistilledState::
+ FAILURE:
+ return ReadingListEntry::DISTILLATION_ERROR;
+ }
+ NOTREACHED();
+ return ReadingListEntry::PROCESSING;
+}
+
+ReadingListSuggestionExtra::ReadingListSuggestionDistilledState
+SuggestionStateFromReadingListState(
+ ReadingListEntry::DistillationState distilled_state) {
+ switch (distilled_state) {
+ case ReadingListEntry::WILL_RETRY:
+ case ReadingListEntry::PROCESSING:
+ case ReadingListEntry::WAITING:
+ return ReadingListSuggestionExtra::ReadingListSuggestionDistilledState::
+ PENDING;
+ case ReadingListEntry::PROCESSED:
+ return ReadingListSuggestionExtra::ReadingListSuggestionDistilledState::
+ SUCCESS;
+ case ReadingListEntry::DISTILLATION_ERROR:
+ return ReadingListSuggestionExtra::ReadingListSuggestionDistilledState::
+ FAILURE;
+ }
+ NOTREACHED();
+ return ReadingListSuggestionExtra::ReadingListSuggestionDistilledState::
+ PENDING;
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.h b/chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.h
new file mode 100644
index 00000000000..a00553fc98a
--- /dev/null
+++ b/chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.h
@@ -0,0 +1,23 @@
+// 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_NTP_SNIPPETS_READING_LIST_READING_LIST_DISTILLATION_STATE_UTIL_H_
+#define COMPONENTS_NTP_SNIPPETS_READING_LIST_READING_LIST_DISTILLATION_STATE_UTIL_H_
+
+#include "components/ntp_snippets/content_suggestion.h"
+#include "components/reading_list/core/reading_list_entry.h"
+
+namespace ntp_snippets {
+
+ReadingListEntry::DistillationState ReadingListStateFromSuggestionState(
+ ReadingListSuggestionExtra::ReadingListSuggestionDistilledState
+ distilled_state);
+
+ReadingListSuggestionExtra::ReadingListSuggestionDistilledState
+SuggestionStateFromReadingListState(
+ ReadingListEntry::DistillationState distilled_state);
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_READING_LIST_READING_LIST_DISTILLATION_STATE_UTIL_H_
diff --git a/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc b/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc
new file mode 100644
index 00000000000..ed11ed83fda
--- /dev/null
+++ b/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc
@@ -0,0 +1,248 @@
+// 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/ntp_snippets/reading_list/reading_list_suggestions_provider.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/reading_list/reading_list_distillation_state_util.h"
+#include "components/reading_list/core/reading_list_entry.h"
+#include "components/reading_list/core/reading_list_model.h"
+#include "components/strings/grit/components_strings.h"
+#include "components/url_formatter/url_formatter.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/image/image.h"
+
+namespace ntp_snippets {
+
+namespace {
+// Max number of entries to return.
+const int kMaxEntries = 3;
+
+bool CompareEntries(const ReadingListEntry* lhs, const ReadingListEntry* rhs) {
+ return lhs->UpdateTime() > rhs->UpdateTime();
+}
+}
+
+ReadingListSuggestionsProvider::ReadingListSuggestionsProvider(
+ ContentSuggestionsProvider::Observer* observer,
+ ReadingListModel* reading_list_model)
+ : ContentSuggestionsProvider(observer),
+ category_status_(CategoryStatus::AVAILABLE_LOADING),
+ provided_category_(
+ Category::FromKnownCategory(KnownCategories::READING_LIST)),
+ reading_list_model_(reading_list_model),
+ scoped_observer_(this) {
+ observer->OnCategoryStatusChanged(this, provided_category_, category_status_);
+
+ // If the ReadingListModel is loaded, this will trigger a call to
+ // ReadingListModelLoaded. Keep it as last instruction.
+ scoped_observer_.Add(reading_list_model_);
+}
+
+ReadingListSuggestionsProvider::~ReadingListSuggestionsProvider(){};
+
+CategoryStatus ReadingListSuggestionsProvider::GetCategoryStatus(
+ Category category) {
+ DCHECK_EQ(category, provided_category_);
+ return category_status_;
+}
+
+CategoryInfo ReadingListSuggestionsProvider::GetCategoryInfo(
+ Category category) {
+ DCHECK_EQ(category, provided_category_);
+
+ return CategoryInfo(l10n_util::GetStringUTF16(
+ IDS_NTP_READING_LIST_SUGGESTIONS_SECTION_HEADER),
+ ContentSuggestionsCardLayout::FULL_CARD,
+ ContentSuggestionsAdditionalAction::VIEW_ALL,
+ /*show_if_empty=*/false,
+ l10n_util::GetStringUTF16(
+ IDS_NTP_READING_LIST_SUGGESTIONS_SECTION_EMPTY));
+}
+
+void ReadingListSuggestionsProvider::DismissSuggestion(
+ const ContentSuggestion::ID& suggestion_id) {
+ if (!reading_list_model_) {
+ return;
+ }
+
+ DCHECK(reading_list_model_->loaded());
+ GURL url(suggestion_id.id_within_category());
+ SetDismissedState(url, true);
+}
+
+void ReadingListSuggestionsProvider::FetchSuggestionImage(
+ const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, gfx::Image()));
+}
+
+void ReadingListSuggestionsProvider::Fetch(
+ const Category& category,
+ const std::set<std::string>& known_suggestion_ids,
+ const FetchDoneCallback& callback) {
+ LOG(DFATAL) << "ReadingListSuggestionsProvider has no |Fetch| functionality!";
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(callback,
+ Status(StatusCode::PERMANENT_ERROR,
+ "ReadingListSuggestionsProvider has no |Fetch| "
+ "functionality!"),
+ base::Passed(std::vector<ContentSuggestion>())));
+}
+
+void ReadingListSuggestionsProvider::ClearHistory(
+ base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter) {
+ // Ignored, Reading List does not depend on history.
+}
+
+void ReadingListSuggestionsProvider::ClearCachedSuggestions(Category category) {
+ DCHECK_EQ(category, provided_category_);
+ // Ignored.
+}
+
+void ReadingListSuggestionsProvider::GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback) {
+ if (!reading_list_model_ || reading_list_model_->IsPerformingBatchUpdates()) {
+ callback.Run(std::vector<ContentSuggestion>());
+ return;
+ }
+
+ DCHECK(reading_list_model_->loaded());
+ std::vector<const ReadingListEntry*> entries;
+ for (const GURL& url : reading_list_model_->Keys()) {
+ const ReadingListEntry* entry = reading_list_model_->GetEntryByURL(url);
+ if (entry->ContentSuggestionsExtra()->dismissed) {
+ entries.emplace_back(entry);
+ }
+ }
+
+ std::sort(entries.begin(), entries.end(), CompareEntries);
+
+ std::vector<ContentSuggestion> suggestions;
+ for (const ReadingListEntry* entry : entries) {
+ suggestions.emplace_back(ConvertEntry(entry));
+ }
+
+ callback.Run(std::move(suggestions));
+}
+
+void ReadingListSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
+ Category category) {
+ for (const auto& url : reading_list_model_->Keys()) {
+ SetDismissedState(url, false);
+ }
+}
+
+void ReadingListSuggestionsProvider::ReadingListModelLoaded(
+ const ReadingListModel* model) {
+ DCHECK(model == reading_list_model_);
+ FetchReadingListInternal();
+}
+
+void ReadingListSuggestionsProvider::ReadingListModelBeingDeleted(
+ const ReadingListModel* model) {
+ DCHECK(model == reading_list_model_);
+ scoped_observer_.Remove(reading_list_model_);
+ reading_list_model_ = nullptr;
+}
+
+void ReadingListSuggestionsProvider::ReadingListDidApplyChanges(
+ ReadingListModel* model) {
+ DCHECK(model == reading_list_model_);
+
+ FetchReadingListInternal();
+}
+
+void ReadingListSuggestionsProvider::ReadingListModelCompletedBatchUpdates(
+ const ReadingListModel* model) {
+ DCHECK(model == reading_list_model_);
+
+ FetchReadingListInternal();
+}
+
+void ReadingListSuggestionsProvider::FetchReadingListInternal() {
+ if (!reading_list_model_ || reading_list_model_->IsPerformingBatchUpdates()) {
+ return;
+ }
+
+ DCHECK(reading_list_model_->loaded());
+ std::vector<const ReadingListEntry*> entries;
+ for (const GURL& url : reading_list_model_->Keys()) {
+ const ReadingListEntry* entry = reading_list_model_->GetEntryByURL(url);
+ if (!entry->IsRead() && !entry->ContentSuggestionsExtra()->dismissed) {
+ entries.emplace_back(entry);
+ }
+ }
+
+ if (entries.size() > kMaxEntries) {
+ // Get the |kMaxEntries| most recent entries.
+ std::partial_sort(entries.begin(), entries.begin() + kMaxEntries,
+ entries.end(), CompareEntries);
+ entries.resize(kMaxEntries);
+ } else {
+ std::sort(entries.begin(), entries.end(), CompareEntries);
+ }
+
+ std::vector<ContentSuggestion> suggestions;
+ for (const ReadingListEntry* entry : entries) {
+ suggestions.emplace_back(ConvertEntry(entry));
+ }
+
+ NotifyStatusChanged(CategoryStatus::AVAILABLE);
+ observer()->OnNewSuggestions(this, provided_category_,
+ std::move(suggestions));
+}
+
+ContentSuggestion ReadingListSuggestionsProvider::ConvertEntry(
+ const ReadingListEntry* entry) {
+ ContentSuggestion suggestion(provided_category_, entry->URL().spec(),
+ entry->URL());
+
+ if (!entry->Title().empty()) {
+ suggestion.set_title(base::UTF8ToUTF16(entry->Title()));
+ } else {
+ suggestion.set_title(url_formatter::FormatUrl(entry->URL()));
+ }
+ suggestion.set_publisher_name(
+ url_formatter::FormatUrl(entry->URL().GetOrigin()));
+
+ auto extra = base::MakeUnique<ReadingListSuggestionExtra>();
+ extra->distilled_state =
+ SuggestionStateFromReadingListState(entry->DistilledState());
+ extra->favicon_page_url =
+ entry->DistilledURL().is_valid() ? entry->DistilledURL() : entry->URL();
+ suggestion.set_reading_list_suggestion_extra(std::move(extra));
+
+ return suggestion;
+}
+
+void ReadingListSuggestionsProvider::NotifyStatusChanged(
+ CategoryStatus new_status) {
+ if (category_status_ == new_status) {
+ return;
+ }
+ category_status_ = new_status;
+ observer()->OnCategoryStatusChanged(this, provided_category_, new_status);
+}
+
+void ReadingListSuggestionsProvider::SetDismissedState(const GURL& url,
+ bool dismissed) {
+ reading_list::ContentSuggestionsExtra extra;
+ extra.dismissed = dismissed;
+ reading_list_model_->SetContentSuggestionsExtra(url, extra);
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.h b/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.h
new file mode 100644
index 00000000000..433d9493b80
--- /dev/null
+++ b/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.h
@@ -0,0 +1,83 @@
+// 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_NTP_SNIPPETS_READING_LIST_READING_LIST_SUGGESTIONS_PROVIDER_H_
+#define COMPONENTS_NTP_SNIPPETS_READING_LIST_READING_LIST_SUGGESTIONS_PROVIDER_H_
+
+#include <set>
+#include <string>
+
+#include "base/scoped_observer.h"
+#include "components/ntp_snippets/callbacks.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/category_info.h"
+#include "components/ntp_snippets/category_status.h"
+#include "components/ntp_snippets/content_suggestion.h"
+#include "components/ntp_snippets/content_suggestions_provider.h"
+#include "components/reading_list/core/reading_list_model_observer.h"
+
+class ReadingListModel;
+
+namespace ntp_snippets {
+
+// Provides content suggestions from the Reading List.
+class ReadingListSuggestionsProvider : public ContentSuggestionsProvider,
+ public ReadingListModelObserver {
+ public:
+ ReadingListSuggestionsProvider(ContentSuggestionsProvider::Observer* observer,
+ ReadingListModel* reading_list_model);
+ ~ReadingListSuggestionsProvider() override;
+
+ // ContentSuggestionsProvider implementation.
+ CategoryStatus GetCategoryStatus(Category category) override;
+ CategoryInfo GetCategoryInfo(Category category) override;
+ void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+ void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) override;
+ void Fetch(const Category& category,
+ const std::set<std::string>& known_suggestion_ids,
+ const FetchDoneCallback& callback) override;
+ void ClearHistory(
+ base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter) override;
+ void ClearCachedSuggestions(Category category) override;
+ void GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback) override;
+ void ClearDismissedSuggestionsForDebugging(Category category) override;
+
+ // ReadingListModelObserver implementation.
+ void ReadingListModelLoaded(const ReadingListModel* model) override;
+ void ReadingListModelBeingDeleted(const ReadingListModel* model) override;
+ void ReadingListDidApplyChanges(ReadingListModel* model) override;
+ void ReadingListModelCompletedBatchUpdates(
+ const ReadingListModel* model) override;
+
+ private:
+ // The actual method to fetch Reading List entries. Must be called after the
+ // model is loaded.
+ void FetchReadingListInternal();
+
+ // Converts |entry| to ContentSuggestion.
+ ContentSuggestion ConvertEntry(const ReadingListEntry* entry);
+
+ // Updates the |category_status_| and notifies the |observer_|, if necessary.
+ void NotifyStatusChanged(CategoryStatus new_status);
+
+ // Sets the dismissed status of the entry to |dismissed|.
+ void SetDismissedState(const GURL& url, bool dismissed);
+
+ CategoryStatus category_status_;
+ const Category provided_category_;
+
+ ReadingListModel* reading_list_model_;
+ ScopedObserver<ReadingListModel, ReadingListModelObserver> scoped_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReadingListSuggestionsProvider);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_READING_LIST_READING_LIST_SUGGESTIONS_PROVIDER_H_
diff --git a/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider_unittest.cc b/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider_unittest.cc
new file mode 100644
index 00000000000..3ed07071891
--- /dev/null
+++ b/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider_unittest.cc
@@ -0,0 +1,158 @@
+// 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/ntp_snippets/reading_list/reading_list_suggestions_provider.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/test/simple_test_clock.h"
+#include "components/ntp_snippets/mock_content_suggestions_provider_observer.h"
+#include "components/reading_list/core/reading_list_model_impl.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ntp_snippets {
+
+namespace {
+
+const char kTitleUnread1[] = "title1";
+const char kTitleUnread2[] = "title2";
+const char kTitleUnread3[] = "title3";
+const char kTitleUnread4[] = "title4";
+const char kTitleRead1[] = "title_read1";
+
+using ::testing::_;
+using ::testing::ElementsAre;
+using ::testing::IsEmpty;
+using ::testing::Property;
+
+class ReadingListSuggestionsProviderTest : public ::testing::Test {
+ public:
+ ReadingListSuggestionsProviderTest() {
+ std::unique_ptr<base::SimpleTestClock> clock =
+ base::MakeUnique<base::SimpleTestClock>();
+ clock_ = clock.get();
+ model_ = base::MakeUnique<ReadingListModelImpl>(
+ /*storage_layer=*/nullptr, /*pref_service=*/nullptr, std::move(clock));
+ }
+
+ void CreateProvider() {
+ EXPECT_CALL(observer_,
+ OnCategoryStatusChanged(_, ReadingListCategory(),
+ CategoryStatus::AVAILABLE_LOADING))
+ .RetiresOnSaturation();
+ EXPECT_CALL(observer_, OnCategoryStatusChanged(_, ReadingListCategory(),
+ CategoryStatus::AVAILABLE))
+ .RetiresOnSaturation();
+ provider_ = base::MakeUnique<ReadingListSuggestionsProvider>(&observer_,
+ model_.get());
+ }
+
+ Category ReadingListCategory() {
+ return Category::FromKnownCategory(KnownCategories::READING_LIST);
+ }
+
+ void AddEntries() {
+ model_->AddEntry(url_unread1_, kTitleUnread1,
+ reading_list::ADDED_VIA_CURRENT_APP);
+ clock_->Advance(base::TimeDelta::FromMilliseconds(10));
+ model_->AddEntry(url_unread2_, kTitleUnread2,
+ reading_list::ADDED_VIA_CURRENT_APP);
+ clock_->Advance(base::TimeDelta::FromMilliseconds(10));
+ model_->AddEntry(url_read1_, kTitleRead1,
+ reading_list::ADDED_VIA_CURRENT_APP);
+ model_->SetReadStatus(url_read1_, true);
+ clock_->Advance(base::TimeDelta::FromMilliseconds(10));
+ model_->AddEntry(url_unread3_, kTitleUnread3,
+ reading_list::ADDED_VIA_CURRENT_APP);
+ clock_->Advance(base::TimeDelta::FromMilliseconds(10));
+ model_->AddEntry(url_unread4_, kTitleUnread4,
+ reading_list::ADDED_VIA_CURRENT_APP);
+ }
+
+ protected:
+ base::SimpleTestClock* clock_;
+ std::unique_ptr<ReadingListModelImpl> model_;
+ testing::StrictMock<MockContentSuggestionsProviderObserver> observer_;
+ std::unique_ptr<ReadingListSuggestionsProvider> provider_;
+
+ const GURL url_unread1_{"http://www.foo1.bar"};
+ const GURL url_unread2_{"http://www.foo2.bar"};
+ const GURL url_unread3_{"http://www.foo3.bar"};
+ const GURL url_unread4_{"http://www.foo4.bar"};
+ const GURL url_read1_{"http://www.bar.foor"};
+};
+
+TEST_F(ReadingListSuggestionsProviderTest, CategoryInfo) {
+ EXPECT_CALL(observer_, OnNewSuggestions(_, ReadingListCategory(), IsEmpty()))
+ .RetiresOnSaturation();
+ CreateProvider();
+
+ CategoryInfo categoryInfo = provider_->GetCategoryInfo(ReadingListCategory());
+ EXPECT_EQ(ContentSuggestionsAdditionalAction::VIEW_ALL,
+ categoryInfo.additional_action());
+}
+
+TEST_F(ReadingListSuggestionsProviderTest, ReturnsThreeLatestUnreadSuggestion) {
+ AddEntries();
+
+ EXPECT_CALL(
+ observer_,
+ OnNewSuggestions(
+ _, ReadingListCategory(),
+ ElementsAre(Property(&ContentSuggestion::url, url_unread4_),
+ Property(&ContentSuggestion::url, url_unread3_),
+ Property(&ContentSuggestion::url, url_unread2_))));
+
+ CreateProvider();
+}
+
+// Tests that the provider returns only unread suggestions even if there is less
+// unread suggestions than the maximum number of suggestions.
+TEST_F(ReadingListSuggestionsProviderTest, ReturnsOnlyUnreadSuggestion) {
+ GURL url_unread1 = GURL("http://www.foo1.bar");
+ GURL url_read1 = GURL("http://www.bar.foor");
+ std::string title_unread1 = "title1";
+ std::string title_read1 = "title_read1";
+ model_->AddEntry(url_unread1, title_unread1,
+ reading_list::ADDED_VIA_CURRENT_APP);
+ clock_->Advance(base::TimeDelta::FromMilliseconds(10));
+ model_->AddEntry(url_read1, title_read1, reading_list::ADDED_VIA_CURRENT_APP);
+ model_->SetReadStatus(url_read1, true);
+
+ EXPECT_CALL(observer_,
+ OnNewSuggestions(
+ _, ReadingListCategory(),
+ ElementsAre(Property(&ContentSuggestion::url, url_unread1))));
+
+ CreateProvider();
+}
+
+TEST_F(ReadingListSuggestionsProviderTest, DismissesEntry) {
+ AddEntries();
+
+ EXPECT_CALL(
+ observer_,
+ OnNewSuggestions(
+ _, ReadingListCategory(),
+ ElementsAre(Property(&ContentSuggestion::url, url_unread4_),
+ Property(&ContentSuggestion::url, url_unread3_),
+ Property(&ContentSuggestion::url, url_unread2_))));
+
+ CreateProvider();
+
+ EXPECT_CALL(
+ observer_,
+ OnNewSuggestions(
+ _, ReadingListCategory(),
+ ElementsAre(Property(&ContentSuggestion::url, url_unread4_),
+ Property(&ContentSuggestion::url, url_unread2_),
+ Property(&ContentSuggestion::url, url_unread1_))));
+
+ provider_->DismissSuggestion(
+ ContentSuggestion::ID(ReadingListCategory(), url_unread3_.spec()));
+}
+
+} // namespace
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/fetch.py b/chromium/components/ntp_snippets/remote/fetch.py
new file mode 100755
index 00000000000..48f448a3ec7
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/fetch.py
@@ -0,0 +1,228 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# 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.
+
+"""Fetches articles from the server.
+
+Examples:
+ $ fetch.py # unauthenticated, no experiments
+ $ fetch.py --short # abbreviate instead of dumping JSON
+ $ fetch.py --signed-in -x3313279 # authenticated, results from Google Now
+
+If getting signed-in results, authenticates with OAuth2 and stores the
+credentials at ~/.zineauth.
+"""
+
+from __future__ import absolute_import, division, print_function, unicode_literals
+
+import argparse
+import base64
+import datetime
+import json
+import os
+import textwrap
+import oauth2client.client
+import oauth2client.file
+import oauth2client.tools
+import requests
+import sys
+
+
+API_KEY_FILE = os.path.join(
+ os.path.dirname(__file__),
+ "../../../google_apis/internal/google_chrome_api_keys.h")
+API_SCOPE = "https://www.googleapis.com/auth/chrome-content-suggestions"
+API_HOSTS = {
+ "prod": "https://chromecontentsuggestions-pa.googleapis.com",
+ "staging": "https://staging-chromecontentsuggestions-pa.googleapis.com",
+ "alpha": "https://alpha-chromecontentsuggestions-pa.sandbox.googleapis.com",
+}
+API_PATH = "/v1/suggestions/fetch"
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="fetch articles from server",
+ parents=[oauth2client.tools.argparser])
+ parser.add_argument("-c", "--component",
+ default="prod", choices=["prod", "staging", "alpha"],
+ help="component to fetch from (default: prod)")
+ parser.add_argument("-x", "--experiment", action="append", type=int,
+ help="include an experiment ID")
+ parser.add_argument("--api-key", type=str,
+ help="API key to use for unauthenticated requests"
+ " (default: use official key)")
+ parser.add_argument("-s", "--signed-in", action="store_true",
+ help="sign in and issue authenticated request")
+ parser.add_argument("--client", metavar="ID,SECRET", type=str,
+ help="client project to use for authenticated requests"
+ " (default: use official project ID")
+ parser.add_argument("--short", action="store_true",
+ help="print results in abbreviated form")
+ args = parser.parse_args()
+
+ r = PostRequest(args)
+ j = {}
+ try:
+ j = r.json()
+ except ValueError:
+ print(r.text.encode("utf-8"))
+ sys.exit(1)
+ if j.get("error"):
+ print(r.text.encode("utf-8"))
+ sys.exit(1)
+ if args.short:
+ PrintShortResponse(j)
+ return
+ print(r.text.encode("utf-8"))
+ if r.status_code != 200:
+ sys.exit(1)
+
+
+def GetApiKeyFile():
+ return API_KEY_FILE
+
+
+def GetAPIDefs():
+ """Parses the internal file with API keys and returns a dict."""
+ with open(GetApiKeyFile()) as f:
+ lines = f.readlines()
+ defs = {}
+ next_name = None
+ for line in lines:
+ if next_name:
+ defs[next_name] = json.loads(line)
+ next_name = None
+ elif line.startswith("#define"):
+ try:
+ _, name, value = line.split()
+ except ValueError:
+ continue
+ if value == "\\":
+ next_name = name
+ else:
+ defs[name] = json.loads(value)
+ return defs
+
+
+def GetAPIKey():
+ return GetAPIDefs()["GOOGLE_API_KEY"]
+
+
+def GetOAuthClient():
+ defs = GetAPIDefs()
+ return defs["GOOGLE_CLIENT_ID_MAIN"], defs["GOOGLE_CLIENT_SECRET_MAIN"]
+
+
+def EncodeExperiments(experiments):
+ """Turn a list of experiment IDs into an X-Client-Data header value.
+
+ Encodes all the IDs as a protobuf (tag 1, varint) and base64 encodes the
+ result.
+ """
+ binary = b""
+ for exp in experiments:
+ binary += b"\x08"
+ while True:
+ byte = (exp & 0x7f)
+ exp >>= 7
+ if exp:
+ binary += chr(0x80 | byte)
+ else:
+ binary += chr(byte)
+ break
+ return base64.b64encode(binary)
+
+
+def AbbreviateDuration(duration):
+ """Turn a datetime.timedelta into a short string like "10h 14m"."""
+ w = duration.days // 7
+ d = duration.days % 7
+ h = duration.seconds // 3600
+ m = (duration.seconds % 3600) // 60
+ s = duration.seconds % 60
+ us = duration.microseconds
+ if w:
+ return "%dw %dd" % (w, d)
+ elif d:
+ return "%dd %dh" % (d, h)
+ elif h:
+ return "%dh %dm" % (h, m)
+ elif m:
+ return "%dm %ds" % (m, s)
+ elif s:
+ return "%ds" % s
+ elif us:
+ return "<1s"
+ else:
+ return "0s"
+
+
+def PostRequest(args):
+ url = API_HOSTS[args.component] + API_PATH
+ headers = {}
+
+ if args.experiment:
+ headers["X-Client-Data"] = EncodeExperiments(args.experiment)
+
+ if args.signed_in:
+ if args.client:
+ client_id, client_secret = args.client.split(",")
+ else:
+ client_id, client_secret = GetOAuthClient()
+ Authenticate(args, headers, client_id, client_secret)
+ else:
+ if args.api_key:
+ api_key = args.api_key
+ else:
+ api_key = GetAPIKey()
+ url += "?key=" + api_key
+
+ return requests.post(url, headers=headers)
+
+
+def Authenticate(args, headers, client_id, client_secret):
+ storage = oauth2client.file.Storage(os.path.expanduser("~/.zineauth"))
+ creds = storage.get()
+ if not creds or creds.invalid or creds.access_token_expired:
+ flow = oauth2client.client.OAuth2WebServerFlow(
+ client_id=client_id, client_secret=client_secret,
+ scope=API_SCOPE)
+ oauth2client.tools.run_flow(flow, storage, args)
+ creds = storage.get()
+ creds.apply(headers)
+
+
+def PrintShortResponse(r):
+ now = datetime.datetime.now()
+ for category in r.json()["categories"]:
+ print("%s: " % category["localizedTitle"])
+ for suggestion in category["suggestions"]:
+ attribution = suggestion["attribution"]
+ title = suggestion["title"]
+ full_url = suggestion["fullPageUrl"]
+ amp_url = suggestion.get("ampUrl")
+ creation_time = suggestion["creationTime"]
+
+ if len(title) > 40:
+ title = textwrap.wrap(title, 40)[0] + "…"
+ creation_time = ParseDateTime(creation_time)
+ age = AbbreviateDuration(now - creation_time)
+
+ print(" “%s†(%s, %s ago)" % (title, attribution, age))
+ print(" " + (amp_url or full_url))
+ if category["allowFetchingMoreResults"]:
+ print(" [More]")
+
+
+def ParseDateTime(creation_time):
+ try:
+ return datetime.datetime.strptime(creation_time, "%Y-%m-%dT%H:%M:%SZ")
+ except ValueError:
+ return datetime.datetime.strptime(creation_time, "%Y-%m-%dT%H:%M:%S.%fZ")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/chromium/components/ntp_snippets/remote/json_request.cc b/chromium/components/ntp_snippets/remote/json_request.cc
index c561553c985..3f7af6e8b2b 100644
--- a/chromium/components/ntp_snippets/remote/json_request.cc
+++ b/chromium/components/ntp_snippets/remote/json_request.cc
@@ -132,32 +132,6 @@ std::string GetUserClassString(UserClassifier::UserClass user_class) {
} // namespace
-CategoryInfo BuildArticleCategoryInfo(
- const base::Optional<base::string16>& title) {
- return CategoryInfo(
- title.has_value() ? title.value()
- : l10n_util::GetStringUTF16(
- IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_HEADER),
- ContentSuggestionsCardLayout::FULL_CARD,
- /*has_fetch_action=*/true,
- /*has_view_all_action=*/false,
- /*show_if_empty=*/true,
- l10n_util::GetStringUTF16(IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_EMPTY));
-}
-
-CategoryInfo BuildRemoteCategoryInfo(const base::string16& title,
- bool allow_fetching_more_results) {
- return CategoryInfo(
- title, ContentSuggestionsCardLayout::FULL_CARD,
- /*has_fetch_action=*/allow_fetching_more_results,
- /*has_view_all_action=*/false,
- /*show_if_empty=*/false,
- // TODO(tschumann): The message for no-articles is likely wrong
- // and needs to be added to the stubby protocol if we want to
- // support it.
- l10n_util::GetStringUTF16(IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_EMPTY));
-}
-
JsonRequest::JsonRequest(
base::Optional<Category> exclusive_category,
base::Clock* clock, // Needed until destruction of the request.
@@ -244,9 +218,7 @@ void JsonRequest::OnJsonError(const std::string& error) {
/*error_details=*/base::StringPrintf(" (error %s)", error.c_str()));
}
-JsonRequest::Builder::Builder()
- : fetch_api_(CHROME_READER_API),
- language_model_(nullptr) {}
+JsonRequest::Builder::Builder() : language_model_(nullptr) {}
JsonRequest::Builder::Builder(JsonRequest::Builder&&) = default;
JsonRequest::Builder::~Builder() = default;
@@ -276,11 +248,6 @@ JsonRequest::Builder& JsonRequest::Builder::SetAuthentication(
return *this;
}
-JsonRequest::Builder& JsonRequest::Builder::SetFetchAPI(FetchAPI fetch_api) {
- fetch_api_ = fetch_api;
- return *this;
-}
-
JsonRequest::Builder& JsonRequest::Builder::SetLanguageModel(
const translate::LanguageModel* language_model) {
language_model_ = language_model;
@@ -343,84 +310,43 @@ std::string JsonRequest::Builder::BuildHeaders() const {
std::string JsonRequest::Builder::BuildBody() const {
auto request = base::MakeUnique<base::DictionaryValue>();
std::string user_locale = PosixLocaleFromBCP47Language(params_.language_code);
- switch (fetch_api_) {
- case CHROME_READER_API: {
- auto content_restricts = base::MakeUnique<base::ListValue>();
- for (const auto* metadata : {"TITLE", "SNIPPET", "THUMBNAIL"}) {
- auto entry = base::MakeUnique<base::DictionaryValue>();
- entry->SetString("type", "METADATA");
- entry->SetString("value", metadata);
- content_restricts->Append(std::move(entry));
- }
-
- auto local_scoring_params = base::MakeUnique<base::DictionaryValue>();
- local_scoring_params->Set("content_restricts",
- std::move(content_restricts));
-
- auto global_scoring_params = base::MakeUnique<base::DictionaryValue>();
- global_scoring_params->SetInteger("num_to_return",
- params_.count_to_fetch);
- global_scoring_params->SetInteger("sort_type", 1);
-
- auto advanced = base::MakeUnique<base::DictionaryValue>();
- advanced->Set("local_scoring_params", std::move(local_scoring_params));
- advanced->Set("global_scoring_params", std::move(global_scoring_params));
-
- request->SetString("response_detail_level", "STANDARD");
- request->Set("advanced_options", std::move(advanced));
- if (!obfuscated_gaia_id_.empty()) {
- request->SetString("obfuscated_gaia_id", obfuscated_gaia_id_);
- }
- if (!user_locale.empty()) {
- request->SetString("user_locale", user_locale);
- }
+ if (!user_locale.empty()) {
+ request->SetString("uiLanguage", user_locale);
+ }
+
+ request->SetString("priority", params_.interactive_request
+ ? "USER_ACTION"
+ : "BACKGROUND_PREFETCH");
+
+ auto excluded = base::MakeUnique<base::ListValue>();
+ for (const auto& id : params_.excluded_ids) {
+ excluded->AppendString(id);
+ if (excluded->GetSize() >= kMaxExcludedIds) {
break;
}
+ }
+ request->Set("excludedSuggestionIds", std::move(excluded));
- case CHROME_CONTENT_SUGGESTIONS_API: {
- if (!user_locale.empty()) {
- request->SetString("uiLanguage", user_locale);
- }
-
- request->SetString("priority", params_.interactive_request
- ? "USER_ACTION"
- : "BACKGROUND_PREFETCH");
+ if (!user_class_.empty()) {
+ request->SetString("userActivenessClass", user_class_);
+ }
- auto excluded = base::MakeUnique<base::ListValue>();
- for (const auto& id : params_.excluded_ids) {
- excluded->AppendString(id);
- if (excluded->GetSize() >= kMaxExcludedIds) {
- break;
- }
- }
- request->Set("excludedSuggestionIds", std::move(excluded));
-
- if (!user_class_.empty()) {
- request->SetString("userActivenessClass", user_class_);
- }
-
- translate::LanguageModel::LanguageInfo ui_language;
- translate::LanguageModel::LanguageInfo other_top_language;
- PrepareLanguages(&ui_language, &other_top_language);
-
- if (ui_language.frequency == 0 && other_top_language.frequency == 0) {
- break;
- }
-
- auto language_list = base::MakeUnique<base::ListValue>();
- if (ui_language.frequency > 0) {
- AppendLanguageInfoToList(language_list.get(), ui_language);
- }
- if (other_top_language.frequency > 0) {
- AppendLanguageInfoToList(language_list.get(), other_top_language);
- }
- request->Set("topLanguages", std::move(language_list));
-
- // TODO(sfiera): Support count_to_fetch.
- break;
+ translate::LanguageModel::LanguageInfo ui_language;
+ translate::LanguageModel::LanguageInfo other_top_language;
+ PrepareLanguages(&ui_language, &other_top_language);
+ if (ui_language.frequency != 0 || other_top_language.frequency != 0) {
+ auto language_list = base::MakeUnique<base::ListValue>();
+ if (ui_language.frequency > 0) {
+ AppendLanguageInfoToList(language_list.get(), ui_language);
}
+ if (other_top_language.frequency > 0) {
+ AppendLanguageInfoToList(language_list.get(), other_top_language);
+ }
+ request->Set("topLanguages", std::move(language_list));
}
+ // TODO(sfiera): Support count_to_fetch.
+
std::string request_json;
bool success = base::JSONWriter::WriteWithOptions(
*request, base::JSONWriter::OPTIONS_PRETTY_PRINT, &request_json);
@@ -454,10 +380,10 @@ std::unique_ptr<net::URLFetcher> JsonRequest::Builder::BuildURLFetcher(
setting:
"This feature cannot be disabled by settings now (but is requested "
"to be implemented in crbug.com/695129)."
- policy {
+ chrome_policy {
NTPContentSuggestionsEnabled {
policy_options {mode: MANDATORY}
- value: false
+ NTPContentSuggestionsEnabled: false
}
}
})");
diff --git a/chromium/components/ntp_snippets/remote/json_request.h b/chromium/components/ntp_snippets/remote/json_request.h
index 6c73127140b..849df611b6b 100644
--- a/chromium/components/ntp_snippets/remote/json_request.h
+++ b/chromium/components/ntp_snippets/remote/json_request.h
@@ -24,8 +24,6 @@ class Value;
class Clock;
} // namespace base
-class FetchAPI;
-
namespace ntp_snippets {
class UserClassifier;
@@ -44,12 +42,8 @@ enum class FetchResult {
OAUTH_TOKEN_ERROR = 6,
// DEPRECATED_INTERACTIVE_QUOTA_ERROR = 7,
// DEPRECATED_NON_INTERACTIVE_QUOTA_ERROR = 8,
- RESULT_MAX = 9
-};
-
-enum FetchAPI {
- CHROME_READER_API,
- CHROME_CONTENT_SUGGESTIONS_API,
+ MISSING_API_KEY = 9,
+ RESULT_MAX = 10
};
// A single request to query remote suggestions. On success, the suggestions are
@@ -76,7 +70,6 @@ class JsonRequest : public net::URLFetcherDelegate {
Builder& SetAuthentication(const std::string& account_id,
const std::string& auth_header);
Builder& SetCreationTime(base::TimeTicks creation_time);
- Builder& SetFetchAPI(FetchAPI fetch_api);
// The language_model borrowed from the fetcher needs to stay alive until
// the request body is built.
Builder& SetLanguageModel(const translate::LanguageModel* language_model);
@@ -117,7 +110,6 @@ class JsonRequest : public net::URLFetcherDelegate {
// Only required, if the request needs to be sent.
std::string auth_header_;
base::Clock* clock_;
- FetchAPI fetch_api_;
RequestParams params_;
ParseJSONCallback parse_json_callback_;
GURL url_;
diff --git a/chromium/components/ntp_snippets/remote/json_request_unittest.cc b/chromium/components/ntp_snippets/remote/json_request_unittest.cc
index 912042f6e16..d19f2c8b812 100644
--- a/chromium/components/ntp_snippets/remote/json_request_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/json_request_unittest.cc
@@ -61,7 +61,7 @@ class JsonRequestTest : public testing::Test {
public:
JsonRequestTest()
: params_manager_(
- ntp_snippets::kStudyName,
+ ntp_snippets::kArticleSuggestionsFeature.name,
{{"send_top_languages", "true"}, {"send_user_class", "true"}},
{ntp_snippets::kArticleSuggestionsFeature.name}),
pref_service_(base::MakeUnique<TestingPrefServiceSimple>()),
@@ -112,10 +112,8 @@ TEST_F(JsonRequestTest, BuildRequestAuthenticated) {
params.interactive_request = false;
builder.SetParams(params)
.SetUrl(GURL("http://valid-url.test"))
- .SetUrl(GURL("http://valid-url.test"))
.SetAuthentication("0BFUSGAIA", "headerstuff")
.SetUserClassForTesting("ACTIVE_NTP_USER")
- .SetFetchAPI(FetchAPI::CHROME_READER_API)
.Build();
EXPECT_THAT(builder.PreviewRequestHeadersForTesting(),
@@ -124,36 +122,6 @@ TEST_F(JsonRequestTest, BuildRequestAuthenticated) {
"\r\n"));
EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
EqualsJSON("{"
- " \"response_detail_level\": \"STANDARD\","
- " \"obfuscated_gaia_id\": \"0BFUSGAIA\","
- " \"advanced_options\": {"
- " \"local_scoring_params\": {"
- " \"content_restricts\": ["
- " {"
- " \"type\": \"METADATA\","
- " \"value\": \"TITLE\""
- " },"
- " {"
- " \"type\": \"METADATA\","
- " \"value\": \"SNIPPET\""
- " },"
- " {"
- " \"type\": \"METADATA\","
- " \"value\": \"THUMBNAIL\""
- " }"
- " ]"
- " },"
- " \"global_scoring_params\": {"
- " \"num_to_return\": 25,"
- " \"sort_type\": 1"
- " }"
- " }"
- "}"));
-
- builder.SetFetchAPI(FetchAPI::CHROME_CONTENT_SUGGESTIONS_API);
-
- EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
- EqualsJSON("{"
" \"priority\": \"BACKGROUND_PREFETCH\","
" \"excludedSuggestionIds\": ["
" \"1234567890\""
@@ -167,43 +135,13 @@ TEST_F(JsonRequestTest, BuildRequestUnauthenticated) {
RequestParams params;
params.interactive_request = true;
params.count_to_fetch = 10;
- builder.SetParams(params)
- .SetUserClassForTesting("ACTIVE_NTP_USER")
- .SetFetchAPI(FetchAPI::CHROME_READER_API);
+ builder.SetParams(params).SetUserClassForTesting("ACTIVE_NTP_USER");
EXPECT_THAT(builder.PreviewRequestHeadersForTesting(),
StrEq("Content-Type: application/json; charset=UTF-8\r\n"
"\r\n"));
EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
EqualsJSON("{"
- " \"response_detail_level\": \"STANDARD\","
- " \"advanced_options\": {"
- " \"local_scoring_params\": {"
- " \"content_restricts\": ["
- " {"
- " \"type\": \"METADATA\","
- " \"value\": \"TITLE\""
- " },"
- " {"
- " \"type\": \"METADATA\","
- " \"value\": \"SNIPPET\""
- " },"
- " {"
- " \"type\": \"METADATA\","
- " \"value\": \"THUMBNAIL\""
- " }"
- " ]"
- " },"
- " \"global_scoring_params\": {"
- " \"num_to_return\": 10,"
- " \"sort_type\": 1"
- " }"
- " }"
- "}"));
-
- builder.SetFetchAPI(FetchAPI::CHROME_CONTENT_SUGGESTIONS_API);
- EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
- EqualsJSON("{"
" \"priority\": \"USER_ACTION\","
" \"excludedSuggestionIds\": [],"
" \"userActivenessClass\": \"ACTIVE_NTP_USER\""
@@ -217,9 +155,7 @@ TEST_F(JsonRequestTest, BuildRequestExcludedIds) {
for (int i = 0; i < 200; ++i) {
params.excluded_ids.insert(base::StringPrintf("%03d", i));
}
- builder.SetParams(params)
- .SetUserClassForTesting("ACTIVE_NTP_USER")
- .SetFetchAPI(FetchAPI::CHROME_CONTENT_SUGGESTIONS_API);
+ builder.SetParams(params).SetUserClassForTesting("ACTIVE_NTP_USER");
EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
EqualsJSON("{"
@@ -256,8 +192,7 @@ TEST_F(JsonRequestTest, BuildRequestNoUserClass) {
JsonRequest::Builder builder;
RequestParams params;
params.interactive_request = false;
- builder.SetParams(params)
- .SetFetchAPI(FetchAPI::CHROME_CONTENT_SUGGESTIONS_API);
+ builder.SetParams(params);
EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
EqualsJSON("{"
@@ -273,9 +208,7 @@ TEST_F(JsonRequestTest, BuildRequestWithTwoLanguages) {
RequestParams params;
params.interactive_request = true;
params.language_code = "en";
- builder.SetParams(params)
- .SetLanguageModel(language_model.get())
- .SetFetchAPI(FetchAPI::CHROME_CONTENT_SUGGESTIONS_API);
+ builder.SetParams(params).SetLanguageModel(language_model.get());
EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
EqualsJSON("{"
@@ -302,9 +235,7 @@ TEST_F(JsonRequestTest, BuildRequestWithUILanguageOnly) {
RequestParams params;
params.interactive_request = true;
params.language_code = "en";
- builder.SetParams(params)
- .SetLanguageModel(language_model.get())
- .SetFetchAPI(FetchAPI::CHROME_CONTENT_SUGGESTIONS_API);
+ builder.SetParams(params).SetLanguageModel(language_model.get());
EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
EqualsJSON("{"
diff --git a/chromium/components/ntp_snippets/remote/persistent_scheduler.h b/chromium/components/ntp_snippets/remote/persistent_scheduler.h
index 70a27e74ef0..080ceb0b601 100644
--- a/chromium/components/ntp_snippets/remote/persistent_scheduler.h
+++ b/chromium/components/ntp_snippets/remote/persistent_scheduler.h
@@ -35,6 +35,10 @@ class PersistentScheduler {
// the scheduling was successful.
virtual bool Unschedule() = 0;
+ // TODO(jkrcal): Get this information exposed in the platform-independent
+ // net::NetworkChangeNotifier and remove this function.
+ virtual bool IsOnUnmeteredConnection() = 0;
+
protected:
PersistentScheduler() = default;
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestion.cc b/chromium/components/ntp_snippets/remote/remote_suggestion.cc
index 714e016877a..d1159433740 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestion.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestion.cc
@@ -119,7 +119,7 @@ RemoteSuggestion::CreateFromChromeReaderDictionary(
std::vector<SnippetSource> sources;
for (const auto& value : *corpus_infos_list) {
const base::DictionaryValue* dict_value = nullptr;
- if (!value->GetAsDictionary(&dict_value)) {
+ if (!value.GetAsDictionary(&dict_value)) {
DLOG(WARNING) << "Invalid source info for article " << primary_id;
continue;
}
@@ -151,8 +151,8 @@ RemoteSuggestion::CreateFromChromeReaderDictionary(
// Expected to not have AMP url sometimes.
if (dict_value->GetString("ampUrl", &amp_url_str)) {
amp_url = GURL(amp_url_str);
- DLOG_IF(WARNING, !amp_url.is_valid()) << "Invalid AMP url "
- << amp_url_str;
+ DLOG_IF(WARNING, !amp_url.is_valid())
+ << "Invalid AMP url " << amp_url_str;
}
sources.emplace_back(corpus_id, site_title,
amp_url.is_valid() ? amp_url : GURL());
@@ -228,7 +228,7 @@ RemoteSuggestion::CreateFromContentSuggestionsDictionary(
std::vector<std::string> parsed_ids;
for (const auto& value : *ids) {
std::string id;
- if (!value->GetAsString(&id)) {
+ if (!value.GetAsString(&id)) {
return nullptr;
}
parsed_ids.push_back(id);
@@ -308,8 +308,8 @@ std::unique_ptr<RemoteSuggestion> RemoteSuggestion::CreateFromProto(
GURL amp_url;
if (source_proto.has_amp_url()) {
amp_url = GURL(source_proto.amp_url());
- DLOG_IF(WARNING, !amp_url.is_valid()) << "Invalid AMP URL "
- << source_proto.amp_url();
+ DLOG_IF(WARNING, !amp_url.is_valid())
+ << "Invalid AMP URL " << source_proto.amp_url();
}
sources.emplace_back(url, source_proto.publisher_name(), amp_url);
@@ -389,11 +389,17 @@ SnippetProto RemoteSuggestion::ToProto() const {
ContentSuggestion RemoteSuggestion::ToContentSuggestion(
Category category) const {
GURL url = url_;
- if (base::FeatureList::IsEnabled(kPreferAmpUrlsFeature) &&
- !amp_url_.is_empty()) {
+ bool use_amp = base::FeatureList::IsEnabled(kPreferAmpUrlsFeature) &&
+ !amp_url_.is_empty();
+ if (use_amp) {
url = amp_url_;
}
ContentSuggestion suggestion(category, id(), url);
+ // Set url for fetching favicons if it differs from the main url (domains of
+ // AMP URLs sometimes failed to provide favicons).
+ if (use_amp) {
+ suggestion.set_url_with_favicon(url_);
+ }
suggestion.set_title(base::UTF8ToUTF16(title_));
suggestion.set_snippet_text(base::UTF8ToUTF16(snippet_));
suggestion.set_publish_date(publish_date_);
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher.cc
index 2f9b64334f5..b07a116dfe3 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher.cc
@@ -24,6 +24,7 @@
#include "components/ntp_snippets/ntp_snippets_constants.h"
#include "components/ntp_snippets/remote/request_params.h"
#include "components/ntp_snippets/user_classifier.h"
+#include "components/signin/core/browser/access_token_fetcher.h"
#include "components/signin/core/browser/signin_manager.h"
#include "components/signin/core/browser/signin_manager_base.h"
#include "components/strings/grit/components_strings.h"
@@ -40,13 +41,10 @@ using translate::LanguageModel;
namespace ntp_snippets {
using internal::JsonRequest;
-using internal::FetchAPI;
using internal::FetchResult;
namespace {
-const char kChromeReaderApiScope[] =
- "https://www.googleapis.com/auth/webhistory";
const char kContentSuggestionsApiScope[] =
"https://www.googleapis.com/auth/chrome-content-suggestions";
const char kSnippetsServerNonAuthorizedFormat[] = "%s?key=%s";
@@ -71,6 +69,8 @@ std::string FetchResultToString(FetchResult result) {
return "Invalid / empty list.";
case FetchResult::OAUTH_TOKEN_ERROR:
return "Error in obtaining an OAuth2 access token.";
+ case FetchResult::MISSING_API_KEY:
+ return "No API key available.";
case FetchResult::RESULT_MAX:
break;
}
@@ -85,6 +85,7 @@ Status FetchResultToStatus(FetchResult result) {
// Permanent errors occur if it is more likely that the error originated
// from the client.
case FetchResult::OAUTH_TOKEN_ERROR:
+ case FetchResult::MISSING_API_KEY:
return Status(StatusCode::PERMANENT_ERROR, FetchResultToString(result));
// Temporary errors occur if it's more likely that the client behaved
// correctly but the server failed to respond as expected.
@@ -101,20 +102,6 @@ Status FetchResultToStatus(FetchResult result) {
return Status(StatusCode::PERMANENT_ERROR, std::string());
}
-bool UsesChromeContentSuggestionsAPI(const GURL& endpoint) {
- if (endpoint == kChromeReaderServer) {
- return false;
- }
-
- if (endpoint != kContentSuggestionsServer &&
- endpoint != kContentSuggestionsStagingServer &&
- endpoint != kContentSuggestionsAlphaServer) {
- LOG(WARNING) << "Unknown value for " << kContentSuggestionsBackend << ": "
- << endpoint << "; assuming chromecontentsuggestions-style API";
- }
- return true;
-}
-
// Creates suggestions from dictionary values in |list| and adds them to
// |suggestions|. Returns true on success, false if anything went wrong.
// |remote_category_id| is only used if |content_suggestions_api| is true.
@@ -125,7 +112,7 @@ bool AddSuggestionsFromListValue(bool content_suggestions_api,
const base::Time& fetch_time) {
for (const auto& value : list) {
const base::DictionaryValue* dict = nullptr;
- if (!value->GetAsDictionary(&dict)) {
+ if (!value.GetAsDictionary(&dict)) {
return false;
}
@@ -213,18 +200,20 @@ CategoryInfo BuildArticleCategoryInfo(
: l10n_util::GetStringUTF16(
IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_HEADER),
ContentSuggestionsCardLayout::FULL_CARD,
- /*has_fetch_action=*/true,
- /*has_view_all_action=*/false,
+ ContentSuggestionsAdditionalAction::FETCH,
/*show_if_empty=*/true,
l10n_util::GetStringUTF16(IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_EMPTY));
}
CategoryInfo BuildRemoteCategoryInfo(const base::string16& title,
bool allow_fetching_more_results) {
+ ContentSuggestionsAdditionalAction action =
+ ContentSuggestionsAdditionalAction::NONE;
+ if (allow_fetching_more_results) {
+ action = ContentSuggestionsAdditionalAction::FETCH;
+ }
return CategoryInfo(
- title, ContentSuggestionsCardLayout::FULL_CARD,
- /*has_fetch_action=*/allow_fetching_more_results,
- /*has_view_all_action=*/false,
+ title, ContentSuggestionsCardLayout::FULL_CARD, action,
/*show_if_empty=*/false,
// TODO(tschumann): The message for no-articles is likely wrong
// and needs to be added to the stubby protocol if we want to
@@ -255,25 +244,17 @@ RemoteSuggestionsFetcher::RemoteSuggestionsFetcher(
const GURL& api_endpoint,
const std::string& api_key,
const UserClassifier* user_classifier)
- : OAuth2TokenService::Consumer("ntp_snippets"),
- signin_manager_(signin_manager),
+ : signin_manager_(signin_manager),
token_service_(token_service),
url_request_context_getter_(std::move(url_request_context_getter)),
language_model_(language_model),
parse_json_callback_(parse_json_callback),
fetch_url_(api_endpoint),
- fetch_api_(UsesChromeContentSuggestionsAPI(fetch_url_)
- ? FetchAPI::CHROME_CONTENT_SUGGESTIONS_API
- : FetchAPI::CHROME_READER_API),
api_key_(api_key),
clock_(new base::DefaultClock()),
user_classifier_(user_classifier) {}
-RemoteSuggestionsFetcher::~RemoteSuggestionsFetcher() {
- if (waiting_for_refresh_token_) {
- token_service_->RemoveObserver(this);
- }
-}
+RemoteSuggestionsFetcher::~RemoteSuggestionsFetcher() = default;
void RemoteSuggestionsFetcher::FetchSnippets(
const RequestParams& params,
@@ -290,29 +271,17 @@ void RemoteSuggestionsFetcher::FetchSnippets(
}
JsonRequest::Builder builder;
- builder.SetFetchAPI(fetch_api_)
- .SetFetchAPI(fetch_api_)
- .SetLanguageModel(language_model_)
+ builder.SetLanguageModel(language_model_)
.SetParams(params)
.SetParseJsonCallback(parse_json_callback_)
.SetClock(clock_.get())
.SetUrlRequestContextGetter(url_request_context_getter_)
.SetUserClassifier(*user_classifier_);
- if (signin_manager_->IsAuthenticated()) {
+ if (signin_manager_->IsAuthenticated() || signin_manager_->AuthInProgress()) {
// Signed-in: get OAuth token --> fetch suggestions.
- oauth_token_retried_ = false;
pending_requests_.emplace(std::move(builder), std::move(callback));
StartTokenRequest();
- } else if (signin_manager_->AuthInProgress()) {
- // Currently signing in: wait for auth to finish (the refresh token) -->
- // get OAuth token --> fetch suggestions.
- pending_requests_.emplace(std::move(builder), std::move(callback));
- if (!waiting_for_refresh_token_) {
- // Wait until we get a refresh token.
- waiting_for_refresh_token_ = true;
- token_service_->AddObserver(this);
- }
} else {
// Not signed in: fetch suggestions (without authentication).
FetchSnippetsNonAuthenticated(std::move(builder), std::move(callback));
@@ -322,6 +291,12 @@ void RemoteSuggestionsFetcher::FetchSnippets(
void RemoteSuggestionsFetcher::FetchSnippetsNonAuthenticated(
JsonRequest::Builder builder,
SnippetsAvailableCallback callback) {
+ if (api_key_.empty()) {
+ // If we don't have an API key, don't even try.
+ FetchFinished(OptionalFetchedCategories(), std::move(callback),
+ FetchResult::MISSING_API_KEY, std::string());
+ return;
+ }
// When not providing OAuth token, we need to pass the Google API key.
builder.SetUrl(
GURL(base::StringPrintf(kSnippetsServerNonAuthorizedFormat,
@@ -332,11 +307,10 @@ void RemoteSuggestionsFetcher::FetchSnippetsNonAuthenticated(
void RemoteSuggestionsFetcher::FetchSnippetsAuthenticated(
JsonRequest::Builder builder,
SnippetsAvailableCallback callback,
- const std::string& account_id,
const std::string& oauth_access_token) {
// TODO(jkrcal, treib): Add unit-tests for authenticated fetches.
builder.SetUrl(fetch_url_)
- .SetAuthentication(account_id,
+ .SetAuthentication(signin_manager_->GetAuthenticatedAccountId(),
base::StringPrintf(kAuthorizationRequestHeaderFormat,
oauth_access_token.c_str()));
StartRequest(std::move(builder), std::move(callback));
@@ -353,25 +327,33 @@ void RemoteSuggestionsFetcher::StartRequest(
}
void RemoteSuggestionsFetcher::StartTokenRequest() {
- OAuth2TokenService::ScopeSet scopes;
- scopes.insert(fetch_api_ == FetchAPI::CHROME_CONTENT_SUGGESTIONS_API
- ? kContentSuggestionsApiScope
- : kChromeReaderApiScope);
- oauth_request_ = token_service_->StartRequest(
- signin_manager_->GetAuthenticatedAccountId(), scopes, this);
+ // If there is already an ongoing token request, just wait for that.
+ if (token_fetcher_) {
+ return;
+ }
+
+ OAuth2TokenService::ScopeSet scopes{kContentSuggestionsApiScope};
+ token_fetcher_ = base::MakeUnique<AccessTokenFetcher>(
+ "ntp_snippets", signin_manager_, token_service_, scopes,
+ base::BindOnce(&RemoteSuggestionsFetcher::AccessTokenFetchFinished,
+ base::Unretained(this)));
}
-////////////////////////////////////////////////////////////////////////////////
-// OAuth2TokenService::Consumer overrides
-void RemoteSuggestionsFetcher::OnGetTokenSuccess(
- const OAuth2TokenService::Request* request,
- const std::string& access_token,
- const base::Time& expiration_time) {
- // Delete the request after we leave this method.
- std::unique_ptr<OAuth2TokenService::Request> oauth_request(
- std::move(oauth_request_));
- DCHECK_EQ(oauth_request.get(), request)
- << "Got tokens from some previous request";
+void RemoteSuggestionsFetcher::AccessTokenFetchFinished(
+ const GoogleServiceAuthError& error,
+ const std::string& access_token) {
+ // Delete the fetcher only after we leave this method (which is called from
+ // the fetcher itself).
+ DCHECK(token_fetcher_);
+ std::unique_ptr<AccessTokenFetcher> token_fetcher_deleter(
+ std::move(token_fetcher_));
+
+ if (error.state() != GoogleServiceAuthError::NONE) {
+ AccessTokenError(error);
+ return;
+ }
+
+ DCHECK(!access_token.empty());
while (!pending_requests_.empty()) {
std::pair<JsonRequest::Builder, SnippetsAvailableCallback>
@@ -379,25 +361,16 @@ void RemoteSuggestionsFetcher::OnGetTokenSuccess(
pending_requests_.pop();
FetchSnippetsAuthenticated(std::move(builder_and_callback.first),
std::move(builder_and_callback.second),
- oauth_request->GetAccountId(), access_token);
+ access_token);
}
}
-void RemoteSuggestionsFetcher::OnGetTokenFailure(
- const OAuth2TokenService::Request* request,
+void RemoteSuggestionsFetcher::AccessTokenError(
const GoogleServiceAuthError& error) {
- oauth_request_.reset();
-
- if (!oauth_token_retried_ &&
- error.state() == GoogleServiceAuthError::State::REQUEST_CANCELED) {
- // The request (especially on startup) can get reset by loading the refresh
- // token - do it one more time.
- oauth_token_retried_ = true;
- StartTokenRequest();
- return;
- }
+ DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
DLOG(ERROR) << "Unable to get token: " << error.ToString();
+
while (!pending_requests_.empty()) {
std::pair<JsonRequest::Builder, SnippetsAvailableCallback>
builder_and_callback = std::move(pending_requests_.front());
@@ -405,27 +378,12 @@ void RemoteSuggestionsFetcher::OnGetTokenFailure(
FetchFinished(OptionalFetchedCategories(),
std::move(builder_and_callback.second),
FetchResult::OAUTH_TOKEN_ERROR,
- /*error_details=*/base::StringPrintf(
- " (%s)", error.ToString().c_str()));
+ /*error_details=*/
+ base::StringPrintf(" (%s)", error.ToString().c_str()));
pending_requests_.pop();
}
}
-////////////////////////////////////////////////////////////////////////////////
-// OAuth2TokenService::Observer overrides
-void RemoteSuggestionsFetcher::OnRefreshTokenAvailable(
- const std::string& account_id) {
- // Only react on tokens for the account the user has signed in with.
- if (account_id != signin_manager_->GetAuthenticatedAccountId()) {
- return;
- }
-
- token_service_->RemoveObserver(this);
- waiting_for_refresh_token_ = false;
- oauth_token_retried_ = false;
- StartTokenRequest();
-}
-
void RemoteSuggestionsFetcher::JsonRequestDone(
std::unique_ptr<JsonRequest> request,
SnippetsAvailableCallback callback,
@@ -446,8 +404,8 @@ void RemoteSuggestionsFetcher::JsonRequestDone(
error_details);
return;
}
- FetchedCategoriesVector categories;
+ FetchedCategoriesVector categories;
if (!JsonToSnippets(*result, &categories, fetch_time)) {
LOG(WARNING) << "Received invalid snippets: " << last_fetch_json_;
FetchFinished(OptionalFetchedCategories(), std::move(callback),
@@ -491,70 +449,51 @@ bool RemoteSuggestionsFetcher::JsonToSnippets(
return false;
}
- switch (fetch_api_) {
- case FetchAPI::CHROME_READER_API: {
- const int kUnusedRemoteCategoryId = -1;
- categories->push_back(FetchedCategory(
- Category::FromKnownCategory(KnownCategories::ARTICLES),
- BuildArticleCategoryInfo(base::nullopt)));
-
- const base::ListValue* recos = nullptr;
- return top_dict->GetList("recos", &recos) &&
- AddSuggestionsFromListValue(
- /*content_suggestions_api=*/false, kUnusedRemoteCategoryId,
- *recos, &categories->back().suggestions, fetch_time);
+ const base::ListValue* categories_value = nullptr;
+ if (!top_dict->GetList("categories", &categories_value)) {
+ return false;
+ }
+
+ for (const auto& v : *categories_value) {
+ std::string utf8_title;
+ int remote_category_id = -1;
+ const base::DictionaryValue* category_value = nullptr;
+ if (!(v.GetAsDictionary(&category_value) &&
+ category_value->GetString("localizedTitle", &utf8_title) &&
+ category_value->GetInteger("id", &remote_category_id) &&
+ (remote_category_id > 0))) {
+ return false;
}
- case FetchAPI::CHROME_CONTENT_SUGGESTIONS_API: {
- const base::ListValue* categories_value = nullptr;
- if (!top_dict->GetList("categories", &categories_value)) {
+ RemoteSuggestion::PtrVector suggestions;
+ const base::ListValue* suggestions_list = nullptr;
+ // Absence of a list of suggestions is treated as an empty list, which
+ // is permissible.
+ if (category_value->GetList("suggestions", &suggestions_list)) {
+ if (!AddSuggestionsFromListValue(
+ /*content_suggestions_api=*/true, remote_category_id,
+ *suggestions_list, &suggestions, fetch_time)) {
return false;
}
-
- for (const auto& v : *categories_value) {
- std::string utf8_title;
- int remote_category_id = -1;
- const base::DictionaryValue* category_value = nullptr;
- if (!(v->GetAsDictionary(&category_value) &&
- category_value->GetString("localizedTitle", &utf8_title) &&
- category_value->GetInteger("id", &remote_category_id) &&
- (remote_category_id > 0))) {
- return false;
- }
-
- RemoteSuggestion::PtrVector suggestions;
- const base::ListValue* suggestions_list = nullptr;
- // Absence of a list of suggestions is treated as an empty list, which
- // is permissible.
- if (category_value->GetList("suggestions", &suggestions_list)) {
- if (!AddSuggestionsFromListValue(
- /*content_suggestions_api=*/true, remote_category_id,
- *suggestions_list, &suggestions, fetch_time)) {
- return false;
- }
- }
- Category category = Category::FromRemoteCategory(remote_category_id);
- if (category.IsKnownCategory(KnownCategories::ARTICLES)) {
- categories->push_back(FetchedCategory(
- category,
- BuildArticleCategoryInfo(base::UTF8ToUTF16(utf8_title))));
- } else {
- // TODO(tschumann): Right now, the backend does not yet populate this
- // field. Make it mandatory once the backends provide it.
- bool allow_fetching_more_results = false;
- category_value->GetBoolean("allowFetchingMoreResults",
- &allow_fetching_more_results);
- categories->push_back(FetchedCategory(
- category, BuildRemoteCategoryInfo(base::UTF8ToUTF16(utf8_title),
- allow_fetching_more_results)));
- }
- categories->back().suggestions = std::move(suggestions);
- }
- return true;
}
+ Category category = Category::FromRemoteCategory(remote_category_id);
+ if (category.IsKnownCategory(KnownCategories::ARTICLES)) {
+ categories->push_back(FetchedCategory(
+ category, BuildArticleCategoryInfo(base::UTF8ToUTF16(utf8_title))));
+ } else {
+ // TODO(tschumann): Right now, the backend does not yet populate this
+ // field. Make it mandatory once the backends provide it.
+ bool allow_fetching_more_results = false;
+ category_value->GetBoolean("allowFetchingMoreResults",
+ &allow_fetching_more_results);
+ categories->push_back(FetchedCategory(
+ category, BuildRemoteCategoryInfo(base::UTF8ToUTF16(utf8_title),
+ allow_fetching_more_results)));
+ }
+ categories->back().suggestions = std::move(suggestions);
}
- NOTREACHED();
- return false;
+
+ return true;
}
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher.h b/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher.h
index c2c929722ed..ffe7fd9be04 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher.h
@@ -25,6 +25,8 @@
#include "components/version_info/version_info.h"
#include "net/url_request/url_request_context_getter.h"
+class AccessTokenFetcher;
+class OAuth2TokenService;
class PrefService;
class SigninManagerBase;
@@ -60,8 +62,7 @@ CategoryInfo BuildRemoteCategoryInfo(const base::string16& title,
// TODO(fhorschig): Untangle cyclic dependencies by introducing a
// RemoteSuggestionsFetcherInterface. (Would be good for mock implementations,
// too!)
-class RemoteSuggestionsFetcher : public OAuth2TokenService::Consumer,
- public OAuth2TokenService::Observer {
+class RemoteSuggestionsFetcher {
public:
struct FetchedCategory {
Category category;
@@ -90,7 +91,7 @@ class RemoteSuggestionsFetcher : public OAuth2TokenService::Consumer,
const GURL& api_endpoint,
const std::string& api_key,
const UserClassifier* user_classifier);
- ~RemoteSuggestionsFetcher() override;
+ ~RemoteSuggestionsFetcher();
// Initiates a fetch from the server. When done (successfully or not), calls
// the callback.
@@ -135,22 +136,15 @@ class RemoteSuggestionsFetcher : public OAuth2TokenService::Consumer,
SnippetsAvailableCallback callback);
void FetchSnippetsAuthenticated(internal::JsonRequest::Builder builder,
SnippetsAvailableCallback callback,
- const std::string& account_id,
const std::string& oauth_access_token);
void StartRequest(internal::JsonRequest::Builder builder,
SnippetsAvailableCallback callback);
void StartTokenRequest();
- // OAuth2TokenService::Consumer overrides:
- void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
- const std::string& access_token,
- const base::Time& expiration_time) override;
- void OnGetTokenFailure(const OAuth2TokenService::Request* request,
- const GoogleServiceAuthError& error) override;
-
- // OAuth2TokenService::Observer overrides:
- void OnRefreshTokenAvailable(const std::string& account_id) override;
+ void AccessTokenFetchFinished(const GoogleServiceAuthError& error,
+ const std::string& access_token);
+ void AccessTokenError(const GoogleServiceAuthError& error);
void JsonRequestDone(std::unique_ptr<internal::JsonRequest> request,
SnippetsAvailableCallback callback,
@@ -169,11 +163,8 @@ class RemoteSuggestionsFetcher : public OAuth2TokenService::Consumer,
// Authentication for signed-in users.
SigninManagerBase* signin_manager_;
OAuth2TokenService* token_service_;
- std::unique_ptr<OAuth2TokenService::Request> oauth_request_;
- bool waiting_for_refresh_token_ = false;
- // When a token request gets canceled, we want to retry once.
- bool oauth_token_retried_ = false;
+ std::unique_ptr<AccessTokenFetcher> token_fetcher_;
// Holds the URL request context.
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
@@ -190,8 +181,6 @@ class RemoteSuggestionsFetcher : public OAuth2TokenService::Consumer,
// API endpoint for fetching suggestions.
const GURL fetch_url_;
- // Which API to use
- const internal::FetchAPI fetch_api_;
// API key to use for non-authenticated requests.
const std::string api_key_;
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_unittest.cc
index 4771148b964..7607efe00ca 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_unittest.cc
@@ -6,16 +6,15 @@
#include <deque>
#include <map>
-#include <set>
#include <utility>
#include <vector>
#include "base/json/json_reader.h"
#include "base/memory/ptr_util.h"
-#include "base/strings/stringprintf.h"
#include "base/test/histogram_tester.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "base/values.h"
#include "components/ntp_snippets/category.h"
@@ -44,19 +43,12 @@ using testing::_;
using testing::AllOf;
using testing::ElementsAre;
using testing::Eq;
-using testing::Field;
using testing::IsEmpty;
using testing::Not;
using testing::NotNull;
-using testing::Pointee;
-using testing::PrintToString;
-using testing::Return;
using testing::StartsWith;
-using testing::WithArg;
const char kAPIKey[] = "fakeAPIkey";
-const char kTestChromeReaderUrl[] =
- "https://chromereader-pa.googleapis.com/v1/fetch?key=fakeAPIkey";
const char kTestChromeContentSuggestionsSignedOutUrl[] =
"https://chromecontentsuggestions-pa.googleapis.com/v1/suggestions/"
"fetch?key=fakeAPIkey";
@@ -86,6 +78,12 @@ MATCHER(IsSuccess, "") {
return arg.IsSuccess();
}
+MATCHER(IsEmptyCategoriesList, "is an empty list of categories") {
+ RemoteSuggestionsFetcher::OptionalFetchedCategories& fetched_categories =
+ *arg;
+ return fetched_categories && fetched_categories->empty();
+}
+
MATCHER(IsEmptyArticleList, "is an empty list of articles") {
RemoteSuggestionsFetcher::OptionalFetchedCategories& fetched_categories =
*arg;
@@ -119,12 +117,8 @@ MATCHER_P(IsSingleArticle, url, "is a list with the single article %(url)s") {
}
MATCHER(IsCategoryInfoForArticles, "") {
- if (!arg.has_fetch_action()) {
- *result_listener << "missing expected has_fetc_action";
- return false;
- }
- if (arg.has_view_all_action()) {
- *result_listener << "unexpected has_view_all_action";
+ if (arg.additional_action() != ContentSuggestionsAdditionalAction::FETCH) {
+ *result_listener << "missing expected FETCH action";
return false;
}
if (!arg.show_if_empty()) {
@@ -277,20 +271,23 @@ class RemoteSuggestionsFetcherTestBase : public testing::Test {
explicit RemoteSuggestionsFetcherTestBase(const GURL& gurl)
: default_variation_params_(
{{"send_top_languages", "true"}, {"send_user_class", "true"}}),
- params_manager_(ntp_snippets::kStudyName,
+ params_manager_(ntp_snippets::kArticleSuggestionsFeature.name,
default_variation_params_,
{ntp_snippets::kArticleSuggestionsFeature.name}),
mock_task_runner_(new base::TestMockTimeTaskRunner()),
mock_task_runner_handle_(mock_task_runner_),
test_url_(gurl) {
UserClassifier::RegisterProfilePrefs(utils_.pref_service()->registry());
- user_classifier_ = base::MakeUnique<UserClassifier>(utils_.pref_service());
+ user_classifier_ = base::MakeUnique<UserClassifier>(
+ utils_.pref_service(), base::MakeUnique<base::DefaultClock>());
// Increase initial time such that ticks are non-zero.
mock_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(1234));
ResetFetcher();
}
- void ResetFetcher() {
+ void ResetFetcher() { ResetFetcherWithAPIKey(kAPIKey); }
+
+ void ResetFetcherWithAPIKey(const std::string& api_key) {
scoped_refptr<net::TestURLRequestContextGetter> request_context_getter =
new net::TestURLRequestContextGetter(mock_task_runner_.get());
@@ -302,7 +299,7 @@ class RemoteSuggestionsFetcherTestBase : public testing::Test {
utils_.fake_signin_manager(), fake_token_service_.get(),
std::move(request_context_getter), utils_.pref_service(), nullptr,
base::Bind(&ParseJsonDelayed),
- GetFetchEndpoint(version_info::Channel::STABLE), kAPIKey,
+ GetFetchEndpoint(version_info::Channel::STABLE), api_key,
user_classifier_.get());
fetcher_->SetClockForTesting(mock_task_runner_->GetMockClock());
@@ -361,7 +358,7 @@ class RemoteSuggestionsFetcherTestBase : public testing::Test {
params_manager_.ClearAllVariationParams();
params_manager_.SetVariationParamsWithFeatureAssociations(
- ntp_snippets::kStudyName, params,
+ ntp_snippets::kArticleSuggestionsFeature.name, params,
{ntp_snippets::kArticleSuggestionsFeature.name});
}
@@ -394,18 +391,6 @@ class RemoteSuggestionsFetcherTestBase : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsFetcherTestBase);
};
-class RemoteSuggestionsChromeReaderFetcherTest
- : public RemoteSuggestionsFetcherTestBase {
- public:
- RemoteSuggestionsChromeReaderFetcherTest()
- : RemoteSuggestionsFetcherTestBase(GURL(kTestChromeReaderUrl)) {
- default_variation_params_["content_suggestions_backend"] =
- kChromeReaderServer;
- SetVariationParam("content_suggestions_backend", kChromeReaderServer);
- ResetFetcher();
- }
-};
-
class RemoteSuggestionsSignedOutFetcherTest
: public RemoteSuggestionsFetcherTestBase {
public:
@@ -414,9 +399,11 @@ class RemoteSuggestionsSignedOutFetcherTest
GURL(kTestChromeContentSuggestionsSignedOutUrl)) {}
};
-// TODO(jkrcal): Add unit-tests for the "authentication in progress" case as it
-// requires more changes (instead FakeSigninManagerBase use FakeSigninManager
-// which does not exist on ChromeOS). crbug.com/688310
+// TODO(jkrcal): Investigate whether the "authentication in progress" case can
+// ever happen (see discussion on https://codereview.chromium.org/2582573002),
+// and if so, add unit-tests for it. This will require more changes (instead of
+// FakeSigninManagerBase use FakeSigninManager which does not exist on
+// ChromeOS). crbug.com/688310
class RemoteSuggestionsSignedInFetcherTest
: public RemoteSuggestionsFetcherTestBase {
public:
@@ -425,7 +412,7 @@ class RemoteSuggestionsSignedInFetcherTest
GURL(kTestChromeContentSuggestionsSignedInUrl)) {}
};
-TEST_F(RemoteSuggestionsChromeReaderFetcherTest, ShouldNotFetchOnCreation) {
+TEST_F(RemoteSuggestionsSignedOutFetcherTest, ShouldNotFetchOnCreation) {
// The lack of registered baked in responses would cause any fetch to fail.
FastForwardUntilNoTasksRemain();
EXPECT_THAT(histogram_tester().GetAllSamples(
@@ -436,37 +423,6 @@ TEST_F(RemoteSuggestionsChromeReaderFetcherTest, ShouldNotFetchOnCreation) {
EXPECT_THAT(fetcher().last_status(), IsEmpty());
}
-TEST_F(RemoteSuggestionsChromeReaderFetcherTest, ShouldFetchSuccessfully) {
- const std::string kJsonStr =
- "{\"recos\": [{"
- " \"contentInfo\": {"
- " \"url\" : \"http://localhost/foobar\","
- " \"sourceCorpusInfo\" : [{"
- " \"ampUrl\" : \"http://localhost/amp\","
- " \"corpusId\" : \"http://localhost/foobar\","
- " \"publisherData\": { \"sourceName\" : \"Foo News\" }"
- " }]"
- " }"
- "}]}";
- SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK,
- net::URLRequestStatus::SUCCESS);
- EXPECT_CALL(mock_callback(),
- Run(IsSuccess(),
- AllOf(IsSingleArticle("http://localhost/foobar"),
- FirstCategoryHasInfo(IsCategoryInfoForArticles()))));
- fetcher().FetchSnippets(test_params(),
- ToSnippetsAvailableCallback(&mock_callback()));
- FastForwardUntilNoTasksRemain();
- EXPECT_THAT(fetcher().last_status(), Eq("OK"));
- EXPECT_THAT(fetcher().last_json(), Eq(kJsonStr));
- EXPECT_THAT(histogram_tester().GetAllSamples(
- "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
- ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
- ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs,
- /*count=*/1)));
-}
-
TEST_F(RemoteSuggestionsSignedOutFetcherTest, ShouldFetchSuccessfully) {
const std::string kJsonStr =
"{\"categories\" : [{"
@@ -549,8 +505,7 @@ TEST_F(RemoteSuggestionsSignedInFetcherTest, ShouldFetchSuccessfully) {
/*count=*/1)));
}
-TEST_F(RemoteSuggestionsSignedInFetcherTest,
- ShouldRetryWhenOAuthCancelled) {
+TEST_F(RemoteSuggestionsSignedInFetcherTest, ShouldRetryWhenOAuthCancelled) {
SignIn();
IssueRefreshToken();
@@ -672,8 +627,8 @@ TEST_F(RemoteSuggestionsSignedOutFetcherTest, ServerCategories) {
} else if (category.category == Category::FromRemoteCategory(2)) {
ASSERT_THAT(articles.size(), Eq(1u));
EXPECT_THAT(articles[0]->url().spec(), Eq("http://localhost/foo2"));
- EXPECT_THAT(category.info.has_fetch_action(), Eq(true));
- EXPECT_THAT(category.info.has_view_all_action(), Eq(false));
+ EXPECT_THAT(category.info.additional_action(),
+ Eq(ContentSuggestionsAdditionalAction::FETCH));
EXPECT_THAT(category.info.show_if_empty(), Eq(false));
} else {
FAIL() << "unknown category ID " << category.category.id();
@@ -724,7 +679,8 @@ TEST_F(RemoteSuggestionsSignedOutFetcherTest,
ASSERT_TRUE(fetched_categories);
ASSERT_THAT(fetched_categories->size(), Eq(1u));
- EXPECT_THAT(fetched_categories->front().info.has_fetch_action(), Eq(false));
+ EXPECT_THAT(fetched_categories->front().info.additional_action(),
+ Eq(ContentSuggestionsAdditionalAction::NONE));
EXPECT_THAT(fetched_categories->front().info.title(),
Eq(base::UTF8ToUTF16("Articles for Me")));
}
@@ -800,12 +756,30 @@ TEST_F(RemoteSuggestionsSignedOutFetcherTest, ExclusiveCategoryOnly) {
Eq("http://localhost/foo2"));
}
-TEST_F(RemoteSuggestionsChromeReaderFetcherTest,
+TEST_F(RemoteSuggestionsSignedOutFetcherTest, ShouldNotFetchWithoutApiKey) {
+ ResetFetcherWithAPIKey(std::string());
+
+ EXPECT_CALL(mock_callback(), Run(HasCode(StatusCode::PERMANENT_ERROR),
+ /*snippets=*/Not(HasValue())))
+ .Times(1);
+ fetcher().FetchSnippets(test_params(),
+ ToSnippetsAvailableCallback(&mock_callback()));
+ FastForwardUntilNoTasksRemain();
+
+ EXPECT_THAT(fetcher().last_status(), Eq("No API key available."));
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
+ IsEmpty());
+ EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
+ IsEmpty());
+}
+
+TEST_F(RemoteSuggestionsSignedOutFetcherTest,
ShouldFetchSuccessfullyEmptyList) {
- const std::string kJsonStr = "{\"recos\": []}";
+ const std::string kJsonStr = "{\"categories\": []}";
SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
- EXPECT_CALL(mock_callback(), Run(IsSuccess(), IsEmptyArticleList()));
+ EXPECT_CALL(mock_callback(), Run(IsSuccess(), IsEmptyCategoriesList()));
fetcher().FetchSnippets(test_params(),
ToSnippetsAvailableCallback(&mock_callback()));
FastForwardUntilNoTasksRemain();
@@ -819,7 +793,7 @@ TEST_F(RemoteSuggestionsChromeReaderFetcherTest,
ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
}
-TEST_F(RemoteSuggestionsChromeReaderFetcherTest, RetryOnInteractiveRequests) {
+TEST_F(RemoteSuggestionsSignedOutFetcherTest, RetryOnInteractiveRequests) {
DelegateCallingTestURLFetcherFactory fetcher_factory;
RequestParams params = test_params();
params.interactive_request = true;
@@ -832,7 +806,7 @@ TEST_F(RemoteSuggestionsChromeReaderFetcherTest, RetryOnInteractiveRequests) {
EXPECT_THAT(fetcher->GetMaxRetriesOn5xx(), Eq(2));
}
-TEST_F(RemoteSuggestionsChromeReaderFetcherTest,
+TEST_F(RemoteSuggestionsSignedOutFetcherTest,
RetriesConfigurableOnNonInteractiveRequests) {
struct ExpectationForVariationParam {
std::string param_value;
@@ -862,7 +836,7 @@ TEST_F(RemoteSuggestionsChromeReaderFetcherTest,
}
}
-TEST_F(RemoteSuggestionsChromeReaderFetcherTest, ShouldReportUrlStatusError) {
+TEST_F(RemoteSuggestionsSignedOutFetcherTest, ShouldReportUrlStatusError) {
SetFakeResponse(/*response_data=*/std::string(), net::HTTP_NOT_FOUND,
net::URLRequestStatus::FAILED);
EXPECT_CALL(mock_callback(), Run(HasCode(StatusCode::TEMPORARY_ERROR),
@@ -883,7 +857,7 @@ TEST_F(RemoteSuggestionsChromeReaderFetcherTest, ShouldReportUrlStatusError) {
Not(IsEmpty()));
}
-TEST_F(RemoteSuggestionsChromeReaderFetcherTest, ShouldReportHttpError) {
+TEST_F(RemoteSuggestionsSignedOutFetcherTest, ShouldReportHttpError) {
SetFakeResponse(/*response_data=*/std::string(), net::HTTP_NOT_FOUND,
net::URLRequestStatus::SUCCESS);
EXPECT_CALL(mock_callback(), Run(HasCode(StatusCode::TEMPORARY_ERROR),
@@ -903,7 +877,7 @@ TEST_F(RemoteSuggestionsChromeReaderFetcherTest, ShouldReportHttpError) {
Not(IsEmpty()));
}
-TEST_F(RemoteSuggestionsChromeReaderFetcherTest, ShouldReportJsonError) {
+TEST_F(RemoteSuggestionsSignedOutFetcherTest, ShouldReportJsonError) {
const std::string kInvalidJsonStr = "{ \"recos\": []";
SetFakeResponse(/*response_data=*/kInvalidJsonStr, net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
@@ -927,7 +901,7 @@ TEST_F(RemoteSuggestionsChromeReaderFetcherTest, ShouldReportJsonError) {
/*count=*/1)));
}
-TEST_F(RemoteSuggestionsChromeReaderFetcherTest,
+TEST_F(RemoteSuggestionsSignedOutFetcherTest,
ShouldReportJsonErrorForEmptyResponse) {
SetFakeResponse(/*response_data=*/std::string(), net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
@@ -946,7 +920,7 @@ TEST_F(RemoteSuggestionsChromeReaderFetcherTest,
ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
}
-TEST_F(RemoteSuggestionsChromeReaderFetcherTest, ShouldReportInvalidListError) {
+TEST_F(RemoteSuggestionsSignedOutFetcherTest, ShouldReportInvalidListError) {
const std::string kJsonStr =
"{\"recos\": [{ \"contentInfo\": { \"foo\" : \"bar\" }}]}";
SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK,
@@ -970,7 +944,7 @@ TEST_F(RemoteSuggestionsChromeReaderFetcherTest, ShouldReportInvalidListError) {
// This test actually verifies that the test setup itself is sane, to prevent
// hard-to-reproduce test failures.
-TEST_F(RemoteSuggestionsChromeReaderFetcherTest,
+TEST_F(RemoteSuggestionsSignedOutFetcherTest,
ShouldReportHttpErrorForMissingBakedResponse) {
InitFakeURLFetcherFactory();
EXPECT_CALL(mock_callback(), Run(HasCode(StatusCode::TEMPORARY_ERROR),
@@ -981,12 +955,12 @@ TEST_F(RemoteSuggestionsChromeReaderFetcherTest,
FastForwardUntilNoTasksRemain();
}
-TEST_F(RemoteSuggestionsChromeReaderFetcherTest,
- ShouldProcessConcurrentFetches) {
- const std::string kJsonStr = "{ \"recos\": [] }";
+TEST_F(RemoteSuggestionsSignedOutFetcherTest, ShouldProcessConcurrentFetches) {
+ const std::string kJsonStr = "{ \"categories\": [] }";
SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
- EXPECT_CALL(mock_callback(), Run(IsSuccess(), IsEmptyArticleList())).Times(5);
+ EXPECT_CALL(mock_callback(), Run(IsSuccess(), IsEmptyCategoriesList()))
+ .Times(5);
fetcher().FetchSnippets(test_params(),
ToSnippetsAvailableCallback(&mock_callback()));
// More calls to FetchSnippets() do not interrupt the previous.
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_provider.h b/chromium/components/ntp_snippets/remote/remote_suggestions_provider.h
index 4e3ec4d028d..5e94b8a9db6 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_provider.h
@@ -32,14 +32,15 @@ class RemoteSuggestionsProvider : public ContentSuggestionsProvider {
// triggered by the user and have lower priority on the server. After the
// fetch finished, the provided |callback| will be triggered with the status
// of the fetch (unless nullptr).
- // TODO(jkrcal): Change to FetchStatusCallback callback as callbacks already
- // have is_empty() functionality. crbug.com/676317
- virtual void RefetchInTheBackground(
- std::unique_ptr<FetchStatusCallback> callback) = 0;
+ virtual void RefetchInTheBackground(const FetchStatusCallback& callback) = 0;
virtual const RemoteSuggestionsFetcher* suggestions_fetcher_for_debugging()
const = 0;
+ // Get the url with favicon for the suggestion.
+ virtual GURL GetUrlWithFavicon(
+ const ContentSuggestion::ID& suggestion_id) const = 0;
+
protected:
RemoteSuggestionsProvider(Observer* observer);
};
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 ac58f3b2d1b..2c637e3a57a 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
@@ -21,9 +21,10 @@
#include "base/time/time.h"
#include "base/values.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "components/image_fetcher/image_decoder.h"
-#include "components/image_fetcher/image_fetcher.h"
+#include "components/image_fetcher/core/image_decoder.h"
+#include "components/image_fetcher/core/image_fetcher.h"
#include "components/ntp_snippets/category_rankers/category_ranker.h"
+#include "components/ntp_snippets/features.h"
#include "components/ntp_snippets/pref_names.h"
#include "components/ntp_snippets/remote/remote_suggestions_database.h"
#include "components/ntp_snippets/remote/remote_suggestions_scheduler.h"
@@ -31,6 +32,7 @@
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/strings/grit/components_strings.h"
+#include "components/variations/variations_associated_data.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
@@ -51,6 +53,47 @@ const char kCategoryContentTitle[] = "title";
const char kCategoryContentProvidedByServer[] = "provided_by_server";
const char kCategoryContentAllowFetchingMore[] = "allow_fetching_more";
+// Variation parameter for ordering new remote categories based on their
+// position in the response relative to "Article for you" category.
+const char kOrderNewRemoteCategoriesBasedOnArticlesCategory[] =
+ "order_new_remote_categories_based_on_articles_category";
+
+bool IsOrderingNewRemoteCategoriesBasedOnArticlesCategoryEnabled() {
+ return variations::GetVariationParamByFeatureAsBool(
+ ntp_snippets::kArticleSuggestionsFeature,
+ kOrderNewRemoteCategoriesBasedOnArticlesCategory,
+ /*default_value=*/false);
+}
+
+void AddFetchedCategoriesToRankerBasedOnArticlesCategory(
+ CategoryRanker* ranker,
+ const RemoteSuggestionsFetcher::FetchedCategoriesVector& fetched_categories,
+ Category articles_category) {
+ DCHECK(IsOrderingNewRemoteCategoriesBasedOnArticlesCategoryEnabled());
+ // Insert categories which precede "Articles" in the response.
+ for (const RemoteSuggestionsFetcher::FetchedCategory& fetched_category :
+ fetched_categories) {
+ if (fetched_category.category == articles_category) {
+ break;
+ }
+ ranker->InsertCategoryBeforeIfNecessary(fetched_category.category,
+ articles_category);
+ }
+ // 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) {
+ return;
+ }
+ ranker->InsertCategoryAfterIfNecessary(fetched_category_it->category,
+ articles_category);
+ }
+ NOTREACHED() << "Articles category was not found.";
+}
+
template <typename SuggestionPtrContainer>
std::unique_ptr<std::vector<std::string>> GetSuggestionIDVector(
const SuggestionPtrContainer& suggestions) {
@@ -74,13 +117,11 @@ bool HasIntersection(const std::vector<std::string>& a,
void EraseByPrimaryID(RemoteSuggestion::PtrVector* suggestions,
const std::vector<std::string>& ids) {
std::set<std::string> ids_lookup(ids.begin(), ids.end());
- suggestions->erase(
- std::remove_if(
- suggestions->begin(), suggestions->end(),
- [&ids_lookup](const std::unique_ptr<RemoteSuggestion>& suggestion) {
- return base::ContainsValue(ids_lookup, suggestion->id());
- }),
- suggestions->end());
+ base::EraseIf(
+ *suggestions,
+ [&ids_lookup](const std::unique_ptr<RemoteSuggestion>& suggestion) {
+ return base::ContainsValue(ids_lookup, suggestion->id());
+ });
}
void EraseMatchingSuggestions(
@@ -91,23 +132,18 @@ void EraseMatchingSuggestions(
const std::vector<std::string>& suggestion_ids = suggestion->GetAllIDs();
compare_against_ids.insert(suggestion_ids.begin(), suggestion_ids.end());
}
- suggestions->erase(
- std::remove_if(suggestions->begin(), suggestions->end(),
- [&compare_against_ids](
- const std::unique_ptr<RemoteSuggestion>& suggestion) {
- return HasIntersection(suggestion->GetAllIDs(),
- compare_against_ids);
- }),
- suggestions->end());
+ base::EraseIf(
+ *suggestions, [&compare_against_ids](
+ const std::unique_ptr<RemoteSuggestion>& suggestion) {
+ return HasIntersection(suggestion->GetAllIDs(), compare_against_ids);
+ });
}
void RemoveNullPointers(RemoteSuggestion::PtrVector* suggestions) {
- suggestions->erase(
- std::remove_if(suggestions->begin(), suggestions->end(),
- [](const std::unique_ptr<RemoteSuggestion>& suggestion) {
- return !suggestion;
- }),
- suggestions->end());
+ base::EraseIf(*suggestions,
+ [](const std::unique_ptr<RemoteSuggestion>& suggestion) {
+ return !suggestion;
+ });
}
void RemoveIncompleteSuggestions(RemoteSuggestion::PtrVector* suggestions) {
@@ -118,12 +154,10 @@ void RemoveIncompleteSuggestions(RemoteSuggestion::PtrVector* suggestions) {
int num_suggestions = suggestions->size();
// Remove suggestions that do not have all the info we need to display it to
// the user.
- suggestions->erase(
- std::remove_if(suggestions->begin(), suggestions->end(),
- [](const std::unique_ptr<RemoteSuggestion>& suggestion) {
- return !suggestion->is_complete();
- }),
- suggestions->end());
+ base::EraseIf(*suggestions,
+ [](const std::unique_ptr<RemoteSuggestion>& suggestion) {
+ return !suggestion->is_complete();
+ });
int num_suggestions_removed = num_suggestions - suggestions->size();
UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch",
num_suggestions_removed > 0);
@@ -162,11 +196,9 @@ void CallWithEmptyResults(const FetchDoneCallback& callback,
CachedImageFetcher::CachedImageFetcher(
std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
- std::unique_ptr<image_fetcher::ImageDecoder> image_decoder,
PrefService* pref_service,
RemoteSuggestionsDatabase* database)
: image_fetcher_(std::move(image_fetcher)),
- image_decoder_(std::move(image_decoder)),
database_(database),
thumbnail_requests_throttler_(
pref_service,
@@ -205,7 +237,8 @@ void CachedImageFetcher::OnImageDataFetched(
void CachedImageFetcher::OnImageDecodingDone(
const ImageFetchedCallback& callback,
const std::string& id_within_category,
- const gfx::Image& image) {
+ const gfx::Image& image,
+ const image_fetcher::RequestMetadata& metadata) {
callback.Run(image);
}
@@ -214,9 +247,9 @@ void CachedImageFetcher::OnImageFetchedFromDatabase(
const ContentSuggestion::ID& suggestion_id,
const GURL& url,
std::string data) { // SnippetImageCallback requires by-value.
- // |image_decoder_| is null in tests.
- if (image_decoder_ && !data.empty()) {
- image_decoder_->DecodeImage(
+ // The image decoder is null in tests.
+ if (image_fetcher_->GetImageDecoder() && !data.empty()) {
+ image_fetcher_->GetImageDecoder()->DecodeImage(
data,
// We're not dealing with multi-frame images.
/*desired_image_frame_size=*/gfx::Size(),
@@ -246,9 +279,8 @@ void CachedImageFetcher::FetchImageFromNetwork(
const ContentSuggestion::ID& suggestion_id,
const GURL& url,
const ImageFetchedCallback& callback) {
- if (url.is_empty() ||
- !thumbnail_requests_throttler_.DemandQuotaForRequest(
- /*interactive_request=*/true)) {
+ if (url.is_empty() || !thumbnail_requests_throttler_.DemandQuotaForRequest(
+ /*interactive_request=*/true)) {
// Return an empty image. Directly, this is never synchronous with the
// original FetchSuggestionImage() call - an asynchronous database query has
// happened in the meantime.
@@ -267,9 +299,9 @@ RemoteSuggestionsProviderImpl::RemoteSuggestionsProviderImpl(
PrefService* pref_service,
const std::string& application_language_code,
CategoryRanker* category_ranker,
+ RemoteSuggestionsScheduler* scheduler,
std::unique_ptr<RemoteSuggestionsFetcher> suggestions_fetcher,
std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
- std::unique_ptr<image_fetcher::ImageDecoder> image_decoder,
std::unique_ptr<RemoteSuggestionsDatabase> database,
std::unique_ptr<RemoteSuggestionsStatusService> status_service)
: RemoteSuggestionsProvider(observer),
@@ -279,17 +311,13 @@ RemoteSuggestionsProviderImpl::RemoteSuggestionsProviderImpl(
Category::FromKnownCategory(KnownCategories::ARTICLES)),
application_language_code_(application_language_code),
category_ranker_(category_ranker),
+ remote_suggestions_scheduler_(scheduler),
suggestions_fetcher_(std::move(suggestions_fetcher)),
database_(std::move(database)),
- image_fetcher_(std::move(image_fetcher),
- std::move(image_decoder),
- pref_service,
- database_.get()),
+ image_fetcher_(std::move(image_fetcher), pref_service, database_.get()),
status_service_(std::move(status_service)),
fetch_when_ready_(false),
fetch_when_ready_interactive_(false),
- fetch_when_ready_callback_(nullptr),
- remote_suggestions_scheduler_(nullptr),
clear_history_dependent_state_when_initialized_(false),
clock_(base::MakeUnique<base::DefaultClock>()) {
RestoreCategoriesFromPrefs();
@@ -331,21 +359,22 @@ void RemoteSuggestionsProviderImpl::RegisterProfilePrefs(
RemoteSuggestionsStatusService::RegisterProfilePrefs(registry);
}
-void RemoteSuggestionsProviderImpl::SetRemoteSuggestionsScheduler(
- RemoteSuggestionsScheduler* scheduler) {
- remote_suggestions_scheduler_ = scheduler;
- // Call the observer right away if we've reached any final state.
- NotifyStateChanged();
-}
-
void RemoteSuggestionsProviderImpl::ReloadSuggestions() {
- FetchSuggestions(/*interactive_request=*/true,
- /*callback=*/nullptr);
+ if (!remote_suggestions_scheduler_->AcquireQuotaForInteractiveFetch()) {
+ return;
+ }
+ FetchSuggestions(
+ /*interactive_request=*/true,
+ base::Bind(
+ [](RemoteSuggestionsScheduler* scheduler, Status status_code) {
+ scheduler->OnInteractiveFetchFinished(status_code);
+ },
+ base::Unretained(remote_suggestions_scheduler_)));
}
void RemoteSuggestionsProviderImpl::RefetchInTheBackground(
- std::unique_ptr<FetchStatusCallback> callback) {
- FetchSuggestions(/*interactive_request=*/false, std::move(callback));
+ const FetchStatusCallback& callback) {
+ FetchSuggestions(/*interactive_request=*/false, callback);
}
const RemoteSuggestionsFetcher*
@@ -353,13 +382,27 @@ RemoteSuggestionsProviderImpl::suggestions_fetcher_for_debugging() const {
return suggestions_fetcher_.get();
}
+GURL RemoteSuggestionsProviderImpl::GetUrlWithFavicon(
+ const ContentSuggestion::ID& suggestion_id) const {
+ DCHECK(base::ContainsKey(category_contents_, suggestion_id.category()));
+
+ const CategoryContent& content =
+ category_contents_.at(suggestion_id.category());
+ const RemoteSuggestion* suggestion =
+ content.FindSuggestion(suggestion_id.id_within_category());
+ if (!suggestion) {
+ return GURL();
+ }
+ return ContentSuggestion::GetFaviconDomain(suggestion->url());
+}
+
void RemoteSuggestionsProviderImpl::FetchSuggestions(
bool interactive_request,
- std::unique_ptr<FetchStatusCallback> callback) {
+ const FetchStatusCallback& callback) {
if (!ready()) {
fetch_when_ready_ = true;
fetch_when_ready_interactive_ = interactive_request;
- fetch_when_ready_callback_ = std::move(callback);
+ fetch_when_ready_callback_ = callback;
return;
}
@@ -368,9 +411,9 @@ void RemoteSuggestionsProviderImpl::FetchSuggestions(
RequestParams params = BuildFetchParams();
params.interactive_request = interactive_request;
suggestions_fetcher_->FetchSnippets(
- params, base::BindOnce(&RemoteSuggestionsProviderImpl::OnFetchFinished,
- base::Unretained(this), std::move(callback),
- interactive_request));
+ params,
+ base::BindOnce(&RemoteSuggestionsProviderImpl::OnFetchFinished,
+ base::Unretained(this), callback, interactive_request));
}
void RemoteSuggestionsProviderImpl::Fetch(
@@ -383,6 +426,21 @@ void RemoteSuggestionsProviderImpl::Fetch(
"RemoteSuggestionsProvider is not ready!"));
return;
}
+ if (!remote_suggestions_scheduler_->AcquireQuotaForInteractiveFetch()) {
+ CallWithEmptyResults(callback, Status(StatusCode::TEMPORARY_ERROR,
+ "Interactive quota exceeded!"));
+ return;
+ }
+ // Make sure after the fetch, the scheduler is informed about the status.
+ FetchDoneCallback callback_wrapper = base::Bind(
+ [](RemoteSuggestionsScheduler* scheduler,
+ const FetchDoneCallback& callback, Status status_code,
+ std::vector<ContentSuggestion> suggestions) {
+ scheduler->OnInteractiveFetchFinished(status_code);
+ callback.Run(status_code, std::move(suggestions));
+ },
+ base::Unretained(remote_suggestions_scheduler_), callback);
+
RequestParams params = BuildFetchParams();
params.excluded_ids.insert(known_suggestion_ids.begin(),
known_suggestion_ids.end());
@@ -392,7 +450,7 @@ void RemoteSuggestionsProviderImpl::Fetch(
suggestions_fetcher_->FetchSnippets(
params,
base::BindOnce(&RemoteSuggestionsProviderImpl::OnFetchMoreFinished,
- base::Unretained(this), callback));
+ base::Unretained(this), callback_wrapper));
}
// Builds default fetcher params.
@@ -657,13 +715,12 @@ void RemoteSuggestionsProviderImpl::OnFetchMoreFinished(
// Should Nuke also cancel outstanding requests, or do we want to check the
// status?
UpdateCategoryStatus(category, CategoryStatus::AVAILABLE);
- // Notify callers and observers.
fetching_callback.Run(Status::Success(), std::move(result));
NotifyNewSuggestions(category, *existing_content);
}
void RemoteSuggestionsProviderImpl::OnFetchFinished(
- std::unique_ptr<FetchStatusCallback> callback,
+ const FetchStatusCallback& callback,
bool interactive_request,
Status status,
RemoteSuggestionsFetcher::OptionalFetchedCategories fetched_categories) {
@@ -696,6 +753,7 @@ void RemoteSuggestionsProviderImpl::OnFetchFinished(
if (fetched_categories) {
// TODO(treib): Reorder |category_contents_| to match the order we received
// from the server. crbug.com/653816
+ bool response_includes_article_category = false;
for (RemoteSuggestionsFetcher::FetchedCategory& fetched_category :
*fetched_categories) {
// TODO(tschumann): Remove this histogram once we only talk to the content
@@ -705,8 +763,9 @@ void RemoteSuggestionsProviderImpl::OnFetchFinished(
"NewTabPage.Snippets.NumArticlesFetched",
std::min(fetched_category.suggestions.size(),
static_cast<size_t>(kMaxSuggestionCount + 1)));
+ response_includes_article_category = true;
}
- category_ranker_->AppendCategoryIfNecessary(fetched_category.category);
+
CategoryContent* content =
UpdateCategoryInfo(fetched_category.category, fetched_category.info);
content->included_in_last_server_response = true;
@@ -714,6 +773,18 @@ void RemoteSuggestionsProviderImpl::OnFetchFinished(
&fetched_category.suggestions);
IntegrateSuggestions(content, std::move(fetched_category.suggestions));
}
+
+ // Add new remote categories to the ranker.
+ if (IsOrderingNewRemoteCategoriesBasedOnArticlesCategoryEnabled() &&
+ response_includes_article_category) {
+ AddFetchedCategoriesToRankerBasedOnArticlesCategory(
+ category_ranker_, *fetched_categories, articles_category_);
+ } else {
+ for (const RemoteSuggestionsFetcher::FetchedCategory& fetched_category :
+ *fetched_categories) {
+ category_ranker_->AppendCategoryIfNecessary(fetched_category.category);
+ }
+ }
}
// TODO(tschumann): The suggestions fetcher needs to signal errors so that we
@@ -743,7 +814,7 @@ void RemoteSuggestionsProviderImpl::OnFetchFinished(
}
if (callback) {
- callback->Run(status);
+ callback.Run(status);
}
}
@@ -887,18 +958,14 @@ void RemoteSuggestionsProviderImpl::ClearHistoryDependentState() {
}
NukeAllSuggestions();
- if (remote_suggestions_scheduler_) {
- remote_suggestions_scheduler_->OnHistoryCleared();
- }
+ remote_suggestions_scheduler_->OnHistoryCleared();
}
void RemoteSuggestionsProviderImpl::ClearSuggestions() {
DCHECK(initialized());
NukeAllSuggestions();
- if (remote_suggestions_scheduler_) {
- remote_suggestions_scheduler_->OnSuggestionsCleared();
- }
+ remote_suggestions_scheduler_->OnSuggestionsCleared();
}
void RemoteSuggestionsProviderImpl::NukeAllSuggestions() {
@@ -947,8 +1014,7 @@ void RemoteSuggestionsProviderImpl::EnterStateReady() {
auto article_category_it = category_contents_.find(articles_category_);
DCHECK(article_category_it != category_contents_.end());
if (fetch_when_ready_) {
- FetchSuggestions(fetch_when_ready_interactive_,
- std::move(fetch_when_ready_callback_));
+ FetchSuggestions(fetch_when_ready_interactive_, fetch_when_ready_callback_);
fetch_when_ready_ = false;
}
@@ -1085,10 +1151,6 @@ void RemoteSuggestionsProviderImpl::EnterState(State state) {
}
void RemoteSuggestionsProviderImpl::NotifyStateChanged() {
- if (!remote_suggestions_scheduler_) {
- return;
- }
-
switch (state_) {
case State::NOT_INITED:
// Initial state, not sure yet whether active or not.
@@ -1200,29 +1262,29 @@ void RemoteSuggestionsProviderImpl::RestoreCategoriesFromPrefs() {
const base::ListValue* list =
pref_service_->GetList(prefs::kRemoteSuggestionCategories);
- for (const std::unique_ptr<base::Value>& entry : *list) {
+ for (const base::Value& entry : *list) {
const base::DictionaryValue* dict = nullptr;
- if (!entry->GetAsDictionary(&dict)) {
- DLOG(WARNING) << "Invalid category pref value: " << *entry;
+ if (!entry.GetAsDictionary(&dict)) {
+ DLOG(WARNING) << "Invalid category pref value: " << entry;
continue;
}
int id = 0;
if (!dict->GetInteger(kCategoryContentId, &id)) {
DLOG(WARNING) << "Invalid category pref value, missing '"
- << kCategoryContentId << "': " << *entry;
+ << kCategoryContentId << "': " << entry;
continue;
}
base::string16 title;
if (!dict->GetString(kCategoryContentTitle, &title)) {
DLOG(WARNING) << "Invalid category pref value, missing '"
- << kCategoryContentTitle << "': " << *entry;
+ << kCategoryContentTitle << "': " << entry;
continue;
}
bool included_in_last_server_response = false;
if (!dict->GetBoolean(kCategoryContentProvidedByServer,
&included_in_last_server_response)) {
DLOG(WARNING) << "Invalid category pref value, missing '"
- << kCategoryContentProvidedByServer << "': " << *entry;
+ << kCategoryContentProvidedByServer << "': " << entry;
continue;
}
bool allow_fetching_more_results = false;
@@ -1270,8 +1332,9 @@ void RemoteSuggestionsProviderImpl::StoreCategoriesToPrefs() {
dict->SetString(kCategoryContentTitle, content.info.title());
dict->SetBoolean(kCategoryContentProvidedByServer,
content.included_in_last_server_response);
- dict->SetBoolean(kCategoryContentAllowFetchingMore,
- content.info.has_fetch_action());
+ bool has_fetch_action = content.info.additional_action() ==
+ ContentSuggestionsAdditionalAction::FETCH;
+ dict->SetBoolean(kCategoryContentAllowFetchingMore, has_fetch_action);
list.Append(std::move(dict));
}
// Finally, store the result in the pref service.
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
index ecd1566b2b3..2540c3abae3 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
@@ -19,7 +19,7 @@
#include "base/macros.h"
#include "base/time/clock.h"
#include "base/time/time.h"
-#include "components/image_fetcher/image_fetcher_delegate.h"
+#include "components/image_fetcher/core/image_fetcher_delegate.h"
#include "components/ntp_snippets/category.h"
#include "components/ntp_snippets/category_status.h"
#include "components/ntp_snippets/content_suggestion.h"
@@ -39,8 +39,8 @@ class Image;
} // namespace gfx
namespace image_fetcher {
-class ImageDecoder;
class ImageFetcher;
+struct RequestMetadata;
} // namespace image_fetcher
namespace ntp_snippets {
@@ -60,7 +60,6 @@ class CachedImageFetcher : public image_fetcher::ImageFetcherDelegate {
// |pref_service| and |database| need to outlive the created image fetcher
// instance.
CachedImageFetcher(std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
- std::unique_ptr<image_fetcher::ImageDecoder> image_decoder,
PrefService* pref_service,
RemoteSuggestionsDatabase* database);
~CachedImageFetcher() override;
@@ -78,7 +77,8 @@ class CachedImageFetcher : public image_fetcher::ImageFetcherDelegate {
void OnImageDecodingDone(const ImageFetchedCallback& callback,
const std::string& id_within_category,
- const gfx::Image& image);
+ const gfx::Image& image,
+ const image_fetcher::RequestMetadata& metadata);
void OnImageFetchedFromDatabase(
const ImageFetchedCallback& callback,
const ContentSuggestion::ID& suggestion_id,
@@ -94,7 +94,6 @@ class CachedImageFetcher : public image_fetcher::ImageFetcherDelegate {
const ImageFetchedCallback& callback);
std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher_;
- std::unique_ptr<image_fetcher::ImageDecoder> image_decoder_;
RemoteSuggestionsDatabase* database_;
// Request throttler for limiting requests to thumbnail images.
RequestThrottler thumbnail_requests_throttler_;
@@ -118,9 +117,9 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
PrefService* pref_service,
const std::string& application_language_code,
CategoryRanker* category_ranker,
+ RemoteSuggestionsScheduler* scheduler,
std::unique_ptr<RemoteSuggestionsFetcher> suggestions_fetcher,
std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
- std::unique_ptr<image_fetcher::ImageDecoder> image_decoder,
std::unique_ptr<RemoteSuggestionsDatabase> database,
std::unique_ptr<RemoteSuggestionsStatusService> status_service);
@@ -137,21 +136,17 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
// false, some calls may trigger DCHECKs.
bool initialized() const { return ready() || state_ == State::DISABLED; }
- // Set the scheduler to be notified whenever the provider becomes active /
- // in-active and whenever history is deleted. The initial change is also
- // notified (switching from an initial undecided status). If the scheduler is
- // set after the first change, it is called back immediately.
- void SetRemoteSuggestionsScheduler(RemoteSuggestionsScheduler* scheduler);
-
// RemoteSuggestionsProvider implementation.
- void RefetchInTheBackground(
- std::unique_ptr<FetchStatusCallback> callback) override;
+ void RefetchInTheBackground(const FetchStatusCallback& callback) override;
// TODO(fhorschig): Remove this getter when there is an interface for the
// fetcher that allows better mocks.
const RemoteSuggestionsFetcher* suggestions_fetcher_for_debugging()
const override;
+ GURL GetUrlWithFavicon(
+ const ContentSuggestion::ID& suggestion_id) const override;
+
// ContentSuggestionsProvider implementation.
CategoryStatus GetCategoryStatus(Category category) override;
CategoryInfo GetCategoryInfo(Category category) override;
@@ -300,7 +295,7 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
// the fetch finished, the provided |callback| will be triggered with the
// status of the fetch.
void FetchSuggestions(bool interactive_request,
- std::unique_ptr<FetchStatusCallback> callback);
+ const FetchStatusCallback& callback);
// Returns the URL of the image of a suggestion if it is among the current or
// among the archived suggestions in the matching category. Returns an empty
@@ -319,7 +314,7 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
// Callback for regular fetch requests with the RemoteSuggestionsFetcher.
void OnFetchFinished(
- std::unique_ptr<FetchStatusCallback> callback,
+ const FetchStatusCallback& callback,
bool interactive_request,
Status status,
RemoteSuggestionsFetcher::OptionalFetchedCategories fetched_categories);
@@ -432,6 +427,9 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
// Ranker that orders the categories. Not owned.
CategoryRanker* category_ranker_;
+ // Scheduler to inform about scheduling-related events. Not owned.
+ RemoteSuggestionsScheduler* remote_suggestions_scheduler_;
+
// The suggestions fetcher.
std::unique_ptr<RemoteSuggestionsFetcher> suggestions_fetcher_;
@@ -452,9 +450,7 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
// The parameters for the fetch to perform later.
bool fetch_when_ready_interactive_;
- std::unique_ptr<FetchStatusCallback> fetch_when_ready_callback_;
-
- RemoteSuggestionsScheduler* remote_suggestions_scheduler_;
+ FetchStatusCallback fetch_when_ready_callback_;
// Set to true if ClearHistoryDependentState is called while the service isn't
// ready. The nuke will be executed once the service finishes initialization
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
index 79bff6cc426..ee6175526de 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
@@ -22,10 +22,12 @@
#include "base/test/histogram_tester.h"
#include "base/test/simple_test_clock.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/default_clock.h"
#include "base/time/time.h"
-#include "components/image_fetcher/image_decoder.h"
-#include "components/image_fetcher/image_fetcher.h"
-#include "components/image_fetcher/image_fetcher_delegate.h"
+#include "components/image_fetcher/core/image_decoder.h"
+#include "components/image_fetcher/core/image_fetcher.h"
+#include "components/image_fetcher/core/image_fetcher_delegate.h"
+#include "components/image_fetcher/core/request_metadata.h"
#include "components/ntp_snippets/category.h"
#include "components/ntp_snippets/category_info.h"
#include "components/ntp_snippets/category_rankers/category_ranker.h"
@@ -49,6 +51,7 @@
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gmock_mutant.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
@@ -57,6 +60,7 @@
using image_fetcher::ImageFetcher;
using image_fetcher::ImageFetcherDelegate;
using testing::_;
+using testing::CreateFunctor;
using testing::ElementsAre;
using testing::Eq;
using testing::InSequence;
@@ -66,6 +70,7 @@ using testing::Mock;
using testing::MockFunction;
using testing::NiceMock;
using testing::Not;
+using testing::Return;
using testing::SaveArg;
using testing::SizeIs;
using testing::StartsWith;
@@ -84,10 +89,6 @@ MATCHER_P(IdWithinCategoryEq, expected_id, "") {
return arg.id().id_within_category() == expected_id;
}
-MATCHER_P(IsCategory, id, "") {
- return arg.id() == static_cast<int>(id);
-}
-
MATCHER_P(HasCode, code, "") {
return arg.code == code;
}
@@ -284,14 +285,19 @@ std::string GetIncompleteSuggestion() {
using ServeImageCallback = base::Callback<void(
const std::string&,
- base::Callback<void(const std::string&, const gfx::Image&)>)>;
+ base::Callback<void(const std::string&,
+ const gfx::Image&,
+ const image_fetcher::RequestMetadata&)>)>;
void ServeOneByOneImage(
image_fetcher::ImageFetcherDelegate* notify,
const std::string& id,
- base::Callback<void(const std::string&, const gfx::Image&)> callback) {
+ base::Callback<void(const std::string&,
+ const gfx::Image&,
+ const image_fetcher::RequestMetadata&)> callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, id, gfx::test::CreateImage(1, 1)));
+ FROM_HERE, base::Bind(callback, id, gfx::test::CreateImage(1, 1),
+ image_fetcher::RequestMetadata()));
notify->OnImageDataFetched(id, "1-by-1-image-data");
}
@@ -341,12 +347,14 @@ class MockImageFetcher : public ImageFetcher {
public:
MOCK_METHOD1(SetImageFetcherDelegate, void(ImageFetcherDelegate*));
MOCK_METHOD1(SetDataUseServiceName, void(DataUseServiceName));
+ MOCK_METHOD1(SetImageDownloadLimit,
+ void(base::Optional<int64_t> max_download_bytes));
MOCK_METHOD1(SetDesiredImageFrameSize, void(const gfx::Size&));
- MOCK_METHOD3(
- StartOrQueueNetworkRequest,
- void(const std::string&,
- const GURL&,
- base::Callback<void(const std::string&, const gfx::Image&)>));
+ MOCK_METHOD3(StartOrQueueNetworkRequest,
+ void(const std::string&,
+ const GURL&,
+ const ImageFetcherCallback&));
+ MOCK_METHOD0(GetImageDecoder, image_fetcher::ImageDecoder*());
};
class FakeImageDecoder : public image_fetcher::ImageDecoder {
@@ -368,10 +376,13 @@ class FakeImageDecoder : public image_fetcher::ImageDecoder {
class MockScheduler : public RemoteSuggestionsScheduler {
public:
+ MOCK_METHOD1(SetProvider, void(RemoteSuggestionsProvider* provider));
MOCK_METHOD0(OnProviderActivated, void());
MOCK_METHOD0(OnProviderDeactivated, void());
MOCK_METHOD0(OnSuggestionsCleared, void());
MOCK_METHOD0(OnHistoryCleared, void());
+ MOCK_METHOD0(AcquireQuotaForInteractiveFetch, bool());
+ MOCK_METHOD1(OnInteractiveFetchFinished, void(Status fetch_status));
MOCK_METHOD0(OnBrowserForegrounded, void());
MOCK_METHOD0(OnBrowserColdStart, void());
MOCK_METHOD0(OnNTPOpened, void());
@@ -384,7 +395,7 @@ class MockScheduler : public RemoteSuggestionsScheduler {
class RemoteSuggestionsProviderImplTest : public ::testing::Test {
public:
RemoteSuggestionsProviderImplTest()
- : params_manager_(ntp_snippets::kStudyName,
+ : params_manager_(ntp_snippets::kArticleSuggestionsFeature.name,
{{"content_suggestions_backend",
kTestContentSuggestionsServerEndpoint}},
{ntp_snippets::kArticleSuggestionsFeature.name}),
@@ -392,10 +403,11 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
/*default_factory=*/&failing_url_fetcher_factory_),
test_url_(kTestContentSuggestionsServerWithAPIKey),
category_ranker_(base::MakeUnique<ConstantCategoryRanker>()),
- user_classifier_(/*pref_service=*/nullptr),
+ user_classifier_(/*pref_service=*/nullptr,
+ base::MakeUnique<base::DefaultClock>()),
suggestions_fetcher_(nullptr),
image_fetcher_(nullptr),
- image_decoder_(nullptr),
+ scheduler_(base::MakeUnique<NiceMock<MockScheduler>>()),
database_(nullptr) {
RemoteSuggestionsProviderImpl::RegisterProfilePrefs(
utils_.pref_service()->registry());
@@ -439,8 +451,8 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
image_fetcher_ = image_fetcher.get();
EXPECT_CALL(*image_fetcher, SetImageFetcherDelegate(_));
- auto image_decoder = base::MakeUnique<FakeImageDecoder>();
- image_decoder_ = image_decoder.get();
+ ON_CALL(*image_fetcher, GetImageDecoder())
+ .WillByDefault(Return(&image_decoder_));
EXPECT_FALSE(observer_);
observer_ = base::MakeUnique<FakeContentSuggestionsProviderObserver>();
auto database = base::MakeUnique<RemoteSuggestionsDatabase>(
@@ -448,10 +460,17 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
database_ = database.get();
return base::MakeUnique<RemoteSuggestionsProviderImpl>(
observer_.get(), utils_.pref_service(), "fr", category_ranker_.get(),
- std::move(suggestions_fetcher), std::move(image_fetcher),
- std::move(image_decoder), std::move(database),
+ scheduler_.get(), std::move(suggestions_fetcher),
+ std::move(image_fetcher), std::move(database),
base::MakeUnique<RemoteSuggestionsStatusService>(
- utils_.fake_signin_manager(), utils_.pref_service()));
+ utils_.fake_signin_manager(), utils_.pref_service(),
+ std::string()));
+ }
+
+ std::unique_ptr<RemoteSuggestionsProviderImpl>
+ MakeSuggestionsProviderWithoutInitializationWithStrictScheduler() {
+ scheduler_ = base::MakeUnique<StrictMock<MockScheduler>>();
+ return MakeSuggestionsProviderWithoutInitialization();
}
void WaitForSuggestionsProviderInitialization(
@@ -513,9 +532,10 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
// TODO(tschumann): Make this a strict-mock. We want to avoid unneccesary
// network requests.
NiceMock<MockImageFetcher>* image_fetcher() { return image_fetcher_; }
- FakeImageDecoder* image_decoder() { return image_decoder_; }
+ FakeImageDecoder* image_decoder() { return &image_decoder_; }
PrefService* pref_service() { return utils_.pref_service(); }
RemoteSuggestionsDatabase* database() { return database_; }
+ MockScheduler* scheduler() { return scheduler_.get(); }
// Provide the json to be returned by the fake fetcher.
void SetUpFetchResponse(const std::string& json) {
@@ -534,7 +554,7 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
const std::string& json) {
SetUpFetchResponse(json);
service->FetchSuggestions(/*interactive_request=*/true,
- /*callback=*/nullptr);
+ RemoteSuggestionsProvider::FetchStatusCallback());
base::RunLoop().RunUntilIdle();
}
@@ -544,10 +564,27 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
const std::set<std::string>& known_ids,
FetchDoneCallback callback) {
SetUpFetchResponse(json);
+ EXPECT_CALL(*scheduler(), AcquireQuotaForInteractiveFetch())
+ .WillOnce(Return(true))
+ .RetiresOnSaturation();
service->Fetch(category, known_ids, callback);
base::RunLoop().RunUntilIdle();
}
+ void SetOrderNewRemoteCategoriesBasedOnArticlesCategoryParam(bool value) {
+ // params_manager supports only one
+ // |SetVariationParamsWithFeatureAssociations| at a time, so we clear
+ // previous settings first and then set everything we need.
+ params_manager_.ClearAllVariationParams();
+ params_manager_.SetVariationParamsWithFeatureAssociations(
+ kArticleSuggestionsFeature.name,
+ {{"order_new_remote_categories_based_on_articles_category",
+ value ? "true" : "false"},
+ {"content_suggestions_backend",
+ kTestContentSuggestionsServerEndpoint}},
+ {kArticleSuggestionsFeature.name});
+ }
+
private:
variations::testing::VariationParamsManager params_manager_;
test::RemoteSuggestionsTestUtils utils_;
@@ -561,7 +598,8 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
std::unique_ptr<FakeContentSuggestionsProviderObserver> observer_;
RemoteSuggestionsFetcher* suggestions_fetcher_;
NiceMock<MockImageFetcher>* image_fetcher_;
- FakeImageDecoder* image_decoder_;
+ FakeImageDecoder image_decoder_;
+ std::unique_ptr<MockScheduler> scheduler_;
base::ScopedTempDir database_dir_;
RemoteSuggestionsDatabase* database_;
@@ -604,8 +642,8 @@ TEST_F(RemoteSuggestionsProviderImplTest, CategoryTitle) {
CategoryInfo info_before = service->GetCategoryInfo(articles_category());
ASSERT_THAT(info_before.title(), Not(IsEmpty()));
ASSERT_THAT(info_before.title(), Not(Eq(test_default_title)));
- EXPECT_THAT(info_before.has_fetch_action(), Eq(true));
- EXPECT_THAT(info_before.has_view_all_action(), Eq(false));
+ EXPECT_THAT(info_before.additional_action(),
+ Eq(ContentSuggestionsAdditionalAction::FETCH));
EXPECT_THAT(info_before.show_if_empty(), Eq(true));
std::string json_str_with_title(GetTestJson({GetSuggestion()}));
@@ -621,8 +659,8 @@ TEST_F(RemoteSuggestionsProviderImplTest, CategoryTitle) {
CategoryInfo info_with_title = service->GetCategoryInfo(articles_category());
EXPECT_THAT(info_before.title(), Not(Eq(info_with_title.title())));
EXPECT_THAT(test_default_title, Eq(info_with_title.title()));
- EXPECT_THAT(info_before.has_fetch_action(), Eq(true));
- EXPECT_THAT(info_before.has_view_all_action(), Eq(false));
+ EXPECT_THAT(info_before.additional_action(),
+ Eq(ContentSuggestionsAdditionalAction::FETCH));
EXPECT_THAT(info_before.show_if_empty(), Eq(true));
}
@@ -677,8 +715,8 @@ TEST_F(RemoteSuggestionsProviderImplTest, MultipleCategories) {
TEST_F(RemoteSuggestionsProviderImplTest, ArticleCategoryInfo) {
auto service = MakeSuggestionsProvider();
CategoryInfo article_info = service->GetCategoryInfo(articles_category());
- EXPECT_THAT(article_info.has_fetch_action(), Eq(true));
- EXPECT_THAT(article_info.has_view_all_action(), Eq(false));
+ EXPECT_THAT(article_info.additional_action(),
+ Eq(ContentSuggestionsAdditionalAction::FETCH));
EXPECT_THAT(article_info.show_if_empty(), Eq(true));
}
@@ -694,8 +732,8 @@ TEST_F(RemoteSuggestionsProviderImplTest, ExperimentalCategoryInfo) {
LoadFromJSONString(service.get(), json_str);
CategoryInfo info = service->GetCategoryInfo(unknown_category());
- EXPECT_THAT(info.has_fetch_action(), Eq(false));
- EXPECT_THAT(info.has_view_all_action(), Eq(false));
+ EXPECT_THAT(info.additional_action(),
+ Eq(ContentSuggestionsAdditionalAction::NONE));
EXPECT_THAT(info.show_if_empty(), Eq(false));
}
@@ -724,6 +762,58 @@ TEST_F(RemoteSuggestionsProviderImplTest, AddRemoteCategoriesToCategoryRanker) {
LoadFromJSONString(service.get(), json_str);
}
+TEST_F(RemoteSuggestionsProviderImplTest,
+ AddRemoteCategoriesToCategoryRankerRelativeToArticles) {
+ SetOrderNewRemoteCategoriesBasedOnArticlesCategoryParam(true);
+ auto mock_ranker = base::MakeUnique<MockCategoryRanker>();
+ MockCategoryRanker* raw_mock_ranker = mock_ranker.get();
+ SetCategoryRanker(std::move(mock_ranker));
+ std::string json_str =
+ MultiCategoryJsonBuilder()
+ .AddCategory({GetSuggestionN(0)}, /*remote_category_id=*/14)
+ .AddCategory({GetSuggestionN(1)}, /*remote_category_id=*/13)
+ .AddCategory({GetSuggestionN(2)}, /*remote_category_id=*/1)
+ .AddCategory({GetSuggestionN(3)}, /*remote_category_id=*/12)
+ .AddCategory({GetSuggestionN(4)}, /*remote_category_id=*/11)
+ .Build();
+ {
+ InSequence s;
+ EXPECT_CALL(*raw_mock_ranker,
+ InsertCategoryBeforeIfNecessary(
+ Category::FromRemoteCategory(14), articles_category()));
+ EXPECT_CALL(*raw_mock_ranker,
+ InsertCategoryBeforeIfNecessary(
+ Category::FromRemoteCategory(13), articles_category()));
+ EXPECT_CALL(*raw_mock_ranker,
+ InsertCategoryAfterIfNecessary(Category::FromRemoteCategory(11),
+ articles_category()));
+ EXPECT_CALL(*raw_mock_ranker,
+ InsertCategoryAfterIfNecessary(Category::FromRemoteCategory(12),
+ articles_category()));
+ }
+ auto service = MakeSuggestionsProvider(/*set_empty_response=*/false);
+ LoadFromJSONString(service.get(), json_str);
+}
+
+TEST_F(
+ RemoteSuggestionsProviderImplTest,
+ AddRemoteCategoriesToCategoryRankerRelativeToArticlesWithArticlesAbsent) {
+ SetOrderNewRemoteCategoriesBasedOnArticlesCategoryParam(true);
+ auto mock_ranker = base::MakeUnique<MockCategoryRanker>();
+ MockCategoryRanker* raw_mock_ranker = mock_ranker.get();
+ SetCategoryRanker(std::move(mock_ranker));
+ std::string json_str =
+ MultiCategoryJsonBuilder()
+ .AddCategory({GetSuggestionN(0)}, /*remote_category_id=*/11)
+ .Build();
+
+ EXPECT_CALL(*raw_mock_ranker, InsertCategoryBeforeIfNecessary(_, _)).Times(0);
+ EXPECT_CALL(*raw_mock_ranker,
+ AppendCategoryIfNecessary(Category::FromRemoteCategory(11)));
+ auto service = MakeSuggestionsProvider(/*set_empty_response=*/false);
+ LoadFromJSONString(service.get(), json_str);
+}
+
TEST_F(RemoteSuggestionsProviderImplTest, PersistCategoryInfos) {
auto service = MakeSuggestionsProvider();
// TODO(vitaliii): Use |articles_category()| instead of constant ID below.
@@ -897,11 +987,12 @@ TEST_F(RemoteSuggestionsProviderImplTest, LoadsAdditionalSuggestions) {
EXPECT_THAT(service->GetSuggestionsForTesting(articles_category()),
ElementsAre(IdEq("http://first")));
- auto expect_only_second_suggestion_received = base::Bind([](
- Status status, std::vector<ContentSuggestion> suggestions) {
- EXPECT_THAT(suggestions, SizeIs(1));
- EXPECT_THAT(suggestions[0].id().id_within_category(), Eq("http://second"));
- });
+ auto expect_only_second_suggestion_received =
+ base::Bind([](Status status, std::vector<ContentSuggestion> suggestions) {
+ EXPECT_THAT(suggestions, SizeIs(1));
+ EXPECT_THAT(suggestions[0].id().id_within_category(),
+ Eq("http://second"));
+ });
LoadMoreFromJSONString(service.get(), articles_category(),
GetTestJson({GetSuggestionWithUrl("http://second")}),
/*known_ids=*/std::set<std::string>(),
@@ -912,7 +1003,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, LoadsAdditionalSuggestions) {
base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting());
EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
.Times(2)
- .WillRepeatedly(WithArgs<0, 2>(Invoke(&cb, &ServeImageCallback::Run)));
+ .WillRepeatedly(WithArgs<0, 2>(Invoke(CreateFunctor(cb))));
image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
gfx::Image image = FetchImage(service.get(), MakeArticleID("http://first"));
EXPECT_FALSE(image.IsEmpty());
@@ -974,9 +1065,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
service.get(), articles_category(),
GetTestJson({GetSuggestionWithUrl("http://more-id-1"),
GetSuggestionWithUrl("http://more-id-2")}),
- /*known_ids=*/{"http://id-1", "http://id-2", "http://id-3", "http://id-4",
- "http://id-5", "http://id-6", "http://id-7", "http://id-8",
- "http://id-9", "http://id-10"},
+ /*known_ids=*/
+ {"http://id-1", "http://id-2", "http://id-3", "http://id-4",
+ "http://id-5", "http://id-6", "http://id-7", "http://id-8",
+ "http://id-9", "http://id-10"},
expect_receiving_two_new_suggestions);
// Verify that the observer received the update as well. We should see the
@@ -1015,7 +1107,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting());
EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
.Times(2)
- .WillRepeatedly(WithArgs<0, 2>(Invoke(&cb, &ServeImageCallback::Run)));
+ .WillRepeatedly(WithArgs<0, 2>(Invoke(CreateFunctor(cb))));
image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
gfx::Image image = FetchImage(service.get(), MakeArticleID("http://id-1"));
ASSERT_FALSE(image.IsEmpty());
@@ -1086,9 +1178,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
GetSuggestionWithUrl("http://more-id-8"),
GetSuggestionWithUrl("http://more-id-9"),
GetSuggestionWithUrl("http://more-id-10")}),
- /*known_ids=*/{"http://id-1", "http://id-2", "http://id-3", "http://id-4",
- "http://id-5", "http://id-6", "http://id-7", "http://id-8",
- "http://id-9", "http://id-10"},
+ /*known_ids=*/
+ {"http://id-1", "http://id-2", "http://id-3", "http://id-4",
+ "http://id-5", "http://id-6", "http://id-7", "http://id-8",
+ "http://id-9", "http://id-10"},
expect_receiving_ten_new_suggestions);
EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
ElementsAre(IdWithinCategoryEq("http://more-id-1"),
@@ -1253,7 +1346,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, Dismiss) {
ServeImageCallback cb =
base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting());
EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
- .WillOnce(WithArgs<0, 2>(Invoke(&cb, &ServeImageCallback::Run)));
+ .WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb))));
image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
gfx::Image image = FetchImage(service.get(), MakeArticleID(kSuggestionUrl));
EXPECT_FALSE(image.IsEmpty());
@@ -1358,7 +1451,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, RemoveExpiredDismissedContent) {
ServeImageCallback cb =
base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting());
EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
- .WillOnce(WithArgs<0, 2>(Invoke(&cb, &ServeImageCallback::Run)));
+ .WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb))));
image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
gfx::Image image = FetchImage(service.get(), MakeArticleID(kSuggestionUrl));
EXPECT_FALSE(image.IsEmpty());
@@ -1532,7 +1625,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, ImageReturnedWithTheSameId) {
{
InSequence s;
EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
- .WillOnce(WithArgs<0, 2>(Invoke(&cb, &ServeImageCallback::Run)));
+ .WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb))));
EXPECT_CALL(image_fetched, Call(_)).WillOnce(SaveArg<0>(&image));
}
@@ -1639,7 +1732,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, ShouldClearOrphanedImagesOnRestart) {
base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting());
EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
- .WillOnce(WithArgs<0, 2>(Invoke(&cb, &ServeImageCallback::Run)));
+ .WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb))));
image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
gfx::Image image = FetchImage(service.get(), MakeArticleID(kSuggestionUrl));
@@ -1701,7 +1794,8 @@ TEST_F(RemoteSuggestionsProviderImplTest,
// background fetch.
simple_test_clock_ptr->Advance(TimeDelta::FromHours(1));
- service->RefetchInTheBackground(/*callback=*/nullptr);
+ service->RefetchInTheBackground(
+ RemoteSuggestionsProvider::FetchStatusCallback());
base::RunLoop().RunUntilIdle();
// TODO(jkrcal): Move together with the pref storage into the scheduler.
EXPECT_EQ(
@@ -1711,100 +1805,78 @@ TEST_F(RemoteSuggestionsProviderImplTest,
// scheduler refactoring is done (crbug.com/672434).
}
-TEST_F(RemoteSuggestionsProviderImplTest, CallsSchedulerIfInited) {
- // Initiate the service so that it is already READY.
- auto service = MakeSuggestionsProvider();
- StrictMock<MockScheduler> scheduler;
- // The scheduler should be notified of activation of the provider.
- EXPECT_CALL(scheduler, OnProviderActivated());
- service->SetRemoteSuggestionsScheduler(&scheduler);
-}
-
-TEST_F(RemoteSuggestionsProviderImplTest, DoesNotCallSchedulerIfNotInited) {
- auto service = MakeSuggestionsProviderWithoutInitialization();
- StrictMock<MockScheduler> scheduler;
- // The provider is not initialized yet, no callback should be called on
- // registering.
- service->SetRemoteSuggestionsScheduler(&scheduler);
-}
-
TEST_F(RemoteSuggestionsProviderImplTest, CallsSchedulerWhenReady) {
- auto service = MakeSuggestionsProviderWithoutInitialization();
- StrictMock<MockScheduler> scheduler;
- // The provider is not initialized yet, no callback should be called yet.
- service->SetRemoteSuggestionsScheduler(&scheduler);
+ auto service =
+ MakeSuggestionsProviderWithoutInitializationWithStrictScheduler();
// Should be called when becoming ready.
- EXPECT_CALL(scheduler, OnProviderActivated());
+ EXPECT_CALL(*scheduler(), OnProviderActivated());
WaitForSuggestionsProviderInitialization(service.get(),
/*set_empty_response=*/true);
}
TEST_F(RemoteSuggestionsProviderImplTest, CallsSchedulerOnError) {
- auto service = MakeSuggestionsProviderWithoutInitialization();
- StrictMock<MockScheduler> scheduler;
- // The provider is not initialized yet, no callback should be called yet.
- service->SetRemoteSuggestionsScheduler(&scheduler);
+ auto service =
+ MakeSuggestionsProviderWithoutInitializationWithStrictScheduler();
// Should be called on error.
- EXPECT_CALL(scheduler, OnProviderDeactivated());
+ EXPECT_CALL(*scheduler(), OnProviderDeactivated());
service->EnterState(RemoteSuggestionsProviderImpl::State::ERROR_OCCURRED);
}
TEST_F(RemoteSuggestionsProviderImplTest, CallsSchedulerWhenDisabled) {
- auto service = MakeSuggestionsProviderWithoutInitialization();
- StrictMock<MockScheduler> scheduler;
- // The provider is not initialized yet, no callback should be called yet.
- service->SetRemoteSuggestionsScheduler(&scheduler);
+ auto service =
+ MakeSuggestionsProviderWithoutInitializationWithStrictScheduler();
// Should be called when becoming disabled. First deactivate and only after
// that clear the suggestions so that they are not fetched again.
{
InSequence s;
- EXPECT_CALL(scheduler, OnProviderDeactivated());
+ EXPECT_CALL(*scheduler(), OnProviderDeactivated());
ASSERT_THAT(service->ready(), Eq(false));
- EXPECT_CALL(scheduler, OnSuggestionsCleared());
+ EXPECT_CALL(*scheduler(), OnSuggestionsCleared());
}
service->EnterState(RemoteSuggestionsProviderImpl::State::DISABLED);
}
TEST_F(RemoteSuggestionsProviderImplTest, CallsSchedulerWhenHistoryCleared) {
+ auto service =
+ MakeSuggestionsProviderWithoutInitializationWithStrictScheduler();
// Initiate the service so that it is already READY.
- auto service = MakeSuggestionsProvider();
- StrictMock<MockScheduler> scheduler;
- // The scheduler should be notified of activation of the provider.
- EXPECT_CALL(scheduler, OnProviderActivated());
+ EXPECT_CALL(*scheduler(), OnProviderActivated());
+ WaitForSuggestionsProviderInitialization(service.get(),
+ /*set_empty_response=*/true);
+
// The scheduler should be notified of clearing the history.
- EXPECT_CALL(scheduler, OnHistoryCleared());
- service->SetRemoteSuggestionsScheduler(&scheduler);
+ EXPECT_CALL(*scheduler(), OnHistoryCleared());
service->ClearHistory(GetDefaultCreationTime(), GetDefaultExpirationTime(),
base::Callback<bool(const GURL& url)>());
}
TEST_F(RemoteSuggestionsProviderImplTest, CallsSchedulerWhenSignedIn) {
+ auto service =
+ MakeSuggestionsProviderWithoutInitializationWithStrictScheduler();
// Initiate the service so that it is already READY.
- auto service = MakeSuggestionsProvider();
- StrictMock<MockScheduler> scheduler;
- // The scheduler should be notified of activation of the provider.
- EXPECT_CALL(scheduler, OnProviderActivated());
- // The scheduler should be notified of clearing the history.
- EXPECT_CALL(scheduler, OnSuggestionsCleared());
+ EXPECT_CALL(*scheduler(), OnProviderActivated());
+ WaitForSuggestionsProviderInitialization(service.get(),
+ /*set_empty_response=*/true);
- service->SetRemoteSuggestionsScheduler(&scheduler);
+ // The scheduler should be notified of clearing the history.
+ EXPECT_CALL(*scheduler(), OnSuggestionsCleared());
service->OnStatusChanged(RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN,
RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT);
}
TEST_F(RemoteSuggestionsProviderImplTest, CallsSchedulerWhenSignedOut) {
+ auto service =
+ MakeSuggestionsProviderWithoutInitializationWithStrictScheduler();
// Initiate the service so that it is already READY.
- auto service = MakeSuggestionsProvider();
- StrictMock<MockScheduler> scheduler;
- // The scheduler should be notified of activation of the provider.
- EXPECT_CALL(scheduler, OnProviderActivated());
- // The scheduler should be notified of clearing the history.
- EXPECT_CALL(scheduler, OnSuggestionsCleared());
+ EXPECT_CALL(*scheduler(), OnProviderActivated());
+ WaitForSuggestionsProviderInitialization(service.get(),
+ /*set_empty_response=*/true);
- service->SetRemoteSuggestionsScheduler(&scheduler);
+ // The scheduler should be notified of clearing the history.
+ EXPECT_CALL(*scheduler(), OnSuggestionsCleared());
service->OnStatusChanged(RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT,
RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN);
}
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler.h b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler.h
index 40eb5fa6bf4..6af62879fc8 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler.h
@@ -9,10 +9,21 @@
namespace ntp_snippets {
-// Interface for informing the scheduler.
+class RemoteSuggestionsProvider;
+struct Status;
+
+// The scheduler for background fetching of remote suggestions has two callers:
+// a) The actual provider that implements the fetching informs the scheduler
+// about relevant events and changes in its state.
+// b) External parties (such as the UI) that need to inform the scheduler about
+// their events.
class RemoteSuggestionsScheduler {
public:
- // Internal triggers to consider fetching content suggestions.
+ // Set the provider that performs background fetching. Should be only called
+ // by the factory.
+ virtual void SetProvider(RemoteSuggestionsProvider* provider) = 0;
+
+ // ***** Internal triggers to consider fetching content suggestions. *****
// Called whenever the remote suggestions provider becomes active (on startup,
// or later on).
@@ -29,7 +40,14 @@ class RemoteSuggestionsScheduler {
// because history gets cleared (and we must not show them any more).
virtual void OnHistoryCleared() = 0;
- // External triggers to consider fetching content suggestions.
+ // Returns true if quota is available for another request.
+ virtual bool AcquireQuotaForInteractiveFetch() = 0;
+
+ // Called whenever the remote suggestions provider finishes an interactive
+ // fetch (with provided |fetch_status|).
+ virtual void OnInteractiveFetchFinished(Status fetch_status) = 0;
+
+ // ***** External triggers to consider fetching content suggestions. *****
// Called whenever chrome is started warm or the user switches to Chrome.
virtual void OnBrowserForegrounded() = 0;
diff --git a/chromium/components/ntp_snippets/remote/scheduling_remote_suggestions_provider.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc
index a26e49e208c..4b5a0e10b42 100644
--- a/chromium/components/ntp_snippets/remote/scheduling_remote_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_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/ntp_snippets/remote/scheduling_remote_suggestions_provider.h"
+#include "components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h"
#include <random>
#include <string>
@@ -17,10 +17,12 @@
#include "components/ntp_snippets/features.h"
#include "components/ntp_snippets/pref_names.h"
#include "components/ntp_snippets/remote/persistent_scheduler.h"
+#include "components/ntp_snippets/remote/remote_suggestions_provider.h"
#include "components/ntp_snippets/status.h"
#include "components/ntp_snippets/user_classifier.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
+#include "net/base/network_change_notifier.h"
namespace ntp_snippets {
@@ -29,16 +31,23 @@ namespace {
// The FetchingInterval enum specifies overlapping time intervals that are used
// for scheduling the next remote suggestion fetch. Therefore a timer is created
// for each interval. Initially all the timers are started at the same time.
-// Fetches are
-// only performed when certain conditions associated with the intervals are
-// met. If a fetch failed, then only the corresponding timer is reset. The
-// other timers are not touched.
-// TODO(markusheintz): Describe the individual intervals.
+// Fetches are only performed when conditions associated with the intervals are
+// met:
+// - A "soft" fetch is performed only at a moment when the user actively uses
+// Chrome after the interval has elapsed and causes a trigger that is currently
+// enabled while
+// - a "persistent" fetch is initiated automatically by the OS after the
+// interval elapses.
+// - A "wifi" fetch is performed only when the user is on a connection that
+// the OS classifies as unmetered while
+// - a "fallback" fetch happens on any connection.
+// If a fetch failed, then only the corresponding timer is reset. The other
+// timers are not touched.
enum class FetchingInterval {
PERSISTENT_FALLBACK,
PERSISTENT_WIFI,
- SOFT_ON_USAGE_EVENT,
- SOFT_ON_NTP_OPENED,
+ SOFT_FALLBACK,
+ SOFT_WIFI,
COUNT
};
@@ -48,10 +57,10 @@ enum class FetchingInterval {
// The values of each array specify a default time interval for the intervals
// defined by the enum FetchingInterval. The default time intervals defined in
// the arrays can be overridden using different variation parameters.
-const double kDefaultFetchingIntervalHoursRareNtpUser[] = {48.0, 24.0, 12.0,
- 6.0};
-const double kDefaultFetchingIntervalHoursActiveNtpUser[] = {24.0, 6.0, 2.0,
- 2.0};
+const double kDefaultFetchingIntervalHoursRareNtpUser[] = {48.0, 24.0, 8.0,
+ 4.0};
+const double kDefaultFetchingIntervalHoursActiveNtpUser[] = {24.0, 8.0, 6.0,
+ 3.0};
const double kDefaultFetchingIntervalHoursActiveSuggestionsConsumer[] = {
24.0, 6.0, 2.0, 1.0};
@@ -60,18 +69,18 @@ const double kDefaultFetchingIntervalHoursActiveSuggestionsConsumer[] = {
const char* kFetchingIntervalParamNameRareNtpUser[] = {
"fetching_interval_hours-fallback-rare_ntp_user",
"fetching_interval_hours-wifi-rare_ntp_user",
- "soft_fetching_interval_hours-active-rare_ntp_user",
- "soft_on_ntp_opened_interval_hours-rare_ntp_user"};
+ "soft_fetching_interval_hours-fallback-rare_ntp_user",
+ "soft_fetching_interval_hours-wifi-rare_ntp_user"};
const char* kFetchingIntervalParamNameActiveNtpUser[] = {
"fetching_interval_hours-fallback-active_ntp_user",
"fetching_interval_hours-wifi-active_ntp_user",
- "soft_fetching_interval_hours-active-active_ntp_user",
- "soft_on_ntp_opened_interval_hours-active_ntp_user"};
+ "soft_fetching_interval_hours-fallback-active_ntp_user",
+ "soft_fetching_interval_hours-wifi-active_ntp_user"};
const char* kFetchingIntervalParamNameActiveSuggestionsConsumer[] = {
"fetching_interval_hours-fallback-active_suggestions_consumer",
"fetching_interval_hours-wifi-active_suggestions_consumer",
- "soft_fetching_interval_hours-active-active_suggestions_consumer",
- "soft_on_ntp_opened_interval_hours-active_suggestions_consumer"};
+ "soft_fetching_interval_hours-fallback-active_suggestions_consumer",
+ "soft_fetching_interval_hours-wifi-active_suggestions_consumer"};
static_assert(
static_cast<unsigned int>(FetchingInterval::COUNT) ==
@@ -97,6 +106,11 @@ const char* kTriggerTypesParamValueForEmptyList = "-";
const int kBlockBackgroundFetchesMinutesAfterClearingHistory = 30;
+const char kSnippetSoftFetchingIntervalOnUsageEventDeprecated[] =
+ "ntp_snippets.soft_fetching_interval_on_usage_event";
+const char kSnippetSoftFetchingIntervalOnNtpOpenedDeprecated[] =
+ "ntp_snippets.soft_fetching_interval_on_ntp_opened";
+
// Returns the time interval to use for scheduling remote suggestion fetches for
// the given interval and user_class.
base::TimeDelta GetDesiredFetchingInterval(
@@ -131,33 +145,162 @@ base::TimeDelta GetDesiredFetchingInterval(
return base::TimeDelta::FromSecondsD(value_hours * 3600.0);
}
+void ReportTimeUntilFirstSoftTrigger(UserClassifier::UserClass user_class,
+ base::TimeDelta time_until_first_trigger) {
+ switch (user_class) {
+ case UserClassifier::UserClass::RARE_NTP_USER:
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NewTabPage.ContentSuggestions.TimeUntilFirstSoftTrigger.RareNTPUser",
+ time_until_first_trigger, base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromDays(7),
+ /*bucket_count=*/50);
+ break;
+ case UserClassifier::UserClass::ACTIVE_NTP_USER:
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NewTabPage.ContentSuggestions.TimeUntilFirstSoftTrigger."
+ "ActiveNTPUser",
+ time_until_first_trigger, base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromDays(7),
+ /*bucket_count=*/50);
+ break;
+ case UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER:
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NewTabPage.ContentSuggestions.TimeUntilFirstSoftTrigger."
+ "ActiveSuggestionsConsumer",
+ time_until_first_trigger, base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromDays(7),
+ /*bucket_count=*/50);
+ break;
+ }
+}
+
+void ReportTimeUntilSoftFetch(UserClassifier::UserClass user_class,
+ base::TimeDelta time_until_soft_fetch) {
+ switch (user_class) {
+ case UserClassifier::UserClass::RARE_NTP_USER:
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NewTabPage.ContentSuggestions.TimeUntilSoftFetch."
+ "RareNTPUser",
+ time_until_soft_fetch, base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromDays(7),
+ /*bucket_count=*/50);
+ break;
+ case UserClassifier::UserClass::ACTIVE_NTP_USER:
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NewTabPage.ContentSuggestions.TimeUntilSoftFetch."
+ "ActiveNTPUser",
+ time_until_soft_fetch, base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromDays(7),
+ /*bucket_count=*/50);
+ break;
+ case UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER:
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NewTabPage.ContentSuggestions.TimeUntilSoftFetch."
+ "ActiveSuggestionsConsumer",
+ time_until_soft_fetch, base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromDays(7),
+ /*bucket_count=*/50);
+ break;
+ }
+}
+
+void ReportTimeUntilPersistentFetch(
+ UserClassifier::UserClass user_class,
+ base::TimeDelta time_until_persistent_fetch) {
+ switch (user_class) {
+ case UserClassifier::UserClass::RARE_NTP_USER:
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NewTabPage.ContentSuggestions.TimeUntilPersistentFetch."
+ "RareNTPUser",
+ time_until_persistent_fetch, base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromDays(7),
+ /*bucket_count=*/50);
+ break;
+ case UserClassifier::UserClass::ACTIVE_NTP_USER:
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NewTabPage.ContentSuggestions.TimeUntilPersistentFetch."
+ "ActiveNTPUser",
+ time_until_persistent_fetch, base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromDays(7),
+ /*bucket_count=*/50);
+ break;
+ case UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER:
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NewTabPage.ContentSuggestions.TimeUntilPersistentFetch."
+ "ActiveSuggestionsConsumer",
+ time_until_persistent_fetch, base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromDays(7),
+ /*bucket_count=*/50);
+ break;
+ }
+}
+
} // namespace
+class EulaState : public web_resource::EulaAcceptedNotifier::Observer {
+ public:
+ EulaState(PrefService* local_state_prefs,
+ RemoteSuggestionsScheduler* scheduler)
+ : eula_notifier_(
+ web_resource::EulaAcceptedNotifier::Create(local_state_prefs)),
+ scheduler_(scheduler) {
+ // EulaNotifier is not constructed on some platforms (such as desktop).
+ if (!eula_notifier_) {
+ return;
+ }
+
+ // Register the observer.
+ eula_notifier_->Init(this);
+ }
+
+ ~EulaState() = default;
+
+ bool IsEulaAccepted() {
+ if (!eula_notifier_) {
+ return true;
+ }
+ return eula_notifier_->IsEulaAccepted();
+ }
+
+ // EulaAcceptedNotifier::Observer implementation.
+ void OnEulaAccepted() override {
+ // Emulate a persistent fetch - we really want to fetch, initially!
+ // TODO(jkrcal): Find a cleaner solution. This is somewhat hacky and can
+ // mess up with metrics.
+ scheduler_->OnPersistentSchedulerWakeUp();
+ }
+
+ private:
+ std::unique_ptr<web_resource::EulaAcceptedNotifier> eula_notifier_;
+ RemoteSuggestionsScheduler* scheduler_;
+
+ DISALLOW_COPY_AND_ASSIGN(EulaState);
+};
+
// static
-SchedulingRemoteSuggestionsProvider::FetchingSchedule
-SchedulingRemoteSuggestionsProvider::FetchingSchedule::Empty() {
+RemoteSuggestionsSchedulerImpl::FetchingSchedule
+RemoteSuggestionsSchedulerImpl::FetchingSchedule::Empty() {
return FetchingSchedule{base::TimeDelta(), base::TimeDelta(),
base::TimeDelta(), base::TimeDelta()};
}
-bool SchedulingRemoteSuggestionsProvider::FetchingSchedule::operator==(
+bool RemoteSuggestionsSchedulerImpl::FetchingSchedule::operator==(
const FetchingSchedule& other) const {
return interval_persistent_wifi == other.interval_persistent_wifi &&
interval_persistent_fallback == other.interval_persistent_fallback &&
- interval_soft_on_usage_event == other.interval_soft_on_usage_event &&
- interval_soft_on_ntp_opened == other.interval_soft_on_ntp_opened;
+ interval_soft_wifi == other.interval_soft_wifi &&
+ interval_soft_fallback == other.interval_soft_fallback;
}
-bool SchedulingRemoteSuggestionsProvider::FetchingSchedule::operator!=(
+bool RemoteSuggestionsSchedulerImpl::FetchingSchedule::operator!=(
const FetchingSchedule& other) const {
return !operator==(other);
}
-bool SchedulingRemoteSuggestionsProvider::FetchingSchedule::is_empty() const {
+bool RemoteSuggestionsSchedulerImpl::FetchingSchedule::is_empty() const {
return interval_persistent_wifi.is_zero() &&
interval_persistent_fallback.is_zero() &&
- interval_soft_on_usage_event.is_zero() &&
- interval_soft_on_ntp_opened.is_zero();
+ interval_soft_wifi.is_zero() && interval_soft_fallback.is_zero();
}
// The TriggerType enum specifies values for the events that can trigger
@@ -165,7 +308,7 @@ bool SchedulingRemoteSuggestionsProvider::FetchingSchedule::is_empty() const {
// values can be added, but existing enums must never be renumbered or deleted
// and reused. When adding new entries, also update the array
// |kTriggerTypeNames| above.
-enum class SchedulingRemoteSuggestionsProvider::TriggerType {
+enum class RemoteSuggestionsSchedulerImpl::TriggerType {
PERSISTENT_SCHEDULER_WAKE_UP = 0,
NTP_OPENED = 1,
BROWSER_FOREGROUNDED = 2,
@@ -173,71 +316,85 @@ enum class SchedulingRemoteSuggestionsProvider::TriggerType {
COUNT
};
-SchedulingRemoteSuggestionsProvider::SchedulingRemoteSuggestionsProvider(
- Observer* observer,
- std::unique_ptr<RemoteSuggestionsProvider> provider,
+RemoteSuggestionsSchedulerImpl::RemoteSuggestionsSchedulerImpl(
PersistentScheduler* persistent_scheduler,
const UserClassifier* user_classifier,
- PrefService* pref_service,
+ PrefService* profile_prefs,
+ PrefService* local_state_prefs,
std::unique_ptr<base::Clock> clock)
- : RemoteSuggestionsProvider(observer),
- RemoteSuggestionsScheduler(),
- provider_(std::move(provider)),
- persistent_scheduler_(persistent_scheduler),
+ : persistent_scheduler_(persistent_scheduler),
+ provider_(nullptr),
background_fetch_in_progress_(false),
user_classifier_(user_classifier),
request_throttler_rare_ntp_user_(
- pref_service,
+ profile_prefs,
RequestThrottler::RequestType::
CONTENT_SUGGESTION_FETCHER_RARE_NTP_USER),
request_throttler_active_ntp_user_(
- pref_service,
+ profile_prefs,
RequestThrottler::RequestType::
CONTENT_SUGGESTION_FETCHER_ACTIVE_NTP_USER),
request_throttler_active_suggestions_consumer_(
- pref_service,
+ profile_prefs,
RequestThrottler::RequestType::
CONTENT_SUGGESTION_FETCHER_ACTIVE_SUGGESTIONS_CONSUMER),
- pref_service_(pref_service),
+ time_until_first_trigger_reported_(false),
+ eula_state_(base::MakeUnique<EulaState>(local_state_prefs, this)),
+ profile_prefs_(profile_prefs),
clock_(std::move(clock)),
enabled_triggers_(GetEnabledTriggerTypes()) {
DCHECK(user_classifier);
- DCHECK(pref_service);
+ DCHECK(profile_prefs);
+
+ // Cleanup procedure in M59. Remove for M62.
+ profile_prefs_->ClearPref(kSnippetSoftFetchingIntervalOnUsageEventDeprecated);
+ profile_prefs_->ClearPref(kSnippetSoftFetchingIntervalOnNtpOpenedDeprecated);
LoadLastFetchingSchedule();
}
-SchedulingRemoteSuggestionsProvider::~SchedulingRemoteSuggestionsProvider() =
- default;
+RemoteSuggestionsSchedulerImpl::~RemoteSuggestionsSchedulerImpl() = default;
// static
-void SchedulingRemoteSuggestionsProvider::RegisterProfilePrefs(
+void RemoteSuggestionsSchedulerImpl::RegisterProfilePrefs(
PrefRegistrySimple* registry) {
registry->RegisterInt64Pref(prefs::kSnippetPersistentFetchingIntervalWifi, 0);
registry->RegisterInt64Pref(prefs::kSnippetPersistentFetchingIntervalFallback,
0);
- registry->RegisterInt64Pref(prefs::kSnippetSoftFetchingIntervalOnUsageEvent,
- 0);
+ registry->RegisterInt64Pref(prefs::kSnippetSoftFetchingIntervalWifi, 0);
+ registry->RegisterInt64Pref(prefs::kSnippetSoftFetchingIntervalFallback, 0);
registry->RegisterInt64Pref(prefs::kSnippetLastFetchAttempt, 0);
- registry->RegisterInt64Pref(prefs::kSnippetSoftFetchingIntervalOnNtpOpened,
+
+ // Cleanup procedure in M59. Remove for M62.
+ registry->RegisterInt64Pref(
+ kSnippetSoftFetchingIntervalOnUsageEventDeprecated, 0);
+ registry->RegisterInt64Pref(kSnippetSoftFetchingIntervalOnNtpOpenedDeprecated,
0);
}
-void SchedulingRemoteSuggestionsProvider::OnProviderActivated() {
+void RemoteSuggestionsSchedulerImpl::SetProvider(
+ RemoteSuggestionsProvider* provider) {
+ DCHECK(provider);
+ provider_ = provider;
+}
+
+void RemoteSuggestionsSchedulerImpl::OnProviderActivated() {
StartScheduling();
}
-void SchedulingRemoteSuggestionsProvider::OnProviderDeactivated() {
+void RemoteSuggestionsSchedulerImpl::OnProviderDeactivated() {
StopScheduling();
}
-void SchedulingRemoteSuggestionsProvider::OnSuggestionsCleared() {
+void RemoteSuggestionsSchedulerImpl::OnSuggestionsCleared() {
+ // This should be called by |provider_| so it should exist.
+ DCHECK(provider_);
// Some user action causes suggestions to be cleared, fetch now (as an
// interactive request).
- ReloadSuggestions();
+ provider_->ReloadSuggestions();
}
-void SchedulingRemoteSuggestionsProvider::OnHistoryCleared() {
+void RemoteSuggestionsSchedulerImpl::OnHistoryCleared() {
// Due to privacy, we should not fetch for a while (unless the user explicitly
// asks for new suggestions) to give sync the time to propagate the changes in
// history to the server.
@@ -248,152 +405,45 @@ void SchedulingRemoteSuggestionsProvider::OnHistoryCleared() {
ClearLastFetchAttemptTime();
}
-void SchedulingRemoteSuggestionsProvider::RescheduleFetching() {
+void RemoteSuggestionsSchedulerImpl::RescheduleFetching() {
// Force the reschedule by stopping and starting it again.
StopScheduling();
StartScheduling();
}
-void SchedulingRemoteSuggestionsProvider::OnPersistentSchedulerWakeUp() {
- RefetchInTheBackgroundIfEnabled(TriggerType::PERSISTENT_SCHEDULER_WAKE_UP);
-}
-
-void SchedulingRemoteSuggestionsProvider::OnBrowserForegrounded() {
- // TODO(jkrcal): Consider that this is called whenever we open or return to an
- // Activity. Therefore, keep work light for fast start up calls.
- if (!ShouldRefetchInTheBackgroundNow(TriggerType::BROWSER_FOREGROUNDED)) {
- return;
- }
-
- RefetchInTheBackgroundIfEnabled(TriggerType::BROWSER_FOREGROUNDED);
-}
-
-void SchedulingRemoteSuggestionsProvider::OnBrowserColdStart() {
- // TODO(fhorschig|jkrcal): Consider that work here must be kept light for fast
- // cold start ups.
- if (!ShouldRefetchInTheBackgroundNow(TriggerType::BROWSER_COLD_START)) {
- return;
- }
-
- RefetchInTheBackgroundIfEnabled(TriggerType::BROWSER_COLD_START);
-}
-
-void SchedulingRemoteSuggestionsProvider::OnNTPOpened() {
- if (!ShouldRefetchInTheBackgroundNow(TriggerType::NTP_OPENED)) {
- return;
- }
-
- RefetchInTheBackgroundIfEnabled(TriggerType::NTP_OPENED);
-}
-
-void SchedulingRemoteSuggestionsProvider::RefetchInTheBackground(
- std::unique_ptr<FetchStatusCallback> callback) {
- if (background_fetch_in_progress_) {
- if (callback) {
- callback->Run(
- Status(StatusCode::TEMPORARY_ERROR, "Background fetch in progress"));
- }
- return;
- }
-
- if (!AcquireQuota(/*interactive_request=*/false)) {
- if (callback) {
- callback->Run(Status(StatusCode::TEMPORARY_ERROR,
- "Non-interactive quota exceeded"));
- }
- return;
- }
-
- background_fetch_in_progress_ = true;
- RemoteSuggestionsProvider::FetchStatusCallback wrapper_callback = base::Bind(
- &SchedulingRemoteSuggestionsProvider::RefetchInTheBackgroundFinished,
- base::Unretained(this), base::Passed(&callback));
- provider_->RefetchInTheBackground(
- base::MakeUnique<RemoteSuggestionsProvider::FetchStatusCallback>(
- std::move(wrapper_callback)));
-}
-
-const RemoteSuggestionsFetcher*
-SchedulingRemoteSuggestionsProvider::suggestions_fetcher_for_debugging() const {
- return provider_->suggestions_fetcher_for_debugging();
-}
-
-CategoryStatus SchedulingRemoteSuggestionsProvider::GetCategoryStatus(
- Category category) {
- return provider_->GetCategoryStatus(category);
-}
-
-CategoryInfo SchedulingRemoteSuggestionsProvider::GetCategoryInfo(
- Category category) {
- return provider_->GetCategoryInfo(category);
-}
-
-void SchedulingRemoteSuggestionsProvider::DismissSuggestion(
- const ContentSuggestion::ID& suggestion_id) {
- provider_->DismissSuggestion(suggestion_id);
-}
-
-void SchedulingRemoteSuggestionsProvider::FetchSuggestionImage(
- const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) {
- provider_->FetchSuggestionImage(suggestion_id, callback);
-}
-
-void SchedulingRemoteSuggestionsProvider::Fetch(
- const Category& category,
- const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) {
- if (!AcquireQuota(/*interactive_request=*/true)) {
- if (callback) {
- callback.Run(
- Status(StatusCode::TEMPORARY_ERROR, "Interactive quota exceeded"),
- std::vector<ContentSuggestion>());
- }
- return;
- }
-
- provider_->Fetch(
- category, known_suggestion_ids,
- base::Bind(&SchedulingRemoteSuggestionsProvider::FetchFinished,
- base::Unretained(this), callback));
-}
-
-void SchedulingRemoteSuggestionsProvider::ReloadSuggestions() {
- if (!AcquireQuota(/*interactive_request=*/true)) {
- return;
- }
-
- provider_->ReloadSuggestions();
+bool RemoteSuggestionsSchedulerImpl::AcquireQuotaForInteractiveFetch() {
+ return AcquireQuota(/*interactive_request=*/true);
}
-void SchedulingRemoteSuggestionsProvider::ClearHistory(
- base::Time begin,
- base::Time end,
- const base::Callback<bool(const GURL& url)>& filter) {
- provider_->ClearHistory(begin, end, filter);
+void RemoteSuggestionsSchedulerImpl::OnInteractiveFetchFinished(
+ Status fetch_status) {
+ OnFetchCompleted(fetch_status);
}
-void SchedulingRemoteSuggestionsProvider::ClearCachedSuggestions(
- Category category) {
- provider_->ClearCachedSuggestions(category);
+void RemoteSuggestionsSchedulerImpl::OnPersistentSchedulerWakeUp() {
+ RefetchInTheBackgroundIfAppropriate(
+ TriggerType::PERSISTENT_SCHEDULER_WAKE_UP);
}
-void SchedulingRemoteSuggestionsProvider::OnSignInStateChanged() {
- provider_->OnSignInStateChanged();
+void RemoteSuggestionsSchedulerImpl::OnBrowserForegrounded() {
+ // TODO(jkrcal): Consider that this is called whenever we open or return to an
+ // Activity. Therefore, keep work light for fast start up calls.
+ RefetchInTheBackgroundIfAppropriate(TriggerType::BROWSER_FOREGROUNDED);
}
-void SchedulingRemoteSuggestionsProvider::GetDismissedSuggestionsForDebugging(
- Category category,
- const DismissedSuggestionsCallback& callback) {
- provider_->GetDismissedSuggestionsForDebugging(category, callback);
+void RemoteSuggestionsSchedulerImpl::OnBrowserColdStart() {
+ // TODO(jkrcal): Consider that work here must be kept light for fast
+ // cold start ups.
+ RefetchInTheBackgroundIfAppropriate(TriggerType::BROWSER_COLD_START);
}
-void SchedulingRemoteSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
- Category category) {
- provider_->ClearDismissedSuggestionsForDebugging(category);
+void RemoteSuggestionsSchedulerImpl::OnNTPOpened() {
+ // TODO(jkrcal): Consider that this is called whenever we open an NTP.
+ // Therefore, keep work light for fast start up calls.
+ RefetchInTheBackgroundIfAppropriate(TriggerType::NTP_OPENED);
}
-void SchedulingRemoteSuggestionsProvider::StartScheduling() {
+void RemoteSuggestionsSchedulerImpl::StartScheduling() {
FetchingSchedule new_schedule = GetDesiredFetchingSchedule();
if (schedule_ == new_schedule) {
@@ -406,7 +456,7 @@ void SchedulingRemoteSuggestionsProvider::StartScheduling() {
ApplyPersistentFetchingSchedule();
}
-void SchedulingRemoteSuggestionsProvider::StopScheduling() {
+void RemoteSuggestionsSchedulerImpl::StopScheduling() {
if (schedule_.is_empty()) {
// Do not unschedule if already switched off.
return;
@@ -417,7 +467,7 @@ void SchedulingRemoteSuggestionsProvider::StopScheduling() {
ApplyPersistentFetchingSchedule();
}
-void SchedulingRemoteSuggestionsProvider::ApplyPersistentFetchingSchedule() {
+void RemoteSuggestionsSchedulerImpl::ApplyPersistentFetchingSchedule() {
// The scheduler only exists on Android so far, it's null on other platforms.
if (persistent_scheduler_) {
if (schedule_.is_empty()) {
@@ -429,8 +479,8 @@ void SchedulingRemoteSuggestionsProvider::ApplyPersistentFetchingSchedule() {
}
}
-SchedulingRemoteSuggestionsProvider::FetchingSchedule
-SchedulingRemoteSuggestionsProvider::GetDesiredFetchingSchedule() const {
+RemoteSuggestionsSchedulerImpl::FetchingSchedule
+RemoteSuggestionsSchedulerImpl::GetDesiredFetchingSchedule() const {
UserClassifier::UserClass user_class = user_classifier_->GetUserClass();
FetchingSchedule schedule;
@@ -438,81 +488,107 @@ SchedulingRemoteSuggestionsProvider::GetDesiredFetchingSchedule() const {
GetDesiredFetchingInterval(FetchingInterval::PERSISTENT_WIFI, user_class);
schedule.interval_persistent_fallback = GetDesiredFetchingInterval(
FetchingInterval::PERSISTENT_FALLBACK, user_class);
- schedule.interval_soft_on_usage_event = GetDesiredFetchingInterval(
- FetchingInterval::SOFT_ON_USAGE_EVENT, user_class);
- schedule.interval_soft_on_ntp_opened = GetDesiredFetchingInterval(
- FetchingInterval::SOFT_ON_NTP_OPENED, user_class);
+ schedule.interval_soft_wifi =
+ GetDesiredFetchingInterval(FetchingInterval::SOFT_WIFI, user_class);
+ schedule.interval_soft_fallback =
+ GetDesiredFetchingInterval(FetchingInterval::SOFT_FALLBACK, user_class);
return schedule;
}
-void SchedulingRemoteSuggestionsProvider::LoadLastFetchingSchedule() {
+void RemoteSuggestionsSchedulerImpl::LoadLastFetchingSchedule() {
schedule_.interval_persistent_wifi = base::TimeDelta::FromInternalValue(
- pref_service_->GetInt64(prefs::kSnippetPersistentFetchingIntervalWifi));
+ profile_prefs_->GetInt64(prefs::kSnippetPersistentFetchingIntervalWifi));
schedule_.interval_persistent_fallback =
- base::TimeDelta::FromInternalValue(pref_service_->GetInt64(
+ base::TimeDelta::FromInternalValue(profile_prefs_->GetInt64(
prefs::kSnippetPersistentFetchingIntervalFallback));
- schedule_.interval_soft_on_usage_event = base::TimeDelta::FromInternalValue(
- pref_service_->GetInt64(prefs::kSnippetSoftFetchingIntervalOnUsageEvent));
- schedule_.interval_soft_on_ntp_opened = base::TimeDelta::FromInternalValue(
- pref_service_->GetInt64(prefs::kSnippetSoftFetchingIntervalOnNtpOpened));
+ schedule_.interval_soft_wifi = base::TimeDelta::FromInternalValue(
+ profile_prefs_->GetInt64(prefs::kSnippetSoftFetchingIntervalWifi));
+ schedule_.interval_soft_fallback = base::TimeDelta::FromInternalValue(
+ profile_prefs_->GetInt64(prefs::kSnippetSoftFetchingIntervalFallback));
}
-void SchedulingRemoteSuggestionsProvider::StoreFetchingSchedule() {
- pref_service_->SetInt64(prefs::kSnippetPersistentFetchingIntervalWifi,
- schedule_.interval_persistent_wifi.ToInternalValue());
- pref_service_->SetInt64(
+void RemoteSuggestionsSchedulerImpl::StoreFetchingSchedule() {
+ profile_prefs_->SetInt64(
+ prefs::kSnippetPersistentFetchingIntervalWifi,
+ schedule_.interval_persistent_wifi.ToInternalValue());
+ profile_prefs_->SetInt64(
prefs::kSnippetPersistentFetchingIntervalFallback,
schedule_.interval_persistent_fallback.ToInternalValue());
- pref_service_->SetInt64(
- prefs::kSnippetSoftFetchingIntervalOnUsageEvent,
- schedule_.interval_soft_on_usage_event.ToInternalValue());
- pref_service_->SetInt64(
- prefs::kSnippetSoftFetchingIntervalOnNtpOpened,
- schedule_.interval_soft_on_ntp_opened.ToInternalValue());
+ profile_prefs_->SetInt64(prefs::kSnippetSoftFetchingIntervalWifi,
+ schedule_.interval_soft_wifi.ToInternalValue());
+ profile_prefs_->SetInt64(prefs::kSnippetSoftFetchingIntervalFallback,
+ schedule_.interval_soft_fallback.ToInternalValue());
}
-void SchedulingRemoteSuggestionsProvider::RefetchInTheBackgroundIfEnabled(
- SchedulingRemoteSuggestionsProvider::TriggerType trigger) {
+void RemoteSuggestionsSchedulerImpl::RefetchInTheBackgroundIfAppropriate(
+ TriggerType trigger) {
+ if (background_fetch_in_progress_) {
+ return;
+ }
+
if (BackgroundFetchesDisabled(trigger)) {
return;
}
+ bool is_soft = trigger != TriggerType::PERSISTENT_SCHEDULER_WAKE_UP;
+ const base::Time last_fetch_attempt_time = base::Time::FromInternalValue(
+ profile_prefs_->GetInt64(prefs::kSnippetLastFetchAttempt));
+
+ if (is_soft && !time_until_first_trigger_reported_) {
+ time_until_first_trigger_reported_ = true;
+ ReportTimeUntilFirstSoftTrigger(user_classifier_->GetUserClass(),
+ clock_->Now() - last_fetch_attempt_time);
+ }
+
+ if (is_soft && !ShouldRefetchInTheBackgroundNow(last_fetch_attempt_time)) {
+ return;
+ }
+
+ if (!AcquireQuota(/*interactive_request=*/false)) {
+ return;
+ }
+
+ if (is_soft) {
+ ReportTimeUntilSoftFetch(user_classifier_->GetUserClass(),
+ clock_->Now() - last_fetch_attempt_time);
+ } else {
+ ReportTimeUntilPersistentFetch(user_classifier_->GetUserClass(),
+ clock_->Now() - last_fetch_attempt_time);
+ }
+
UMA_HISTOGRAM_ENUMERATION(
"NewTabPage.ContentSuggestions.BackgroundFetchTrigger",
static_cast<int>(trigger), static_cast<int>(TriggerType::COUNT));
- RefetchInTheBackground(/*callback=*/nullptr);
+ background_fetch_in_progress_ = true;
+ provider_->RefetchInTheBackground(base::Bind(
+ &RemoteSuggestionsSchedulerImpl::RefetchInTheBackgroundFinished,
+ base::Unretained(this)));
}
-bool SchedulingRemoteSuggestionsProvider::ShouldRefetchInTheBackgroundNow(
- SchedulingRemoteSuggestionsProvider::TriggerType trigger) {
- const base::Time last_fetch_attempt_time = base::Time::FromInternalValue(
- pref_service_->GetInt64(prefs::kSnippetLastFetchAttempt));
- base::Time first_allowed_fetch_time;
- switch (trigger) {
- case TriggerType::NTP_OPENED:
- first_allowed_fetch_time =
- last_fetch_attempt_time + schedule_.interval_soft_on_ntp_opened;
- break;
- case TriggerType::BROWSER_FOREGROUNDED:
- case TriggerType::BROWSER_COLD_START:
- first_allowed_fetch_time =
- last_fetch_attempt_time + schedule_.interval_soft_on_usage_event;
- break;
- case TriggerType::PERSISTENT_SCHEDULER_WAKE_UP:
- case TriggerType::COUNT:
- NOTREACHED();
- break;
+bool RemoteSuggestionsSchedulerImpl::ShouldRefetchInTheBackgroundNow(
+ base::Time last_fetch_attempt_time) {
+ // If we have no persistent scheduler to ask, err on the side of caution.
+ bool wifi = false;
+ if (persistent_scheduler_) {
+ wifi = persistent_scheduler_->IsOnUnmeteredConnection();
}
- base::Time now = clock_->Now();
+ base::Time first_allowed_fetch_time =
+ last_fetch_attempt_time +
+ (wifi ? schedule_.interval_soft_wifi : schedule_.interval_soft_fallback);
+ base::Time now = clock_->Now();
return background_fetches_allowed_after_ <= now &&
first_allowed_fetch_time <= now;
}
-bool SchedulingRemoteSuggestionsProvider::BackgroundFetchesDisabled(
- SchedulingRemoteSuggestionsProvider::TriggerType trigger) const {
+bool RemoteSuggestionsSchedulerImpl::BackgroundFetchesDisabled(
+ TriggerType trigger) const {
+ if (!provider_) {
+ return true; // Cannot fetch as remote suggestions provider does not exist.
+ }
+
if (schedule_.is_empty()) {
return true; // Background fetches are disabled in general.
}
@@ -520,11 +596,15 @@ bool SchedulingRemoteSuggestionsProvider::BackgroundFetchesDisabled(
if (enabled_triggers_.count(trigger) == 0) {
return true; // Background fetches for |trigger| are not enabled.
}
+
+ if (!eula_state_->IsEulaAccepted()) {
+ return true; // No background fetches are allowed before EULA is accepted.
+ }
+
return false;
}
-bool SchedulingRemoteSuggestionsProvider::AcquireQuota(
- bool interactive_request) {
+bool RemoteSuggestionsSchedulerImpl::AcquireQuota(bool interactive_request) {
switch (user_classifier_->GetUserClass()) {
case UserClassifier::UserClass::RARE_NTP_USER:
return request_throttler_rare_ntp_user_.DemandQuotaForRequest(
@@ -540,30 +620,16 @@ bool SchedulingRemoteSuggestionsProvider::AcquireQuota(
return false;
}
-void SchedulingRemoteSuggestionsProvider::FetchFinished(
- const FetchDoneCallback& callback,
- Status fetch_status,
- std::vector<ContentSuggestion> suggestions) {
- OnFetchCompleted(fetch_status);
- if (callback) {
- callback.Run(fetch_status, std::move(suggestions));
- }
-}
-
-void SchedulingRemoteSuggestionsProvider::RefetchInTheBackgroundFinished(
- std::unique_ptr<FetchStatusCallback> callback,
+void RemoteSuggestionsSchedulerImpl::RefetchInTheBackgroundFinished(
Status fetch_status) {
background_fetch_in_progress_ = false;
OnFetchCompleted(fetch_status);
- if (callback) {
- callback->Run(fetch_status);
- }
}
-void SchedulingRemoteSuggestionsProvider::OnFetchCompleted(
- Status fetch_status) {
- pref_service_->SetInt64(prefs::kSnippetLastFetchAttempt,
- clock_->Now().ToInternalValue());
+void RemoteSuggestionsSchedulerImpl::OnFetchCompleted(Status fetch_status) {
+ profile_prefs_->SetInt64(prefs::kSnippetLastFetchAttempt,
+ clock_->Now().ToInternalValue());
+ time_until_first_trigger_reported_ = false;
// Reschedule after a fetch. The persistent schedule is applied only after a
// successful fetch. After a failed fetch, we want to keep the previous
@@ -575,12 +641,12 @@ void SchedulingRemoteSuggestionsProvider::OnFetchCompleted(
ApplyPersistentFetchingSchedule();
}
-void SchedulingRemoteSuggestionsProvider::ClearLastFetchAttemptTime() {
- pref_service_->ClearPref(prefs::kSnippetLastFetchAttempt);
+void RemoteSuggestionsSchedulerImpl::ClearLastFetchAttemptTime() {
+ profile_prefs_->ClearPref(prefs::kSnippetLastFetchAttempt);
}
-std::set<SchedulingRemoteSuggestionsProvider::TriggerType>
-SchedulingRemoteSuggestionsProvider::GetEnabledTriggerTypes() {
+std::set<RemoteSuggestionsSchedulerImpl::TriggerType>
+RemoteSuggestionsSchedulerImpl::GetEnabledTriggerTypes() {
static_assert(static_cast<unsigned int>(TriggerType::COUNT) ==
arraysize(kTriggerTypeNames),
"Fill in names for trigger types.");
@@ -618,10 +684,9 @@ SchedulingRemoteSuggestionsProvider::GetEnabledTriggerTypes() {
return enabled_types;
}
-std::set<SchedulingRemoteSuggestionsProvider::TriggerType>
-SchedulingRemoteSuggestionsProvider::GetDefaultEnabledTriggerTypes() {
- return {TriggerType::PERSISTENT_SCHEDULER_WAKE_UP, TriggerType::NTP_OPENED,
- TriggerType::BROWSER_FOREGROUNDED};
+std::set<RemoteSuggestionsSchedulerImpl::TriggerType>
+RemoteSuggestionsSchedulerImpl::GetDefaultEnabledTriggerTypes() {
+ return {TriggerType::PERSISTENT_SCHEDULER_WAKE_UP, TriggerType::NTP_OPENED};
}
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h
new file mode 100644
index 00000000000..9921f51489a
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h
@@ -0,0 +1,164 @@
+// 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_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_SCHEDULER_IMPL_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_SCHEDULER_IMPL_H_
+
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/time/clock.h"
+#include "base/time/time.h"
+#include "components/ntp_snippets/content_suggestions_provider.h"
+#include "components/ntp_snippets/remote/persistent_scheduler.h"
+#include "components/ntp_snippets/remote/remote_suggestions_scheduler.h"
+#include "components/ntp_snippets/remote/request_throttler.h"
+#include "components/web_resource/eula_accepted_notifier.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace base {
+class Clock;
+}
+
+namespace ntp_snippets {
+
+struct Status;
+class EulaState;
+class UserClassifier;
+
+// A client of RemoteSuggestionsProvider that introduces periodic fetching.
+class RemoteSuggestionsSchedulerImpl : public RemoteSuggestionsScheduler {
+ public:
+ RemoteSuggestionsSchedulerImpl(PersistentScheduler* persistent_scheduler,
+ const UserClassifier* user_classifier,
+ PrefService* profile_prefs,
+ PrefService* local_state_prefs,
+ std::unique_ptr<base::Clock> clock);
+
+ ~RemoteSuggestionsSchedulerImpl();
+
+ static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ // RemoteSuggestionsScheduler implementation.
+ void SetProvider(RemoteSuggestionsProvider* provider) override;
+ void OnProviderActivated() override;
+ void OnProviderDeactivated() override;
+ void OnSuggestionsCleared() override;
+ void OnHistoryCleared() override;
+ void RescheduleFetching() override;
+ bool AcquireQuotaForInteractiveFetch() override;
+ void OnInteractiveFetchFinished(Status fetch_status) override;
+ void OnPersistentSchedulerWakeUp() override;
+ void OnBrowserForegrounded() override;
+ void OnBrowserColdStart() override;
+ void OnNTPOpened() override;
+
+ private:
+ // Abstract description of the fetching schedule. See the enum
+ // FetchingInterval for more documentation.
+ struct FetchingSchedule {
+ static FetchingSchedule Empty();
+ bool operator==(const FetchingSchedule& other) const;
+ bool operator!=(const FetchingSchedule& other) const;
+ bool is_empty() const;
+
+ base::TimeDelta interval_persistent_wifi;
+ base::TimeDelta interval_persistent_fallback;
+ base::TimeDelta interval_soft_wifi;
+ base::TimeDelta interval_soft_fallback;
+ };
+
+ enum class TriggerType;
+
+ // After the call, updates will be scheduled in the future. Idempotent, can be
+ // run any time later without impacting the current schedule.
+ // If you want to enforce rescheduling, call Unschedule() and then Schedule().
+ void StartScheduling();
+
+ // After the call, no updates will happen before another call to Schedule().
+ // Idempotent, can be run any time later without impacting the current
+ // schedule.
+ void StopScheduling();
+
+ // Trigger a background refetch for the given |trigger| if enabled and if the
+ // timing is appropriate for another fetch.
+ void RefetchInTheBackgroundIfAppropriate(TriggerType trigger);
+
+ // Checks whether it is time to perform a soft background fetch, according to
+ // |schedule|.
+ bool ShouldRefetchInTheBackgroundNow(base::Time last_fetch_attempt_time);
+
+ // Returns whether background fetching (for the given |trigger|) is disabled.
+ bool BackgroundFetchesDisabled(TriggerType trigger) const;
+
+ // Returns true if quota is available for another request.
+ bool AcquireQuota(bool interactive_request);
+
+ // Callback after RefetchInTheBackground is completed.
+ void RefetchInTheBackgroundFinished(Status fetch_status);
+
+ // Common function to call after a fetch of any type is finished.
+ void OnFetchCompleted(Status fetch_status);
+
+ // Clears the time of the last fetch so that the provider is ready to make a
+ // soft fetch at any later time (upon a trigger).
+ void ClearLastFetchAttemptTime();
+
+ FetchingSchedule GetDesiredFetchingSchedule() const;
+
+ // Load and store |schedule_|.
+ void LoadLastFetchingSchedule();
+ void StoreFetchingSchedule();
+
+ // Applies the persistent schedule given by |schedule_|.
+ void ApplyPersistentFetchingSchedule();
+
+ // Gets enabled trigger types from the variation parameter.
+ std::set<TriggerType> GetEnabledTriggerTypes();
+
+ // Gets trigger types enabled by default.
+ std::set<TriggerType> GetDefaultEnabledTriggerTypes();
+
+ // Interface for scheduling hard fetches, OS dependent. Not owned, may be
+ // null.
+ PersistentScheduler* persistent_scheduler_;
+
+ // Interface for doing all the actual work (apart from scheduling). Not owned.
+ RemoteSuggestionsProvider* provider_;
+
+ FetchingSchedule schedule_;
+ bool background_fetch_in_progress_;
+
+ // Used to adapt the schedule based on usage activity of the user. Not owned.
+ const UserClassifier* user_classifier_;
+
+ // Request throttlers for limiting requests for different classes of users.
+ RequestThrottler request_throttler_rare_ntp_user_;
+ RequestThrottler request_throttler_active_ntp_user_;
+ RequestThrottler request_throttler_active_suggestions_consumer_;
+
+ // To make sure we only report the first trigger to UMA.
+ bool time_until_first_trigger_reported_;
+
+ // We should not fetch in background before EULA gets accepted.
+ std::unique_ptr<EulaState> eula_state_;
+
+ PrefService* profile_prefs_;
+ std::unique_ptr<base::Clock> clock_;
+ std::set<TriggerType> enabled_triggers_;
+
+ base::Time background_fetches_allowed_after_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsSchedulerImpl);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_SCHEDULER_IMPL_H_
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
new file mode 100644
index 00000000000..ea142787bcd
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
@@ -0,0 +1,842 @@
+// 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/ntp_snippets/remote/remote_suggestions_scheduler_impl.h"
+
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/simple_test_clock.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/clock.h"
+#include "base/time/default_clock.h"
+#include "base/time/time.h"
+#include "components/ntp_snippets/features.h"
+#include "components/ntp_snippets/ntp_snippets_constants.h"
+#include "components/ntp_snippets/pref_names.h"
+#include "components/ntp_snippets/remote/persistent_scheduler.h"
+#include "components/ntp_snippets/remote/remote_suggestions_provider.h"
+#include "components/ntp_snippets/remote/test_utils.h"
+#include "components/ntp_snippets/status.h"
+#include "components/ntp_snippets/user_classifier.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/variations/variations_params_manager.h"
+#include "components/web_resource/web_resource_pref_names.h"
+#include "net/base/network_change_notifier.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::ElementsAre;
+using testing::Eq;
+using testing::Field;
+using testing::InSequence;
+using testing::Invoke;
+using testing::IsEmpty;
+using testing::Mock;
+using testing::MockFunction;
+using testing::Not;
+using testing::Return;
+using testing::SaveArg;
+using testing::SaveArgPointee;
+using testing::SizeIs;
+using testing::StartsWith;
+using testing::StrictMock;
+using testing::WithArgs;
+using testing::_;
+
+namespace ntp_snippets {
+
+class RemoteSuggestionsFetcher;
+
+namespace {
+
+class MockPersistentScheduler : public PersistentScheduler {
+ public:
+ MOCK_METHOD2(Schedule,
+ bool(base::TimeDelta period_wifi,
+ base::TimeDelta period_fallback));
+ MOCK_METHOD0(Unschedule, bool());
+ MOCK_METHOD0(IsOnUnmeteredConnection, bool());
+};
+
+// TODO(jkrcal): Move into its own library to reuse in other unit-tests?
+class MockRemoteSuggestionsProvider : public RemoteSuggestionsProvider {
+ public:
+ MockRemoteSuggestionsProvider(Observer* observer)
+ : RemoteSuggestionsProvider(observer) {}
+ MOCK_METHOD1(RefetchInTheBackground,
+ void(const RemoteSuggestionsProvider::FetchStatusCallback&));
+ MOCK_CONST_METHOD0(suggestions_fetcher_for_debugging,
+ const RemoteSuggestionsFetcher*());
+ MOCK_CONST_METHOD1(GetUrlWithFavicon,
+ GURL(const ContentSuggestion::ID& suggestion_id));
+ MOCK_METHOD1(GetCategoryStatus, CategoryStatus(Category));
+ MOCK_METHOD1(GetCategoryInfo, CategoryInfo(Category));
+ MOCK_METHOD3(ClearHistory,
+ void(base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter));
+ MOCK_METHOD3(Fetch,
+ void(const Category&,
+ const std::set<std::string>&,
+ const FetchDoneCallback&));
+ MOCK_METHOD0(ReloadSuggestions, void());
+ MOCK_METHOD1(ClearCachedSuggestions, void(Category));
+ MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category));
+ MOCK_METHOD1(DismissSuggestion, void(const ContentSuggestion::ID&));
+ MOCK_METHOD2(FetchSuggestionImage,
+ void(const ContentSuggestion::ID&, const ImageFetchedCallback&));
+ MOCK_METHOD2(GetDismissedSuggestionsForDebugging,
+ void(Category, const DismissedSuggestionsCallback&));
+ MOCK_METHOD0(OnSignInStateChanged, void());
+};
+
+} // namespace
+
+class RemoteSuggestionsSchedulerImplTest : public ::testing::Test {
+ public:
+ RemoteSuggestionsSchedulerImplTest()
+ : // For the test we enabled all trigger types.
+ default_variation_params_{{"scheduler_trigger_types",
+ "persistent_scheduler_wake_up,ntp_opened,"
+ "browser_foregrounded,browser_cold_start"}},
+ params_manager_(ntp_snippets::kArticleSuggestionsFeature.name,
+ default_variation_params_,
+ {kArticleSuggestionsFeature.name}),
+ user_classifier_(/*pref_service=*/nullptr,
+ base::MakeUnique<base::DefaultClock>()) {
+ RemoteSuggestionsSchedulerImpl::RegisterProfilePrefs(
+ utils_.pref_service()->registry());
+ RequestThrottler::RegisterProfilePrefs(utils_.pref_service()->registry());
+ // TODO(jkrcal) Create a static function in EulaAcceptedNotifier that
+ // registers this pref and replace the call in browser_process_impl.cc & in
+ // eula_accepted_notifier_unittest.cc with the new static function.
+ local_state_.registry()->RegisterBooleanPref(::prefs::kEulaAccepted, false);
+ // By default pretend we are on WiFi.
+ EXPECT_CALL(*persistent_scheduler(), IsOnUnmeteredConnection())
+ .WillRepeatedly(Return(true));
+ ResetProvider();
+ }
+
+ void ResetProvider() {
+ provider_ = base::MakeUnique<StrictMock<MockRemoteSuggestionsProvider>>(
+ /*observer=*/nullptr);
+
+ auto test_clock = base::MakeUnique<base::SimpleTestClock>();
+ test_clock_ = test_clock.get();
+ test_clock_->SetNow(base::Time::Now());
+
+ scheduler_ = base::MakeUnique<RemoteSuggestionsSchedulerImpl>(
+ &persistent_scheduler_, &user_classifier_, utils_.pref_service(),
+ &local_state_, std::move(test_clock));
+ scheduler_->SetProvider(provider_.get());
+ }
+
+ void SetVariationParameter(const std::string& param_name,
+ const std::string& param_value) {
+ std::map<std::string, std::string> params = default_variation_params_;
+ params[param_name] = param_value;
+
+ params_manager_.ClearAllVariationParams();
+ params_manager_.SetVariationParamsWithFeatureAssociations(
+ ntp_snippets::kArticleSuggestionsFeature.name, params,
+ {ntp_snippets::kArticleSuggestionsFeature.name});
+ }
+
+ bool IsEulaNotifierAvailable() {
+ // Create() returns a unique_ptr, so this is no leak.
+ return web_resource::EulaAcceptedNotifier::Create(&local_state_) != nullptr;
+ }
+
+ void SetEulaAcceptedPref() {
+ local_state_.SetBoolean(::prefs::kEulaAccepted, true);
+ }
+
+ // GMock cannot deal with move-only types. We need to pass the vector to the
+ // mock function as const ref using this wrapper callback.
+ void FetchDoneWrapper(
+ MockFunction<void(Status status_code,
+ const std::vector<ContentSuggestion>& suggestions)>*
+ fetch_done,
+ Status status_code,
+ std::vector<ContentSuggestion> suggestions) {
+ fetch_done->Call(status_code, suggestions);
+ }
+
+ protected:
+ std::map<std::string, std::string> default_variation_params_;
+ variations::testing::VariationParamsManager params_manager_;
+
+ void ActivateProvider() {
+ SetEulaAcceptedPref();
+ scheduler_->OnProviderActivated();
+ }
+
+ void DeactivateProvider() { scheduler_->OnProviderDeactivated(); }
+
+ MockPersistentScheduler* persistent_scheduler() {
+ return &persistent_scheduler_;
+ }
+ base::SimpleTestClock* test_clock() { return test_clock_; }
+ MockRemoteSuggestionsProvider* provider() { return provider_.get(); }
+ RemoteSuggestionsSchedulerImpl* scheduler() { return scheduler_.get(); }
+
+ private:
+ test::RemoteSuggestionsTestUtils utils_;
+ UserClassifier user_classifier_;
+ TestingPrefServiceSimple local_state_;
+ StrictMock<MockPersistentScheduler> persistent_scheduler_;
+ base::SimpleTestClock* test_clock_;
+ std::unique_ptr<MockRemoteSuggestionsProvider> provider_;
+ std::unique_ptr<RemoteSuggestionsSchedulerImpl> scheduler_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsSchedulerImplTest);
+};
+
+TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldIgnoreSignalsWhenNotEnabled) {
+ scheduler()->OnPersistentSchedulerWakeUp();
+ scheduler()->OnNTPOpened();
+ scheduler()->OnBrowserForegrounded();
+ scheduler()->OnBrowserColdStart();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldIgnoreEulaStateOnPlatformsWhereNotAvaiable) {
+ // Only run this tests on platforms that don't support Eula.
+ if (IsEulaNotifierAvailable()) {
+ return;
+ }
+
+ // Activating the provider should schedule the persistent background fetches.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ scheduler()->OnProviderActivated();
+
+ // Verify fetches get triggered.
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ scheduler()->OnPersistentSchedulerWakeUp();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldIgnoreSignalsWhenEulaNotAccepted) {
+ // Only run this tests on platforms supporting Eula.
+ if (!IsEulaNotifierAvailable()) {
+ return;
+ }
+ // Activating the provider should schedule the persistent background fetches.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ scheduler()->OnProviderActivated();
+
+ // All signals are ignored because of Eula not being accepted.
+ scheduler()->OnPersistentSchedulerWakeUp();
+ scheduler()->OnNTPOpened();
+ scheduler()->OnBrowserForegrounded();
+ scheduler()->OnBrowserColdStart();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldFetchWhenEulaGetsAccepted) {
+ // Only run this tests on platforms supporting Eula.
+ if (!IsEulaNotifierAvailable()) {
+ return;
+ }
+ // Activating the provider should schedule the persistent background fetches.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ scheduler()->OnProviderActivated();
+
+ // Make one (ignored) call to make sure we are interested in eula state.
+ scheduler()->OnPersistentSchedulerWakeUp();
+
+ // Accepting Eula afterwards results in a background fetch.
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ SetEulaAcceptedPref();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldIgnoreSignalsWhenDisabledByParam) {
+ // First set an empty list of allowed trigger types.
+ SetVariationParameter("scheduler_trigger_types", "-");
+ ResetProvider();
+
+ // Then enable the scheduler.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ scheduler()->OnPersistentSchedulerWakeUp();
+ scheduler()->OnNTPOpened();
+ scheduler()->OnBrowserForegrounded();
+ scheduler()->OnBrowserColdStart();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldHandleEmptyParamForTriggerTypes) {
+ // First set an empty param for allowed trigger types -> should result in the
+ // default list.
+ SetVariationParameter("scheduler_trigger_types", "");
+ ResetProvider();
+
+ // Then enable the scheduler.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ // For instance, persistent scheduler wake up should be enabled by default.
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ scheduler()->OnPersistentSchedulerWakeUp();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldHandleIncorrentParamForTriggerTypes) {
+ // First set an invalid list of allowed trigger types.
+ SetVariationParameter("scheduler_trigger_types", "ntp_opened,foo;");
+ ResetProvider();
+
+ // Then enable the scheduler.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ // For instance, persistent scheduler wake up should be enabled by default.
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ scheduler()->OnPersistentSchedulerWakeUp();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldFetchOnPersistentSchedulerWakeUp) {
+ // First set only this type to be allowed.
+ SetVariationParameter("scheduler_trigger_types",
+ "persistent_scheduler_wake_up");
+ ResetProvider();
+
+ // Then enable the scheduler.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ scheduler()->OnPersistentSchedulerWakeUp();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldFetchOnPersistentSchedulerWakeUpRepeated) {
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
+ {
+ InSequence s;
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ .WillOnce(SaveArg<0>(&signal_fetch_done));
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ }
+ // First enable the scheduler -- calling Schedule() for the first time.
+ ActivateProvider();
+ // Make the first persistent fetch successful -- calling Schedule() again.
+ scheduler()->OnPersistentSchedulerWakeUp();
+ signal_fetch_done.Run(Status::Success());
+ // Make the second fetch.
+ scheduler()->OnPersistentSchedulerWakeUp();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldNotTriggerBackgroundFetchIfAlreadyInProgess) {
+ {
+ InSequence s;
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ // RefetchInTheBackground is not called after the second trigger.
+ }
+ // First enable the scheduler -- calling Schedule() for the first time.
+ ActivateProvider();
+ // Make the first persistent fetch never finish.
+ scheduler()->OnPersistentSchedulerWakeUp();
+ // Make the second fetch.
+ scheduler()->OnPersistentSchedulerWakeUp();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldFetchOnNTPOpenedForTheFirstTime) {
+ // First set only this type to be allowed.
+ SetVariationParameter("scheduler_trigger_types", "ntp_opened");
+ ResetProvider();
+
+ // Then enable the scheduler.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ scheduler()->OnNTPOpened();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldFetchOnBrowserForegroundedForTheFirstTime) {
+ // First set only this type to be allowed.
+ SetVariationParameter("scheduler_trigger_types", "browser_foregrounded");
+ ResetProvider();
+
+ // Then enable the scheduler.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ scheduler()->OnBrowserForegrounded();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldFetchOnBrowserColdStartForTheFirstTime) {
+ // First set only this type to be allowed.
+ SetVariationParameter("scheduler_trigger_types", "browser_cold_start");
+ ResetProvider();
+
+ // Then enable the scheduler.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ scheduler()->OnBrowserColdStart();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldNotFetchOnNTPOpenedAfterSuccessfulSoftFetch) {
+ // First enable the scheduler; the second Schedule is called after the
+ // successful fetch.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
+ ActivateProvider();
+
+ // Make the first soft fetch successful.
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ .WillOnce(SaveArg<0>(&signal_fetch_done));
+ scheduler()->OnNTPOpened();
+ signal_fetch_done.Run(Status::Success());
+ // The second call is ignored if it happens right after the first one.
+ scheduler()->OnNTPOpened();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldNotFetchOnNTPOpenedAfterSuccessfulPersistentFetch) {
+ // First enable the scheduler; the second Schedule is called after the
+ // successful fetch.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
+ ActivateProvider();
+
+ // Make the first persistent fetch successful.
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ .WillOnce(SaveArg<0>(&signal_fetch_done));
+ scheduler()->OnPersistentSchedulerWakeUp();
+ signal_fetch_done.Run(Status::Success());
+ // The second call is ignored if it happens right after the first one.
+ scheduler()->OnNTPOpened();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldNotFetchOnNTPOpenedAfterFailedSoftFetch) {
+ // First enable the scheduler.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ // Make the first soft fetch failed.
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ .WillOnce(SaveArg<0>(&signal_fetch_done));
+ scheduler()->OnNTPOpened();
+ signal_fetch_done.Run(Status(StatusCode::PERMANENT_ERROR, ""));
+
+ // The second call is ignored if it happens right after the first one.
+ scheduler()->OnNTPOpened();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldNotFetchOnNTPOpenedAfterFailedPersistentFetch) {
+ // First enable the scheduler.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ // Make the first persistent fetch failed.
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ .WillOnce(SaveArg<0>(&signal_fetch_done));
+ scheduler()->OnPersistentSchedulerWakeUp();
+ signal_fetch_done.Run(Status(StatusCode::PERMANENT_ERROR, ""));
+
+ // The second call is ignored if it happens right after the first one.
+ scheduler()->OnNTPOpened();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldFetchAgainOnBrowserForgroundLaterAgain) {
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
+ {
+ InSequence s;
+ // Initial scheduling after being enabled.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ // The first call to NTPOpened results in a fetch.
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ .WillOnce(SaveArg<0>(&signal_fetch_done));
+ // Rescheduling after a succesful fetch.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ // The second call to NTPOpened 4hrs later again results in a fetch.
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ }
+
+ // First enable the scheduler.
+ ActivateProvider();
+ // Make the first soft fetch successful.
+ scheduler()->OnBrowserForegrounded();
+ signal_fetch_done.Run(Status::Success());
+ // Open NTP again after 4hrs.
+ test_clock()->Advance(base::TimeDelta::FromHours(4));
+ scheduler()->OnBrowserForegrounded();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldRescheduleOnRescheduleFetching) {
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ scheduler()->RescheduleFetching();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldScheduleOnActivation) {
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldUnscheduleOnLaterInactivation) {
+ {
+ InSequence s;
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ EXPECT_CALL(*persistent_scheduler(), Unschedule());
+ }
+ ActivateProvider();
+ DeactivateProvider();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldScheduleOnLaterActivation) {
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ // There is no schedule yet, so inactivation does not trigger unschedule.
+ DeactivateProvider();
+ ActivateProvider();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldRescheduleAfterSuccessfulFetch) {
+ // First reschedule on becoming active.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
+ ActivateProvider();
+
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ .WillOnce(SaveArg<0>(&signal_fetch_done));
+
+ // Trigger a fetch.
+ scheduler()->OnPersistentSchedulerWakeUp();
+ // Second reschedule after a successful fetch.
+ signal_fetch_done.Run(Status::Success());
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldNotRescheduleAfterFailedFetch) {
+ // Only reschedule on becoming active.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ .WillOnce(SaveArg<0>(&signal_fetch_done));
+
+ // Trigger a fetch.
+ scheduler()->OnPersistentSchedulerWakeUp();
+ // No furter reschedule after a failure.
+ signal_fetch_done.Run(Status(StatusCode::PERMANENT_ERROR, ""));
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldScheduleOnlyOnce) {
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+ // No further call to Schedule on a second status callback.
+ ActivateProvider();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldUnscheduleOnlyOnce) {
+ {
+ InSequence s;
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ EXPECT_CALL(*persistent_scheduler(), Unschedule());
+ }
+ // First schedule so that later we really unschedule.
+ ActivateProvider();
+ DeactivateProvider();
+ // No further call to Unschedule on second status callback.
+ DeactivateProvider();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ReschedulesWhenPersistentWifiParamChanges) {
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
+ ActivateProvider();
+
+ // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
+ // null. Change the wifi interval for this class.
+ SetVariationParameter("fetching_interval_hours-wifi-active_ntp_user", "1.5");
+
+ // Schedule() should get called for the second time after params have changed.
+ ActivateProvider();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ReschedulesWhenPersistentFallbackParamChanges) {
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
+ ActivateProvider();
+
+ // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
+ // null. Change the fallback interval for this class.
+ SetVariationParameter("fetching_interval_hours-fallback-active_ntp_user",
+ "1.5");
+
+ // Schedule() should get called for the second time after params have changed.
+ ActivateProvider();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ReschedulesWhenSoftWifiParamChanges) {
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
+ ActivateProvider();
+
+ // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
+ // null. Change the on usage interval for this class.
+ SetVariationParameter("soft_fetching_interval_hours-wifi-active_ntp_user",
+ "1.5");
+
+ // Schedule() should get called for the second time after params have changed.
+ ActivateProvider();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ReschedulesWhenSoftFallbackParamChanges) {
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
+ ActivateProvider();
+
+ // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
+ // null. Change the fallback interval for this class.
+ SetVariationParameter("soft_fetching_interval_hours-fallback-active_ntp_user",
+ "1.5");
+
+ // Schedule() should get called for the second time after params have changed.
+ ActivateProvider();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest, FetchIntervalForSoftTriggerOnWifi) {
+ // Pretend we are on WiFi (already done in ctor, we make it explicit here).
+ EXPECT_CALL(*persistent_scheduler(), IsOnUnmeteredConnection())
+ .WillRepeatedly(Return(true));
+ // UserClassifier defaults to UserClass::ACTIVE_NTP_USER which uses a 3h time
+ // interval by default for soft background fetches on WiFi.
+
+ // Initial scheduling after being enabled.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ // The first call to NTPOpened results in a fetch.
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ .WillOnce(SaveArg<0>(&signal_fetch_done));
+ scheduler()->OnNTPOpened();
+ // Rescheduling after a succesful fetch.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ signal_fetch_done.Run(Status::Success());
+
+ // Open NTP again after too short delay. This time no fetch is executed.
+ test_clock()->Advance(base::TimeDelta::FromMinutes(30));
+ scheduler()->OnNTPOpened();
+
+ // Open NTP after another delay, now together long enough to issue a fetch.
+ test_clock()->Advance(base::TimeDelta::FromMinutes(150));
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ scheduler()->OnNTPOpened();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ OverrideFetchIntervalForSoftTriggerOnWifi) {
+ // Pretend we are on WiFi (already done in ctor, we make it explicit here).
+ EXPECT_CALL(*persistent_scheduler(), IsOnUnmeteredConnection())
+ .WillRepeatedly(Return(true));
+ // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
+ // null. Change the on usage interval for this class from 2h to 30min.
+ SetVariationParameter("soft_fetching_interval_hours-wifi-active_ntp_user",
+ "0.5");
+
+ // Initial scheduling after being enabled.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ // The first call to NTPOpened results in a fetch.
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ .WillOnce(SaveArg<0>(&signal_fetch_done));
+ scheduler()->OnNTPOpened();
+ // Rescheduling after a succesful fetch.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ signal_fetch_done.Run(Status::Success());
+
+ // Open NTP again after too short delay. This time no fetch is executed.
+ test_clock()->Advance(base::TimeDelta::FromMinutes(20));
+ scheduler()->OnNTPOpened();
+
+ // Open NTP after another delay, now together long enough to issue a fetch.
+ test_clock()->Advance(base::TimeDelta::FromMinutes(10));
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ scheduler()->OnNTPOpened();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ FetchIntervalForSoftTriggerOnFallback) {
+ // Pretend we are not on wifi -> fallback connection.
+ EXPECT_CALL(*persistent_scheduler(), IsOnUnmeteredConnection())
+ .WillRepeatedly(Return(false));
+ // UserClassifier defaults to UserClass::ACTIVE_NTP_USER which uses a 6h time
+ // interval by default for soft background fetches not on WiFi.
+
+ // Initial scheduling after being enabled.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ // The first call to NTPOpened results in a fetch.
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ .WillOnce(SaveArg<0>(&signal_fetch_done));
+ scheduler()->OnNTPOpened();
+ // Rescheduling after a succesful fetch.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ signal_fetch_done.Run(Status::Success());
+
+ // Open NTP again after too short delay. This time no fetch is executed.
+ test_clock()->Advance(base::TimeDelta::FromMinutes(300));
+ scheduler()->OnNTPOpened();
+
+ // Open NTP after another delay, now together long enough to issue a fetch.
+ test_clock()->Advance(base::TimeDelta::FromMinutes(60));
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ scheduler()->OnNTPOpened();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ OverrideFetchIntervalForSoftTriggerOnFallback) {
+ // Pretend we are not on wifi -> fallback connection.
+ EXPECT_CALL(*persistent_scheduler(), IsOnUnmeteredConnection())
+ .WillRepeatedly(Return(false));
+ // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
+ // null. Change the on usage interval for this class from 4h to 30min.
+ SetVariationParameter("soft_fetching_interval_hours-fallback-active_ntp_user",
+ "0.5");
+
+ // Initial scheduling after being enabled.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ // The first call to NTPOpened results in a fetch.
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ .WillOnce(SaveArg<0>(&signal_fetch_done));
+ scheduler()->OnNTPOpened();
+ // Rescheduling after a succesful fetch.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ signal_fetch_done.Run(Status::Success());
+
+ // Open NTP again after too short delay. This time no fetch is executed.
+ test_clock()->Advance(base::TimeDelta::FromMinutes(20));
+ scheduler()->OnNTPOpened();
+
+ // Open NTP after another delay, now together long enough to issue a fetch.
+ test_clock()->Advance(base::TimeDelta::FromMinutes(10));
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ scheduler()->OnNTPOpened();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldBlockFetchingForSomeTimeAfterHistoryCleared) {
+ // First enable the scheduler -- this will trigger the persistent scheduling.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+ // Clear the history.
+ scheduler()->OnHistoryCleared();
+
+ // A trigger after 15 minutes is ignored.
+ test_clock()->Advance(base::TimeDelta::FromMinutes(15));
+ scheduler()->OnBrowserForegrounded();
+
+ // A trigger after another 16 minutes is performed (more than 30m after
+ // clearing the history).
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ test_clock()->Advance(base::TimeDelta::FromMinutes(16));
+ scheduler()->OnBrowserForegrounded();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldImmediatelyFetchAfterSuggestionsCleared) {
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
+
+ // First enable the scheduler -- this will trigger the persistent scheduling.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ActivateProvider();
+
+ // The first trigger results in a fetch.
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ .WillOnce(SaveArg<0>(&signal_fetch_done));
+ scheduler()->OnBrowserForegrounded();
+ // Make the fetch successful -- this results in rescheduling.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ signal_fetch_done.Run(Status::Success());
+
+ // Clear the suggestions - results in an immediate fetch.
+ EXPECT_CALL(*provider(), ReloadSuggestions());
+ scheduler()->OnSuggestionsCleared();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldThrottleInteractiveRequests) {
+ // Change the quota for interactive requests ("active NTP user" is the default
+ // class in tests).
+ SetVariationParameter("interactive_quota_SuggestionFetcherActiveNTPUser",
+ "10");
+ ResetProvider();
+
+ for (int x = 0; x < 10; ++x) {
+ EXPECT_THAT(scheduler()->AcquireQuotaForInteractiveFetch(), Eq(true));
+ }
+
+ // Now the quota is over.
+ EXPECT_THAT(scheduler()->AcquireQuotaForInteractiveFetch(), Eq(false));
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldThrottleNonInteractiveRequests) {
+ // Change the quota for interactive requests ("active NTP user" is the default
+ // class in tests).
+ SetVariationParameter("quota_SuggestionFetcherActiveNTPUser", "5");
+ ResetProvider();
+
+ // One scheduling on start, 5 times after successful fetches.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(6);
+
+ // First enable the scheduler -- this will trigger the persistent scheduling.
+ ActivateProvider();
+
+ // As long as the quota suffices, the call gets through.
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
+ EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ .Times(5)
+ .WillRepeatedly(SaveArg<0>(&signal_fetch_done));
+ for (int x = 0; x < 5; ++x) {
+ scheduler()->OnPersistentSchedulerWakeUp();
+ signal_fetch_done.Run(Status::Success());
+ }
+
+ // For the 6th time, it is blocked by the scheduling provider.
+ scheduler()->OnPersistentSchedulerWakeUp();
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.cc
index 525dbbdbc1a..f035bba4f57 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.cc
@@ -6,6 +6,7 @@
#include <string>
+#include "components/ntp_snippets/content_suggestions_metrics.h"
#include "components/ntp_snippets/features.h"
#include "components/ntp_snippets/pref_names.h"
#include "components/prefs/pref_registry_simple.h"
@@ -17,10 +18,15 @@ namespace ntp_snippets {
RemoteSuggestionsStatusService::RemoteSuggestionsStatusService(
SigninManagerBase* signin_manager,
- PrefService* pref_service)
+ PrefService* pref_service,
+ const std::string& additional_toggle_pref)
: status_(RemoteSuggestionsStatus::EXPLICITLY_DISABLED),
+ additional_toggle_pref_(additional_toggle_pref),
signin_manager_(signin_manager),
- pref_service_(pref_service) {}
+ pref_service_(pref_service) {
+ ntp_snippets::metrics::RecordRemoteSuggestionsProviderState(
+ !IsExplicitlyDisabled());
+}
RemoteSuggestionsStatusService::~RemoteSuggestionsStatusService() = default;
@@ -47,6 +53,13 @@ void RemoteSuggestionsStatusService::Init(
prefs::kEnableSnippets,
base::Bind(&RemoteSuggestionsStatusService::OnSnippetsEnabledChanged,
base::Unretained(this)));
+
+ if (!additional_toggle_pref_.empty()) {
+ pref_change_registrar_.Add(
+ additional_toggle_pref_,
+ base::Bind(&RemoteSuggestionsStatusService::OnSnippetsEnabledChanged,
+ base::Unretained(this)));
+ }
}
void RemoteSuggestionsStatusService::OnSnippetsEnabledChanged() {
@@ -73,10 +86,25 @@ void RemoteSuggestionsStatusService::OnSignInStateChanged() {
OnStateChanged(GetStatusFromDeps());
}
-RemoteSuggestionsStatus RemoteSuggestionsStatusService::GetStatusFromDeps()
- const {
+bool RemoteSuggestionsStatusService::IsExplicitlyDisabled() const {
if (!pref_service_->GetBoolean(prefs::kEnableSnippets)) {
DVLOG(1) << "[GetStatusFromDeps] Disabled via pref";
+ return true;
+ }
+
+ if (!additional_toggle_pref_.empty()) {
+ if (!pref_service_->GetBoolean(additional_toggle_pref_)) {
+ DVLOG(1) << "[GetStatusFromDeps] Disabled via additional pref";
+ return true;
+ }
+ }
+
+ return false;
+}
+
+RemoteSuggestionsStatus RemoteSuggestionsStatusService::GetStatusFromDeps()
+ const {
+ if (IsExplicitlyDisabled()) {
return RemoteSuggestionsStatus::EXPLICITLY_DISABLED;
}
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.h b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.h
index 4d1a1cbfb6b..f37187ee0fe 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.h
@@ -34,7 +34,8 @@ class RemoteSuggestionsStatusService {
RemoteSuggestionsStatus new_status)>;
RemoteSuggestionsStatusService(SigninManagerBase* signin_manager,
- PrefService* pref_service);
+ PrefService* pref_service,
+ const std::string& additional_toggle_pref);
virtual ~RemoteSuggestionsStatusService();
@@ -64,11 +65,19 @@ class RemoteSuggestionsStatusService {
bool IsSignedIn() const;
+ // Returns whether the service is explicitly disabled, by the user or by a
+ // policy for example.
+ bool IsExplicitlyDisabled() const;
+
RemoteSuggestionsStatus GetStatusFromDeps() const;
RemoteSuggestionsStatus status_;
StatusChangeCallback status_change_callback_;
+ // Name of a preference to be used as an additional toggle to guard the
+ // remote suggestions provider.
+ std::string additional_toggle_pref_;
+
SigninManagerBase* signin_manager_;
PrefService* pref_service_;
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_unittest.cc
index 6b6fd7a5900..dcfc9b83e67 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_unittest.cc
@@ -32,7 +32,7 @@ class RemoteSuggestionsStatusServiceTest : public ::testing::Test {
std::unique_ptr<RemoteSuggestionsStatusService> MakeService() {
return base::MakeUnique<RemoteSuggestionsStatusService>(
- utils_.fake_signin_manager(), utils_.pref_service());
+ utils_.fake_signin_manager(), utils_.pref_service(), std::string());
}
protected:
diff --git a/chromium/components/ntp_snippets/remote/request_throttler.cc b/chromium/components/ntp_snippets/remote/request_throttler.cc
index bba80a2ce1c..efe56366ed9 100644
--- a/chromium/components/ntp_snippets/remote/request_throttler.cc
+++ b/chromium/components/ntp_snippets/remote/request_throttler.cc
@@ -41,12 +41,12 @@ const int kUnlimitedQuota = INT_MAX;
} // namespace
struct RequestThrottler::RequestTypeInfo {
- const char* name;
- const char* count_pref;
- const char* interactive_count_pref;
- const char* day_pref;
- const int default_quota;
- const int default_interactive_quota;
+ const char* name;
+ const char* count_pref;
+ const char* interactive_count_pref;
+ const char* day_pref;
+ const int default_quota;
+ const int default_interactive_quota;
};
// When adding a new type here, extend also the "RequestThrottlerTypes"
@@ -82,8 +82,7 @@ RequestThrottler::RequestThrottler(PrefService* pref_service, RequestType type)
base::StringPrintf("quota_%s", GetRequestTypeName()));
if (!base::StringToInt(quota, &quota_)) {
LOG_IF(WARNING, !quota.empty())
- << "Invalid variation parameter for quota for "
- << GetRequestTypeName();
+ << "Invalid variation parameter for quota for " << GetRequestTypeName();
quota_ = type_info_.default_quota;
}
diff --git a/chromium/components/ntp_snippets/remote/scheduling_remote_suggestions_provider.h b/chromium/components/ntp_snippets/remote/scheduling_remote_suggestions_provider.h
deleted file mode 100644
index 32f19641341..00000000000
--- a/chromium/components/ntp_snippets/remote/scheduling_remote_suggestions_provider.h
+++ /dev/null
@@ -1,212 +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_NTP_SNIPPETS_REMOTE_SCHEDULING_REMOTE_SUGGESTIONS_PROVIDER_H_
-#define COMPONENTS_NTP_SNIPPETS_REMOTE_SCHEDULING_REMOTE_SUGGESTIONS_PROVIDER_H_
-
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "components/ntp_snippets/content_suggestions_provider.h"
-#include "components/ntp_snippets/remote/persistent_scheduler.h"
-#include "components/ntp_snippets/remote/remote_suggestions_provider.h"
-#include "components/ntp_snippets/remote/remote_suggestions_scheduler.h"
-#include "components/ntp_snippets/remote/request_throttler.h"
-
-class PrefRegistrySimple;
-class PrefService;
-
-namespace base {
-class Clock;
-}
-
-namespace ntp_snippets {
-
-struct Status;
-class UserClassifier;
-
-// A wrapper around RemoteSuggestionsProvider that introduces periodic fetching.
-//
-// The class initiates fetches on its own in these situations:
-// - initial fetch when the provider is constructed and we have no suggestions;
-// - regular fetches according to its schedule.
-// TODO(jkrcal): After soft fetch on Chrome startup is introduced, remove
-// the initial fetch completely.
-//
-// The class also needs to understand when last fetch trials and successful
-// fetches happen and thus it intercepts following interactive fetch requests:
-// - Fetch() - after "More" button of a remote section is pressed in the UI;
-// TODO(jkrcal): Clarify what Fetch() should do for this provider and maybe stop
-// intercepting it.
-// TODO(jkrcal): Intercept also ReloadSuggestions() call (after the user swipes
-// away everything incl. all empty sections and presses "More"); Not done in the
-// first shot because it implements a public interface function without any
-// callback.
-// This class is final because it does things in its constructor which make it
-// unsafe to derive from it.
-// TODO(jkrcal): Introduce two-phase initialization and make the class not
-// final? (see the same comment for RemoteSuggestionsProvider)
-// TODO(jkrcal): Change the interface to ContentSuggestionsProvider. We do not
-// need any special functionality, all special should be exposed in the
-// Scheduler interface. crbug.com/695447
-class SchedulingRemoteSuggestionsProvider final
- : public RemoteSuggestionsProvider,
- public RemoteSuggestionsScheduler {
- public:
- SchedulingRemoteSuggestionsProvider(
- Observer* observer,
- std::unique_ptr<RemoteSuggestionsProvider> provider,
- PersistentScheduler* persistent_scheduler,
- const UserClassifier* user_classifier,
- PrefService* pref_service,
- std::unique_ptr<base::Clock> clock);
-
- ~SchedulingRemoteSuggestionsProvider() override;
-
- static void RegisterProfilePrefs(PrefRegistrySimple* registry);
-
- // RemoteSuggestionsScheduler implementation.
- void OnProviderActivated() override;
- void OnProviderDeactivated() override;
- void OnSuggestionsCleared() override;
- void OnHistoryCleared() override;
- void RescheduleFetching() override;
- void OnPersistentSchedulerWakeUp() override;
- void OnBrowserForegrounded() override;
- void OnBrowserColdStart() override;
- void OnNTPOpened() override;
-
- // RemoteSuggestionsProvider implementation.
- void RefetchInTheBackground(
- std::unique_ptr<FetchStatusCallback> callback) override;
- const RemoteSuggestionsFetcher* suggestions_fetcher_for_debugging()
- const override;
-
- // ContentSuggestionsProvider implementation.
- CategoryStatus GetCategoryStatus(Category category) override;
- CategoryInfo GetCategoryInfo(Category category) override;
- void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
- void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) override;
- void Fetch(const Category& category,
- const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) override;
- void ReloadSuggestions() override;
- void ClearHistory(
- base::Time begin,
- base::Time end,
- const base::Callback<bool(const GURL& url)>& filter) override;
- void ClearCachedSuggestions(Category category) override;
- void OnSignInStateChanged() override;
- void GetDismissedSuggestionsForDebugging(
- Category category,
- const DismissedSuggestionsCallback& callback) override;
- void ClearDismissedSuggestionsForDebugging(Category category) override;
-
- private:
- // Abstract description of the fetching schedule.
- struct FetchingSchedule {
- static FetchingSchedule Empty();
- bool operator==(const FetchingSchedule& other) const;
- bool operator!=(const FetchingSchedule& other) const;
- bool is_empty() const;
-
- base::TimeDelta interval_persistent_wifi;
- base::TimeDelta interval_persistent_fallback;
- base::TimeDelta interval_soft_on_usage_event;
- base::TimeDelta interval_soft_on_ntp_opened;
- };
-
- enum class TriggerType;
-
- // After the call, updates will be scheduled in the future. Idempotent, can be
- // run any time later without impacting the current schedule.
- // If you want to enforce rescheduling, call Unschedule() and then Schedule().
- void StartScheduling();
-
- // After the call, no updates will happen before another call to Schedule().
- // Idempotent, can be run any time later without impacting the current
- // schedule.
- void StopScheduling();
-
- // Trigger a background refetch for the given |trigger| if enabled.
- void RefetchInTheBackgroundIfEnabled(TriggerType trigger);
-
- // Checks whether it is time to perform a soft background fetch, according to
- // |schedule|.
- bool ShouldRefetchInTheBackgroundNow(TriggerType trigger);
-
- // Returns whether background fetching (for the given |trigger|) is disabled.
- bool BackgroundFetchesDisabled(TriggerType trigger) const;
-
- // Returns true if quota is available for another request.
- bool AcquireQuota(bool interactive_request);
-
- // Callback after Fetch is completed.
- void FetchFinished(const FetchDoneCallback& callback,
- Status fetch_status,
- std::vector<ContentSuggestion> suggestions);
-
- // Callback after RefetchInTheBackground is completed.
- void RefetchInTheBackgroundFinished(
- std::unique_ptr<FetchStatusCallback> callback,
- Status fetch_status);
-
- // Common function to call after a fetch of any type is finished.
- void OnFetchCompleted(Status fetch_status);
-
- // Clears the time of the last fetch so that the provider is ready to make a
- // soft fetch at any later time (upon a trigger).
- void ClearLastFetchAttemptTime();
-
- FetchingSchedule GetDesiredFetchingSchedule() const;
-
- // Load and store |schedule_|.
- void LoadLastFetchingSchedule();
- void StoreFetchingSchedule();
-
- // Applies the persistent schedule given by |schedule_|.
- void ApplyPersistentFetchingSchedule();
-
- // Gets enabled trigger types from the variation parameter.
- std::set<TriggerType> GetEnabledTriggerTypes();
-
- // Gets trigger types enabled by default.
- std::set<TriggerType> GetDefaultEnabledTriggerTypes();
-
- // Interface for doing all the actual work (apart from scheduling).
- std::unique_ptr<RemoteSuggestionsProvider> provider_;
-
- // Interface for scheduling hard fetches, OS dependent. Not owned, may be
- // null.
- PersistentScheduler* persistent_scheduler_;
-
- FetchingSchedule schedule_;
- bool background_fetch_in_progress_;
-
- // Used to adapt the schedule based on usage activity of the user. Not owned.
- const UserClassifier* user_classifier_;
-
- // Request throttlers for limiting requests for different classes of users.
- RequestThrottler request_throttler_rare_ntp_user_;
- RequestThrottler request_throttler_active_ntp_user_;
- RequestThrottler request_throttler_active_suggestions_consumer_;
-
- PrefService* pref_service_;
- std::unique_ptr<base::Clock> clock_;
- std::set<SchedulingRemoteSuggestionsProvider::TriggerType> enabled_triggers_;
-
- base::Time background_fetches_allowed_after_;
-
- DISALLOW_COPY_AND_ASSIGN(SchedulingRemoteSuggestionsProvider);
-};
-
-} // namespace ntp_snippets
-
-#endif // COMPONENTS_NTP_SNIPPETS_REMOTE_SCHEDULING_REMOTE_SUGGESTIONS_PROVIDER_H_
diff --git a/chromium/components/ntp_snippets/remote/scheduling_remote_suggestions_provider_unittest.cc b/chromium/components/ntp_snippets/remote/scheduling_remote_suggestions_provider_unittest.cc
deleted file mode 100644
index b5ae799498a..00000000000
--- a/chromium/components/ntp_snippets/remote/scheduling_remote_suggestions_provider_unittest.cc
+++ /dev/null
@@ -1,768 +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/ntp_snippets/remote/scheduling_remote_suggestions_provider.h"
-
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/command_line.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/test/simple_test_clock.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/clock.h"
-#include "base/time/time.h"
-#include "components/ntp_snippets/features.h"
-#include "components/ntp_snippets/ntp_snippets_constants.h"
-#include "components/ntp_snippets/pref_names.h"
-#include "components/ntp_snippets/remote/persistent_scheduler.h"
-#include "components/ntp_snippets/remote/remote_suggestions_provider.h"
-#include "components/ntp_snippets/remote/test_utils.h"
-#include "components/ntp_snippets/status.h"
-#include "components/ntp_snippets/user_classifier.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/variations/variations_params_manager.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::ElementsAre;
-using testing::Eq;
-using testing::Field;
-using testing::InSequence;
-using testing::Invoke;
-using testing::IsEmpty;
-using testing::Mock;
-using testing::MockFunction;
-using testing::Not;
-using testing::Return;
-using testing::SaveArg;
-using testing::SaveArgPointee;
-using testing::SizeIs;
-using testing::StartsWith;
-using testing::StrictMock;
-using testing::WithArgs;
-using testing::_;
-
-namespace ntp_snippets {
-
-class RemoteSuggestionsFetcher;
-
-namespace {
-
-class MockPersistentScheduler : public PersistentScheduler {
- public:
- MOCK_METHOD2(Schedule,
- bool(base::TimeDelta period_wifi,
- base::TimeDelta period_fallback));
- MOCK_METHOD0(Unschedule, bool());
-};
-
-// TODO(jkrcal): Move into its own library to reuse in other unit-tests?
-class MockRemoteSuggestionsProvider : public RemoteSuggestionsProvider {
- public:
- MockRemoteSuggestionsProvider(Observer* observer)
- : RemoteSuggestionsProvider(observer) {}
-
- MOCK_METHOD1(SetRemoteSuggestionsScheduler,
- void(RemoteSuggestionsScheduler*));
-
- // Move-only params are not supported by GMock. We want to mock out
- // RefetchInTheBackground() which takes a unique_ptr<>. Instead, we add a new
- // mock function which takes a copy of the callback and override the
- // RemoteSuggestionsProvider's method to forward the call into the new mock
- // function.
- void RefetchInTheBackground(
- std::unique_ptr<RemoteSuggestionsProvider::FetchStatusCallback> callback)
- override {
- RefetchInTheBackground(*callback);
- }
- MOCK_METHOD1(RefetchInTheBackground,
- void(RemoteSuggestionsProvider::FetchStatusCallback));
-
- MOCK_CONST_METHOD0(suggestions_fetcher_for_debugging,
- const RemoteSuggestionsFetcher*());
-
- MOCK_METHOD1(GetCategoryStatus, CategoryStatus(Category));
- MOCK_METHOD1(GetCategoryInfo, CategoryInfo(Category));
- MOCK_METHOD3(ClearHistory,
- void(base::Time begin,
- base::Time end,
- const base::Callback<bool(const GURL& url)>& filter));
- MOCK_METHOD3(Fetch,
- void(const Category&,
- const std::set<std::string>&,
- const FetchDoneCallback&));
- MOCK_METHOD0(ReloadSuggestions, void());
- MOCK_METHOD1(ClearCachedSuggestions, void(Category));
- MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category));
- MOCK_METHOD1(DismissSuggestion, void(const ContentSuggestion::ID&));
- MOCK_METHOD2(FetchSuggestionImage,
- void(const ContentSuggestion::ID&, const ImageFetchedCallback&));
- MOCK_METHOD2(GetDismissedSuggestionsForDebugging,
- void(Category, const DismissedSuggestionsCallback&));
- MOCK_METHOD0(OnSignInStateChanged, void());
-};
-
-} // namespace
-
-class SchedulingRemoteSuggestionsProviderTest
- : public ::testing::Test {
- public:
- SchedulingRemoteSuggestionsProviderTest()
- : // For the test we enabled all trigger types.
- default_variation_params_{{"scheduler_trigger_types",
- "persistent_scheduler_wake_up,ntp_opened,"
- "browser_foregrounded,browser_cold_start"}},
- params_manager_(ntp_snippets::kStudyName,
- default_variation_params_,
- {kArticleSuggestionsFeature.name}),
- underlying_provider_(nullptr),
- scheduling_provider_(nullptr),
- user_classifier_(/*pref_service=*/nullptr) {
- SchedulingRemoteSuggestionsProvider::RegisterProfilePrefs(
- utils_.pref_service()->registry());
- RequestThrottler::RegisterProfilePrefs(utils_.pref_service()->registry());
- ResetProvider();
- }
-
- void ResetProvider() {
- auto underlying_provider =
- base::MakeUnique<StrictMock<MockRemoteSuggestionsProvider>>(
- /*observer=*/nullptr);
- underlying_provider_ = underlying_provider.get();
-
- auto test_clock = base::MakeUnique<base::SimpleTestClock>();
- test_clock_ = test_clock.get();
- test_clock_->SetNow(base::Time::Now());
-
- scheduling_provider_ =
- base::MakeUnique<SchedulingRemoteSuggestionsProvider>(
- /*observer=*/nullptr, std::move(underlying_provider),
- &persistent_scheduler_, &user_classifier_, utils_.pref_service(),
- std::move(test_clock));
- }
-
- void SetVariationParameter(const std::string& param_name,
- const std::string& param_value) {
- std::map<std::string, std::string> params = default_variation_params_;
- params[param_name] = param_value;
-
- params_manager_.ClearAllVariationParams();
- params_manager_.SetVariationParamsWithFeatureAssociations(
- ntp_snippets::kStudyName, params,
- {ntp_snippets::kArticleSuggestionsFeature.name});
- }
-
- // GMock cannot deal with move-only types. We need to pass the vector to the
- // mock function as const ref using this wrapper callback.
- void FetchDoneWrapper(
- MockFunction<void(Status status_code,
- const std::vector<ContentSuggestion>& suggestions)>*
- fetch_done,
- Status status_code,
- std::vector<ContentSuggestion> suggestions) {
- fetch_done->Call(status_code, suggestions);
- }
-
- protected:
- std::map<std::string, std::string> default_variation_params_;
- variations::testing::VariationParamsManager params_manager_;
- StrictMock<MockPersistentScheduler> persistent_scheduler_;
- StrictMock<MockRemoteSuggestionsProvider>* underlying_provider_;
- std::unique_ptr<SchedulingRemoteSuggestionsProvider> scheduling_provider_;
- base::SimpleTestClock* test_clock_;
-
- void ActivateUnderlyingProvider() {
- scheduling_provider_->OnProviderActivated();
- }
-
- void InactivateUnderlyingProvider() {
- scheduling_provider_->OnProviderDeactivated();
- }
-
- private:
- test::RemoteSuggestionsTestUtils utils_;
- UserClassifier user_classifier_;
-
- DISALLOW_COPY_AND_ASSIGN(SchedulingRemoteSuggestionsProviderTest);
-};
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldIgnoreSignalsWhenNotEnabled) {
- scheduling_provider_->OnPersistentSchedulerWakeUp();
- scheduling_provider_->OnNTPOpened();
- scheduling_provider_->OnBrowserForegrounded();
- scheduling_provider_->OnBrowserColdStart();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldIgnoreSignalsWhenDisabledByParam) {
- // First set an empty list of allowed trigger types.
- SetVariationParameter("scheduler_trigger_types", "-");
- ResetProvider();
-
- // Then enable the scheduler.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- ActivateUnderlyingProvider();
-
- scheduling_provider_->OnPersistentSchedulerWakeUp();
- scheduling_provider_->OnNTPOpened();
- scheduling_provider_->OnBrowserForegrounded();
- scheduling_provider_->OnBrowserColdStart();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldHandleEmptyParamForTriggerTypes) {
- // First set an empty param for allowed trigger types -> should result in the
- // default list.
- SetVariationParameter("scheduler_trigger_types", "");
- ResetProvider();
-
- // Then enable the scheduler.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- ActivateUnderlyingProvider();
-
- // For instance, persistent scheduler wake up should be enabled by default.
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
- scheduling_provider_->OnPersistentSchedulerWakeUp();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldHandleIncorrentParamForTriggerTypes) {
- // First set an invalid list of allowed trigger types.
- SetVariationParameter("scheduler_trigger_types", "ntp_opened,foo;");
- ResetProvider();
-
- // Then enable the scheduler.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- ActivateUnderlyingProvider();
-
- // For instance, persistent scheduler wake up should be enabled by default.
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
- scheduling_provider_->OnPersistentSchedulerWakeUp();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldFetchOnPersistentSchedulerWakeUp) {
- // First set only this type to be allowed.
- SetVariationParameter("scheduler_trigger_types",
- "persistent_scheduler_wake_up");
- ResetProvider();
-
- // Then enable the scheduler.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- ActivateUnderlyingProvider();
-
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
- scheduling_provider_->OnPersistentSchedulerWakeUp();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldFetchOnPersistentSchedulerWakeUpRepeated) {
- RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- {
- InSequence s;
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
- }
- // First enable the scheduler -- calling Schedule() for the first time.
- ActivateUnderlyingProvider();
- // Make the first persistent fetch successful -- calling Schedule() again.
- scheduling_provider_->OnPersistentSchedulerWakeUp();
- signal_fetch_done.Run(Status::Success());
- // Make the second fetch.
- scheduling_provider_->OnPersistentSchedulerWakeUp();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldNotTriggerBackgroundFetchIfAlreadyInProgess) {
- {
- InSequence s;
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
- // RefetchInTheBackground is not called after the second trigger.
- }
- // First enable the scheduler -- calling Schedule() for the first time.
- ActivateUnderlyingProvider();
- // Make the first persistent fetch never finish.
- scheduling_provider_->OnPersistentSchedulerWakeUp();
- // Make the second fetch.
- scheduling_provider_->OnPersistentSchedulerWakeUp();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldFetchOnNTPOpenedForTheFirstTime) {
- // First set only this type to be allowed.
- SetVariationParameter("scheduler_trigger_types", "ntp_opened");
- ResetProvider();
-
- // Then enable the scheduler.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- ActivateUnderlyingProvider();
-
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
- scheduling_provider_->OnNTPOpened();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldFetchOnBrowserForegroundedForTheFirstTime) {
- // First set only this type to be allowed.
- SetVariationParameter("scheduler_trigger_types", "browser_foregrounded");
- ResetProvider();
-
- // Then enable the scheduler.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- ActivateUnderlyingProvider();
-
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
- scheduling_provider_->OnBrowserForegrounded();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldFetchOnBrowserColdStartForTheFirstTime) {
- // First set only this type to be allowed.
- SetVariationParameter("scheduler_trigger_types", "browser_cold_start");
- ResetProvider();
-
- // Then enable the scheduler.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- ActivateUnderlyingProvider();
-
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
- scheduling_provider_->OnBrowserColdStart();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldNotFetchOnNTPOpenedAfterSuccessfulSoftFetch) {
- // First enable the scheduler; the second Schedule is called after the
- // successful fetch.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(2);
- ActivateUnderlyingProvider();
-
- // Make the first soft fetch successful.
- RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
- scheduling_provider_->OnNTPOpened();
- signal_fetch_done.Run(Status::Success());
- // The second call is ignored if it happens right after the first one.
- scheduling_provider_->OnNTPOpened();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldNotFetchOnNTPOpenedAfterSuccessfulPersistentFetch) {
- // First enable the scheduler; the second Schedule is called after the
- // successful fetch.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(2);
- ActivateUnderlyingProvider();
-
- // Make the first persistent fetch successful.
- RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
- scheduling_provider_->OnPersistentSchedulerWakeUp();
- signal_fetch_done.Run(Status::Success());
- // The second call is ignored if it happens right after the first one.
- scheduling_provider_->OnNTPOpened();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldNotFetchOnNTPOpenedAfterFailedSoftFetch) {
- // First enable the scheduler.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- ActivateUnderlyingProvider();
-
- // Make the first soft fetch failed.
- RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
- scheduling_provider_->OnNTPOpened();
- signal_fetch_done.Run(Status(StatusCode::PERMANENT_ERROR, ""));
-
- // The second call is ignored if it happens right after the first one.
- scheduling_provider_->OnNTPOpened();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldNotFetchOnNTPOpenedAfterFailedPersistentFetch) {
- // First enable the scheduler.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- ActivateUnderlyingProvider();
-
- // Make the first persistent fetch failed.
- RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
- scheduling_provider_->OnPersistentSchedulerWakeUp();
- signal_fetch_done.Run(Status(StatusCode::PERMANENT_ERROR, ""));
-
- // The second call is ignored if it happens right after the first one.
- scheduling_provider_->OnNTPOpened();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldFetchAgainOnBrowserForgroundLaterAgain) {
- RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- {
- InSequence s;
- // Initial scheduling after being enabled.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- // The first call to NTPOpened results in a fetch.
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
- // Rescheduling after a succesful fetch.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- // The second call to NTPOpened 2hrs later again results in a fetch.
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
- }
-
- // First enable the scheduler.
- ActivateUnderlyingProvider();
- // Make the first soft fetch successful.
- scheduling_provider_->OnBrowserForegrounded();
- signal_fetch_done.Run(Status::Success());
- // Open NTP again after 2hrs.
- test_clock_->Advance(base::TimeDelta::FromHours(2));
- scheduling_provider_->OnBrowserForegrounded();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldRescheduleOnRescheduleFetching) {
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- scheduling_provider_->RescheduleFetching();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest, ShouldScheduleOnActivation) {
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- ActivateUnderlyingProvider();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldUnscheduleOnLaterInactivation) {
- {
- InSequence s;
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- EXPECT_CALL(persistent_scheduler_, Unschedule());
- }
- ActivateUnderlyingProvider();
- InactivateUnderlyingProvider();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldScheduleOnLaterActivation) {
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- // There is no schedule yet, so inactivation does not trigger unschedule.
- InactivateUnderlyingProvider();
- ActivateUnderlyingProvider();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldRescheduleAfterSuccessfulFetch) {
- // First reschedule on becoming active.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(2);
- ActivateUnderlyingProvider();
-
- RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
-
- // Trigger a fetch.
- scheduling_provider_->OnPersistentSchedulerWakeUp();
- // Second reschedule after a successful fetch.
- signal_fetch_done.Run(Status::Success());
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldNotRescheduleAfterFailedFetch) {
- // Only reschedule on becoming active.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- ActivateUnderlyingProvider();
-
- RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
-
- // Trigger a fetch.
- scheduling_provider_->OnPersistentSchedulerWakeUp();
- // No furter reschedule after a failure.
- signal_fetch_done.Run(Status(StatusCode::PERMANENT_ERROR, ""));
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest, ShouldScheduleOnlyOnce) {
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- ActivateUnderlyingProvider();
- // No further call to Schedule on a second status callback.
- ActivateUnderlyingProvider();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest, ShouldUnscheduleOnlyOnce) {
- {
- InSequence s;
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- EXPECT_CALL(persistent_scheduler_, Unschedule());
- }
- // First schedule so that later we really unschedule.
- ActivateUnderlyingProvider();
- InactivateUnderlyingProvider();
- // No further call to Unschedule on second status callback.
- InactivateUnderlyingProvider();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ReschedulesWhenWifiParamChanges) {
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(2);
- ActivateUnderlyingProvider();
-
- // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
- // null. Change the wifi interval for this class.
- SetVariationParameter("fetching_interval_hours-wifi-active_ntp_user", "1.5");
-
- // Schedule() should get called for the second time after params have changed.
- ActivateUnderlyingProvider();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ReschedulesWhenFallbackParamChanges) {
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(2);
- ActivateUnderlyingProvider();
-
- // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
- // null. Change the fallback interval for this class.
- SetVariationParameter("fetching_interval_hours-fallback-active_ntp_user",
- "1.5");
-
- // Schedule() should get called for the second time after params have changed.
- ActivateUnderlyingProvider();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ReschedulesWhenOnUsageEventParamChanges) {
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(2);
- ActivateUnderlyingProvider();
-
- // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
- // null. Change the on usage interval for this class.
- SetVariationParameter("soft_fetching_interval_hours-active-active_ntp_user",
- "1.5");
-
- // Schedule() should get called for the second time after params have changed.
- ActivateUnderlyingProvider();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ReschedulesWhenOnNtpOpenedParamChanges) {
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(2);
- ActivateUnderlyingProvider();
-
- // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
- // null. Change the fallback interval for this class.
- SetVariationParameter("soft_on_ntp_opened_interval_hours-active_ntp_user",
- "1.5");
-
- // Schedule() should get called for the second time after params have changed.
- ActivateUnderlyingProvider();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- FetchIntervalForNtpOpenedTrigger) {
- RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- {
- InSequence s;
- // Initial scheduling after being enabled.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- // The first call to NTPOpened results in a fetch.
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
- // Rescheduling after a succesful fetch.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- // The third call to NTPOpened 35min later again results in a fetch.
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
- }
-
- ActivateUnderlyingProvider();
-
- scheduling_provider_->OnNTPOpened();
- signal_fetch_done.Run(Status::Success());
-
- // UserClassifier defaults to UserClass::ACTIVE_NTP_USER which uses a 2h time
- // interval by default for soft backgroudn fetches on ntp open events.
-
- // Open NTP again after 20min. This time no fetch is executed.
- test_clock_->Advance(base::TimeDelta::FromMinutes(20));
- scheduling_provider_->OnNTPOpened();
-
- // Open NTP again after 101min (121min since first opened). Since the default
- // time interval has passed refetch again.
- test_clock_->Advance(base::TimeDelta::FromMinutes(101));
- scheduling_provider_->OnNTPOpened();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- OverrideFetchIntervalForNtpOpenedTrigger) {
- // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
- // null. Change the on usage interval for this class from 2h to 30min.
- SetVariationParameter("soft_on_ntp_opened_interval_hours-active_ntp_user",
- "0.5");
-
- RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- {
- InSequence s;
- // Initial scheduling after being enabled.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- // The first call to NTPOpened results in a fetch.
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
- // Rescheduling after a succesful fetch.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- // The third call to NTPOpened 35min later again results in a fetch.
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
- }
-
- ActivateUnderlyingProvider();
-
- scheduling_provider_->OnNTPOpened();
- signal_fetch_done.Run(Status::Success());
-
- // Open NTP again after 20min. No fetch request is issues since the 30 min
- // time interval has not passed yet.
- test_clock_->Advance(base::TimeDelta::FromMinutes(20));
- scheduling_provider_->OnNTPOpened();
-
- // Open NTP again after 15min (35min since first opened)
- test_clock_->Advance(base::TimeDelta::FromMinutes(15));
- scheduling_provider_->OnNTPOpened();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldBlockFetchingForSomeTimeAfterHistoryCleared) {
- // First enable the scheduler -- this will trigger the persistent scheduling.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- ActivateUnderlyingProvider();
- // Clear the history.
- scheduling_provider_->OnHistoryCleared();
-
- // A trigger after 15 minutes is ignored.
- test_clock_->Advance(base::TimeDelta::FromMinutes(15));
- scheduling_provider_->OnBrowserForegrounded();
-
- // A trigger after another 16 minutes is performed (more than 30m after
- // clearing the history).
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
- test_clock_->Advance(base::TimeDelta::FromMinutes(16));
- scheduling_provider_->OnBrowserForegrounded();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldImmediatelyFetchAfterSuggestionsCleared) {
- RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
-
- // First enable the scheduler -- this will trigger the persistent scheduling.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- ActivateUnderlyingProvider();
-
- // The first trigger results in a fetch.
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
- scheduling_provider_->OnBrowserForegrounded();
- // Make the fetch successful -- this results in rescheduling.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
- signal_fetch_done.Run(Status::Success());
-
- // Clear the suggestions - results in an immediate fetch.
- EXPECT_CALL(*underlying_provider_, ReloadSuggestions());
- scheduling_provider_->OnSuggestionsCleared();
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldThrottleInteractiveRequests) {
- // Change the quota for interactive requests ("active NTP user" is the default
- // class in tests).
- SetVariationParameter("interactive_quota_SuggestionFetcherActiveNTPUser",
- "10");
- ResetProvider();
-
- Category category = Category::FromKnownCategory(KnownCategories::ARTICLES);
- std::set<std::string> known_suggestions;
-
- // Both Fetch(..) and ReloadSuggestions() consume the same quota. As long as
- // the quota suffices, the call gets through.
- EXPECT_CALL(*underlying_provider_, ReloadSuggestions()).Times(5);
- for (int x = 0; x < 5; ++x) {
- scheduling_provider_->ReloadSuggestions();
- }
-
- // Expect underlying provider being called and store the callback to inform
- // scheduling provider.
- FetchDoneCallback signal_fetch_done_from_underlying_provider;
- EXPECT_CALL(*underlying_provider_, Fetch(_, _, _))
- .Times(5)
- .WillRepeatedly(SaveArg<2>(&signal_fetch_done_from_underlying_provider));
- // Expect scheduling provider to pass the information through.
- MockFunction<void(Status status_code,
- const std::vector<ContentSuggestion>& suggestions)>
- fetch_done_from_scheduling_provider;
- EXPECT_CALL(fetch_done_from_scheduling_provider,
- Call(Field(&Status::code, StatusCode::SUCCESS), _))
- .Times(5);
- // Scheduling is not activated, each successful fetch results in Unschedule().
- EXPECT_CALL(persistent_scheduler_, Unschedule()).Times(5);
- for (int x = 0; x < 5; ++x) {
- scheduling_provider_->Fetch(
- category, known_suggestions,
- base::Bind(&SchedulingRemoteSuggestionsProviderTest::FetchDoneWrapper,
- base::Unretained(this),
- &fetch_done_from_scheduling_provider));
- // Inform scheduling provider the fetc is successful (with no suggestions).
- signal_fetch_done_from_underlying_provider.Run(
- Status::Success(), std::vector<ContentSuggestion>{});
- }
-
- // When the quota expires, it is blocked by the scheduling provider, directly
- // calling the callback.
- EXPECT_CALL(fetch_done_from_scheduling_provider,
- Call(Field(&Status::code, StatusCode::TEMPORARY_ERROR), _));
- scheduling_provider_->ReloadSuggestions();
- scheduling_provider_->Fetch(
- category, known_suggestions,
- base::Bind(&SchedulingRemoteSuggestionsProviderTest::FetchDoneWrapper,
- base::Unretained(this), &fetch_done_from_scheduling_provider));
-}
-
-TEST_F(SchedulingRemoteSuggestionsProviderTest,
- ShouldThrottleNonInteractiveRequests) {
- // Change the quota for interactive requests ("active NTP user" is the default
- // class in tests).
- SetVariationParameter("quota_SuggestionFetcherActiveNTPUser", "5");
- ResetProvider();
-
- // One scheduling on start, 5 times after successful fetches.
- EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(6);
-
- // First enable the scheduler -- this will trigger the persistent scheduling.
- ActivateUnderlyingProvider();
-
- // As long as the quota suffices, the call gets through.
- RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_))
- .Times(5)
- .WillRepeatedly(SaveArg<0>(&signal_fetch_done));
- for (int x = 0; x < 5; ++x) {
- scheduling_provider_->OnPersistentSchedulerWakeUp();
- signal_fetch_done.Run(Status::Success());
- }
-
- // For the 6th time, it is blocked by the scheduling provider.
- scheduling_provider_->OnPersistentSchedulerWakeUp();
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc b/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
index 783fb337689..eae4fc2cb30 100644
--- a/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
@@ -34,6 +34,7 @@ using base::TimeDelta;
using sessions::SerializedNavigationEntry;
using sessions::SessionTab;
using sessions::SessionWindow;
+using sync_sessions::SyncedSessionWindow;
using sync_sessions::SyncedSession;
using DismissedFilter = base::Callback<bool(const std::string& id)>;
@@ -199,8 +200,7 @@ CategoryInfo ForeignSessionsSuggestionsProvider::GetCategoryInfo(
return CategoryInfo(l10n_util::GetStringUTF16(
IDS_NTP_FOREIGN_SESSIONS_SUGGESTIONS_SECTION_HEADER),
ContentSuggestionsCardLayout::MINIMAL_CARD,
- /*has_fetch_action=*/false,
- /*has_view_all_action=*/true,
+ ContentSuggestionsAdditionalAction::VIEW_ALL,
/*show_if_empty=*/false,
l10n_util::GetStringUTF16(
IDS_NTP_FOREIGN_SESSIONS_SUGGESTIONS_SECTION_EMPTY));
@@ -232,11 +232,11 @@ void ForeignSessionsSuggestionsProvider::Fetch(
LOG(DFATAL)
<< "ForeignSessionsSuggestionsProvider has no |Fetch| functionality!";
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(callback, Status(StatusCode::PERMANENT_ERROR,
- "ForeignSessionsSuggestionsProvider "
- "has no |Fetch| functionality!"),
- base::Passed(std::vector<ContentSuggestion>())));
+ FROM_HERE, base::Bind(callback,
+ Status(StatusCode::PERMANENT_ERROR,
+ "ForeignSessionsSuggestionsProvider "
+ "has no |Fetch| functionality!"),
+ base::Passed(std::vector<ContentSuggestion>())));
}
void ForeignSessionsSuggestionsProvider::ClearHistory(
@@ -366,10 +366,9 @@ ForeignSessionsSuggestionsProvider::GetSuggestionCandidates(
const TimeDelta max_foreign_tab_age = GetMaxForeignTabAge();
std::vector<SessionData> suggestion_candidates;
for (const SyncedSession* session : foreign_sessions) {
- for (const std::pair<const SessionID::id_type,
- std::unique_ptr<sessions::SessionWindow>>& key_value :
- session->windows) {
- for (const std::unique_ptr<SessionTab>& tab : key_value.second->tabs) {
+ for (const auto& key_value : session->windows) {
+ for (const std::unique_ptr<SessionTab>& tab :
+ key_value.second->wrapped_window.tabs) {
if (tab->navigations.empty()) {
continue;
}
diff --git a/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc b/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc
index e966048a538..0d9071ee4e8 100644
--- a/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc
+++ b/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc
@@ -27,6 +27,7 @@ using sessions::SerializedNavigationEntry;
using sessions::SessionTab;
using sessions::SessionWindow;
using sync_sessions::SyncedSession;
+using sync_sessions::SyncedSessionWindow;
using testing::ElementsAre;
using testing::IsEmpty;
using testing::Property;
@@ -51,10 +52,10 @@ const char kTitle[] = "title is ignored";
SessionWindow* GetOrCreateWindow(SyncedSession* session, int window_id) {
if (session->windows.find(window_id) == session->windows.end()) {
- session->windows[window_id] = base::MakeUnique<SessionWindow>();
+ session->windows[window_id] = base::MakeUnique<SyncedSessionWindow>();
}
- return session->windows[window_id].get();
+ return &session->windows[window_id]->wrapped_window;
}
void AddTabToSession(SyncedSession* session,
diff --git a/chromium/components/ntp_snippets/user_classifier.cc b/chromium/components/ntp_snippets/user_classifier.cc
index 8686700fd64..92b0312de49 100644
--- a/chromium/components/ntp_snippets/user_classifier.cc
+++ b/chromium/components/ntp_snippets/user_classifier.cc
@@ -10,6 +10,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
+#include "base/time/clock.h"
#include "components/ntp_snippets/features.h"
#include "components/ntp_snippets/pref_names.h"
#include "components/prefs/pref_registry_simple.h"
@@ -23,8 +24,7 @@ namespace {
// The discount rate for computing the discounted-average metrics. Must be
// strictly larger than 0 and strictly smaller than 1!
const double kDiscountRatePerDay = 0.25;
-const char kDiscountRatePerDayParam[] =
- "user_classifier_discount_rate_per_day";
+const char kDiscountRatePerDayParam[] = "user_classifier_discount_rate_per_day";
// Never consider any larger interval than this (so that extreme situations such
// as losing your phone or going for a long offline vacation do not skew the
@@ -181,8 +181,10 @@ double GetMetricValueForEstimateHoursBetweenEvents(
} // namespace
-UserClassifier::UserClassifier(PrefService* pref_service)
+UserClassifier::UserClassifier(PrefService* pref_service,
+ std::unique_ptr<base::Clock> clock)
: pref_service_(pref_service),
+ clock_(std::move(clock)),
discount_rate_per_hour_(GetDiscountRatePerHour()),
min_hours_(GetMinHours()),
max_hours_(GetMaxHours()),
@@ -328,7 +330,7 @@ double UserClassifier::UpdateMetricOnEvent(Metric metric) {
// Add 1 to the discounted metric as the event has happened right now.
double new_metric_value =
1 + DiscountMetric(metric_value, hours_since_last_time,
- discount_rate_per_hour_);
+ discount_rate_per_hour_);
SetMetricValue(metric, new_metric_value);
return new_metric_value;
}
@@ -353,8 +355,8 @@ double UserClassifier::GetHoursSinceLastTime(Metric metric) const {
}
base::TimeDelta since_last_time =
- base::Time::Now() - base::Time::FromInternalValue(pref_service_->GetInt64(
- kLastTimeKeys[static_cast<int>(metric)]));
+ clock_->Now() - base::Time::FromInternalValue(pref_service_->GetInt64(
+ kLastTimeKeys[static_cast<int>(metric)]));
return since_last_time.InSecondsF() / 3600;
}
@@ -364,7 +366,7 @@ bool UserClassifier::HasLastTime(Metric metric) const {
void UserClassifier::SetLastTimeToNow(Metric metric) {
pref_service_->SetInt64(kLastTimeKeys[static_cast<int>(metric)],
- base::Time::Now().ToInternalValue());
+ clock_->Now().ToInternalValue());
}
double UserClassifier::GetMetricValue(Metric metric) const {
diff --git a/chromium/components/ntp_snippets/user_classifier.h b/chromium/components/ntp_snippets/user_classifier.h
index 477e23ac760..93be8fa42e0 100644
--- a/chromium/components/ntp_snippets/user_classifier.h
+++ b/chromium/components/ntp_snippets/user_classifier.h
@@ -5,14 +5,18 @@
#ifndef COMPONENTS_NTP_SNIPPETS_USER_CLASSIFIER_H_
#define COMPONENTS_NTP_SNIPPETS_USER_CLASSIFIER_H_
+#include <memory>
#include <string>
#include "base/macros.h"
-#include "base/time/time.h"
class PrefRegistrySimple;
class PrefService;
+namespace base {
+class Clock;
+} // namespace base
+
namespace ntp_snippets {
// Collects data about user usage patterns of content suggestions, computes
@@ -52,7 +56,7 @@ class UserClassifier {
};
// The provided |pref_service| may be nullptr in unit-tests.
- explicit UserClassifier(PrefService* pref_service);
+ UserClassifier(PrefService* pref_service, std::unique_ptr<base::Clock> clock);
~UserClassifier();
// Registers profile prefs for all metrics. Called from browser_prefs.cc.
@@ -93,6 +97,7 @@ class UserClassifier {
void ClearMetricValue(Metric metric);
PrefService* pref_service_;
+ std::unique_ptr<base::Clock> clock_;
// Params of the metric.
const double discount_rate_per_hour_;
diff --git a/chromium/components/ntp_snippets/user_classifier_unittest.cc b/chromium/components/ntp_snippets/user_classifier_unittest.cc
new file mode 100644
index 00000000000..882e7e6682b
--- /dev/null
+++ b/chromium/components/ntp_snippets/user_classifier_unittest.cc
@@ -0,0 +1,317 @@
+// 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/ntp_snippets/user_classifier.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/test/histogram_tester.h"
+#include "base/test/simple_test_clock.h"
+#include "base/time/time.h"
+#include "components/ntp_snippets/features.h"
+#include "components/ntp_snippets/ntp_snippets_constants.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/variations/variations_params_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::DoubleNear;
+using testing::Eq;
+using testing::Gt;
+using testing::Lt;
+using testing::SizeIs;
+
+namespace ntp_snippets {
+namespace {
+
+char kNowString[] = "2017-03-01 10:45";
+
+class UserClassifierTest : public testing::Test {
+ public:
+ UserClassifierTest() {
+ UserClassifier::RegisterProfilePrefs(test_prefs_.registry());
+ }
+
+ UserClassifier* CreateUserClassifier() {
+ auto test_clock = base::MakeUnique<base::SimpleTestClock>();
+ test_clock_ = test_clock.get();
+
+ base::Time now;
+ CHECK(base::Time::FromUTCString(kNowString, &now));
+ test_clock_->SetNow(now);
+
+ user_classifier_ =
+ base::MakeUnique<UserClassifier>(&test_prefs_, std::move(test_clock));
+ return user_classifier_.get();
+ }
+
+ base::SimpleTestClock* test_clock() { return test_clock_; }
+
+ private:
+ TestingPrefServiceSimple test_prefs_;
+ std::unique_ptr<UserClassifier> user_classifier_;
+
+ // Owned by the UserClassifier.
+ base::SimpleTestClock* test_clock_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserClassifierTest);
+};
+
+TEST_F(UserClassifierTest, ShouldBeActiveNtpUserInitially) {
+ UserClassifier* user_classifier = CreateUserClassifier();
+ EXPECT_THAT(user_classifier->GetUserClass(),
+ Eq(UserClassifier::UserClass::ACTIVE_NTP_USER));
+}
+
+TEST_F(UserClassifierTest,
+ ShouldBecomeActiveSuggestionsConsumerByClickingOften) {
+ UserClassifier* user_classifier = CreateUserClassifier();
+
+ // After one click still only an active user.
+ user_classifier->OnEvent(UserClassifier::Metric::SUGGESTIONS_USED);
+ EXPECT_THAT(user_classifier->GetUserClass(),
+ Eq(UserClassifier::UserClass::ACTIVE_NTP_USER));
+
+ // After a few more clicks, become an active consumer.
+ for (int i = 0; i < 5; i++) {
+ test_clock()->Advance(base::TimeDelta::FromHours(1));
+ user_classifier->OnEvent(UserClassifier::Metric::SUGGESTIONS_USED);
+ }
+ EXPECT_THAT(user_classifier->GetUserClass(),
+ Eq(UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER));
+}
+
+TEST_F(UserClassifierTest,
+ ShouldBecomeActiveSuggestionsConsumerByClickingOftenWithDecreasedParam) {
+ // Increase the param to one half.
+ variations::testing::VariationParamsManager variation_params(
+ kArticleSuggestionsFeature.name,
+ {{"user_classifier_active_consumer_clicks_at_least_once_per_hours",
+ "36"}},
+ {kArticleSuggestionsFeature.name});
+ UserClassifier* user_classifier = CreateUserClassifier();
+
+ // After two clicks still only an active user.
+ user_classifier->OnEvent(UserClassifier::Metric::SUGGESTIONS_USED);
+ test_clock()->Advance(base::TimeDelta::FromHours(1));
+ user_classifier->OnEvent(UserClassifier::Metric::SUGGESTIONS_USED);
+ EXPECT_THAT(user_classifier->GetUserClass(),
+ Eq(UserClassifier::UserClass::ACTIVE_NTP_USER));
+
+ // One more click to become an active consumer.
+ test_clock()->Advance(base::TimeDelta::FromHours(1));
+ user_classifier->OnEvent(UserClassifier::Metric::SUGGESTIONS_USED);
+ EXPECT_THAT(user_classifier->GetUserClass(),
+ Eq(UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER));
+}
+
+TEST_F(UserClassifierTest, ShouldBecomeRareNtpUserByNoActivity) {
+ UserClassifier* user_classifier = CreateUserClassifier();
+
+ // After two days of waiting still an active user.
+ test_clock()->Advance(base::TimeDelta::FromDays(2));
+ EXPECT_THAT(user_classifier->GetUserClass(),
+ Eq(UserClassifier::UserClass::ACTIVE_NTP_USER));
+
+ // Two more days to become a rare user.
+ test_clock()->Advance(base::TimeDelta::FromDays(2));
+ EXPECT_THAT(user_classifier->GetUserClass(),
+ Eq(UserClassifier::UserClass::RARE_NTP_USER));
+}
+
+TEST_F(UserClassifierTest,
+ ShouldBecomeRareNtpUserByNoActivityWithDecreasedParam) {
+ // Decrease the param to one half.
+ variations::testing::VariationParamsManager variation_params(
+ kArticleSuggestionsFeature.name,
+ {{"user_classifier_rare_user_opens_ntp_at_most_once_per_hours", "48"}},
+ {kArticleSuggestionsFeature.name});
+ UserClassifier* user_classifier = CreateUserClassifier();
+
+ // After one days of waiting still an active user.
+ test_clock()->Advance(base::TimeDelta::FromDays(1));
+ EXPECT_THAT(user_classifier->GetUserClass(),
+ Eq(UserClassifier::UserClass::ACTIVE_NTP_USER));
+
+ // One more day to become a rare user.
+ test_clock()->Advance(base::TimeDelta::FromDays(1));
+ EXPECT_THAT(user_classifier->GetUserClass(),
+ Eq(UserClassifier::UserClass::RARE_NTP_USER));
+}
+
+class UserClassifierMetricTest
+ : public UserClassifierTest,
+ public ::testing::WithParamInterface<
+ std::pair<UserClassifier::Metric, std::string>> {
+ public:
+ UserClassifierMetricTest() : UserClassifierTest() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(UserClassifierMetricTest);
+};
+
+TEST_P(UserClassifierMetricTest, ShouldDecreaseEstimateAfterEvent) {
+ UserClassifier::Metric metric = GetParam().first;
+ UserClassifier* user_classifier = CreateUserClassifier();
+
+ // The initial event does not decrease the estimate.
+ user_classifier->OnEvent(metric);
+
+ for (int i = 0; i < 10; i++) {
+ test_clock()->Advance(base::TimeDelta::FromHours(1));
+ double old_metric = user_classifier->GetEstimatedAvgTime(metric);
+ user_classifier->OnEvent(metric);
+ EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric), Lt(old_metric));
+ }
+}
+
+TEST_P(UserClassifierMetricTest, ShouldReportToUmaOnEvent) {
+ UserClassifier::Metric metric = GetParam().first;
+ const std::string& histogram_name = GetParam().second;
+ base::HistogramTester histogram_tester;
+ UserClassifier* user_classifier = CreateUserClassifier();
+
+ user_classifier->OnEvent(metric);
+ EXPECT_THAT(histogram_tester.GetAllSamples(histogram_name), SizeIs(1));
+}
+
+TEST_P(UserClassifierMetricTest, ShouldConvergeTowardsPattern) {
+ UserClassifier::Metric metric = GetParam().first;
+ UserClassifier* user_classifier = CreateUserClassifier();
+
+ // Have the pattern of an event every five hours and start changing it towards
+ // an event every 10 hours.
+ for (int i = 0; i < 100; i++) {
+ test_clock()->Advance(base::TimeDelta::FromHours(5));
+ user_classifier->OnEvent(metric);
+ }
+ EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric),
+ DoubleNear(5.0, 0.1));
+ for (int i = 0; i < 3; i++) {
+ test_clock()->Advance(base::TimeDelta::FromHours(10));
+ user_classifier->OnEvent(metric);
+ }
+ EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric), Gt(5.5));
+ for (int i = 0; i < 100; i++) {
+ test_clock()->Advance(base::TimeDelta::FromHours(10));
+ user_classifier->OnEvent(metric);
+ }
+ EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric),
+ DoubleNear(10.0, 0.1));
+}
+
+TEST_P(UserClassifierMetricTest, ShouldIgnoreSubsequentEventsForHalfAnHour) {
+ UserClassifier::Metric metric = GetParam().first;
+ UserClassifier* user_classifier = CreateUserClassifier();
+
+ // The initial event
+ user_classifier->OnEvent(metric);
+ // Subsequent events get ignored for the next 30 minutes.
+ for (int i = 0; i < 5; i++) {
+ test_clock()->Advance(base::TimeDelta::FromMinutes(5));
+ double old_metric = user_classifier->GetEstimatedAvgTime(metric);
+ user_classifier->OnEvent(metric);
+ EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric), Eq(old_metric));
+ }
+ // An event 30 minutes after the initial event is finally not ignored.
+ test_clock()->Advance(base::TimeDelta::FromMinutes(5));
+ double old_metric = user_classifier->GetEstimatedAvgTime(metric);
+ user_classifier->OnEvent(metric);
+ EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric), Lt(old_metric));
+}
+
+TEST_P(UserClassifierMetricTest,
+ ShouldIgnoreSubsequentEventsWithIncreasedLimit) {
+ UserClassifier::Metric metric = GetParam().first;
+ // Increase the min_hours to 1.0, i.e. 60 minutes.
+ variations::testing::VariationParamsManager variation_params(
+ kArticleSuggestionsFeature.name, {{"user_classifier_min_hours", "1.0"}},
+ {kArticleSuggestionsFeature.name});
+ UserClassifier* user_classifier = CreateUserClassifier();
+
+ // The initial event
+ user_classifier->OnEvent(metric);
+ // Subsequent events get ignored for the next 60 minutes.
+ for (int i = 0; i < 11; i++) {
+ test_clock()->Advance(base::TimeDelta::FromMinutes(5));
+ double old_metric = user_classifier->GetEstimatedAvgTime(metric);
+ user_classifier->OnEvent(metric);
+ EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric), Eq(old_metric));
+ }
+ // An event 60 minutes after the initial event is finally not ignored.
+ test_clock()->Advance(base::TimeDelta::FromMinutes(5));
+ double old_metric = user_classifier->GetEstimatedAvgTime(metric);
+ user_classifier->OnEvent(metric);
+ EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric), Lt(old_metric));
+}
+
+TEST_P(UserClassifierMetricTest, ShouldCapDelayBetweenEvents) {
+ UserClassifier::Metric metric = GetParam().first;
+ UserClassifier* user_classifier = CreateUserClassifier();
+
+ // The initial event
+ user_classifier->OnEvent(metric);
+ // Wait for an insane amount of time
+ test_clock()->Advance(base::TimeDelta::FromDays(365));
+ user_classifier->OnEvent(metric);
+ double metric_after_a_year = user_classifier->GetEstimatedAvgTime(metric);
+
+ // Now repeat the same with s/one year/one week.
+ user_classifier->ClearClassificationForDebugging();
+ user_classifier->OnEvent(metric);
+ test_clock()->Advance(base::TimeDelta::FromDays(7));
+ user_classifier->OnEvent(metric);
+
+ // The results should be the same.
+ EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric),
+ Eq(metric_after_a_year));
+}
+
+TEST_P(UserClassifierMetricTest,
+ ShouldCapDelayBetweenEventsWithDecreasedLimit) {
+ UserClassifier::Metric metric = GetParam().first;
+ // Decrease the max_hours to 72, i.e. 3 days.
+ variations::testing::VariationParamsManager variation_params(
+ kArticleSuggestionsFeature.name, {{"user_classifier_max_hours", "72"}},
+ {kArticleSuggestionsFeature.name});
+ UserClassifier* user_classifier = CreateUserClassifier();
+
+ // The initial event
+ user_classifier->OnEvent(metric);
+ // Wait for an insane amount of time
+ test_clock()->Advance(base::TimeDelta::FromDays(365));
+ user_classifier->OnEvent(metric);
+ double metric_after_a_year = user_classifier->GetEstimatedAvgTime(metric);
+
+ // Now repeat the same with s/one year/two days.
+ user_classifier->ClearClassificationForDebugging();
+ user_classifier->OnEvent(metric);
+ test_clock()->Advance(base::TimeDelta::FromDays(3));
+ user_classifier->OnEvent(metric);
+
+ // The results should be the same.
+ EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric),
+ Eq(metric_after_a_year));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ , // An empty prefix for the parametrized tests names (no need to
+ // distinguish the only instance we make here).
+ UserClassifierMetricTest,
+ testing::Values(
+ std::make_pair(UserClassifier::Metric::NTP_OPENED,
+ "NewTabPage.UserClassifier.AverageHoursToOpenNTP"),
+ std::make_pair(
+ UserClassifier::Metric::SUGGESTIONS_SHOWN,
+ "NewTabPage.UserClassifier.AverageHoursToShowSuggestions"),
+ std::make_pair(
+ UserClassifier::Metric::SUGGESTIONS_USED,
+ "NewTabPage.UserClassifier.AverageHoursToUseSuggestions")));
+
+} // namespace
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets_strings.grdp b/chromium/components/ntp_snippets_strings.grdp
index 25c61a790d4..5f047253d27 100644
--- a/chromium/components/ntp_snippets_strings.grdp
+++ b/chromium/components/ntp_snippets_strings.grdp
@@ -8,7 +8,9 @@
<message name="IDS_SNIPPETS_DISABLED_GENERIC_PROMPT" desc="Title of the card explaining what action the user can take to get personalized content suggestions on the New Tab Page." formatter_data="android_java">
Get personalized content
</message>
- <message name="IDS_NTP_STATUS_CARD_TITLE_NO_SUGGESTIONS" desc="On the New Tab Page, title of the status card explaining that there is no new content available in the section." formatter_data="android_java">
+ </if>
+ <if expr="is_android or is_ios">
+ <message name="IDS_NTP_TITLE_NO_SUGGESTIONS" desc="On the New Tab Page, title text explaining there is no content." formatter_data="android_java">
That’s all for now
</message>
</if>
@@ -46,6 +48,14 @@
Your nearby suggestions appear here
</message>
+ <message name="IDS_NTP_READING_LIST_SUGGESTIONS_SECTION_HEADER" desc="Header of the Reading List section. The Reading List section shows a list of unread pages from the Reading List.">
+ Reading list
+ </message>
+
+ <message name="IDS_NTP_READING_LIST_SUGGESTIONS_SECTION_EMPTY" desc="On the New Tab Page, text of the card explaining to the user that they can expect to see Reading List articles in this area in the future.">
+ Pages from your reading list appear here
+ </message>
+
<message name="IDS_NTP_RECENT_TAB_SUGGESTIONS_SECTION_HEADER" desc="Header of the recent tabs section, which is a list of recent open tabs, which are currently opened and were automatically saved for offline consumption. This list is displayed as cards on the New Tab Page. The saved version is opened only if there are problems with the data connection (e.g. slow or absent).">
Open tabs
</message>
@@ -54,8 +64,8 @@
Your open tabs appear here
</message>
- <message name="IDS_NTP_NOTIFICATIONS_READ_THIS_STORY_AND_MORE" desc="When notifying the user about a news article, identifies the publisher of that article and gives the number of additional news articles that are available to read. Shown beneath the title of the article. Articles come in batches of 10, so the number of additional articles will usually be 9.">
- Read stories from <ph name="ARTICLE_PUBLISHER">$1<ex>World News Corporation</ex></ph> and <ph name="OTHER_ARTICLE_COUNT">$2<ex>9</ex></ph> more
+ <message name="IDS_NTP_NOTIFICATIONS_READ_THIS_STORY_AND_MORE" desc="Used in notifications about news articles. The notification first gives the title of a headline article, then uses this string to identify the publisher of that article and the number of additional articles available to read. Articles come in batches of 10, from a variety of publishers, so usually the number of additional articles is 9 (headline article + 9 others = 10 articles).">
+ From <ph name="ARTICLE_PUBLISHER">$1<ex>World News Corporation</ex></ph>. Read this and <ph name="OTHER_ARTICLE_COUNT">$2<ex>9</ex></ph> other stories.
</message>
</grit-part>
diff --git a/chromium/components/ntp_tiles/BUILD.gn b/chromium/components/ntp_tiles/BUILD.gn
index 0e98bf7157b..b0784a80bc1 100644
--- a/chromium/components/ntp_tiles/BUILD.gn
+++ b/chromium/components/ntp_tiles/BUILD.gn
@@ -23,7 +23,6 @@ static_library("ntp_tiles") {
"most_visited_sites.h",
"ntp_tile.cc",
"ntp_tile.h",
- "ntp_tile_source.h",
"popular_sites.h",
"popular_sites_impl.cc",
"popular_sites_impl.h",
@@ -31,8 +30,11 @@ static_library("ntp_tiles") {
"pref_names.h",
"switches.cc",
"switches.h",
+ "tile_source.h",
+ "tile_visual_type.h",
"webui/ntp_tiles_internals_message_handler.cc",
"webui/ntp_tiles_internals_message_handler.h",
+ "webui/ntp_tiles_internals_message_handler_client.cc",
"webui/ntp_tiles_internals_message_handler_client.h",
"webui/popular_sites_internals_message_handler.cc",
"webui/popular_sites_internals_message_handler.h",
@@ -49,7 +51,7 @@ static_library("ntp_tiles") {
"//components/favicon/core",
"//components/favicon_base",
"//components/google/core/browser",
- "//components/image_fetcher",
+ "//components/image_fetcher/core",
"//components/pref_registry",
"//components/prefs",
"//components/rappor/public",
@@ -97,7 +99,7 @@ source_set("unit_tests") {
"//base/test:test_support",
"//components/favicon/core",
"//components/favicon_base",
- "//components/image_fetcher",
+ "//components/image_fetcher/core",
"//components/pref_registry:pref_registry",
"//components/rappor:test_support",
"//components/sync_preferences:test_support",
@@ -112,8 +114,8 @@ source_set("unit_tests") {
if (is_android) {
java_cpp_enum("ntp_tiles_enums_java") {
sources = [
- "metrics.h",
- "ntp_tile_source.h",
+ "tile_source.h",
+ "tile_visual_type.h",
]
}
}
diff --git a/chromium/components/ntp_tiles/icon_cacher_impl.cc b/chromium/components/ntp_tiles/icon_cacher_impl.cc
index 6c7076f85fa..f8480de51e9 100644
--- a/chromium/components/ntp_tiles/icon_cacher_impl.cc
+++ b/chromium/components/ntp_tiles/icon_cacher_impl.cc
@@ -6,11 +6,13 @@
#include <utility>
+#include "base/memory/ptr_util.h"
#include "components/favicon/core/favicon_service.h"
#include "components/favicon/core/favicon_util.h"
#include "components/favicon_base/favicon_types.h"
#include "components/favicon_base/favicon_util.h"
-#include "components/image_fetcher/image_fetcher.h"
+#include "components/image_fetcher/core/image_decoder.h"
+#include "components/image_fetcher/core/image_fetcher.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
@@ -20,6 +22,8 @@ namespace ntp_tiles {
namespace {
+constexpr int kDesiredFrameSize = 128;
+
favicon_base::IconType IconType(const PopularSites::Site& site) {
return site.large_icon_url.is_valid() ? favicon_base::TOUCH_ICON
: favicon_base::FAVICON;
@@ -36,11 +40,13 @@ IconCacherImpl::IconCacherImpl(
favicon::FaviconService* favicon_service,
std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher)
: favicon_service_(favicon_service),
- image_fetcher_(std::move(image_fetcher)) {
+ image_fetcher_(std::move(image_fetcher)),
+ weak_ptr_factory_(this) {
image_fetcher_->SetDataUseServiceName(
data_use_measurement::DataUseUserData::NTP_TILES);
// For images with multiple frames, prefer one of size 128x128px.
- image_fetcher_->SetDesiredImageFrameSize(gfx::Size(128, 128));
+ image_fetcher_->SetDesiredImageFrameSize(
+ gfx::Size(kDesiredFrameSize, kDesiredFrameSize));
}
IconCacherImpl::~IconCacherImpl() = default;
@@ -49,8 +55,11 @@ void IconCacherImpl::StartFetch(
PopularSites::Site site,
const base::Closure& icon_available,
const base::Closure& preliminary_icon_available) {
+ // Copy values from |site| before it is moved.
+ GURL site_url = site.url;
+ favicon_base::IconType icon_type = IconType(site);
favicon::GetFaviconImageForPageURL(
- favicon_service_, site.url, IconType(site),
+ favicon_service_, site_url, icon_type,
base::Bind(&IconCacherImpl::OnGetFaviconImageForPageURLFinished,
base::Unretained(this), std::move(site), icon_available,
preliminary_icon_available),
@@ -65,43 +74,70 @@ void IconCacherImpl::OnGetFaviconImageForPageURLFinished(
if (!result.image.IsEmpty()) {
return;
}
- if (ProvideDefaultIcon(site) && !preliminary_icon_available.is_null()) {
- preliminary_icon_available.Run();
- }
+
+ std::unique_ptr<CancelableImageCallback> preliminary_callback =
+ MaybeProvideDefaultIcon(site, preliminary_icon_available);
image_fetcher_->StartOrQueueNetworkRequest(
std::string(), IconURL(site),
base::Bind(&IconCacherImpl::OnFaviconDownloaded, base::Unretained(this),
- site, icon_available));
+ site, base::Passed(std::move(preliminary_callback)),
+ icon_available));
}
-void IconCacherImpl::OnFaviconDownloaded(PopularSites::Site site,
- const base::Closure& icon_available,
- const std::string& id,
- const gfx::Image& fetched_image) {
+void IconCacherImpl::OnFaviconDownloaded(
+ PopularSites::Site site,
+ std::unique_ptr<CancelableImageCallback> preliminary_callback,
+ const base::Closure& icon_available,
+ const std::string& id,
+ const gfx::Image& fetched_image,
+ const image_fetcher::RequestMetadata& metadata) {
if (fetched_image.IsEmpty()) {
return;
}
- SaveIconForSite(site, fetched_image);
- if (icon_available) {
- icon_available.Run();
+ // Avoid invoking callback about preliminary icon to be triggered. The best
+ // possible icon has already been downloaded.
+ if (preliminary_callback) {
+ preliminary_callback->Cancel();
}
+ SaveAndNotifyIconForSite(site, icon_available, fetched_image);
}
-void IconCacherImpl::SaveIconForSite(const PopularSites::Site& site,
- gfx::Image image) {
- favicon_base::SetFaviconColorSpace(&image);
- favicon_service_->SetFavicons(site.url, IconURL(site), IconType(site), image);
+void IconCacherImpl::SaveAndNotifyIconForSite(
+ const PopularSites::Site& site,
+ const base::Closure& icon_available,
+ const gfx::Image& image) {
+ // Although |SetFaviconColorSpace| affects OSX only, copies of gfx::Images are
+ // just copies of the reference to the image and therefore cheap.
+ gfx::Image img(image);
+ favicon_base::SetFaviconColorSpace(&img);
+
+ favicon_service_->SetFavicons(site.url, IconURL(site), IconType(site),
+ std::move(img));
+
+ if (icon_available) {
+ icon_available.Run();
+ }
}
-bool IconCacherImpl::ProvideDefaultIcon(const PopularSites::Site& site) {
+std::unique_ptr<IconCacherImpl::CancelableImageCallback>
+IconCacherImpl::MaybeProvideDefaultIcon(const PopularSites::Site& site,
+ const base::Closure& icon_available) {
if (site.default_icon_resource < 0) {
- return false;
+ return std::unique_ptr<CancelableImageCallback>();
}
- SaveIconForSite(site, ResourceBundle::GetSharedInstance().GetNativeImageNamed(
- site.default_icon_resource));
- return true;
+ std::unique_ptr<CancelableImageCallback> preliminary_callback(
+ new CancelableImageCallback(
+ base::Bind(&IconCacherImpl::SaveAndNotifyIconForSite,
+ weak_ptr_factory_.GetWeakPtr(), site, icon_available)));
+ image_fetcher_->GetImageDecoder()->DecodeImage(
+ ResourceBundle::GetSharedInstance()
+ .GetRawDataResource(site.default_icon_resource)
+ .as_string(),
+ gfx::Size(kDesiredFrameSize, kDesiredFrameSize),
+ preliminary_callback->callback());
+ return preliminary_callback;
}
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/icon_cacher_impl.h b/chromium/components/ntp_tiles/icon_cacher_impl.h
index 20c5922f89f..58ed735eb65 100644
--- a/chromium/components/ntp_tiles/icon_cacher_impl.h
+++ b/chromium/components/ntp_tiles/icon_cacher_impl.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/callback.h"
+#include "base/cancelable_callback.h"
#include "base/memory/weak_ptr.h"
#include "base/task/cancelable_task_tracker.h"
#include "components/ntp_tiles/icon_cacher.h"
@@ -28,6 +29,7 @@ class Image;
namespace image_fetcher {
class ImageFetcher;
+struct RequestMetadata;
} // namespace image_fetcher
namespace ntp_tiles {
@@ -43,24 +45,36 @@ class IconCacherImpl : public IconCacher {
const base::Closure& preliminary_icon_available) override;
private:
+ using CancelableImageCallback =
+ base::CancelableCallback<void(const gfx::Image&)>;
+
void OnGetFaviconImageForPageURLFinished(
PopularSites::Site site,
const base::Closure& icon_available,
const base::Closure& preliminary_icon_available,
const favicon_base::FaviconImageResult& result);
- void OnFaviconDownloaded(PopularSites::Site site,
- const base::Closure& icon_available,
- const std::string& id,
- const gfx::Image& fetched_image);
+ void OnFaviconDownloaded(
+ PopularSites::Site site,
+ std::unique_ptr<CancelableImageCallback> preliminary_callback,
+ const base::Closure& icon_available,
+ const std::string& id,
+ const gfx::Image& fetched_image,
+ const image_fetcher::RequestMetadata& metadata);
- bool ProvideDefaultIcon(const PopularSites::Site& site);
- void SaveIconForSite(const PopularSites::Site& site, const gfx::Image image);
+ std::unique_ptr<CancelableImageCallback> MaybeProvideDefaultIcon(
+ const PopularSites::Site& site,
+ const base::Closure& icon_available);
+ void SaveAndNotifyIconForSite(const PopularSites::Site& site,
+ const base::Closure& icon_available,
+ const gfx::Image& image);
base::CancelableTaskTracker tracker_;
favicon::FaviconService* const favicon_service_;
std::unique_ptr<image_fetcher::ImageFetcher> const image_fetcher_;
+ base::WeakPtrFactory<IconCacherImpl> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(IconCacherImpl);
};
diff --git a/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc b/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
index bab8c30ed95..4a2ddc2513d 100644
--- a/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
+++ b/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
@@ -12,6 +12,7 @@
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/favicon/core/favicon_client.h"
@@ -19,7 +20,9 @@
#include "components/favicon/core/favicon_util.h"
#include "components/history/core/browser/history_database_params.h"
#include "components/history/core/browser/history_service.h"
-#include "components/image_fetcher/image_fetcher.h"
+#include "components/image_fetcher/core/image_decoder.h"
+#include "components/image_fetcher/core/image_fetcher.h"
+#include "components/image_fetcher/core/request_metadata.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/resource/resource_bundle.h"
@@ -43,12 +46,22 @@ class MockImageFetcher : public image_fetcher::ImageFetcher {
void(image_fetcher::ImageFetcherDelegate* delegate));
MOCK_METHOD1(SetDataUseServiceName,
void(image_fetcher::ImageFetcher::DataUseServiceName name));
+ MOCK_METHOD1(SetImageDownloadLimit,
+ void(base::Optional<int64_t> max_download_bytes));
MOCK_METHOD3(StartOrQueueNetworkRequest,
void(const std::string& id,
const GURL& image_url,
- base::Callback<void(const std::string& id,
- const gfx::Image& image)> callback));
+ const ImageFetcherCallback& callback));
MOCK_METHOD1(SetDesiredImageFrameSize, void(const gfx::Size&));
+ MOCK_METHOD0(GetImageDecoder, image_fetcher::ImageDecoder*());
+};
+
+class MockImageDecoder : public image_fetcher::ImageDecoder {
+ public:
+ MOCK_METHOD3(DecodeImage,
+ void(const std::string& image_data,
+ const gfx::Size& desired_image_frame_size,
+ const image_fetcher::ImageDecodedCallback& callback));
};
// This class provides methods to inject an image resource where a real resource
@@ -90,6 +103,7 @@ class IconCacherTest : public ::testing::Test {
GURL("http://url.google/favicon.ico"),
GURL()), // thumbnail, unused
image_fetcher_(new ::testing::StrictMock<MockImageFetcher>),
+ image_decoder_(new ::testing::StrictMock<MockImageDecoder>),
favicon_service_(/*favicon_client=*/nullptr, &history_service_),
task_runner_(new base::TestSimpleTaskRunner()) {
CHECK(history_dir_.CreateUniqueTempDir());
@@ -164,9 +178,10 @@ class IconCacherTest : public ::testing::Test {
void WaitForTasksToFinish() { task_runner_->RunUntilIdle(); }
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
PopularSites::Site site_;
std::unique_ptr<MockImageFetcher> image_fetcher_;
+ std::unique_ptr<MockImageDecoder> image_decoder_;
base::ScopedTempDir history_dir_;
history::HistoryService history_service_;
favicon::FaviconServiceImpl favicon_service_;
@@ -176,12 +191,19 @@ class IconCacherTest : public ::testing::Test {
ACTION(FailFetch) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(arg2, arg0, gfx::Image()));
+ FROM_HERE,
+ base::Bind(arg2, arg0, gfx::Image(), image_fetcher::RequestMetadata()));
+}
+
+ACTION_P2(DecodeSuccessfully, width, height) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(arg2, gfx::test::CreateImage(width, height)));
}
ACTION_P2(PassFetch, width, height) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(arg2, arg0, gfx::test::CreateImage(width, height)));
+ FROM_HERE, base::Bind(arg2, arg0, gfx::test::CreateImage(width, height),
+ image_fetcher::RequestMetadata()));
}
ACTION_P(Quit, run_loop) {
@@ -286,12 +308,15 @@ TEST_F(IconCacherTest, HandlesEmptyCallbacksNicely) {
}
TEST_F(IconCacherTest, ProvidesDefaultIconAndSucceedsWithFetching) {
- // We are not interested which delegate function actually handles the call to
- // |GetNativeImageNamed| as long as we receive the right image.
- ON_CALL(mock_resource_delegate_, GetNativeImageNamed(12345))
- .WillByDefault(Return(gfx::test::CreateImage(64, 64)));
- ON_CALL(mock_resource_delegate_, GetImageNamed(12345))
- .WillByDefault(Return(gfx::test::CreateImage(64, 64)));
+ // The returned data string is not used by the mocked decoder.
+ ON_CALL(mock_resource_delegate_, GetRawDataResource(12345, _, _))
+ .WillByDefault(Return(""));
+ // It's not important when the image_fetcher's decoder is used to decode the
+ // image but it must happen at some point.
+ EXPECT_CALL(*image_fetcher_, GetImageDecoder())
+ .WillOnce(Return(image_decoder_.get()));
+ EXPECT_CALL(*image_decoder_, DecodeImage(_, gfx::Size(128, 128), _))
+ .WillOnce(DecodeSuccessfully(64, 64));
base::MockCallback<base::Closure> preliminary_icon_available;
base::MockCallback<base::Closure> icon_available;
base::RunLoop default_loop;
@@ -302,11 +327,14 @@ TEST_F(IconCacherTest, ProvidesDefaultIconAndSucceedsWithFetching) {
SetDataUseServiceName(
data_use_measurement::DataUseUserData::NTP_TILES));
EXPECT_CALL(*image_fetcher_, SetDesiredImageFrameSize(gfx::Size(128, 128)));
- EXPECT_CALL(preliminary_icon_available, Run())
- .WillOnce(Quit(&default_loop));
EXPECT_CALL(*image_fetcher_,
StartOrQueueNetworkRequest(_, site_.large_icon_url, _))
.WillOnce(PassFetch(128, 128));
+
+ // Both callback are called async after the request but preliminary has to
+ // preceed icon_available.
+ EXPECT_CALL(preliminary_icon_available, Run())
+ .WillOnce(Quit(&default_loop));
EXPECT_CALL(icon_available, Run()).WillOnce(Quit(&fetch_loop));
}
diff --git a/chromium/components/ntp_tiles/metrics.cc b/chromium/components/ntp_tiles/metrics.cc
index 4acc1c0d5c5..819a6aed935 100644
--- a/chromium/components/ntp_tiles/metrics.cc
+++ b/chromium/components/ntp_tiles/metrics.cc
@@ -27,9 +27,11 @@ const char kHistogramPopularName[] = "popular";
const char kHistogramWhitelistName[] = "whitelist";
// Suffixes for the various icon types.
-const char kIconTypeSuffixColor[] = "IconsColor";
-const char kIconTypeSuffixGray[] = "IconsGray";
-const char kIconTypeSuffixReal[] = "IconsReal";
+const char kTileTypeSuffixIconColor[] = "IconsColor";
+const char kTileTypeSuffixIconGray[] = "IconsGray";
+const char kTileTypeSuffixIconReal[] = "IconsReal";
+const char kTileTypeSuffixThumbnail[] = "Thumbnail";
+const char kTileTypeSuffixThumbnailFailed[] = "ThumbnailFailed";
// Log an event for a given |histogram| at a given element |position|. This
// routine exists because regular histogram macros are cached thus can't be used
@@ -44,33 +46,35 @@ void LogHistogramEvent(const std::string& histogram,
counter->Add(position);
}
-std::string GetSourceHistogramName(NTPTileSource source) {
+std::string GetSourceHistogramName(TileSource source) {
switch (source) {
- case NTPTileSource::TOP_SITES:
+ case TileSource::TOP_SITES:
return kHistogramClientName;
- case NTPTileSource::POPULAR:
+ case TileSource::POPULAR:
return kHistogramPopularName;
- case NTPTileSource::WHITELIST:
+ case TileSource::WHITELIST:
return kHistogramWhitelistName;
- case NTPTileSource::SUGGESTIONS_SERVICE:
+ case TileSource::SUGGESTIONS_SERVICE:
return kHistogramServerName;
}
NOTREACHED();
return std::string();
}
-const char* GetIconTypeSuffix(MostVisitedTileType type) {
+const char* GetTileTypeSuffix(TileVisualType type) {
switch (type) {
- case ICON_COLOR:
- return kIconTypeSuffixColor;
- case ICON_DEFAULT:
- return kIconTypeSuffixGray;
- case ICON_REAL:
- return kIconTypeSuffixReal;
- case NONE: // Fall through.
- case NUM_RECORDED_TILE_TYPES: // Fall through.
- case THUMBNAIL: // Fall through.
- case UNKNOWN_TILE_TYPE:
+ case TileVisualType::ICON_COLOR:
+ return kTileTypeSuffixIconColor;
+ case TileVisualType::ICON_DEFAULT:
+ return kTileTypeSuffixIconGray;
+ case TileVisualType::ICON_REAL:
+ return kTileTypeSuffixIconReal;
+ case THUMBNAIL:
+ return kTileTypeSuffixThumbnail;
+ case THUMBNAIL_FAILED:
+ return kTileTypeSuffixThumbnailFailed;
+ case TileVisualType::NONE: // Fall through.
+ case TileVisualType::UNKNOWN_TILE_TYPE:
break;
}
return nullptr;
@@ -82,12 +86,9 @@ void RecordPageImpression(const std::vector<TileImpression>& tiles,
rappor::RapporService* rappor_service) {
UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfTiles", tiles.size());
- int counts_per_type[NUM_RECORDED_TILE_TYPES] = {0};
- bool have_tile_types = false;
for (int index = 0; index < static_cast<int>(tiles.size()); index++) {
- NTPTileSource source = tiles[index].source;
- MostVisitedTileType tile_type = tiles[index].type;
- const GURL& url = tiles[index].url;
+ TileSource source = tiles[index].source;
+ TileVisualType tile_type = tiles[index].type;
UMA_HISTOGRAM_ENUMERATION("NewTabPage.SuggestionsImpression", index,
kMaxNumTiles);
@@ -97,67 +98,55 @@ void RecordPageImpression(const std::vector<TileImpression>& tiles,
"NewTabPage.SuggestionsImpression.%s", source_name.c_str());
LogHistogramEvent(impression_histogram, index, kMaxNumTiles);
- if (tile_type >= NUM_RECORDED_TILE_TYPES) {
+ if (tile_type > LAST_RECORDED_TILE_TYPE) {
continue;
}
- have_tile_types = true;
- ++counts_per_type[tile_type];
-
UMA_HISTOGRAM_ENUMERATION("NewTabPage.TileType", tile_type,
- NUM_RECORDED_TILE_TYPES);
+ LAST_RECORDED_TILE_TYPE + 1);
std::string tile_type_histogram =
base::StringPrintf("NewTabPage.TileType.%s", source_name.c_str());
- LogHistogramEvent(tile_type_histogram, tile_type, NUM_RECORDED_TILE_TYPES);
+ LogHistogramEvent(tile_type_histogram, tile_type,
+ LAST_RECORDED_TILE_TYPE + 1);
- const char* icon_type_suffix = GetIconTypeSuffix(tile_type);
- if (icon_type_suffix) {
+ const char* tile_type_suffix = GetTileTypeSuffix(tile_type);
+ if (tile_type_suffix) {
+ // Note: This handles a null |rappor_service|.
rappor::SampleDomainAndRegistryFromGURL(
rappor_service,
- base::StringPrintf("NTP.SuggestionsImpressions.%s", icon_type_suffix),
- url);
+ base::StringPrintf("NTP.SuggestionsImpressions.%s", tile_type_suffix),
+ tiles[index].url);
std::string icon_impression_histogram = base::StringPrintf(
- "NewTabPage.SuggestionsImpression.%s", icon_type_suffix);
+ "NewTabPage.SuggestionsImpression.%s", tile_type_suffix);
LogHistogramEvent(icon_impression_histogram, index, kMaxNumTiles);
}
}
-
- if (have_tile_types) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsReal",
- counts_per_type[ICON_REAL]);
- UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsColor",
- counts_per_type[ICON_COLOR]);
- UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsGray",
- counts_per_type[ICON_DEFAULT]);
- }
}
-void RecordTileClick(int index,
- NTPTileSource source,
- MostVisitedTileType tile_type) {
+void RecordTileClick(int index, TileSource source, TileVisualType tile_type) {
UMA_HISTOGRAM_ENUMERATION("NewTabPage.MostVisited", index, kMaxNumTiles);
std::string histogram = base::StringPrintf(
"NewTabPage.MostVisited.%s", GetSourceHistogramName(source).c_str());
LogHistogramEvent(histogram, index, kMaxNumTiles);
- const char* icon_type_suffix = GetIconTypeSuffix(tile_type);
- if (icon_type_suffix) {
- std::string icon_histogram =
- base::StringPrintf("NewTabPage.MostVisited.%s", icon_type_suffix);
- LogHistogramEvent(icon_histogram, index, kMaxNumTiles);
+ const char* tile_type_suffix = GetTileTypeSuffix(tile_type);
+ if (tile_type_suffix) {
+ std::string tile_type_histogram =
+ base::StringPrintf("NewTabPage.MostVisited.%s", tile_type_suffix);
+ LogHistogramEvent(tile_type_histogram, index, kMaxNumTiles);
}
- if (tile_type < NUM_RECORDED_TILE_TYPES) {
+ if (tile_type <= LAST_RECORDED_TILE_TYPE) {
UMA_HISTOGRAM_ENUMERATION("NewTabPage.TileTypeClicked", tile_type,
- NUM_RECORDED_TILE_TYPES);
+ LAST_RECORDED_TILE_TYPE + 1);
std::string histogram =
base::StringPrintf("NewTabPage.TileTypeClicked.%s",
GetSourceHistogramName(source).c_str());
- LogHistogramEvent(histogram, tile_type, NUM_RECORDED_TILE_TYPES);
+ LogHistogramEvent(histogram, tile_type, LAST_RECORDED_TILE_TYPE + 1);
}
}
diff --git a/chromium/components/ntp_tiles/metrics.h b/chromium/components/ntp_tiles/metrics.h
index 009c4942b8b..187d71960d9 100644
--- a/chromium/components/ntp_tiles/metrics.h
+++ b/chromium/components/ntp_tiles/metrics.h
@@ -9,6 +9,7 @@
#include <vector>
#include "components/ntp_tiles/ntp_tile.h"
+#include "components/ntp_tiles/tile_visual_type.h"
#include "url/gurl.h"
namespace rappor {
@@ -18,40 +19,12 @@ class RapporService;
namespace ntp_tiles {
namespace metrics {
-// The visual type of a most visited tile.
-//
-// These values must stay in sync with the MostVisitedTileType enum
-// in histograms.xml.
-//
-// A Java counterpart will be generated for this enum.
-// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp
-enum MostVisitedTileType {
- // The icon or thumbnail hasn't loaded yet.
- NONE,
- // The item displays a site's actual favicon or touch icon.
- ICON_REAL,
- // The item displays a color derived from the site's favicon or touch icon.
- ICON_COLOR,
- // The item displays a default gray box in place of an icon.
- ICON_DEFAULT,
- // The number of different tile types that get recorded. Entries below this
- // are not recorded in UMA.
- NUM_RECORDED_TILE_TYPES,
- // The item displays a thumbnail of the page. Used on desktop.
- THUMBNAIL,
- // The tile type has not been determined yet. Used on iOS, until we can detect
- // when all tiles have loaded.
- UNKNOWN_TILE_TYPE,
-};
-
struct TileImpression {
- TileImpression(NTPTileSource source,
- MostVisitedTileType type,
- const GURL& url)
+ TileImpression(TileSource source, TileVisualType type, const GURL& url)
: source(source), type(type), url(url) {}
- NTPTileSource source;
- MostVisitedTileType type;
+ TileSource source;
+ TileVisualType type;
GURL url;
};
@@ -62,9 +35,7 @@ void RecordPageImpression(const std::vector<TileImpression>& tiles,
rappor::RapporService* rappor_service);
// Records a click on a tile.
-void RecordTileClick(int index,
- NTPTileSource source,
- MostVisitedTileType tile_type);
+void RecordTileClick(int index, TileSource source, TileVisualType tile_type);
} // namespace metrics
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/metrics_unittest.cc b/chromium/components/ntp_tiles/metrics_unittest.cc
index acb8c5a0ef2..4b5eac9a7d5 100644
--- a/chromium/components/ntp_tiles/metrics_unittest.cc
+++ b/chromium/components/ntp_tiles/metrics_unittest.cc
@@ -24,16 +24,15 @@ using testing::IsEmpty;
TEST(RecordPageImpressionTest, ShouldRecordUmaForIcons) {
base::HistogramTester histogram_tester;
- RecordPageImpression(
- {{NTPTileSource::TOP_SITES, ICON_REAL, GURL()},
- {NTPTileSource::TOP_SITES, ICON_REAL, GURL()},
- {NTPTileSource::TOP_SITES, ICON_REAL, GURL()},
- {NTPTileSource::TOP_SITES, ICON_COLOR, GURL()},
- {NTPTileSource::TOP_SITES, ICON_COLOR, GURL()},
- {NTPTileSource::SUGGESTIONS_SERVICE, ICON_REAL, GURL()},
- {NTPTileSource::SUGGESTIONS_SERVICE, ICON_DEFAULT, GURL()},
- {NTPTileSource::POPULAR, ICON_COLOR, GURL()}},
- /*rappor_service=*/nullptr);
+ RecordPageImpression({{TileSource::TOP_SITES, ICON_REAL, GURL()},
+ {TileSource::TOP_SITES, ICON_REAL, GURL()},
+ {TileSource::TOP_SITES, ICON_REAL, GURL()},
+ {TileSource::TOP_SITES, ICON_COLOR, GURL()},
+ {TileSource::TOP_SITES, ICON_COLOR, GURL()},
+ {TileSource::SUGGESTIONS_SERVICE, ICON_REAL, GURL()},
+ {TileSource::SUGGESTIONS_SERVICE, ICON_DEFAULT, GURL()},
+ {TileSource::POPULAR, ICON_COLOR, GURL()}},
+ /*rappor_service=*/nullptr);
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.NumberOfTiles"),
ElementsAre(base::Bucket(/*min=*/8, /*count=*/1)));
EXPECT_THAT(
@@ -71,13 +70,8 @@ TEST(RecordPageImpressionTest, ShouldRecordUmaForIcons) {
ElementsAre(base::Bucket(/*min=*/ICON_REAL, /*count=*/3),
base::Bucket(/*min=*/ICON_COLOR, /*count=*/2)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.popular"),
- ElementsAre(base::Bucket(/*min=*/ICON_COLOR, /*count=*/1)));
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.IconsReal"),
- ElementsAre(base::Bucket(/*min=*/4, /*count=*/1)));
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.IconsColor"),
- ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.IconsGray"),
- ElementsAre(base::Bucket(/*min=*/1, /*count=*/1)));
+ ElementsAre(base::Bucket(/*min=*/ICON_COLOR,
+ /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples(
"NewTabPage.SuggestionsImpression.IconsReal"),
ElementsAre(base::Bucket(/*min=*/0, /*count=*/1),
@@ -96,9 +90,9 @@ TEST(RecordPageImpressionTest, ShouldRecordUmaForIcons) {
TEST(RecordPageImpressionTest, ShouldRecordUmaForThumbnails) {
base::HistogramTester histogram_tester;
- RecordPageImpression({{NTPTileSource::TOP_SITES, THUMBNAIL, GURL()},
- {NTPTileSource::SUGGESTIONS_SERVICE, THUMBNAIL, GURL()},
- {NTPTileSource::POPULAR, THUMBNAIL, GURL()}},
+ RecordPageImpression({{TileSource::TOP_SITES, THUMBNAIL_FAILED, GURL()},
+ {TileSource::SUGGESTIONS_SERVICE, THUMBNAIL, GURL()},
+ {TileSource::POPULAR, THUMBNAIL, GURL()}},
/*rappor_service=*/nullptr);
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.NumberOfTiles"),
ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
@@ -116,19 +110,15 @@ TEST(RecordPageImpressionTest, ShouldRecordUmaForThumbnails) {
EXPECT_THAT(histogram_tester.GetAllSamples(
"NewTabPage.SuggestionsImpression.popular"),
ElementsAre(base::Bucket(/*min=*/2, /*count=*/1)));
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType"), IsEmpty());
+ EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType"),
+ ElementsAre(base::Bucket(/*min=*/THUMBNAIL, /*count=*/2),
+ base::Bucket(/*min=*/THUMBNAIL_FAILED, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.server"),
- IsEmpty());
+ ElementsAre(base::Bucket(/*min=*/THUMBNAIL, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.client"),
- IsEmpty());
+ ElementsAre(base::Bucket(/*min=*/THUMBNAIL_FAILED, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.popular"),
- IsEmpty());
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.IconsReal"),
- IsEmpty());
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.IconsColor"),
- IsEmpty());
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.IconsGray"),
- IsEmpty());
+ ElementsAre(base::Bucket(/*min=*/THUMBNAIL, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples(
"NewTabPage.SuggestionsImpression.IconsReal"),
IsEmpty());
@@ -140,9 +130,11 @@ TEST(RecordPageImpressionTest, ShouldRecordUmaForThumbnails) {
IsEmpty());
}
-TEST(RecordTileClickTest, ShouldRecordUma) {
+TEST(RecordTileClickTest, ShouldRecordUmaForIcon) {
base::HistogramTester histogram_tester;
- RecordTileClick(3, NTPTileSource::TOP_SITES, ICON_REAL);
+ RecordTileClick(3, TileSource::TOP_SITES, ICON_REAL);
+ EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited"),
+ ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"),
ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
@@ -158,11 +150,55 @@ TEST(RecordTileClickTest, ShouldRecordUma) {
EXPECT_THAT(
histogram_tester.GetAllSamples("NewTabPage.MostVisited.IconsGray"),
IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.Thumbnail"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.ThumbnailFailed"),
+ IsEmpty());
+}
+
+TEST(RecordTileClickTest, ShouldRecordUmaForThumbnail) {
+ base::HistogramTester histogram_tester;
+ RecordTileClick(3, TileSource::TOP_SITES, THUMBNAIL);
+ EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited"),
+ ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
+ EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"),
+ ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
+ EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
+ IsEmpty());
+ EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.IconsReal"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.IconsColor"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.IconsGray"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.Thumbnail"),
+ ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.ThumbnailFailed"),
+ IsEmpty());
}
-TEST(RecordTileClickTest, ShouldIgnoreThumbnails) {
+TEST(RecordTileClickTest, ShouldNotRecordUnknownTileType) {
base::HistogramTester histogram_tester;
- RecordTileClick(3, NTPTileSource::TOP_SITES, THUMBNAIL);
+ RecordTileClick(3, TileSource::TOP_SITES, UNKNOWN_TILE_TYPE);
+ // The click should still get recorded.
+ EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited"),
+ ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
+ EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"),
+ ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
+ EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
+ IsEmpty());
+ EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular"),
+ IsEmpty());
+ // But all of the tile type histograms should be empty.
EXPECT_THAT(
histogram_tester.GetAllSamples("NewTabPage.MostVisited.IconsReal"),
IsEmpty());
@@ -172,19 +208,23 @@ TEST(RecordTileClickTest, ShouldIgnoreThumbnails) {
EXPECT_THAT(
histogram_tester.GetAllSamples("NewTabPage.MostVisited.IconsGray"),
IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.Thumbnail"),
+ IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.ThumbnailFailed"),
+ IsEmpty());
}
TEST(RecordPageImpressionTest, ShouldRecordRappor) {
rappor::TestRapporServiceImpl rappor_service;
RecordPageImpression(
- {{NTPTileSource::TOP_SITES, ICON_REAL, GURL("http://www.site1.com/")},
- {NTPTileSource::TOP_SITES, ICON_COLOR, GURL("http://www.site2.com/")},
- {NTPTileSource::TOP_SITES, ICON_DEFAULT, GURL("http://www.site3.com/")},
- {NTPTileSource::TOP_SITES, THUMBNAIL, GURL("http://www.site4.com/")}},
+ {{TileSource::TOP_SITES, ICON_REAL, GURL("http://www.site1.com/")},
+ {TileSource::TOP_SITES, ICON_COLOR, GURL("http://www.site2.com/")},
+ {TileSource::TOP_SITES, ICON_DEFAULT, GURL("http://www.site3.com/")}},
&rappor_service);
- // Thumbnail shouldn't get reported.
EXPECT_EQ(3, rappor_service.GetReportsCount());
{
@@ -215,6 +255,18 @@ TEST(RecordPageImpressionTest, ShouldRecordRappor) {
}
}
+TEST(RecordPageImpressionTest, ShouldNotRecordRapporForUnknownTileType) {
+ rappor::TestRapporServiceImpl rappor_service;
+
+ RecordPageImpression(
+ {{TileSource::TOP_SITES, ICON_REAL, GURL("http://www.s1.com/")},
+ {TileSource::TOP_SITES, UNKNOWN_TILE_TYPE, GURL("http://www.s2.com/")}},
+ &rappor_service);
+
+ // Unknown tile type shouldn't get reported.
+ EXPECT_EQ(1, rappor_service.GetReportsCount());
+}
+
} // namespace
} // namespace metrics
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/most_visited_sites.cc b/chromium/components/ntp_tiles/most_visited_sites.cc
index 800ccb422c2..6809aa4dcbd 100644
--- a/chromium/components/ntp_tiles/most_visited_sites.cc
+++ b/chromium/components/ntp_tiles/most_visited_sites.cc
@@ -63,7 +63,7 @@ MostVisitedSites::MostVisitedSites(
observer_(nullptr),
num_sites_(0),
top_sites_observer_(this),
- mv_source_(NTPTileSource::TOP_SITES),
+ mv_source_(TileSource::TOP_SITES),
top_sites_weak_ptr_factory_(this) {
DCHECK(prefs_);
// top_sites_ can be null in tests.
@@ -78,15 +78,15 @@ MostVisitedSites::~MostVisitedSites() {
supervisor_->SetObserver(nullptr);
}
-bool MostVisitedSites::DoesSourceExist(NTPTileSource source) const {
+bool MostVisitedSites::DoesSourceExist(TileSource source) const {
switch (source) {
- case NTPTileSource::TOP_SITES:
+ case TileSource::TOP_SITES:
return top_sites_ != nullptr;
- case NTPTileSource::SUGGESTIONS_SERVICE:
+ case TileSource::SUGGESTIONS_SERVICE:
return suggestions_service_ != nullptr;
- case NTPTileSource::POPULAR:
+ case TileSource::POPULAR:
return popular_sites_ != nullptr;
- case NTPTileSource::WHITELIST:
+ case TileSource::WHITELIST:
return supervisor_ != nullptr;
}
NOTREACHED();
@@ -143,7 +143,7 @@ void MostVisitedSites::AddOrRemoveBlacklistedUrl(const GURL& url,
}
// Only blacklist in the server-side suggestions service if it's active.
- if (mv_source_ == NTPTileSource::SUGGESTIONS_SERVICE) {
+ if (mv_source_ == TileSource::SUGGESTIONS_SERVICE) {
if (add_url)
suggestions_service_->BlacklistURL(url);
else
@@ -158,7 +158,7 @@ void MostVisitedSites::ClearBlacklistedUrls() {
}
// Only update the server-side blacklist if it's active.
- if (mv_source_ == NTPTileSource::SUGGESTIONS_SERVICE) {
+ if (mv_source_ == TileSource::SUGGESTIONS_SERVICE) {
suggestions_service_->ClearBlacklist();
}
}
@@ -198,7 +198,7 @@ void MostVisitedSites::OnMostVisitedURLsAvailable(
const history::MostVisitedURLList& visited_list) {
// Ignore the event if tiles provided by the Suggestions Service, which take
// precedence.
- if (mv_source_ == NTPTileSource::SUGGESTIONS_SERVICE) {
+ if (mv_source_ == TileSource::SUGGESTIONS_SERVICE) {
return;
}
@@ -215,21 +215,20 @@ void MostVisitedSites::OnMostVisitedURLsAvailable(
NTPTile tile;
tile.title = visited.title;
tile.url = visited.url;
- tile.source = NTPTileSource::TOP_SITES;
+ tile.source = TileSource::TOP_SITES;
tile.whitelist_icon_path = GetWhitelistLargeIconPath(visited.url);
tiles.push_back(std::move(tile));
}
- mv_source_ = NTPTileSource::TOP_SITES;
- SaveNewTiles(std::move(tiles));
- NotifyMostVisitedURLsObserver();
+ mv_source_ = TileSource::TOP_SITES;
+ SaveNewTilesAndNotify(std::move(tiles));
}
void MostVisitedSites::OnSuggestionsProfileChanged(
const SuggestionsProfile& suggestions_profile) {
if (suggestions_profile.suggestions_size() == 0 &&
- mv_source_ != NTPTileSource::SUGGESTIONS_SERVICE) {
+ mv_source_ != TileSource::SUGGESTIONS_SERVICE) {
return;
}
@@ -248,7 +247,7 @@ void MostVisitedSites::BuildCurrentTilesGivenSuggestionsProfile(
// With no server suggestions, fall back to local TopSites.
if (num_tiles == 0 ||
!base::FeatureList::IsEnabled(kDisplaySuggestionsServiceTiles)) {
- mv_source_ = NTPTileSource::TOP_SITES;
+ mv_source_ = TileSource::TOP_SITES;
InitiateTopSitesQuery();
return;
}
@@ -265,7 +264,7 @@ void MostVisitedSites::BuildCurrentTilesGivenSuggestionsProfile(
NTPTile tile;
tile.title = base::UTF8ToUTF16(suggestion_pb.title());
tile.url = url;
- tile.source = NTPTileSource::SUGGESTIONS_SERVICE;
+ tile.source = TileSource::SUGGESTIONS_SERVICE;
tile.whitelist_icon_path = GetWhitelistLargeIconPath(url);
tile.thumbnail_url = GURL(suggestion_pb.thumbnail());
tile.favicon_url = GURL(suggestion_pb.favicon_url());
@@ -273,9 +272,8 @@ void MostVisitedSites::BuildCurrentTilesGivenSuggestionsProfile(
tiles.push_back(std::move(tile));
}
- mv_source_ = NTPTileSource::SUGGESTIONS_SERVICE;
- SaveNewTiles(std::move(tiles));
- NotifyMostVisitedURLsObserver();
+ mv_source_ = TileSource::SUGGESTIONS_SERVICE;
+ SaveNewTilesAndNotify(std::move(tiles));
}
NTPTilesVector MostVisitedSites::CreateWhitelistEntryPointTiles(
@@ -314,7 +312,7 @@ NTPTilesVector MostVisitedSites::CreateWhitelistEntryPointTiles(
NTPTile tile;
tile.title = whitelist.title;
tile.url = whitelist.entry_point;
- tile.source = NTPTileSource::WHITELIST;
+ tile.source = TileSource::WHITELIST;
tile.whitelist_icon_path = whitelist.large_icon_path;
whitelist_tiles.push_back(std::move(tile));
}
@@ -356,7 +354,7 @@ NTPTilesVector MostVisitedSites::CreatePopularSitesTiles(
NTPTile tile;
tile.title = popular_site.title;
tile.url = GURL(popular_site.url);
- tile.source = NTPTileSource::POPULAR;
+ tile.source = TileSource::POPULAR;
popular_sites_tiles.push_back(std::move(tile));
base::Closure icon_available =
@@ -370,7 +368,7 @@ NTPTilesVector MostVisitedSites::CreatePopularSitesTiles(
return popular_sites_tiles;
}
-void MostVisitedSites::SaveNewTiles(NTPTilesVector personal_tiles) {
+void MostVisitedSites::SaveNewTilesAndNotify(NTPTilesVector personal_tiles) {
NTPTilesVector whitelist_tiles =
CreateWhitelistEntryPointTiles(personal_tiles);
NTPTilesVector popular_sites_tiles =
@@ -380,17 +378,26 @@ void MostVisitedSites::SaveNewTiles(NTPTilesVector personal_tiles) {
popular_sites_tiles.size();
DCHECK_LE(num_actual_tiles, static_cast<size_t>(num_sites_));
- current_tiles_ =
+ NTPTilesVector new_tiles =
MergeTiles(std::move(personal_tiles), std::move(whitelist_tiles),
std::move(popular_sites_tiles));
- DCHECK_EQ(num_actual_tiles, current_tiles_.size());
+ if (current_tiles_.has_value() && (*current_tiles_ == new_tiles)) {
+ return;
+ }
+
+ current_tiles_.emplace(std::move(new_tiles));
+ DCHECK_EQ(num_actual_tiles, current_tiles_->size());
int num_personal_tiles = 0;
- for (const auto& tile : current_tiles_) {
- if (tile.source != NTPTileSource::POPULAR)
+ for (const auto& tile : *current_tiles_) {
+ if (tile.source != TileSource::POPULAR)
num_personal_tiles++;
}
prefs_->SetInteger(prefs::kNumPersonalTiles, num_personal_tiles);
+
+ if (!observer_)
+ return;
+ observer_->OnMostVisitedURLsAvailable(*current_tiles_);
}
// static
@@ -407,13 +414,6 @@ NTPTilesVector MostVisitedSites::MergeTiles(NTPTilesVector personal_tiles,
return merged_tiles;
}
-void MostVisitedSites::NotifyMostVisitedURLsObserver() {
- if (!observer_)
- return;
-
- observer_->OnMostVisitedURLsAvailable(current_tiles_);
-}
-
void MostVisitedSites::OnPopularSitesDownloaded(bool success) {
if (!success) {
LOG(WARNING) << "Download of popular sites failed";
@@ -434,7 +434,7 @@ void MostVisitedSites::TopSitesLoaded(TopSites* top_sites) {}
void MostVisitedSites::TopSitesChanged(TopSites* top_sites,
ChangeReason change_reason) {
- if (mv_source_ == NTPTileSource::TOP_SITES) {
+ if (mv_source_ == TileSource::TOP_SITES) {
// The displayed tiles are invalidated.
InitiateTopSitesQuery();
}
diff --git a/chromium/components/ntp_tiles/most_visited_sites.h b/chromium/components/ntp_tiles/most_visited_sites.h
index 12cf44e6eb2..10473ce6886 100644
--- a/chromium/components/ntp_tiles/most_visited_sites.h
+++ b/chromium/components/ntp_tiles/most_visited_sites.h
@@ -14,12 +14,14 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "base/scoped_observer.h"
#include "base/strings/string16.h"
#include "components/history/core/browser/history_types.h"
#include "components/history/core/browser/top_sites_observer.h"
#include "components/ntp_tiles/ntp_tile.h"
#include "components/ntp_tiles/popular_sites.h"
+#include "components/ntp_tiles/tile_source.h"
#include "components/suggestions/proto/suggestions.pb.h"
#include "components/suggestions/suggestions_service.h"
#include "url/gurl.h"
@@ -104,7 +106,7 @@ class MostVisitedSites : public history::TopSitesObserver,
// Returns true if this object was created with a non-null provider for the
// given NTP tile source. That source may or may not actually provide tiles,
// depending on its configuration and the priority of different sources.
- bool DoesSourceExist(NTPTileSource source) const;
+ bool DoesSourceExist(TileSource source) const;
// Returns the corresponding object passed at construction.
history::TopSites* top_sites() { return top_sites_.get(); }
@@ -120,7 +122,7 @@ class MostVisitedSites : public history::TopSitesObserver,
void SetMostVisitedURLsObserver(Observer* observer, int num_sites);
// Requests an asynchronous refresh of the suggestions. Notifies the observer
- // once the request completes.
+ // if the request resulted in the set of tiles changing.
void Refresh();
void AddOrRemoveBlacklistedUrl(const GURL& url, bool add_url);
@@ -131,8 +133,8 @@ class MostVisitedSites : public history::TopSitesObserver,
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
- // Workhorse for SaveNewTiles. Implemented as a separate static and public
- // method for ease of testing.
+ // Workhorse for SaveNewTilesAndNotify. Implemented as a separate static and
+ // public method for ease of testing.
static NTPTilesVector MergeTiles(NTPTilesVector personal_tiles,
NTPTilesVector whitelist_tiles,
NTPTilesVector popular_tiles);
@@ -172,12 +174,9 @@ class MostVisitedSites : public history::TopSitesObserver,
const NTPTilesVector& whitelist_tiles);
// Takes the personal tiles, creates and merges in whitelist and popular tiles
- // if appropriate, and saves the new tiles.
- void SaveNewTiles(NTPTilesVector personal_tiles);
-
- // Notifies the observer about the availability of tiles.
- // Also records impressions UMA if not done already.
- void NotifyMostVisitedURLsObserver();
+ // if appropriate, and saves the new tiles. Notifies the observer if the tiles
+ // were actually changed.
+ void SaveNewTilesAndNotify(NTPTilesVector personal_tiles);
void OnPopularSitesDownloaded(bool success);
@@ -208,9 +207,12 @@ class MostVisitedSites : public history::TopSitesObserver,
top_sites_observer_;
// The main source of personal tiles - either TOP_SITES or SUGGESTIONS_SEVICE.
- NTPTileSource mv_source_;
+ TileSource mv_source_;
- NTPTilesVector current_tiles_;
+ // Current set of tiles. Optional so that the observer can be notified
+ // whenever it changes, including possibily an initial change from
+ // !current_tiles_.has_value() to current_tiles_->empty().
+ base::Optional<NTPTilesVector> current_tiles_;
// For callbacks may be run after destruction, used exclusively for TopSites
// (since it's used to detect whether there's a query in flight).
diff --git a/chromium/components/ntp_tiles/most_visited_sites_unittest.cc b/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
index 0a7a5b576d7..650b10e925a 100644
--- a/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
+++ b/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
@@ -21,6 +21,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/test/sequenced_worker_pool_owner.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "components/history/core/browser/top_sites.h"
#include "components/history/core/browser/top_sites_observer.h"
#include "components/ntp_tiles/icon_cacher.h"
@@ -86,7 +87,7 @@ ACTION_TEMPLATE(InvokeCallbackArgument,
NTPTile MakeTile(const std::string& title,
const std::string& url,
- NTPTileSource source) {
+ TileSource source) {
NTPTile tile;
tile.title = base::ASCIIToUTF16(title);
tile.url = GURL(url);
@@ -374,15 +375,15 @@ TEST_P(MostVisitedSitesTest, ShouldHandleTopSitesCacheHit) {
EXPECT_CALL(
mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", NTPTileSource::TOP_SITES),
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
MatchesTile("PopularSite1", "http://popularsite1/",
- NTPTileSource::POPULAR),
+ TileSource::POPULAR),
MatchesTile("PopularSite2", "http://popularsite2/",
- NTPTileSource::POPULAR))));
+ TileSource::POPULAR))));
} else {
EXPECT_CALL(mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(MatchesTile(
- "Site 1", "http://site1/", NTPTileSource::TOP_SITES))));
+ "Site 1", "http://site1/", TileSource::TOP_SITES))));
}
EXPECT_CALL(mock_suggestions_service_, FetchSuggestionsData())
.WillOnce(Return(true));
@@ -431,22 +432,22 @@ class MostVisitedSitesWithCacheHitTest : public MostVisitedSitesTest {
EXPECT_CALL(mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(
MatchesTile("Site 1", "http://site1/",
- NTPTileSource::SUGGESTIONS_SERVICE),
+ TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 2", "http://site2/",
- NTPTileSource::SUGGESTIONS_SERVICE),
+ TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 3", "http://site3/",
- NTPTileSource::SUGGESTIONS_SERVICE),
+ TileSource::SUGGESTIONS_SERVICE),
MatchesTile("PopularSite1", "http://popularsite1/",
- NTPTileSource::POPULAR))));
+ TileSource::POPULAR))));
} else {
EXPECT_CALL(mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(
MatchesTile("Site 1", "http://site1/",
- NTPTileSource::SUGGESTIONS_SERVICE),
+ TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 2", "http://site2/",
- NTPTileSource::SUGGESTIONS_SERVICE),
+ TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 3", "http://site3/",
- NTPTileSource::SUGGESTIONS_SERVICE))));
+ TileSource::SUGGESTIONS_SERVICE))));
}
EXPECT_CALL(mock_suggestions_service_, FetchSuggestionsData())
.WillOnce(Return(true));
@@ -467,15 +468,15 @@ TEST_P(MostVisitedSitesWithCacheHitTest, ShouldFavorSuggestionsServiceCache) {
TEST_P(MostVisitedSitesWithCacheHitTest,
ShouldPropagateUpdateBySuggestionsService) {
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 4", "http://site4/",
- NTPTileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 5", "http://site5/",
- NTPTileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 6", "http://site6/",
- NTPTileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 7", "http://site7/",
- NTPTileSource::SUGGESTIONS_SERVICE))));
+ OnMostVisitedURLsAvailable(
+ ElementsAre(MatchesTile("Site 4", "http://site4/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 5", "http://site5/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 6", "http://site6/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 7", "http://site7/",
+ TileSource::SUGGESTIONS_SERVICE))));
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 4", "http://site4/"),
MakeSuggestion("Site 5", "http://site5/"),
@@ -501,16 +502,16 @@ TEST_P(MostVisitedSitesWithCacheHitTest,
EXPECT_CALL(mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(
MatchesTile("Site 4", "http://site4/",
- NTPTileSource::SUGGESTIONS_SERVICE),
+ TileSource::SUGGESTIONS_SERVICE),
MatchesTile("PopularSite1", "http://popularsite1/",
- NTPTileSource::POPULAR),
+ TileSource::POPULAR),
MatchesTile("PopularSite2", "http://popularsite2/",
- NTPTileSource::POPULAR))));
+ TileSource::POPULAR))));
} else {
EXPECT_CALL(
mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(MatchesTile(
- "Site 4", "http://site4/", NTPTileSource::SUGGESTIONS_SERVICE))));
+ "Site 4", "http://site4/", TileSource::SUGGESTIONS_SERVICE))));
}
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 4", "http://site4/")}));
@@ -527,10 +528,10 @@ TEST_P(MostVisitedSitesWithCacheHitTest,
EXPECT_CALL(
mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 4", "http://site4/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 5", "http://site5/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 6", "http://site6/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 7", "http://site7/", NTPTileSource::TOP_SITES))));
+ MatchesTile("Site 4", "http://site4/", TileSource::TOP_SITES),
+ MatchesTile("Site 5", "http://site5/", TileSource::TOP_SITES),
+ MatchesTile("Site 6", "http://site6/", TileSource::TOP_SITES),
+ MatchesTile("Site 7", "http://site7/", TileSource::TOP_SITES))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 4", "http://site4/"),
MakeMostVisitedURL("Site 5", "http://site5/"),
@@ -580,16 +581,16 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
EXPECT_CALL(mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(
MatchesTile("Site 4", "http://site4/",
- NTPTileSource::SUGGESTIONS_SERVICE),
+ TileSource::SUGGESTIONS_SERVICE),
MatchesTile("PopularSite1", "http://popularsite1/",
- NTPTileSource::POPULAR),
+ TileSource::POPULAR),
MatchesTile("PopularSite2", "http://popularsite2/",
- NTPTileSource::POPULAR))));
+ TileSource::POPULAR))));
} else {
EXPECT_CALL(
mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(MatchesTile(
- "Site 4", "http://site4/", NTPTileSource::SUGGESTIONS_SERVICE))));
+ "Site 4", "http://site4/", TileSource::SUGGESTIONS_SERVICE))));
}
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 4", "http://site4/")}));
@@ -600,13 +601,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
ShouldIgnoreTopSitesIfSuggestionsServiceFaster) {
// Reply from suggestions service triggers and update to our observer.
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/",
- NTPTileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 2", "http://site2/",
- NTPTileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 3", "http://site3/",
- NTPTileSource::SUGGESTIONS_SERVICE))));
+ OnMostVisitedURLsAvailable(
+ ElementsAre(MatchesTile("Site 1", "http://site1/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 2", "http://site2/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::SUGGESTIONS_SERVICE))));
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 1", "http://site1/"),
MakeSuggestion("Site 2", "http://site2/"),
@@ -634,9 +635,9 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
EXPECT_CALL(
mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", NTPTileSource::TOP_SITES))));
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 1", "http://site1/"),
MakeMostVisitedURL("Site 2", "http://site2/"),
@@ -650,9 +651,9 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
EXPECT_CALL(
mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", NTPTileSource::TOP_SITES))));
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 1", "http://site1/"),
MakeMostVisitedURL("Site 2", "http://site2/"),
@@ -662,13 +663,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
// Reply from suggestions service overrides top sites.
InSequence seq;
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 4", "http://site4/",
- NTPTileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 5", "http://site5/",
- NTPTileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 6", "http://site6/",
- NTPTileSource::SUGGESTIONS_SERVICE))));
+ OnMostVisitedURLsAvailable(
+ ElementsAre(MatchesTile("Site 4", "http://site4/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 5", "http://site5/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 6", "http://site6/",
+ TileSource::SUGGESTIONS_SERVICE))));
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 4", "http://site4/"),
MakeSuggestion("Site 5", "http://site5/"),
@@ -682,9 +683,9 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
EXPECT_CALL(
mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", NTPTileSource::TOP_SITES))));
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 1", "http://site1/"),
MakeMostVisitedURL("Site 2", "http://site2/"),
@@ -701,9 +702,9 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest, ShouldPropagateUpdateByTopSites) {
EXPECT_CALL(
mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", NTPTileSource::TOP_SITES))));
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 1", "http://site1/"),
MakeMostVisitedURL("Site 2", "http://site2/"),
@@ -724,9 +725,9 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest, ShouldPropagateUpdateByTopSites) {
EXPECT_CALL(
mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 4", "http://site4/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 5", "http://site5/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 6", "http://site6/", NTPTileSource::TOP_SITES))));
+ MatchesTile("Site 4", "http://site4/", TileSource::TOP_SITES),
+ MatchesTile("Site 5", "http://site5/", TileSource::TOP_SITES),
+ MatchesTile("Site 6", "http://site6/", TileSource::TOP_SITES))));
mock_top_sites_->NotifyTopSitesChanged(
history::TopSitesObserver::ChangeReason::MOST_VISITED);
base::RunLoop().RunUntilIdle();
@@ -738,10 +739,12 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
EXPECT_CALL(mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(
MatchesTile("PopularSite1", "http://popularsite1/",
- NTPTileSource::POPULAR),
+ TileSource::POPULAR),
MatchesTile("PopularSite2", "http://popularsite2/",
- NTPTileSource::POPULAR))));
+ TileSource::POPULAR))));
} else {
+ // The Android NTP doesn't finish initialization until it gets tiles, so a
+ // 0-tile notification is always needed.
EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(IsEmpty()));
}
suggestions_service_callbacks_.Notify(SuggestionsProfile());
@@ -751,14 +754,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
}
TEST_P(MostVisitedSitesWithEmptyCacheTest,
- ShouldRepeatedlyNotifyObserverIfTopSitesNotifies) {
+ ShouldNotifyOnceIfTopSitesUnchanged) {
EXPECT_CALL(
mock_observer_,
OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", NTPTileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", NTPTileSource::TOP_SITES))))
- .Times(5);
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
suggestions_service_callbacks_.Notify(SuggestionsProfile());
@@ -783,16 +785,15 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
}
TEST_P(MostVisitedSitesWithEmptyCacheTest,
- ShouldRepeatedlyNotifyObserverIfSuggestionsServiceNotifies) {
+ ShouldNotifyOnceIfSuggestionsUnchanged) {
EXPECT_CALL(mock_observer_,
OnMostVisitedURLsAvailable(
ElementsAre(MatchesTile("Site 1", "http://site1/",
- NTPTileSource::SUGGESTIONS_SERVICE),
+ TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 2", "http://site2/",
- NTPTileSource::SUGGESTIONS_SERVICE),
+ TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 3", "http://site3/",
- NTPTileSource::SUGGESTIONS_SERVICE))))
- .Times(5);
+ TileSource::SUGGESTIONS_SERVICE))));
for (int i = 0; i < 5; ++i) {
suggestions_service_callbacks_.Notify(
@@ -815,10 +816,10 @@ INSTANTIATE_TEST_CASE_P(MostVisitedSitesWithEmptyCacheTest,
// - Ensuring personal tiles are not duplicated in popular tiles.
TEST(MostVisitedSitesMergeTest, ShouldMergeTilesWithPersonalOnly) {
std::vector<NTPTile> personal_tiles{
- MakeTile("Site 1", "https://www.site1.com/", NTPTileSource::TOP_SITES),
- MakeTile("Site 2", "https://www.site2.com/", NTPTileSource::TOP_SITES),
- MakeTile("Site 3", "https://www.site3.com/", NTPTileSource::TOP_SITES),
- MakeTile("Site 4", "https://www.site4.com/", NTPTileSource::TOP_SITES),
+ MakeTile("Site 1", "https://www.site1.com/", TileSource::TOP_SITES),
+ MakeTile("Site 2", "https://www.site2.com/", TileSource::TOP_SITES),
+ MakeTile("Site 3", "https://www.site3.com/", TileSource::TOP_SITES),
+ MakeTile("Site 4", "https://www.site4.com/", TileSource::TOP_SITES),
};
// Without any popular tiles, the result after merge should be the personal
// tiles.
@@ -826,21 +827,21 @@ TEST(MostVisitedSitesMergeTest, ShouldMergeTilesWithPersonalOnly) {
/*whitelist_tiles=*/NTPTilesVector(),
/*popular_tiles=*/NTPTilesVector()),
ElementsAre(MatchesTile("Site 1", "https://www.site1.com/",
- NTPTileSource::TOP_SITES),
+ TileSource::TOP_SITES),
MatchesTile("Site 2", "https://www.site2.com/",
- NTPTileSource::TOP_SITES),
+ TileSource::TOP_SITES),
MatchesTile("Site 3", "https://www.site3.com/",
- NTPTileSource::TOP_SITES),
+ TileSource::TOP_SITES),
MatchesTile("Site 4", "https://www.site4.com/",
- NTPTileSource::TOP_SITES)));
+ TileSource::TOP_SITES)));
}
TEST(MostVisitedSitesMergeTest, ShouldMergeTilesWithPopularOnly) {
std::vector<NTPTile> popular_tiles{
- MakeTile("Site 1", "https://www.site1.com/", NTPTileSource::POPULAR),
- MakeTile("Site 2", "https://www.site2.com/", NTPTileSource::POPULAR),
- MakeTile("Site 3", "https://www.site3.com/", NTPTileSource::POPULAR),
- MakeTile("Site 4", "https://www.site4.com/", NTPTileSource::POPULAR),
+ MakeTile("Site 1", "https://www.site1.com/", TileSource::POPULAR),
+ MakeTile("Site 2", "https://www.site2.com/", TileSource::POPULAR),
+ MakeTile("Site 3", "https://www.site3.com/", TileSource::POPULAR),
+ MakeTile("Site 4", "https://www.site4.com/", TileSource::POPULAR),
};
// Without any personal tiles, the result after merge should be the popular
// tiles.
@@ -848,37 +849,35 @@ TEST(MostVisitedSitesMergeTest, ShouldMergeTilesWithPopularOnly) {
MostVisitedSites::MergeTiles(/*personal_tiles=*/NTPTilesVector(),
/*whitelist_tiles=*/NTPTilesVector(),
/*popular_tiles=*/std::move(popular_tiles)),
- ElementsAre(MatchesTile("Site 1", "https://www.site1.com/",
- NTPTileSource::POPULAR),
- MatchesTile("Site 2", "https://www.site2.com/",
- NTPTileSource::POPULAR),
- MatchesTile("Site 3", "https://www.site3.com/",
- NTPTileSource::POPULAR),
- MatchesTile("Site 4", "https://www.site4.com/",
- NTPTileSource::POPULAR)));
+ ElementsAre(
+ MatchesTile("Site 1", "https://www.site1.com/", TileSource::POPULAR),
+ MatchesTile("Site 2", "https://www.site2.com/", TileSource::POPULAR),
+ MatchesTile("Site 3", "https://www.site3.com/", TileSource::POPULAR),
+ MatchesTile("Site 4", "https://www.site4.com/",
+ TileSource::POPULAR)));
}
TEST(MostVisitedSitesMergeTest, ShouldMergeTilesFavoringPersonalOverPopular) {
std::vector<NTPTile> popular_tiles{
- MakeTile("Site 1", "https://www.site1.com/", NTPTileSource::POPULAR),
- MakeTile("Site 2", "https://www.site2.com/", NTPTileSource::POPULAR),
+ MakeTile("Site 1", "https://www.site1.com/", TileSource::POPULAR),
+ MakeTile("Site 2", "https://www.site2.com/", TileSource::POPULAR),
};
std::vector<NTPTile> personal_tiles{
- MakeTile("Site 3", "https://www.site3.com/", NTPTileSource::TOP_SITES),
- MakeTile("Site 4", "https://www.site4.com/", NTPTileSource::TOP_SITES),
+ MakeTile("Site 3", "https://www.site3.com/", TileSource::TOP_SITES),
+ MakeTile("Site 4", "https://www.site4.com/", TileSource::TOP_SITES),
};
EXPECT_THAT(
MostVisitedSites::MergeTiles(std::move(personal_tiles),
/*whitelist_tiles=*/NTPTilesVector(),
/*popular_tiles=*/std::move(popular_tiles)),
- ElementsAre(MatchesTile("Site 3", "https://www.site3.com/",
- NTPTileSource::TOP_SITES),
- MatchesTile("Site 4", "https://www.site4.com/",
- NTPTileSource::TOP_SITES),
- MatchesTile("Site 1", "https://www.site1.com/",
- NTPTileSource::POPULAR),
- MatchesTile("Site 2", "https://www.site2.com/",
- NTPTileSource::POPULAR)));
+ ElementsAre(
+ MatchesTile("Site 3", "https://www.site3.com/",
+ TileSource::TOP_SITES),
+ MatchesTile("Site 4", "https://www.site4.com/",
+ TileSource::TOP_SITES),
+ MatchesTile("Site 1", "https://www.site1.com/", TileSource::POPULAR),
+ MatchesTile("Site 2", "https://www.site2.com/",
+ TileSource::POPULAR)));
}
} // namespace
diff --git a/chromium/components/ntp_tiles/ntp_tile.cc b/chromium/components/ntp_tiles/ntp_tile.cc
index ece28625aa4..ea2a62f209c 100644
--- a/chromium/components/ntp_tiles/ntp_tile.cc
+++ b/chromium/components/ntp_tiles/ntp_tile.cc
@@ -6,10 +6,21 @@
namespace ntp_tiles {
-NTPTile::NTPTile() : source(NTPTileSource::TOP_SITES) {}
+NTPTile::NTPTile() : source(TileSource::TOP_SITES) {}
NTPTile::NTPTile(const NTPTile&) = default;
NTPTile::~NTPTile() {}
+bool operator==(const NTPTile& a, const NTPTile& b) {
+ return (a.title == b.title) && (a.url == b.url) && (a.source == b.source) &&
+ (a.whitelist_icon_path == b.whitelist_icon_path) &&
+ (a.thumbnail_url == b.thumbnail_url) &&
+ (a.favicon_url == b.favicon_url);
+}
+
+bool operator!=(const NTPTile& a, const NTPTile& b) {
+ return !(a == b);
+}
+
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/ntp_tile.h b/chromium/components/ntp_tiles/ntp_tile.h
index e64a19fa6be..a80fc0f03e4 100644
--- a/chromium/components/ntp_tiles/ntp_tile.h
+++ b/chromium/components/ntp_tiles/ntp_tile.h
@@ -10,7 +10,7 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/strings/string16.h"
-#include "components/ntp_tiles/ntp_tile_source.h"
+#include "components/ntp_tiles/tile_source.h"
#include "url/gurl.h"
namespace ntp_tiles {
@@ -19,7 +19,7 @@ namespace ntp_tiles {
struct NTPTile {
base::string16 title;
GURL url;
- NTPTileSource source;
+ TileSource source;
// Empty unless whitelists are enabled and this site is in a whitelist.
// However, may be non-empty even if |source| is not |WHITELIST|, if this tile
@@ -37,6 +37,9 @@ struct NTPTile {
~NTPTile();
};
+bool operator==(const NTPTile& a, const NTPTile& b);
+bool operator!=(const NTPTile& a, const NTPTile& b);
+
using NTPTilesVector = std::vector<NTPTile>;
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/popular_sites_impl.cc b/chromium/components/ntp_tiles/popular_sites_impl.cc
index 97867178500..f083770a26e 100644
--- a/chromium/components/ntp_tiles/popular_sites_impl.cc
+++ b/chromium/components/ntp_tiles/popular_sites_impl.cc
@@ -332,8 +332,7 @@ void PopularSitesImpl::RegisterProfilePrefs(
user_prefs->RegisterInt64Pref(kPopularSitesLastDownloadPref, 0);
user_prefs->RegisterStringPref(kPopularSitesURLPref, std::string());
- user_prefs->RegisterListPref(kPopularSitesJsonPref,
- DefaultPopularSites().release());
+ user_prefs->RegisterListPref(kPopularSitesJsonPref, DefaultPopularSites());
}
void PopularSitesImpl::FetchPopularSites() {
@@ -380,8 +379,9 @@ void PopularSitesImpl::OnURLFetchComplete(const net::URLFetcher* source) {
return;
}
- parse_json_.Run(json_string, base::Bind(&PopularSitesImpl::OnJsonParsed,
- weak_ptr_factory_.GetWeakPtr()),
+ parse_json_.Run(json_string,
+ base::Bind(&PopularSitesImpl::OnJsonParsed,
+ weak_ptr_factory_.GetWeakPtr()),
base::Bind(&PopularSitesImpl::OnJsonParseFailed,
weak_ptr_factory_.GetWeakPtr()));
}
diff --git a/chromium/components/ntp_tiles/switches.cc b/chromium/components/ntp_tiles/switches.cc
index 6a76ba14431..9ae60506c5d 100644
--- a/chromium/components/ntp_tiles/switches.cc
+++ b/chromium/components/ntp_tiles/switches.cc
@@ -13,10 +13,10 @@ const char kEnableNTPSearchEngineCountryDetection[] =
"enable-ntp-search-engine-country-detection";
// Enables showing popular sites on the NTP.
-const char kEnableNTPPopularSites[] = "enable-ntp-popular-sites";
+const char kEnableNTPPopularSites[] = "enable-ntp-popular-sites";
// Disables showing popular sites on the NTP.
-const char kDisableNTPPopularSites[] = "disable-ntp-popular-sites";
+const char kDisableNTPPopularSites[] = "disable-ntp-popular-sites";
} // namespace switches
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/ntp_tile_source.h b/chromium/components/ntp_tiles/tile_source.h
index 1ac85a91b71..f8aec297ad2 100644
--- a/chromium/components/ntp_tiles/ntp_tile_source.h
+++ b/chromium/components/ntp_tiles/tile_source.h
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_NTP_TILES_NTP_TILE_SOURCE_H_
-#define COMPONENTS_NTP_TILES_NTP_TILE_SOURCE_H_
+#ifndef COMPONENTS_NTP_TILES_TILE_SOURCE_H_
+#define COMPONENTS_NTP_TILES_TILE_SOURCE_H_
namespace ntp_tiles {
// The source of an NTP tile.
// A Java counterpart will be generated for this enum.
-// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp
-enum class NTPTileSource {
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.suggestions
+enum class TileSource {
// Tile comes from the personal top sites list, based on local history.
TOP_SITES,
// Tile comes from the suggestions service, based on synced history.
@@ -25,4 +25,4 @@ enum class NTPTileSource {
} // namespace ntp_tiles
-#endif // COMPONENTS_NTP_TILES_NTP_TILE_SOURCE_H_
+#endif // COMPONENTS_NTP_TILES_TILE_SOURCE_H_
diff --git a/chromium/components/ntp_tiles/tile_visual_type.h b/chromium/components/ntp_tiles/tile_visual_type.h
new file mode 100644
index 00000000000..05318d45ca2
--- /dev/null
+++ b/chromium/components/ntp_tiles/tile_visual_type.h
@@ -0,0 +1,46 @@
+// 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_NTP_TILES_TILE_VISUAL_TYPE_H_
+#define COMPONENTS_NTP_TILES_TILE_VISUAL_TYPE_H_
+
+namespace ntp_tiles {
+
+// The visual type of an NTP tile.
+//
+// These values must stay in sync with the NTPTileVisualType enum in
+// histograms.xml.
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.suggestions
+enum TileVisualType {
+ // The icon or thumbnail hasn't loaded yet.
+ NONE = 0,
+ // The item displays a site's actual favicon or touch icon.
+ ICON_REAL = 1,
+ // The item displays a color derived from the site's favicon or touch icon.
+ ICON_COLOR = 2,
+ // The item displays a default gray box in place of an icon.
+ ICON_DEFAULT = 3,
+ // Deleted: THUMBNAIL_LOCAL = 4
+ // Deleted: THUMBNAIL_SERVER = 5
+ // Deleted: THUMBNAIL_DEFAULT = 6
+ // The item displays a thumbnail of the page. Used on desktop.
+ THUMBNAIL = 7,
+ // The item wants to display a thumbnail of the page, but it failed to load.
+ // Used on desktop.
+ THUMBNAIL_FAILED = 8,
+ // The maximum tile type value that gets recorded in UMA.
+ LAST_RECORDED_TILE_TYPE = THUMBNAIL_FAILED,
+
+ // The tile type has not been determined yet. Used on iOS, until we can detect
+ // when all tiles have loaded.
+ UNKNOWN_TILE_TYPE,
+
+ TILE_TYPE_MAX = UNKNOWN_TILE_TYPE
+};
+
+} // namespace ntp_tiles
+
+#endif // COMPONENTS_NTP_TILES_TILE_VISUAL_TYPE_H_
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 e362f777501..7cc00477154 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
@@ -34,11 +34,6 @@ std::string FormatJson(const base::Value& value) {
} // namespace
-NTPTilesInternalsMessageHandlerClient::NTPTilesInternalsMessageHandlerClient() =
- default;
-NTPTilesInternalsMessageHandlerClient::
- ~NTPTilesInternalsMessageHandlerClient() = default;
-
NTPTilesInternalsMessageHandler::NTPTilesInternalsMessageHandler()
: client_(nullptr), site_count_(8), weak_ptr_factory_(this) {}
@@ -103,7 +98,7 @@ void NTPTilesInternalsMessageHandler::HandleUpdate(
PrefService* prefs = client_->GetPrefs();
- if (most_visited_sites_->DoesSourceExist(ntp_tiles::NTPTileSource::POPULAR)) {
+ if (most_visited_sites_->DoesSourceExist(ntp_tiles::TileSource::POPULAR)) {
popular_sites_json_.clear();
std::string url;
@@ -144,7 +139,7 @@ void NTPTilesInternalsMessageHandler::HandleFetchSuggestions(
const base::ListValue* args) {
DCHECK_EQ(0u, args->GetSize());
if (!most_visited_sites_->DoesSourceExist(
- ntp_tiles::NTPTileSource::SUGGESTIONS_SERVICE)) {
+ ntp_tiles::TileSource::SUGGESTIONS_SERVICE)) {
return;
}
@@ -159,13 +154,12 @@ void NTPTilesInternalsMessageHandler::HandleFetchSuggestions(
void NTPTilesInternalsMessageHandler::HandleViewPopularSitesJson(
const base::ListValue* args) {
DCHECK_EQ(0u, args->GetSize());
- if (!most_visited_sites_->DoesSourceExist(
- ntp_tiles::NTPTileSource::POPULAR)) {
+ if (!most_visited_sites_->DoesSourceExist(ntp_tiles::TileSource::POPULAR)) {
return;
}
- popular_sites_json_ = FormatJson(
- *most_visited_sites_->popular_sites()->GetCachedJson());
+ popular_sites_json_ =
+ FormatJson(*most_visited_sites_->popular_sites()->GetCachedJson());
SendSourceInfo();
}
@@ -173,19 +167,18 @@ void NTPTilesInternalsMessageHandler::SendSourceInfo() {
PrefService* prefs = client_->GetPrefs();
base::DictionaryValue value;
- value.SetBoolean("topSites", most_visited_sites_->DoesSourceExist(
- NTPTileSource::TOP_SITES));
- value.SetBoolean("whitelist", most_visited_sites_->DoesSourceExist(
- NTPTileSource::WHITELIST));
+ value.SetBoolean("topSites",
+ most_visited_sites_->DoesSourceExist(TileSource::TOP_SITES));
+ value.SetBoolean("whitelist",
+ most_visited_sites_->DoesSourceExist(TileSource::WHITELIST));
- if (most_visited_sites_->DoesSourceExist(
- NTPTileSource::SUGGESTIONS_SERVICE)) {
+ if (most_visited_sites_->DoesSourceExist(TileSource::SUGGESTIONS_SERVICE)) {
value.SetString("suggestionsService.status", suggestions_status_);
} else {
value.SetBoolean("suggestionsService", false);
}
- if (most_visited_sites_->DoesSourceExist(NTPTileSource::POPULAR)) {
+ if (most_visited_sites_->DoesSourceExist(TileSource::POPULAR)) {
auto* popular_sites = most_visited_sites_->popular_sites();
value.SetString("popular.url", popular_sites->GetURLToFetch().spec());
value.SetString("popular.country", popular_sites->GetCountryToFetch());
diff --git a/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h b/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h
index d8463615dbd..456f52e1994 100644
--- a/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h
+++ b/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h
@@ -11,7 +11,7 @@
#include "base/callback_forward.h"
#include "base/macros.h"
-#include "components/ntp_tiles/ntp_tile_source.h"
+#include "components/ntp_tiles/tile_source.h"
class PrefService;
@@ -35,7 +35,7 @@ class NTPTilesInternalsMessageHandlerClient {
// Returns true if the given source is enabled (even if, in practice, none of
// the tiles would come from it).
- virtual bool DoesSourceExist(NTPTileSource source) = 0;
+ virtual bool DoesSourceExist(TileSource source) = 0;
// Creates a new MostVisitedSites based on the context pf the WebUI page.
virtual std::unique_ptr<ntp_tiles::MostVisitedSites>
diff --git a/chromium/components/ntp_tiles/webui/popular_sites_internals_message_handler.cc b/chromium/components/ntp_tiles/webui/popular_sites_internals_message_handler.cc
index 29e69b93eb4..7163b59fd88 100644
--- a/chromium/components/ntp_tiles/webui/popular_sites_internals_message_handler.cc
+++ b/chromium/components/ntp_tiles/webui/popular_sites_internals_message_handler.cc
@@ -114,12 +114,12 @@ void PopularSitesInternalsMessageHandler::SendOverrides() {
std::string version =
prefs->GetString(ntp_tiles::prefs::kPopularSitesOverrideVersion);
web_ui_->CallJavascriptFunction(
- "chrome.popular_sites_internals.receiveOverrides", base::StringValue(url),
- base::StringValue(country), base::StringValue(version));
+ "chrome.popular_sites_internals.receiveOverrides", base::Value(url),
+ base::Value(country), base::Value(version));
}
void PopularSitesInternalsMessageHandler::SendDownloadResult(bool success) {
- base::StringValue result(success ? "Success" : "Fail");
+ base::Value result(success ? "Success" : "Fail");
web_ui_->CallJavascriptFunction(
"chrome.popular_sites_internals.receiveDownloadResult", result);
}
@@ -142,7 +142,7 @@ void PopularSitesInternalsMessageHandler::SendSites() {
void PopularSitesInternalsMessageHandler::SendJson(const std::string& json) {
web_ui_->CallJavascriptFunction("chrome.popular_sites_internals.receiveJson",
- base::StringValue(json));
+ base::Value(json));
}
void PopularSitesInternalsMessageHandler::OnPopularSitesAvailable(
diff --git a/chromium/components/offline_items_collection/OWNERS b/chromium/components/offline_items_collection/OWNERS
new file mode 100644
index 00000000000..20949be2e1f
--- /dev/null
+++ b/chromium/components/offline_items_collection/OWNERS
@@ -0,0 +1,6 @@
+dimich@chromium.org
+dtrainor@chromium.org
+fgorski@chromium.org
+qinmin@chromium.org
+
+# COMPONENT: UI>Browser>Downloads
diff --git a/chromium/components/offline_items_collection/core/BUILD.gn b/chromium/components/offline_items_collection/core/BUILD.gn
new file mode 100644
index 00000000000..ee5d1350792
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/BUILD.gn
@@ -0,0 +1,96 @@
+# 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) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+
+static_library("core") {
+ sources = [
+ "offline_content_aggregator.cc",
+ "offline_content_aggregator.h",
+ "offline_content_provider.h",
+ "offline_item.cc",
+ "offline_item.h",
+ "offline_item_filter.h",
+ "offline_item_state.h",
+ "throttled_offline_content_provider.cc",
+ "throttled_offline_content_provider.h",
+ ]
+
+ public_deps = [
+ "//base",
+ "//components/keyed_service/core",
+ "//url",
+ ]
+
+ deps = []
+
+ if (is_android) {
+ sources += [
+ "android/offline_content_aggregator_bridge.cc",
+ "android/offline_content_aggregator_bridge.h",
+ "android/offline_item_bridge.cc",
+ "android/offline_item_bridge.h",
+ ]
+
+ deps += [ ":jni_headers" ]
+ }
+}
+
+source_set("unit_tests") {
+ testonly = true
+
+ sources = [
+ "offline_content_aggregator_unittest.cc",
+ "throttled_offline_content_provider_unittest.cc",
+ ]
+
+ deps = [
+ ":core",
+ "//base/test:test_support",
+ "//components/offline_items_collection/core/test_support",
+ ]
+}
+
+if (is_android) {
+ android_library("core_java") {
+ java_files = [
+ "android/java/src/org/chromium/components/offline_items_collection/ContentId.java",
+ "android/java/src/org/chromium/components/offline_items_collection/LegacyHelpers.java",
+ "android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java",
+ "android/java/src/org/chromium/components/offline_items_collection/OfflineContentProvider.java",
+ "android/java/src/org/chromium/components/offline_items_collection/OfflineItem.java",
+ "android/java/src/org/chromium/components/offline_items_collection/OfflineItemBridge.java",
+ ]
+
+ srcjar_deps = [ ":jni_enums" ]
+
+ deps = [
+ "//base:base_java",
+ "//third_party/android_tools:android_support_annotations_java",
+ ]
+ }
+
+ generate_jni("jni_headers") {
+ visibility = [ ":*" ]
+
+ sources = [
+ "android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java",
+ "android/java/src/org/chromium/components/offline_items_collection/OfflineItemBridge.java",
+ ]
+
+ jni_package = "components/offline_items_collection/core/android"
+ }
+
+ java_cpp_enum("jni_enums") {
+ visibility = [ ":*" ]
+
+ sources = [
+ "offline_item_filter.h",
+ "offline_item_state.h",
+ ]
+ }
+}
diff --git a/chromium/components/offline_items_collection/core/DEPS b/chromium/components/offline_items_collection/core/DEPS
new file mode 100644
index 00000000000..bf267f99ddd
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/DEPS
@@ -0,0 +1,8 @@
+include_rules = [
+ "+base",
+ "+components/keyed_service",
+ "+components/offline_pages",
+ "+jni",
+ "+testing",
+ "+url",
+]
diff --git a/chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc b/chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc
new file mode 100644
index 00000000000..70184f92a2e
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc
@@ -0,0 +1,176 @@
+// 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/offline_items_collection/core/android/offline_content_aggregator_bridge.h"
+
+#include "base/android/jni_string.h"
+#include "components/offline_items_collection/core/android/offline_item_bridge.h"
+#include "components/offline_items_collection/core/offline_item.h"
+#include "jni/OfflineContentAggregatorBridge_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
+namespace offline_items_collection {
+namespace android {
+
+namespace {
+const char kOfflineContentAggregatorBridgeUserDataKey[] = "aggregator_bridge";
+
+ContentId CreateContentId(JNIEnv* env,
+ const JavaParamRef<jstring>& j_namespace,
+ const JavaParamRef<jstring>& j_id) {
+ return ContentId(ConvertJavaStringToUTF8(env, j_namespace),
+ ConvertJavaStringToUTF8(env, j_id));
+}
+
+} // namespace
+
+// static.
+bool OfflineContentAggregatorBridge::Register(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+// static
+base::android::ScopedJavaLocalRef<jobject>
+OfflineContentAggregatorBridge::GetBridgeForOfflineContentAggregator(
+ OfflineContentAggregator* aggregator) {
+ if (!aggregator->GetUserData(kOfflineContentAggregatorBridgeUserDataKey)) {
+ aggregator->SetUserData(kOfflineContentAggregatorBridgeUserDataKey,
+ new OfflineContentAggregatorBridge(aggregator));
+ }
+ OfflineContentAggregatorBridge* bridge =
+ static_cast<OfflineContentAggregatorBridge*>(
+ aggregator->GetUserData(kOfflineContentAggregatorBridgeUserDataKey));
+
+ return ScopedJavaLocalRef<jobject>(bridge->java_ref_);
+}
+
+OfflineContentAggregatorBridge::OfflineContentAggregatorBridge(
+ OfflineContentAggregator* aggregator)
+ : aggregator_(aggregator) {
+ JNIEnv* env = AttachCurrentThread();
+ java_ref_.Reset(Java_OfflineContentAggregatorBridge_create(
+ env, reinterpret_cast<intptr_t>(this)));
+
+ aggregator_->AddObserver(this);
+}
+
+OfflineContentAggregatorBridge::~OfflineContentAggregatorBridge() {
+ // TODO(dtrainor): Do not need to unregister because in the destructor of the
+ // base class of OfflineContentAggregator. Is |observers_| already dead?
+ aggregator_->RemoveObserver(this);
+
+ Java_OfflineContentAggregatorBridge_onNativeDestroyed(AttachCurrentThread(),
+ java_ref_.obj());
+}
+
+jboolean OfflineContentAggregatorBridge::AreItemsAvailable(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& jobj) {
+ return aggregator_->AreItemsAvailable();
+}
+
+void OfflineContentAggregatorBridge::OpenItem(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& jobj,
+ const JavaParamRef<jstring>& j_namespace,
+ const JavaParamRef<jstring>& j_id) {
+ aggregator_->OpenItem(CreateContentId(env, j_namespace, j_id));
+}
+
+void OfflineContentAggregatorBridge::RemoveItem(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& jobj,
+ const JavaParamRef<jstring>& j_namespace,
+ const JavaParamRef<jstring>& j_id) {
+ aggregator_->RemoveItem(CreateContentId(env, j_namespace, j_id));
+}
+
+void OfflineContentAggregatorBridge::CancelDownload(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& jobj,
+ const JavaParamRef<jstring>& j_namespace,
+ const JavaParamRef<jstring>& j_id) {
+ aggregator_->CancelDownload(CreateContentId(env, j_namespace, j_id));
+}
+
+void OfflineContentAggregatorBridge::PauseDownload(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& jobj,
+ const JavaParamRef<jstring>& j_namespace,
+ const JavaParamRef<jstring>& j_guid) {
+ aggregator_->PauseDownload(CreateContentId(env, j_namespace, j_guid));
+}
+
+void OfflineContentAggregatorBridge::ResumeDownload(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& jobj,
+ const JavaParamRef<jstring>& j_namespace,
+ const JavaParamRef<jstring>& j_id) {
+ aggregator_->ResumeDownload(CreateContentId(env, j_namespace, j_id));
+}
+
+ScopedJavaLocalRef<jobject> OfflineContentAggregatorBridge::GetItemById(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& jobj,
+ const JavaParamRef<jstring>& j_namespace,
+ const JavaParamRef<jstring>& j_id) {
+ const OfflineItem* item =
+ aggregator_->GetItemById(CreateContentId(env, j_namespace, j_id));
+
+ return OfflineItemBridge::CreateOfflineItem(env, item);
+}
+
+ScopedJavaLocalRef<jobject> OfflineContentAggregatorBridge::GetAllItems(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& jobj) {
+ return OfflineItemBridge::CreateOfflineItemList(env,
+ aggregator_->GetAllItems());
+}
+
+void OfflineContentAggregatorBridge::OnItemsAvailable(
+ OfflineContentProvider* provider) {
+ if (java_ref_.is_null())
+ return;
+
+ JNIEnv* env = AttachCurrentThread();
+ Java_OfflineContentAggregatorBridge_onItemsAvailable(env, java_ref_.obj());
+}
+
+void OfflineContentAggregatorBridge::OnItemsAdded(
+ const OfflineContentProvider::OfflineItemList& items) {
+ if (java_ref_.is_null())
+ return;
+
+ JNIEnv* env = AttachCurrentThread();
+ Java_OfflineContentAggregatorBridge_onItemsAdded(
+ env, java_ref_.obj(),
+ OfflineItemBridge::CreateOfflineItemList(env, items));
+}
+
+void OfflineContentAggregatorBridge::OnItemRemoved(const ContentId& id) {
+ if (java_ref_.is_null())
+ return;
+
+ JNIEnv* env = AttachCurrentThread();
+ Java_OfflineContentAggregatorBridge_onItemRemoved(
+ env, java_ref_.obj(), ConvertUTF8ToJavaString(env, id.name_space),
+ ConvertUTF8ToJavaString(env, id.id));
+}
+
+void OfflineContentAggregatorBridge::OnItemUpdated(const OfflineItem& item) {
+ if (java_ref_.is_null())
+ return;
+
+ JNIEnv* env = AttachCurrentThread();
+ Java_OfflineContentAggregatorBridge_onItemUpdated(
+ env, java_ref_.obj(), OfflineItemBridge::CreateOfflineItem(env, &item));
+}
+
+} // namespace android
+} // namespace offline_items_collection
diff --git a/chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h b/chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h
new file mode 100644
index 00000000000..5a291c6f1d6
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h
@@ -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.
+
+#ifndef COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_CONTENT_AGGREGATOR_BRIDGE_H_
+#define COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_CONTENT_AGGREGATOR_BRIDGE_H_
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/supports_user_data.h"
+#include "components/offline_items_collection/core/offline_content_aggregator.h"
+#include "components/offline_items_collection/core/offline_content_provider.h"
+
+namespace offline_items_collection {
+
+struct ContentId;
+struct OfflineItem;
+
+namespace android {
+
+// A helper class responsible for bridging an OfflineContentAggregator from C++
+// to Java. This class attaches as a piece of SupportsUserData::Data to the
+// OfflineContentAggregator and can only be created through the
+// GetForOfflineContentAggregator() method.
+// This class creates and contains a strong reference to it's Java counterpart,
+// so the Java bridge will live as long as this class lives. For more
+// information on the Java counterpart see OfflineContentAggregatorBridge.java.
+class OfflineContentAggregatorBridge : public OfflineContentProvider::Observer,
+ public base::SupportsUserData::Data {
+ public:
+ // Helper method to initialize the JNI hooks between Java and C++.
+ static bool Register(JNIEnv* env);
+
+ // Returns a Java OfflineContentAggregatorBridge for |aggregator|. There will
+ // be only one bridge per OfflineContentAggregator.
+ static base::android::ScopedJavaLocalRef<jobject>
+ GetBridgeForOfflineContentAggregator(OfflineContentAggregator* aggregator);
+
+ ~OfflineContentAggregatorBridge() override;
+
+ // Methods called from Java via JNI.
+ jboolean AreItemsAvailable(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj);
+ void OpenItem(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& j_namespace,
+ const base::android::JavaParamRef<jstring>& j_id);
+ void RemoveItem(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& j_namespace,
+ const base::android::JavaParamRef<jstring>& j_id);
+ void CancelDownload(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& j_namespace,
+ const base::android::JavaParamRef<jstring>& j_id);
+ void PauseDownload(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& j_namespace,
+ const base::android::JavaParamRef<jstring>& j_id);
+ void ResumeDownload(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& j_namespace,
+ const base::android::JavaParamRef<jstring>& j_id);
+ base::android::ScopedJavaLocalRef<jobject> GetItemById(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& j_namespace,
+ const base::android::JavaParamRef<jstring>& j_id);
+ base::android::ScopedJavaLocalRef<jobject> GetAllItems(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj);
+
+ private:
+ OfflineContentAggregatorBridge(OfflineContentAggregator* aggregator);
+
+ // OfflineContentProvider::Observer implementation.
+ void OnItemsAvailable(OfflineContentProvider* provider) override;
+ void OnItemsAdded(
+ const OfflineContentProvider::OfflineItemList& items) override;
+ void OnItemRemoved(const ContentId& id) override;
+ void OnItemUpdated(const OfflineItem& item) override;
+
+ // A reference to the Java counterpart of this class. See
+ // OfflineContentAggregatorBridge.java.
+ base::android::ScopedJavaGlobalRef<jobject> java_ref_;
+
+ OfflineContentAggregator* const aggregator_;
+
+ DISALLOW_COPY_AND_ASSIGN(OfflineContentAggregatorBridge);
+};
+
+} // namespace android
+} // namespace offline_items_collection
+
+#endif // COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_CONTENT_AGGREGATOR_BRIDGE_H_
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
new file mode 100644
index 00000000000..a21c50c5343
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/android/offline_item_bridge.cc
@@ -0,0 +1,70 @@
+// 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/offline_items_collection/core/android/offline_item_bridge.h"
+
+#include "base/android/jni_string.h"
+#include "jni/OfflineItemBridge_jni.h"
+
+using base::android::ConvertUTF8ToJavaString;
+using base::android::ScopedJavaLocalRef;
+
+namespace offline_items_collection {
+namespace android {
+
+namespace {
+
+// Helper method to unify the OfflineItem conversion argument list to a single
+// place. This is meant to reduce code churn from OfflineItem member
+// modification. The behavior is as follows:
+// - The method always returns the new Java OfflineItem instance.
+// - If |jlist| is specified (an ArrayList<OfflineItem>), the item is added to
+// that list. |jlist| can also be null, in which case the item isn't added to
+// anything.
+ScopedJavaLocalRef<jobject> createOfflineItemAndMaybeAddToList(
+ JNIEnv* env,
+ ScopedJavaLocalRef<jobject> jlist,
+ const OfflineItem& item) {
+ return Java_OfflineItemBridge_createOfflineItemAndMaybeAddToList(
+ env, jlist, ConvertUTF8ToJavaString(env, item.id.name_space),
+ ConvertUTF8ToJavaString(env, item.id.id),
+ ConvertUTF8ToJavaString(env, item.title),
+ ConvertUTF8ToJavaString(env, item.description),
+ static_cast<jint>(item.filter), item.is_transient, item.total_size_bytes,
+ item.externally_removed, item.creation_time.ToJavaTime(),
+ item.last_accessed_time.ToJavaTime(), item.is_openable,
+ ConvertUTF8ToJavaString(env, item.page_url.spec()),
+ ConvertUTF8ToJavaString(env, item.original_url.spec()),
+ item.is_off_the_record, static_cast<jint>(item.state), item.is_resumable,
+ item.allow_metered, item.received_bytes, item.percent_completed,
+ item.time_remaining_ms);
+}
+
+} // namespace
+
+// static
+ScopedJavaLocalRef<jobject> OfflineItemBridge::CreateOfflineItem(
+ JNIEnv* env,
+ const OfflineItem* const item) {
+ return item ? createOfflineItemAndMaybeAddToList(env, nullptr, *item)
+ : nullptr;
+}
+
+// static
+ScopedJavaLocalRef<jobject> OfflineItemBridge::CreateOfflineItemList(
+ JNIEnv* env,
+ const std::vector<OfflineItem>& items) {
+ ScopedJavaLocalRef<jobject> jlist =
+ Java_OfflineItemBridge_createArrayList(env);
+
+ for (const auto& item : items)
+ createOfflineItemAndMaybeAddToList(env, jlist, item);
+
+ return jlist;
+}
+
+OfflineItemBridge::OfflineItemBridge() = default;
+
+} // namespace android
+} // namespace offline_items_collection
diff --git a/chromium/components/offline_items_collection/core/android/offline_item_bridge.h b/chromium/components/offline_items_collection/core/android/offline_item_bridge.h
new file mode 100644
index 00000000000..76d1513b7a8
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/android/offline_item_bridge.h
@@ -0,0 +1,38 @@
+// 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_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_ITEM_BRIDGE_H_
+#define COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_ITEM_BRIDGE_H_
+
+#include <vector>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "components/offline_items_collection/core/offline_item.h"
+
+namespace offline_items_collection {
+namespace android {
+
+// A helper class for creating Java OfflineItem instances from the C++
+// OfflineItem counterpart.
+class OfflineItemBridge {
+ public:
+ // Creates a Java OfflineItem from |item|.
+ static base::android::ScopedJavaLocalRef<jobject> CreateOfflineItem(
+ JNIEnv* env,
+ const OfflineItem* const item);
+
+ // Creates an Java ArrayList<OfflineItem> from |items|.
+ static base::android::ScopedJavaLocalRef<jobject> CreateOfflineItemList(
+ JNIEnv* env,
+ const std::vector<OfflineItem>& items);
+
+ private:
+ OfflineItemBridge();
+};
+
+} // namespace android
+} // namespace offline_items_collection
+
+#endif // COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_ITEM_BRIDGE_H_
diff --git a/chromium/components/offline_items_collection/core/offline_content_aggregator.cc b/chromium/components/offline_items_collection/core/offline_content_aggregator.cc
new file mode 100644
index 00000000000..acbfd5a130b
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/offline_content_aggregator.cc
@@ -0,0 +1,263 @@
+// 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 <algorithm>
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_items_collection/core/offline_content_aggregator.h"
+#include "components/offline_items_collection/core/offline_item.h"
+
+namespace offline_items_collection {
+
+namespace {
+
+template <typename T, typename U>
+bool MapContainsValue(const std::map<T, U>& map, U value) {
+ for (const auto& it : map) {
+ if (it.second == value)
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+OfflineContentAggregator::OfflineContentAggregator()
+ : sent_on_items_available_(false), weak_ptr_factory_(this) {}
+
+OfflineContentAggregator::~OfflineContentAggregator() = default;
+
+void OfflineContentAggregator::RegisterProvider(
+ const std::string& name_space,
+ OfflineContentProvider* provider) {
+ // Validate that this is the first OfflineContentProvider registered that is
+ // associated with |name_space|.
+ DCHECK(providers_.find(name_space) == providers_.end());
+
+ // Only set up the connection to the provider if the provider isn't associated
+ // with any other namespace.
+ if (!MapContainsValue(providers_, provider))
+ provider->AddObserver(this);
+
+ providers_[name_space] = provider;
+}
+
+void OfflineContentAggregator::UnregisterProvider(
+ const std::string& name_space) {
+ auto provider_it = providers_.find(name_space);
+
+ OfflineContentProvider* provider = provider_it->second;
+ providers_.erase(provider_it);
+
+ // Only clean up the connection to the provider if the provider isn't
+ // associated with any other namespace.
+ if (!MapContainsValue(providers_, provider)) {
+ provider->RemoveObserver(this);
+ pending_actions_.erase(provider);
+ }
+}
+
+bool OfflineContentAggregator::AreItemsAvailable() {
+ return sent_on_items_available_;
+}
+
+void OfflineContentAggregator::OpenItem(const ContentId& id) {
+ auto it = providers_.find(id.name_space);
+
+ if (it == providers_.end())
+ return;
+
+ RunIfReady(it->second, base::Bind(&OfflineContentProvider::OpenItem,
+ base::Unretained(it->second), id));
+}
+
+void OfflineContentAggregator::RemoveItem(const ContentId& id) {
+ auto it = providers_.find(id.name_space);
+
+ if (it == providers_.end())
+ return;
+
+ RunIfReady(it->second, base::Bind(&OfflineContentProvider::RemoveItem,
+ base::Unretained(it->second), id));
+}
+
+void OfflineContentAggregator::CancelDownload(const ContentId& id) {
+ auto it = providers_.find(id.name_space);
+
+ if (it == providers_.end())
+ return;
+
+ RunIfReady(it->second, base::Bind(&OfflineContentProvider::CancelDownload,
+ base::Unretained(it->second), id));
+}
+
+void OfflineContentAggregator::PauseDownload(const ContentId& id) {
+ auto it = providers_.find(id.name_space);
+
+ if (it == providers_.end())
+ return;
+
+ RunIfReady(it->second, base::Bind(&OfflineContentProvider::PauseDownload,
+ base::Unretained(it->second), id));
+}
+
+void OfflineContentAggregator::ResumeDownload(const ContentId& id) {
+ auto it = providers_.find(id.name_space);
+
+ if (it == providers_.end())
+ return;
+
+ RunIfReady(it->second, base::Bind(&OfflineContentProvider::ResumeDownload,
+ base::Unretained(it->second), id));
+}
+
+const OfflineItem* OfflineContentAggregator::GetItemById(const ContentId& id) {
+ auto it = providers_.find(id.name_space);
+
+ if (it == providers_.end() || !it->second->AreItemsAvailable())
+ return nullptr;
+
+ return it->second->GetItemById(id);
+}
+
+OfflineContentProvider::OfflineItemList
+OfflineContentAggregator::GetAllItems() {
+ // Create a set of unique providers to iterate over.
+ std::set<OfflineContentProvider*> providers;
+ for (auto provider_it : providers_)
+ providers.insert(provider_it.second);
+
+ OfflineItemList items;
+ for (auto* provider : providers) {
+ if (!provider->AreItemsAvailable())
+ continue;
+
+ OfflineItemList provider_items = provider->GetAllItems();
+ items.insert(items.end(), provider_items.begin(), provider_items.end());
+ }
+
+ return items;
+}
+
+void OfflineContentAggregator::AddObserver(
+ OfflineContentProvider::Observer* observer) {
+ DCHECK(observer);
+ if (observers_.HasObserver(observer))
+ return;
+
+ observers_.AddObserver(observer);
+
+ if (sent_on_items_available_) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&OfflineContentAggregator::CheckAndNotifyItemsAvailable,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+}
+
+void OfflineContentAggregator::RemoveObserver(
+ OfflineContentProvider::Observer* observer) {
+ DCHECK(observer);
+ if (!observers_.HasObserver(observer))
+ return;
+
+ signaled_observers_.erase(observer);
+ observers_.RemoveObserver(observer);
+}
+
+void OfflineContentAggregator::OnItemsAvailable(
+ OfflineContentProvider* provider) {
+ // Flush any pending actions that should be mirrored to the provider.
+ FlushPendingActionsIfReady(provider);
+
+ // Some observers might already be under the impression that this class was
+ // initialized. Just treat this as an OnItemsAdded and notify those observers
+ // of the new items.
+ if (signaled_observers_.size() > 0) {
+ OfflineItemList items = provider->GetAllItems();
+ if (items.size() > 0) {
+ for (auto* observer : signaled_observers_)
+ observer->OnItemsAdded(items);
+ }
+ }
+
+ // Check if there were any observers who haven't been told that this class is
+ // initialized yet. If so, notify them now.
+ CheckAndNotifyItemsAvailable();
+}
+
+void OfflineContentAggregator::OnItemsAdded(const OfflineItemList& items) {
+ for (auto& observer : observers_)
+ observer.OnItemsAdded(items);
+}
+
+void OfflineContentAggregator::OnItemRemoved(const ContentId& id) {
+ for (auto& observer : observers_)
+ observer.OnItemRemoved(id);
+}
+
+void OfflineContentAggregator::OnItemUpdated(const OfflineItem& item) {
+ for (auto& observer : observers_)
+ observer.OnItemUpdated(item);
+}
+
+void OfflineContentAggregator::CheckAndNotifyItemsAvailable() {
+ if (providers_.size() == 0)
+ return;
+
+ // If we haven't sent out the initialization message yet, make sure all
+ // underlying OfflineContentProviders are ready before notifying observers
+ // that we're ready to send items.
+ if (!sent_on_items_available_) {
+ for (auto& it : providers_) {
+ if (!it.second->AreItemsAvailable())
+ return;
+ }
+ }
+
+ // Notify all observers who haven't been told about the initialization that we
+ // are initialized. Track the observers so that we don't notify them again.
+ for (auto& observer : observers_) {
+ if (!base::ContainsValue(signaled_observers_, &observer)) {
+ observer.OnItemsAvailable(this);
+ signaled_observers_.insert(&observer);
+ }
+ }
+
+ // Track that we've told the world that we are initialized.
+ sent_on_items_available_ = true;
+}
+
+void OfflineContentAggregator::FlushPendingActionsIfReady(
+ OfflineContentProvider* provider) {
+ DCHECK(MapContainsValue(providers_, provider));
+
+ if (!provider->AreItemsAvailable())
+ return;
+
+ CallbackList actions = std::move(pending_actions_[provider]);
+ for (auto& action : actions) {
+ action.Run();
+
+ // Check to see if the OfflineContentProvider was removed during the call to
+ // |action|. If so stop the loop.
+ if (pending_actions_.find(provider) == pending_actions_.end())
+ return;
+ }
+}
+
+void OfflineContentAggregator::RunIfReady(OfflineContentProvider* provider,
+ const base::Closure& action) {
+ if (provider->AreItemsAvailable())
+ action.Run();
+ else
+ pending_actions_[provider].push_back(action);
+}
+
+} // namespace offline_items_collection
diff --git a/chromium/components/offline_items_collection/core/offline_content_aggregator.h b/chromium/components/offline_items_collection/core/offline_content_aggregator.h
new file mode 100644
index 00000000000..03497084678
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/offline_content_aggregator.h
@@ -0,0 +1,147 @@
+// 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_OFFLINE_ITEMS_COLLETION_CORE_OFFLINE_CONTENT_AGGREGATOR_H_
+#define COMPONENTS_OFFLINE_ITEMS_COLLETION_CORE_OFFLINE_CONTENT_AGGREGATOR_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/supports_user_data.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/offline_items_collection/core/offline_content_provider.h"
+#include "url/gurl.h"
+
+namespace offline_items_collection {
+
+struct OfflineItem;
+
+// An implementation of OfflineContentProvider that aggregates multiple other
+// providers into a single set of data. See the OfflineContentProvider header
+// for comments on expected behavior of the interface. This implementation has
+// a few caveats:
+// - Once all currently registered providers are initialized this provider will
+// trigger OnItemsAvailable on all observers. Until then the provider will
+// not be initialized.
+// - If a provider is added after OnItemsAvailable was sent, it's initialization
+// will act as a notification for OnItemsAdded. This provider will still be
+// in the initialized state.
+// - Calling any modification method on this provider (Open, Update, Delete,
+// etc.) on an OfflineItem belonging to an uninitialized
+// OfflineContentProvider will be queued until that provider is initialized.
+// NOTE: Any actions taken will be propagated to the provider *before* the
+// observers are notified that the provider is initialized. This is meant to
+// try to guarantee that the data set incorporates the results of those
+// actions.
+//
+// Routing to the correct provider:
+// - Providers must be registered with a unique namespace. The OfflineItems
+// created by the provider must also be tagged with the same namespace so that
+// actions taken on the OfflineItem can be routed to the correct internal
+// provider. The namespace must also be consistent across startups.
+class OfflineContentAggregator : public OfflineContentProvider,
+ public OfflineContentProvider::Observer,
+ public base::SupportsUserData,
+ public KeyedService {
+ public:
+ OfflineContentAggregator();
+ ~OfflineContentAggregator() override;
+
+ // Registers a provider and associates it with all OfflineItems with
+ // |name_space|. UI actions taken on OfflineItems with |name_space| will be
+ // routed to |provider|. |provider| is expected to only expose OfflineItems
+ // with |name_space| set.
+ // It is okay to register the same provider with multiple unique namespaces.
+ // The class will work as expected with a few caveats. These are fixable if
+ // they are necessary for proper operation. Contact dtrainor@ if changes to
+ // this behavior is needed.
+ // 1. Unregistering the first namespace won't remove any pending actions
+ // that are queued for this provider. That means the provider might
+ // still get actions for the removed namespace once it is done
+ // initializing itself. This case must be handled by the individual
+ // provider for now.
+ // 2. The provider needs to handle calls to GetAllItems properly (not return
+ // any items for a namespace that it didn't register).
+ void RegisterProvider(const std::string& name_space,
+ OfflineContentProvider* provider);
+
+ // Removes the OfflineContentProvider associated with |name_space| from this
+ // aggregator.
+ void UnregisterProvider(const std::string& name_space);
+
+ // OfflineContentProvider implementation.
+ bool AreItemsAvailable() override;
+ void OpenItem(const ContentId& id) override;
+ void RemoveItem(const ContentId& id) override;
+ void CancelDownload(const ContentId& id) override;
+ void PauseDownload(const ContentId& id) override;
+ void ResumeDownload(const ContentId& id) override;
+ const OfflineItem* GetItemById(const ContentId& id) override;
+ OfflineItemList GetAllItems() override;
+ void AddObserver(OfflineContentProvider::Observer* observer) override;
+ void RemoveObserver(OfflineContentProvider::Observer* observer) override;
+
+ private:
+ // OfflineContentProvider::Observer implementation.
+ void OnItemsAvailable(OfflineContentProvider* provider) override;
+ void OnItemsAdded(const OfflineItemList& items) override;
+ void OnItemRemoved(const ContentId& id) override;
+ void OnItemUpdated(const OfflineItem& item) override;
+
+ // Checks if the underlying OfflineContentProviders are available. If so,
+ // it calls OnItemsAvailable on all observers that haven't yet been notified
+ // of this.
+ void CheckAndNotifyItemsAvailable();
+
+ // Checks to see if |provider| is initialized. If so, this flushes any
+ // pending actions taken on OfflineItems that belong to |provider|.
+ void FlushPendingActionsIfReady(OfflineContentProvider* provider);
+
+ // Checks if |provider| is initialized. If so, runs |action|, otherwise
+ // queues it to run once |provider| triggers that it is ready.
+ // NOTE: It is expected that |provider| is the same as the
+ // OfflineContentProvider bound in |action|. The class provides safety checks
+ // for that scenario only.
+ void RunIfReady(OfflineContentProvider* provider,
+ const base::Closure& action);
+
+ // Stores a map of name_space -> OfflineContentProvider. These
+ // OfflineContentProviders are all aggregated by this class and exposed to the
+ // consumer as a single list.
+ using OfflineProviderMap = std::map<std::string, OfflineContentProvider*>;
+ OfflineProviderMap providers_;
+
+ // Stores a map of OfflineContentProvider -> list of closures that represent
+ // all actions that need to be taken on the associated OfflineContentProvider
+ // when it becomes initialized.
+ using CallbackList = std::vector<base::Closure>;
+ using PendingActionMap = std::map<OfflineContentProvider*, CallbackList>;
+ PendingActionMap pending_actions_;
+
+ // A list of all currently registered observers.
+ base::ObserverList<OfflineContentProvider::Observer> observers_;
+
+ // A set of observers that have been notified that this class is initialized.
+ // We do not want to notify them of this initialization more than once, so
+ // we track them here.
+ using ObserverSet = std::set<OfflineContentProvider::Observer*>;
+ ObserverSet signaled_observers_;
+
+ // Whether or not this class currently identifies itself as available and has
+ // notified the observers.
+ bool sent_on_items_available_;
+
+ base::WeakPtrFactory<OfflineContentAggregator> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(OfflineContentAggregator);
+};
+
+} // namespace offline_items_collection
+
+#endif // COMPONENTS_OFFLINE_ITEMS_COLLETION_CORE_OFFLINE_CONTENT_AGGREGATOR_H_
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
new file mode 100644
index 00000000000..36193408445
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc
@@ -0,0 +1,477 @@
+// Copyright (c) 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/offline_items_collection/core/offline_content_aggregator.h"
+
+#include <map>
+
+#include "base/memory/ptr_util.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_items_collection/core/offline_item.h"
+#include "components/offline_items_collection/core/test_support/mock_offline_content_provider.h"
+#include "components/offline_items_collection/core/test_support/scoped_mock_offline_content_provider.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::ContainerEq;
+using testing::Return;
+
+namespace offline_items_collection {
+namespace {
+
+struct CompareOfflineItemsById {
+ bool operator()(const OfflineItem& a, const OfflineItem& b) const {
+ return a.id < b.id;
+ }
+};
+
+// A custom comparator that makes sure two vectors contain the same elements.
+// TODO(dtrainor): Look into building a better matcher that works with gmock.
+template <typename T>
+bool VectorContentsEq(const std::vector<T>& list1,
+ const std::vector<T>& list2) {
+ if (list1.size() != list2.size())
+ return false;
+
+ std::map<T, int, CompareOfflineItemsById> occurance_counts;
+ for (auto it = list1.begin(); it != list1.end(); it++)
+ occurance_counts[*it]++;
+
+ for (auto it = list2.begin(); it != list2.end(); it++)
+ occurance_counts[*it]--;
+
+ for (auto it = occurance_counts.begin(); it != occurance_counts.end(); it++) {
+ if (it->second != 0)
+ return false;
+ }
+
+ return true;
+}
+
+// Helper class that automatically unregisters itself from the aggregator in the
+// case that someone calls OpenItem on it.
+class OpenItemRemovalOfflineContentProvider
+ : public ScopedMockOfflineContentProvider {
+ public:
+ OpenItemRemovalOfflineContentProvider(const std::string& name_space,
+ OfflineContentAggregator* aggregator)
+ : ScopedMockOfflineContentProvider(name_space, aggregator) {}
+ ~OpenItemRemovalOfflineContentProvider() override {}
+
+ void OpenItem(const ContentId& id) override {
+ ScopedMockOfflineContentProvider::OpenItem(id);
+ Unregister();
+ }
+};
+
+class OfflineContentAggregatorTest : public testing::Test {
+ public:
+ OfflineContentAggregatorTest()
+ : task_runner_(new base::TestMockTimeTaskRunner), handle_(task_runner_) {}
+ ~OfflineContentAggregatorTest() override {}
+
+ protected:
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+ base::ThreadTaskRunnerHandle handle_;
+ OfflineContentAggregator aggregator_;
+};
+
+TEST_F(OfflineContentAggregatorTest, ObserversAddedBeforeProvidersAvailable) {
+ ScopedMockOfflineContentProvider provider1("1", &aggregator_);
+ ScopedMockOfflineContentProvider provider2("2", &aggregator_);
+ EXPECT_FALSE(aggregator_.AreItemsAvailable());
+ EXPECT_TRUE(provider1.HasObserver(&aggregator_));
+ EXPECT_TRUE(provider2.HasObserver(&aggregator_));
+
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer1(&aggregator_);
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer2(&aggregator_);
+ task_runner_->RunUntilIdle();
+
+ {
+ EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(0);
+ EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(0);
+ provider1.NotifyOnItemsAvailable();
+ }
+
+ {
+ EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(1);
+ EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(1);
+ provider2.NotifyOnItemsAvailable();
+ }
+}
+
+TEST_F(OfflineContentAggregatorTest, ObserversAddedAfterProvidersAvailable) {
+ ScopedMockOfflineContentProvider provider1("1", &aggregator_);
+ ScopedMockOfflineContentProvider provider2("2", &aggregator_);
+ EXPECT_FALSE(aggregator_.AreItemsAvailable());
+ EXPECT_TRUE(provider1.HasObserver(&aggregator_));
+ EXPECT_TRUE(provider2.HasObserver(&aggregator_));
+
+ provider1.NotifyOnItemsAvailable();
+ provider2.NotifyOnItemsAvailable();
+
+ {
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer1(
+ &aggregator_);
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer2(
+ &aggregator_);
+ EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(1);
+ EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(1);
+ task_runner_->RunUntilIdle();
+ }
+}
+
+TEST_F(OfflineContentAggregatorTest,
+ ProvidersAddedAfterObserversNotifiedAvailable) {
+ ScopedMockOfflineContentProvider provider1("1", &aggregator_);
+ EXPECT_FALSE(aggregator_.AreItemsAvailable());
+ EXPECT_TRUE(provider1.HasObserver(&aggregator_));
+
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer1(&aggregator_);
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer2(&aggregator_);
+ task_runner_->RunUntilIdle();
+
+ {
+ EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(1);
+ EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(1);
+ provider1.NotifyOnItemsAvailable();
+ }
+
+ {
+ OfflineContentProvider::OfflineItemList items;
+ items.push_back(OfflineItem());
+
+ ScopedMockOfflineContentProvider provider2("2", &aggregator_);
+ EXPECT_TRUE(provider2.HasObserver(&aggregator_));
+
+ EXPECT_CALL(provider2, GetAllItems()).WillOnce(Return(items));
+ EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(0);
+ EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(0);
+ EXPECT_CALL(observer1, OnItemsAdded(items)).Times(1);
+ EXPECT_CALL(observer2, OnItemsAdded(items)).Times(1);
+ provider2.NotifyOnItemsAvailable();
+ }
+}
+
+TEST_F(OfflineContentAggregatorTest, QueryingItemsWithProviderThatIsntReady) {
+ ScopedMockOfflineContentProvider provider1("1", &aggregator_);
+ ScopedMockOfflineContentProvider provider2("2", &aggregator_);
+ EXPECT_FALSE(aggregator_.AreItemsAvailable());
+
+ OfflineContentProvider::OfflineItemList items1;
+ items1.push_back(OfflineItem(ContentId("1", "A")));
+ items1.push_back(OfflineItem(ContentId("1", "B")));
+
+ OfflineContentProvider::OfflineItemList items2;
+ items2.push_back(OfflineItem(ContentId("2", "C")));
+ items2.push_back(OfflineItem(ContentId("2", "D")));
+
+ EXPECT_CALL(provider1, GetAllItems()).WillRepeatedly(Return(items1));
+ EXPECT_CALL(provider2, GetAllItems()).WillRepeatedly(Return(items2));
+
+ provider1.NotifyOnItemsAvailable();
+ EXPECT_TRUE(VectorContentsEq(items1, aggregator_.GetAllItems()));
+
+ OfflineContentProvider::OfflineItemList combined_items(items1);
+ combined_items.insert(combined_items.end(), items2.begin(), items2.end());
+ provider2.NotifyOnItemsAvailable();
+
+ EXPECT_TRUE(VectorContentsEq(combined_items, aggregator_.GetAllItems()));
+}
+
+TEST_F(OfflineContentAggregatorTest, QueryingItemFromRemovedProvider) {
+ ContentId id("1", "A");
+ OfflineItem item(id);
+
+ {
+ ScopedMockOfflineContentProvider provider("1", &aggregator_);
+ provider.NotifyOnItemsAvailable();
+ EXPECT_TRUE(aggregator_.AreItemsAvailable());
+
+ EXPECT_CALL(provider, GetItemById(id)).WillRepeatedly(Return(&item));
+ EXPECT_EQ(&item, aggregator_.GetItemById(id));
+ }
+
+ EXPECT_EQ(nullptr, aggregator_.GetItemById(id));
+}
+
+TEST_F(OfflineContentAggregatorTest, QueryingItemWithProviderThatIsntReady) {
+ ScopedMockOfflineContentProvider provider1("1", &aggregator_);
+ ScopedMockOfflineContentProvider provider2("2", &aggregator_);
+ EXPECT_FALSE(aggregator_.AreItemsAvailable());
+
+ ContentId id1("1", "A");
+ ContentId id2("2", "B");
+ ContentId id3("3", "C");
+
+ OfflineItem item1(id1);
+ OfflineItem item2(id2);
+
+ EXPECT_CALL(provider1, GetItemById(id1)).WillRepeatedly(Return(&item1));
+ EXPECT_CALL(provider2, GetItemById(id2)).WillRepeatedly(Return(&item2));
+
+ EXPECT_EQ(nullptr, aggregator_.GetItemById(id1));
+ EXPECT_EQ(nullptr, aggregator_.GetItemById(id2));
+ EXPECT_EQ(nullptr, aggregator_.GetItemById(id3));
+
+ provider1.NotifyOnItemsAvailable();
+ EXPECT_EQ(&item1, aggregator_.GetItemById(id1));
+ EXPECT_EQ(nullptr, aggregator_.GetItemById(id2));
+ EXPECT_EQ(nullptr, aggregator_.GetItemById(id3));
+
+ provider2.NotifyOnItemsAvailable();
+ EXPECT_EQ(&item1, aggregator_.GetItemById(id1));
+ EXPECT_EQ(&item2, aggregator_.GetItemById(id2));
+ EXPECT_EQ(nullptr, aggregator_.GetItemById(id3));
+}
+
+TEST_F(OfflineContentAggregatorTest, GetItemByIdPropagatesToRightProvider) {
+ ScopedMockOfflineContentProvider provider1("1", &aggregator_);
+ ScopedMockOfflineContentProvider provider2("2", &aggregator_);
+ provider1.NotifyOnItemsAvailable();
+ provider2.NotifyOnItemsAvailable();
+
+ ContentId id1("1", "A");
+ ContentId id2("2", "B");
+ ContentId id3("1", "C");
+ ContentId id4("3", "D");
+ OfflineItem item1(id1);
+ OfflineItem item2(id2);
+
+ EXPECT_CALL(provider1, GetItemById(id1)).WillRepeatedly(Return(&item1));
+ EXPECT_CALL(provider2, GetItemById(id2)).WillRepeatedly(Return(&item2));
+ EXPECT_CALL(provider1, GetItemById(id3)).WillRepeatedly(Return(nullptr));
+
+ EXPECT_EQ(&item1, aggregator_.GetItemById(id1));
+ EXPECT_EQ(&item2, aggregator_.GetItemById(id2));
+ EXPECT_EQ(nullptr, aggregator_.GetItemById(id3));
+ EXPECT_EQ(nullptr, aggregator_.GetItemById(id4));
+}
+
+TEST_F(OfflineContentAggregatorTest, AreItemsAvailable) {
+ ScopedMockOfflineContentProvider provider1("1", &aggregator_);
+ ScopedMockOfflineContentProvider provider2("2", &aggregator_);
+
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer1(&aggregator_);
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer2(&aggregator_);
+ task_runner_->RunUntilIdle();
+
+ EXPECT_FALSE(aggregator_.AreItemsAvailable());
+
+ {
+ EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(0);
+ EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(0);
+
+ provider1.NotifyOnItemsAvailable();
+ }
+
+ EXPECT_FALSE(aggregator_.AreItemsAvailable());
+
+ {
+ EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(1);
+ EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(1);
+
+ provider2.NotifyOnItemsAvailable();
+ }
+
+ EXPECT_TRUE(aggregator_.AreItemsAvailable());
+}
+
+TEST_F(OfflineContentAggregatorTest, ActionPropagatesToRightProvider) {
+ ScopedMockOfflineContentProvider provider1("1", &aggregator_);
+ ScopedMockOfflineContentProvider provider2("2", &aggregator_);
+ provider1.NotifyOnItemsAvailable();
+ provider2.NotifyOnItemsAvailable();
+
+ testing::InSequence sequence;
+ ContentId id1("1", "A");
+ ContentId id2("2", "B");
+ EXPECT_CALL(provider1, OpenItem(id1)).Times(1);
+ EXPECT_CALL(provider2, OpenItem(id2)).Times(1);
+ EXPECT_CALL(provider1, RemoveItem(id1)).Times(1);
+ EXPECT_CALL(provider2, RemoveItem(id2)).Times(1);
+ EXPECT_CALL(provider1, CancelDownload(id1)).Times(1);
+ EXPECT_CALL(provider2, CancelDownload(id2)).Times(1);
+ EXPECT_CALL(provider1, ResumeDownload(id1)).Times(1);
+ EXPECT_CALL(provider2, ResumeDownload(id2)).Times(1);
+ EXPECT_CALL(provider1, PauseDownload(id1)).Times(1);
+ EXPECT_CALL(provider2, PauseDownload(id2)).Times(1);
+ aggregator_.OpenItem(id1);
+ aggregator_.OpenItem(id2);
+ aggregator_.RemoveItem(id1);
+ aggregator_.RemoveItem(id2);
+ aggregator_.CancelDownload(id1);
+ aggregator_.CancelDownload(id2);
+ aggregator_.ResumeDownload(id1);
+ aggregator_.ResumeDownload(id2);
+ aggregator_.PauseDownload(id1);
+ aggregator_.PauseDownload(id2);
+}
+
+TEST_F(OfflineContentAggregatorTest, ActionPropagatesAfterInitialize) {
+ ScopedMockOfflineContentProvider provider1("1", &aggregator_);
+ ScopedMockOfflineContentProvider provider2("2", &aggregator_);
+
+ ContentId id1("1", "A");
+ ContentId id2("2", "B");
+ ContentId id3("2", "C");
+
+ {
+ EXPECT_CALL(provider1, PauseDownload(id1)).Times(0);
+ aggregator_.PauseDownload(id1);
+ }
+
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(provider1, PauseDownload(id1)).Times(1);
+ EXPECT_CALL(provider1, ResumeDownload(id1)).Times(1);
+ EXPECT_CALL(provider1, OpenItem(id1)).Times(1);
+ EXPECT_CALL(provider2, OpenItem(id2)).Times(0);
+
+ aggregator_.ResumeDownload(id1);
+ aggregator_.OpenItem(id1);
+ provider1.NotifyOnItemsAvailable();
+ aggregator_.OpenItem(id2);
+ }
+
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(provider2, OpenItem(id2)).Times(1);
+ EXPECT_CALL(provider2, RemoveItem(id3)).Times(1);
+ aggregator_.RemoveItem(id3);
+ provider2.NotifyOnItemsAvailable();
+ }
+}
+
+TEST_F(OfflineContentAggregatorTest, OnItemsAddedPropagatedToObservers) {
+ ScopedMockOfflineContentProvider provider1("1", &aggregator_);
+ ScopedMockOfflineContentProvider provider2("2", &aggregator_);
+ provider1.NotifyOnItemsAvailable();
+ provider2.NotifyOnItemsAvailable();
+
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer1(&aggregator_);
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer2(&aggregator_);
+
+ EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(1);
+ EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(1);
+ task_runner_->RunUntilIdle();
+
+ OfflineContentProvider::OfflineItemList items1;
+ items1.push_back(OfflineItem(ContentId("1", "A")));
+ items1.push_back(OfflineItem(ContentId("1", "B")));
+
+ OfflineContentProvider::OfflineItemList items2;
+ items2.push_back(OfflineItem(ContentId("2", "C")));
+ items2.push_back(OfflineItem(ContentId("2", "D")));
+
+ EXPECT_CALL(observer1, OnItemsAdded(items1)).Times(1);
+ EXPECT_CALL(observer1, OnItemsAdded(items2)).Times(1);
+ EXPECT_CALL(observer2, OnItemsAdded(items1)).Times(1);
+ EXPECT_CALL(observer2, OnItemsAdded(items2)).Times(1);
+ provider1.NotifyOnItemsAdded(items1);
+ provider2.NotifyOnItemsAdded(items2);
+}
+
+TEST_F(OfflineContentAggregatorTest, OnItemRemovedPropagatedToObservers) {
+ ScopedMockOfflineContentProvider provider1("1", &aggregator_);
+ ScopedMockOfflineContentProvider provider2("2", &aggregator_);
+ provider1.NotifyOnItemsAvailable();
+ provider2.NotifyOnItemsAvailable();
+
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer1(&aggregator_);
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer2(&aggregator_);
+
+ EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(1);
+ EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(1);
+ task_runner_->RunUntilIdle();
+
+ ContentId id1("1", "A");
+ ContentId id2("2", "B");
+
+ EXPECT_CALL(observer1, OnItemRemoved(id1)).Times(1);
+ EXPECT_CALL(observer1, OnItemRemoved(id2)).Times(1);
+ EXPECT_CALL(observer2, OnItemRemoved(id1)).Times(1);
+ EXPECT_CALL(observer2, OnItemRemoved(id2)).Times(1);
+ provider1.NotifyOnItemRemoved(id1);
+ provider2.NotifyOnItemRemoved(id2);
+}
+
+TEST_F(OfflineContentAggregatorTest, OnItemUpdatedPropagatedToObservers) {
+ ScopedMockOfflineContentProvider provider1("1", &aggregator_);
+ ScopedMockOfflineContentProvider provider2("2", &aggregator_);
+ provider1.NotifyOnItemsAvailable();
+ provider2.NotifyOnItemsAvailable();
+
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer1(&aggregator_);
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer2(&aggregator_);
+
+ EXPECT_CALL(observer1, OnItemsAvailable(&aggregator_)).Times(1);
+ EXPECT_CALL(observer2, OnItemsAvailable(&aggregator_)).Times(1);
+ task_runner_->RunUntilIdle();
+
+ OfflineItem item1(ContentId("1", "A"));
+ OfflineItem item2(ContentId("2", "B"));
+
+ EXPECT_CALL(observer1, OnItemUpdated(item1)).Times(1);
+ EXPECT_CALL(observer1, OnItemUpdated(item2)).Times(1);
+ EXPECT_CALL(observer2, OnItemUpdated(item1)).Times(1);
+ EXPECT_CALL(observer2, OnItemUpdated(item2)).Times(1);
+ provider1.NotifyOnItemUpdated(item1);
+ provider2.NotifyOnItemUpdated(item2);
+}
+
+TEST_F(OfflineContentAggregatorTest, ProviderRemovedDuringCallbackFlush) {
+ OpenItemRemovalOfflineContentProvider provider1("1", &aggregator_);
+
+ ContentId id1("1", "A");
+ ContentId id2("1", "B");
+ aggregator_.OpenItem(id1);
+ aggregator_.OpenItem(id2);
+ aggregator_.RemoveItem(id2);
+
+ EXPECT_CALL(provider1, OpenItem(id1)).Times(1);
+ EXPECT_CALL(provider1, RemoveItem(id2)).Times(0);
+ provider1.NotifyOnItemsAvailable();
+}
+
+TEST_F(OfflineContentAggregatorTest, SameProviderWithMultipleNamespaces) {
+ MockOfflineContentProvider provider;
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer(&aggregator_);
+
+ ContentId id1("1", "A");
+ ContentId id2("2", "B");
+ OfflineItem item1(id1);
+ OfflineItem item2(id2);
+ OfflineContentProvider::OfflineItemList items;
+ items.push_back(item1);
+ items.push_back(item2);
+
+ aggregator_.RegisterProvider("1", &provider);
+ aggregator_.RegisterProvider("2", &provider);
+ EXPECT_TRUE(provider.HasObserver(&aggregator_));
+
+ EXPECT_CALL(provider, GetAllItems()).WillRepeatedly(Return(items));
+ EXPECT_CALL(provider, GetItemById(id1)).WillRepeatedly(Return(&item1));
+ EXPECT_CALL(provider, GetItemById(id2)).WillRepeatedly(Return(&item2));
+
+ EXPECT_CALL(observer, OnItemsAvailable(&aggregator_)).Times(1);
+ provider.NotifyOnItemsAvailable();
+
+ EXPECT_TRUE(VectorContentsEq(items, aggregator_.GetAllItems()));
+ EXPECT_EQ(&item1, aggregator_.GetItemById(id1));
+ EXPECT_EQ(&item2, aggregator_.GetItemById(id2));
+
+ aggregator_.UnregisterProvider("1");
+ EXPECT_TRUE(provider.HasObserver(&aggregator_));
+ EXPECT_EQ(nullptr, aggregator_.GetItemById(id1));
+ EXPECT_EQ(&item2, aggregator_.GetItemById(id2));
+
+ aggregator_.UnregisterProvider("2");
+ EXPECT_FALSE(provider.HasObserver(&aggregator_));
+}
+
+} // namespace
+} // namespace offline_items_collection
diff --git a/chromium/components/offline_items_collection/core/offline_content_provider.h b/chromium/components/offline_items_collection/core/offline_content_provider.h
new file mode 100644
index 00000000000..353a7bc2520
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/offline_content_provider.h
@@ -0,0 +1,97 @@
+// 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_OFFLINE_ITEMS_COLLETION_CORE_OFFLINE_CONTENT_PROVIDER_H_
+#define COMPONENTS_OFFLINE_ITEMS_COLLETION_CORE_OFFLINE_CONTENT_PROVIDER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "url/gurl.h"
+
+namespace offline_items_collection {
+
+struct ContentId;
+struct OfflineItem;
+
+// A provider of a set of OfflineItems that are meant to be exposed to the UI.
+// The provider is required to notify all observers of OnItemsAvailable when the
+// underlying data set is initialized. Without that call it should not expect
+// nor have to support any other calls to this provider.
+class OfflineContentProvider {
+ public:
+ using OfflineItemList = std::vector<OfflineItem>;
+
+ // An observer class that should be notified of relevant changes to the
+ // underlying data source.
+ class Observer {
+ public:
+ // Called when the underlying data source for the provider has been
+ // initialized and the contents are able to be queried and interacted with.
+ // |provider| should be a reference to this OfflineContentProvider that is
+ // initialized.
+ virtual void OnItemsAvailable(OfflineContentProvider* provider) = 0;
+
+ // Called when one or more OfflineItems have been added and should be shown
+ // in the UI.
+ virtual void OnItemsAdded(const OfflineItemList& items) = 0;
+
+ // Called when the OfflineItem represented by |id| should be removed from
+ // the UI.
+ virtual void OnItemRemoved(const ContentId& id) = 0;
+
+ // Called when the contents of |item| have been updated and the UI should be
+ // refreshed for that item.
+ virtual void OnItemUpdated(const OfflineItem& item) = 0;
+
+ protected:
+ virtual ~Observer() = default;
+ };
+
+ // Returns whether or not the underlying data source for this provider has
+ // been initialized and is ready to start returning content. This provider
+ // should not need to support handling the other data query/manipulation
+ // methods if this returns false.
+ virtual bool AreItemsAvailable() = 0;
+
+ // Called to trigger opening an OfflineItem represented by |id|.
+ virtual void OpenItem(const ContentId& id) = 0;
+
+ // Called to trigger removal of an OfflineItem represented by |id|.
+ virtual void RemoveItem(const ContentId& id) = 0;
+
+ // Called to cancel a download of an OfflineItem represented by |id|.
+ virtual void CancelDownload(const ContentId& id) = 0;
+
+ // Called to pause a download of an OfflineItem represented by |id|.
+ virtual void PauseDownload(const ContentId& id) = 0;
+
+ // Called to resume a paused download of an OfflineItem represented by |id|.
+ virtual void ResumeDownload(const ContentId& id) = 0;
+
+ // Returns an OfflineItem represented by |id| or |nullptr| if none exists.
+ // The caller should not hold ownership of the returned item beyond the scope
+ // of the function call.
+ virtual const OfflineItem* GetItemById(const ContentId& id) = 0;
+
+ // Returns all OfflineItems for this particular provider.
+ virtual OfflineItemList GetAllItems() = 0;
+
+ // Adds an observer that should be notified of OfflineItem list modifications.
+ // If the provider is already initialized OnItemsAvailable should be scheduled
+ // on this observer (suggested over calling the method directly to avoid
+ // reentrancy).
+ virtual void AddObserver(Observer* observer) = 0;
+
+ // Removes an observer. No further notifications should be sent to it.
+ virtual void RemoveObserver(Observer* observer) = 0;
+
+ protected:
+ virtual ~OfflineContentProvider() = default;
+};
+
+} // namespace offline_items_collection
+
+#endif // COMPONENTS_OFFLINE_ITEMS_COLLETION_CORE_OFFLINE_CONTENT_PROVIDER_H_
diff --git a/chromium/components/offline_items_collection/core/offline_item.cc b/chromium/components/offline_items_collection/core/offline_item.cc
new file mode 100644
index 00000000000..9506bcf7f8d
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/offline_item.cc
@@ -0,0 +1,72 @@
+// 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/offline_items_collection/core/offline_item.h"
+
+namespace offline_items_collection {
+
+ContentId::ContentId() = default;
+
+ContentId::ContentId(const ContentId& other) = default;
+
+ContentId::ContentId(const std::string& name_space, const std::string& id)
+ : name_space(name_space), id(id) {
+ DCHECK_EQ(std::string::npos, name_space.find_first_of(","));
+}
+
+ContentId::~ContentId() = default;
+
+bool ContentId::operator==(const ContentId& content_id) const {
+ return name_space == content_id.name_space && id == content_id.id;
+}
+
+bool ContentId::operator<(const ContentId& content_id) const {
+ return std::tie(name_space, id) <
+ std::tie(content_id.name_space, content_id.id);
+}
+
+OfflineItem::OfflineItem()
+ : filter(OfflineItemFilter::FILTER_OTHER),
+ is_transient(false),
+ total_size_bytes(0),
+ externally_removed(false),
+ is_openable(false),
+ is_off_the_record(false),
+ state(OfflineItemState::COMPLETE),
+ is_resumable(false),
+ allow_metered(false),
+ received_bytes(0),
+ percent_completed(0),
+ time_remaining_ms(0) {}
+
+OfflineItem::OfflineItem(const OfflineItem& other) = default;
+
+OfflineItem::OfflineItem(const ContentId& id) : OfflineItem() {
+ this->id = id;
+}
+
+OfflineItem::~OfflineItem() = default;
+
+bool OfflineItem::operator==(const OfflineItem& offline_item) const {
+ return id == offline_item.id && title == offline_item.title &&
+ description == offline_item.description &&
+ filter == offline_item.filter &&
+ is_transient == offline_item.is_transient &&
+ total_size_bytes == offline_item.total_size_bytes &&
+ externally_removed == offline_item.externally_removed &&
+ creation_time == offline_item.creation_time &&
+ last_accessed_time == offline_item.last_accessed_time &&
+ is_openable == offline_item.is_openable &&
+ page_url == offline_item.page_url &&
+ original_url == offline_item.original_url &&
+ is_off_the_record == offline_item.is_off_the_record &&
+ state == offline_item.state &&
+ is_resumable == offline_item.is_resumable &&
+ allow_metered == offline_item.allow_metered &&
+ received_bytes == offline_item.received_bytes &&
+ percent_completed == offline_item.percent_completed &&
+ time_remaining_ms == offline_item.time_remaining_ms;
+}
+
+} // namespace offline_items_collection
diff --git a/chromium/components/offline_items_collection/core/offline_item.h b/chromium/components/offline_items_collection/core/offline_item.h
new file mode 100644
index 00000000000..5c98e94cd2b
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/offline_item.h
@@ -0,0 +1,138 @@
+// 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_OFFLINE_ITEMS_COLLECTION_CORE_OFFLINE_ITEM_H_
+#define COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_OFFLINE_ITEM_H_
+
+#include <string>
+
+#include "base/time/time.h"
+#include "components/offline_items_collection/core/offline_item_filter.h"
+#include "components/offline_items_collection/core/offline_item_state.h"
+#include "url/gurl.h"
+
+namespace offline_items_collection {
+
+// An id that uniquely represents a piece of offline content.
+struct ContentId {
+ // The namespace for the offline content. This will be used to associate this
+ // id with a particular OfflineContentProvider. A name_space can include
+ // any characters except ','. This is due to a serialization format
+ // limitation.
+ // TODO(dtrainor): Remove the 'no ,' limitation.
+ std::string name_space;
+
+ // The id of the offline item.
+ std::string id;
+
+ ContentId();
+ ContentId(const ContentId& other);
+ ContentId(const std::string& name_space, const std::string& id);
+
+ ~ContentId();
+
+ bool operator==(const ContentId& content_id) const;
+
+ bool operator<(const ContentId& content_id) const;
+};
+
+// This struct holds the relevant pieces of information to represent an abstract
+// offline item to the front end. This is meant to be backed by components that
+// need to both show content being offlined (downloading, saving, etc.) as well
+// as content that should be exposed as available offline (downloads, pages,
+// etc.).
+//
+// A new feature should expose these OfflineItems via an OfflineContentProvider.
+struct OfflineItem {
+ OfflineItem();
+ OfflineItem(const OfflineItem& other);
+ explicit OfflineItem(const ContentId& id);
+
+ ~OfflineItem();
+
+ bool operator==(const OfflineItem& offline_item) const;
+
+ // The id of this OfflineItem. Used to identify this item across all relevant
+ // systems.
+ ContentId id;
+
+ // Display Metadata.
+ // ---------------------------------------------------------------------------
+ // The title of the OfflineItem to display in the UI.
+ std::string title;
+
+ // The description of the OfflineItem to display in the UI (may or may not be
+ // displayed depending on the specific UI component).
+ std::string description;
+
+ // The type of offline item this is. This can be used for filtering offline
+ // items as well as for determining which default icon to use.
+ OfflineItemFilter filter;
+
+ // Whether or not this item is transient. Transient items won't show up in
+ // persistent UI spaces and will only show up as notifications.
+ bool is_transient;
+
+ // TODO(dtrainor): Build out custom per-item icon support.
+
+ // Content Metadata.
+ // ---------------------------------------------------------------------------
+ // The total size of the offline item as best known at the current time.
+ int64_t total_size_bytes;
+
+ // Whether or not this item has been removed externally (not by Chrome).
+ bool externally_removed;
+
+ // The time when the underlying offline content was created.
+ base::Time creation_time;
+
+ // The last time the underlying offline content was accessed.
+ base::Time last_accessed_time;
+
+ // Whether or not this item can be opened after it is done being downloaded.
+ bool is_openable;
+
+ // Request Metadata.
+ // ---------------------------------------------------------------------------
+ // The URL of the top level frame at the time the content was offlined.
+ GURL page_url;
+
+ // The URL that represents the original request (before any redirection).
+ GURL original_url;
+
+ // Whether or not this item is off the record.
+ bool is_off_the_record;
+
+ // In Progress Metadata.
+ // ---------------------------------------------------------------------------
+ // The current state of the OfflineItem.
+ OfflineItemState state;
+
+ // Whether or not the offlining of this content can be resumed if it was
+ // paused or interrupted.
+ bool is_resumable;
+
+ // Whether or not this OfflineItem can be downloaded using a metered
+ // connection.
+ bool allow_metered;
+
+ // The current amount of bytes received for this item. This field is not used
+ // if |state| is COMPLETE.
+ int64_t received_bytes;
+
+ // How complete (from 0 to 100) the offlining process is for this item. -1
+ // represents that progress cannot be determined for this item and an
+ // indeterminate progress bar should be used. This field is not used if
+ // |state| is COMPLETE.
+ int percent_completed;
+
+ // The estimated time remaining for the download in milliseconds. -1
+ // represents an unknown time remaining. This field is not used if |state| is
+ // COMPLETE.
+ int64_t time_remaining_ms;
+};
+
+} // namespace offline_items_collection
+
+#endif // COMPONENTS_OFFLINE_ITEMS_COLLECTION_OFFLINE_ITEM_H_
diff --git a/chromium/components/offline_items_collection/core/offline_item_filter.h b/chromium/components/offline_items_collection/core/offline_item_filter.h
new file mode 100644
index 00000000000..3bdb64b242a
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/offline_item_filter.h
@@ -0,0 +1,27 @@
+// 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_OFFLINE_ITEMS_COLLECTION_CORE_OFFLINE_ITEM_FILTER_H_
+#define COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_OFFLINE_ITEM_FILTER_H_
+
+namespace offline_items_collection {
+
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.offline_items_collection
+enum OfflineItemFilter {
+ FILTER_ALL = 0,
+ FILTER_PAGE,
+ FILTER_VIDEO,
+ FILTER_AUDIO,
+ FILTER_IMAGE,
+ FILTER_DOCUMENT,
+ FILTER_OTHER,
+
+ // Maximum value.
+ FILTER_BOUNDARY,
+};
+
+} // namespace offline_items_collection
+
+#endif // COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_OFFLINE_ITEM_FILTER_H_
diff --git a/chromium/components/offline_items_collection/core/offline_item_state.h b/chromium/components/offline_items_collection/core/offline_item_state.h
new file mode 100644
index 00000000000..db23a527fb1
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/offline_item_state.h
@@ -0,0 +1,26 @@
+// 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_OFFLINE_ITEMS_COLLECTION_CORE_OFFLINE_ITEM_STATE_H_
+#define COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_OFFLINE_ITEM_STATE_H_
+
+namespace offline_items_collection {
+
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.offline_items_collection
+enum OfflineItemState {
+ IN_PROGRESS = 0,
+ PENDING,
+ COMPLETE,
+ CANCELLED,
+ INTERRUPTED,
+ FAILED,
+ PAUSED, // TODO(dtrainor): Make sure exposing a PAUSED state does not impact
+ // downloads resumption.
+ MAX_DOWNLOAD_STATE,
+};
+
+} // namespace offline_items_collection
+
+#endif // COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_OFFLINE_ITEM_STATE_H_
diff --git a/chromium/components/offline_items_collection/core/test_support/BUILD.gn b/chromium/components/offline_items_collection/core/test_support/BUILD.gn
new file mode 100644
index 00000000000..e2314388d3e
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/test_support/BUILD.gn
@@ -0,0 +1,23 @@
+# 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.
+
+source_set("test_support") {
+ visibility = [ "//components/offline_items_collection/core:unit_tests" ]
+
+ testonly = true
+
+ sources = [
+ "mock_offline_content_provider.cc",
+ "mock_offline_content_provider.h",
+ "scoped_mock_offline_content_provider.cc",
+ "scoped_mock_offline_content_provider.h",
+ ]
+
+ public_deps = [
+ "//base",
+ "//components/offline_items_collection/core",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/offline_items_collection/core/test_support/mock_offline_content_provider.cc b/chromium/components/offline_items_collection/core/test_support/mock_offline_content_provider.cc
new file mode 100644
index 00000000000..748c21807ea
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/test_support/mock_offline_content_provider.cc
@@ -0,0 +1,54 @@
+// 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/offline_items_collection/core/test_support/mock_offline_content_provider.h"
+
+namespace offline_items_collection {
+
+MockOfflineContentProvider::MockObserver::MockObserver() = default;
+MockOfflineContentProvider::MockObserver::~MockObserver() = default;
+
+MockOfflineContentProvider::MockOfflineContentProvider()
+ : items_available_(false) {}
+MockOfflineContentProvider::~MockOfflineContentProvider() = default;
+
+bool MockOfflineContentProvider::HasObserver(Observer* observer) {
+ return observers_.HasObserver(observer);
+}
+
+void MockOfflineContentProvider::NotifyOnItemsAvailable() {
+ items_available_ = true;
+ for (auto& observer : observers_)
+ observer.OnItemsAvailable(this);
+}
+
+void MockOfflineContentProvider::NotifyOnItemsAdded(
+ const OfflineItemList& items) {
+ for (auto& observer : observers_)
+ observer.OnItemsAdded(items);
+}
+
+void MockOfflineContentProvider::NotifyOnItemRemoved(const ContentId& id) {
+ for (auto& observer : observers_)
+ observer.OnItemRemoved(id);
+}
+
+void MockOfflineContentProvider::NotifyOnItemUpdated(const OfflineItem& item) {
+ for (auto& observer : observers_)
+ observer.OnItemUpdated(item);
+}
+
+bool MockOfflineContentProvider::AreItemsAvailable() {
+ return items_available_;
+}
+
+void MockOfflineContentProvider::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void MockOfflineContentProvider::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+} // namespace offline_items_collection
diff --git a/chromium/components/offline_items_collection/core/test_support/mock_offline_content_provider.h b/chromium/components/offline_items_collection/core/test_support/mock_offline_content_provider.h
new file mode 100644
index 00000000000..5e4e0d599fe
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/test_support/mock_offline_content_provider.h
@@ -0,0 +1,58 @@
+// 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_OFFLINE_ITEMS_COLLECTION_CORE_TEST_SUPPORT_MOCK_OFFLINE_CONTENT_PROVIDER_H_
+#define COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_TEST_SUPPORT_MOCK_OFFLINE_CONTENT_PROVIDER_H_
+
+#include "base/observer_list.h"
+#include "components/offline_items_collection/core/offline_content_provider.h"
+#include "components/offline_items_collection/core/offline_item.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_items_collection {
+
+class MockOfflineContentProvider : public OfflineContentProvider {
+ public:
+ class MockObserver : public OfflineContentProvider::Observer {
+ public:
+ MockObserver();
+ ~MockObserver() override;
+
+ // OfflineContentProvider::Observer implementation.
+ MOCK_METHOD1(OnItemsAvailable, void(OfflineContentProvider*));
+ MOCK_METHOD1(OnItemsAdded, void(const OfflineItemList&));
+ MOCK_METHOD1(OnItemRemoved, void(const ContentId&));
+ MOCK_METHOD1(OnItemUpdated, void(const OfflineItem&));
+ };
+
+ MockOfflineContentProvider();
+ ~MockOfflineContentProvider() override;
+
+ bool HasObserver(Observer* observer);
+ void NotifyOnItemsAvailable();
+ void NotifyOnItemsAdded(const OfflineItemList& items);
+ void NotifyOnItemRemoved(const ContentId& id);
+ void NotifyOnItemUpdated(const OfflineItem& item);
+
+ // OfflineContentProvider implementation.
+ bool AreItemsAvailable() override;
+ MOCK_METHOD1(OpenItem, void(const ContentId&));
+ MOCK_METHOD1(RemoveItem, void(const ContentId&));
+ MOCK_METHOD1(CancelDownload, void(const ContentId&));
+ MOCK_METHOD1(PauseDownload, void(const ContentId&));
+ MOCK_METHOD1(ResumeDownload, void(const ContentId&));
+ MOCK_METHOD1(GetItemById, const OfflineItem*(const ContentId&));
+ MOCK_METHOD0(GetAllItems, OfflineItemList());
+ void AddObserver(Observer* observer) override;
+ void RemoveObserver(Observer* observer) override;
+
+ private:
+ base::ObserverList<Observer> observers_;
+ bool items_available_;
+};
+
+} // namespace offline_items_collection
+
+#endif // COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_TEST_SUPPORT_MOCK_OFFLINE_CONTENT_PROVIDER_H_
diff --git a/chromium/components/offline_items_collection/core/test_support/scoped_mock_offline_content_provider.cc b/chromium/components/offline_items_collection/core/test_support/scoped_mock_offline_content_provider.cc
new file mode 100644
index 00000000000..6b3d93c9034
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/test_support/scoped_mock_offline_content_provider.cc
@@ -0,0 +1,41 @@
+// 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/offline_items_collection/core/test_support/scoped_mock_offline_content_provider.h"
+
+#include "components/offline_items_collection/core/offline_content_aggregator.h"
+#include "components/offline_items_collection/core/offline_content_provider.h"
+
+namespace offline_items_collection {
+
+ScopedMockOfflineContentProvider::ScopedMockObserver::ScopedMockObserver(
+ OfflineContentProvider* provider)
+ : provider_(provider) {
+ provider_->AddObserver(this);
+}
+
+ScopedMockOfflineContentProvider::ScopedMockObserver::~ScopedMockObserver() {
+ provider_->RemoveObserver(this);
+}
+
+ScopedMockOfflineContentProvider::ScopedMockOfflineContentProvider(
+ const std::string& name_space,
+ OfflineContentAggregator* aggregator)
+ : name_space_(name_space), aggregator_(aggregator) {
+ aggregator_->RegisterProvider(name_space_, this);
+}
+
+ScopedMockOfflineContentProvider::~ScopedMockOfflineContentProvider() {
+ Unregister();
+}
+
+void ScopedMockOfflineContentProvider::Unregister() {
+ if (!aggregator_)
+ return;
+
+ aggregator_->UnregisterProvider(name_space_);
+ aggregator_ = nullptr;
+}
+
+} // namespace offline_items_collection
diff --git a/chromium/components/offline_items_collection/core/test_support/scoped_mock_offline_content_provider.h b/chromium/components/offline_items_collection/core/test_support/scoped_mock_offline_content_provider.h
new file mode 100644
index 00000000000..a0593a201ed
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/test_support/scoped_mock_offline_content_provider.h
@@ -0,0 +1,40 @@
+// 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_OFFLINE_ITEMS_COLLECTION_CORE_TEST_SUPPORT_SCOPED_MOCK_OFFLINE_CONTENT_PROVIDER_H_
+#define COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_TEST_SUPPORT_SCOPED_MOCK_OFFLINE_CONTENT_PROVIDER_H_
+
+#include "components/offline_items_collection/core/test_support/mock_offline_content_provider.h"
+
+namespace offline_items_collection {
+
+class OfflineContentAggregator;
+class OfflineContentProvider;
+
+class ScopedMockOfflineContentProvider : public MockOfflineContentProvider {
+ public:
+ class ScopedMockObserver : public MockObserver {
+ public:
+ explicit ScopedMockObserver(OfflineContentProvider* provider);
+ ~ScopedMockObserver() override;
+
+ private:
+ OfflineContentProvider* const provider_;
+ };
+
+ ScopedMockOfflineContentProvider(const std::string& name_space,
+ OfflineContentAggregator* aggregator);
+ ~ScopedMockOfflineContentProvider() override;
+
+ protected:
+ void Unregister();
+
+ private:
+ const std::string name_space_;
+ OfflineContentAggregator* aggregator_;
+};
+
+} // namespace offline_items_collection
+
+#endif // COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_TEST_SUPPORT_SCOPED_MOCK_OFFLINE_CONTENT_PROVIDER_H_
diff --git a/chromium/components/offline_items_collection/core/throttled_offline_content_provider.cc b/chromium/components/offline_items_collection/core/throttled_offline_content_provider.cc
new file mode 100644
index 00000000000..1b534c84b87
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/throttled_offline_content_provider.cc
@@ -0,0 +1,154 @@
+// 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/offline_items_collection/core/throttled_offline_content_provider.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/offline_items_collection/core/offline_item.h"
+
+namespace offline_items_collection {
+namespace {
+const int kDelayBetweenUpdatesMs = 1000;
+} // namespace
+
+ThrottledOfflineContentProvider::ThrottledOfflineContentProvider(
+ OfflineContentProvider* provider)
+ : ThrottledOfflineContentProvider(
+ base::TimeDelta::FromMilliseconds(kDelayBetweenUpdatesMs),
+ provider) {}
+
+ThrottledOfflineContentProvider::ThrottledOfflineContentProvider(
+ const base::TimeDelta& delay_between_updates,
+ OfflineContentProvider* provider)
+ : delay_between_updates_(delay_between_updates),
+ update_queued_(false),
+ wrapped_provider_(provider),
+ weak_ptr_factory_(this) {
+ DCHECK(wrapped_provider_);
+ wrapped_provider_->AddObserver(this);
+}
+
+ThrottledOfflineContentProvider::~ThrottledOfflineContentProvider() {
+ wrapped_provider_->RemoveObserver(this);
+}
+
+bool ThrottledOfflineContentProvider::AreItemsAvailable() {
+ return wrapped_provider_->AreItemsAvailable();
+}
+
+void ThrottledOfflineContentProvider::OpenItem(const ContentId& id) {
+ wrapped_provider_->OpenItem(id);
+}
+
+void ThrottledOfflineContentProvider::RemoveItem(const ContentId& id) {
+ wrapped_provider_->RemoveItem(id);
+}
+
+void ThrottledOfflineContentProvider::CancelDownload(const ContentId& id) {
+ wrapped_provider_->CancelDownload(id);
+}
+
+void ThrottledOfflineContentProvider::PauseDownload(const ContentId& id) {
+ wrapped_provider_->PauseDownload(id);
+}
+
+void ThrottledOfflineContentProvider::ResumeDownload(const ContentId& id) {
+ wrapped_provider_->ResumeDownload(id);
+}
+
+const OfflineItem* ThrottledOfflineContentProvider::GetItemById(
+ const ContentId& id) {
+ const OfflineItem* item = wrapped_provider_->GetItemById(id);
+ if (item)
+ UpdateItemIfPresent(*item);
+ return item;
+}
+
+OfflineContentProvider::OfflineItemList
+ThrottledOfflineContentProvider::GetAllItems() {
+ OfflineItemList items = wrapped_provider_->GetAllItems();
+ for (auto item : items)
+ UpdateItemIfPresent(item);
+ return items;
+}
+
+void ThrottledOfflineContentProvider::AddObserver(
+ OfflineContentProvider::Observer* observer) {
+ DCHECK(observer);
+ observers_.AddObserver(observer);
+ if (!wrapped_provider_->AreItemsAvailable())
+ return;
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThrottledOfflineContentProvider::NotifyItemsAvailable,
+ weak_ptr_factory_.GetWeakPtr(), base::Unretained(observer)));
+}
+
+void ThrottledOfflineContentProvider::RemoveObserver(
+ OfflineContentProvider::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void ThrottledOfflineContentProvider::OnItemsAvailable(
+ OfflineContentProvider* provider) {
+ DCHECK_EQ(provider, wrapped_provider_);
+ for (auto& observer : observers_)
+ observer.OnItemsAvailable(this);
+}
+
+void ThrottledOfflineContentProvider::OnItemsAdded(
+ const OfflineItemList& items) {
+ for (auto& observer : observers_)
+ observer.OnItemsAdded(items);
+}
+
+void ThrottledOfflineContentProvider::OnItemRemoved(const ContentId& id) {
+ updates_.erase(id);
+ for (auto& observer : observers_)
+ observer.OnItemRemoved(id);
+}
+
+void ThrottledOfflineContentProvider::OnItemUpdated(const OfflineItem& item) {
+ updates_[item.id] = item;
+ if (update_queued_)
+ return;
+
+ update_queued_ = true;
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&ThrottledOfflineContentProvider::FlushUpdates,
+ weak_ptr_factory_.GetWeakPtr()),
+ delay_between_updates_);
+}
+
+void ThrottledOfflineContentProvider::NotifyItemsAvailable(
+ OfflineContentProvider::Observer* observer) {
+ if (!observers_.HasObserver(observer))
+ return;
+ observer->OnItemsAvailable(this);
+}
+
+void ThrottledOfflineContentProvider::UpdateItemIfPresent(
+ const OfflineItem& item) {
+ OfflineItemMap::iterator it = updates_.find(item.id);
+ if (it != updates_.end())
+ it->second = item;
+}
+
+void ThrottledOfflineContentProvider::FlushUpdates() {
+ update_queued_ = false;
+
+ OfflineItemMap updates = std::move(updates_);
+ for (auto item_pair : updates) {
+ for (auto& observer : observers_)
+ observer.OnItemUpdated(item_pair.second);
+ }
+}
+
+} // namespace offline_items_collection
diff --git a/chromium/components/offline_items_collection/core/throttled_offline_content_provider.h b/chromium/components/offline_items_collection/core/throttled_offline_content_provider.h
new file mode 100644
index 00000000000..b704ffb0a23
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/throttled_offline_content_provider.h
@@ -0,0 +1,83 @@
+// 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_OFFLINE_ITEMS_COLLETION_CORE_THROTTLED_OFFLINE_CONTENT_PROVIDER_H_
+#define COMPONENTS_OFFLINE_ITEMS_COLLETION_CORE_THROTTLED_OFFLINE_CONTENT_PROVIDER_H_
+
+#include <map>
+
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "components/offline_items_collection/core/offline_content_provider.h"
+
+namespace base {
+class TimeDelta;
+} // namespace base
+
+namespace offline_items_collection {
+
+// A simple wrapper around an OfflineContentProvider that throttles
+// OfflineContentProvider::Observer::OnItemUpdated() calls to all registered
+// observers. This class will coalesce updates to an item with an equal
+// ContentId.
+class ThrottledOfflineContentProvider
+ : public OfflineContentProvider,
+ public OfflineContentProvider::Observer {
+ public:
+ explicit ThrottledOfflineContentProvider(OfflineContentProvider* provider);
+ ThrottledOfflineContentProvider(const base::TimeDelta& delay_between_updates,
+ OfflineContentProvider* provider);
+ ~ThrottledOfflineContentProvider() override;
+
+ // OfflineContentProvider implementation.
+ bool AreItemsAvailable() override;
+ void OpenItem(const ContentId& id) override;
+ void RemoveItem(const ContentId& id) override;
+ void CancelDownload(const ContentId& id) override;
+ void PauseDownload(const ContentId& id) override;
+ void ResumeDownload(const ContentId& id) override;
+
+ // Because this class queues updates, a call to Observer::OnItemUpdated might
+ // get triggered with the same contents as returned by these getter methods in
+ // the future.
+ const OfflineItem* GetItemById(const ContentId& id) override;
+ OfflineItemList GetAllItems() override;
+ void AddObserver(OfflineContentProvider::Observer* observer) override;
+ void RemoveObserver(OfflineContentProvider::Observer* observer) override;
+
+ private:
+ // OfflineContentProvider::Observer implementation.
+ void OnItemsAvailable(OfflineContentProvider* provider) override;
+ void OnItemsAdded(const OfflineItemList& items) override;
+ void OnItemRemoved(const ContentId& id) override;
+ void OnItemUpdated(const OfflineItem& item) override;
+
+ // Used to notify |observer| that the underying OfflineContentProvider has
+ // called OfflineContentProvider::Observer::OnItemsAvailable().
+ void NotifyItemsAvailable(OfflineContentProvider::Observer* observer);
+
+ // Checks if |item| already has an update pending. If so, replaces the
+ // content of the update with |item|.
+ void UpdateItemIfPresent(const OfflineItem& item);
+
+ // Flushes all pending updates to the observers.
+ void FlushUpdates();
+
+ const base::TimeDelta delay_between_updates_;
+ bool update_queued_;
+
+ OfflineContentProvider* const wrapped_provider_;
+ base::ObserverList<OfflineContentProvider::Observer> observers_;
+
+ typedef std::map<ContentId, OfflineItem> OfflineItemMap;
+ OfflineItemMap updates_;
+
+ base::WeakPtrFactory<ThrottledOfflineContentProvider> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThrottledOfflineContentProvider);
+};
+
+} // namespace offline_items_collection
+
+#endif // COMPONENTS_OFFLINE_ITEMS_COLLETION_CORE_THROTTLED_OFFLINE_CONTENT_PROVIDER_H_
diff --git a/chromium/components/offline_items_collection/core/throttled_offline_content_provider_unittest.cc b/chromium/components/offline_items_collection/core/throttled_offline_content_provider_unittest.cc
new file mode 100644
index 00000000000..414247b35c5
--- /dev/null
+++ b/chromium/components/offline_items_collection/core/throttled_offline_content_provider_unittest.cc
@@ -0,0 +1,279 @@
+// 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/offline_items_collection/core/offline_content_aggregator.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/offline_items_collection/core/offline_item.h"
+#include "components/offline_items_collection/core/test_support/mock_offline_content_provider.h"
+#include "components/offline_items_collection/core/test_support/scoped_mock_offline_content_provider.h"
+#include "components/offline_items_collection/core/throttled_offline_content_provider.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Return;
+
+namespace offline_items_collection {
+namespace {
+
+// Helper class to automatically trigger another OnItemUpdated() to the
+// underlying provider when this observer gets notified of OnItemUpdated().
+// This will only happen the first time the ContentId of the udpated OfflineItem
+// matches the ContentId of the OfflineItem passed into this class constructor.
+class TriggerSingleReentrantUpdateHelper
+ : public ScopedMockOfflineContentProvider::ScopedMockObserver {
+ public:
+ TriggerSingleReentrantUpdateHelper(
+ OfflineContentProvider* provider,
+ MockOfflineContentProvider* wrapped_provider,
+ const OfflineItem& new_item)
+ : ScopedMockObserver(provider),
+ wrapped_provider_(wrapped_provider),
+ new_item_(new_item) {}
+ ~TriggerSingleReentrantUpdateHelper() override {}
+
+ void OnItemUpdated(const OfflineItem& item) override {
+ if (wrapped_provider_) {
+ if (item.id == new_item_.id)
+ wrapped_provider_->NotifyOnItemUpdated(new_item_);
+ wrapped_provider_ = nullptr;
+ }
+ ScopedMockObserver::OnItemUpdated(item);
+ }
+
+ private:
+ MockOfflineContentProvider* wrapped_provider_;
+ OfflineItem new_item_;
+};
+
+class ThrottledOfflineContentProviderTest : public testing::Test {
+ public:
+ ThrottledOfflineContentProviderTest()
+ : task_runner_(new base::TestMockTimeTaskRunner),
+ handle_(task_runner_),
+ provider_(base::TimeDelta::FromMilliseconds(1), &wrapped_provider_) {}
+ ~ThrottledOfflineContentProviderTest() override {}
+
+ protected:
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+ base::ThreadTaskRunnerHandle handle_;
+
+ MockOfflineContentProvider wrapped_provider_;
+ ThrottledOfflineContentProvider provider_;
+};
+
+TEST_F(ThrottledOfflineContentProviderTest, TestReadyBeforeObserver) {
+ EXPECT_FALSE(provider_.AreItemsAvailable());
+ wrapped_provider_.NotifyOnItemsAvailable();
+ EXPECT_TRUE(provider_.AreItemsAvailable());
+
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer1(&provider_);
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer2(&provider_);
+
+ EXPECT_CALL(observer1, OnItemsAvailable(&provider_));
+ EXPECT_CALL(observer2, OnItemsAvailable(&provider_));
+ task_runner_->RunUntilIdle();
+}
+
+TEST_F(ThrottledOfflineContentProviderTest, TestReadyAfterObserver) {
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer(&provider_);
+
+ EXPECT_CALL(observer, OnItemsAvailable(&provider_));
+ EXPECT_FALSE(provider_.AreItemsAvailable());
+ wrapped_provider_.NotifyOnItemsAvailable();
+ EXPECT_TRUE(provider_.AreItemsAvailable());
+}
+
+TEST_F(ThrottledOfflineContentProviderTest, TestBasicPassthrough) {
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer(&provider_);
+
+ ContentId id("1", "A");
+ OfflineItem item(id);
+
+ OfflineContentProvider::OfflineItemList items;
+ items.push_back(item);
+
+ testing::InSequence sequence;
+ EXPECT_CALL(observer, OnItemsAvailable(&provider_));
+ EXPECT_CALL(wrapped_provider_, OpenItem(id));
+ EXPECT_CALL(wrapped_provider_, RemoveItem(id));
+ EXPECT_CALL(wrapped_provider_, CancelDownload(id));
+ EXPECT_CALL(wrapped_provider_, PauseDownload(id));
+ EXPECT_CALL(wrapped_provider_, ResumeDownload(id));
+ EXPECT_CALL(wrapped_provider_, GetItemById(id)).WillRepeatedly(Return(&item));
+ EXPECT_CALL(wrapped_provider_, GetAllItems()).WillRepeatedly(Return(items));
+
+ wrapped_provider_.NotifyOnItemsAvailable();
+ provider_.OpenItem(id);
+ provider_.RemoveItem(id);
+ provider_.CancelDownload(id);
+ provider_.PauseDownload(id);
+ provider_.ResumeDownload(id);
+ EXPECT_EQ(&item, provider_.GetItemById(id));
+ EXPECT_EQ(items, provider_.GetAllItems());
+}
+
+TEST_F(ThrottledOfflineContentProviderTest, TestRemoveCancelsUpdate) {
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer(&provider_);
+
+ ContentId id("1", "A");
+ OfflineItem item(id);
+
+ EXPECT_CALL(observer, OnItemsAvailable(&provider_)).Times(1);
+ EXPECT_CALL(observer, OnItemUpdated(item)).Times(0);
+ EXPECT_CALL(observer, OnItemRemoved(id)).Times(1);
+
+ wrapped_provider_.NotifyOnItemsAvailable();
+ wrapped_provider_.NotifyOnItemUpdated(item);
+ wrapped_provider_.NotifyOnItemRemoved(id);
+ task_runner_->FastForwardUntilNoTasksRemain();
+}
+
+TEST_F(ThrottledOfflineContentProviderTest, TestOnItemUpdatedSquashed) {
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer(&provider_);
+
+ ContentId id1("1", "A");
+ ContentId id2("2", "B");
+
+ OfflineItem item1(id1);
+ OfflineItem item2(id2);
+
+ OfflineItem updated_item1(id1);
+ updated_item1.title = "updated1";
+ OfflineItem updated_item2(id2);
+ updated_item2.title = "updated2";
+
+ EXPECT_CALL(observer, OnItemsAvailable(&provider_)).Times(1);
+ EXPECT_CALL(observer, OnItemUpdated(updated_item1)).Times(1);
+ EXPECT_CALL(observer, OnItemUpdated(updated_item2)).Times(1);
+
+ wrapped_provider_.NotifyOnItemsAvailable();
+ wrapped_provider_.NotifyOnItemUpdated(item1);
+ wrapped_provider_.NotifyOnItemUpdated(item2);
+ wrapped_provider_.NotifyOnItemUpdated(updated_item2);
+ wrapped_provider_.NotifyOnItemUpdated(updated_item1);
+
+ task_runner_->FastForwardUntilNoTasksRemain();
+}
+
+TEST_F(ThrottledOfflineContentProviderTest, TestGetItemByIdOverridesUpdate) {
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer(&provider_);
+
+ ContentId id1("1", "A");
+ ContentId id2("2", "B");
+
+ OfflineItem item1(id1);
+ OfflineItem item2(id2);
+
+ OfflineItem updated_item1(id1);
+ updated_item1.title = "updated1";
+
+ EXPECT_CALL(observer, OnItemsAvailable(&provider_)).Times(1);
+ EXPECT_CALL(wrapped_provider_, GetItemById(id1))
+ .WillRepeatedly(Return(&updated_item1));
+ EXPECT_CALL(observer, OnItemUpdated(updated_item1)).Times(1);
+ EXPECT_CALL(observer, OnItemUpdated(item2)).Times(1);
+
+ wrapped_provider_.NotifyOnItemsAvailable();
+ wrapped_provider_.NotifyOnItemUpdated(item1);
+ wrapped_provider_.NotifyOnItemUpdated(item2);
+
+ EXPECT_EQ(&updated_item1, provider_.GetItemById(id1));
+
+ task_runner_->FastForwardUntilNoTasksRemain();
+}
+
+TEST_F(ThrottledOfflineContentProviderTest, TestGetAllItemsOverridesUpdate) {
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer(&provider_);
+
+ ContentId id1("1", "A");
+ ContentId id2("2", "B");
+
+ OfflineItem item1(id1);
+ OfflineItem item2(id2);
+
+ OfflineItem updated_item1(id1);
+ updated_item1.title = "updated1";
+
+ OfflineContentProvider::OfflineItemList items;
+ items.push_back(updated_item1);
+ items.push_back(item2);
+
+ EXPECT_CALL(observer, OnItemsAvailable(&provider_)).Times(1);
+ EXPECT_CALL(wrapped_provider_, GetAllItems()).WillRepeatedly(Return(items));
+ EXPECT_CALL(observer, OnItemUpdated(updated_item1)).Times(1);
+ EXPECT_CALL(observer, OnItemUpdated(item2)).Times(1);
+
+ wrapped_provider_.NotifyOnItemsAvailable();
+ wrapped_provider_.NotifyOnItemUpdated(item1);
+ wrapped_provider_.NotifyOnItemUpdated(item2);
+
+ EXPECT_EQ(items, provider_.GetAllItems());
+
+ task_runner_->FastForwardUntilNoTasksRemain();
+}
+
+TEST_F(ThrottledOfflineContentProviderTest, TestThrottleWorksProperly) {
+ ScopedMockOfflineContentProvider::ScopedMockObserver observer(&provider_);
+
+ ContentId id1("1", "A");
+
+ OfflineItem item1(id1);
+
+ OfflineItem item2(id1);
+ item2.title = "updated1";
+
+ OfflineItem item3(id1);
+ item3.title = "updated2";
+
+ EXPECT_CALL(observer, OnItemsAvailable(&provider_)).Times(1);
+ EXPECT_CALL(observer, OnItemUpdated(item2)).Times(1);
+
+ wrapped_provider_.NotifyOnItemsAvailable();
+
+ {
+ wrapped_provider_.NotifyOnItemUpdated(item1);
+ wrapped_provider_.NotifyOnItemUpdated(item2);
+ task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(1));
+ }
+
+ {
+ EXPECT_CALL(observer, OnItemUpdated(item3)).Times(1);
+ wrapped_provider_.NotifyOnItemUpdated(item3);
+ task_runner_->FastForwardUntilNoTasksRemain();
+ }
+}
+
+TEST_F(ThrottledOfflineContentProviderTest, TestReentrantUpdatesGetQueued) {
+ ContentId id("1", "A");
+
+ OfflineItem item(id);
+ OfflineItem updated_item(id);
+ updated_item.title = "updated";
+
+ TriggerSingleReentrantUpdateHelper observer(&provider_, &wrapped_provider_,
+ updated_item);
+
+ EXPECT_CALL(observer, OnItemsAvailable(&provider_)).Times(1);
+
+ wrapped_provider_.NotifyOnItemsAvailable();
+
+ {
+ wrapped_provider_.NotifyOnItemUpdated(item);
+ EXPECT_CALL(observer, OnItemUpdated(item)).Times(1);
+ task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(1));
+ }
+
+ {
+ EXPECT_CALL(observer, OnItemUpdated(updated_item)).Times(1);
+ task_runner_->FastForwardUntilNoTasksRemain();
+ }
+}
+
+} // namespace
+} // namespace offline_items_collection;
diff --git a/chromium/components/offline_pages/OWNERS b/chromium/components/offline_pages/OWNERS
index 394e90ea958..4b3428eacec 100644
--- a/chromium/components/offline_pages/OWNERS
+++ b/chromium/components/offline_pages/OWNERS
@@ -3,3 +3,5 @@ dimich@chromium.org
fgorski@chromium.org
jianli@chromium.org
petewil@chromium.org
+
+# COMPONENT: UI>Browser>Offline
diff --git a/chromium/components/offline_pages/core/background/cleanup_task.cc b/chromium/components/offline_pages/core/background/cleanup_task.cc
index 84e2a7864d4..d66d48b610e 100644
--- a/chromium/components/offline_pages/core/background/cleanup_task.cc
+++ b/chromium/components/offline_pages/core/background/cleanup_task.cc
@@ -56,8 +56,8 @@ void CleanupTask::Prune(
return;
}
- // TODO(petewil): Add UMA saying why we remove them
- // TODO(petewil): Round trip the reason for deleting through the RQ
+ // TODO(petewil): Add UMA saying why we remove them. Round trip the reason
+ // for deleting through the RQ callbacks. crbug.com/705115.
store_->RemoveRequests(expired_request_ids,
base::Bind(&CleanupTask::OnRequestsExpired,
weak_ptr_factory_.GetWeakPtr()));
diff --git a/chromium/components/offline_pages/core/background/network_quality_provider_stub.cc b/chromium/components/offline_pages/core/background/network_quality_provider_stub.cc
index aaca69530b1..f4243af9ade 100644
--- a/chromium/components/offline_pages/core/background/network_quality_provider_stub.cc
+++ b/chromium/components/offline_pages/core/background/network_quality_provider_stub.cc
@@ -36,6 +36,14 @@ void NetworkQualityProviderStub::AddEffectiveConnectionTypeObserver(
void NetworkQualityProviderStub::RemoveEffectiveConnectionTypeObserver(
net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer) {}
+void NetworkQualityProviderStub::AddRTTAndThroughputEstimatesObserver(
+ net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer) {
+}
+
+void NetworkQualityProviderStub::RemoveRTTAndThroughputEstimatesObserver(
+ net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer) {
+}
+
net::EffectiveConnectionType
NetworkQualityProviderStub::GetEffectiveConnectionType() const {
return connection_type_;
diff --git a/chromium/components/offline_pages/core/background/network_quality_provider_stub.h b/chromium/components/offline_pages/core/background/network_quality_provider_stub.h
index 1c13a17b3ea..525e1141f39 100644
--- a/chromium/components/offline_pages/core/background/network_quality_provider_stub.h
+++ b/chromium/components/offline_pages/core/background/network_quality_provider_stub.h
@@ -35,6 +35,14 @@ class NetworkQualityProviderStub
net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer)
override;
+ void AddRTTAndThroughputEstimatesObserver(
+ net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer)
+ override;
+
+ void RemoveRTTAndThroughputEstimatesObserver(
+ net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer)
+ override;
+
void SetEffectiveConnectionTypeForTest(net::EffectiveConnectionType type) {
connection_type_ = type;
}
diff --git a/chromium/components/offline_pages/core/background/offliner_policy.h b/chromium/components/offline_pages/core/background/offliner_policy.h
index d828d4c6ea6..f61085b4b51 100644
--- a/chromium/components/offline_pages/core/background/offliner_policy.h
+++ b/chromium/components/offline_pages/core/background/offliner_policy.h
@@ -66,7 +66,7 @@ class OfflinerPolicy {
// TODO(petewil): Numbers here are chosen arbitrarily, do the proper studies
// to get good policy numbers. Eventually this should get data from a finch
- // experiment.
+ // experiment. crbug.com/705112.
// Returns true if we should prefer retrying lesser tried requests.
bool ShouldPreferUntriedRequests() const { return prefer_untried_requests_; }
diff --git a/chromium/components/offline_pages/core/background/pick_request_task.cc b/chromium/components/offline_pages/core/background/pick_request_task.cc
index 006d08b47af..d2faeac9cb1 100644
--- a/chromium/components/offline_pages/core/background/pick_request_task.cc
+++ b/chromium/components/offline_pages/core/background/pick_request_task.cc
@@ -4,6 +4,8 @@
#include "components/offline_pages/core/background/pick_request_task.h"
+#include <unordered_set>
+
#include "base/bind.h"
#include "base/logging.h"
#include "base/time/time.h"
@@ -35,13 +37,15 @@ PickRequestTask::PickRequestTask(RequestQueueStore* store,
RequestNotPickedCallback not_picked_callback,
RequestCountCallback request_count_callback,
DeviceConditions& device_conditions,
- const std::set<int64_t>& disabled_requests)
+ const std::set<int64_t>& disabled_requests,
+ std::deque<int64_t>& prioritized_requests)
: store_(store),
policy_(policy),
picked_callback_(picked_callback),
not_picked_callback_(not_picked_callback),
request_count_callback_(request_count_callback),
disabled_requests_(disabled_requests),
+ prioritized_requests_(prioritized_requests),
weak_ptr_factory_(this) {
device_conditions_.reset(new DeviceConditions(device_conditions));
}
@@ -80,24 +84,26 @@ void PickRequestTask::Choose(
else
comparator = &PickRequestTask::RecencyFirstCompareFunction;
- // TODO(petewil): Consider replacing this bool with a better named enum.
bool non_user_requested_tasks_remaining = false;
bool cleanup_needed = false;
size_t available_request_count = 0;
+ // Request ids which are available for picking.
+ std::unordered_set<int64_t> available_request_ids;
- // Iterate once through the requests, keeping track of best candidate.
- for (unsigned i = 0; i < requests.size(); ++i) {
+ // Iterate through the requests, filter out unavailable requests and get other
+ // information (if cleanup is needed and number of non-user-requested
+ // requests).
+ for (const auto& request : requests) {
// If the request is expired or has exceeded the retry count, skip it.
- if (OfflinerPolicyUtils::CheckRequestExpirationStatus(requests[i].get(),
+ if (OfflinerPolicyUtils::CheckRequestExpirationStatus(request.get(),
policy_) !=
OfflinerPolicyUtils::RequestExpirationStatus::VALID) {
cleanup_needed = true;
continue;
}
-
- // If the request is on the disabled list, skip it.
- auto search = disabled_requests_.find(requests[i]->request_id());
+ // If the request is on the disabled list, skip it.
+ auto search = disabled_requests_.find(request->request_id());
if (search != disabled_requests_.end())
continue;
@@ -106,21 +112,50 @@ void PickRequestTask::Choose(
// detect if any exist. If we don't find any user-requested tasks, we will
// inform the "not_picked_callback_" that it needs to schedule a task for
// non-user-requested items, which have different network and power needs.
- if (!requests[i]->user_requested())
+ if (!request->user_requested())
non_user_requested_tasks_remaining = true;
- if (requests[i]->request_state() ==
- SavePageRequest::RequestState::AVAILABLE) {
+ if (request->request_state() == SavePageRequest::RequestState::AVAILABLE) {
available_request_count++;
}
- if (!RequestConditionsSatisfied(requests[i].get()))
+ if (!RequestConditionsSatisfied(request.get()))
continue;
- if (IsNewRequestBetter(picked_request, requests[i].get(), comparator))
- picked_request = requests[i].get();
+ available_request_ids.insert(request->request_id());
}
-
// Report the request queue counts.
request_count_callback_.Run(requests.size(), available_request_count);
+ // Search for and pick the prioritized request which is available for picking
+ // from |available_request_ids|, the closer to the end means higher priority.
+ // Also if a request in |prioritized_requests_| doesn't exist in |requests|
+ // we're going to remove it.
+ // For every ID in |available_request_ids|, there exists a corresponding
+ // request in |requests|, so this won't be an infinite loop: either we pick a
+ // request, or there's a request being poped from |prioritized_requests_|.
+ while (!picked_request && !prioritized_requests_.empty()) {
+ if (available_request_ids.count(prioritized_requests_.back()) > 0) {
+ for (const auto& request : requests) {
+ if (request->request_id() == prioritized_requests_.back()) {
+ picked_request = request.get();
+ break;
+ }
+ }
+ DCHECK(picked_request);
+ } else {
+ prioritized_requests_.pop_back();
+ }
+ }
+
+ // If no request was found from the priority list, find the best request
+ // according to current policies.
+ if (!picked_request) {
+ for (const auto& request : requests) {
+ if ((available_request_ids.count(request->request_id()) > 0) &&
+ (IsNewRequestBetter(picked_request, request.get(), comparator))) {
+ picked_request = request.get();
+ }
+ }
+ }
+
// If we have a best request to try next, get the request coodinator to
// start it. Otherwise return that we have no candidates.
if (picked_request != nullptr) {
@@ -161,13 +196,6 @@ bool PickRequestTask::RequestConditionsSatisfied(
if (request->request_state() == SavePageRequest::RequestState::PAUSED)
return false;
- // If this request is not active yet, return false.
- // TODO(petewil): If the only reason we return nothing to do is that we have
- // inactive requests, we still want to try again later after their activation
- // time elapses, we shouldn't take ourselves completely off the scheduler.
- if (request->activation_time() > base::Time::Now())
- return false;
-
return true;
}
diff --git a/chromium/components/offline_pages/core/background/pick_request_task.h b/chromium/components/offline_pages/core/background/pick_request_task.h
index ef046124b1e..b6cad2cce18 100644
--- a/chromium/components/offline_pages/core/background/pick_request_task.h
+++ b/chromium/components/offline_pages/core/background/pick_request_task.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_BACKGROUND_PICK_REQUEST_TASK_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_BACKGROUND_PICK_REQUEST_TASK_H_
+#include <deque>
#include <set>
#include "base/memory/weak_ptr.h"
@@ -43,7 +44,8 @@ class PickRequestTask : public Task {
RequestNotPickedCallback not_picked_callback,
RequestCountCallback request_count_callback,
DeviceConditions& device_conditions,
- const std::set<int64_t>& disabled_requests);
+ const std::set<int64_t>& disabled_requests,
+ std::deque<int64_t>& prioritized_requests);
~PickRequestTask() override;
@@ -94,6 +96,7 @@ class PickRequestTask : public Task {
RequestCountCallback request_count_callback_;
std::unique_ptr<DeviceConditions> device_conditions_;
const std::set<int64_t>& disabled_requests_;
+ std::deque<int64_t>& prioritized_requests_;
// Allows us to pass a weak pointer to callbacks.
base::WeakPtrFactory<PickRequestTask> weak_ptr_factory_;
};
diff --git a/chromium/components/offline_pages/core/background/pick_request_task_unittest.cc b/chromium/components/offline_pages/core/background/pick_request_task_unittest.cc
index 1b3ca4642f0..7f686246551 100644
--- a/chromium/components/offline_pages/core/background/pick_request_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/pick_request_task_unittest.cc
@@ -4,6 +4,7 @@
#include "components/offline_pages/core/background/pick_request_task.h"
+#include <deque>
#include <memory>
#include <set>
@@ -127,6 +128,7 @@ class PickRequestTaskTest : public testing::Test {
std::unique_ptr<OfflinerPolicy> policy_;
RequestCoordinatorEventLogger event_logger_;
std::set<int64_t> disabled_requests_;
+ std::deque<int64_t> prioritized_requests_;
std::unique_ptr<PickRequestTask> task_;
bool request_queue_not_picked_called_;
bool cleanup_needed_;
@@ -215,7 +217,7 @@ void PickRequestTaskTest::MakePickRequestTask() {
base::Unretained(this)),
base::Bind(&PickRequestTaskTest::RequestCountCallback,
base::Unretained(this)),
- conditions, disabled_requests_));
+ conditions, disabled_requests_, prioritized_requests_));
task_->SetTaskCompletionCallbackForTesting(
task_runner_.get(),
base::Bind(&PickRequestTaskTest::TaskCompletionCallback,
@@ -493,4 +495,74 @@ TEST_F(PickRequestTaskTest, ChooseRequestThatIsNotDisabled) {
EXPECT_TRUE(task_complete_called_);
}
+TEST_F(PickRequestTaskTest, ChoosePrioritizedRequests) {
+ prioritized_requests_.push_back(kRequestId2);
+ MakePickRequestTask();
+
+ base::Time creation_time = base::Time::Now();
+ SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time,
+ kUserRequested);
+ SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time,
+ kUserRequested);
+ // Since default policy prefer untried requests, make request1 the favorable
+ // pick if no prioritized requests. But request2 is prioritized so it should
+ // be picked.
+ request2.set_completed_attempt_count(kAttemptCount);
+
+ // Add test requests on the Queue.
+ QueueRequests(request1, request2);
+
+ task()->Run();
+ PumpLoop();
+
+ // Pump the loop again to give the async queue the opportunity to return
+ // results from the Get operation, and for the picker to call the "picked"
+ // callback.
+ PumpLoop();
+
+ EXPECT_EQ(kRequestId2, last_picked_->request_id());
+ EXPECT_FALSE(request_queue_not_picked_called_);
+ EXPECT_EQ(2UL, total_request_count_);
+ EXPECT_EQ(2UL, available_request_count_);
+ EXPECT_TRUE(task_complete_called_);
+ EXPECT_EQ(1UL, prioritized_requests_.size());
+}
+
+TEST_F(PickRequestTaskTest, ChooseFromTwoPrioritizedRequests) {
+ // Make two prioritized requests, the second one should be picked because
+ // higher priority requests are later on the list.
+ prioritized_requests_.push_back(kRequestId1);
+ prioritized_requests_.push_back(kRequestId2);
+ MakePickRequestTask();
+
+ // Making request 1 more attractive to be picked not considering the
+ // prioritizing issues with older creation time, fewer attempt count and it's
+ // earlier in the request queue.
+ base::Time creation_time = base::Time::Now();
+ base::Time older_creation_time =
+ creation_time - base::TimeDelta::FromMinutes(10);
+ SavePageRequest request1(kRequestId1, kUrl1, kClientId1, older_creation_time,
+ kUserRequested);
+ SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time,
+ kUserRequested);
+ request2.set_completed_attempt_count(kAttemptCount);
+
+ // Add test requests on the Queue.
+ QueueRequests(request1, request2);
+
+ task()->Run();
+ PumpLoop();
+
+ // Pump the loop again to give the async queue the opportunity to return
+ // results from the Get operation, and for the picker to call the "picked"
+ // callback.
+ PumpLoop();
+
+ EXPECT_EQ(kRequestId2, last_picked_->request_id());
+ EXPECT_FALSE(request_queue_not_picked_called_);
+ EXPECT_EQ(2UL, total_request_count_);
+ EXPECT_EQ(2UL, available_request_count_);
+ EXPECT_TRUE(task_complete_called_);
+ EXPECT_EQ(2UL, prioritized_requests_.size());
+}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/background/reconcile_task.cc b/chromium/components/offline_pages/core/background/reconcile_task.cc
index 9b8427530b5..66833e859e4 100644
--- a/chromium/components/offline_pages/core/background/reconcile_task.cc
+++ b/chromium/components/offline_pages/core/background/reconcile_task.cc
@@ -48,8 +48,6 @@ void ReconcileTask::Reconcile(
if (request->request_state() == SavePageRequest::RequestState::OFFLINING) {
request->set_request_state(SavePageRequest::RequestState::AVAILABLE);
items_to_update.push_back(*request.get());
- // TODO(petewil): Consider adding UMA to see how often chrome gets killed
- // while processing a request.
}
}
diff --git a/chromium/components/offline_pages/core/background/request_coordinator.cc b/chromium/components/offline_pages/core/background/request_coordinator.cc
index 1a859fbcf11..167ffa78c7f 100644
--- a/chromium/components/offline_pages/core/background/request_coordinator.cc
+++ b/chromium/components/offline_pages/core/background/request_coordinator.cc
@@ -197,8 +197,7 @@ RequestCoordinator::RequestCoordinator(
net::NetworkQualityEstimator::NetworkQualityProvider*
network_quality_estimator)
: is_low_end_device_(base::SysInfo::IsLowEndDevice()),
- is_busy_(false),
- is_starting_(false),
+ state_(RequestCoordinatorState::IDLE),
processing_state_(ProcessingWindowState::STOPPED),
use_test_device_conditions_(false),
offliner_(std::move(offliner)),
@@ -287,7 +286,7 @@ void RequestCoordinator::GetQueuedRequestsCallback(
void RequestCoordinator::StopPrerendering(
const Offliner::CancelCallback& final_callback,
Offliner::RequestStatus stop_status) {
- if (offliner_ && is_busy_) {
+ if (offliner_ && state_ == RequestCoordinatorState::OFFLINING) {
DCHECK(active_request_.get());
offliner_->Cancel(base::Bind(
&RequestCoordinator::HandleCancelUpdateStatusCallback,
@@ -415,6 +414,15 @@ void RequestCoordinator::RemoveRequests(
void RequestCoordinator::PauseRequests(
const std::vector<int64_t>& request_ids) {
bool canceled = CancelActiveRequestIfItMatches(request_ids);
+
+ // Remove the paused requests from prioritized list.
+ for (int64_t id : request_ids) {
+ auto it = std::find(prioritized_requests_.begin(),
+ prioritized_requests_.end(), id);
+ if (it != prioritized_requests_.end())
+ prioritized_requests_.erase(it);
+ }
+
queue_->ChangeRequestsState(
request_ids, SavePageRequest::RequestState::PAUSED,
base::Bind(&RequestCoordinator::UpdateMultipleRequestsCallback,
@@ -434,6 +442,8 @@ void RequestCoordinator::PauseRequests(
void RequestCoordinator::ResumeRequests(
const std::vector<int64_t>& request_ids) {
+ prioritized_requests_.insert(prioritized_requests_.end(), request_ids.begin(),
+ request_ids.end());
queue_->ChangeRequestsState(
request_ids, SavePageRequest::RequestState::AVAILABLE,
base::Bind(&RequestCoordinator::UpdateMultipleRequestsCallback,
@@ -544,9 +554,9 @@ void RequestCoordinator::UpdateStatusForCancel(
RecordOfflinerResultUMA(active_request_->client_id(),
active_request_->creation_time(),
last_offlining_status_);
- is_busy_ = false;
active_request_.reset();
}
+ state_ = RequestCoordinatorState::IDLE;
}
void RequestCoordinator::ResetActiveRequestCallback(int64_t offline_id) {
@@ -613,7 +623,7 @@ bool RequestCoordinator::StartImmediateProcessing(
bool RequestCoordinator::StartProcessingInternal(
const ProcessingWindowState processing_state,
const base::Callback<void(bool)>& callback) {
- if (is_starting_ || is_busy_)
+ if (state_ != RequestCoordinatorState::IDLE)
return false;
processing_state_ = processing_state;
scheduler_callback_ = callback;
@@ -636,7 +646,7 @@ RequestCoordinator::TryImmediateStart(
const base::Callback<void(bool)>& callback) {
DVLOG(2) << "Immediate " << __func__;
// Make sure not already busy processing.
- if (is_busy_)
+ if (state_ == RequestCoordinatorState::OFFLINING)
return OfflinerImmediateStartStatus::BUSY;
// Make sure we are not on svelte device to start immediately.
@@ -691,13 +701,10 @@ void RequestCoordinator::UpdateCurrentConditionsFromAndroid() {
}
void RequestCoordinator::TryNextRequest(bool is_start_of_processing) {
- is_starting_ = true;
+ state_ = RequestCoordinatorState::PICKING;
// If this is the first call, the device conditions are current, no need to
// update them.
- // TODO(petewil): Now that we can get conditions any time, consider getting
- // them now instead of passing them in earlier when we start scheduled
- // processing.
if (!is_start_of_processing) {
// Get current device conditions from the Java side across the bridge.
// NetworkChangeNotifier will not have the right conditions if chromium is
@@ -726,7 +733,7 @@ void RequestCoordinator::TryNextRequest(bool is_start_of_processing) {
if (connection_type ==
net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE ||
(base::Time::Now() - operation_start_time_) > processing_time_budget) {
- is_starting_ = false;
+ state_ = RequestCoordinatorState::IDLE;
// If we were doing immediate processing, try to start it again
// when we get connected.
@@ -734,37 +741,34 @@ void RequestCoordinator::TryNextRequest(bool is_start_of_processing) {
RequestConnectedEventForStarting();
// Let the scheduler know we are done processing.
- // TODO: Make sure the scheduler callback is valid before running it.
scheduler_callback_.Run(true);
DVLOG(2) << " out of time, giving up. " << __func__;
return;
}
- // Ask request queue to make a new PickRequestTask object, then put it on the
- // task queue.
+ // Ask request queue to make a new PickRequestTask object, then put it on
+ // the task queue.
queue_->PickNextRequest(
- policy_.get(), base::Bind(&RequestCoordinator::RequestPicked,
- weak_ptr_factory_.GetWeakPtr()),
+ policy_.get(),
+ base::Bind(&RequestCoordinator::RequestPicked,
+ weak_ptr_factory_.GetWeakPtr()),
base::Bind(&RequestCoordinator::RequestNotPicked,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&RequestCoordinator::RequestCounts,
weak_ptr_factory_.GetWeakPtr(), is_start_of_processing),
- *current_conditions_.get(), disabled_requests_);
- // TODO(petewil): Verify current_conditions has a good value on all calling
- // paths. It is really more of a "last known conditions" than "current
- // conditions". Consider having a call to Java to check the current
- // conditions.
+ *current_conditions_.get(), disabled_requests_, prioritized_requests_);
}
// Called by the request picker when a request has been picked.
void RequestCoordinator::RequestPicked(const SavePageRequest& request,
bool cleanup_needed) {
DVLOG(2) << request.url() << " " << __func__;
- is_starting_ = false;
- // Make sure we were not stopped while picking.
- if (processing_state_ != ProcessingWindowState::STOPPED) {
+ // Make sure we were not stopped while picking, since any kind of cancel/stop
+ // will reset the state back to IDLE.
+ if (state_ == RequestCoordinatorState::PICKING) {
+ state_ = RequestCoordinatorState::OFFLINING;
// Send the request on to the offliner.
SendRequestToOffliner(request);
}
@@ -778,7 +782,7 @@ void RequestCoordinator::RequestNotPicked(
bool non_user_requested_tasks_remaining,
bool cleanup_needed) {
DVLOG(2) << __func__;
- is_starting_ = false;
+ state_ = RequestCoordinatorState::IDLE;
// Clear the outstanding "safety" task in the scheduler.
scheduler_->Unschedule();
@@ -848,21 +852,7 @@ void RequestCoordinator::RequestCounts(bool is_start_of_processing,
}
void RequestCoordinator::SendRequestToOffliner(const SavePageRequest& request) {
- // Check that offlining didn't get cancelled while performing some async
- // steps.
- if (processing_state_ == ProcessingWindowState::STOPPED)
- return;
-
- if (!offliner_) {
- // TODO(chili,petewil): We should have UMA here to track frequency of this,
- // if it happens at all.
- DVLOG(0) << "Offliner crashed. Cannot background offline page.";
- return;
- }
-
- DCHECK(!is_busy_);
- is_busy_ = true;
-
+ DCHECK(state_ == RequestCoordinatorState::OFFLINING);
// Record start time if this is first attempt.
if (request.started_attempt_count() == 0) {
RecordStartTimeUMA(request);
@@ -884,7 +874,7 @@ void RequestCoordinator::StartOffliner(
update_result->item_statuses.size() != 1 ||
update_result->item_statuses.at(0).first != request_id ||
update_result->item_statuses.at(0).second != ItemActionStatus::SUCCESS) {
- is_busy_ = false;
+ state_ = RequestCoordinatorState::IDLE;
StopProcessing(Offliner::QUEUE_UPDATE_FAILED);
DVLOG(1) << "Failed to mark attempt started: " << request_id;
UpdateRequestResult request_result =
@@ -924,7 +914,7 @@ void RequestCoordinator::StartOffliner(
watchdog_timer_.Start(FROM_HERE, timeout, this,
&RequestCoordinator::HandleWatchdogTimeout);
} else {
- is_busy_ = false;
+ state_ = RequestCoordinatorState::IDLE;
DVLOG(0) << "Unable to start LoadAndSave";
StopProcessing(Offliner::LOADING_NOT_ACCEPTED);
@@ -947,7 +937,7 @@ void RequestCoordinator::OfflinerDoneCallback(const SavePageRequest& request,
RecordOfflinerResultUMA(request.client_id(), request.creation_time(),
last_offlining_status_);
watchdog_timer_.Stop();
- is_busy_ = false;
+ state_ = RequestCoordinatorState::IDLE;
active_request_.reset(nullptr);
UpdateRequestForCompletedAttempt(request, status);
diff --git a/chromium/components/offline_pages/core/background/request_coordinator.h b/chromium/components/offline_pages/core/background/request_coordinator.h
index d4b91009ebd..412808c9da6 100644
--- a/chromium/components/offline_pages/core/background/request_coordinator.h
+++ b/chromium/components/offline_pages/core/background/request_coordinator.h
@@ -62,6 +62,12 @@ class RequestCoordinator : public KeyedService,
DISABLED_FOR_OFFLINER,
};
+ enum class RequestCoordinatorState {
+ IDLE,
+ PICKING,
+ OFFLINING,
+ };
+
// Describes the parameters to control how to save a page when system
// conditions allow.
struct SavePageLaterParams {
@@ -204,11 +210,8 @@ class RequestCoordinator : public KeyedService,
return last_offlining_status_;
}
- bool is_busy() { return is_busy_; }
-
- // Returns whether processing is starting (before it is decided to actually
- // process a request (is_busy()) at this time or not.
- bool is_starting() { return is_starting_; }
+ // Return the state of the request coordinator.
+ RequestCoordinatorState state() { return state_; }
// Tracks whether the last offlining attempt got canceled. This is reset by
// the next call to start processing.
@@ -406,13 +409,8 @@ class RequestCoordinator : public KeyedService,
// Cached value of whether low end device. Overwritable for testing.
bool is_low_end_device_;
- // The offliner can only handle one request at a time - if the offliner is
- // busy, prevent other requests. This flag marks whether the offliner is in
- // use.
- bool is_busy_;
- // There is more than one path to start processing so this flag is used
- // to avoid race conditions before is_busy_ is established.
- bool is_starting_;
+ // Current state of the request coordinator.
+ RequestCoordinatorState state_;
// Identifies the type of current processing window or if processing stopped.
ProcessingWindowState processing_state_;
// True if we should use the test device conditions instead of actual
@@ -461,6 +459,15 @@ class RequestCoordinator : public KeyedService,
base::OneShotTimer watchdog_timer_;
// Used for potential immediate processing when we get network connection.
std::unique_ptr<ConnectionNotifier> connection_notifier_;
+ // Used to track prioritized requests.
+ // The requests can only be added by RC when they are resumed and there are
+ // two places where deletion from the |prioritized_requests_| would happen:
+ // 1. When request is paused RC will remove it.
+ // 2. When a task is not available to be picked by PickRequestTask (because
+ // it was completed or cancelled), the task will remove it.
+ // Currently it's used as LIFO.
+ // TODO(romax): see if LIFO is a good idea or change to FIFO. crbug.com/705106
+ std::deque<int64_t> prioritized_requests_;
// Allows us to pass a weak pointer to callbacks.
base::WeakPtrFactory<RequestCoordinator> weak_ptr_factory_;
diff --git a/chromium/components/offline_pages/core/background/request_coordinator_unittest.cc b/chromium/components/offline_pages/core/background/request_coordinator_unittest.cc
index b732165b4e4..b45cf5547f3 100644
--- a/chromium/components/offline_pages/core/background/request_coordinator_unittest.cc
+++ b/chromium/components/offline_pages/core/background/request_coordinator_unittest.cc
@@ -119,6 +119,8 @@ class ObserverStub : public RequestCoordinator::Observer {
class RequestCoordinatorTest : public testing::Test {
public:
+ using RequestCoordinatorState = RequestCoordinator::RequestCoordinatorState;
+
RequestCoordinatorTest();
~RequestCoordinatorTest() override;
@@ -130,9 +132,7 @@ class RequestCoordinatorTest : public testing::Test {
return coordinator_taco_->request_coordinator();
}
- bool is_busy() { return coordinator()->is_busy(); }
-
- bool is_starting() { return coordinator()->is_starting(); }
+ RequestCoordinatorState state() { return coordinator()->state(); }
// Test processing callback function.
void ProcessingCallbackFunction(bool result) {
@@ -310,6 +310,10 @@ class RequestCoordinatorTest : public testing::Test {
return coordinator()->disabled_requests_;
}
+ const std::deque<int64_t>& prioritized_requests() {
+ return coordinator()->prioritized_requests_;
+ }
+
private:
GetRequestsResult last_get_requests_result_;
MultipleItemStatuses last_remove_results_;
@@ -489,7 +493,7 @@ TEST_F(RequestCoordinatorTest, StartScheduledProcessingWithRequestInProgress) {
processing_callback()));
PumpLoop();
- EXPECT_TRUE(is_busy());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
// Since the offliner is disabled, this callback should not be called.
EXPECT_FALSE(processing_callback_called());
@@ -538,7 +542,7 @@ TEST_F(RequestCoordinatorTest, StartImmediateProcessingWithRequestInProgress) {
EXPECT_TRUE(coordinator()->StartImmediateProcessing(processing_callback()));
PumpLoop();
- EXPECT_TRUE(is_busy());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
// Since the offliner is disabled, this callback should not be called.
EXPECT_FALSE(processing_callback_called());
@@ -693,13 +697,13 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestSucceededButLostNetwork) {
EXPECT_TRUE(processing_callback_called());
// Verify not busy with 2nd request (since no connection).
- EXPECT_FALSE(is_busy());
+ EXPECT_FALSE(state() == RequestCoordinatorState::OFFLINING);
// Now connect network and verify processing starts.
SetNetworkConnected(true);
CallConnectionTypeObserver();
PumpLoop();
- EXPECT_TRUE(is_busy());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
}
TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailed) {
@@ -725,7 +729,7 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailed) {
EXPECT_FALSE(processing_callback_called());
// Busy processing 2nd request.
- EXPECT_TRUE(is_busy());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
coordinator()->queue()->GetRequests(base::Bind(
&RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
@@ -767,7 +771,7 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailedNoRetryFailure) {
EXPECT_FALSE(processing_callback_called());
// Busy processing 2nd request.
- EXPECT_TRUE(is_busy());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
coordinator()->queue()->GetRequests(base::Bind(
&RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
@@ -804,7 +808,7 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailedNoNextFailure) {
EXPECT_TRUE(processing_callback_called());
// Not busy for NO_NEXT failure.
- EXPECT_FALSE(is_busy());
+ EXPECT_FALSE(state() == RequestCoordinatorState::OFFLINING);
coordinator()->queue()->GetRequests(base::Bind(
&RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
@@ -868,13 +872,13 @@ TEST_F(RequestCoordinatorTest, OfflinerDonePrerenderingCancel) {
TEST_F(RequestCoordinatorTest, RequestNotPickedDisabledItemsRemain) {
coordinator()->StartScheduledProcessing(device_conditions(),
processing_callback());
- EXPECT_TRUE(is_starting());
+ EXPECT_TRUE(state() == RequestCoordinatorState::PICKING);
// Call RequestNotPicked, simulating a request on the disabled list.
CallRequestNotPicked(false, true);
PumpLoop();
- EXPECT_FALSE(is_starting());
+ EXPECT_FALSE(state() == RequestCoordinatorState::PICKING);
// The scheduler should have been called to schedule the disabled task for
// 5 minutes from now.
@@ -889,14 +893,14 @@ TEST_F(RequestCoordinatorTest, RequestNotPickedDisabledItemsRemain) {
TEST_F(RequestCoordinatorTest, RequestNotPickedNonUserRequestedItemsRemain) {
coordinator()->StartScheduledProcessing(device_conditions(),
processing_callback());
- EXPECT_TRUE(is_starting());
+ EXPECT_TRUE(state() == RequestCoordinatorState::PICKING);
// Call RequestNotPicked, and make sure we pick schedule a task for non user
// requested conditions, with no tasks on the disabled list.
CallRequestNotPicked(true, false);
PumpLoop();
- EXPECT_FALSE(is_starting());
+ EXPECT_FALSE(state() == RequestCoordinatorState::PICKING);
EXPECT_TRUE(processing_callback_called());
// The scheduler should have been called to schedule the non-user requested
@@ -959,7 +963,7 @@ TEST_F(RequestCoordinatorTest, StartScheduledProcessingWithLoadingDisabled) {
PumpLoop();
EXPECT_TRUE(processing_callback_called());
- EXPECT_FALSE(is_starting());
+ EXPECT_FALSE(state() == RequestCoordinatorState::PICKING);
EXPECT_EQ(Offliner::LOADING_NOT_ACCEPTED, last_offlining_status());
}
@@ -975,7 +979,7 @@ TEST_F(RequestCoordinatorTest,
EXPECT_TRUE(coordinator()->StartScheduledProcessing(device_conditions(),
processing_callback()));
- EXPECT_TRUE(is_starting());
+ EXPECT_TRUE(state() == RequestCoordinatorState::PICKING);
// Now, quick, before it can do much (we haven't called PumpLoop), cancel it.
coordinator()->StopProcessing(Offliner::REQUEST_COORDINATOR_CANCELED);
@@ -984,7 +988,7 @@ TEST_F(RequestCoordinatorTest,
PumpLoop();
EXPECT_TRUE(processing_callback_called());
- EXPECT_FALSE(is_starting());
+ EXPECT_FALSE(state() == RequestCoordinatorState::PICKING);
// OfflinerDoneCallback will not end up getting called with status SAVED,
// since we cancelled the event before it called offliner_->LoadAndSave().
@@ -1007,7 +1011,7 @@ TEST_F(RequestCoordinatorTest,
EXPECT_TRUE(coordinator()->StartScheduledProcessing(device_conditions(),
processing_callback()));
- EXPECT_TRUE(is_starting());
+ EXPECT_TRUE(state() == RequestCoordinatorState::PICKING);
// Let all the async parts of the start processing pipeline run to completion.
PumpLoop();
@@ -1021,8 +1025,8 @@ TEST_F(RequestCoordinatorTest,
EXPECT_FALSE(processing_callback_called());
// Coordinator should now be busy.
- EXPECT_TRUE(is_busy());
- EXPECT_FALSE(is_starting());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
+ EXPECT_FALSE(state() == RequestCoordinatorState::PICKING);
// Now we cancel it while the prerenderer is busy.
coordinator()->StopProcessing(Offliner::REQUEST_COORDINATOR_CANCELED);
@@ -1035,7 +1039,7 @@ TEST_F(RequestCoordinatorTest,
EXPECT_EQ(SavePageRequest::RequestState::AVAILABLE, observer().state());
observer().Clear();
- EXPECT_FALSE(is_busy());
+ EXPECT_FALSE(state() == RequestCoordinatorState::OFFLINING);
// OfflinerDoneCallback will not end up getting called with status SAVED,
// since we cancelled the event before the LoadAndSave completed.
@@ -1167,8 +1171,8 @@ TEST_F(RequestCoordinatorTest,
WaitForCallback();
PumpLoop();
- EXPECT_FALSE(is_starting());
- EXPECT_FALSE(coordinator()->is_busy());
+ EXPECT_FALSE(state() == RequestCoordinatorState::PICKING);
+ EXPECT_FALSE(state() == RequestCoordinatorState::OFFLINING);
EXPECT_TRUE(OfflinerWasCanceled());
}
@@ -1182,7 +1186,7 @@ TEST_F(RequestCoordinatorTest,
PumpLoop();
// Verify that immediate start from adding the request did happen.
- EXPECT_TRUE(coordinator()->is_busy());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
// Advance the mock clock 1 second before the watchdog timeout.
AdvanceClockBy(base::TimeDelta::FromSeconds(
@@ -1193,7 +1197,7 @@ TEST_F(RequestCoordinatorTest,
PumpLoop();
// Verify still busy.
- EXPECT_TRUE(coordinator()->is_busy());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
EXPECT_FALSE(OfflinerWasCanceled());
// Advance the mock clock past the watchdog timeout now.
@@ -1253,7 +1257,7 @@ TEST_F(RequestCoordinatorTest, TryNextRequestWithNoNetwork) {
EXPECT_TRUE(coordinator()->StartScheduledProcessing(device_conditions(),
waiting_callback()));
PumpLoop();
- EXPECT_TRUE(coordinator()->is_busy());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
// Now lose the network connection.
SetNetworkConnected(false);
@@ -1264,8 +1268,8 @@ TEST_F(RequestCoordinatorTest, TryNextRequestWithNoNetwork) {
PumpLoop();
// Not starting nor busy with next request.
- EXPECT_FALSE(coordinator()->is_starting());
- EXPECT_FALSE(coordinator()->is_busy());
+ EXPECT_FALSE(state() == RequestCoordinatorState::PICKING);
+ EXPECT_FALSE(state() == RequestCoordinatorState::OFFLINING);
// Get queued requests.
coordinator()->queue()->GetRequests(base::Bind(
@@ -1369,7 +1373,7 @@ TEST_F(RequestCoordinatorTest,
EXPECT_NE(0, SavePageLater());
PumpLoop();
- EXPECT_TRUE(is_busy());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
}
TEST_F(RequestCoordinatorTest,
@@ -1383,7 +1387,7 @@ TEST_F(RequestCoordinatorTest,
PumpLoop();
// Verify not immediately busy (since low-end device).
- EXPECT_FALSE(is_busy());
+ EXPECT_FALSE(state() == RequestCoordinatorState::OFFLINING);
// Set feature flag to allow concurrent loads.
base::test::ScopedFeatureList scoped_feature_list;
@@ -1404,7 +1408,7 @@ TEST_F(RequestCoordinatorTest,
PumpLoop();
// Verify immediate processing did start this time.
- EXPECT_TRUE(is_busy());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
}
TEST_F(RequestCoordinatorTest, SavePageDoesntStartProcessingWhenDisconnected) {
@@ -1412,13 +1416,13 @@ TEST_F(RequestCoordinatorTest, SavePageDoesntStartProcessingWhenDisconnected) {
EnableOfflinerCallback(false);
EXPECT_NE(0, SavePageLater());
PumpLoop();
- EXPECT_FALSE(is_busy());
+ EXPECT_FALSE(state() == RequestCoordinatorState::OFFLINING);
// Now connect network and verify processing starts.
SetNetworkConnected(true);
CallConnectionTypeObserver();
PumpLoop();
- EXPECT_TRUE(is_busy());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
}
TEST_F(RequestCoordinatorTest,
@@ -1436,7 +1440,7 @@ TEST_F(RequestCoordinatorTest,
EXPECT_NE(0, SavePageLater());
PumpLoop();
- EXPECT_TRUE(is_busy());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
}
TEST_F(RequestCoordinatorTest,
@@ -1451,7 +1455,7 @@ TEST_F(RequestCoordinatorTest,
// Add a request to the queue.
AddRequest1();
PumpLoop();
- EXPECT_FALSE(is_busy());
+ EXPECT_FALSE(state() == RequestCoordinatorState::OFFLINING);
// Pause the request.
std::vector<int64_t> request_ids;
@@ -1462,21 +1466,24 @@ TEST_F(RequestCoordinatorTest,
// Resume the request while disconnected.
coordinator()->ResumeRequests(request_ids);
PumpLoop();
- EXPECT_FALSE(is_busy());
+ EXPECT_FALSE(state() == RequestCoordinatorState::OFFLINING);
+ EXPECT_EQ(1UL, prioritized_requests().size());
// Pause the request again.
coordinator()->PauseRequests(request_ids);
PumpLoop();
+ EXPECT_EQ(0UL, prioritized_requests().size());
// Now simulate reasonable connection.
SetNetworkConnected(true);
// Resume the request while connected.
coordinator()->ResumeRequests(request_ids);
- EXPECT_FALSE(is_busy());
+ EXPECT_FALSE(state() == RequestCoordinatorState::OFFLINING);
PumpLoop();
+ EXPECT_EQ(1UL, prioritized_requests().size());
- EXPECT_TRUE(is_busy());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
}
TEST_F(RequestCoordinatorTest, SnapshotOnLastTryForScheduledProcessing) {
@@ -1542,7 +1549,7 @@ TEST_F(RequestCoordinatorTest, SnapshotOnLastTryForImmediateProcessing) {
observer().Clear();
// Verify that the request is being processed.
- EXPECT_TRUE(coordinator()->is_busy());
+ EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
// Advance the mock clock 1 second more than the watchdog timeout.
AdvanceClockBy(base::TimeDelta::FromSeconds(
diff --git a/chromium/components/offline_pages/core/background/request_queue.cc b/chromium/components/offline_pages/core/background/request_queue.cc
index 406f0ae0ce4..bac52ae5abb 100644
--- a/chromium/components/offline_pages/core/background/request_queue.cc
+++ b/chromium/components/offline_pages/core/background/request_queue.cc
@@ -31,10 +31,6 @@ void GetRequestsDone(const RequestQueue::GetRequestsCallback& callback,
std::vector<std::unique_ptr<SavePageRequest>> requests) {
GetRequestsResult result =
success ? GetRequestsResult::SUCCESS : GetRequestsResult::STORE_FAILURE;
- // TODO(fgorski): Filter out expired requests based on policy.
- // This may trigger the purging if necessary.
- // Also this may be turned into a method on the request queue or add a policy
- // parameter in the process.
callback.Run(result, std::move(requests));
}
@@ -78,8 +74,6 @@ void RequestQueue::GetRequests(const GetRequestsCallback& callback) {
void RequestQueue::AddRequest(const SavePageRequest& request,
const AddRequestCallback& callback) {
- // TODO(fgorski): check that request makes sense.
- // TODO(fgorski): check that request does not violate policy.
std::unique_ptr<AddRequestTask> task(new AddRequestTask(
store_.get(), request, base::Bind(&AddRequestDone, callback, request)));
task_queue_.AddTask(std::move(task));
@@ -128,11 +122,13 @@ void RequestQueue::PickNextRequest(
PickRequestTask::RequestNotPickedCallback not_picked_callback,
PickRequestTask::RequestCountCallback request_count_callback,
DeviceConditions& conditions,
- std::set<int64_t>& disabled_requests) {
+ std::set<int64_t>& disabled_requests,
+ std::deque<int64_t>& prioritized_requests) {
// Using the PickerContext, create a picker task.
- std::unique_ptr<Task> task(new PickRequestTask(
- store_.get(), policy, picked_callback, not_picked_callback,
- request_count_callback, conditions, disabled_requests));
+ std::unique_ptr<Task> task(
+ new PickRequestTask(store_.get(), policy, picked_callback,
+ not_picked_callback, request_count_callback,
+ conditions, disabled_requests, prioritized_requests));
// Queue up the picking task, it will call one of the callbacks when it
// completes.
diff --git a/chromium/components/offline_pages/core/background/request_queue.h b/chromium/components/offline_pages/core/background/request_queue.h
index 8325dd07173..d0c66a7ad48 100644
--- a/chromium/components/offline_pages/core/background/request_queue.h
+++ b/chromium/components/offline_pages/core/background/request_queue.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include <deque>
#include <memory>
#include <set>
#include <string>
@@ -95,7 +96,8 @@ class RequestQueue {
PickRequestTask::RequestNotPickedCallback not_picked_callback,
PickRequestTask::RequestCountCallback request_count_callback,
DeviceConditions& conditions,
- std::set<int64_t>& disabled_requests);
+ std::set<int64_t>& disabled_requests,
+ std::deque<int64_t>& prioritized_requests);
// Reconcile any requests that were active the last time chrome exited.
void ReconcileRequests(const UpdateCallback& callback);
diff --git a/chromium/components/offline_pages/core/background/request_queue_store_sql.cc b/chromium/components/offline_pages/core/background/request_queue_store_sql.cc
index 099f774180f..16a13e49c6b 100644
--- a/chromium/components/offline_pages/core/background/request_queue_store_sql.cc
+++ b/chromium/components/offline_pages/core/background/request_queue_store_sql.cc
@@ -97,7 +97,7 @@ bool CreateSchema(sql::Connection* db) {
return false;
}
- // TODO(fgorski): Add indices here.
+ // This would be a great place to add indices when we need them.
return transaction.Commit();
}
@@ -109,8 +109,6 @@ std::unique_ptr<SavePageRequest> MakeSavePageRequest(
const int64_t id = statement.ColumnInt64(0);
const base::Time creation_time =
base::Time::FromInternalValue(statement.ColumnInt64(1));
- const base::Time activation_time =
- base::Time::FromInternalValue(statement.ColumnInt64(2));
const base::Time last_attempt_time =
base::Time::FromInternalValue(statement.ColumnInt64(3));
const int64_t started_attempt_count = statement.ColumnInt64(4);
@@ -127,8 +125,8 @@ std::unique_ptr<SavePageRequest> MakeSavePageRequest(
<< " creation time " << creation_time << " user requested "
<< kUserRequested << " original_url " << original_url;
- std::unique_ptr<SavePageRequest> request(new SavePageRequest(
- id, url, client_id, creation_time, activation_time, kUserRequested));
+ std::unique_ptr<SavePageRequest> request(
+ new SavePageRequest(id, url, client_id, creation_time, kUserRequested));
request->set_last_attempt_time(last_attempt_time);
request->set_started_attempt_count(started_attempt_count);
request->set_completed_attempt_count(completed_attempt_count);
@@ -178,7 +176,7 @@ ItemActionStatus Insert(sql::Connection* db, const SavePageRequest& request) {
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
statement.BindInt64(0, request.request_id());
statement.BindInt64(1, request.creation_time().ToInternalValue());
- statement.BindInt64(2, request.activation_time().ToInternalValue());
+ statement.BindInt64(2, 0);
statement.BindInt64(3, request.last_attempt_time().ToInternalValue());
statement.BindInt64(4, request.started_attempt_count());
statement.BindInt64(5, request.completed_attempt_count());
@@ -205,7 +203,7 @@ ItemActionStatus Update(sql::Connection* db, const SavePageRequest& request) {
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
statement.BindInt64(0, request.creation_time().ToInternalValue());
- statement.BindInt64(1, request.activation_time().ToInternalValue());
+ statement.BindInt64(1, 0);
statement.BindInt64(2, request.last_attempt_time().ToInternalValue());
statement.BindInt64(3, request.started_attempt_count());
statement.BindInt64(4, request.completed_attempt_count());
@@ -294,7 +292,6 @@ void GetRequestsByIdsSync(sql::Connection* db,
scoped_refptr<base::SingleThreadTaskRunner> runner,
const std::vector<int64_t>& request_ids,
const RequestQueueStore::UpdateCallback& callback) {
- // TODO(fgorski): Perhaps add metrics here.
std::unique_ptr<UpdateRequestsResult> result(
new UpdateRequestsResult(StoreState::LOADED));
@@ -332,7 +329,6 @@ void AddRequestSync(sql::Connection* db,
scoped_refptr<base::SingleThreadTaskRunner> runner,
const SavePageRequest& request,
const RequestQueueStore::AddCallback& callback) {
- // TODO(fgorski): add UMA metrics here.
ItemActionStatus status = Insert(db, request);
runner->PostTask(FROM_HERE, base::Bind(callback, status));
}
@@ -341,7 +337,6 @@ void UpdateRequestsSync(sql::Connection* db,
scoped_refptr<base::SingleThreadTaskRunner> runner,
const std::vector<SavePageRequest>& requests,
const RequestQueueStore::UpdateCallback& callback) {
- // TODO(fgorski): add UMA metrics here.
std::unique_ptr<UpdateRequestsResult> result(
new UpdateRequestsResult(StoreState::LOADED));
@@ -371,7 +366,6 @@ void RemoveRequestsSync(sql::Connection* db,
scoped_refptr<base::SingleThreadTaskRunner> runner,
const std::vector<int64_t>& request_ids,
const RequestQueueStore::UpdateCallback& callback) {
- // TODO(fgorski): Perhaps add metrics here.
std::unique_ptr<UpdateRequestsResult> result(
new UpdateRequestsResult(StoreState::LOADED));
diff --git a/chromium/components/offline_pages/core/background/request_queue_store_sql.h b/chromium/components/offline_pages/core/background/request_queue_store_sql.h
index 6bd9b9a4ccd..7c694f39db7 100644
--- a/chromium/components/offline_pages/core/background/request_queue_store_sql.h
+++ b/chromium/components/offline_pages/core/background/request_queue_store_sql.h
@@ -24,6 +24,17 @@ class Connection;
namespace offline_pages {
// SQLite implementation of RequestQueueStore.
+//
+// This store has a history of schema updates.
+// Original schema was delivered in M57. Since then the following changes
+// happened:
+// * In M58 original_url was added.
+//
+// TODO(romax): remove all activation_time related code the next we change the
+// schema.
+//
+// Looking for procesure to update the schema, please refer to
+// offline_page_metadata_store_sql.h
class RequestQueueStoreSQL : public RequestQueueStore {
public:
RequestQueueStoreSQL(
diff --git a/chromium/components/offline_pages/core/background/request_queue_store_unittest.cc b/chromium/components/offline_pages/core/background/request_queue_store_unittest.cc
index bf78969fc92..9b0009fde61 100644
--- a/chromium/components/offline_pages/core/background/request_queue_store_unittest.cc
+++ b/chromium/components/offline_pages/core/background/request_queue_store_unittest.cc
@@ -428,16 +428,13 @@ TYPED_TEST(RequestQueueStoreTest, UpdateRequest) {
base::Time new_creation_time =
creation_time + base::TimeDelta::FromMinutes(1);
- base::Time activation_time = creation_time + base::TimeDelta::FromHours(6);
// Try updating an existing request.
SavePageRequest updated_request(kRequestId, kUrl, kClientId,
- new_creation_time, activation_time,
- kUserRequested);
+ new_creation_time, kUserRequested);
updated_request.set_original_url(kUrl2);
// Try to update a non-existing request.
SavePageRequest updated_request2(kRequestId2, kUrl, kClientId,
- new_creation_time, activation_time,
- kUserRequested);
+ new_creation_time, kUserRequested);
std::vector<SavePageRequest> requests_to_update{updated_request,
updated_request2};
store->UpdateRequests(
diff --git a/chromium/components/offline_pages/core/background/request_queue_unittest.cc b/chromium/components/offline_pages/core/background/request_queue_unittest.cc
index ed9054bc6c0..24903504eaf 100644
--- a/chromium/components/offline_pages/core/background/request_queue_unittest.cc
+++ b/chromium/components/offline_pages/core/background/request_queue_unittest.cc
@@ -85,7 +85,6 @@ class RequestNotifierStub : public RequestNotifier {
int32_t total_expired_requests_;
};
-// TODO(fgorski): Add tests for store failures in add/remove/get.
class RequestQueueTest : public testing::Test {
public:
RequestQueueTest();
diff --git a/chromium/components/offline_pages/core/background/save_page_request.cc b/chromium/components/offline_pages/core/background/save_page_request.cc
index 9b19dc4d429..d95df18069e 100644
--- a/chromium/components/offline_pages/core/background/save_page_request.cc
+++ b/chromium/components/offline_pages/core/background/save_page_request.cc
@@ -15,23 +15,6 @@ SavePageRequest::SavePageRequest(int64_t request_id,
url_(url),
client_id_(client_id),
creation_time_(creation_time),
- activation_time_(creation_time),
- started_attempt_count_(0),
- completed_attempt_count_(0),
- user_requested_(user_requested),
- state_(RequestState::AVAILABLE) {}
-
-SavePageRequest::SavePageRequest(int64_t request_id,
- const GURL& url,
- const ClientId& client_id,
- const base::Time& creation_time,
- const base::Time& activation_time,
- const bool user_requested)
- : request_id_(request_id),
- url_(url),
- client_id_(client_id),
- creation_time_(creation_time),
- activation_time_(activation_time),
started_attempt_count_(0),
completed_attempt_count_(0),
user_requested_(user_requested),
@@ -42,7 +25,6 @@ SavePageRequest::SavePageRequest(const SavePageRequest& other)
url_(other.url_),
client_id_(other.client_id_),
creation_time_(other.creation_time_),
- activation_time_(other.activation_time_),
started_attempt_count_(other.started_attempt_count_),
completed_attempt_count_(other.completed_attempt_count_),
last_attempt_time_(other.last_attempt_time_),
@@ -56,7 +38,6 @@ bool SavePageRequest::operator==(const SavePageRequest& other) const {
return request_id_ == other.request_id_ && url_ == other.url_ &&
client_id_ == other.client_id_ &&
creation_time_ == other.creation_time_ &&
- activation_time_ == other.activation_time_ &&
started_attempt_count_ == other.started_attempt_count_ &&
completed_attempt_count_ == other.completed_attempt_count_ &&
last_attempt_time_ == other.last_attempt_time_ &&
@@ -64,10 +45,6 @@ bool SavePageRequest::operator==(const SavePageRequest& other) const {
}
void SavePageRequest::MarkAttemptStarted(const base::Time& start_time) {
- DCHECK_LE(activation_time_, start_time);
- // TODO(fgorski): As part of introducing policy in GetStatus, we can make a
- // check here to ensure we only start tasks in status pending, and bail out in
- // other cases.
last_attempt_time_ = start_time;
++started_attempt_count_;
state_ = RequestState::OFFLINING;
diff --git a/chromium/components/offline_pages/core/background/save_page_request.h b/chromium/components/offline_pages/core/background/save_page_request.h
index b1bd54e806b..52dee9556a1 100644
--- a/chromium/components/offline_pages/core/background/save_page_request.h
+++ b/chromium/components/offline_pages/core/background/save_page_request.h
@@ -28,12 +28,6 @@ class SavePageRequest {
const ClientId& client_id,
const base::Time& creation_time,
const bool user_requested);
- SavePageRequest(int64_t request_id,
- const GURL& url,
- const ClientId& client_id,
- const base::Time& creation_time,
- const base::Time& activation_time,
- const bool user_requested);
SavePageRequest(const SavePageRequest& other);
~SavePageRequest();
@@ -64,8 +58,6 @@ class SavePageRequest {
const base::Time& creation_time() const { return creation_time_; }
- const base::Time& activation_time() const { return activation_time_; }
-
int64_t started_attempt_count() const { return started_attempt_count_; }
void set_started_attempt_count(int64_t started_attempt_count) {
started_attempt_count_ = started_attempt_count;
@@ -106,9 +98,6 @@ class SavePageRequest {
// Time when this request was created. (Alternative 2).
base::Time creation_time_;
- // Time when this request will become active.
- base::Time activation_time_;
-
// Number of attempts started to get the page. This may be different than the
// number of attempts completed because we could crash.
int started_attempt_count_;
diff --git a/chromium/components/offline_pages/core/background/save_page_request_unittest.cc b/chromium/components/offline_pages/core/background/save_page_request_unittest.cc
index ddfc2b990b7..df073bd61e3 100644
--- a/chromium/components/offline_pages/core/background/save_page_request_unittest.cc
+++ b/chromium/components/offline_pages/core/background/save_page_request_unittest.cc
@@ -32,7 +32,6 @@ TEST_F(SavePageRequestTest, CreatePendingReqeust) {
EXPECT_EQ(kUrl, request.url());
EXPECT_EQ(kClientId, request.client_id());
EXPECT_EQ(creation_time, request.creation_time());
- EXPECT_EQ(creation_time, request.activation_time());
EXPECT_EQ(base::Time(), request.last_attempt_time());
EXPECT_EQ(0, request.completed_attempt_count());
EXPECT_EQ(SavePageRequest::RequestState::AVAILABLE, request.request_state());
@@ -43,11 +42,10 @@ TEST_F(SavePageRequestTest, CreatePendingReqeust) {
TEST_F(SavePageRequestTest, StartAndCompleteRequest) {
base::Time creation_time = base::Time::Now();
- base::Time activation_time = creation_time + base::TimeDelta::FromHours(6);
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
- activation_time, kUserRequested);
+ kUserRequested);
- base::Time start_time = activation_time + base::TimeDelta::FromHours(3);
+ base::Time start_time = creation_time + base::TimeDelta::FromHours(3);
request.MarkAttemptStarted(start_time);
// Most things don't change about the request.
@@ -55,7 +53,6 @@ TEST_F(SavePageRequestTest, StartAndCompleteRequest) {
EXPECT_EQ(kUrl, request.url());
EXPECT_EQ(kClientId, request.client_id());
EXPECT_EQ(creation_time, request.creation_time());
- EXPECT_EQ(activation_time, request.activation_time());
// Attempt time, attempt count and status will though.
EXPECT_EQ(start_time, request.last_attempt_time());
@@ -69,7 +66,6 @@ TEST_F(SavePageRequestTest, StartAndCompleteRequest) {
EXPECT_EQ(kUrl, request.url());
EXPECT_EQ(kClientId, request.client_id());
EXPECT_EQ(creation_time, request.creation_time());
- EXPECT_EQ(activation_time, request.activation_time());
// Last attempt time and status are updated.
EXPECT_EQ(1, request.completed_attempt_count());
diff --git a/chromium/components/offline_pages/core/offline_page_archiver.h b/chromium/components/offline_pages/core/offline_page_archiver.h
index 17631406db3..cfada7b4dea 100644
--- a/chromium/components/offline_pages/core/offline_page_archiver.h
+++ b/chromium/components/offline_pages/core/offline_page_archiver.h
@@ -39,12 +39,6 @@ namespace offline_pages {
// archiver whether to respond with ERROR_CONTENT_UNAVAILBLE, wait longer to
// actually snapshot a complete page, or snapshot whatever is available at that
// point in time (what the user sees).
-//
-// TODO(fgorski): Add ability to delete archive.
-// TODO(fgorski): Add ability to check that archive exists.
-// TODO(fgorski): Add ability to refresh an existing archive in one step.
-// TODO(fgorski): Add ability to identify all of the archives in the directory,
-// to enable to model to reconcile the archives.
class OfflinePageArchiver {
public:
// Results of the archive creation.
@@ -56,6 +50,8 @@ class OfflinePageArchiver {
ERROR_ARCHIVE_CREATION_FAILED, // Creation of archive failed.
ERROR_SECURITY_CERTIFICATE, // Page was loaded on secure connection, but
// there was a security error.
+ ERROR_ERROR_PAGE, // We detected an error page.
+ ERROR_INTERSTITIAL_PAGE, // We detected an interstitial page.
};
// Describes the parameters to control how to create an archive.
diff --git a/chromium/components/offline_pages/core/offline_page_feature.cc b/chromium/components/offline_pages/core/offline_page_feature.cc
index 9f283129f19..9dfab58bfca 100644
--- a/chromium/components/offline_pages/core/offline_page_feature.cc
+++ b/chromium/components/offline_pages/core/offline_page_feature.cc
@@ -36,12 +36,18 @@ const base::Feature kOfflinePagesSharingFeature{
const base::Feature kOfflinePagesSvelteConcurrentLoadingFeature{
"OfflinePagesSvelteConcurrentLoading", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kOfflinePagesLoadSignalCollectingFeature{
+ "OfflinePagesLoadSignalCollecting", base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kBackgroundLoaderForDownloadsFeature{
"BackgroundLoadingForDownloads", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kOfflinePagesAsyncDownloadFeature{
"OfflinePagesAsyncDownload", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kPrefetchingOfflinePagesFeature{
+ "OfflinePagesPrefetching", base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kNewBackgroundLoaderFeature {
"BackgroundLoader", base::FEATURE_DISABLED_BY_DEFAULT
};
@@ -75,6 +81,14 @@ bool IsOfflinePagesAsyncDownloadEnabled() {
return base::FeatureList::IsEnabled(kOfflinePagesAsyncDownloadFeature);
}
+bool IsPrefetchingOfflinePagesEnabled() {
+ return base::FeatureList::IsEnabled(kPrefetchingOfflinePagesFeature);
+}
+
+bool IsOfflinePagesLoadSignalCollectingEnabled() {
+ return base::FeatureList::IsEnabled(kOfflinePagesLoadSignalCollectingFeature);
+}
+
bool ShouldUseNewBackgroundLoader() {
return base::FeatureList::IsEnabled(kNewBackgroundLoaderFeature);
}
diff --git a/chromium/components/offline_pages/core/offline_page_feature.h b/chromium/components/offline_pages/core/offline_page_feature.h
index fdd42e6ed8c..11a5b68cf83 100644
--- a/chromium/components/offline_pages/core/offline_page_feature.h
+++ b/chromium/components/offline_pages/core/offline_page_feature.h
@@ -17,7 +17,9 @@ extern const base::Feature kOfflinePagesCTFeature;
extern const base::Feature kOfflinePagesSharingFeature;
extern const base::Feature kBackgroundLoaderForDownloadsFeature;
extern const base::Feature kOfflinePagesAsyncDownloadFeature;
+extern const base::Feature kPrefetchingOfflinePagesFeature;
extern const base::Feature kNewBackgroundLoaderFeature;
+extern const base::Feature kOfflinePagesLoadSignalCollectingFeature;
// Returns true if saving bookmarked pages for offline viewing is enabled.
bool IsOfflineBookmarksEnabled();
@@ -41,6 +43,12 @@ bool IsOfflinePagesSvelteConcurrentLoadingEnabled();
// Returns true if downloading a page asynchonously is enabled.
bool IsOfflinePagesAsyncDownloadEnabled();
+// Returns true if prefetching offline pages is enabled.
+bool IsPrefetchingOfflinePagesEnabled();
+
+// Returns true if we enable load timing signals to be collected.
+bool IsOfflinePagesLoadSignalCollectingEnabled();
+
// Returns true if we should use background loader rather than prerenderer
// to offline pages.
bool ShouldUseNewBackgroundLoader();
diff --git a/chromium/components/offline_pages/core/offline_page_metadata_store_impl_unittest.cc b/chromium/components/offline_pages/core/offline_page_metadata_store_impl_unittest.cc
index 36abbcc98f9..7dcb7898685 100644
--- a/chromium/components/offline_pages/core/offline_page_metadata_store_impl_unittest.cc
+++ b/chromium/components/offline_pages/core/offline_page_metadata_store_impl_unittest.cc
@@ -39,7 +39,6 @@ int64_t kFileSize = 234567LL;
int64_t kOfflineId = 12345LL;
// Build a store with outdated schema to simulate the upgrading process.
-// TODO(romax): move it to sql_unittests.
void BuildTestStoreWithSchemaFromM52(const base::FilePath& file) {
sql::Connection connection;
ASSERT_TRUE(
@@ -392,8 +391,6 @@ void OfflinePageMetadataStoreTest::GetOfflinePagesCallback(
void OfflinePageMetadataStoreTest::AddCallback(ItemActionStatus status) {
last_called_callback_ = ADD;
- // TODO(fgorski): Add specific add status.
- // last_item_status_ = status;
last_status_ =
status == ItemActionStatus::SUCCESS ? STATUS_TRUE : STATUS_FALSE;
}
@@ -636,7 +633,6 @@ TEST_F(OfflinePageMetadataStoreTest, GetOfflinePagesFromInvalidStore) {
// Loads a store which has an outdated schema.
// This test case would crash if it's not handling correctly when we're loading
// old version stores.
-// TODO(romax): Move this to sql_unittest.
TEST_F(OfflinePageMetadataStoreTest, LoadVersion52Store) {
std::unique_ptr<OfflinePageMetadataStore> store(
BuildStoreWithSchemaFromM52());
@@ -648,7 +644,6 @@ TEST_F(OfflinePageMetadataStoreTest, LoadVersion52Store) {
// Loads a store which has an outdated schema.
// This test case would crash if it's not handling correctly when we're loading
// old version stores.
-// TODO(romax): Move this to sql_unittest.
TEST_F(OfflinePageMetadataStoreTest, LoadVersion53Store) {
std::unique_ptr<OfflinePageMetadataStore> store(
BuildStoreWithSchemaFromM53());
@@ -660,7 +655,6 @@ TEST_F(OfflinePageMetadataStoreTest, LoadVersion53Store) {
// Loads a string with schema from M54.
// This test case would crash if it's not handling correctly when we're loading
// old version stores.
-// TODO(romax): Move this to sql_unittest.
TEST_F(OfflinePageMetadataStoreTest, LoadVersion54Store) {
std::unique_ptr<OfflinePageMetadataStore> store(
BuildStoreWithSchemaFromM54());
@@ -672,7 +666,6 @@ TEST_F(OfflinePageMetadataStoreTest, LoadVersion54Store) {
// Loads a string with schema from M55.
// This test case would crash if it's not handling correctly when we're loading
// old version stores.
-// TODO(romax): Move this to sql_unittest.
TEST_F(OfflinePageMetadataStoreTest, LoadVersion55Store) {
std::unique_ptr<OfflinePageMetadataStore> store(
BuildStoreWithSchemaFromM55());
@@ -684,7 +677,6 @@ TEST_F(OfflinePageMetadataStoreTest, LoadVersion55Store) {
// Loads a string with schema from M56.
// This test case would crash if it's not handling correctly when we're loading
// old version stores.
-// TODO(romax): Move this to sql_unittest.
TEST_F(OfflinePageMetadataStoreTest, LoadVersion56Store) {
std::unique_ptr<OfflinePageMetadataStore> store(
BuildStoreWithSchemaFromM56());
diff --git a/chromium/components/offline_pages/core/offline_page_metadata_store_sql.cc b/chromium/components/offline_pages/core/offline_page_metadata_store_sql.cc
index c8e3ee0e953..a4a8ea080b2 100644
--- a/chromium/components/offline_pages/core/offline_page_metadata_store_sql.cc
+++ b/chromium/components/offline_pages/core/offline_page_metadata_store_sql.cc
@@ -158,7 +158,7 @@ bool CreateSchema(sql::Connection* db) {
return false;
}
- // TODO(fgorski): Add indices here.
+ // This would be a great place to add indices when we need them.
return transaction.Commit();
}
@@ -292,7 +292,6 @@ void NotifyLoadResult(scoped_refptr<base::SingleThreadTaskRunner> runner,
const OfflinePageMetadataStore::LoadCallback& callback,
OfflinePageMetadataStore::LoadStatus status,
const std::vector<OfflinePageItem>& result) {
- // TODO(fgorski): Switch to SQL specific UMA metrics.
UMA_HISTOGRAM_ENUMERATION("OfflinePages.LoadStatus", status,
OfflinePageMetadataStore::LOAD_STATUS_COUNT);
if (status == OfflinePageMetadataStore::LOAD_SUCCEEDED) {
@@ -427,7 +426,6 @@ void RemoveOfflinePagesSync(
sql::Connection* db,
scoped_refptr<base::SingleThreadTaskRunner> runner,
const OfflinePageMetadataStore::UpdateCallback& callback) {
- // TODO(fgorski): Perhaps add metrics here.
std::unique_ptr<OfflinePagesUpdateResult> result(
new OfflinePagesUpdateResult(StoreState::LOADED));
diff --git a/chromium/components/offline_pages/core/offline_page_model_impl.cc b/chromium/components/offline_pages/core/offline_page_model_impl.cc
index 2e87035d1f6..596892d6171 100644
--- a/chromium/components/offline_pages/core/offline_page_model_impl.cc
+++ b/chromium/components/offline_pages/core/offline_page_model_impl.cc
@@ -72,6 +72,11 @@ SavePageResult ToSavePageResult(ArchiverResult archiver_result) {
case ArchiverResult::ERROR_SECURITY_CERTIFICATE:
result = SavePageResult::SECURITY_CERTIFICATE_ERROR;
break;
+ case ArchiverResult::ERROR_ERROR_PAGE:
+ result = SavePageResult::ERROR_PAGE;
+ break;
+ case ArchiverResult::ERROR_INTERSTITIAL_PAGE:
+ result = SavePageResult::INTERSTITIAL_PAGE;
default:
NOTREACHED();
result = SavePageResult::CONTENT_UNAVAILABLE;
@@ -572,7 +577,6 @@ const std::vector<int64_t> OfflinePageModelImpl::MaybeGetOfflineIdsForClientId(
std::vector<int64_t> results;
// We want only all pages, including those marked for deletion.
- // TODO(fgorski): actually use an index rather than linear scan.
for (const auto& id_page_pair : offline_pages_) {
if (id_page_pair.second.client_id == client_id)
results.push_back(id_page_pair.second.offline_id);
@@ -684,20 +688,10 @@ void OfflinePageModelImpl::OnCreateArchiveDone(
const SavePageCallback& callback,
OfflinePageArchiver* archiver,
ArchiverResult archiver_result,
- const GURL& url,
+ const GURL& saved_url,
const base::FilePath& file_path,
const base::string16& title,
int64_t file_size) {
- if (save_page_params.url != url) {
- DVLOG(1) << "Saved URL does not match requested URL.";
- // TODO(fgorski): We have created an archive for a wrong URL. It should be
- // deleted from here, once archiver has the right functionality.
- InformSavePageDone(callback, SavePageResult::ARCHIVE_CREATION_FAILED,
- save_page_params.client_id, offline_id);
- DeletePendingArchiver(archiver);
- return;
- }
-
if (archiver_result != ArchiverResult::SUCCESSFULLY_CREATED) {
SavePageResult result = ToSavePageResult(archiver_result);
InformSavePageDone(
@@ -705,8 +699,18 @@ void OfflinePageModelImpl::OnCreateArchiveDone(
DeletePendingArchiver(archiver);
return;
}
- OfflinePageItem offline_page_item(url, offline_id, save_page_params.client_id,
- file_path, file_size, start_time);
+
+ if (save_page_params.url != saved_url) {
+ DVLOG(1) << "Saved URL does not match requested URL.";
+ InformSavePageDone(callback, SavePageResult::ARCHIVE_CREATION_FAILED,
+ save_page_params.client_id, offline_id);
+ DeletePendingArchiver(archiver);
+ return;
+ }
+
+ OfflinePageItem offline_page_item(saved_url, offline_id,
+ save_page_params.client_id, file_path,
+ file_size, start_time);
offline_page_item.title = title;
offline_page_item.original_url = save_page_params.original_url;
store_->AddOfflinePage(offline_page_item,
@@ -907,7 +911,6 @@ void OfflinePageModelImpl::OnPagesFoundWithSameURL(
void OfflinePageModelImpl::OnDeleteOldPagesWithSameURL(
DeletePageResult result) {
- // TODO(romax) Add UMAs for failure cases.
PostClearStorageIfNeededTask(false /* delayed */);
}
@@ -956,10 +959,6 @@ void OfflinePageModelImpl::OnRemoveOfflinePagesDone(
observer.OfflinePageDeleted(page.offline_id, page.client_id);
}
- // TODO(fgorski): React the FAILED_INITIALIZATION, FAILED_RESET here.
- // TODO(fgorski): We need a better callback interface for the Remove action on
- // the this class. Currently removing an item that does not exist is
- // considered a success, but not called out as such to the caller.
DeletePageResult delete_result;
if (result->store_state == StoreState::LOADED)
delete_result = DeletePageResult::SUCCESS;
diff --git a/chromium/components/offline_pages/core/offline_page_model_impl.h b/chromium/components/offline_pages/core/offline_page_model_impl.h
index 5221644d7f3..64e2e3cfdfd 100644
--- a/chromium/components/offline_pages/core/offline_page_model_impl.h
+++ b/chromium/components/offline_pages/core/offline_page_model_impl.h
@@ -163,7 +163,7 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
const SavePageCallback& callback,
OfflinePageArchiver* archiver,
OfflinePageArchiver::ArchiverResult result,
- const GURL& url,
+ const GURL& saved_url,
const base::FilePath& file_path,
const base::string16& title,
int64_t file_size);
diff --git a/chromium/components/offline_pages/core/offline_page_model_impl_unittest.cc b/chromium/components/offline_pages/core/offline_page_model_impl_unittest.cc
index b5806b222b7..8d20e475263 100644
--- a/chromium/components/offline_pages/core/offline_page_model_impl_unittest.cc
+++ b/chromium/components/offline_pages/core/offline_page_model_impl_unittest.cc
@@ -1347,4 +1347,15 @@ TEST(CommandLineFlagsTest, OfflinePagesSvelteConcurrentLoading) {
EXPECT_TRUE(offline_pages::IsOfflinePagesSvelteConcurrentLoadingEnabled());
}
+TEST(CommandLineFlagsTest, OfflinePagesLoadSignalCollecting) {
+ // This feature is disabled by default.
+ EXPECT_FALSE(offline_pages::IsOfflinePagesLoadSignalCollectingEnabled());
+
+ // Check if feature is correctly enabled by command-line flag.
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ kOfflinePagesLoadSignalCollectingFeature);
+ EXPECT_TRUE(offline_pages::IsOfflinePagesLoadSignalCollectingEnabled());
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/offline_page_storage_manager.cc b/chromium/components/offline_pages/core/offline_page_storage_manager.cc
index efe9ec2f856..1c17729f768 100644
--- a/chromium/components/offline_pages/core/offline_page_storage_manager.cc
+++ b/chromium/components/offline_pages/core/offline_page_storage_manager.cc
@@ -93,7 +93,6 @@ void OfflinePageStorageManager::GetPageIdsToClear(
const MultipleOfflinePageItemResult& pages,
const ArchiveManager::StorageStats& stats,
std::vector<int64_t>* page_ids_to_clear) {
- // TODO(romax): See how persistent should be considered here.
// Creating a map from namespace to a vector of page items.
// Sort each vector based on last accessed time and all pages after index
// min{size(), page_limit} should be deleted.
diff --git a/chromium/components/offline_pages/core/offline_page_test_archiver.h b/chromium/components/offline_pages/core/offline_page_test_archiver.h
index 6d7c04e8753..1ece7c811eb 100644
--- a/chromium/components/offline_pages/core/offline_page_test_archiver.h
+++ b/chromium/components/offline_pages/core/offline_page_test_archiver.h
@@ -26,8 +26,6 @@ namespace offline_pages {
// for an actual web contents.
class OfflinePageTestArchiver : public OfflinePageArchiver {
public:
- // TODO(fgorski): Try refactoring the observer out and replace it with a
- // callback, or completely remove the call to |SetLastPathCreatedByArchiver|.
class Observer {
public:
virtual ~Observer() {}
diff --git a/chromium/components/offline_pages/core/offline_page_test_store.cc b/chromium/components/offline_pages/core/offline_page_test_store.cc
index 556c12a2356..225d777694d 100644
--- a/chromium/components/offline_pages/core/offline_page_test_store.cc
+++ b/chromium/components/offline_pages/core/offline_page_test_store.cc
@@ -44,7 +44,6 @@ void OfflinePageTestStore::GetOfflinePages(const LoadCallback& callback) {
void OfflinePageTestStore::AddOfflinePage(const OfflinePageItem& offline_page,
const AddCallback& callback) {
- // TODO(fgorski): Add and cover scenario with existing item.
ItemActionStatus result;
if (store_state_ == StoreState::LOADED &&
scenario_ != TestScenario::WRITE_FAILED) {
@@ -61,8 +60,6 @@ void OfflinePageTestStore::AddOfflinePage(const OfflinePageItem& offline_page,
void OfflinePageTestStore::UpdateOfflinePages(
const std::vector<OfflinePageItem>& pages,
const UpdateCallback& callback) {
- // TODO(fgorski): Cover scenario where new items are being created while they
- // shouldn't.
std::unique_ptr<OfflinePagesUpdateResult> result(
new OfflinePagesUpdateResult(StoreState::LOADED));
if (scenario_ == TestScenario::WRITE_FAILED) {
diff --git a/chromium/components/offline_pages/core/offline_page_types.h b/chromium/components/offline_pages/core/offline_page_types.h
index ae9e298af8e..4bb3342e1d1 100644
--- a/chromium/components/offline_pages/core/offline_page_types.h
+++ b/chromium/components/offline_pages/core/offline_page_types.h
@@ -34,6 +34,10 @@ enum class SavePageResult {
// are already locally accessible.
SKIPPED,
SECURITY_CERTIFICATE_ERROR,
+ // Returned when we detect trying to save a chrome error page.
+ ERROR_PAGE,
+ // Returned when we detect trying to save a chrome interstitial page.
+ INTERSTITIAL_PAGE,
// 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.
diff --git a/chromium/components/offline_pages/core/offline_store_types.h b/chromium/components/offline_pages/core/offline_store_types.h
index 77d6a6a9bdf..aa95914e8ea 100644
--- a/chromium/components/offline_pages/core/offline_store_types.h
+++ b/chromium/components/offline_pages/core/offline_store_types.h
@@ -14,7 +14,6 @@
// offline page related components.
namespace offline_pages {
-// TODO(fgorski): This enum is meant to replace |LoadStatus|.
// Current store state. When LOADED, the store is operational. When
// loading or reset fails, it is reflected appropriately.
enum class StoreState {
diff --git a/chromium/components/offline_pages/core/snapshot_controller.cc b/chromium/components/offline_pages/core/snapshot_controller.cc
index c683a1a9b10..9d62297fb7b 100644
--- a/chromium/components/offline_pages/core/snapshot_controller.cc
+++ b/chromium/components/offline_pages/core/snapshot_controller.cc
@@ -11,6 +11,8 @@
#include "components/offline_pages/core/offline_page_feature.h"
namespace {
+const bool kDocumentAvailableTriggersSnapshot = true;
+
// Default delay, in milliseconds, between the main document parsed event and
// snapshot. Note: this snapshot might not occur if the OnLoad event and
// OnLoad delay elapses first to trigger a final snapshot.
@@ -18,7 +20,8 @@ const int64_t kDefaultDelayAfterDocumentAvailableMs = 7000;
// Default delay, in milliseconds, between the main document OnLoad event and
// snapshot.
-const int64_t kDelayAfterDocumentOnLoadCompletedMs = 1000;
+const int64_t kDelayAfterDocumentOnLoadCompletedMsForeground = 1000;
+const int64_t kDelayAfterDocumentOnLoadCompletedMsBackground = 2000;
// Delay for testing to keep polling times reasonable.
const int64_t kDelayForTests = 0;
@@ -27,25 +30,42 @@ const int64_t kDelayForTests = 0;
namespace offline_pages {
-SnapshotController::SnapshotController(
+// static
+std::unique_ptr<SnapshotController>
+SnapshotController::CreateForForegroundOfflining(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ SnapshotController::Client* client) {
+ return std::unique_ptr<SnapshotController>(new SnapshotController(
+ task_runner, client, kDefaultDelayAfterDocumentAvailableMs,
+ kDelayAfterDocumentOnLoadCompletedMsForeground,
+ kDocumentAvailableTriggersSnapshot));
+}
+
+// static
+std::unique_ptr<SnapshotController>
+SnapshotController::CreateForBackgroundOfflining(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- SnapshotController::Client* client)
- : SnapshotController(task_runner,
- client,
- kDefaultDelayAfterDocumentAvailableMs,
- kDelayAfterDocumentOnLoadCompletedMs) {}
+ SnapshotController::Client* client) {
+ return std::unique_ptr<SnapshotController>(new SnapshotController(
+ task_runner, client, kDefaultDelayAfterDocumentAvailableMs,
+ kDelayAfterDocumentOnLoadCompletedMsBackground,
+ !kDocumentAvailableTriggersSnapshot));
+}
SnapshotController::SnapshotController(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
SnapshotController::Client* client,
int64_t delay_after_document_available_ms,
- int64_t delay_after_document_on_load_completed_ms)
+ int64_t delay_after_document_on_load_completed_ms,
+ bool document_available_triggers_snapshot)
: task_runner_(task_runner),
client_(client),
state_(State::READY),
delay_after_document_available_ms_(delay_after_document_available_ms),
delay_after_document_on_load_completed_ms_(
delay_after_document_on_load_completed_ms),
+ document_available_triggers_snapshot_(
+ document_available_triggers_snapshot),
weak_ptr_factory_(this) {
if (offline_pages::ShouldUseTestingSnapshotDelay()) {
delay_after_document_available_ms_ = kDelayForTests;
@@ -75,13 +95,16 @@ void SnapshotController::PendingSnapshotCompleted() {
}
void SnapshotController::DocumentAvailableInMainFrame() {
- DCHECK_EQ(PageQuality::POOR, current_page_quality_);
- // Post a delayed task to snapshot.
- task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(&SnapshotController::MaybeStartSnapshot,
- weak_ptr_factory_.GetWeakPtr(),
- PageQuality::FAIR_AND_IMPROVING),
- base::TimeDelta::FromMilliseconds(delay_after_document_available_ms_));
+ if (document_available_triggers_snapshot_) {
+ DCHECK_EQ(PageQuality::POOR, current_page_quality_);
+ // Post a delayed task to snapshot.
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&SnapshotController::MaybeStartSnapshot,
+ weak_ptr_factory_.GetWeakPtr(),
+ PageQuality::FAIR_AND_IMPROVING),
+ base::TimeDelta::FromMilliseconds(delay_after_document_available_ms_));
+ }
}
void SnapshotController::DocumentOnLoadCompletedInMainFrame() {
diff --git a/chromium/components/offline_pages/core/snapshot_controller.h b/chromium/components/offline_pages/core/snapshot_controller.h
index 36e1680a6f0..bcd5ee00b1b 100644
--- a/chromium/components/offline_pages/core/snapshot_controller.h
+++ b/chromium/components/offline_pages/core/snapshot_controller.h
@@ -60,14 +60,23 @@ class SnapshotController {
virtual ~Client() {}
};
- SnapshotController(
+ // Creates a SnapshotController with document available delay = 7s,
+ // document on load delay = 1s and triggers snapshot on document available.
+ static std::unique_ptr<SnapshotController> CreateForForegroundOfflining(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ SnapshotController::Client* client);
+ // Creates a SnapshotController with document on load delay = 2s
+ // and ignores document available signal.
+ static std::unique_ptr<SnapshotController> CreateForBackgroundOfflining(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
SnapshotController::Client* client);
+
SnapshotController(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
SnapshotController::Client* client,
int64_t delay_after_document_available_ms,
- int64_t delay_after_document_on_load_completed_ms);
+ int64_t delay_after_document_on_load_completed_ms,
+ bool document_available_triggers_snapshot);
virtual ~SnapshotController();
// Resets the 'session', returning controller to initial state.
@@ -103,6 +112,7 @@ class SnapshotController {
SnapshotController::State state_;
int64_t delay_after_document_available_ms_;
int64_t delay_after_document_on_load_completed_ms_;
+ bool document_available_triggers_snapshot_;
// The expected quality of a snapshot taken at the moment this value is
// queried.
diff --git a/chromium/components/offline_pages/core/snapshot_controller_unittest.cc b/chromium/components/offline_pages/core/snapshot_controller_unittest.cc
index a57c2da897b..123437b4e48 100644
--- a/chromium/components/offline_pages/core/snapshot_controller_unittest.cc
+++ b/chromium/components/offline_pages/core/snapshot_controller_unittest.cc
@@ -53,7 +53,8 @@ SnapshotControllerTest::SnapshotControllerTest()
SnapshotControllerTest::~SnapshotControllerTest() {}
void SnapshotControllerTest::SetUp() {
- controller_.reset(new SnapshotController(task_runner_, this));
+ controller_ =
+ SnapshotController::CreateForForegroundOfflining(task_runner_, this);
snapshot_started_ = true;
}
diff --git a/chromium/components/omnibox/browser/BUILD.gn b/chromium/components/omnibox/browser/BUILD.gn
index d4bc859b8ff..a6fc236517c 100644
--- a/chromium/components/omnibox/browser/BUILD.gn
+++ b/chromium/components/omnibox/browser/BUILD.gn
@@ -19,7 +19,6 @@ aggregate_vector_icons("omnibox_vector_icons") {
"extension_app.icon",
"http.icon",
"keyword_search.icon",
- "search.icon",
"star.1x.icon",
"star.icon",
]
@@ -53,8 +52,6 @@ static_library("browser") {
"builtin_provider.h",
"clipboard_url_provider.cc",
"clipboard_url_provider.h",
- "features.cc",
- "features.h",
"history_provider.cc",
"history_provider.h",
"history_quick_provider.cc",
@@ -70,6 +67,7 @@ static_library("browser") {
"keyword_provider.cc",
"keyword_provider.h",
"match_compare.h",
+ "omnibox_client.cc",
"omnibox_client.h",
"omnibox_controller.cc",
"omnibox_controller.h",
@@ -169,7 +167,10 @@ static_library("browser") {
if (!is_android && !is_ios) {
sources += get_target_outputs(":omnibox_vector_icons")
- deps += [ ":omnibox_vector_icons" ]
+ deps += [
+ ":omnibox_vector_icons",
+ "//ui/vector_icons",
+ ]
}
# TODO(brettw) Fix the include cycle and remove this line.
@@ -238,8 +239,8 @@ bundle_data("unit_tests_bundle_data") {
sources = [
"//components/test/data/omnibox/Shortcuts.no_fill_into_edit.sql",
"//components/test/data/omnibox/Shortcuts.v0.sql",
- "//components/test/data/omnibox/in_memory_url_index_test.db.txt",
- "//components/test/data/omnibox/in_memory_url_index_test_limited.db.txt",
+ "//components/test/data/omnibox/in_memory_url_index_test.sql",
+ "//components/test/data/omnibox/in_memory_url_index_test_limited.sql",
]
outputs = [
"{{bundle_resources_dir}}/" +
diff --git a/chromium/components/onc/OWNERS b/chromium/components/onc/OWNERS
index 71fd0d206f9..ae9ccd55c9c 100644
--- a/chromium/components/onc/OWNERS
+++ b/chromium/components/onc/OWNERS
@@ -1,5 +1,4 @@
armansito@chromium.org
-cschuet@chromium.org
gauravsh@chromium.org
gspencer@chromium.org
stevenjb@chromium.org
diff --git a/chromium/components/onc/docs/onc_spec.css b/chromium/components/onc/docs/onc_spec.css
deleted file mode 100644
index d4f32b3644e..00000000000
--- a/chromium/components/onc/docs/onc_spec.css
+++ /dev/null
@@ -1,62 +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. */
-
-.value {
- font-family: monospace;
- font-style: italic;
-}
-
-.type {
- color: blue;
- font-family: monospace;
-}
-
-.field {
- font-weight: bold;
- font-family: monospace;
-}
-
-.field_meta {
- text-align: left;
- background: rgb(240,240,240);
- display: block;
-}
-
-.field_list {
- margin-left: 1em;
-}
-
-.rule {
- display: block;
- border-style:solid;
- border-width:2px;
-}
-
-.rule_id {
- background: rgb(220,220,220);
- border-style:none solid solid none;
- border-width:2px;
-}
-
-.rule_id:before {
- content: "Rule ";
-}
-
-.snippet {
- font-family: monospace;
-}
-
-body {
- text-align: justify;
- width:600px;
-}
-
-h1{font-size: 38px}
-section h1{font-size: 32px}
-section section h1{font-size: 28px}
-section section section h1{font-size: 24px}
-section section section section h1{font-size: 20px}
-section section section section section h1{font-size: 18px}
-section section section section section section h1{font-size: 16px}
-section section section section section section section h1{font-size: 14px}
diff --git a/chromium/components/onc/docs/onc_spec.html b/chromium/components/onc/docs/onc_spec.html
deleted file mode 100644
index 3c6daf1591e..00000000000
--- a/chromium/components/onc/docs/onc_spec.html
+++ /dev/null
@@ -1,3180 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <meta charset="utf-8">
- <link rel="stylesheet" href="onc_spec.css" >
- <script src="onc_spec.js"></script>
- <title>Open Network Configuration Format</title>
-</head>
-<body>
-
-<section id="root" class="not_in_toc">
- <h1>Open Network Configuration Format</h1>
-
-<section class="not_in_toc">
- <h1>Outline</h1>
- <div id="outline"></div>
-</section>
-
-<section>
- <h1>Objective</h1>
- <p>
- We would like to create a simple, open, but complete format to describe
- multiple network configurations for WiFi, Ethernet, Cellular,
- Bluetooth/WiFi-Direct, and VPN connections in a single file format, in order
- to simplify and automate network configuration for users.
- </p>
-</section>
-
-<section>
- <h1>Background</h1>
- <p>
- Configuring networks is a painful and error-prone experience for users. It
- is a problem shared across desktop, laptop, tablet, and phone users of all
- operating system types. It is exacerbated in business and schools which
- often have complex network configurations (VPNs and 802.1X networking) that
- change often and have many connected devices. Configuration of WiFi is
- still done manually, often by administrators physically standing next to
- users working on devices. Certificate distribution is particularly painful
- which often results in admins instead using passphrases to protect networks
- or using protocols without client certificates that instead use LDAP
- passwords for authentication. Even after networks are configured, updates to
- the network configuration require another round of manual changes, and
- accidental changes by a user or malicious changes by an attacker can break
- connectivity or make connections less private or secure.
- </p>
-
-<section>
- <h1>Overview</h1>
- <p>
- We propose a single-file format for network configuration that is
- human-readable, can describe all of the common kinds of network
- configurations, supports integrity checking, certificate and key
- provisioning, and updating. The file can be encrypted with a single
- passphrase so that upon entering the passphrase the entire configuration is
- loaded. The format can be described as an open format to enable multiple OS
- vendors to interoperate and share configuration editors.
- </p>
-
- <p>
- This format neither supports configuring browser settings nor allows setting
- other types of system policies.
- </p>
-</section>
-
-<section>
- <h1>Infrastructure</h1>
- <p>
- A standalone configuration editor will be created, downloadable as a Chrome
- app. This editor will allow creating, modifying, and encrypting an open
- network configuration file in a way that is intuitive for a system
- administrator.
- </p>
-
- <p>
- This file format may be delivered to a user and manually imported into a
- device.
- </p>
-
- <p>
- This file format may be created by an administrator, stored in a policy
- repository, and automatically pushed to a device.
- </p>
-</section>
-
-</section>
-
-<section>
- <h1>Detailed Design</h1>
- <p>
- We use JSON format for the files. The fields in a JSON file are always
- case-sensitive, so the exact case of the fields in this section must be
- matched. In addition, the values that are called out as explicit constants
- must also match the case specified (e.g. WiFi must not be written as wifi,
- etc.). This document describes a minimum set of required fields and optional
- fields. Other fields may be created, however, see the
- implementation-specific fields for guidelines for these fields.
- </p>
-
- <p>
- The JSON consists of a top level dictionary containing
- a <span class="field">Type</span> field which must have either the
- value <span class="value">EncryptedConfiguration</span>
- or <span class="value">UnencryptedConfiguration</span>.
- </p>
-
- <p>
- For a description of the <span class="type">EncryptedConfiguration</span>
- type, see the section on Encrypted Configuration
- below. The <span class="type">EncryptedConfiguration</span> format encrypts
- an unencrypted JSON object.
- </p>
-
-<section>
- <h1>GUIDs and Updating</h1>
- <p>
- This format allows for importing updated network configurations and
- certificates by providing GUIDs to each network configuration and
- certificate so they can be modified or even removed in future updates.
- </p>
-
- <p>
- GUIDs are non-empty strings that are meant to be stable and unique. When
- they refer to the same entity, they should be the same between ONC files. No
- two different networks or certificates should have the same GUID, similarly
- a network and certificate should not have the same GUID. A single ONC file
- should not contain the same entity twice (with the same GUID). Failing any
- of these tests indicates the ONC file is not valid.
- </p>
-
- <p>
- Any GUID referred to in an ONC file must be present in the same ONC file. In
- particular, it is an error to create a certificate in one ONC file and refer
- to it in a NetworkConfiguration in another ONC file and not define it there,
- even if the previous ONC file has been imported.
- </p>
-</section>
-
-<section>
- <h1>Implementation-specific fields</h1>
- <p>
- As there are many different kinds of connections and some that are not yet
- anticipated may require new fields. This format allows arbitrary other
- fields to be added.
- </p>
-
- <p>
- Fields and values should follow these general guidelines:
- </p>
-
- <ul>
- <li>
- Certificates (with and without keys) should always be placed in the
- certificate section - specifically certificate contents should not be
- placed in fields directly. Referring to certificates should be done using
- a field whose name ends in Ref and whose value is the GUID of the
- certificate, or if the certificate is not contained in this file, its
- pattern can be described using a field ending in Pattern of
- <span class="type">CertificatePattern</span> type.
- </li>
- <li>
- Fields should exist in the most-specific object in the hierarchy and
- should be named CamelCase style.
- </li>
- <li>
- Booleans and integers should be used directly instead of using a
- stringified version of the type.
- </li>
- </ul>
-
- <p>
- Any editor of network configuration information should allows the user to
- modify any fields that are implementation-specific. It may not be present
- directly in the UI but it should be able to import files with such settings
- and leave preserve these settings on export.
- </p>
-</section>
-
-<section>
- <h1>Unencrypted Configuration</h1>
- <p>
- When the top level <span class="field">Type</span> field
- is <span class="value">UnencryptedConfiguration</span>, the top level JSON
- has the <span class="type">UnencryptedConfiguration</span>
- type. <span class="type">UnencryptedConfiguration</span> type contains the
- following:
- </p>
-
- <dl class="field_list">
- <dt class="field">Type</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">UnencryptedConfiguration
- </span>)
- <span class="type">string</span>
- </span>
- Must be <span class="value">UnencryptedConfiguration</span>.
- </dd>
-
- <dt class="field">NetworkConfigurations</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">array of NetworkConfiguration</span>
- </span>
- Describes WiFi, Ethernet, VPN, and wireless connections.
- </dd>
-
- <dt class="field">Certificates</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">array of Certificate</span>
- </span>
- Contains certificates stored in X.509 or PKCS#12 format.
- </dd>
- </dl>
-
- At least one actual configuration field
- (<span class="field">NetworkConfigurations</span> or
- <span class="field">Certificates</span>) should be present, however it should
- not be considered an error if no such field is present.
-
-<section>
- <h1>Network Configuration</h1>
- <p>
- Field <span class="field">NetworkConfigurations</span> is an array
- of <span class="type">NetworkConfiguration</span> typed
- objects. The <span class="type">NetworkConfiguration</span> type contains
- the following:
- </p>
-
- <dl class="field_list">
- <dt class="field">Ethernet</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Type</span> is
- <span class="value">Ethernet</span>, otherwise ignored)
- <span class="type">Ethernet</span>
- </span>
- Ethernet settings.
- </dd>
-
- <dt class="field">GUID</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- A unique identifier for this network connection, which exists to make it
- possible to update previously imported configurations. Must be a non-empty
- string.
- </dd>
-
- <dt class="field">IPAddressConfigType</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">Remove</span> is
- <span class="value">false</span>, otherwise ignored. Defaults to
- <span class="value">DHCP</span> if
- <span class="field">NameServersConfigType</span> is specified)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">DHCP</span> and
- <span class="value">Static</span>.
- </span>
- Determines whether the IP Address configuration is statically configured,
- see <span class="field">StaticIPConfig</span>, or automatically configured
- using DHCP.
- </dd>
-
- <dt class="field">NameServersConfigType</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">Remove</span> is
- <span class="value">false</span>, otherwise ignored. Defaults to
- <span class="value">DHCP</span> if
- <span class="field">IPAddressConfigType</span> is specified)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">DHCP</span> and
- <span class="value">Static</span>.
- </span>
- Determines whether the NameServers configuration is statically configured,
- see <span class="field">StaticIPConfig</span>, or automatically configured
- using DHCP.
- </dd>
-
- <dt class="field">IPConfigs</dt>
- <dd>
- <span class="field_meta">
- (optional for connected networks, read-only)
- <span class="type">array of IPConfig</span>
- </span>
- Array of IPConfig properties associated with this connection.
- </dd>
-
- <dt class="field">StaticIPConfig</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">IPAddressConfigType</span> or
- <span class="field">NameServersConfigType</span> is set to
- <span class="value">Static</span>)
- <span class="type">IPConfig</span>
- </span>
- Each property set in this IPConfig object overrides the respective
- parameter received over DHCP.
- If <span class="field">IPAddressConfigType</span> is set to
- <span class="value">Static</span>, <span class="field">IPAddress</span>
- and <span class="field">Gateway</span> are required.
- If <span class="field">NameServersConfigType</span> is set to
- <span class="value">Static</span>, <span class="field">NameServers</span>
- is required.
- </dd>
-
- <dt class="field">SavedIPConfig</dt>
- <dd>
- <span class="field_meta">
- (optional for connected networks, read-only)
- <span class="type">IPConfig</span>
- </span>
- IPConfig property containing the configuration that was received from the
- DHCP server prior to applying any StaticIPConfig parameters.
- </dd>
-
- <dt class="field">Name</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Remove</span> is
- <span class="value">false</span>, otherwise ignored)
- <span class="type">string</span>
- </span>
- A user-friendly description of this connection. This name will not be used
- for referencing and may not be unique. Instead it may be used for
- describing the network to the user.
- </dd>
-
- <dt class="field">Remove</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- If set, remove this network configuration (only GUID should be set).
- </dd>
-
- <dt class="field">ProxySettings</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">Remove</span> is
- <span class="value">false</span>, otherwise ignored)
- <span class="type">ProxySettings</span>
- </span>
- Proxy settings for this network
- </dd>
-
- <dt class="field">VPN</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Type</span> is
- <span class="value">VPN</span>, otherwise ignored)
- <span class="type">VPN</span>
- </span>
- VPN settings.
- </dd>
-
- <dt class="field">WiFi</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Type</span> is
- <span class="value">WiFi</span>, otherwise ignored)
- <span class="type">WiFi</span>
- </span>
- WiFi settings.
- </dd>
-
- <dt class="field">WiMAX</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Type</span> is
- <span class="value">WiMAX</span>, otherwise ignored)
- <span class="type">WiMAX</span>
- </span>
- WiMAX settings.
- </dd>
-
- <dt class="field">Cellular</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Type</span> is
- <span class="value">Cellular</span>, otherwise ignored)
- <span class="type">Cellular</span>
- </span>
- Cellular settings.
- </dd>
-
- <dt class="field">Type</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Remove</span> is
- <span class="value">false</span>, otherwise ignored)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">Cellular</span>,
- <span class="value">Ethernet</span>, <span class="value">WiFi</span>,
- <span class="value">WiMAX</span> and <span class="value">VPN</span>.
- </span>
- Indicates which kind of connection this is.
- </dd>
-
- <dt class="field">ConnectionState</dt>
- <dd>
- <span class="field_meta">
- (optional, read-only)
- <span class="type">string</span>
- </span>
- The current connection state for this network, provided by the system.
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are:
- <span class="value">Connected</span>,
- <span class="value">Connecting</span>,
- <span class="value">NotConnected</span>
- </span>
- </dd>
-
- <dt class="field">RestrictedConnectivity</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>, read-only)
- <span class="type">boolean</span>
- </span>
- True if a connnected network has limited connectivity to the Internet,
- e.g. a connection is behind a portal or a cellular network is not
- activated or requires payment.
- </dd>
-
- <dt class="field">Connectable</dt>
- <dd>
- <span class="field_meta">
- (optional, read-only)
- <span class="type">boolean</span>
- </span>
- True if the system indicates that the network can be connected to without
- any additional configuration.
- </dd>
-
- <dt class="field">ErrorState</dt>
- <dd>
- <span class="field_meta">
- (optional, read-only)
- <span class="type">string</span>
- </span>
- The current error state for this network, if any. Error states are
- provided by the system and are not explicitly defined here. They may or
- may not be human-readable. This field will be empty or absent if the
- network is not in an error state.
- </dd>
-
- <dt class="field">MacAddress</dt>
- <dd>
- <span class="field_meta">
- (optional, read-only)
- <span class="type">string</span>
- </span>
- The MAC address for the network. Only applies to connected non-virtual
- networks. The format is 00:11:22:AA:BB:CC.
- </dd>
-
- <dt class="field">Source</dt>
- <dd>
- <span class="field_meta">
- (optional, read-only)
- <span class="type">string</span>
- </span>
- Indicates whether the network is configured and how it is configured:
- <ul>
- <li><span class="value">User</span>: Configured for the active
- user only, i.e. an unshared configuration.</li>
- <li><span class="value">Device</span>: Configured for all users of the
- device (e.g laptop), i.e. a shared configuration.</li>
- <li><span class="value">UserPolicy</span>: Configured by the user
- policy for the active user.</li>
- <li><span class="value">DevicePolicy</span>: Configured by the device
- policy for the device.</li>
- <li><span class="value">None</span>: Not configured, e.g. a visible
- but unconfigured WiFi network.</li>
- </ul>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are:
- <span class="value">User</span>,
- <span class="value">Device</span>,
- <span class="value">UserPolicy</span>,
- <span class="value">DevicePolicy</span>,
- <span class="value">None</span>
- </span>
- </dd>
-
- <dt class="field">Priority</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">integer</span>
- </span>
- Provides a suggested priority value for this network. May be used by the
- system to determine which network to connect to when multiple configured
- networks are available (or may be ignored).
- </dd>
-
- </dl>
-
-<section>
- <h1>Ethernet networks</h1>
- <p>
- For Ethernet connections, <span class="field">Type</span> must be set to
- <span class="value">Ethernet</span> and the
- field <span class="field">Ethernet</span> must be set to an object of
- type <span class="type">Ethernet</span> containing the following fields:
- </p>
-
- <dl class="field_list">
- <dt class="field">Authentication</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">None</span> and
- <span class="value">8021X</span>.
- </span>
- </dd>
-
- <dt class="field">EAP</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Authentication</span> is
- <span class="value">8021X</span>, otherwise ignored)
- <span class="type">EAP</span>
- </span>
- EAP settings.
- </dd>
- </dl>
-</section>
-
-<section>
- <h1>IPConfig</h1>
- <p>
- Objects of type <span class="type">IPConfig</span> are used to report the
- actual IP configuration of a connected network (see
- <span class="field">IPConfigs</span>), the IP configuration received from
- DHCP (see <span class="field">SavedIPConfig</span>) and to configure a
- static IP configuration (see <span class="field">StaticIPConfig</span>).
- </p>
-
- <dl class="field_list">
- <dt class="field">Type</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">IPv4</span>
- and <span class="value">IPv6</span>
- </span>
- Describes the type of configuration this is.
- </dd>
-
- <dt class="field">IPAddress</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- Describes the IPv4 or IPv6 address of a connection, depending on the value
- of <span class="field">Type</span> field. It should not contain the
- routing prefix (i.e. should not end in something like /64).
- </dd>
-
- <dt class="field">RoutingPrefix</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">IPAddress</span> is set. Otherwise
- ignored.)
- <span class="type">integer</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Must be a number in the range [1, 32] for IPv4 and [1, 128] for IPv6
- addresses.
- </span>
- Describes the routing prefix.
- </dd>
-
- <dt class="field">Gateway</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">IPAddress</span> is set. Otherwise
- ignored.)
- <span class="type">string</span>
- </span>
- Describes the gateway address to use for the configuration. Must match
- address type specified in <span class="field">Type</span> field. If not
- specified, DHCP values will be used.
- </dd>
-
- <dt class="field">NameServers</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">array of string</span>
- </span>
- Array of addresses to use for name servers. Address format must match that
- specified in the <span class="field">Type</span> field. If not specified,
- DHCP values will be used.
- </dd>
-
- <dt class="field">SearchDomains</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">array of string</span>
- </span>
- Array of strings to append to names for resolution. Items in this array
- should not start with a dot. Example: <span class="snippet">[
- "corp.acme.org", "acme.org" ]</span>. If not specified, DHCP values will
- be used.
- </dd>
-
- <dt class="field">WebProxyAutoDiscoveryUrl</dt>
- <dd>
- <span class="field_meta">
- (optional if part of <span class="field">IPConfigs</span>, read-only)
- <span class="type">string</span>
- </span>
- The Web Proxy Auto-Discovery URL for this network as reported over DHCP.
- </dd>
-
- </dl>
-</section>
-
-<section>
- <h1>WiFi networks</h1>
- <p>
- For WiFi connections, <span class="field">Type</span> must be set to
- <span class="value">WiFi</span> and the
- field <span class="field">WiFi</span> must be set to an object of
- type <span class="type">WiFi</span> containing the following fields:
- </p>
-
- <dl class="field_list">
- <dt class="field">AllowGatewayARPPolling</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">true</span>)
- <span class="type">boolean</span>
- </span>
- Indicaties if ARP polling of default gateway is allowed.
- When it is allowed, periodic ARP messages will be sent to
- the default gateway. This is used for monitoring the status
- of the current connection.
- </dd>
-
- <dt class="field">AutoConnect</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- Indicating that the network should be connected to automatically when in
- range.
- </dd>
-
- <dt class="field">EAP</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Security</span> is
- <span class="value">WEP-8021X</span> or
- <span class="value">WPA-EAP</span>, otherwise ignored)
- <span class="type">EAP</span>
- </span>
- EAP settings.
- </dd>
-
- <dt class="field">HexSSID</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">SSID</span> is set, if so defaults to
- a hex representation of <span class="field">SSID</span>)
- <span class="type">string</span>
- </span>
- Hex representation of the network's SSID.
- </dd>
-
- <dt class="field">HiddenSSID</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- Indicating if the SSID will be broadcast.
- </dd>
-
- <dt class="field">Passphrase</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Security</span> is
- <span class="value">WEP-PSK</span> or
- <span class="value">WPA-PSK</span>, otherwise ignored)
- <span class="type">string</span>
- </span>
- Describes the passphrase for WEP/WPA/WPA2
- connections. If <span class="value">WEP-PSK</span> is used, the passphrase
- must be of the format 0x&lt;hex-number&gt;, where &lt;hex-number&gt; is
- 40, 104, 128, or 232 bits.
- </dd>
-
- <dt class="field">RoamThreshold</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">integer</span>
- </span>
- The roam threshold for this network, which is the signal-to-noise value
- (in dB) below which we will attempt to roam to a new network. If this
- value is not set, the default value will be used.
- </dd>
-
- <dt class="field">Security</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">None</span>,
- <span class="value">WEP-PSK</span>,
- <span class="value">WEP-8021X</span>,
- <span class="value">WPA-PSK</span>, and
- <span class="value">WPA-EAP</span>.
- </span>
- </dd>
-
- <dt class="field">SSID</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">HexSSID</span> is set, otherwise
- ignored)
- <span class="type">string</span>
- </span>
- Property to access the decoded SSID of a network.<br/>
- If this field is set, but <span class="field">HexSSID</span> is not,
- its value will be UTF-8 encoded and the hex representation will be
- assigned to <span class="field">HexSSID</span>. To configure a non-UTF-8
- SSID, field <span class="field">HexSSID</span> must be used.<br/>
- When reading the configuration of a network, both this field and
- <span class="field">HexSSID</span> might be set. Then this field is the
- decoding of <span class="field">HexSSID</span>. If possible the HexSSID is
- decoded using UTF-8, otherwise an encoding is guessed on a best effort
- basis.
- </dd>
-
- <dt class="field">SignalStrength</dt>
- <dd>
- <span class="field_meta">
- (optional, read-only)
- <span class="type">integer</span>
- </span>
- The current signal strength for this network in the range [0, 100],
- provided by the system. If the network is not in range this field will
- be set to '0' or not present.
- </dd>
- </dl>
- <span class="rule">
- <span class="rule_id"></span>
- At least one of the fields <span class="field">HexSSID</span> or
- <span class="field">SSID</span> must be present. If both
- <span class="field">HexSSID</span> and <span class="field">SSID</span>
- are set, the values must be consistent.
- </span>
- </span>
-</section>
-
-<section>
- <h1>VPN networks</h1>
- <p>
- There are many kinds of VPNs with widely varying configuration options. We
- offer standard configuration options for a few common configurations at this
- time, and may add more later. For all others, implementation specific fields
- should be used.
- </p>
-
- <p>
- For VPN connections, <span class="field">Type</span> must be set
- to <span class="value">VPN</span> and the
- field <span class="field">VPN</span> must be set to an object of
- type <span class="type">VPN</span> containing the following fields:
- </p>
-
- <dl class="field_list">
- <dt class="field">AutoConnect</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- Indicating that the network should be connected to automatically.
- </dd>
-
- <dt class="field">Host</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- Host name or IP address of server to connect to. The only scenario that
- does not require a host is a VPN that encrypts but does not tunnel
- traffic. Standalone IPsec (v1 or v2, cert or PSK based -- this is not the
- same as L2TP over IPsec) is one such setup. For all other types of VPN,
- the <span class="field">Host</span> field is required.
- </dd>
-
- <dt class="field">IPsec</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Type</span> is
- <span class="value">IPsec</span> or
- <span class="value">L2TP-IPsec</span>, otherwise ignored)
- <span class="type">IPsec</span>
- </span>
- IPsec layer settings.
- </dd>
-
- <dt class="field">L2TP</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Type</span> is
- <span class="value">L2TP-IPsec</span>, otherwise ignored)
- <span class="type">L2TP</span>
- </span>
- L2TP layer settings.
- </dd>
-
- <dt class="field">OpenVPN</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Type</span> is
- <span class="value">OpenVPN</span>, otherwise ignored)
- <span class="type">OpenVPN</span>
- </span>
- OpenVPN settings.
- </dd>
-
- <dt class="field">ThirdPartyVPN</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Type</span> is
- <span class="value">ThirdPartyVPN</span>, otherwise ignored)
- <span class="type">ThirdPartyVPN</span>
- </span>
- Third-party VPN provider settings.
- </dd>
-
- <dt class="field">Type</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">IPsec</span>,
- <span class="value">L2TP-IPsec</span>,
- <span class="value">OpenVPN</span>, and
- <span class="value">ThirdPartyVPN</span>.
- </span>
- Type of the VPN.
- </dd>
- </dl>
-
- <section>
- <h1>IPsec-based VPN types</h1>
- <p>
- The <span class="type">IPsec</span> type contains the following:
- </p>
-
- <dl class="field_list">
- <dt class="field">AuthenticationType</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">PSK</span> and
- <span class="value">Cert</span>. If <span class="value">Cert</span> is used, <span class="field">ClientCertType</span> and <span class="field">ServerCARefs</span> (or the deprecated <span class="field">ServerCARef</span>) must be set.
- </span>
- </dd>
-
- <dt class="field">ClientCertPattern</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">ClientCertType</span>
- is <span class="value">Pattern</span>, otherwise ignored)
- <span class="type">CertificatePattern</span>
- </span>
- Pattern describing the client certificate.
- </dd>
-
- <dt class="field">ClientCertRef</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">ClientCertType</span>
- is <span class="value">Ref</span>, otherwise ignored)
- <span class="type">string</span>
- </span>
- Reference to client certificate stored in certificate section.
- </dd>
-
- <dt class="field">ClientCertType</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">AuthenticationType</span>
- is <span class="value">Cert</span>, otherwise ignored)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">Ref</span> and
- <span class="value">Pattern</span>
- </span>
- </dd>
-
- <dt class="field">EAP</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">IKEVersion</span> is 2, otherwise
- ignored)
- <span class="type">EAP</span>
- </span>
- Indicating that EAP authentication should be used with the provided
- parameters.
- </dd>
-
- <dt class="field">Group</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">IKEVersion</span> is 1, otherwise
- ignored)
- <span class="type">string</span>
- </span>
- Group name used for machine authentication.
- </dd>
-
- <dt class="field">IKEVersion</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">integer</span>
- </span>
- Version of IKE protocol to use.
- </dd>
-
- <dt class="field">PSK</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">AuthenticationType</span>
- is <span class="value">PSK</span>, otherwise ignored)
- <span class="type">string</span>
- </span>
- Pre-Shared Key. If not specified, user is prompted at time of
- connection.
- </dd>
-
- <dt class="field">SaveCredentials</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">AuthenticationType</span>
- is <span class="value">PSK</span>, otherwise ignored, defaults
- to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- If <span class="value">false</span>, require user to enter credentials
- (PSK) each time they connect.
- </dd>
-
- <dt class="field">ServerCARefs</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">AuthenticationType</span>
- is <span class="value">Cert</span>, otherwise rejected)
- <span class="type">array of string</span>
- </span>
- Non-empty list of references to CA certificates in <span class="field">Certificates</span> to be used for verifying the host's certificate chain. At least one of the CA certificates must match. If this field is set, <span class="field">ServerCARef</span> must be unset.
- </dd>
-
- <dt class="field">ServerCARef</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">AuthenticationType</span>
- is <span class="value">Cert</span>, otherwise rejected)
- <span class="type">string</span>
- </span>
- DEPRECATED, use <span class="field">ServerCARefs</span> instead.<br/>
- Reference to a CA certificate in <span class="field">Certificates</span>. Certificate authority to use for verifying connection. If this field is set, <span class="field">ServerCARefs</span> must be unset.
- </dd>
-
- <dt class="field">XAUTH</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">IKEVersion</span> is 1, otherwise
- ignored)
- <span class="type">XAUTH</span>
- </span>
- Describing XAUTH credentials. XAUTH is not used if this object is not
- present.
- </dd>
- </dl>
-
- <p class="rule">
- <span class="rule_id"></span>
- If <span class="field">AuthenticationType</span> is set to <span class="value">Cert</span>, <span class="field">ServerCARefs</span> or <span class="field">ServerCARef</span> must be set.
- </p>
-
- <p class="rule">
- <span class="rule_id"></span>
- At most one of <span class="field">ServerCARefs</span> and <span class="field">ServerCARef</span> can be set.
- </p>
-
- <p>
- <span class="type">L2TP</span> type contains the following:
- </p>
-
- <dl class="field_list">
- <dt class="field">LcpEchoDisabled</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- Disable L2TP connection monitoring via PPP LCP frames. This
- allows the VPN client to work around server implementations
- that do not support the LCP echo feature.
- </dd>
-
- <dt class="field">Password</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- User authentication password. If not specified, user is prompted at time
- of connection.
- </dd>
-
- <dt class="field">SaveCredentials</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- If <span class="value">false</span>, require user to enter credentials
- each time they connect.
- </dd>
-
- <dt class="field">Username</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- User identity. This value is subject to string expansions. If not
- specified, user is prompted at time of connection.
- </dd>
- </dl>
-
- <p>
- <span class="type">XAUTH</span> type contains the following:
- </p>
-
- <dl class="field_list">
- <dt class="field">Password</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- XAUTH password. If not specified, user is prompted at time of
- connection.
- </dd>
-
- <dt class="field">SaveCredentials</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- If <span class="value">false</span>, require user to enter credentials
- each time they connect.
- </dd>
-
- <dt class="field">Username</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- XAUTH user name. This value is subject to string expansions. If not
- specified, user is prompted at time of connection.
- </dd>
- </dl>
-
-<section>
- <h1>IPsec IKE v1 VPN connections</h1>
- <p>
- <span class="field">VPN.Type</span> must
- be <span class="value">IPsec</span>, <span class="field">IKEVersion</span>
- must be 1. Do not use this for L2TP over IPsec. This may be used for
- machine-authentication-only IKEv1 or for IKEv1 with XAUTH. See
- the <span class="type">IPsec</span> type described below.
- </p>
-</section>
-
-<section>
- <h1>IPsec IKE v2 VPN connections</h1>
- <p>
- <span class="field">VPN.Type</span> must
- be <span class="value">IPsec</span>, <span class="field">IKEVersion</span>
- must be 2. This may be used with EAP-based user authentication.
- </p>
-</section>
-
-<section>
- <h1>L2TP over IPsec VPN connections</h1>
- <p>
- There are two major configurations L2TP over IPsec which depend on how IPsec
- is authenticated. In either case <span class="field">Type</span> must be
- <span class="value">L2TP-IPsec</span>. They are described below.
- </p>
-
- <p>
- L2TP over IPsec with pre-shared key:
- </p>
-
- <ul>
- <li>The field <span class="field">IPsec</span> must be present and have the
- following settings:
- <ul>
- <li><span class="field">IKEVersion</span> must be 1.</li>
- <li><span class="field">AuthenticationType</span> must be PSK.</li>
- <li><span class="field">XAUTH</span> must not be set.</li>
- </ul>
- </li>
- <li>The field <span class="field">L2TP</span> must be present.</li>
- </ul>
-</section>
-
-</section>
-
-<section>
- <h1>OpenVPN connections and types</h1>
- <p>
- <span class="field">VPN.Type</span> must be
- <span class="value">OpenVPN</span>.
- </p>
-
- <p>
- <span class="type">OpenVPN</span> type contains the following:
- </p>
-
- <dl class="field_list">
- <dt class="field">Auth</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">SHA1</span>)
- <span class="type">string</span>
- </span>
- </dd>
-
- <dt class="field">AuthRetry</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">none</span>)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">none</span>,
- <span class="value">nointeract</span>, and
- <span class="value">interact</span>.
- </span>
- Controls how OpenVPN responds to username/password verification
- errors:<br> Either fail with error on retry
- (<span class="value">none</span>), retry without asking for authentication
- (<span class="value">nointeract</span>), or ask again for authentication
- each time (<span class="value">interact</span>).
- </dd>
-
- <dt class="field">AuthNoCache</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- Disable caching of credentials in memory.
- </dd>
-
- <dt class="field">Cipher</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">BF-CBC</span>)
- <span class="type">string</span>
- </span>
- Cipher to use.
- </dd>
-
- <dt class="field">ClientCertRef</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">ClientCertType</span> is
- <span class="value">Ref</span>, otherwise ignored)
- <span class="type">string</span>
- </span>
- Reference to client certificate stored in certificate section.
- </dd>
-
- <dt class="field">ClientCertPattern</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">ClientCertType</span> is
- <span class="value">Pattern</span>, otherwise ignored)
- <span class="type">CertificatePattern</span>
- </span>
- Pattern to use to find the client certificate.
- </dd>
-
- <dt class="field">ClientCertType</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">Ref</span>,
- <span class="value">Pattern</span>, and <span class="value">None</span>.
- </span>
- <span class="value">None</span> implies that the server is configured to
- not require client certificates.
- </dd>
-
- <dt class="field">CompLZO</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">adaptive</span>)
- <span class="type">string</span>
- </span>
- Decides to fast LZO compression with <span class="value">true</span>
- and <span class="value">false</span> as other values.
- </dd>
-
- <dt class="field">CompNoAdapt</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- Disables adaptive compression.
- </dd>
-
- <dt class="field">IgnoreDefaultRoute</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">bool</span>
- </span>
- Omits a default route to the VPN gateway while the connection is active.
- By default, the client creates a default route to the gateway address
- advertised by the VPN server. Setting this value to
- <span class="value">true</span> will allow split tunnelling for
- configurations where the VPN server omits explicit default routes.
- This is roughly equivalent to omitting "redirect-gateway" OpenVPN client
- configuration option. If the server pushes a "redirect-gateway"
- configuration flag to the client, this option is ignored.
- </dd>
-
- <dt class="field">KeyDirection</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- Passed as --key-direction.
- </dd>
-
- <dt class="field">NsCertType</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- If set, checks peer certificate type. Should only be set
- to <span class="value">server</span> if set.
- </dd>
-
- <dt class="field">OTP</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">UserAuthenticationType</span> is
- <span class="value">OTP</span>,
- <span class="value">PasswordAndOTP</span> or unset, otherwise ignored,
- defaults to empty string)
- <span class="type">string</span>
- </span>
- If <span class="field">UserAuthenticationType</span> is
- <span class="value">OTP</span> or <span class="value">PasswordAndOTP</span>
- and this field is not set, the user will be asked for an OTP.
- The OTP is never persisted and must be provided on every connection
- attempt.
- </dd>
-
- <dt class="field">Password</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">UserAuthenticationType</span> is
- <span class="value">Password</span>,
- <span class="value">PasswordAndOTP</span> or unset, otherwise ignored,
- defaults to empty string)
- <span class="type">string</span>
- </span>
- If <span class="field">UserAuthenticationType</span> is
- <span class="value">Password</span> or
- <span class="value">PasswordAndOTP</span> and this field is not set, the user
- will be asked for a password.
- If <span class="field">SaveCredentials</span> is
- <span class="value">true</span>, the password is persisted for future
- connection attempts. Otherwise it is not persisted but might still be
- reused for consecutive connection attempts (opposed to an OTP, which will
- never be reused).
- </dd>
-
- <dt class="field">Port</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">1194</span>)
- <span class="type">integer</span>
- </span>
- Port for connecting to server.
- </dd>
-
- <dt class="field">Proto</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">udp</span>)
- <span class="type">string</span>
- </span>
- Protocol for communicating with server.
- </dd>
-
- <dt class="field">PushPeerInfo</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- </dd>
-
- <dt class="field">RemoteCertEKU</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- Require that the peer certificate was signed with this explicit extended
- key usage in oid notation.
- </dd>
-
- <dt class="field">RemoteCertKU</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to [])
- <span class="type">array of string</span>
- </span>
- Require the given array of key usage numbers. These are strings that are
- hex encoded numbers.
- </dd>
-
- <dt class="field">RemoteCertTLS</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">server</span>)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">none</span> and
- <span class="value">server</span>.
- </span>
- Require peer certificate signing based on RFC3280 TLS rules.
- </dd>
-
- <dt class="field">RenegSec</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">3600</span>)
- <span class="type">integer</span>
- </span>
- Renegotiate data channel key after this number of seconds.
- </dd>
-
- <dt class="field">SaveCredentials</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- If <span class="value">false</span>, require user to enter credentials
- each time they connect.
- </dd>
-
- <dt class="field">ServerCARefs</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">array of string</span>
- </span>
- Non-empty list of references to CA certificates in <span class="field">Certificates</span> to be used for verifying the host's certificate chain. At least one of the CA certificates must match. See also OpenVPN's command line option "--ca". If this field is set, <span class="field">ServerCARef</span> must be unset.
- </dd>
-
- <dt class="field">ServerCARef</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- DEPRECATED, use <span class="field">ServerCARefs</span> instead.<br/>
- Reference to a CA certificate in <span class="field">Certificates</span>. Certificate authority to use for verifying connection. If this field is set, <span class="field">ServerCARefs</span> must be unset.
- </dd>
-
- <dt class="field">ServerCertRef</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- Reference to a certificate. Peer's signed certificate.
- </dd>
-
- <dt class="field">ServerPollTimeout</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">integer</span>
- </span>
- Spend no more than this number of seconds before trying the next server.
- </dd>
-
- <dt class="field">Shaper</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">integer</span>
- </span>
- If not specified no bandwidth limiting, otherwise limit bandwidth of
- outgoing tunnel data to this number of bytes per second.
- </dd>
-
- <dt class="field">StaticChallenge</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- String is used in static challenge response. Note that echoing is always
- done.
- </dd>
-
- <dt class="field">TLSAuthContents</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- If not set, tls auth is not used. If set, this is the TLS Auth key
- contents (usually starts with "-----BEGIN OpenVPN Static Key..."
- </dd>
-
- <dt class="field">TLSRemote</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- If set, only allow connections to server hosts with X509 name or common
- name equal to this string.
- </dd>
-
- <dt class="field">UserAuthenticationType</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">None</span>)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">None</span>,
- <span class="value">Password</span>,
- <span class="value">PasswordAndOTP</span> and
- <span class="value">OTP</span>.
- </span>
- Determines the required form of user authentication:
- <ul><li>
- <span class="value">PasswordAndOTP</span>: This VPN requires a password
- and an OTP (possibly empty). Both will be send to the server in the
- 'password' response using the SCRv1 encoding.
- </li><li>
- <span class="value">Password</span>: This VPN requires only a password,
- which will be send without modification to the server in the 'password'
- response (no CRv1 or SCRv1 encoding).
- </li><li>
- <span class="value">OTP</span>: This VPN requires only an OTP, which
- will be send without modification to the server in the 'password'
- response (no CRv1 or SCRv1 encoding).
- </li><li>
- <span class="value">None</span>: Neither password nor OTP are required.
- No password request from the server is expected.
- </li></ul>
- If not set, the user can provide a password and an OTP (both not
- mandatory) and the network manager will send both in the SCRv1 encoding,
- when the server sends a static-challenge. If the server does not send a
- static-challenge, the client will reply with only the password (without
- any encoding). This behavior is deprecated and new configurations should
- explicitly set one of the above values.
-
- See the fields <span class="field">Password</span> and
- <span class="field">OTP</span> for configuring the password and OTP.
- </dd>
-
- <dt class="field">Username</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- OpenVPN user name. This value is subject to string expansions. If not
- specified, user is prompted at time of connection.
- </dd>
-
- <dt class="field">Verb</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- Verbosity level, defaults to OpenVpn's default if not specified.
- </dd>
-
- <dt class="field">VerifyHash</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- If set, this value is passed as the "--verify-hash" argument to OpenVPN,
- which specifies the SHA1 fingerprint for the level-1 certificate.
- </dd>
-
- <dt class="field">VerifyX509</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">VerifyX509</span>
- </span>
- If set, the "--verify-x509-name" argument is passed to OpenVPN with the values of this object and only connections will be accepted if a host's X.509 name is equal to the given name.
- </dd>
- </dl>
-
- <p class="rule">
- <span class="rule_id"></span>
- At most one of <span class="field">ServerCARefs</span> and <span class="field">ServerCARef</span> can be set.
- </p>
-
- <p>
- <span class="type">VerifyX509</span> type contains the following:
- </p>
- <dl class="field_list">
- <dt class="field">Name</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- The name that the host's X.509 name is compared to. Which host name is compared depends on the value of <span class="field">Type</span>.
- </dd>
-
- <dt class="field">Type</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- Determines which of the host's X.509 names will be verified. Allowed values are <span class="value">name</span>, <span class="value">name-prefix</span> and <span class="value">subject</span>. See OpenVPN's documentation for "--verify-x509-name" for the meaning of each value. Defaults to OpenVPN's default if not specified.
- </dd>
- </dl>
-</section>
-
-<section>
- <h1>Third-party VPN provider based connections and types</h1>
- <p>
- <span class="field">VPN.Type</span> must be
- <span class="value">ThirdPartyVPN</span>.
- </p>
-
- <p>
- <span class="type">ThirdPartyVPN</span> type contains the following:
- </p>
-
- <dl class="field_list">
- <dt class="field">ExtensionID</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- The extension ID of the third-party VPN provider used by this network.
- </dd>
- <dt class="field">ProviderName</dt>
- <dd>
- <span class="field_meta">
- (optional, read-only)
- <span class="type">string</span>
- </span>
- The name of the third-party VPN provider used by this network.
- </dd>
- </dl>
-</section>
-
-</section>
-
-<section>
- <h1>Client certificate patterns</h1>
- <p>
- In order to allow clients to securely key their private keys and request
- certificates through PKCS#10 format or through a web flow, we provide
- alternative CertificatePattern types. The
- <span class="type">CertificatePattern</span> type contains the following:
- </p>
-
- <dl class="field_list">
- <dt class="field">IssuerCARef</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">array of string</span>
- </span>
- Array of references to certificates. At least one must have signed the
- client certificate.
- </dd>
-
- <dt class="field">Issuer</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">IssuerSubjectPattern</span>
- </span>
- Pattern to match the issuer X.509 settings against. If not specified, the
- only checks done will be a signature check against
- the <span class="field">IssuerCARef</span> field. Issuer of the
- certificate must match this field exactly to match the pattern.
- </dd>
-
- <dt class="field">Subject</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">IssuerSubjectPattern</span>
- </span>
- Pattern to match the subject X.509 settings against. If not specified, the
- subject settings are not checked and any certificate matches. Subject of
- the certificate must match this field exactly to match the pattern.
- </dd>
-
- <dt class="field">EnrollmentURI</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">array of string</span>
- </span>
- If no certificate matches this CertificatePattern, the first URI from this
- array with a recognized scheme is navigated to, with the intention this
- informs the user how to either get the certificate or gets the certificate
- for the user. For instance, the array may be [
- "chrome-extension://asakgksjssjwwkeielsjs/fetch-client-cert.html",
- "http://intra/connecting-to-wireless.html" ] so that for Chrome browsers a
- Chrome app or extension is shown to the user, but for other browsers, a
- web URL is shown.
- </dd>
- </dl>
-
- <p>
- The <span class="type">IssuerSubjectPattern</span> type contains the
- following:
- </p>
-
- <dl class="field_list">
- <dt class="field">CommonName</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- Certificate subject's commonName must match this string if present.
- </dd>
-
- <dt class="field">Locality</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- Certificate subject's location must match this string if present.
- </dd>
-
- <dt class="field">Organization</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- At least one of certificate subject's organizations must match this string
- if present.
- </dd>
-
- <dt class="field">OrganizationalUnit</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- At least one of certificate subject's organizational units must match this
- string if present.
- </dd>
- </dl>
-
- <p class="rule">
- <span class="rule_id"></span>
- One field in <span class="field">Subject</span>,
- <span class="field">Issuer</span>, or <span class="field">IssuerCARef</span>
- must be given for a <span class="type">CertificatePattern</span> typed field
- to be valid.
- </p>
-
- <p>
- For a certificate to be considered matching, it must match all
- the fields in the certificate pattern. If multiple certificates match, the
- certificate with the latest issue date that is still in the past, and hence
- valid, will be used.
- </p>
-
- <p>
- If <span class="field">EnrollmentURI</span> is not given and no match is
- found to this pattern, the importing tool may show an error to the user.
- </p>
-</section>
-
-<section>
- <h1>Proxy settings</h1>
- <p>
- Every network can be configured to use a
- proxy. The <span class="type">ProxySettings</span> type contains the
- following:
- </p>
-
- <dl class="field_list">
- <dt class="field">Type</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">Direct</span>,
- <span class="value">Manual</span>, <span class="value">PAC</span>, and
- <span class="value">WPAD</span>.
- </span>
- <span class="value">PAC</span> indicates Proxy Auto-Configuration.
- <span class="value">WPAD</span> indicates Web Proxy Autodiscovery.
- </dd>
-
- <dt class="field">Manual</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Type</span>
- is <span class="value">Manual</span>, otherwise ignored)
- <span class="type">ManualProxySettings</span>
- </span>
- Manual proxy settings.
- </dd>
-
- <dt class="field">ExcludeDomains</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">Type</span>
- is <span class="value">Manual</span>, otherwise ignored)
- <span class="type">array of string</span>
- </span>
- Domains and hosts for which to exclude proxy settings.
- </dd>
-
- <dt class="field">PAC</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Type</span> is
- <span class="value">PAC</span>, otherwise ignored)
- <span class="type">string</span>
- </span>
- URL of proxy auto-config file.
- </dd>
- </dl>
-
- <p>
- The <span class="type">ManualProxySettings</span> type contains the
- following:
- </p>
-
- <dl class="field_list">
- <dt class="field">HTTPProxy</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">ProxyLocation</span>
- </span>
- settings for HTTP proxy.
- </dd>
-
- <dt class="field">SecureHTTPProxy</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">ProxyLocation</span>
- </span>
- settings for secure HTTP proxy.
- </dd>
-
- <dt class="field">FTPProxy</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">ProxyLocation</span>
- </span>
- settings for FTP proxy
- </dd>
-
- <dt class="field">SOCKS</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">ProxyLocation</span>
- </span>
- settings for SOCKS proxy.
- </dd>
- </dl>
-
- <p>
- The <span class="type">ProxyLocation</span> type contains the following:
- </p>
-
- <dl class="field_list">
- <dt class="field">Host</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- Host (or IP address) to use for proxy
- </dd>
-
- <dt class="field">Port</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">integer</span>
- </span>
- Port to use for proxy
- </dd>
- </dl>
-</section>
-
-<section>
- <h1>EAP configurations</h1>
- <p>
- For networks with 802.1X authentication, an <span class="type">EAP</span>
- type exists to configure the
- authentication. The <span class="type">EAP</span> type contains the
- following:
- </p>
-
- <dl class="field_list">
- <dt class="field">AnonymousIdentity</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">Outer</span> is
- <span class="value">PEAP</span> or <span class="value">EAP-TTLS</span>,
- otherwise ignored)
- <span class="type">string</span>
- </span>
- For tunnelling protocols only, this indicates the identity of the user
- presented to the outer protocol. This value is subject to string
- expansions. If not specified, use empty string.
- </dd>
-
- <dt class="field">ClientCertPattern</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">ClientCertType</span> is
- <span class="value">Pattern</span>, otherwise ignored)
- <span class="type">CertificatePattern</span>
- </span>
- Pattern to use to find the client certificate.
- </dd>
-
- <dt class="field">ClientCertRef</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">ClientCertType</span> is
- <span class="value">Ref</span>, otherwise ignored)
- <span class="type">string</span>
- </span>
- Reference to client certificate stored in certificate section.
- </dd>
-
- <dt class="field">ClientCertType</dt>
- <dd>
- <span class="field_meta">
- (optional) <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">Ref</span>, and
- <span class="value">Pattern</span>.
- </span>
- </dd>
-
- <dt class="field">Identity</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- Identity of user. For tunneling outer protocols
- (<span class="value">PEAP</span>, <span class="value">EAP-TTLS</span>, and
- <span class="value">EAP-FAST</span>), this is used to authenticate inside
- the tunnel, and <span class="field">AnonymousIdentity</span> is used for
- the EAP identity outside the tunnel. For non-tunneling outer protocols,
- this is used for the EAP identity. This value is subject to string
- expansions.
- </dd>
-
- <dt class="field">Inner</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">Outer</span> is
- <span class="value">EAP-FAST</span>, <span class="value">EAP-TTLS</span>
- or <span class="value">PEAP</span>, otherwise ignored, defaults to
- <span class="value">Automatic</span>)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">Automatic</span>,
- <span class="value">MD5</span>, <span class="value">MSCHAPv2</span>,
- <span class="value">EAP-MSCHAPv2</span>,
- <span class="value">PAP</span>, and <span class="value">GTC</span>.
- </span>
- For tunneling outer protocols.
- </dd>
-
- <dt class="field">Outer</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">LEAP</span>,
- <span class="value">EAP-AKA</span>, <span class="value">EAP-FAST</span>,
- <span class="value">EAP-TLS</span>, <span class="value">EAP-TTLS</span>,
- <span class="value">EAP-SIM</span> and <span class="value">PEAP</span>.
- </span>
- </dd>
-
- <dt class="field">Password</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- Password of user. If not specified, defaults to prompting the user.
- </dd>
-
- <dt class="field">SaveCredentials</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- If <span class="value">false</span>, require user to enter credentials
- each time they connect. Specifying <span class="field">Identity</span>
- and/or <span class="field">Password</span> when
- <span class="field">SaveCredentials</span> is
- <span class="value">false</span> is not allowed.
- </dd>
-
- <dt class="field">ServerCARefs</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">array of string</span>
- </span>
- Non-empty list of references to CA certificates in <span class="field">Certificates</span> to be used for verifying the host's certificate chain. At least one of the CA certificates must match. If this field is set, <span class="field">ServerCARef</span> must be unset. If neither <span class="field">ServerCARefs</span> nor <span class="field">ServerCARef</span> is set, the client does not check that the server certificate is signed by a specific CA. A verification using the system's CA certificates may still apply. See <span class="field">UseSystemCAs</span> for this.
- </dd>
-
- <dt class="field">ServerCARef</dt>
- <dd>
- <span class="field_meta">
- (optional)
- <span class="type">string</span>
- </span>
- DEPRECATED, use <span class="field">ServerCARefs</span> instead.<br/>
- Reference to a CA certificate in <span class="field">Certificates</span>. If this field is set, <span class="field">ServerCARefs</span> must be unset. If neither <span class="field">ServerCARefs</span> nor <span class="field">ServerCARef</span> is set, the client does not check that the server certificate is signed by a specific CA. A verification using the system's CA certificates may still apply. See <span class="field">UseSystemCAs</span> for this.
- </dd>
-
- <dt class="field">UseSystemCAs</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">true</span>)
- <span class="type">boolean</span>
- </span>
- Required server certificate to be signed by "system default certificate
- authorities". If both <span class="field">ServerCARefs</span> (or <span class="field">ServerCARef</span>)
- and <span class="field">UseSystemCAs</span> are supplied, a server
- certificate will be allowed if it either has a chain of trust to a system
- CA or to one of the given CA certificates. If <span class="field">UseSystemCAs</span>
- is <span class="value">false</span>, and no <span class="field">ServerCARef</span> is set, the certificate
- must be a self signed certificate, and no CA signature is required.
- </dd>
-
- <dt class="field">UseProactiveKeyCaching</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- Indicates whether Proactive Key Caching (also known as Opportunistic
- Key Caching) should be used on a per-service basis.
- </dd>
- </dl>
-
- <p class="rule">
- <span class="rule_id"></span>
- At most one of <span class="field">ServerCARefs</span> and <span class="field">ServerCARef</span> can be set.
- </p>
-</section>
-
-<section>
- <h1>WiMAX Networks</h1>
- <p>
- For WiMAX connections, <span class="field">Type</span> must be set to
- <span class="value">WiMAX</span> and the
- field <span class="field">WiMAX</span> must be set to an object of
- type <span class="type">WiMAX</span>. Currently only used for
- representing an existing configuration; ONC configuration of
- of <span class="field">WiMAX</span> networks is not yet fully supported.
- Contains the following fields:
- </p>
-
- <dl class="field_list">
- <dt class="field">AutoConnect</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- Indicating that the network should be connected to automatically when
- possible.
- </dd>
-
- <dt class="field">EAP</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">EAP</span>
- </span>
- EAP settings.
- </dd>
-
- <dt class="field">SignalStrength</dt>
- <dd>
- <span class="field_meta">
- (optional, read-only)
- <span class="type">integer</span>
- </span>
- The current signal strength for this network in the range [0, 100],
- provided by the system. If the network is not in range this field will
- be set to '0' or not present.
- </dd>
- </dl>
-
-</section>
-
-<section>
- <h1>Cellular Networks</h1>
- <p>
- For Cellular connections, <span class="field">Type</span> must be set to
- <span class="value">Cellular</span> and the
- field <span class="field">Cellular</span> must be set to an object of
- type <span class="type">Cellular</span>. Currently only used for
- representing an existing configuration; ONC configuration of
- of <span class="field">Cellular</span> networks is not yet supported.
- Contains the following fields:
- </p>
-
- <dl class="field_list">
- <dt class="field">AutoConnect</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- Indicating that the network should be connected to automatically when
- possible. Note, that disabled <span class="field">AllowRoaming</span>
- takes precedence over autoconnect.
- </dd>
-
- <dt class="field">APN</dt>
- <dd>
- <span class="field_meta">(optional)
- <span class="type">APN</span>
- </span>
- Currently active <span class="type">APN</span> object to be used with a
- GSM carrier for making data connections.
- </dd>
-
- <dt class="field">APNList</dt>
- <dd>
- <span class="field_meta">(optional)
- <span class="type">array of APN</span>
- </span>
- List of available APN configurations.
- </dd>
-
- <dt class="field">ActivationType</dt>
- <dd>
- <span class="field_meta">(optional)
- <span class="type">string</span>
- </span>
- Activation type.
- </dd>
-
- <dt class="field">ActivationState</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">string</span>
- </span>
- Carrier account activation state.
- <span class="rule">
- <span class="rule_id"></span>Allowed values are
- <span class="value">Activated</span>,
- <span class="value">Activating</span>,
- <span class="value">NotActivated</span>,
- <span class="value">PartiallyActivated</span>
- </span>
- </dd>
-
- <dt class="field">AllowRoaming</dt>
- <dd>
- <span class="field_meta">(optional)
- <span class="type">boolean</span>
- </span>
- Whether cellular data connections are allowed when the device is roaming.
- </dd>
-
- <dt class="field">Carrier</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">string</span>
- </span>
- The name of the carrier for which the device is configured.
- </dd>
-
- <dt class="field">ESN</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">string</span>
- </span>
- The Electronic Serial Number of the cellular modem.
- </dd>
-
- <dt class="field">Family</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">string</span>
- </span>
- Technology family.
- <span class="rule"><span class="rule_id"></span>
- Allowed values are
- <span class="value">CDMA</span>,
- <span class="value">GSM</span>
- </span>
- </dd>
-
- <dt class="field">FirmwareRevision</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">string</span>
- </span>
- The revision of firmware that is loaded in the modem.
- </dd>
-
- <dt class="field">FoundNetworks</dt>
- <dd>
- <span class="field_meta">(optional, read-only, provided only
- if <span class="field">Family</span> is <span class="value">GSM</span>)
- <span class="type">array of FoundNetwork</span>
- </span>
- The list of cellular netwoks found in the most recent scan operation.
- </dd>
-
- <dt class="field">HardwareRevision</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">string</span>
- </span>
- The hardware revision of the cellular modem.
- </dd>
-
- <dt class="field">HomeProvider</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">CellularProvider</span>
- </span>
- Description of the operator that issued the SIM card currently installed
- in the modem.
- </dd>
-
- <dt class="field">ICCID</dt>
- <dd>
- <span class="field_meta">(optional, read-only, provided only
- if <span class="field">Family</span> is <span class="value">GSM</span>
- or <span class="field">NetworkTechnology</span>
- is <span class="value">LTE</span>)
- <span class="type">string</span>
- </span>
- For GSM / LTE modems, the Integrated Circuit Card Identifer of the SIM
- card installed in the device.
- </dd>
-
- <dt class="field">IMEI</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">string</span>
- </span>
- The International Mobile Equipment Identity of the cellular modem.
- </dd>
-
- <dt class="field">IMSI</dt>
- <dd>
- <span class="field_meta">(optional, read-only, provided only
- if <span class="field">Family</span> is <span class="value">GSM</span>)
- <span class="type">string</span>
- </span>
- For GSM modems, the International Mobile Subscriber Identity of the SIM
- card installed in the device.
- </dd>
-
- <dt class="field">LastGoodAPN</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">APN</span>
- </span>
- The APN information used in the last successful connection attempt.
- </dd>
-
- <dt class="field">Manufacturer</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">string</span>
- </span>
- The manufacturer of the cellular modem.
- </dd>
-
- <dt class="field">MDN</dt>
- <dd>
- <span class="field_meta">(optional)
- <span class="type">string</span>
- </span>
- The Mobile Directory Number (i.e., phone number) of the device.
- </dd>
-
- <dt class="field">MEID</dt>
- <dd>
- <span class="field_meta">(optional, read-only, provided only
- if <span class="field">Family</span> is <span class="value">CDMA</span>)
- <span class="type">string</span>
- </span>
- For CDMA modems, the Mobile Equipment Identifer of the cellular modem.
- </dd>
-
- <dt class="field">MIN</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">string</span>
- </span>
- The Mobile Identification Number of the device.
- </dd>
-
- <dt class="field">ModelID</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">string</span>
- </span>
- The hardware model of the cellular modem.
- </dd>
-
- <dt class="field">NetworkTechnology</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">string</span>
- </span>
- If the modem is registered on a network, then this is set to the
- network technology currently in use.
- <span class="rule"><span class="rule_id"></span>
- Allowed values are
- <span class="value">CDMA1XRTT</span>,
- <span class="value">EDGE</span>,
- <span class="value">EVDO</span>,
- <span class="value">GPRS</span>,
- <span class="value">GSM</span>,
- <span class="value">HSPA</span>,
- <span class="value">HSPAPlus</span>,
- <span class="value">LTE</span>,
- <span class="value">LTEAdvanced</span>
- <span class="value">UMTS</span>,
- </span>
- </dd>
-
- <dt class="field">PaymentPortal</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">PaymentPortal</span>
- </span>
- Properties describing the online payment portal (OLP) at which a user can
- sign up for or modify a mobile data plan.
- </dd>
-
- <dt class="field">PRLVersion</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">integer</span>
- </span>
- The revision of the Preferred Roaming List that is loaded in the modem.
- </dd>
-
- <dt class="field">RoamingState</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">string</span>
- </span>
- The roaming status of the cellular modem on the current network.
- <span class="rule"><span class="rule_id"></span>
- Allowed values are <span class="value">Home</span>,
- <span class="value">Roaming</span>, or if the provider has no home
- network, <span class="value">Required</span>.
- </span>
- </dd>
-
- <dt class="field">ServingOperator</dt>
- <dd>
- <span class="field_meta">(optional, read-only, provided only
- if <span class="field">Family</span> is <span class="value">GSM</span>)
- <span class="type">CellularProvider</span>
- </span>
- Description of the operator on whose network the modem is currently
- registered
- </dd>
-
- <dt class="field">SignalStrength</dt>
- <dd>
- <span class="field_meta">
- (optional, read-only)
- <span class="type">integer</span>
- </span>
- The current signal strength for this network in the range [0, 100],
- provided by the system. If the network is not in range this field will
- be set to '0' or not present.
- </dd>
-
- <dt class="field">SIMLockStatus</dt>
- <dd>
- <span class="field_meta">(optional, read-only, provided only
- if <span class="field">Family</span> is <span class="value">GSM</span>)
- <span class="type">SIMLockStatus</span>
- </span>
- For GSM modems, a dictionary containing two properties describing the
- state of the SIM card lock.
- </dd>
-
- <dt class="field">SIMPresent</dt>
- <dd>
- <span class="field_meta">(optional, read-only, provided only
- if <span class="field">Family</span> is <span class="value">GSM</span>
- or <span class="field">NetworkTechnology</span>
- is <span class="value">LTE</span>)
- <span class="type">boolean</span>
- </span>
- For GSM or LTE modems, indicates whether a SIM card is present or not.
- </dd>
-
- <dt class="field">SupportNetworkScan</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">boolean</span>
- </span>
- True if the cellular network supports scanning.
- </dd>
-
- <dt class="field">SupportedCarriers</dt>
- <dd>
- <span class="field_meta">(optional, read-only)
- <span class="type">array of string</span>
- </span>
- A list of supported carriers.
- </dd>
-
- </dl>
-
- <p><span class="type">APN</span> type contains the following:</p>
- <dl class="field_list">
- <dt class="field">AccessPointName</dt>
- <dd>
- <span class="field_meta">(required)
- <span class="type">string</span>
- </span>
- The access point name used when making connections.
- </dd>
-
- <dt class="field">Name</dt>
- <dd>
- <span class="field_meta">(optional)
- <span class="type">string</span>
- </span>
- Description of the APN.
- </dd>
-
- <dt class="field">LocalizedName</dt>
- <dd>
- <span class="field_meta">(optional)
- <span class="type">string</span>
- </span>
- Localized description of the APN.
- </dd>
-
- <dt class="field">Username</dt>
- <dd>
- <span class="field_meta">(optional)
- <span class="type">string</span>
- </span>
- Username for making connections if required.
- </dd>
-
- <dt class="field">Password</dt>
- <dd>
- <span class="field_meta">(optional)
- <span class="type">string</span>
- </span>
- Password for making connections if required.
- </dd>
-
- <dt class="field">Language</dt>
- <dd>
- <span class="field_meta">(optional, rquired if <span class="field">
- LocalizedName</span> is provided)
- <span class="type">string</span>
- </span>
- Two letter language code for Localizedname if provided.
- </dd>
- </dl>
-
- <p><span class="type">FoundNetwork</span> type contains the following:</p>
- <dl class="field_list">
- <dt class="field">Status</dt>
- <dd>
- <span class="field_meta">(required)
- <span class="type">string</span>
- </span>
- The availability of the network.
- </dd>
-
- <dt class="field">NetworkId</dt>
- <dd>
- <span class="field_meta">(required)
- <span class="type">string</span>
- </span>
- The network id in the form MCC/MNC (without the '/').
- </dd>
-
- <dt class="field">Technology</dt>
- <dd>
- <span class="field_meta">(required)
- <span class="type">string</span>
- </span>
- Access technology used by the network,
- e.g. "GSM", "UMTS", "EDGE", "HSPA", etc.
- </dd>
-
- <dt class="field">ShortName</dt>
- <dd>
- <span class="field_meta">(optional)
- <span class="type">string</span>
- </span>
- Short-format name of the network operator.
- </dd>
-
- <dt class="field">LongName</dt>
- <dd>
- <span class="field_meta">(optional)
- <span class="type">string</span>
- </span>
- Long-format name of the network operator.
- </dd>
- </dl>
-
- <p><span class="type">PaymentPortal</span> type contains the following:</p>
- <dl class="field_list">
- <dt class="field">Method</dt>
- <dd>
- <span class="field_meta">(required)
- <span class="type">string</span>
- </span>
- The HTTP method to use, "GET" or "POST"
- </dd>
-
- <dt class="field">PostData</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Method</span> is
- <span class="value">POST</span>, otherwise ignored)
- <span class="type">string</span>
- </span>
- The postdata to send.
- </dd>
-
- <dt class="field">Url</dt>
- <dd>
- <span class="field_meta">(required)
- <span class="type">string</span>
- </span>
- The URL for the portal.
- </dd>
- </dl>
-
- <p><span class="type">CellularProvider</span> type contains the following:</p>
- <dl class="field_list">
- <dt class="field">Name</dt>
- <dd>
- <span class="field_meta">(required)
- <span class="type">string</span>
- </span>
- The operator name.
- </dd>
-
- <dt class="field">Code</dt>
- <dd>
- <span class="field_meta">(required)
- <span class="type">string</span>
- </span>
- The network id in the form MCC/MNC (without the '/').
- </dd>
-
- <dt class="field">Country</dt>
- <dd>
- <span class="field_meta">(optional)
- <span class="type">string</span>
- </span>
- The two-letter country code.
- </dd>
- </dl>
-
- <p><span class="type">SIMLockStatus</span> type contains the following:</p>
- <dl class="field_list">
- <dt class="field">LockType</dt>
- <dd>
- <span class="field_meta">(required)
- <span class="type">string</span>
- </span>
- Specifies the type of lock in effect, or an empty string if unlocked.
- <span class="rule"><span class="rule_id"></span>
- Allowed values are
- <span class="value">sim-pin</span>,
- <span class="value">sim-puk</span>
- </span>
- </dd>
-
- <dt class="field">LockEnabled</dt>
- <dd>
- <span class="field_meta">(required)
- <span class="type">boolean</span>
- </span>
- Indicates whether SIM locking is enabled
- </dd>
-
- <dt class="field">RetriesLeft</dt>
- <dd>
- <span class="field_meta">(optional)
- <span class="type">integer</span>
- </span>
- If <span class="field">LockType</span> is empty
- or <span class="value">sim-pin</span>, then this property represents
- the number of attempts remaining to supply a correct PIN before the
- PIN becomes blocked, at which point a PUK provided by the carrier would
- be necessary to unlock the SIM (and <span class="field">LockType</span>
- changes to <span class="value">sim-puk</span>).
- </dd>
- </dl>
-
-</section>
-
-<section>
- <h1>Bluetooth / WiFi Direct Networks</h1>
- <p>
- This format will eventually also cover configuration of Bluetooth and WiFi
- Direct network technologies, however they are currently not supported.
- </p>
-</section>
-
-</section>
-
-<section>
- <h1>Certificates</h1>
- <p>
- Certificate data is stored in a separate section. Each certificate may be
- referenced from within the NetworkConfigurations array using a certificate
- reference. A certificate reference is its GUID.
- </p>
-
- <p>
- The top-level field <span class="field">Certificates</span> is an array of
- objects of <span class="type">Certificate</span> type.
- </p>
-
- <p>
- The <span class="type">Certificate</span> type contains the following:
- </p>
-
- <dl class="field_list">
- <dt class="field">GUID</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- A unique identifier for this certificate. Must be a non-empty string.
- </dd>
-
- <dt class="field">PKCS12</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Type</span> is
- <span class="value">Client</span>, otherwise ignored)
- <span class="type">string</span>
- </span> For certificates with
- private keys, this is the base64 encoding of the a PKCS#12 file.
- </dd>
-
- <dt class="field">Remove</dt>
- <dd>
- <span class="field_meta">
- (optional, defaults to <span class="value">false</span>)
- <span class="type">boolean</span>
- </span>
- If <span class="value">true</span>, remove this certificate (only GUID
- should be set).
- </dd>
-
- <dt class="field">TrustBits</dt>
- <dd>
- <span class="field_meta">
- (optional if <span class="field">Type</span>
- is <span class="value">Server</span>
- or <span class="value">Authority</span>, otherwise ignored, defaults to
- [])
- <span class="type">array of string</span>
- </span>
- An array of trust flags. Clients should ignore unknown flags. For
- backwards compatibility, each flag should only increase the trust and
- never restrict. The trust flag <span class="value">Web</span> implies that
- the certificate is to be trusted for HTTPS SSL identification. A typical
- web certificate authority would have <span class="field">Type</span> set
- to <span class="value">Authority</span> and
- <span class="field">TrustBits</span> set to
- <span class="snippet">["Web"]</span>.
- </dd>
-
- <dt class="field">Type</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Remove</span> is
- <span class="value">false</span>, otherwise ignored)
- <span class="type">string</span>
- </span>
- <span class="rule">
- <span class="rule_id"></span>
- Allowed values are <span class="value">Client</span>,
- <span class="value">Server</span>, and
- <span class="value">Authority</span>.
- </span>
- <span class="value">Client</span> indicates the certificate is for
- identifying the user or device over HTTPS or for
- VPN/802.1X. <span class="value">Server</span> indicates the certificate
- identifies an HTTPS or VPN/802.1X peer.
- <span class="value">Authority</span> indicates the certificate is a
- certificate authority and any certificates it issues should be
- trusted. Note that if <span class="field">Type</span> disagrees with the
- x509 v3 basic constraints or key usage attributes, the
- <span class="field">Type</span> field should be honored.
- </dd>
-
- <dt class="field">X509</dt>
- <dd>
- <span class="field_meta">
- (required if <span class="field">Type</span> is
- <span class="value">Server</span> or
- <span class="value">Authority</span>, otherwise ignored)
- <span class="type">string</span>
- </span> For certificate
- without private keys, this is the X509 certificate in PEM format.
- </dd>
- </dl>
-
- <p>
- The passphrase of the PKCS#12 encoding must be empty. Encryption of key data
- should be handled at the level of the entire file, or the transport of the
- file.
- </p>
-
- <p>
- If a global-scoped network connection refers to a user-scoped certificate,
- results are undefined, so this configuration should be prohibited by the
- configuration editor.
- </p>
-</section>
-
-</section>
-
-<section>
- <h1>Encrypted Configuration</h1>
- <p>
- We assume that when this format is imported as part of policy that
- file-level encryption will not be necessary because the policy transport is
- already encrypted, but when it is imported as a standalone file, it is
- desirable to encrypt it. Since this file has private information (user
- names) and secrets (passphrases and private keys) in it, and we want it to
- be usable as a manual way to distribute network configuration, we must
- support encryption.
- </p>
-
- <p>
- For this standalone export, the entire file will be encrypted in a symmetric
- fashion with a passphrase stretched using salted PBKDF2 using at least 20000
- iterations, and encrypted using an AES-256 CBC mode cipher with an SHA-1
- HMAC on the ciphertext.
- </p>
-
- <p>
- An encrypted ONC file's top level object will have the
- <span class="type">EncryptedConfiguration</span>
- type. <span class="type">EncryptedConfiguration</span> type contains the
- following:
- </p>
-
- <dl class="field_list">
- <dt class="field">Cipher</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- The type of cipher used. Currently only <span class="value">AES256</span>
- is supported.
- </dd>
-
- <dt class="field">Ciphertext</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- The raw ciphertext of the encrypted ONC file, base64 encoded.
- </dd>
-
- <dt class="field">HMAC</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- The HMAC for the ciphertext, base64 encoded.
- </dd>
-
- <dt class="field">HMACMethod</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- The method used to compute the Hash-based Message Authentication Code
- (HMAC). Currently only <span class="value">SHA1</span> is supported.
- </dd>
-
- <dt class="field">Salt</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- The salt value used during key stretching.
- </dd>
-
- <dt class="field">Stretch</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- The key stretching algorithm used. Currently
- only <span class="value">PBKDF2</span> is supported.
- </dd>
-
- <dt class="field">Iterations</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">integer</span>
- </span>
- The number of iterations to use during key stretching.
- </dd>
-
- <dt class="field">IV</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- The initial vector (IV) used for Cyclic Block Cipher (CBC) mode, base64
- encoded.
- </dd>
-
- <dt class="field">Type</dt>
- <dd>
- <span class="field_meta">
- (required)
- <span class="type">string</span>
- </span>
- The type of the ONC file, which must be set
- to <span class="value">EncryptedConfiguration</span>.
- </dd>
- </dl>
-
- <p class="rule">
- <span class="rule_id"></span>
- When decrypted, the ciphertext must contain a JSON object of
- type <span class="type">UnencryptedConfiguration</span>.
- </p>
-</section>
-
-<section>
- <h1>String Expansions</h1>
- <p>
- The values of some fields, such
- as <span class="field">WiFi.EAP.Identity</span>
- and <span class="field">VPN.*.Username</span>, are subject to string
- expansions. These allow one ONC to have basic user-specific variations.
- </p>
-
- <p>
- The expansions are:
- </p>
-
- <ul>
- <li>
- ${LOGIN_ID} - expands to the email address of the user, but before the
- '@'.
- </li>
- <li>
- ${LOGIN_EMAIL} - expands to the email address of the user.
- </li>
- </ul>
-
- <p>
- The following SED would properly handle resolution.
- </p>
-
- <ul>
- <li>
- s/\$\{LOGIN_ID\}/bobquail$1/g
- </li>
- <li>
- s/\$\{LOGIN_EMAIL\}/bobquail@example.com$1/g
- </li>
- </ul>
-
- <p>
- Example expansions, assuming the user was bobquail@example.com:
- </p>
-
- <ul>
- <li>
- "${LOGIN_ID}" -> "bobquail"
- </li>
- <li>
- "${LOGIN_ID}@corp.example.com" -> "bobquail@corp.example.com"
- </li>
- <li>
- "${LOGIN_EMAIL}" -> "bobquail@example.com"
- </li>
- <li>
- "${LOGIN_ID}X" -> "bobquailX"
- </li>
- <li>
- "${LOGIN_IDX}" -> "${LOGIN_IDX}"
- </li>
- <li>
- "X${LOGIN_ID}" -> "Xbobquail"
- </li>
- </ul>
-</section>
-
-<section>
- <h1>Detection</h1>
- <p>
- This format should be sent in files ending in the .onc extension. When
- transmitted with a MIME type, the MIME type should be
- application/x-onc. These two methods make detection of data to be handled in
- this format, especially when encryption is used and the payload itself is
- not detectable.
- </p>
-</section>
-
-</section>
-
-<section>
- <h1>Alternatives considered</h1>
- <p>
- For the overall format, we considered XML, ASN.1, and protobufs. JSON and
- ASN.1 seem more widely known than protobufs. Since administrators are
- likely to want to tweak settings that will not exist in common UIs, we
- should provide a format that is well known and human modifiable. ASN.1 is
- not human modifiable. Protobufs formats are known by open source developers
- but seem less likely to be known by administrators. JSON serialization
- seems to have good support across languages.
- </p>
-
- <p>
- We considered sending the exact connection manager configuration format of
- an open source connection manager like connman. There are a few issues
- here, for instance, referencing certificates by identifiers not tied to a
- particular PKCS#11 token, and tying to one OS's connection manager.
- </p>
-</section>
-
-<section>
- <h1>Detection</h1>
- <p>
- This format should be sent in files ending in the .onc extension. When
- transmitted with a MIME type, the MIME type should be
- application/x-onc. These two methods make detection of data to be handled in
- this format, especially when encryption is used and the payload itself is
- not detectable.
- </p>
-</section>
-
-<section>
- <h1>Mocks</h1>
-
-<section>
- <h1>Simple format example: PEAP/MSCHAPv2 network (per device)</h1>
-
- <pre>
-{
- "Type": "UnencryptedConfiguration",
- "NetworkConfigurations": [
- {
- "GUID": "{f2c17903-b0e1-8593-b3ca74f977236bd7}",
- "Name": "MySSID",
- "Type": "WiFi",
- "WiFi": {
- "AutoConnect": true,
- "EAP": {
- "Outer": "PEAP",
- "UseSystemCAs": true
- },
- "HiddenSSID": false,
- "SSID": "MySSID",
- "Security": "WPA-EAP"
- }
- }
- ],
- "Certificates": []
-}
- </pre>
-
- <p>
- Notice that in this case, we do not provide a username and password - we set
- SaveCredentials to <span class="value">false</span> so we are prompted every
- time. We could have passed in username and password - but such a file should
- be encrypted.
- </p>
-</section>
-
-<section>
- <h1>Complex format example: TLS network with client certs (per device)</h1>
-
- <pre>
-{
- "Type": "UnencryptedConfiguration",
- "NetworkConfigurations": [
- {
- "GUID": "{00f79111-51e0-e6e0-76b3b55450d80a1b}",
- "Name": "MyTTLSNetwork",
- "Type": "WiFi",
- "WiFi": {
- "AutoConnect": false,
- "EAP": {
- "ClientCertPattern": {
- "EnrollmentURI": [
- "http://fetch-my-certificate.com"
- ],
- "IssuerCARef": [
- "{6ed8dce9-64c8-d568-d225d7e467e37828}"
- ]
- },
- "ClientCertType": "Pattern",
- "Outer": "EAP-TLS",
- "ServerCARef": "{6ed8dce9-64c8-d568-d225d7e467e37828}",
- "UseSystemCAs": true
- },
- "HiddenSSID": false,
- "SSID": "MyTTLSNetwork",
- "Security": "WPA-EAP"
- }
- }
- ],
- "Certificates": [
- {
- "GUID": "{6ed8dce9-64c8-d568-d225d7e467e37828}",
- "Type": "Authority",
- "X509": "MIIEpzCCA4+gAwIBAgIJAMueiWq5WEIAMA0GCSqGSIb3DQEBBQUAMIGTMQswCQYDVQQGEwJGUjEPMA0GA1UECBMGUmFkaXVzMRIwEAYDVQQHEwlTb21ld2hlcmUxFTATBgNVBAoTDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5jb20xJjAkBgNVBAMTHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTExMDEyODA2MjA0MFoXDTEyMDEyODA2MjA0MFowgZMxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIEwZSYWRpdXMxEjAQBgNVBAcTCVNvbWV3aGVyZTEVMBMGA1UEChMMRXhhbXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTEmMCQGA1UEAxMdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9EDplhyrVNJIoy1OsVqvD/K67B5PW2bDKKxGznodrzCu8jHsP1Ne3mgrK20vbzQUUBdmxTCWO6x3a3//r4ZuPOuZd1ViycWjt6mRfRbBzNrHzP7NiyFuXjdlz74beHQQLcHwvZ3qFAWZK37uweiLiDPaMaEQlka2Bztqx4PsogmSdoVPSCxi5Cl1XlJmITA03LlKpO79+0rEPRamWO/DMCwvffn2/UUjJLog4/lYe16HQ6iq/6bjhffm2rLXDFKOGZmBVbLNMCfANRMtdFWHYdBXERoUo2zpM9tduOOUNLy7E7kRKVm/wy38s51ChFPlpORrhimN2j1caar+KAv2tAgMBAAGjgfswgfgwHQYDVR0OBBYEFBTIImiXp+57jjgn2N5wq93GgAAtMIHIBgNVHSMEgcAwgb2AFBTIImiXp+57jjgn2N5wq93GgAAtoYGZpIGWMIGTMQswCQYDVQQGEwJGUjEPMA0GA1UECBMGUmFkaXVzMRIwEAYDVQQHEwlTb21ld2hlcmUxFTATBgNVBAoTDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5jb20xJjAkBgNVBAMTHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5ggkAy56JarlYQgAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAnNd0YY7s2YVYPsgEgDS+rBNjcQloTFWgc9Hv4RWBjwcdJdSPIrpBp7LSjC96wH5U4eWpQjlWbOYQ9RBq9Z/RpuAPEjzRV78rIrQrCWQ3lxwywWEb5Th1EVJSN68eNv7Ke5BlZ2l9kfLRKFm5MEBXX9YoHMX0U8I8dPIXfTyevmKOT1PuEta5cQOM6/zH86XWn6WYx3EXkyjpeIbVOw49AqaEY8u70yBmut4MO03zz/pwLjV1BWyIkXhsrtuJyA+ZImvgLK2oAMZtGGFo7b0GW/sWY/P3R6Un3RFy35k6U3kXCDYYhgZEcS36lIqcj5y6vYUUVM732/etCsuOLz6ppw=="
- }
- ]
-}
- </pre>
-
- <p>
- In this example, the client certificate is not sent in the ONC format, but
- rather we send a certificate authority which we know will have signed the
- client certificate that is needed, along with an enrollment URI to navigate
- to if the required certificate is not yet available on the client.
- </p>
-</section>
-
-<section>
- <h1>Simple format example: HTTPS Certificate Authority</h1>
-
- <p>
- In this example a new certificate authority is added to be trusted for HTTPS
- server authentication.
- </p>
-
- <pre>
-{
- "Type": "UnencryptedConfiguration",
- "NetworkConfigurations": [],
- "Certificates": [
- {
- "GUID": "{f31f2110-9f5f-61a7-a8bd7c00b94237af}",
- "TrustBits": [ "Web" ],
- "Type": "Authority",
- "X509": "MIIEpzCCA4+gAwIBAgIJAMueiWq5WEIAMA0GCSqGSIb3DQEBBQUAMIGTMQswCQYDVQQGEwJGUjEPMA0GA1UECBMGUmFkaXVzMRIwEAYDVQQHEwlTb21ld2hlcmUxFTATBgNVBAoTDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5jb20xJjAkBgNVBAMTHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTExMDEyODA2MjA0MFoXDTEyMDEyODA2MjA0MFowgZMxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIEwZSYWRpdXMxEjAQBgNVBAcTCVNvbWV3aGVyZTEVMBMGA1UEChMMRXhhbXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTEmMCQGA1UEAxMdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9EDplhyrVNJIoy1OsVqvD/K67B5PW2bDKKxGznodrzCu8jHsP1Ne3mgrK20vbzQUUBdmxTCWO6x3a3//r4ZuPOuZd1ViycWjt6mRfRbBzNrHzP7NiyFuXjdlz74beHQQLcHwvZ3qFAWZK37uweiLiDPaMaEQlka2Bztqx4PsogmSdoVPSCxi5Cl1XlJmITA03LlKpO79+0rEPRamWO/DMCwvffn2/UUjJLog4/lYe16HQ6iq/6bjhffm2rLXDFKOGZmBVbLNMCfANRMtdFWHYdBXERoUo2zpM9tduOOUNLy7E7kRKVm/wy38s51ChFPlpORrhimN2j1caar+KAv2tAgMBAAGjgfswgfgwHQYDVR0OBBYEFBTIImiXp+57jjgn2N5wq93GgAAtMIHIBgNVHSMEgcAwgb2AFBTIImiXp+57jjgn2N5wq93GgAAtoYGZpIGWMIGTMQswCQYDVQQGEwJGUjEPMA0GA1UECBMGUmFkaXVzMRIwEAYDVQQHEwlTb21ld2hlcmUxFTATBgNVBAoTDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5jb20xJjAkBgNVBAMTHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5ggkAy56JarlYQgAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAnNd0YY7s2YVYPsgEgDS+rBNjcQloTFWgc9Hv4RWBjwcdJdSPIrpBp7LSjC96wH5U4eWpQjlWbOYQ9RBq9Z/RpuAPEjzRV78rIrQrCWQ3lxwywWEb5Th1EVJSN68eNv7Ke5BlZ2l9kfLRKFm5MEBXX9YoHMX0U8I8dPIXfTyevmKOT1PuEta5cQOM6/zH86XWn6WYx3EXkyjpeIbVOw49AqaEY8u70yBmut4MO03zz/pwLjV1BWyIkXhsrtuJyA+ZImvgLK2oAMZtGGFo7b0GW/sWY/P3R6Un3RFy35k6U3kXCDYYhgZEcS36lIqcj5y6vYUUVM732/etCsuOLz6ppw=="
- }
- ]
-}
- </pre>
-</section>
-
-<section>
- <h1>Encrypted format example</h1>
-
- <p>
-In this example a simple wireless network is added, but the file is encrypted
-with the passphrase "test0000".
- </p>
-
- <pre>
-{
- "Cipher": "AES256",
- "Ciphertext": "eQ9/r6v29/83M745aa0JllEj4lklt3Nfy4kPPvXgjBt1eTByxXB+FnsdvL6Uca5JBU5aROxfiol2+ZZOkxPmUNNIFZj70pkdqOGVe09ncf0aVBDsAa27veGIG8rG/VQTTbAo7d8QaxdNNbZvwQVkdsAXawzPCu7zSh4NF/hDnDbYjbN/JEm1NzvWgEjeOfqnnw3PnGUYCArIaRsKq9uD0a1NccU+16ZSzyDhX724JNrJjsuxohotk5YXsCK0lP7ZXuXj+nSR0aRIETSQ+eqGhrew2octLXq8cXK05s6ZuVAc0mFKPkntSI/fzBACuPi4ZaGd3YEYiKzNOgKJ+qEwgoE39xp0EXMZOZyjMOAtA6e1ZZDQGWG7vKdTLmLKNztHGrXvlZkyEf1RDs10YgkwwLgUhm0yBJ+eqbxO/RiBXz7O2/UVOkkkVcmeI6yh3BdL6HIYsMMygnZa5WRkd/2/EudoqEnjcqUyGsL+YUqV6KRTC0PH+z7zSwvFs2KygrSM7SIAZM2yiQHTQACkA/YCJDwACkkQOBFnRWTWiX0xmN55WMbgrs/wqJ4zGC9LgdAInOBlc3P+76+i7QLaNjMovQ==",
- "HMAC": "3ylRy5InlhVzFGakJ/9lvGSyVH0=",
- "HMACMethod": "SHA1",
- "Iterations": 20000,
- "IV": "hcm6OENfqG6C/TVO6p5a8g==",
- "Salt": "/3O73QadCzA=",
- "Stretch": "PBKDF2",
- "Type": "EncryptedConfiguration"
-}
- </pre>
-</section>
-
-</section>
-
-<section>
- <h1>Standalone editor</h1>
-
- <p>
- The source code for a Chrome packaged app to generate ONC configuration can
- be found here:
- <a href="https://gerrit.chromium.org/gitweb/?p=chromiumos/platform/spigots.git;a=tree">"https://gerrit.chromium.org/gitweb/?p=chromiumos/platform/spigots.git;a=tree"</a>
- </p>
-</section>
-
-<section>
- <h1>Internationalization and Localization</h1>
-
- <p>
- UIs will need to have internationalization and localizations - the file
- format will remain in English.
- </p>
-</section>
-
-<section>
- <h1>Security Considerations</h1>
-
- <p>
- Data stored inside of open network configuration files is highly sensitive
- to users and enterprises. The file format itself provides adequate
- encryption options to allow standalone use-cases to be secure. For automatic
- updates sent by policy, the policy transport should be made secure. The file
- should not be stored unencrypted on disk as part of policy fetching and
- should be cleared from memory after use.
- </p>
-</section>
-
-<section>
- <h1>Privacy Considerations</h1>
-
- <p>
- Similarly to the security considerations, user names will be present in
- these files for certain kinds of connections, so any places where the file
- is transmitted or saved to disk should be secure. On client device, when
- user names for connections that are user-specific are persisted to disk,
- they should be stored in a location that is encrypted. Users can also opt in
- these cases to not save their user credentials in the config file and will
- instead be prompted when they are needed.
- </p>
-</section>
-</section>
-</body>
-</html>
diff --git a/chromium/components/onc/docs/onc_spec.js b/chromium/components/onc/docs/onc_spec.js
deleted file mode 100644
index 8cc027a0f80..00000000000
--- a/chromium/components/onc/docs/onc_spec.js
+++ /dev/null
@@ -1,55 +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.
-
-var outline_root = null;
-var root = null;
-var outline_ptr = null;
-
-function onEnter(node) {
- var li = document.createElement('li');
- outline_ptr.appendChild(li);
-
- var header = node.querySelector('h1');
- header.id = 'sec_' + header.textContent.replace(/ /g, '_');
- var link = document.createElement('a');
- link.href = '#' + header.id;
- link.textContent = header.textContent;
- li.appendChild(link);
- var ul = document.createElement('ul');
- li.appendChild(ul);
- outline_ptr = ul;
-}
-
-function onExit(node) {
- outline_ptr = outline_ptr.parentNode.parentNode;
-}
-
-function outline(node) {
- var in_toc = !node.classList.contains('not_in_toc');
- if (in_toc) {
- onEnter(node);
- }
- var child = node.firstChild;
- while (child) {
- if (child.tagName === 'SECTION') {
- outline(child);
- }
- child = child.nextSibling;
- }
- if (in_toc) {
- onExit(node);
- }
-}
-
-
-window.onload = function () {
- outline_root = document.getElementById('outline');
- root = document.getElementById('root');
-
- var ul = document.createElement('ul');
- outline_root.appendChild(ul);
- outline_ptr = ul;
-
- outline(root);
-}; \ No newline at end of file
diff --git a/chromium/components/onc/docs/onc_spec.md b/chromium/components/onc/docs/onc_spec.md
new file mode 100644
index 00000000000..7729193aa98
--- /dev/null
+++ b/chromium/components/onc/docs/onc_spec.md
@@ -0,0 +1,1782 @@
+# Open Network Configuration
+
+[TOC]
+
+## Objective
+
+We would like to create a simple, open, but complete format to describe
+multiple network configurations for WiFi, Ethernet, Cellular,
+Bluetooth/WiFi-Direct, and VPN connections in a single file format, in order
+to simplify and automate network configuration for users.
+
+## Background
+
+Configuring networks is a painful and error-prone experience for users. It
+is a problem shared across desktop, laptop, tablet, and phone users of all
+operating system types. It is exacerbated in business and schools which
+often have complex network configurations (VPNs and 802.1X networking) that
+change often and have many connected devices. Configuration of WiFi is
+still done manually, often by administrators physically standing next to
+users working on devices. Certificate distribution is particularly painful
+which often results in admins instead using passphrases to protect networks
+or using protocols without client certificates that instead use LDAP
+passwords for authentication. Even after networks are configured, updates to
+the network configuration require another round of manual changes, and
+accidental changes by a user or malicious changes by an attacker can break
+connectivity or make connections less private or secure.
+
+## Overview
+
+We propose a single-file format for network configuration that is
+human-readable, can describe all of the common kinds of network
+configurations, supports integrity checking, certificate and key
+provisioning, and updating. The file can be encrypted with a single
+passphrase so that upon entering the passphrase the entire configuration is
+loaded. The format can be described as an open format to enable multiple OS
+vendors to interoperate and share configuration editors.
+
+This format neither supports configuring browser settings nor allows setting
+other types of system policies.
+
+## Infrastructure
+
+A standalone configuration editor will be created, downloadable as a Chrome
+app. This editor will allow creating, modifying, and encrypting an open
+network configuration file in a way that is intuitive for a system
+administrator.
+
+This file format may be delivered to a user and manually imported into a
+device.
+
+This file format may be created by an administrator, stored in a policy
+repository, and automatically pushed to a device.
+
+## Detailed Design
+
+We use JSON format for the files. The fields in a JSON file are always
+case-sensitive, so the exact case of the fields in this section must be
+matched. In addition, the values that are called out as explicit constants
+must also match the case specified (e.g. WiFi must not be written as wifi,
+etc.). This document describes a minimum set of required fields and optional
+fields. Other fields may be created, however, see the
+implementation-specific fields for guidelines for these fields.
+
+The JSON consists of a top level dictionary containing
+a `Type` field which must have either the value
+[EncryptedConfiguration](#EncryptedConfiguration-type) or
+[UnencryptedConfiguration](#UnencryptedConfiguration-type).
+
+For a description of the [EncryptedConfiguration](#EncryptedConfiguration-type)
+type, see the section on [Encrypted Configuration](#Encrypted-Configuration)
+below.
+The [EncryptedConfiguration](#Encrypted-Configuration) format encrypts
+an unencrypted JSON object.
+
+## GUIDs and Updating
+
+This format allows for importing updated network configurations and
+certificates by providing GUIDs to each network configuration and
+certificate so they can be modified or even removed in future updates.
+
+GUIDs are non-empty strings that are meant to be stable and unique. When
+they refer to the same entity, they should be the same between ONC files. No
+two different networks or certificates should have the same GUID, similarly
+a network and certificate should not have the same GUID. A single ONC file
+should not contain the same entity twice (with the same GUID). Failing any
+of these tests indicates the ONC file is not valid.
+
+Any GUID referred to in an ONC file must be present in the same ONC file. In
+particular, it is an error to create a certificate in one ONC file and refer
+to it in a NetworkConfiguration in another ONC file and not define it there,
+even if the previous ONC file has been imported.
+
+## Implementation-specific fields
+
+As there are many different kinds of connections and some that are not yet
+anticipated may require new fields. This format allows arbitrary other
+fields to be added.
+
+Fields and values should follow these general guidelines:
+
+* Certificates (with and without keys) should always be placed in the
+ certificate section - specifically certificate contents should not be
+ placed in fields directly. Referring to certificates should be done using
+ a field whose name ends in Ref and whose value is the GUID of the
+ certificate, or if the certificate is not contained in this file, its
+ pattern can be described using a field ending in Pattern of
+ [CertificatePattern](#CertificatePattern-type) type.
+* Fields should exist in the most-specific object in the hierarchy and
+ should be named CamelCase style.
+* Booleans and integers should be used directly instead of using a
+ stringified version of the type.
+
+Any editor of network configuration information should allows the user to
+modify any fields that are implementation-specific. It may not be present
+directly in the UI but it should be able to import files with such settings
+and leave preserve these settings on export.
+
+## Unencrypted Configuration
+
+When the top level **Type** field
+is *UnencryptedConfiguration*, the top level JSON
+has the [UnencryptedConfiguration](#UnencryptedConfiguration-type) type.
+
+### UnencryptedConfiguration type
+
+* **Type**
+ * (optional, defaults to *UnencryptedConfiguration*) - **string**
+ * Must be *UnencryptedConfiguration*.
+
+* **NetworkConfigurations**
+ * (optional) - [array of NetworkConfiguration](#Network-Configuration)
+ * Describes WiFi, Ethernet, VPN, and wireless connections.
+
+* **Certificates**
+ * (optional) - [array of Certificate](#Certificate-type)
+ * Contains certificates stored in X.509 or PKCS#12 format.
+
+---
+ * At least one actual configuration field
+ (**NetworkConfigurations** or **Certificates**) should be present,
+ however it should not be considered an error if no such field is present.
+---
+
+## Network Configuration
+
+Field **NetworkConfigurations** is an array of
+[NetworkConfiguration](#NetworkConfiguration-type) typed objects.
+
+### NetworkConfiguration type
+
+* **Ethernet**
+ * (required if **Type** is *Ethernet*, otherwise ignored) -
+ [Ethernet](#Ethernet-type)
+ * Ethernet settings.
+
+* **GUID**
+ * (required) - **string**
+ * A unique identifier for this network connection, which exists to make it
+ possible to update previously imported configurations. Must be a non-empty
+ string.
+
+* **IPAddressConfigType**
+ * (optional if **Remove** is *false*, otherwise ignored. Defaults to *DHCP*
+ if **NameServersConfigType** is specified) - **string**
+ * `Allowed values are` *DHCP* and *Static*.
+ * Determines whether the IP Address configuration is statically configured,
+ see **StaticIPConfig**, or automatically configured
+ using DHCP.
+
+* **NameServersConfigType**
+ * (optional if **Remove** is *false*, otherwise ignored. Defaults to *DHCP*
+ if **IPAddressConfigType** is specified) - **string**
+ * `Allowed values are` *DHCP* and *Static*.
+ * Determines whether the NameServers configuration is statically configured,
+ see **StaticIPConfig**, or automatically configured
+ using DHCP.
+
+* **IPConfigs**
+ * (optional for connected networks, read-only) -
+ [array of IPConfig](#IPConfig-type)
+ * Array of IPConfig properties associated with this connection.
+
+* **StaticIPConfig**
+ * (required if **IPAddressConfigType** or **NameServersConfigType** is set
+ to *Static*) - [IPConfig](#IPConfig-type)
+ * Each property set in this IPConfig object overrides the respective
+ parameter received over DHCP.
+ If **IPAddressConfigType** is set to
+ *Static*, **IPAddress**
+ and **Gateway** are required.
+ If **NameServersConfigType** is set to
+ *Static*, **NameServers**
+ is required.
+
+* **SavedIPConfig**
+ * (optional for connected networks, read-only) - [IPConfig](#IPConfig-type)
+ * IPConfig property containing the configuration that was received from the
+ DHCP server prior to applying any StaticIPConfig parameters.
+
+* **Name**
+ * (required if **Remove** is *false*, otherwise ignored) - **string**
+ * A user-friendly description of this connection. This name will not be used
+ for referencing and may not be unique. Instead it may be used for
+ describing the network to the user.
+
+* **Remove**
+ * (optional, defaults to *false*) - **boolean**
+ * If set, remove this network configuration (only GUID should be set).
+
+* **ProxySettings**
+ * (optional if **Remove** is *false*, otherwise ignored) -
+ [ProxySettings](#ProxySettings-type)
+ * Proxy settings for this network
+
+* **VPN**
+ * (required if **Type** is *VPN*, otherwise ignored) - [VPN](#VPN-type)
+ * VPN settings.
+
+* **WiFi**
+ * (required if **Type** is *WiFi*, otherwise ignored) - [WiFi](#WiFi-type)
+ * WiFi settings.
+
+* **WiMAX**
+ * (required if **Type** is *WiMAX*, otherwise ignored) -
+ [WiMAX](#WiMAX-type)
+ * WiMAX settings.
+
+* **Cellular**
+ * (required if **Type** is *Cellular*, otherwise ignored) -
+ [Cellular](#Cellular-type)
+ * Cellular settings.
+
+* **Type**
+ * (required if **Remove** is *false*, otherwise ignored) - **string**
+ * `Allowed values are` *Cellular*,
+ *Ethernet*, *WiFi*,
+ *WiMAX* and *VPN*.
+ * Indicates which kind of connection this is.
+
+* **ConnectionState**
+ * (optional, read-only) - **string**
+ * The current connection state for this network, provided by the system.
+ `Allowed values are`:
+ *Connected*,
+ *Connecting*,
+ *NotConnected*
+
+* **RestrictedConnectivity**
+ * (optional, defaults to *false*, read-only) - **boolean**
+ * True if a connnected network has limited connectivity to the Internet,
+ e.g. a connection is behind a portal or a cellular network is not
+ activated or requires payment.
+
+* **Connectable**
+ * (optional, read-only) - **boolean**
+ * True if the system indicates that the network can be connected to without
+ any additional configuration.
+
+* **ErrorState**
+ * (optional, read-only) - **string**
+ * The current error state for this network, if any. Error states are
+ provided by the system and are not explicitly defined here. They may or
+ may not be human-readable. This field will be empty or absent if the
+ network is not in an error state.
+
+* **MacAddress**
+ * (optional, read-only) - **string**
+ * The MAC address for the network. Only applies to connected non-virtual
+ networks. The format is 00:11:22:AA:BB:CC.
+
+* **Source**
+ * (optional, read-only) - **string**
+ * Indicates whether the network is configured and how it is configured:
+ * *User*: Configured for the active
+ user only, i.e. an unshared configuration.
+ * *Device*: Configured for all users of the
+ device (e.g laptop), i.e. a shared configuration.
+ * *UserPolicy*: Configured by the user
+ policy for the active user.
+ * *DevicePolicy*: Configured by the device
+ policy for the device.
+ * *None*: Not configured, e.g. a visible
+ but unconfigured WiFi network.
+ * `Allowed values are`:
+ *User*,
+ *Device*,
+ *UserPolicy*,
+ *DevicePolicy*,
+ *None*
+
+* **Priority**
+ * (optional) - **integer**
+ * Provides a suggested priority value for this network. May be used by the
+ system to determine which network to connect to when multiple configured
+ networks are available (or may be ignored).
+
+
+## Ethernet networks
+
+For Ethernet connections, **Type** must be set to
+*Ethernet* and the field **Ethernet** must be set to an object of
+type [Ethernet](#Ethernet-type).
+
+### Ethernet type
+
+* **Authentication**
+ * (optional) - **string**
+ * `Allowed values are` *None* and *8021X*.
+
+* **EAP**
+ * (required if **Authentication** is *8021X*, otherwise ignored) -
+ [EAP](#EAP-type)
+ * EAP settings.
+
+## IPConfig
+
+Objects of type [IPConfig](#IPConfig-type) are used to report the
+actual IP configuration of a connected network (see
+**IPConfigs**), the IP configuration received from
+DHCP (see **SavedIPConfig**) and to configure a
+static IP configuration (see **StaticIPConfig**).
+
+### IPConfig type
+
+* **Type**
+ * (required) - **string**
+ * `Allowed values are` *IPv4* and *IPv6*
+ * Describes the type of configuration this is.
+
+* **IPAddress**
+ * (optional) - **string**
+ * Describes the IPv4 or IPv6 address of a connection, depending on the value
+ of **Type** field. It should not contain the
+ routing prefix (i.e. should not end in something like /64).
+
+* **RoutingPrefix**
+ * (required if **IPAddress** is set. Otherwise ignored.) - **integer**
+ * `Must be a number in the range [1, 32] for IPv4 and [1, 128] for
+ IPv6 addresses.`
+ * Describes the routing prefix.
+
+* **Gateway**
+ * (required if **IPAddress** is set. Otherwise ignored.) - **string**
+ * Describes the gateway address to use for the configuration. Must match
+ address type specified in **Type** field. If not
+ specified, DHCP values will be used.
+
+* **NameServers**
+ * (optional) - **array of string**
+ * Array of addresses to use for name servers. Address format must match that
+ specified in the **Type** field. If not specified,
+ DHCP values will be used.
+
+* **SearchDomains**
+ * (optional) - **array of string**
+ * Array of strings to append to names for resolution. Items in this array
+ should not start with a dot. Example: `["corp.acme.org", "acme.org" ]`.
+ If not specified, DHCP values will be used.
+
+* **WebProxyAutoDiscoveryUrl**
+ * (optional if part of **IPConfigs**, read-only) - **string**
+ * The Web Proxy Auto-Discovery URL for this network as reported over DHCP.
+
+
+## WiFi networks
+
+For WiFi connections, **Type** must be set to *WiFi* and the
+field **WiFi** must be set to an object of type [WiFi](#WiFi-type).
+
+### WiFi type
+
+* **AllowGatewayARPPolling**
+ * (optional, defaults to *true*) - **boolean**
+ * Indicaties if ARP polling of default gateway is allowed.
+ When it is allowed, periodic ARP messages will be sent to
+ the default gateway. This is used for monitoring the status
+ of the current connection.
+
+* **AutoConnect**
+ * (optional, defaults to *false*) - **boolean**
+ * Indicating that the network should be connected to automatically when in
+ range.
+
+* **EAP**
+ * (required if **Security** is
+ *WEP-8021X* or *WPA-EAP*, otherwise ignored) - [EAP](#EAP-type)
+ * EAP settings.
+
+* **HexSSID**
+ * (optional if **SSID** is set, if so defaults to a hex representation of
+ **SSID**) - **string**
+ * Hex representation of the network's SSID.
+
+* **HiddenSSID**
+ * (optional, defaults to *false*) - **boolean**
+ * Indicating if the SSID will be broadcast.
+
+* **Passphrase**
+ * (required if **Security** is
+ *WEP-PSK* or *WPA-PSK*, otherwise ignored) - **string**
+ * Describes the passphrase for WEP/WPA/WPA2
+ connections. If *WEP-PSK* is used, the passphrase
+ must be of the format 0x&lt;hex-number&gt;, where &lt;hex-number&gt; is
+ 40, 104, 128, or 232 bits.
+
+* **RoamThreshold**
+ * (optional) - **integer**
+ * The roam threshold for this network, which is the signal-to-noise value
+ (in dB) below which we will attempt to roam to a new network. If this
+ value is not set, the default value will be used.
+
+* **Security**
+ * (required) - **string**
+ * `Allowed values are` *None*,
+ *WEP-PSK*,
+ *WEP-8021X*,
+ *WPA-PSK*, and
+ *WPA-EAP*.
+
+* **SSID**
+ * (optional if **HexSSID** is set, otherwise ignored) - **string**
+ * Property to access the decoded SSID of a network.<br/>
+ If this field is set, but **HexSSID** is not,
+ its value will be UTF-8 encoded and the hex representation will be
+ assigned to **HexSSID**. To configure a non-UTF-8
+ SSID, field **HexSSID** must be used.<br/>
+ When reading the configuration of a network, both this field and
+ **HexSSID** might be set. Then this field is the
+ decoding of **HexSSID**. If possible the HexSSID is
+ decoded using UTF-8, otherwise an encoding is guessed on a best effort
+ basis.
+
+* **SignalStrength**
+ * (optional, read-only) - **integer**
+ * The current signal strength for this network in the range [0, 100],
+ provided by the system. If the network is not in range this field will
+ be set to '0' or not present.
+
+---
+ * At least one of the fields **HexSSID** or **SSID** must be present.
+ * If both **HexSSID** and **SSID** are set, the values must be consistent.
+---
+
+## VPN networks
+
+There are many kinds of VPNs with widely varying configuration options. We
+offer standard configuration options for a few common configurations at this
+time, and may add more later. For all others, implementation specific fields
+should be used.
+
+For VPN connections, **Type** must be set to *VPN* and the
+field **VPN** must be set to an object of type [VPN](#VPN-type).
+
+### VPN type
+
+* **AutoConnect**
+ * (optional, defaults to *false*) - **boolean**
+ * Indicating that the network should be connected to automatically.
+
+* **Host**
+ * (optional) - **string**
+ * Host name or IP address of server to connect to. The only scenario that
+ does not require a host is a VPN that encrypts but does not tunnel
+ traffic. Standalone IPsec (v1 or v2, cert or PSK based -- this is not the
+ same as L2TP over IPsec) is one such setup. For all other types of VPN,
+ the **Host** field is required.
+
+* **IPsec**
+ * (required if **Type** is
+ *IPsec* or *L2TP-IPsec*, otherwise ignored) - [IPsec](#IPsec-type)
+ * IPsec layer settings.
+
+* **L2TP**
+ * (required if **Type** is *L2TP-IPsec*, otherwise ignored) -
+ [L2TP](#L2TP-type)
+ * L2TP layer settings.
+
+* **OpenVPN**
+ * (required if **Type** is *OpenVPN*, otherwise ignored) -
+ [OpenVPN](#OpenVPN-type)
+ * OpenVPN settings.
+
+* **ThirdPartyVPN**
+ * (required if **Type** is *ThirdPartyVPN*, otherwise ignored) -
+ [ThirdPartyVPN](#ThirdPartyVPN-type)
+ * Third-party VPN provider settings.
+
+* **Type**
+ * (required) - **string**
+ * `Allowed values are` *IPsec*,
+ *L2TP-IPsec*,
+ *OpenVPN*, and
+ *ThirdPartyVPN*.
+ * Type of the VPN.
+
+## IPsec-based VPN types
+
+### IPsec type
+
+* **AuthenticationType**
+ * (required) - **string**
+ * `Allowed values are` *PSK* and
+ *Cert*. If *Cert* is used, **ClientCertType** and *ServerCARefs* (or the
+ deprecated *ServerCARef*) must be set.
+
+* **ClientCertPattern**
+ * (required if **ClientCertType** is *Pattern*, otherwise ignored) -
+ [CertificatePattern](#CertificatePattern-type)
+ * Pattern describing the client certificate.
+
+* **ClientCertRef**
+ * (required if **ClientCertType** is *Ref*, otherwise ignored) - **string**
+ * Reference to client certificate stored in certificate section.
+
+* **ClientCertType**
+ * (required if **AuthenticationType** is *Cert*, otherwise ignored) -
+ **string**
+ * `Allowed values are` *Ref* and *Pattern*
+
+* **EAP**
+ * (optional if **IKEVersion** is 2, otherwise ignored) - [EAP](#EAP-type)
+ * Indicating that EAP authentication should be used with the provided
+ parameters.
+
+* **Group**
+ * (optional if **IKEVersion** is 1, otherwise ignored) - **string**
+ * Group name used for machine authentication.
+
+* **IKEVersion**
+ * (required) - **integer**
+ * Version of IKE protocol to use.
+
+* **PSK**
+ * (optional if **AuthenticationType** is *PSK*, otherwise ignored)
+ - **string**
+ * Pre-Shared Key. If not specified, user is prompted at time of
+ connection.
+
+* **SaveCredentials**
+ * (optional if **AuthenticationType**
+ is *PSK*, otherwise ignored, defaults to *false*) - **boolean**
+ * If *false*, require user to enter credentials
+ (PSK) each time they connect.
+
+* **ServerCARefs**
+ * (optional if **AuthenticationType** is *Cert*, otherwise rejected)
+ - **array of string**
+ * Non-empty list of references to CA certificates in **Certificates** to be
+ used for verifying the host's certificate chain. At least one of the CA
+ certificates must match. If this field is set, **ServerCARef** must be
+ unset.
+
+* **ServerCARef**
+ * (optional if **AuthenticationType** is *Cert*, otherwise rejected) -
+ **string**
+ * DEPRECATED, use **ServerCARefs** instead.<br/>
+ Reference to a CA certificate in **Certificates**. Certificate authority
+ to use for verifying connection. If this field is set, **ServerCARefs**
+ must be unset.
+
+* **XAUTH**
+ * (optional if **IKEVersion** is 1, otherwise ignored) -
+ [XAUTH](#XAUTH-type)
+ * Describing XAUTH credentials. XAUTH is not used if this object is not
+ present.
+
+---
+ * If **AuthenticationType** is set to *Cert*, *ServerCARefs* or *ServerCARef*
+ must be set.
+ * At most one of **ServerCARefs** and **ServerCARef** can be set
+---
+
+### L2TP type
+
+* **LcpEchoDisabled**
+ * (optional, defaults to *false*) - **boolean**
+ * Disable L2TP connection monitoring via PPP LCP frames. This
+ allows the VPN client to work around server implementations
+ that do not support the LCP echo feature.
+
+* **Password**
+ * (optional) - **string**
+ * User authentication password. If not specified, user is prompted at time
+ of connection.
+
+* **SaveCredentials**
+ * (optional, defaults to *false*) - **boolean**
+ * If *false*, require user to enter credentials
+ each time they connect.
+
+* **Username**
+ * (optional) - **string**
+ * User identity. This value is subject to string expansions. If not
+ specified, user is prompted at time of connection.
+
+### XAUTH type
+
+* **Password**
+ * (optional) - **string**
+ * XAUTH password. If not specified, user is prompted at time of
+ connection.
+
+* **SaveCredentials**
+ * (optional, defaults to *false*) - **boolean**
+ * If *false*, require user to enter credentials
+ each time they connect.
+
+* **Username**
+ * (optional) - **string**
+ * XAUTH user name. This value is subject to string expansions. If not
+ specified, user is prompted at time of connection.
+
+## IPsec IKE v1 VPN connections
+
+**VPN.Type** must
+be *IPsec*, **IKEVersion**
+must be 1. Do not use this for L2TP over IPsec. This may be used for
+machine-authentication-only IKEv1 or for IKEv1 with XAUTH. See
+the [IPsec](#IPsec-type) type described below.
+
+## IPsec IKE v2 VPN connections
+
+**VPN.Type** must
+be *IPsec*, **IKEVersion**
+must be 2. This may be used with EAP-based user authentication.
+
+## L2TP over IPsec VPN connections
+
+There are two major configurations L2TP over IPsec which depend on how IPsec
+is authenticated. In either case **Type** must be
+*L2TP-IPsec*. They are described below.
+
+L2TP over IPsec with pre-shared key:
+
+* The field **IPsec** must be present and have the
+ following settings:
+ * **IKEVersion** must be 1.
+ * **AuthenticationType** must be PSK.
+ * **XAUTH** must not be set.
+
+* The field **L2TP** must be present.
+
+
+## OpenVPN connections and types
+
+**VPN.Type** must be *OpenVPN*.
+
+### OpenVPN type
+
+* **Auth**
+ * (optional, defaults to *SHA1*) - **string**
+
+* **AuthRetry**
+ * (optional, defaults to *none*) - **string**
+ * `Allowed values are none, nointeract, and interact`:
+ * *none* = Fail with error on retry
+ * *nointeract* = retry without asking for authentication
+ * *interact* = ask again for authentication each time
+ * Controls how OpenVPN responds to username/password verification failure.
+
+* **AuthNoCache**
+ * (optional, defaults to *false*) - **boolean**
+ * Disable caching of credentials in memory.
+
+* **Cipher**
+ * (optional, defaults to *BF-CBC*) - **string**
+ * Cipher to use.
+
+* **ClientCertRef**
+ * (required if **ClientCertType** is *Ref*, otherwise ignored) - **string**
+ * Reference to client certificate stored in certificate section.
+
+* **ClientCertPattern**
+ * (required if **ClientCertType** is *Pattern*, otherwise ignored) -
+ [CertificatePattern](#CertificatePattern-type)
+ * Pattern to use to find the client certificate.
+
+* **ClientCertType**
+ * (required) - **string**
+ * `Allowed values are` *Ref*, *Pattern*, and *None*.
+ * *None* implies that the server is configured to
+ not require client certificates.
+
+* **CompLZO**
+ * (optional, defaults to *adaptive*) - **string**
+ * Decides to fast LZO compression with *true*
+ and *false* as other values.
+
+* **CompNoAdapt**
+ * (optional, defaults to *false*) - **boolean**
+ * Disables adaptive compression.
+
+* **IgnoreDefaultRoute**
+ * (optional, defaults to *false*) - **boolean**
+ * Omits a default route to the VPN gateway while the connection is active.
+ By default, the client creates a default route to the gateway address
+ advertised by the VPN server. Setting this value to
+ *true* will allow split tunnelling for
+ configurations where the VPN server omits explicit default routes.
+ This is roughly equivalent to omitting "redirect-gateway" OpenVPN client
+ configuration option. If the server pushes a "redirect-gateway"
+ configuration flag to the client, this option is ignored.
+
+* **KeyDirection**
+ * (optional) - **string**
+ * Passed as --key-direction.
+
+* **NsCertType**
+ * (optional) - **string**
+ * If set, checks peer certificate type. Should only be set
+ to *server* if set.
+
+* **OTP**
+ * (optional if **UserAuthenticationType** is *OTP*, *PasswordAndOTP* or
+ unset, otherwise ignored, defaults to empty string) - **string**
+ * If **UserAuthenticationType** is
+ *OTP* or *PasswordAndOTP*
+ and this field is not set, the user will be asked for an OTP.
+ The OTP is never persisted and must be provided on every connection
+ attempt.
+
+* **Password**
+ * (optional if **UserAuthenticationType** is *Password*, *PasswordAndOTP*
+ or unset, otherwise ignored, defaults to empty string) - **string**
+ * If **UserAuthenticationType** is
+ *Password* or
+ *PasswordAndOTP* and this field is not set, the user
+ will be asked for a password.
+ If **SaveCredentials** is
+ *true*, the password is persisted for future
+ connection attempts. Otherwise it is not persisted but might still be
+ reused for consecutive connection attempts (opposed to an OTP, which will
+ never be reused).
+
+* **Port**
+ * (optional, defaults to *1194*) - **integer**
+ * Port for connecting to server.
+
+* **Proto**
+ * (optional, defaults to *udp*) - **string**
+ * Protocol for communicating with server.
+
+* **PushPeerInfo**
+ * (optional, defaults to *false*) - **boolean**
+
+* **RemoteCertEKU**
+ * (optional) - **string**
+ * Require that the peer certificate was signed with this explicit extended
+ key usage in oid notation.
+
+* **RemoteCertKU**
+ * (optional, defaults to []) - **array of string**
+ * Require the given array of key usage numbers. These are strings that are
+ hex encoded numbers.
+
+* **RemoteCertTLS**
+ * (optional, defaults to *server*) - **string**
+ * `Allowed values are` *none* and *server*.
+ * Require peer certificate signing based on RFC3280 TLS rules.
+
+* **RenegSec**
+ * (optional, defaults to *3600*) - **integer**
+ * Renegotiate data channel key after this number of seconds.
+
+* **SaveCredentials**
+ * (optional, defaults to *false*) - **boolean**
+ * If *false*, require user to enter credentials
+ each time they connect.
+
+* **ServerCARefs**
+ * (optional) - **array of string**
+ * Non-empty list of references to CA certificates in **Certificates** to be
+ used for verifying the host's certificate chain. At least one of the CA
+ certificates must match. See also OpenVPN's command line option "--ca".
+ If this field is set, **ServerCARef** must be unset.
+
+* **ServerCARef**
+ * (optional) - **string**
+ * DEPRECATED, use **ServerCARefs** instead.<br/>
+ Reference to a CA certificate in **Certificates**. Certificate authority
+ to use for verifying connection. If this field is set, **ServerCARefs**
+ must be unset.
+
+* **ServerCertRef**
+ * (optional) - **string**
+ * Reference to a certificate. Peer's signed certificate.
+
+* **ServerPollTimeout**
+ * (optional) - **integer**
+ * Spend no more than this number of seconds before trying the next server.
+
+* **Shaper**
+ * (optional) - **integer**
+ * If not specified no bandwidth limiting, otherwise limit bandwidth of
+ outgoing tunnel data to this number of bytes per second.
+
+* **StaticChallenge**
+ * (optional) - **string**
+ * String is used in static challenge response. Note that echoing is always
+ done.
+
+* **TLSAuthContents**
+ * (optional) - **string**
+ * If not set, tls auth is not used. If set, this is the TLS Auth key
+ contents (usually starts with "-----BEGIN OpenVPN Static Key..."
+
+* **TLSRemote**
+ * (optional) - **string**
+ * If set, only allow connections to server hosts with X509 name or common
+ name equal to this string.
+
+* **UserAuthenticationType**
+ * (optional, defaults to *None*) - **string**
+ * `Allowed values are` *None*,
+ *Password*,
+ *PasswordAndOTP* and
+ *OTP*.
+ * Determines the required form of user authentication:
+ * *PasswordAndOTP*: This VPN requires a password
+ and an OTP (possibly empty). Both will be send to the server in the
+ 'password' response using the SCRv1 encoding.
+ * *Password*: This VPN requires only a password,
+ which will be send without modification to the server in the 'password'
+ response (no CRv1 or SCRv1 encoding).
+ * *OTP*: This VPN requires only an OTP, which
+ will be send without modification to the server in the 'password'
+ response (no CRv1 or SCRv1 encoding).
+ * *None*: Neither password nor OTP are required.
+ No password request from the server is expected.
+ If not set, the user can provide a password and an OTP (both not
+ mandatory) and the network manager will send both in the SCRv1 encoding,
+ when the server sends a static-challenge. If the server does not send a
+ static-challenge, the client will reply with only the password (without
+ any encoding). This behavior is deprecated and new configurations should
+ explicitly set one of the above values.
+
+ See the fields **Password** and
+ **OTP** for configuring the password and OTP.
+
+* **Username**
+ * (optional) - **string**
+ * OpenVPN user name. This value is subject to string expansions. If not
+ specified, user is prompted at time of connection.
+
+* **Verb**
+ * (optional) - **string**
+ * Verbosity level, defaults to OpenVpn's default if not specified.
+
+* **VerifyHash**
+ * (optional) - **string**
+ * If set, this value is passed as the "--verify-hash" argument to OpenVPN,
+ which specifies the SHA1 fingerprint for the level-1 certificate.
+
+* **VerifyX509**
+ * (optional) - [VerifyX509](#VerifyX509-type)
+ * If set, the "--verify-x509-name" argument is passed to OpenVPN with the
+ values of this object and only connections will be accepted if a host's
+ X.509 name is equal to the given name.
+
+---
+ * At most one of **ServerCARefs** and **ServerCARef**
+ can be set.
+---
+
+### VerifyX509 type
+
+* **Name**
+ * (required) - **string**
+ * The name that the host's X.509 name is compared to. Which host name is
+ compared depends on the value of **Type**.
+
+* **Type**
+ * (optional) - **string**
+ * Determines which of the host's X.509 names will be verified.
+ * `Allowed values are` *name*, *name-prefix* and *subject*.
+ See OpenVPN's documentation for "--verify-x509-name" for the meaning of
+ each value. Defaults to OpenVPN's default if not specified.
+
+## Third-party VPN provider based connections and types
+
+**VPN.Type** must be *ThirdPartyVPN*.
+
+### ThirdPartyVPN type
+
+* **ExtensionID**
+ * (required) - **string**
+ * The extension ID of the third-party VPN provider used by this network.
+* **ProviderName**
+ * (optional, read-only) - **string**
+ * The name of the third-party VPN provider used by this network.
+
+
+## Client certificate patterns
+
+In order to allow clients to securely key their private keys and request
+certificates through PKCS#10 format or through a web flow, we provide
+alternative CertificatePattern types. The
+
+### CertificatePattern type
+
+* **IssuerCARef**
+ * (optional) - **array of string**
+ * Array of references to certificates. At least one must have signed the
+ client certificate.
+
+* **Issuer**
+ * (optional) - [IssuerSubjectPattern](#IssuerSubjectPattern-type)
+ * Pattern to match the issuer X.509 settings against. If not specified, the
+ only checks done will be a signature check against
+ the **IssuerCARef** field. Issuer of the
+ certificate must match this field exactly to match the pattern.
+
+* **Subject**
+ * (optional) - [IssuerSubjectPattern](#IssuerSubjectPattern-type)
+ * Pattern to match the subject X.509 settings against. If not specified, the
+ subject settings are not checked and any certificate matches. Subject of
+ the certificate must match this field exactly to match the pattern.
+
+* **EnrollmentURI**
+ * (optional) - **array of string**
+ * If no certificate matches this CertificatePattern, the first URI from this
+ array with a recognized scheme is navigated to, with the intention this
+ informs the user how to either get the certificate or gets the certificate
+ for the user. For instance, the array may be [
+ "chrome-extension://asakgksjssjwwkeielsjs/fetch-client-cert.html",
+ "http://intra/connecting-to-wireless.html" ] so that for Chrome browsers a
+ Chrome app or extension is shown to the user, but for other browsers, a
+ web URL is shown.
+
+### IssuerSubjectPattern type
+
+* **CommonName**
+ * (optional) - **string**
+ * Certificate subject's commonName must match this string if present.
+
+* **Locality**
+ * (optional) - **string**
+ * Certificate subject's location must match this string if present.
+
+* **Organization**
+ * (optional) - **string**
+ * At least one of certificate subject's organizations must match this string
+ if present.
+
+* **OrganizationalUnit**
+ * (optional) - **string**
+ * At least one of certificate subject's organizational units must match this
+ string if present.
+
+---
+ * One field in **Subject**, **Issuer**, or **IssuerCARef**
+ must be given for a [CertificatePattern](#CertificatePattern-type) typed
+ field to be valid.
+ * For a certificate to be considered matching, it must match all
+ the fields in the certificate pattern. If multiple certificates match, the
+ certificate with the latest issue date that is still in the past, and
+ hence valid, will be used.
+ * If **EnrollmentURI** is not given and no match is
+ found to this pattern, the importing tool may show an error to the user.
+---
+
+## Proxy settings
+
+Every network can be configured to use a proxy.
+
+### ProxySettings type
+
+* **Type**
+ * (required) - **string**
+ * `Allowed values are` *Direct*,
+ *Manual*, *PAC*, and *WPAD*.
+ * *PAC* indicates Proxy Auto-Configuration.
+ *WPAD* indicates Web Proxy Autodiscovery.
+
+* **Manual**
+ * (required if **Type** is *Manual*, otherwise ignored) -
+ [ManualProxySettings](#ManualProxySettings-type)
+ * Manual proxy settings.
+
+* **ExcludeDomains**
+ * (optional if **Type** is *Manual*, otherwise ignored) -
+ **array of string**
+ * Domains and hosts for which to exclude proxy settings.
+
+* **PAC**
+ * (required if **Type** is *PAC*, otherwise ignored) - **string**
+ * URL of proxy auto-config file.
+
+### ManualProxySettings type
+
+* **HTTPProxy**
+ * (optional) - [ProxyLocation](#ProxyLocation-type)
+ * settings for HTTP proxy.
+
+* **SecureHTTPProxy**
+ * (optional) - [ProxyLocation](#ProxyLocation-type)
+ * settings for secure HTTP proxy.
+
+* **FTPProxy**
+ * (optional) - [ProxyLocation](#ProxyLocation-type)
+ * settings for FTP proxy
+
+* **SOCKS**
+ * (optional) - [ProxyLocation](#ProxyLocation-type)
+ * settings for SOCKS proxy.
+
+### ProxyLocation type
+
+* **Host**
+ * (required) - **string**
+ * Host (or IP address) to use for proxy
+
+* **Port**
+ * (required) - **integer**
+ * Port to use for proxy
+
+## EAP configurations
+
+For networks with 802.1X authentication, an [EAP](#EAP-type)
+type exists to configure the authentication.
+
+### EAP type
+
+* **AnonymousIdentity**
+ * (optional if **Outer** is
+ *PEAP* or *EAP-TTLS*, otherwise ignored) - **string**
+ * For tunnelling protocols only, this indicates the identity of the user
+ presented to the outer protocol. This value is subject to string
+ expansions. If not specified, use empty string.
+
+* **ClientCertPattern**
+ * (required if **ClientCertType** is *Pattern*, otherwise ignored) -
+ [CertificatePattern](#CertificatePattern-type)
+ * Pattern to use to find the client certificate.
+
+* **ClientCertRef**
+ * (required if **ClientCertType** is *Ref*, otherwise ignored) - **string**
+ * Reference to client certificate stored in certificate section.
+
+* **ClientCertType**
+ * (optional) **string**
+ `Allowed values are` *Ref*, and *Pattern*.
+
+* **Identity**
+ * (optional) - **string**
+ * Identity of user. For tunneling outer protocols
+ (*PEAP*, *EAP-TTLS*, and
+ *EAP-FAST*), this is used to authenticate inside
+ the tunnel, and **AnonymousIdentity** is used for
+ the EAP identity outside the tunnel. For non-tunneling outer protocols,
+ this is used for the EAP identity. This value is subject to string
+ expansions.
+
+* **Inner**
+ * (optional if **Outer** is
+ *EAP-FAST*, *EAP-TTLS*
+ or *PEAP*, otherwise ignored, defaults to *Automatic*) - **string**
+ * `Allowed values are` *Automatic*,
+ *MD5*, *MSCHAPv2*,
+ *EAP-MSCHAPv2*,
+ *PAP*, and *GTC*.
+ * For tunneling outer protocols.
+
+* **Outer**
+ * (required) - **string**
+ * `Allowed values are` *LEAP*,
+ *EAP-AKA*, *EAP-FAST*,
+ *EAP-TLS*, *EAP-TTLS*,
+ *EAP-SIM* and *PEAP*.
+
+* **Password**
+ * (optional) - **string**
+ * Password of user. If not specified, defaults to prompting the user.
+
+* **SaveCredentials**
+ * (optional, defaults to *false*) - **boolean**
+ * If *false*, require user to enter credentials
+ each time they connect. Specifying **Identity**
+ and/or **Password** when
+ **SaveCredentials** is
+ *false* is not allowed.
+
+* **ServerCAPEMs**
+ * (optional) - **array of string**
+ * Non-empty list of CA certificates in PEM format, If this field is set,
+ **ServerCARef** and **ServerCARefs** must be unset.
+
+* **ServerCARefs**
+ * (optional) - **array of string**
+ * Non-empty list of references to CA certificates in **Certificates** to be
+ used for verifying the host's certificate chain. At least one of the CA
+ certificates must match. If this field is set, **ServerCARef** must be
+ unset. If neither **ServerCARefs** nor **ServerCARef** is set, the client
+ does not check that the server certificate is signed by a specific CA.
+ A verification using the system's CA certificates may still apply.
+ See **UseSystemCAs** for this.
+
+* **ServerCARef**
+ * (optional) - **string**
+ * DEPRECATED, use **ServerCARefs** instead.<br/>
+ Reference to a CA certificate in **Certificates**.
+ * If this field is set, **ServerCARefs** must be unset.
+ If neither **ServerCARefs** nor **ServerCARef** is set, the client does
+ not check that the server certificate is signed by a specific CA.
+ A verification using the system's CA certificates may still apply.
+ See **UseSystemCAs** for this.
+
+* **UseSystemCAs**
+ * (optional, defaults to *true*) - **boolean**
+ * Required server certificate to be signed by "system default certificate
+ authorities". If both **ServerCARefs** (or **ServerCARef**)
+ and **UseSystemCAs** are supplied, a server
+ certificate will be allowed if it either has a chain of trust to a system
+ CA or to one of the given CA certificates. If **UseSystemCAs**
+ is *false*, and no **ServerCARef** is set, the certificate
+ must be a self signed certificate, and no CA signature is required.
+
+* **UseProactiveKeyCaching**
+ * (optional, defaults to *false*) - **boolean**
+ * Indicates whether Proactive Key Caching (also known as Opportunistic
+ Key Caching) should be used on a per-service basis.
+
+---
+ * At most one of **ServerCARefs** and **ServerCARef**
+ can be set.
+---
+
+## WiMAX Networks
+
+For WiMAX connections, **Type** must be set to
+*WiMAX* and the field **WiMAX** must be set to an object of
+type [WiMAX](#WiMAX-type).
+
+Currently only used for representing an existing configuration;
+ONC configuration of of **WiMAX** networks is not yet fully supported.
+
+### WiMAX type
+
+* **AutoConnect**
+ * (optional, defaults to *false*) - **boolean**
+ * Indicating that the network should be connected to automatically when
+ possible.
+
+* **EAP**
+ * (required) - [EAP](#EAP-type)
+ * EAP settings.
+
+* **SignalStrength**
+ * (optional, read-only) - **integer**
+ * The current signal strength for this network in the range [0, 100],
+ provided by the system. If the network is not in range this field will
+ be set to '0' or not present.
+
+
+## Cellular Networks
+
+For Cellular connections, **Type** must be set to *Cellular* and the
+field **Cellular** must be set to an object of type [Cellular](#Cellular-type).
+
+Currently only used for representing an existing configuration;
+ONC configuration of of **Cellular** networks is not yet supported.
+
+### Cellular type
+
+* **AutoConnect**
+ * (optional, defaults to *false*) - **boolean**
+ * Indicating that the network should be connected to automatically when
+ possible. Note, that disabled **AllowRoaming**
+ takes precedence over autoconnect.
+
+* **APN**
+ * (optional) - [APN](#APN-type)
+ * Currently active [APN](#APN-type) object to be used with a
+ GSM carrier for making data connections.
+
+* **APNList**
+ * (optional) - [array of APN](#APN-type)
+ * List of available APN configurations.
+
+* **ActivationType**
+ * (optional) - **string**
+ * Activation type.
+
+* **ActivationState**
+ * (optional, read-only) - **string**
+ * Carrier account activation state.
+ * `Allowed values are`
+ *Activated*,
+ *Activating*,
+ *NotActivated*,
+ *PartiallyActivated*
+
+* **AllowRoaming**
+ * (optional) - **boolean**
+ * Whether cellular data connections are allowed when the device is roaming.
+
+* **Carrier**
+ * (optional, read-only) - **string**
+ * The name of the carrier for which the device is configured.
+
+* **ESN**
+ * (optional, read-only) - **string**
+ * The Electronic Serial Number of the cellular modem.
+
+* **Family**
+ * (optional, read-only) - **string**
+ * Technology family.
+ * `Allowed values are`
+ *CDMA*,
+ *GSM*
+
+* **FirmwareRevision**
+ * (optional, read-only) - **string**
+ * The revision of firmware that is loaded in the modem.
+
+* **FoundNetworks**
+ * (optional, read-only, provided only if **Family** is *GSM*) -
+ [array of FoundNetwork](#FoundNetwork-type)
+ * The list of cellular netwoks found in the most recent scan operation.
+
+* **HardwareRevision**
+ * (optional, read-only) - **string**
+ * The hardware revision of the cellular modem.
+
+* **HomeProvider**
+ * (optional, read-only) - [CellularProvider](#CellularProvider-type)
+ * Description of the operator that issued the SIM card currently installed
+ in the modem.
+
+* **ICCID**
+ * (optional, read-only, provided only if **Family** is *GSM*
+ or **NetworkTechnology**
+ is *LTE*) - **string**
+ * For GSM / LTE modems, the Integrated Circuit Card Identifer of the SIM
+ card installed in the device.
+
+* **IMEI**
+ * (optional, read-only) - **string**
+ * The International Mobile Equipment Identity of the cellular modem.
+
+* **IMSI**
+ * (optional, read-only, provided only if **Family** is *GSM*) - **string**
+ * For GSM modems, the International Mobile Subscriber Identity of the SIM
+ card installed in the device.
+
+* **LastGoodAPN**
+ * (optional, read-only) - [APN](#APN-type)
+ * The APN information used in the last successful connection attempt.
+
+* **Manufacturer**
+ * (optional, read-only) - **string**
+ * The manufacturer of the cellular modem.
+
+* **MDN**
+ * (optional) - **string**
+ * The Mobile Directory Number (i.e., phone number) of the device.
+
+* **MEID**
+ * (optional, read-only, provided only if **Family** is *CDMA*) - **string**
+ * For CDMA modems, the Mobile Equipment Identifer of the cellular modem.
+
+* **MIN**
+ * (optional, read-only) - **string**
+ * The Mobile Identification Number of the device.
+
+* **ModelID**
+ * (optional, read-only) - **string**
+ * The hardware model of the cellular modem.
+
+* **NetworkTechnology**
+ * (optional, read-only) - **string**
+ * If the modem is registered on a network, then this is set to the
+ network technology currently in use.
+ * `Allowed values are`
+ *CDMA1XRTT*,
+ *EDGE*,
+ *EVDO*,
+ *GPRS*,
+ *GSM*,
+ *HSPA*,
+ *HSPAPlus*,
+ *LTE*,
+ *LTEAdvanced*
+ *UMTS*,
+
+* **PaymentPortal**
+ * (optional, read-only) - [PaymentPortal](#PaymentPortal-type)
+ * Properties describing the online payment portal (OLP) at which a user can
+ sign up for or modify a mobile data plan.
+
+* **PRLVersion**
+ * (optional, read-only) - **integer**
+ * The revision of the Preferred Roaming List that is loaded in the modem.
+
+* **RoamingState**
+ * (optional, read-only) - **string**
+ * The roaming status of the cellular modem on the current network.
+ * `Allowed values are` *Home*,
+ *Roaming*, or if the provider has no home network, *Required*.
+
+* **ServingOperator**
+ * (optional, read-only, provided only if **Family** is *GSM*) -
+ [CellularProvider](#CellularProvider-type)
+ * Description of the operator on whose network the modem is currently
+ registered
+
+* **SignalStrength**
+ * (optional, read-only) - **integer**
+ * The current signal strength for this network in the range [0, 100],
+ provided by the system. If the network is not in range this field will
+ be set to '0' or not present.
+
+* **SIMLockStatus**
+ * (optional, read-only, provided only if **Family** is *GSM*) -
+ [SIMLockStatus](#SIMLockStatus-type)
+ * For GSM modems, a dictionary containing two properties describing the
+ state of the SIM card lock.
+
+* **SIMPresent**
+ * (optional, read-only, provided only if **Family** is *GSM*
+ or **NetworkTechnology**
+ is *LTE*) - **boolean**
+ * For GSM or LTE modems, indicates whether a SIM card is present or not.
+
+* **SupportNetworkScan**
+ * (optional, read-only) - **boolean**
+ * True if the cellular network supports scanning.
+
+* **SupportedCarriers**
+ * (optional, read-only) - **array of string**
+ * A list of supported carriers.
+
+
+### APN type
+
+* **AccessPointName**
+ * (required) - **string**
+ * The access point name used when making connections.
+
+* **Name**
+ * (optional) - **string**
+ * Description of the APN.
+
+* **LocalizedName**
+ * (optional) - **string**
+ * Localized description of the APN.
+
+* **Username**
+ * (optional) - **string**
+ * Username for making connections if required.
+
+* **Password**
+ * (optional) - **string**
+ * Password for making connections if required.
+
+* **Language**
+ * (optional, rquired if **LocalizedName** is provided) - **string**
+ Two letter language code for Localizedname if provided.
+
+### FoundNetwork type
+
+* **Status**
+ * (required) - **string**
+ * The availability of the network.
+
+* **NetworkId**
+ * (required) - **string**
+ * The network id in the form MCC/MNC (without the '/').
+
+* **Technology**
+ * (required) - **string**
+ * Access technology used by the network,
+ e.g. "GSM", "UMTS", "EDGE", "HSPA", etc.
+
+* **ShortName**
+ * (optional) - **string**
+ * Short-format name of the network operator.
+
+* **LongName**
+ * (optional) - **string**
+ * Long-format name of the network operator.
+
+### PaymentPortal type
+
+* **Method**
+ * (required) - **string**
+ * The HTTP method to use, "GET" or "POST"
+
+* **PostData**
+ * (required if **Method** is *POST*, otherwise ignored) - **string**
+ * The postdata to send.
+
+* **Url**
+ * (required) - **string**
+ * The URL for the portal.
+
+### CellularProvider type
+
+* **Name**
+ * (required) - **string**
+ * The operator name.
+
+* **Code**
+ * (required) - **string**
+ * The network id in the form MCC/MNC (without the '/').
+
+* **Country**
+ * (optional) - **string**
+ * The two-letter country code.
+
+### SIMLockStatus type
+
+* **LockType**
+ * (required) - **string**
+ * Specifies the type of lock in effect, or an empty string if unlocked.
+ * `Allowed values are`
+ *sim-pin*,
+ *sim-puk*
+
+* **LockEnabled**
+ * (required) - **boolean**
+ * Indicates whether SIM locking is enabled
+
+* **RetriesLeft**
+ * (optional) - **integer**
+ * If **LockType** is empty
+ or *sim-pin*, then this property represents
+ the number of attempts remaining to supply a correct PIN before the
+ PIN becomes blocked, at which point a PUK provided by the carrier would
+ be necessary to unlock the SIM (and **LockType**
+ changes to *sim-puk*).
+
+
+## Bluetooth / WiFi Direct Networks
+
+This format will eventually also cover configuration of Bluetooth and WiFi
+Direct network technologies, however they are currently not supported.
+
+
+## Certificates
+
+Certificate data is stored in a separate section. Each certificate may be
+referenced from within the NetworkConfigurations array using a certificate
+reference. A certificate reference is its GUID.
+
+The top-level field **Certificates** is an array of
+objects of [Certificate](#Certificate-type) type.
+
+### Certificate type
+
+* **GUID**
+ * (required) - **string**
+ * A unique identifier for this certificate. Must be a non-empty string.
+
+* **PKCS12**
+ * (required if **Type** is
+ *Client*, otherwise ignored) - **string**
+ * For certificates with
+ private keys, this is the base64 encoding of the a PKCS#12 file.
+
+* **Remove**
+ * (optional, defaults to *false*) - **boolean**
+ * If *true*, remove this certificate (only GUID
+ should be set).
+
+* **TrustBits**
+ * (optional if **Type**
+ is *Server*
+ or *Authority*, otherwise ignored, defaults to []) - **array of string**
+ * An array of trust flags. Clients should ignore unknown flags. For
+ backwards compatibility, each flag should only increase the trust and
+ never restrict. The trust flag *Web* implies that
+ the certificate is to be trusted for HTTPS SSL identification. A typical
+ web certificate authority would have **Type** set
+ to *Authority* and **TrustBits** set to `["Web"]`
+
+* **Type**
+ * (required if **Remove** is *false*, otherwise ignored) - **string**
+ * `Allowed values are` *Client*,
+ *Server*, and
+ *Authority*.
+ * *Client* indicates the certificate is for
+ identifying the user or device over HTTPS or for
+ VPN/802.1X. *Server* indicates the certificate
+ identifies an HTTPS or VPN/802.1X peer.
+ *Authority* indicates the certificate is a
+ certificate authority and any certificates it issues should be
+ trusted. Note that if **Type** disagrees with the
+ x509 v3 basic constraints or key usage attributes, the
+ **Type** field should be honored.
+
+* **X509**
+ * (required if **Type** is
+ *Server* or *Authority*, otherwise ignored) - **string**
+ * For certificate
+ without private keys, this is the X509 certificate in PEM format.
+
+ The passphrase of the PKCS#12 encoding must be empty. Encryption of key data
+ should be handled at the level of the entire file, or the transport of the
+ file.
+
+ If a global-scoped network connection refers to a user-scoped certificate,
+ results are undefined, so this configuration should be prohibited by the
+ configuration editor.
+
+
+## Encrypted Configuration
+
+We assume that when this format is imported as part of policy that
+file-level encryption will not be necessary because the policy transport is
+already encrypted, but when it is imported as a standalone file, it is
+desirable to encrypt it. Since this file has private information (user
+names) and secrets (passphrases and private keys) in it, and we want it to
+be usable as a manual way to distribute network configuration, we must
+support encryption.
+
+For this standalone export, the entire file will be encrypted in a symmetric
+fashion with a passphrase stretched using salted PBKDF2 using at least 20000
+iterations, and encrypted using an AES-256 CBC mode cipher with an SHA-1
+HMAC on the ciphertext.
+
+An encrypted ONC file's top level object will have the
+[EncryptedConfiguration](#EncryptedConfiguration-type) type.
+
+### EncryptedConfiguration type
+
+* **Cipher**
+ * (required) - **string**
+ * The type of cipher used. Currently only *AES256*
+ is supported.
+
+* **Ciphertext**
+ * (required) - **string**
+ * The raw ciphertext of the encrypted ONC file, base64 encoded.
+
+* **HMAC**
+ * (required) - **string**
+ * The HMAC for the ciphertext, base64 encoded.
+
+* **HMACMethod**
+ * (required) - **string**
+ * The method used to compute the Hash-based Message Authentication Code
+ (HMAC). Currently only *SHA1* is supported.
+
+* **Salt**
+ * (required) - **string**
+ * The salt value used during key stretching.
+
+* **Stretch**
+ * (required) - **string**
+ * The key stretching algorithm used. Currently
+ only *PBKDF2* is supported.
+
+* **Iterations**
+ * (required) - **integer**
+ * The number of iterations to use during key stretching.
+
+* **IV**
+ * (required) - **string**
+ * The initial vector (IV) used for Cyclic Block Cipher (CBC) mode, base64
+ encoded.
+
+* **Type**
+ * (required) - **string**
+ * The type of the ONC file, which must be set
+ to *EncryptedConfiguration*.
+
+---
+ * When decrypted, the ciphertext must contain a JSON object of
+ type [UnencryptedConfiguration](#UnencryptedConfiguration-type).
+---
+
+## String Expansions
+
+The values of some fields, such
+as **WiFi.EAP.Identity**
+and **VPN.*.Username**, are subject to string
+expansions. These allow one ONC to have basic user-specific variations.
+
+### The expansions are:
+
+* ${LOGIN_ID} - expands to the email address of the user, but before the '@'.
+
+* ${LOGIN_EMAIL} - expands to the email address of the user.
+
+### The following SED would properly handle resolution.
+
+* s/\$\{LOGIN_ID\}/bobquail$1/g
+
+* s/\$\{LOGIN_EMAIL\}/bobquail@example.com$1/g
+
+### Example expansions, assuming the user was bobquail@example.com:
+
+* "${LOGIN_ID}" -> "bobquail"
+
+* "${LOGIN_ID}@corp.example.com" -> "bobquail@corp.example.com"
+
+* "${LOGIN_EMAIL}" -> "bobquail@example.com"
+
+* "${LOGIN_ID}X" -> "bobquailX"
+
+* "${LOGIN_IDX}" -> "${LOGIN_IDX}"
+
+* "X${LOGIN_ID}" -> "Xbobquail"
+
+## Detection
+
+This format should be sent in files ending in the .onc extension. When
+transmitted with a MIME type, the MIME type should be
+application/x-onc. These two methods make detection of data to be handled in
+this format, especially when encryption is used and the payload itself is
+not detectable.
+
+
+## Alternatives considered
+
+For the overall format, we considered XML, ASN.1, and protobufs. JSON and
+ASN.1 seem more widely known than protobufs. Since administrators are
+likely to want to tweak settings that will not exist in common UIs, we
+should provide a format that is well known and human modifiable. ASN.1 is
+not human modifiable. Protobufs formats are known by open source developers
+but seem less likely to be known by administrators. JSON serialization
+seems to have good support across languages.
+
+We considered sending the exact connection manager configuration format of
+an open source connection manager like connman. There are a few issues
+here, for instance, referencing certificates by identifiers not tied to a
+particular PKCS#11 token, and tying to one OS's connection manager.
+
+## Examples
+
+### Simple format example: PEAP/MSCHAPv2 network (per device)
+
+```
+{
+ "Type": "UnencryptedConfiguration",
+ "NetworkConfigurations": [
+ {
+ "GUID": "{f2c17903-b0e1-8593-b3ca74f977236bd7}",
+ "Name": "MySSID",
+ "Type": "WiFi",
+ "WiFi": {
+ "AutoConnect": true,
+ "EAP": {
+ "Outer": "PEAP",
+ "UseSystemCAs": true
+ },
+ "HiddenSSID": false,
+ "SSID": "MySSID",
+ "Security": "WPA-EAP"
+ }
+ }
+ ],
+ "Certificates": []
+}
+```
+
+Notice that in this case, we do not provide a username and password - we set
+SaveCredentials to *false* so we are prompted every
+time. We could have passed in username and password - but such a file should
+be encrypted.
+
+### Complex format example: TLS network with client certs (per device)
+
+```
+{
+ "Type": "UnencryptedConfiguration",
+ "NetworkConfigurations": [
+ {
+ "GUID": "{00f79111-51e0-e6e0-76b3b55450d80a1b}",
+ "Name": "MyTTLSNetwork",
+ "Type": "WiFi",
+ "WiFi": {
+ "AutoConnect": false,
+ "EAP": {
+ "ClientCertPattern": {
+ "EnrollmentURI": [
+ "http://fetch-my-certificate.com"
+ ],
+ "IssuerCARef": [
+ "{6ed8dce9-64c8-d568-d225d7e467e37828}"
+ ]
+ },
+ "ClientCertType": "Pattern",
+ "Outer": "EAP-TLS",
+ "ServerCARef": "{6ed8dce9-64c8-d568-d225d7e467e37828}",
+ "UseSystemCAs": true
+ },
+ "HiddenSSID": false,
+ "SSID": "MyTTLSNetwork",
+ "Security": "WPA-EAP"
+ }
+ }
+ ],
+ "Certificates": [
+ {
+ "GUID": "{6ed8dce9-64c8-d568-d225d7e467e37828}",
+ "Type": "Authority",
+ "X509": "MIIEpzCCA4+gAwIBAgIJAMueiWq5WEIAMA0GCSqGSIb3DQEBBQUAMIGTMQswCQYDVQQGEwJGUjEPMA0GA1UECBMGUmFkaXVzMRIwEAYDVQQHEwlTb21ld2hlcmUxFTATBgNVBAoTDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5jb20xJjAkBgNVBAMTHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTExMDEyODA2MjA0MFoXDTEyMDEyODA2MjA0MFowgZMxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIEwZSYWRpdXMxEjAQBgNVBAcTCVNvbWV3aGVyZTEVMBMGA1UEChMMRXhhbXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTEmMCQGA1UEAxMdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9EDplhyrVNJIoy1OsVqvD/K67B5PW2bDKKxGznodrzCu8jHsP1Ne3mgrK20vbzQUUBdmxTCWO6x3a3//r4ZuPOuZd1ViycWjt6mRfRbBzNrHzP7NiyFuXjdlz74beHQQLcHwvZ3qFAWZK37uweiLiDPaMaEQlka2Bztqx4PsogmSdoVPSCxi5Cl1XlJmITA03LlKpO79+0rEPRamWO/DMCwvffn2/UUjJLog4/lYe16HQ6iq/6bjhffm2rLXDFKOGZmBVbLNMCfANRMtdFWHYdBXERoUo2zpM9tduOOUNLy7E7kRKVm/wy38s51ChFPlpORrhimN2j1caar+KAv2tAgMBAAGjgfswgfgwHQYDVR0OBBYEFBTIImiXp+57jjgn2N5wq93GgAAtMIHIBgNVHSMEgcAwgb2AFBTIImiXp+57jjgn2N5wq93GgAAtoYGZpIGWMIGTMQswCQYDVQQGEwJGUjEPMA0GA1UECBMGUmFkaXVzMRIwEAYDVQQHEwlTb21ld2hlcmUxFTATBgNVBAoTDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5jb20xJjAkBgNVBAMTHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5ggkAy56JarlYQgAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAnNd0YY7s2YVYPsgEgDS+rBNjcQloTFWgc9Hv4RWBjwcdJdSPIrpBp7LSjC96wH5U4eWpQjlWbOYQ9RBq9Z/RpuAPEjzRV78rIrQrCWQ3lxwywWEb5Th1EVJSN68eNv7Ke5BlZ2l9kfLRKFm5MEBXX9YoHMX0U8I8dPIXfTyevmKOT1PuEta5cQOM6/zH86XWn6WYx3EXkyjpeIbVOw49AqaEY8u70yBmut4MO03zz/pwLjV1BWyIkXhsrtuJyA+ZImvgLK2oAMZtGGFo7b0GW/sWY/P3R6Un3RFy35k6U3kXCDYYhgZEcS36lIqcj5y6vYUUVM732/etCsuOLz6ppw=="
+ }
+ ]
+}
+```
+
+In this example, the client certificate is not sent in the ONC format, but
+rather we send a certificate authority which we know will have signed the
+client certificate that is needed, along with an enrollment URI to navigate
+to if the required certificate is not yet available on the client.
+
+### Simple format example: HTTPS Certificate Authority
+
+In this example a new certificate authority is added to be trusted for HTTPS
+server authentication.
+
+```
+{
+ "Type": "UnencryptedConfiguration",
+ "NetworkConfigurations": [],
+ "Certificates": [
+ {
+ "GUID": "{f31f2110-9f5f-61a7-a8bd7c00b94237af}",
+ "TrustBits": [ "Web" ],
+ "Type": "Authority",
+ "X509": "MIIEpzCCA4+gAwIBAgIJAMueiWq5WEIAMA0GCSqGSIb3DQEBBQUAMIGTMQswCQYDVQQGEwJGUjEPMA0GA1UECBMGUmFkaXVzMRIwEAYDVQQHEwlTb21ld2hlcmUxFTATBgNVBAoTDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5jb20xJjAkBgNVBAMTHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTExMDEyODA2MjA0MFoXDTEyMDEyODA2MjA0MFowgZMxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIEwZSYWRpdXMxEjAQBgNVBAcTCVNvbWV3aGVyZTEVMBMGA1UEChMMRXhhbXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTEmMCQGA1UEAxMdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9EDplhyrVNJIoy1OsVqvD/K67B5PW2bDKKxGznodrzCu8jHsP1Ne3mgrK20vbzQUUBdmxTCWO6x3a3//r4ZuPOuZd1ViycWjt6mRfRbBzNrHzP7NiyFuXjdlz74beHQQLcHwvZ3qFAWZK37uweiLiDPaMaEQlka2Bztqx4PsogmSdoVPSCxi5Cl1XlJmITA03LlKpO79+0rEPRamWO/DMCwvffn2/UUjJLog4/lYe16HQ6iq/6bjhffm2rLXDFKOGZmBVbLNMCfANRMtdFWHYdBXERoUo2zpM9tduOOUNLy7E7kRKVm/wy38s51ChFPlpORrhimN2j1caar+KAv2tAgMBAAGjgfswgfgwHQYDVR0OBBYEFBTIImiXp+57jjgn2N5wq93GgAAtMIHIBgNVHSMEgcAwgb2AFBTIImiXp+57jjgn2N5wq93GgAAtoYGZpIGWMIGTMQswCQYDVQQGEwJGUjEPMA0GA1UECBMGUmFkaXVzMRIwEAYDVQQHEwlTb21ld2hlcmUxFTATBgNVBAoTDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5jb20xJjAkBgNVBAMTHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5ggkAy56JarlYQgAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAnNd0YY7s2YVYPsgEgDS+rBNjcQloTFWgc9Hv4RWBjwcdJdSPIrpBp7LSjC96wH5U4eWpQjlWbOYQ9RBq9Z/RpuAPEjzRV78rIrQrCWQ3lxwywWEb5Th1EVJSN68eNv7Ke5BlZ2l9kfLRKFm5MEBXX9YoHMX0U8I8dPIXfTyevmKOT1PuEta5cQOM6/zH86XWn6WYx3EXkyjpeIbVOw49AqaEY8u70yBmut4MO03zz/pwLjV1BWyIkXhsrtuJyA+ZImvgLK2oAMZtGGFo7b0GW/sWY/P3R6Un3RFy35k6U3kXCDYYhgZEcS36lIqcj5y6vYUUVM732/etCsuOLz6ppw=="
+ }
+ ]
+}
+```
+
+### Encrypted format example
+
+In this example a simple wireless network is added, but the file is encrypted
+with the passphrase "test0000".
+
+```
+{
+ "Cipher": "AES256",
+ "Ciphertext": "eQ9/r6v29/83M745aa0JllEj4lklt3Nfy4kPPvXgjBt1eTByxXB+FnsdvL6Uca5JBU5aROxfiol2+ZZOkxPmUNNIFZj70pkdqOGVe09ncf0aVBDsAa27veGIG8rG/VQTTbAo7d8QaxdNNbZvwQVkdsAXawzPCu7zSh4NF/hDnDbYjbN/JEm1NzvWgEjeOfqnnw3PnGUYCArIaRsKq9uD0a1NccU+16ZSzyDhX724JNrJjsuxohotk5YXsCK0lP7ZXuXj+nSR0aRIETSQ+eqGhrew2octLXq8cXK05s6ZuVAc0mFKPkntSI/fzBACuPi4ZaGd3YEYiKzNOgKJ+qEwgoE39xp0EXMZOZyjMOAtA6e1ZZDQGWG7vKdTLmLKNztHGrXvlZkyEf1RDs10YgkwwLgUhm0yBJ+eqbxO/RiBXz7O2/UVOkkkVcmeI6yh3BdL6HIYsMMygnZa5WRkd/2/EudoqEnjcqUyGsL+YUqV6KRTC0PH+z7zSwvFs2KygrSM7SIAZM2yiQHTQACkA/YCJDwACkkQOBFnRWTWiX0xmN55WMbgrs/wqJ4zGC9LgdAInOBlc3P+76+i7QLaNjMovQ==",
+ "HMAC": "3ylRy5InlhVzFGakJ/9lvGSyVH0=",
+ "HMACMethod": "SHA1",
+ "Iterations": 20000,
+ "IV": "hcm6OENfqG6C/TVO6p5a8g==",
+ "Salt": "/3O73QadCzA=",
+ "Stretch": "PBKDF2",
+ "Type": "EncryptedConfiguration"
+}
+```
+
+
+## Standalone editor
+
+The source code for a Chrome packaged app to generate ONC configuration can
+be found here: https://chromium.googlesource.com/chromiumos/platform/spigots/
+
+## Internationalization and Localization
+
+UIs will need to have internationalization and localizations - the file
+format will remain in English.
+
+## Security Considerations
+
+Data stored inside of open network configuration files is highly sensitive
+to users and enterprises. The file format itself provides adequate
+encryption options to allow standalone use-cases to be secure. For automatic
+updates sent by policy, the policy transport should be made secure. The file
+should not be stored unencrypted on disk as part of policy fetching and
+should be cleared from memory after use.
+
+## Privacy Considerations
+
+Similarly to the security considerations, user names will be present in
+these files for certain kinds of connections, so any places where the file
+is transmitted or saved to disk should be secure. On client device, when
+user names for connections that are user-specific are persisted to disk,
+they should be stored in a location that is encrypted. Users can also opt in
+these cases to not save their user credentials in the config file and will
+instead be prompted when they are needed.
+
+## Authors
+
+* pneubeck@chromium.org
+* stevenjb@chromium.org
diff --git a/chromium/components/open_from_clipboard/BUILD.gn b/chromium/components/open_from_clipboard/BUILD.gn
index fe46837a69a..73e360ed1b5 100644
--- a/chromium/components/open_from_clipboard/BUILD.gn
+++ b/chromium/components/open_from_clipboard/BUILD.gn
@@ -10,12 +10,39 @@ static_library("open_from_clipboard") {
"clipboard_recent_content_ios.mm",
]
+ if (!is_ios) {
+ sources += [
+ "clipboard_recent_content_generic.cc",
+ "clipboard_recent_content_generic.h",
+ ]
+ }
+
deps = [
+ ":open_from_clipboard_impl",
"//base",
+ "//components/variations",
+ "//net",
+ "//ui/base:base",
"//url",
]
}
+# Helper classes used by "open_from_clipboard" target. These classes must have
+# no dependencies on "//base:i18n".
+source_set("open_from_clipboard_impl") {
+ sources = [
+ "clipboard_recent_content_impl_ios.h",
+ "clipboard_recent_content_impl_ios.mm",
+ ]
+ deps = [
+ "//base",
+ ]
+ assert_no_deps = [ "//base:i18n" ]
+ if (is_ios) {
+ configs += [ "//build/config/compiler:enable_arc" ]
+ }
+}
+
static_library("test_support") {
testonly = true
sources = [
@@ -36,9 +63,16 @@ source_set("unit_tests") {
"clipboard_recent_content_ios_unittest.mm",
]
+ if (!is_ios) {
+ sources += [ "clipboard_recent_content_generic_unittest.cc" ]
+ }
+
deps = [
":open_from_clipboard",
+ ":open_from_clipboard_impl",
"//base",
"//testing/gtest",
+ "//ui/base:test_support",
+ "//url",
]
}
diff --git a/chromium/components/open_from_clipboard/DEPS b/chromium/components/open_from_clipboard/DEPS
new file mode 100644
index 00000000000..d80a9dc1485
--- /dev/null
+++ b/chromium/components/open_from_clipboard/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ "+components/variations",
+ "+net",
+ "+ui/base/clipboard",
+ "+ui/base/test",
+]
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content.cc b/chromium/components/open_from_clipboard/clipboard_recent_content.cc
index 56312ec2ae0..a06be7bf454 100644
--- a/chromium/components/open_from_clipboard/clipboard_recent_content.cc
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content.cc
@@ -4,13 +4,30 @@
#include "components/open_from_clipboard/clipboard_recent_content.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "components/variations/variations_associated_data.h"
+#include "url/url_constants.h"
+
namespace {
ClipboardRecentContent* g_clipboard_recent_content = nullptr;
-}
+
+// Schemes appropriate for suggestion by ClipboardRecentContent.
+const char* kAuthorizedSchemes[] = {
+ url::kAboutScheme, url::kDataScheme, url::kHttpScheme, url::kHttpsScheme,
+ // TODO(mpearson): add support for chrome:// URLs. Right now the scheme
+ // for that lives in content and is accessible via
+ // GetEmbedderRepresentationOfAboutScheme() or content::kChromeUIScheme
+ // TODO(mpearson): when adding desktop support, add kFileScheme, kFtpScheme,
+ // and kGopherScheme.
+};
+
+} // namespace
ClipboardRecentContent::ClipboardRecentContent() {}
-ClipboardRecentContent::~ClipboardRecentContent() {}
+ClipboardRecentContent::~ClipboardRecentContent() {
+}
// static
ClipboardRecentContent* ClipboardRecentContent::GetInstance() {
@@ -18,6 +35,38 @@ ClipboardRecentContent* ClipboardRecentContent::GetInstance() {
}
// static
-void ClipboardRecentContent::SetInstance(ClipboardRecentContent* instance) {
- g_clipboard_recent_content = instance;
+void ClipboardRecentContent::SetInstance(
+ std::unique_ptr<ClipboardRecentContent> new_instance) {
+ delete g_clipboard_recent_content;
+ g_clipboard_recent_content = new_instance.release();
+}
+
+// static
+bool ClipboardRecentContent::IsAppropriateSuggestion(const GURL& url) {
+ // Check to make sure it's a scheme we're willing to suggest.
+ for (const auto* authorized_scheme : kAuthorizedSchemes) {
+ if (url.SchemeIs(authorized_scheme))
+ return true;
+ }
+
+ // Not a scheme we're allowed to return.
+ return false;
+}
+
+// static
+base::TimeDelta ClipboardRecentContent::MaximumAgeOfClipboard() {
+ // Identify the current setting for this parameter from the omnibox field
+ // trial.
+ std::string value_str = variations::GetVariationParamValue(
+ "OmniboxBundledExperimentV1", "ClipboardURLMaximumAge");
+ // If the parameter is not set, use a 1 hour timeout.
+ if (value_str.empty())
+ return base::TimeDelta::FromHours(1);
+ // This is a best-effort conversion; we trust the hand-crafted parameters
+ // downloaded from the server to be perfect. There's no need for handle
+ // errors smartly.
+ int value;
+ // The value in the parameter is stored in seconds.
+ base::StringToInt(value_str, &value);
+ return base::TimeDelta::FromSeconds(value);
}
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content.h b/chromium/components/open_from_clipboard/clipboard_recent_content.h
index 46e3449c305..78a1b49c4bf 100644
--- a/chromium/components/open_from_clipboard/clipboard_recent_content.h
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content.h
@@ -5,12 +5,12 @@
#ifndef COMPONENTS_OPEN_FROM_CLIPBOARD_CLIPBOARD_RECENT_CONTENT_H_
#define COMPONENTS_OPEN_FROM_CLIPBOARD_CLIPBOARD_RECENT_CONTENT_H_
+#include <memory>
#include <string>
#include "base/macros.h"
#include "base/time/time.h"
-
-class GURL;
+#include "url/gurl.h"
// Helper class returning an URL if the content of the clipboard can be turned
// into an URL, and if it estimates that the content of the clipboard is not too
@@ -26,11 +26,11 @@ class ClipboardRecentContent {
static ClipboardRecentContent* GetInstance();
// Sets the global instance of ClipboardRecentContent singleton.
- static void SetInstance(ClipboardRecentContent* instance);
+ static void SetInstance(std::unique_ptr<ClipboardRecentContent> new_instance);
- // Returns true if the clipboard contains a recent URL that has not been
- // supressed, and copies it in |url|. Otherwise, returns false. |url| must not
- // be null.
+ // Returns true if the clipboard contains a recent URL that is appropriate to
+ // be suggested and has not been supressed, and copies it in |url|.
+ // Otherwise, returns false. |url| must not be null.
virtual bool GetRecentURLFromClipboard(GURL* url) = 0;
// Returns how old the content of the clipboard is.
@@ -40,6 +40,14 @@ class ClipboardRecentContent {
// clipboard's content changed.
virtual void SuppressClipboardContent() = 0;
+ protected:
+ // GetRecentURLFromClipboard() should never return a URL from a clipboard
+ // older than this.
+ static base::TimeDelta MaximumAgeOfClipboard();
+
+ // Returns true if the URL is appropriate to be suggested.
+ static bool IsAppropriateSuggestion(const GURL& url);
+
private:
DISALLOW_COPY_AND_ASSIGN(ClipboardRecentContent);
};
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content_generic.cc b/chromium/components/open_from_clipboard/clipboard_recent_content_generic.cc
new file mode 100644
index 00000000000..15ffa42eb98
--- /dev/null
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_generic.cc
@@ -0,0 +1,65 @@
+// 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/open_from_clipboard/clipboard_recent_content_generic.h"
+
+#include "base/strings/string_util.h"
+#include "ui/base/clipboard/clipboard.h"
+
+ClipboardRecentContentGeneric::ClipboardRecentContentGeneric() {}
+
+bool ClipboardRecentContentGeneric::GetRecentURLFromClipboard(GURL* url) {
+ if (GetClipboardContentAge() > MaximumAgeOfClipboard())
+ return false;
+
+ // Get and clean up the clipboard before processing.
+ std::string gurl_string;
+ ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
+ clipboard->ReadAsciiText(ui::CLIPBOARD_TYPE_COPY_PASTE, &gurl_string);
+ base::TrimWhitespaceASCII(gurl_string, base::TrimPositions::TRIM_ALL,
+ &gurl_string);
+
+ // Interpret the clipboard as a URL if possible.
+ DCHECK(url);
+ // If there is mid-string whitespace, don't attempt to interpret the string
+ // as a URL. (Otherwise gurl will happily try to convert
+ // "http://example.com extra words" into "http://example.com%20extra%20words",
+ // which is not likely to be a useful or intended destination.)
+ if (gurl_string.find_first_of(base::kWhitespaceASCII) != std::string::npos)
+ return false;
+ if (!gurl_string.empty()) {
+ *url = GURL(gurl_string);
+ } else {
+ // Fall back to unicode / UTF16, as some URLs may use international domain
+ // names, not punycode.
+ base::string16 gurl_string16;
+ clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &gurl_string16);
+ base::TrimWhitespace(gurl_string16, base::TrimPositions::TRIM_ALL,
+ &gurl_string16);
+ if (gurl_string16.find_first_of(base::kWhitespaceUTF16) !=
+ std::string::npos)
+ return false;
+ if (!gurl_string16.empty())
+ *url = GURL(gurl_string16);
+ }
+ return url->is_valid() && IsAppropriateSuggestion(*url);
+}
+
+base::TimeDelta ClipboardRecentContentGeneric::GetClipboardContentAge() const {
+ const base::Time last_modified_time =
+ ui::Clipboard::GetForCurrentThread()->GetLastModifiedTime();
+ const base::Time now = base::Time::Now();
+ // In case of system clock change, assume the last modified time is now.
+ // (Don't return a negative age, i.e., a time in the future.)
+ if (last_modified_time > now)
+ return base::TimeDelta();
+ return now - last_modified_time;
+}
+
+void ClipboardRecentContentGeneric::SuppressClipboardContent() {
+ // User cleared the user data. The pasteboard entry must be removed from the
+ // omnibox list. Do this by pretending the current clipboard is ancient,
+ // not recent.
+ ui::Clipboard::GetForCurrentThread()->ClearLastModifiedTime();
+}
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content_generic.h b/chromium/components/open_from_clipboard/clipboard_recent_content_generic.h
new file mode 100644
index 00000000000..c0b8704742a
--- /dev/null
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_generic.h
@@ -0,0 +1,33 @@
+// 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_OPEN_FROM_CLIPBOARD_CLIPBOARD_RECENT_CONTENT_GENERIC_H_
+#define COMPONENTS_OPEN_FROM_CLIPBOARD_CLIPBOARD_RECENT_CONTENT_GENERIC_H_
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "components/open_from_clipboard/clipboard_recent_content.h"
+#include "url/gurl.h"
+
+// An implementation of ClipboardRecentContent that uses
+// ui/base/clipboard/clipboard.h
+// and hence works on all platforms for which Clipboard is implemented.
+// (This includes all platforms Chrome runs on except iOS.)
+// Note that on some platforms Clipboard may not implement the necessary
+// functions for this provider to function. In those cases, it will not do
+// anything.
+class ClipboardRecentContentGeneric : public ClipboardRecentContent {
+ public:
+ explicit ClipboardRecentContentGeneric();
+
+ // ClipboardRecentContent implementation.
+ bool GetRecentURLFromClipboard(GURL* url) override;
+ base::TimeDelta GetClipboardContentAge() const override;
+ void SuppressClipboardContent() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ClipboardRecentContentGeneric);
+};
+
+#endif // COMPONENTS_OPEN_FROM_CLIPBOARD_CLIPBOARD_RECENT_CONTENT_GENERIC_H_
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
new file mode 100644
index 00000000000..83b9ac943cf
--- /dev/null
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_generic_unittest.cc
@@ -0,0 +1,122 @@
+// 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/open_from_clipboard/clipboard_recent_content_generic.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/test/test_clipboard.h"
+#include "url/gurl.h"
+
+class ClipboardRecentContentGenericTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ test_clipboard_ = new ui::TestClipboard;
+ std::unique_ptr<ui::Clipboard> clipboard(test_clipboard_);
+ ui::Clipboard::SetClipboardForCurrentThread(std::move(clipboard));
+ }
+
+ void TearDown() override {
+ ui::Clipboard::DestroyClipboardForCurrentThread();
+ }
+
+ ui::TestClipboard* test_clipboard_;
+};
+
+TEST_F(ClipboardRecentContentGenericTest, RecognizesURLs) {
+ struct {
+ std::string clipboard;
+ const bool expected_get_recent_url_value;
+ } test_data[] = {
+ {"www", false},
+ {"query string", false},
+ {"www.example.com", false},
+ {"http://www.example.com/", true},
+ // The missing trailing slash shouldn't matter.
+ {"http://www.example.com", true},
+ {"https://another-example.com/", true},
+ {"http://example.com/with-path/", true},
+ {"about:version", true},
+ {"data:,Hello%2C%20World!", true},
+ // Certain schemes are not eligible to be suggested.
+ {"ftp://example.com/", false},
+ // Leading and trailing spaces are okay, other spaces not.
+ {" http://leading.com", true},
+ {" http://both.com/trailing ", true},
+ {"http://malformed url", false},
+ {"http://another.com/malformed url", false},
+ // Internationalized domain names should work.
+ {"http://xn--c1yn36f", true},
+ {" http://xn--c1yn36f/path ", true},
+ {"http://xn--c1yn36f extra ", false},
+ {"http://點看", true},
+ {"http://點看/path", true},
+ {" http://點看/path ", true},
+ {" http://點看/path extra word", false},
+ };
+
+ ClipboardRecentContentGeneric recent_content;
+ base::Time now = base::Time::Now();
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ test_clipboard_->WriteText(test_data[i].clipboard.data(),
+ test_data[i].clipboard.length());
+ test_clipboard_->SetLastModifiedTime(now -
+ base::TimeDelta::FromSeconds(10));
+ GURL url;
+ EXPECT_EQ(test_data[i].expected_get_recent_url_value,
+ recent_content.GetRecentURLFromClipboard(&url))
+ << "for input " << test_data[i].clipboard;
+ }
+}
+
+TEST_F(ClipboardRecentContentGenericTest, OlderURLsNotSuggested) {
+ ClipboardRecentContentGeneric recent_content;
+ base::Time now = base::Time::Now();
+ std::string text = "http://example.com/";
+ test_clipboard_->WriteText(text.data(), text.length());
+ test_clipboard_->SetLastModifiedTime(now - base::TimeDelta::FromSeconds(10));
+ GURL url;
+ EXPECT_TRUE(recent_content.GetRecentURLFromClipboard(&url));
+ // If the last modified time is days ago, the URL shouldn't be suggested.
+ test_clipboard_->SetLastModifiedTime(now - base::TimeDelta::FromDays(2));
+ EXPECT_FALSE(recent_content.GetRecentURLFromClipboard(&url));
+}
+
+TEST_F(ClipboardRecentContentGenericTest, GetClipboardContentAge) {
+ ClipboardRecentContentGeneric recent_content;
+ base::Time now = base::Time::Now();
+ std::string text = " whether URL or not should not matter here.";
+ test_clipboard_->WriteText(text.data(), text.length());
+ test_clipboard_->SetLastModifiedTime(now - base::TimeDelta::FromSeconds(32));
+ base::TimeDelta age = recent_content.GetClipboardContentAge();
+ // It's possible the GetClipboardContentAge() took some time, so allow a
+ // little slop (5 seconds) in this comparison; don't check for equality.
+ EXPECT_LT(age - base::TimeDelta::FromSeconds(32),
+ base::TimeDelta::FromSeconds(5));
+}
+
+TEST_F(ClipboardRecentContentGenericTest, SuppressClipboardContent) {
+ // Make sure the URL is suggested.
+ ClipboardRecentContentGeneric recent_content;
+ base::Time now = base::Time::Now();
+ std::string text = "http://example.com/";
+ test_clipboard_->WriteText(text.data(), text.length());
+ test_clipboard_->SetLastModifiedTime(now - base::TimeDelta::FromSeconds(10));
+ GURL url;
+ EXPECT_TRUE(recent_content.GetRecentURLFromClipboard(&url));
+
+ // After suppressing it, it shouldn't be suggested.
+ recent_content.SuppressClipboardContent();
+ EXPECT_FALSE(recent_content.GetRecentURLFromClipboard(&url));
+
+ // If the clipboard changes, even if to the same thing again, the content
+ // should be suggested again.
+ test_clipboard_->WriteText(text.data(), text.length());
+ test_clipboard_->SetLastModifiedTime(now);
+ EXPECT_TRUE(recent_content.GetRecentURLFromClipboard(&url));
+}
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content_impl_ios.h b/chromium/components/open_from_clipboard/clipboard_recent_content_impl_ios.h
new file mode 100644
index 00000000000..9507df011a3
--- /dev/null
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_impl_ios.h
@@ -0,0 +1,55 @@
+// 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_OPEN_FROM_CLIPBOARD_CLIPBOARD_RECENT_CONTENT_IMPL_IOS_H_
+#define COMPONENTS_OPEN_FROM_CLIPBOARD_CLIPBOARD_RECENT_CONTENT_IMPL_IOS_H_
+
+#import <Foundation/Foundation.h>
+
+// A protocol implemented by delegates to handle clipboard changes.
+@protocol ClipboardRecentContentDelegate<NSObject>
+
+- (void)onClipboardChanged;
+
+@end
+
+// Helper class returning a URL if the content of the clipboard can be turned
+// into a URL, and if it estimates that the content of the clipboard is not too
+// old.
+@interface ClipboardRecentContentImplIOS : NSObject
+
+// |delegate| is used for metrics logging and can be nil. |authorizedSchemes|
+// should contain all schemes considered valid. |groupUserDefaults| is the
+// NSUserDefaults used to store information on pasteboard entry expiration. This
+// information will be shared with other applications in the application group.
+- (instancetype)initWithMaxAge:(NSTimeInterval)maxAge
+ authorizedSchemes:(NSSet<NSString*>*)authorizedSchemes
+ userDefaults:(NSUserDefaults*)groupUserDefaults
+ delegate:(id<ClipboardRecentContentDelegate>)delegate
+ NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+// Returns the copied URL if the clipboard contains a recent URL that has not
+// been supressed. Otherwise, returns nil.
+- (NSURL*)recentURLFromClipboard;
+
+// Returns how old the content of the clipboard is.
+- (NSTimeInterval)clipboardContentAge;
+
+// Prevents GetRecentURLFromClipboard from returning anything until the
+// clipboard's content changes.
+- (void)suppressClipboardContent;
+
+// Methods below are exposed for testing purposes.
+
+// Estimation of the date when the pasteboard changed.
+@property(nonatomic, strong) NSDate* lastPasteboardChangeDate;
+
+// Saves information to the user defaults about the latest pasteboard entry.
+- (void)saveToUserDefaults;
+
+@end
+
+#endif // COMPONENTS_OPEN_FROM_CLIPBOARD_CLIPBOARD_RECENT_CONTENT_IMPL_IOS_H_
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content_impl_ios.mm b/chromium/components/open_from_clipboard/clipboard_recent_content_impl_ios.mm
new file mode 100644
index 00000000000..5e506ee8540
--- /dev/null
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_impl_ios.mm
@@ -0,0 +1,219 @@
+// 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 "components/open_from_clipboard/clipboard_recent_content_impl_ios.h"
+
+#import <CommonCrypto/CommonDigest.h>
+#import <UIKit/UIKit.h>
+
+#import "base/mac/foundation_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/sys_info.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+// Key used to store the pasteboard's current change count. If when resuming
+// chrome the pasteboard's change count is different from the stored one, then
+// it means that the pasteboard's content has changed.
+NSString* const kPasteboardChangeCountKey = @"PasteboardChangeCount";
+// Key used to store the last date at which it was detected that the pasteboard
+// changed. It is used to evaluate the age of the pasteboard's content.
+NSString* const kPasteboardChangeDateKey = @"PasteboardChangeDate";
+// Key used to store the hash of the content of the pasteboard. Whenever the
+// hash changed, the pasteboard content is considered to have changed.
+NSString* const kPasteboardEntryMD5Key = @"PasteboardEntryMD5";
+
+// Compute a hash consisting of the first 4 bytes of the MD5 hash of |string|.
+// This value is used to detect pasteboard content change. Keeping only 4 bytes
+// is a privacy requirement to introduce collision and allow deniability of
+// having copied a given string.
+NSData* WeakMD5FromNSString(NSString* string) {
+ unsigned char hash[CC_MD5_DIGEST_LENGTH];
+ const std::string clipboard = base::SysNSStringToUTF8(string);
+ const char* c_string = clipboard.c_str();
+ CC_MD5(c_string, strlen(c_string), hash);
+ NSData* data = [NSData dataWithBytes:hash length:4];
+ return data;
+}
+
+} // namespace
+
+@interface ClipboardRecentContentImplIOS ()
+
+// The user defaults from the app group used to optimize the pasteboard change
+// detection.
+@property(nonatomic, strong) NSUserDefaults* sharedUserDefaults;
+// The pasteboard's change count. Increases everytime the pasteboard changes.
+@property(nonatomic) NSInteger lastPasteboardChangeCount;
+// MD5 hash of the last registered pasteboard entry.
+@property(nonatomic, strong) NSData* lastPasteboardEntryMD5;
+// Contains the authorized schemes for URLs.
+@property(nonatomic, readonly) NSSet* authorizedSchemes;
+// Delegate for metrics.
+@property(nonatomic, strong) id<ClipboardRecentContentDelegate> delegate;
+// Maximum age of clipboard in seconds.
+@property(nonatomic, readonly) NSTimeInterval maximumAgeOfClipboard;
+
+// If the content of the pasteboard has changed, updates the change count,
+// change date, and md5 of the latest pasteboard entry if necessary.
+- (void)updateIfNeeded;
+
+// Returns whether the pasteboard changed since the last time a pasteboard
+// change was detected.
+- (BOOL)hasPasteboardChanged;
+
+// Loads information from the user defaults about the latest pasteboard entry.
+- (void)loadFromUserDefaults;
+
+// Returns the URL contained in the clipboard (if any).
+- (NSURL*)URLFromPasteboard;
+
+// Returns the uptime.
+- (NSTimeInterval)uptime;
+
+@end
+
+@implementation ClipboardRecentContentImplIOS
+
+@synthesize lastPasteboardChangeCount = _lastPasteboardChangeCount;
+@synthesize lastPasteboardChangeDate = _lastPasteboardChangeDate;
+@synthesize lastPasteboardEntryMD5 = _lastPasteboardEntryMD5;
+@synthesize sharedUserDefaults = _sharedUserDefaults;
+@synthesize authorizedSchemes = _authorizedSchemes;
+@synthesize delegate = _delegate;
+@synthesize maximumAgeOfClipboard = _maximumAgeOfClipboard;
+
+- (instancetype)initWithMaxAge:(NSTimeInterval)maxAge
+ authorizedSchemes:(NSSet<NSString*>*)authorizedSchemes
+ userDefaults:(NSUserDefaults*)groupUserDefaults
+ delegate:(id<ClipboardRecentContentDelegate>)delegate {
+ self = [super init];
+ if (self) {
+ _maximumAgeOfClipboard = maxAge;
+ _delegate = delegate;
+ _authorizedSchemes = authorizedSchemes;
+ _sharedUserDefaults = groupUserDefaults;
+
+ _lastPasteboardChangeCount = NSIntegerMax;
+ [self loadFromUserDefaults];
+ [self updateIfNeeded];
+
+ // Makes sure |last_pasteboard_change_count_| was properly initialized.
+ DCHECK_NE(_lastPasteboardChangeCount, NSIntegerMax);
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(didBecomeActive:)
+ name:UIApplicationDidBecomeActiveNotification
+ object:nil];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)didBecomeActive:(NSNotification*)notification {
+ [self loadFromUserDefaults];
+ [self updateIfNeeded];
+}
+
+- (NSData*)getCurrentMD5 {
+ NSString* pasteboardString = [UIPasteboard generalPasteboard].string;
+ NSData* md5 = WeakMD5FromNSString(pasteboardString);
+
+ return md5;
+}
+
+- (BOOL)hasPasteboardChanged {
+ // If |MD5Changed|, we know for sure there has been at least one pasteboard
+ // copy since last time it was checked.
+ // If the pasteboard content is still the same but the device was not
+ // rebooted, the change count can be checked to see if it changed.
+ // Note: due to a mismatch between the actual behavior and documentation, and
+ // lack of consistency on different reboot scenarios, the change count cannot
+ // be checked after a reboot.
+ // See radar://21833556 for more information.
+ BOOL deviceRebooted = [self clipboardContentAge] >= [self uptime];
+ if (!deviceRebooted) {
+ NSInteger changeCount = [UIPasteboard generalPasteboard].changeCount;
+ bool changeCountChanged = changeCount != self.lastPasteboardChangeCount;
+ return changeCountChanged;
+ }
+
+ BOOL md5Changed =
+ ![[self getCurrentMD5] isEqualToData:self.lastPasteboardEntryMD5];
+ return md5Changed;
+}
+
+- (NSURL*)recentURLFromClipboard {
+ [self updateIfNeeded];
+ if ([self clipboardContentAge] > self.maximumAgeOfClipboard) {
+ return nil;
+ }
+ return [self URLFromPasteboard];
+}
+
+- (NSTimeInterval)clipboardContentAge {
+ return -[self.lastPasteboardChangeDate timeIntervalSinceNow];
+}
+
+- (void)suppressClipboardContent {
+ // User cleared the user data. The pasteboard entry must be removed from the
+ // omnibox list. Force entry expiration by setting copy date to 1970.
+ self.lastPasteboardChangeDate =
+ [[NSDate alloc] initWithTimeIntervalSince1970:0];
+ [self saveToUserDefaults];
+}
+
+- (void)updateIfNeeded {
+ if (![self hasPasteboardChanged]) {
+ return;
+ }
+
+ [self.delegate onClipboardChanged];
+
+ self.lastPasteboardChangeDate = [NSDate date];
+ self.lastPasteboardChangeCount = [UIPasteboard generalPasteboard].changeCount;
+ self.lastPasteboardEntryMD5 = [self getCurrentMD5];
+
+ [self saveToUserDefaults];
+}
+
+- (NSURL*)URLFromPasteboard {
+ NSString* clipboardString = [UIPasteboard generalPasteboard].string;
+
+ NSURL* url = [NSURL URLWithString:clipboardString];
+ if (![self.authorizedSchemes containsObject:url.scheme]) {
+ return nil;
+ }
+ return url;
+}
+
+- (void)loadFromUserDefaults {
+ self.lastPasteboardChangeCount =
+ [self.sharedUserDefaults integerForKey:kPasteboardChangeCountKey];
+ self.lastPasteboardChangeDate = base::mac::ObjCCastStrict<NSDate>(
+ [self.sharedUserDefaults objectForKey:kPasteboardChangeDateKey]);
+ self.lastPasteboardEntryMD5 = base::mac::ObjCCastStrict<NSData>(
+ [self.sharedUserDefaults objectForKey:kPasteboardEntryMD5Key]);
+}
+
+- (void)saveToUserDefaults {
+ [self.sharedUserDefaults setInteger:self.lastPasteboardChangeCount
+ forKey:kPasteboardChangeCountKey];
+ [self.sharedUserDefaults setObject:self.lastPasteboardChangeDate
+ forKey:kPasteboardChangeDateKey];
+ [self.sharedUserDefaults setObject:self.lastPasteboardEntryMD5
+ forKey:kPasteboardEntryMD5Key];
+}
+
+- (NSTimeInterval)uptime {
+ return base::SysInfo::Uptime().InSecondsF();
+}
+
+@end
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content_ios.h b/chromium/components/open_from_clipboard/clipboard_recent_content_ios.h
index d4b7d7ec831..abbf510182e 100644
--- a/chromium/components/open_from_clipboard/clipboard_recent_content_ios.h
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_ios.h
@@ -11,13 +11,16 @@
#include "components/open_from_clipboard/clipboard_recent_content.h"
#include "url/gurl.h"
+@class NSArray;
@class NSDate;
@class NSUserDefaults;
-@class ApplicationDidBecomeActiveNotificationListenerBridge;
+@class ClipboardRecentContentImplIOS;
-class ClipboardRecentContentIOSTest;
-
-// IOS implementation of ClipboardRecentContent
+// IOS implementation of ClipboardRecentContent.
+// A large part of the implementation is in clipboard_recent_content_impl_ios,
+// a GURL-free class that is used by some of the iOS extensions. Not using GURL
+// in extensions is preferable as GURL requires depending on ICU which makes the
+// extensions much larger.
class ClipboardRecentContentIOS : public ClipboardRecentContent {
public:
// |application_scheme| is the URL scheme that can be used to open the
@@ -26,53 +29,22 @@ class ClipboardRecentContentIOS : public ClipboardRecentContent {
// |group_user_defaults| is the NSUserDefaults used to store information on
// pasteboard entry expiration. This information will be shared with other
// application in the application group.
- explicit ClipboardRecentContentIOS(const std::string& application_scheme,
- NSUserDefaults* group_user_defaults);
- ~ClipboardRecentContentIOS() override;
+ ClipboardRecentContentIOS(const std::string& application_scheme,
+ NSUserDefaults* group_user_defaults);
- // If the content of the pasteboard has changed, updates the change count,
- // change date, and md5 of the latest pasteboard entry if necessary.
- void UpdateIfNeeded();
+ // Constructor that directly takes an |implementation|. For use in tests.
+ ClipboardRecentContentIOS(ClipboardRecentContentImplIOS* implementation);
- // Returns whether the pasteboard changed since the last time a pasteboard
- // change was detected.
- bool HasPasteboardChanged() const;
-
- // Loads information from the user defaults about the latest pasteboard entry.
- void LoadFromUserDefaults();
+ ~ClipboardRecentContentIOS() override;
// ClipboardRecentContent implementation.
bool GetRecentURLFromClipboard(GURL* url) override;
base::TimeDelta GetClipboardContentAge() const override;
void SuppressClipboardContent() override;
- protected:
- // Returns the uptime. Override in tests to return custom value.
- virtual base::TimeDelta Uptime() const;
-
private:
- friend class ClipboardRecentContentIOSTest;
-
- // Saves information to the user defaults about the latest pasteboard entry.
- void SaveToUserDefaults();
-
- // Returns the URL contained in the clipboard (if any).
- GURL URLFromPasteboard();
-
- // Contains the URL scheme opening the app. May be empty.
- std::string application_scheme_;
- // The pasteboard's change count. Increases everytime the pasteboard changes.
- NSInteger last_pasteboard_change_count_;
- // Estimation of the date when the pasteboard changed.
- base::scoped_nsobject<NSDate> last_pasteboard_change_date_;
- // MD5 hash of the last registered pasteboard entry.
- base::scoped_nsobject<NSData> last_pasteboard_entry_md5_;
- // Bridge to receive notifications when the application becomes active.
- base::scoped_nsobject<ApplicationDidBecomeActiveNotificationListenerBridge>
- notification_bridge_;
- // The user defaults from the app group used to optimize the pasteboard change
- // detection.
- base::scoped_nsobject<NSUserDefaults> shared_user_defaults_;
+ // The implementation instance.
+ base::scoped_nsobject<ClipboardRecentContentImplIOS> implementation_;
DISALLOW_COPY_AND_ASSIGN(ClipboardRecentContentIOS);
};
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content_ios.mm b/chromium/components/open_from_clipboard/clipboard_recent_content_ios.mm
index 0ef8e97124d..14a8646ed8d 100644
--- a/chromium/components/open_from_clipboard/clipboard_recent_content_ios.mm
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_ios.mm
@@ -15,233 +15,79 @@
#include "base/metrics/user_metrics.h"
#include "base/strings/sys_string_conversions.h"
#include "base/sys_info.h"
+#import "components/open_from_clipboard/clipboard_recent_content_impl_ios.h"
+#import "net/base/mac/url_conversions.h"
#include "url/gurl.h"
#include "url/url_constants.h"
-// Bridge that forwards UIApplicationDidBecomeActiveNotification notifications
-// to its delegate.
-@interface ApplicationDidBecomeActiveNotificationListenerBridge : NSObject
-
-// Initialize the ApplicationDidBecomeActiveNotificationListenerBridge with
-// |delegate| which must not be null.
-- (instancetype)initWithDelegate:(ClipboardRecentContentIOS*)delegate
- NS_DESIGNATED_INITIALIZER;
-
-- (instancetype)init NS_UNAVAILABLE;
-
-@end
-
-@implementation ApplicationDidBecomeActiveNotificationListenerBridge {
- ClipboardRecentContentIOS* _delegate;
-}
-
-- (instancetype)init {
- NOTREACHED();
- return nil;
-}
-
-- (instancetype)initWithDelegate:(ClipboardRecentContentIOS*)delegate {
- DCHECK(delegate);
- self = [super init];
- if (self) {
- _delegate = delegate;
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(didBecomeActive:)
- name:UIApplicationDidBecomeActiveNotification
- object:nil];
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-- (void)didBecomeActive:(NSNotification*)notification {
- if (_delegate) {
- _delegate->LoadFromUserDefaults();
- _delegate->UpdateIfNeeded();
- }
-}
-
-- (void)disconnect {
- _delegate = nullptr;
-}
-
-@end
-
namespace {
-// Key used to store the pasteboard's current change count. If when resuming
-// chrome the pasteboard's change count is different from the stored one, then
-// it means that the pasteboard's content has changed.
-NSString* kPasteboardChangeCountKey = @"PasteboardChangeCount";
-// Key used to store the last date at which it was detected that the pasteboard
-// changed. It is used to evaluate the age of the pasteboard's content.
-NSString* kPasteboardChangeDateKey = @"PasteboardChangeDate";
-// Key used to store the hash of the content of the pasteboard. Whenever the
-// hash changed, the pasteboard content is considered to have changed.
-NSString* kPasteboardEntryMD5Key = @"PasteboardEntryMD5";
-base::TimeDelta kMaximumAgeOfClipboard = base::TimeDelta::FromHours(3);
+
// Schemes accepted by the ClipboardRecentContentIOS.
const char* kAuthorizedSchemes[] = {
- url::kHttpScheme,
- url::kHttpsScheme,
- url::kDataScheme,
- url::kAboutScheme,
+ url::kHttpScheme, url::kHttpsScheme, url::kDataScheme, url::kAboutScheme,
};
-// Compute a hash consisting of the first 4 bytes of the MD5 hash of |string|.
-// This value is used to detect pasteboard content change. Keeping only 4 bytes
-// is a privacy requirement to introduce collision and allow deniability of
-// having copied a given string.
-NSData* WeakMD5FromNSString(NSString* string) {
- unsigned char hash[CC_MD5_DIGEST_LENGTH];
- const std::string clipboard = base::SysNSStringToUTF8(string);
- const char* c_string = clipboard.c_str();
- CC_MD5(c_string, strlen(c_string), hash);
- NSData* data = [NSData dataWithBytes:hash length:4];
- return data;
-}
-
-} // namespace
-
-bool ClipboardRecentContentIOS::GetRecentURLFromClipboard(GURL* url) {
- DCHECK(url);
- UpdateIfNeeded();
- if (GetClipboardContentAge() > kMaximumAgeOfClipboard) {
- return false;
+// Get the list of authorized schemes.
+NSSet<NSString*>* getAuthorizedSchemeList(
+ const std::string& application_scheme) {
+ NSMutableSet<NSString*>* schemes = [NSMutableSet set];
+ for (size_t i = 0; i < arraysize(kAuthorizedSchemes); ++i) {
+ [schemes addObject:base::SysUTF8ToNSString(kAuthorizedSchemes[i])];
}
-
- GURL url_from_pasteboard = URLFromPasteboard();
- if (url_from_pasteboard.is_valid()) {
- *url = url_from_pasteboard;
- return true;
+ if (!application_scheme.empty()) {
+ [schemes addObject:base::SysUTF8ToNSString(application_scheme)];
}
- return false;
-}
-base::TimeDelta ClipboardRecentContentIOS::GetClipboardContentAge() const {
- return base::TimeDelta::FromSeconds(static_cast<int64_t>(
- -[last_pasteboard_change_date_ timeIntervalSinceNow]));
+ return [schemes copy];
}
-void ClipboardRecentContentIOS::SuppressClipboardContent() {
- // User cleared the user data. The pasteboard entry must be removed from the
- // omnibox list. Force entry expiration by setting copy date to 1970.
- last_pasteboard_change_date_.reset(
- [[NSDate alloc] initWithTimeIntervalSince1970:0]);
- SaveToUserDefaults();
-}
+} // namespace
-void ClipboardRecentContentIOS::UpdateIfNeeded() {
- if (!HasPasteboardChanged())
- return;
+@interface ClipboardRecentContentDelegateImpl
+ : NSObject<ClipboardRecentContentDelegate>
+@end
- base::RecordAction(base::UserMetricsAction("MobileOmniboxClipboardChanged"));
+@implementation ClipboardRecentContentDelegateImpl
- GURL url_from_pasteboard = URLFromPasteboard();
- last_pasteboard_change_date_.reset([[NSDate date] retain]);
- last_pasteboard_change_count_ = [UIPasteboard generalPasteboard].changeCount;
- NSString* pasteboard_string = [[UIPasteboard generalPasteboard] string];
- if (!pasteboard_string) {
- pasteboard_string = @"";
- }
- NSData* MD5 = WeakMD5FromNSString(pasteboard_string);
- last_pasteboard_entry_md5_.reset([MD5 retain]);
- SaveToUserDefaults();
+- (void)onClipboardChanged {
+ base::RecordAction(base::UserMetricsAction("MobileOmniboxClipboardChanged"));
}
+@end
+
ClipboardRecentContentIOS::ClipboardRecentContentIOS(
const std::string& application_scheme,
NSUserDefaults* group_user_defaults)
- : application_scheme_(application_scheme),
- shared_user_defaults_([group_user_defaults retain]) {
- last_pasteboard_change_count_ = NSIntegerMax;
- LoadFromUserDefaults();
-
- UpdateIfNeeded();
-
- // Makes sure |last_pasteboard_change_count_| was properly initialized.
- DCHECK_NE(last_pasteboard_change_count_, NSIntegerMax);
- notification_bridge_.reset(
- [[ApplicationDidBecomeActiveNotificationListenerBridge alloc]
- initWithDelegate:this]);
-}
+ : ClipboardRecentContentIOS([[ClipboardRecentContentImplIOS alloc]
+ initWithMaxAge:MaximumAgeOfClipboard().InSecondsF()
+ authorizedSchemes:getAuthorizedSchemeList(application_scheme)
+ userDefaults:group_user_defaults
+ delegate:[[ClipboardRecentContentDelegateImpl alloc]
+ init]]) {}
-bool ClipboardRecentContentIOS::HasPasteboardChanged() const {
- // If |MD5Changed|, we know for sure there has been at least one pasteboard
- // copy since last time it was checked.
- // If the pasteboard content is still the same but the device was not
- // rebooted, the change count can be checked to see if it changed.
- // Note: due to a mismatch between the actual behavior and documentation, and
- // lack of consistency on different reboot scenarios, the change count cannot
- // be checked after a reboot.
- // See radar://21833556 for more information.
- NSInteger change_count = [UIPasteboard generalPasteboard].changeCount;
- bool change_count_changed = change_count != last_pasteboard_change_count_;
-
- bool not_rebooted = Uptime() > GetClipboardContentAge();
- if (not_rebooted)
- return change_count_changed;
-
- NSString* pasteboard_string = [[UIPasteboard generalPasteboard] string];
- if (!pasteboard_string) {
- pasteboard_string = @"";
- }
- NSData* md5 = WeakMD5FromNSString(pasteboard_string);
- BOOL md5_changed = ![md5 isEqualToData:last_pasteboard_entry_md5_];
-
- return md5_changed;
-}
-
-ClipboardRecentContentIOS::~ClipboardRecentContentIOS() {
- [notification_bridge_ disconnect];
+ClipboardRecentContentIOS::ClipboardRecentContentIOS(
+ ClipboardRecentContentImplIOS* implementation) {
+ implementation_.reset(implementation);
}
-GURL ClipboardRecentContentIOS::URLFromPasteboard() {
- NSString* clipboard_string = [[UIPasteboard generalPasteboard] string];
- if (!clipboard_string) {
- return GURL::EmptyGURL();
- }
- const std::string clipboard = base::SysNSStringToUTF8(clipboard_string);
- GURL gurl = GURL(clipboard);
- if (gurl.is_valid()) {
- for (size_t i = 0; i < arraysize(kAuthorizedSchemes); ++i) {
- if (gurl.SchemeIs(kAuthorizedSchemes[i])) {
- return gurl;
- }
- }
- if (!application_scheme_.empty() &&
- gurl.SchemeIs(application_scheme_.c_str())) {
- return gurl;
- }
+bool ClipboardRecentContentIOS::GetRecentURLFromClipboard(GURL* url) {
+ DCHECK(url);
+ NSURL* url_from_pasteboard = [implementation_ recentURLFromClipboard];
+ GURL converted_url = net::GURLWithNSURL(url_from_pasteboard);
+ if (converted_url.is_valid()) {
+ *url = std::move(converted_url);
+ return true;
}
- return GURL::EmptyGURL();
+ return false;
}
-void ClipboardRecentContentIOS::LoadFromUserDefaults() {
- last_pasteboard_change_count_ =
- [shared_user_defaults_ integerForKey:kPasteboardChangeCountKey];
- last_pasteboard_change_date_.reset(
- [[shared_user_defaults_ objectForKey:kPasteboardChangeDateKey] retain]);
- last_pasteboard_entry_md5_.reset(
- [[shared_user_defaults_ objectForKey:kPasteboardEntryMD5Key] retain]);
+ClipboardRecentContentIOS::~ClipboardRecentContentIOS() {}
- DCHECK(!last_pasteboard_change_date_ ||
- [last_pasteboard_change_date_ isKindOfClass:[NSDate class]]);
-}
-
-void ClipboardRecentContentIOS::SaveToUserDefaults() {
- [shared_user_defaults_ setInteger:last_pasteboard_change_count_
- forKey:kPasteboardChangeCountKey];
- [shared_user_defaults_ setObject:last_pasteboard_change_date_
- forKey:kPasteboardChangeDateKey];
- [shared_user_defaults_ setObject:last_pasteboard_entry_md5_
- forKey:kPasteboardEntryMD5Key];
+base::TimeDelta ClipboardRecentContentIOS::GetClipboardContentAge() const {
+ return base::TimeDelta::FromSeconds(
+ static_cast<int64_t>([implementation_ clipboardContentAge]));
}
-base::TimeDelta ClipboardRecentContentIOS::Uptime() const {
- return base::SysInfo::Uptime();
+void ClipboardRecentContentIOS::SuppressClipboardContent() {
+ [implementation_ suppressClipboardContent];
}
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm b/chromium/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm
index 670a92354c0..6a68d6e8687 100644
--- a/chromium/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm
@@ -9,6 +9,9 @@
#include <memory>
+#include "base/memory/ptr_util.h"
+#include "base/strings/sys_string_conversions.h"
+#import "components/open_from_clipboard/clipboard_recent_content_impl_ios.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -37,28 +40,57 @@ void SetPasteboardContent(const char* data) {
setValue:[NSString stringWithUTF8String:data]
forPasteboardType:@"public.plain-text"];
}
-const char kUnrecognizedURL[] = "ftp://foo/";
-const char kRecognizedURL[] = "http://bar/";
-const char kRecognizedURL2[] = "http://bar/2";
+const char kUnrecognizedURL[] = "bad://foo/";
+const char kRecognizedURL[] = "good://bar/";
+const char kRecognizedURL2[] = "good://bar/2";
const char kAppSpecificURL[] = "test://qux/";
const char kAppSpecificScheme[] = "test";
-NSTimeInterval kSevenHours = 60 * 60 * 7;
+const char kRecognizedScheme[] = "good";
+NSTimeInterval kLongerThanMaxAge = 60 * 60 * 7;
+NSTimeInterval kMaxAge = 60 * 60 * 1;
} // namespace
+@interface ClipboardRecentContentImplIOSWithFakeUptime
+ : ClipboardRecentContentImplIOS
+@property(nonatomic) NSTimeInterval fakeUptime;
+
+- (instancetype)initWithMaxAge:(NSTimeInterval)maxAge
+ authorizedSchemes:(NSArray*)authorizedSchemes
+ userDefaults:(NSUserDefaults*)groupUserDefaults
+ uptime:(NSTimeInterval)uptime;
+
+@end
+
+@implementation ClipboardRecentContentImplIOSWithFakeUptime
+
+@synthesize fakeUptime = _fakeUptime;
+
+- (instancetype)initWithMaxAge:(NSTimeInterval)maxAge
+ authorizedSchemes:(NSSet*)authorizedSchemes
+ userDefaults:(NSUserDefaults*)groupUserDefaults
+ uptime:(NSTimeInterval)uptime {
+ self = [super initWithMaxAge:maxAge
+ authorizedSchemes:authorizedSchemes
+ userDefaults:groupUserDefaults
+ delegate:nil];
+ if (self) {
+ _fakeUptime = uptime;
+ }
+ return self;
+}
+
+- (NSTimeInterval)uptime {
+ return self.fakeUptime;
+}
+
+@end
+
class ClipboardRecentContentIOSWithFakeUptime
: public ClipboardRecentContentIOS {
public:
- ClipboardRecentContentIOSWithFakeUptime(const std::string& application_scheme,
- NSUserDefaults* group_user_defaults)
- : ClipboardRecentContentIOS(application_scheme, group_user_defaults) {}
- // Sets the uptime.
- void SetUptime(base::TimeDelta uptime) { uptime_ = uptime; }
-
- protected:
- base::TimeDelta Uptime() const override { return uptime_; }
-
- private:
- base::TimeDelta uptime_;
+ ClipboardRecentContentIOSWithFakeUptime(
+ ClipboardRecentContentImplIOS* implementation)
+ : ClipboardRecentContentIOS(implementation) {}
};
class ClipboardRecentContentIOSTest : public ::testing::Test {
@@ -76,23 +108,31 @@ class ClipboardRecentContentIOSTest : public ::testing::Test {
void ResetClipboardRecentContent(const std::string& application_scheme,
base::TimeDelta time_delta) {
- clipboard_content_.reset(new ClipboardRecentContentIOSWithFakeUptime(
- application_scheme, [NSUserDefaults standardUserDefaults]));
- clipboard_content_->SetUptime(time_delta);
- }
-
- void SetStoredPasteboardChangeDate(NSDate* changeDate) {
- clipboard_content_->last_pasteboard_change_date_.reset([changeDate copy]);
- clipboard_content_->SaveToUserDefaults();
+ clipboard_content_implementation_ =
+ [[ClipboardRecentContentImplIOSWithFakeUptime alloc]
+ initWithMaxAge:kMaxAge
+ authorizedSchemes:@[
+ base::SysUTF8ToNSString(kRecognizedScheme),
+ base::SysUTF8ToNSString(application_scheme)
+ ]
+ userDefaults:[NSUserDefaults standardUserDefaults]
+ uptime:time_delta.InSecondsF()];
+
+ clipboard_content_ =
+ base::MakeUnique<ClipboardRecentContentIOSWithFakeUptime>(
+ clipboard_content_implementation_);
}
- void SetStoredPasteboardChangeCount(NSInteger newChangeCount) {
- clipboard_content_->last_pasteboard_change_count_ = newChangeCount;
- clipboard_content_->SaveToUserDefaults();
+ void SetStoredPasteboardChangeDate(NSDate* change_date) {
+ clipboard_content_implementation_.lastPasteboardChangeDate =
+ [change_date copy];
+ [clipboard_content_implementation_ saveToUserDefaults];
}
protected:
std::unique_ptr<ClipboardRecentContentIOSWithFakeUptime> clipboard_content_;
+ ClipboardRecentContentImplIOSWithFakeUptime*
+ clipboard_content_implementation_;
};
TEST_F(ClipboardRecentContentIOSTest, SchemeFiltering) {
@@ -129,7 +169,7 @@ TEST_F(ClipboardRecentContentIOSTest, PasteboardURLObsolescence) {
// Test that old pasteboard data is not provided.
SetStoredPasteboardChangeDate(
- [NSDate dateWithTimeIntervalSinceNow:-kSevenHours]);
+ [NSDate dateWithTimeIntervalSinceNow:-kLongerThanMaxAge]);
EXPECT_FALSE(clipboard_content_->GetRecentURLFromClipboard(&gurl));
// Tests that if chrome is relaunched, old pasteboard data is still
@@ -164,7 +204,7 @@ TEST_F(ClipboardRecentContentIOSTest, SupressedPasteboard) {
// Check that the pasteboard content is still suppressed.
EXPECT_FALSE(clipboard_content_->GetRecentURLFromClipboard(&gurl));
- // Check that the even if the device is restarted, pasteboard content is
+ // Check that even if the device is restarted, pasteboard content is
// still suppressed.
SimulateDeviceRestart();
EXPECT_FALSE(clipboard_content_->GetRecentURLFromClipboard(&gurl));
diff --git a/chromium/components/os_crypt/BUILD.gn b/chromium/components/os_crypt/BUILD.gn
index 19aa93eeafd..e91c6815e6a 100644
--- a/chromium/components/os_crypt/BUILD.gn
+++ b/chromium/components/os_crypt/BUILD.gn
@@ -58,6 +58,7 @@ static_library("os_crypt") {
if (is_ios) {
set_sources_assignment_filter([])
sources += [
+ "keychain_password_mac.h",
"keychain_password_mac.mm",
"os_crypt_mac.mm",
]
diff --git a/chromium/components/os_crypt/key_storage_linux.cc b/chromium/components/os_crypt/key_storage_linux.cc
index b54fe0d2155..c8b18324ce7 100644
--- a/chromium/components/os_crypt/key_storage_linux.cc
+++ b/chromium/components/os_crypt/key_storage_linux.cc
@@ -39,7 +39,8 @@ struct Configuration {
scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner;
};
-base::LazyInstance<Configuration> g_config = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<Configuration>::DestructorAtExit g_config =
+ LAZY_INSTANCE_INITIALIZER;
} // namespace
diff --git a/chromium/components/ownership/owner_settings_service.cc b/chromium/components/ownership/owner_settings_service.cc
index 6fbd9029638..49b0b3aab6c 100644
--- a/chromium/components/ownership/owner_settings_service.cc
+++ b/chromium/components/ownership/owner_settings_service.cc
@@ -32,7 +32,9 @@ using ScopedSGNContext = std::unique_ptr<
std::unique_ptr<em::PolicyFetchResponse> AssembleAndSignPolicy(
std::unique_ptr<em::PolicyData> policy,
- SECKEYPrivateKey* private_key) {
+ scoped_refptr<ownership::PrivateKey> private_key) {
+ DCHECK(private_key->key());
+
// Assemble the policy.
std::unique_ptr<em::PolicyFetchResponse> policy_response(
new em::PolicyFetchResponse());
@@ -41,8 +43,8 @@ std::unique_ptr<em::PolicyFetchResponse> AssembleAndSignPolicy(
return nullptr;
}
- ScopedSGNContext sign_context(
- SGN_NewContext(SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, private_key));
+ ScopedSGNContext sign_context(SGN_NewContext(
+ SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, private_key->key()));
if (!sign_context) {
NOTREACHED();
return nullptr;
@@ -109,10 +111,8 @@ bool OwnerSettingsService::AssembleAndSignPolicyAsync(
if (!task_runner || !IsOwner())
return false;
return base::PostTaskAndReplyWithResult(
- task_runner,
- FROM_HERE,
- base::Bind(
- &AssembleAndSignPolicy, base::Passed(&policy), private_key_->key()),
+ task_runner, FROM_HERE,
+ base::Bind(&AssembleAndSignPolicy, base::Passed(&policy), private_key_),
callback);
}
@@ -137,7 +137,7 @@ bool OwnerSettingsService::SetDouble(const std::string& setting, double value) {
bool OwnerSettingsService::SetString(const std::string& setting,
const std::string& value) {
DCHECK(thread_checker_.CalledOnValidThread());
- base::StringValue in_value(value);
+ base::Value in_value(value);
return Set(setting, in_value);
}
diff --git a/chromium/components/packed_ct_ev_whitelist/OWNERS b/chromium/components/packed_ct_ev_whitelist/OWNERS
index facb789f58d..009e29e53fb 100644
--- a/chromium/components/packed_ct_ev_whitelist/OWNERS
+++ b/chromium/components/packed_ct_ev_whitelist/OWNERS
@@ -1,2 +1,5 @@
eranm@chromium.org
rsleevi@chromium.org
+
+# TEAM: net-dev@chromium.org
+# COMPONENT: Internals>Network>CertTrans
diff --git a/chromium/components/pageinfo_strings.grdp b/chromium/components/page_info_strings.grdp
index f5cacbe480c..54e83360073 100644
--- a/chromium/components/pageinfo_strings.grdp
+++ b/chromium/components/page_info_strings.grdp
@@ -58,6 +58,9 @@
<message name="IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_WARNING" desc="Some extra text of the connection section when the connection is encrypted and the page contains insecure content which has been displayed (e.g. images, CSS).">
Further, this page includes other resources which are not secure. These resources can be viewed by others while in transit, and can be modified by an attacker to change the look of the page.
</message>
+ <message name="IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_FORM_WARNING" desc="Some extra text of the connection section when the connection is encrypted and the page contains a form with a non-secure target.">
+ This page includes a form that may not submit securely. Data you send can be viewed by others while in transit or could be modified by an attacker to change what the server receives.
+ </message>
<message name="IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK" desc="Linking 2 sentences in 1 paragraph.">
<ph name="SENTENCE1">$1<ex>Your connection is encrypted.</ex></ph> <ph name="SENTENCE2">$2<ex>However, this page includes resources from other pages whose identity cannot be verified.</ex></ph>
</message>
diff --git a/chromium/components/pairing/bluetooth_host_pairing_controller.cc b/chromium/components/pairing/bluetooth_host_pairing_controller.cc
index 18c747bb843..c8c534fa06a 100644
--- a/chromium/components/pairing/bluetooth_host_pairing_controller.cc
+++ b/chromium/components/pairing/bluetooth_host_pairing_controller.cc
@@ -166,28 +166,18 @@ void BluetoothHostPairingController::SendHostStatus() {
}
void BluetoothHostPairingController::Reset() {
- if (controller_socket_.get()) {
- controller_socket_->Close();
- controller_socket_ = nullptr;
- }
-
- if (service_socket_.get()) {
- service_socket_->Close();
- service_socket_ = nullptr;
- }
-
if (adapter_.get()) {
- if (adapter_->IsDiscoverable()) {
- adapter_->SetDiscoverable(false, base::Bind(&base::DoNothing),
- base::Bind(&base::DoNothing));
+ device::BluetoothDevice* device =
+ adapter_->GetDevice(controller_device_address_);
+ if (device && device->IsPaired()) {
+ device->Forget(base::Bind(&BluetoothHostPairingController::OnForget,
+ ptr_factory_.GetWeakPtr()),
+ base::Bind(&BluetoothHostPairingController::OnForget,
+ ptr_factory_.GetWeakPtr()));
+ return;
}
-
- base::PostTaskAndReplyWithResult(
- file_task_runner_.get(), FROM_HERE, base::Bind(&GetDevices),
- base::Bind(&BluetoothHostPairingController::PowerOffAdapterIfApplicable,
- ptr_factory_.GetWeakPtr()));
}
- ChangeStage(STAGE_NONE);
+ OnForget();
}
void BluetoothHostPairingController::OnGetAdapter(
@@ -272,6 +262,8 @@ void BluetoothHostPairingController::OnCreateService(
void BluetoothHostPairingController::OnAccept(
const device::BluetoothDevice* device,
scoped_refptr<device::BluetoothSocket> socket) {
+ controller_device_address_ = device->GetAddress();
+
DCHECK(thread_checker_.CalledOnValidThread());
adapter_->SetDiscoverable(
false,
@@ -279,9 +271,7 @@ void BluetoothHostPairingController::OnAccept(
ptr_factory_.GetWeakPtr(), false),
base::Bind(&BluetoothHostPairingController::OnSetError,
ptr_factory_.GetWeakPtr()));
-
controller_socket_ = socket;
- service_socket_ = nullptr;
SendHostStatus();
@@ -371,6 +361,36 @@ void BluetoothHostPairingController::ResetAdapter() {
delegate_->OnAdapterReset();
}
+void BluetoothHostPairingController::OnForget() {
+ if (controller_socket_.get()) {
+ controller_socket_->Close();
+ controller_socket_ = nullptr;
+ }
+
+ if (service_socket_.get()) {
+ service_socket_->Close();
+ service_socket_ = nullptr;
+ }
+
+ if (adapter_.get()) {
+ if (adapter_->IsDiscoverable()) {
+ adapter_->SetDiscoverable(false, base::Bind(&base::DoNothing),
+ base::Bind(&base::DoNothing));
+ }
+
+ base::PostTaskAndReplyWithResult(
+ file_task_runner_.get(), FROM_HERE, base::Bind(&GetDevices),
+ base::Bind(&BluetoothHostPairingController::PowerOffAdapterIfApplicable,
+ ptr_factory_.GetWeakPtr()));
+ }
+ ChangeStage(STAGE_NONE);
+}
+
+void BluetoothHostPairingController::SetControllerDeviceAddressForTesting(
+ const std::string& address) {
+ controller_device_address_ = address;
+}
+
void BluetoothHostPairingController::OnReceiveError(
device::BluetoothSocket::ErrorReason reason,
const std::string& error_message) {
diff --git a/chromium/components/pairing/bluetooth_host_pairing_controller.h b/chromium/components/pairing/bluetooth_host_pairing_controller.h
index 3b0e47836a3..9c84a0d3dfa 100644
--- a/chromium/components/pairing/bluetooth_host_pairing_controller.h
+++ b/chromium/components/pairing/bluetooth_host_pairing_controller.h
@@ -33,6 +33,10 @@ namespace net {
class IOBuffer;
}
+namespace chromeos {
+class BluetoothHostPairingNoInputTest;
+}
+
namespace pairing_chromeos {
class BluetoothHostPairingController
@@ -66,6 +70,8 @@ class BluetoothHostPairingController
scoped_refptr<device::BluetoothAdapter> GetAdapterForTesting();
private:
+ friend class chromeos::BluetoothHostPairingNoInputTest;
+
void ChangeStage(Stage new_stage);
void SendHostStatus();
@@ -88,6 +94,9 @@ class BluetoothHostPairingController
const std::string& error_message);
void PowerOffAdapterIfApplicable(const std::vector<InputDeviceInfo>& devices);
void ResetAdapter();
+ void OnForget();
+
+ void SetControllerDeviceAddressForTesting(const std::string& address);
// HostPairingController:
void AddObserver(Observer* observer) override;
@@ -137,6 +146,7 @@ class BluetoothHostPairingController
UpdateStatus update_status_;
EnrollmentStatus enrollment_status_;
std::string permanent_id_;
+ std::string controller_device_address_;
bool was_powered_ = false;
scoped_refptr<device::BluetoothAdapter> adapter_;
diff --git a/chromium/components/password_manager/DEPS b/chromium/components/password_manager/DEPS
index 99eb6bdd02d..d5d8ecef063 100644
--- a/chromium/components/password_manager/DEPS
+++ b/chromium/components/password_manager/DEPS
@@ -8,6 +8,7 @@ include_rules = [
"+components/sync/protocol",
"+net/base",
"+net/http/http_status_code.h",
+ "+net/http/transport_security_state.h",
"+net/traffic_annotation",
"+net/url_request",
"+sql",
diff --git a/chromium/components/password_manager/OWNERS b/chromium/components/password_manager/OWNERS
index 206695fd12d..568d03ba65c 100644
--- a/chromium/components/password_manager/OWNERS
+++ b/chromium/components/password_manager/OWNERS
@@ -1,6 +1,5 @@
dvadym@chromium.org
engedy@chromium.org
-gcasto@chromium.org
melandory@chromium.org
mkwst@chromium.org
vabr@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 26695612a11..90b20e9f4e3 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
@@ -86,7 +86,8 @@ void ContentPasswordManagerDriver::FillPasswordForm(
const autofill::PasswordFormFillData& form_data) {
const int key = next_free_key_++;
password_autofill_manager_.OnAddPasswordFormMapping(key, form_data);
- GetPasswordAutofillAgent()->FillPasswordForm(key, form_data);
+ GetPasswordAutofillAgent()->FillPasswordForm(
+ key, autofill::ClearPasswordValues(form_data));
}
void ContentPasswordManagerDriver::AllowPasswordGenerationForForm(
@@ -235,7 +236,8 @@ void ContentPasswordManagerDriver::
void ContentPasswordManagerDriver::DidNavigateFrame(
content::NavigationHandle* navigation_handle) {
// Clear page specific data after main frame navigation.
- if (navigation_handle->IsInMainFrame() && !navigation_handle->IsSamePage()) {
+ if (navigation_handle->IsInMainFrame() &&
+ !navigation_handle->IsSameDocument()) {
GetPasswordManager()->DidNavigateMainFrame();
GetPasswordAutofillManager()->DidNavigateMainFrame();
}
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 0606690226b..e91435b3185 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
@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
#include "components/autofill/content/common/autofill_agent.mojom.h"
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/password_manager/core/browser/stub_log_manager.h"
@@ -21,6 +22,10 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using autofill::PasswordForm;
+using autofill::PasswordFormFillData;
+using base::ASCIIToUTF16;
+using testing::_;
using testing::Return;
namespace password_manager {
@@ -67,12 +72,11 @@ class FakePasswordAutofillAgent
logging_state_active_ = false;
}
- private:
// autofill::mojom::PasswordAutofillAgent:
- void FillPasswordForm(
- int key,
- const autofill::PasswordFormFillData& form_data) override {}
+ MOCK_METHOD2(FillPasswordForm,
+ void(int, const autofill::PasswordFormFillData&));
+ private:
void SetLoggingState(bool active) override {
called_set_logging_state_ = true;
logging_state_active_ = active;
@@ -92,6 +96,47 @@ class FakePasswordAutofillAgent
mojo::Binding<autofill::mojom::PasswordAutofillAgent> binding_;
};
+PasswordFormFillData GetTestPasswordFormFillData() {
+ // Create the current form on the page.
+ PasswordForm form_on_page;
+ form_on_page.origin = GURL("https://foo.com/");
+ form_on_page.action = GURL("https://foo.com/login");
+ form_on_page.signon_realm = "https://foo.com/";
+ form_on_page.scheme = PasswordForm::SCHEME_HTML;
+
+ // Create an exact match in the database.
+ PasswordForm preferred_match = form_on_page;
+ preferred_match.username_element = ASCIIToUTF16("username");
+ preferred_match.username_value = ASCIIToUTF16("test@gmail.com");
+ preferred_match.password_element = ASCIIToUTF16("password");
+ preferred_match.password_value = ASCIIToUTF16("test");
+ preferred_match.preferred = true;
+
+ std::map<base::string16, const PasswordForm*> matches;
+ PasswordForm non_preferred_match = preferred_match;
+ non_preferred_match.username_value = ASCIIToUTF16("test1@gmail.com");
+ non_preferred_match.password_value = ASCIIToUTF16("test1");
+ matches[non_preferred_match.username_value] = &non_preferred_match;
+
+ PasswordFormFillData result;
+ InitPasswordFormFillData(form_on_page, matches, &preferred_match, true, false,
+ &result);
+ return result;
+}
+
+MATCHER_P(WerePasswordsCleared,
+ should_preferred_password_cleared,
+ "Passwords not cleared") {
+ if (should_preferred_password_cleared && !arg.password_field.value.empty())
+ return false;
+
+ for (auto& credentials : arg.additional_logins)
+ if (!credentials.second.password.empty())
+ return false;
+
+ return true;
+}
+
} // namespace
class ContentPasswordManagerDriverTest
@@ -366,6 +411,20 @@ TEST_F(ContentPasswordManagerDriverTest,
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
}
+TEST_F(ContentPasswordManagerDriverTest, ClearPasswordsOnAutofill) {
+ std::unique_ptr<ContentPasswordManagerDriver> driver(
+ new ContentPasswordManagerDriver(main_rfh(), &password_manager_client_,
+ &autofill_client_));
+
+ for (bool wait_for_username : {false, true}) {
+ PasswordFormFillData fill_data = GetTestPasswordFormFillData();
+ fill_data.wait_for_username = wait_for_username;
+ EXPECT_CALL(fake_agent_,
+ FillPasswordForm(_, WerePasswordsCleared(wait_for_username)));
+ driver->FillPasswordForm(fill_data);
+ }
+}
+
INSTANTIATE_TEST_CASE_P(,
ContentPasswordManagerDriverTest,
testing::Values(true, false));
diff --git a/chromium/components/password_manager/content/browser/credential_manager_impl.cc b/chromium/components/password_manager/content/browser/credential_manager_impl.cc
index fcd6940a168..14261ccac92 100644
--- a/chromium/components/password_manager/content/browser/credential_manager_impl.cc
+++ b/chromium/components/password_manager/content/browser/credential_manager_impl.cc
@@ -122,9 +122,7 @@ void CredentialManagerImpl::OnProvisionalSaveComplete() {
}
// Otherwise, this is a new form, so as the user if they'd like to save.
- client_->PromptUserToSaveOrUpdatePassword(
- std::move(form_manager_), CredentialSourceType::CREDENTIAL_SOURCE_API,
- false);
+ client_->PromptUserToSaveOrUpdatePassword(std::move(form_manager_), false);
}
void CredentialManagerImpl::RequireUserMediation(
@@ -202,7 +200,7 @@ void CredentialManagerImpl::Get(bool zero_click_only,
}
bool CredentialManagerImpl::IsZeroClickAllowed() const {
- return *auto_signin_enabled_ && !client_->IsOffTheRecord();
+ return *auto_signin_enabled_ && !client_->IsIncognito();
}
GURL CredentialManagerImpl::GetOrigin() const {
diff --git a/chromium/components/password_manager/content/browser/credential_manager_impl_unittest.cc b/chromium/components/password_manager/content/browser/credential_manager_impl_unittest.cc
index 103f8300f84..9563fc28c69 100644
--- a/chromium/components/password_manager/content/browser/credential_manager_impl_unittest.cc
+++ b/chromium/components/password_manager/content/browser/credential_manager_impl_unittest.cc
@@ -59,13 +59,12 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
MOCK_CONST_METHOD0(IsSavingAndFillingEnabledForCurrentPage, bool());
MOCK_CONST_METHOD0(IsFillingEnabledForCurrentPage, bool());
MOCK_METHOD0(OnCredentialManagerUsed, bool());
- MOCK_CONST_METHOD0(IsOffTheRecord, bool());
+ MOCK_CONST_METHOD0(IsIncognito, bool());
MOCK_METHOD0(NotifyUserAutoSigninPtr, bool());
MOCK_METHOD1(NotifyUserCouldBeAutoSignedInPtr,
bool(autofill::PasswordForm* form));
MOCK_METHOD0(NotifyStorePasswordCalled, void());
- MOCK_METHOD2(PromptUserToSavePasswordPtr,
- void(PasswordFormManager*, CredentialSourceType type));
+ MOCK_METHOD1(PromptUserToSavePasswordPtr, void(PasswordFormManager*));
MOCK_METHOD3(PromptUserToChooseCredentialsPtr,
bool(const std::vector<autofill::PasswordForm*>& local_forms,
const GURL& origin,
@@ -81,10 +80,9 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
bool PromptUserToSaveOrUpdatePassword(
std::unique_ptr<PasswordFormManager> manager,
- CredentialSourceType type,
bool update_password) override {
manager_.swap(manager);
- PromptUserToSavePasswordPtr(manager_.get(), type);
+ PromptUserToSavePasswordPtr(manager_.get());
return true;
}
@@ -226,7 +224,7 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
.WillByDefault(testing::Return(true));
ON_CALL(*client_, OnCredentialManagerUsed())
.WillByDefault(testing::Return(true));
- ON_CALL(*client_, IsOffTheRecord()).WillByDefault(testing::Return(false));
+ ON_CALL(*client_, IsIncognito()).WillByDefault(testing::Return(false));
NavigateAndCommit(GURL("https://example.com/test.html"));
@@ -403,8 +401,7 @@ TEST_F(CredentialManagerImplTest, IsZeroClickAllowed) {
TEST_F(CredentialManagerImplTest, CredentialManagerOnStore) {
CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
- EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_API))
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
.Times(testing::Exactly(1));
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
@@ -433,8 +430,7 @@ TEST_F(CredentialManagerImplTest, CredentialManagerOnStore) {
}
TEST_F(CredentialManagerImplTest, CredentialManagerOnStoreFederated) {
- EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_API))
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
.Times(testing::Exactly(1));
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
@@ -477,8 +473,7 @@ TEST_F(CredentialManagerImplTest, StoreFederatedAfterPassword) {
federated.federation_origin = url::Origin(GURL("https://google.com/"));
federated.signon_realm = "federation://example.com/google.com";
CredentialInfo info(federated, CredentialType::CREDENTIAL_TYPE_FEDERATED);
- EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_API));
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
bool called = false;
@@ -511,7 +506,7 @@ TEST_F(CredentialManagerImplTest, CredentialManagerStoreOverwrite) {
// the password without prompting the user.
CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
info.password = base::ASCIIToUTF16("Totally new password.");
- EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_)).Times(0);
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
bool called = false;
CallStore(info, base::Bind(&RespondCallback, &called));
@@ -540,7 +535,7 @@ TEST_F(CredentialManagerImplTest,
// credential with identical username and password should result in a silent
// save without prompting the user.
CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
- EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_, _))
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
.Times(testing::Exactly(0));
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
bool called = false;
@@ -567,7 +562,7 @@ TEST_F(CredentialManagerImplTest,
// credential but has a different username should prompt the user and not
// result in a silent save.
CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
- EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_, _))
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
.Times(testing::Exactly(1));
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
bool called = false;
@@ -598,7 +593,7 @@ TEST_F(CredentialManagerImplTest,
// credential but has a different password should prompt the user and not
// result in a silent save.
CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
- EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_, _))
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
.Times(testing::Exactly(1));
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
bool called = false;
@@ -701,8 +696,7 @@ TEST_F(CredentialManagerImplTest,
CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
EXPECT_CALL(*client_, IsSavingAndFillingEnabledForCurrentPage())
.WillRepeatedly(testing::Return(false));
- EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_API))
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
.Times(testing::Exactly(0));
EXPECT_CALL(*client_, NotifyStorePasswordCalled()).Times(0);
@@ -811,8 +805,7 @@ TEST_F(CredentialManagerImplTest,
TEST_F(CredentialManagerImplTest,
CredentialManagerOnRequestCredentialWithEmptyPasswordStore) {
std::vector<GURL> federations;
- EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_API))
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
.Times(testing::Exactly(0));
EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
.Times(testing::Exactly(0));
@@ -928,8 +921,7 @@ TEST_F(CredentialManagerImplTest,
store_->AddLogin(cross_origin_form_);
std::vector<GURL> federations;
- EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_API))
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
.Times(testing::Exactly(0));
EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
.Times(testing::Exactly(0));
@@ -1306,7 +1298,7 @@ TEST_F(CredentialManagerImplTest, ResetSkipZeroClickAfterPrompt) {
}
TEST_F(CredentialManagerImplTest, NoResetSkipZeroClickAfterPromptInIncognito) {
- EXPECT_CALL(*client_, IsOffTheRecord()).WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*client_, IsIncognito()).WillRepeatedly(testing::Return(true));
// Turn on the global zero-click flag which should be overriden by Incognito.
client_->set_zero_click_enabled(true);
form_.skip_zero_click = true;
@@ -1341,7 +1333,7 @@ TEST_F(CredentialManagerImplTest, NoResetSkipZeroClickAfterPromptInIncognito) {
}
TEST_F(CredentialManagerImplTest, IncognitoZeroClickRequestCredential) {
- EXPECT_CALL(*client_, IsOffTheRecord()).WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*client_, IsIncognito()).WillRepeatedly(testing::Return(true));
store_->AddLogin(form_);
std::vector<GURL> federations;
@@ -1476,6 +1468,14 @@ TEST_F(CredentialManagerImplTest, ZeroClickAfterMigratingHttpCredential) {
CredentialType::CREDENTIAL_TYPE_PASSWORD);
}
+TEST_F(CredentialManagerImplTest, MigrateWithEmptyStore) {
+ // HTTP scheme is valid for localhost. Nothing should crash.
+ NavigateAndCommit(GURL("http://127.0.0.1:8000/"));
+
+ std::vector<GURL> federations;
+ ExpectZeroClickSignInFailure(false, true, federations);
+}
+
TEST_F(CredentialManagerImplTest, GetSynthesizedFormForOrigin) {
PasswordStore::FormDigest synthesized =
cm_service_impl_->GetSynthesizedFormForOrigin();
@@ -1485,8 +1485,7 @@ TEST_F(CredentialManagerImplTest, GetSynthesizedFormForOrigin) {
}
TEST_F(CredentialManagerImplTest, BlacklistPasswordCredential) {
- EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_API));
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
bool called = false;
@@ -1515,8 +1514,7 @@ TEST_F(CredentialManagerImplTest, BlacklistFederatedCredential) {
form_.password_value = base::string16();
form_.signon_realm = "federation://example.com/example.com";
- EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_API));
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_FEDERATED);
bool called = false;
CallStore(info, base::Bind(&RespondCallback, &called));
@@ -1551,8 +1549,7 @@ TEST_F(CredentialManagerImplTest, RespectBlacklistingPasswordCredential) {
CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
bool called = false;
- EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_API));
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
CallStore(info, base::Bind(&RespondCallback, &called));
// Allow the PasswordFormManager to talk to the password store
RunAllPendingTasks();
@@ -1573,8 +1570,7 @@ TEST_F(CredentialManagerImplTest, RespectBlacklistingFederatedCredential) {
form_.signon_realm = "federation://example.com/example.com";
CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_FEDERATED);
bool called = false;
- EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_API));
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
CallStore(info, base::Bind(&RespondCallback, &called));
// Allow the PasswordFormManager to talk to the password store
RunAllPendingTasks();
diff --git a/chromium/components/password_manager/content/renderer/credential_manager_client.cc b/chromium/components/password_manager/content/renderer/credential_manager_client.cc
index bc8291f3886..b859abb1185 100644
--- a/chromium/components/password_manager/content/renderer/credential_manager_client.cc
+++ b/chromium/components/password_manager/content/renderer/credential_manager_client.cc
@@ -28,20 +28,20 @@ namespace {
void WebCredentialToCredentialInfo(const blink::WebCredential& credential,
CredentialInfo* out) {
- out->id = credential.id().utf16();
- out->name = credential.name().utf16();
- out->icon = credential.iconURL();
- if (credential.isPasswordCredential()) {
+ out->id = credential.Id().Utf16();
+ out->name = credential.GetName().Utf16();
+ out->icon = credential.GetIconURL();
+ if (credential.IsPasswordCredential()) {
out->type = CredentialType::CREDENTIAL_TYPE_PASSWORD;
out->password = static_cast<const blink::WebPasswordCredential&>(credential)
- .password()
- .utf16();
+ .Password()
+ .Utf16();
} else {
- DCHECK(credential.isFederatedCredential());
+ DCHECK(credential.IsFederatedCredential());
out->type = CredentialType::CREDENTIAL_TYPE_FEDERATED;
out->federation =
static_cast<const blink::WebFederatedCredential&>(credential)
- .provider();
+ .Provider();
}
}
@@ -50,13 +50,13 @@ std::unique_ptr<blink::WebCredential> CredentialInfoToWebCredential(
switch (info.type) {
case CredentialType::CREDENTIAL_TYPE_FEDERATED:
return base::MakeUnique<blink::WebFederatedCredential>(
- blink::WebString::fromUTF16(info.id), info.federation,
- blink::WebString::fromUTF16(info.name), info.icon);
+ blink::WebString::FromUTF16(info.id), info.federation,
+ blink::WebString::FromUTF16(info.name), info.icon);
case CredentialType::CREDENTIAL_TYPE_PASSWORD:
return base::MakeUnique<blink::WebPasswordCredential>(
- blink::WebString::fromUTF16(info.id),
- blink::WebString::fromUTF16(info.password),
- blink::WebString::fromUTF16(info.name), info.icon);
+ blink::WebString::FromUTF16(info.id),
+ blink::WebString::FromUTF16(info.password),
+ blink::WebString::FromUTF16(info.name), info.icon);
case CredentialType::CREDENTIAL_TYPE_EMPTY:
return nullptr;
}
@@ -70,22 +70,23 @@ blink::WebCredentialManagerError GetWebCredentialManagerErrorFromMojo(
switch (error) {
case mojom::CredentialManagerError::DISABLED:
return blink::WebCredentialManagerError::
- WebCredentialManagerDisabledError;
+ kWebCredentialManagerDisabledError;
case mojom::CredentialManagerError::PENDINGREQUEST:
return blink::WebCredentialManagerError::
- WebCredentialManagerPendingRequestError;
+ kWebCredentialManagerPendingRequestError;
case mojom::CredentialManagerError::PASSWORDSTOREUNAVAILABLE:
return blink::WebCredentialManagerError::
- WebCredentialManagerPasswordStoreUnavailableError;
+ kWebCredentialManagerPasswordStoreUnavailableError;
case mojom::CredentialManagerError::UNKNOWN:
- return blink::WebCredentialManagerError::WebCredentialManagerUnknownError;
+ return blink::WebCredentialManagerError::
+ kWebCredentialManagerUnknownError;
case mojom::CredentialManagerError::SUCCESS:
NOTREACHED();
break;
}
NOTREACHED();
- return blink::WebCredentialManagerError::WebCredentialManagerUnknownError;
+ return blink::WebCredentialManagerError::kWebCredentialManagerUnknownError;
}
// Takes ownership of blink::WebCredentialManagerClient::NotificationCallbacks
@@ -113,14 +114,14 @@ NotificationCallbacksWrapper::NotificationCallbacksWrapper(
NotificationCallbacksWrapper::~NotificationCallbacksWrapper() {
if (callbacks_)
- callbacks_->onError(blink::WebCredentialManagerUnknownError);
+ callbacks_->OnError(blink::kWebCredentialManagerUnknownError);
}
void NotificationCallbacksWrapper::NotifySuccess() {
// Call onSuccess() and reset callbacks to avoid calling onError() in
// destructor.
if (callbacks_) {
- callbacks_->onSuccess();
+ callbacks_->OnSuccess();
callbacks_.reset();
}
}
@@ -152,21 +153,21 @@ RequestCallbacksWrapper::RequestCallbacksWrapper(
RequestCallbacksWrapper::~RequestCallbacksWrapper() {
if (callbacks_)
- callbacks_->onError(blink::WebCredentialManagerUnknownError);
+ callbacks_->OnError(blink::kWebCredentialManagerUnknownError);
}
void RequestCallbacksWrapper::NotifySuccess(const CredentialInfo& info) {
// Call onSuccess() and reset callbacks to avoid calling onError() in
// destructor.
if (callbacks_) {
- callbacks_->onSuccess(CredentialInfoToWebCredential(info));
+ callbacks_->OnSuccess(CredentialInfoToWebCredential(info));
callbacks_.reset();
}
}
void RequestCallbacksWrapper::NotifyError(mojom::CredentialManagerError error) {
if (callbacks_) {
- callbacks_->onError(GetWebCredentialManagerErrorFromMojo(error));
+ callbacks_->OnError(GetWebCredentialManagerErrorFromMojo(error));
callbacks_.reset();
}
}
@@ -193,7 +194,7 @@ void RespondToRequestCallback(RequestCallbacksWrapper* callbacks_wrapper,
CredentialManagerClient::CredentialManagerClient(
content::RenderView* render_view)
: content::RenderViewObserver(render_view) {
- render_view->GetWebView()->setCredentialManagerClient(this);
+ render_view->GetWebView()->SetCredentialManagerClient(this);
}
CredentialManagerClient::~CredentialManagerClient() {}
@@ -201,7 +202,7 @@ CredentialManagerClient::~CredentialManagerClient() {}
// -----------------------------------------------------------------------------
// Access mojo CredentialManagerService.
-void CredentialManagerClient::dispatchStore(
+void CredentialManagerClient::DispatchStore(
const blink::WebCredential& credential,
blink::WebCredentialManagerClient::NotificationCallbacks* callbacks) {
DCHECK(callbacks);
@@ -215,7 +216,7 @@ void CredentialManagerClient::dispatchStore(
base::Owned(new NotificationCallbacksWrapper(callbacks))));
}
-void CredentialManagerClient::dispatchRequireUserMediation(
+void CredentialManagerClient::DispatchRequireUserMediation(
blink::WebCredentialManagerClient::NotificationCallbacks* callbacks) {
DCHECK(callbacks);
ConnectToMojoCMIfNeeded();
@@ -225,7 +226,7 @@ void CredentialManagerClient::dispatchRequireUserMediation(
base::Owned(new NotificationCallbacksWrapper(callbacks))));
}
-void CredentialManagerClient::dispatchGet(
+void CredentialManagerClient::DispatchGet(
bool zero_click_only,
bool include_passwords,
const blink::WebVector<blink::WebURL>& federations,
diff --git a/chromium/components/password_manager/content/renderer/credential_manager_client.h b/chromium/components/password_manager/content/renderer/credential_manager_client.h
index 406524faea0..388ed941ec8 100644
--- a/chromium/components/password_manager/content/renderer/credential_manager_client.h
+++ b/chromium/components/password_manager/content/renderer/credential_manager_client.h
@@ -43,11 +43,11 @@ class CredentialManagerClient : public blink::WebCredentialManagerClient,
~CredentialManagerClient() override;
// blink::WebCredentialManagerClient:
- void dispatchStore(
+ void DispatchStore(
const blink::WebCredential& credential,
WebCredentialManagerClient::NotificationCallbacks* callbacks) override;
- void dispatchRequireUserMediation(NotificationCallbacks* callbacks) override;
- void dispatchGet(bool zero_click_only,
+ void DispatchRequireUserMediation(NotificationCallbacks* callbacks) override;
+ void DispatchGet(bool zero_click_only,
bool include_passwords,
const blink::WebVector<blink::WebURL>& federations,
RequestCallbacks* callbacks) override;
diff --git a/chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc b/chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
index d52a00ac0c5..8b25db6779c 100644
--- a/chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
+++ b/chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
@@ -134,9 +134,9 @@ class TestNotificationCallbacks
~TestNotificationCallbacks() override {}
- void onSuccess() override { test_->set_callback_succeeded(true); }
+ void OnSuccess() override { test_->set_callback_succeeded(true); }
- void onError(blink::WebCredentialManagerError reason) override {
+ void OnError(blink::WebCredentialManagerError reason) override {
test_->set_callback_errored(true);
}
@@ -152,14 +152,14 @@ class TestRequestCallbacks
~TestRequestCallbacks() override {}
- void onSuccess(std::unique_ptr<blink::WebCredential> credential) override {
+ void OnSuccess(std::unique_ptr<blink::WebCredential> credential) override {
test_->set_callback_succeeded(true);
blink::WebCredential* ptr = credential.release();
test_->credential_.reset(static_cast<blink::WebPasswordCredential*>(ptr));
}
- void onError(blink::WebCredentialManagerError reason) override {
+ void OnError(blink::WebCredentialManagerError reason) override {
test_->set_callback_errored(true);
test_->credential_.reset();
test_->error_ = reason;
@@ -182,7 +182,7 @@ TEST_F(CredentialManagerClientTest, SendStore) {
credential_.reset(new blink::WebPasswordCredential("", "", "", GURL()));
std::unique_ptr<TestNotificationCallbacks> callbacks(
new TestNotificationCallbacks(this));
- client_->dispatchStore(*credential_, callbacks.release());
+ client_->DispatchStore(*credential_, callbacks.release());
RunAllPendingTasks();
@@ -193,7 +193,7 @@ TEST_F(CredentialManagerClientTest, SendStore) {
TEST_F(CredentialManagerClientTest, SendRequestUserMediation) {
std::unique_ptr<TestNotificationCallbacks> callbacks(
new TestNotificationCallbacks(this));
- client_->dispatchRequireUserMediation(callbacks.release());
+ client_->DispatchRequireUserMediation(callbacks.release());
RunAllPendingTasks();
@@ -206,14 +206,14 @@ TEST_F(CredentialManagerClientTest, SendRequestCredential) {
new TestRequestCallbacks(this));
std::vector<GURL> federations;
federations.push_back(GURL(kTestCredentialPassword));
- client_->dispatchGet(false, true, federations, callbacks.release());
+ client_->DispatchGet(false, true, federations, callbacks.release());
RunAllPendingTasks();
EXPECT_TRUE(callback_succeeded());
EXPECT_FALSE(callback_errored());
EXPECT_TRUE(credential_);
- EXPECT_EQ("password", credential_->type());
+ EXPECT_EQ("password", credential_->GetType());
}
TEST_F(CredentialManagerClientTest, SendRequestCredentialEmpty) {
@@ -221,7 +221,7 @@ TEST_F(CredentialManagerClientTest, SendRequestCredentialEmpty) {
new TestRequestCallbacks(this));
std::vector<GURL> federations;
federations.push_back(GURL(kTestCredentialEmpty));
- client_->dispatchGet(false, true, federations, callbacks.release());
+ client_->DispatchGet(false, true, federations, callbacks.release());
RunAllPendingTasks();
@@ -235,7 +235,7 @@ TEST_F(CredentialManagerClientTest, SendRequestCredentialReject) {
new TestRequestCallbacks(this));
std::vector<GURL> federations;
federations.push_back(GURL(kTestCredentialReject));
- client_->dispatchGet(false, true, federations, callbacks.release());
+ client_->DispatchGet(false, true, federations, callbacks.release());
RunAllPendingTasks();
@@ -243,7 +243,7 @@ TEST_F(CredentialManagerClientTest, SendRequestCredentialReject) {
EXPECT_TRUE(callback_errored());
EXPECT_FALSE(credential_);
EXPECT_EQ(blink::WebCredentialManagerError::
- WebCredentialManagerPasswordStoreUnavailableError,
+ kWebCredentialManagerPasswordStoreUnavailableError,
error_);
}
diff --git a/chromium/components/password_manager/core/browser/BUILD.gn b/chromium/components/password_manager/core/browser/BUILD.gn
index 6b7fe2d88fa..d7be596e6c7 100644
--- a/chromium/components/password_manager/core/browser/BUILD.gn
+++ b/chromium/components/password_manager/core/browser/BUILD.gn
@@ -8,6 +8,9 @@ if (is_android) {
import("//build/config/android/config.gni")
}
+# TODO(crbug.com/706392): Fix password reuse detection for Android.
+password_reuse_detection_support = !is_android && !is_ios
+
static_library("browser") {
sources = [
"affiliated_match_helper.cc",
@@ -52,8 +55,8 @@ static_library("browser") {
"form_saver.h",
"form_saver_impl.cc",
"form_saver_impl.h",
- "http_password_migrator.cc",
- "http_password_migrator.h",
+ "http_password_store_migrator.cc",
+ "http_password_store_migrator.h",
"import/csv_reader.cc",
"import/csv_reader.h",
"import/password_csv_reader.cc",
@@ -74,8 +77,6 @@ static_library("browser") {
"login_database_win.cc",
"login_model.cc",
"login_model.h",
- "obsolete_http_cleaner.cc",
- "obsolete_http_cleaner.h",
"password_autofill_manager.cc",
"password_autofill_manager.h",
"password_bubble_experiment.cc",
@@ -99,12 +100,6 @@ static_library("browser") {
"password_manager_settings_migration_experiment.h",
"password_manager_util.cc",
"password_manager_util.h",
- "password_reuse_detection_manager.cc",
- "password_reuse_detection_manager.h",
- "password_reuse_detector.cc",
- "password_reuse_detector.h",
- "password_reuse_detector_consumer.cc",
- "password_reuse_detector_consumer.h",
"password_store.cc",
"password_store.h",
"password_store_change.cc",
@@ -135,6 +130,17 @@ static_library("browser") {
"webdata/password_web_data_service_win.h",
]
+ if (password_reuse_detection_support) {
+ sources += [
+ "password_reuse_detection_manager.cc",
+ "password_reuse_detection_manager.h",
+ "password_reuse_detector.cc",
+ "password_reuse_detector.h",
+ "password_reuse_detector_consumer.cc",
+ "password_reuse_detector_consumer.h",
+ ]
+ }
+
public_deps = [
"//base",
"//components/sync",
@@ -167,10 +173,23 @@ static_library("browser") {
"//url",
]
+ if (!is_ios) {
+ sources += [
+ "hsts_query.cc",
+ "hsts_query.h",
+ "http_data_cleaner.cc",
+ "http_data_cleaner.h",
+ ]
+ }
+
if (is_mac || is_ios) {
sources -= [ "login_database_posix.cc" ]
}
+ if (!is_ios) {
+ deps += [ "//components/safe_browsing/password_protection" ]
+ }
+
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
}
@@ -219,6 +238,7 @@ static_library("test_support") {
deps = [
"//base",
"//components/autofill/core/common",
+ "//net:net",
"//testing/gtest",
]
}
@@ -237,6 +257,7 @@ bundle_data("unit_tests_bundle_data") {
"//components/test/data/password_manager/login_db_v16.sql",
"//components/test/data/password_manager/login_db_v17.sql",
"//components/test/data/password_manager/login_db_v18.sql",
+ "//components/test/data/password_manager/login_db_v19.sql",
"//components/test/data/password_manager/login_db_v1_broken.sql",
"//components/test/data/password_manager/login_db_v2.sql",
"//components/test/data/password_manager/login_db_v2_broken.sql",
@@ -275,7 +296,7 @@ source_set("unit_tests") {
"facet_manager_unittest.cc",
"form_fetcher_impl_unittest.cc",
"form_saver_impl_unittest.cc",
- "http_password_migrator_unittest.cc",
+ "http_password_store_migrator_unittest.cc",
"import/csv_reader_unittest.cc",
"import/password_csv_reader_unittest.cc",
"import/password_importer_unittest.cc",
@@ -283,7 +304,6 @@ source_set("unit_tests") {
"log_router_unittest.cc",
"login_database_unittest.cc",
"login_model_unittest.cc",
- "obsolete_http_cleaner_unittest.cc",
"password_autofill_manager_unittest.cc",
"password_bubble_experiment_unittest.cc",
"password_form_manager_unittest.cc",
@@ -291,8 +311,6 @@ source_set("unit_tests") {
"password_manager_settings_migration_experiment_unittest.cc",
"password_manager_unittest.cc",
"password_manager_util_unittest.cc",
- "password_reuse_detection_manager_unittest.cc",
- "password_reuse_detector_unittest.cc",
"password_store_default_unittest.cc",
"password_store_origin_unittest.h",
"password_store_unittest.cc",
@@ -305,6 +323,20 @@ source_set("unit_tests") {
if (is_mac) {
sources -= [ "password_store_default_unittest.cc" ]
}
+ if (is_ios) {
+ sources += [ "login_database_ios_unittest.cc" ]
+ } else {
+ sources += [
+ "hsts_query_unittest.cc",
+ "http_data_cleaner_unittest.cc",
+ ]
+ }
+ if (password_reuse_detection_support) {
+ sources += [
+ "password_reuse_detection_manager_unittest.cc",
+ "password_reuse_detector_unittest.cc",
+ ]
+ }
deps = [
":test_support",
":unit_tests_bundle_data",
diff --git a/chromium/components/password_manager/core/browser/DEPS b/chromium/components/password_manager/core/browser/DEPS
index fac484e01a7..2b537df53bd 100644
--- a/chromium/components/password_manager/core/browser/DEPS
+++ b/chromium/components/password_manager/core/browser/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+components/autofill/core/browser",
"+components/keyed_service/core",
"+components/pref_registry",
+ "+components/safe_browsing/password_protection",
"+components/security_state",
"+components/sync/base",
"+components/sync/driver",
diff --git a/chromium/components/password_manager/core/browser/affiliation_fetcher.cc b/chromium/components/password_manager/core/browser/affiliation_fetcher.cc
index b1dd01a944a..15eae8c99d6 100644
--- a/chromium/components/password_manager/core/browser/affiliation_fetcher.cc
+++ b/chromium/components/password_manager/core/browser/affiliation_fetcher.cc
@@ -113,13 +113,13 @@ void AffiliationFetcher::StartRequest() {
setting:
"Users can enable or disable this feature either by stoping "
"syncing passwords to Google (via unchecking 'Passwords' in "
- "Chrome's settings under 'Sign In', 'Advanced sync settings') or "
+ "Chromium's settings under 'Sign In', 'Advanced sync settings') or "
"by introducing a custom passphrase to disable this service. The "
"feature is enabled by default."
- policy {
+ chrome_policy {
SyncDisabled {
policy_options {mode: MANDATORY}
- value: True
+ SyncDisabled: True
}
}
})");
diff --git a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
index db8803d8e57..e2523ec7a17 100644
--- a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
+++ b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
@@ -161,7 +161,7 @@ std::string BrowserSavePasswordProgressLogger::FormStructureToFieldsLogString(
void BrowserSavePasswordProgressLogger::LogString(StringID label,
const std::string& s) {
- LogValue(label, base::StringValue(s));
+ LogValue(label, base::Value(s));
}
void BrowserSavePasswordProgressLogger::SendLog(const std::string& log) {
diff --git a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc
index 0677a17f1c3..4406d199bef 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc
@@ -37,12 +37,12 @@ CredentialManagerPasswordFormManager::CredentialManagerPasswordFormManager(
form_fetcher.get()),
delegate_(delegate),
saved_form_(std::move(saved_form)),
- form_fetcher_(std::move(form_fetcher)),
weak_factory_(this) {
DCHECK(saved_form_);
// This condition is only false on iOS.
- if (form_fetcher_)
- form_fetcher_->Fetch();
+ if (form_fetcher)
+ form_fetcher->Fetch();
+ GrabFetcher(std::move(form_fetcher));
}
CredentialManagerPasswordFormManager::~CredentialManagerPasswordFormManager() {
diff --git a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h
index d41f8079297..4816e1768bc 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h
+++ b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h
@@ -52,17 +52,12 @@ class CredentialManagerPasswordFormManager : public PasswordFormManager {
const std::vector<const autofill::PasswordForm*>& non_federated,
size_t filtered_count) override;
-#if defined(UNIT_TEST)
- FormFetcher* form_fetcher() const { return form_fetcher_.get(); }
-#endif // defined(UNIT_TEST)
-
private:
// Calls OnProvisionalSaveComplete on |delegate_|.
void NotifyDelegate();
CredentialManagerPasswordFormManagerDelegate* delegate_;
std::unique_ptr<autofill::PasswordForm> saved_form_;
- std::unique_ptr<FormFetcher> form_fetcher_;
base::WeakPtrFactory<CredentialManagerPasswordFormManager> weak_factory_;
diff --git a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc
index 63c79bb0a5c..cd89fb0e894 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc
@@ -11,6 +11,7 @@
#include "base/memory/ptr_util.h"
#include "base/metrics/user_metrics.h"
+#include "base/stl_util.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/affiliated_match_helper.h"
#include "components/password_manager/core/browser/password_bubble_experiment.h"
@@ -95,15 +96,14 @@ void FilterDuplicatesAndEmptyUsername(
bool* has_empty_username,
bool* has_duplicates) {
// Remove empty usernames from the list.
- auto begin_empty =
- std::remove_if(forms->begin(), forms->end(),
- [](const std::unique_ptr<autofill::PasswordForm>& form) {
- return form->username_value.empty();
- });
- *has_empty_username = (begin_empty != forms->end());
- forms->erase(begin_empty, forms->end());
+ size_t size_before = forms->size();
+ base::EraseIf(*forms,
+ [](const std::unique_ptr<autofill::PasswordForm>& form) {
+ return form->username_value.empty();
+ });
+ *has_empty_username = (size_before != forms->size());
- const size_t size_before = forms->size();
+ size_before = forms->size();
FilterDuplicates(forms);
*has_duplicates = (size_before != forms->size());
}
@@ -131,11 +131,11 @@ CredentialManagerPendingRequestTask::~CredentialManagerPendingRequestTask() =
void CredentialManagerPendingRequestTask::OnGetPasswordStoreResults(
std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
- if (results.empty()) {
+ // localhost is a secure origin but not https.
+ if (results.empty() && origin_.SchemeIs(url::kHttpsScheme)) {
// Try to migrate the HTTP passwords and process them later.
- http_migrator_ = base::MakeUnique<HttpPasswordMigrator>(
- origin_, HttpPasswordMigrator::MigrationMode::COPY,
- delegate_->client()->GetPasswordStore(), this);
+ http_migrator_ = base::MakeUnique<HttpPasswordStoreMigrator>(
+ origin_, delegate_->client(), this);
return;
}
ProcessForms(std::move(results));
diff --git a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h
index 289a820efb4..a444a723130 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h
+++ b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h
@@ -12,7 +12,7 @@
#include "base/callback_forward.h"
#include "base/macros.h"
-#include "components/password_manager/core/browser/http_password_migrator.h"
+#include "components/password_manager/core/browser/http_password_store_migrator.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
#include "url/gurl.h"
@@ -55,7 +55,7 @@ class CredentialManagerPendingRequestTaskDelegate {
// Retrieves credentials from the PasswordStore.
class CredentialManagerPendingRequestTask
: public PasswordStoreConsumer,
- public HttpPasswordMigrator::Consumer {
+ public HttpPasswordStoreMigrator::Consumer {
public:
CredentialManagerPendingRequestTask(
CredentialManagerPendingRequestTaskDelegate* delegate,
@@ -73,7 +73,7 @@ class CredentialManagerPendingRequestTask
std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
private:
- // HttpPasswordMigrator::Consumer:
+ // HttpPasswordStoreMigrator::Consumer:
void ProcessMigratedForms(
std::vector<std::unique_ptr<autofill::PasswordForm>> forms) override;
@@ -87,7 +87,7 @@ class CredentialManagerPendingRequestTask
const bool include_passwords_;
std::set<std::string> federations_;
- std::unique_ptr<HttpPasswordMigrator> http_migrator_;
+ std::unique_ptr<HttpPasswordStoreMigrator> http_migrator_;
DISALLOW_COPY_AND_ASSIGN(CredentialManagerPendingRequestTask);
};
diff --git a/chromium/components/password_manager/core/browser/fake_form_fetcher.cc b/chromium/components/password_manager/core/browser/fake_form_fetcher.cc
index 3f0ca14b1f8..e2f13a896c3 100644
--- a/chromium/components/password_manager/core/browser/fake_form_fetcher.cc
+++ b/chromium/components/password_manager/core/browser/fake_form_fetcher.cc
@@ -19,6 +19,10 @@ void FakeFormFetcher::AddConsumer(Consumer* consumer) {
consumers_.insert(consumer);
}
+void FakeFormFetcher::RemoveConsumer(Consumer* consumer) {
+ consumers_.erase(consumer);
+}
+
FormFetcher::State FakeFormFetcher::GetState() const {
return state_;
}
@@ -46,4 +50,8 @@ void FakeFormFetcher::Fetch() {
state_ = State::WAITING;
}
+std::unique_ptr<FormFetcher> FakeFormFetcher::Clone() {
+ return nullptr;
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/fake_form_fetcher.h b/chromium/components/password_manager/core/browser/fake_form_fetcher.h
index 93fa7e39846..891291d1938 100644
--- a/chromium/components/password_manager/core/browser/fake_form_fetcher.h
+++ b/chromium/components/password_manager/core/browser/fake_form_fetcher.h
@@ -33,6 +33,8 @@ class FakeFormFetcher : public FormFetcher {
// has to first call AddConsumer and then SetNonFederated.
void AddConsumer(Consumer* consumer) override;
+ void RemoveConsumer(Consumer* consumer) override;
+
// Returns State::WAITING if Fetch() was called after any Set* calls, and
// State::NOT_WAITING otherwise.
State GetState() const override;
@@ -61,6 +63,9 @@ class FakeFormFetcher : public FormFetcher {
// Only sets the internal state to WAITING, no call to PasswordStore.
void Fetch() override;
+ // A no-op, returns null.
+ std::unique_ptr<FormFetcher> Clone() override;
+
private:
std::set<Consumer*> consumers_;
State state_ = State::NOT_WAITING;
diff --git a/chromium/components/password_manager/core/browser/form_fetcher.h b/chromium/components/password_manager/core/browser/form_fetcher.h
index e2e16423c7f..bfbd22f7709 100644
--- a/chromium/components/password_manager/core/browser/form_fetcher.h
+++ b/chromium/components/password_manager/core/browser/form_fetcher.h
@@ -56,6 +56,9 @@ class FormFetcher {
// |consumer| outlives |this|.
virtual void AddConsumer(Consumer* consumer) = 0;
+ // Call this to stop |consumer| from receiving updates from |this|.
+ virtual void RemoveConsumer(Consumer* consumer) = 0;
+
// Returns the current state of the FormFetcher
virtual State GetState() const = 0;
@@ -74,6 +77,11 @@ class FormFetcher {
// of the cached credentials.
virtual void Fetch() = 0;
+ // Creates a copy of |*this| with contains the same credentials without the
+ // need for calling Fetch(). Only call this if GetState() returns NOT_WAITING,
+ // otherwise the original FormFetcher does not have any data to be cloned.
+ virtual std::unique_ptr<FormFetcher> Clone() = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(FormFetcher);
};
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 6bff00d8fc6..b73501a2c74 100644
--- a/chromium/components/password_manager/core/browser/form_fetcher_impl.cc
+++ b/chromium/components/password_manager/core/browser/form_fetcher_impl.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <utility>
+#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
@@ -56,6 +57,18 @@ std::vector<const PasswordForm*> MakeWeakCopies(
return result;
}
+// Create a vector of unique_ptr<PasswordForm> from another such vector by
+// copying the pointed-to forms.
+std::vector<std::unique_ptr<PasswordForm>> MakeCopies(
+ const std::vector<std::unique_ptr<PasswordForm>>& source) {
+ std::vector<std::unique_ptr<PasswordForm>> result(source.size());
+ std::transform(source.begin(), source.end(), result.begin(),
+ [](const std::unique_ptr<PasswordForm>& ptr) {
+ return base::MakeUnique<PasswordForm>(*ptr);
+ });
+ return result;
+}
+
} // namespace
FormFetcherImpl::FormFetcherImpl(PasswordStore::FormDigest form_digest,
@@ -74,6 +87,11 @@ void FormFetcherImpl::AddConsumer(FormFetcher::Consumer* consumer) {
consumer->ProcessMatches(weak_non_federated_, filtered_count_);
}
+void FormFetcherImpl::RemoveConsumer(FormFetcher::Consumer* consumer) {
+ size_t removed_consumers = consumers_.erase(consumer);
+ DCHECK_EQ(1u, removed_consumers);
+}
+
FormFetcherImpl::State FormFetcherImpl::GetState() const {
return state_;
}
@@ -91,10 +109,10 @@ const std::vector<const PasswordForm*>& FormFetcherImpl::GetFederatedMatches()
void FormFetcherImpl::OnGetPasswordStoreResults(
std::vector<std::unique_ptr<PasswordForm>> results) {
DCHECK_EQ(State::WAITING, state_);
- state_ = State::NOT_WAITING;
if (need_to_refetch_) {
// The received results are no longer up to date, need to re-request.
+ state_ = State::NOT_WAITING;
Fetch();
need_to_refetch_ = false;
return;
@@ -110,9 +128,8 @@ void FormFetcherImpl::OnGetPasswordStoreResults(
if (should_migrate_http_passwords_ && results.empty() &&
form_digest_.origin.SchemeIs(url::kHttpsScheme)) {
- http_migrator_ = base::MakeUnique<HttpPasswordMigrator>(
- form_digest_.origin, HttpPasswordMigrator::MigrationMode::COPY,
- client_->GetPasswordStore(), this);
+ http_migrator_ = base::MakeUnique<HttpPasswordStoreMigrator>(
+ form_digest_.origin, client_, this);
return;
}
@@ -166,8 +183,32 @@ void FormFetcherImpl::Fetch() {
#endif
}
+std::unique_ptr<FormFetcher> FormFetcherImpl::Clone() {
+ DCHECK_EQ(State::NOT_WAITING, state_);
+
+ // Create the copy without the "HTTPS migration" activated. If it was needed,
+ // then it was done by |this| already.
+ auto result = base::MakeUnique<FormFetcherImpl>(form_digest_, client_, false);
+
+ result->non_federated_ = MakeCopies(this->non_federated_);
+ result->federated_ = MakeCopies(this->federated_);
+ result->interactions_stats_ = this->interactions_stats_;
+
+ result->weak_non_federated_ = MakeWeakCopies(result->non_federated_);
+ result->weak_federated_ = MakeWeakCopies(result->federated_);
+
+ result->filtered_count_ = this->filtered_count_;
+ result->state_ = this->state_;
+ result->need_to_refetch_ = this->need_to_refetch_;
+
+ // TODO(crbug.com/703565): remove std::move() once Xcode 9.0+ is required.
+ return std::move(result);
+}
+
void FormFetcherImpl::ProcessPasswordStoreResults(
std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+ DCHECK_EQ(State::WAITING, state_);
+ state_ = State::NOT_WAITING;
federated_ = SplitFederatedMatches(&results);
non_federated_ = std::move(results);
diff --git a/chromium/components/password_manager/core/browser/form_fetcher_impl.h b/chromium/components/password_manager/core/browser/form_fetcher_impl.h
index 0a7b2a556b0..af6ba69f034 100644
--- a/chromium/components/password_manager/core/browser/form_fetcher_impl.h
+++ b/chromium/components/password_manager/core/browser/form_fetcher_impl.h
@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "components/password_manager/core/browser/form_fetcher.h"
-#include "components/password_manager/core/browser/http_password_migrator.h"
+#include "components/password_manager/core/browser/http_password_store_migrator.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
@@ -23,7 +23,7 @@ class PasswordManagerClient;
// with a particular origin.
class FormFetcherImpl : public FormFetcher,
public PasswordStoreConsumer,
- public HttpPasswordMigrator::Consumer {
+ public HttpPasswordStoreMigrator::Consumer {
public:
// |form_digest| describes what credentials need to be retrieved and
// |client| serves the PasswordStore, the logging information etc.
@@ -35,18 +35,20 @@ class FormFetcherImpl : public FormFetcher,
// FormFetcher:
void AddConsumer(FormFetcher::Consumer* consumer) override;
+ void RemoveConsumer(FormFetcher::Consumer* consumer) override;
State GetState() const override;
const std::vector<InteractionsStats>& GetInteractionsStats() const override;
const std::vector<const autofill::PasswordForm*>& GetFederatedMatches()
const override;
void Fetch() override;
+ std::unique_ptr<FormFetcher> Clone() override;
// PasswordStoreConsumer:
void OnGetPasswordStoreResults(
std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
void OnGetSiteStatistics(std::vector<InteractionsStats> stats) override;
- // HttpPasswordMigrator::Consumer:
+ // HttpPasswordStoreMigrator::Consumer:
void ProcessMigratedForms(
std::vector<std::unique_ptr<autofill::PasswordForm>> forms) override;
@@ -94,7 +96,7 @@ class FormFetcherImpl : public FormFetcher,
const bool should_migrate_http_passwords_;
// Does the actual migration.
- std::unique_ptr<HttpPasswordMigrator> http_migrator_;
+ std::unique_ptr<HttpPasswordStoreMigrator> http_migrator_;
DISALLOW_COPY_AND_ASSIGN(FormFetcherImpl);
};
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 4dd2d5931d8..90c36a90dbf 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
@@ -13,6 +13,7 @@
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
@@ -60,12 +61,9 @@ class NameFilter : public StubCredentialsFilter {
std::vector<std::unique_ptr<PasswordForm>> FilterResults(
std::vector<std::unique_ptr<PasswordForm>> results) const override {
- results.erase(
- std::remove_if(results.begin(), results.end(),
- [this](const std::unique_ptr<PasswordForm>& form) {
- return !ShouldSave(*form);
- }),
- results.end());
+ base::EraseIf(results, [this](const std::unique_ptr<PasswordForm>& form) {
+ return !ShouldSave(*form);
+ });
return results;
}
@@ -154,23 +152,6 @@ std::vector<std::unique_ptr<PasswordForm>> MakeResults(
return results;
}
-class MockFormFetcherImpl : public FormFetcherImpl {
- public:
- // Inherit constructors.
- using FormFetcherImpl::FormFetcherImpl;
-
- // Google Mock is currently unable to mock |ProcessMigratedForms| due to the
- // presence of move-only types. In order to ensure it is called, a dummy is
- // added which can be passed to |EXPECT_CALL|.
- void ProcessMigratedForms(
- std::vector<std::unique_ptr<autofill::PasswordForm>> results) override {
- FormFetcherImpl::ProcessMigratedForms(std::move(results));
- ProcessMigratedFormsDummy();
- }
-
- MOCK_METHOD0(ProcessMigratedFormsDummy, void());
-};
-
ACTION_P(GetAndAssignWeakPtr, ptr) {
*ptr = arg0->GetWeakPtr();
}
@@ -417,7 +398,7 @@ TEST_F(FormFetcherImplTest, DoNotTryToMigrateHTTPPasswordsOnHTTPSites) {
// A new form fetcher is created to be able to set the form digest and
// migration flag.
- form_fetcher_ = base::MakeUnique<MockFormFetcherImpl>(
+ form_fetcher_ = base::MakeUnique<FormFetcherImpl>(
form_digest_, &client_, /* should_migrate_http_passwords */ true);
EXPECT_CALL(consumer_, ProcessMatches(IsEmpty(), 0u));
form_fetcher_->AddConsumer(&consumer_);
@@ -459,7 +440,7 @@ TEST_F(FormFetcherImplTest, TryToMigrateHTTPPasswordsOnHTTPSSites) {
// A new form fetcher is created to be able to set the form digest and
// migration flag.
- form_fetcher_ = base::MakeUnique<MockFormFetcherImpl>(
+ form_fetcher_ = base::MakeUnique<FormFetcherImpl>(
form_digest_, &client_, /* should_migrate_http_passwords */ true);
EXPECT_CALL(consumer_, ProcessMatches(IsEmpty(), 0u));
form_fetcher_->AddConsumer(&consumer_);
@@ -492,11 +473,9 @@ TEST_F(FormFetcherImplTest, TryToMigrateHTTPPasswordsOnHTTPSSites) {
// Now perform the actual migration.
EXPECT_CALL(*mock_store_, AddLogin(https_form));
- EXPECT_CALL(*static_cast<MockFormFetcherImpl*>(form_fetcher_.get()),
- ProcessMigratedFormsDummy());
EXPECT_CALL(consumer_,
ProcessMatches(UnorderedElementsAre(Pointee(https_form)), 0u));
- static_cast<HttpPasswordMigrator*>(migrator_ptr.get())
+ static_cast<HttpPasswordStoreMigrator*>(migrator_ptr.get())
->OnGetPasswordStoreResults(MakeResults({http_form}));
EXPECT_THAT(form_fetcher_->GetFederatedMatches(), IsEmpty());
@@ -519,4 +498,131 @@ TEST_F(FormFetcherImplTest, TryToMigrateHTTPPasswordsOnHTTPSSites) {
UnorderedElementsAre(Pointee(federated_form)));
}
+// When the FormFetcher delegates to the HttpPasswordMigrator, its state should
+// be WAITING until the migrator passes the results.
+TEST_F(FormFetcherImplTest, StateIsWaitingDuringMigration) {
+ GURL::Replacements https_rep;
+ https_rep.SetSchemeStr(url::kHttpsScheme);
+ const GURL https_origin = form_digest_.origin.ReplaceComponents(https_rep);
+ form_digest_ = PasswordStore::FormDigest(
+ PasswordForm::SCHEME_HTML, https_origin.GetOrigin().spec(), https_origin);
+
+ // A new form fetcher is created to be able to set the form digest and
+ // migration flag.
+ form_fetcher_ = base::MakeUnique<FormFetcherImpl>(
+ form_digest_, &client_, /* should_migrate_http_passwords */ true);
+
+ PasswordForm https_form = CreateNonFederated();
+
+ // Create HTTP form for the same orgin (except scheme), which will be passed
+ // to the migrator.
+ GURL::Replacements http_rep;
+ http_rep.SetSchemeStr(url::kHttpScheme);
+ PasswordForm http_form = https_form;
+ http_form.origin = https_form.origin.ReplaceComponents(http_rep);
+ http_form.signon_realm = http_form.origin.GetOrigin().spec();
+
+ std::vector<PasswordForm> empty_forms;
+
+ // Ensure there is an attempt to migrate credentials on HTTPS origins and
+ // extract the migrator.
+ const GURL form_digest_http_origin =
+ form_digest_.origin.ReplaceComponents(http_rep);
+ PasswordStore::FormDigest http_form_digest(
+ PasswordForm::SCHEME_HTML, form_digest_http_origin.GetOrigin().spec(),
+ form_digest_http_origin);
+ Fetch();
+ // First the FormFetcher is waiting for the initial response from
+ // PasswordStore.
+ EXPECT_EQ(FormFetcher::State::WAITING, form_fetcher_->GetState());
+ base::WeakPtr<PasswordStoreConsumer> migrator_ptr;
+ EXPECT_CALL(*mock_store_, GetLogins(http_form_digest, _))
+ .WillOnce(WithArg<1>(GetAndAssignWeakPtr(&migrator_ptr)));
+ form_fetcher_->OnGetPasswordStoreResults(MakeResults(empty_forms));
+ ASSERT_TRUE(migrator_ptr);
+ // While the initial results from PasswordStore arrived to the FormFetcher, it
+ // should be still waiting for the migrator.
+ EXPECT_EQ(FormFetcher::State::WAITING, form_fetcher_->GetState());
+
+ // Now perform the actual migration.
+ EXPECT_CALL(*mock_store_, AddLogin(https_form));
+ static_cast<HttpPasswordStoreMigrator*>(migrator_ptr.get())
+ ->OnGetPasswordStoreResults(MakeResults({http_form}));
+ EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
+}
+
+// Cloning a FormFetcherImpl with empty results should result in an
+// instance with empty results.
+TEST_F(FormFetcherImplTest, Clone_EmptyResults) {
+ Fetch();
+ form_fetcher_->OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>>());
+
+ // Clone() should not cause re-fetching from PasswordStore.
+ EXPECT_CALL(*mock_store_, GetLogins(_, _)).Times(0);
+ auto clone = form_fetcher_->Clone();
+ EXPECT_EQ(FormFetcher::State::NOT_WAITING, clone->GetState());
+ EXPECT_THAT(clone->GetInteractionsStats(), IsEmpty());
+ EXPECT_THAT(clone->GetFederatedMatches(), IsEmpty());
+ MockConsumer consumer;
+ EXPECT_CALL(consumer, ProcessMatches(IsEmpty(), 0u));
+ clone->AddConsumer(&consumer);
+}
+
+// Cloning a FormFetcherImpl with non-empty results should result in an
+// instance with the same results.
+TEST_F(FormFetcherImplTest, Clone_NonEmptyResults) {
+ Fetch();
+ PasswordForm non_federated = CreateNonFederated();
+ PasswordForm federated = CreateFederated();
+ PasswordForm android_federated = CreateAndroidFederated();
+ std::vector<std::unique_ptr<PasswordForm>> results;
+ results.push_back(base::MakeUnique<PasswordForm>(non_federated));
+ results.push_back(base::MakeUnique<PasswordForm>(federated));
+ results.push_back(base::MakeUnique<PasswordForm>(android_federated));
+ form_fetcher_->OnGetPasswordStoreResults(std::move(results));
+
+ // Clone() should not cause re-fetching from PasswordStore.
+ EXPECT_CALL(*mock_store_, GetLogins(_, _)).Times(0);
+ auto clone = form_fetcher_->Clone();
+
+ // Additionally, destroy the original FormFetcher. This should not invalidate
+ // the data in |clone|.
+ form_fetcher_.reset();
+
+ EXPECT_EQ(FormFetcher::State::NOT_WAITING, clone->GetState());
+ EXPECT_THAT(clone->GetInteractionsStats(), IsEmpty());
+ EXPECT_THAT(
+ clone->GetFederatedMatches(),
+ UnorderedElementsAre(Pointee(federated), Pointee(android_federated)));
+ MockConsumer consumer;
+ EXPECT_CALL(consumer,
+ ProcessMatches(UnorderedElementsAre(Pointee(non_federated)), 0u));
+ clone->AddConsumer(&consumer);
+}
+
+// Cloning a FormFetcherImpl with some stats should result in an instance with
+// the same stats.
+TEST_F(FormFetcherImplTest, Clone_Stats) {
+ Fetch();
+ // Pass empty results to make the state NOT_WAITING.
+ form_fetcher_->OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>>());
+ std::vector<InteractionsStats> stats(1);
+ form_fetcher_->OnGetSiteStatistics(std::move(stats));
+
+ auto clone = form_fetcher_->Clone();
+ EXPECT_EQ(1u, clone->GetInteractionsStats().size());
+}
+
+// Check that removing consumers stops them from receiving store updates.
+TEST_F(FormFetcherImplTest, RemoveConsumer) {
+ Fetch();
+ form_fetcher_->AddConsumer(&consumer_);
+ form_fetcher_->RemoveConsumer(&consumer_);
+ EXPECT_CALL(consumer_, ProcessMatches(_, _)).Times(0);
+ form_fetcher_->OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>>());
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/hsts_query.cc b/chromium/components/password_manager/core/browser/hsts_query.cc
new file mode 100644
index 00000000000..24810d3220c
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/hsts_query.cc
@@ -0,0 +1,44 @@
+// 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/password_manager/core/browser/hsts_query.h"
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/task_runner_util.h"
+#include "net/url_request/url_request_context.h"
+#include "url/gurl.h"
+
+namespace password_manager {
+
+namespace {
+
+bool IsHSTSActiveForHostAndRequestContext(
+ const GURL& origin,
+ const scoped_refptr<net::URLRequestContextGetter>& request_context) {
+ if (!origin.is_valid())
+ return false;
+
+ net::TransportSecurityState* security_state =
+ request_context->GetURLRequestContext()->transport_security_state();
+
+ if (!security_state)
+ return false;
+
+ return security_state->ShouldUpgradeToSSL(origin.host());
+}
+
+} // namespace
+
+void PostHSTSQueryForHostAndRequestContext(
+ const GURL& origin,
+ const scoped_refptr<net::URLRequestContextGetter>& request_context,
+ const HSTSCallback& callback) {
+ base::PostTaskAndReplyWithResult(
+ request_context->GetNetworkTaskRunner().get(), FROM_HERE,
+ base::Bind(&IsHSTSActiveForHostAndRequestContext, origin,
+ request_context),
+ callback);
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/hsts_query.h b/chromium/components/password_manager/core/browser/hsts_query.h
new file mode 100644
index 00000000000..59cf7771d1d
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/hsts_query.h
@@ -0,0 +1,28 @@
+// 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_PASSWORD_MANAGER_CORE_BROWSER_HSTS_QUERY_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_HSTS_QUERY_H_
+
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "net/url_request/url_request_context_getter.h"
+
+class GURL;
+
+namespace password_manager {
+
+using HSTSCallback = base::Callback<void(bool)>;
+
+// Checks asynchronously whether HTTP Strict Transport Security (HSTS) is active
+// for the host of the given origin for a given request context. Notifies
+// |callback| with the result on the calling thread.
+void PostHSTSQueryForHostAndRequestContext(
+ const GURL& origin,
+ const scoped_refptr<net::URLRequestContextGetter>& request_context,
+ const HSTSCallback& callback);
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_HSTS_QUERY_H_
diff --git a/chromium/components/password_manager/core/browser/hsts_query_unittest.cc b/chromium/components/password_manager/core/browser/hsts_query_unittest.cc
new file mode 100644
index 00000000000..3f5f0a1bade
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/hsts_query_unittest.cc
@@ -0,0 +1,64 @@
+// 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/password_manager/core/browser/hsts_query.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/password_manager/core/browser/password_manager_test_utils.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace password_manager {
+
+class HSTSQueryTest : public testing::Test {
+ public:
+ HSTSQueryTest()
+ : request_context_(new net::TestURLRequestContextGetter(
+ base::ThreadTaskRunnerHandle::Get())) {}
+
+ const scoped_refptr<net::TestURLRequestContextGetter>& request_context() {
+ return request_context_;
+ }
+
+ private:
+ base::MessageLoop message_loop_; // Used by request_context_.
+ scoped_refptr<net::TestURLRequestContextGetter> request_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(HSTSQueryTest);
+};
+
+TEST_F(HSTSQueryTest, TestPostHSTSQueryForHostAndRequestContext) {
+ const GURL origin("https://example.org");
+ for (bool is_hsts : {false, true}) {
+ SCOPED_TRACE(testing::Message()
+ << std::boolalpha << "is_hsts: " << is_hsts);
+
+ HSTSStateManager manager(
+ request_context()->GetURLRequestContext()->transport_security_state(),
+ is_hsts, origin.host());
+ // Post query and ensure callback gets run.
+ bool callback_ran = false;
+ PostHSTSQueryForHostAndRequestContext(
+ origin, request_context(),
+ base::Bind(
+ [](bool* ran, bool expectation, bool result) {
+ *ran = true;
+ EXPECT_EQ(expectation, result);
+ },
+ &callback_ran, is_hsts));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(callback_ran);
+ }
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/http_data_cleaner.cc b/chromium/components/password_manager/core/browser/http_data_cleaner.cc
new file mode 100644
index 00000000000..0df47eab8dc
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/http_data_cleaner.cc
@@ -0,0 +1,272 @@
+// 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/password_manager/core/browser/http_data_cleaner.h"
+
+#include <algorithm>
+#include <iterator>
+#include <memory>
+#include <tuple>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/keyed_service/core/service_access_type.h"
+#include "components/password_manager/core/browser/hsts_query.h"
+#include "components/password_manager/core/browser/password_store.h"
+#include "components/password_manager/core/browser/password_store_consumer.h"
+#include "components/password_manager/core/browser/statistics_table.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_service.h"
+
+using autofill::PasswordForm;
+
+namespace password_manager {
+
+namespace {
+
+constexpr int kDefaultDelay = 40;
+
+// Utility function that moves all elements from a specified iterator into a new
+// vector and returns it. The moved elements are deleted from the original
+// vector.
+std::vector<std::unique_ptr<PasswordForm>> SplitFormsFrom(
+ std::vector<std::unique_ptr<PasswordForm>>::iterator from,
+ std::vector<std::unique_ptr<PasswordForm>>* forms) {
+ const auto end_forms = std::end(*forms);
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ result.reserve(std::distance(from, end_forms));
+ std::move(from, end_forms, std::back_inserter(result));
+ forms->erase(from, end_forms);
+ return result;
+}
+
+void RemoveLoginIfHSTS(const scoped_refptr<PasswordStore>& store,
+ const PasswordForm& form,
+ bool is_hsts) {
+ if (is_hsts)
+ store->RemoveLogin(form);
+}
+
+void RemoveSiteStatsIfHSTS(const scoped_refptr<PasswordStore>& store,
+ const InteractionsStats& stats,
+ bool is_hsts) {
+ if (is_hsts)
+ store->RemoveSiteStats(stats.origin_domain);
+}
+
+// This class removes obsolete HTTP data from a password store. HTTP data is
+// obsolete if the corresponding host migrated to HTTPS and has HSTS enabled.
+class ObsoleteHttpCleaner : public password_manager::PasswordStoreConsumer {
+ public:
+ // Constructing a ObsoleteHttpCleaner will result in issuing the clean up
+ // tasks already.
+ ObsoleteHttpCleaner(
+ const scoped_refptr<PasswordStore>& store,
+ const scoped_refptr<net::URLRequestContextGetter>& request_context);
+ ~ObsoleteHttpCleaner() override;
+
+ // PasswordStoreConsumer:
+ // This will be called for both autofillable logins as well as blacklisted
+ // logins. Blacklisted logins are removed iff the scheme is HTTP and HSTS is
+ // enabled for the host.
+ // Autofillable logins are removed iff the scheme is HTTP and there exists
+ // another HTTPS login with active HSTS that has the same host as well as the
+ // same username and password.
+ void OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>> results) override;
+
+ // This will remove all stats for HTTP sites for which HSTS is active.
+ void OnGetSiteStatistics(std::vector<InteractionsStats> stats) override;
+
+ PasswordStore* store() { return store_.get(); }
+
+ const scoped_refptr<net::URLRequestContextGetter>& request_context() {
+ return request_context_;
+ }
+
+ bool finished_cleaning() const { return remaining_cleaning_tasks_ == 0; }
+
+ private:
+ scoped_refptr<PasswordStore> store_;
+ scoped_refptr<net::URLRequestContextGetter> request_context_;
+ // There are 3 cleaning tasks initiated in the constructor.
+ int remaining_cleaning_tasks_ = 3;
+
+ DISALLOW_COPY_AND_ASSIGN(ObsoleteHttpCleaner);
+};
+
+ObsoleteHttpCleaner::ObsoleteHttpCleaner(
+ const scoped_refptr<PasswordStore>& password_store,
+ const scoped_refptr<net::URLRequestContextGetter>& request_context)
+ : store_(password_store), request_context_(request_context) {
+ DCHECK(store_);
+ DCHECK(request_context_.get());
+ store()->GetBlacklistLogins(this);
+ store()->GetAutofillableLogins(this);
+ store()->GetAllSiteStats(this);
+}
+
+ObsoleteHttpCleaner::~ObsoleteHttpCleaner() = default;
+
+void ObsoleteHttpCleaner::OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>> results) {
+ --remaining_cleaning_tasks_;
+ // Non HTTP or HTTPS credentials are ignored.
+ base::EraseIf(results, [](const std::unique_ptr<PasswordForm>& form) {
+ return !form->origin.SchemeIsHTTPOrHTTPS();
+ });
+
+ // Move HTTPS forms into their own container.
+ auto https_forms = SplitFormsFrom(
+ std::partition(std::begin(results), std::end(results),
+ [](const std::unique_ptr<PasswordForm>& form) {
+ return form->origin.SchemeIs(url::kHttpScheme);
+ }),
+ &results);
+
+ // Move blacklisted HTTP forms into their own container.
+ const auto blacklisted_http_forms = SplitFormsFrom(
+ std::partition(std::begin(results), std::end(results),
+ [](const std::unique_ptr<PasswordForm>& form) {
+ return !form->blacklisted_by_user;
+ }),
+ &results);
+
+ // Remove blacklisted HTTP forms from the password store when HSTS is active
+ // for the given host.
+ for (const auto& form : blacklisted_http_forms) {
+ PostHSTSQueryForHostAndRequestContext(
+ form->origin, request_context(),
+ base::Bind(&RemoveLoginIfHSTS, make_scoped_refptr(store()), *form));
+ }
+
+ // Return early if there are no non-blacklisted HTTP forms.
+ if (results.empty())
+ return;
+
+ // Sort HTTPS forms according to custom comparison function. Consider two
+ // forms equivalent if they have the same host, as well as the same username
+ // and password.
+ const auto form_cmp = [](const std::unique_ptr<PasswordForm>& lhs,
+ const std::unique_ptr<PasswordForm>& rhs) {
+ return std::forward_as_tuple(lhs->origin.host_piece(), lhs->username_value,
+ lhs->password_value) <
+ std::forward_as_tuple(rhs->origin.host_piece(), rhs->username_value,
+ rhs->password_value);
+ };
+
+ std::sort(std::begin(https_forms), std::end(https_forms), form_cmp);
+
+ // Iterate through HTTP forms and remove them from the password store if there
+ // exists an equivalent HTTPS form that has HSTS enabled.
+ for (const auto& form : results) {
+ if (std::binary_search(std::begin(https_forms), std::end(https_forms), form,
+ form_cmp)) {
+ PostHSTSQueryForHostAndRequestContext(
+ form->origin, request_context(),
+ base::Bind(&RemoveLoginIfHSTS, make_scoped_refptr(store()), *form));
+ }
+ }
+}
+
+void ObsoleteHttpCleaner::OnGetSiteStatistics(
+ std::vector<InteractionsStats> stats) {
+ --remaining_cleaning_tasks_;
+ for (const auto& stat : stats) {
+ if (stat.origin_domain.SchemeIs(url::kHttpScheme)) {
+ PostHSTSQueryForHostAndRequestContext(
+ stat.origin_domain, request_context(),
+ base::Bind(&RemoveSiteStatsIfHSTS, make_scoped_refptr(store()),
+ stat));
+ }
+ }
+}
+
+void WaitUntilCleaningIsDone(std::unique_ptr<ObsoleteHttpCleaner> cleaner,
+ PrefService* prefs) {
+ // Given the async nature of the cleaning tasks it is non-trivial to determine
+ // when they are all done. In this method we make use of the fact that as long
+ // the cleaning is not completed, weak pointers to the cleaner object exist
+ // (the scheduled, but not yet executed tasks hold them). If the cleaning is
+ // not done yet, this method schedules a task on the password store, which
+ // will be behind the cleaning tasks in the task queue. When the scheduled
+ // task gets executed, this method is called again. Now it is guaranteed that
+ // the initial scheduled cleaning tasks will have been executed, but it might
+ // be the case that they wait for the result of other scheduled tasks (e.g. on
+ // Windows there could be async calls to GetIE7Login). In this case another
+ // round trip of tasks will be scheduled. Finally, when no weak ptrs remain,
+ // this method sets a boolean preference flag and returns.
+ if (cleaner->HasWeakPtrs()) {
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner =
+ base::ThreadTaskRunnerHandle::Get();
+ const auto post_to_thread =
+ [](std::unique_ptr<ObsoleteHttpCleaner> cleaner, PrefService* prefs,
+ scoped_refptr<base::SingleThreadTaskRunner> thread_runner) {
+ thread_runner->PostTask(
+ FROM_HERE, base::Bind(&WaitUntilCleaningIsDone,
+ base::Passed(std::move(cleaner)), prefs));
+ };
+
+ // Calling |ScheduleTask| through the raw pointer is necessary, because
+ // |std::move(cleaner)| might be executed before |cleaner->store()|.
+ // However, at this point cleaner is moved from, leading to a crash. Using a
+ // raw pointer avoids this issue.
+ ObsoleteHttpCleaner* raw_cleaner = cleaner.get();
+ raw_cleaner->store()->ScheduleTask(
+ base::Bind(post_to_thread, base::Passed(std::move(cleaner)), prefs,
+ main_thread_runner));
+ return;
+ }
+
+ DCHECK(cleaner->finished_cleaning());
+ prefs->SetBoolean(password_manager::prefs::kWasObsoleteHttpDataCleaned, true);
+}
+
+void InitiateCleaning(
+ const scoped_refptr<PasswordStore>& store,
+ PrefService* prefs,
+ const scoped_refptr<net::URLRequestContextGetter>& request_context) {
+ WaitUntilCleaningIsDone(
+ base::MakeUnique<ObsoleteHttpCleaner>(store, request_context), prefs);
+}
+
+void DelayCleanObsoleteHttpDataForPasswordStoreAndPrefsImpl(
+ PasswordStore* store,
+ PrefService* prefs,
+ const scoped_refptr<net::URLRequestContextGetter>& request_context,
+ int delay_in_seconds) {
+ if (!prefs->GetBoolean(
+ password_manager::prefs::kWasObsoleteHttpDataCleaned)) {
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&InitiateCleaning, make_scoped_refptr(store), prefs,
+ request_context),
+ base::TimeDelta::FromSeconds(delay_in_seconds));
+ }
+}
+
+} // namespace
+
+void DelayCleanObsoleteHttpDataForPasswordStoreAndPrefs(
+ PasswordStore* store,
+ PrefService* prefs,
+ const scoped_refptr<net::URLRequestContextGetter>& request_context) {
+ DelayCleanObsoleteHttpDataForPasswordStoreAndPrefsImpl(
+ store, prefs, request_context, kDefaultDelay);
+}
+
+void CleanObsoleteHttpDataForPasswordStoreAndPrefsForTesting(
+ PasswordStore* store,
+ PrefService* prefs,
+ const scoped_refptr<net::URLRequestContextGetter>& request_context) {
+ DelayCleanObsoleteHttpDataForPasswordStoreAndPrefsImpl(store, prefs,
+ request_context, 0);
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/http_data_cleaner.h b/chromium/components/password_manager/core/browser/http_data_cleaner.h
new file mode 100644
index 00000000000..2aa6a07ef34
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/http_data_cleaner.h
@@ -0,0 +1,29 @@
+// 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_PASSWORD_MANAGER_CORE_BROWSER_HTTP_DATA_CLEANER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_HTTP_DATA_CLEANER_H_
+
+#include "base/memory/ref_counted.h"
+#include "net/url_request/url_request_context_getter.h"
+
+class PrefService;
+
+namespace password_manager {
+
+class PasswordStore;
+
+void DelayCleanObsoleteHttpDataForPasswordStoreAndPrefs(
+ PasswordStore* store,
+ PrefService* prefs,
+ const scoped_refptr<net::URLRequestContextGetter>& request_context);
+
+void CleanObsoleteHttpDataForPasswordStoreAndPrefsForTesting(
+ PasswordStore* store,
+ PrefService* prefs,
+ const scoped_refptr<net::URLRequestContextGetter>& request_context);
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_HTTP_DATA_CLEANER_H_
diff --git a/chromium/components/password_manager/core/browser/http_data_cleaner_unittest.cc b/chromium/components/password_manager/core/browser/http_data_cleaner_unittest.cc
new file mode 100644
index 00000000000..4e04980cfbb
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/http_data_cleaner_unittest.cc
@@ -0,0 +1,241 @@
+// 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/password_manager/core/browser/http_data_cleaner.h"
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/password_manager/core/browser/mock_password_store.h"
+#include "components/password_manager/core/browser/password_manager_test_utils.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 "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using autofill::PasswordForm;
+using testing::Invoke;
+using testing::Message;
+using testing::Mock;
+using testing::NiceMock;
+using testing::_;
+
+namespace password_manager {
+
+constexpr char kTestHttpURL[] = "http://example.org/";
+constexpr char kTestHttpsURL[] = "https://example.org/";
+
+PasswordForm CreateTestHTTPForm() {
+ PasswordForm form;
+ form.origin = GURL(kTestHttpURL);
+ form.signon_realm = form.origin.spec();
+ form.action = form.origin;
+ form.username_value = base::ASCIIToUTF16("user");
+ form.password_value = base::ASCIIToUTF16("password");
+ return form;
+}
+
+PasswordForm CreateTestHTTPSForm() {
+ PasswordForm form;
+ form.origin = GURL(kTestHttpsURL);
+ form.signon_realm = form.origin.spec();
+ form.action = form.origin;
+ form.username_value = base::ASCIIToUTF16("user");
+ form.password_value = base::ASCIIToUTF16("password");
+ return form;
+}
+
+InteractionsStats CreateTestHTTPStats() {
+ InteractionsStats stats;
+ stats.origin_domain = GURL(kTestHttpURL);
+ stats.username_value = base::ASCIIToUTF16("user");
+ return stats;
+}
+
+InteractionsStats CreateTestHTTPSStats() {
+ InteractionsStats stats;
+ stats.origin_domain = GURL(kTestHttpsURL);
+ stats.username_value = base::ASCIIToUTF16("user");
+ return stats;
+}
+
+class HTTPDataCleanerTest : public testing::Test {
+ public:
+ HTTPDataCleanerTest()
+ : store_(new NiceMock<MockPasswordStore>),
+ prefs_(base::MakeUnique<TestingPrefServiceSimple>()),
+ request_context_(new net::TestURLRequestContextGetter(
+ base::ThreadTaskRunnerHandle::Get())) {
+ prefs()->registry()->RegisterBooleanPref(prefs::kWasObsoleteHttpDataCleaned,
+ false);
+ }
+
+ ~HTTPDataCleanerTest() override { store_->ShutdownOnUIThread(); }
+
+ MockPasswordStore* store() { return store_.get(); }
+
+ TestingPrefServiceSimple* prefs() { return prefs_.get(); }
+
+ const scoped_refptr<net::TestURLRequestContextGetter>& request_context() {
+ return request_context_;
+ }
+
+ private:
+ base::MessageLoop message_loop_; // Used by store_ and request_context_.
+ scoped_refptr<MockPasswordStore> store_;
+ std::unique_ptr<TestingPrefServiceSimple> prefs_;
+ scoped_refptr<net::TestURLRequestContextGetter> request_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(HTTPDataCleanerTest);
+};
+
+TEST_F(HTTPDataCleanerTest, TestBlacklistDeletion) {
+ for (bool is_http : {false, true}) {
+ for (bool is_hsts : {false, true}) {
+ SCOPED_TRACE(Message() << std::boolalpha << "(is_http, is_hsts): ("
+ << is_http << ", " << is_hsts << ")");
+
+ prefs()->SetBoolean(prefs::kWasObsoleteHttpDataCleaned, false);
+
+ const bool should_be_deleted = is_http && is_hsts;
+
+ PasswordForm form =
+ is_http ? CreateTestHTTPForm() : CreateTestHTTPSForm();
+ form.blacklisted_by_user = true;
+ form.username_value.clear();
+ form.password_value.clear();
+
+ HSTSStateManager manager(
+ request_context()->GetURLRequestContext()->transport_security_state(),
+ is_hsts, form.origin.host());
+
+ EXPECT_CALL(*store(), FillBlacklistLogins(_))
+ .WillOnce(Invoke(
+ [&form](
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) {
+ *forms = WrapForms({form});
+ return true;
+ }));
+
+ EXPECT_CALL(*store(), RemoveLogin(form)).Times(should_be_deleted);
+
+ // Initiate clean up and make sure all aync tasks are run until
+ // completion.
+ CleanObsoleteHttpDataForPasswordStoreAndPrefsForTesting(
+ store(), prefs(), request_context());
+ base::RunLoop().RunUntilIdle();
+
+ // Verify and clear all expectations as well as the preference.
+ Mock::VerifyAndClearExpectations(store());
+ EXPECT_TRUE(prefs()->GetBoolean(prefs::kWasObsoleteHttpDataCleaned));
+ }
+ }
+}
+
+TEST_F(HTTPDataCleanerTest, TestAutofillableDeletion) {
+ for (bool is_hsts : {false, true}) {
+ for (bool same_host : {false, true}) {
+ for (bool same_user : {false, true}) {
+ for (bool same_pass : {false, true}) {
+ SCOPED_TRACE(Message()
+ << std::boolalpha
+ << "(is_hsts, same_host, same_user, same_pass): ("
+ << is_hsts << ", " << same_host << ", " << same_user
+ << ", " << same_pass);
+
+ prefs()->SetBoolean(prefs::kWasObsoleteHttpDataCleaned, false);
+
+ const bool should_be_deleted =
+ is_hsts && same_host && same_user && same_pass;
+
+ PasswordForm http_form = CreateTestHTTPForm();
+ PasswordForm https_form = CreateTestHTTPSForm();
+
+ if (!same_host) {
+ GURL::Replacements rep;
+ rep.SetHostStr("a-totally-different-host");
+ http_form.origin = http_form.origin.ReplaceComponents(rep);
+ }
+
+ if (!same_user)
+ http_form.username_value = base::ASCIIToUTF16("different-user");
+
+ if (!same_pass)
+ http_form.password_value = base::ASCIIToUTF16("different-pass");
+
+ HSTSStateManager manager(request_context()
+ ->GetURLRequestContext()
+ ->transport_security_state(),
+ is_hsts, https_form.origin.host());
+
+ EXPECT_CALL(*store(), FillAutofillableLogins(_))
+ .WillOnce(Invoke(
+ [&http_form, &https_form](
+ std::vector<std::unique_ptr<autofill::PasswordForm>>*
+ forms) {
+ *forms = WrapForms({http_form, https_form});
+ return true;
+ }));
+
+ EXPECT_CALL(*store(), RemoveLogin(http_form))
+ .Times(should_be_deleted);
+
+ // Initiate clean up and make sure all aync tasks are run until
+ // completion.
+ CleanObsoleteHttpDataForPasswordStoreAndPrefsForTesting(
+ store(), prefs(), request_context());
+ base::RunLoop().RunUntilIdle();
+
+ // Verify and clear all expectations as well as the preference.
+ Mock::VerifyAndClearExpectations(store());
+ EXPECT_TRUE(prefs()->GetBoolean(prefs::kWasObsoleteHttpDataCleaned));
+ }
+ }
+ }
+ }
+}
+
+TEST_F(HTTPDataCleanerTest, TestSiteStatsDeletion) {
+ for (bool is_http : {false, true}) {
+ for (bool is_hsts : {false, true}) {
+ SCOPED_TRACE(Message() << std::boolalpha << "(is_http, is_hsts): ("
+ << is_http << ", " << is_hsts);
+
+ prefs()->SetBoolean(prefs::kWasObsoleteHttpDataCleaned, false);
+
+ const bool should_be_deleted = is_http && is_hsts;
+
+ InteractionsStats stats =
+ is_http ? CreateTestHTTPStats() : CreateTestHTTPSStats();
+
+ HSTSStateManager manager(
+ request_context()->GetURLRequestContext()->transport_security_state(),
+ is_hsts, stats.origin_domain.host());
+
+ EXPECT_CALL(*store(), GetAllSiteStatsImpl()).WillOnce(Invoke([&stats]() {
+ return std::vector<InteractionsStats>({stats});
+ }));
+ EXPECT_CALL(*store(), RemoveSiteStatsImpl(stats.origin_domain))
+ .Times(should_be_deleted);
+
+ // Initiate clean up and make sure all async tasks are run until
+ // completion.
+ CleanObsoleteHttpDataForPasswordStoreAndPrefsForTesting(
+ store(), prefs(), request_context());
+ base::RunLoop().RunUntilIdle();
+
+ // Verify and clear all expectations as well as the preference.
+ Mock::VerifyAndClearExpectations(store());
+ EXPECT_TRUE(prefs()->GetBoolean(prefs::kWasObsoleteHttpDataCleaned));
+ }
+ }
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/http_password_migrator.cc b/chromium/components/password_manager/core/browser/http_password_migrator.cc
deleted file mode 100644
index 700327ca480..00000000000
--- a/chromium/components/password_manager/core/browser/http_password_migrator.cc
+++ /dev/null
@@ -1,73 +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/password_manager/core/browser/http_password_migrator.h"
-
-#include "components/password_manager/core/browser/password_manager_metrics_util.h"
-#include "components/password_manager/core/browser/password_store.h"
-#include "url/gurl.h"
-#include "url/url_constants.h"
-
-namespace password_manager {
-
-HttpPasswordMigrator::HttpPasswordMigrator(const GURL& https_origin,
- MigrationMode mode,
- PasswordStore* password_store,
- Consumer* consumer)
- : mode_(mode), consumer_(consumer), password_store_(password_store) {
- DCHECK(password_store_);
- DCHECK(https_origin.is_valid());
- DCHECK(https_origin.SchemeIs(url::kHttpsScheme)) << https_origin;
-
- GURL::Replacements rep;
- rep.SetSchemeStr(url::kHttpScheme);
- GURL http_origin = https_origin.ReplaceComponents(rep);
- PasswordStore::FormDigest form(autofill::PasswordForm::SCHEME_HTML,
- http_origin.GetOrigin().spec(), http_origin);
- password_store_->GetLogins(form, this);
-}
-
-HttpPasswordMigrator::~HttpPasswordMigrator() = default;
-
-void HttpPasswordMigrator::OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
- // Android and PSL matches are ignored.
- results.erase(
- std::remove_if(results.begin(), results.end(),
- [](const std::unique_ptr<autofill::PasswordForm>& form) {
- return form->is_affiliation_based_match ||
- form->is_public_suffix_match;
- }),
- results.end());
-
- // Add the new credentials to the password store. The HTTP forms are
- // removed iff |mode_| == MigrationMode::MOVE.
- for (const auto& form : results) {
- autofill::PasswordForm new_form = *form;
-
- GURL::Replacements rep;
- rep.SetSchemeStr(url::kHttpsScheme);
- new_form.origin = form->origin.ReplaceComponents(rep);
- new_form.signon_realm = new_form.origin.spec();
- // If |action| is not HTTPS then it's most likely obsolete. Otherwise, it
- // may still be valid.
- if (!form->action.SchemeIs(url::kHttpsScheme))
- new_form.action = new_form.origin;
- new_form.form_data = autofill::FormData();
- new_form.generation_upload_status = autofill::PasswordForm::NO_SIGNAL_SENT;
- new_form.skip_zero_click = false;
- password_store_->AddLogin(new_form);
-
- if (mode_ == MigrationMode::MOVE)
- password_store_->RemoveLogin(*form);
- *form = std::move(new_form);
- }
-
- metrics_util::LogCountHttpMigratedPasswords(results.size());
-
- if (consumer_)
- consumer_->ProcessMigratedForms(std::move(results));
-}
-
-} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/http_password_migrator.h b/chromium/components/password_manager/core/browser/http_password_migrator.h
deleted file mode 100644
index 7d9d0963df1..00000000000
--- a/chromium/components/password_manager/core/browser/http_password_migrator.h
+++ /dev/null
@@ -1,65 +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_PASSWORD_MANAGER_CORE_BROWSER_HTTP_PASSWORD_MIGRATOR_H_
-#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_HTTP_PASSWORD_MIGRATOR_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "components/password_manager/core/browser/password_store_consumer.h"
-
-namespace autofill {
-struct PasswordForm;
-}
-
-class GURL;
-
-namespace password_manager {
-
-class PasswordStore;
-
-// The class is responsible for migrating the passwords saved on HTTP to HTTPS
-// origin.
-class HttpPasswordMigrator : public PasswordStoreConsumer {
- public:
- enum class MigrationMode {
- MOVE, // HTTP credentials are deleted after migration to HTTPS.
- COPY, // HTTP credentials are kept after migration to HTTPS.
- };
-
- // API to be implemented by an embedder of HttpPasswordMigrator.
- class Consumer {
- public:
- virtual ~Consumer() = default;
-
- // Notify the embedder that |forms| were migrated to HTTPS. |forms| contain
- // the updated HTTPS scheme.
- virtual void ProcessMigratedForms(
- std::vector<std::unique_ptr<autofill::PasswordForm>> forms) = 0;
- };
-
- // |https_origin| should specify a valid HTTPS URL.
- HttpPasswordMigrator(const GURL& https_origin,
- MigrationMode mode,
- PasswordStore* password_store,
- Consumer* consumer);
- ~HttpPasswordMigrator() override;
-
- // PasswordStoreConsumer:
- void OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
-
- private:
- const MigrationMode mode_;
- Consumer* consumer_;
- PasswordStore* password_store_;
-
- DISALLOW_COPY_AND_ASSIGN(HttpPasswordMigrator);
-};
-
-} // namespace password_manager
-
-#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_HTTP_PASSWORD_MIGRATOR_H_
diff --git a/chromium/components/password_manager/core/browser/http_password_migrator_unittest.cc b/chromium/components/password_manager/core/browser/http_password_migrator_unittest.cc
deleted file mode 100644
index 76cc5937a3e..00000000000
--- a/chromium/components/password_manager/core/browser/http_password_migrator_unittest.cc
+++ /dev/null
@@ -1,156 +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/password_manager/core/browser/http_password_migrator.h"
-
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/password_manager/core/browser/mock_password_store.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace password_manager {
-namespace {
-
-using autofill::PasswordForm;
-using testing::_;
-using testing::ElementsAre;
-using testing::Pointee;
-
-constexpr char kTestHttpsURL[] = "https://example.org/";
-constexpr char kTestHttpURL[] = "http://example.org/";
-constexpr char kTestSubdomainHttpURL[] = "http://login.example.org/";
-
-// Creates a dummy http form with some basic arbitrary values.
-PasswordForm CreateTestForm() {
- PasswordForm form;
- form.origin = GURL(kTestHttpURL);
- form.signon_realm = form.origin.spec();
- form.action = GURL("https://example.org/action.html");
- form.username_value = base::ASCIIToUTF16("user");
- form.password_value = base::ASCIIToUTF16("password");
- return form;
-}
-
-// Creates a dummy http PSL-matching form with some basic arbitrary values.
-PasswordForm CreateTestPSLForm() {
- PasswordForm form;
- form.origin = GURL(kTestSubdomainHttpURL);
- form.signon_realm = form.origin.spec();
- form.action = GURL(kTestSubdomainHttpURL);
- form.username_value = base::ASCIIToUTF16("user2");
- form.password_value = base::ASCIIToUTF16("password2");
- form.is_public_suffix_match = true;
- return form;
-}
-
-// Creates an Android credential.
-PasswordForm CreateAndroidCredential() {
- PasswordForm form;
- form.username_value = base::ASCIIToUTF16("user3");
- form.password_value = base::ASCIIToUTF16("password3");
- form.signon_realm = "android://hash@com.example.android/";
- form.origin = GURL(form.signon_realm);
- form.action = GURL();
- form.is_affiliation_based_match = true;
- return form;
-}
-
-class MockConsumer : public HttpPasswordMigrator::Consumer {
- public:
- MOCK_METHOD1(ProcessForms,
- void(const std::vector<autofill::PasswordForm*>& forms));
-
- void ProcessMigratedForms(
- std::vector<std::unique_ptr<autofill::PasswordForm>> forms) override {
- std::vector<autofill::PasswordForm*> raw_forms(forms.size());
- std::transform(forms.begin(), forms.end(), raw_forms.begin(),
- [](const std::unique_ptr<autofill::PasswordForm>& form) {
- return form.get();
- });
- ProcessForms(raw_forms);
- }
-};
-
-class HttpPasswordMigratorTest : public testing::Test {
- public:
- HttpPasswordMigratorTest() {
- mock_store_ = new testing::StrictMock<MockPasswordStore>;
- }
-
- ~HttpPasswordMigratorTest() override { mock_store_->ShutdownOnUIThread(); }
-
- MockConsumer& consumer() { return consumer_; }
- MockPasswordStore& store() { return *mock_store_; }
-
- protected:
- void TestEmptyStore(HttpPasswordMigrator::MigrationMode mode);
- void TestFullStore(HttpPasswordMigrator::MigrationMode mode);
-
- private:
- base::MessageLoop message_loop_; // Used by mock_store_.
- MockConsumer consumer_;
- scoped_refptr<MockPasswordStore> mock_store_;
-
- DISALLOW_COPY_AND_ASSIGN(HttpPasswordMigratorTest);
-};
-
-void HttpPasswordMigratorTest::TestEmptyStore(
- HttpPasswordMigrator::MigrationMode mode) {
- PasswordStore::FormDigest form(autofill::PasswordForm::SCHEME_HTML,
- kTestHttpURL, GURL(kTestHttpURL));
- EXPECT_CALL(store(), GetLogins(form, _));
- HttpPasswordMigrator migrator(GURL(kTestHttpsURL), mode, &store(),
- &consumer());
-
- EXPECT_CALL(consumer(), ProcessForms(std::vector<autofill::PasswordForm*>()));
- migrator.OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<autofill::PasswordForm>>());
-}
-
-void HttpPasswordMigratorTest::TestFullStore(
- HttpPasswordMigrator::MigrationMode mode) {
- PasswordStore::FormDigest form_digest(autofill::PasswordForm::SCHEME_HTML,
- kTestHttpURL, GURL(kTestHttpURL));
- EXPECT_CALL(store(), GetLogins(form_digest, _));
- HttpPasswordMigrator migrator(GURL(kTestHttpsURL), mode, &store(),
- &consumer());
-
- PasswordForm form = CreateTestForm();
- PasswordForm psl_form = CreateTestPSLForm();
- PasswordForm android_form = CreateAndroidCredential();
- PasswordForm expected_form = form;
- expected_form.origin = GURL(kTestHttpsURL);
- expected_form.signon_realm = expected_form.origin.spec();
-
- EXPECT_CALL(store(), AddLogin(expected_form));
- EXPECT_CALL(store(), RemoveLogin(form))
- .Times(mode == HttpPasswordMigrator::MigrationMode::MOVE);
- EXPECT_CALL(consumer(), ProcessForms(ElementsAre(Pointee(expected_form))));
- std::vector<std::unique_ptr<autofill::PasswordForm>> results;
- results.push_back(base::MakeUnique<PasswordForm>(psl_form));
- results.push_back(base::MakeUnique<PasswordForm>(form));
- results.push_back(base::MakeUnique<PasswordForm>(android_form));
- migrator.OnGetPasswordStoreResults(std::move(results));
-}
-
-TEST_F(HttpPasswordMigratorTest, EmptyStoreWithMove) {
- TestEmptyStore(HttpPasswordMigrator::MigrationMode::MOVE);
-}
-
-TEST_F(HttpPasswordMigratorTest, EmptyStoreWithCopy) {
- TestEmptyStore(HttpPasswordMigrator::MigrationMode::COPY);
-}
-
-TEST_F(HttpPasswordMigratorTest, FullStoreWithMove) {
- TestFullStore(HttpPasswordMigrator::MigrationMode::MOVE);
-}
-
-TEST_F(HttpPasswordMigratorTest, FullStoreWithCopy) {
- TestFullStore(HttpPasswordMigrator::MigrationMode::COPY);
-}
-
-} // namespace
-} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/http_password_store_migrator.cc b/chromium/components/password_manager/core/browser/http_password_store_migrator.cc
new file mode 100644
index 00000000000..4611457227c
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/http_password_store_migrator.cc
@@ -0,0 +1,119 @@
+// 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/password_manager/core/browser/http_password_store_migrator.h"
+
+#include "base/memory/weak_ptr.h"
+#include "base/stl_util.h"
+#include "components/password_manager/core/browser/password_manager_client.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
+#include "components/password_manager/core/browser/password_store.h"
+#include "url/gurl.h"
+#include "url/url_constants.h"
+
+namespace password_manager {
+
+namespace {
+
+// Helper method that allows us to pass WeakPtrs to |PasswordStoreConsumer|
+// obtained via |GetWeakPtr|. This is not possible otherwise.
+void OnHSTSQueryResultHelper(
+ const base::WeakPtr<PasswordStoreConsumer>& migrator,
+ bool is_hsts) {
+ if (migrator) {
+ static_cast<HttpPasswordStoreMigrator*>(migrator.get())
+ ->OnHSTSQueryResult(is_hsts);
+ }
+}
+
+} // namespace
+
+HttpPasswordStoreMigrator::HttpPasswordStoreMigrator(
+ const GURL& https_origin,
+ const PasswordManagerClient* client,
+ Consumer* consumer)
+ : client_(client), consumer_(consumer) {
+ DCHECK(client_);
+ DCHECK(https_origin.is_valid());
+ DCHECK(https_origin.SchemeIs(url::kHttpsScheme)) << https_origin;
+
+ GURL::Replacements rep;
+ rep.SetSchemeStr(url::kHttpScheme);
+ GURL http_origin = https_origin.ReplaceComponents(rep);
+ PasswordStore::FormDigest form(autofill::PasswordForm::SCHEME_HTML,
+ http_origin.GetOrigin().spec(), http_origin);
+ http_origin_domain_ = http_origin.GetOrigin();
+ client_->GetPasswordStore()->GetLogins(form, this);
+ client_->PostHSTSQueryForHost(
+ https_origin, base::Bind(&OnHSTSQueryResultHelper, GetWeakPtr()));
+}
+
+HttpPasswordStoreMigrator::~HttpPasswordStoreMigrator() = default;
+
+void HttpPasswordStoreMigrator::OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ results_ = std::move(results);
+ got_password_store_results_ = true;
+
+ if (got_hsts_query_result_)
+ ProcessPasswordStoreResults();
+}
+
+void HttpPasswordStoreMigrator::OnHSTSQueryResult(bool is_hsts) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ mode_ = is_hsts ? MigrationMode::MOVE : MigrationMode::COPY;
+ got_hsts_query_result_ = true;
+
+ if (is_hsts)
+ client_->GetPasswordStore()->RemoveSiteStats(http_origin_domain_);
+
+ if (got_password_store_results_)
+ ProcessPasswordStoreResults();
+}
+
+void HttpPasswordStoreMigrator::ProcessPasswordStoreResults() {
+ // Android and PSL matches are ignored.
+ base::EraseIf(
+ results_, [](const std::unique_ptr<autofill::PasswordForm>& form) {
+ return form->is_affiliation_based_match || form->is_public_suffix_match;
+ });
+
+ // Add the new credentials to the password store. The HTTP forms are
+ // removed iff |mode_| == MigrationMode::MOVE.
+ for (const auto& form : results_) {
+ autofill::PasswordForm new_form = *form;
+
+ GURL::Replacements rep;
+ rep.SetSchemeStr(url::kHttpsScheme);
+ new_form.origin = form->origin.ReplaceComponents(rep);
+ new_form.signon_realm = new_form.origin.spec();
+ // If |action| is not HTTPS then it's most likely obsolete. Otherwise, it
+ // may still be valid.
+ if (!form->action.SchemeIs(url::kHttpsScheme))
+ new_form.action = new_form.origin;
+ new_form.form_data = autofill::FormData();
+ new_form.generation_upload_status = autofill::PasswordForm::NO_SIGNAL_SENT;
+ new_form.skip_zero_click = false;
+ client_->GetPasswordStore()->AddLogin(new_form);
+
+ if (mode_ == MigrationMode::MOVE)
+ client_->GetPasswordStore()->RemoveLogin(*form);
+ *form = std::move(new_form);
+ }
+
+ if (!results_.empty()) {
+ // Only log data if there was at least one migrated password.
+ metrics_util::LogCountHttpMigratedPasswords(results_.size());
+ metrics_util::LogHttpPasswordMigrationMode(
+ mode_ == MigrationMode::MOVE
+ ? metrics_util::HTTP_PASSWORD_MIGRATION_MODE_MOVE
+ : metrics_util::HTTP_PASSWORD_MIGRATION_MODE_COPY);
+ }
+
+ if (consumer_)
+ consumer_->ProcessMigratedForms(std::move(results_));
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/http_password_store_migrator.h b/chromium/components/password_manager/core/browser/http_password_store_migrator.h
new file mode 100644
index 00000000000..47a378cc0a0
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/http_password_store_migrator.h
@@ -0,0 +1,86 @@
+// 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_PASSWORD_MANAGER_CORE_BROWSER_HTTP_PASSWORD_STORE_MIGRATOR_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_HTTP_PASSWORD_STORE_MIGRATOR_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "components/password_manager/core/browser/password_store_consumer.h"
+#include "url/gurl.h"
+
+namespace autofill {
+struct PasswordForm;
+}
+
+namespace password_manager {
+
+class PasswordManagerClient;
+
+// The class is responsible for migrating the passwords saved on HTTP to HTTPS
+// origin. It automatically determines whether HTTP passwords should be moved or
+// copied depending on the site's HSTS status. If a site has HSTS enabled, the
+// HTTP password is considered obsolete and will be replaced by an HTTPS
+// version. If HSTS is not enabled, some parts of the site might still be served
+// via HTTP, which is why the password is copied in this case.
+// Furthermore, if a site has migrated to HTTPS and HSTS is enabled, the
+// corresponding HTTP site statistics are cleared as well, since they are
+// obsolete.
+class HttpPasswordStoreMigrator : public PasswordStoreConsumer {
+ public:
+ // API to be implemented by an embedder of HttpPasswordStoreMigrator.
+ class Consumer {
+ public:
+ virtual ~Consumer() = default;
+
+ // Notify the embedder that |forms| were migrated to HTTPS. |forms| contain
+ // the updated HTTPS scheme.
+ virtual void ProcessMigratedForms(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms) = 0;
+ };
+
+ // |https_origin| should specify a valid HTTPS URL.
+ HttpPasswordStoreMigrator(const GURL& https_origin,
+ const PasswordManagerClient* client,
+ Consumer* consumer);
+ ~HttpPasswordStoreMigrator() override;
+
+ // PasswordStoreConsumer:
+ void OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
+
+ // Callback for |PasswordManagerClient::PostHSTSQueryForHost|.
+ void OnHSTSQueryResult(bool is_hsts);
+
+ private:
+ enum class MigrationMode {
+ MOVE, // HTTP credentials are deleted after migration to HTTPS.
+ COPY, // HTTP credentials are kept after migration to HTTPS.
+ };
+
+ void ProcessPasswordStoreResults();
+
+ const PasswordManagerClient* const client_;
+ Consumer* consumer_;
+
+ // |ProcessPasswordStoreResults| requires that both |OnHSTSQueryResult| and
+ // |OnGetPasswordStoreResults| have returned. Since this can happen in an
+ // arbitrary order, boolean flags are introduced to indicate completion. Only
+ // if both are set to true |ProcessPasswordStoreResults| gets called.
+ bool got_hsts_query_result_ = false;
+ bool got_password_store_results_ = false;
+ MigrationMode mode_;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results_;
+ GURL http_origin_domain_;
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(HttpPasswordStoreMigrator);
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_HTTP_PASSWORD_STORE_MIGRATOR_H_
diff --git a/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc b/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
new file mode 100644
index 00000000000..6aa5d2b74fc
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
@@ -0,0 +1,233 @@
+// 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/password_manager/core/browser/http_password_store_migrator.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/password_manager/core/browser/mock_password_store.h"
+#include "components/password_manager/core/browser/stub_password_manager_client.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+namespace {
+
+using autofill::PasswordForm;
+using testing::ElementsAre;
+using testing::Invoke;
+using testing::Pointee;
+using testing::SaveArg;
+using testing::Unused;
+using testing::_;
+
+constexpr char kTestHttpsURL[] = "https://example.org/";
+constexpr char kTestHttpURL[] = "http://example.org/";
+constexpr char kTestSubdomainHttpURL[] = "http://login.example.org/";
+
+// Creates a dummy http form with some basic arbitrary values.
+PasswordForm CreateTestForm() {
+ PasswordForm form;
+ form.origin = GURL(kTestHttpURL);
+ form.signon_realm = form.origin.spec();
+ form.action = GURL("https://example.org/action.html");
+ form.username_value = base::ASCIIToUTF16("user");
+ form.password_value = base::ASCIIToUTF16("password");
+ return form;
+}
+
+// Creates a dummy http PSL-matching form with some basic arbitrary values.
+PasswordForm CreateTestPSLForm() {
+ PasswordForm form;
+ form.origin = GURL(kTestSubdomainHttpURL);
+ form.signon_realm = form.origin.spec();
+ form.action = GURL(kTestSubdomainHttpURL);
+ form.username_value = base::ASCIIToUTF16("user2");
+ form.password_value = base::ASCIIToUTF16("password2");
+ form.is_public_suffix_match = true;
+ return form;
+}
+
+// Creates an Android credential.
+PasswordForm CreateAndroidCredential() {
+ PasswordForm form;
+ form.username_value = base::ASCIIToUTF16("user3");
+ form.password_value = base::ASCIIToUTF16("password3");
+ form.signon_realm = "android://hash@com.example.android/";
+ form.origin = GURL(form.signon_realm);
+ form.action = GURL();
+ form.is_affiliation_based_match = true;
+ return form;
+}
+
+class MockConsumer : public HttpPasswordStoreMigrator::Consumer {
+ public:
+ MOCK_METHOD1(ProcessForms,
+ void(const std::vector<autofill::PasswordForm*>& forms));
+
+ void ProcessMigratedForms(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms) override {
+ std::vector<autofill::PasswordForm*> raw_forms(forms.size());
+ std::transform(forms.begin(), forms.end(), raw_forms.begin(),
+ [](const std::unique_ptr<autofill::PasswordForm>& form) {
+ return form.get();
+ });
+ ProcessForms(raw_forms);
+ }
+};
+
+class MockPasswordManagerClient : public StubPasswordManagerClient {
+ public:
+ explicit MockPasswordManagerClient(PasswordStore* store) : store_(store) {}
+
+ PasswordStore* GetPasswordStore() const override { return store_; }
+ MOCK_CONST_METHOD2(PostHSTSQueryForHost,
+ void(const GURL&, const HSTSCallback& callback));
+
+ private:
+ PasswordStore* store_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockPasswordManagerClient);
+};
+
+} // namespace
+
+class HttpPasswordStoreMigratorTest : public testing::Test {
+ public:
+ HttpPasswordStoreMigratorTest()
+ : mock_store_(new testing::StrictMock<MockPasswordStore>),
+ client_(mock_store_.get()) {}
+
+ ~HttpPasswordStoreMigratorTest() override {
+ mock_store_->ShutdownOnUIThread();
+ }
+
+ MockConsumer& consumer() { return consumer_; }
+ MockPasswordStore& store() { return *mock_store_; }
+ MockPasswordManagerClient& client() { return client_; }
+
+ protected:
+ void TestEmptyStore(bool is_hsts);
+ void TestFullStore(bool is_hsts);
+ void TestMigratorDeletionByConsumer(bool is_hsts);
+
+ private:
+ base::MessageLoop message_loop_; // Used by mock_store_.
+ MockConsumer consumer_;
+ scoped_refptr<MockPasswordStore> mock_store_;
+ MockPasswordManagerClient client_;
+
+ DISALLOW_COPY_AND_ASSIGN(HttpPasswordStoreMigratorTest);
+};
+
+void HttpPasswordStoreMigratorTest::TestEmptyStore(bool is_hsts) {
+ PasswordStore::FormDigest form(autofill::PasswordForm::SCHEME_HTML,
+ kTestHttpURL, GURL(kTestHttpURL));
+ EXPECT_CALL(store(), GetLogins(form, _));
+ PasswordManagerClient::HSTSCallback callback;
+ EXPECT_CALL(client(), PostHSTSQueryForHost(GURL(kTestHttpsURL), _))
+ .WillOnce(SaveArg<1>(&callback));
+ HttpPasswordStoreMigrator migrator(GURL(kTestHttpsURL), &client(),
+ &consumer());
+ callback.Run(is_hsts);
+ // We expect a potential call to |RemoveSiteStatsImpl| which is a async task
+ // posted from |PasswordStore::RemoveSiteStats|. Hence the following lines are
+ // necessary to ensure |RemoveSiteStatsImpl| gets called when expected.
+ EXPECT_CALL(store(), RemoveSiteStatsImpl(GURL(kTestHttpURL))).Times(is_hsts);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_CALL(consumer(), ProcessForms(std::vector<autofill::PasswordForm*>()));
+ migrator.OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<autofill::PasswordForm>>());
+}
+
+void HttpPasswordStoreMigratorTest::TestFullStore(bool is_hsts) {
+ PasswordStore::FormDigest form_digest(autofill::PasswordForm::SCHEME_HTML,
+ kTestHttpURL, GURL(kTestHttpURL));
+ EXPECT_CALL(store(), GetLogins(form_digest, _));
+ PasswordManagerClient::HSTSCallback callback;
+ EXPECT_CALL(client(), PostHSTSQueryForHost(GURL(kTestHttpsURL), _))
+ .WillOnce(SaveArg<1>(&callback));
+ HttpPasswordStoreMigrator migrator(GURL(kTestHttpsURL), &client(),
+ &consumer());
+ callback.Run(is_hsts);
+ // We expect a potential call to |RemoveSiteStatsImpl| which is a async task
+ // posted from |PasswordStore::RemoveSiteStats|. Hence the following lines are
+ // necessary to ensure |RemoveSiteStatsImpl| gets called when expected.
+ EXPECT_CALL(store(), RemoveSiteStatsImpl(GURL(kTestHttpURL))).Times(is_hsts);
+ base::RunLoop().RunUntilIdle();
+
+ PasswordForm form = CreateTestForm();
+ PasswordForm psl_form = CreateTestPSLForm();
+ PasswordForm android_form = CreateAndroidCredential();
+ PasswordForm expected_form = form;
+ expected_form.origin = GURL(kTestHttpsURL);
+ expected_form.signon_realm = expected_form.origin.spec();
+
+ EXPECT_CALL(store(), AddLogin(expected_form));
+ EXPECT_CALL(store(), RemoveLogin(form)).Times(is_hsts);
+ EXPECT_CALL(consumer(), ProcessForms(ElementsAre(Pointee(expected_form))));
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results;
+ results.push_back(base::MakeUnique<PasswordForm>(psl_form));
+ results.push_back(base::MakeUnique<PasswordForm>(form));
+ results.push_back(base::MakeUnique<PasswordForm>(android_form));
+ migrator.OnGetPasswordStoreResults(std::move(results));
+}
+
+// This test checks whether the migration successfully completes even if the
+// migrator gets explicitly deleted by its consumer. This test will crash if
+// this is not the case.
+void HttpPasswordStoreMigratorTest::TestMigratorDeletionByConsumer(
+ bool is_hsts) {
+ // Setup expectations on store and client.
+ EXPECT_CALL(store(), GetLogins(_, _));
+ PasswordManagerClient::HSTSCallback callback;
+ EXPECT_CALL(client(), PostHSTSQueryForHost(GURL(kTestHttpsURL), _))
+ .WillOnce(SaveArg<1>(&callback));
+
+ // Construct the migrator, call |OnGetPasswordStoreResults| explicitly and
+ // manually delete it.
+ auto migrator = base::MakeUnique<HttpPasswordStoreMigrator>(
+ GURL(kTestHttpsURL), &client(), &consumer());
+ migrator->OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<autofill::PasswordForm>>());
+ EXPECT_CALL(consumer(), ProcessForms(_)).WillOnce(Invoke([&migrator](Unused) {
+ migrator.reset();
+ }));
+
+ callback.Run(is_hsts);
+ // We expect a potential call to |RemoveSiteStatsImpl| which is a async task
+ // posted from |PasswordStore::RemoveSiteStats|. Hence the following lines are
+ // necessary to ensure |RemoveSiteStatsImpl| gets called when expected.
+ EXPECT_CALL(store(), RemoveSiteStatsImpl(GURL(kTestHttpURL))).Times(is_hsts);
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(HttpPasswordStoreMigratorTest, EmptyStoreWithHSTS) {
+ TestEmptyStore(true);
+}
+
+TEST_F(HttpPasswordStoreMigratorTest, EmptyStoreWithoutHSTS) {
+ TestEmptyStore(false);
+}
+
+TEST_F(HttpPasswordStoreMigratorTest, FullStoreWithHSTS) {
+ TestFullStore(true);
+}
+
+TEST_F(HttpPasswordStoreMigratorTest, FullStoreWithoutHSTS) {
+ TestFullStore(false);
+}
+
+TEST_F(HttpPasswordStoreMigratorTest, MigratorDeletionByConsumerWithHSTS) {
+ TestMigratorDeletionByConsumer(true);
+}
+
+TEST_F(HttpPasswordStoreMigratorTest, MigratorDeletionByConsumerWithoutHSTS) {
+ TestMigratorDeletionByConsumer(false);
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc b/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc
index 24ff2dce5bc..26b0149ab9b 100644
--- a/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc
+++ b/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc
@@ -78,8 +78,8 @@ TEST_F(PasswordImporterTest, CSVImport) {
base::FilePath input_path =
temp_directory_.GetPath().AppendASCII(kTestFileName);
- ASSERT_TRUE(
- base::WriteFile(input_path, kTestCSVInput, strlen(kTestCSVInput)));
+ ASSERT_EQ(static_cast<int>(strlen(kTestCSVInput)),
+ base::WriteFile(input_path, kTestCSVInput, strlen(kTestCSVInput)));
ASSERT_NO_FATAL_FAILURE(StartImportAndWaitForCompletion(input_path));
EXPECT_EQ(PasswordImporter::SUCCESS, result());
diff --git a/chromium/components/password_manager/core/browser/login_database.cc b/chromium/components/password_manager/core/browser/login_database.cc
index ff7d4da2794..5de021e0ea7 100644
--- a/chromium/components/password_manager/core/browser/login_database.cc
+++ b/chromium/components/password_manager/core/browser/login_database.cc
@@ -44,26 +44,32 @@ using autofill::PasswordForm;
namespace password_manager {
// The current version number of the login database schema.
-const int kCurrentVersionNumber = 18;
+const int kCurrentVersionNumber = 19;
// The oldest version of the schema such that a legacy Chrome client using that
// version can still read/write the current database.
-const int kCompatibleVersionNumber = 18;
+const int kCompatibleVersionNumber = 19;
-base::Pickle SerializeVector(const std::vector<base::string16>& vec) {
+base::Pickle SerializePossibleUsernamePairs(
+ const autofill::PossibleUsernamesVector& vec) {
base::Pickle p;
for (size_t i = 0; i < vec.size(); ++i) {
- p.WriteString16(vec[i]);
+ p.WriteString16(vec[i].first);
+ p.WriteString16(vec[i].second);
}
return p;
}
-std::vector<base::string16> DeserializeVector(const base::Pickle& p) {
- std::vector<base::string16> ret;
- base::string16 str;
+autofill::PossibleUsernamesVector DeserializePossibleUsernamePairs(
+ const base::Pickle& p) {
+ autofill::PossibleUsernamesVector ret;
+ base::string16 value;
+ base::string16 field_name;
base::PickleIterator iterator(p);
- while (iterator.ReadString16(&str)) {
- ret.push_back(str);
+ while (iterator.ReadString16(&value)) {
+ bool name_success = iterator.ReadString16(&field_name);
+ DCHECK(name_success);
+ ret.push_back(autofill::PossibleUsernamePair(value, field_name));
}
return ret;
}
@@ -85,7 +91,6 @@ enum LoginTableColumns {
COLUMN_BLACKLISTED_BY_USER,
COLUMN_SCHEME,
COLUMN_PASSWORD_TYPE,
- COLUMN_POSSIBLE_USERNAMES,
COLUMN_TIMES_USED,
COLUMN_FORM_DATA,
COLUMN_DATE_SYNCED,
@@ -94,6 +99,7 @@ enum LoginTableColumns {
COLUMN_FEDERATION_URL,
COLUMN_SKIP_ZERO_CLICK,
COLUMN_GENERATION_UPLOAD_STATUS,
+ COLUMN_POSSIBLE_USERNAME_PAIRS,
COLUMN_NUM // Keep this last.
};
@@ -131,11 +137,6 @@ void BindAddStatement(const PasswordForm& form,
s->BindInt(COLUMN_BLACKLISTED_BY_USER, form.blacklisted_by_user);
s->BindInt(COLUMN_SCHEME, form.scheme);
s->BindInt(COLUMN_PASSWORD_TYPE, form.type);
- base::Pickle usernames_pickle =
- SerializeVector(form.other_possible_usernames);
- s->BindBlob(COLUMN_POSSIBLE_USERNAMES,
- usernames_pickle.data(),
- usernames_pickle.size());
s->BindInt(COLUMN_TIMES_USED, form.times_used);
base::Pickle form_data_pickle;
autofill::SerializeFormData(form.form_data, &form_data_pickle);
@@ -152,6 +153,10 @@ void BindAddStatement(const PasswordForm& form,
: form.federation_origin.Serialize());
s->BindInt(COLUMN_SKIP_ZERO_CLICK, form.skip_zero_click);
s->BindInt(COLUMN_GENERATION_UPLOAD_STATUS, form.generation_upload_status);
+ base::Pickle usernames_pickle =
+ SerializePossibleUsernamePairs(form.other_possible_usernames);
+ s->BindBlob(COLUMN_POSSIBLE_USERNAME_PAIRS, usernames_pickle.data(),
+ usernames_pickle.size());
}
void AddCallback(int err, sql::Statement* /*stmt*/) {
@@ -431,6 +436,12 @@ void InitializeBuilder(SQLTableBuilder* builder) {
version = builder->SealVersion();
DCHECK_EQ(18u, version);
+ // Version 19.
+ builder->DropColumn("possible_usernames");
+ builder->AddColumn("possible_username_pairs", "BLOB");
+ version = builder->SealVersion();
+ DCHECK_EQ(19u, version);
+
DCHECK_EQ(static_cast<size_t>(COLUMN_NUM), builder->NumberOfColumns())
<< "Adjust LoginTableColumns if you change column definitions here.";
}
@@ -844,37 +855,43 @@ PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form) {
DCHECK(!update_statement_.empty());
sql::Statement s(
db_.GetCachedStatement(SQL_FROM_HERE, update_statement_.c_str()));
- s.BindString(0, form.action.spec());
- s.BindBlob(1, encrypted_password.data(),
+ int next_param = 0;
+ s.BindString(next_param++, form.action.spec());
+ s.BindBlob(next_param++, encrypted_password.data(),
static_cast<int>(encrypted_password.length()));
- s.BindString16(2, form.submit_element);
- s.BindInt(3, form.preferred);
- s.BindInt64(4, form.date_created.ToInternalValue());
- s.BindInt(5, form.blacklisted_by_user);
- s.BindInt(6, form.scheme);
- s.BindInt(7, form.type);
- base::Pickle pickle = SerializeVector(form.other_possible_usernames);
- s.BindBlob(8, pickle.data(), pickle.size());
- s.BindInt(9, form.times_used);
+ s.BindString16(next_param++, form.submit_element);
+ s.BindInt(next_param++, form.preferred);
+ s.BindInt64(next_param++, form.date_created.ToInternalValue());
+ s.BindInt(next_param++, form.blacklisted_by_user);
+ s.BindInt(next_param++, form.scheme);
+ s.BindInt(next_param++, form.type);
+ s.BindInt(next_param++, form.times_used);
base::Pickle form_data_pickle;
autofill::SerializeFormData(form.form_data, &form_data_pickle);
- s.BindBlob(10, form_data_pickle.data(), form_data_pickle.size());
- s.BindInt64(11, form.date_synced.ToInternalValue());
- s.BindString16(12, form.display_name);
- s.BindString(13, form.icon_url.spec());
+ s.BindBlob(next_param++, form_data_pickle.data(), form_data_pickle.size());
+ s.BindInt64(next_param++, form.date_synced.ToInternalValue());
+ s.BindString16(next_param++, form.display_name);
+ s.BindString(next_param++, form.icon_url.spec());
// An empty Origin serializes as "null" which would be strange to store here.
- s.BindString(14, form.federation_origin.unique()
- ? std::string()
- : form.federation_origin.Serialize());
- s.BindInt(15, form.skip_zero_click);
- s.BindInt(16, form.generation_upload_status);
+ s.BindString(next_param++, form.federation_origin.unique()
+ ? std::string()
+ : form.federation_origin.Serialize());
+ s.BindInt(next_param++, form.skip_zero_click);
+ s.BindInt(next_param++, form.generation_upload_status);
+ base::Pickle username_pickle =
+ SerializePossibleUsernamePairs(form.other_possible_usernames);
+ s.BindBlob(next_param++, username_pickle.data(), username_pickle.size());
+ // NOTE: Add new fields here unless the field is a part of the unique key.
+ // If so, add new field below.
// WHERE starts here.
- s.BindString(17, form.origin.spec());
- s.BindString16(18, form.username_element);
- s.BindString16(19, form.username_value);
- s.BindString16(20, form.password_element);
- s.BindString(21, form.signon_realm);
+ s.BindString(next_param++, form.origin.spec());
+ s.BindString16(next_param++, form.username_element);
+ s.BindString16(next_param++, form.username_value);
+ s.BindString16(next_param++, form.password_element);
+ s.BindString(next_param++, form.signon_realm);
+ // NOTE: Add new fields here only if the field is a part of the unique key.
+ // Otherwise, add the field above "WHERE starts here" comment.
if (!s.Run())
return PasswordStoreChangeList();
@@ -998,11 +1015,11 @@ LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement(
int type_int = s.ColumnInt(COLUMN_PASSWORD_TYPE);
DCHECK(type_int >= 0 && type_int <= PasswordForm::TYPE_LAST) << type_int;
form->type = static_cast<PasswordForm::Type>(type_int);
- if (s.ColumnByteLength(COLUMN_POSSIBLE_USERNAMES)) {
+ if (s.ColumnByteLength(COLUMN_POSSIBLE_USERNAME_PAIRS)) {
base::Pickle pickle(
- static_cast<const char*>(s.ColumnBlob(COLUMN_POSSIBLE_USERNAMES)),
- s.ColumnByteLength(COLUMN_POSSIBLE_USERNAMES));
- form->other_possible_usernames = DeserializeVector(pickle);
+ static_cast<const char*>(s.ColumnBlob(COLUMN_POSSIBLE_USERNAME_PAIRS)),
+ s.ColumnByteLength(COLUMN_POSSIBLE_USERNAME_PAIRS));
+ form->other_possible_usernames = DeserializePossibleUsernamePairs(pickle);
}
form->times_used = s.ColumnInt(COLUMN_TIMES_USED);
if (s.ColumnByteLength(COLUMN_FORM_DATA)) {
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 e93ce3f9cba..e04d1c25c32 100644
--- a/chromium/components/password_manager/core/browser/login_database_unittest.cc
+++ b/chromium/components/password_manager/core/browser/login_database_unittest.cc
@@ -30,6 +30,8 @@
#include "url/origin.h"
using autofill::PasswordForm;
+using autofill::PossibleUsernamePair;
+using autofill::PossibleUsernamesVector;
using base::ASCIIToUTF16;
using ::testing::Eq;
using ::testing::Pointee;
@@ -130,8 +132,9 @@ MATCHER(IsBasicAuthAccount, "") {
} // namespace
// Serialization routines for vectors implemented in login_database.cc.
-base::Pickle SerializeVector(const std::vector<base::string16>& vec);
-std::vector<base::string16> DeserializeVector(const base::Pickle& pickle);
+base::Pickle SerializePossibleUsernamePairs(const PossibleUsernamesVector& vec);
+PossibleUsernamesVector DeserializePossibleUsernamePairs(
+ const base::Pickle& pickle);
class LoginDatabaseTest : public testing::Test {
protected:
@@ -428,6 +431,37 @@ TEST_F(LoginDatabaseTest, TestFederatedMatching) {
EXPECT_THAT(result, UnorderedElementsAre(Pointee(form), Pointee(form2)));
}
+TEST_F(LoginDatabaseTest, TestFederatedMatchingLocalhost) {
+ PasswordForm form;
+ form.origin = GURL("http://localhost/");
+ form.signon_realm = "federation://localhost/accounts.google.com";
+ form.federation_origin = url::Origin(GURL("https://accounts.google.com/"));
+ form.username_value = ASCIIToUTF16("test@gmail.com");
+ form.type = PasswordForm::TYPE_API;
+ form.scheme = PasswordForm::SCHEME_HTML;
+
+ PasswordForm form_with_port(form);
+ form_with_port.origin = GURL("http://localhost:8080/");
+ form_with_port.signon_realm = "federation://localhost/accounts.google.com";
+
+ EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
+ EXPECT_EQ(AddChangeForForm(form_with_port), db().AddLogin(form_with_port));
+
+ // Match twice.
+ PasswordStore::FormDigest form_request(PasswordForm::SCHEME_HTML,
+ "http://localhost/",
+ GURL("http://localhost/"));
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ EXPECT_TRUE(db().GetLogins(form_request, &result));
+ EXPECT_THAT(result, UnorderedElementsAre(Pointee(form)));
+
+ // Match against the mobile site.
+ form_request.origin = GURL("http://localhost:8080/");
+ form_request.signon_realm = "http://localhost:8080/";
+ EXPECT_TRUE(db().GetLogins(form_request, &result));
+ EXPECT_THAT(result, UnorderedElementsAre(Pointee(form_with_port)));
+}
+
TEST_F(LoginDatabaseTest, TestPublicSuffixDisabledForNonHTMLForms) {
TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_BASIC);
TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_DIGEST);
@@ -963,18 +997,21 @@ TEST_F(LoginDatabaseTest, BlacklistedLogins) {
TEST_F(LoginDatabaseTest, VectorSerialization) {
// Empty vector.
- std::vector<base::string16> vec;
- base::Pickle temp = SerializeVector(vec);
- std::vector<base::string16> output = DeserializeVector(temp);
+ PossibleUsernamesVector vec;
+ base::Pickle temp = SerializePossibleUsernamePairs(vec);
+ PossibleUsernamesVector output = DeserializePossibleUsernamePairs(temp);
EXPECT_THAT(output, Eq(vec));
// Normal data.
- vec.push_back(ASCIIToUTF16("first"));
- vec.push_back(ASCIIToUTF16("second"));
- vec.push_back(ASCIIToUTF16("third"));
-
- temp = SerializeVector(vec);
- output = DeserializeVector(temp);
+ vec.push_back(
+ PossibleUsernamePair(ASCIIToUTF16("first"), ASCIIToUTF16("id1")));
+ vec.push_back(
+ PossibleUsernamePair(ASCIIToUTF16("second"), ASCIIToUTF16("id2")));
+ vec.push_back(
+ PossibleUsernamePair(ASCIIToUTF16("third"), ASCIIToUTF16("id3")));
+
+ temp = SerializePossibleUsernamePairs(vec);
+ output = DeserializePossibleUsernamePairs(temp);
EXPECT_THAT(output, Eq(vec));
}
@@ -1149,7 +1186,8 @@ TEST_F(LoginDatabaseTest, UpdateLogin) {
form.action = GURL("http://accounts.google.com/login");
form.password_value = ASCIIToUTF16("my_new_password");
form.preferred = false;
- form.other_possible_usernames.push_back(ASCIIToUTF16("my_new_username"));
+ form.other_possible_usernames.push_back(autofill::PossibleUsernamePair(
+ ASCIIToUTF16("my_new_username"), ASCIIToUTF16("new_username_id")));
form.times_used = 20;
form.submit_element = ASCIIToUTF16("submit_element");
form.date_synced = base::Time::Now();
diff --git a/chromium/components/password_manager/core/browser/mock_password_store.h b/chromium/components/password_manager/core/browser/mock_password_store.h
index 7d05812bf30..a8dbbf4d36b 100644
--- a/chromium/components/password_manager/core/browser/mock_password_store.h
+++ b/chromium/components/password_manager/core/browser/mock_password_store.h
@@ -19,6 +19,9 @@ class MockPasswordStore : public PasswordStore {
public:
MockPasswordStore();
+ bool Init(const syncer::SyncableService::StartSyncFlare& flare) override {
+ return true;
+ };
MOCK_METHOD1(RemoveLogin, void(const autofill::PasswordForm&));
MOCK_METHOD2(GetLogins,
void(const PasswordStore::FormDigest&, PasswordStoreConsumer*));
@@ -64,10 +67,13 @@ class MockPasswordStore : public PasswordStore {
std::vector<InteractionsStats>(const GURL& origin_domain));
MOCK_METHOD1(AddSiteStatsImpl, void(const InteractionsStats&));
MOCK_METHOD1(RemoveSiteStatsImpl, void(const GURL&));
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
MOCK_METHOD3(CheckReuse,
void(const base::string16&,
const std::string&,
PasswordReuseDetectorConsumer*));
+#endif
PasswordStoreSync* GetSyncInterface() { return this; }
diff --git a/chromium/components/password_manager/core/browser/obsolete_http_cleaner.cc b/chromium/components/password_manager/core/browser/obsolete_http_cleaner.cc
deleted file mode 100644
index c1daec4eddd..00000000000
--- a/chromium/components/password_manager/core/browser/obsolete_http_cleaner.cc
+++ /dev/null
@@ -1,118 +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/password_manager/core/browser/obsolete_http_cleaner.h"
-
-#include <algorithm>
-#include <iterator>
-#include <tuple>
-
-#include "base/logging.h"
-#include "components/autofill/core/common/password_form.h"
-#include "components/password_manager/core/browser/password_manager_client.h"
-#include "components/password_manager/core/browser/password_store.h"
-#include "components/password_manager/core/browser/statistics_table.h"
-#include "url/url_constants.h"
-
-using autofill::PasswordForm;
-
-namespace password_manager {
-
-namespace {
-
-std::vector<std::unique_ptr<PasswordForm>> SplitFormsFrom(
- std::vector<std::unique_ptr<PasswordForm>>::iterator from,
- std::vector<std::unique_ptr<PasswordForm>>* forms) {
- std::vector<std::unique_ptr<PasswordForm>> result;
- result.reserve(std::distance(from, std::end(*forms)));
- std::move(from, std::end(*forms), std::back_inserter(result));
- forms->erase(from, std::end(*forms));
- return result;
-}
-
-} // namespace
-
-ObsoleteHttpCleaner::ObsoleteHttpCleaner(const PasswordManagerClient* client)
- : client_(client) {
- DCHECK(client_);
-}
-
-ObsoleteHttpCleaner::~ObsoleteHttpCleaner() = default;
-
-void ObsoleteHttpCleaner::OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<PasswordForm>> results) {
- // Non HTTP or HTTPS credentials are ignored.
- results.erase(std::remove_if(std::begin(results), std::end(results),
- [](const std::unique_ptr<PasswordForm>& form) {
- return !form->origin.SchemeIsHTTPOrHTTPS();
- }),
- std::end(results));
-
- // Move HTTPS forms into their own container.
- auto https_forms = SplitFormsFrom(
- std::partition(std::begin(results), std::end(results),
- [](const std::unique_ptr<PasswordForm>& form) {
- return form->origin.SchemeIs(url::kHttpScheme);
- }),
- &results);
-
- // Move blacklisted HTTP forms into their own container.
- const auto blacklisted_http_forms = SplitFormsFrom(
- std::partition(std::begin(results), std::end(results),
- [](const std::unique_ptr<PasswordForm>& form) {
- return !form->blacklisted_by_user;
- }),
- &results);
-
- // Remove blacklisted HTTP forms from the password store when HSTS is active
- // for the given host.
- for (const auto& form : blacklisted_http_forms) {
- if (client_->IsHSTSActiveForHost(form->origin))
- client_->GetPasswordStore()->RemoveLogin(*form);
- }
-
- // Return early if there are no non-blacklisted HTTP forms.
- if (results.empty())
- return;
-
- // Ignore non HSTS forms.
- https_forms.erase(
- std::remove_if(std::begin(https_forms), std::end(https_forms),
- [this](const std::unique_ptr<PasswordForm>& form) {
- return !client_->IsHSTSActiveForHost(form->origin);
- }),
- std::end(https_forms));
-
- // Sort HSTS forms according to custom comparison function. Consider two forms
- // equivalent if they have the same host, as well as the same username and
- // password.
- const auto form_cmp = [](const std::unique_ptr<PasswordForm>& lhs,
- const std::unique_ptr<PasswordForm>& rhs) {
- return std::forward_as_tuple(lhs->origin.host_piece(), lhs->username_value,
- lhs->password_value) <
- std::forward_as_tuple(rhs->origin.host_piece(), rhs->username_value,
- rhs->password_value);
- };
-
- std::sort(std::begin(https_forms), std::end(https_forms), form_cmp);
-
- // Iterate through HTTP forms and remove them from the password store if there
- // exists an equivalent HSTS form.
- for (const auto& form : results) {
- if (std::binary_search(std::begin(https_forms), std::end(https_forms), form,
- form_cmp))
- client_->GetPasswordStore()->RemoveLogin(*form);
- }
-}
-
-void ObsoleteHttpCleaner::OnGetSiteStatistics(
- std::vector<InteractionsStats> stats) {
- for (const auto& stat : stats) {
- if (stat.origin_domain.SchemeIs(url::kHttpScheme) &&
- client_->IsHSTSActiveForHost(stat.origin_domain))
- client_->GetPasswordStore()->RemoveSiteStats(stat.origin_domain);
- }
-}
-
-} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/obsolete_http_cleaner.h b/chromium/components/password_manager/core/browser/obsolete_http_cleaner.h
deleted file mode 100644
index 6b974e82990..00000000000
--- a/chromium/components/password_manager/core/browser/obsolete_http_cleaner.h
+++ /dev/null
@@ -1,50 +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_PASSWORD_MANAGER_CORE_BROWSER_OBSOLETE_HTTP_CLEANER_H_
-#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_OBSOLETE_HTTP_CLEANER_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "components/password_manager/core/browser/password_store_consumer.h"
-
-namespace autofill {
-struct PasswordForm;
-}
-
-namespace password_manager {
-
-class PasswordManagerClient;
-
-// This class removes obsolete HTTP data from a password store. HTTP data is
-// obsolete, if the corresponding host migrated to HTTPS and has HSTS enabled.
-class ObsoleteHttpCleaner : public PasswordStoreConsumer {
- public:
- explicit ObsoleteHttpCleaner(const PasswordManagerClient* client);
- ~ObsoleteHttpCleaner() override;
-
- // PasswordStoreConsumer:
- // This will be called for both autofillable logins as well as blacklisted
- // logins. Blacklisted logins are removed iff the scheme is HTTP and HSTS is
- // enabled for the host.
- // Autofillable logins are removed iff the scheme is HTTP and there exists
- // another HTTPS login with active HSTS that has the same host as well as the
- // same username and password.
- void OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
-
- // This will remove all stats for HTTP sites for which HSTS is active.
- void OnGetSiteStatistics(std::vector<InteractionsStats> stats) override;
-
- private:
- const PasswordManagerClient* const client_;
-
- DISALLOW_COPY_AND_ASSIGN(ObsoleteHttpCleaner);
-};
-
-} // namespace password_manager
-
-#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_OBSOLETE_HTTP_CLEANER_H_
diff --git a/chromium/components/password_manager/core/browser/obsolete_http_cleaner_unittest.cc b/chromium/components/password_manager/core/browser/obsolete_http_cleaner_unittest.cc
deleted file mode 100644
index 7ae1fd70d40..00000000000
--- a/chromium/components/password_manager/core/browser/obsolete_http_cleaner_unittest.cc
+++ /dev/null
@@ -1,233 +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/password_manager/core/browser/obsolete_http_cleaner.h"
-
-#include <ios>
-
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/password_manager/core/browser/mock_password_store.h"
-#include "components/password_manager/core/browser/stub_password_manager_client.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-using autofill::PasswordForm;
-using testing::Return;
-
-namespace password_manager {
-
-namespace {
-
-constexpr char kTestHttpURL[] = "http://example.org/";
-constexpr char kTestHttpsURL[] = "https://example.org/";
-
-PasswordForm CreateTestHTTPForm() {
- PasswordForm form;
- form.origin = GURL(kTestHttpURL);
- form.signon_realm = form.origin.spec();
- form.action = form.origin;
- form.username_value = base::ASCIIToUTF16("user");
- form.password_value = base::ASCIIToUTF16("password");
- return form;
-}
-
-PasswordForm CreateTestHTTPSForm() {
- PasswordForm form;
- form.origin = GURL(kTestHttpsURL);
- form.signon_realm = form.origin.spec();
- form.action = form.origin;
- form.username_value = base::ASCIIToUTF16("user");
- form.password_value = base::ASCIIToUTF16("password");
- return form;
-}
-
-InteractionsStats CreateTestHTTPStats() {
- InteractionsStats stats;
- stats.origin_domain = GURL(kTestHttpURL);
- stats.username_value = base::ASCIIToUTF16("user");
- return stats;
-}
-
-InteractionsStats CreateTestHTTPSStats() {
- InteractionsStats stats;
- stats.origin_domain = GURL(kTestHttpsURL);
- stats.username_value = base::ASCIIToUTF16("user");
- return stats;
-}
-
-// Small helper that wraps passed in forms in unique ptrs.
-std::vector<std::unique_ptr<PasswordForm>> MakeResults(
- const std::vector<PasswordForm>& forms) {
- std::vector<std::unique_ptr<PasswordForm>> results;
- results.reserve(forms.size());
- for (const auto& form : forms)
- results.push_back(base::MakeUnique<PasswordForm>(form));
- return results;
-}
-
-class MockPasswordManagerClient : public StubPasswordManagerClient {
- public:
- explicit MockPasswordManagerClient(PasswordStore* store) : store_(store) {}
-
- PasswordStore* GetPasswordStore() const override { return store_; }
- MOCK_CONST_METHOD1(IsHSTSActiveForHost, bool(const GURL&));
-
- private:
- PasswordStore* store_;
-
- DISALLOW_COPY_AND_ASSIGN(MockPasswordManagerClient);
-};
-
-} // namespace
-
-class ObsoleteHttpCleanerTest : public testing::Test {
- public:
- ObsoleteHttpCleanerTest()
- : mock_store_(new testing::StrictMock<MockPasswordStore>),
- client_(mock_store_.get()) {}
- ~ObsoleteHttpCleanerTest() override { mock_store_->ShutdownOnUIThread(); }
-
- MockPasswordStore& store() { return *mock_store_; }
- MockPasswordManagerClient& client() { return client_; }
-
- private:
- base::MessageLoop message_loop_; // Used by mock_store_.
- scoped_refptr<MockPasswordStore> mock_store_;
- MockPasswordManagerClient client_;
-
- DISALLOW_COPY_AND_ASSIGN(ObsoleteHttpCleanerTest);
-};
-
-TEST_F(ObsoleteHttpCleanerTest, TestBlacklistDeletion) {
- struct TestCase {
- bool is_http;
- bool is_blacklisted;
- bool is_hsts;
- bool is_deleted;
- };
-
- constexpr static TestCase cases[] = {
- {true, true, true, true}, {true, true, false, false},
- {true, false, true, false}, {true, false, false, false},
- {false, true, true, false}, {false, true, false, false},
- {false, false, true, false}, {false, false, false, false},
- };
-
- ObsoleteHttpCleaner cleaner(&client());
- for (const auto& test_case : cases) {
- SCOPED_TRACE(testing::Message()
- << std::boolalpha
- << "(is_http, is_blacklisted, is_hsts, is_deleted): ("
- << test_case.is_http << ", " << test_case.is_blacklisted
- << ", " << test_case.is_hsts << ", " << test_case.is_deleted
- << ")");
-
- PasswordForm form =
- test_case.is_http ? CreateTestHTTPForm() : CreateTestHTTPSForm();
- form.blacklisted_by_user = test_case.is_blacklisted;
- if (test_case.is_http && test_case.is_blacklisted) {
- EXPECT_CALL(client(), IsHSTSActiveForHost(form.origin))
- .WillOnce(Return(test_case.is_hsts));
- }
-
- EXPECT_CALL(store(), RemoveLogin(form)).Times(test_case.is_deleted);
- cleaner.OnGetPasswordStoreResults(MakeResults({form}));
- }
-}
-
-TEST_F(ObsoleteHttpCleanerTest, TestAutofillableDeletion) {
- struct TestCase {
- bool is_hsts;
- bool same_host;
- bool same_user;
- bool same_pass;
- bool is_deleted;
- };
-
- constexpr static TestCase cases[] = {
- {true, true, true, true, true}, {true, true, true, false, false},
- {true, true, false, true, false}, {true, true, false, false, false},
- {true, false, true, true, false}, {true, false, true, false, false},
- {true, false, false, true, false}, {true, false, false, false, false},
- {false, true, true, true, false}, {false, true, true, false, false},
- {false, true, false, true, false}, {false, true, false, false, false},
- {false, false, true, true, false}, {false, false, true, false, false},
- {false, false, false, true, false}, {false, false, false, false, false},
- };
-
- ObsoleteHttpCleaner cleaner(&client());
- for (const auto& test_case : cases) {
- SCOPED_TRACE(testing::Message()
- << std::boolalpha
- << "(is_hsts, same_host, same_user, same_pass, is_deleted): ("
- << test_case.is_hsts << ", " << test_case.same_host << ", "
- << test_case.same_user << ", " << test_case.same_pass << ", "
- << test_case.is_deleted << ")");
-
- PasswordForm http_form = CreateTestHTTPForm();
- PasswordForm https_form = CreateTestHTTPSForm();
-
- if (!test_case.same_host) {
- GURL::Replacements rep;
- rep.SetHostStr("a-totally-different-host");
- http_form.origin = http_form.origin.ReplaceComponents(rep);
- }
-
- if (!test_case.same_user) {
- http_form.username_value =
- https_form.username_value + base::ASCIIToUTF16("-different");
- }
-
- if (!test_case.same_pass) {
- http_form.password_value =
- https_form.password_value + base::ASCIIToUTF16("-different");
- }
-
- EXPECT_CALL(client(), IsHSTSActiveForHost(https_form.origin))
- .WillOnce(Return(test_case.is_hsts));
- EXPECT_CALL(store(), RemoveLogin(http_form)).Times(test_case.is_deleted);
- cleaner.OnGetPasswordStoreResults(MakeResults({http_form, https_form}));
- }
-}
-
-TEST_F(ObsoleteHttpCleanerTest, TestSiteStatsDeletion) {
- struct TestCase {
- bool is_http;
- bool is_hsts;
- bool is_deleted;
- };
-
- constexpr static TestCase cases[] = {
- {true, true, true},
- {true, false, false},
- {false, true, false},
- {false, false, false},
- };
-
- ObsoleteHttpCleaner cleaner(&client());
- for (const auto& test_case : cases) {
- SCOPED_TRACE(testing::Message()
- << std::boolalpha << "(is_http, is_hsts, is_deleted): ("
- << test_case.is_http << ", " << test_case.is_hsts << ", "
- << test_case.is_deleted << ")");
-
- InteractionsStats stats =
- test_case.is_http ? CreateTestHTTPStats() : CreateTestHTTPSStats();
- if (test_case.is_http) {
- EXPECT_CALL(client(), IsHSTSActiveForHost(stats.origin_domain))
- .WillOnce(Return(test_case.is_hsts));
- }
-
- EXPECT_CALL(store(), RemoveSiteStatsImpl(stats.origin_domain))
- .Times(test_case.is_deleted);
- cleaner.OnGetSiteStatistics({stats});
- base::RunLoop().RunUntilIdle();
- }
-}
-
-} // namespace password_manager
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 af37be8c190..eb88be67ab7 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_form_manager.cc
@@ -14,6 +14,7 @@
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
+#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -24,6 +25,7 @@
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/affiliation_utils.h"
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
+#include "components/password_manager/core/browser/form_fetcher_impl.h"
#include "components/password_manager/core/browser/form_saver.h"
#include "components/password_manager/core/browser/log_manager.h"
#include "components/password_manager/core/browser/password_manager.h"
@@ -37,6 +39,7 @@
using autofill::FormStructure;
using autofill::PasswordForm;
+using autofill::PossibleUsernamePair;
using base::Time;
// Shorten the name to spare line breaks. The code provides enough context
@@ -107,16 +110,16 @@ void SanitizePossibleUsernames(PasswordForm* form) {
// Deduplicate.
std::sort(usernames.begin(), usernames.end());
- auto new_end = std::unique(usernames.begin(), usernames.end());
-
- // Filter out |form->username_value|.
- new_end = std::remove(usernames.begin(), new_end, form->username_value);
-
- // Filter out sensitive information.
- new_end = std::remove_if(usernames.begin(), new_end,
- autofill::IsValidCreditCardNumber);
- new_end = std::remove_if(usernames.begin(), new_end, autofill::IsSSN);
- usernames.erase(new_end, usernames.end());
+ usernames.erase(std::unique(usernames.begin(), usernames.end()),
+ usernames.end());
+
+ // Filter out |form->username_value| and sensitive information.
+ const base::string16& username_value = form->username_value;
+ base::EraseIf(usernames, [&username_value](const PossibleUsernamePair& pair) {
+ return pair.first == username_value ||
+ autofill::IsValidCreditCardNumber(pair.first) ||
+ autofill::IsSSN(pair.first);
+ });
}
// Copies field properties masks from the form |from| to the form |to|.
@@ -194,6 +197,14 @@ void LabelFields(const FieldTypeMap& field_types,
}
}
+// Check whether |form_data| corresponds to a 2 field form with 1 text field and
+// 1 password field. Such form is likely sign-in form.
+bool IsSignInSubmission(const FormData& form_data) {
+ return form_data.fields.size() == 2 &&
+ form_data.fields[0].form_control_type == "text" &&
+ form_data.fields[1].form_control_type == "password";
+}
+
} // namespace
PasswordFormManager::PasswordFormManager(
@@ -228,16 +239,16 @@ PasswordFormManager::PasswordFormManager(
submit_result_(kSubmitResultNotSubmitted),
form_type_(kFormTypeUnspecified),
form_saver_(std::move(form_saver)),
- form_fetcher_impl_(form_fetcher
- ? nullptr
- : base::MakeUnique<FormFetcherImpl>(
- PasswordStore::FormDigest(observed_form),
- client,
- /* should_migrate_http_passwords */ true)),
- form_fetcher_(form_fetcher ? form_fetcher : form_fetcher_impl_.get()),
+ owned_form_fetcher_(form_fetcher
+ ? nullptr
+ : base::MakeUnique<FormFetcherImpl>(
+ PasswordStore::FormDigest(observed_form),
+ client,
+ /* should_migrate_http_passwords */ true)),
+ form_fetcher_(form_fetcher ? form_fetcher : owned_form_fetcher_.get()),
is_main_frame_secure_(client->IsMainFrameSecure()) {
- if (form_fetcher_impl_)
- form_fetcher_impl_->Fetch();
+ if (owned_form_fetcher_)
+ owned_form_fetcher_->Fetch();
DCHECK_EQ(observed_form.scheme == PasswordForm::SCHEME_HTML,
driver != nullptr);
if (driver)
@@ -246,6 +257,8 @@ PasswordFormManager::PasswordFormManager(
}
PasswordFormManager::~PasswordFormManager() {
+ form_fetcher_->RemoveConsumer(this);
+
UMA_HISTOGRAM_ENUMERATION("PasswordManager.ActionsTakenV3", GetActionsTaken(),
kMaxNumActionsTaken);
// Use the visible main frame URL at the time the PasswordFormManager
@@ -364,7 +377,7 @@ bool PasswordFormManager::IsBlacklisted() const {
void PasswordFormManager::PermanentlyBlacklist() {
DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
- DCHECK(!client_->IsOffTheRecord());
+ DCHECK(!client_->IsIncognito());
if (!new_blacklisted_) {
new_blacklisted_ = base::MakeUnique<PasswordForm>(observed_form_);
@@ -404,7 +417,7 @@ void PasswordFormManager::ProvisionallySave(
void PasswordFormManager::Save() {
DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
- DCHECK(!client_->IsOffTheRecord());
+ DCHECK(!client_->IsIncognito());
if ((user_action_ == kUserActionNone) &&
DidPreferenceChange(best_matches_, pending_credentials_.username_value)) {
@@ -440,7 +453,7 @@ void PasswordFormManager::Update(
const autofill::PasswordForm& credentials_to_update) {
if (observed_form_.IsPossibleChangePasswordForm()) {
FormStructure form_structure(credentials_to_update.form_data);
- UploadPasswordVote(autofill::NEW_PASSWORD,
+ UploadPasswordVote(observed_form_, autofill::NEW_PASSWORD,
form_structure.FormSignatureAsStr());
}
base::string16 password_to_save = pending_credentials_.password_value;
@@ -617,7 +630,7 @@ void PasswordFormManager::ProcessFrameInternal(
// via affiliation-based matching (we want to autofill them).
// TODO(engedy): Clean this up. See: https://crbug.com/476519.
bool wait_for_username =
- client_->IsOffTheRecord() ||
+ client_->IsIncognito() ||
(!IsValidAndroidFacetURI(preferred_match_->signon_realm) &&
(observed_form_.action.GetWithEmptyPath() !=
preferred_match_->action.GetWithEmptyPath() ||
@@ -663,7 +676,7 @@ void PasswordFormManager::ProcessUpdate() {
// username, or the user selected one of the non-preferred matches,
// thus requiring a swap of preferred bits.
DCHECK(!IsNewLogin() && pending_credentials_.preferred);
- DCHECK(!client_->IsOffTheRecord());
+ DCHECK(!client_->IsIncognito());
UpdateMetadataForUsage(&pending_credentials_);
@@ -674,7 +687,7 @@ void PasswordFormManager::ProcessUpdate() {
// Do not send votes on change password forms, since they were already sent in
// Update() method.
if (!observed_form_.IsPossibleChangePasswordForm())
- SendAutofillVotes(observed_form_, &pending_credentials_);
+ SendVoteOnCredentialsReuse(observed_form_, &pending_credentials_);
}
bool PasswordFormManager::UpdatePendingCredentialsIfOtherPossibleUsername(
@@ -682,7 +695,7 @@ bool PasswordFormManager::UpdatePendingCredentialsIfOtherPossibleUsername(
for (const auto& key_value : best_matches_) {
const PasswordForm& match = *key_value.second;
for (size_t i = 0; i < match.other_possible_usernames.size(); ++i) {
- if (match.other_possible_usernames[i] == username) {
+ if (match.other_possible_usernames[i].first == username) {
pending_credentials_ = match;
return true;
}
@@ -691,8 +704,40 @@ bool PasswordFormManager::UpdatePendingCredentialsIfOtherPossibleUsername(
return false;
}
-void PasswordFormManager::SendAutofillVotes(const PasswordForm& observed,
- PasswordForm* pending) {
+bool PasswordFormManager::FindUsernameInOtherPossibleUsernames(
+ const autofill::PasswordForm& match,
+ const base::string16& username) {
+ DCHECK(!username_correction_vote_);
+
+ for (const PossibleUsernamePair& pair : match.other_possible_usernames) {
+ if (pair.first == username) {
+ username_correction_vote_.reset(new autofill::PasswordForm(match));
+ username_correction_vote_->username_element = pair.second;
+ return true;
+ }
+ }
+ return false;
+}
+
+void PasswordFormManager::FindCorrectedUsernameElement(
+ const base::string16& username,
+ const base::string16& password) {
+ for (const auto& key_value : best_matches_) {
+ const PasswordForm* match = key_value.second;
+ if ((match->password_value == password) &&
+ FindUsernameInOtherPossibleUsernames(*match, username))
+ return;
+ }
+ for (const autofill::PasswordForm* match : not_best_matches_) {
+ if ((match->password_value == password) &&
+ FindUsernameInOtherPossibleUsernames(*match, username))
+ return;
+ }
+}
+
+void PasswordFormManager::SendVoteOnCredentialsReuse(
+ const PasswordForm& observed,
+ PasswordForm* pending) {
// Ignore |pending_structure| if its FormData has no fields. This is to
// weed out those credentials that were saved before FormData was added
// to PasswordForm. Even without this check, these FormStructure's won't
@@ -713,7 +758,7 @@ void PasswordFormManager::SendAutofillVotes(const PasswordForm& observed,
// in cases where we currently save the wrong username isn't great.
// TODO(gcasto): Determine if generation should be offered in this case.
if (pending->times_used == 1 && selected_username_.empty()) {
- if (UploadPasswordVote(autofill::ACCOUNT_CREATION_PASSWORD,
+ if (UploadPasswordVote(*pending, autofill::ACCOUNT_CREATION_PASSWORD,
observed_structure.FormSignatureAsStr())) {
pending->generation_upload_status =
autofill::PasswordForm::POSITIVE_SIGNAL_SENT;
@@ -724,7 +769,7 @@ void PasswordFormManager::SendAutofillVotes(const PasswordForm& observed,
// A signal was sent that this was an account creation form, but the
// credential is now being used on the same form again. This cancels out
// the previous vote.
- if (UploadPasswordVote(autofill::NOT_ACCOUNT_CREATION_PASSWORD,
+ if (UploadPasswordVote(*pending, autofill::NOT_ACCOUNT_CREATION_PASSWORD,
std::string())) {
pending->generation_upload_status =
autofill::PasswordForm::NEGATIVE_SIGNAL_SENT;
@@ -732,11 +777,12 @@ void PasswordFormManager::SendAutofillVotes(const PasswordForm& observed,
} else if (generation_popup_was_shown_) {
// Even if there is no autofill vote to be sent, send the vote about the
// usage of the generation popup.
- UploadPasswordVote(autofill::UNKNOWN_TYPE, std::string());
+ UploadPasswordVote(*pending, autofill::UNKNOWN_TYPE, std::string());
}
}
bool PasswordFormManager::UploadPasswordVote(
+ const autofill::PasswordForm& form_to_upload,
const autofill::ServerFieldType& password_type,
const std::string& login_form_signature) {
// Check if there is any vote to be sent.
@@ -750,14 +796,10 @@ bool PasswordFormManager::UploadPasswordVote(
if (!autofill_manager || !autofill_manager->download_manager())
return false;
- bool is_update = password_type == autofill::NEW_PASSWORD ||
- password_type == autofill::PROBABLY_NEW_PASSWORD ||
- password_type == autofill::NOT_NEW_PASSWORD;
// If this is an update, a vote about the observed form is sent. If the user
// re-uses credentials, a vote about the saved form is sent. If the user saves
// credentials, the observed and pending forms are the same.
- FormStructure form_structure(is_update ? observed_form_.form_data
- : pending_credentials_.form_data);
+ FormStructure form_structure(form_to_upload.form_data);
if (!autofill_manager->ShouldUploadForm(form_structure) ||
!form_structure.ShouldBeCrowdsourced()) {
UMA_HISTOGRAM_BOOLEAN("PasswordGeneration.UploadStarted", false);
@@ -765,30 +807,39 @@ bool PasswordFormManager::UploadPasswordVote(
}
autofill::ServerFieldTypeSet available_field_types;
- if (has_autofill_vote) {
- // A map from field names to field types.
- FieldTypeMap field_types;
- DCHECK(submitted_form_);
- if (is_update) {
- if (submitted_form_->new_password_element.empty())
- return false;
- SetFieldLabelsOnUpdate(password_type, *submitted_form_, &field_types);
- } else {
- SetFieldLabelsOnSave(password_type, *submitted_form_, &field_types);
- if (password_type == autofill::ACCOUNT_CREATION_PASSWORD) {
- field_types[pending_credentials_.username_element] = autofill::USERNAME;
+ if (password_type != autofill::USERNAME) {
+ if (has_autofill_vote) {
+ // A map from field names to field types.
+ FieldTypeMap field_types;
+ DCHECK(submitted_form_);
+ bool is_update = password_type == autofill::NEW_PASSWORD ||
+ password_type == autofill::PROBABLY_NEW_PASSWORD ||
+ password_type == autofill::NOT_NEW_PASSWORD;
+ if (is_update) {
+ if (submitted_form_->new_password_element.empty())
+ return false;
+ SetFieldLabelsOnUpdate(password_type, *submitted_form_, &field_types);
+ } else { // Saving.
+ SetFieldLabelsOnSave(password_type, *submitted_form_, &field_types);
}
+ field_types[submitted_form_->confirmation_password_element] =
+ autofill::CONFIRMATION_PASSWORD;
+ LabelFields(field_types, &form_structure, &available_field_types);
+ }
+ if (password_type != autofill::ACCOUNT_CREATION_PASSWORD) {
+ if (generation_popup_was_shown_)
+ AddGeneratedVote(&form_structure);
+ if (form_classifier_outcome_ != kNoOutcome)
+ AddFormClassifierVote(&form_structure);
}
- field_types[submitted_form_->confirmation_password_element] =
- autofill::CONFIRMATION_PASSWORD;
+ } else { // Username correction vote.
+ FieldTypeMap field_types;
+ field_types[form_to_upload.username_element] = autofill::USERNAME;
+ field_types[form_to_upload.password_element] =
+ autofill::ACCOUNT_CREATION_PASSWORD;
LabelFields(field_types, &form_structure, &available_field_types);
}
- if (generation_popup_was_shown_)
- AddGeneratedVote(&form_structure);
- if (form_classifier_outcome_ != kNoOutcome)
- AddFormClassifierVote(&form_structure);
-
// Force uploading as these events are relatively rare and we want to make
// sure to receive them.
form_structure.set_upload_required(UPLOAD_REQUIRED);
@@ -969,6 +1020,8 @@ void PasswordFormManager::CreatePendingCredentials() {
}
} else {
CreatePendingCredentialsForNewCredentials();
+ FindCorrectedUsernameElement(submitted_form_->username_value,
+ submitted_form_->password_value);
}
if (!IsValidAndroidFacetURI(pending_credentials_.signon_realm)) {
@@ -1161,19 +1214,22 @@ void PasswordFormManager::CreatePendingCredentialsForNewCredentials() {
}
void PasswordFormManager::OnNopeUpdateClicked() {
- UploadPasswordVote(autofill::NOT_NEW_PASSWORD, std::string());
+ UploadPasswordVote(observed_form_, autofill::NOT_NEW_PASSWORD, std::string());
}
void PasswordFormManager::OnNeverClicked() {
- UploadPasswordVote(autofill::UNKNOWN_TYPE, std::string());
+ UploadPasswordVote(pending_credentials_, autofill::UNKNOWN_TYPE,
+ std::string());
PermanentlyBlacklist();
}
void PasswordFormManager::OnNoInteraction(bool is_update) {
if (is_update)
- UploadPasswordVote(autofill::PROBABLY_NEW_PASSWORD, std::string());
+ UploadPasswordVote(observed_form_, autofill::PROBABLY_NEW_PASSWORD,
+ std::string());
else {
- UploadPasswordVote(autofill::UNKNOWN_TYPE, std::string());
+ UploadPasswordVote(pending_credentials_, autofill::UNKNOWN_TYPE,
+ std::string());
}
}
@@ -1219,21 +1275,64 @@ void PasswordFormManager::SaveGenerationFieldDetectedByClassifier(
generation_element_detected_by_classifier_ = generation_field;
}
+void PasswordFormManager::ResetStoredMatches() {
+ preferred_match_ = nullptr;
+ best_matches_.clear();
+ not_best_matches_.clear();
+ blacklisted_matches_.clear();
+ new_blacklisted_.reset();
+}
+
+void PasswordFormManager::GrabFetcher(std::unique_ptr<FormFetcher> fetcher) {
+ DCHECK(!owned_form_fetcher_);
+ owned_form_fetcher_ = std::move(fetcher);
+ if (owned_form_fetcher_.get() == form_fetcher_)
+ return;
+ ResetStoredMatches();
+ form_fetcher_->RemoveConsumer(this);
+ form_fetcher_ = owned_form_fetcher_.get();
+ form_fetcher_->AddConsumer(this);
+}
+
void PasswordFormManager::SendVotesOnSave() {
if (observed_form_.IsPossibleChangePasswordFormWithoutUsername())
return;
+ if (IsSignInSubmission(pending_credentials_.form_data)) {
+ SendSignInVote(pending_credentials_.form_data);
+ return;
+ }
+
// Upload credentials the first time they are saved. This data is used
// by password generation to help determine account creation sites.
// Credentials that have been previously used (e.g., PSL matches) are checked
// to see if they are valid account creation forms.
if (pending_credentials_.times_used == 0) {
- autofill::ServerFieldType password_type = autofill::PASSWORD;
- if (does_look_like_signup_form_)
- password_type = autofill::PROBABLY_ACCOUNT_CREATION_PASSWORD;
- UploadPasswordVote(password_type, std::string());
+ autofill::ServerFieldType password_type = autofill::PASSWORD;
+ if (does_look_like_signup_form_)
+ password_type = autofill::PROBABLY_ACCOUNT_CREATION_PASSWORD;
+ UploadPasswordVote(pending_credentials_, password_type, std::string());
+ if (username_correction_vote_) {
+ UploadPasswordVote(
+ *username_correction_vote_, autofill::USERNAME,
+ FormStructure(observed_form_.form_data).FormSignatureAsStr());
+ }
} else
- SendAutofillVotes(observed_form_, &pending_credentials_);
+ SendVoteOnCredentialsReuse(observed_form_, &pending_credentials_);
+}
+
+void PasswordFormManager::SendSignInVote(const FormData& form_data) {
+ autofill::AutofillManager* autofill_manager =
+ client_->GetAutofillManagerForMainFrame();
+ if (!autofill_manager)
+ return;
+ std::unique_ptr<FormStructure> form_structure(new FormStructure(form_data));
+ form_structure->set_is_signin_upload(true);
+ DCHECK(form_structure->ShouldBeCrowdsourced());
+ DCHECK_EQ(2u, form_structure->field_count());
+ form_structure->field(1)->set_possible_types({autofill::PASSWORD});
+ autofill_manager->StartUploadProcess(std::move(form_structure),
+ base::TimeTicks::Now(), true);
}
void PasswordFormManager::SetUserAction(UserAction user_action) {
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 fa0257629d4..0ad2261d268 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.h
+++ b/chromium/components/password_manager/core/browser/password_form_manager.h
@@ -21,10 +21,10 @@
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/form_fetcher.h"
-#include "components/password_manager/core/browser/form_fetcher_impl.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
#include "components/password_manager/core/browser/password_store.h"
+using autofill::FormData;
using autofill::FormStructure;
namespace password_manager {
@@ -43,7 +43,8 @@ class PasswordFormManager : public FormFetcher::Consumer {
// |password_manager| owns |this|, |client| and |driver| serve to
// communicate with embedder, |observed_form| is the associated form |this|
// is managing, |form_saver| is used to save/update the form and
- // |form_fetcher| to get saved data about the form.
+ // |form_fetcher| to get saved data about the form. |form_fetcher| must not be
+ // destroyed before |this|.
//
// TODO(crbug.com/621355): So far, |form_fetcher| can be null. In that case
// |this| creates an instance of it itself (meant for production code). Once
@@ -242,6 +243,17 @@ class PasswordFormManager : public FormFetcher::Consumer {
FormSaver* form_saver() { return form_saver_.get(); }
+ // Clears references to matches derived from the associated FormFetcher data.
+ // After calling this, the PasswordFormManager holds no references to objects
+ // owned by the associated FormFetcher. This does not cause removing |this| as
+ // a consumer of |form_fetcher_|.
+ void ResetStoredMatches();
+
+ // Takes ownership of |fetcher|. If |fetcher| is different from the current
+ // |form_fetcher_| then also resets matches stored from the old fetcher and
+ // adds itself as a consumer of the new one.
+ void GrabFetcher(std::unique_ptr<FormFetcher> fetcher);
+
protected:
// FormFetcher::Consumer:
void ProcessMatches(
@@ -350,8 +362,8 @@ class PasswordFormManager : public FormFetcher::Consumer {
// Autofill server to vote for the correct username field, and also so that
// we will trigger password generation in the future. This function will
// update generation_upload_status of |pending| if an upload is performed.
- void SendAutofillVotes(const autofill::PasswordForm& observed,
- autofill::PasswordForm* pending);
+ void SendVoteOnCredentialsReuse(const autofill::PasswordForm& observed,
+ autofill::PasswordForm* pending);
// Update all login matches to reflect new preferred state - preferred flag
// will be reset on all matched logins that different than the current
@@ -364,6 +376,19 @@ class PasswordFormManager : public FormFetcher::Consumer {
bool UpdatePendingCredentialsIfOtherPossibleUsername(
const base::string16& username);
+ // Searches for |username| in |other_possible_usernames| of |best_matches_|
+ // and |not_best_matches_|. If the username value is found in
+ // |other_possible_usernames| and the password value of the match is equal to
+ // |password|, the match is saved to |username_correction_vote_|.
+ void FindCorrectedUsernameElement(const base::string16& username,
+ const base::string16& password);
+
+ // Searches for |username| in |other_possible_usernames| of |match|. If the
+ // username value is found, the match is saved to |username_correction_vote_|
+ // and the function returns true.
+ bool FindUsernameInOtherPossibleUsernames(const autofill::PasswordForm& match,
+ const base::string16& username);
+
// Returns true if |form| is a username update of a credential already in
// |best_matches_|. Sets |pending_credentials_| to the appropriate
// PasswordForm if it returns true.
@@ -376,7 +401,8 @@ class PasswordFormManager : public FormFetcher::Consumer {
// Tries to set all votes (e.g. autofill field types, generation vote) to
// a |FormStructure| and upload it to the server. Returns true on success.
- bool UploadPasswordVote(const autofill::ServerFieldType& password_type,
+ bool UploadPasswordVote(const autofill::PasswordForm& form_to_upload,
+ const autofill::ServerFieldType& password_type,
const std::string& login_form_signature);
// Adds a vote on password generation usage to |form_structure|.
@@ -415,6 +441,9 @@ class PasswordFormManager : public FormFetcher::Consumer {
// Send appropriate votes based on what is currently being saved.
void SendVotesOnSave();
+ // Send a vote for sign-in forms with autofill types for a username field.
+ void SendSignInVote(const FormData& form_data);
+
// Sets |user_action_| and records some metrics.
void SetUserAction(UserAction user_action);
@@ -462,6 +491,14 @@ class PasswordFormManager : public FormFetcher::Consumer {
// option should apply.
OtherPossibleUsernamesAction other_possible_username_action_;
+ // If the user typed username that doesn't match any saved credentials, but
+ // matches an entry from |other_possible_usernames| of a saved credential,
+ // then |username_correction_vote_| stores the credential with matched
+ // username. The matched credential is copied to |username_correction_vote_|,
+ // but |username_correction_vote_.username_element| is set to the name of the
+ // field where matched username was found.
+ std::unique_ptr<autofill::PasswordForm> username_correction_vote_;
+
// The origin url path of observed_form_ tokenized, for convenience when
// scoring.
const std::vector<std::string> form_path_segments_;
@@ -557,13 +594,11 @@ class PasswordFormManager : public FormFetcher::Consumer {
// credentials.
std::unique_ptr<FormSaver> form_saver_;
- // TODO(crbug.com/621355) Remove this, ultimately the form fetcher will not be
- // owned by PasswordFormManager. Temporarily, this is the object which
- // |form_fetcher_| points to, unless set otherwise in the constructor.
- std::unique_ptr<FormFetcherImpl> form_fetcher_impl_;
+ // When not null, then this is the object which |form_fetcher_| points to.
+ std::unique_ptr<FormFetcher> owned_form_fetcher_;
// FormFetcher instance which owns the login data from PasswordStore.
- FormFetcher* const form_fetcher_;
+ FormFetcher* form_fetcher_;
// True if the main frame's visible URL, at the time this PasswordFormManager
// was created, is secure.
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 30f6cfe82de..fd752c0aa7a 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
@@ -47,6 +47,7 @@
using autofill::FieldPropertiesFlags;
using autofill::FieldPropertiesMask;
using autofill::PasswordForm;
+using autofill::PossibleUsernamePair;
using base::ASCIIToUTF16;
using ::testing::_;
using ::testing::IsEmpty;
@@ -57,6 +58,7 @@ using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SaveArgPointee;
using ::testing::UnorderedElementsAre;
+using ::testing::WithArg;
namespace password_manager {
@@ -98,6 +100,12 @@ class MockFormSaver : public StubFormSaver {
DISALLOW_COPY_AND_ASSIGN(MockFormSaver);
};
+class MockFormFetcher : public FakeFormFetcher {
+ public:
+ MOCK_METHOD1(AddConsumer, void(Consumer*));
+ MOCK_METHOD1(RemoveConsumer, void(Consumer*));
+};
+
MATCHER_P(CheckUsername, username_value, "Username incorrect") {
return arg.username_value == username_value;
}
@@ -106,9 +114,10 @@ MATCHER_P(CheckUsernamePtr, username_value, "Username incorrect") {
return arg && arg->username_value == username_value;
}
-MATCHER_P2(CheckUploadedAutofillTypesAndSignature,
+MATCHER_P3(CheckUploadedAutofillTypesAndSignature,
form_signature,
expected_types,
+ expect_generation_vote,
"Unexpected autofill types or form signature") {
if (form_signature != arg.FormSignatureAsStr()) {
// Unexpected form's signature.
@@ -116,12 +125,17 @@ MATCHER_P2(CheckUploadedAutofillTypesAndSignature,
<< ", but found " << arg.FormSignatureAsStr();
return false;
}
+ bool found_generation_vote = false;
for (const auto& field : arg) {
if (field->possible_types().size() > 1) {
ADD_FAILURE() << field->name << " field has several possible types";
return false;
}
+ found_generation_vote |=
+ field->generation_type() !=
+ autofill::AutofillUploadContents::Field::NO_GENERATION;
+
autofill::ServerFieldType expected_vote =
expected_types.find(field->name) == expected_types.end()
? autofill::NO_SERVER_DATA
@@ -135,6 +149,7 @@ MATCHER_P2(CheckUploadedAutofillTypesAndSignature,
return false;
}
}
+ EXPECT_EQ(expect_generation_vote, found_generation_vote);
return true;
}
@@ -239,6 +254,17 @@ class MockAutofillManager : public autofill::AutofillManager {
set_download_manager(manager);
}
+ // Workaround for std::unique_ptr<> lacking a copy constructor.
+ void StartUploadProcess(std::unique_ptr<FormStructure> form_structure,
+ const base::TimeTicks& timestamp,
+ bool observed_submission) {
+ StartUploadProcessPtr(form_structure.release(), timestamp,
+ observed_submission);
+ }
+
+ MOCK_METHOD3(StartUploadProcessPtr,
+ void(FormStructure*, const base::TimeTicks&, bool));
+
private:
DISALLOW_COPY_AND_ASSIGN(MockAutofillManager);
};
@@ -310,6 +336,10 @@ class TestPasswordManagerClient : public StubPasswordManagerClient {
std::unique_ptr<MockPasswordManagerDriver> driver_;
};
+ACTION_P(SaveToUniquePtr, scoped) {
+ scoped->reset(arg0);
+}
+
} // namespace
class PasswordFormManagerTest : public testing::Test {
@@ -330,8 +360,8 @@ class PasswordFormManagerTest : public testing::Test {
saved_match_.preferred = true;
saved_match_.username_value = ASCIIToUTF16("test@gmail.com");
saved_match_.password_value = ASCIIToUTF16("test1");
- saved_match_.other_possible_usernames.push_back(
- ASCIIToUTF16("test2@gmail.com"));
+ saved_match_.other_possible_usernames.push_back(PossibleUsernamePair(
+ ASCIIToUTF16("test2@gmail.com"), ASCIIToUTF16("full_name")));
psl_saved_match_ = saved_match_;
psl_saved_match_.is_public_suffix_match = true;
@@ -401,33 +431,29 @@ class PasswordFormManagerTest : public testing::Test {
autofill::ServerFieldTypeSet expected_available_field_types;
FieldTypeMap expected_types;
expected_types[ASCIIToUTF16("full_name")] = autofill::UNKNOWN_TYPE;
+ expected_types[match.username_element] = autofill::UNKNOWN_TYPE;
- // When we're voting for an account creation form, we should also vote
- // for its username field.
- if (field_type && *field_type == autofill::ACCOUNT_CREATION_PASSWORD) {
- expected_types[match.username_element] = autofill::USERNAME;
- expected_available_field_types.insert(autofill::USERNAME);
- } else {
- expected_types[match.username_element] = autofill::UNKNOWN_TYPE;
- }
-
+ bool expect_generation_vote = false;
if (field_type) {
+ // Show the password generation popup to check that the generation vote
+ // would be ignored.
+ form_manager.set_generation_element(saved_match()->password_element);
+ form_manager.set_generation_popup_was_shown(true);
+ expect_generation_vote =
+ *field_type != autofill::ACCOUNT_CREATION_PASSWORD;
+
expected_available_field_types.insert(*field_type);
expected_types[saved_match()->password_element] = *field_type;
- } else {
- expected_available_field_types.insert(
- autofill::NOT_ACCOUNT_CREATION_PASSWORD);
- expected_types[saved_match()->password_element] =
- autofill::NOT_ACCOUNT_CREATION_PASSWORD;
}
if (field_type) {
- EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(CheckUploadedAutofillTypesAndSignature(
- pending_structure.FormSignatureAsStr(),
- expected_types),
- false, expected_available_field_types,
- expected_login_signature, true));
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(CheckUploadedAutofillTypesAndSignature(
+ pending_structure.FormSignatureAsStr(),
+ expected_types, expect_generation_vote),
+ false, expected_available_field_types,
+ expected_login_signature, true));
} else {
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(_, _, _, _, _))
@@ -524,7 +550,8 @@ class PasswordFormManagerTest : public testing::Test {
}
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(CheckUploadedAutofillTypesAndSignature(
- observed_form_signature, expected_types),
+ observed_form_signature, expected_types,
+ false /* expect_generation_vote */),
false, expected_available_field_types,
expected_login_signature, true));
@@ -695,8 +722,10 @@ class PasswordFormManagerTest : public testing::Test {
PasswordForm psl_saved_match_;
TestPasswordManagerClient client_;
std::unique_ptr<PasswordManager> password_manager_;
- std::unique_ptr<PasswordFormManager> form_manager_;
+ // Define |fake_form_fetcher_| before |form_manager_|, because the former
+ // needs to outlive the latter.
FakeFormFetcher fake_form_fetcher_;
+ std::unique_ptr<PasswordFormManager> form_manager_;
};
class PasswordFormManagerFillOnAccountSelectTest
@@ -934,7 +963,6 @@ TEST_F(PasswordFormManagerTest, PSLMatchedCredentialsMetadataUpdated) {
PasswordForm actual_saved_form;
autofill::ServerFieldTypeSet expected_available_field_types;
- expected_available_field_types.insert(autofill::USERNAME);
expected_available_field_types.insert(autofill::ACCOUNT_CREATION_PASSWORD);
EXPECT_CALL(
*client()->mock_driver()->mock_autofill_download_manager(),
@@ -1166,7 +1194,8 @@ TEST_F(PasswordFormManagerTest, TestAlternateUsername_NoChange) {
PasswordForm saved_form = *saved_match();
saved_form.other_possible_usernames.push_back(
- ASCIIToUTF16("other_possible@gmail.com"));
+ PossibleUsernamePair(ASCIIToUTF16("other_possible@gmail.com"),
+ ASCIIToUTF16("other_username")));
fake_form_fetcher()->SetNonFederated({&saved_form}, 0u);
@@ -1201,8 +1230,8 @@ TEST_F(PasswordFormManagerTest, TestAlternateUsername_NoChange) {
TEST_F(PasswordFormManagerTest, TestAlternateUsername_OtherUsername) {
EXPECT_CALL(*client()->mock_driver(), AllowPasswordGenerationForForm(_));
- const base::string16 kOtherUsername =
- ASCIIToUTF16("other_possible@gmail.com");
+ const PossibleUsernamePair kOtherUsername(
+ ASCIIToUTF16("other_possible@gmail.com"), ASCIIToUTF16("other_username"));
PasswordForm saved_form = *saved_match();
saved_form.other_possible_usernames.push_back(kOtherUsername);
@@ -1211,7 +1240,7 @@ TEST_F(PasswordFormManagerTest, TestAlternateUsername_OtherUsername) {
// The user chooses an alternative username.
PasswordForm login(*observed_form());
login.preferred = true;
- login.username_value = kOtherUsername;
+ login.username_value = kOtherUsername.first;
login.password_value = saved_match()->password_value;
form_manager()->ProvisionallySave(
@@ -1229,7 +1258,7 @@ TEST_F(PasswordFormManagerTest, TestAlternateUsername_OtherUsername) {
// |other_possible_usernames| should also be empty, but username_value should
// be changed to match |new_username|.
- EXPECT_EQ(kOtherUsername, saved_result.username_value);
+ EXPECT_EQ(kOtherUsername.first, saved_result.username_value);
EXPECT_TRUE(saved_result.other_possible_usernames.empty());
}
@@ -1331,14 +1360,16 @@ TEST_F(PasswordFormManagerTest, TestBestCredentialsForEachUsernameAreIncluded) {
}
TEST_F(PasswordFormManagerTest, TestSanitizePossibleUsernames) {
- const base::string16 kUsernameOther = ASCIIToUTF16("other username");
+ const PossibleUsernamePair kUsernameOther(ASCIIToUTF16("other username"),
+ ASCIIToUTF16("other_username_id"));
fake_form_fetcher()->SetNonFederated(std::vector<const PasswordForm*>(), 0u);
PasswordForm credentials(*observed_form());
- credentials.other_possible_usernames.push_back(ASCIIToUTF16("543-43-1234"));
credentials.other_possible_usernames.push_back(
- ASCIIToUTF16("378282246310005"));
+ PossibleUsernamePair(ASCIIToUTF16("543-43-1234"), ASCIIToUTF16("id1")));
+ credentials.other_possible_usernames.push_back(PossibleUsernamePair(
+ ASCIIToUTF16("378282246310005"), ASCIIToUTF16("id2")));
credentials.other_possible_usernames.push_back(kUsernameOther);
credentials.username_value = ASCIIToUTF16("test@gmail.com");
credentials.preferred = true;
@@ -1359,19 +1390,24 @@ TEST_F(PasswordFormManagerTest, TestSanitizePossibleUsernames) {
}
TEST_F(PasswordFormManagerTest, TestSanitizePossibleUsernamesDuplicates) {
- const base::string16 kUsernameEmail = ASCIIToUTF16("test@gmail.com");
- const base::string16 kUsernameDuplicate = ASCIIToUTF16("duplicate");
- const base::string16 kUsernameRandom = ASCIIToUTF16("random");
+ const PossibleUsernamePair kUsernameSsn(ASCIIToUTF16("511-32-9830"),
+ ASCIIToUTF16("ssn_id"));
+ const PossibleUsernamePair kUsernameEmail(ASCIIToUTF16("test@gmail.com"),
+ ASCIIToUTF16("email_id"));
+ const PossibleUsernamePair kUsernameDuplicate(ASCIIToUTF16("duplicate"),
+ ASCIIToUTF16("duplicate_id"));
+ const PossibleUsernamePair kUsernameRandom(ASCIIToUTF16("random"),
+ ASCIIToUTF16("random_id"));
fake_form_fetcher()->SetNonFederated(std::vector<const PasswordForm*>(), 0u);
PasswordForm credentials(*observed_form());
- credentials.other_possible_usernames.push_back(ASCIIToUTF16("511-32-9830"));
+ credentials.other_possible_usernames.push_back(kUsernameSsn);
credentials.other_possible_usernames.push_back(kUsernameDuplicate);
credentials.other_possible_usernames.push_back(kUsernameDuplicate);
credentials.other_possible_usernames.push_back(kUsernameRandom);
credentials.other_possible_usernames.push_back(kUsernameEmail);
- credentials.username_value = kUsernameEmail;
+ credentials.username_value = kUsernameEmail.first;
credentials.preferred = true;
// Pass in ALLOW_OTHER_POSSIBLE_USERNAMES, although it will not make a
@@ -2572,7 +2608,8 @@ TEST_F(PasswordFormManagerTest,
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(CheckUploadedAutofillTypesAndSignature(
- observed_form_signature, expected_types),
+ observed_form_signature, expected_types,
+ false /* expect_generation_vote */),
false, expected_available_field_types,
expected_login_signature, true));
@@ -2776,7 +2813,8 @@ TEST_F(PasswordFormManagerTest, ProbablyAccountCreationUpload) {
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(
CheckUploadedAutofillTypesAndSignature(
- pending_structure.FormSignatureAsStr(), expected_types),
+ pending_structure.FormSignatureAsStr(), expected_types,
+ false /* expect_generation_vote */),
false, expected_available_field_types, std::string(), true));
form_manager.ProvisionallySave(
@@ -2898,4 +2936,248 @@ TEST_F(PasswordFormManagerTest, DoesManageDifferentSignonRealmSameDrivers) {
form_manager()->DoesManage(submitted_form, client()->driver().get()));
}
+TEST_F(PasswordFormManagerTest, UploadUsernameCorrectionVote) {
+ // Observed and saved forms have the same password, but different usernames.
+ PasswordForm new_login(*observed_form());
+ new_login.username_value = saved_match()->other_possible_usernames[0].first;
+ new_login.password_value = saved_match()->password_value;
+
+ fake_form_fetcher()->SetNonFederated({saved_match()}, 0u);
+ form_manager()->ProvisionallySave(
+ new_login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ // No match found (because usernames are different).
+ EXPECT_TRUE(form_manager()->IsNewLogin());
+
+ // Checks the username correction vote is saved.
+ PasswordForm expected_username_vote(*saved_match());
+ expected_username_vote.username_element =
+ saved_match()->other_possible_usernames[0].second;
+
+ // Checks the upload.
+ autofill::ServerFieldTypeSet expected_available_field_types;
+ expected_available_field_types.insert(autofill::USERNAME);
+ expected_available_field_types.insert(autofill::ACCOUNT_CREATION_PASSWORD);
+
+ FormStructure expected_upload(expected_username_vote.form_data);
+
+ std::string expected_login_signature =
+ FormStructure(form_manager()->observed_form().form_data)
+ .FormSignatureAsStr();
+
+ std::map<base::string16, autofill::ServerFieldType> expected_types;
+ expected_types[expected_username_vote.username_element] = autofill::USERNAME;
+ expected_types[expected_username_vote.password_element] =
+ autofill::ACCOUNT_CREATION_PASSWORD;
+ expected_types[ASCIIToUTF16("Email")] = autofill::UNKNOWN_TYPE;
+
+ EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(CheckUploadedAutofillTypesAndSignature(
+ expected_upload.FormSignatureAsStr(),
+ expected_types, false),
+ false, expected_available_field_types,
+ expected_login_signature, true));
+ form_manager()->Save();
+}
+
+// Test that ResetStoredMatches removes references to previously fetched store
+// results.
+TEST_F(PasswordFormManagerTest, ResetStoredMatches) {
+ PasswordForm best_match1 = *observed_form();
+ best_match1.username_value = ASCIIToUTF16("user1");
+ best_match1.password_value = ASCIIToUTF16("pass");
+ best_match1.preferred = true;
+
+ PasswordForm best_match2 = best_match1;
+ best_match2.username_value = ASCIIToUTF16("user2");
+ best_match2.preferred = false;
+
+ PasswordForm non_best_match = best_match1;
+ non_best_match.action = GURL();
+
+ PasswordForm blacklisted = *observed_form();
+ blacklisted.blacklisted_by_user = true;
+ blacklisted.username_value.clear();
+
+ fake_form_fetcher()->SetNonFederated(
+ {&best_match1, &best_match2, &non_best_match, &blacklisted}, 0u);
+
+ EXPECT_EQ(2u, form_manager()->best_matches().size());
+ EXPECT_TRUE(form_manager()->preferred_match());
+ EXPECT_EQ(1u, form_manager()->blacklisted_matches().size());
+
+ // Trigger Update to verify that there is a non-best match.
+ PasswordForm updated(best_match1);
+ updated.password_value = ASCIIToUTF16("updated password");
+ form_manager()->ProvisionallySave(
+ updated, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ std::vector<PasswordForm> credentials_to_update;
+ EXPECT_CALL(MockFormSaver::Get(form_manager()), Update(_, _, _, nullptr))
+ .WillOnce(SaveArgPointee<2>(&credentials_to_update));
+ form_manager()->Save();
+
+ PasswordForm updated_non_best = non_best_match;
+ updated_non_best.password_value = updated.password_value;
+ EXPECT_THAT(credentials_to_update, UnorderedElementsAre(updated_non_best));
+
+ form_manager()->ResetStoredMatches();
+
+ EXPECT_THAT(form_manager()->best_matches(), IsEmpty());
+ EXPECT_FALSE(form_manager()->preferred_match());
+ EXPECT_THAT(form_manager()->blacklisted_matches(), IsEmpty());
+
+ // Simulate updating a saved credential again, but this time without non-best
+ // matches. Verify that the old non-best matches are no longer present.
+ fake_form_fetcher()->Fetch();
+ fake_form_fetcher()->SetNonFederated({&best_match1}, 0u);
+
+ form_manager()->ProvisionallySave(
+ updated, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ credentials_to_update.clear();
+ EXPECT_CALL(MockFormSaver::Get(form_manager()), Update(_, _, _, nullptr))
+ .WillOnce(SaveArgPointee<2>(&credentials_to_update));
+ form_manager()->Save();
+
+ EXPECT_THAT(credentials_to_update, IsEmpty());
+}
+
+// Check that on changing FormFetcher, the PasswordFormManager removes itself
+// from consuming the old one.
+TEST_F(PasswordFormManagerTest, DropFetcherOnDestruction) {
+ MockFormFetcher fetcher;
+ FormFetcher::Consumer* added_consumer = nullptr;
+ EXPECT_CALL(fetcher, AddConsumer(_)).WillOnce(SaveArg<0>(&added_consumer));
+ auto form_manager = base::MakeUnique<PasswordFormManager>(
+ password_manager(), client(), client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>(), &fetcher);
+ EXPECT_EQ(form_manager.get(), added_consumer);
+
+ EXPECT_CALL(fetcher, RemoveConsumer(form_manager.get()));
+ form_manager.reset();
+}
+
+// Check that if asked to take ownership of the same FormFetcher which it had
+// consumed before, the PasswordFormManager does not add itself as a consumer
+// again.
+TEST_F(PasswordFormManagerTest, GrabFetcher_Same) {
+ auto fetcher = base::MakeUnique<MockFormFetcher>();
+ fetcher->Fetch();
+ PasswordFormManager form_manager(
+ password_manager(), client(), client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>(), fetcher.get());
+
+ EXPECT_CALL(*fetcher, AddConsumer(_)).Times(0);
+ EXPECT_CALL(*fetcher, RemoveConsumer(_)).Times(0);
+ form_manager.GrabFetcher(std::move(fetcher));
+ // There will be a RemoveConsumer call as soon as form_manager goes out of
+ // scope, but the test needs to ensure that there is none as a result of
+ // GrabFetcher.
+ Mock::VerifyAndClearExpectations(form_manager.form_fetcher());
+}
+
+// Check that if asked to take ownership of a different FormFetcher than which
+// it had consumed before, the PasswordFormManager adds itself as a consumer
+// and replaces the references to the old results.
+TEST_F(PasswordFormManagerTest, GrabFetcher_Different) {
+ PasswordForm old_match = *observed_form();
+ old_match.username_value = ASCIIToUTF16("user1");
+ old_match.password_value = ASCIIToUTF16("pass");
+ fake_form_fetcher()->SetNonFederated({&old_match}, 0u);
+ EXPECT_EQ(1u, form_manager()->best_matches().size());
+ EXPECT_EQ(&old_match, form_manager()->best_matches().begin()->second);
+
+ // |form_manager()| uses |fake_form_fetcher()|, which is an instance different
+ // from |fetcher| below.
+ auto fetcher = base::MakeUnique<MockFormFetcher>();
+ fetcher->Fetch();
+ fetcher->SetNonFederated(std::vector<const PasswordForm*>(), 0u);
+ EXPECT_CALL(*fetcher, AddConsumer(form_manager()));
+ form_manager()->GrabFetcher(std::move(fetcher));
+
+ EXPECT_EQ(0u, form_manager()->best_matches().size());
+}
+
+// Check that on changing FormFetcher, the PasswordFormManager removes itself
+// from consuming the old one.
+TEST_F(PasswordFormManagerTest, GrabFetcher_Remove) {
+ MockFormFetcher old_fetcher;
+ FormFetcher::Consumer* added_consumer = nullptr;
+ EXPECT_CALL(old_fetcher, AddConsumer(_))
+ .WillOnce(SaveArg<0>(&added_consumer));
+ PasswordFormManager form_manager(
+ password_manager(), client(), client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>(), &old_fetcher);
+ EXPECT_EQ(&form_manager, added_consumer);
+
+ auto new_fetcher = base::MakeUnique<MockFormFetcher>();
+ EXPECT_CALL(*new_fetcher, AddConsumer(&form_manager));
+ EXPECT_CALL(old_fetcher, RemoveConsumer(&form_manager));
+ form_manager.GrabFetcher(std::move(new_fetcher));
+}
+
+TEST_F(PasswordFormManagerTest, UploadSignInForm_WithAutofillTypes) {
+ // For newly saved passwords on a sign-in form, upload an autofill vote for a
+ // username field and a autofill::PASSWORD vote for a password field.
+ autofill::FormFieldData field;
+ field.name = ASCIIToUTF16("Email");
+ field.form_control_type = "text";
+ observed_form()->form_data.fields.push_back(field);
+
+ field.name = ASCIIToUTF16("Passwd");
+ field.form_control_type = "password";
+ observed_form()->form_data.fields.push_back(field);
+
+ FakeFormFetcher fetcher;
+ fetcher.Fetch();
+ PasswordFormManager form_manager(
+ password_manager(), client(), client()->driver(), *observed_form(),
+ base::MakeUnique<NiceMock<MockFormSaver>>(), &fetcher);
+ fetcher.SetNonFederated(std::vector<const PasswordForm*>(), 0u);
+
+ PasswordForm form_to_save(*observed_form());
+ form_to_save.preferred = true;
+ form_to_save.username_value = ASCIIToUTF16("test@gmail.com");
+ form_to_save.password_value = ASCIIToUTF16("password");
+
+ std::unique_ptr<FormStructure> uploaded_form_structure;
+ auto* mock_autofill_manager =
+ client()->mock_driver()->mock_autofill_manager();
+ EXPECT_CALL(*mock_autofill_manager, StartUploadProcessPtr(_, _, true))
+ .WillOnce(WithArg<0>(SaveToUniquePtr(&uploaded_form_structure)));
+ form_manager.ProvisionallySave(
+ form_to_save, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.Save();
+
+ ASSERT_EQ(2u, uploaded_form_structure->field_count());
+ autofill::ServerFieldTypeSet expected_types = {autofill::PASSWORD};
+ EXPECT_EQ(expected_types,
+ uploaded_form_structure->field(1)->possible_types());
+}
+
+// Checks that there is no upload on saving a password on a password form only
+// with 1 field.
+TEST_F(PasswordFormManagerTest, NoUploadsForSubmittedFormWithOnlyOneField) {
+ autofill::FormFieldData field;
+ field.name = ASCIIToUTF16("Passwd");
+ field.form_control_type = "password";
+ observed_form()->form_data.fields.push_back(field);
+
+ FakeFormFetcher fetcher;
+ fetcher.Fetch();
+ PasswordFormManager form_manager(
+ password_manager(), client(), client()->driver(), *observed_form(),
+ base::MakeUnique<NiceMock<MockFormSaver>>(), &fetcher);
+ fetcher.SetNonFederated(std::vector<const PasswordForm*>(), 0u);
+
+ PasswordForm form_to_save(*observed_form());
+ form_to_save.preferred = true;
+ form_to_save.password_value = ASCIIToUTF16("password");
+
+ auto* mock_autofill_manager =
+ client()->mock_driver()->mock_autofill_manager();
+ EXPECT_CALL(*mock_autofill_manager, StartUploadProcessPtr(_, _, _)).Times(0);
+ form_manager.ProvisionallySave(
+ form_to_save, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.Save();
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_generation_manager.cc b/chromium/components/password_manager/core/browser/password_generation_manager.cc
index d97054a4f6a..a30adf80276 100644
--- a/chromium/components/password_manager/core/browser/password_generation_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_generation_manager.cc
@@ -4,16 +4,28 @@
#include "components/password_manager/core/browser/password_generation_manager.h"
+#include "base/optional.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/password_form_generation_data.h"
+#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
+
+using autofill::AutofillField;
+using autofill::FieldSignature;
+using autofill::FormSignature;
+using autofill::FormStructure;
namespace password_manager {
+namespace {
+using Logger = autofill::SavePasswordProgressLogger;
+}
+
PasswordGenerationManager::PasswordGenerationManager(
PasswordManagerClient* client,
PasswordManagerDriver* driver)
@@ -30,17 +42,25 @@ void PasswordGenerationManager::DetectFormsEligibleForGeneration(
std::vector<autofill::PasswordFormGenerationData>
forms_eligible_for_generation;
- for (auto form_it = forms.begin(); form_it != forms.end(); ++form_it) {
- autofill::FormStructure* form = *form_it;
- for (auto field_it = form->begin(); field_it != form->end(); ++field_it) {
- autofill::AutofillField* field = field_it->get();
+ for (const FormStructure* form : forms) {
+ const AutofillField* generation_field = nullptr;
+ const AutofillField* confirmation_field = nullptr;
+ for (const std::unique_ptr<AutofillField>& field : *form) {
if (field->server_type() == autofill::ACCOUNT_CREATION_PASSWORD ||
field->server_type() == autofill::NEW_PASSWORD) {
- forms_eligible_for_generation.push_back(
- autofill::PasswordFormGenerationData{form->form_signature(),
- field->GetFieldSignature()});
- break;
+ generation_field = field.get();
+ } else if (field->server_type() == autofill::CONFIRMATION_PASSWORD) {
+ confirmation_field = field.get();
+ }
+ }
+ if (generation_field) {
+ autofill::PasswordFormGenerationData data(
+ form->form_signature(), generation_field->GetFieldSignature());
+ if (confirmation_field != nullptr) {
+ data.confirmation_field_signature.emplace(
+ confirmation_field->GetFieldSignature());
}
+ forms_eligible_for_generation.push_back(data);
}
}
if (!forms_eligible_for_generation.empty())
@@ -51,16 +71,29 @@ void PasswordGenerationManager::DetectFormsEligibleForGeneration(
// (1) Password sync is enabled, and
// (2) Password saving is enabled.
bool PasswordGenerationManager::IsGenerationEnabled() const {
+ std::unique_ptr<Logger> logger;
+ if (password_manager_util::IsLoggingActive(client_)) {
+ logger.reset(
+ new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
+ }
+
if (!client_->IsSavingAndFillingEnabledForCurrentPage()) {
- VLOG(2) << "Generation disabled because password saving is disabled";
+ if (logger)
+ logger->LogMessage(Logger::STRING_GENERATION_DISABLED_SAVING_DISABLED);
return false;
}
// Don't consider sync enabled if the user has a custom passphrase. See
// http://crbug.com/358998 for more details.
if (client_->GetPasswordSyncState() != SYNCING_NORMAL_ENCRYPTION) {
- VLOG(2) << "Generation disabled because passwords are not being synced or"
- << " custom passphrase is used.";
+ if (logger) {
+ if (client_->GetPasswordSyncState() == NOT_SYNCING_PASSWORDS)
+ logger->LogMessage(Logger::STRING_GENERATION_DISABLED_NO_SYNC);
+ else if (client_->GetPasswordSyncState() ==
+ SYNCING_WITH_CUSTOM_PASSPHRASE)
+ logger->LogMessage(
+ Logger::STRING_GENERATION_DISABLED_CUSTOM_PASSPHRASE);
+ }
return false;
}
diff --git a/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc
index f5fe0637b3e..9a08022a83e 100644
--- a/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc
@@ -83,7 +83,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
public:
MOCK_CONST_METHOD0(GetPasswordSyncState, PasswordSyncState());
MOCK_CONST_METHOD0(IsSavingAndFillingEnabledForCurrentPage, bool());
- MOCK_CONST_METHOD0(IsOffTheRecord, bool());
+ MOCK_CONST_METHOD0(IsIncognito, bool());
explicit MockPasswordManagerClient(std::unique_ptr<PrefService> prefs)
: prefs_(std::move(prefs)),
@@ -201,13 +201,15 @@ TEST_F(PasswordGenerationManagerTest, DetectFormsEligibleForGeneration) {
account_creation_form.fields.push_back(password);
autofill::FormFieldData confirm_password;
confirm_password.label = ASCIIToUTF16("confirm_password");
- confirm_password.name = ASCIIToUTF16("password");
+ confirm_password.name = ASCIIToUTF16("confirm_password");
confirm_password.form_control_type = "password";
account_creation_form.fields.push_back(confirm_password);
autofill::FormSignature account_creation_form_signature =
autofill::CalculateFormSignature(account_creation_form);
autofill::FieldSignature account_creation_field_signature =
autofill::CalculateFieldSignatureForField(password);
+ autofill::FieldSignature confirmation_field_signature =
+ autofill::CalculateFieldSignatureForField(confirm_password);
autofill::FormStructure form2(account_creation_form);
forms.push_back(&form2);
@@ -231,6 +233,7 @@ TEST_F(PasswordGenerationManagerTest, DetectFormsEligibleForGeneration) {
// PASSWORD = 75
// ACCOUNT_CREATION_PASSWORD = 76
// NEW_PASSWORD = 88
+ // CONFIRMATION_PASSWORD = 95
autofill::AutofillQueryResponseContents response;
response.add_field()->set_autofill_type(9);
response.add_field()->set_autofill_type(75);
@@ -238,7 +241,7 @@ TEST_F(PasswordGenerationManagerTest, DetectFormsEligibleForGeneration) {
response.add_field()->set_autofill_type(76);
response.add_field()->set_autofill_type(75);
response.add_field()->set_autofill_type(88);
- response.add_field()->set_autofill_type(88);
+ response.add_field()->set_autofill_type(95);
std::string response_string;
ASSERT_TRUE(response.SerializeToString(&response_string));
@@ -252,6 +255,9 @@ TEST_F(PasswordGenerationManagerTest, DetectFormsEligibleForGeneration) {
EXPECT_EQ(
account_creation_field_signature,
GetTestDriver()->GetFoundEligibleForGenerationForms()[0].field_signature);
+ EXPECT_FALSE(GetTestDriver()
+ ->GetFoundEligibleForGenerationForms()[0]
+ .confirmation_field_signature.has_value());
EXPECT_EQ(
change_password_form_signature,
@@ -259,13 +265,20 @@ TEST_F(PasswordGenerationManagerTest, DetectFormsEligibleForGeneration) {
EXPECT_EQ(
change_password_field_signature,
GetTestDriver()->GetFoundEligibleForGenerationForms()[1].field_signature);
+ ASSERT_TRUE(GetTestDriver()
+ ->GetFoundEligibleForGenerationForms()[1]
+ .confirmation_field_signature.has_value());
+ EXPECT_EQ(confirmation_field_signature,
+ GetTestDriver()
+ ->GetFoundEligibleForGenerationForms()[1]
+ .confirmation_field_signature.value());
}
TEST_F(PasswordGenerationManagerTest, UpdatePasswordSyncStateIncognito) {
// Disable password manager by going incognito. Even though password
// syncing is enabled, generation should still
// be disabled.
- EXPECT_CALL(*client_, IsOffTheRecord()).WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*client_, IsIncognito()).WillRepeatedly(testing::Return(true));
PrefService* prefs = client_->GetPrefs();
prefs->SetBoolean(prefs::kCredentialsEnableService, true);
EXPECT_CALL(*client_, GetPasswordSyncState())
diff --git a/chromium/components/password_manager/core/browser/password_manager.cc b/chromium/components/password_manager/core/browser/password_manager.cc
index e854c370ee6..dae64390d35 100644
--- a/chromium/components/password_manager/core/browser/password_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_manager.cc
@@ -154,6 +154,7 @@ void PasswordManager::RegisterProfilePrefs(
registry->RegisterBooleanPref(
prefs::kCredentialsEnableAutosignin, true,
user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
+ registry->RegisterBooleanPref(prefs::kWasObsoleteHttpDataCleaned, false);
#if defined(OS_MACOSX)
registry->RegisterIntegerPref(
prefs::kKeychainMigrationStatus,
@@ -743,9 +744,7 @@ void PasswordManager::OnLoginSuccessful() {
provisional_save_manager_->password_overridden() ||
provisional_save_manager_->retry_password_form_password_update();
if (client_->PromptUserToSaveOrUpdatePassword(
- std::move(provisional_save_manager_),
- CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER,
- update_password)) {
+ std::move(provisional_save_manager_), update_password)) {
if (logger)
logger->LogMessage(Logger::STRING_SHOW_PASSWORD_PROMPT);
}
diff --git a/chromium/components/password_manager/core/browser/password_manager_client.cc b/chromium/components/password_manager/core/browser/password_manager_client.cc
index 8e61e498c96..6ed6f1e7a8e 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_client.cc
@@ -15,8 +15,10 @@ bool PasswordManagerClient::IsFillingEnabledForCurrentPage() const {
return true;
}
-bool PasswordManagerClient::IsHSTSActiveForHost(const GURL& origin) const {
- return false;
+void PasswordManagerClient::PostHSTSQueryForHost(
+ const GURL& origin,
+ const HSTSCallback& callback) const {
+ callback.Run(false);
}
bool PasswordManagerClient::OnCredentialManagerUsed() {
@@ -46,7 +48,7 @@ bool PasswordManagerClient::DidLastPageLoadEncounterSSLErrors() const {
return false;
}
-bool PasswordManagerClient::IsOffTheRecord() const {
+bool PasswordManagerClient::IsIncognito() const {
return false;
}
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 e1a0cb3e145..5e854e16db4 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client.h
+++ b/chromium/components/password_manager/core/browser/password_manager_client.h
@@ -21,6 +21,12 @@ class AutofillManager;
class GURL;
+#if defined(SAFE_BROWSING_DB_LOCAL)
+namespace safe_browsing {
+class PasswordProtectionService;
+}
+#endif
+
namespace password_manager {
class LogManager;
@@ -34,16 +40,11 @@ enum PasswordSyncState {
SYNCING_WITH_CUSTOM_PASSPHRASE
};
-enum class CredentialSourceType {
- CREDENTIAL_SOURCE_PASSWORD_MANAGER = 0,
- CREDENTIAL_SOURCE_API,
- CREDENTIAL_SOURCE_LAST = CREDENTIAL_SOURCE_API
-};
-
// An abstraction of operations that depend on the embedders (e.g. Chrome)
// environment.
class PasswordManagerClient {
public:
+ using HSTSCallback = base::Callback<void(bool)>;
using CredentialsCallback =
base::Callback<void(const autofill::PasswordForm*)>;
@@ -59,9 +60,11 @@ class PasswordManagerClient {
// password manager is disabled, or in the presence of SSL errors on a page.
virtual bool IsFillingEnabledForCurrentPage() const;
- // Checks whether HTTP Strict Transport Security (HSTS) is active for the host
- // of the given origin.
- virtual bool IsHSTSActiveForHost(const GURL& origin) const;
+ // Checks asynchronously whether HTTP Strict Transport Security (HSTS) is
+ // active for the host of the given origin. Notifies |callback| with the
+ // result on the calling thread.
+ virtual void PostHSTSQueryForHost(const GURL& origin,
+ const HSTSCallback& callback) const;
// Checks if the Credential Manager API is allowed to run on the page. It's
// not allowed while prerendering and the pre-rendered WebContents will be
@@ -87,11 +90,8 @@ class PasswordManagerClient {
// the stored one. In this case form_to_save.password_overridden() == true
// and form_to_save.pending_credentials() should correspond to the credential
// that was overidden.
- // TODO(crbug.com/576747): Analyze usefulness of the |type| parameter, make a
- // decision if it should be kept or removed.
virtual bool PromptUserToSaveOrUpdatePassword(
std::unique_ptr<PasswordFormManager> form_to_save,
- CredentialSourceType type,
bool update_password) = 0;
// Informs the embedder of a password forms that the user should choose from.
@@ -171,7 +171,7 @@ class PasswordManagerClient {
virtual bool DidLastPageLoadEncounterSSLErrors() const;
// If this browsing session should not be persisted.
- virtual bool IsOffTheRecord() const;
+ virtual bool IsIncognito() const;
// Returns the PasswordManager associated with this client. The non-const
// version calls the const one.
@@ -198,6 +198,12 @@ class PasswordManagerClient {
// Record that we saw a password field on this page.
virtual void AnnotateNavigationEntry(bool has_password_field);
+#if defined(SAFE_BROWSING_DB_LOCAL)
+ // Return the PasswordProtectionService associated with this instance.
+ virtual safe_browsing::PasswordProtectionService*
+ GetPasswordProtectionService() const = 0;
+#endif
+
private:
DISALLOW_COPY_AND_ASSIGN(PasswordManagerClient);
};
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc b/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc
index 2bce4dff2b5..642f0308eda 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc
@@ -115,6 +115,11 @@ void LogCountHttpMigratedPasswords(int count) {
UMA_HISTOGRAM_COUNTS_100("PasswordManager.HttpPasswordMigrationCount", count);
}
+void LogHttpPasswordMigrationMode(HttpPasswordMigrationMode mode) {
+ UMA_HISTOGRAM_ENUMERATION("PasswordManager.HttpPasswordMigrationMode", mode,
+ HTTP_PASSWORD_MIGRATION_MODE_COUNT);
+}
+
void LogAccountChooserUsability(AccountChooserUsabilityMetric usability,
int count_empty_icons,
int count_accounts) {
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 040a3be61f5..2fb1b731404 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
@@ -173,6 +173,13 @@ enum CredentialManagerGetMediation {
CREDENTIAL_MANAGER_GET_UNMEDIATED
};
+// Metrics: "PasswordManager.HttpPasswordMigrationMode"
+enum HttpPasswordMigrationMode {
+ HTTP_PASSWORD_MIGRATION_MODE_MOVE,
+ HTTP_PASSWORD_MIGRATION_MODE_COPY,
+ HTTP_PASSWORD_MIGRATION_MODE_COUNT
+};
+
enum PasswordReusePasswordFieldDetected {
NO_PASSWORD_FIELD,
HAS_PASSWORD_FIELD,
@@ -229,6 +236,9 @@ void LogShouldBlockPasswordForSameOriginButDifferentScheme(bool should_block);
// Logs number of passwords migrated from HTTP to HTTPS.
void LogCountHttpMigratedPasswords(int count);
+// Logs mode of HTTP password migration.
+void LogHttpPasswordMigrationMode(HttpPasswordMigrationMode mode);
+
// Log if the account chooser has empty username or duplicate usernames. In
// addition record number of the placeholder avatars and total number of rows.
void LogAccountChooserUsability(AccountChooserUsabilityMetric usability,
diff --git a/chromium/components/password_manager/core/browser/password_manager_test_utils.cc b/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
index 4fd51933642..080b607facb 100644
--- a/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
@@ -11,6 +11,7 @@
#include "base/feature_list.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
using autofill::PasswordForm;
@@ -59,6 +60,17 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromDataForTesting(
return form;
}
+std::vector<std::unique_ptr<PasswordForm>> WrapForms(
+ std::vector<PasswordForm> forms) {
+ std::vector<std::unique_ptr<PasswordForm>> results;
+ results.reserve(forms.size());
+ std::transform(forms.begin(), forms.end(), std::back_inserter(results),
+ [](PasswordForm& form) {
+ return base::MakeUnique<PasswordForm>(std::move(form));
+ });
+ return results;
+}
+
bool ContainsEqualPasswordFormsUnordered(
const std::vector<std::unique_ptr<PasswordForm>>& expectations,
const std::vector<std::unique_ptr<PasswordForm>>& actual_values,
@@ -104,8 +116,26 @@ MockPasswordStoreObserver::MockPasswordStoreObserver() {}
MockPasswordStoreObserver::~MockPasswordStoreObserver() {}
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
MockPasswordReuseDetectorConsumer::MockPasswordReuseDetectorConsumer() {}
MockPasswordReuseDetectorConsumer::~MockPasswordReuseDetectorConsumer() {}
+#endif
+
+HSTSStateManager::HSTSStateManager(net::TransportSecurityState* state,
+ bool is_hsts,
+ const std::string& host)
+ : state_(state), is_hsts_(is_hsts), host_(host) {
+ if (is_hsts_) {
+ base::Time expiry = base::Time::Max();
+ bool include_subdomains = false;
+ state_->AddHSTS(host_, expiry, include_subdomains);
+ }
+}
+HSTSStateManager::~HSTSStateManager() {
+ if (is_hsts_)
+ state_->DeleteDynamicDataForHost(host_);
+}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager_test_utils.h b/chromium/components/password_manager/core/browser/password_manager_test_utils.h
index 8d1577315d0..1958745a632 100644
--- a/chromium/components/password_manager/core/browser/password_manager_test_utils.h
+++ b/chromium/components/password_manager/core/browser/password_manager_test_utils.h
@@ -6,12 +6,15 @@
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_TEST_UTILS_H_
#include <iosfwd>
+#include <string>
#include <vector>
#include "base/feature_list.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/password_store.h"
+#include "net/http/transport_security_state.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace password_manager {
@@ -59,6 +62,11 @@ struct PasswordFormData {
std::unique_ptr<autofill::PasswordForm> CreatePasswordFormFromDataForTesting(
const PasswordFormData& form_data);
+// Convenience method that wraps the passed in forms in unique ptrs and returns
+// the result.
+std::vector<std::unique_ptr<autofill::PasswordForm>> WrapForms(
+ std::vector<autofill::PasswordForm> forms);
+
// Checks whether the PasswordForms pointed to in |actual_values| are in some
// permutation pairwise equal to those in |expectations|. Returns true in case
// of a perfect match; otherwise returns false and writes details of mismatches
@@ -83,6 +91,8 @@ class MockPasswordStoreObserver : public PasswordStore::Observer {
MOCK_METHOD1(OnLoginsChanged, void(const PasswordStoreChangeList& changes));
};
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
class MockPasswordReuseDetectorConsumer : public PasswordReuseDetectorConsumer {
public:
MockPasswordReuseDetectorConsumer();
@@ -91,6 +101,24 @@ class MockPasswordReuseDetectorConsumer : public PasswordReuseDetectorConsumer {
MOCK_METHOD4(OnReuseFound,
void(const base::string16&, const std::string&, int, int));
};
+#endif
+
+// Auxiliary class to automatically set and reset the HSTS state for a given
+// host.
+class HSTSStateManager {
+ public:
+ HSTSStateManager(net::TransportSecurityState* state,
+ bool is_hsts,
+ const std::string& host);
+ ~HSTSStateManager();
+
+ private:
+ net::TransportSecurityState* state_;
+ const bool is_hsts_;
+ const std::string host_;
+
+ DISALLOW_COPY_AND_ASSIGN(HSTSStateManager);
+};
} // namespace password_manager
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 894a67cd2c6..668303a45f5 100644
--- a/chromium/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_unittest.cc
@@ -15,6 +15,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
+#include "components/password_manager/core/browser/form_fetcher_impl.h"
#include "components/password_manager/core/browser/mock_password_store.h"
#include "components/password_manager/core/browser/password_autofill_manager.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
@@ -62,8 +63,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
MOCK_CONST_METHOD0(GetPasswordStore, PasswordStore*());
// The code inside EXPECT_CALL for PromptUserToSaveOrUpdatePasswordPtr owns
// the PasswordFormManager* argument.
- MOCK_METHOD2(PromptUserToSaveOrUpdatePasswordPtr,
- void(PasswordFormManager*, CredentialSourceType type));
+ MOCK_METHOD1(PromptUserToSaveOrUpdatePasswordPtr, void(PasswordFormManager*));
MOCK_METHOD1(NotifySuccessfulLoginWithExistingPassword,
void(const autofill::PasswordForm&));
MOCK_METHOD0(AutomaticPasswordSaveIndicator, void());
@@ -75,9 +75,8 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
// Workaround for std::unique_ptr<> lacking a copy constructor.
bool PromptUserToSaveOrUpdatePassword(
std::unique_ptr<PasswordFormManager> manager,
- password_manager::CredentialSourceType type,
bool update_password) override {
- PromptUserToSaveOrUpdatePasswordPtr(manager.release(), type);
+ PromptUserToSaveOrUpdatePasswordPtr(manager.release());
return false;
}
void AutomaticPasswordSave(
@@ -271,9 +270,7 @@ TEST_F(PasswordManagerTest, FormSubmitWithOnlyNewPasswordField) {
OnPasswordFormSubmitted(form);
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
// Now the password manager waits for the navigation to complete.
@@ -314,7 +311,7 @@ TEST_F(PasswordManagerTest, GeneratedPasswordFormSubmitEmptyStore) {
// consent by using the generated password. The form should be saved once
// navigation occurs. The client will be informed that automatic saving has
// occured.
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
PasswordForm form_to_save;
EXPECT_CALL(*store_, AddLogin(_)).WillOnce(SaveArg<0>(&form_to_save));
EXPECT_CALL(client_, AutomaticPasswordSaveIndicator());
@@ -351,9 +348,7 @@ TEST_F(PasswordManagerTest, FormSubmitNoGoodMatch) {
// We still expect an add, since we didn't have a good match.
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
// Now the password manager waits for the navigation to complete.
@@ -378,7 +373,7 @@ TEST_F(PasswordManagerTest, FormSeenThenLeftPage) {
// No message from the renderer that a password was submitted. No
// expected calls.
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
observed.clear();
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -401,9 +396,7 @@ TEST_F(PasswordManagerTest, FormSubmit) {
OnPasswordFormSubmitted(form);
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
observed.clear();
@@ -452,9 +445,7 @@ TEST_F(PasswordManagerTest, FormSubmitWithFormOnPreviousPage) {
OnPasswordFormSubmitted(second_form);
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
// Navigation after form submit, no forms appear.
observed.clear();
@@ -485,9 +476,7 @@ TEST_F(PasswordManagerTest, FormSubmitInvisibleLogin) {
// Expect info bar to appear:
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
// The form reappears, but is not visible in the layout:
@@ -560,7 +549,7 @@ TEST_F(PasswordManagerTest, PasswordFormReappearance) {
observed.push_back(MakeTwitterFailedLoginForm());
// A PasswordForm appears, and is visible in the layout:
// No expected calls to the PasswordStore...
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
EXPECT_CALL(client_, AutomaticPasswordSaveIndicator()).Times(0);
EXPECT_CALL(*store_, AddLogin(_)).Times(0);
EXPECT_CALL(*store_, UpdateLogin(_)).Times(0);
@@ -580,7 +569,7 @@ TEST_F(PasswordManagerTest, SyncCredentialsNotSaved) {
manager()->OnPasswordFormsRendered(&driver_, observed, true);
// User should not be prompted and password should not be saved.
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
EXPECT_CALL(*store_, AddLogin(_)).Times(0);
// Prefs are needed for failure logging about sync credentials.
EXPECT_CALL(client_, GetPrefs()).WillRepeatedly(Return(nullptr));
@@ -693,7 +682,7 @@ TEST_F(PasswordManagerTest, SyncCredentialsDroppedWhenObsolete) {
// Because the user successfully uses an updated sync password, Chrome should
// remove the obsolete copy of it.
EXPECT_CALL(*store_, RemoveLogin(form));
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
observed.clear();
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -751,7 +740,7 @@ TEST_F(PasswordManagerTest,
observed.push_back(second_form);
// Verify that no prompt to save the password is shown.
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
}
@@ -824,9 +813,7 @@ TEST_F(PasswordManagerTest, AttemptedSavePasswordSameOriginInsecureScheme) {
// Make sure |PromptUserToSaveOrUpdatePassword| gets called, and the resulting
// form manager is saved.
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
EXPECT_CALL(client_, GetMainFrameURL())
@@ -840,7 +827,7 @@ TEST_F(PasswordManagerTest, AttemptedSavePasswordSameOriginInsecureScheme) {
// Expect no further calls to |ProptUserToSaveOrUpdatePassword| due to
// insecure origin.
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
// Trigger call to |ProvisionalSavePassword| by rendering a page without
// forms.
@@ -877,9 +864,7 @@ TEST_F(PasswordManagerTest, DoNotSaveWithEmptyNewPasswordAndNonemptyPassword) {
OnPasswordFormSubmitted(form);
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
// Now the password manager waits for the login to complete successfully.
@@ -912,9 +897,7 @@ TEST_F(PasswordManagerTest, FormSubmitWithOnlyPasswordField) {
OnPasswordFormSubmitted(form);
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
// Now the password manager waits for the navigation to complete.
@@ -964,9 +947,7 @@ TEST_F(PasswordManagerTest, InPageNavigation) {
.WillRepeatedly(Return(true));
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
manager()->OnInPageNavigation(&driver_, form);
@@ -998,9 +979,7 @@ TEST_F(PasswordManagerTest, InPageNavigationBlacklistedSite) {
EXPECT_CALL(client_, GetPrefs()).WillRepeatedly(Return(nullptr));
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
manager()->OnInPageNavigation(&driver_, form);
@@ -1035,9 +1014,7 @@ TEST_F(PasswordManagerTest, SavingSignupForms_NoHTMLMatch) {
OnPasswordFormSubmitted(submitted_form);
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
// Now the password manager waits for the navigation to complete.
@@ -1090,9 +1067,7 @@ TEST_F(PasswordManagerTest, SavingSignupForms_NoActionMatch) {
OnPasswordFormSubmitted(submitted_form);
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
// Now the password manager waits for the navigation to complete.
@@ -1144,9 +1119,7 @@ TEST_F(PasswordManagerTest, FormSubmittedChangedWithAutofillResponse) {
OnPasswordFormSubmitted(form);
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
// Now the password manager waits for the navigation to complete.
@@ -1178,7 +1151,7 @@ TEST_F(PasswordManagerTest, FormSubmittedUnchangedNotifiesClient) {
autofill::PasswordForm updated_form;
autofill::PasswordForm notified_form;
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
EXPECT_CALL(*store_, UpdateLogin(_)).WillOnce(SaveArg<0>(&updated_form));
EXPECT_CALL(client_, NotifySuccessfulLoginWithExistingPassword(_))
.WillOnce(SaveArg<0>(&notified_form));
@@ -1219,9 +1192,7 @@ TEST_F(PasswordManagerTest, SaveFormFetchedAfterSubmit) {
->OnGetPasswordStoreResults(std::vector<std::unique_ptr<PasswordForm>>());
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
// Now the password manager waits for the navigation to complete.
@@ -1249,7 +1220,7 @@ TEST_F(PasswordManagerTest, PasswordGeneration_FailedSubmission) {
manager()->SetHasGeneratedPasswordForForm(&driver_, form, true);
// Do not save generated password when the password form reappears.
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
EXPECT_CALL(*store_, AddLogin(_)).Times(0);
EXPECT_CALL(client_, AutomaticPasswordSaveIndicator()).Times(0);
@@ -1281,7 +1252,7 @@ TEST_F(PasswordManagerTest, PasswordGenerationPasswordEdited_FailedSubmission) {
OnPasswordFormSubmitted(form);
// Do not save generated password when the password form reappears.
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
EXPECT_CALL(*store_, AddLogin(_)).Times(0);
EXPECT_CALL(client_, AutomaticPasswordSaveIndicator()).Times(0);
@@ -1315,7 +1286,7 @@ TEST_F(PasswordManagerTest,
OnPasswordFormSubmitted(form);
// No infobar or prompt is shown if submission fails.
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
EXPECT_CALL(client_, AutomaticPasswordSaveIndicator()).Times(0);
// Simulate submission failing, with the same form being visible after
@@ -1348,9 +1319,7 @@ TEST_F(PasswordManagerTest,
// Verify that a normal prompt is shown instead of the force saving UI.
std::unique_ptr<PasswordFormManager> form_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save)));
EXPECT_CALL(client_, AutomaticPasswordSaveIndicator()).Times(0);
@@ -1379,7 +1348,7 @@ TEST_F(PasswordManagerTest, PasswordGenerationUsernameChanged) {
form.username_value = ASCIIToUTF16("new_username");
OnPasswordFormSubmitted(form);
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
PasswordForm form_to_save;
EXPECT_CALL(*store_, AddLogin(_)).WillOnce(SaveArg<0>(&form_to_save));
EXPECT_CALL(client_, AutomaticPasswordSaveIndicator());
@@ -1442,13 +1411,10 @@ TEST_F(PasswordManagerTest, PasswordGenerationPresavePasswordAndLogin) {
}
std::unique_ptr<PasswordFormManager> form_manager;
if (found_matched_logins_in_store) {
- EXPECT_CALL(
- client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager)));
} else {
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
}
EXPECT_CALL(client_, AutomaticPasswordSaveIndicator())
.Times(found_matched_logins_in_store ? 0 : 1);
@@ -1518,9 +1484,7 @@ TEST_F(PasswordManagerTest, ForceSavingPasswords) {
std::unique_ptr<PasswordFormManager> form_manager_to_save;
EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
.WillRepeatedly(Return(true));
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
manager()->OnPasswordFormForceSaveRequested(&driver_, form);
ASSERT_TRUE(form_manager_to_save);
@@ -1546,7 +1510,7 @@ TEST_F(PasswordManagerTest, ForceSavingPasswords_Empty) {
EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
.WillRepeatedly(Return(true));
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
manager()->OnPasswordFormForceSaveRequested(&driver_, empty_password_form);
}
@@ -1587,7 +1551,7 @@ TEST_F(PasswordManagerTest, DropFormManagers) {
.WillRepeatedly(Return(true));
OnPasswordFormSubmitted(form);
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
observed.clear();
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1623,7 +1587,7 @@ TEST_F(PasswordManagerTest, AutofillingOfAffiliatedCredentials) {
PasswordForm saved_form;
PasswordForm saved_notified_form;
EXPECT_CALL(*store_, UpdateLogin(_)).WillOnce(SaveArg<0>(&saved_form));
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
EXPECT_CALL(client_, NotifySuccessfulLoginWithExistingPassword(_))
.WillOnce(SaveArg<0>(&saved_notified_form));
EXPECT_CALL(*store_, AddLogin(_)).Times(0);
@@ -1662,9 +1626,7 @@ TEST_F(PasswordManagerTest, UpdatePasswordOfAffiliatedCredential) {
OnPasswordFormSubmitted(filled_form);
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
observed_forms.clear();
@@ -1715,9 +1677,7 @@ TEST_F(PasswordManagerTest, ClearedFieldsSuccessCriteria) {
// Check success of the submission.
std::unique_ptr<PasswordFormManager> form_manager_to_save;
- EXPECT_CALL(client_,
- PromptUserToSaveOrUpdatePasswordPtr(
- _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
manager()->OnPasswordFormsParsed(&driver_, observed);
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 ae5e3fc3443..d8d4eb65b9c 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_util.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/log_manager.h"
#include "components/sync/driver/sync_service.h"
@@ -61,15 +62,12 @@ void FindDuplicates(
void TrimUsernameOnlyCredentials(
std::vector<std::unique_ptr<autofill::PasswordForm>>* android_credentials) {
// Remove username-only credentials which are not federated.
- android_credentials->erase(
- std::remove_if(
- android_credentials->begin(), android_credentials->end(),
- [](const std::unique_ptr<autofill::PasswordForm>& form) {
- return form->scheme ==
- autofill::PasswordForm::SCHEME_USERNAME_ONLY &&
- form->federation_origin.unique();
- }),
- android_credentials->end());
+ base::EraseIf(*android_credentials,
+ [](const std::unique_ptr<autofill::PasswordForm>& form) {
+ return form->scheme ==
+ autofill::PasswordForm::SCHEME_USERNAME_ONLY &&
+ form->federation_origin.unique();
+ });
// Set "skip_zero_click" on federated credentials.
std::for_each(
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 24a7c4f8e5e..ab55375398f 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
@@ -9,6 +9,9 @@
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_manager_util.h"
+#if defined(SAFE_BROWSING_DB_LOCAL) || defined(SAFE_BROWSING_DB_REMOTE)
+#include "components/safe_browsing/password_protection/password_protection_service.h"
+#endif
namespace password_manager {
@@ -60,6 +63,13 @@ void PasswordReuseDetectionManager::OnReuseFound(
metrics_util::LogPasswordReuse(
password.size(), saved_passwords, number_matches,
client_->GetPasswordManager()->IsPasswordFieldDetectedOnPage());
+#if defined(SAFE_BROWSING_DB_LOCAL)
+ // TODO(jialiul): After CSD whitelist being added to Android, we should gate
+ // this by either SAFE_BROWSING_DB_LOCAL or SAFE_BROWSING_DB_REMOTE.
+ safe_browsing::PasswordProtectionService* password_protection_service =
+ client_->GetPasswordProtectionService();
+ password_protection_service->RecordPasswordReuse(main_frame_url_);
+#endif
}
} // namespace password_manager
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 eaf9384fd99..9235fa5ab0d 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
@@ -21,7 +21,6 @@ class PasswordReuseDetectionManager : public PasswordReuseDetectorConsumer {
public:
explicit PasswordReuseDetectionManager(PasswordManagerClient* client);
~PasswordReuseDetectionManager() override;
-
void DidNavigateMainFrame(const GURL& main_frame_url);
void OnKeyPressed(const base::string16& 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 a2a4557eceb..3dadcc79450 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
@@ -6,6 +6,7 @@
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
#include "components/password_manager/core/browser/mock_password_store.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -48,7 +49,7 @@ class PasswordReuseDetectionManagerTest : public ::testing::Test {
protected:
// It's needed for an initialisation of thread runners that are used in
// MockPasswordStore.
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
MockPasswordManagerClient client_;
scoped_refptr<MockPasswordStore> store_;
diff --git a/chromium/components/password_manager/core/browser/password_store.cc b/chromium/components/password_manager/core/browser/password_store.cc
index 4750796439f..3597674b5ba 100644
--- a/chromium/components/password_manager/core/browser/password_store.cc
+++ b/chromium/components/password_manager/core/browser/password_store.cc
@@ -38,13 +38,10 @@ PasswordStore::GetLoginsRequest::~GetLoginsRequest() {
void PasswordStore::GetLoginsRequest::NotifyConsumerWithResults(
std::vector<std::unique_ptr<PasswordForm>> results) {
if (!ignore_logins_cutoff_.is_null()) {
- results.erase(
- std::remove_if(results.begin(), results.end(),
- [this](const std::unique_ptr<PasswordForm>& credential) {
- return (credential->date_created <
- ignore_logins_cutoff_);
- }),
- results.end());
+ base::EraseIf(results,
+ [this](const std::unique_ptr<PasswordForm>& credential) {
+ return (credential->date_created < ignore_logins_cutoff_);
+ });
}
origin_task_runner_->PostTask(
@@ -59,6 +56,8 @@ void PasswordStore::GetLoginsRequest::NotifyWithSiteStatistics(
consumer_weak_, base::Passed(&stats)));
}
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
PasswordStore::CheckReuseRequest::CheckReuseRequest(
PasswordReuseDetectorConsumer* consumer)
: origin_task_runner_(base::ThreadTaskRunnerHandle::Get()),
@@ -76,6 +75,7 @@ void PasswordStore::CheckReuseRequest::OnReuseFound(
base::Bind(&PasswordReuseDetectorConsumer::OnReuseFound, consumer_weak_,
password, saved_domain, saved_passwords, number_matches));
}
+#endif
PasswordStore::FormDigest::FormDigest(autofill::PasswordForm::Scheme new_scheme,
const std::string& new_signon_realm,
@@ -308,6 +308,8 @@ PasswordStore::GetPasswordSyncableService() {
return syncable_service_->AsWeakPtr();
}
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
void PasswordStore::CheckReuse(const base::string16& input,
const std::string& domain,
PasswordReuseDetectorConsumer* consumer) {
@@ -315,6 +317,7 @@ void PasswordStore::CheckReuse(const base::string16& input,
ScheduleTask(base::Bind(&PasswordStore::CheckReuseImpl, this,
base::Passed(&check_reuse_request), input, domain));
}
+#endif
PasswordStore::~PasswordStore() {
DCHECK(shutdown_called_);
@@ -380,17 +383,23 @@ void PasswordStore::NotifyLoginsChanged(
observers_->Notify(FROM_HERE, &Observer::OnLoginsChanged, changes);
if (syncable_service_)
syncable_service_->ActOnPasswordStoreChanges(changes);
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
if (reuse_detector_)
reuse_detector_->OnLoginsChanged(changes);
+#endif
}
}
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
void PasswordStore::CheckReuseImpl(std::unique_ptr<CheckReuseRequest> request,
const base::string16& input,
const std::string& domain) {
if (reuse_detector_)
reuse_detector_->CheckReuse(input, domain, request.get());
}
+#endif
void PasswordStore::Schedule(
void (PasswordStore::*func)(std::unique_ptr<GetLoginsRequest>),
@@ -704,10 +713,9 @@ void PasswordStore::InitOnBackgroundThread(
DCHECK(!syncable_service_);
syncable_service_.reset(new PasswordSyncableService(this));
syncable_service_->InjectStartSyncFlare(flare);
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
reuse_detector_.reset(new PasswordReuseDetector);
-#if !defined(OS_MACOSX)
- // TODO(crbug.com/668155): For non-migrated keychain users it can lead to
- // hundreds of requests to unlock keychain.
GetAutofillableLoginsImpl(
base::MakeUnique<GetLoginsRequest>(reuse_detector_.get()));
#endif
@@ -716,7 +724,10 @@ void PasswordStore::InitOnBackgroundThread(
void PasswordStore::DestroyOnBackgroundThread() {
DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
syncable_service_.reset();
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
reuse_detector_.reset();
+#endif
}
std::ostream& operator<<(std::ostream& os,
diff --git a/chromium/components/password_manager/core/browser/password_store.h b/chromium/components/password_manager/core/browser/password_store.h
index dd34afc9bc9..0a0b915bbef 100644
--- a/chromium/components/password_manager/core/browser/password_store.h
+++ b/chromium/components/password_manager/core/browser/password_store.h
@@ -17,12 +17,16 @@
#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
#include "components/keyed_service/core/refcounted_keyed_service.h"
-#include "components/password_manager/core/browser/password_reuse_detector.h"
-#include "components/password_manager/core/browser/password_reuse_detector_consumer.h"
#include "components/password_manager/core/browser/password_store_change.h"
#include "components/password_manager/core/browser/password_store_sync.h"
#include "components/sync/model/syncable_service.h"
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#include "components/password_manager/core/browser/password_reuse_detector.h"
+#include "components/password_manager/core/browser/password_reuse_detector_consumer.h"
+#endif
+
class PasswordStoreProxyMac;
namespace autofill {
@@ -227,6 +231,8 @@ class PasswordStore : protected PasswordStoreSync,
base::WeakPtr<syncer::SyncableService> GetPasswordSyncableService();
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
// Checks that some suffix of |input| equals to a password saved on another
// registry controlled domain than |domain|.
// If such suffix is found, |consumer|->OnReuseFound() is called on the same
@@ -235,6 +241,7 @@ class PasswordStore : protected PasswordStoreSync,
virtual void CheckReuse(const base::string16& input,
const std::string& domain,
PasswordReuseDetectorConsumer* consumer);
+#endif
protected:
friend class base::RefCountedThreadSafe<PasswordStore>;
@@ -271,6 +278,8 @@ class PasswordStore : protected PasswordStoreSync,
DISALLOW_COPY_AND_ASSIGN(GetLoginsRequest);
};
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
// Represents a single CheckReuse() request. Implements functionality to
// listen to reuse events and propagate them to |consumer| on the thread on
// which CheckReuseRequest is created.
@@ -292,6 +301,7 @@ class PasswordStore : protected PasswordStoreSync,
DISALLOW_COPY_AND_ASSIGN(CheckReuseRequest);
};
+#endif
~PasswordStore() override;
@@ -386,10 +396,13 @@ class PasswordStore : protected PasswordStoreSync,
// may have been changed.
void NotifyLoginsChanged(const PasswordStoreChangeList& changes) override;
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
// Synchronous implementation of CheckReuse().
void CheckReuseImpl(std::unique_ptr<CheckReuseRequest> request,
const base::string16& input,
const std::string& domain);
+#endif
// TaskRunner for tasks that run on the main thread (usually the UI thread).
scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner_;
@@ -541,7 +554,10 @@ class PasswordStore : protected PasswordStoreSync,
std::unique_ptr<PasswordSyncableService> syncable_service_;
std::unique_ptr<AffiliatedMatchHelper> affiliated_match_helper_;
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
std::unique_ptr<PasswordReuseDetector> reuse_detector_;
+#endif
bool is_propagating_password_changes_to_web_credentials_enabled_;
bool shutdown_called_;
diff --git a/chromium/components/password_manager/core/browser/password_store_consumer.h b/chromium/components/password_manager/core/browser/password_store_consumer.h
index 89d7975d0ee..6800919b516 100644
--- a/chromium/components/password_manager/core/browser/password_store_consumer.h
+++ b/chromium/components/password_manager/core/browser/password_store_consumer.h
@@ -46,6 +46,8 @@ class PasswordStoreConsumer {
return weak_ptr_factory_.GetWeakPtr();
}
+ bool HasWeakPtrs() const { return weak_ptr_factory_.HasWeakPtrs(); }
+
protected:
virtual ~PasswordStoreConsumer();
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 c47fcebe9fd..527770396f7 100644
--- a/chromium/components/password_manager/core/browser/password_store_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_unittest.cc
@@ -31,6 +31,10 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_MACOSX)
+#include "components/os_crypt/os_crypt_mocker.h"
+#endif
+
using autofill::PasswordForm;
using base::WaitableEvent;
using testing::_;
@@ -840,9 +844,8 @@ TEST_F(PasswordStoreTest, GetLoginsWithAffiliatedRealms) {
}
}
-#if !defined(OS_MACOSX)
-// TODO(crbug.com/668155): Enable this test after fixing issues with
-// initialization PasswordStore with MockKeyChain in tests on MacOS.
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
TEST_F(PasswordStoreTest, CheckPasswordReuse) {
static constexpr PasswordFormData kTestCredentials[] = {
{PasswordForm::SCHEME_HTML, "https://www.google.com",
@@ -850,6 +853,11 @@ TEST_F(PasswordStoreTest, CheckPasswordReuse) {
{PasswordForm::SCHEME_HTML, "https://facebook.com",
"https://facebook.com", "", L"", L"", L"", L"", L"topsecret", true, 1}};
+#if defined(OS_MACOSX)
+ // Mock Keychain. There is a call to Keychain on initializling
+ // PasswordReuseDetector, so it should be mocked.
+ OSCryptMocker::SetUpWithSingleton();
+#endif
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
@@ -889,6 +897,9 @@ TEST_F(PasswordStoreTest, CheckPasswordReuse) {
store->ShutdownOnUIThread();
base::RunLoop().RunUntilIdle();
+#if defined(OS_MACOSX)
+ OSCryptMocker::TearDown();
+#endif
}
#endif
diff --git a/chromium/components/password_manager/core/browser/password_ui_utils.cc b/chromium/components/password_manager/core/browser/password_ui_utils.cc
index cd30086f73d..34f03d6833a 100644
--- a/chromium/components/password_manager/core/browser/password_ui_utils.cc
+++ b/chromium/components/password_manager/core/browser/password_ui_utils.cc
@@ -7,7 +7,6 @@
#include <algorithm>
#include <string>
-#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -25,8 +24,8 @@ const char* const kRemovedPrefixes[] = {"m.", "mobile.", "www."};
} // namespace
std::string SplitByDotAndReverse(base::StringPiece host) {
- std::vector<std::string> parts =
- base::SplitString(host, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ std::vector<base::StringPiece> parts = base::SplitStringPiece(
+ host, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
std::reverse(parts.begin(), parts.end());
return base::JoinString(parts, ".");
}
diff --git a/chromium/components/password_manager/core/browser/psl_matching_helper.cc b/chromium/components/password_manager/core/browser/psl_matching_helper.cc
index 5ae887d4c54..b4c4bef165c 100644
--- a/chromium/components/password_manager/core/browser/psl_matching_helper.cc
+++ b/chromium/components/password_manager/core/browser/psl_matching_helper.cc
@@ -36,6 +36,24 @@ std::ostream& operator<<(std::ostream& out, MatchResult result) {
return out;
}
+bool IsFederatedRealm(const std::string& form_signon_realm,
+ const GURL& origin) {
+ // The format should be "federation://origin.host/federation.host;
+ std::string federated_realm = "federation://" + origin.host() + "/";
+ return form_signon_realm.size() > federated_realm.size() &&
+ base::StartsWith(form_signon_realm, federated_realm,
+ base::CompareCase::INSENSITIVE_ASCII);
+}
+
+bool IsFederatedPSLMatch(const std::string& form_signon_realm,
+ const GURL& form_origin,
+ const GURL& origin) {
+ if (!IsPublicSuffixDomainMatch(form_origin.spec(), origin.spec()))
+ return false;
+
+ return IsFederatedRealm(form_signon_realm, form_origin);
+}
+
MatchResult GetMatchResult(const PasswordForm& form,
const PasswordStore::FormDigest& form_digest) {
if (form.signon_realm == form_digest.signon_realm)
@@ -55,11 +73,12 @@ MatchResult GetMatchResult(const PasswordForm& form,
return MatchResult::PSL_MATCH;
if (allow_federated_match &&
- IsFederatedMatch(form.signon_realm, form_digest.origin))
+ IsFederatedRealm(form.signon_realm, form_digest.origin) &&
+ form.origin.GetOrigin() == form_digest.origin.GetOrigin())
return MatchResult::FEDERATED_MATCH;
if (allow_psl_match && allow_federated_match &&
- IsFederatedPSLMatch(form.signon_realm, form_digest.origin))
+ IsFederatedPSLMatch(form.signon_realm, form.origin, form_digest.origin))
return MatchResult::FEDERATED_PSL_MATCH;
return MatchResult::NO_MATCH;
@@ -97,39 +116,4 @@ std::string GetRegistryControlledDomain(const GURL& signon_realm) {
signon_realm,
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
}
-
-bool IsFederatedMatch(const std::string& signon_realm, const GURL& origin) {
- // Federated matches only apply to HTTPS.
- if (!origin.SchemeIs(url::kHttpsScheme))
- return false;
-
- // The format should be "federation://origin.host/federation.host;
- std::string federated_realm = "federation://" + origin.host() + "/";
- return signon_realm.size() > federated_realm.size() &&
- base::StartsWith(signon_realm, federated_realm,
- base::CompareCase::INSENSITIVE_ASCII);
-}
-
-bool IsFederatedPSLMatch(const std::string& signon_realm, const GURL& origin) {
- // The format should be "federation://origin.host/federation.host;
- // Check for presence of "federation://" prefix.
- static constexpr char federation_prefix[] = "federation://";
- if (!base::StartsWith(signon_realm, federation_prefix,
- base::CompareCase::INSENSITIVE_ASCII))
- return false;
-
- // Replace federation scheme with HTTPS. This results in correct parsing of
- // host and path, and forces origin to have a HTTPS scheme in order to return
- // true.
- GURL::Replacements replacements;
- replacements.SetSchemeStr(url::kHttpsScheme);
- GURL https_signon_realm = GURL(signon_realm).ReplaceComponents(replacements);
-
- // Check for non-empty federation.host.
- if (!https_signon_realm.has_path() || https_signon_realm.path_piece() == "/")
- return false;
-
- return IsPublicSuffixDomainMatch(https_signon_realm.GetOrigin().spec(),
- origin.GetOrigin().spec());
-}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/psl_matching_helper.h b/chromium/components/password_manager/core/browser/psl_matching_helper.h
index d5839c54205..7bfea29daa9 100644
--- a/chromium/components/password_manager/core/browser/psl_matching_helper.h
+++ b/chromium/components/password_manager/core/browser/psl_matching_helper.h
@@ -33,9 +33,21 @@ enum class MatchResult {
FEDERATED_PSL_MATCH,
};
-// For testing.
+#if defined(UNIT_TEST)
std::ostream& operator<<(std::ostream& out, MatchResult result);
+// Returns true iff |form_signon_realm| designates a federated credential for
+// |origin|. It doesn't check the port because |form_signon_realm| doesn't have
+// it.
+bool IsFederatedRealm(const std::string& form_signon_realm, const GURL& origin);
+
+// Returns true iff |form_signon_realm| and |form_origin| designate a federated
+// PSL matching credential for the |origin|.
+bool IsFederatedPSLMatch(const std::string& form_signon_realm,
+ const GURL& form_origin,
+ const GURL& origin);
+#endif
+
// Returns what type of match applies to |form| and |form_digest|.
MatchResult GetMatchResult(const autofill::PasswordForm& form,
const PasswordStore::FormDigest& form_digest);
@@ -62,13 +74,6 @@ bool IsPublicSuffixDomainMatch(const std::string& url1,
// registry-controlled domain part.
std::string GetRegistryControlledDomain(const GURL& signon_realm);
-// Returns true iff |signon_realm| designates a federated credential for the
-// |origin|.
-bool IsFederatedMatch(const std::string& signon_realm, const GURL& origin);
-
-// Returns true iff |signon_realm| designates a federated PSL matching
-// credential for the |origin|.
-bool IsFederatedPSLMatch(const std::string& signon_realm, const GURL& origin);
} // namespace password_manager
#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PSL_MATCHING_HELPER_H_
diff --git a/chromium/components/password_manager/core/browser/psl_matching_helper_unittest.cc b/chromium/components/password_manager/core/browser/psl_matching_helper_unittest.cc
index 8c176b3c802..66c798df366 100644
--- a/chromium/components/password_manager/core/browser/psl_matching_helper_unittest.cc
+++ b/chromium/components/password_manager/core/browser/psl_matching_helper_unittest.cc
@@ -14,150 +14,245 @@ namespace password_manager {
namespace {
-TEST(PSLMatchingUtilsTest, GetMatchResult) {
+TEST(PSLMatchingUtilsTest, GetMatchResultNormalCredentials) {
struct TestData {
- const char* form_signon_realm;
- const char* form_federation_origin;
- autofill::PasswordForm::Scheme digest_scheme;
- const char* digest_signon_realm;
+ const char* form_origin;
const char* digest_origin;
MatchResult match_result;
};
const TestData cases[] = {
// Test Exact Matches.
- {"http://facebook.com/", "", autofill::PasswordForm::SCHEME_HTML,
- "http://facebook.com/", "http://facebook.com", MatchResult::EXACT_MATCH},
+ {"http://facebook.com/p", "http://facebook.com/p1",
+ MatchResult::EXACT_MATCH},
- {"http://m.facebook.com/", "", autofill::PasswordForm::SCHEME_HTML,
- "http://m.facebook.com/", "http://m.facebook.com",
+ {"http://m.facebook.com/p", "http://m.facebook.com/p1",
MatchResult::EXACT_MATCH},
// Scheme mismatch.
- {"http://www.example.com/", "", autofill::PasswordForm::SCHEME_HTML,
- "https://www.example.com/", "https://www.example.com",
+ {"http://www.example.com", "https://www.example.com",
MatchResult::NO_MATCH},
// Host mismatch.
- {"http://www.example.com/", "", autofill::PasswordForm::SCHEME_HTML,
- "http://wwwexample.com/", "http://wwwexample.com",
+ {"http://www.example.com", "http://wwwexample.com",
MatchResult::NO_MATCH},
- {"http://www.example1.com/", "", autofill::PasswordForm::SCHEME_HTML,
- "http://www.example2.com/", "http://www.example2.com",
+ {"http://www.example1.com", "http://www.example2.com",
MatchResult::NO_MATCH},
// Port mismatch.
- {"http://www.example.com:123/", "", autofill::PasswordForm::SCHEME_HTML,
- "http://www.example.com/", "http://www.example.com",
+ {"http://www.example.com:123/", "http://www.example.com",
MatchResult::NO_MATCH},
// TLD mismatch.
- {"http://www.example.org/", "", autofill::PasswordForm::SCHEME_HTML,
- "http://www.example.com/", "http://www.example.com",
+ {"http://www.example.org/", "http://www.example.com/",
MatchResult::NO_MATCH},
// URLs without registry controlled domains should not match.
- {"http://localhost/", "", autofill::PasswordForm::SCHEME_HTML,
- "http://127.0.0.1/", "http://127.0.0.1", MatchResult::NO_MATCH},
+ {"http://localhost/", "http://127.0.0.1/", MatchResult::NO_MATCH},
// Invalid URLs don't match.
- {"http://www.example.com/", "", autofill::PasswordForm::SCHEME_HTML,
- "http://", "", MatchResult::NO_MATCH},
+ {"http://www.example.com/", "http://", MatchResult::NO_MATCH},
- {"", "", autofill::PasswordForm::SCHEME_HTML, "http://www.example.com/",
- "http://www.example.com", MatchResult::NO_MATCH},
+ {"", "http://www.example.com/", MatchResult::NO_MATCH},
- {"http://www.example.com", "", autofill::PasswordForm::SCHEME_HTML,
- "bad url", "", MatchResult::NO_MATCH},
+ {"http://www.example.com", "bad url", MatchResult::NO_MATCH}};
- // Test PSL Matches.
- {"http://facebook.com/", "", autofill::PasswordForm::SCHEME_HTML,
- "http://m.facebook.com/", "http://m.facebook.com",
- MatchResult::PSL_MATCH},
+ for (const TestData& data : cases) {
+ autofill::PasswordForm form;
+ form.origin = GURL(data.form_origin);
+ form.signon_realm = form.origin.GetOrigin().spec();
+ PasswordStore::FormDigest digest(
+ autofill::PasswordForm::SCHEME_HTML,
+ GURL(data.digest_origin).GetOrigin().spec(), GURL(data.digest_origin));
- {"https://facebook.com/", "", autofill::PasswordForm::SCHEME_HTML,
- "https://m.facebook.com/", "https://m.facebook.com",
+ EXPECT_EQ(data.match_result, GetMatchResult(form, digest))
+ << "form_origin = " << data.form_origin << ", digest = " << digest;
+ }
+}
+
+TEST(PSLMatchingUtilsTest, GetMatchResultPSL) {
+ struct TestData {
+ const char* form_origin;
+ const char* digest_origin;
+ MatchResult match_result;
+ };
+
+ const TestData cases[] = {
+ // Test PSL Matches.
+ {"http://facebook.com/p1", "http://m.facebook.com/p2",
MatchResult::PSL_MATCH},
- {"https://www.facebook.com/", "", autofill::PasswordForm::SCHEME_HTML,
- "https://m.facebook.com/", "https://m.facebook.com",
+ {"https://www.facebook.com/", "https://m.facebook.com",
MatchResult::PSL_MATCH},
// Don't apply PSL matching to Google domains.
- {"https://google.com/", "", autofill::PasswordForm::SCHEME_HTML,
- "https://maps.google.com/", "https://maps.google.com",
+ {"https://google.com/", "https://maps.google.com/",
+ MatchResult::NO_MATCH},
+
+ // Scheme mismatch.
+ {"http://facebook.com/", "https://m.facebook.com/",
+ MatchResult::NO_MATCH},
+
+ {"https://facebook.com/", "http://m.facebook.com/",
+ MatchResult::NO_MATCH},
+
+ // Port mismatch.
+ {"http://facebook.com/", "https://m.facebook.com:8080/",
MatchResult::NO_MATCH},
- {"https://google.com/", "", autofill::PasswordForm::SCHEME_HTML,
- "https://maps.google.com/", "https://maps.google.com",
+ {"http://facebook.com:8080/", "https://m.facebook.com/",
MatchResult::NO_MATCH},
+ // Port match.
+ {"http://facebook.com:8080/p1", "http://m.facebook.com:8080/p2",
+ MatchResult::PSL_MATCH},
+ };
+
+ for (const TestData& data : cases) {
+ autofill::PasswordForm form;
+ form.origin = GURL(data.form_origin);
+ form.signon_realm = form.origin.GetOrigin().spec();
+ PasswordStore::FormDigest digest(
+ autofill::PasswordForm::SCHEME_HTML,
+ GURL(data.digest_origin).GetOrigin().spec(), GURL(data.digest_origin));
+
+ EXPECT_EQ(data.match_result, GetMatchResult(form, digest))
+ << "form_origin = " << data.form_origin << ", digest = " << digest;
+ }
+}
+
+TEST(PSLMatchingUtilsTest, GetMatchResultFederated) {
+ struct TestData {
+ const char* form_origin;
+ const char* form_federation_origin;
+ const char* digest_origin;
+ MatchResult match_result;
+ };
+
+ const TestData cases[] = {
// Test Federated Matches.
- {"federation://example.com/google.com", "https://google.com",
- autofill::PasswordForm::SCHEME_HTML, "https://example.com/",
- "https://example.com", MatchResult::FEDERATED_MATCH},
+ {"https://example.com/p", "https://google.com", "https://example.com/p2",
+ MatchResult::FEDERATED_MATCH},
// Empty federation providers don't match.
- {"federation://example.com/", "", autofill::PasswordForm::SCHEME_HTML,
- "https://example.com/", "https://example.com", MatchResult::NO_MATCH},
+ {"https://example.com/", "", "https://example.com",
+ MatchResult::NO_MATCH},
// Invalid origins don't match.
- {"federation://example.com/google.com", "https://google.com",
- autofill::PasswordForm::SCHEME_HTML, "https://example.com",
- "example.com", MatchResult::NO_MATCH},
+ {"https://example.com/", "https://google.com", "example.com",
+ MatchResult::NO_MATCH},
+
+ {"https://example.com/", "https://google.com", "example",
+ MatchResult::NO_MATCH},
+
+ // TLD Mismatch.
+ {"https://example.com/", "https://google.com", "https://example.org",
+ MatchResult::NO_MATCH},
+
+ // Scheme mismatch.
+ {"http://example.com/", "https://google.com", "https://example.com/",
+ MatchResult::NO_MATCH},
+
+ {"https://example.com/", "https://google.com", "http://example.com/",
+ MatchResult::NO_MATCH},
+
+ // Port mismatch.
+ {"https://localhost/", "https://google.com", "http://localhost:8080",
+ MatchResult::NO_MATCH},
- {"federation://example.com/google.com", "https://google.com",
- autofill::PasswordForm::SCHEME_HTML, "https://example.com", "example",
+ {"https://localhost:8080", "https://google.com", "http://localhost",
MatchResult::NO_MATCH},
+ // Port match.
+ {"https://localhost:8080/p", "https://google.com",
+ "https://localhost:8080/p2", MatchResult::FEDERATED_MATCH},
+ };
+
+ for (const TestData& data : cases) {
+ autofill::PasswordForm form;
+ form.origin = GURL(data.form_origin);
+ form.federation_origin = url::Origin(GURL(data.form_federation_origin));
+ form.signon_realm = "federation://" + form.origin.host() + "/" +
+ form.federation_origin.host();
+
+ PasswordStore::FormDigest digest(
+ autofill::PasswordForm::SCHEME_HTML,
+ GURL(data.digest_origin).GetOrigin().spec(), GURL(data.digest_origin));
+
+ EXPECT_EQ(data.match_result, GetMatchResult(form, digest))
+ << "form_origin = " << data.form_origin
+ << ", form_federation_origin = " << data.form_federation_origin
+ << ", digest = " << digest;
+ }
+}
+
+TEST(PSLMatchingUtilsTest, GetMatchResultFederatedPSL) {
+ struct TestData {
+ const char* form_origin;
+ const char* form_federation_origin;
+ const char* digest_origin;
+ MatchResult match_result;
+ };
+
+ const TestData cases[] = {
// Test Federated PSL Matches.
- {"federation://sub.example.com/google.com", "https://google.com",
- autofill::PasswordForm::SCHEME_HTML, "https://sub.example.com/",
- "https://sub.example.com", MatchResult::FEDERATED_MATCH},
+ {"https://sub.example.com/p2", "https://google.com",
+ "https://sub.example.com/p1", MatchResult::FEDERATED_MATCH},
- {"federation://sub1.example.com/google.com", "https://google.com",
- autofill::PasswordForm::SCHEME_HTML, "https://sub2.example.com/",
- "https://sub2.example.com", MatchResult::FEDERATED_PSL_MATCH},
+ {"https://sub1.example.com/p1", "https://google.com",
+ "https://sub2.example.com/p2", MatchResult::FEDERATED_PSL_MATCH},
- {"federation://example.com/google.com", "https://google.com",
- autofill::PasswordForm::SCHEME_HTML, "https://sub.example.com/",
- "https://sub.example.com", MatchResult::FEDERATED_PSL_MATCH},
+ {"https://example.com/", "https://google.com", "https://sub.example.com",
+ MatchResult::FEDERATED_PSL_MATCH},
// Federated PSL matches do not apply to HTTP.
- {"federation://sub1.example.com/google.com", "https://google.com",
- autofill::PasswordForm::SCHEME_HTML, "http://sub2.example.com/",
+ {"https://sub1.example.com/", "https://google.com",
"http://sub2.example.com", MatchResult::NO_MATCH},
- {"federation://example.com/google.com", "https://google.com",
- autofill::PasswordForm::SCHEME_HTML, "http://sub.example.com/",
- "http://sub.example.com", MatchResult::NO_MATCH},
+ {"https://example.com/", "https://google.com", "http://sub.example.com",
+ MatchResult::NO_MATCH},
+
+ {"http://example.com/", "https://google.com", "https://example.com/",
+ MatchResult::NO_MATCH},
// Federated PSL matches do not apply to Google on HTTP or HTTPS.
- {"federation://accounts.google.com/facebook.com", "https://facebook.com",
- autofill::PasswordForm::SCHEME_HTML, "https://maps.google.com/",
+ {"https://accounts.google.com/", "https://facebook.com",
"https://maps.google.com", MatchResult::NO_MATCH},
- {"federation://accounts.google.com/facebook.com", "https://facebook.com",
- autofill::PasswordForm::SCHEME_HTML, "http://maps.google.com/",
+ {"https://accounts.google.com/facebook.com", "https://facebook.com",
"http://maps.google.com", MatchResult::NO_MATCH},
// TLD Mismatch.
- {"federation://sub.example.com/google.com", "https://google.com",
- autofill::PasswordForm::SCHEME_HTML, "https://sub.example.org/",
+ {"https://sub.example.com/google.com", "https://google.com",
"https://sub.example.org", MatchResult::NO_MATCH},
+
+ // Port mismatch.
+ {"https://example.com/", "https://google.com", "https://example.com:8080",
+ MatchResult::NO_MATCH},
+
+ {"https://example.com:8080", "https://google.com", "https://example.com",
+ MatchResult::NO_MATCH},
+
+ // Port match.
+ {"https://sub.example.com:8080/p", "https://google.com",
+ "https://sub2.example.com:8080/p2", MatchResult::FEDERATED_PSL_MATCH},
};
for (const TestData& data : cases) {
autofill::PasswordForm form;
- form.signon_realm = data.form_signon_realm;
+ form.origin = GURL(data.form_origin);
form.federation_origin = url::Origin(GURL(data.form_federation_origin));
+ form.signon_realm = "federation://" + form.origin.host() + "/" +
+ form.federation_origin.host();
+
PasswordStore::FormDigest digest(
- data.digest_scheme, data.digest_signon_realm, GURL(data.digest_origin));
+ autofill::PasswordForm::SCHEME_HTML,
+ GURL(data.digest_origin).GetOrigin().spec(), GURL(data.digest_origin));
EXPECT_EQ(data.match_result, GetMatchResult(form, digest))
- << "signon_realm = " << data.form_signon_realm
- << ", federation_origin = " << data.form_federation_origin
+ << "form_origin = " << data.form_origin
+ << ", form_federation_origin = " << data.form_federation_origin
<< ", digest = " << digest;
}
}
@@ -206,9 +301,9 @@ TEST(PSLMatchingUtilsTest, IsPublicSuffixDomainMatch) {
}
}
-TEST(PSLMatchingUtilsTest, IsFederatedMatch) {
+TEST(PSLMatchingUtilsTest, IsFederatedRealm) {
struct TestPair {
- const char* signon_realm;
+ const char* form_signon_realm;
const char* origin;
bool should_match;
};
@@ -219,55 +314,76 @@ TEST(PSLMatchingUtilsTest, IsFederatedMatch) {
{"", "https://facebook.com/", false},
{"https://facebook.com/", "", false},
{"federation://example.com/google.com", "https://example.com/", true},
- {"federation://example.com/google.com", "http://example.com/", false},
+ {"federation://example.com/google.com", "http://example.com/", true},
{"federation://example.com/google.com", "example.com", false},
{"federation://example.com/", "http://example.com/", false},
{"federation://example.com/google.com", "example", false},
+
+ {"federation://localhost/google.com", "http://localhost/", true},
+ {"federation://localhost/google.com", "http://localhost:8000/", true},
};
for (const TestPair& pair : pairs) {
- std::string signon_realm = pair.signon_realm;
- GURL origin(pair.origin);
- EXPECT_EQ(pair.should_match, IsFederatedMatch(signon_realm, origin))
- << "signon_realm = " << pair.signon_realm
+ EXPECT_EQ(pair.should_match,
+ IsFederatedRealm(pair.form_signon_realm, GURL(pair.origin)))
+ << "form_signon_realm = " << pair.form_signon_realm
<< ", origin = " << pair.origin;
}
}
TEST(PSLMatchingUtilsTest, IsFederatedPSLMatch) {
struct TestPair {
- const char* signon_realm;
+ const char* form_signon_realm;
+ const char* form_origin;
const char* origin;
bool should_match;
};
const TestPair pairs[] = {
- {"https://facebook.com", "https://facebook.com", false},
- {"", "", false},
- {"", "https://facebook.com/", false},
- {"https://facebook.com/", "", false},
-
- {"federation://example.com/google.com", "https://example.com/", true},
- {"federation://example.com/google.com", "http://example.com/", false},
- {"federation://example.com/google.com", "example.com", false},
- {"federation://example.com/", "http://example.com/", false},
- {"federation://example.com/google.com", "example", false},
-
- {"federation://sub.example.com/google.com", "https://sub.example.com/",
- true},
- {"federation://sub1.example.com/google.com", "https://sub2.example.com/",
- true},
- {"federation://example.com/google.com", "https://sub.example.com/", true},
- {"federation://example.com/google.com", "http://sub.example.com/", false},
- {"federation://sub.example.com/", "https://sub.example.com/", false},
+ {"https://facebook.com", "https://facebook.com", "https://facebook.com",
+ false},
+ {"", "", "", false},
+ {"", "", "https://facebook.com/", false},
+ {"https://facebook.com/", "https://facebook.com/", "", false},
+
+ {"federation://example.com/google.com", "https://example.com/p1",
+ "https://example.com/p2", true},
+ {"federation://example.com/google.com", "https://example.com/",
+ "http://example.com/", false},
+ {"federation://example.com/google.com", "https://example.com/",
+ "example.com", false},
+ {"federation://example.com/", "https://example.com/",
+ "https://example.com/", false},
+ {"federation://example.com/google.com", "https://example.com/", "example",
+ false},
+
+ {"federation://sub.example.com/google.com", "https://sub.example.com/p1",
+ "https://sub.example.com/p2", true},
+ {"federation://sub.example.com/google.com", "https://sub.example.com/p1",
+ "https://sub2.example.com/p2", true},
+ {"federation://example.com/google.com", "https://example.com/p1",
+ "https://sub.example.com/", true},
+ {"federation://example.com/google.com", "https://example.com/",
+ "http://sub.example.com/", false},
+ {"federation://sub.example.com/", "https://sub.example.com/",
+ "https://sub.example.com/", false},
+
+ {"federation://localhost/google.com", "http://localhost/",
+ "http://localhost/", true},
+ {"federation://localhost/google.com", "http://localhost:8000/",
+ "http://localhost:8000/", true},
+ {"federation://localhost/google.com", "http://localhost:8000/",
+ "http://localhost/", false},
+ {"federation://localhost/google.com", "http://localhost/",
+ "http://localhost:8000/", false},
};
for (const TestPair& pair : pairs) {
- std::string signon_realm = pair.signon_realm;
- GURL origin(pair.origin);
- EXPECT_EQ(pair.should_match, IsFederatedPSLMatch(signon_realm, origin))
- << "signon_realm = " << pair.signon_realm
- << ", origin = " << pair.origin;
+ EXPECT_EQ(pair.should_match,
+ IsFederatedPSLMatch(pair.form_signon_realm,
+ GURL(pair.form_origin), GURL(pair.origin)))
+ << "form_signon_realm = " << pair.form_signon_realm
+ << "form_origin = " << pair.form_origin << ", origin = " << pair.origin;
}
}
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 4ef0f8d23e7..c4c9658ea66 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
@@ -17,7 +17,6 @@ StubPasswordManagerClient::~StubPasswordManagerClient() {}
bool StubPasswordManagerClient::PromptUserToSaveOrUpdatePassword(
std::unique_ptr<PasswordFormManager> form_to_save,
- password_manager::CredentialSourceType type,
bool update_password) {
return false;
}
@@ -65,4 +64,11 @@ const LogManager* StubPasswordManagerClient::GetLogManager() const {
return &log_manager_;
}
+#if defined(SAFE_BROWSING_DB_LOCAL)
+safe_browsing::PasswordProtectionService*
+StubPasswordManagerClient::GetPasswordProtectionService() const {
+ return nullptr;
+}
+#endif
+
} // namespace password_manager
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 c25fea9cf12..a7a6b49588c 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
@@ -23,7 +23,6 @@ class StubPasswordManagerClient : public PasswordManagerClient {
// PasswordManagerClient:
bool PromptUserToSaveOrUpdatePassword(
std::unique_ptr<PasswordFormManager> form_to_save,
- password_manager::CredentialSourceType type,
bool update_password) override;
bool PromptUserToChooseCredentials(
std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
@@ -44,6 +43,10 @@ class StubPasswordManagerClient : public PasswordManagerClient {
const GURL& GetLastCommittedEntryURL() const override;
const CredentialsFilter* GetStoreResultFilter() const override;
const LogManager* GetLogManager() const override;
+#if defined(SAFE_BROWSING_DB_LOCAL)
+ safe_browsing::PasswordProtectionService* GetPasswordProtectionService()
+ const override;
+#endif
private:
const StubCredentialsFilter credentials_filter_;
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 efd3aecd98e..6ab4b775e25 100644
--- a/chromium/components/password_manager/core/browser/test_password_store.cc
+++ b/chromium/components/password_manager/core/browser/test_password_store.cc
@@ -86,17 +86,26 @@ std::vector<std::unique_ptr<autofill::PasswordForm>>
TestPasswordStore::FillMatchingLogins(const FormDigest& form) {
std::vector<std::unique_ptr<autofill::PasswordForm>> matched_forms;
for (const auto& elements : stored_passwords_) {
+ // The code below doesn't support PSL federated credential. It's doable but
+ // no test need it so far.
const bool realm_matches = elements.first == form.signon_realm;
const bool realm_psl_matches =
IsPublicSuffixDomainMatch(elements.first, form.signon_realm);
if (realm_matches || realm_psl_matches ||
(form.scheme == autofill::PasswordForm::SCHEME_HTML &&
- password_manager::IsFederatedMatch(elements.first, form.origin))) {
+ password_manager::IsFederatedRealm(elements.first, form.origin))) {
const bool is_psl = !realm_matches && realm_psl_matches;
for (const auto& stored_form : elements.second) {
- matched_forms.push_back(
- base::MakeUnique<autofill::PasswordForm>(stored_form));
- matched_forms.back()->is_public_suffix_match = is_psl;
+ // Repeat the condition above with an additional check for origin.
+ if (realm_matches || realm_psl_matches ||
+ (form.scheme == autofill::PasswordForm::SCHEME_HTML &&
+ stored_form.origin.GetOrigin() == form.origin.GetOrigin() &&
+ password_manager::IsFederatedRealm(stored_form.signon_realm,
+ form.origin))) {
+ matched_forms.push_back(
+ base::MakeUnique<autofill::PasswordForm>(stored_form));
+ matched_forms.back()->is_public_suffix_match = is_psl;
+ }
}
}
}
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 f990b37ae13..fd70a41fe4b 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
@@ -30,6 +30,9 @@ const char kPasswordManagerSavingEnabled[] = "profile.password_manager_enabled";
const char kWasAutoSignInFirstRunExperienceShown[] =
"profile.was_auto_sign_in_first_run_experience_shown";
+const char kWasObsoleteHttpDataCleaned[] =
+ "profile.was_obsolete_http_data_cleaned";
+
const char kWasSignInPasswordPromoClicked[] =
"profile.was_sign_in_password_promo_clicked";
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 c0d92f321af..dba5fb451e4 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
@@ -59,6 +59,9 @@ extern const char kPasswordManagerSavingEnabled[];
// prompt was shown or not.
extern const char kWasAutoSignInFirstRunExperienceShown[];
+// Boolean that indicated if obsolete HTTP data has been cleaned in the past.
+extern const char kWasObsoleteHttpDataCleaned[];
+
// Boolean that indicated if user interacted with the Chrome Sign in promo.
extern const char kWasSignInPasswordPromoClicked[];
diff --git a/chromium/components/password_manager/sync/browser/password_model_worker.cc b/chromium/components/password_manager/sync/browser/password_model_worker.cc
index 81fb889b3b5..997a0b1cbe1 100644
--- a/chromium/components/password_manager/sync/browser/password_model_worker.cc
+++ b/chromium/components/password_manager/sync/browser/password_model_worker.cc
@@ -4,60 +4,18 @@
#include "components/password_manager/sync/browser/password_model_worker.h"
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/synchronization/waitable_event.h"
+#include <utility>
+
#include "components/password_manager/core/browser/password_store.h"
-#include "components/sync/base/scoped_event_signal.h"
namespace browser_sync {
-namespace {
-
-void CallDoWorkAndSignalEvent(const syncer::WorkCallback& work,
- syncer::ScopedEventSignal scoped_event_signal,
- syncer::SyncerError* error_info) {
- *error_info = work.Run();
- // The event in |scoped_event_signal| is signaled at the end of this scope.
-}
-
-} // namespace
-
PasswordModelWorker::PasswordModelWorker(
const scoped_refptr<password_manager::PasswordStore>& password_store)
: password_store_(password_store) {
DCHECK(password_store.get());
}
-syncer::SyncerError PasswordModelWorker::DoWorkAndWaitUntilDoneImpl(
- const syncer::WorkCallback& work) {
- syncer::SyncerError error = syncer::UNSET;
-
- // Signaled when the task is deleted, i.e. after it runs or when it is
- // abandoned.
- base::WaitableEvent work_done_or_abandoned(
- base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- bool scheduled = false;
- {
- base::AutoLock lock(password_store_lock_);
- if (!password_store_.get())
- return syncer::CANNOT_DO_WORK;
-
- scheduled = password_store_->ScheduleTask(base::Bind(
- &CallDoWorkAndSignalEvent, work,
- base::Passed(syncer::ScopedEventSignal(&work_done_or_abandoned)),
- &error));
- }
-
- if (scheduled)
- work_done_or_abandoned.Wait();
- else
- error = syncer::CANNOT_DO_WORK;
- return error;
-}
-
syncer::ModelSafeGroup PasswordModelWorker::GetModelSafeGroup() {
return syncer::GROUP_PASSWORD;
}
@@ -71,6 +29,15 @@ bool PasswordModelWorker::IsOnModelThread() {
PasswordModelWorker::~PasswordModelWorker() {}
+void PasswordModelWorker::ScheduleWork(base::OnceClosure work) {
+ base::AutoLock lock(password_store_lock_);
+ if (password_store_) {
+ password_store_->ScheduleTask(
+ base::Bind([](base::OnceClosure work) { std::move(work).Run(); },
+ base::Passed(std::move(work))));
+ }
+}
+
void PasswordModelWorker::RequestStop() {
ModelSafeWorker::RequestStop();
diff --git a/chromium/components/password_manager/sync/browser/password_model_worker.h b/chromium/components/password_manager/sync/browser/password_model_worker.h
index eb45efc7e31..08405739119 100644
--- a/chromium/components/password_manager/sync/browser/password_model_worker.h
+++ b/chromium/components/password_manager/sync/browser/password_model_worker.h
@@ -28,13 +28,11 @@ class PasswordModelWorker : public syncer::ModelSafeWorker {
bool IsOnModelThread() override;
void RequestStop() override;
- protected:
- syncer::SyncerError DoWorkAndWaitUntilDoneImpl(
- const syncer::WorkCallback& work) override;
-
private:
~PasswordModelWorker() override;
+ void ScheduleWork(base::OnceClosure work) override;
+
// |password_store_| is used on password thread but released on UI thread.
// Protected by |password_store_lock_|.
base::Lock password_store_lock_;
diff --git a/chromium/components/payments/DEPS b/chromium/components/payments/DEPS
new file mode 100644
index 00000000000..90053c98a42
--- /dev/null
+++ b/chromium/components/payments/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "-base/json/json_reader.h",
+]
diff --git a/chromium/components/payments/README b/chromium/components/payments/README
new file mode 100644
index 00000000000..414314a4874
--- /dev/null
+++ b/chromium/components/payments/README
@@ -0,0 +1,35 @@
+This directory contains shared code used by multiple platforms' native
+implementations of PaymentRequest. In general, business logic (i.e., logic which
+manipulates data and is not specific to any particular platform's display of the
+data) should live here as much as possible.
+
+
+Internally, the directory uses the Layered Components model:
+
+http://www.chromium.org/developers/design-documents/layered-components-design
+
+
+In practical terms, our division between content/ and core/ is usually just a
+question of whether the contents have a dependency on Mojo:
+
+* ./core/ -- preferred whenever possible
+
+* ./content/ -- code with a Mojo dependency
+
+* ./content/android/ -- Android bindings for code in either core/ or content/
+
+
+Intended consumers of this code are organized as follows:
+
+* chrome/android/.../chrome/browser/payments/ -- Android UI Implementation
+
+* chrome/browser/ui/views/payments/ -- Desktop UI implementation
+
+* content/browser/android/payments -- Android bindings for PaymentApps
+
+* content/browser/payments/ -- PaymentApps implementation
+
+* ios/chrome/browser/payments/ -- iOS UI implementation
+
+* ios/web/payments/ and ios/web/public/payments/ -- iOS communication layer,
+ replacing Mojo
diff --git a/chromium/components/payments/android/BUILD.gn b/chromium/components/payments/android/BUILD.gn
new file mode 100644
index 00000000000..fc5fe8b95a7
--- /dev/null
+++ b/chromium/components/payments/android/BUILD.gn
@@ -0,0 +1,32 @@
+# 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.
+
+static_library("android") {
+ sources = [
+ "payment_method_manifest_table.cc",
+ "payment_method_manifest_table.h",
+ "web_app_manifest_section_table.cc",
+ "web_app_manifest_section_table.h",
+ ]
+
+ deps = [
+ "//components/payments/content:mojom_parser",
+ "//components/webdata/common",
+ "//sql",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "payment_method_manifest_table_unittest.cc",
+ "web_app_manifest_section_table_unittest.cc",
+ ]
+
+ deps = [
+ ":android",
+ "//base",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/payments/android/DEPS b/chromium/components/payments/android/DEPS
new file mode 100644
index 00000000000..0d58d2feb26
--- /dev/null
+++ b/chromium/components/payments/android/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+components/payments/content",
+ "+components/webdata/common",
+ "+sql",
+] \ No newline at end of file
diff --git a/chromium/components/payments/android/payment_method_manifest_table.cc b/chromium/components/payments/android/payment_method_manifest_table.cc
new file mode 100644
index 00000000000..8e7ac7f3d86
--- /dev/null
+++ b/chromium/components/payments/android/payment_method_manifest_table.cc
@@ -0,0 +1,102 @@
+// 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/payments/android/payment_method_manifest_table.h"
+
+#include "sql/statement.h"
+#include "sql/transaction.h"
+
+namespace payments {
+namespace {
+WebDatabaseTable::TypeKey GetKey() {
+ // We just need a unique constant. Use the address of a static that
+ // COMDAT folding won't touch in an optimizing linker.
+ static int table_key = 0;
+ return reinterpret_cast<void*>(&table_key);
+}
+}
+
+PaymentMethodManifestTable::PaymentMethodManifestTable() {}
+
+PaymentMethodManifestTable::~PaymentMethodManifestTable() {}
+
+PaymentMethodManifestTable* PaymentMethodManifestTable::FromWebDatabase(
+ WebDatabase* db) {
+ return static_cast<PaymentMethodManifestTable*>(db->GetTable(GetKey()));
+}
+
+WebDatabaseTable::TypeKey PaymentMethodManifestTable::GetTypeKey() const {
+ return GetKey();
+}
+
+bool PaymentMethodManifestTable::CreateTablesIfNecessary() {
+ if (!db_->Execute("CREATE TABLE IF NOT EXISTS payment_method_manifest ( "
+ "method_name VARCHAR, "
+ "web_app_id VARCHAR) ")) {
+ NOTREACHED();
+ return false;
+ }
+
+ return true;
+}
+
+bool PaymentMethodManifestTable::IsSyncable() {
+ return false;
+}
+
+bool PaymentMethodManifestTable::MigrateToVersion(
+ int version,
+ bool* update_compatible_version) {
+ return true;
+}
+
+bool PaymentMethodManifestTable::AddManifest(
+ const std::string& payment_method,
+ const std::vector<std::string>& web_app_ids) {
+ sql::Transaction transaction(db_);
+ if (!transaction.Begin())
+ return false;
+
+ sql::Statement s1(db_->GetUniqueStatement(
+ "DELETE FROM payment_method_manifest WHERE method_name=? "));
+ s1.BindString(0, payment_method);
+ if (!s1.Run())
+ return false;
+
+ sql::Statement s2(
+ db_->GetUniqueStatement("INSERT INTO payment_method_manifest "
+ "(method_name, web_app_id) "
+ "VALUES (?, ?) "));
+ for (const auto& id : web_app_ids) {
+ int index = 0;
+ s2.BindString(index++, payment_method);
+ s2.BindString(index, id);
+ if (!s2.Run())
+ return false;
+ s2.Reset(true);
+ }
+
+ if (!transaction.Commit())
+ return false;
+
+ return true;
+}
+
+std::vector<std::string> PaymentMethodManifestTable::GetManifest(
+ const std::string& payment_method) {
+ std::vector<std::string> web_app_ids;
+ sql::Statement s(
+ db_->GetUniqueStatement("SELECT web_app_id "
+ "FROM payment_method_manifest "
+ "WHERE method_name=?"));
+ s.BindString(0, payment_method);
+
+ while (s.Step()) {
+ web_app_ids.emplace_back(s.ColumnString(0));
+ }
+
+ return web_app_ids;
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/android/payment_method_manifest_table.h b/chromium/components/payments/android/payment_method_manifest_table.h
new file mode 100644
index 00000000000..0e1f5ef9c88
--- /dev/null
+++ b/chromium/components/payments/android/payment_method_manifest_table.h
@@ -0,0 +1,56 @@
+// 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_PAYMENTS_ANDROID_PAYMENT_METHOD_MANIFEST_TABLE_H_
+#define COMPONENTS_PAYMENTS_ANDROID_PAYMENT_METHOD_MANIFEST_TABLE_H_
+
+#include <string>
+#include <vector>
+
+#include "components/webdata/common/web_database.h"
+#include "components/webdata/common/web_database_table.h"
+
+namespace payments {
+
+// This class manages payment_method_manifest table in SQLite database. It
+// expects the following schema.
+//
+// payment_method_manifest The table stores WebAppManifestSection.id of the
+// supported web app in this payment method manifest.
+// Note that a payment method manifest might contain
+// multiple supported web apps ids.
+// method_name The method name.
+// web_app_id The supported web app id.
+// (WebAppManifestSection.id).
+//
+class PaymentMethodManifestTable : public WebDatabaseTable {
+ public:
+ PaymentMethodManifestTable();
+ ~PaymentMethodManifestTable() override;
+
+ // Retrieves the PaymentMethodManifestTable* owned by |db|.
+ static PaymentMethodManifestTable* FromWebDatabase(WebDatabase* db);
+
+ // WebDatabaseTable:
+ WebDatabaseTable::TypeKey GetTypeKey() const override;
+ bool CreateTablesIfNecessary() override;
+ bool IsSyncable() override;
+ bool MigrateToVersion(int version, bool* update_compatible_version) override;
+
+ // Adds |payment_method|'s manifest. |web_app_ids| contains supported web apps
+ // ids.
+ bool AddManifest(const std::string& payment_method,
+ const std::vector<std::string>& web_app_ids);
+
+ // Gets manifest for |payment_method|. Return empty vector if no manifest
+ // exists for this method.
+ std::vector<std::string> GetManifest(const std::string& payment_method);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PaymentMethodManifestTable);
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_ANDROID_PAYMENT_METHOD_MANIFEST_TABLE_H_ \ No newline at end of file
diff --git a/chromium/components/payments/android/payment_method_manifest_table_unittest.cc b/chromium/components/payments/android/payment_method_manifest_table_unittest.cc
new file mode 100644
index 00000000000..fb407c5b372
--- /dev/null
+++ b/chromium/components/payments/android/payment_method_manifest_table_unittest.cc
@@ -0,0 +1,126 @@
+// 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/payments/android/payment_method_manifest_table.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+namespace {
+
+class PaymentMethodManifestTableTest : public testing::Test {
+ public:
+ PaymentMethodManifestTableTest() {}
+ ~PaymentMethodManifestTableTest() override {}
+
+ protected:
+ void SetUp() override {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ file_ = temp_dir_.GetPath().AppendASCII("TestWebDatabase");
+
+ table_.reset(new PaymentMethodManifestTable);
+ db_.reset(new WebDatabase);
+ db_->AddTable(table_.get());
+ ASSERT_EQ(sql::INIT_OK, db_->Init(file_));
+ }
+
+ void TearDown() override {}
+
+ base::FilePath file_;
+ base::ScopedTempDir temp_dir_;
+ std::unique_ptr<PaymentMethodManifestTable> table_;
+ std::unique_ptr<WebDatabase> db_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PaymentMethodManifestTableTest);
+};
+
+TEST_F(PaymentMethodManifestTableTest, GetNonExistManifest) {
+ PaymentMethodManifestTable* payment_method_manifest_table =
+ PaymentMethodManifestTable::FromWebDatabase(db_.get());
+ std::vector<std::string> web_app_ids =
+ payment_method_manifest_table->GetManifest("https://bobpay.com");
+ ASSERT_TRUE(web_app_ids.empty());
+}
+
+TEST_F(PaymentMethodManifestTableTest, AddAndGetSingleManifest) {
+ PaymentMethodManifestTable* payment_method_manifest_table =
+ PaymentMethodManifestTable::FromWebDatabase(db_.get());
+
+ std::string method_name("https://bobpay.com");
+ std::vector<std::string> web_app_ids = {"com.bobpay"};
+ ASSERT_TRUE(
+ payment_method_manifest_table->AddManifest(method_name, web_app_ids));
+
+ std::vector<std::string> retrieved_web_app_ids =
+ payment_method_manifest_table->GetManifest(method_name);
+ ASSERT_EQ(web_app_ids.size(), retrieved_web_app_ids.size());
+ ASSERT_EQ(web_app_ids[0], retrieved_web_app_ids[0]);
+
+ web_app_ids.emplace_back("com.alicepay");
+ ASSERT_TRUE(
+ payment_method_manifest_table->AddManifest(method_name, web_app_ids));
+
+ retrieved_web_app_ids =
+ payment_method_manifest_table->GetManifest("https://bobpay.com");
+ ASSERT_EQ(web_app_ids.size(), retrieved_web_app_ids.size());
+ ASSERT_TRUE(std::find(retrieved_web_app_ids.begin(),
+ retrieved_web_app_ids.end(),
+ web_app_ids[0]) != retrieved_web_app_ids.end());
+ ASSERT_TRUE(std::find(retrieved_web_app_ids.begin(),
+ retrieved_web_app_ids.end(),
+ web_app_ids[1]) != retrieved_web_app_ids.end());
+}
+
+TEST_F(PaymentMethodManifestTableTest, AddAndGetMultipleManifest) {
+ PaymentMethodManifestTable* payment_method_manifest_table =
+ PaymentMethodManifestTable::FromWebDatabase(db_.get());
+
+ std::string method_name_1("https://bobpay.com");
+ std::string method_name_2("https://alicepay.com");
+ std::vector<std::string> web_app_ids = {"com.bobpay"};
+ ASSERT_TRUE(
+ payment_method_manifest_table->AddManifest(method_name_1, web_app_ids));
+ ASSERT_TRUE(
+ payment_method_manifest_table->AddManifest(method_name_2, web_app_ids));
+
+ std::vector<std::string> bobpay_web_app_ids =
+ payment_method_manifest_table->GetManifest(method_name_1);
+ ASSERT_EQ(web_app_ids.size(), bobpay_web_app_ids.size());
+ ASSERT_EQ(web_app_ids[0], bobpay_web_app_ids[0]);
+
+ std::vector<std::string> alicepay_web_app_ids =
+ payment_method_manifest_table->GetManifest(method_name_2);
+ ASSERT_EQ(web_app_ids.size(), alicepay_web_app_ids.size());
+ ASSERT_EQ(web_app_ids[0], alicepay_web_app_ids[0]);
+
+ web_app_ids.emplace_back("com.alicepay");
+ ASSERT_TRUE(
+ payment_method_manifest_table->AddManifest(method_name_1, web_app_ids));
+ ASSERT_TRUE(
+ payment_method_manifest_table->AddManifest(method_name_2, web_app_ids));
+
+ bobpay_web_app_ids =
+ payment_method_manifest_table->GetManifest(method_name_1);
+ ASSERT_EQ(web_app_ids.size(), bobpay_web_app_ids.size());
+ ASSERT_TRUE(std::find(bobpay_web_app_ids.begin(), bobpay_web_app_ids.end(),
+ web_app_ids[0]) != bobpay_web_app_ids.end());
+ ASSERT_TRUE(std::find(bobpay_web_app_ids.begin(), bobpay_web_app_ids.end(),
+ web_app_ids[1]) != bobpay_web_app_ids.end());
+
+ alicepay_web_app_ids =
+ payment_method_manifest_table->GetManifest(method_name_1);
+ ASSERT_EQ(web_app_ids.size(), alicepay_web_app_ids.size());
+ ASSERT_TRUE(std::find(alicepay_web_app_ids.begin(),
+ alicepay_web_app_ids.end(),
+ web_app_ids[0]) != alicepay_web_app_ids.end());
+ ASSERT_TRUE(std::find(alicepay_web_app_ids.begin(),
+ alicepay_web_app_ids.end(),
+ web_app_ids[1]) != alicepay_web_app_ids.end());
+}
+
+} // namespace
+
+} // namespace payments
diff --git a/chromium/components/payments/android/web_app_manifest_section_table.cc b/chromium/components/payments/android/web_app_manifest_section_table.cc
new file mode 100644
index 00000000000..f7a06580fd8
--- /dev/null
+++ b/chromium/components/payments/android/web_app_manifest_section_table.cc
@@ -0,0 +1,144 @@
+// 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/payments/android/web_app_manifest_section_table.h"
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "sql/statement.h"
+
+namespace payments {
+namespace {
+
+// Note that the fingerprint is calculated with SHA-256.
+const size_t kFingerPrintLength = 32;
+
+WebDatabaseTable::TypeKey GetKey() {
+ // We just need a unique constant. Use the address of a static that
+ // COMDAT folding won't touch in an optimizing linker.
+ static int table_key = 0;
+ return reinterpret_cast<void*>(&table_key);
+}
+
+// Converts 2-dimensional vector |fingerprints| to 1-dimesional vector.
+std::unique_ptr<std::vector<uint8_t>> SerializeFingerPrints(
+ const std::vector<std::vector<uint8_t>>& fingerprints) {
+ auto serialized_fingerprints = base::MakeUnique<std::vector<uint8_t>>();
+
+ for (const auto& fingerprint : fingerprints) {
+ DCHECK_EQ(fingerprint.size(), kFingerPrintLength);
+ serialized_fingerprints->insert(serialized_fingerprints->end(),
+ fingerprint.begin(), fingerprint.end());
+ }
+
+ return serialized_fingerprints;
+}
+
+// Converts 1-dimensional vector created by SerializeFingerPrints back to
+// 2-dimensional vector. Each vector of the second dimensional vector has exact
+// kFingerPrintLength number of elements.
+bool DeserializeFingerPrints(
+ const std::vector<uint8_t>& fingerprints,
+ std::vector<std::vector<uint8_t>>& deserialized_fingerprints) {
+ if (fingerprints.size() % kFingerPrintLength != 0)
+ return false;
+
+ for (size_t i = 0; i < fingerprints.size(); i += kFingerPrintLength) {
+ deserialized_fingerprints.emplace_back(
+ fingerprints.begin() + i,
+ fingerprints.begin() + i + kFingerPrintLength);
+ }
+ return true;
+}
+
+} // namespace
+
+WebAppManifestSectionTable::WebAppManifestSectionTable() {}
+
+WebAppManifestSectionTable::~WebAppManifestSectionTable() {}
+
+WebAppManifestSectionTable* WebAppManifestSectionTable::FromWebDatabase(
+ WebDatabase* db) {
+ return static_cast<WebAppManifestSectionTable*>(db->GetTable(GetKey()));
+}
+
+WebDatabaseTable::TypeKey WebAppManifestSectionTable::GetTypeKey() const {
+ return GetKey();
+}
+
+bool WebAppManifestSectionTable::CreateTablesIfNecessary() {
+ if (!db_->Execute("CREATE TABLE IF NOT EXISTS web_app_manifest_section ( "
+ "id VARCHAR PRIMARY KEY, "
+ "min_version INTEGER NOT NULL DEFAULT 0, "
+ "fingerprints BLOB) ")) {
+ NOTREACHED();
+ return false;
+ }
+
+ return true;
+}
+
+bool WebAppManifestSectionTable::IsSyncable() {
+ return false;
+}
+
+bool WebAppManifestSectionTable::MigrateToVersion(
+ int version,
+ bool* update_compatible_version) {
+ return true;
+}
+
+bool WebAppManifestSectionTable::AddWebAppManifest(
+ mojom::WebAppManifestSection* manifest) {
+ DCHECK(manifest);
+ DCHECK(!manifest->id.empty());
+
+ sql::Statement s(
+ db_->GetUniqueStatement("INSERT OR REPLACE INTO web_app_manifest_section "
+ "(id, min_version, fingerprints) "
+ "VALUES (?, ?, ?)"));
+ int index = 0;
+ s.BindString(index++, manifest->id);
+ s.BindInt64(index++, manifest->min_version);
+ std::unique_ptr<std::vector<uint8_t>> serialized_fingerprints =
+ SerializeFingerPrints(manifest->fingerprints);
+ s.BindBlob(index, serialized_fingerprints->data(),
+ serialized_fingerprints->size());
+ if (!s.Run())
+ return false;
+
+ return true;
+}
+
+mojom::WebAppManifestSectionPtr WebAppManifestSectionTable::GetWebAppManifest(
+ const std::string& web_app) {
+ sql::Statement s(
+ db_->GetUniqueStatement("SELECT id, min_version, fingerprints "
+ "FROM web_app_manifest_section "
+ "WHERE id=?"));
+ s.BindString(0, web_app);
+
+ if (!s.Step())
+ return nullptr;
+
+ mojom::WebAppManifestSectionPtr manifest =
+ mojom::WebAppManifestSection::New();
+
+ int index = 0;
+ manifest->id = s.ColumnString(index++);
+ manifest->min_version = s.ColumnInt64(index++);
+
+ std::vector<uint8_t> fingerprints;
+ if (!s.ColumnBlobAsVector(index, &fingerprints))
+ return nullptr;
+
+ if (!DeserializeFingerPrints(fingerprints, manifest->fingerprints))
+ return nullptr;
+
+ return manifest;
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/android/web_app_manifest_section_table.h b/chromium/components/payments/android/web_app_manifest_section_table.h
new file mode 100644
index 00000000000..44a5c046a75
--- /dev/null
+++ b/chromium/components/payments/android/web_app_manifest_section_table.h
@@ -0,0 +1,57 @@
+// 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_PAYMENTS_ANDROID_WEB_APP_MANIFEST_SECTION_TABLE_H_
+#define COMPONENTS_PAYMENTS_ANDROID_WEB_APP_MANIFEST_SECTION_TABLE_H_
+
+#include <string>
+#include <vector>
+
+#include "components/payments/content/payment_manifest_parser.mojom.h"
+#include "components/webdata/common/web_database.h"
+#include "components/webdata/common/web_database_table.h"
+
+namespace payments {
+
+// This class manages web_app_manifest_section table in SQLite database. It
+// expects the following schema.
+// The interfaces should only be accessed on DB thread.
+//
+// web_app_manifest_section The table stores the contents in
+// WebAppManifestSection.
+//
+// id The package name of the app.
+// min_version Minimum version number of the app.
+// fingerprints The result of SHA256(signing certificate bytes) for
+// each certificate in the app.
+//
+class WebAppManifestSectionTable : public WebDatabaseTable {
+ public:
+ WebAppManifestSectionTable();
+ ~WebAppManifestSectionTable() override;
+
+ // Retrieves the WebAppManifestSectionTable* owned by |db|.
+ static WebAppManifestSectionTable* FromWebDatabase(WebDatabase* db);
+
+ // WebDatabaseTable:
+ WebDatabaseTable::TypeKey GetTypeKey() const override;
+ bool CreateTablesIfNecessary() override;
+ bool IsSyncable() override;
+ bool MigrateToVersion(int version, bool* update_compatible_version) override;
+
+ // Adds the web app |*manifest|. Note that the previous web app manifest will
+ // be deleted.
+ bool AddWebAppManifest(mojom::WebAppManifestSection* manifest);
+
+ // Gets manifest of the |web_app|. Returns nullptr if no manifest exists for
+ // the |web_app|.
+ mojom::WebAppManifestSectionPtr GetWebAppManifest(const std::string& web_app);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WebAppManifestSectionTable);
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_ANDROID_WEB_APP_MANIFEST_SECTION_TABLE_H_
diff --git a/chromium/components/payments/android/web_app_manifest_section_table_unittest.cc b/chromium/components/payments/android/web_app_manifest_section_table_unittest.cc
new file mode 100644
index 00000000000..900cb34589d
--- /dev/null
+++ b/chromium/components/payments/android/web_app_manifest_section_table_unittest.cc
@@ -0,0 +1,140 @@
+// 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/payments/android/web_app_manifest_section_table.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+namespace {
+
+class WebAppManifestSectionTableTest : public testing::Test {
+ public:
+ WebAppManifestSectionTableTest() {}
+ ~WebAppManifestSectionTableTest() override {}
+
+ protected:
+ void SetUp() override {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ file_ = temp_dir_.GetPath().AppendASCII("TestWebDatabase");
+
+ table_.reset(new WebAppManifestSectionTable);
+ db_.reset(new WebDatabase);
+ db_->AddTable(table_.get());
+ ASSERT_EQ(sql::INIT_OK, db_->Init(file_));
+ }
+
+ void TearDown() override {}
+
+ std::vector<uint8_t> GenerateFingerprint(uint8_t seed) {
+ std::vector<uint8_t> fingerprint;
+ // Note that the fingerprint is calculated with SHA-256, so the length is
+ // 32.
+ for (size_t i = 0; i < 32U; i++) {
+ fingerprint.push_back((seed + i) % 256U);
+ }
+ return fingerprint;
+ }
+
+ base::FilePath file_;
+ base::ScopedTempDir temp_dir_;
+ std::unique_ptr<WebAppManifestSectionTable> table_;
+ std::unique_ptr<WebDatabase> db_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WebAppManifestSectionTableTest);
+};
+
+TEST_F(WebAppManifestSectionTableTest, GetNonExistManifest) {
+ WebAppManifestSectionTable* web_app_manifest_section_table =
+ WebAppManifestSectionTable::FromWebDatabase(db_.get());
+ mojom::WebAppManifestSectionPtr retrieved_manifest =
+ web_app_manifest_section_table->GetWebAppManifest("https://bobpay.com");
+ ASSERT_TRUE(retrieved_manifest.get() == nullptr);
+}
+
+TEST_F(WebAppManifestSectionTableTest, AddAndGetManifest) {
+ std::vector<uint8_t> fingerprint_one = GenerateFingerprint(1);
+ std::vector<uint8_t> fingerprint_two = GenerateFingerprint(32);
+
+ // create a bobpay web app manifest.
+ mojom::WebAppManifestSectionPtr manifest =
+ mojom::WebAppManifestSection::New();
+ manifest->id = "com.bobpay";
+ manifest->min_version = static_cast<int64_t>(1);
+ manifest->fingerprints.push_back(fingerprint_one);
+ manifest->fingerprints.push_back(fingerprint_two);
+
+ // Adds the manifest to the table.
+ WebAppManifestSectionTable* web_app_manifest_section_table =
+ WebAppManifestSectionTable::FromWebDatabase(db_.get());
+ ASSERT_TRUE(
+ web_app_manifest_section_table->AddWebAppManifest(manifest.get()));
+
+ // Gets and verifys the manifest.
+ mojom::WebAppManifestSectionPtr retrieved_manifest =
+ web_app_manifest_section_table->GetWebAppManifest("com.bobpay");
+ ASSERT_EQ(retrieved_manifest->id, "com.bobpay");
+ ASSERT_EQ(retrieved_manifest->min_version, 1);
+ ASSERT_EQ(retrieved_manifest->fingerprints.size(), 2U);
+
+ // Verify the two fingerprints.
+ ASSERT_TRUE(retrieved_manifest->fingerprints[0] == fingerprint_one);
+ ASSERT_TRUE(retrieved_manifest->fingerprints[1] == fingerprint_two);
+}
+
+TEST_F(WebAppManifestSectionTableTest, AddAndGetMultipleManifests) {
+ std::vector<uint8_t> fingerprint_one = GenerateFingerprint(1);
+ std::vector<uint8_t> fingerprint_two = GenerateFingerprint(32);
+ std::vector<uint8_t> fingerprint_three = GenerateFingerprint(2);
+ std::vector<uint8_t> fingerprint_four = GenerateFingerprint(30);
+
+ WebAppManifestSectionTable* web_app_manifest_section_table =
+ WebAppManifestSectionTable::FromWebDatabase(db_.get());
+
+ // Adds bobpay manifest to the table.
+ mojom::WebAppManifestSectionPtr manifest_1 =
+ mojom::WebAppManifestSection::New();
+ manifest_1->id = "com.bobpay";
+ manifest_1->min_version = static_cast<int64_t>(1);
+ // Adds two finger prints.
+ manifest_1->fingerprints.push_back(fingerprint_one);
+ manifest_1->fingerprints.push_back(fingerprint_two);
+ ASSERT_TRUE(
+ web_app_manifest_section_table->AddWebAppManifest(manifest_1.get()));
+
+ // Adds alicepay manifest to the table.
+ mojom::WebAppManifestSectionPtr manifest_2 =
+ mojom::WebAppManifestSection::New();
+ manifest_2->id = "com.alicepay";
+ manifest_2->min_version = static_cast<int64_t>(2);
+ // Adds two finger prints.
+ manifest_2->fingerprints.push_back(fingerprint_three);
+ manifest_2->fingerprints.push_back(fingerprint_four);
+ ASSERT_TRUE(
+ web_app_manifest_section_table->AddWebAppManifest(manifest_2.get()));
+
+ // Verifys bobpay manifest.
+ mojom::WebAppManifestSectionPtr bobpay_manifest =
+ web_app_manifest_section_table->GetWebAppManifest("com.bobpay");
+ ASSERT_EQ(bobpay_manifest->id, "com.bobpay");
+ ASSERT_EQ(bobpay_manifest->min_version, 1);
+ ASSERT_EQ(bobpay_manifest->fingerprints.size(), 2U);
+ ASSERT_TRUE(bobpay_manifest->fingerprints[0] == fingerprint_one);
+ ASSERT_TRUE(bobpay_manifest->fingerprints[1] == fingerprint_two);
+
+ // Verifys alicepay manifest.
+ mojom::WebAppManifestSectionPtr alicepay_manifest =
+ web_app_manifest_section_table->GetWebAppManifest("com.alicepay");
+ ASSERT_EQ(alicepay_manifest->id, "com.alicepay");
+ ASSERT_EQ(alicepay_manifest->min_version, 2);
+ ASSERT_EQ(alicepay_manifest->fingerprints.size(), 2U);
+ ASSERT_TRUE(alicepay_manifest->fingerprints[0] == fingerprint_three);
+ ASSERT_TRUE(alicepay_manifest->fingerprints[1] == fingerprint_four);
+}
+
+} // namespace
+
+} // namespace payments
diff --git a/chromium/components/payments/content/BUILD.gn b/chromium/components/payments/content/BUILD.gn
index a6f75fe71c8..a20079996c5 100644
--- a/chromium/components/payments/content/BUILD.gn
+++ b/chromium/components/payments/content/BUILD.gn
@@ -4,62 +4,85 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("payment_request") {
+static_library("content") {
sources = [
- "payment_request.mojom",
+ "payment_request.cc",
+ "payment_request.h",
+ "payment_request_dialog.h",
+ "payment_request_spec.cc",
+ "payment_request_spec.h",
+ "payment_request_state.cc",
+ "payment_request_state.h",
+ "payment_request_web_contents_manager.cc",
+ "payment_request_web_contents_manager.h",
+ "payment_response_helper.cc",
+ "payment_response_helper.h",
]
- public_deps = [
- "//mojo/common:common_custom_types",
+ deps = [
+ ":mojom",
+ ":utils",
+ "//components/autofill/core/browser",
+ "//components/payments/core",
+ "//content/public/browser",
+ "//mojo/public/cpp/bindings",
+ "//third_party/libphonenumber",
]
}
-mojom("payment_app") {
+mojom("mojom") {
sources = [
- "payment_app.mojom",
+ "payment_request.mojom",
+ ]
+}
+
+mojom("mojom_parser") {
+ sources = [
+ "payment_manifest_parser.mojom",
]
public_deps = [
- ":payment_request",
- "//mojo/common:common_custom_types",
"//url/mojo:url_mojom_gurl",
]
}
-static_library("payment_request_impl") {
+mojom("mojom_payment_app") {
sources = [
- "payment_request.cc",
- "payment_request.h",
- "payment_request_delegate.h",
- "payment_request_dialog.h",
- "payment_request_web_contents_manager.cc",
- "payment_request_web_contents_manager.h",
+ "payment_app.mojom",
]
- deps = [
- ":payment_request",
- ":payment_validation",
- "//components/autofill/core/browser",
- "//components/payments/core",
- "//content/public/browser",
- "//mojo/public/cpp/bindings",
+ public_deps = [
+ ":mojom",
+ "//mojo/common:common_custom_types",
+ "//url/mojo:url_mojom_gurl",
]
}
-static_library("payment_validation") {
+static_library("utils") {
sources = [
"payment_details_validation.cc",
"payment_details_validation.h",
+ "payment_manifest_downloader.cc",
+ "payment_manifest_downloader.h",
+ "payment_manifest_parser_host.cc",
+ "payment_manifest_parser_host.h",
"payments_validators.cc",
"payments_validators.h",
]
deps = [
- ":payment_request",
+ ":mojom",
+ ":mojom_parser",
"//base",
"//components/autofill/core/browser",
+ "//components/data_use_measurement/core",
+ "//components/link_header_util",
"//components/payments/core",
+ "//components/strings",
+ "//content/public/browser",
+ "//net",
"//third_party/re2",
+ "//ui/base",
"//url",
]
@@ -72,14 +95,24 @@ static_library("payment_validation") {
source_set("unit_tests") {
testonly = true
sources = [
- "payments_validators_test.cc",
+ "payment_manifest_downloader_unittest.cc",
+ "payment_request_spec_unittest.cc",
+ "payment_request_state_unittest.cc",
+ "payment_response_helper_unittest.cc",
+ "payments_validators_unittest.cc",
]
deps = [
- ":payment_validation",
+ ":content",
+ ":mojom",
+ ":utils",
"//base",
"//base/test:test_support",
"//components/autofill/core/browser",
+ "//components/autofill/core/browser:test_support",
+ "//components/payments/core",
+ "//content/test:test_support",
+ "//net:test_support",
"//testing/gtest",
"//third_party/icu",
"//third_party/libaddressinput:test_support",
diff --git a/chromium/components/payments/content/DEPS b/chromium/components/payments/content/DEPS
index ec8a11647d6..548a1642252 100644
--- a/chromium/components/payments/content/DEPS
+++ b/chromium/components/payments/content/DEPS
@@ -1,6 +1,14 @@
include_rules = [
+ "-components/payments/content/android",
+ "-components/payments/content/utility",
"+components/autofill",
- "+content/public/browser",
+ "+components/data_use_measurement",
+ "+components/link_header_util",
+ "+components/strings",
+ "+content/public",
"+mojo/public/cpp",
+ "+net",
+ "+third_party/libphonenumber",
"+third_party/re2",
+ "+ui/base",
]
diff --git a/chromium/components/payments/content/android/BUILD.gn b/chromium/components/payments/content/android/BUILD.gn
index 8dafb9b75d6..609224f1487 100644
--- a/chromium/components/payments/content/android/BUILD.gn
+++ b/chromium/components/payments/content/android/BUILD.gn
@@ -4,27 +4,54 @@
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
static_library("android") {
sources = [
+ "component_jni_registrar.cc",
+ "component_jni_registrar.h",
"currency_formatter_android.cc",
"currency_formatter_android.h",
"payment_details_validation_android.cc",
"payment_details_validation_android.h",
+ "payment_manifest_downloader_android.cc",
+ "payment_manifest_downloader_android.h",
+ "payment_manifest_parser_android.cc",
+ "payment_manifest_parser_android.h",
]
deps = [
":jni_headers",
"//base",
- "//components/payments/content:payment_request",
- "//components/payments/content:payment_validation",
+ "//components/payments/content:mojom",
+ "//components/payments/content:utils",
"//components/payments/core",
+ "//content/public/browser",
+ "//net",
]
}
generate_jni("jni_headers") {
sources = [
- "//chrome/android/java/src/org/chromium/chrome/browser/payments/CurrencyFormatter.java",
- "//chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentValidator.java",
+ "java/src/org/chromium/components/payments/CurrencyFormatter.java",
+ "java/src/org/chromium/components/payments/PaymentManifestDownloader.java",
+ "java/src/org/chromium/components/payments/PaymentManifestParser.java",
+ "java/src/org/chromium/components/payments/PaymentValidator.java",
]
jni_package = "payments"
}
+
+android_library("java") {
+ java_files = [
+ "java/src/org/chromium/components/payments/CurrencyFormatter.java",
+ "java/src/org/chromium/components/payments/PaymentManifestDownloader.java",
+ "java/src/org/chromium/components/payments/PaymentManifestParser.java",
+ "java/src/org/chromium/components/payments/PaymentValidator.java",
+ ]
+ deps = [
+ "//base:base_java",
+ "//components/payments/content:mojom_java",
+ "//components/payments/content:mojom_parser_java",
+ "//content/public/android:content_java",
+ "//mojo/public/java:bindings_java",
+ ]
+}
diff --git a/chromium/components/payments/content/android/OWNERS b/chromium/components/payments/content/android/OWNERS
new file mode 100644
index 00000000000..08850f42120
--- /dev/null
+++ b/chromium/components/payments/content/android/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/payments/content/android/currency_formatter_android.cc b/chromium/components/payments/content/android/currency_formatter_android.cc
index 0ea0f912033..3b3694e5c3d 100644
--- a/chromium/components/payments/content/android/currency_formatter_android.cc
+++ b/chromium/components/payments/content/android/currency_formatter_android.cc
@@ -19,7 +19,7 @@ using ::base::android::ConvertJavaStringToUTF8;
CurrencyFormatterAndroid::CurrencyFormatterAndroid(
JNIEnv* env,
- jobject unused_obj,
+ jobject jcaller,
const JavaParamRef<jstring>& currency_code,
const JavaParamRef<jstring>& currency_system,
const JavaParamRef<jstring>& locale_name) {
@@ -34,13 +34,13 @@ CurrencyFormatterAndroid::CurrencyFormatterAndroid(
CurrencyFormatterAndroid::~CurrencyFormatterAndroid() {}
void CurrencyFormatterAndroid::Destroy(JNIEnv* env,
- const JavaParamRef<jobject>& obj) {
+ const JavaParamRef<jobject>& jcaller) {
delete this;
}
base::android::ScopedJavaLocalRef<jstring> CurrencyFormatterAndroid::Format(
JNIEnv* env,
- const JavaParamRef<jobject>& unused_obj,
+ const JavaParamRef<jobject>& jcaller,
const JavaParamRef<jstring>& amount) {
base::string16 result =
currency_formatter_->Format(ConvertJavaStringToUTF8(env, amount));
diff --git a/chromium/components/payments/content/android/currency_formatter_android.h b/chromium/components/payments/content/android/currency_formatter_android.h
index 9693c200b83..7249e14d2c5 100644
--- a/chromium/components/payments/content/android/currency_formatter_android.h
+++ b/chromium/components/payments/content/android/currency_formatter_android.h
@@ -18,29 +18,30 @@ class CurrencyFormatter;
// Forwarding calls to payments::CurrencyFormatter.
class CurrencyFormatterAndroid {
public:
+ // Registers the JNI bindings for this class.
+ static bool Register(JNIEnv* env);
+
CurrencyFormatterAndroid(
JNIEnv* env,
- jobject unused_obj,
+ jobject jcaller,
const base::android::JavaParamRef<jstring>& currency_code,
const base::android::JavaParamRef<jstring>& currency_system,
const base::android::JavaParamRef<jstring>& locale_name);
~CurrencyFormatterAndroid();
// Message from Java to destroy this object.
- void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+ void Destroy(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller);
// Refer to CurrencyFormatter::Format documentation.
base::android::ScopedJavaLocalRef<jstring> Format(
JNIEnv* env,
- const base::android::JavaParamRef<jobject>& unused_obj,
+ const base::android::JavaParamRef<jobject>& jcaller,
const base::android::JavaParamRef<jstring>& amount);
base::android::ScopedJavaLocalRef<jstring> GetFormattedCurrencyCode(
JNIEnv* env,
- const base::android::JavaParamRef<jobject>& unused_obj);
-
- // Registers the JNI bindings for this class.
- static bool Register(JNIEnv* env);
+ const base::android::JavaParamRef<jobject>& jcaller);
private:
std::unique_ptr<CurrencyFormatter> currency_formatter_;
diff --git a/chromium/components/payments/content/android/payment_details_validation_android.cc b/chromium/components/payments/content/android/payment_details_validation_android.cc
index 072dda083a4..ddc7ffc4951 100644
--- a/chromium/components/payments/content/android/payment_details_validation_android.cc
+++ b/chromium/components/payments/content/android/payment_details_validation_android.cc
@@ -4,9 +4,14 @@
#include "components/payments/content/android/payment_details_validation_android.h"
+#include <stdint.h>
+
+#include <cstring>
#include <string>
#include <utility>
+#include <vector>
+#include "base/android/jni_android.h"
#include "components/payments/content/payment_details_validation.h"
#include "components/payments/content/payment_request.mojom.h"
#include "jni/PaymentValidator_jni.h"
@@ -25,11 +30,11 @@ jboolean ValidatePaymentDetails(
if (!mojom::PaymentDetails::Deserialize(std::move(mojo_buffer), &details))
return false;
std::string unused_error_message;
- return payments::validatePaymentDetails(details, &unused_error_message);
+ return validatePaymentDetails(details, &unused_error_message);
}
-} // namespace payments
-
bool RegisterPaymentValidator(JNIEnv* env) {
- return payments::RegisterNativesImpl(env);
+ return RegisterNativesImpl(env);
}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/android/payment_details_validation_android.h b/chromium/components/payments/content/android/payment_details_validation_android.h
index 88367ae1e8e..1ff1d6a9bb4 100644
--- a/chromium/components/payments/content/android/payment_details_validation_android.h
+++ b/chromium/components/payments/content/android/payment_details_validation_android.h
@@ -7,6 +7,10 @@
#include <jni.h>
+namespace payments {
+
bool RegisterPaymentValidator(JNIEnv* env);
+} // namespace payments
+
#endif // COMPONENTS_PAYMENTS_CONTENT_ANDROID_PAYMENT_DETAILS_VALIDATION_ANDROID_H_
diff --git a/chromium/components/payments/content/android/payment_manifest_downloader_android.cc b/chromium/components/payments/content/android/payment_manifest_downloader_android.cc
new file mode 100644
index 00000000000..41241e05b9a
--- /dev/null
+++ b/chromium/components/payments/content/android/payment_manifest_downloader_android.cc
@@ -0,0 +1,140 @@
+// 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/payments/content/android/payment_manifest_downloader_android.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "components/payments/content/payment_manifest_downloader.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_contents.h"
+#include "jni/PaymentManifestDownloader_jni.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "url/gurl.h"
+#include "url/url_constants.h"
+
+namespace payments {
+namespace {
+
+class SelfDeletingDownloadDelegate
+ : public PaymentManifestDownloader::Delegate {
+ public:
+ explicit SelfDeletingDownloadDelegate(
+ const base::android::JavaParamRef<jobject>& jcallback)
+ : jcallback_(jcallback), is_downloading_payment_method_manifest_(true) {}
+
+ void set_downloader(std::unique_ptr<PaymentManifestDownloader> downloader) {
+ downloader_ = std::move(downloader);
+ }
+
+ void DownloadPaymentMethodManifest() {
+ is_downloading_payment_method_manifest_ = true;
+ downloader_->DownloadPaymentMethodManifest();
+ }
+
+ void DownloadWebAppManifest() {
+ is_downloading_payment_method_manifest_ = false;
+ downloader_->DownloadWebAppManifest();
+ }
+
+ // PaymentManifestDownloader::Delegate
+ void OnManifestDownloadSuccess(const std::string& content) override {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ if (is_downloading_payment_method_manifest_) {
+ Java_ManifestDownloadCallback_onPaymentMethodManifestDownloadSuccess(
+ env, jcallback_,
+ base::android::ConvertUTF8ToJavaString(env, content));
+ } else {
+ Java_ManifestDownloadCallback_onWebAppManifestDownloadSuccess(
+ env, jcallback_,
+ base::android::ConvertUTF8ToJavaString(env, content));
+ }
+ delete this;
+ }
+
+ // PaymentManifestDownloader::Delegate
+ void OnManifestDownloadFailure() override {
+ Java_ManifestDownloadCallback_onManifestDownloadFailure(
+ base::android::AttachCurrentThread(), jcallback_);
+ delete this;
+ }
+
+ private:
+ ~SelfDeletingDownloadDelegate() override {}
+
+ base::android::ScopedJavaGlobalRef<jobject> jcallback_;
+ bool is_downloading_payment_method_manifest_;
+ std::unique_ptr<PaymentManifestDownloader> downloader_;
+
+ DISALLOW_COPY_AND_ASSIGN(SelfDeletingDownloadDelegate);
+};
+
+SelfDeletingDownloadDelegate* BuildSelfDeletingDownloadDelegate(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jweb_contents,
+ const base::android::JavaParamRef<jobject>& juri,
+ const base::android::JavaParamRef<jobject>& jcallback) {
+ SelfDeletingDownloadDelegate* delegate =
+ new SelfDeletingDownloadDelegate(jcallback);
+
+ content::WebContents* web_contents =
+ content::WebContents::FromJavaWebContents(jweb_contents);
+ if (!web_contents) {
+ delegate->OnManifestDownloadFailure();
+ return nullptr;
+ }
+
+ GURL url(base::android::ConvertJavaStringToUTF8(
+ env, Java_PaymentManifestDownloader_getUriString(env, juri)));
+ DCHECK(url.is_valid());
+ DCHECK(url.SchemeIs(url::kHttpsScheme));
+
+ std::unique_ptr<PaymentManifestDownloader> downloader =
+ base::MakeUnique<PaymentManifestDownloader>(
+ content::BrowserContext::GetDefaultStoragePartition(
+ web_contents->GetBrowserContext())
+ ->GetURLRequestContext(),
+ url, delegate);
+ delegate->set_downloader(std::move(downloader));
+
+ return delegate;
+}
+
+} // namespace
+
+bool RegisterPaymentManifestDownloader(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+void DownloadPaymentMethodManifest(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jclass>& jcaller,
+ const base::android::JavaParamRef<jobject>& jweb_contents,
+ const base::android::JavaParamRef<jobject>& jmethod_name,
+ const base::android::JavaParamRef<jobject>& jcallback) {
+ SelfDeletingDownloadDelegate* delegate = BuildSelfDeletingDownloadDelegate(
+ env, jweb_contents, jmethod_name, jcallback);
+ if (delegate)
+ delegate->DownloadPaymentMethodManifest();
+}
+
+void DownloadWebAppManifest(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jclass>& jcaller,
+ const base::android::JavaParamRef<jobject>& jweb_contents,
+ const base::android::JavaParamRef<jobject>& jweb_app_manifest_uri,
+ const base::android::JavaParamRef<jobject>& jcallback) {
+ SelfDeletingDownloadDelegate* delegate = BuildSelfDeletingDownloadDelegate(
+ env, jweb_contents, jweb_app_manifest_uri, jcallback);
+ if (delegate)
+ delegate->DownloadWebAppManifest();
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/android/payment_manifest_downloader_android.h b/chromium/components/payments/content/android/payment_manifest_downloader_android.h
new file mode 100644
index 00000000000..12f2306d646
--- /dev/null
+++ b/chromium/components/payments/content/android/payment_manifest_downloader_android.h
@@ -0,0 +1,16 @@
+// 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_PAYMENTS_CONTENT_ANDROID_PAYMENT_MANIFEST_DOWNLOADER_ANDROID_H_
+#define COMPONENTS_PAYMENTS_CONTENT_ANDROID_PAYMENT_MANIFEST_DOWNLOADER_ANDROID_H_
+
+#include <jni.h>
+
+namespace payments {
+
+bool RegisterPaymentManifestDownloader(JNIEnv* env);
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CONTENT_ANDROID_PAYMENT_MANIFEST_DOWNLOADER_ANDROID_H_
diff --git a/chromium/components/payments/content/android/payment_manifest_parser_android.cc b/chromium/components/payments/content/android/payment_manifest_parser_android.cc
new file mode 100644
index 00000000000..65a3e26e449
--- /dev/null
+++ b/chromium/components/payments/content/android/payment_manifest_parser_android.cc
@@ -0,0 +1,152 @@
+// 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/payments/content/android/payment_manifest_parser_android.h"
+
+#include <stddef.h>
+
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/numerics/safe_conversions.h"
+#include "jni/PaymentManifestParser_jni.h"
+#include "url/gurl.h"
+
+namespace payments {
+namespace {
+
+class ParseCallback {
+ public:
+ explicit ParseCallback(const base::android::JavaParamRef<jobject>& jcallback)
+ : jcallback_(jcallback) {}
+
+ ~ParseCallback() {}
+
+ // Copies payment method manifest into Java.
+ void OnPaymentMethodManifestParsed(std::vector<GURL> web_app_manifest_urls) {
+ DCHECK_GE(100U, web_app_manifest_urls.size());
+ JNIEnv* env = base::android::AttachCurrentThread();
+
+ if (web_app_manifest_urls.empty()) {
+ // Can trigger synchronous deletion of PaymentManifestParserAndroid.
+ Java_ManifestParseCallback_onManifestParseFailure(env, jcallback_);
+ return;
+ }
+
+ base::android::ScopedJavaLocalRef<jobjectArray> juris =
+ Java_PaymentManifestParser_createWebAppManifestUris(
+ env, web_app_manifest_urls.size());
+
+ for (size_t i = 0; i < web_app_manifest_urls.size(); ++i) {
+ bool is_valid_uri = Java_PaymentManifestParser_addUri(
+ env, juris.obj(), base::checked_cast<int>(i),
+ base::android::ConvertUTF8ToJavaString(
+ env, web_app_manifest_urls[i].spec()));
+ DCHECK(is_valid_uri);
+ }
+
+ // Can trigger synchronous deletion of PaymentManifestParserAndroid.
+ Java_ManifestParseCallback_onPaymentMethodManifestParseSuccess(
+ env, jcallback_, juris.obj());
+ }
+
+ // Copies web app manifest into Java.
+ void OnWebAppManifestParsed(
+ std::vector<mojom::WebAppManifestSectionPtr> manifest) {
+ DCHECK_GE(100U, manifest.size());
+ JNIEnv* env = base::android::AttachCurrentThread();
+
+ if (manifest.empty()) {
+ // Can trigger synchronous deletion of PaymentManifestParserAndroid.
+ Java_ManifestParseCallback_onManifestParseFailure(env, jcallback_);
+ return;
+ }
+
+ base::android::ScopedJavaLocalRef<jobjectArray> jmanifest =
+ Java_PaymentManifestParser_createManifest(env, manifest.size());
+
+ for (size_t i = 0; i < manifest.size(); ++i) {
+ const mojom::WebAppManifestSectionPtr& section = manifest[i];
+ DCHECK_GE(100U, section->fingerprints.size());
+
+ Java_PaymentManifestParser_addSectionToManifest(
+ env, jmanifest.obj(), base::checked_cast<int>(i),
+ base::android::ConvertUTF8ToJavaString(env, section->id),
+ section->min_version,
+ base::checked_cast<int>(section->fingerprints.size()));
+
+ for (size_t j = 0; j < section->fingerprints.size(); ++j) {
+ const std::vector<uint8_t>& fingerprint = section->fingerprints[j];
+ Java_PaymentManifestParser_addFingerprintToSection(
+ env, jmanifest.obj(), base::checked_cast<int>(i),
+ base::checked_cast<int>(j),
+ base::android::ToJavaByteArray(env, fingerprint));
+ }
+ }
+
+ // Can trigger synchronous deletion of PaymentManifestParserAndroid.
+ Java_ManifestParseCallback_onWebAppManifestParseSuccess(env, jcallback_,
+ jmanifest.obj());
+ }
+
+ private:
+ base::android::ScopedJavaGlobalRef<jobject> jcallback_;
+
+ DISALLOW_COPY_AND_ASSIGN(ParseCallback);
+};
+
+} // namespace
+
+PaymentManifestParserAndroid::PaymentManifestParserAndroid() {}
+
+PaymentManifestParserAndroid::~PaymentManifestParserAndroid() {}
+
+void PaymentManifestParserAndroid::StartUtilityProcess(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller) {
+ host_.StartUtilityProcess();
+}
+
+void PaymentManifestParserAndroid::ParsePaymentMethodManifest(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ const base::android::JavaParamRef<jstring>& jcontent,
+ const base::android::JavaParamRef<jobject>& jcallback) {
+ host_.ParsePaymentMethodManifest(
+ base::android::ConvertJavaStringToUTF8(env, jcontent),
+ base::BindOnce(&ParseCallback::OnPaymentMethodManifestParsed,
+ base::MakeUnique<ParseCallback>(jcallback)));
+}
+
+void PaymentManifestParserAndroid::ParseWebAppManifest(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ const base::android::JavaParamRef<jstring>& jcontent,
+ const base::android::JavaParamRef<jobject>& jcallback) {
+ host_.ParseWebAppManifest(
+ base::android::ConvertJavaStringToUTF8(env, jcontent),
+ base::BindOnce(&ParseCallback::OnWebAppManifestParsed,
+ base::MakeUnique<ParseCallback>(jcallback)));
+}
+
+void PaymentManifestParserAndroid::StopUtilityProcess(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller) {
+ delete this;
+}
+
+bool RegisterPaymentManifestParser(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+// Caller owns the result.
+jlong CreatePaymentManifestParserAndroid(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jclass>& jcaller) {
+ return reinterpret_cast<jlong>(new PaymentManifestParserAndroid);
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/android/payment_manifest_parser_android.h b/chromium/components/payments/content/android/payment_manifest_parser_android.h
new file mode 100644
index 00000000000..a2b7e22a5f6
--- /dev/null
+++ b/chromium/components/payments/content/android/payment_manifest_parser_android.h
@@ -0,0 +1,56 @@
+// 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_PAYMENTS_CONTENT_ANDROID_PAYMENT_MANIFEST_PARSER_ANDROID_H_
+#define COMPONENTS_PAYMENTS_CONTENT_ANDROID_PAYMENT_MANIFEST_PARSER_ANDROID_H_
+
+#include <jni.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/macros.h"
+#include "components/payments/content/payment_manifest_parser_host.h"
+
+namespace payments {
+
+// Android wrapper for the host of the utility process that parses manifest
+// contents.
+class PaymentManifestParserAndroid {
+ public:
+ PaymentManifestParserAndroid();
+ ~PaymentManifestParserAndroid();
+
+ void StartUtilityProcess(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller);
+
+ void ParsePaymentMethodManifest(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ const base::android::JavaParamRef<jstring>& jcontent,
+ const base::android::JavaParamRef<jobject>& jcallback);
+
+ void ParseWebAppManifest(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ const base::android::JavaParamRef<jstring>& jcontent,
+ const base::android::JavaParamRef<jobject>& jcallback);
+
+ // Deletes this object.
+ void StopUtilityProcess(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller);
+
+ private:
+ PaymentManifestParserHost host_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaymentManifestParserAndroid);
+};
+
+bool RegisterPaymentManifestParser(JNIEnv* env);
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CONTENT_ANDROID_PAYMENT_MANIFEST_PARSER_ANDROID_H_
diff --git a/chromium/components/payments/content/payment_app.mojom b/chromium/components/payments/content/payment_app.mojom
index 0d9f7c655ad..a980ddcf8a8 100644
--- a/chromium/components/payments/content/payment_app.mojom
+++ b/chromium/components/payments/content/payment_app.mojom
@@ -5,6 +5,7 @@
module payments.mojom;
import "components/payments/content/payment_request.mojom";
+import "mojo/common/time.mojom";
import "url/mojo/url.mojom";
enum PaymentAppManifestError {
@@ -27,7 +28,7 @@ struct PaymentAppManifest {
array<PaymentAppOption> options;
};
-interface PaymentAppManager {
+interface PaymentManager {
Init(string service_worker_scope);
SetManifest(PaymentAppManifest payment_app_manifest)
=> (PaymentAppManifestError error);
@@ -42,3 +43,15 @@ struct PaymentAppRequest {
array<PaymentDetailsModifier> modifiers;
string optionId;
};
+
+struct PaymentAppResponse {
+ string method_name;
+ string stringified_details;
+};
+
+// This interface is provided to pass a payment app response from payment
+// request event in renderer side to browser side by calling respondWith().
+interface PaymentAppResponseCallback {
+ OnPaymentAppResponse(PaymentAppResponse response,
+ mojo.common.mojom.Time dispatch_event_time);
+};
diff --git a/chromium/components/payments/content/payment_details_validation.cc b/chromium/components/payments/content/payment_details_validation.cc
index 3933c1c3337..351e82c961b 100644
--- a/chromium/components/payments/content/payment_details_validation.cc
+++ b/chromium/components/payments/content/payment_details_validation.cc
@@ -40,7 +40,7 @@ bool validateShippingOptionOrPaymentItem(
return false;
}
- if (item->amount->currency != total->amount->currency) {
+ if (total && item->amount->currency != total->amount->currency) {
*error_message = "Currencies must all be equal";
return false;
}
@@ -142,18 +142,15 @@ bool validatePaymentDetailsModifiers(
bool validatePaymentDetails(const mojom::PaymentDetailsPtr& details,
std::string* error_message) {
- if (details->total.is_null()) {
- *error_message = "Must specify total";
- return false;
- }
-
- if (!validateShippingOptionOrPaymentItem(details->total, details->total,
- error_message))
- return false;
+ if (details->total) {
+ if (!validateShippingOptionOrPaymentItem(details->total, details->total,
+ error_message))
+ return false;
- if (details->total->amount->value[0] == '-') {
- *error_message = "Total amount value should be non-negative";
- return false;
+ if (details->total->amount->value[0] == '-') {
+ *error_message = "Total amount value should be non-negative";
+ return false;
+ }
}
if (details->display_items.size()) {
diff --git a/chromium/components/payments/content/payment_manifest_downloader.cc b/chromium/components/payments/content/payment_manifest_downloader.cc
new file mode 100644
index 00000000000..15a8783d71a
--- /dev/null
+++ b/chromium/components/payments/content/payment_manifest_downloader.cc
@@ -0,0 +1,151 @@
+// 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/payments/content/payment_manifest_downloader.h"
+
+#include <algorithm>
+#include <unordered_map>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/strings/string_split.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "components/link_header_util/link_header_util.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "net/http/http_util.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "url/url_constants.h"
+
+namespace payments {
+namespace {
+
+bool IsValidManifestUrl(const GURL& url) {
+ return url.is_valid() && url.SchemeIs(url::kHttpsScheme);
+}
+
+} // namespace
+
+PaymentManifestDownloader::PaymentManifestDownloader(
+ const scoped_refptr<net::URLRequestContextGetter>& context,
+ const GURL& url,
+ Delegate* delegate)
+ : context_(context),
+ url_(url),
+ delegate_(delegate),
+ is_downloading_http_link_header_(true) {
+ DCHECK(IsValidManifestUrl(url_));
+}
+
+PaymentManifestDownloader::~PaymentManifestDownloader() {}
+
+void PaymentManifestDownloader::DownloadPaymentMethodManifest() {
+ DCHECK(!fetcher_);
+ is_downloading_http_link_header_ = true;
+ InitiateDownload(url_, net::URLFetcher::HEAD);
+}
+
+void PaymentManifestDownloader::DownloadWebAppManifest() {
+ DCHECK(!fetcher_);
+ is_downloading_http_link_header_ = false;
+ InitiateDownload(url_, net::URLFetcher::GET);
+}
+
+void PaymentManifestDownloader::InitiateDownload(
+ const GURL& url,
+ net::URLFetcher::RequestType request_type) {
+ if (!IsValidManifestUrl(url)) {
+ delegate_->OnManifestDownloadFailure();
+ return;
+ }
+
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("payment_manifest_downloader", R"(
+ semantics {
+ sender: "Web Payments"
+ description:
+ "Chromium downloads manifest files for web payments API to help "
+ "users make secure and convenient payments on the web."
+ trigger:
+ "A user that has a payment app visits a website that uses the web "
+ "payments API."
+ data: "None."
+ destination: WEBSITE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "This feature cannot be disabled in settings. Users can uninstall/"
+ "disable all payment apps to stop this feature."
+ policy_exception_justification: "Not implemented."
+ })");
+ fetcher_ = net::URLFetcher::Create(0 /* id */, url, request_type, this,
+ traffic_annotation);
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ fetcher_.get(), data_use_measurement::DataUseUserData::PAYMENTS);
+ fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DO_NOT_SAVE_COOKIES);
+ fetcher_->SetStopOnRedirect(true);
+ fetcher_->SetRequestContext(context_.get());
+ fetcher_->Start();
+}
+
+void PaymentManifestDownloader::OnURLFetchComplete(
+ const net::URLFetcher* source) {
+ if (source->GetResponseCode() != net::HTTP_OK) {
+ delegate_->OnManifestDownloadFailure();
+ return;
+ }
+
+ if (is_downloading_http_link_header_) {
+ is_downloading_http_link_header_ = false;
+
+ net::HttpResponseHeaders* headers = source->GetResponseHeaders();
+ if (!headers) {
+ delegate_->OnManifestDownloadFailure();
+ return;
+ }
+
+ std::string link_header;
+ headers->GetNormalizedHeader("link", &link_header);
+ if (!link_header.empty()) {
+ std::string payment_method_manifest_url;
+ std::unordered_map<std::string, base::Optional<std::string>> params;
+ for (const auto& value : link_header_util::SplitLinkHeader(link_header)) {
+ if (!link_header_util::ParseLinkHeaderValue(
+ value.first, value.second, &payment_method_manifest_url,
+ &params)) {
+ continue;
+ }
+
+ auto rel = params.find("rel");
+ if (rel == params.end())
+ continue;
+
+ std::vector<std::string> rel_parts =
+ base::SplitString(rel->second.value_or(""), HTTP_LWS,
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ if (std::find(rel_parts.begin(), rel_parts.end(),
+ "payment-method-manifest") != rel_parts.end()) {
+ InitiateDownload(url_.Resolve(payment_method_manifest_url),
+ net::URLFetcher::GET);
+ return;
+ }
+ }
+ }
+ } else {
+ std::string content;
+ if (source->GetResponseAsString(&content) && !content.empty()) {
+ delegate_->OnManifestDownloadSuccess(content);
+ return;
+ }
+ }
+
+ delegate_->OnManifestDownloadFailure();
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/payment_manifest_downloader.h b/chromium/components/payments/content/payment_manifest_downloader.h
new file mode 100644
index 00000000000..ac1a95ba59d
--- /dev/null
+++ b/chromium/components/payments/content/payment_manifest_downloader.h
@@ -0,0 +1,107 @@
+// 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_PAYMENTS_CONTENT_PAYMENT_MANIFEST_DOWNLOADER_H_
+#define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_MANIFEST_DOWNLOADER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace payments {
+
+// Downloader of the payment method manifest and web-app manifest based on the
+// payment method name that is a URL with HTTPS scheme, e.g.,
+// https://bobpay.com.
+//
+// The downloader does not follow redirects. A download succeeds only if all
+// HTTP response codes are 200.
+class PaymentManifestDownloader : public net::URLFetcherDelegate {
+ public:
+ // The interface for receiving the result of downloading a manifest.
+ class Delegate {
+ public:
+ // Called when a manifest has been successfully downloaded.
+ virtual void OnManifestDownloadSuccess(const std::string& content) = 0;
+
+ // Called when failed to download the manifest for any reason:
+ // - HTTP response code is not 200.
+ // - HTTP GET on the manifest URL returns empty content.
+ //
+ // In the case of a payment method manifest download, can also be called
+ // when:
+ // - HTTP response headers are absent.
+ // - HTTP response headers do not contain Link headers.
+ // - Link header does not contain rel="payment-method-manifest".
+ // - Link header does not contain a valid URL.
+ virtual void OnManifestDownloadFailure() = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ // |delegate| should not be null and must outlive this object. |url| should be
+ // a valid URL with HTTPS scheme.
+ PaymentManifestDownloader(
+ const scoped_refptr<net::URLRequestContextGetter>& context,
+ const GURL& url,
+ Delegate* delegate);
+
+ ~PaymentManifestDownloader() override;
+
+ // Download a payment method manifest via two consecutive HTTP requests:
+ //
+ // 1) HEAD request for the payment method name. The HTTP response header is
+ // parsed for Link header that points to the location of the payment method
+ // manifest file. Example of a relative location:
+ //
+ // Link: <data/payment-manifest.json>; rel="payment-method-manifest"
+ //
+ // (This is relative to the payment method URL.) Example of an absolute
+ // location:
+ //
+ // Link: <https://bobpay.com/data/payment-manifest.json>;
+ // rel="payment-method-manifest"
+ //
+ // The absolute location must use HTTPS scheme.
+ //
+ // 2) GET request for the payment method manifest file.
+ void DownloadPaymentMethodManifest();
+
+ // Download a web app manifest via a single HTTP request:
+ //
+ // 1) GET request for the payment method name.
+ void DownloadWebAppManifest();
+
+ private:
+ void InitiateDownload(const GURL& url,
+ net::URLFetcher::RequestType request_type);
+
+ // net::URLFetcherDelegate
+ void OnURLFetchComplete(const net::URLFetcher* source) override;
+
+ scoped_refptr<net::URLRequestContextGetter> context_;
+ const GURL url_;
+
+ // Non-owned. Never null. Outlives this object.
+ Delegate* delegate_;
+
+ bool is_downloading_http_link_header_;
+ std::unique_ptr<net::URLFetcher> fetcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaymentManifestDownloader);
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CONTENT_PAYMENT_MANIFEST_DOWNLOADER_H_
diff --git a/chromium/components/payments/content/payment_manifest_downloader_unittest.cc b/chromium/components/payments/content/payment_manifest_downloader_unittest.cc
new file mode 100644
index 00000000000..bc7d26bcfb1
--- /dev/null
+++ b/chromium/components/payments/content/payment_manifest_downloader_unittest.cc
@@ -0,0 +1,259 @@
+// 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/payments/content/payment_manifest_downloader.h"
+
+#include "base/threading/thread_task_runner_handle.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+namespace {
+
+class PaymentMethodManifestDownloaderTest
+ : public testing::Test,
+ public PaymentManifestDownloader::Delegate {
+ public:
+ PaymentMethodManifestDownloaderTest()
+ : context_(new net::TestURLRequestContextGetter(
+ base::ThreadTaskRunnerHandle::Get())),
+ downloader_(context_, GURL("https://bobpay.com"), this) {
+ downloader_.DownloadPaymentMethodManifest();
+ }
+
+ ~PaymentMethodManifestDownloaderTest() override {}
+
+ // PaymentManifestDownloader::Delegate
+ MOCK_METHOD1(OnManifestDownloadSuccess, void(const std::string& content));
+ MOCK_METHOD0(OnManifestDownloadFailure, void());
+
+ net::TestURLFetcher* fetcher() { return factory_.GetFetcherByID(0); }
+
+ private:
+ content::TestBrowserThreadBundle thread_bundle_;
+ net::TestURLFetcherFactory factory_;
+ scoped_refptr<net::TestURLRequestContextGetter> context_;
+ PaymentManifestDownloader downloader_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaymentMethodManifestDownloaderTest);
+};
+
+TEST_F(PaymentMethodManifestDownloaderTest, HttpHeadResponse404IsFailure) {
+ fetcher()->set_response_code(404);
+
+ EXPECT_CALL(*this, OnManifestDownloadFailure());
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, NoHttpHeadersIsFailure) {
+ fetcher()->set_response_code(200);
+
+ EXPECT_CALL(*this, OnManifestDownloadFailure());
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, EmptyHttpHeaderIsFailure) {
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(std::string()));
+ fetcher()->set_response_headers(headers);
+ fetcher()->set_response_code(200);
+
+ EXPECT_CALL(*this, OnManifestDownloadFailure());
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, EmptyHttpLinkHeaderIsFailure) {
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(std::string()));
+ headers->AddHeader("Link:");
+ fetcher()->set_response_headers(headers);
+ fetcher()->set_response_code(200);
+
+ EXPECT_CALL(*this, OnManifestDownloadFailure());
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, NoRelInHttpLinkHeaderIsFailure) {
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(std::string()));
+ headers->AddHeader("Link: <manifest.json>");
+ fetcher()->set_response_headers(headers);
+ fetcher()->set_response_code(200);
+
+ EXPECT_CALL(*this, OnManifestDownloadFailure());
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, NoUrlInHttpLinkHeaderIsFailure) {
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(std::string()));
+ headers->AddHeader("Link: rel=payment-method-manifest");
+ fetcher()->set_response_headers(headers);
+ fetcher()->set_response_code(200);
+
+ EXPECT_CALL(*this, OnManifestDownloadFailure());
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest,
+ NoManifestRellInHttpLinkHeaderIsFailure) {
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(std::string()));
+ headers->AddHeader("Link: <manifest.json>; rel=web-app-manifest");
+ fetcher()->set_response_headers(headers);
+ fetcher()->set_response_code(200);
+
+ EXPECT_CALL(*this, OnManifestDownloadFailure());
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, HttpGetResponse404IsFailure) {
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(std::string()));
+ headers->AddHeader("Link: <manifest.json>; rel=payment-method-manifest");
+ fetcher()->set_response_headers(headers);
+ fetcher()->set_response_code(200);
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+ fetcher()->set_response_code(404);
+
+ EXPECT_CALL(*this, OnManifestDownloadFailure());
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, EmptyHttpGetResponseIsFailure) {
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(std::string()));
+ headers->AddHeader("Link: <manifest.json>; rel=payment-method-manifest");
+ fetcher()->set_response_headers(headers);
+ fetcher()->set_response_code(200);
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+ fetcher()->set_response_code(200);
+
+ EXPECT_CALL(*this, OnManifestDownloadFailure());
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, NonEmptyHttpGetResponseIsSuccess) {
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(std::string()));
+ headers->AddHeader("Link: <manifest.json>; rel=payment-method-manifest");
+ fetcher()->set_response_headers(headers);
+ fetcher()->set_response_code(200);
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+ fetcher()->SetResponseString("manifest content");
+ fetcher()->set_response_code(200);
+
+ EXPECT_CALL(*this, OnManifestDownloadSuccess("manifest content"));
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, RelativeHttpHeaderLinkUrl) {
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(std::string()));
+ headers->AddHeader("Link: <manifest.json>; rel=payment-method-manifest");
+ fetcher()->set_response_headers(headers);
+ fetcher()->set_response_code(200);
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+
+ EXPECT_EQ("https://bobpay.com/manifest.json",
+ fetcher()->GetOriginalURL().spec());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, AbsoluteHttpsHeaderLinkUrl) {
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(std::string()));
+ headers->AddHeader(
+ "Link: <https://alicepay.com/manifest.json>; "
+ "rel=payment-method-manifest");
+ fetcher()->set_response_headers(headers);
+ fetcher()->set_response_code(200);
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+
+ EXPECT_EQ("https://alicepay.com/manifest.json",
+ fetcher()->GetOriginalURL().spec());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, AbsoluteHttpHeaderLinkUrl) {
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(std::string()));
+ headers->AddHeader(
+ "Link: <http://alicepay.com/manifest.json>; "
+ "rel=payment-method-manifest");
+ fetcher()->set_response_headers(headers);
+ fetcher()->set_response_code(200);
+
+ EXPECT_CALL(*this, OnManifestDownloadFailure());
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+class WebAppManifestDownloaderTest
+ : public testing::Test,
+ public PaymentManifestDownloader::Delegate {
+ public:
+ WebAppManifestDownloaderTest()
+ : context_(new net::TestURLRequestContextGetter(
+ base::ThreadTaskRunnerHandle::Get())),
+ downloader_(context_, GURL("https://bobpay.com"), this) {
+ downloader_.DownloadWebAppManifest();
+ }
+
+ ~WebAppManifestDownloaderTest() override {}
+
+ // PaymentManifestDownloader::Delegate
+ MOCK_METHOD1(OnManifestDownloadSuccess, void(const std::string& content));
+ MOCK_METHOD0(OnManifestDownloadFailure, void());
+
+ net::TestURLFetcher* fetcher() { return factory_.GetFetcherByID(0); }
+
+ private:
+ content::TestBrowserThreadBundle thread_bundle_;
+ net::TestURLFetcherFactory factory_;
+ scoped_refptr<net::TestURLRequestContextGetter> context_;
+ PaymentManifestDownloader downloader_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebAppManifestDownloaderTest);
+};
+
+TEST_F(WebAppManifestDownloaderTest, HttpGetResponse404IsFailure) {
+ fetcher()->set_response_code(404);
+
+ EXPECT_CALL(*this, OnManifestDownloadFailure());
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(WebAppManifestDownloaderTest, EmptyHttpGetResponseIsFailure) {
+ fetcher()->set_response_code(200);
+
+ EXPECT_CALL(*this, OnManifestDownloadFailure());
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(WebAppManifestDownloaderTest, NonEmptyHttpGetResponseIsSuccess) {
+ fetcher()->SetResponseString("manifest content");
+ fetcher()->set_response_code(200);
+
+ EXPECT_CALL(*this, OnManifestDownloadSuccess("manifest content"));
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+} // namespace
+} // namespace payments
diff --git a/chromium/components/payments/content/payment_manifest_parser.mojom b/chromium/components/payments/content/payment_manifest_parser.mojom
new file mode 100644
index 00000000000..96c3d3cb6d3
--- /dev/null
+++ b/chromium/components/payments/content/payment_manifest_parser.mojom
@@ -0,0 +1,25 @@
+// 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.
+
+[JavaPackage="org.chromium.payments.mojom"]
+module payments.mojom;
+
+import "url/mojo/url.mojom";
+
+struct WebAppManifestSection {
+ // The package name of the app.
+ string id;
+ // Minimum version number of the app.
+ int64 min_version;
+ // The result of SHA256(signing certificate bytes) for each certificate in the
+ // app.
+ array<array<uint8, 32>> fingerprints;
+};
+
+interface PaymentManifestParser {
+ ParsePaymentMethodManifest(string content)
+ => (array<url.mojom.Url> webAppManifestUrls);
+ ParseWebAppManifest(string content)
+ => (array<WebAppManifestSection> manifest);
+};
diff --git a/chromium/components/payments/content/payment_manifest_parser_host.cc b/chromium/components/payments/content/payment_manifest_parser_host.cc
new file mode 100644
index 00000000000..0af9a38c23b
--- /dev/null
+++ b/chromium/components/payments/content/payment_manifest_parser_host.cc
@@ -0,0 +1,170 @@
+// 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/payments/content/payment_manifest_parser_host.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "components/strings/grit/components_strings.h"
+#include "content/public/browser/utility_process_mojo_client.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "url/url_constants.h"
+
+namespace payments {
+
+PaymentManifestParserHost::PaymentManifestParserHost() : callback_counter_(0) {}
+
+PaymentManifestParserHost::~PaymentManifestParserHost() {}
+
+void PaymentManifestParserHost::StartUtilityProcess() {
+ mojo_client_ = base::MakeUnique<
+ content::UtilityProcessMojoClient<mojom::PaymentManifestParser>>(
+ l10n_util::GetStringUTF16(
+ IDS_UTILITY_PROCESS_PAYMENT_MANIFEST_PARSER_NAME));
+ mojo_client_->set_error_callback(
+ base::Bind(&PaymentManifestParserHost::OnUtilityProcessStopped,
+ base::Unretained(this)));
+ mojo_client_->Start();
+}
+
+void PaymentManifestParserHost::ParsePaymentMethodManifest(
+ const std::string& content,
+ PaymentMethodCallback callback) {
+ if (!mojo_client_) {
+ std::move(callback).Run(std::vector<GURL>());
+ return;
+ }
+
+ int64_t callback_identifier = callback_counter_++;
+ const auto& result = pending_payment_method_callbacks_.insert(
+ std::make_pair(callback_identifier, std::move(callback)));
+ DCHECK(result.second);
+ DCHECK_GE(10U, pending_payment_method_callbacks_.size());
+
+ mojo_client_->service()->ParsePaymentMethodManifest(
+ content, base::Bind(&PaymentManifestParserHost::OnPaymentMethodParse,
+ base::Unretained(this), callback_identifier));
+}
+
+void PaymentManifestParserHost::ParseWebAppManifest(const std::string& content,
+ WebAppCallback callback) {
+ if (!mojo_client_) {
+ std::move(callback).Run(std::vector<mojom::WebAppManifestSectionPtr>());
+ return;
+ }
+
+ int64_t callback_identifier = callback_counter_++;
+ const auto& result = pending_web_app_callbacks_.insert(
+ std::make_pair(callback_identifier, std::move(callback)));
+ DCHECK(result.second);
+ DCHECK_GE(10U, pending_web_app_callbacks_.size());
+
+ mojo_client_->service()->ParseWebAppManifest(
+ content, base::Bind(&PaymentManifestParserHost::OnWebAppParse,
+ base::Unretained(this), callback_identifier));
+}
+
+void PaymentManifestParserHost::OnPaymentMethodParse(
+ int64_t callback_identifier,
+ const std::vector<GURL>& web_app_manifest_urls) {
+ const auto& pending_callback_it =
+ pending_payment_method_callbacks_.find(callback_identifier);
+ if (pending_callback_it == pending_payment_method_callbacks_.end()) {
+ // If unable to find the pending callback, then something went wrong in the
+ // utility process. Stop the utility process and notify all callbacks.
+ OnUtilityProcessStopped();
+ return;
+ }
+
+ const size_t kMaximumNumberOfWebAppUrls = 100U;
+ if (web_app_manifest_urls.size() > kMaximumNumberOfWebAppUrls) {
+ // If more than 100 items, then something went wrong in the utility
+ // process. Stop the utility process and notify all callbacks.
+ OnUtilityProcessStopped();
+ return;
+ }
+
+ for (const auto& url : web_app_manifest_urls) {
+ if (!url.is_valid() || !url.SchemeIs(url::kHttpsScheme)) {
+ // If not a valid URL with HTTPS scheme, then something went wrong in the
+ // utility process. Stop the utility process and notify all callbacks.
+ OnUtilityProcessStopped();
+ return;
+ }
+ }
+
+ PaymentMethodCallback callback = std::move(pending_callback_it->second);
+ pending_payment_method_callbacks_.erase(pending_callback_it);
+
+ // Can trigger synchronous deletion of this object, so can't access any of
+ // the member variables after this block.
+ std::move(callback).Run(web_app_manifest_urls);
+}
+
+void PaymentManifestParserHost::OnWebAppParse(
+ int64_t callback_identifier,
+ std::vector<mojom::WebAppManifestSectionPtr> manifest) {
+ const auto& pending_callback_it =
+ pending_web_app_callbacks_.find(callback_identifier);
+ if (pending_callback_it == pending_web_app_callbacks_.end()) {
+ // If unable to find the pending callback, then something went wrong in the
+ // utility process. Stop the utility process and notify all callbacks.
+ OnUtilityProcessStopped();
+ return;
+ }
+
+ const size_t kMaximumNumberOfSections = 100U;
+ if (manifest.size() > kMaximumNumberOfSections) {
+ // If more than 100 items, then something went wrong in the utility
+ // process. Stop the utility process and notify all callbacks.
+ OnUtilityProcessStopped();
+ return;
+ }
+
+ for (size_t i = 0; i < manifest.size(); ++i) {
+ const size_t kMaximumNumberOfFingerprints = 100U;
+ if (manifest[i]->fingerprints.size() > kMaximumNumberOfFingerprints) {
+ // If more than 100 items, then something went wrong in the utility
+ // process. Stop the utility process and notify all callbacks.
+ OnUtilityProcessStopped();
+ return;
+ }
+ }
+
+ WebAppCallback callback = std::move(pending_callback_it->second);
+ pending_web_app_callbacks_.erase(pending_callback_it);
+
+ // Can trigger synchronous deletion of this object, so can't access any of
+ // the member variables after this block.
+ std::move(callback).Run(std::move(manifest));
+}
+
+void PaymentManifestParserHost::OnUtilityProcessStopped() {
+ mojo_client_.reset();
+
+ std::unordered_map<int64_t, PaymentMethodCallback> payment_method_callbacks =
+ std::move(pending_payment_method_callbacks_);
+ std::unordered_map<int64_t, WebAppCallback> web_app_callbacks =
+ std::move(pending_web_app_callbacks_);
+
+ for (auto& callback : payment_method_callbacks) {
+ // Can trigger synchronous deletion of this object, so can't access any of
+ // the member variables after this line.
+ std::move(callback.second).Run(std::vector<GURL>());
+ }
+
+ for (auto& callback : web_app_callbacks) {
+ // Can trigger synchronous deletion of this object, so can't access any of
+ // the member variables after this line.
+ std::move(callback.second)
+ .Run(std::vector<mojom::WebAppManifestSectionPtr>());
+ }
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/payment_manifest_parser_host.h b/chromium/components/payments/content/payment_manifest_parser_host.h
new file mode 100644
index 00000000000..2873bdf6d62
--- /dev/null
+++ b/chromium/components/payments/content/payment_manifest_parser_host.h
@@ -0,0 +1,72 @@
+// 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_PAYMENTS_CONTENT_PAYMENT_MANIFEST_PARSER_HOST_H_
+#define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_MANIFEST_PARSER_HOST_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "components/payments/content/payment_manifest_parser.mojom.h"
+#include "url/gurl.h"
+
+namespace content {
+template <class MojoInterface>
+class UtilityProcessMojoClient;
+}
+
+namespace payments {
+
+// Host of the utility process that parses manifest contents.
+class PaymentManifestParserHost {
+ public:
+ // Called on successful parsing of a payment method manifest. The result is a
+ // move-only vector, which is empty on parse failure.
+ using PaymentMethodCallback = base::OnceCallback<void(std::vector<GURL>)>;
+ // Called on successful parsing of a web app manifest. The result is a
+ // move-only vector, which is empty on parse failure.
+ using WebAppCallback =
+ base::OnceCallback<void(std::vector<mojom::WebAppManifestSectionPtr>)>;
+
+ PaymentManifestParserHost();
+
+ // Stops the utility process.
+ ~PaymentManifestParserHost();
+
+ // Starts the utility process. This can take up to 2 seconds and should be
+ // done as soon as it is known that the parser will be needed.
+ void StartUtilityProcess();
+
+ void ParsePaymentMethodManifest(const std::string& content,
+ PaymentMethodCallback callback);
+ void ParseWebAppManifest(const std::string& content, WebAppCallback callback);
+
+ private:
+ void OnPaymentMethodParse(int64_t callback_identifier,
+ const std::vector<GURL>& web_app_manifest_urls);
+ void OnWebAppParse(int64_t callback_identifier,
+ std::vector<mojom::WebAppManifestSectionPtr> manifest);
+
+ void OnUtilityProcessStopped();
+
+ std::unique_ptr<
+ content::UtilityProcessMojoClient<mojom::PaymentManifestParser>>
+ mojo_client_;
+
+ int64_t callback_counter_;
+ std::unordered_map<int64_t, PaymentMethodCallback>
+ pending_payment_method_callbacks_;
+ std::unordered_map<int64_t, WebAppCallback> pending_web_app_callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaymentManifestParserHost);
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CONTENT_PAYMENT_MANIFEST_PARSER_HOST_H_
diff --git a/chromium/components/payments/content/payment_request.cc b/chromium/components/payments/content/payment_request.cc
index e55e68b272a..15aee2c6791 100644
--- a/chromium/components/payments/content/payment_request.cc
+++ b/chromium/components/payments/content/payment_request.cc
@@ -4,17 +4,12 @@
#include "components/payments/content/payment_request.h"
-#include <algorithm>
-#include <unordered_map>
+#include <string>
#include <utility>
#include "base/memory/ptr_util.h"
-#include "components/autofill/core/browser/autofill_data_util.h"
-#include "components/autofill/core/browser/field_types.h"
-#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/payments/content/payment_details_validation.h"
#include "components/payments/content/payment_request_web_contents_manager.h"
-#include "components/payments/core/currency_formatter.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
@@ -24,15 +19,13 @@ PaymentRequest::PaymentRequest(
content::WebContents* web_contents,
std::unique_ptr<PaymentRequestDelegate> delegate,
PaymentRequestWebContentsManager* manager,
- mojo::InterfaceRequest<payments::mojom::PaymentRequest> request)
+ mojo::InterfaceRequest<payments::mojom::PaymentRequest> request,
+ ObserverForTest* observer_for_testing)
: web_contents_(web_contents),
delegate_(std::move(delegate)),
manager_(manager),
binding_(this, std::move(request)),
- is_ready_to_pay_(false),
- selected_shipping_profile_(nullptr),
- selected_contact_profile_(nullptr),
- selected_credit_card_(nullptr) {
+ observer_for_testing_(observer_for_testing) {
// OnConnectionTerminated will be called when the Mojo pipe is closed. This
// will happen as a result of many renderer-side events (both successful and
// erroneous in nature).
@@ -56,12 +49,18 @@ void PaymentRequest::Init(
OnConnectionTerminated();
return;
}
+ if (!details->total) {
+ LOG(ERROR) << "Missing total";
+ OnConnectionTerminated();
+ return;
+ }
client_ = std::move(client);
- details_ = std::move(details);
- options_ = std::move(options);
- PopulateValidatedMethodData(method_data);
- PopulateProfileCache();
- SetDefaultProfileSelections();
+ spec_ = base::MakeUnique<PaymentRequestSpec>(
+ std::move(options), std::move(details), std::move(method_data), this,
+ delegate_->GetApplicationLocale());
+ state_ = base::MakeUnique<PaymentRequestState>(
+ spec_.get(), this, delegate_->GetApplicationLocale(),
+ delegate_->GetPersonalDataManager(), delegate_.get());
}
void PaymentRequest::Show() {
@@ -73,6 +72,16 @@ void PaymentRequest::Show() {
delegate_->ShowDialog(this);
}
+void PaymentRequest::UpdateWith(mojom::PaymentDetailsPtr details) {
+ std::string error;
+ if (!payments::validatePaymentDetails(details, &error)) {
+ LOG(ERROR) << error;
+ OnConnectionTerminated();
+ return;
+ }
+ spec_->UpdateWith(std::move(details));
+}
+
void PaymentRequest::Abort() {
// The API user has decided to abort. We return a successful abort message to
// the renderer, which closes the Mojo message pipe, which triggers
@@ -81,6 +90,49 @@ void PaymentRequest::Abort() {
client_->OnAbort(true /* aborted_successfully */);
}
+void PaymentRequest::Complete(mojom::PaymentComplete result) {
+ if (!client_.is_bound())
+ return;
+
+ if (result != mojom::PaymentComplete::SUCCESS) {
+ delegate_->ShowErrorMessage();
+ } else {
+ // When the renderer closes the connection,
+ // PaymentRequest::OnConnectionTerminated will be called.
+ client_->OnComplete();
+ }
+}
+
+void PaymentRequest::CanMakePayment() {
+ // TODO(crbug.com/704676): Implement a quota policy for this method.
+ // PaymentRequest.canMakePayments() never returns false in incognito mode.
+ client_->OnCanMakePayment(
+ delegate_->IsIncognito() || state()->CanMakePayment()
+ ? mojom::CanMakePaymentQueryResult::CAN_MAKE_PAYMENT
+ : mojom::CanMakePaymentQueryResult::CANNOT_MAKE_PAYMENT);
+ if (observer_for_testing_)
+ observer_for_testing_->OnCanMakePaymentCalled();
+}
+
+void PaymentRequest::OnInvalidSpecProvided() {
+ OnConnectionTerminated();
+}
+
+void PaymentRequest::OnPaymentResponseAvailable(
+ mojom::PaymentResponsePtr response) {
+ client_->OnPaymentResponse(std::move(response));
+}
+
+void PaymentRequest::OnShippingOptionIdSelected(
+ std::string shipping_option_id) {
+ client_->OnShippingOptionChange(shipping_option_id);
+}
+
+void PaymentRequest::OnShippingAddressSelected(
+ mojom::PaymentAddressPtr address) {
+ client_->OnShippingAddressChange(std::move(address));
+}
+
void PaymentRequest::UserCancelled() {
// If |client_| is not bound, then the object is already being destroyed as
// a result of a renderer event.
@@ -109,225 +161,7 @@ void PaymentRequest::OnConnectionTerminated() {
}
void PaymentRequest::Pay() {
- DCHECK(is_ready_to_pay_);
-
- // TODO(mathp): Return the PaymentResponse to the |client_|.
- OnConnectionTerminated();
-}
-
-void PaymentRequest::AddObserver(Observer* observer) {
- CHECK(observer);
- observers_.AddObserver(observer);
-}
-
-void PaymentRequest::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
-
-CurrencyFormatter* PaymentRequest::GetOrCreateCurrencyFormatter(
- const std::string& currency_code,
- const std::string& currency_system,
- const std::string& locale_name) {
- if (!currency_formatter_) {
- currency_formatter_.reset(
- new CurrencyFormatter(currency_code, currency_system, locale_name));
- }
- return currency_formatter_.get();
-}
-
-void PaymentRequest::SetSelectedShippingProfile(
- autofill::AutofillProfile* profile) {
- selected_shipping_profile_ = profile;
- UpdateIsReadyToPayAndNotifyObservers();
-}
-
-void PaymentRequest::SetSelectedContactProfile(
- autofill::AutofillProfile* profile) {
- selected_contact_profile_ = profile;
- UpdateIsReadyToPayAndNotifyObservers();
-}
-
-void PaymentRequest::SetSelectedCreditCard(autofill::CreditCard* card) {
- selected_credit_card_ = card;
- UpdateIsReadyToPayAndNotifyObservers();
-}
-
-void PaymentRequest::PopulateProfileCache() {
- std::vector<autofill::AutofillProfile*> profiles =
- personal_data_manager()->GetProfilesToSuggest();
-
- // PaymentRequest may outlive the Profiles returned by the Data Manager.
- // Thus, we store copies, and return a vector of pointers to these copies
- // whenever Profiles are requested. The same is true for credit cards.
- for (size_t i = 0; i < profiles.size(); i++) {
- profile_cache_.push_back(
- base::MakeUnique<autofill::AutofillProfile>(*profiles[i]));
-
- // TODO(tmartino): Implement deduplication rules specific to shipping and
- // contact profiles.
- shipping_profiles_.push_back(profile_cache_[i].get());
- contact_profiles_.push_back(profile_cache_[i].get());
- }
-
- const std::vector<autofill::CreditCard*>& cards =
- personal_data_manager()->GetCreditCardsToSuggest();
- for (autofill::CreditCard* card : cards) {
- card_cache_.push_back(base::MakeUnique<autofill::CreditCard>(*card));
- credit_cards_.push_back(card_cache_.back().get());
- }
-}
-
-void PaymentRequest::SetDefaultProfileSelections() {
- if (!shipping_profiles().empty())
- selected_shipping_profile_ = shipping_profiles()[0];
-
- if (!contact_profiles().empty())
- selected_contact_profile_ = contact_profiles()[0];
-
- // TODO(anthonyvd): Change this code to prioritize server cards and implement
- // a way to modify this function's return value.
- const std::vector<autofill::CreditCard*> cards = credit_cards();
- auto first_complete_card =
- std::find_if(cards.begin(), cards.end(),
- [](autofill::CreditCard* card) { return card->IsValid(); });
-
- selected_credit_card_ =
- first_complete_card == cards.end() ? nullptr : *first_complete_card;
-
- UpdateIsReadyToPayAndNotifyObservers();
-}
-
-void PaymentRequest::PopulateValidatedMethodData(
- const std::vector<payments::mojom::PaymentMethodDataPtr>& method_data) {
- if (method_data.empty()) {
- LOG(ERROR) << "Invalid payment methods or data";
- OnConnectionTerminated();
- return;
- }
-
- // Identifier for the basic card payment method in the PaymentMethodData.
- const char* const kBasicCardMethodName = "basic-card";
- std::set<std::string> card_networks{"amex", "diners", "discover",
- "jcb", "mastercard", "mir",
- "unionpay", "visa"};
- for (const payments::mojom::PaymentMethodDataPtr& method_data_entry :
- method_data) {
- std::vector<std::string> supported_methods =
- method_data_entry->supported_methods;
- if (supported_methods.empty()) {
- LOG(ERROR) << "Invalid payment methods or data";
- OnConnectionTerminated();
- return;
- }
-
- for (const std::string& method : supported_methods) {
- if (method.empty())
- continue;
-
- // If a card network is specified right in "supportedMethods", add it.
- auto card_it = card_networks.find(method);
- if (card_it != card_networks.end()) {
- supported_card_networks_.push_back(method);
- // |method| removed from |card_networks| so that it is not doubly added
- // to |supported_card_networks_| if "basic-card" is specified with no
- // supported networks.
- card_networks.erase(card_it);
- } else if (method == kBasicCardMethodName) {
- // For the "basic-card" method, check "supportedNetworks".
- if (method_data_entry->supported_networks.empty()) {
- // Empty |supported_networks| means all networks are supported.
- supported_card_networks_.insert(supported_card_networks_.end(),
- card_networks.begin(),
- card_networks.end());
- // Clear the set so that no further networks are added to
- // |supported_card_networks_|.
- card_networks.clear();
- } else {
- // The merchant has specified a few basic card supported networks. Use
- // the mapping to transform to known basic-card types.
- using ::payments::mojom::BasicCardNetwork;
- std::unordered_map<BasicCardNetwork, std::string> networks = {
- {BasicCardNetwork::AMEX, "amex"},
- {BasicCardNetwork::DINERS, "diners"},
- {BasicCardNetwork::DISCOVER, "discover"},
- {BasicCardNetwork::JCB, "jcb"},
- {BasicCardNetwork::MASTERCARD, "mastercard"},
- {BasicCardNetwork::MIR, "mir"},
- {BasicCardNetwork::UNIONPAY, "unionpay"},
- {BasicCardNetwork::VISA, "visa"}};
- for (const BasicCardNetwork& supported_network :
- method_data_entry->supported_networks) {
- // Make sure that the network was not already added to
- // |supported_card_networks_|.
- auto card_it = card_networks.find(networks[supported_network]);
- if (card_it != card_networks.end()) {
- supported_card_networks_.push_back(networks[supported_network]);
- card_networks.erase(card_it);
- }
- }
- }
- }
- }
- }
-}
-
-void PaymentRequest::UpdateIsReadyToPayAndNotifyObservers() {
- is_ready_to_pay_ =
- ArePaymentDetailsSatisfied() && ArePaymentOptionsSatisfied();
- NotifyOnSelectedInformationChanged();
-}
-
-void PaymentRequest::NotifyOnSelectedInformationChanged() {
- for (auto& observer : observers_)
- observer.OnSelectedInformationChanged();
-}
-
-bool PaymentRequest::ArePaymentDetailsSatisfied() {
- // TODO(mathp): A masked card may not satisfy IsValid().
- if (selected_credit_card_ == nullptr || !selected_credit_card_->IsValid())
- return false;
-
- const std::string basic_card_payment_type =
- autofill::data_util::GetPaymentRequestData(selected_credit_card_->type())
- .basic_card_payment_type;
- return !supported_card_networks_.empty() &&
- std::find(supported_card_networks_.begin(),
- supported_card_networks_.end(),
- basic_card_payment_type) != supported_card_networks_.end();
-}
-
-bool PaymentRequest::ArePaymentOptionsSatisfied() {
- // TODO(mathp): Have a measure of shipping address completeness.
- if (request_shipping() && selected_shipping_profile_ == nullptr)
- return false;
-
- // TODO(mathp): Make an encompassing class to validate contact info.
- const std::string& app_locale = delegate_->GetApplicationLocale();
- if (request_payer_name() &&
- (selected_contact_profile_ == nullptr ||
- selected_contact_profile_
- ->GetInfo(autofill::AutofillType(autofill::NAME_FULL), app_locale)
- .empty())) {
- return false;
- }
- if (request_payer_email() &&
- (selected_contact_profile_ == nullptr ||
- selected_contact_profile_
- ->GetInfo(autofill::AutofillType(autofill::EMAIL_ADDRESS),
- app_locale)
- .empty())) {
- return false;
- }
- if (request_payer_phone() &&
- (selected_contact_profile_ == nullptr ||
- selected_contact_profile_
- ->GetInfo(autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
- app_locale)
- .empty())) {
- return false;
- }
-
- return true;
+ state_->GeneratePaymentResponse();
}
} // namespace payments
diff --git a/chromium/components/payments/content/payment_request.h b/chromium/components/payments/content/payment_request.h
index 18d3f94229b..ad2abed152a 100644
--- a/chromium/components/payments/content/payment_request.h
+++ b/chromium/components/payments/content/payment_request.h
@@ -6,20 +6,15 @@
#define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_H_
#include <memory>
-#include <string>
#include <vector>
#include "base/macros.h"
-#include "base/observer_list.h"
#include "components/payments/content/payment_request.mojom.h"
-#include "components/payments/content/payment_request_delegate.h"
+#include "components/payments/content/payment_request_spec.h"
+#include "components/payments/content/payment_request_state.h"
+#include "components/payments/core/payment_request_delegate.h"
#include "mojo/public/cpp/bindings/binding.h"
-
-namespace autofill {
-class AutofillProfile;
-class CreditCard;
-class PersonalDataManager;
-}
+#include "mojo/public/cpp/bindings/interface_request.h"
namespace content {
class WebContents;
@@ -27,38 +22,52 @@ class WebContents;
namespace payments {
-class CurrencyFormatter;
class PaymentRequestWebContentsManager;
-class PaymentRequest : payments::mojom::PaymentRequest {
+// This class manages the interaction between the renderer (through the
+// PaymentRequestClient and Mojo stub implementation) and the UI (through the
+// PaymentRequestDelegate). The API user (merchant) specification (supported
+// payment methods, required information, order details) is stored in
+// PaymentRequestSpec, and the current user selection state (and related data)
+// is stored in PaymentRequestSpec.
+class PaymentRequest : public mojom::PaymentRequest,
+ public PaymentRequestSpec::Observer,
+ public PaymentRequestState::Delegate {
public:
- class Observer {
+ class ObserverForTest {
public:
- // Called when the information (payment method, address/contact info,
- // shipping option) changes.
- virtual void OnSelectedInformationChanged() = 0;
+ virtual void OnCanMakePaymentCalled() = 0;
protected:
- virtual ~Observer() {}
+ virtual ~ObserverForTest() {}
};
- PaymentRequest(
- content::WebContents* web_contents,
- std::unique_ptr<PaymentRequestDelegate> delegate,
- PaymentRequestWebContentsManager* manager,
- mojo::InterfaceRequest<payments::mojom::PaymentRequest> request);
+ PaymentRequest(content::WebContents* web_contents,
+ std::unique_ptr<PaymentRequestDelegate> delegate,
+ PaymentRequestWebContentsManager* manager,
+ mojo::InterfaceRequest<mojom::PaymentRequest> request,
+ ObserverForTest* observer_for_testing);
~PaymentRequest() override;
- // payments::mojom::PaymentRequest "stub"
- void Init(payments::mojom::PaymentRequestClientPtr client,
- std::vector<payments::mojom::PaymentMethodDataPtr> method_data,
- payments::mojom::PaymentDetailsPtr details,
- payments::mojom::PaymentOptionsPtr options) override;
+ // mojom::PaymentRequest
+ void Init(mojom::PaymentRequestClientPtr client,
+ std::vector<mojom::PaymentMethodDataPtr> method_data,
+ mojom::PaymentDetailsPtr details,
+ mojom::PaymentOptionsPtr options) override;
void Show() override;
- void UpdateWith(payments::mojom::PaymentDetailsPtr details) override {}
+ void UpdateWith(mojom::PaymentDetailsPtr details) override;
void Abort() override;
- void Complete(payments::mojom::PaymentComplete result) override {}
- void CanMakePayment() override {}
+ void Complete(mojom::PaymentComplete result) override;
+ void CanMakePayment() override;
+
+ // PaymentRequestSpec::Observer:
+ void OnSpecUpdated() override {}
+ void OnInvalidSpecProvided() override;
+
+ // PaymentRequestState::Delegate:
+ void OnPaymentResponseAvailable(mojom::PaymentResponsePtr response) override;
+ void OnShippingOptionIdSelected(std::string shipping_option_id) override;
+ void OnShippingAddressSelected(mojom::PaymentAddressPtr address) override;
// Called when the user explicitely cancelled the flow. Will send a message
// to the renderer which will indirectly destroy this object (through
@@ -74,122 +83,24 @@ class PaymentRequest : payments::mojom::PaymentRequest {
// Called when the user clicks on the "Pay" button.
void Pay();
- void AddObserver(Observer* observer);
- void RemoveObserver(Observer* observer);
-
- // Returns the CurrencyFormatter instance for this PaymentRequest.
- // |locale_name| should be the result of the browser's GetApplicationLocale().
- // Note: Having multiple currencies per PaymentRequest is not supported; hence
- // the CurrencyFormatter is cached here.
- CurrencyFormatter* GetOrCreateCurrencyFormatter(
- const std::string& currency_code,
- const std::string& currency_system,
- const std::string& locale_name);
-
- // Returns the appropriate Autofill Profiles for this user. On the first
- // invocation of either getter, the profiles are fetched from the
- // PersonalDataManager; on subsequent invocations, a cached version is
- // returned. The profiles returned are owned by the request object.
- const std::vector<autofill::AutofillProfile*>& shipping_profiles() {
- return shipping_profiles_;
- }
- const std::vector<autofill::AutofillProfile*>& contact_profiles() {
- return contact_profiles_;
- }
- const std::vector<autofill::CreditCard*>& credit_cards() {
- return credit_cards_;
- }
-
- // Gets the Autofill Profile representing the shipping address or contact
- // information currently selected for this PaymentRequest flow. Can return
- // null.
- autofill::AutofillProfile* selected_shipping_profile() const {
- return selected_shipping_profile_;
- }
- autofill::AutofillProfile* selected_contact_profile() const {
- return selected_contact_profile_;
- }
- // Returns the currently selected credit card for this PaymentRequest flow.
- // It's not guaranteed to be complete. Returns nullptr if there is no selected
- // card.
- autofill::CreditCard* selected_credit_card() { return selected_credit_card_; }
-
- // Sets the |profile| to be the selected one and will update state and notify
- // observers.
- void SetSelectedShippingProfile(autofill::AutofillProfile* profile);
- void SetSelectedContactProfile(autofill::AutofillProfile* profile);
- void SetSelectedCreditCard(autofill::CreditCard* card);
-
- autofill::PersonalDataManager* personal_data_manager() {
- return delegate_->GetPersonalDataManager();
- }
-
- payments::mojom::PaymentDetails* details() { return details_.get(); }
- const std::vector<std::string>& supported_card_networks() {
- return supported_card_networks_;
- }
content::WebContents* web_contents() { return web_contents_; }
- bool request_shipping() const { return options_->request_shipping; }
- bool request_payer_name() const { return options_->request_payer_name; }
- bool request_payer_phone() const { return options_->request_payer_phone; }
- bool request_payer_email() const { return options_->request_payer_email; }
-
- bool is_ready_to_pay() { return is_ready_to_pay_; }
+ PaymentRequestSpec* spec() { return spec_.get(); }
+ PaymentRequestState* state() { return state_.get(); }
private:
- // Fetches the Autofill Profiles for this user from the PersonalDataManager,
- // and stores copies of them, owned by this Request, in profile_cache_.
- void PopulateProfileCache();
-
- // Sets the default values for the selected Shipping and Contact profiles, as
- // well as the selected Credit Card.
- void SetDefaultProfileSelections();
-
- // Validates the |method_data| and fills |supported_card_networks_|.
- void PopulateValidatedMethodData(
- const std::vector<payments::mojom::PaymentMethodDataPtr>& method_data);
-
- // Updates |is_ready_to_pay_| with the current state, by validating that all
- // the required information is available and notify observers.
- void UpdateIsReadyToPayAndNotifyObservers();
-
- // Notifies all observers that selected information has changed.
- void NotifyOnSelectedInformationChanged();
-
- // Returns whether the selected data satisfies the PaymentDetails requirements
- // (payment methods).
- bool ArePaymentDetailsSatisfied();
- // Returns whether the selected data satisfies the PaymentOptions requirements
- // (contact info, shipping address).
- bool ArePaymentOptionsSatisfied();
-
content::WebContents* web_contents_;
std::unique_ptr<PaymentRequestDelegate> delegate_;
// |manager_| owns this PaymentRequest.
PaymentRequestWebContentsManager* manager_;
- mojo::Binding<payments::mojom::PaymentRequest> binding_;
- payments::mojom::PaymentRequestClientPtr client_;
- payments::mojom::PaymentDetailsPtr details_;
- payments::mojom::PaymentOptionsPtr options_;
- std::unique_ptr<CurrencyFormatter> currency_formatter_;
- // A set of supported basic card networks.
- std::vector<std::string> supported_card_networks_;
- bool is_ready_to_pay_;
-
- base::ObserverList<Observer> observers_;
-
- // Profiles may change due to (e.g.) sync events, so profiles are cached after
- // loading and owned here. They are populated once only, and ordered by
- // frecency.
- std::vector<std::unique_ptr<autofill::AutofillProfile>> profile_cache_;
- std::vector<autofill::AutofillProfile*> shipping_profiles_;
- std::vector<autofill::AutofillProfile*> contact_profiles_;
- autofill::AutofillProfile* selected_shipping_profile_;
- autofill::AutofillProfile* selected_contact_profile_;
- std::vector<std::unique_ptr<autofill::CreditCard>> card_cache_;
- std::vector<autofill::CreditCard*> credit_cards_;
- autofill::CreditCard* selected_credit_card_;
+ mojo::Binding<mojom::PaymentRequest> binding_;
+ mojom::PaymentRequestClientPtr client_;
+
+ std::unique_ptr<PaymentRequestSpec> spec_;
+ std::unique_ptr<PaymentRequestState> state_;
+
+ // May be null, must outlive this object.
+ ObserverForTest* observer_for_testing_;
DISALLOW_COPY_AND_ASSIGN(PaymentRequest);
};
diff --git a/chromium/components/payments/content/payment_request.mojom b/chromium/components/payments/content/payment_request.mojom
index d8ad5833f48..600838286ad 100644
--- a/chromium/components/payments/content/payment_request.mojom
+++ b/chromium/components/payments/content/payment_request.mojom
@@ -183,11 +183,11 @@ struct PaymentDetailsModifier {
};
struct PaymentDetails {
- PaymentItem total;
+ PaymentItem? total;
array<PaymentItem> display_items;
array<PaymentShippingOption> shipping_options;
array<PaymentDetailsModifier> modifiers;
- string error;
+ string error = "";
};
enum PaymentShippingType {
diff --git a/chromium/components/payments/content/payment_request_delegate.h b/chromium/components/payments/content/payment_request_delegate.h
deleted file mode 100644
index 46faaaea93a..00000000000
--- a/chromium/components/payments/content/payment_request_delegate.h
+++ /dev/null
@@ -1,38 +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_PAYMENTS_CONTENT_PAYMENT_REQUEST_DELEGATE_H_
-#define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_DELEGATE_H_
-
-#include <string>
-
-namespace autofill {
-class PersonalDataManager;
-}
-
-namespace payments {
-
-class PaymentRequest;
-
-class PaymentRequestDelegate {
- public:
- virtual ~PaymentRequestDelegate() {}
-
- // Shows the Payment Request dialog for the given |request|.
- virtual void ShowDialog(PaymentRequest* request) = 0;
-
- // Closes the same dialog that was opened by this delegate. Must be safe to
- // call when the dialog is not showing.
- virtual void CloseDialog() = 0;
-
- // Gets the PersonalDataManager associated with this PaymentRequest flow.
- // Cannot be null.
- virtual autofill::PersonalDataManager* GetPersonalDataManager() = 0;
-
- virtual const std::string& GetApplicationLocale() const = 0;
-};
-
-} // namespace payments
-
-#endif // COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_DELEGATE_H_
diff --git a/chromium/components/payments/content/payment_request_dialog.h b/chromium/components/payments/content/payment_request_dialog.h
index 5befff8d08f..c73413963b4 100644
--- a/chromium/components/payments/content/payment_request_dialog.h
+++ b/chromium/components/payments/content/payment_request_dialog.h
@@ -5,6 +5,13 @@
#ifndef COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_DIALOG_H_
#define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_DIALOG_H_
+#include "base/memory/weak_ptr.h"
+#include "components/autofill/core/browser/payments/full_card_request.h"
+
+namespace content {
+class WebContents;
+}
+
namespace payments {
// Used to interact with a cross-platform Payment Request dialog.
@@ -15,6 +22,16 @@ class PaymentRequestDialog {
virtual void ShowDialog() = 0;
virtual void CloseDialog() = 0;
+
+ virtual void ShowErrorMessage() = 0;
+
+ // Shows the CVC unmask sheet and starts a FullCardRequest with the info
+ // entered by the user.
+ virtual void ShowCvcUnmaskPrompt(
+ const autofill::CreditCard& credit_card,
+ base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate>
+ result_delegate,
+ content::WebContents* web_contents) = 0;
};
} // namespace payments
diff --git a/chromium/components/payments/content/payment_request_spec.cc b/chromium/components/payments/content/payment_request_spec.cc
new file mode 100644
index 00000000000..6fbfc5f63cd
--- /dev/null
+++ b/chromium/components/payments/content/payment_request_spec.cc
@@ -0,0 +1,220 @@
+// 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/payments/content/payment_request_spec.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "components/payments/core/payment_method_data.h"
+#include "components/payments/core/payment_request_data_util.h"
+
+namespace payments {
+
+namespace {
+
+// Returns the card network name associated with a given BasicCardNetwork. Names
+// are inspired by https://www.w3.org/Payments/card-network-ids.
+std::string GetBasicCardNetworkName(const mojom::BasicCardNetwork& network) {
+ switch (network) {
+ case mojom::BasicCardNetwork::AMEX:
+ return "amex";
+ case mojom::BasicCardNetwork::DINERS:
+ return "diners";
+ case mojom::BasicCardNetwork::DISCOVER:
+ return "discover";
+ case mojom::BasicCardNetwork::JCB:
+ return "jcb";
+ case mojom::BasicCardNetwork::MASTERCARD:
+ return "mastercard";
+ case mojom::BasicCardNetwork::MIR:
+ return "mir";
+ case mojom::BasicCardNetwork::UNIONPAY:
+ return "unionpay";
+ case mojom::BasicCardNetwork::VISA:
+ return "visa";
+ }
+ NOTREACHED();
+ return std::string();
+}
+
+} // namespace
+
+const char kBasicCardMethodName[] = "basic-card";
+
+PaymentRequestSpec::PaymentRequestSpec(
+ mojom::PaymentOptionsPtr options,
+ mojom::PaymentDetailsPtr details,
+ std::vector<mojom::PaymentMethodDataPtr> method_data,
+ Observer* observer,
+ const std::string& app_locale)
+ : options_(std::move(options)),
+ details_(std::move(details)),
+ app_locale_(app_locale),
+ selected_shipping_option_(nullptr),
+ observer_for_testing_(nullptr) {
+ if (observer)
+ AddObserver(observer);
+ UpdateSelectedShippingOption();
+ PopulateValidatedMethodData(method_data);
+}
+PaymentRequestSpec::~PaymentRequestSpec() {}
+
+void PaymentRequestSpec::UpdateWith(mojom::PaymentDetailsPtr details) {
+ details_ = std::move(details);
+ // We reparse the |details_| and update the observers.
+ UpdateSelectedShippingOption();
+ NotifyOnSpecUpdated();
+}
+
+void PaymentRequestSpec::AddObserver(Observer* observer) {
+ CHECK(observer);
+ observers_.AddObserver(observer);
+}
+
+void PaymentRequestSpec::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+bool PaymentRequestSpec::request_shipping() const {
+ return options_->request_shipping;
+}
+bool PaymentRequestSpec::request_payer_name() const {
+ return options_->request_payer_name;
+}
+bool PaymentRequestSpec::request_payer_phone() const {
+ return options_->request_payer_phone;
+}
+bool PaymentRequestSpec::request_payer_email() const {
+ return options_->request_payer_email;
+}
+
+PaymentShippingType PaymentRequestSpec::shipping_type() const {
+ // Transform Mojo-specific enum into platform-agnostic equivalent.
+ switch (options_->shipping_type) {
+ case mojom::PaymentShippingType::DELIVERY:
+ return PaymentShippingType::DELIVERY;
+ case payments::mojom::PaymentShippingType::PICKUP:
+ return PaymentShippingType::PICKUP;
+ case payments::mojom::PaymentShippingType::SHIPPING:
+ return PaymentShippingType::SHIPPING;
+ default:
+ NOTREACHED();
+ }
+ // Needed for compilation on some platforms.
+ return PaymentShippingType::SHIPPING;
+}
+
+bool PaymentRequestSpec::IsMethodSupportedThroughBasicCard(
+ const std::string& method_name) {
+ return basic_card_specified_networks_.count(method_name) > 0;
+}
+
+base::string16 PaymentRequestSpec::GetFormattedCurrencyAmount(
+ const std::string& amount) {
+ CurrencyFormatter* formatter = GetOrCreateCurrencyFormatter(
+ details_->total->amount->currency,
+ details_->total->amount->currency_system, app_locale_);
+ return formatter->Format(amount);
+}
+
+std::string PaymentRequestSpec::GetFormattedCurrencyCode() {
+ CurrencyFormatter* formatter = GetOrCreateCurrencyFormatter(
+ details_->total->amount->currency,
+ details_->total->amount->currency_system, app_locale_);
+
+ return formatter->formatted_currency_code();
+}
+
+void PaymentRequestSpec::StartWaitingForUpdateWith(
+ PaymentRequestSpec::UpdateReason reason) {
+ for (auto& observer : observers_) {
+ observer.OnStartUpdating(reason);
+ }
+}
+
+void PaymentRequestSpec::PopulateValidatedMethodData(
+ const std::vector<mojom::PaymentMethodDataPtr>& method_data_mojom) {
+ if (method_data_mojom.empty()) {
+ LOG(ERROR) << "Invalid payment methods or data";
+ NotifyOnInvalidSpecProvided();
+ return;
+ }
+
+ std::vector<PaymentMethodData> method_data_vector;
+ method_data_vector.reserve(method_data_mojom.size());
+ for (const mojom::PaymentMethodDataPtr& method_data_entry :
+ method_data_mojom) {
+ PaymentMethodData method_data;
+ method_data.supported_methods = method_data_entry->supported_methods;
+ // Transfer the supported basic card networks.
+ std::vector<std::string> supported_networks;
+ for (const mojom::BasicCardNetwork& network :
+ method_data_entry->supported_networks) {
+ supported_networks.push_back(GetBasicCardNetworkName(network));
+ }
+ method_data.supported_networks = std::move(supported_networks);
+
+ // TODO(crbug.com/708603): Add browser-side support for
+ // |method_data.supported_types|.
+ method_data_vector.push_back(std::move(method_data));
+ }
+
+ if (!data_util::ParseBasicCardSupportedNetworks(
+ method_data_vector, &supported_card_networks_,
+ &basic_card_specified_networks_)) {
+ LOG(ERROR) << "Invalid payment methods or data";
+ NotifyOnInvalidSpecProvided();
+ return;
+ }
+ supported_card_networks_set_.insert(supported_card_networks_.begin(),
+ supported_card_networks_.end());
+}
+
+void PaymentRequestSpec::UpdateSelectedShippingOption() {
+ if (!request_shipping())
+ return;
+
+ // As per the spec, the selected shipping option should initially be the last
+ // one in the array that has its selected field set to true.
+ auto selected_shipping_option_it = std::find_if(
+ details().shipping_options.rbegin(), details().shipping_options.rend(),
+ [](const payments::mojom::PaymentShippingOptionPtr& element) {
+ return element->selected;
+ });
+ if (selected_shipping_option_it != details().shipping_options.rend()) {
+ selected_shipping_option_ = selected_shipping_option_it->get();
+ } else {
+ // It's possible that there is no selected shipping option.
+ // TODO(crbug.com/710004): Show an error in this case.
+ selected_shipping_option_ = nullptr;
+ }
+}
+
+void PaymentRequestSpec::NotifyOnInvalidSpecProvided() {
+ for (auto& observer : observers_)
+ observer.OnInvalidSpecProvided();
+ if (observer_for_testing_)
+ observer_for_testing_->OnInvalidSpecProvided();
+}
+
+void PaymentRequestSpec::NotifyOnSpecUpdated() {
+ for (auto& observer : observers_)
+ observer.OnSpecUpdated();
+ if (observer_for_testing_)
+ observer_for_testing_->OnSpecUpdated();
+}
+
+CurrencyFormatter* PaymentRequestSpec::GetOrCreateCurrencyFormatter(
+ const std::string& currency_code,
+ const std::string& currency_system,
+ const std::string& locale_name) {
+ if (!currency_formatter_) {
+ currency_formatter_.reset(
+ new CurrencyFormatter(currency_code, currency_system, locale_name));
+ }
+ return currency_formatter_.get();
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/payment_request_spec.h b/chromium/components/payments/content/payment_request_spec.h
new file mode 100644
index 00000000000..de0187a5aaa
--- /dev/null
+++ b/chromium/components/payments/content/payment_request_spec.h
@@ -0,0 +1,163 @@
+// 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_PAYMENTS_CONTENT_PAYMENT_REQUEST_SPEC_H_
+#define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_SPEC_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "components/payments/content/payment_request.mojom.h"
+#include "components/payments/core/currency_formatter.h"
+#include "components/payments/core/payment_options_provider.h"
+
+namespace payments {
+
+// Identifier for the basic card payment method in the PaymentMethodData.
+extern const char kBasicCardMethodName[];
+
+// The spec contains all the options that the merchant has specified about this
+// Payment Request. It's a (mostly) read-only view, which can be updated in
+// certain occasions by the merchant (see API).
+class PaymentRequestSpec : public PaymentOptionsProvider {
+ public:
+ // This enum represents which bit of information was changed to trigger an
+ // update roundtrip with the website.
+ enum class UpdateReason {
+ NONE,
+ SHIPPING_OPTION,
+ SHIPPING_ADDRESS,
+ };
+
+ // Any class call add itself as Observer via AddObserver() and receive
+ // notification about spec events.
+ class Observer {
+ public:
+ // Called when the provided spec (details, options, method_data) is invalid.
+ virtual void OnInvalidSpecProvided() = 0;
+
+ // Called when the website is notified that the user selected shipping
+ // options or a shipping address. This will be followed by a call to
+ // OnSpecUpdated or the PaymentRequest being aborted due to a timeout.
+ virtual void OnStartUpdating(UpdateReason reason) {}
+
+ // Called when the provided spec has changed.
+ virtual void OnSpecUpdated() = 0;
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ PaymentRequestSpec(mojom::PaymentOptionsPtr options,
+ mojom::PaymentDetailsPtr details,
+ std::vector<mojom::PaymentMethodDataPtr> method_data,
+ PaymentRequestSpec::Observer* observer,
+ const std::string& app_locale);
+ ~PaymentRequestSpec() override;
+
+ // Called when the merchant has new PaymentDetails. Will recompute every spec
+ // state that depends on |details|.
+ void UpdateWith(mojom::PaymentDetailsPtr details);
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // PaymentOptionsProvider:
+ bool request_shipping() const override;
+ bool request_payer_name() const override;
+ bool request_payer_phone() const override;
+ bool request_payer_email() const override;
+ PaymentShippingType shipping_type() const override;
+
+ const std::vector<std::string>& supported_card_networks() const {
+ return supported_card_networks_;
+ }
+ const std::set<std::string>& supported_card_networks_set() const {
+ return supported_card_networks_set_;
+ }
+ // Returns whether the |method_name| was specified as supported through the
+ // "basic-card" payment method. If false, it means either the |method_name| is
+ // not supported at all, or specified directly in supportedMethods.
+ bool IsMethodSupportedThroughBasicCard(const std::string& method_name);
+
+ // Uses CurrencyFormatter to format |amount| with the currency symbol for this
+ // request's currency. Will use currency of the "total" display item, because
+ // all items are supposed to have the same currency in a given request.
+ base::string16 GetFormattedCurrencyAmount(const std::string& amount);
+
+ // Uses CurrencyFormatter to get the formatted currency code for this
+ // request's currency. Will use currency of the "total" display item, because
+ // all items are supposed to have the same currency in a given request.
+ std::string GetFormattedCurrencyCode();
+
+ mojom::PaymentShippingOption* selected_shipping_option() const {
+ return selected_shipping_option_;
+ }
+
+ const mojom::PaymentDetails& details() const { return *details_.get(); }
+
+ void StartWaitingForUpdateWith(UpdateReason reason);
+
+ private:
+ friend class PaymentRequestDialogView;
+ void add_observer_for_testing(Observer* observer_for_testing) {
+ observer_for_testing_ = observer_for_testing;
+ }
+
+ // Validates the |method_data| and fills |supported_card_networks_|,
+ // |supported_card_networks_set_| and |basic_card_specified_networks_|.
+ void PopulateValidatedMethodData(
+ const std::vector<mojom::PaymentMethodDataPtr>& method_data);
+
+ // Updates the selected_shipping_option based on the data passed to this
+ // payment request by the website. This will set selected_shipping_option_ to
+ // the last option marked selected in the options array.
+ void UpdateSelectedShippingOption();
+
+ // Will notify all observers that the spec is invalid.
+ void NotifyOnInvalidSpecProvided();
+ // Will notify all observers that the spec has changed.
+ void NotifyOnSpecUpdated();
+
+ // Returns the CurrencyFormatter instance for this PaymentRequest.
+ // |locale_name| should be the result of the browser's GetApplicationLocale().
+ // Note: Having multiple currencies per PaymentRequest is not supported; hence
+ // the CurrencyFormatter is cached here.
+ CurrencyFormatter* GetOrCreateCurrencyFormatter(
+ const std::string& currency_code,
+ const std::string& currency_system,
+ const std::string& locale_name);
+
+ mojom::PaymentOptionsPtr options_;
+ mojom::PaymentDetailsPtr details_;
+ const std::string app_locale_;
+ // The currently shipping option as specified by the merchant.
+ mojom::PaymentShippingOption* selected_shipping_option_;
+
+ std::unique_ptr<CurrencyFormatter> currency_formatter_;
+
+ // A list/set of supported basic card networks. The list is used to keep the
+ // order in which they were specified by the merchant. The set is used for
+ // fast lookup of supported methods.
+ std::vector<std::string> supported_card_networks_;
+ std::set<std::string> supported_card_networks_set_;
+
+ // Only the set of basic-card specified networks. NOTE: callers should use
+ // |supported_card_networks_set_| to check merchant support.
+ std::set<std::string> basic_card_specified_networks_;
+
+ // The |observer_for_testing_| will fire after all the |observers_| have been
+ // notified.
+ base::ObserverList<Observer> observers_;
+ Observer* observer_for_testing_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaymentRequestSpec);
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_SPEC_H_
diff --git a/chromium/components/payments/content/payment_request_spec_unittest.cc b/chromium/components/payments/content/payment_request_spec_unittest.cc
new file mode 100644
index 00000000000..a90d1e45191
--- /dev/null
+++ b/chromium/components/payments/content/payment_request_spec_unittest.cc
@@ -0,0 +1,317 @@
+// 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/payments/content/payment_request_spec.h"
+
+#include <utility>
+
+#include "base/memory/weak_ptr.h"
+#include "components/payments/content/payment_request.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+class PaymentRequestSpecTest : public testing::Test,
+ public PaymentRequestSpec::Observer {
+ protected:
+ ~PaymentRequestSpecTest() override {}
+
+ void OnInvalidSpecProvided() override {
+ on_invalid_spec_provided_called_ = true;
+ }
+ void OnSpecUpdated() override { on_spec_updated_called_ = true; }
+
+ void RecreateSpecWithMethodData(
+ std::vector<mojom::PaymentMethodDataPtr> method_data) {
+ spec_ = base::MakeUnique<PaymentRequestSpec>(
+ mojom::PaymentOptions::New(), mojom::PaymentDetails::New(),
+ std::move(method_data), this, "en-US");
+ }
+
+ void RecreateSpecWithOptionsAndDetails(mojom::PaymentOptionsPtr options,
+ mojom::PaymentDetailsPtr details) {
+ spec_ = base::MakeUnique<PaymentRequestSpec>(
+ std::move(options), std::move(details),
+ std::vector<mojom::PaymentMethodDataPtr>(), this, "en-US");
+ }
+
+ PaymentRequestSpec* spec() { return spec_.get(); }
+ bool on_invalid_spec_provided_called() {
+ return on_invalid_spec_provided_called_;
+ }
+
+ private:
+ std::unique_ptr<PaymentRequestSpec> spec_;
+ bool on_invalid_spec_provided_called_ = false;
+ bool on_spec_updated_called_ = false;
+};
+
+// Test that empty method data notifies observers of an invalid spec.
+TEST_F(PaymentRequestSpecTest, EmptyMethodData) {
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ RecreateSpecWithMethodData(std::move(method_data));
+ EXPECT_TRUE(on_invalid_spec_provided_called());
+
+ // No supported card networks.
+ EXPECT_EQ(0u, spec()->supported_card_networks().size());
+}
+
+TEST_F(PaymentRequestSpecTest, IsMethodSupportedThroughBasicCard) {
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_methods.push_back("visa");
+ entry->supported_methods.push_back("mastercard");
+ entry->supported_methods.push_back("invalid");
+ entry->supported_methods.push_back("");
+ entry->supported_methods.push_back("visa");
+ mojom::PaymentMethodDataPtr entry2 = mojom::PaymentMethodData::New();
+ entry2->supported_methods.push_back("basic-card");
+ entry2->supported_networks.push_back(mojom::BasicCardNetwork::UNIONPAY);
+ entry2->supported_networks.push_back(mojom::BasicCardNetwork::JCB);
+ entry2->supported_networks.push_back(mojom::BasicCardNetwork::VISA);
+
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ method_data.push_back(std::move(entry));
+ method_data.push_back(std::move(entry2));
+
+ RecreateSpecWithMethodData(std::move(method_data));
+
+ // Only unionpay and jcb are supported through basic-card.
+ EXPECT_TRUE(spec()->IsMethodSupportedThroughBasicCard("unionpay"));
+ EXPECT_TRUE(spec()->IsMethodSupportedThroughBasicCard("jcb"));
+ // "visa" is NOT supported through basic card because it was specified
+ // directly first in supportedMethods.
+ EXPECT_FALSE(spec()->IsMethodSupportedThroughBasicCard("visa"));
+ EXPECT_FALSE(spec()->IsMethodSupportedThroughBasicCard("mastercard"));
+ EXPECT_FALSE(spec()->IsMethodSupportedThroughBasicCard("diners"));
+ EXPECT_FALSE(spec()->IsMethodSupportedThroughBasicCard("garbage"));
+}
+
+// Order matters when parsing the supportedMethods and basic card networks.
+TEST_F(PaymentRequestSpecTest,
+ IsMethodSupportedThroughBasicCard_DifferentOrder) {
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_methods.push_back("basic-card");
+ entry->supported_networks.push_back(mojom::BasicCardNetwork::UNIONPAY);
+ entry->supported_networks.push_back(mojom::BasicCardNetwork::VISA);
+ mojom::PaymentMethodDataPtr entry2 = mojom::PaymentMethodData::New();
+ entry2->supported_methods.push_back("visa");
+ entry2->supported_methods.push_back("unionpay");
+ entry2->supported_methods.push_back("jcb");
+
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ method_data.push_back(std::move(entry));
+ method_data.push_back(std::move(entry2));
+
+ RecreateSpecWithMethodData(std::move(method_data));
+
+ // unionpay and visa are supported through basic-card; they were specified
+ // first as basic card networks.
+ EXPECT_TRUE(spec()->IsMethodSupportedThroughBasicCard("unionpay"));
+ EXPECT_TRUE(spec()->IsMethodSupportedThroughBasicCard("visa"));
+ // "jcb" is NOT supported through basic card; it was specified directly
+ // as a supportedMethods
+ EXPECT_FALSE(spec()->IsMethodSupportedThroughBasicCard("jcb"));
+}
+
+// Test that parsing supported methods (with invalid values and duplicates)
+// works as expected.
+TEST_F(PaymentRequestSpecTest, SupportedMethods) {
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_methods.push_back("visa");
+ entry->supported_methods.push_back("mastercard");
+ entry->supported_methods.push_back("invalid");
+ entry->supported_methods.push_back("");
+ entry->supported_methods.push_back("visa");
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ method_data.push_back(std::move(entry));
+
+ RecreateSpecWithMethodData(std::move(method_data));
+ EXPECT_FALSE(on_invalid_spec_provided_called());
+
+ // Only "visa" and "mastercard" remain, in order.
+ EXPECT_EQ(2u, spec()->supported_card_networks().size());
+ EXPECT_EQ("visa", spec()->supported_card_networks()[0]);
+ EXPECT_EQ("mastercard", spec()->supported_card_networks()[1]);
+}
+
+// Test that parsing supported methods in different method data entries (with
+// invalid values and duplicates) works as expected.
+TEST_F(PaymentRequestSpecTest, SupportedMethods_MultipleEntries) {
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_methods.push_back("visa");
+ mojom::PaymentMethodDataPtr entry2 = mojom::PaymentMethodData::New();
+ entry2->supported_methods.push_back("mastercard");
+ mojom::PaymentMethodDataPtr entry3 = mojom::PaymentMethodData::New();
+ entry3->supported_methods.push_back("invalid");
+
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ method_data.push_back(std::move(entry));
+ method_data.push_back(std::move(entry2));
+ method_data.push_back(std::move(entry3));
+
+ RecreateSpecWithMethodData(std::move(method_data));
+ EXPECT_FALSE(on_invalid_spec_provided_called());
+
+ // Only "visa" and "mastercard" remain, in order.
+ EXPECT_EQ(2u, spec()->supported_card_networks().size());
+ EXPECT_EQ("visa", spec()->supported_card_networks()[0]);
+ EXPECT_EQ("mastercard", spec()->supported_card_networks()[1]);
+}
+
+// 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) {
+ // First entry is valid.
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_methods.push_back("visa");
+ // Empty method data entry.
+ mojom::PaymentMethodDataPtr entry2 = mojom::PaymentMethodData::New();
+ // Valid one follows the empty.
+ mojom::PaymentMethodDataPtr entry3 = mojom::PaymentMethodData::New();
+ entry3->supported_methods.push_back("mastercard");
+
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ method_data.push_back(std::move(entry));
+ method_data.push_back(std::move(entry2));
+ method_data.push_back(std::move(entry3));
+
+ RecreateSpecWithMethodData(std::move(method_data));
+ EXPECT_TRUE(on_invalid_spec_provided_called());
+
+ // Visa was parsed, but not mastercard.
+ EXPECT_EQ(1u, spec()->supported_card_networks().size());
+ EXPECT_EQ("visa", spec()->supported_card_networks()[0]);
+}
+
+// Test that only specifying basic-card means that all are supported.
+TEST_F(PaymentRequestSpecTest, SupportedMethods_OnlyBasicCard) {
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_methods.push_back("basic-card");
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ method_data.push_back(std::move(entry));
+
+ RecreateSpecWithMethodData(std::move(method_data));
+ EXPECT_FALSE(on_invalid_spec_provided_called());
+
+ // All of the basic card networks are supported.
+ EXPECT_EQ(8u, spec()->supported_card_networks().size());
+ EXPECT_EQ("amex", spec()->supported_card_networks()[0]);
+ EXPECT_EQ("diners", spec()->supported_card_networks()[1]);
+ EXPECT_EQ("discover", spec()->supported_card_networks()[2]);
+ EXPECT_EQ("jcb", spec()->supported_card_networks()[3]);
+ EXPECT_EQ("mastercard", spec()->supported_card_networks()[4]);
+ EXPECT_EQ("mir", spec()->supported_card_networks()[5]);
+ EXPECT_EQ("unionpay", spec()->supported_card_networks()[6]);
+ EXPECT_EQ("visa", spec()->supported_card_networks()[7]);
+}
+
+// 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) {
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_methods.push_back("jcb");
+ entry->supported_methods.push_back("basic-card");
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ method_data.push_back(std::move(entry));
+
+ RecreateSpecWithMethodData(std::move(method_data));
+ EXPECT_FALSE(on_invalid_spec_provided_called());
+
+ // All of the basic card networks are supported, but JCB is first because it
+ // was specified first.
+ EXPECT_EQ(8u, spec()->supported_card_networks().size());
+ EXPECT_EQ("jcb", spec()->supported_card_networks()[0]);
+ EXPECT_EQ("amex", spec()->supported_card_networks()[1]);
+ EXPECT_EQ("diners", spec()->supported_card_networks()[2]);
+ EXPECT_EQ("discover", spec()->supported_card_networks()[3]);
+ EXPECT_EQ("mastercard", spec()->supported_card_networks()[4]);
+ EXPECT_EQ("mir", spec()->supported_card_networks()[5]);
+ EXPECT_EQ("unionpay", spec()->supported_card_networks()[6]);
+ EXPECT_EQ("visa", spec()->supported_card_networks()[7]);
+}
+
+// Test that specifying basic-card with a supported network (with previous
+// supported methods) will work as expected
+TEST_F(PaymentRequestSpecTest, SupportedMethods_BasicCard_Overlap) {
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_methods.push_back("mastercard");
+ entry->supported_methods.push_back("visa");
+ // Visa and mastercard are repeated, but in reverse order.
+ mojom::PaymentMethodDataPtr entry2 = mojom::PaymentMethodData::New();
+ entry2->supported_methods.push_back("basic-card");
+ entry2->supported_networks.push_back(mojom::BasicCardNetwork::VISA);
+ entry2->supported_networks.push_back(mojom::BasicCardNetwork::MASTERCARD);
+ entry2->supported_networks.push_back(mojom::BasicCardNetwork::UNIONPAY);
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ method_data.push_back(std::move(entry));
+ method_data.push_back(std::move(entry2));
+
+ RecreateSpecWithMethodData(std::move(method_data));
+ EXPECT_FALSE(on_invalid_spec_provided_called());
+
+ EXPECT_EQ(3u, spec()->supported_card_networks().size());
+ EXPECT_EQ("mastercard", spec()->supported_card_networks()[0]);
+ EXPECT_EQ("visa", spec()->supported_card_networks()[1]);
+ EXPECT_EQ("unionpay", spec()->supported_card_networks()[2]);
+}
+
+// Test that specifying basic-card with supported networks after specifying
+// some methods
+TEST_F(PaymentRequestSpecTest,
+ SupportedMethods_BasicCard_WithSupportedNetworks) {
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_methods.push_back("basic-card");
+ entry->supported_networks.push_back(mojom::BasicCardNetwork::VISA);
+ entry->supported_networks.push_back(mojom::BasicCardNetwork::UNIONPAY);
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ method_data.push_back(std::move(entry));
+
+ RecreateSpecWithMethodData(std::move(method_data));
+ EXPECT_FALSE(on_invalid_spec_provided_called());
+
+ // Only the specified networks are supported.
+ EXPECT_EQ(2u, spec()->supported_card_networks().size());
+ EXPECT_EQ("visa", spec()->supported_card_networks()[0]);
+ EXPECT_EQ("unionpay", spec()->supported_card_networks()[1]);
+}
+
+// Test that the last shipping option is selected, even in the case of
+// updateWith.
+TEST_F(PaymentRequestSpecTest, ShippingOptionsSelection) {
+ std::vector<mojom::PaymentShippingOptionPtr> shipping_options;
+ mojom::PaymentShippingOptionPtr option = mojom::PaymentShippingOption::New();
+ option->id = "option:1";
+ option->selected = false;
+ shipping_options.push_back(std::move(option));
+ mojom::PaymentShippingOptionPtr option2 = mojom::PaymentShippingOption::New();
+ option2->id = "option:2";
+ option2->selected = true;
+ shipping_options.push_back(std::move(option2));
+ mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New();
+ details->shipping_options = std::move(shipping_options);
+
+ mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New();
+ options->request_shipping = true;
+ RecreateSpecWithOptionsAndDetails(std::move(options), std::move(details));
+
+ EXPECT_EQ("option:2", spec()->selected_shipping_option()->id);
+
+ std::vector<mojom::PaymentShippingOptionPtr> new_shipping_options;
+ mojom::PaymentShippingOptionPtr new_option =
+ mojom::PaymentShippingOption::New();
+ new_option->id = "option:1";
+ new_option->selected = false;
+ shipping_options.push_back(std::move(new_option));
+ mojom::PaymentShippingOptionPtr new_option2 =
+ mojom::PaymentShippingOption::New();
+ new_option2->id = "option:2";
+ new_option2->selected = true;
+ new_shipping_options.push_back(std::move(new_option2));
+ mojom::PaymentDetailsPtr new_details = mojom::PaymentDetails::New();
+ new_details->shipping_options = std::move(new_shipping_options);
+
+ spec()->UpdateWith(std::move(new_details));
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/payment_request_state.cc b/chromium/components/payments/content/payment_request_state.cc
new file mode 100644
index 00000000000..c3f152640f2
--- /dev/null
+++ b/chromium/components/payments/content/payment_request_state.cc
@@ -0,0 +1,238 @@
+// 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/payments/content/payment_request_state.h"
+
+#include <algorithm>
+#include <set>
+#include <utility>
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_data_util.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/payments/content/payment_request_spec.h"
+#include "components/payments/content/payment_response_helper.h"
+#include "components/payments/core/autofill_payment_instrument.h"
+#include "components/payments/core/payment_instrument.h"
+#include "components/payments/core/payment_request_delegate.h"
+#include "components/payments/core/profile_util.h"
+
+namespace payments {
+
+PaymentRequestState::PaymentRequestState(
+ PaymentRequestSpec* spec,
+ Delegate* delegate,
+ const std::string& app_locale,
+ autofill::PersonalDataManager* personal_data_manager,
+ PaymentRequestDelegate* payment_request_delegate)
+ : is_ready_to_pay_(false),
+ app_locale_(app_locale),
+ spec_(spec),
+ delegate_(delegate),
+ personal_data_manager_(personal_data_manager),
+ selected_shipping_profile_(nullptr),
+ selected_contact_profile_(nullptr),
+ selected_instrument_(nullptr),
+ payment_request_delegate_(payment_request_delegate) {
+ PopulateProfileCache();
+ SetDefaultProfileSelections();
+}
+PaymentRequestState::~PaymentRequestState() {}
+
+void PaymentRequestState::OnPaymentResponseReady(
+ mojom::PaymentResponsePtr payment_response) {
+ delegate_->OnPaymentResponseAvailable(std::move(payment_response));
+}
+
+bool PaymentRequestState::CanMakePayment() const {
+ for (const std::unique_ptr<PaymentInstrument>& instrument :
+ available_instruments_) {
+ if (instrument->IsValidForCanMakePayment() &&
+ spec_->supported_card_networks_set().count(
+ instrument.get()->method_name())) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void PaymentRequestState::AddObserver(Observer* observer) {
+ CHECK(observer);
+ observers_.AddObserver(observer);
+}
+
+void PaymentRequestState::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void PaymentRequestState::GeneratePaymentResponse() {
+ DCHECK(is_ready_to_pay());
+
+ // Once the response is ready, will call back into OnPaymentResponseReady.
+ response_helper_ = base::MakeUnique<PaymentResponseHelper>(
+ app_locale_, spec_, selected_instrument_, selected_shipping_profile_,
+ selected_contact_profile_, this);
+}
+
+void PaymentRequestState::AddAutofillPaymentInstrument(
+ bool selected,
+ const autofill::CreditCard& card) {
+ std::string basic_card_network =
+ autofill::data_util::GetPaymentRequestData(card.type())
+ .basic_card_payment_type;
+ if (!spec_->supported_card_networks_set().count(basic_card_network))
+ return;
+
+ // AutofillPaymentInstrument makes a copy of |card| so it is effectively
+ // owned by this object.
+ std::unique_ptr<PaymentInstrument> instrument =
+ base::MakeUnique<AutofillPaymentInstrument>(
+ basic_card_network, card, shipping_profiles_, app_locale_,
+ payment_request_delegate_);
+ available_instruments_.push_back(std::move(instrument));
+
+ if (selected)
+ SetSelectedInstrument(available_instruments_.back().get());
+}
+
+void PaymentRequestState::SetSelectedShippingOption(
+ const std::string& shipping_option_id) {
+ spec_->StartWaitingForUpdateWith(
+ PaymentRequestSpec::UpdateReason::SHIPPING_OPTION);
+ // This will inform the merchant and will lead to them calling updateWith with
+ // new PaymentDetails.
+ delegate_->OnShippingOptionIdSelected(shipping_option_id);
+}
+
+void PaymentRequestState::SetSelectedShippingProfile(
+ autofill::AutofillProfile* profile) {
+ spec_->StartWaitingForUpdateWith(
+ PaymentRequestSpec::UpdateReason::SHIPPING_ADDRESS);
+ selected_shipping_profile_ = profile;
+ UpdateIsReadyToPayAndNotifyObservers();
+ delegate_->OnShippingAddressSelected(
+ PaymentResponseHelper::GetMojomPaymentAddressFromAutofillProfile(
+ selected_shipping_profile_, app_locale_));
+}
+
+void PaymentRequestState::SetSelectedContactProfile(
+ autofill::AutofillProfile* profile) {
+ selected_contact_profile_ = profile;
+ UpdateIsReadyToPayAndNotifyObservers();
+}
+
+void PaymentRequestState::SetSelectedInstrument(PaymentInstrument* instrument) {
+ selected_instrument_ = instrument;
+ UpdateIsReadyToPayAndNotifyObservers();
+}
+
+const std::string& PaymentRequestState::GetApplicationLocale() {
+ return app_locale_;
+}
+
+autofill::PersonalDataManager* PaymentRequestState::GetPersonalDataManager() {
+ return personal_data_manager_;
+}
+
+std::unique_ptr<const ::i18n::addressinput::Source>
+PaymentRequestState::GetAddressInputSource() {
+ return payment_request_delegate_->GetAddressInputSource();
+}
+
+std::unique_ptr<::i18n::addressinput::Storage>
+PaymentRequestState::GetAddressInputStorage() {
+ return payment_request_delegate_->GetAddressInputStorage();
+}
+
+void PaymentRequestState::PopulateProfileCache() {
+ std::vector<autofill::AutofillProfile*> profiles =
+ personal_data_manager_->GetProfilesToSuggest();
+
+ // PaymentRequest may outlive the Profiles returned by the Data Manager.
+ // Thus, we store copies, and return a vector of pointers to these copies
+ // whenever Profiles are requested. The same is true for credit cards.
+ for (size_t i = 0; i < profiles.size(); i++) {
+ profile_cache_.push_back(
+ base::MakeUnique<autofill::AutofillProfile>(*profiles[i]));
+
+ // TODO(tmartino): Implement deduplication rules specific to shipping
+ // profiles.
+ shipping_profiles_.push_back(profile_cache_[i].get());
+ }
+
+ std::vector<autofill::AutofillProfile*> raw_profiles_for_filtering(
+ profile_cache_.size());
+ std::transform(profile_cache_.begin(), profile_cache_.end(),
+ raw_profiles_for_filtering.begin(),
+ [](const std::unique_ptr<autofill::AutofillProfile>& p) {
+ return p.get();
+ });
+
+ contact_profiles_ = profile_util::FilterProfilesForContact(
+ raw_profiles_for_filtering, GetApplicationLocale(), *spec_);
+
+ // Create the list of available instruments.
+ const std::vector<autofill::CreditCard*>& cards =
+ personal_data_manager_->GetCreditCardsToSuggest();
+ for (autofill::CreditCard* card : cards)
+ AddAutofillPaymentInstrument(/*selected=*/false, *card);
+}
+
+void PaymentRequestState::SetDefaultProfileSelections() {
+ // Only pre-select an address if the merchant provided at least one selected
+ // shipping option.
+ if (!shipping_profiles().empty() && spec_->selected_shipping_option())
+ selected_shipping_profile_ = shipping_profiles()[0];
+
+ if (!contact_profiles().empty())
+ selected_contact_profile_ = contact_profiles()[0];
+
+ // TODO(crbug.com/702063): Change this code to prioritize instruments by use
+ // count and other means, and implement a way to modify this function's return
+ // value.
+ const std::vector<std::unique_ptr<PaymentInstrument>>& instruments =
+ available_instruments();
+ auto first_complete_instrument =
+ std::find_if(instruments.begin(), instruments.end(),
+ [](const std::unique_ptr<PaymentInstrument>& instrument) {
+ return instrument->IsCompleteForPayment();
+ });
+
+ selected_instrument_ = first_complete_instrument == instruments.end()
+ ? nullptr
+ : first_complete_instrument->get();
+
+ UpdateIsReadyToPayAndNotifyObservers();
+}
+
+void PaymentRequestState::UpdateIsReadyToPayAndNotifyObservers() {
+ is_ready_to_pay_ =
+ ArePaymentDetailsSatisfied() && ArePaymentOptionsSatisfied();
+ NotifyOnSelectedInformationChanged();
+}
+
+void PaymentRequestState::NotifyOnSelectedInformationChanged() {
+ for (auto& observer : observers_)
+ observer.OnSelectedInformationChanged();
+}
+
+bool PaymentRequestState::ArePaymentDetailsSatisfied() {
+ // There is no need to check for supported networks, because only supported
+ // instruments are listed/created in the flow.
+ return selected_instrument_ != nullptr &&
+ selected_instrument_->IsCompleteForPayment();
+}
+
+bool PaymentRequestState::ArePaymentOptionsSatisfied() {
+ // TODO(mathp): Have a measure of shipping address completeness.
+ if (spec_->request_shipping() && selected_shipping_profile_ == nullptr)
+ return false;
+
+ profile_util::PaymentsProfileComparator comparator(app_locale_, *spec_);
+ return comparator.IsContactInfoComplete(selected_contact_profile_);
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/payment_request_state.h b/chromium/components/payments/content/payment_request_state.h
new file mode 100644
index 00000000000..cb0b2a97dd0
--- /dev/null
+++ b/chromium/components/payments/content/payment_request_state.h
@@ -0,0 +1,201 @@
+// 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_PAYMENTS_CONTENT_PAYMENT_REQUEST_STATE_H_
+#define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_STATE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "components/payments/content/payment_request.mojom.h"
+#include "components/payments/content/payment_response_helper.h"
+
+namespace i18n {
+namespace addressinput {
+class Storage;
+class Source;
+} // namespace addressinput
+} // namespace i18n
+
+namespace autofill {
+class AutofillProfile;
+class CreditCard;
+class PersonalDataManager;
+} // namespace autofill
+
+namespace payments {
+
+class PaymentInstrument;
+class PaymentRequestDelegate;
+class PaymentRequestSpec;
+
+// Keeps track of the information currently selected by the user and whether the
+// user is ready to pay. Uses information from the PaymentRequestSpec, which is
+// what the merchant has specified, as input into the "is ready to pay"
+// computation.
+class PaymentRequestState : public PaymentResponseHelper::Delegate {
+ public:
+ // Any class call add itself as Observer via AddObserver() and receive
+ // notification about the state changing.
+ class Observer {
+ public:
+ // Called when the information (payment method, address/contact info,
+ // shipping option) changes.
+ virtual void OnSelectedInformationChanged() = 0;
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ class Delegate {
+ public:
+ // Called when the PaymentResponse is available.
+ virtual void OnPaymentResponseAvailable(
+ mojom::PaymentResponsePtr response) = 0;
+
+ // Called when the shipping option has changed to |shipping_option_id|.
+ virtual void OnShippingOptionIdSelected(std::string shipping_option_id) = 0;
+
+ // Called when the shipping address has changed to |address|.
+ virtual void OnShippingAddressSelected(
+ mojom::PaymentAddressPtr address) = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ PaymentRequestState(PaymentRequestSpec* spec,
+ Delegate* delegate,
+ const std::string& app_locale,
+ autofill::PersonalDataManager* personal_data_manager,
+ PaymentRequestDelegate* payment_request_delegate);
+ ~PaymentRequestState() override;
+
+ // PaymentResponseHelper::Delegate
+ void OnPaymentResponseReady(
+ mojom::PaymentResponsePtr payment_response) override;
+
+ // Returns whether the user has at least one instrument that satisfies the
+ // specified supported payment methods.
+ bool CanMakePayment() const;
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // Initiates the generation of the PaymentResponse. Callers should check
+ // |is_ready_to_pay|, which is inexpensive.
+ void GeneratePaymentResponse();
+
+ // Gets the Autofill Profile representing the shipping address or contact
+ // information currently selected for this PaymentRequest flow. Can return
+ // null.
+ autofill::AutofillProfile* selected_shipping_profile() const {
+ return selected_shipping_profile_;
+ }
+ autofill::AutofillProfile* selected_contact_profile() const {
+ return selected_contact_profile_;
+ }
+ // Returns the currently selected instrument for this PaymentRequest flow.
+ // It's not guaranteed to be complete. Returns nullptr if there is no selected
+ // instrument.
+ PaymentInstrument* selected_instrument() const {
+ return selected_instrument_;
+ }
+
+ // Returns the appropriate Autofill Profiles for this user. The profiles
+ // returned are owned by the PaymentRequestState.
+ const std::vector<autofill::AutofillProfile*>& shipping_profiles() {
+ return shipping_profiles_;
+ }
+ const std::vector<autofill::AutofillProfile*>& contact_profiles() {
+ return contact_profiles_;
+ }
+ const std::vector<std::unique_ptr<PaymentInstrument>>&
+ available_instruments() {
+ return available_instruments_;
+ }
+
+ // Creates and adds an AutofillPaymentInstrument, which makes a copy of
+ // |card|. |selected| indicates if the newly-created instrument should be
+ // selected, after which observers will be notified.
+ void AddAutofillPaymentInstrument(bool selected,
+ const autofill::CreditCard& card);
+
+ // Setters to change the selected information. Will have the side effect of
+ // recomputing "is ready to pay" and notify observers.
+ void SetSelectedShippingOption(const std::string& shipping_option_id);
+ void SetSelectedShippingProfile(autofill::AutofillProfile* profile);
+ void SetSelectedContactProfile(autofill::AutofillProfile* profile);
+ void SetSelectedInstrument(PaymentInstrument* instrument);
+
+ bool is_ready_to_pay() { return is_ready_to_pay_; }
+
+ const std::string& GetApplicationLocale();
+ autofill::PersonalDataManager* GetPersonalDataManager();
+ std::unique_ptr<const ::i18n::addressinput::Source> GetAddressInputSource();
+ std::unique_ptr<::i18n::addressinput::Storage> GetAddressInputStorage();
+
+ Delegate* delegate() { return delegate_; }
+
+ private:
+ // Fetches the Autofill Profiles for this user from the PersonalDataManager,
+ // and stores copies of them, owned by this PaymentRequestState, in
+ // profile_cache_.
+ void PopulateProfileCache();
+
+ // Sets the initial selections for instruments and profiles, and notifies
+ // observers.
+ void SetDefaultProfileSelections();
+
+ // Uses the user-selected information as well as the merchant spec to update
+ // |is_ready_to_pay_| with the current state, by validating that all the
+ // required information is available. Will notify observers.
+ void UpdateIsReadyToPayAndNotifyObservers();
+
+ // Notifies all observers that selected information has changed.
+ void NotifyOnSelectedInformationChanged();
+
+ // Returns whether the selected data satisfies the PaymentDetails requirements
+ // (payment methods).
+ bool ArePaymentDetailsSatisfied();
+ // Returns whether the selected data satisfies the PaymentOptions requirements
+ // (contact info, shipping address).
+ bool ArePaymentOptionsSatisfied();
+
+ bool is_ready_to_pay_;
+
+ const std::string app_locale_;
+
+ // Not owned. Never null. Both outlive this object.
+ PaymentRequestSpec* spec_;
+ Delegate* delegate_;
+ autofill::PersonalDataManager* personal_data_manager_;
+
+ autofill::AutofillProfile* selected_shipping_profile_;
+ autofill::AutofillProfile* selected_contact_profile_;
+ PaymentInstrument* selected_instrument_;
+
+ // Profiles may change due to (e.g.) sync events, so profiles are cached after
+ // loading and owned here. They are populated once only, and ordered by
+ // frecency.
+ std::vector<std::unique_ptr<autofill::AutofillProfile>> profile_cache_;
+ std::vector<autofill::AutofillProfile*> shipping_profiles_;
+ std::vector<autofill::AutofillProfile*> contact_profiles_;
+ // Credit cards are directly owned by the instruments in this list.
+ std::vector<std::unique_ptr<PaymentInstrument>> available_instruments_;
+
+ PaymentRequestDelegate* payment_request_delegate_;
+
+ std::unique_ptr<PaymentResponseHelper> response_helper_;
+
+ base::ObserverList<Observer> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaymentRequestState);
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_STATE_H_
diff --git a/chromium/components/payments/content/payment_request_state_unittest.cc b/chromium/components/payments/content/payment_request_state_unittest.cc
new file mode 100644
index 00000000000..8509777bda6
--- /dev/null
+++ b/chromium/components/payments/content/payment_request_state_unittest.cc
@@ -0,0 +1,250 @@
+// 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/payments/content/payment_request_state.h"
+
+#include <utility>
+
+#include "base/memory/weak_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/payments/content/payment_request.mojom.h"
+#include "components/payments/content/payment_request_spec.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+class PaymentRequestStateTest : public testing::Test,
+ public PaymentRequestState::Observer,
+ public PaymentRequestState::Delegate {
+ protected:
+ PaymentRequestStateTest()
+ : num_on_selected_information_changed_called_(0),
+ address_(autofill::test::GetFullProfile()),
+ credit_card_visa_(autofill::test::GetCreditCard()) {
+ test_personal_data_manager_.AddTestingProfile(&address_);
+ credit_card_visa_.set_billing_address_id(address_.guid());
+ credit_card_visa_.set_use_count(5u);
+ test_personal_data_manager_.AddTestingCreditCard(&credit_card_visa_);
+ }
+ ~PaymentRequestStateTest() override {}
+
+ // PaymentRequestState::Observer:
+ void OnSelectedInformationChanged() override {
+ num_on_selected_information_changed_called_++;
+ }
+
+ // PaymentRequestState::Delegate:
+ void OnPaymentResponseAvailable(mojom::PaymentResponsePtr response) override {
+ payment_response_ = std::move(response);
+ };
+ void OnShippingOptionIdSelected(std::string shipping_option_id) override {}
+ void OnShippingAddressSelected(mojom::PaymentAddressPtr address) override {}
+
+ void RecreateStateWithOptionsAndDetails(
+ mojom::PaymentOptionsPtr options,
+ mojom::PaymentDetailsPtr details,
+ std::vector<mojom::PaymentMethodDataPtr> method_data) {
+ // The spec will be based on the |options| and |details| passed in.
+ spec_ = base::MakeUnique<PaymentRequestSpec>(
+ std::move(options), std::move(details), std::move(method_data), nullptr,
+ "en-US");
+ state_ = base::MakeUnique<PaymentRequestState>(
+ spec_.get(), this, "en-US", &test_personal_data_manager_, nullptr);
+ 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) {
+ // Create dummy PaymentDetails with a single shipping option.
+ std::vector<mojom::PaymentShippingOptionPtr> shipping_options;
+ mojom::PaymentShippingOptionPtr option =
+ mojom::PaymentShippingOption::New();
+ option->id = "option:1";
+ shipping_options.push_back(std::move(option));
+ mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New();
+ details->shipping_options = std::move(shipping_options);
+
+ RecreateStateWithOptionsAndDetails(std::move(options), std::move(details),
+ GetMethodDataForVisa());
+ }
+
+ // 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_methods.push_back("visa");
+ method_data.push_back(std::move(entry));
+ return method_data;
+ }
+
+ PaymentRequestState* state() { return state_.get(); }
+ const mojom::PaymentResponsePtr& response() { return payment_response_; }
+ int num_on_selected_information_changed_called() {
+ return num_on_selected_information_changed_called_;
+ }
+
+ autofill::AutofillProfile* test_address() { return &address_; }
+
+ private:
+ std::unique_ptr<PaymentRequestState> state_;
+ std::unique_ptr<PaymentRequestSpec> spec_;
+ int num_on_selected_information_changed_called_;
+ mojom::PaymentResponsePtr payment_response_;
+ autofill::TestPersonalDataManager test_personal_data_manager_;
+
+ // Test data.
+ autofill::AutofillProfile address_;
+ autofill::CreditCard credit_card_visa_;
+};
+
+TEST_F(PaymentRequestStateTest, CanMakePayment) {
+ // Default options.
+ RecreateStateWithOptions(mojom::PaymentOptions::New());
+
+ // CanMakePayment returns true because the method data requires Visa, and the
+ // user has a Visa card on file.
+ EXPECT_TRUE(state()->CanMakePayment());
+}
+
+TEST_F(PaymentRequestStateTest, CanMakePayment_CannotMakePayment) {
+ // The method data requires MasterCard.
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_methods.push_back("mastercard");
+ method_data.push_back(std::move(entry));
+ RecreateStateWithOptionsAndDetails(mojom::PaymentOptions::New(),
+ mojom::PaymentDetails::New(),
+ std::move(method_data));
+
+ // CanMakePayment returns false because the method data requires MasterCard,
+ // and the user doesn't have such an instrument.
+ EXPECT_FALSE(state()->CanMakePayment());
+}
+
+TEST_F(PaymentRequestStateTest, CanMakePayment_OnlyBasicCard) {
+ // The method data supports everything in basic-card.
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_methods.push_back("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));
+
+ // CanMakePayment returns true because the method data supports everything,
+ // and the user has at least one instrument.
+ EXPECT_TRUE(state()->CanMakePayment());
+}
+
+TEST_F(PaymentRequestStateTest, CanMakePayment_BasicCard_SpecificAvailable) {
+ // The method data supports visa through basic-card.
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_methods.push_back("basic-card");
+ 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));
+
+ // CanMakePayment returns true because the method data supports visa, and the
+ // user has a Visa instrument.
+ EXPECT_TRUE(state()->CanMakePayment());
+}
+
+TEST_F(PaymentRequestStateTest,
+ CanMakePayment_BasicCard_SpecificAvailableButInvalid) {
+ // The method data supports jcb through basic-card.
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_methods.push_back("basic-card");
+ 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));
+
+ // CanMakePayment returns false because the method data supports jcb, and the
+ // user has a JCB instrument, but it's invalid.
+ EXPECT_FALSE(state()->CanMakePayment());
+}
+
+TEST_F(PaymentRequestStateTest, CanMakePayment_BasicCard_SpecificUnavailable) {
+ // The method data supports mastercard through basic-card.
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_methods.push_back("basic-card");
+ 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));
+
+ // CanMakePayment returns false because the method data supports mastercard,
+ // and the user doesn't have such an instrument.
+ EXPECT_FALSE(state()->CanMakePayment());
+}
+
+TEST_F(PaymentRequestStateTest, 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));
+
+ // 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(1, num_on_selected_information_changed_called());
+
+ EXPECT_TRUE(state()->is_ready_to_pay());
+}
+
+// Testing that only supported intruments are shown. In this test the merchant
+// only supports Visa.
+TEST_F(PaymentRequestStateTest, UnsupportedCardAreNotAvailable) {
+ // Default options.
+ RecreateStateWithOptions(mojom::PaymentOptions::New());
+
+ // Ready to pay because the default instrument is selected and supported.
+ EXPECT_TRUE(state()->is_ready_to_pay());
+
+ // There's only one instrument available, even though there's an Amex in
+ // PersonalDataManager.
+ EXPECT_EQ(1u, state()->available_instruments().size());
+}
+
+// Test selecting a contact info profile will make the user ready to pay.
+TEST_F(PaymentRequestStateTest, 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));
+
+ // Ready to pay because of default selections.
+ EXPECT_TRUE(state()->is_ready_to_pay());
+
+ // Unselecting contact profile.
+ state()->SetSelectedContactProfile(nullptr);
+ EXPECT_EQ(1, num_on_selected_information_changed_called());
+
+ EXPECT_FALSE(state()->is_ready_to_pay());
+
+ state()->SetSelectedContactProfile(test_address());
+ EXPECT_EQ(2, num_on_selected_information_changed_called());
+
+ // Ready to pay!
+ EXPECT_TRUE(state()->is_ready_to_pay());
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/payment_request_web_contents_manager.cc b/chromium/components/payments/content/payment_request_web_contents_manager.cc
index db68134c47c..2f11a65ebdb 100644
--- a/chromium/components/payments/content/payment_request_web_contents_manager.cc
+++ b/chromium/components/payments/content/payment_request_web_contents_manager.cc
@@ -9,7 +9,7 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "components/payments/content/payment_request.h"
-#include "components/payments/content/payment_request_delegate.h"
+#include "components/payments/core/payment_request_delegate.h"
#include "content/public/browser/web_contents.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(payments::PaymentRequestWebContentsManager);
@@ -30,9 +30,11 @@ PaymentRequestWebContentsManager::GetOrCreateForWebContents(
void PaymentRequestWebContentsManager::CreatePaymentRequest(
content::WebContents* web_contents,
std::unique_ptr<PaymentRequestDelegate> delegate,
- mojo::InterfaceRequest<payments::mojom::PaymentRequest> request) {
+ mojo::InterfaceRequest<payments::mojom::PaymentRequest> request,
+ PaymentRequest::ObserverForTest* observer_for_testing) {
auto new_request = base::MakeUnique<PaymentRequest>(
- web_contents, std::move(delegate), this, std::move(request));
+ web_contents, std::move(delegate), this, std::move(request),
+ observer_for_testing);
PaymentRequest* request_ptr = new_request.get();
payment_requests_.insert(std::make_pair(request_ptr, std::move(new_request)));
}
diff --git a/chromium/components/payments/content/payment_request_web_contents_manager.h b/chromium/components/payments/content/payment_request_web_contents_manager.h
index 52323140d10..08433584721 100644
--- a/chromium/components/payments/content/payment_request_web_contents_manager.h
+++ b/chromium/components/payments/content/payment_request_web_contents_manager.h
@@ -9,6 +9,7 @@
#include <unordered_map>
#include "base/macros.h"
+#include "components/payments/content/payment_request.h"
#include "components/payments/content/payment_request.mojom.h"
#include "content/public/browser/web_contents_user_data.h"
#include "mojo/public/cpp/bindings/binding.h"
@@ -19,7 +20,6 @@ class WebContents;
namespace payments {
-class PaymentRequest;
class PaymentRequestDelegate;
// This class owns the PaymentRequest associated with a given WebContents.
@@ -44,7 +44,8 @@ class PaymentRequestWebContentsManager
void CreatePaymentRequest(
content::WebContents* web_contents,
std::unique_ptr<PaymentRequestDelegate> delegate,
- mojo::InterfaceRequest<payments::mojom::PaymentRequest> request);
+ mojo::InterfaceRequest<payments::mojom::PaymentRequest> request,
+ PaymentRequest::ObserverForTest* observer_for_testing);
// Destroys the given |request|.
void DestroyRequest(PaymentRequest* request);
@@ -52,7 +53,7 @@ class PaymentRequestWebContentsManager
private:
explicit PaymentRequestWebContentsManager(content::WebContents* web_contents);
friend class content::WebContentsUserData<PaymentRequestWebContentsManager>;
- friend class PaymentRequestInteractiveTestBase;
+ friend class PaymentRequestBrowserTestBase;
// Owns all the PaymentRequest for this WebContents. Since the
// PaymentRequestWebContentsManager's lifetime is tied to the WebContents,
diff --git a/chromium/components/payments/content/payment_response_helper.cc b/chromium/components/payments/content/payment_response_helper.cc
new file mode 100644
index 00000000000..0d1177a9490
--- /dev/null
+++ b/chromium/components/payments/content/payment_response_helper.cc
@@ -0,0 +1,149 @@
+// 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/payments/content/payment_response_helper.h"
+
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/payments/content/payment_request_spec.h"
+#include "third_party/libphonenumber/phonenumber_api.h"
+
+namespace payments {
+
+namespace {
+
+using ::i18n::phonenumbers::PhoneNumberUtil;
+
+} // namespace
+
+PaymentResponseHelper::PaymentResponseHelper(
+ const std::string& app_locale,
+ PaymentRequestSpec* spec,
+ PaymentInstrument* selected_instrument,
+ autofill::AutofillProfile* selected_shipping_profile,
+ autofill::AutofillProfile* selected_contact_profile,
+ Delegate* delegate)
+ : app_locale_(app_locale),
+ spec_(spec),
+ delegate_(delegate),
+ selected_instrument_(selected_instrument),
+ selected_shipping_profile_(selected_shipping_profile),
+ selected_contact_profile_(selected_contact_profile) {
+ DCHECK(spec_);
+ DCHECK(selected_instrument_);
+ DCHECK(delegate_);
+
+ // Start to get the instrument details. Will call back into
+ // OnInstrumentDetailsReady.
+ selected_instrument_->InvokePaymentApp(this);
+};
+
+PaymentResponseHelper::~PaymentResponseHelper(){};
+
+// static
+mojom::PaymentAddressPtr
+PaymentResponseHelper::GetMojomPaymentAddressFromAutofillProfile(
+ const autofill::AutofillProfile* const profile,
+ const std::string& app_locale) {
+ mojom::PaymentAddressPtr payment_address = mojom::PaymentAddress::New();
+
+ payment_address->country =
+ base::UTF16ToUTF8(profile->GetRawInfo(autofill::ADDRESS_HOME_COUNTRY));
+ payment_address->address_line = base::SplitString(
+ base::UTF16ToUTF8(profile->GetInfo(
+ autofill::AutofillType(autofill::ADDRESS_HOME_STREET_ADDRESS),
+ app_locale)),
+ "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ payment_address->region =
+ base::UTF16ToUTF8(profile->GetRawInfo(autofill::ADDRESS_HOME_STATE));
+ payment_address->city =
+ base::UTF16ToUTF8(profile->GetRawInfo(autofill::ADDRESS_HOME_CITY));
+ payment_address->dependent_locality = base::UTF16ToUTF8(
+ profile->GetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_LOCALITY));
+ payment_address->postal_code =
+ base::UTF16ToUTF8(profile->GetRawInfo(autofill::ADDRESS_HOME_ZIP));
+ payment_address->sorting_code = base::UTF16ToUTF8(
+ profile->GetRawInfo(autofill::ADDRESS_HOME_SORTING_CODE));
+ payment_address->language_code = profile->language_code();
+ payment_address->organization =
+ base::UTF16ToUTF8(profile->GetRawInfo(autofill::COMPANY_NAME));
+ payment_address->recipient = base::UTF16ToUTF8(profile->GetInfo(
+ autofill::AutofillType(autofill::NAME_FULL), app_locale));
+
+ // TODO(crbug.com/705945): Format phone number according to spec.
+ payment_address->phone =
+ base::UTF16ToUTF8(profile->GetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER));
+
+ return payment_address;
+}
+
+void PaymentResponseHelper::OnInstrumentDetailsReady(
+ const std::string& method_name,
+ const std::string& stringified_details) {
+ mojom::PaymentResponsePtr payment_response = mojom::PaymentResponse::New();
+
+ // Make sure that we return the method name that the merchant specified for
+ // this instrument: cards can be either specified through their name (e.g.,
+ // "visa") or through basic-card's supportedNetworks.
+ payment_response->method_name =
+ spec_->IsMethodSupportedThroughBasicCard(method_name)
+ ? kBasicCardMethodName
+ : method_name;
+ payment_response->stringified_details = stringified_details;
+
+ // Shipping Address section
+ if (spec_->request_shipping()) {
+ DCHECK(selected_shipping_profile_);
+ payment_response->shipping_address =
+ GetMojomPaymentAddressFromAutofillProfile(selected_shipping_profile_,
+ app_locale_);
+
+ DCHECK(spec_->selected_shipping_option());
+ payment_response->shipping_option = spec_->selected_shipping_option()->id;
+ }
+
+ // Contact Details section.
+ if (spec_->request_payer_name()) {
+ DCHECK(selected_contact_profile_);
+ payment_response->payer_name =
+ base::UTF16ToUTF8(selected_contact_profile_->GetInfo(
+ autofill::AutofillType(autofill::NAME_FULL), app_locale_));
+ }
+ if (spec_->request_payer_email()) {
+ DCHECK(selected_contact_profile_);
+ payment_response->payer_email = base::UTF16ToUTF8(
+ selected_contact_profile_->GetRawInfo(autofill::EMAIL_ADDRESS));
+ }
+ if (spec_->request_payer_phone()) {
+ DCHECK(selected_contact_profile_);
+
+ // Try to format the phone number to the E.164 format to send in the Payment
+ // Response, as defined in the Payment Request spec. If it's not possible,
+ // send the original. More info at:
+ // https://w3c.github.io/browser-payment-api/#paymentrequest-updated-algorithm
+ // TODO(sebsg): Move this code to a reusable location.
+ const std::string original_number =
+ base::UTF16ToUTF8(selected_contact_profile_->GetInfo(
+ autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
+ app_locale_));
+ i18n::phonenumbers::PhoneNumber parsed_number;
+ PhoneNumberUtil* phone_number_util = PhoneNumberUtil::GetInstance();
+ if (phone_number_util->Parse(original_number, "US", &parsed_number) ==
+ ::i18n::phonenumbers::PhoneNumberUtil::NO_PARSING_ERROR) {
+ std::string formatted_number;
+ phone_number_util->Format(parsed_number,
+ PhoneNumberUtil::PhoneNumberFormat::E164,
+ &formatted_number);
+ payment_response->payer_phone = formatted_number;
+ } else {
+ payment_response->payer_phone = original_number;
+ }
+ }
+
+ delegate_->OnPaymentResponseReady(std::move(payment_response));
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/payment_response_helper.h b/chromium/components/payments/content/payment_response_helper.h
new file mode 100644
index 00000000000..c8903e22b92
--- /dev/null
+++ b/chromium/components/payments/content/payment_response_helper.h
@@ -0,0 +1,71 @@
+// 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_PAYMENTS_CONTENT_PAYMENT_RESPONSE_HELPER_H_
+#define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_RESPONSE_HELPER_H_
+
+#include "base/macros.h"
+#include "components/payments/content/payment_request.mojom.h"
+#include "components/payments/core/payment_instrument.h"
+
+namespace autofill {
+class AutofillProfile;
+} // namespace autofill
+
+namespace payments {
+
+class PaymentRequestSpec;
+
+// TODO(sebsg): Asynchronously normalize the billing and shipping addresses
+// before adding them to the PaymentResponse.
+// A helper class to facilitate the creation of the PaymentResponse.
+class PaymentResponseHelper : public PaymentInstrument::Delegate {
+ public:
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ virtual void OnPaymentResponseReady(
+ mojom::PaymentResponsePtr payment_response) = 0;
+ };
+
+ // The spec, selected_instrument and delegate cannot be null.
+ PaymentResponseHelper(const std::string& app_locale,
+ PaymentRequestSpec* spec,
+ PaymentInstrument* selected_instrument,
+ autofill::AutofillProfile* selected_shipping_profile,
+ autofill::AutofillProfile* selected_contact_profile,
+ Delegate* delegate);
+ ~PaymentResponseHelper() override;
+
+ // Returns a new mojo PaymentAddress based on the specified
+ // |profile| and |app_locale|.
+ static mojom::PaymentAddressPtr GetMojomPaymentAddressFromAutofillProfile(
+ const autofill::AutofillProfile* const profile,
+ const std::string& app_locale);
+
+ // PaymentInstrument::Delegate
+ void OnInstrumentDetailsReady(
+ const std::string& method_name,
+ const std::string& stringified_details) override;
+ void OnInstrumentDetailsError() override {}
+
+ private:
+ const std::string& app_locale_;
+
+ // Not owned, cannot be null.
+ PaymentRequestSpec* spec_;
+ Delegate* delegate_;
+ PaymentInstrument* selected_instrument_;
+
+ // Not owned, can be null (dependent on the spec).
+ autofill::AutofillProfile* selected_shipping_profile_;
+ autofill::AutofillProfile* selected_contact_profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaymentResponseHelper);
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CONTENT_PAYMENT_RESPONSE_HELPER_H_
diff --git a/chromium/components/payments/content/payment_response_helper_unittest.cc b/chromium/components/payments/content/payment_response_helper_unittest.cc
new file mode 100644
index 00000000000..7f63b6658e9
--- /dev/null
+++ b/chromium/components/payments/content/payment_response_helper_unittest.cc
@@ -0,0 +1,300 @@
+// 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/payments/content/payment_response_helper.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/payments/content/payment_request.mojom.h"
+#include "components/payments/content/payment_request_spec.h"
+#include "components/payments/core/autofill_payment_instrument.h"
+#include "components/payments/core/payment_request_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+class FakePaymentRequestDelegate : public PaymentRequestDelegate {
+ public:
+ FakePaymentRequestDelegate(
+ autofill::PersonalDataManager* personal_data_manager)
+ : personal_data_manager_(personal_data_manager), locale_("en-US") {}
+ void ShowDialog(PaymentRequest* request) override {}
+
+ void CloseDialog() override {}
+
+ void ShowErrorMessage() override {}
+
+ autofill::PersonalDataManager* GetPersonalDataManager() override {
+ return personal_data_manager_;
+ }
+
+ const std::string& GetApplicationLocale() const override { return locale_; }
+
+ bool IsIncognito() const override { return false; }
+
+ void DoFullCardRequest(
+ const autofill::CreditCard& credit_card,
+ base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate>
+ result_delegate) override {
+ result_delegate->OnFullCardRequestSucceeded(credit_card,
+ base::ASCIIToUTF16("123"));
+ }
+
+ std::unique_ptr<const ::i18n::addressinput::Source> GetAddressInputSource()
+ override {
+ return nullptr;
+ }
+
+ std::unique_ptr<::i18n::addressinput::Storage> GetAddressInputStorage()
+ override {
+ return nullptr;
+ }
+
+ private:
+ autofill::PersonalDataManager* personal_data_manager_;
+ std::string locale_;
+ DISALLOW_COPY_AND_ASSIGN(FakePaymentRequestDelegate);
+};
+
+class PaymentResponseHelperTest : public testing::Test,
+ public PaymentResponseHelper::Delegate {
+ protected:
+ PaymentResponseHelperTest()
+ : payment_request_delegate_(&test_personal_data_manager_),
+ address_(autofill::test::GetFullProfile()),
+ billing_addresses_({&address_}) {
+ test_personal_data_manager_.AddTestingProfile(&address_);
+
+ // Setup the autofill payment instrument.
+ autofill::CreditCard visa_card = autofill::test::GetCreditCard();
+ visa_card.set_billing_address_id(address_.guid());
+ visa_card.set_use_count(5u);
+ autofill_instrument_ = base::MakeUnique<AutofillPaymentInstrument>(
+ "visa", visa_card, billing_addresses_, "en-US",
+ &payment_request_delegate_);
+ }
+ ~PaymentResponseHelperTest() override {}
+
+ // PaymentRequestState::Delegate:
+ void OnPaymentResponseReady(mojom::PaymentResponsePtr response) override {
+ payment_response_ = std::move(response);
+ };
+
+ // Convenience method to create a PaymentRequestSpec with specified |details|
+ // and |method_data|.
+ void RecreateSpecWithOptionsAndDetails(
+ mojom::PaymentOptionsPtr options,
+ mojom::PaymentDetailsPtr details,
+ std::vector<mojom::PaymentMethodDataPtr> method_data) {
+ // The spec will be based on the |options| and |details| passed in.
+ spec_ = base::MakeUnique<PaymentRequestSpec>(
+ std::move(options), std::move(details), std::move(method_data), nullptr,
+ "en-US");
+ }
+
+ // Convenience method to create a PaymentRequestSpec with default details
+ // (one shipping option) and method data (only supports visa).
+ void RecreateSpecWithOptions(mojom::PaymentOptionsPtr options) {
+ // Create dummy PaymentDetails with a single shipping option.
+ std::vector<mojom::PaymentShippingOptionPtr> shipping_options;
+ mojom::PaymentShippingOptionPtr option =
+ mojom::PaymentShippingOption::New();
+ option->id = "option:1";
+ shipping_options.push_back(std::move(option));
+ mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New();
+ details->shipping_options = std::move(shipping_options);
+
+ RecreateSpecWithOptionsAndDetails(std::move(options), std::move(details),
+ GetMethodDataForVisa());
+ }
+
+ // 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_methods.push_back("visa");
+ method_data.push_back(std::move(entry));
+ return method_data;
+ }
+
+ PaymentRequestSpec* spec() { return spec_.get(); }
+ const mojom::PaymentResponsePtr& response() { return payment_response_; }
+ autofill::AutofillProfile* test_address() { return &address_; }
+ PaymentInstrument* test_instrument() { return autofill_instrument_.get(); }
+
+ private:
+ std::unique_ptr<PaymentRequestSpec> spec_;
+ mojom::PaymentResponsePtr payment_response_;
+ autofill::TestPersonalDataManager test_personal_data_manager_;
+ FakePaymentRequestDelegate payment_request_delegate_;
+
+ // Test data.
+ autofill::AutofillProfile address_;
+ const std::vector<autofill::AutofillProfile*> billing_addresses_;
+ std::unique_ptr<AutofillPaymentInstrument> autofill_instrument_;
+};
+
+// Test generating a PaymentResponse.
+TEST_F(PaymentResponseHelperTest, GeneratePaymentResponse_SupportedMethod) {
+ // Default options (no shipping, no contact info).
+ RecreateSpecWithOptions(mojom::PaymentOptions::New());
+
+ // TODO(mathp): Currently synchronous, when async will need a RunLoop.
+ // "visa" is specified directly in the supportedMethods so it is returned
+ // as the method name.
+ PaymentResponseHelper helper("en-US", spec(), test_instrument(),
+ test_address(), test_address(), this);
+ EXPECT_EQ("visa", response()->method_name);
+ EXPECT_EQ(
+ "{\"billingAddress\":"
+ "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"],"
+ "\"city\":\"Elysium\","
+ "\"country\":\"US\","
+ "\"organization\":\"Underworld\","
+ "\"phone\":\"16502111111\","
+ "\"postalCode\":\"91111\","
+ "\"recipient\":\"John H. Doe\","
+ "\"region\":\"CA\"},"
+ "\"cardNumber\":\"4111111111111111\","
+ "\"cardSecurityCode\":\"123\","
+ "\"cardholderName\":\"Test User\","
+ "\"expiryMonth\":\"11\","
+ "\"expiryYear\":\"2022\"}",
+ 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_methods.push_back("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));
+
+ // TODO(mathp): Currently synchronous, when async will need a RunLoop.
+ // "basic-card" is specified so it is returned as the method name.
+ PaymentResponseHelper helper("en-US", spec(), test_instrument(),
+ test_address(), test_address(), this);
+ EXPECT_EQ("basic-card", response()->method_name);
+ EXPECT_EQ(
+ "{\"billingAddress\":"
+ "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"],"
+ "\"city\":\"Elysium\","
+ "\"country\":\"US\","
+ "\"organization\":\"Underworld\","
+ "\"phone\":\"16502111111\","
+ "\"postalCode\":\"91111\","
+ "\"recipient\":\"John H. Doe\","
+ "\"region\":\"CA\"},"
+ "\"cardNumber\":\"4111111111111111\","
+ "\"cardSecurityCode\":\"123\","
+ "\"cardholderName\":\"Test User\","
+ "\"expiryMonth\":\"11\","
+ "\"expiryYear\":\"2022\"}",
+ response()->stringified_details);
+}
+
+// Tests the the generated PaymentResponse has the correct values for the
+// shipping address.
+TEST_F(PaymentResponseHelperTest, GeneratePaymentResponse_ShippingAddress) {
+ // Setup so that a shipping address is requested.
+ std::vector<mojom::PaymentShippingOptionPtr> shipping_options;
+ mojom::PaymentShippingOptionPtr option = mojom::PaymentShippingOption::New();
+ option->id = "option:1";
+ option->selected = true;
+ shipping_options.push_back(std::move(option));
+ mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New();
+ details->shipping_options = std::move(shipping_options);
+ mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New();
+ options->request_shipping = true;
+ RecreateSpecWithOptionsAndDetails(std::move(options), std::move(details),
+ GetMethodDataForVisa());
+
+ PaymentResponseHelper helper("en-US", spec(), test_instrument(),
+ test_address(), test_address(), this);
+
+ // Check that all the expected values were set.
+ EXPECT_EQ("US", response()->shipping_address->country);
+ EXPECT_EQ("666 Erebus St.", response()->shipping_address->address_line[0]);
+ EXPECT_EQ("Apt 8", response()->shipping_address->address_line[1]);
+ EXPECT_EQ("CA", response()->shipping_address->region);
+ EXPECT_EQ("Elysium", response()->shipping_address->city);
+ EXPECT_EQ("", response()->shipping_address->dependent_locality);
+ EXPECT_EQ("91111", response()->shipping_address->postal_code);
+ EXPECT_EQ("", response()->shipping_address->sorting_code);
+ EXPECT_EQ("", response()->shipping_address->language_code);
+ EXPECT_EQ("Underworld", response()->shipping_address->organization);
+ EXPECT_EQ("John H. Doe", response()->shipping_address->recipient);
+ EXPECT_EQ("16502111111", response()->shipping_address->phone);
+}
+
+// Tests the the generated PaymentResponse has the correct values for the
+// contact details when all values are requested.
+TEST_F(PaymentResponseHelperTest, GeneratePaymentResponse_ContactDetails_All) {
+ // Request all contact detail values.
+ mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New();
+ options->request_payer_name = true;
+ options->request_payer_phone = true;
+ options->request_payer_email = true;
+ RecreateSpecWithOptions(std::move(options));
+
+ PaymentResponseHelper helper("en-US", spec(), test_instrument(),
+ test_address(), test_address(), this);
+
+ // Check that all the expected values were set.
+ EXPECT_EQ("John H. Doe", response()->payer_name.value());
+ EXPECT_EQ("+16502111111", response()->payer_phone.value());
+ EXPECT_EQ("johndoe@hades.com", response()->payer_email.value());
+}
+
+// Tests the the generated PaymentResponse has the correct values for the
+// contact details when all values are requested.
+TEST_F(PaymentResponseHelperTest, GeneratePaymentResponse_ContactDetails_Some) {
+ // Request one contact detail value.
+ mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New();
+ options->request_payer_name = true;
+ RecreateSpecWithOptions(std::move(options));
+
+ PaymentResponseHelper helper("en-US", spec(), test_instrument(),
+ test_address(), test_address(), this);
+
+ // Check that the name was set, but not the other values.
+ EXPECT_EQ("John H. Doe", response()->payer_name.value());
+ EXPECT_FALSE(response()->payer_phone.has_value());
+ EXPECT_FALSE(response()->payer_email.has_value());
+}
+
+// Tests the the generated PaymentResponse has the correct values for the
+// contact details when all values are requested.
+TEST_F(PaymentResponseHelperTest,
+ GeneratePaymentResponse_ContactPhoneIsFormatted) {
+ // Request one contact detail value.
+ mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New();
+ options->request_payer_phone = true;
+ test_address()->SetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER,
+ base::UTF8ToUTF16("(515) 123-1234"));
+ RecreateSpecWithOptions(std::move(options));
+
+ PaymentResponseHelper helper("en-US", spec(), test_instrument(),
+ test_address(), test_address(), this);
+
+ // Check that the phone was formatted.
+ EXPECT_EQ("+15151231234", response()->payer_phone.value());
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/payments_validators_test.cc b/chromium/components/payments/content/payments_validators_unittest.cc
index 8214ce148dc..8214ce148dc 100644
--- a/chromium/components/payments/content/payments_validators_test.cc
+++ b/chromium/components/payments/content/payments_validators_unittest.cc
diff --git a/chromium/components/payments/content/utility/BUILD.gn b/chromium/components/payments/content/utility/BUILD.gn
new file mode 100644
index 00000000000..643a1b64437
--- /dev/null
+++ b/chromium/components/payments/content/utility/BUILD.gn
@@ -0,0 +1,30 @@
+# 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.
+
+static_library("utility") {
+ sources = [
+ "fingerprint_parser.cc",
+ "fingerprint_parser.h",
+ "payment_manifest_parser.cc",
+ "payment_manifest_parser.h",
+ ]
+ deps = [
+ "//base",
+ "//components/payments/content:mojom_parser",
+ "//url",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "fingerprint_parser_unittest.cc",
+ "payment_manifest_parser_unittest.cc",
+ ]
+ deps = [
+ ":utility",
+ "//base",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/payments/content/utility/DEPS b/chromium/components/payments/content/utility/DEPS
new file mode 100644
index 00000000000..0afa1dd1dfa
--- /dev/null
+++ b/chromium/components/payments/content/utility/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+base/json/json_reader.h",
+]
diff --git a/chromium/components/payments/content/utility/fingerprint_parser.cc b/chromium/components/payments/content/utility/fingerprint_parser.cc
new file mode 100644
index 00000000000..594d58908b6
--- /dev/null
+++ b/chromium/components/payments/content/utility/fingerprint_parser.cc
@@ -0,0 +1,50 @@
+// 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/payments/content/utility/fingerprint_parser.h"
+
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+
+namespace payments {
+namespace {
+
+bool IsUpperCaseHexDigit(char c) {
+ return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F');
+}
+
+uint8_t HexDigitToByte(char c) {
+ DCHECK(IsUpperCaseHexDigit(c));
+ return base::checked_cast<uint8_t>(c >= '0' && c <= '9' ? c - '0'
+ : c - 'A' + 10);
+}
+
+} // namespace
+
+std::vector<uint8_t> FingerprintStringToByteArray(const std::string& input) {
+ std::vector<uint8_t> output;
+ if (input.size() != 32 * 3 - 1)
+ return output;
+
+ for (size_t i = 0; i < input.size(); i += 3) {
+ if (i < input.size() - 2 && input[i + 2] != ':') {
+ output.clear();
+ return output;
+ }
+
+ char big_end = input[i];
+ char little_end = input[i + 1];
+ if (!IsUpperCaseHexDigit(big_end) || !IsUpperCaseHexDigit(little_end)) {
+ output.clear();
+ return output;
+ }
+
+ output.push_back(HexDigitToByte(big_end) * static_cast<uint8_t>(16) +
+ HexDigitToByte(little_end));
+ }
+
+ return output;
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/utility/fingerprint_parser.h b/chromium/components/payments/content/utility/fingerprint_parser.h
new file mode 100644
index 00000000000..c4115ffd0fc
--- /dev/null
+++ b/chromium/components/payments/content/utility/fingerprint_parser.h
@@ -0,0 +1,21 @@
+// 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_PAYMENTS_CONTENT_UTILITY_FINGERPRINT_PARSER_H_
+#define COMPONENTS_PAYMENTS_CONTENT_UTILITY_FINGERPRINT_PARSER_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <vector>
+
+namespace payments {
+
+// Converts a string representation of a 32-byte array (e.g., "01:02:03:04")
+// into a list of the corresponding bytes. Returns an empty list on error.
+std::vector<uint8_t> FingerprintStringToByteArray(const std::string& input);
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CONTENT_UTILITY_FINGERPRINT_PARSER_H_
diff --git a/chromium/components/payments/content/utility/fingerprint_parser_unittest.cc b/chromium/components/payments/content/utility/fingerprint_parser_unittest.cc
new file mode 100644
index 00000000000..2c79635466d
--- /dev/null
+++ b/chromium/components/payments/content/utility/fingerprint_parser_unittest.cc
@@ -0,0 +1,90 @@
+// 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/payments/content/utility/fingerprint_parser.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+namespace {
+
+TEST(FingerprintParserTest, CheckInputSize) {
+ // To short.
+ EXPECT_TRUE(FingerprintStringToByteArray("00:01:02:03:04:05:06:07:08:09:"
+ "A0:A1:A2:A3:A4:A5:A6:A7:A8:A9:"
+ "B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:"
+ "C0:C")
+ .empty());
+ EXPECT_TRUE(FingerprintStringToByteArray("00:01:02:03:04:05:06:07:08:09:"
+ "A0:A1:A2:A3:A4:A5:A6:A7:A8:A9:"
+ "B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:"
+ "C0:")
+ .empty());
+ EXPECT_TRUE(FingerprintStringToByteArray("00:01:02:03:04:05:06:07:08:09:"
+ "A0:A1:A2:A3:A4:A5:A6:A7:A8:A9:"
+ "B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:"
+ "C0")
+ .empty());
+
+ // To long.
+ EXPECT_TRUE(FingerprintStringToByteArray("00:01:02:03:04:05:06:07:08:09:"
+ "A0:A1:A2:A3:A4:A5:A6:A7:A8:A9:"
+ "B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:"
+ "C0:C11")
+ .empty());
+ EXPECT_TRUE(FingerprintStringToByteArray("00:01:02:03:04:05:06:07:08:09:"
+ "A0:A1:A2:A3:A4:A5:A6:A7:A8:A9:"
+ "B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:"
+ "C0:C1:")
+ .empty());
+ EXPECT_TRUE(FingerprintStringToByteArray("00:01:02:03:04:05:06:07:08:09:"
+ "A0:A1:A2:A3:A4:A5:A6:A7:A8:A9:"
+ "B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:"
+ "C0:C1:C")
+ .empty());
+ EXPECT_TRUE(FingerprintStringToByteArray("00:01:02:03:04:05:06:07:08:09:"
+ "A0:A1:A2:A3:A4:A5:A6:A7:A8:A9:"
+ "B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:"
+ "C0:C1:C2")
+ .empty());
+}
+
+TEST(FingerprintParserTest, CheckColonSeparator) {
+ EXPECT_TRUE(FingerprintStringToByteArray("00-01-02-03-04-05-06-07-08-09-"
+ "A0-A1-A2-A3-A4-A5-A6-A7-A8-A9-"
+ "B0-B1-B2-B3-B4-B5-B6-B7-B8-B9-"
+ "C0-C1")
+ .empty());
+}
+
+TEST(FingerprintParserTest, MustBeHex) {
+ EXPECT_TRUE(FingerprintStringToByteArray("G0:G1:G2:G3:G4:G5:G6:G7:G8:G9:"
+ "A0:A1:A2:A3:A4:A5:A6:A7:A8:A9:"
+ "B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:"
+ "C0:C1")
+ .empty());
+}
+
+TEST(FingerprintParserTest, MustBeUpperCaseHex) {
+ EXPECT_TRUE(FingerprintStringToByteArray("00:01:02:03:04:05:06:07:08:09:"
+ "a0:a1:a2:a3:a4:a5:a6:a7:a8:a9:"
+ "b0:b1:b2:b3:b4:b5:b6:b7:b8:b9:"
+ "c0:c1")
+ .empty());
+}
+
+TEST(FingerprintParserTest, CorrectParsing) {
+ std::vector<uint8_t> actual_output = FingerprintStringToByteArray(
+ "00:01:02:03:04:05:06:07:08:09:A0:"
+ "A1:A2:A3:A4:A5:A6:A7:A8:A9:B0:B1:"
+ "B2:B3:B4:B5:B6:B7:B8:B9:FE:FF");
+ std::vector<uint8_t> expect_output = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA0,
+ 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xB0, 0xB1,
+ 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xFE, 0xFF};
+ EXPECT_EQ(expect_output, actual_output);
+}
+
+} // namespace
+} // namespace payments
diff --git a/chromium/components/payments/content/utility/payment_manifest_parser.cc b/chromium/components/payments/content/utility/payment_manifest_parser.cc
new file mode 100644
index 00000000000..4c77062fdaf
--- /dev/null
+++ b/chromium/components/payments/content/utility/payment_manifest_parser.cc
@@ -0,0 +1,192 @@
+// 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/payments/content/utility/payment_manifest_parser.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <utility>
+
+#include "base/json/json_reader.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "components/payments/content/utility/fingerprint_parser.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "url/url_constants.h"
+
+namespace payments {
+
+// static
+void PaymentManifestParser::Create(
+ mojom::PaymentManifestParserRequest request) {
+ mojo::MakeStrongBinding(base::MakeUnique<PaymentManifestParser>(),
+ std::move(request));
+}
+
+// static
+std::vector<GURL> PaymentManifestParser::ParsePaymentMethodManifestIntoVector(
+ const std::string& input) {
+ std::vector<GURL> output;
+ std::unique_ptr<base::Value> value(base::JSONReader::Read(input));
+ if (!value)
+ return output;
+
+ std::unique_ptr<base::DictionaryValue> dict =
+ base::DictionaryValue::From(std::move(value));
+ if (!dict)
+ return output;
+
+ base::ListValue* list = nullptr;
+ if (!dict->GetList("default_applications", &list))
+ return output;
+
+ size_t apps_number = list->GetSize();
+ const size_t kMaximumNumberOfApps = 100U;
+ if (apps_number > kMaximumNumberOfApps)
+ return output;
+
+ std::string item;
+ for (size_t i = 0; i < apps_number; ++i) {
+ if (!list->GetString(i, &item) && item.empty()) {
+ output.clear();
+ return output;
+ }
+
+ GURL url(item);
+ if (!url.is_valid() || !url.SchemeIs(url::kHttpsScheme)) {
+ output.clear();
+ return output;
+ }
+
+ output.push_back(url);
+ }
+
+ return output;
+}
+
+// static
+std::vector<mojom::WebAppManifestSectionPtr>
+PaymentManifestParser::ParseWebAppManifestIntoVector(const std::string& input) {
+ std::vector<mojom::WebAppManifestSectionPtr> output;
+ std::unique_ptr<base::Value> value(base::JSONReader::Read(input));
+ if (!value)
+ return output;
+
+ std::unique_ptr<base::DictionaryValue> dict =
+ base::DictionaryValue::From(std::move(value));
+ if (!dict)
+ return output;
+
+ base::ListValue* list = nullptr;
+ if (!dict->GetList("related_applications", &list))
+ return output;
+
+ size_t related_applications_size = list->GetSize();
+ for (size_t i = 0; i < related_applications_size; ++i) {
+ base::DictionaryValue* related_application = nullptr;
+ if (!list->GetDictionary(i, &related_application) || !related_application) {
+ output.clear();
+ return output;
+ }
+
+ std::string platform;
+ if (!related_application->GetString("platform", &platform) ||
+ platform != "play") {
+ continue;
+ }
+
+ const size_t kMaximumNumberOfRelatedApplications = 100U;
+ if (output.size() >= kMaximumNumberOfRelatedApplications) {
+ output.clear();
+ return output;
+ }
+
+ const char* const kId = "id";
+ const char* const kMinVersion = "min_version";
+ const char* const kFingerprints = "fingerprints";
+ if (!related_application->HasKey(kId) ||
+ !related_application->HasKey(kMinVersion) ||
+ !related_application->HasKey(kFingerprints)) {
+ output.clear();
+ return output;
+ }
+
+ mojom::WebAppManifestSectionPtr section =
+ mojom::WebAppManifestSection::New();
+ section->min_version = 0;
+
+ if (!related_application->GetString(kId, &section->id) ||
+ section->id.empty() || !base::IsStringASCII(section->id)) {
+ output.clear();
+ return output;
+ }
+
+ 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)) {
+ output.clear();
+ return output;
+ }
+
+ const size_t kMaximumNumberOfFingerprints = 100U;
+ base::ListValue* fingerprints_list = nullptr;
+ if (!related_application->GetList(kFingerprints, &fingerprints_list) ||
+ fingerprints_list->empty() ||
+ fingerprints_list->GetSize() > kMaximumNumberOfFingerprints) {
+ output.clear();
+ return output;
+ }
+
+ size_t fingerprints_size = fingerprints_list->GetSize();
+ for (size_t j = 0; j < fingerprints_size; ++j) {
+ base::DictionaryValue* fingerprint_dict = nullptr;
+ std::string fingerprint_type;
+ std::string fingerprint_value;
+ if (!fingerprints_list->GetDictionary(i, &fingerprint_dict) ||
+ !fingerprint_dict ||
+ !fingerprint_dict->GetString("type", &fingerprint_type) ||
+ fingerprint_type != "sha256_cert" ||
+ !fingerprint_dict->GetString("value", &fingerprint_value) ||
+ fingerprint_value.empty()) {
+ output.clear();
+ return output;
+ }
+
+ std::vector<uint8_t> hash =
+ FingerprintStringToByteArray(fingerprint_value);
+ if (hash.empty()) {
+ output.clear();
+ return output;
+ }
+
+ section->fingerprints.push_back(hash);
+ }
+
+ output.push_back(std::move(section));
+ }
+
+ return output;
+}
+
+PaymentManifestParser::PaymentManifestParser() {}
+
+PaymentManifestParser::~PaymentManifestParser() {}
+
+void PaymentManifestParser::ParsePaymentMethodManifest(
+ const std::string& content,
+ const ParsePaymentMethodManifestCallback& callback) {
+ callback.Run(ParsePaymentMethodManifestIntoVector(content));
+}
+
+void PaymentManifestParser::ParseWebAppManifest(
+ const std::string& content,
+ const ParseWebAppManifestCallback& callback) {
+ callback.Run(ParseWebAppManifestIntoVector(content));
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/utility/payment_manifest_parser.h b/chromium/components/payments/content/utility/payment_manifest_parser.h
new file mode 100644
index 00000000000..3e74394ed0c
--- /dev/null
+++ b/chromium/components/payments/content/utility/payment_manifest_parser.h
@@ -0,0 +1,70 @@
+// 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_PAYMENTS_CONTENT_UTILITY_PAYMENT_MANIFEST_PARSER_H_
+#define COMPONENTS_PAYMENTS_CONTENT_UTILITY_PAYMENT_MANIFEST_PARSER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "components/payments/content/payment_manifest_parser.mojom.h"
+#include "url/gurl.h"
+
+namespace payments {
+
+// Parser for payment method manifests and web app manifests. Should be used
+// only in a sandboxed utility process.
+//
+// Example valid payment method manifest structure:
+//
+// {
+// "default_applications": ["https://bobpay.com/payment-app.json"],
+// "supported_origins": ["https://alicepay.com"] // Not yet parsed or used.
+// }
+//
+// Example valid web app manifest structure:
+//
+// {
+// "related_applications": [{
+// "platform": "play",
+// "id": "com.bobpay.app",
+// "min_version": "1",
+// "fingerprint": [{
+// "type": "sha256_cert",
+// "value": "91:5C:88:65:FF:C4:E8:20:CF:F7:3E:C8:64:D0:95:F0:06:19:2E:A6"
+// }]
+// }]
+// }
+//
+// Spec:
+// https://docs.google.com/document/d/1izV4uC-tiRJG3JLooqY3YRLU22tYOsLTNq0P_InPJeE
+class PaymentManifestParser : public mojom::PaymentManifestParser {
+ public:
+ static void Create(mojom::PaymentManifestParserRequest request);
+
+ static std::vector<GURL> ParsePaymentMethodManifestIntoVector(
+ const std::string& input);
+
+ // The return value is move-only, so no copying occurs.
+ static std::vector<mojom::WebAppManifestSectionPtr>
+ ParseWebAppManifestIntoVector(const std::string& input);
+
+ PaymentManifestParser();
+ ~PaymentManifestParser() override;
+
+ // mojom::PaymentManifestParser
+ void ParsePaymentMethodManifest(
+ const std::string& content,
+ const ParsePaymentMethodManifestCallback& callback) override;
+ void ParseWebAppManifest(const std::string& content,
+ const ParseWebAppManifestCallback& callack) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PaymentManifestParser);
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CONTENT_UTILITY_PAYMENT_MANIFEST_PARSER_H_
diff --git a/chromium/components/payments/content/utility/payment_manifest_parser_unittest.cc b/chromium/components/payments/content/utility/payment_manifest_parser_unittest.cc
new file mode 100644
index 00000000000..de804990ad4
--- /dev/null
+++ b/chromium/components/payments/content/utility/payment_manifest_parser_unittest.cc
@@ -0,0 +1,494 @@
+// 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/payments/content/utility/payment_manifest_parser.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+namespace {
+
+// Payment method manifest parsing:
+
+TEST(PaymentManifestParserTest, NullPaymentMethodManifestIsMalformed) {
+ EXPECT_TRUE(
+ PaymentManifestParser::ParsePaymentMethodManifestIntoVector(std::string())
+ .empty());
+}
+
+TEST(PaymentManifestParserTest, NonJsonPaymentMethodManifestIsMalformed) {
+ EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector(
+ "this is not json")
+ .empty());
+}
+
+TEST(PaymentManifestParserTest, StringPaymentMethodManifestIsMalformed) {
+ EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector(
+ "\"this is a string\"")
+ .empty());
+}
+
+TEST(PaymentManifestParserTest,
+ EmptyDictionaryPaymentMethodManifestIsMalformed) {
+ EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector("{}")
+ .empty());
+}
+
+TEST(PaymentManifestParserTest, NullDefaultApplicationIsMalformed) {
+ EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector(
+ "{\"default_applications\": null}")
+ .empty());
+}
+
+TEST(PaymentManifestParserTest, NumberDefaultApplicationIsMalformed) {
+ EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector(
+ "{\"default_applications\": 0}")
+ .empty());
+}
+
+TEST(PaymentManifestParserTest, ListOfNumbersDefaultApplicationIsMalformed) {
+ EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector(
+ "{\"default_applications\": [0]}")
+ .empty());
+}
+
+TEST(PaymentManifestParserTest, EmptyListOfDefaultApplicationsIsMalformed) {
+ EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector(
+ "{\"default_applications\": []}")
+ .empty());
+}
+
+TEST(PaymentManifestParserTest, ListOfEmptyDefaultApplicationsIsMalformed) {
+ EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector(
+ "{\"default_applications\": [\"\"]}")
+ .empty());
+}
+
+TEST(PaymentManifestParserTest, DefaultApplicationsShouldNotHaveNulCharacters) {
+ EXPECT_TRUE(
+ PaymentManifestParser::ParsePaymentMethodManifestIntoVector(
+ "{\"default_applications\": [\"https://bobpay.com/app\0json\"]}")
+ .empty());
+}
+
+TEST(PaymentManifestParserTest, DefaultApplicationKeyShouldBeLowercase) {
+ EXPECT_TRUE(
+ PaymentManifestParser::ParsePaymentMethodManifestIntoVector(
+ "{\"Default_Applications\": [\"https://bobpay.com/app.json\"]}")
+ .empty());
+}
+
+TEST(PaymentManifestParserTest, DefaultApplicationsShouldBeAbsoluteUrls) {
+ EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector(
+ "{\"default_applications\": ["
+ "\"https://bobpay.com/app.json\","
+ "\"app.json\"]}")
+ .empty());
+}
+
+TEST(PaymentManifestParserTest, DefaultApplicationsShouldBeHttps) {
+ EXPECT_TRUE(PaymentManifestParser::ParsePaymentMethodManifestIntoVector(
+ "{\"default_applications\": ["
+ "\"https://bobpay.com/app.json\","
+ "\"http://alicepay.com/app.json\"]}")
+ .empty());
+}
+
+TEST(PaymentManifestParserTest, WellFormedPaymentMethodManifest) {
+ std::vector<GURL> expected = {GURL("https://bobpay.com/app.json"),
+ GURL("https://alicepay.com/app.json")};
+ EXPECT_EQ(expected,
+ PaymentManifestParser::ParsePaymentMethodManifestIntoVector(
+ "{\"default_applications\": ["
+ "\"https://bobpay.com/app.json\","
+ "\"https://alicepay.com/app.json\"]}"));
+}
+
+// Web app manifest parsing:
+
+void ExpectUnableToParse(const std::string& input) {
+ std::vector<mojom::WebAppManifestSectionPtr> actual_output =
+ PaymentManifestParser::ParseWebAppManifestIntoVector(input);
+ EXPECT_TRUE(actual_output.empty());
+}
+
+void ExpectParsed(
+ const std::string& input,
+ const std::string& expected_id,
+ int64_t expected_min_version,
+ const std::vector<std::vector<uint8_t>>& expected_fingerprints) {
+ std::vector<mojom::WebAppManifestSectionPtr> actual_output =
+ PaymentManifestParser::ParseWebAppManifestIntoVector(input);
+ ASSERT_EQ(1U, actual_output.size());
+ EXPECT_EQ(expected_id, actual_output.front()->id);
+ EXPECT_EQ(expected_min_version, actual_output.front()->min_version);
+ EXPECT_EQ(expected_fingerprints, actual_output.front()->fingerprints);
+}
+
+TEST(PaymentManifestParserTest, NullContentIsMalformed) {
+ ExpectUnableToParse(std::string());
+}
+
+TEST(PaymentManifestParserTest, NonJsonContentIsMalformed) {
+ ExpectUnableToParse("this is not json");
+}
+
+TEST(PaymentManifestParserTest, StringContentIsMalformed) {
+ ExpectUnableToParse("\"this is a string\"");
+}
+
+TEST(PaymentManifestParserTest, EmptyDictionaryIsMalformed) {
+ ExpectUnableToParse("{}");
+}
+
+TEST(PaymentManifestParserTest, NullRelatedApplicationsSectionIsMalformed) {
+ ExpectUnableToParse("{\"related_applications\": null}");
+}
+
+TEST(PaymentManifestParserTest, NumberRelatedApplicationsectionIsMalformed) {
+ ExpectUnableToParse("{\"related_applications\": 0}");
+}
+
+TEST(PaymentManifestParserTest,
+ ListOfNumbersRelatedApplicationsSectionIsMalformed) {
+ ExpectUnableToParse("{\"related_applications\": [0]}");
+}
+
+TEST(PaymentManifestParserTest,
+ ListOfEmptyDictionariesRelatedApplicationsSectionIsMalformed) {
+ ExpectUnableToParse("{\"related_applications\": [{}]}");
+}
+
+TEST(PaymentManifestParserTest, NoPlayPlatformIsMalformed) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_cert\", "
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, NoPackageNameIsMalformed) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_cert\", "
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, NoVersionIsMalformed) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_cert\", "
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, NoFingerprintIsMalformed) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\""
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, EmptyFingerprintsIsMalformed) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": []"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, EmptyFingerprintsDictionaryIsMalformed) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{}]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, NoFingerprintTypeIsMalformed) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, NoFingerprintValueIsMalformed) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_cert\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, PlatformShouldNotHaveNullCharacters) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"pl\0ay\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_cert\", "
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, PackageNameShouldNotHaveNullCharacters) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bob\0pay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_cert\", "
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, VersionShouldNotHaveNullCharacters) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\01\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_cert\", "
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, FingerprintTypeShouldNotHaveNullCharacters) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_c\0ert\", "
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, FingerprintValueShouldNotHaveNullCharacters) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_cert\", "
+ " \"value\": "
+ "\"00:01:02:0\0:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, KeysShouldBeLowerCase) {
+ ExpectUnableToParse(
+ "{"
+ " \"Related_applications\": [{"
+ " \"Platform\": \"play\", "
+ " \"Id\": \"com.bobpay.app\", "
+ " \"Min_version\": \"1\", "
+ " \"Fingerprints\": [{"
+ " \"Type\": \"sha256_cert\", "
+ " \"Value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, FingerprintsShouldBeSha256) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha1_cert\", "
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, FingerprintBytesShouldBeColonSeparated) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_cert\", "
+ " \"value\" \"00010203040506070809A0A1A2A3A4A5A6A7A8A9B0B1B2B3B4B5B6"
+ "B7B8B9C0C1\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, FingerprintBytesShouldBeUpperCase) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_cert\", "
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:a0:a1:a2:a3:a4:a5:a6:a7"
+ ":a8:a9:b0:b1:b2:b3:b4:b5:b6:b7:b8:b9:c0:c1\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, FingerprintsShouldContainsThirtyTwoBytes) {
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_cert\", "
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1:C2\""
+ " }]"
+ " }]"
+ "}");
+ ExpectUnableToParse(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_cert\", "
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0\""
+ " }]"
+ " }]"
+ "}");
+}
+
+TEST(PaymentManifestParserTest, WellFormed) {
+ ExpectParsed(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_cert\", "
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+ " }]"
+ " }]"
+ "}",
+ "com.bobpay.app", 1,
+ {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA0,
+ 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xB0, 0xB1,
+ 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC0, 0xC1}});
+}
+
+TEST(PaymentManifestParserTest, DuplicateSignaturesWellFormed) {
+ ExpectParsed(
+ "{"
+ " \"related_applications\": [{"
+ " \"platform\": \"play\", "
+ " \"id\": \"com.bobpay.app\", "
+ " \"min_version\": \"1\", "
+ " \"fingerprints\": [{"
+ " \"type\": \"sha256_cert\", "
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+ " }, {"
+ " \"type\": \"sha256_cert\", "
+ " \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+ ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+ " }]"
+ " }]"
+ "}",
+ "com.bobpay.app", 1,
+ {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA0,
+ 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xB0, 0xB1,
+ 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC0, 0xC1},
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA0,
+ 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xB0, 0xB1,
+ 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC0, 0xC1}});
+}
+
+} // namespace
+} // namespace payments
diff --git a/chromium/components/payments/core/BUILD.gn b/chromium/components/payments/core/BUILD.gn
index e0a51dfc193..1892be27352 100644
--- a/chromium/components/payments/core/BUILD.gn
+++ b/chromium/components/payments/core/BUILD.gn
@@ -6,13 +6,38 @@ static_library("core") {
sources = [
"address_normalizer.cc",
"address_normalizer.h",
+ "autofill_payment_instrument.cc",
+ "autofill_payment_instrument.h",
+ "basic_card_response.cc",
+ "basic_card_response.h",
"currency_formatter.cc",
"currency_formatter.h",
+ "journey_logger.cc",
+ "journey_logger.h",
+ "payment_address.cc",
+ "payment_address.h",
+ "payment_instrument.cc",
+ "payment_instrument.h",
+ "payment_method_data.cc",
+ "payment_method_data.h",
+ "payment_options_provider.h",
+ "payment_request_data_util.cc",
+ "payment_request_data_util.h",
+ "payment_request_delegate.h",
+ "profile_util.cc",
+ "profile_util.h",
+ "strings_util.cc",
+ "strings_util.h",
]
deps = [
"//base",
"//components/autofill/core/browser",
+ "//components/strings:components_strings_grit",
+ "//components/ukm",
+ "//third_party/libphonenumber",
+ "//ui/base",
+ "//url",
]
public_deps = [
@@ -25,7 +50,14 @@ source_set("unit_tests") {
testonly = true
sources = [
"address_normalizer_unittest.cc",
+ "autofill_payment_instrument_unittest.cc",
+ "basic_card_response_unittest.cc",
"currency_formatter_unittest.cc",
+ "journey_logger_unittest.cc",
+ "payment_address_unittest.cc",
+ "payment_method_data_unittest.cc",
+ "payment_request_data_util_unittest.cc",
+ "profile_util_unittest.cc",
]
deps = [
@@ -33,6 +65,11 @@ source_set("unit_tests") {
"//base",
"//base/test:test_support",
"//components/autofill/core/browser",
+ "//components/autofill/core/browser:test_support",
+ "//components/metrics/proto",
+ "//components/ukm",
+ "//components/ukm:test_support",
+ "//testing/gmock",
"//testing/gtest",
"//third_party/libaddressinput:test_support",
]
diff --git a/chromium/components/payments/core/DEPS b/chromium/components/payments/core/DEPS
index 77981288756..9347542b4fc 100644
--- a/chromium/components/payments/core/DEPS
+++ b/chromium/components/payments/core/DEPS
@@ -1,5 +1,11 @@
include_rules = [
+ "-components/payments/content",
"-content",
"+components/autofill/core",
+ "+components/metrics",
+ "+components/strings",
+ "+components/ukm",
"+third_party/libaddressinput",
+ "+third_party/libphonenumber",
+ "+ui/base",
]
diff --git a/chromium/components/payments/core/address_normalizer.cc b/chromium/components/payments/core/address_normalizer.cc
index 3114c5a8922..d432ff11e15 100644
--- a/chromium/components/payments/core/address_normalizer.cc
+++ b/chromium/components/payments/core/address_normalizer.cc
@@ -18,6 +18,7 @@
#include "base/time/time.h"
#include "components/autofill/core/browser/address_i18n.h"
#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/payments/core/payment_request_data_util.h"
#include "third_party/libaddressinput/chromium/chrome_address_validator.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
@@ -62,6 +63,9 @@ class AddressNormalizationRequest : public AddressNormalizer::Request {
return;
has_responded_ = true;
+ // In either case, format the phone number.
+ FormatPhoneNumberForResponse();
+
if (!success) {
delegate_->OnCouldNotNormalize(profile_);
return;
@@ -90,6 +94,22 @@ class AddressNormalizationRequest : public AddressNormalizer::Request {
}
private:
+ // Tries to format the phone number to the E.164 format to send in the Payment
+ // Response, as defined in the Payment Request spec. Keeps the original
+ // if it cannot be formatted. More info at:
+ // https://w3c.github.io/browser-payment-api/#paymentrequest-updated-algorithm
+ void FormatPhoneNumberForResponse() {
+ const std::string original_number = base::UTF16ToUTF8(profile_.GetInfo(
+ autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
+ region_code_));
+
+ std::string formatted_number =
+ data_util::FormatPhoneForResponse(original_number, region_code_);
+
+ profile_.SetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER,
+ base::UTF8ToUTF16(formatted_number));
+ }
+
AutofillProfile profile_;
std::string region_code_;
AddressNormalizer::Delegate* delegate_;
diff --git a/chromium/components/payments/core/address_normalizer.h b/chromium/components/payments/core/address_normalizer.h
index 0280d82b1e3..f3d2a240fb5 100644
--- a/chromium/components/payments/core/address_normalizer.h
+++ b/chromium/components/payments/core/address_normalizer.h
@@ -49,8 +49,8 @@ class AddressNormalizer : public autofill::LoadRulesListener {
virtual ~Request() {}
};
- AddressNormalizer(std::unique_ptr<i18n::addressinput::Source> source,
- std::unique_ptr<i18n::addressinput::Storage> storage);
+ AddressNormalizer(std::unique_ptr<::i18n::addressinput::Source> source,
+ std::unique_ptr<::i18n::addressinput::Storage> storage);
~AddressNormalizer() override;
// Start loading the validation rules for the specified |region_code|.
diff --git a/chromium/components/payments/core/address_normalizer_unittest.cc b/chromium/components/payments/core/address_normalizer_unittest.cc
index 0d2f3fae5fc..da9760b3ef2 100644
--- a/chromium/components/payments/core/address_normalizer_unittest.cc
+++ b/chromium/components/payments/core/address_normalizer_unittest.cc
@@ -4,6 +4,8 @@
#include "components/payments/core/address_normalizer.h"
+#include <utility>
+
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_task_scheduler.h"
@@ -23,6 +25,8 @@ using ::i18n::addressinput::Source;
using ::i18n::addressinput::Storage;
using ::i18n::addressinput::TestdataSource;
+const char kLocale[] = "US";
+
// The requester of normalization for this test.
class NormalizationDelegate : public AddressNormalizer::Delegate {
public:
@@ -31,22 +35,26 @@ class NormalizationDelegate : public AddressNormalizer::Delegate {
~NormalizationDelegate() override {}
- void OnAddressNormalized(
- const autofill::AutofillProfile& normalized_profile) override {
+ void OnAddressNormalized(const autofill::AutofillProfile& profile) override {
normalized_called_ = true;
+ profile_ = profile;
}
void OnCouldNotNormalize(const autofill::AutofillProfile& profile) override {
not_normalized_called_ = true;
+ profile_ = profile;
}
- bool normalized_called() { return normalized_called_; }
+ bool normalized_called() const { return normalized_called_; }
- bool not_normalized_called() { return not_normalized_called_; }
+ bool not_normalized_called() const { return not_normalized_called_; }
+
+ const AutofillProfile& profile() const { return profile_; }
private:
bool normalized_called_;
bool not_normalized_called_;
+ AutofillProfile profile_;
DISALLOW_COPY_AND_ASSIGN(NormalizationDelegate);
};
@@ -58,7 +66,7 @@ class ChromiumTestdataSource : public TestdataSource {
~ChromiumTestdataSource() override {}
- // For this test, only load the rules for the "US".
+ // For this test, only load the rules for the kLocale.
void Get(const std::string& key, const Callback& data_ready) const override {
data_ready(
true, key,
@@ -75,8 +83,8 @@ class ChromiumTestdataSource : public TestdataSource {
// loaded.
class TestAddressNormalizer : public AddressNormalizer {
public:
- TestAddressNormalizer(std::unique_ptr<i18n::addressinput::Source> source,
- std::unique_ptr<i18n::addressinput::Storage> storage)
+ TestAddressNormalizer(std::unique_ptr<::i18n::addressinput::Source> source,
+ std::unique_ptr<::i18n::addressinput::Storage> storage)
: AddressNormalizer(std::move(source), std::move(storage)),
should_load_rules_(true) {}
@@ -119,13 +127,13 @@ class AddressNormalizerTest : public testing::Test {
// Tests that rules are not loaded by default.
TEST_F(AddressNormalizerTest, AreRulesLoadedForRegion_NotLoaded) {
- EXPECT_FALSE(normalizer_->AreRulesLoadedForRegion("US"));
+ EXPECT_FALSE(normalizer_->AreRulesLoadedForRegion(kLocale));
}
// Tests that the rules are loaded correctly.
TEST_F(AddressNormalizerTest, AreRulesLoadedForRegion_Loaded) {
- normalizer_->LoadRulesForRegion("US");
- EXPECT_TRUE(normalizer_->AreRulesLoadedForRegion("US"));
+ normalizer_->LoadRulesForRegion(kLocale);
+ EXPECT_TRUE(normalizer_->AreRulesLoadedForRegion(kLocale));
}
// Tests that if the rules are loaded before the normalization is started, the
@@ -135,11 +143,11 @@ TEST_F(AddressNormalizerTest, StartNormalization_RulesLoaded) {
AutofillProfile profile;
// Load the rules.
- normalizer_->LoadRulesForRegion("US");
- EXPECT_TRUE(normalizer_->AreRulesLoadedForRegion("US"));
+ normalizer_->LoadRulesForRegion(kLocale);
+ EXPECT_TRUE(normalizer_->AreRulesLoadedForRegion(kLocale));
// Start the normalization.
- normalizer_->StartAddressNormalization(profile, "US", 0, &delegate);
+ normalizer_->StartAddressNormalization(profile, kLocale, 0, &delegate);
// Since the rules are already loaded, the address should be normalized
// synchronously.
@@ -159,7 +167,7 @@ TEST_F(AddressNormalizerTest, StartNormalization_RulesNotLoaded_WillNotLoad) {
normalizer_->ShouldLoadRules(false);
// Start the normalization.
- normalizer_->StartAddressNormalization(profile, "US", 0, &delegate);
+ normalizer_->StartAddressNormalization(profile, kLocale, 0, &delegate);
// Let the timeout execute.
base::RunLoop().RunUntilIdle();
@@ -177,15 +185,63 @@ TEST_F(AddressNormalizerTest, StartNormalization_RulesNotLoaded_WillLoad) {
AutofillProfile profile;
// Start the normalization.
- normalizer_->StartAddressNormalization(profile, "US", 0, &delegate);
+ normalizer_->StartAddressNormalization(profile, kLocale, 0, &delegate);
// Even if the rules are not loaded before the call to
// StartAddressNormalization, they should get loaded in the call. Since our
// test source is synchronous, the normalization will happen synchronously
// too.
- EXPECT_TRUE(normalizer_->AreRulesLoadedForRegion("US"));
+ EXPECT_TRUE(normalizer_->AreRulesLoadedForRegion(kLocale));
EXPECT_TRUE(delegate.normalized_called());
EXPECT_FALSE(delegate.not_normalized_called());
}
-} // namespace payments \ No newline at end of file
+// Tests that the phone number is formatted when the address is normalized.
+TEST_F(AddressNormalizerTest, FormatPhone_AddressNormalized) {
+ NormalizationDelegate delegate;
+ AutofillProfile profile;
+ profile.SetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER,
+ base::UTF8ToUTF16("(515) 123-1234"));
+
+ // Load the rules.
+ normalizer_->LoadRulesForRegion(kLocale);
+ EXPECT_TRUE(normalizer_->AreRulesLoadedForRegion(kLocale));
+
+ // Start the normalization.
+ normalizer_->StartAddressNormalization(profile, kLocale, 0, &delegate);
+
+ // Make sure the address was normalized.
+ EXPECT_TRUE(delegate.normalized_called());
+
+ // Expect that the phone number was formatted.
+ EXPECT_EQ("+15151231234", base::UTF16ToUTF8(delegate.profile().GetRawInfo(
+ autofill::PHONE_HOME_WHOLE_NUMBER)));
+}
+
+// Tests that the phone number is formatted even when the address is not
+// normalized.
+TEST_F(AddressNormalizerTest, FormatPhone_AddressNotNormalized) {
+ NormalizationDelegate delegate;
+ AutofillProfile profile;
+ profile.SetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER,
+ base::UTF8ToUTF16("515-123-1234"));
+
+ // Make sure the rules will not be loaded in the StartAddressNormalization
+ // call.
+ normalizer_->ShouldLoadRules(false);
+
+ // Start the normalization.
+ normalizer_->StartAddressNormalization(profile, kLocale, 0, &delegate);
+
+ // Let the timeout execute.
+ base::RunLoop().RunUntilIdle();
+
+ // Make sure the address was not normalized.
+ EXPECT_TRUE(delegate.not_normalized_called());
+
+ // Expect that the phone number was formatted.
+ EXPECT_EQ("+15151231234", base::UTF16ToUTF8(delegate.profile().GetRawInfo(
+ autofill::PHONE_HOME_WHOLE_NUMBER)));
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/autofill_payment_instrument.cc b/chromium/components/payments/core/autofill_payment_instrument.cc
new file mode 100644
index 00000000000..398edb70f90
--- /dev/null
+++ b/chromium/components/payments/core/autofill_payment_instrument.cc
@@ -0,0 +1,103 @@
+// 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/payments/core/autofill_payment_instrument.h"
+
+#include "base/json/json_writer.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "components/autofill/core/browser/autofill_data_util.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/common/autofill_clock.h"
+#include "components/payments/core/basic_card_response.h"
+#include "components/payments/core/payment_request_data_util.h"
+#include "components/payments/core/payment_request_delegate.h"
+
+namespace payments {
+
+namespace {
+
+// Returns whether |card| has a non-empty number and cardholder name. Server
+// cards will have a non-empty number.
+bool CreditCardHasNumberAndName(const autofill::CreditCard& card,
+ const std::string& app_locale) {
+ return !card.number().empty() &&
+ !card.GetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
+ app_locale)
+ .empty();
+}
+
+} // namespace
+
+AutofillPaymentInstrument::AutofillPaymentInstrument(
+ const std::string& method_name,
+ const autofill::CreditCard& card,
+ const std::vector<autofill::AutofillProfile*>& billing_profiles,
+ const std::string& app_locale,
+ PaymentRequestDelegate* payment_request_delegate)
+ : PaymentInstrument(
+ method_name,
+ /* label= */ card.TypeAndLastFourDigits(),
+ /* sublabel= */
+ card.GetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
+ app_locale),
+ autofill::data_util::GetPaymentRequestData(card.type())
+ .icon_resource_id,
+ PaymentInstrument::Type::AUTOFILL),
+ credit_card_(card),
+ billing_profiles_(billing_profiles),
+ app_locale_(app_locale),
+ delegate_(nullptr),
+ payment_request_delegate_(payment_request_delegate),
+ weak_ptr_factory_(this) {}
+AutofillPaymentInstrument::~AutofillPaymentInstrument() {}
+
+void AutofillPaymentInstrument::InvokePaymentApp(
+ PaymentInstrument::Delegate* delegate) {
+ DCHECK(delegate);
+ // There can be only one FullCardRequest going on at a time. If |delegate_| is
+ // not null, there's already an active request, which shouldn't happen.
+ // |delegate_| is reset to nullptr when the request succeeds or fails.
+ DCHECK(!delegate_);
+ delegate_ = delegate;
+
+ payment_request_delegate_->DoFullCardRequest(credit_card_,
+ weak_ptr_factory_.GetWeakPtr());
+}
+
+bool AutofillPaymentInstrument::IsCompleteForPayment() {
+ // A card is complete for payment if it's not expired, its number is not
+ // empty (a server card fills this condition) and there is a cardholder name.
+ // TODO(crbug.com/709776): Check for billing address association.
+ return !credit_card_.IsExpired(autofill::AutofillClock::Now()) &&
+ CreditCardHasNumberAndName(credit_card_, app_locale_);
+}
+
+bool AutofillPaymentInstrument::IsValidForCanMakePayment() {
+ // An expired card is still valid for the purposes of canMakePayment.
+ return CreditCardHasNumberAndName(credit_card_, app_locale_);
+}
+
+void AutofillPaymentInstrument::OnFullCardRequestSucceeded(
+ const autofill::CreditCard& card,
+ const base::string16& cvc) {
+ DCHECK(delegate_);
+ credit_card_ = card;
+ std::unique_ptr<base::DictionaryValue> response_value =
+ payments::data_util::GetBasicCardResponseFromAutofillCreditCard(
+ credit_card_, cvc, billing_profiles_, app_locale_)
+ .ToDictionaryValue();
+ std::string stringified_details;
+ base::JSONWriter::Write(*response_value, &stringified_details);
+ delegate_->OnInstrumentDetailsReady(method_name(), stringified_details);
+ delegate_ = nullptr;
+}
+
+void AutofillPaymentInstrument::OnFullCardRequestFailed() {
+ // TODO(anthonyvd): Do something with the error.
+ delegate_ = nullptr;
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/autofill_payment_instrument.h b/chromium/components/payments/core/autofill_payment_instrument.h
new file mode 100644
index 00000000000..84b343ab4c6
--- /dev/null
+++ b/chromium/components/payments/core/autofill_payment_instrument.h
@@ -0,0 +1,71 @@
+// 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_PAYMENTS_CORE_AUTOFILL_PAYMENT_INSTRUMENT_H_
+#define COMPONENTS_PAYMENTS_CORE_AUTOFILL_PAYMENT_INSTRUMENT_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/payments/full_card_request.h"
+#include "components/payments/core/payment_instrument.h"
+
+namespace autofill {
+class AutofillProfile;
+}
+
+namespace payments {
+
+class PaymentRequestDelegate;
+
+// Represents an Autofill/Payments credit card form of payment in Payment
+// Request.
+class AutofillPaymentInstrument
+ : public PaymentInstrument,
+ public autofill::payments::FullCardRequest::ResultDelegate {
+ public:
+ // |billing_profiles| is owned by the caller and should outlive this object.
+ // |payment_request_delegate| must outlive this object.
+ AutofillPaymentInstrument(
+ const std::string& method_name,
+ const autofill::CreditCard& card,
+ const std::vector<autofill::AutofillProfile*>& billing_profiles,
+ const std::string& app_locale,
+ PaymentRequestDelegate* payment_request_delegate);
+ ~AutofillPaymentInstrument() override;
+
+ // PaymentInstrument:
+ void InvokePaymentApp(PaymentInstrument::Delegate* delegate) override;
+ bool IsCompleteForPayment() override;
+ bool IsValidForCanMakePayment() override;
+
+ // autofill::payments::FullCardRequest::ResultDelegate:
+ void OnFullCardRequestSucceeded(const autofill::CreditCard& card,
+ const base::string16& cvc) override;
+ void OnFullCardRequestFailed() override;
+
+ autofill::CreditCard* credit_card() { return &credit_card_; }
+
+ private:
+ // A copy of the card is owned by this object.
+ autofill::CreditCard credit_card_;
+ // Not owned by this object, should outlive this.
+ const std::vector<autofill::AutofillProfile*>& billing_profiles_;
+
+ const std::string app_locale_;
+
+ PaymentInstrument::Delegate* delegate_;
+ PaymentRequestDelegate* payment_request_delegate_;
+
+ base::WeakPtrFactory<AutofillPaymentInstrument> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutofillPaymentInstrument);
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_AUTOFILL_PAYMENT_INSTRUMENT_H_
diff --git a/chromium/components/payments/core/autofill_payment_instrument_unittest.cc b/chromium/components/payments/core/autofill_payment_instrument_unittest.cc
new file mode 100644
index 00000000000..7b9db0be6a9
--- /dev/null
+++ b/chromium/components/payments/core/autofill_payment_instrument_unittest.cc
@@ -0,0 +1,127 @@
+// 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/payments/core/autofill_payment_instrument.h"
+
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+class AutofillPaymentInstrumentTest : public testing::Test {
+ protected:
+ AutofillPaymentInstrumentTest()
+ : address_(autofill::test::GetFullProfile()),
+ local_card_(autofill::test::GetCreditCard()),
+ billing_profiles_({&address_}) {
+ local_card_.set_billing_address_id(address_.guid());
+ }
+
+ autofill::CreditCard& local_credit_card() { return local_card_; }
+ const std::vector<autofill::AutofillProfile*>& billing_profiles() {
+ return billing_profiles_;
+ }
+
+ private:
+ autofill::AutofillProfile address_;
+ autofill::CreditCard local_card_;
+ std::vector<autofill::AutofillProfile*> billing_profiles_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutofillPaymentInstrumentTest);
+};
+
+// A valid local credit card is a valid instrument for payment.
+TEST_F(AutofillPaymentInstrumentTest, IsCompleteForPayment) {
+ AutofillPaymentInstrument instrument("visa", local_credit_card(),
+ billing_profiles(), "en-US", nullptr);
+ EXPECT_TRUE(instrument.IsCompleteForPayment());
+}
+
+// An expired local card is not a valid instrument for payment.
+TEST_F(AutofillPaymentInstrumentTest, IsCompleteForPayment_Expired) {
+ autofill::CreditCard& card = local_credit_card();
+ card.SetExpirationYear(2016); // Expired.
+ AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
+ "en-US", nullptr);
+ EXPECT_FALSE(instrument.IsCompleteForPayment());
+}
+
+// A local card with no name is not a valid instrument for payment.
+TEST_F(AutofillPaymentInstrumentTest, IsCompleteForPayment_NoName) {
+ autofill::CreditCard& card = local_credit_card();
+ card.SetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
+ base::ASCIIToUTF16(""), "en-US");
+ AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
+ "en-US", nullptr);
+ EXPECT_FALSE(instrument.IsCompleteForPayment());
+}
+
+// A local card with no name is not a valid instrument for payment.
+TEST_F(AutofillPaymentInstrumentTest, IsCompleteForPayment_NoNumber) {
+ autofill::CreditCard& card = local_credit_card();
+ card.SetNumber(base::ASCIIToUTF16(""));
+ AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
+ "en-US", nullptr);
+ EXPECT_FALSE(instrument.IsCompleteForPayment());
+}
+
+// A Masked (server) card is a valid instrument for payment.
+TEST_F(AutofillPaymentInstrumentTest, IsCompleteForPayment_MaskedCard) {
+ autofill::CreditCard card = autofill::test::GetMaskedServerCard();
+ AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
+ "en-US", nullptr);
+ EXPECT_TRUE(instrument.IsCompleteForPayment());
+}
+
+// An expired masked (server) card is not a valid instrument for payment.
+TEST_F(AutofillPaymentInstrumentTest, IsCompleteForPayment_ExpiredMaskedCard) {
+ autofill::CreditCard card = autofill::test::GetMaskedServerCard();
+ card.SetExpirationYear(2016); // Expired.
+ AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
+ "en-US", nullptr);
+ EXPECT_FALSE(instrument.IsCompleteForPayment());
+}
+
+// An expired card is a valid instrument for canMakePayment.
+TEST_F(AutofillPaymentInstrumentTest, IsValidForCanMakePayment_Minimal) {
+ autofill::CreditCard& card = local_credit_card();
+ card.SetExpirationYear(2016); // Expired.
+ AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
+ "en-US", nullptr);
+ EXPECT_TRUE(instrument.IsValidForCanMakePayment());
+}
+
+// An expired Masked (server) card is a valid instrument for canMakePayment.
+TEST_F(AutofillPaymentInstrumentTest, IsValidForCanMakePayment_MaskedCard) {
+ autofill::CreditCard card = autofill::test::GetMaskedServerCard();
+ card.SetExpirationYear(2016); // Expired.
+ AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
+ "en-US", nullptr);
+ EXPECT_TRUE(instrument.IsValidForCanMakePayment());
+}
+
+// A card with no name is not a valid instrument for canMakePayment.
+TEST_F(AutofillPaymentInstrumentTest, IsValidForCanMakePayment_NoName) {
+ autofill::CreditCard& card = local_credit_card();
+ card.SetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
+ base::ASCIIToUTF16(""), "en-US");
+ AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
+ "en-US", nullptr);
+ EXPECT_FALSE(instrument.IsValidForCanMakePayment());
+}
+
+// A card with no number is not a valid instrument for canMakePayment.
+TEST_F(AutofillPaymentInstrumentTest, IsValidForCanMakePayment_NoNumber) {
+ autofill::CreditCard& card = local_credit_card();
+ card.SetNumber(base::ASCIIToUTF16(""));
+ AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
+ "en-US", nullptr);
+ EXPECT_FALSE(instrument.IsValidForCanMakePayment());
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/basic_card_response.cc b/chromium/components/payments/core/basic_card_response.cc
new file mode 100644
index 00000000000..77921c1c294
--- /dev/null
+++ b/chromium/components/payments/core/basic_card_response.cc
@@ -0,0 +1,63 @@
+// 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/payments/core/basic_card_response.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+
+namespace payments {
+
+namespace {
+
+// These are defined as part of the spec at:
+// https://w3c.github.io/webpayments-methods-card/#basiccardresponse
+static const char kCardBillingAddress[] = "billingAddress";
+static const char kCardCardholderName[] = "cardholderName";
+static const char kCardCardNumber[] = "cardNumber";
+static const char kCardCardSecurityCode[] = "cardSecurityCode";
+static const char kCardExpiryMonth[] = "expiryMonth";
+static const char kCardExpiryYear[] = "expiryYear";
+
+} // namespace
+
+BasicCardResponse::BasicCardResponse() {}
+BasicCardResponse::BasicCardResponse(const BasicCardResponse& other) = default;
+BasicCardResponse::~BasicCardResponse() = default;
+
+bool BasicCardResponse::operator==(const BasicCardResponse& other) const {
+ return this->cardholder_name == other.cardholder_name &&
+ this->card_number == other.card_number &&
+ this->expiry_month == other.expiry_month &&
+ this->expiry_year == other.expiry_year &&
+ this->card_security_code == other.card_security_code &&
+ this->billing_address == other.billing_address;
+}
+
+bool BasicCardResponse::operator!=(const BasicCardResponse& other) const {
+ return !(*this == other);
+}
+
+std::unique_ptr<base::DictionaryValue> BasicCardResponse::ToDictionaryValue()
+ const {
+ std::unique_ptr<base::DictionaryValue> result =
+ base::MakeUnique<base::DictionaryValue>();
+
+ if (!this->cardholder_name.empty())
+ result->SetString(kCardCardholderName, this->cardholder_name);
+ result->SetString(kCardCardNumber, this->card_number);
+ if (!this->expiry_month.empty())
+ result->SetString(kCardExpiryMonth, this->expiry_month);
+ if (!this->expiry_year.empty())
+ result->SetString(kCardExpiryYear, this->expiry_year);
+ if (!this->card_security_code.empty())
+ result->SetString(kCardCardSecurityCode, this->card_security_code);
+ if (!this->billing_address.ToDictionaryValue()->empty())
+ result->Set(kCardBillingAddress, this->billing_address.ToDictionaryValue());
+
+ return result;
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/basic_card_response.h b/chromium/components/payments/core/basic_card_response.h
new file mode 100644
index 00000000000..55f4c38014b
--- /dev/null
+++ b/chromium/components/payments/core/basic_card_response.h
@@ -0,0 +1,55 @@
+// 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_PAYMENTS_CORE_BASIC_CARD_RESPONSE_H_
+#define COMPONENTS_PAYMENTS_CORE_BASIC_CARD_RESPONSE_H_
+
+#include <memory>
+
+#include "base/strings/string16.h"
+#include "components/payments/core/payment_address.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace payments {
+
+// Contains the response from the PaymentRequest API when a user accepts
+// payment with a Basic Payment Card payment method.
+struct BasicCardResponse {
+ public:
+ BasicCardResponse();
+ BasicCardResponse(const BasicCardResponse& other);
+ ~BasicCardResponse();
+
+ bool operator==(const BasicCardResponse& other) const;
+ bool operator!=(const BasicCardResponse& other) const;
+
+ // Populates |value| with the properties of this BasicCardResponse.
+ std::unique_ptr<base::DictionaryValue> ToDictionaryValue() const;
+
+ // The cardholder's name as it appears on the card.
+ base::string16 cardholder_name;
+
+ // The primary account number (PAN) for the payment card.
+ base::string16 card_number;
+
+ // A two-digit string for the expiry month of the card in the range 01 to 12.
+ base::string16 expiry_month;
+
+ // A two-digit string for the expiry year of the card in the range 00 to 99.
+ base::string16 expiry_year;
+
+ // A three or four digit string for the security code of the card (sometimes
+ // known as the CVV, CVC, CVN, CVE or CID).
+ base::string16 card_security_code;
+
+ // The billing address information associated with the payment card.
+ PaymentAddress billing_address;
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_BASIC_CARD_RESPONSE_H_
diff --git a/chromium/components/payments/core/basic_card_response_unittest.cc b/chromium/components/payments/core/basic_card_response_unittest.cc
new file mode 100644
index 00000000000..51b2bc27f91
--- /dev/null
+++ b/chromium/components/payments/core/basic_card_response_unittest.cc
@@ -0,0 +1,68 @@
+// 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/payments/core/basic_card_response.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+// Tests that two credit card response objects are not equal if their property
+// values differ or one is missing a value present in the other, and equal
+// otherwise. Doesn't test all properties of child objects, relying instead on
+// their respective tests.
+TEST(PaymentRequestTest, BasicCardResponseEquality) {
+ BasicCardResponse card_response1;
+ BasicCardResponse card_response2;
+ EXPECT_EQ(card_response1, card_response2);
+
+ card_response1.cardholder_name = base::ASCIIToUTF16("Shadow Moon");
+ EXPECT_NE(card_response1, card_response2);
+ card_response2.cardholder_name = base::ASCIIToUTF16("Mad Sweeney");
+ EXPECT_NE(card_response1, card_response2);
+ card_response2.cardholder_name = base::ASCIIToUTF16("Shadow Moon");
+ EXPECT_EQ(card_response1, card_response2);
+
+ card_response1.card_number = base::ASCIIToUTF16("4111111111111111");
+ EXPECT_NE(card_response1, card_response2);
+ card_response2.card_number = base::ASCIIToUTF16("1111");
+ EXPECT_NE(card_response1, card_response2);
+ card_response2.card_number = base::ASCIIToUTF16("4111111111111111");
+ EXPECT_EQ(card_response1, card_response2);
+
+ card_response1.expiry_month = base::ASCIIToUTF16("01");
+ EXPECT_NE(card_response1, card_response2);
+ card_response2.expiry_month = base::ASCIIToUTF16("11");
+ EXPECT_NE(card_response1, card_response2);
+ card_response2.expiry_month = base::ASCIIToUTF16("01");
+ EXPECT_EQ(card_response1, card_response2);
+
+ card_response1.expiry_year = base::ASCIIToUTF16("27");
+ EXPECT_NE(card_response1, card_response2);
+ card_response2.expiry_year = base::ASCIIToUTF16("72");
+ EXPECT_NE(card_response1, card_response2);
+ card_response2.expiry_year = base::ASCIIToUTF16("27");
+ EXPECT_EQ(card_response1, card_response2);
+
+ card_response1.expiry_year = base::ASCIIToUTF16("123");
+ EXPECT_NE(card_response1, card_response2);
+ card_response2.expiry_year = base::ASCIIToUTF16("999");
+ EXPECT_NE(card_response1, card_response2);
+ card_response2.expiry_year = base::ASCIIToUTF16("123");
+ EXPECT_EQ(card_response1, card_response2);
+
+ PaymentAddress billing_address1;
+ billing_address1.postal_code = base::ASCIIToUTF16("90210");
+ PaymentAddress billing_address2;
+ billing_address2.postal_code = base::ASCIIToUTF16("01209");
+ card_response1.billing_address = billing_address1;
+ EXPECT_NE(card_response1, card_response2);
+ card_response2.billing_address = billing_address2;
+ EXPECT_NE(card_response1, card_response2);
+ card_response2.billing_address = billing_address1;
+ EXPECT_EQ(card_response1, card_response2);
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/journey_logger.cc b/chromium/components/payments/core/journey_logger.cc
new file mode 100644
index 00000000000..dc25cf6f1bf
--- /dev/null
+++ b/chromium/components/payments/core/journey_logger.cc
@@ -0,0 +1,237 @@
+// 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/payments/core/journey_logger.h"
+
+#include <algorithm>
+
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
+#include "components/ukm/ukm_entry_builder.h"
+#include "components/ukm/ukm_service.h"
+
+namespace payments {
+
+namespace internal {
+extern const char kUKMCheckoutEventsEntryName[] =
+ "PaymentRequest.CheckoutEvents";
+extern const char kUKMCompletionStatusMetricName[] = "CompletionStatus";
+extern const char kUKMEventsMetricName[] = "Events";
+} // namespace internal
+
+namespace {
+
+// Returns the JourneyLogger histograms name suffix based on the |section| and
+// the |completion_status|.
+std::string GetHistogramNameSuffix(
+ int section,
+ JourneyLogger::CompletionStatus completion_status) {
+ std::string name_suffix = "";
+
+ switch (section) {
+ case JourneyLogger::SECTION_SHIPPING_ADDRESS:
+ name_suffix = "ShippingAddress.";
+ break;
+ case JourneyLogger::SECTION_CONTACT_INFO:
+ name_suffix = "ContactInfo.";
+ break;
+ case JourneyLogger::SECTION_CREDIT_CARDS:
+ name_suffix = "CreditCards.";
+ break;
+ default:
+ break;
+ }
+
+ switch (completion_status) {
+ case JourneyLogger::COMPLETION_STATUS_COMPLETED:
+ name_suffix += "Completed";
+ break;
+ case JourneyLogger::COMPLETION_STATUS_USER_ABORTED:
+ name_suffix += "UserAborted";
+ break;
+ case JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED:
+ name_suffix += "OtherAborted";
+ break;
+ default:
+ break;
+ }
+
+ DCHECK(!name_suffix.empty());
+ return name_suffix;
+}
+
+} // namespace
+
+JourneyLogger::JourneyLogger(bool is_incognito,
+ const GURL& url,
+ ukm::UkmService* ukm_service)
+ : was_can_make_payments_used_(false),
+ could_make_payment_(false),
+ was_show_called_(false),
+ is_incognito_(is_incognito),
+ events_(EVENT_INITIATED),
+ url_(url),
+ ukm_service_(ukm_service) {}
+
+JourneyLogger::~JourneyLogger() {}
+
+void JourneyLogger::IncrementSelectionAdds(Section section) {
+ DCHECK_LT(section, SECTION_MAX);
+ sections_[section].number_selection_adds_++;
+}
+
+void JourneyLogger::IncrementSelectionChanges(Section section) {
+ DCHECK_LT(section, SECTION_MAX);
+ sections_[section].number_selection_changes_++;
+}
+
+void JourneyLogger::IncrementSelectionEdits(Section section) {
+ DCHECK_LT(section, SECTION_MAX);
+ sections_[section].number_selection_edits_++;
+}
+
+void JourneyLogger::SetNumberOfSuggestionsShown(Section section, int number) {
+ DCHECK_LT(section, SECTION_MAX);
+ sections_[section].number_suggestions_shown_ = number;
+ sections_[section].is_requested_ = true;
+}
+
+void JourneyLogger::SetCanMakePaymentValue(bool value) {
+ was_can_make_payments_used_ = true;
+ could_make_payment_ |= value;
+}
+
+void JourneyLogger::SetShowCalled() {
+ was_show_called_ = true;
+}
+
+void JourneyLogger::SetEventOccurred(Event event) {
+ events_ |= event;
+}
+
+void JourneyLogger::RecordJourneyStatsHistograms(
+ CompletionStatus completion_status) {
+ RecordSectionSpecificStats(completion_status);
+
+ // Record the CanMakePayment metrics based on whether the transaction was
+ // completed or aborted by the user (UserAborted) or otherwise (OtherAborted).
+ RecordCanMakePaymentStats(completion_status);
+
+ RecordUrlKeyedMetrics(completion_status);
+}
+
+void JourneyLogger::RecordSectionSpecificStats(
+ CompletionStatus completion_status) {
+ // Record whether the user had suggestions for each requested information.
+ bool user_had_all_requested_information = true;
+
+ for (int i = 0; i < NUMBER_OF_SECTIONS; ++i) {
+ std::string name_suffix = GetHistogramNameSuffix(i, completion_status);
+
+ // Only log the metrics for a section if it was requested by the merchant.
+ if (sections_[i].is_requested_) {
+ base::UmaHistogramCustomCounts(
+ "PaymentRequest.NumberOfSelectionAdds." + name_suffix,
+ std::min(sections_[i].number_selection_adds_, MAX_EXPECTED_SAMPLE),
+ MIN_EXPECTED_SAMPLE, MAX_EXPECTED_SAMPLE, NUMBER_BUCKETS);
+ base::UmaHistogramCustomCounts(
+ "PaymentRequest.NumberOfSelectionChanges." + name_suffix,
+ std::min(sections_[i].number_selection_changes_, MAX_EXPECTED_SAMPLE),
+ MIN_EXPECTED_SAMPLE, MAX_EXPECTED_SAMPLE, NUMBER_BUCKETS);
+ base::UmaHistogramCustomCounts(
+ "PaymentRequest.NumberOfSelectionEdits." + name_suffix,
+ std::min(sections_[i].number_selection_edits_, MAX_EXPECTED_SAMPLE),
+ MIN_EXPECTED_SAMPLE, MAX_EXPECTED_SAMPLE, NUMBER_BUCKETS);
+ base::UmaHistogramCustomCounts(
+ "PaymentRequest.NumberOfSuggestionsShown." + name_suffix,
+ std::min(sections_[i].number_suggestions_shown_, MAX_EXPECTED_SAMPLE),
+ MIN_EXPECTED_SAMPLE, MAX_EXPECTED_SAMPLE, NUMBER_BUCKETS);
+
+ if (sections_[i].number_suggestions_shown_ == 0) {
+ user_had_all_requested_information = false;
+ }
+ }
+ }
+
+ // Record metrics about completion based on whether the user had suggestions
+ // for each requested information.
+ if (user_had_all_requested_information) {
+ base::UmaHistogramEnumeration(
+ "PaymentRequest.UserHadSuggestionsForEverything."
+ "EffectOnCompletion",
+ completion_status, COMPLETION_STATUS_MAX);
+ } else {
+ base::UmaHistogramEnumeration(
+ "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
+ "EffectOnCompletion",
+ completion_status, COMPLETION_STATUS_MAX);
+ }
+}
+
+void JourneyLogger::RecordCanMakePaymentStats(
+ CompletionStatus completion_status) {
+ // CanMakePayment always returns true in incognito mode. Don't log the
+ // metrics.
+ if (is_incognito_)
+ return;
+
+ // Record CanMakePayment usage.
+ UMA_HISTOGRAM_ENUMERATION("PaymentRequest.CanMakePayment.Usage",
+ was_can_make_payments_used_
+ ? CAN_MAKE_PAYMENT_USED
+ : CAN_MAKE_PAYMENT_NOT_USED,
+ CAN_MAKE_PAYMENT_USE_MAX);
+
+ RecordCanMakePaymentEffectOnShow();
+ RecordCanMakePaymentEffectOnCompletion(completion_status);
+}
+
+void JourneyLogger::RecordCanMakePaymentEffectOnShow() {
+ if (!was_can_make_payments_used_)
+ return;
+
+ int effect_on_show = 0;
+ if (was_show_called_)
+ effect_on_show |= CMP_SHOW_DID_SHOW;
+ if (could_make_payment_)
+ effect_on_show |= CMP_SHOW_COULD_MAKE_PAYMENT;
+
+ UMA_HISTOGRAM_ENUMERATION("PaymentRequest.CanMakePayment.Used.EffectOnShow",
+ effect_on_show, CMP_SHOW_MAX);
+}
+
+void JourneyLogger::RecordCanMakePaymentEffectOnCompletion(
+ CompletionStatus completion_status) {
+ if (!was_show_called_)
+ return;
+
+ std::string histogram_name = "PaymentRequest.CanMakePayment.";
+ if (!was_can_make_payments_used_) {
+ histogram_name += "NotUsed.WithShowEffectOnCompletion";
+ } else if (could_make_payment_) {
+ histogram_name += "Used.TrueWithShowEffectOnCompletion";
+ } else {
+ histogram_name += "Used.FalseWithShowEffectOnCompletion";
+ }
+
+ base::UmaHistogramEnumeration(histogram_name, completion_status,
+ COMPLETION_STATUS_MAX);
+}
+
+void JourneyLogger::RecordUrlKeyedMetrics(CompletionStatus completion_status) {
+ if (!autofill::IsUkmLoggingEnabled() || !ukm_service_ || !url_.is_valid())
+ return;
+
+ // Record the Checkout Funnel UKM.
+ int32_t source_id = ukm_service_->GetNewSourceID();
+ ukm_service_->UpdateSourceURL(source_id, url_);
+ std::unique_ptr<ukm::UkmEntryBuilder> builder = ukm_service_->GetEntryBuilder(
+ source_id, internal::kUKMCheckoutEventsEntryName);
+ builder->AddMetric(internal::kUKMCompletionStatusMetricName,
+ completion_status);
+ builder->AddMetric(internal::kUKMEventsMetricName, events_);
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/journey_logger.h b/chromium/components/payments/core/journey_logger.h
new file mode 100644
index 00000000000..c3330eb8540
--- /dev/null
+++ b/chromium/components/payments/core/journey_logger.h
@@ -0,0 +1,178 @@
+// 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_PAYMENTS_CORE_JOURNEY_LOGGER_H_
+#define COMPONENTS_PAYMENTS_CORE_JOURNEY_LOGGER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "url/gurl.h"
+
+namespace ukm {
+class UkmService;
+}
+
+namespace payments {
+
+namespace internal {
+// Name constants are exposed here so they can be referenced from tests.
+extern const char kUKMCheckoutEventsEntryName[];
+extern const char kUKMCompletionStatusMetricName[];
+extern const char kUKMEventsMetricName[];
+} // namespace internal
+
+// A class to keep track of different stats during a Payment Request journey. It
+// collects different metrics during the course of the checkout flow, like the
+// number of credit cards that the user added or edited. The metrics will be
+// logged when RecordJourneyStatsHistograms is called with the completion status
+// of the Payment Request.
+class JourneyLogger {
+ public:
+ // Note: These constants should always be in sync with their counterpart in
+ // components/payments/content/android/java/src/org/chromium/components/
+ // payments/JourneyLogger.java.
+ // The different sections of a Payment Request. Used to record journey
+ // stats.
+ enum Section {
+ SECTION_CONTACT_INFO = 0,
+ SECTION_CREDIT_CARDS = 1,
+ SECTION_SHIPPING_ADDRESS = 2,
+ SECTION_MAX,
+ };
+
+ // For the CanMakePayment histograms.
+ enum CanMakePaymentUsage {
+ CAN_MAKE_PAYMENT_USED = 0,
+ CAN_MAKE_PAYMENT_NOT_USED = 1,
+ CAN_MAKE_PAYMENT_USE_MAX,
+ };
+
+ // Used to log different parameters' effect on whether the transaction was
+ // completed.
+ enum CompletionStatus {
+ COMPLETION_STATUS_COMPLETED = 0,
+ COMPLETION_STATUS_USER_ABORTED = 1,
+ COMPLETION_STATUS_OTHER_ABORTED = 2,
+ COMPLETION_STATUS_MAX,
+ };
+
+ // Used to record the different events that happened during the Payment
+ // Request.
+ enum Event {
+ EVENT_INITIATED = 0,
+ EVENT_SHOWN = 1 << 0,
+ EVENT_PAY_CLICKED = 1 << 1,
+ EVENT_RECEIVED_INSTRUMENT_DETAILS = 1 << 2,
+ EVENT_SKIPPED_SHOW = 1 << 3,
+ EVENT_MAX = 16,
+ };
+
+ // Used to mesure the impact of the CanMakePayment return value on whether the
+ // Payment Request is shown to the user.
+ static const int CMP_SHOW_COULD_NOT_MAKE_PAYMENT_AND_DID_NOT_SHOW = 0;
+ static const int CMP_SHOW_DID_SHOW = 1 << 0;
+ static const int CMP_SHOW_COULD_MAKE_PAYMENT = 1 << 1;
+ static const int CMP_SHOW_MAX = 4;
+
+ JourneyLogger(bool is_incognito,
+ const GURL& url,
+ ukm::UkmService* ukm_service);
+ ~JourneyLogger();
+
+ // Increments the number of selection adds for the specified section.
+ void IncrementSelectionAdds(Section section);
+
+ // Increments the number of selection changes for the specified section.
+ void IncrementSelectionChanges(Section section);
+
+ // Increments the number of selection edits for the specified section.
+ void IncrementSelectionEdits(Section section);
+
+ // Sets the number of suggestions shown for the specified section.
+ void SetNumberOfSuggestionsShown(Section section, int number);
+
+ // Records the fact that the merchant called CanMakePayment and records it's
+ // return value.
+ void SetCanMakePaymentValue(bool value);
+
+ // Records the fact that the Payment Request was shown to the user.
+ void SetShowCalled();
+
+ // Records that an event occurred.
+ void SetEventOccurred(Event event);
+
+ // Records the histograms for all the sections that were requested by the
+ // merchant and for the usage of the CanMakePayment method and its effect on
+ // the transaction. This method should be called when the Payment Request has
+ // either been completed or aborted.
+ void RecordJourneyStatsHistograms(CompletionStatus completion_status);
+
+ private:
+ static const int NUMBER_OF_SECTIONS = 3;
+
+ // Note: These constants should always be in sync with their counterpart in
+ // components/payments/content/android/java/src/org/chromium/components/
+ // payments/JourneyLogger.java.
+ // The minimum expected value of CustomCountHistograms is always set to 1. It
+ // is still possible to log the value 0 to that type of histogram.
+ const int MIN_EXPECTED_SAMPLE = 1;
+ const int MAX_EXPECTED_SAMPLE = 49;
+ const int NUMBER_BUCKETS = 50;
+
+ struct SectionStats {
+ SectionStats()
+ : number_selection_adds_(0),
+ number_selection_changes_(0),
+ number_selection_edits_(0),
+ number_suggestions_shown_(0),
+ is_requested_(false) {}
+
+ int number_selection_adds_;
+ int number_selection_changes_;
+ int number_selection_edits_;
+ int number_suggestions_shown_;
+ bool is_requested_;
+ };
+
+ // Records the histograms for all the sections that were requested by the
+ // merchant.
+ void RecordSectionSpecificStats(CompletionStatus completion_status);
+
+ // Records the metrics related the the CanMakePayment method unless in
+ // incognito mode.
+ void RecordCanMakePaymentStats(CompletionStatus completion_status);
+
+ // Records CanMakePayment's return value effect on whether the Payment Request
+ // was shown or not.
+ void RecordCanMakePaymentEffectOnShow();
+
+ // Records the completion status depending on the the usage and return value
+ // of the CanMakePaymentMethod.
+ void RecordCanMakePaymentEffectOnCompletion(
+ CompletionStatus completion_status);
+
+ // Records the Payment Request Url Keyed Metrics.
+ void RecordUrlKeyedMetrics(CompletionStatus completion_status);
+
+ SectionStats sections_[NUMBER_OF_SECTIONS];
+ bool was_can_make_payments_used_;
+ bool could_make_payment_;
+ bool was_show_called_;
+ bool is_incognito_;
+
+ // Accumulates the many events that have happened during the Payment Request.
+ int events_;
+
+ const GURL url_;
+
+ // Not owned, will outlive this object.
+ ukm::UkmService* ukm_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(JourneyLogger);
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_JOURNEY_LOGGER_H_
diff --git a/chromium/components/payments/core/journey_logger_unittest.cc b/chromium/components/payments/core/journey_logger_unittest.cc
new file mode 100644
index 00000000000..fbb1efd4cbd
--- /dev/null
+++ b/chromium/components/payments/core/journey_logger_unittest.cc
@@ -0,0 +1,753 @@
+// 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/payments/core/journey_logger.h"
+
+#include "base/metrics/metrics_hashes.h"
+#include "base/test/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
+#include "components/metrics/proto/ukm/entry.pb.h"
+#include "components/ukm/test_ukm_service.h"
+#include "components/ukm/ukm_entry.h"
+#include "components/ukm/ukm_source.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::ContainerEq;
+
+namespace payments {
+
+namespace {
+// Finds the specified UKM metric by |name| in the specified UKM |metrics|.
+const ukm::Entry_Metric* FindMetric(
+ const char* name,
+ const google::protobuf::RepeatedPtrField<ukm::Entry_Metric>& metrics) {
+ for (const auto& metric : metrics) {
+ if (metric.metric_hash() == base::HashMetricName(name))
+ return &metric;
+ }
+ return nullptr;
+}
+} // namespace
+
+// Tests the canMakePayment stats for the case where the merchant does not use
+// it and does not show the PaymentRequest to the user.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_CanMakePaymentNotCalled_NoShow) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_COMPLETED);
+
+ histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
+ JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
+ 1);
+
+ // There should be no completion stats since PR was not shown to the user
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix(
+ "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+}
+
+// Tests the canMakePayment stats for the case where the merchant does not use
+// it and the transaction is aborted.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_CanMakePaymentNotCalled_ShowAndUserAbort) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Expect no log for CanMakePayment.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+
+ // The merchant does not query CanMakePayment, show the PaymentRequest and the
+ // user aborts it.
+ logger.SetShowCalled();
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED);
+
+ histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
+ JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
+ 1);
+
+ // There should be a record for an abort when CanMakePayment is not used but
+ // the PR is shown to the user.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+}
+
+// Tests the canMakePayment stats for the case where the merchant does not use
+// it and the transaction is aborted.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_CanMakePaymentNotCalled_ShowAndOtherAbort) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Expect no log for CanMakePayment.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+
+ // The merchant does not query CanMakePayment, show the PaymentRequest and
+ // there is an abort not initiated by the user.
+ logger.SetShowCalled();
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED);
+
+ histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
+ JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
+ 1);
+
+ // There should be a record for an abort when CanMakePayment is not used but
+ // the PR is shown to the user.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
+}
+
+// Tests the canMakePayment stats for the case where the merchant does not use
+// it and the transaction is completed.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_CanMakePaymentNotCalled_ShowAndComplete) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Expect no log for CanMakePayment.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+
+ // The merchant does not query CanMakePayment, show the PaymentRequest and the
+ // user completes it.
+ logger.SetShowCalled();
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_COMPLETED);
+
+ histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
+ JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
+ 1);
+
+ // There should be a record for an abort when CanMakePayment is not used but
+ // the PR is shown to the user.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
+}
+
+// Tests the canMakePayment stats for the case where the merchant uses it,
+// returns false and show is not called.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_CanMakePaymentCalled_FalseAndNoShow) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Expect no log for CanMakePayment.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+
+ // The user cannot make payment and the PaymentRequest is not shown.
+ logger.SetCanMakePaymentValue(false);
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED);
+
+ histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
+ JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
+
+ // The CanMakePayment effect on show should be recorded as being false and not
+ // shown.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.EffectOnShow",
+ JourneyLogger::CMP_SHOW_COULD_NOT_MAKE_PAYMENT_AND_DID_NOT_SHOW, 1);
+
+ // There should be no completion stats since PR was not shown to the user.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix(
+ "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+}
+
+// Tests the canMakePayment stats for the case where the merchant uses it,
+// returns true and show is not called.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_CanMakePaymentCalled_TrueAndNoShow) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Expect no log for CanMakePayment.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+
+ // The user cannot make payment and the PaymentRequest is not shown.
+ logger.SetCanMakePaymentValue(true);
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED);
+
+ histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
+ JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
+
+ // The CanMakePayment effect on show should be recorded as being true and not
+ // shown.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.EffectOnShow",
+ JourneyLogger::CMP_SHOW_COULD_MAKE_PAYMENT, 1);
+
+ // There should be no completion stats since PR was not shown to the user.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix(
+ "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+}
+
+// Tests the canMakePayment stats for the case where the merchant uses it,
+// returns false, show is called but the transaction is aborted by the user.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_CanMakePaymentCalled_FalseShowAndUserAbort) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Expect no log for CanMakePayment.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+
+ // The user cannot make payment and the PaymentRequest is not shown.
+ logger.SetShowCalled();
+ logger.SetCanMakePaymentValue(false);
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED);
+
+ histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
+ JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
+
+ // The CanMakePayment effect on show should be recorded as being false and
+ // shown.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.EffectOnShow",
+ JourneyLogger::CMP_SHOW_DID_SHOW, 1);
+ // There should be a record for an abort when CanMakePayment is false but the
+ // PR is shown to the user.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+}
+
+// Tests the canMakePayment stats for the case where the merchant uses it,
+// returns false, show is called but the transaction is aborted.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_CanMakePaymentCalled_FalseShowAndOtherAbort) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Expect no log for CanMakePayment.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+
+ // The user cannot make payment and the PaymentRequest is not shown.
+ logger.SetShowCalled();
+ logger.SetCanMakePaymentValue(false);
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED);
+
+ histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
+ JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
+
+ // The CanMakePayment effect on show should be recorded as being false and
+ // shown.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.EffectOnShow",
+ JourneyLogger::CMP_SHOW_DID_SHOW, 1);
+ // There should be a record for an abort when CanMakePayment is false but the
+ // PR is shown to the user.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
+}
+
+// Tests the canMakePayment stats for the case where the merchant uses it,
+// returns false, show is called and the transaction is completed.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_CanMakePaymentCalled_FalseShowAndComplete) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Expect no log for CanMakePayment.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+
+ // The user cannot make payment and the PaymentRequest is not shown.
+ logger.SetShowCalled();
+ logger.SetCanMakePaymentValue(false);
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_COMPLETED);
+
+ histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
+ JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
+
+ // The CanMakePayment effect on show should be recorded as being false and
+ // shown.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.EffectOnShow",
+ JourneyLogger::CMP_SHOW_DID_SHOW, 1);
+
+ // There should be a record for an completion when CanMakePayment is false but
+ // the PR is shown to the user.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
+}
+
+// Tests the canMakePayment stats for the case where the merchant uses it,
+// returns true, show is called but the transaction is aborted by the user.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_CanMakePaymentCalled_TrueShowAndUserAbort) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Expect no log for CanMakePayment.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+
+ // The user cannot make payment and the PaymentRequest is not shown.
+ logger.SetShowCalled();
+ logger.SetCanMakePaymentValue(true);
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED);
+
+ histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
+ JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
+
+ // The CanMakePayment effect on show should be recorded as being true and not
+ // shown.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.EffectOnShow",
+ JourneyLogger::CMP_SHOW_DID_SHOW |
+ JourneyLogger::CMP_SHOW_COULD_MAKE_PAYMENT,
+ 1);
+ // There should be a record for an abort when CanMakePayment is true and the
+ // PR is shown to the user.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+}
+
+// Tests the canMakePayment stats for the case where the merchant uses it,
+// returns true, show is called but the transaction is aborted.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_CanMakePaymentCalled_TrueShowAndOtherAbort) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Expect no log for CanMakePayment.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+
+ // The user cannot make payment and the PaymentRequest is not shown.
+ logger.SetShowCalled();
+ logger.SetCanMakePaymentValue(true);
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED);
+
+ histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
+ JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
+
+ // The CanMakePayment effect on show should be recorded as being true and not
+ // shown.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.EffectOnShow",
+ JourneyLogger::CMP_SHOW_DID_SHOW |
+ JourneyLogger::CMP_SHOW_COULD_MAKE_PAYMENT,
+ 1);
+ // There should be a record for an abort when CanMakePayment is true and the
+ // PR is shown to the user.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
+}
+
+// Tests the canMakePayment stats for the case where the merchant uses it,
+// returns true, show is called and the transaction is completed.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_CanMakePaymentCalled_TrueShowAndComplete) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Expect no log for CanMakePayment.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+
+ // The user cannot make payment and the PaymentRequest is not shown.
+ logger.SetShowCalled();
+ logger.SetCanMakePaymentValue(true);
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_COMPLETED);
+
+ histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
+ JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
+
+ // The CanMakePayment effect on show should be recorded as being true and not
+ // shown.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.EffectOnShow",
+ JourneyLogger::CMP_SHOW_DID_SHOW |
+ JourneyLogger::CMP_SHOW_COULD_MAKE_PAYMENT,
+ 1);
+ // There should be a record for a completion when CanMakePayment is true and
+ // the PR is shown to the user.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
+}
+
+// Tests the canMakePayment metrics are not logged if the Payment Request was
+// done in an incognito tab.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_CanMakePayment_IncognitoTab) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/true, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Expect no log for CanMakePayment.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+
+ // The user cannot make payment and the PaymentRequest is not shown.
+ logger.SetShowCalled();
+ logger.SetCanMakePaymentValue(true);
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_COMPLETED);
+
+ // Expect no log for CanMakePayment.
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+}
+
+// Tests that the completion status metrics based on whether the user had
+// suggestions for all the requested sections are logged as correctly.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_SuggestionsForEverything_Completed) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Simulate that the user had suggestions for all the requested sections.
+ logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_CREDIT_CARDS, 1);
+
+ // Simulate that the user completes the checkout.
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_COMPLETED);
+
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
+
+ EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
+ "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
+ "EffectOnCompletion"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+}
+
+// Tests that the completion status metrics based on whether the user had
+// suggestions for all the requested sections are logged as correctly.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_SuggestionsForEverything_UserAborted) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Simulate that the user had suggestions for all the requested sections.
+ logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_CREDIT_CARDS, 1);
+
+ // Simulate that the user aborts the checkout.
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED);
+
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+
+ EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
+ "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
+ "EffectOnCompletion"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+}
+
+// Tests that the completion status metrics based on whether the user had
+// suggestions for all the requested sections are logged as correctly.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_SuggestionsForEverything_OtherAborted) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Simulate that the user had suggestions for all the requested sections.
+ logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_CREDIT_CARDS, 1);
+
+ // Simulate that the checkout is aborted.
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED);
+
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
+
+ EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
+ "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
+ "EffectOnCompletion"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+}
+
+// Tests that the completion status metrics based on whether the user had
+// suggestions for all the requested sections are logged as correctly, even in
+// incognito mode.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_SuggestionsForEverything_Incognito) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/true, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Simulate that the user had suggestions for all the requested sections.
+ logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_CREDIT_CARDS, 1);
+
+ // Simulate that the user completes the checkout.
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_COMPLETED);
+
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
+
+ EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
+ "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
+ "EffectOnCompletion"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+}
+
+// Tests that the completion status metrics based on whether the user had
+// suggestions for all the requested sections are logged as correctly.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_NoSuggestionsForEverything_Completed) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Simulate that the user had suggestions for all the requested sections.
+ logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_CREDIT_CARDS, 0);
+
+ // Simulate that the user completes the checkout.
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_COMPLETED);
+
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
+ "EffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
+
+ EXPECT_THAT(
+ histogram_tester.GetTotalCountsForPrefix(
+ "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+}
+
+// Tests that the completion status metrics based on whether the user had
+// suggestions for all the requested sections are logged as correctly.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_NoSuggestionsForEverything_UserAborted) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Simulate that the user had suggestions for all the requested sections.
+ logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_CREDIT_CARDS, 0);
+
+ // Simulate that the user aborts the checkout.
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED);
+
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
+ "EffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+
+ EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
+ "PaymentRequest.UserHadSuggestionsForEverything."
+ "EffectOnCompletion"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+}
+
+// Tests that the completion status metrics based on whether the user had
+// suggestions for all the requested sections are logged as correctly.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_NoSuggestionsForEverything_OtherAborted) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Simulate that the user had suggestions for all the requested sections.
+ logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_CREDIT_CARDS, 0);
+
+ // Simulate that the user aborts the checkout.
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED);
+
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
+ "EffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
+
+ EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
+ "PaymentRequest.UserHadSuggestionsForEverything."
+ "EffectOnCompletion"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+}
+
+// Tests that the completion status metrics based on whether the user had
+// suggestions for all the requested sections are logged as correctly, even in
+// incognito mode.
+TEST(JourneyLoggerTest,
+ RecordJourneyStatsHistograms_NoSuggestionsForEverything_Incognito) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/true, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Simulate that the user had suggestions for all the requested sections.
+ logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_CREDIT_CARDS, 0);
+
+ // Simulate that the user aborts the checkout.
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED);
+
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
+ "EffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+
+ EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
+ "PaymentRequest.UserHadSuggestionsForEverything."
+ "EffectOnCompletion"),
+ testing::ContainerEq(base::HistogramTester::CountsMap()));
+}
+
+// Tests that the metrics are logged correctly for two simultaneous Payment
+// Requests.
+TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_TwoPaymentRequests) {
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger1(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+ JourneyLogger logger2(/*is_incognito=*/false, /*url=*/GURL(""),
+ /*ukm_service=*/nullptr);
+
+ // Make the two loggers have different data.
+ logger1.SetShowCalled();
+ logger2.SetShowCalled();
+
+ logger1.SetCanMakePaymentValue(true);
+
+ logger1.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_CREDIT_CARDS, 1);
+ logger2.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_CREDIT_CARDS, 0);
+
+ // Simulate that the user completes one checkout and aborts the other.
+ logger1.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_COMPLETED);
+ logger2.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED);
+
+ // Make sure the appropriate metrics were logged for logger1.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
+ histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
+ JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
+
+ // Make sure the appropriate metrics were logged for logger2.
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
+ "EffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+ histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
+ JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
+ 1);
+ histogram_tester.ExpectBucketCount(
+ "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+}
+
+// Tests that the Payment Request UKMs are logged correctly.
+TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_CheckoutFunnelUkm) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(autofill::kAutofillUkmLogging);
+
+ ukm::UkmServiceTestingHarness ukm_service_test_harness;
+ ukm::TestUkmService* ukm_service =
+ ukm_service_test_harness.test_ukm_service();
+ char test_url[] = "http://www.google.com/";
+
+ base::HistogramTester histogram_tester;
+ JourneyLogger logger(/*is_incognito=*/true, /*url=*/GURL(test_url),
+ /*ukm_service=*/ukm_service);
+
+ // Simulate that the user aborts after being shown the Payment Request and
+ // clicking pay.
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
+ logger.SetEventOccurred(JourneyLogger::EVENT_PAY_CLICKED);
+ logger.RecordJourneyStatsHistograms(
+ JourneyLogger::COMPLETION_STATUS_USER_ABORTED);
+
+ // Make sure the UKM was logged correctly.
+ ASSERT_EQ(1U, ukm_service->sources_count());
+ const ukm::UkmSource* source = ukm_service->GetSourceForUrl(test_url);
+ ASSERT_NE(nullptr, source);
+
+ ASSERT_EQ(1U, ukm_service->entries_count());
+ const ukm::UkmEntry* entry = ukm_service->GetEntry(0);
+ EXPECT_EQ(source->id(), entry->source_id());
+
+ ukm::Entry entry_proto;
+ entry->PopulateProto(&entry_proto);
+ EXPECT_EQ(source->id(), entry_proto.source_id());
+ EXPECT_EQ(base::HashMetricName(internal::kUKMCheckoutEventsEntryName),
+ entry_proto.event_hash());
+
+ const ukm::Entry_Metric* status_metric = FindMetric(
+ internal::kUKMCompletionStatusMetricName, entry_proto.metrics());
+ ASSERT_NE(nullptr, status_metric);
+ EXPECT_EQ(JourneyLogger::COMPLETION_STATUS_USER_ABORTED,
+ status_metric->value());
+
+ const ukm::Entry_Metric* step_metric =
+ FindMetric(internal::kUKMEventsMetricName, entry_proto.metrics());
+ ASSERT_NE(nullptr, step_metric);
+ EXPECT_EQ(JourneyLogger::EVENT_SHOWN | JourneyLogger::EVENT_PAY_CLICKED,
+ step_metric->value());
+}
+
+} // namespace payments \ No newline at end of file
diff --git a/chromium/components/payments/core/payment_address.cc b/chromium/components/payments/core/payment_address.cc
new file mode 100644
index 00000000000..42b61c9ad8d
--- /dev/null
+++ b/chromium/components/payments/core/payment_address.cc
@@ -0,0 +1,90 @@
+// 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/payments/core/payment_address.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+
+namespace payments {
+
+namespace {
+
+// These are defined as part of the spec at:
+// https://w3c.github.io/browser-payment-api/#paymentaddress-interface
+static const char kAddressAddressLine[] = "addressLine";
+static const char kAddressCity[] = "city";
+static const char kAddressCountry[] = "country";
+static const char kAddressDependentLocality[] = "dependentLocality";
+static const char kAddressLanguageCode[] = "languageCode";
+static const char kAddressOrganization[] = "organization";
+static const char kAddressPhone[] = "phone";
+static const char kAddressPostalCode[] = "postalCode";
+static const char kAddressRecipient[] = "recipient";
+static const char kAddressRegion[] = "region";
+static const char kAddressSortingCode[] = "sortingCode";
+
+} // namespace
+
+PaymentAddress::PaymentAddress() {}
+PaymentAddress::PaymentAddress(const PaymentAddress& other) = default;
+PaymentAddress::~PaymentAddress() = default;
+
+bool PaymentAddress::operator==(const PaymentAddress& other) const {
+ return this->country == other.country &&
+ this->address_line == other.address_line &&
+ this->region == other.region && this->city == other.city &&
+ this->dependent_locality == other.dependent_locality &&
+ this->postal_code == other.postal_code &&
+ this->sorting_code == other.sorting_code &&
+ this->language_code == other.language_code &&
+ this->organization == other.organization &&
+ this->recipient == other.recipient && this->phone == other.phone;
+}
+
+bool PaymentAddress::operator!=(const PaymentAddress& other) const {
+ return !(*this == other);
+}
+
+std::unique_ptr<base::DictionaryValue> PaymentAddress::ToDictionaryValue()
+ const {
+ std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
+
+ if (!this->country.empty())
+ result->SetString(kAddressCountry, this->country);
+
+ if (!this->address_line.empty()) {
+ std::unique_ptr<base::ListValue> address_line =
+ base::MakeUnique<base::ListValue>();
+ for (const base::string16& address_line_string : this->address_line) {
+ if (!address_line_string.empty())
+ address_line->AppendString(address_line_string);
+ }
+ result->Set(kAddressAddressLine, std::move(address_line));
+ }
+
+ if (!this->region.empty())
+ result->SetString(kAddressRegion, this->region);
+ if (!this->city.empty())
+ result->SetString(kAddressCity, this->city);
+ if (!this->dependent_locality.empty())
+ result->SetString(kAddressDependentLocality, this->dependent_locality);
+ if (!this->postal_code.empty())
+ result->SetString(kAddressPostalCode, this->postal_code);
+ if (!this->sorting_code.empty())
+ result->SetString(kAddressSortingCode, this->sorting_code);
+ if (!this->language_code.empty())
+ result->SetString(kAddressLanguageCode, this->language_code);
+ if (!this->organization.empty())
+ result->SetString(kAddressOrganization, this->organization);
+ if (!this->recipient.empty())
+ result->SetString(kAddressRecipient, this->recipient);
+ if (!this->phone.empty())
+ result->SetString(kAddressPhone, this->phone);
+
+ return result;
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_address.h b/chromium/components/payments/core/payment_address.h
new file mode 100644
index 00000000000..01403fe3746
--- /dev/null
+++ b/chromium/components/payments/core/payment_address.h
@@ -0,0 +1,78 @@
+// 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_PAYMENTS_CORE_PAYMENT_ADDRESS_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_ADDRESS_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/strings/string16.h"
+
+// C++ bindings for the PaymentRequest API PaymentAddress. Conforms to the
+// following spec:
+// https://w3c.github.io/browser-payment-api/#paymentaddress-interface
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace payments {
+
+// A shipping or billing address.
+struct PaymentAddress {
+ public:
+ PaymentAddress();
+ PaymentAddress(const PaymentAddress& other);
+ ~PaymentAddress();
+
+ bool operator==(const PaymentAddress& other) const;
+ bool operator!=(const PaymentAddress& other) const;
+
+ // Populates |value| with the properties of this PaymentAddress.
+ std::unique_ptr<base::DictionaryValue> ToDictionaryValue() const;
+
+ // The CLDR (Common Locale Data Repository) region code. For example, US, GB,
+ // CN, or JP.
+ base::string16 country;
+
+ // The most specific part of the address. It can include, for example, a
+ // street name, a house number, apartment number, a rural delivery route,
+ // descriptive instructions, or a post office box number.
+ std::vector<base::string16> address_line;
+
+ // The top level administrative subdivision of the country. For example, this
+ // can be a state, a province, an oblast, or a prefecture.
+ base::string16 region;
+
+ // The city/town portion of the address.
+ base::string16 city;
+
+ // The dependent locality or sublocality within a city. For example, used for
+ // neighborhoods, boroughs, districts, or UK dependent localities.
+ base::string16 dependent_locality;
+
+ // The postal code or ZIP code, also known as PIN code in India.
+ base::string16 postal_code;
+
+ // The sorting code as used in, for example, France.
+ base::string16 sorting_code;
+
+ // The BCP-47 language code for the address. It's used to determine the field
+ // separators and the order of fields when formatting the address for display.
+ base::string16 language_code;
+
+ // The organization, firm, company, or institution at this address.
+ base::string16 organization;
+
+ // The name of the recipient or contact person.
+ base::string16 recipient;
+
+ // The phone number of the recipient or contact person.
+ base::string16 phone;
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_PAYMENT_ADDRESS_H_
diff --git a/chromium/components/payments/core/payment_address_unittest.cc b/chromium/components/payments/core/payment_address_unittest.cc
new file mode 100644
index 00000000000..38dac5190aa
--- /dev/null
+++ b/chromium/components/payments/core/payment_address_unittest.cc
@@ -0,0 +1,105 @@
+// 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/payments/core/payment_address.h"
+
+#include <vector>
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+// Tests that two addresses are not equal if their property values differ or
+// one is missing a value present in the other, and equal otherwise.
+TEST(PaymentRequestTest, PaymentAddressEquality) {
+ PaymentAddress address1;
+ PaymentAddress address2;
+ EXPECT_EQ(address1, address2);
+
+ address1.country = base::ASCIIToUTF16("Madagascar");
+ EXPECT_NE(address1, address2);
+ address2.country = base::ASCIIToUTF16("Monaco");
+ EXPECT_NE(address1, address2);
+ address2.country = base::ASCIIToUTF16("Madagascar");
+ EXPECT_EQ(address1, address2);
+
+ std::vector<base::string16> address_line1;
+ address_line1.push_back(base::ASCIIToUTF16("123 Main St."));
+ address_line1.push_back(base::ASCIIToUTF16("Apartment B"));
+ address1.address_line = address_line1;
+ EXPECT_NE(address1, address2);
+ std::vector<base::string16> address_line2;
+ address_line2.push_back(base::ASCIIToUTF16("123 Main St."));
+ address_line2.push_back(base::ASCIIToUTF16("Apartment C"));
+ address2.address_line = address_line2;
+ EXPECT_NE(address1, address2);
+ address2.address_line = address_line1;
+ EXPECT_EQ(address1, address2);
+
+ address1.region = base::ASCIIToUTF16("Quebec");
+ EXPECT_NE(address1, address2);
+ address2.region = base::ASCIIToUTF16("Newfoundland and Labrador");
+ EXPECT_NE(address1, address2);
+ address2.region = base::ASCIIToUTF16("Quebec");
+ EXPECT_EQ(address1, address2);
+
+ address1.city = base::ASCIIToUTF16("Timbuktu");
+ EXPECT_NE(address1, address2);
+ address2.city = base::ASCIIToUTF16("Timbuk 3");
+ EXPECT_NE(address1, address2);
+ address2.city = base::ASCIIToUTF16("Timbuktu");
+ EXPECT_EQ(address1, address2);
+
+ address1.dependent_locality = base::ASCIIToUTF16("Manhattan");
+ EXPECT_NE(address1, address2);
+ address2.dependent_locality = base::ASCIIToUTF16("Queens");
+ EXPECT_NE(address1, address2);
+ address2.dependent_locality = base::ASCIIToUTF16("Manhattan");
+ EXPECT_EQ(address1, address2);
+
+ address1.postal_code = base::ASCIIToUTF16("90210");
+ EXPECT_NE(address1, address2);
+ address2.postal_code = base::ASCIIToUTF16("89049");
+ EXPECT_NE(address1, address2);
+ address2.postal_code = base::ASCIIToUTF16("90210");
+ EXPECT_EQ(address1, address2);
+
+ address1.sorting_code = base::ASCIIToUTF16("14390");
+ EXPECT_NE(address1, address2);
+ address2.sorting_code = base::ASCIIToUTF16("09341");
+ EXPECT_NE(address1, address2);
+ address2.sorting_code = base::ASCIIToUTF16("14390");
+ EXPECT_EQ(address1, address2);
+
+ address1.language_code = base::ASCIIToUTF16("fr");
+ EXPECT_NE(address1, address2);
+ address2.language_code = base::ASCIIToUTF16("zh-HK");
+ EXPECT_NE(address1, address2);
+ address2.language_code = base::ASCIIToUTF16("fr");
+ EXPECT_EQ(address1, address2);
+
+ address1.organization = base::ASCIIToUTF16("The Willy Wonka Candy Company");
+ EXPECT_NE(address1, address2);
+ address2.organization = base::ASCIIToUTF16("Sears");
+ EXPECT_NE(address1, address2);
+ address2.organization = base::ASCIIToUTF16("The Willy Wonka Candy Company");
+ EXPECT_EQ(address1, address2);
+
+ address1.recipient = base::ASCIIToUTF16("Veruca Salt");
+ EXPECT_NE(address1, address2);
+ address2.recipient = base::ASCIIToUTF16("Veronica Mars");
+ EXPECT_NE(address1, address2);
+ address2.recipient = base::ASCIIToUTF16("Veruca Salt");
+ EXPECT_EQ(address1, address2);
+
+ address1.phone = base::ASCIIToUTF16("888-867-5309");
+ EXPECT_NE(address1, address2);
+ address2.phone = base::ASCIIToUTF16("800-984-3672");
+ EXPECT_NE(address1, address2);
+ address2.phone = base::ASCIIToUTF16("888-867-5309");
+ EXPECT_EQ(address1, address2);
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_instrument.cc b/chromium/components/payments/core/payment_instrument.cc
new file mode 100644
index 00000000000..097917c8427
--- /dev/null
+++ b/chromium/components/payments/core/payment_instrument.cc
@@ -0,0 +1,22 @@
+// 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/payments/core/payment_instrument.h"
+
+namespace payments {
+
+PaymentInstrument::PaymentInstrument(const std::string& method_name,
+ const base::string16& label,
+ const base::string16& sublabel,
+ int icon_resource_id,
+ Type type)
+ : method_name_(method_name),
+ label_(label),
+ sublabel_(sublabel),
+ icon_resource_id_(icon_resource_id),
+ type_(type) {}
+
+PaymentInstrument::~PaymentInstrument() {}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_instrument.h b/chromium/components/payments/core/payment_instrument.h
new file mode 100644
index 00000000000..5d70847f4f2
--- /dev/null
+++ b/chromium/components/payments/core/payment_instrument.h
@@ -0,0 +1,71 @@
+// 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_PAYMENTS_CORE_PAYMENT_INSTRUMENT_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_INSTRUMENT_H_
+
+#include <set>
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+
+namespace payments {
+
+// Base class which represents a form of payment in Payment Request.
+class PaymentInstrument {
+ public:
+ // The type of this instrument instance.
+ enum class Type { AUTOFILL };
+
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ // Should be called with method name (e.g., "visa") and json-serialized
+ // stringified details.
+ virtual void OnInstrumentDetailsReady(
+ const std::string& method_name,
+ const std::string& stringified_details) = 0;
+
+ virtual void OnInstrumentDetailsError() = 0;
+ };
+
+ virtual ~PaymentInstrument();
+
+ // Will call into the |delegate| (can't be null) on success or error.
+ virtual void InvokePaymentApp(Delegate* delegate) = 0;
+ // Returns whether the instrument is complete to be used as a payment method
+ // without further editing.
+ virtual bool IsCompleteForPayment() = 0;
+ // Returns whether the instrument is valid for the purposes of responding to
+ // canMakePayment.
+ virtual bool IsValidForCanMakePayment() = 0;
+
+ const std::string& method_name() const { return method_name_; }
+ const base::string16& label() const { return label_; }
+ const base::string16& sublabel() const { return sublabel_; }
+ int icon_resource_id() const { return icon_resource_id_; }
+ Type type() { return type_; }
+
+ protected:
+ PaymentInstrument(const std::string& method_name,
+ const base::string16& label,
+ const base::string16& sublabel,
+ int icon_resource_id,
+ Type type);
+
+ private:
+ const std::string method_name_;
+ const base::string16 label_;
+ const base::string16 sublabel_;
+ int icon_resource_id_;
+ Type type_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaymentInstrument);
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_PAYMENT_INSTRUMENT_H_
diff --git a/chromium/components/payments/core/payment_method_data.cc b/chromium/components/payments/core/payment_method_data.cc
new file mode 100644
index 00000000000..2ea818e579f
--- /dev/null
+++ b/chromium/components/payments/core/payment_method_data.cc
@@ -0,0 +1,94 @@
+// 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/payments/core/payment_method_data.h"
+
+#include "base/json/json_writer.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+
+namespace payments {
+
+namespace {
+
+// These are defined as part of the spec at:
+// https://w3c.github.io/browser-payment-api/#paymentmethoddata-dictionary
+static const char kMethodDataData[] = "data";
+static const char kSupportedMethods[] = "supportedMethods";
+static const char kSupportedNetworks[] = "supportedNetworks";
+static const char kSupportedTypes[] = "supportedTypes";
+
+} // namespace
+
+PaymentMethodData::PaymentMethodData() {}
+PaymentMethodData::PaymentMethodData(const PaymentMethodData& other) = default;
+PaymentMethodData::~PaymentMethodData() = default;
+
+bool PaymentMethodData::operator==(const PaymentMethodData& other) const {
+ return this->supported_methods == other.supported_methods &&
+ this->data == other.data &&
+ this->supported_networks == other.supported_networks &&
+ this->supported_types == other.supported_types;
+}
+
+bool PaymentMethodData::operator!=(const PaymentMethodData& other) const {
+ return !(*this == other);
+}
+
+bool PaymentMethodData::FromDictionaryValue(
+ const base::DictionaryValue& value) {
+ this->supported_methods.clear();
+ this->supported_networks.clear();
+ this->supported_types.clear();
+
+ const base::ListValue* supported_methods_list = nullptr;
+ // At least one supported method is required.
+ if (!value.GetList(kSupportedMethods, &supported_methods_list) ||
+ supported_methods_list->GetSize() == 0) {
+ return false;
+ }
+ for (size_t i = 0; i < supported_methods_list->GetSize(); ++i) {
+ std::string supported_method;
+ if (!supported_methods_list->GetString(i, &supported_method) ||
+ !base::IsStringASCII(supported_method)) {
+ return false;
+ }
+ this->supported_methods.push_back(supported_method);
+ }
+
+ // Data is optional, but if a dictionary is present, save a stringified
+ // version and attempt to parse supportedNetworks/supportedTypes.
+ const base::DictionaryValue* data_dict = nullptr;
+ if (value.GetDictionary(kMethodDataData, &data_dict)) {
+ std::string json_data;
+ base::JSONWriter::Write(*data_dict, &json_data);
+ this->data = json_data;
+ const base::ListValue* supported_networks_list = nullptr;
+ if (data_dict->GetList(kSupportedNetworks, &supported_networks_list)) {
+ for (size_t i = 0; i < supported_networks_list->GetSize(); ++i) {
+ std::string supported_network;
+ if (!supported_networks_list->GetString(i, &supported_network) ||
+ !base::IsStringASCII(supported_network)) {
+ return false;
+ }
+ this->supported_networks.push_back(supported_network);
+ }
+ }
+ const base::ListValue* supported_types_list = nullptr;
+ if (data_dict->GetList(kSupportedTypes, &supported_types_list)) {
+ for (size_t i = 0; i < supported_types_list->GetSize(); ++i) {
+ std::string supported_type;
+ if (!supported_types_list->GetString(i, &supported_type) ||
+ !base::IsStringASCII(supported_type)) {
+ return false;
+ }
+ this->supported_types.push_back(supported_type);
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_method_data.h b/chromium/components/payments/core/payment_method_data.h
new file mode 100644
index 00000000000..5bc7241db27
--- /dev/null
+++ b/chromium/components/payments/core/payment_method_data.h
@@ -0,0 +1,49 @@
+// 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_PAYMENTS_CORE_PAYMENT_METHOD_DATA_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_METHOD_DATA_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace payments {
+
+// A set of supported payment methods and any associated payment method specific
+// data for those methods.
+class PaymentMethodData {
+ public:
+ PaymentMethodData();
+ PaymentMethodData(const PaymentMethodData& other);
+ ~PaymentMethodData();
+
+ bool operator==(const PaymentMethodData& other) const;
+ bool operator!=(const PaymentMethodData& other) const;
+
+ // Populates the properties of this PaymentMethodData from |value|. Returns
+ // true if the required values are present.
+ bool FromDictionaryValue(const base::DictionaryValue& value);
+
+ // Payment method identifiers for payment methods that the merchant web site
+ // accepts.
+ std::vector<std::string> supported_methods;
+
+ // A JSON-serialized object that provides optional information that might be
+ // needed by the supported payment methods.
+ std::string data;
+
+ // When the methods include "basic-card", a list of networks and types that
+ // are supported.
+ std::vector<std::string> supported_networks;
+ std::vector<std::string> supported_types;
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_PAYMENT_METHOD_DATA_H_
diff --git a/chromium/components/payments/core/payment_method_data_unittest.cc b/chromium/components/payments/core/payment_method_data_unittest.cc
new file mode 100644
index 00000000000..a20e283a175
--- /dev/null
+++ b/chromium/components/payments/core/payment_method_data_unittest.cc
@@ -0,0 +1,110 @@
+// 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/payments/core/payment_method_data.h"
+
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+// Tests the success case when populating a PaymentMethodData from a dictionary.
+TEST(PaymentMethodData, FromDictionaryValueSuccess) {
+ PaymentMethodData expected;
+ std::vector<std::string> supported_methods;
+ supported_methods.push_back("visa");
+ supported_methods.push_back("basic-card");
+ expected.supported_methods = supported_methods;
+ expected.data =
+ "{\"supportedNetworks\":[\"mastercard\"],"
+ "\"supportedTypes\":[\"debit\",\"credit\"]}";
+ std::vector<std::string> supported_networks;
+ supported_networks.push_back("mastercard");
+ expected.supported_networks = supported_networks;
+ std::vector<std::string> supported_types;
+ supported_types.push_back("debit");
+ supported_types.push_back("credit");
+ expected.supported_types = supported_types;
+
+ base::DictionaryValue method_data_dict;
+ std::unique_ptr<base::ListValue> supported_methods_list(new base::ListValue);
+ supported_methods_list->AppendString("visa");
+ supported_methods_list->AppendString("basic-card");
+ method_data_dict.Set("supportedMethods", std::move(supported_methods_list));
+ std::unique_ptr<base::DictionaryValue> data_dict(new base::DictionaryValue);
+ std::unique_ptr<base::ListValue> supported_networks_list(new base::ListValue);
+ supported_networks_list->AppendString("mastercard");
+ data_dict->Set("supportedNetworks", std::move(supported_networks_list));
+ std::unique_ptr<base::ListValue> supported_types_list(new base::ListValue);
+ supported_types_list->AppendString("debit");
+ supported_types_list->AppendString("credit");
+ data_dict->Set("supportedTypes", std::move(supported_types_list));
+ method_data_dict.Set("data", std::move(data_dict));
+
+ PaymentMethodData actual;
+ EXPECT_TRUE(actual.FromDictionaryValue(method_data_dict));
+
+ EXPECT_EQ(expected, actual);
+}
+
+// Tests the failure case when populating a PaymentMethodData from a dictionary.
+TEST(PaymentMethodData, FromDictionaryValueFailure) {
+ // At least one supported method is required.
+ PaymentMethodData actual;
+ base::DictionaryValue method_data_dict;
+ EXPECT_FALSE(actual.FromDictionaryValue(method_data_dict));
+
+ // The value in the supported methods list must be a string.
+ std::unique_ptr<base::ListValue> supported_methods_list(new base::ListValue);
+ supported_methods_list->AppendInteger(13);
+ method_data_dict.Set("supportedMethods", std::move(supported_methods_list));
+ EXPECT_FALSE(actual.FromDictionaryValue(method_data_dict));
+}
+
+// Tests that two method data objects are not equal if their property values
+// differ or one is missing a value present in the other, and equal otherwise.
+TEST(PaymentMethodData, Equality) {
+ PaymentMethodData method_data1;
+ PaymentMethodData method_data2;
+ EXPECT_EQ(method_data1, method_data2);
+
+ std::vector<std::string> supported_methods1;
+ supported_methods1.push_back("basic-card");
+ supported_methods1.push_back("http://bobpay.com");
+ method_data1.supported_methods = supported_methods1;
+ EXPECT_NE(method_data1, method_data2);
+ std::vector<std::string> supported_methods2;
+ supported_methods2.push_back("http://bobpay.com");
+ method_data2.supported_methods = supported_methods2;
+ EXPECT_NE(method_data1, method_data2);
+ method_data2.supported_methods = supported_methods1;
+ EXPECT_EQ(method_data1, method_data2);
+
+ method_data1.data = "{merchantId: '123456'}";
+ EXPECT_NE(method_data1, method_data2);
+ method_data2.data = "{merchantId: '9999-88'}";
+ EXPECT_NE(method_data1, method_data2);
+ method_data2.data = "{merchantId: '123456'}";
+ EXPECT_EQ(method_data1, method_data2);
+
+ std::vector<std::string> supported_networks1{"visa"};
+ method_data1.supported_networks = supported_networks1;
+ EXPECT_NE(method_data1, method_data2);
+ std::vector<std::string> supported_networks2{"jcb"};
+ method_data2.supported_networks = supported_networks2;
+ EXPECT_NE(method_data1, method_data2);
+ method_data2.supported_networks = supported_networks1;
+ EXPECT_EQ(method_data1, method_data2);
+
+ std::vector<std::string> supported_types1{"credit"};
+ method_data1.supported_types = supported_types1;
+ EXPECT_NE(method_data1, method_data2);
+ std::vector<std::string> supported_types2{"debit"};
+ method_data2.supported_types = supported_types2;
+ EXPECT_NE(method_data1, method_data2);
+ method_data2.supported_types = supported_types1;
+ EXPECT_EQ(method_data1, method_data2);
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_options_provider.h b/chromium/components/payments/core/payment_options_provider.h
new file mode 100644
index 00000000000..2421b93de71
--- /dev/null
+++ b/chromium/components/payments/core/payment_options_provider.h
@@ -0,0 +1,44 @@
+// 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_PAYMENTS_CORE_PAYMENT_OPTIONS_PROVIDER_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_OPTIONS_PROVIDER_H_
+
+namespace payments {
+
+// See PaymentOptionsProvider::shipping_type() below.
+enum class PaymentShippingType : int32_t {
+ SHIPPING = 0,
+ DELIVERY = 1,
+ PICKUP = 2,
+};
+
+// An interface which provides immutable values, specified by the merchant at
+// request-time, describing the set of information required from the payer, and
+// possibly the method by which the order will be fulfilled.
+class PaymentOptionsProvider {
+ public:
+ virtual ~PaymentOptionsProvider() {}
+
+ // Returns true if this transaction requires the payer's name.
+ virtual bool request_payer_name() const = 0;
+
+ // Returns true if this transaction requires the payer's email address.
+ virtual bool request_payer_email() const = 0;
+
+ // Returns true if this transaction requires the payer's phone number.
+ virtual bool request_payer_phone() const = 0;
+
+ // Returns true if this transaction requires a shipping address.
+ virtual bool request_shipping() const = 0;
+
+ // A value, provided by the merchant at request-time, indicating the method
+ // by which the order will be fulfilled. Used only to modify presentation of
+ // the user interface, and only meaningful when request_shipping() is true.
+ virtual PaymentShippingType shipping_type() const = 0;
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_PAYMENT_OPTIONS_PROVIDER_H_
diff --git a/chromium/components/payments/core/payment_request_data_util.cc b/chromium/components/payments/core/payment_request_data_util.cc
new file mode 100644
index 00000000000..8fb65723122
--- /dev/null
+++ b/chromium/components/payments/core/payment_request_data_util.cc
@@ -0,0 +1,172 @@
+// 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/payments/core/payment_request_data_util.h"
+
+#include "base/strings/string16.h"
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/payments/core/basic_card_response.h"
+#include "components/payments/core/payment_address.h"
+#include "components/payments/core/payment_method_data.h"
+#include "third_party/libphonenumber/phonenumber_api.h"
+
+namespace payments {
+namespace data_util {
+
+namespace {
+using ::i18n::phonenumbers::PhoneNumber;
+using ::i18n::phonenumbers::PhoneNumberUtil;
+
+// Formats the |phone_number| to the specified |format|. Returns the original
+// number if the operation is not possible.
+std::string FormatPhoneNumber(const std::string& phone_number,
+ const std::string& country_code,
+ PhoneNumberUtil::PhoneNumberFormat format) {
+ PhoneNumber parsed_number;
+ PhoneNumberUtil* phone_number_util = PhoneNumberUtil::GetInstance();
+ if (phone_number_util->Parse(phone_number, country_code, &parsed_number) !=
+ PhoneNumberUtil::NO_PARSING_ERROR) {
+ return phone_number;
+ }
+
+ std::string formatted_number;
+ phone_number_util->Format(parsed_number, format, &formatted_number);
+ return formatted_number;
+}
+
+} // namespace
+
+PaymentAddress GetPaymentAddressFromAutofillProfile(
+ const autofill::AutofillProfile& profile,
+ const std::string& app_locale) {
+ PaymentAddress address;
+ address.country = profile.GetRawInfo(autofill::ADDRESS_HOME_COUNTRY);
+ address.address_line = base::SplitString(
+ profile.GetInfo(
+ autofill::AutofillType(autofill::ADDRESS_HOME_STREET_ADDRESS),
+ app_locale),
+ base::ASCIIToUTF16("\n"), base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ address.region = profile.GetRawInfo(autofill::ADDRESS_HOME_STATE);
+ address.city = profile.GetRawInfo(autofill::ADDRESS_HOME_CITY);
+ address.dependent_locality =
+ profile.GetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_LOCALITY);
+ address.postal_code = profile.GetRawInfo(autofill::ADDRESS_HOME_ZIP);
+ address.sorting_code =
+ profile.GetRawInfo(autofill::ADDRESS_HOME_SORTING_CODE);
+ address.language_code = base::UTF8ToUTF16(profile.language_code());
+ address.organization = profile.GetRawInfo(autofill::COMPANY_NAME);
+ address.recipient =
+ profile.GetInfo(autofill::AutofillType(autofill::NAME_FULL), app_locale);
+ address.phone = profile.GetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER);
+
+ return address;
+}
+
+BasicCardResponse GetBasicCardResponseFromAutofillCreditCard(
+ const autofill::CreditCard& card,
+ const base::string16& cvc,
+ const std::vector<autofill::AutofillProfile*>& billing_profiles,
+ const std::string& app_locale) {
+ BasicCardResponse response;
+ response.cardholder_name = card.GetRawInfo(autofill::CREDIT_CARD_NAME_FULL);
+ response.card_number = card.GetRawInfo(autofill::CREDIT_CARD_NUMBER);
+ response.expiry_month = card.GetRawInfo(autofill::CREDIT_CARD_EXP_MONTH);
+ response.expiry_year =
+ card.GetRawInfo(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR);
+ response.card_security_code = cvc;
+
+ // TODO(crbug.com/602666): Ensure we reach here only if the card has a billing
+ // address. Then add DCHECK(!card->billing_address_id().empty()).
+ if (!card.billing_address_id().empty()) {
+ const autofill::AutofillProfile* billing_address =
+ autofill::PersonalDataManager::GetProfileFromProfilesByGUID(
+ card.billing_address_id(), billing_profiles);
+ DCHECK(billing_address);
+ response.billing_address =
+ GetPaymentAddressFromAutofillProfile(*billing_address, app_locale);
+ }
+
+ return response;
+}
+
+bool ParseBasicCardSupportedNetworks(
+ const std::vector<PaymentMethodData>& method_data,
+ std::vector<std::string>* out_supported_networks,
+ std::set<std::string>* out_basic_card_specified_networks) {
+ DCHECK(out_supported_networks->empty());
+ DCHECK(out_basic_card_specified_networks->empty());
+
+ std::set<std::string> card_networks{"amex", "diners", "discover",
+ "jcb", "mastercard", "mir",
+ "unionpay", "visa"};
+ for (const PaymentMethodData& method_data_entry : method_data) {
+ if (method_data_entry.supported_methods.empty())
+ return false;
+
+ for (const std::string& method : method_data_entry.supported_methods) {
+ if (method.empty())
+ continue;
+
+ // If a card network is specified right in "supportedMethods", add it.
+ const char kBasicCardMethodName[] = "basic-card";
+ auto card_it = card_networks.find(method);
+ if (card_it != card_networks.end()) {
+ out_supported_networks->push_back(method);
+ // |method| removed from |card_networks| so that it is not doubly added
+ // to |supported_card_networks_| if "basic-card" is specified with no
+ // supported networks.
+ card_networks.erase(card_it);
+ } else if (method == kBasicCardMethodName) {
+ // For the "basic-card" method, check "supportedNetworks".
+ if (method_data_entry.supported_networks.empty()) {
+ // Empty |supported_networks| means all networks are supported.
+ out_supported_networks->insert(out_supported_networks->end(),
+ card_networks.begin(),
+ card_networks.end());
+ out_basic_card_specified_networks->insert(card_networks.begin(),
+ card_networks.end());
+ // Clear the set so that no further networks are added to
+ // |out_supported_networks|.
+ card_networks.clear();
+ } else {
+ // The merchant has specified a few basic card supported networks. Use
+ // the mapping to transform to known basic-card types.
+ for (const std::string& supported_network :
+ method_data_entry.supported_networks) {
+ // Make sure that the network was not already added to
+ // |out_supported_networks|. If it's still in |card_networks| it's
+ // fair game.
+ auto it = card_networks.find(supported_network);
+ if (it != card_networks.end()) {
+ out_supported_networks->push_back(supported_network);
+ out_basic_card_specified_networks->insert(supported_network);
+ card_networks.erase(it);
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+std::string FormatPhoneForDisplay(const std::string& phone_number,
+ const std::string& country_code) {
+ return FormatPhoneNumber(phone_number, country_code,
+ PhoneNumberUtil::PhoneNumberFormat::INTERNATIONAL);
+}
+
+std::string FormatPhoneForResponse(const std::string& phone_number,
+ const std::string& country_code) {
+ return FormatPhoneNumber(phone_number, country_code,
+ PhoneNumberUtil::PhoneNumberFormat::E164);
+}
+
+} // namespace data_util
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_request_data_util.h b/chromium/components/payments/core/payment_request_data_util.h
new file mode 100644
index 00000000000..f3120c8c3d6
--- /dev/null
+++ b/chromium/components/payments/core/payment_request_data_util.h
@@ -0,0 +1,73 @@
+// 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_PAYMENTS_CORE_PAYMENT_REQUEST_DATA_UTIL_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_REQUEST_DATA_UTIL_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/strings/string16.h"
+
+namespace autofill {
+class AutofillProfile;
+class CreditCard;
+} // namespace autofill
+
+namespace payments {
+
+struct BasicCardResponse;
+struct PaymentAddress;
+class PaymentMethodData;
+
+namespace data_util {
+
+// Helper function to get an instance of web::PaymentAddress from an autofill
+// profile.
+PaymentAddress GetPaymentAddressFromAutofillProfile(
+ const autofill::AutofillProfile& profile,
+ const std::string& app_locale);
+
+// Helper function to get an instance of web::BasicCardResponse from an autofill
+// credit card.
+BasicCardResponse GetBasicCardResponseFromAutofillCreditCard(
+ const autofill::CreditCard& card,
+ const base::string16& cvc,
+ const std::vector<autofill::AutofillProfile*>& billing_profiles,
+ const std::string& app_locale);
+
+// Parse the supported card networks from supportedMethods and "basic-card"'s
+// supportedNetworks. |out_supported_networks| is filled with list of networks
+// in the order that they were specified by the merchant.
+// |out_basic_card_supported_networks| is a subset of |out_supported_networks|
+// that includes all networks that were specified as part of "basic-card". This
+// is used to know whether to return the card network name (e.g., "visa") or
+// "basic-card" in the PaymentResponse. Returns true on success, false on
+// invalid data specified. |method_data.supported_networks| is expected to only
+// contain basic-card card network names (the list is at
+// https://www.w3.org/Payments/card-network-ids).
+bool ParseBasicCardSupportedNetworks(
+ const std::vector<PaymentMethodData>& method_data,
+ std::vector<std::string>* out_supported_networks,
+ std::set<std::string>* out_basic_card_supported_networks);
+
+// Formats the given number |phone_number| to
+// i18n::phonenumbers::PhoneNumberUtil::PhoneNumberFormat::INTERNATIONAL format
+// by using i18n::phonenumbers::PhoneNumberUtil::Format.
+std::string FormatPhoneForDisplay(const std::string& phone_number,
+ const std::string& country_code);
+
+// Formats the given number |phone_number| to
+// i18n::phonenumbers::PhoneNumberUtil::PhoneNumberFormat::E164 format by using
+// i18n::phonenumbers::PhoneNumberUtil::Format, as defined in the Payment
+// Request spec
+// (https://w3c.github.io/browser-payment-api/#paymentrequest-updated-algorithm)
+std::string FormatPhoneForResponse(const std::string& phone_number,
+ const std::string& country_code);
+
+} // namespace data_util
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_PAYMENT_REQUEST_DATA_UTIL_H_
diff --git a/chromium/components/payments/core/payment_request_data_util_unittest.cc b/chromium/components/payments/core/payment_request_data_util_unittest.cc
new file mode 100644
index 00000000000..5ad7e109637
--- /dev/null
+++ b/chromium/components/payments/core/payment_request_data_util_unittest.cc
@@ -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.
+
+#include "components/payments/core/payment_request_data_util.h"
+
+#include <memory>
+
+#include "base/json/json_writer.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/payments/core/basic_card_response.h"
+#include "components/payments/core/payment_address.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+namespace data_util {
+
+// Tests that the serialized version of the PaymentAddress is according to the
+// PaymentAddress spec.
+TEST(PaymentRequestDataUtilTest, GetPaymentAddressFromAutofillProfile) {
+ autofill::AutofillProfile address = autofill::test::GetFullProfile();
+ std::unique_ptr<base::DictionaryValue> address_value =
+ payments::data_util::GetPaymentAddressFromAutofillProfile(address,
+ "en-US")
+ .ToDictionaryValue();
+ std::string json_address;
+ base::JSONWriter::Write(*address_value, &json_address);
+ EXPECT_EQ(
+ "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"],"
+ "\"city\":\"Elysium\","
+ "\"country\":\"US\","
+ "\"organization\":\"Underworld\","
+ "\"phone\":\"16502111111\","
+ "\"postalCode\":\"91111\","
+ "\"recipient\":\"John H. Doe\","
+ "\"region\":\"CA\"}",
+ json_address);
+}
+
+// Tests that the basic card response constructed from a credit card with
+// associated billing address has the right structure once serialized.
+TEST(PaymentRequestDataUtilTest, GetBasicCardResponseFromAutofillCreditCard) {
+ autofill::AutofillProfile address = autofill::test::GetFullProfile();
+ autofill::CreditCard card = autofill::test::GetCreditCard();
+ card.set_billing_address_id(address.guid());
+ std::unique_ptr<base::DictionaryValue> response_value =
+ payments::data_util::GetBasicCardResponseFromAutofillCreditCard(
+ card, base::ASCIIToUTF16("123"),
+ std::vector<autofill::AutofillProfile*>{&address}, "en-US")
+ .ToDictionaryValue();
+ std::string json_response;
+ base::JSONWriter::Write(*response_value, &json_response);
+ EXPECT_EQ(
+ "{\"billingAddress\":"
+ "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"],"
+ "\"city\":\"Elysium\","
+ "\"country\":\"US\","
+ "\"organization\":\"Underworld\","
+ "\"phone\":\"16502111111\","
+ "\"postalCode\":\"91111\","
+ "\"recipient\":\"John H. Doe\","
+ "\"region\":\"CA\"},"
+ "\"cardNumber\":\"4111111111111111\","
+ "\"cardSecurityCode\":\"123\","
+ "\"cardholderName\":\"Test User\","
+ "\"expiryMonth\":\"11\","
+ "\"expiryYear\":\"2022\"}",
+ json_response);
+}
+
+// Tests that the phone numbers are correctly formatted for the Payment
+// Response.
+TEST(PaymentRequestDataUtilTest, FormatPhoneForResponse) {
+ EXPECT_EQ("+15151231234", payments::data_util::FormatPhoneForResponse(
+ "(515) 123-1234", "US"));
+ EXPECT_EQ("+15151231234", payments::data_util::FormatPhoneForResponse(
+ "(1) 515-123-1234", "US"));
+ EXPECT_EQ("+33142685300",
+ payments::data_util::FormatPhoneForResponse("1 42 68 53 00", "FR"));
+}
+
+// Tests that the phone numbers are correctly formatted to display to the user.
+TEST(PaymentRequestDataUtilTest, FormatPhoneForDisplay) {
+ EXPECT_EQ("+1 515-123-1234",
+ payments::data_util::FormatPhoneForDisplay("5151231234", "US"));
+ EXPECT_EQ("+33 1 42 68 53 00",
+ payments::data_util::FormatPhoneForDisplay("142685300", "FR"));
+}
+
+} // namespace data_util
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_request_delegate.h b/chromium/components/payments/core/payment_request_delegate.h
new file mode 100644
index 00000000000..aab278af6f2
--- /dev/null
+++ b/chromium/components/payments/core/payment_request_delegate.h
@@ -0,0 +1,71 @@
+// 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_PAYMENTS_CORE_PAYMENT_REQUEST_DELEGATE_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_REQUEST_DELEGATE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "components/autofill/core/browser/payments/full_card_request.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h"
+
+namespace i18n {
+namespace addressinput {
+class Storage;
+class Source;
+} // namespace addressinput
+} // namespace i18n
+
+namespace autofill {
+class CreditCard;
+class PersonalDataManager;
+} // namespace autofill
+
+namespace payments {
+
+class PaymentRequest;
+
+class PaymentRequestDelegate {
+ public:
+ virtual ~PaymentRequestDelegate() {}
+
+ // Shows the Payment Request dialog for the given |request|.
+ virtual void ShowDialog(PaymentRequest* request) = 0;
+
+ // Closes the same dialog that was opened by this delegate. Must be safe to
+ // call when the dialog is not showing.
+ virtual void CloseDialog() = 0;
+
+ // Disables the dialog and shows an error message that the transaction has
+ // failed.
+ virtual void ShowErrorMessage() = 0;
+
+ // Gets the PersonalDataManager associated with this PaymentRequest flow.
+ // Cannot be null.
+ virtual autofill::PersonalDataManager* GetPersonalDataManager() = 0;
+
+ virtual const std::string& GetApplicationLocale() const = 0;
+
+ // Returns whether the user is in Incognito mode.
+ virtual bool IsIncognito() const = 0;
+
+ // Starts a FullCardRequest to unmask |credit_card|.
+ virtual void DoFullCardRequest(
+ const autofill::CreditCard& credit_card,
+ base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate>
+ result_delegate) = 0;
+
+ // Returns the source and storage for country/region data loads.
+ virtual std::unique_ptr<const ::i18n::addressinput::Source>
+ GetAddressInputSource() = 0;
+ virtual std::unique_ptr<::i18n::addressinput::Storage>
+ GetAddressInputStorage() = 0;
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_PAYMENT_REQUEST_DELEGATE_H_
diff --git a/chromium/components/payments/core/profile_util.cc b/chromium/components/payments/core/profile_util.cc
new file mode 100644
index 00000000000..c1149c85ed8
--- /dev/null
+++ b/chromium/components/payments/core/profile_util.cc
@@ -0,0 +1,123 @@
+// 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/payments/core/profile_util.h"
+
+#include <algorithm>
+
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "components/payments/core/payment_options_provider.h"
+
+namespace payments {
+namespace profile_util {
+
+std::vector<autofill::AutofillProfile*> FilterProfilesForContact(
+ const std::vector<autofill::AutofillProfile*>& profiles,
+ const std::string& app_locale,
+ const PaymentOptionsProvider& options) {
+ // We will be removing profiles, so we operate on a copy.
+ std::vector<autofill::AutofillProfile*> processed = profiles;
+
+ PaymentsProfileComparator comparator(app_locale, options);
+
+ // Stable sort, since profiles are expected to be passed in frecency order.
+ std::stable_sort(
+ processed.begin(), processed.end(),
+ std::bind(&PaymentsProfileComparator::IsContactMoreComplete, &comparator,
+ std::placeholders::_1, std::placeholders::_2));
+
+ auto it = processed.begin();
+ while (it != processed.end()) {
+ if (comparator.GetContactCompletenessScore(*it) == 0) {
+ // Since profiles are sorted by completeness, this and any further
+ // profiles can be discarded.
+ processed.erase(it, processed.end());
+ break;
+ }
+
+ // Attempt to find a matching element in the vector before the current.
+ // This is quadratic, but the number of elements is generally small
+ // (< 10), so a more complicated algorithm would be overkill.
+ if (std::find_if(processed.begin(), it,
+ [&](autofill::AutofillProfile* prior) {
+ return comparator.IsContactEqualOrSuperset(*prior, **it);
+ }) != it) {
+ // Remove the subset profile. |it| will point to the next element after
+ // erasure.
+ it = processed.erase(it);
+ } else {
+ it++;
+ }
+ }
+
+ return processed;
+}
+
+PaymentsProfileComparator::PaymentsProfileComparator(
+ const std::string& app_locale,
+ const PaymentOptionsProvider& options)
+ : autofill::AutofillProfileComparator(app_locale), options_(options) {}
+
+PaymentsProfileComparator::~PaymentsProfileComparator() {}
+
+bool PaymentsProfileComparator::IsContactEqualOrSuperset(
+ const autofill::AutofillProfile& super,
+ const autofill::AutofillProfile& sub) {
+ if (options_.request_payer_name()) {
+ if (sub.HasInfo(autofill::NAME_FULL) &&
+ !super.HasInfo(autofill::NAME_FULL)) {
+ return false;
+ }
+ if (!HaveMergeableNames(super, sub))
+ return false;
+ }
+ if (options_.request_payer_phone()) {
+ if (sub.HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER) &&
+ !super.HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER)) {
+ return false;
+ }
+ if (!HaveMergeablePhoneNumbers(super, sub))
+ return false;
+ }
+ if (options_.request_payer_email()) {
+ if (sub.HasInfo(autofill::EMAIL_ADDRESS) &&
+ !super.HasInfo(autofill::EMAIL_ADDRESS)) {
+ return false;
+ }
+ if (!HaveMergeableEmailAddresses(super, sub))
+ return false;
+ }
+ return true;
+}
+
+int PaymentsProfileComparator::GetContactCompletenessScore(
+ const autofill::AutofillProfile* profile) {
+ if (!profile)
+ return 0;
+
+ return (options_.request_payer_name() &&
+ profile->HasInfo(autofill::NAME_FULL)) +
+ (options_.request_payer_phone() &&
+ profile->HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER)) +
+ (options_.request_payer_email() &&
+ profile->HasInfo(autofill::EMAIL_ADDRESS));
+}
+
+bool PaymentsProfileComparator::IsContactInfoComplete(
+ const autofill::AutofillProfile* profile) {
+ int desired_score = options_.request_payer_name() +
+ options_.request_payer_phone() +
+ options_.request_payer_email();
+ return GetContactCompletenessScore(profile) == desired_score;
+}
+
+bool PaymentsProfileComparator::IsContactMoreComplete(
+ const autofill::AutofillProfile* p1,
+ const autofill::AutofillProfile* p2) {
+ return GetContactCompletenessScore(p1) > GetContactCompletenessScore(p2);
+}
+
+} // namespace profile_util
+} // namespace payments
diff --git a/chromium/components/payments/core/profile_util.h b/chromium/components/payments/core/profile_util.h
new file mode 100644
index 00000000000..6693fe854c8
--- /dev/null
+++ b/chromium/components/payments/core/profile_util.h
@@ -0,0 +1,69 @@
+// 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_PAYMENTS_CONTENT_PROFILE_UTIL_H_
+#define COMPONENTS_PAYMENTS_CONTENT_PROFILE_UTIL_H_
+
+#include <string>
+#include <vector>
+
+#include "components/autofill/core/browser/autofill_profile_comparator.h"
+
+// Utility functions used for processing and filtering address profiles
+// (AutofillProfile).
+
+namespace autofill {
+class AutofillProfile;
+} // namespace autofill
+
+namespace payments {
+
+class PaymentOptionsProvider;
+
+namespace profile_util {
+
+// Returns profiles for contact info, ordered by completeness and deduplicated.
+// |profiles| should be passed in order of frecency, and this order will be
+// preserved among equally-complete profiles. Deduplication here means that
+// profiles returned are excluded if they are a subset of a more complete or
+// more frecent profile. Completeness here refers only to the presence of the
+// fields requested per the request_payer_* fields in |options|.
+std::vector<autofill::AutofillProfile*> FilterProfilesForContact(
+ const std::vector<autofill::AutofillProfile*>& profiles,
+ const std::string& app_locale,
+ const PaymentOptionsProvider& options);
+
+// Helper class which evaluates profiles for similarity and completeness.
+class PaymentsProfileComparator : public autofill::AutofillProfileComparator {
+ public:
+ PaymentsProfileComparator(const std::string& app_locale,
+ const PaymentOptionsProvider& options);
+ ~PaymentsProfileComparator();
+
+ // Returns true iff all of the contact info in |sub| also appears in |super|.
+ // Only operates on fields requested in |options|.
+ bool IsContactEqualOrSuperset(const autofill::AutofillProfile& super,
+ const autofill::AutofillProfile& sub);
+
+ // Returns the number of contact fields requested in |options| which are
+ // nonempty in |profile|.
+ int GetContactCompletenessScore(const autofill::AutofillProfile* profile);
+
+ // Returns true iff every contact field requested in |options| is nonempty in
+ // |profile|.
+ bool IsContactInfoComplete(const autofill::AutofillProfile* profile);
+
+ // Comparison function suitable for sorting profiles by contact completeness
+ // score with std::sort.
+ bool IsContactMoreComplete(const autofill::AutofillProfile* p1,
+ const autofill::AutofillProfile* p2);
+
+ private:
+ const PaymentOptionsProvider& options_;
+};
+
+} // namespace profile_util
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CONTENT_PROFILE_UTIL_H_ \ No newline at end of file
diff --git a/chromium/components/payments/core/profile_util_unittest.cc b/chromium/components/payments/core/profile_util_unittest.cc
new file mode 100644
index 00000000000..5ff1d7ec4e3
--- /dev/null
+++ b/chromium/components/payments/core/profile_util_unittest.cc
@@ -0,0 +1,231 @@
+// 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/payments/core/profile_util.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/guid.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/payments/core/payment_options_provider.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using autofill::AutofillProfile;
+
+namespace payments {
+namespace profile_util {
+
+constexpr uint32_t kRequestPayerName = 1 << 0;
+constexpr uint32_t kRequestPayerEmail = 1 << 1;
+constexpr uint32_t kRequestPayerPhone = 1 << 2;
+constexpr uint32_t kRequestShipping = 1 << 3;
+
+class MockPaymentOptionsProvider : public PaymentOptionsProvider {
+ public:
+ MockPaymentOptionsProvider(uint32_t options) : options_(options) {}
+
+ ~MockPaymentOptionsProvider() override {}
+ bool request_payer_name() const override {
+ return options_ & kRequestPayerName;
+ }
+ bool request_payer_email() const override {
+ return options_ & kRequestPayerEmail;
+ }
+ bool request_payer_phone() const override {
+ return options_ & kRequestPayerPhone;
+ }
+ bool request_shipping() const override { return options_ & kRequestShipping; }
+ PaymentShippingType shipping_type() const override {
+ return PaymentShippingType::SHIPPING;
+ }
+
+ private:
+ uint32_t options_;
+};
+
+AutofillProfile CreateProfileWithContactInfo(const char* name,
+ const char* email,
+ const char* phone) {
+ AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
+ autofill::test::SetProfileInfo(&profile, name, "", "", email, "", "", "", "",
+ "", "", "", phone);
+ return profile;
+}
+
+TEST(PaymentRequestProfileUtilTest, FilterProfilesForContact) {
+ // These profiles are subset/equal, so only the first complete one is
+ // included.
+ AutofillProfile exclude_1 =
+ CreateProfileWithContactInfo("Homer", "", "5551234567");
+
+ AutofillProfile exclude_2 =
+ CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
+
+ AutofillProfile include_1 =
+ CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
+
+ AutofillProfile exclude_3 =
+ CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
+
+ // This profile is different, so it should also be included. Since it is
+ // less complete than |include_1|, it will appear after.
+ AutofillProfile include_2 =
+ CreateProfileWithContactInfo("Marge", "marge@simpson.net", "");
+
+ // This profile is different, so it should also be included. Since it is
+ // equally complete with |include_1|, it will appear before |include_2|, but
+ // after |include_1| since order is preserved amongst profiles of equal
+ // completeness.
+ AutofillProfile include_3 = CreateProfileWithContactInfo(
+ "Bart", "eatmyshorts@simpson.net", "5551234567");
+
+ std::vector<AutofillProfile*> profiles = {&exclude_1, &exclude_2, &include_1,
+ &exclude_3, &include_2, &include_3};
+
+ MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail |
+ kRequestPayerPhone);
+ std::vector<AutofillProfile*> filtered =
+ FilterProfilesForContact(profiles, "en-US", provider);
+
+ ASSERT_EQ(3u, filtered.size());
+ EXPECT_EQ(&include_1, filtered[0]);
+ EXPECT_EQ(&include_3, filtered[1]);
+ EXPECT_EQ(&include_2, filtered[2]);
+
+ // Repeat the filter using a provider set to only request phone numbers.
+ // Under these rules, since all profiles have the same (or no) phone number,
+ // we should only see the first profile with a phone number, |exclude_1|.
+ MockPaymentOptionsProvider phone_only_provider(kRequestPayerPhone);
+ std::vector<AutofillProfile*> filtered_phones =
+ FilterProfilesForContact(profiles, "en-US", phone_only_provider);
+ ASSERT_EQ(1u, filtered_phones.size());
+ EXPECT_EQ(&exclude_1, filtered_phones[0]);
+}
+
+TEST(PaymentRequestProfileUtilTest, IsContactEqualOrSuperset) {
+ MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail |
+ kRequestPayerPhone);
+ PaymentsProfileComparator comp("en-US", provider);
+
+ AutofillProfile p1 =
+ CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
+
+ // Candidate subset profile is equal.
+ AutofillProfile p2 =
+ CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
+ EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p2));
+ EXPECT_TRUE(comp.IsContactEqualOrSuperset(p2, p1));
+
+ // Candidate subset profile has non-matching fields.
+ AutofillProfile p3 = CreateProfileWithContactInfo(
+ "Homer", "homer@springfieldnuclear.gov", "5551234567");
+ EXPECT_FALSE(comp.IsContactEqualOrSuperset(p1, p3));
+ EXPECT_FALSE(comp.IsContactEqualOrSuperset(p3, p1));
+
+ // Candidate subset profile is equal, except for missing fields.
+ AutofillProfile p4 =
+ CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
+ EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p4));
+ EXPECT_FALSE(comp.IsContactEqualOrSuperset(p4, p1));
+
+ // One field is common, but each has a field which the other is missing.
+ AutofillProfile p5 =
+ CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
+ AutofillProfile p6 = CreateProfileWithContactInfo("Homer", "", "5551234567");
+ EXPECT_FALSE(comp.IsContactEqualOrSuperset(p5, p6));
+ EXPECT_FALSE(comp.IsContactEqualOrSuperset(p6, p5));
+}
+
+TEST(PaymentRequestProfileUtilTest, IsContactEqualOrSuperset_WithFieldIgnored) {
+ // Discrepancies in email should be ignored throughout this test.
+ MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone);
+ PaymentsProfileComparator comp("en-US", provider);
+
+ AutofillProfile p1 =
+ CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
+
+ // Candidate subset profile is equal.
+ AutofillProfile p2 =
+ CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
+ EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p2));
+ EXPECT_TRUE(comp.IsContactEqualOrSuperset(p2, p1));
+
+ // Email fields don't match, but profiles are still equal.
+ AutofillProfile p3 = CreateProfileWithContactInfo(
+ "Homer", "homer@springfieldnuclear.gov", "5551234567");
+ EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p3));
+ EXPECT_TRUE(comp.IsContactEqualOrSuperset(p3, p1));
+
+ // Profile without an email is mutual subset of profile with an email.
+ AutofillProfile p4 = CreateProfileWithContactInfo("Homer", "", "5551234567");
+ EXPECT_TRUE(comp.IsContactEqualOrSuperset(p1, p4));
+ EXPECT_TRUE(comp.IsContactEqualOrSuperset(p4, p1));
+}
+
+TEST(PaymentRequestProfileUtilTest, GetContactCompletenessScore) {
+ MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone);
+ PaymentsProfileComparator comp("en-US", provider);
+
+ // Two completeness points: One each for name and phone number, but not email
+ // as it was not requested.
+ AutofillProfile p1 =
+ CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
+ EXPECT_EQ(2, comp.GetContactCompletenessScore(&p1));
+
+ // One completeness point for name, no points for phone number (missing) or
+ // email (not requested).
+ AutofillProfile p2 =
+ CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
+ EXPECT_EQ(1, comp.GetContactCompletenessScore(&p2));
+
+ // No completeness points, as the only field present was not requested.
+ AutofillProfile p3 =
+ CreateProfileWithContactInfo("", "homer@simpson.net", "");
+ EXPECT_EQ(0, comp.GetContactCompletenessScore(&p3));
+
+ // Null profile returns 0.
+ EXPECT_EQ(0, comp.GetContactCompletenessScore(nullptr));
+}
+
+TEST(PaymentRequestProfileUtilTest, IsContactInfoComplete) {
+ MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerEmail);
+ PaymentsProfileComparator comp("en-US", provider);
+
+ // If name and email are present, return true regardless of the (ignored)
+ // phone value.
+ AutofillProfile p1 =
+ CreateProfileWithContactInfo("Homer", "homer@simpson.net", "5551234567");
+ AutofillProfile p2 =
+ CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
+
+ EXPECT_TRUE(comp.IsContactInfoComplete(&p1));
+ EXPECT_TRUE(comp.IsContactInfoComplete(&p2));
+
+ // If name is not present, return false regardless of the (ignored)
+ // phone value.
+ AutofillProfile p3 =
+ CreateProfileWithContactInfo("", "homer@simpson.net", "5551234567");
+ AutofillProfile p4 =
+ CreateProfileWithContactInfo("", "homer@simpson.net", "");
+
+ EXPECT_FALSE(comp.IsContactInfoComplete(&p3));
+ EXPECT_FALSE(comp.IsContactInfoComplete(&p4));
+
+ // If no fields are requested, any profile (even empty or null) is complete.
+ MockPaymentOptionsProvider empty_provider(0);
+ PaymentsProfileComparator empty_comp("en-US", empty_provider);
+
+ AutofillProfile p5 = CreateProfileWithContactInfo("", "", "");
+
+ EXPECT_TRUE(empty_comp.IsContactInfoComplete(&p1));
+ EXPECT_TRUE(empty_comp.IsContactInfoComplete(&p5));
+ EXPECT_TRUE(empty_comp.IsContactInfoComplete(nullptr));
+}
+
+} // namespace profile_util
+} // namespace payments
diff --git a/chromium/components/payments/core/strings_util.cc b/chromium/components/payments/core/strings_util.cc
new file mode 100644
index 00000000000..8c405e5ba83
--- /dev/null
+++ b/chromium/components/payments/core/strings_util.cc
@@ -0,0 +1,61 @@
+// 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/payments/core/strings_util.h"
+
+#include "base/logging.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace payments {
+
+base::string16 GetShippingAddressSelectorInfoMessage(
+ PaymentShippingType shipping_type) {
+ switch (shipping_type) {
+ case payments::PaymentShippingType::DELIVERY:
+ return l10n_util::GetStringUTF16(
+ IDS_PAYMENTS_SELECT_DELIVERY_ADDRESS_FOR_DELIVERY_METHODS);
+ case payments::PaymentShippingType::PICKUP:
+ return l10n_util::GetStringUTF16(
+ IDS_PAYMENTS_SELECT_PICKUP_ADDRESS_FOR_PICKUP_METHODS);
+ case payments::PaymentShippingType::SHIPPING:
+ return l10n_util::GetStringUTF16(
+ IDS_PAYMENTS_SELECT_SHIPPING_ADDRESS_FOR_SHIPPING_METHODS);
+ default:
+ NOTREACHED();
+ return base::string16();
+ }
+}
+
+base::string16 GetShippingAddressSectionString(
+ PaymentShippingType shipping_type) {
+ switch (shipping_type) {
+ case PaymentShippingType::DELIVERY:
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_DELIVERY_ADDRESS_LABEL);
+ case PaymentShippingType::PICKUP:
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_PICKUP_ADDRESS_LABEL);
+ case PaymentShippingType::SHIPPING:
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_SHIPPING_ADDRESS_LABEL);
+ default:
+ NOTREACHED();
+ return base::string16();
+ }
+}
+
+base::string16 GetShippingOptionSectionString(
+ PaymentShippingType shipping_type) {
+ switch (shipping_type) {
+ case PaymentShippingType::DELIVERY:
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_DELIVERY_OPTION_LABEL);
+ case PaymentShippingType::PICKUP:
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_PICKUP_OPTION_LABEL);
+ case PaymentShippingType::SHIPPING:
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_SHIPPING_OPTION_LABEL);
+ default:
+ NOTREACHED();
+ return base::string16();
+ }
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/strings_util.h b/chromium/components/payments/core/strings_util.h
new file mode 100644
index 00000000000..3d72567c44c
--- /dev/null
+++ b/chromium/components/payments/core/strings_util.h
@@ -0,0 +1,30 @@
+// 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_PAYMENTS_CORE_STRINGS_UTIL_H_
+#define COMPONENTS_PAYMENTS_CORE_STRINGS_UTIL_H_
+
+#include "base/strings/string16.h"
+#include "components/payments/core/payment_options_provider.h"
+
+namespace payments {
+
+// Gets the informational message to be displayed in the shipping address
+// selector view when there are no valid shipping options.
+base::string16 GetShippingAddressSelectorInfoMessage(
+ PaymentShippingType shipping_type);
+
+// Gets the appropriate display string for the Shipping Address string for the
+// given PaymentShippingType.
+base::string16 GetShippingAddressSectionString(
+ PaymentShippingType shipping_type);
+
+// Gets the appropriate display string for the Shipping Option string for the
+// given PaymentShippingType.
+base::string16 GetShippingOptionSectionString(
+ PaymentShippingType shipping_type);
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_STRINGS_UTIL_H_
diff --git a/chromium/components/payments_strings.grdp b/chromium/components/payments_strings.grdp
index 5046856ff6f..b1e6220d38f 100644
--- a/chromium/components/payments_strings.grdp
+++ b/chromium/components/payments_strings.grdp
@@ -10,11 +10,11 @@
<message name="IDS_PAYMENTS_SAVE_CARD_TO_DEVICE_CHECKBOX" desc="The label for the checkbox that enables the user to save a credit card to their device, for example, on their phone." formatter_data="android_java">
Save this card to this device
</message>
- <message name="IDS_PAYMENTS_ACCEPTED_CARDS_LABEL" desc="The title for the section that displays the credit card types that the merchant accepts." formatter_data="android_java">
- Cards accepted
+ <message name="IDS_PAYMENTS_ACCEPTED_CARDS_LABEL" desc="The title for the section that displays the credit card types that the merchant accepts. Below the title, we show a row of icons indicating the accepted cards (Visa icon, Mastercard icon, etc.)." formatter_data="android_java">
+ Accepted cards
</message>
<message name="IDS_PAYMENTS_METHOD_OF_PAYMENT_LABEL" desc="The title for the section that lets the user select the method of payment." formatter_data="android_java">
- Payment
+ Payment method
</message>
<message name="IDS_PAYMENTS_CONTACT_DETAILS_LABEL" desc="The title for the section that lets the user select how they can be contacted." formatter_data="android_java">
Contact info
@@ -37,20 +37,20 @@
<message name="IDS_PAYMENTS_ADD_VALID_CARD_NUMBER" desc="The title of the dialog for user to add valid payment card number." formatter_data="android_java">
Add valid card number
</message>
- <message name="IDS_PAYMENTS_ADD_MORE_INFORMATION" desc="The title of the dialog for user to add more information to payment card or shipping address or contact info." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_ADD_MORE_INFORMATION" desc="The title in the Android app title bar for user to add more information to payment card or shipping address or contact info." formatter_data="android_java">
Add more information
</message>
<message name="IDS_PAYMENTS_EDIT_CARD" desc="The title of the dialog for user to edit payment card." formatter_data="android_java">
Edit card
</message>
<message name="IDS_PAYMENTS_CREDIT_CARD_EXPIRATION_DATE_ABBR" desc="Abbreviated label for credit card expiration date. [CHAR-LIMIT=32]" formatter_data="android_java">
- Exp: <ph name="EXPIRATION_MONTH">%1$s<ex>06</ex></ph>/<ph name="EXPIRATION_YEAR">%2$s<ex>17</ex></ph>
+ Expires <ph name="EXPIRATION_MONTH">%1$s<ex>06</ex></ph>/<ph name="EXPIRATION_YEAR">%2$s<ex>17</ex></ph>
</message>
<message name="IDS_PAYMENTS_ADD_PHONE_NUMBER" desc="The title of the dialog for user to add phone number to the shipping address or contact info. This phone number can be used, for example, if there's a problem with shipping a package to its destination." formatter_data="android_java">
Add phone number
</message>
- <message name="IDS_PAYMENTS_ADD_RECIPIENT" desc="The title of the dialog for user to add recipient in the shipping address. The recipient could be a person or institute name identifies the receiver of the shipping package." formatter_data="android_java">
- Add recipient
+ <message name="IDS_PAYMENTS_ADD_RECIPIENT" desc="The title of the dialog for user to add the name in the shipping address. This name identifies the person that will receive the shipped package." formatter_data="android_java">
+ Add name
</message>
<message name="IDS_PAYMENTS_ADD_VALID_ADDRESS" desc="The title of the dialog for user to add valid shipping address. For example, missing state or city name." formatter_data="android_java">
Add valid address
@@ -76,6 +76,9 @@
<message name="IDS_PAYMENTS_PROCESSING_MESSAGE" desc="The text that informs the user that payment is being processed." formatter_data="android_java">
Processing
</message>
+ <message name="IDS_PAYMENTS_ERROR_MESSAGE_DIALOG_TITLE" desc="The title of the dialog that informs the user that there is error in verifying and charging the payment.">
+ Payment not completed
+ </message>
<message name="IDS_PAYMENTS_ERROR_MESSAGE" desc="The text that informs the user that there is error in verifying and charging the payment." formatter_data="android_java">
There was an error processing your order. Please try again.
</message>
@@ -95,54 +98,73 @@
Updated
</message>
<message name="IDS_PAYMENTS_CARD_AND_ADDRESS_SETTINGS" desc="Label of the section containing the link to go to the settings page for card and address options." formatter_data="android_java">
- You can manage cards and addresses in <ph name="BEGIN_LINK">&lt;link&gt;</ph>Settings<ph name="END_LINK">&lt;/link&gt;</ph>.
+ You can manage cards and addresses in <ph name="BEGIN_LINK">BEGIN_LINK</ph>Settings<ph name="END_LINK">END_LINK</ph>.
</message>
<message name="IDS_PAYMENTS_CARD_AND_ADDRESS_SETTINGS_SIGNED_IN" desc="Label of the section containing the origin description and the link to go to the settings page for card and address options. This label is used when the user is signed in." formatter_data="android_java">
- Card and address options are from your Google Account (<ph name="ACCOUNT_EMAIL">%1$s<ex>johndoe@gmail.com</ex></ph>) and Chrome. You can manage these in <ph name="BEGIN_LINK">&lt;link&gt;</ph>Settings<ph name="END_LINK">&lt;/link&gt;</ph>.
+ Cards and addresses are from Chrome and your Google Account (<ph name="ACCOUNT_EMAIL">%1$s<ex>johndoe@gmail.com</ex></ph>). You can manage them in <ph name="BEGIN_LINK">BEGIN_LINK</ph>Settings<ph name="END_LINK">END_LINK</ph>.
</message>
<message name="IDS_PAYMENTS_CARD_AND_ADDRESS_SETTINGS_SIGNED_OUT" desc="Label of the section containing the origin description and the link to go to the settings page for card and address options. This label is used when the user is not signed in." formatter_data="android_java">
- Card and address options are from Chrome. You can manage these in <ph name="BEGIN_LINK">&lt;link&gt;</ph>Settings<ph name="END_LINK">&lt;/link&gt;</ph>.
+ Cards and addresses are from Chrome. You can manage them in <ph name="BEGIN_LINK">BEGIN_LINK</ph>Settings<ph name="END_LINK">END_LINK</ph>.
</message>
+ <!-- Credit Card form -->
+ <if expr="is_ios">
+ <message name="IDS_PAYMENTS_CARD_NUMBER" desc="Title of the field representing the number (PAN) on a credit card.">
+ Card Number
+ </message>
+ <message name="IDS_PAYMENTS_NAME_ON_CARD" desc="Title of the field representing the full name of a credit card holder.">
+ Cardholder Name
+ </message>
+ <message name="IDS_PAYMENTS_EXP_MONTH" desc="Title of the field representing the expiration month of a credit card.">
+ Expiration Month
+ </message>
+ <message name="IDS_PAYMENTS_EXP_YEAR" desc="Title of the field representing the expiration year of a credit card.">
+ Expiration Year
+ </message>
+ <message name="IDS_PAYMENTS_BILLING_ADDRESS" desc="Title of the field representing the billing address of a credit card.">
+ Billing Address
+ </message>
+ </if>
+
<!-- Validation -->
<message name="IDS_PAYMENTS_VALIDATION_INVALID_NAME" desc="Message displayed to user when name validation fails.">
- Invalid name
+ Enter a name
</message>
<message name="IDS_PAYMENTS_VALIDATION_INVALID_CREDIT_CARD_EXPIRATION_YEAR" desc="Message displayed to user when the credit card expiration year is in an invalid format.">
- Invalid expiration year
+ Enter a valid expiration year
</message>
<message name="IDS_PAYMENTS_VALIDATION_INVALID_CREDIT_CARD_EXPIRATION_MONTH" desc="Message displayed to user when the credit card expiration month is in an invalid format.">
- Invalid expiration month
+ Enter a valid expiration month
</message>
<message name="IDS_PAYMENTS_VALIDATION_INVALID_CREDIT_CARD_EXPIRED" desc="Message displayed to user when the credit card is expired.">
- The card is expired
+ This card is expired
</message>
<message name="IDS_PAYMENTS_VALIDATION_UNSUPPORTED_CREDIT_CARD_TYPE" desc="Message displayed to user when the credit card type (e.g visa, mastercard) is not supported for this transaction.">
- Unsupported card type
+ This type of card isn’t supported
</message>
<message name="IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE" desc="The text that informs the user that '*' character indicates an input field that is required. The '*' character should not be changed." formatter_data="android_java">
- * indicates required field
+ * Field is required
</message>
- <message name="IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE" desc="The text that informs the user that an input field is required." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE" desc="The text that informs the user that an input field is required. “Required†is an adjective." formatter_data="android_java">
Required field
</message>
<message name="IDS_PAYMENTS_PHONE_INVALID_VALIDATION_MESSAGE" desc="The text that informs the user that the phone number they have entered is not valid." formatter_data="android_java">
- Invalid phone number
+ Enter a valid phone number
</message>
<message name="IDS_PAYMENTS_EMAIL_INVALID_VALIDATION_MESSAGE" desc="The text that informs the user that the email address they have entered is not valid." formatter_data="android_java">
- Invalid email address
+ Enter a valid email address
</message>
<message name="IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE" desc="The text that informs the user that the credit card number they have entered is not valid." formatter_data="android_java">
- Invalid card number
+ Enter a valid card number
</message>
<message name="IDS_PAYMENTS_CARD_EXPIRATION_INVALID_VALIDATION_MESSAGE" desc="The text that informs the user that the credit card expiration date they have entered is not valid." formatter_data="android_java">
- Invalid expiration date
+ Enter a valid expiration date
</message>
<message name="IDS_PAYMENTS_BILLING_ADDRESS_REQUIRED" desc="The label to indicate billing address is required for payment card." formatter_data="android_java">
Billing address required
</message>
- <message name="IDS_PAYMENTS_NAME_ON_CARD_REQUIRED" desc="The label to indicate name on card is required for payment card." formatter_data="android_java">
- Name on card required
+ <message name="IDS_PAYMENTS_NAME_ON_CARD_REQUIRED" desc="The label to indicate the cardholder name (the name of the owner or “holder†of the credit card) must be entered." formatter_data="android_java">
+ Cardholder name required
</message>
<message name="IDS_PAYMENTS_MORE_INFORMATION_REQUIRED" desc="The label to indicate more information is required for payment card or shipping address or contact info." formatter_data="android_java">
More information required
@@ -150,11 +172,11 @@
<message name="IDS_PAYMENTS_PHONE_NUMBER_REQUIRED" desc="The label to indicate phone number is required in the shipping address or contact info. This phone number can be used, for example, if there's a problem with shipping a package to its destination." formatter_data="android_java">
Phone number required
</message>
- <message name="IDS_PAYMENTS_RECIPIENT_REQUIRED" desc="The label to indicate recipient is required in the shipping address. The recipient could be a person or institute name identifies the receiver of the shipping package." formatter_data="android_java">
- Recipient required
+ <message name="IDS_PAYMENTS_RECIPIENT_REQUIRED" desc="The label to indicate recipient name is required in the shipping address. This name identifies the person that will receive the shipped package." formatter_data="android_java">
+ Name required
</message>
<message name="IDS_PAYMENTS_INVALID_ADDRESS" desc="The label to indicate the shipping address is invalid. For example, missing state or city name." formatter_data="android_java">
- Invalid address
+ Enter a valid address
</message>
<message name="IDS_PAYMENTS_EMAIL_REQUIRED" desc="The label to indicate email is required for the contact details. This email can be used to contact the payer." formatter_data="android_java">
Email required
@@ -176,6 +198,9 @@
<message name="IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SHEET_TOTAL_FORMAT" desc="The format specifier of the Total label in the Order Summary Sheet of the Payment Request dialog.">
<ph name="CURRENCY_CODE">$1<ex>USD</ex></ph> <ph name="FORMATTED_TOTAL_AMOUNT">$2<ex>$ 12.34</ex></ph>
</message>
+ <message name="IDS_PAYMENT_REQUEST_ORDER_SUMMARY_MORE_ITEMS" desc="The label in the Order Summary section of the Payment Sheet that indicates how many display items are hidden.">
+ <ph name="ITEM_COUNT">$1<ex>2</ex></ph> more items...
+ </message>
<message name="IDS_PAYMENT_REQUEST_SHIPPING_SECTION_NAME" desc="The name of the Shipping Address section in the Payment Sheet of the Payment Request dialog.">
Shipping address
</message>
@@ -184,65 +209,74 @@
</message>
<!-- Shipping address in web payments API -->
- <message name="IDS_PAYMENTS_SHIPPING_SUMMARY_LABEL" desc="The title for the section of shipping information. Shipping is typically used for packages." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_SHIPPING_SUMMARY_LABEL" desc="The title for the section of shipping information. Shipping is used for packages and things that are mailed. In American English, “shipping†is differentiated from “deliveryâ€. “Delivery†is used, for example, for food delivery." formatter_data="android_java">
Shipping
</message>
<message name="IDS_PAYMENTS_SHIPPING_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where the product should be shipped. Shipping is typically used for packages." formatter_data="android_java">
Shipping address
</message>
<message name="IDS_PAYMENTS_SHIPPING_OPTION_LABEL" desc="The title for the section that lets the user select how the product should be shipped. Shipping is typically used for packages." formatter_data="android_java">
- Shipping option
+ Shipping method
</message>
<message name="IDS_PAYMENTS_SELECT_SHIPPING_ADDRESS_FOR_SHIPPING_METHODS" desc="Text implying that a user needs to pick a shipping address to see the shipping methods. Shipping is typically used for packages." formatter_data="android_java">
- Select a shipping address to check shipping methods and requirements.
+ To see shipping methods and requirements, select an address
</message>
- <message name="IDS_PAYMENTS_UNSUPPORTED_SHIPPING_ADDRESS" desc="Text implying that a user needs to pick a different shipping address, because the currently selected address is not supported. Shipping is typically used for packages." formatter_data="android_java">
- Unsupported shipping address. Select a different address.
+ <message name="IDS_PAYMENTS_UNSUPPORTED_SHIPPING_ADDRESS" desc="Text implying that a user needs to pick a different shipping address, because the currently selected address is not supported. “Ship†is typically used for packages and items that are sent through the mail. In American English, we differentiate “ship†from “deliver." formatter_data="android_java">
+ Can’t ship to this address. Select a different address.
</message>
- <message name="IDS_PAYMENTS_UNSUPPORTED_SHIPPING_OPTION" desc="Text implying that a user needs to pick a different shipping option, because the currently selected option is not supported. Shipping is typically used for packages." formatter_data="android_java">
- That shipping option isn’t available. Try a different option.
+ <message name="IDS_PAYMENTS_UNSUPPORTED_SHIPPING_OPTION" desc="Text implying that a user needs to pick a different shipping option, because the currently selected option is not supported. “Ship†is typically used for packages and items that are sent through the mail. In American English, we differentiate “ship†from deliver." formatter_data="android_java">
+ This shipping method isn’t available. Try a different method.
</message>
<!-- Delivery address in web payments API -->
<message name="IDS_PAYMENTS_DELIVERY_SUMMARY_LABEL" desc="The title for the section of delivery information. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java">
Delivery
</message>
- <message name="IDS_PAYMENTS_DELIVERY_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where the product should be delivered. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_DELIVERY_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where the product should be delivered. In English, “delivery†is differentiated from “shipping.†For example, “delivery†might be used for meals or meal items or items that need to be immediately sent to a recipient." formatter_data="android_java">
Delivery address
</message>
<message name="IDS_PAYMENTS_DELIVERY_OPTION_LABEL" desc="The title for the section that lets the user select how the product should be delivered. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java">
- Delivery option
+ Delivery method
</message>
<message name="IDS_PAYMENTS_SELECT_DELIVERY_ADDRESS_FOR_DELIVERY_METHODS" desc="Text implying that a user needs to pick a delivery address to see the delivery methods. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java">
- Select a delivery address to check delivery methods and requirements.
+ To see delivery methods and requirements, select an address
</message>
<message name="IDS_PAYMENTS_UNSUPPORTED_DELIVERY_ADDRESS" desc="Text implying that a user needs to pick a different delivery address, because the currently selected address is not supported. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java">
- Unsupported delivery address. Select a different address.
+ Can’t deliver to this address. Select a different address.
</message>
<message name="IDS_PAYMENTS_UNSUPPORTED_DELIVERY_OPTION" desc="Text implying that a user needs to pick a different delivery option, because the currently selected option is not supported. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java">
- That delivery option isn’t available. Try a different option.
+ This delivery method isn’t available. Try a different method.
</message>
<!-- Pickup address in web payments API -->
- <message name="IDS_PAYMENTS_PICKUP_SUMMARY_LABEL" desc="The title for the section of pickup information. For example, this could be the address for laundry pickup." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_PICKUP_SUMMARY_LABEL" desc="The title for the section of information needed for a service to pick up items from a customer. For example, this could be the address for laundry pickup. “Pickup†is a noun." formatter_data="android_java">
Pickup
</message>
- <message name="IDS_PAYMENTS_PICKUP_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where their item should be picked up. For example, this item could be laundry to be cleaned." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_PICKUP_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where a service item should be picked up. For example, the pickup address is where a laundry service picks up a customer’s items to be laundered. “Pickup†functions as an adjective." formatter_data="android_java">
Pickup address
</message>
- <message name="IDS_PAYMENTS_PICKUP_OPTION_LABEL" desc="The title for the section that lets the user select how their item should be picked up. This item can be laundry to be cleaned, for example." formatter_data="android_java">
- Pickup option
+ <message name="IDS_PAYMENTS_PICKUP_OPTION_LABEL" desc="The title for the section that lets the user select how their service item should be picked up. This item can be laundry to be cleaned, for example. “Pickup†functions as an adjective." formatter_data="android_java">
+ Pickup method
</message>
- <message name="IDS_PAYMENTS_SELECT_PICKUP_ADDRESS_FOR_PICKUP_METHODS" desc="Text implying that a user needs to choose a pickup address to see the pickup methods. For example, this could be the address for laundry pickup." formatter_data="android_java">
- Select a pickup address to check pickup methods and requirements.
+ <message name="IDS_PAYMENTS_SELECT_PICKUP_ADDRESS_FOR_PICKUP_METHODS" desc="Text implying that a user needs to choose a pickup address to see the pickup methods. For example, this could be the address for laundry pickup. “Pickup†functions as an adjective." formatter_data="android_java">
+ To see pickup methods and requirements, select an address
</message>
- <message name="IDS_PAYMENTS_UNSUPPORTED_PICKUP_ADDRESS" desc="Text implying that a user needs to choose a different pickup address, because the currently selected address is not supported. This address can be used, for example, for laundry pickup." formatter_data="android_java">
- Unsupported pickup address. Select a different address.
+ <message name="IDS_PAYMENTS_UNSUPPORTED_PICKUP_ADDRESS" desc="Text implying that a user needs to choose a different pickup address, because the service can’t pick up items from that address. This address can be used, for example, for laundry pickup. Note that here, “pick up†is a verb." formatter_data="android_java">
+ Can’t pick up from this address. Select a different address.
</message>
<message name="IDS_PAYMENTS_UNSUPPORTED_PICKUP_OPTION" desc="Text implying that a user needs to choose a different pickup option, because the currently selected option is not supported. This option can be used, for example, for laundry pickup." formatter_data="android_java">
- That pickup option isn’t available. Try a different option.
+ This pickup method isn’t available. Try a different method.
</message>
<message name="IDS_PAYMENTS_ANDROID_APP_ERROR" desc="Error message that is shown when an Android payment application fails to start." formatter_data="android_java">
- Unable to launch payment app.
+ Can’t open payment app
</message>
+
+ <message name="IDS_UTILITY_PROCESS_PAYMENT_MANIFEST_PARSER_NAME" desc="The name of the utility process used for parsing payment manifest files.">
+ Payment Manifest Parser
+ </message>
+ <if expr="is_android">
+ <message name="IDS_EXTERNAL_PAYMENT_APP_LEAVE_INCOGNITO_WARNING" desc="Alert dialog text warning the user that incognito mode does not continue into external payment apps." formatter_data="android_java">
+ Leaving incognito mode to pay via an external application. Continue?
+ </message>
+ </if>
</grit-part>
diff --git a/chromium/components/pdf/browser/BUILD.gn b/chromium/components/pdf/browser/BUILD.gn
index 99f85ad35f3..30fff96eae4 100644
--- a/chromium/components/pdf/browser/BUILD.gn
+++ b/chromium/components/pdf/browser/BUILD.gn
@@ -13,8 +13,11 @@ static_library("browser") {
deps = [
"//base",
- "//components/pdf/common",
+ "//components/pdf/common:interfaces",
"//content/public/browser",
+ ]
+
+ public_deps = [
"//ipc",
]
}
diff --git a/chromium/components/pdf/browser/pdf_web_contents_helper.cc b/chromium/components/pdf/browser/pdf_web_contents_helper.cc
index e4253386787..fdbea015a20 100644
--- a/chromium/components/pdf/browser/pdf_web_contents_helper.cc
+++ b/chromium/components/pdf/browser/pdf_web_contents_helper.cc
@@ -9,7 +9,6 @@
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "components/pdf/browser/pdf_web_contents_helper_client.h"
-#include "components/pdf/common/pdf_messages.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(pdf::PDFWebContentsHelper);
@@ -28,38 +27,25 @@ void PDFWebContentsHelper::CreateForWebContentsWithClient(
PDFWebContentsHelper::PDFWebContentsHelper(
content::WebContents* web_contents,
std::unique_ptr<PDFWebContentsHelperClient> client)
- : content::WebContentsObserver(web_contents), client_(std::move(client)) {}
+ : content::WebContentsObserver(web_contents),
+ pdf_service_bindings_(web_contents, this),
+ client_(std::move(client)) {}
PDFWebContentsHelper::~PDFWebContentsHelper() {
}
-bool PDFWebContentsHelper::OnMessageReceived(
- const IPC::Message& message,
- content::RenderFrameHost* render_frame_host) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(PDFWebContentsHelper, message)
- IPC_MESSAGE_HANDLER(PDFHostMsg_PDFHasUnsupportedFeature,
- OnHasUnsupportedFeature)
- IPC_MESSAGE_HANDLER(PDFHostMsg_PDFSaveURLAs, OnSaveURLAs)
- IPC_MESSAGE_HANDLER(PDFHostMsg_PDFUpdateContentRestrictions,
- OnUpdateContentRestrictions)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void PDFWebContentsHelper::OnHasUnsupportedFeature() {
+void PDFWebContentsHelper::HasUnsupportedFeature() {
client_->OnPDFHasUnsupportedFeature(web_contents());
}
-void PDFWebContentsHelper::OnSaveURLAs(const GURL& url,
- const content::Referrer& referrer) {
+void PDFWebContentsHelper::SaveUrlAs(const GURL& url,
+ const content::Referrer& referrer) {
client_->OnSaveURL(web_contents());
web_contents()->SaveFrame(url, referrer);
}
-void PDFWebContentsHelper::OnUpdateContentRestrictions(
- int content_restrictions) {
+void PDFWebContentsHelper::UpdateContentRestrictions(
+ int32_t content_restrictions) {
client_->UpdateContentRestrictions(web_contents(), content_restrictions);
}
diff --git a/chromium/components/pdf/browser/pdf_web_contents_helper.h b/chromium/components/pdf/browser/pdf_web_contents_helper.h
index c9a2e5897d0..080dca40599 100644
--- a/chromium/components/pdf/browser/pdf_web_contents_helper.h
+++ b/chromium/components/pdf/browser/pdf_web_contents_helper.h
@@ -10,9 +10,10 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "components/pdf/common/pdf.mojom.h"
+#include "content/public/browser/web_contents_binding_set.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
-#include "ipc/ipc_message.h"
namespace content {
class WebContents;
@@ -25,7 +26,8 @@ class PDFWebContentsHelperClient;
// Per-WebContents class to handle PDF messages.
class PDFWebContentsHelper
: public content::WebContentsObserver,
- public content::WebContentsUserData<PDFWebContentsHelper> {
+ public content::WebContentsUserData<PDFWebContentsHelper>,
+ public mojom::PdfService {
public:
static void CreateForWebContentsWithClient(
content::WebContents* contents,
@@ -36,15 +38,12 @@ class PDFWebContentsHelper
std::unique_ptr<PDFWebContentsHelperClient> client);
~PDFWebContentsHelper() override;
- // content::WebContentsObserver overrides:
- bool OnMessageReceived(const IPC::Message& message,
- content::RenderFrameHost* render_frame_host) override;
-
- // Message handlers.
- void OnHasUnsupportedFeature();
- void OnSaveURLAs(const GURL& url, const content::Referrer& referrer);
- void OnUpdateContentRestrictions(int content_restrictions);
+ // mojom::PdfService:
+ void HasUnsupportedFeature() override;
+ void SaveUrlAs(const GURL& url, const content::Referrer& referrer) override;
+ void UpdateContentRestrictions(int32_t content_restrictions) override;
+ content::WebContentsFrameBindingSet<mojom::PdfService> pdf_service_bindings_;
std::unique_ptr<PDFWebContentsHelperClient> client_;
DISALLOW_COPY_AND_ASSIGN(PDFWebContentsHelper);
diff --git a/chromium/components/pdf/common/BUILD.gn b/chromium/components/pdf/common/BUILD.gn
index adff35e0ba6..c0aa0b38073 100644
--- a/chromium/components/pdf/common/BUILD.gn
+++ b/chromium/components/pdf/common/BUILD.gn
@@ -3,18 +3,21 @@
# found in the LICENSE file.
import("//build/config/features.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
-static_library("common") {
+mojom("interfaces") {
sources = [
- "pdf_message_generator.cc",
- "pdf_message_generator.h",
- "pdf_messages.h",
+ "pdf.mojom",
]
- deps = [
- "//base",
- "//content/public/common",
- "//ipc",
- "//url",
+ public_deps = [
+ "//third_party/WebKit/public:mojo_bindings",
+ "//url/mojo:url_mojom_gurl",
]
+
+ overridden_deps = [ "//third_party/WebKit/public:mojo_bindings" ]
+ component_deps = [ "//content/public/common" ]
+
+ overridden_deps_blink = [ "//third_party/WebKit/public:mojo_bindings" ]
+ component_deps_blink = [ "//third_party/WebKit/Source/platform" ]
}
diff --git a/chromium/components/pdf/common/OWNERS b/chromium/components/pdf/common/OWNERS
index 42444bcd16d..08850f42120 100644
--- a/chromium/components/pdf/common/OWNERS
+++ b/chromium/components/pdf/common/OWNERS
@@ -1,2 +1,2 @@
-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
diff --git a/chromium/components/pdf/common/pdf.mojom b/chromium/components/pdf/common/pdf.mojom
new file mode 100644
index 00000000000..0aaed7ba38f
--- /dev/null
+++ b/chromium/components/pdf/common/pdf.mojom
@@ -0,0 +1,19 @@
+// 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.
+
+module pdf.mojom;
+
+import "third_party/WebKit/public/platform/referrer.mojom";
+import "url/mojo/url.mojom";
+
+interface PdfService {
+ // Updates the content restrictions, i.e. to disable print/copy.
+ UpdateContentRestrictions(int32 restrictions);
+
+ // The currently displayed PDF has an unsupported feature.
+ HasUnsupportedFeature();
+
+ // Brings up SaveAs... dialog to save specified URL.
+ SaveUrlAs(url.mojom.Url url, blink.mojom.Referrer referrer);
+};
diff --git a/chromium/components/pdf/common/pdf_message_generator.cc b/chromium/components/pdf/common/pdf_message_generator.cc
deleted file mode 100644
index 3cd31df7d23..00000000000
--- a/chromium/components/pdf/common/pdf_message_generator.cc
+++ /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.
-
-// Get basic type definitions.
-#define IPC_MESSAGE_IMPL
-#include "components/pdf/common/pdf_message_generator.h"
-
-// Generate constructors.
-#include "ipc/struct_constructor_macros.h"
-#include "components/pdf/common/pdf_message_generator.h"
-
-// Generate destructors.
-#include "ipc/struct_destructor_macros.h"
-#include "components/pdf/common/pdf_message_generator.h"
-
-// Generate param traits size methods.
-#include "ipc/param_traits_size_macros.h"
-namespace IPC {
-#include "components/pdf/common/pdf_message_generator.h"
-}
-
-// Generate param traits write methods.
-#include "ipc/param_traits_write_macros.h"
-namespace IPC {
-#include "components/pdf/common/pdf_message_generator.h"
-} // namespace IPC
-
-// Generate param traits read methods.
-#include "ipc/param_traits_read_macros.h"
-namespace IPC {
-#include "components/pdf/common/pdf_message_generator.h"
-} // namespace IPC
-
-// Generate param traits log methods.
-#include "ipc/param_traits_log_macros.h"
-namespace IPC {
-#include "components/pdf/common/pdf_message_generator.h"
-} // namespace IPC
diff --git a/chromium/components/pdf/common/pdf_message_generator.h b/chromium/components/pdf/common/pdf_message_generator.h
deleted file mode 100644
index c55d672f121..00000000000
--- a/chromium/components/pdf/common/pdf_message_generator.h
+++ /dev/null
@@ -1,7 +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.
-
-// Multiply-included file, no traditional include guard.
-
-#include "components/pdf/common/pdf_messages.h"
diff --git a/chromium/components/pdf/common/pdf_messages.h b/chromium/components/pdf/common/pdf_messages.h
deleted file mode 100644
index 20420cd2e4c..00000000000
--- a/chromium/components/pdf/common/pdf_messages.h
+++ /dev/null
@@ -1,26 +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.
-
-// Multiply-included file, no traditional include guard.
-#include <string.h>
-
-#include "content/public/common/common_param_traits_macros.h"
-#include "content/public/common/referrer.h"
-#include "ipc/ipc_message_macros.h"
-#include "url/gurl.h"
-#include "url/ipc/url_param_traits.h"
-
-#define IPC_MESSAGE_START PDFMsgStart
-
-// Updates the content restrictions, i.e. to disable print/copy.
-IPC_MESSAGE_ROUTED1(PDFHostMsg_PDFUpdateContentRestrictions,
- int /* restrictions */)
-
-// The currently displayed PDF has an unsupported feature.
-IPC_MESSAGE_ROUTED0(PDFHostMsg_PDFHasUnsupportedFeature)
-
-// Brings up SaveAs... dialog to save specified URL.
-IPC_MESSAGE_ROUTED2(PDFHostMsg_PDFSaveURLAs,
- GURL /* url */,
- content::Referrer /* referrer */)
diff --git a/chromium/components/pdf/renderer/BUILD.gn b/chromium/components/pdf/renderer/BUILD.gn
index c7b66493bdb..f74c3438c27 100644
--- a/chromium/components/pdf/renderer/BUILD.gn
+++ b/chromium/components/pdf/renderer/BUILD.gn
@@ -14,7 +14,7 @@ static_library("renderer") {
deps = [
"//base",
- "//components/pdf/common",
+ "//components/pdf/common:interfaces",
"//components/resources:components_resources",
"//components/resources:components_scaled_resources",
"//components/strings",
diff --git a/chromium/components/pdf/renderer/pepper_pdf_host.cc b/chromium/components/pdf/renderer/pepper_pdf_host.cc
index af5469363a0..158c3b672e8 100644
--- a/chromium/components/pdf/renderer/pepper_pdf_host.cc
+++ b/chromium/components/pdf/renderer/pepper_pdf_host.cc
@@ -5,8 +5,8 @@
#include "components/pdf/renderer/pepper_pdf_host.h"
#include "base/memory/ptr_util.h"
-#include "components/pdf/common/pdf_messages.h"
#include "components/pdf/renderer/pdf_accessibility_tree.h"
+#include "content/public/common/associated_interface_provider.h"
#include "content/public/common/referrer.h"
#include "content/public/renderer/pepper_plugin_instance.h"
#include "content/public/renderer/render_frame.h"
@@ -118,12 +118,11 @@ int32_t PepperPDFHost::OnHostMsgDidStopLoading(
int32_t PepperPDFHost::OnHostMsgSetContentRestriction(
ppapi::host::HostMessageContext* context,
int restrictions) {
- content::RenderFrame* render_frame = GetRenderFrame();
- if (!render_frame)
+ mojom::PdfService* service = GetRemotePdfService();
+ if (!service)
return PP_ERROR_FAILED;
- render_frame->Send(new PDFHostMsg_PDFUpdateContentRestrictions(
- render_frame->GetRoutingID(), restrictions));
+ service->UpdateContentRestrictions(restrictions);
return PP_OK;
}
@@ -138,12 +137,11 @@ int32_t PepperPDFHost::OnHostMsgUserMetricsRecordAction(
int32_t PepperPDFHost::OnHostMsgHasUnsupportedFeature(
ppapi::host::HostMessageContext* context) {
- content::RenderFrame* render_frame = GetRenderFrame();
- if (!render_frame)
+ mojom::PdfService* service = GetRemotePdfService();
+ if (!service)
return PP_ERROR_FAILED;
- render_frame->Send(
- new PDFHostMsg_PDFHasUnsupportedFeature(render_frame->GetRoutingID()));
+ service->HasUnsupportedFeature();
return PP_OK;
}
@@ -159,17 +157,17 @@ int32_t PepperPDFHost::OnHostMsgSaveAs(
if (!instance)
return PP_ERROR_FAILED;
- content::RenderFrame* render_frame = instance->GetRenderFrame();
- if (!render_frame)
- return PP_ERROR_FAILED;
-
GURL url = instance->GetPluginURL();
content::Referrer referrer;
referrer.url = url;
- referrer.policy = blink::WebReferrerPolicyDefault;
+ referrer.policy = blink::kWebReferrerPolicyDefault;
referrer = content::Referrer::SanitizeForRequest(url, referrer);
- render_frame->Send(
- new PDFHostMsg_PDFSaveURLAs(render_frame->GetRoutingID(), url, referrer));
+
+ mojom::PdfService* service = GetRemotePdfService();
+ if (!service)
+ return PP_ERROR_FAILED;
+
+ service->SaveUrlAs(url, referrer);
return PP_OK;
}
@@ -241,4 +239,16 @@ content::RenderFrame* PepperPDFHost::GetRenderFrame() {
return instance ? instance->GetRenderFrame() : nullptr;
}
+mojom::PdfService* PepperPDFHost::GetRemotePdfService() {
+ content::RenderFrame* render_frame = GetRenderFrame();
+ if (!render_frame)
+ return nullptr;
+
+ if (!remote_pdf_service_) {
+ render_frame->GetRemoteAssociatedInterfaces()->GetInterface(
+ &remote_pdf_service_);
+ }
+ return remote_pdf_service_.get();
+}
+
} // namespace pdf
diff --git a/chromium/components/pdf/renderer/pepper_pdf_host.h b/chromium/components/pdf/renderer/pepper_pdf_host.h
index 94e8cc6c251..b5de8c27bdb 100644
--- a/chromium/components/pdf/renderer/pepper_pdf_host.h
+++ b/chromium/components/pdf/renderer/pepper_pdf_host.h
@@ -14,6 +14,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/strings/string16.h"
+#include "components/pdf/common/pdf.mojom.h"
#include "ipc/ipc_platform_file.h"
#include "ppapi/c/ppb_image_data.h"
#include "ppapi/c/private/ppb_pdf.h"
@@ -103,9 +104,11 @@ class PepperPDFHost : public ppapi::host::ResourceHost {
content::RenderFrame* GetRenderFrame();
- std::unique_ptr<PdfAccessibilityTree> pdf_accessibility_tree_;
+ mojom::PdfService* GetRemotePdfService();
+ std::unique_ptr<PdfAccessibilityTree> pdf_accessibility_tree_;
content::RendererPpapiHost* const host_;
+ mojom::PdfServiceAssociatedPtr remote_pdf_service_;
DISALLOW_COPY_AND_ASSIGN(PepperPDFHost);
};
diff --git a/chromium/components/physical_web/data_source/fake_physical_web_data_source.cc b/chromium/components/physical_web/data_source/fake_physical_web_data_source.cc
index db5d4ff7218..727339a65fa 100644
--- a/chromium/components/physical_web/data_source/fake_physical_web_data_source.cc
+++ b/chromium/components/physical_web/data_source/fake_physical_web_data_source.cc
@@ -75,7 +75,7 @@ bool FakePhysicalWebDataSource::HasUnresolvedDiscoveries() {
}
void FakePhysicalWebDataSource::RegisterListener(
- PhysicalWebListener* physical_web_listener) {
+ PhysicalWebListener* physical_web_listener, ScanMode scan_mode) {
observer_list_.AddObserver(physical_web_listener);
}
diff --git a/chromium/components/physical_web/data_source/fake_physical_web_data_source.h b/chromium/components/physical_web/data_source/fake_physical_web_data_source.h
index fc0a6dc73dc..edec214c8c7 100644
--- a/chromium/components/physical_web/data_source/fake_physical_web_data_source.h
+++ b/chromium/components/physical_web/data_source/fake_physical_web_data_source.h
@@ -42,7 +42,8 @@ class FakePhysicalWebDataSource : public PhysicalWebDataSource {
bool HasUnresolvedDiscoveries() override;
- void RegisterListener(PhysicalWebListener* physical_web_listener) override;
+ void RegisterListener(PhysicalWebListener* physical_web_listener,
+ ScanMode scan_mode) override;
void UnregisterListener(PhysicalWebListener* physical_web_listener) override;
// for testing
diff --git a/chromium/components/physical_web/data_source/physical_web_data_source.h b/chromium/components/physical_web/data_source/physical_web_data_source.h
index 1d03230e048..1fc8f333a3b 100644
--- a/chromium/components/physical_web/data_source/physical_web_data_source.h
+++ b/chromium/components/physical_web/data_source/physical_web_data_source.h
@@ -16,6 +16,16 @@ namespace physical_web {
class PhysicalWebListener;
+// Enum describing scan policies.
+enum ScanMode {
+ // Request no particular scan policy. Opportunistic listeners will receive
+ // notifications when any other listener requests a scan.
+ OPPORTUNISTIC = 0,
+ // Request a scan that runs occassionally, even when Chrome is not in the
+ // foreground. Android only.
+ BACKGROUND_INTERMITTENT = 1 << 0,
+};
+
// Metadata struct for associating data with Physical Web URLs.
struct Metadata {
Metadata();
@@ -89,7 +99,10 @@ class PhysicalWebDataSource {
virtual bool HasUnresolvedDiscoveries() = 0;
// Register for changes to Physical Web URLs and associated page metadata.
- virtual void RegisterListener(PhysicalWebListener* physical_web_listener) = 0;
+ // This may be called multiple times in order to change the associated scan
+ // mode.
+ virtual void RegisterListener(PhysicalWebListener* physical_web_listener,
+ ScanMode scan_mode) = 0;
// Unregister for changes to Physical Web URLs and associated page metadata.
virtual void UnregisterListener(
diff --git a/chromium/components/physical_web/data_source/physical_web_data_source_impl.cc b/chromium/components/physical_web/data_source/physical_web_data_source_impl.cc
index 86b4c185a14..1f75d054793 100644
--- a/chromium/components/physical_web/data_source/physical_web_data_source_impl.cc
+++ b/chromium/components/physical_web/data_source/physical_web_data_source_impl.cc
@@ -14,13 +14,19 @@ PhysicalWebDataSourceImpl::PhysicalWebDataSourceImpl() {}
PhysicalWebDataSourceImpl::~PhysicalWebDataSourceImpl() {}
void PhysicalWebDataSourceImpl::RegisterListener(
- PhysicalWebListener* physical_web_listener) {
- observer_list_.AddObserver(physical_web_listener);
+ PhysicalWebListener* physical_web_listener, ScanMode scan_mode) {
+ if (!observer_list_.HasObserver(physical_web_listener)) {
+ observer_list_.AddObserver(physical_web_listener);
+ }
+ scan_modes_[physical_web_listener] = scan_mode;
}
void PhysicalWebDataSourceImpl::UnregisterListener(
PhysicalWebListener* physical_web_listener) {
+ if (!observer_list_.HasObserver(physical_web_listener)) return;
+
observer_list_.RemoveObserver(physical_web_listener);
+ scan_modes_.erase(physical_web_listener);
}
void PhysicalWebDataSourceImpl::NotifyOnFound(const GURL& url) {
diff --git a/chromium/components/physical_web/data_source/physical_web_data_source_impl.h b/chromium/components/physical_web/data_source/physical_web_data_source_impl.h
index a9326d2e097..0930d50a5b4 100644
--- a/chromium/components/physical_web/data_source/physical_web_data_source_impl.h
+++ b/chromium/components/physical_web/data_source/physical_web_data_source_impl.h
@@ -19,7 +19,8 @@ class PhysicalWebDataSourceImpl : public PhysicalWebDataSource {
~PhysicalWebDataSourceImpl() override;
// Register for changes to Physical Web URLs and associated page metadata.
- void RegisterListener(PhysicalWebListener* physical_web_listener) override;
+ void RegisterListener(PhysicalWebListener* physical_web_listener,
+ ScanMode scan_mode) override;
// Unregister for changes to Physical Web URLs and associated page metadata.
void UnregisterListener(PhysicalWebListener* physical_web_listener) override;
@@ -31,11 +32,11 @@ class PhysicalWebDataSourceImpl : public PhysicalWebDataSource {
void NotifyOnLost(const GURL& url);
// Notify all registered listeners that a distance has changed for a URL.
- void NotifyOnDistanceChanged(const GURL& url,
- double distance_estimate);
+ void NotifyOnDistanceChanged(const GURL& url, double distance_estimate);
private:
base::ObserverList<PhysicalWebListener> observer_list_;
+ std::unordered_map<PhysicalWebListener*, ScanMode> scan_modes_;
};
} // namespace physical_web
diff --git a/chromium/components/physical_web/data_source/physical_web_data_source_impl_unittest.cc b/chromium/components/physical_web/data_source/physical_web_data_source_impl_unittest.cc
index 49ebcccd98e..a5305210844 100644
--- a/chromium/components/physical_web/data_source/physical_web_data_source_impl_unittest.cc
+++ b/chromium/components/physical_web/data_source/physical_web_data_source_impl_unittest.cc
@@ -95,7 +95,7 @@ class PhysicalWebDataSourceImplTest : public ::testing::Test {
};
void PhysicalWebDataSourceImplTest::SetUp() {
- data_source_.RegisterListener(&listener_);
+ data_source_.RegisterListener(&listener_, physical_web::OPPORTUNISTIC);
}
void PhysicalWebDataSourceImplTest::TearDown() {
diff --git a/chromium/components/physical_web/eddystone/BUILD.gn b/chromium/components/physical_web/eddystone/BUILD.gn
new file mode 100644
index 00000000000..a77baaaa240
--- /dev/null
+++ b/chromium/components/physical_web/eddystone/BUILD.gn
@@ -0,0 +1,27 @@
+# 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.
+
+source_set("eddystone") {
+ sources = [
+ "eddystone_encoder.cc",
+ "eddystone_encoder.h",
+ ]
+
+ deps = [
+ "//url",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "eddystone_encoder_unittest.cc",
+ ]
+
+ deps = [
+ ":eddystone",
+ "//testing/gtest",
+ "//url",
+ ]
+}
diff --git a/chromium/components/physical_web/eddystone/eddystone_encoder.cc b/chromium/components/physical_web/eddystone/eddystone_encoder.cc
new file mode 100644
index 00000000000..73b59f0d584
--- /dev/null
+++ b/chromium/components/physical_web/eddystone/eddystone_encoder.cc
@@ -0,0 +1,90 @@
+// 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/physical_web/eddystone/eddystone_encoder.h"
+
+#include <string>
+#include <vector>
+
+#include "url/gurl.h"
+
+namespace {
+const char* kPrefixes[] = {"http://www.", "https://www.", "http://",
+ "https://"};
+const size_t kNumPrefixes = sizeof(kPrefixes) / sizeof(char*);
+
+const char* kSuffixes[] = {".com/", ".org/", ".edu/", ".net/", ".info/",
+ ".biz/", ".gov/", ".com", ".org", ".edu",
+ ".net", ".info", ".biz", ".gov"};
+const size_t kNumSuffixes = sizeof(kSuffixes) / sizeof(char*);
+}
+
+namespace physical_web {
+size_t EncodeUrl(const std::string& url, std::vector<uint8_t>* encoded_url) {
+ /*
+ * Sanitize input.
+ */
+
+ if (encoded_url == NULL)
+ return kNullEncodedUrl;
+ if (url.empty())
+ return kEmptyUrl;
+
+ GURL gurl(url);
+ if (!gurl.is_valid())
+ return kInvalidUrl;
+ if (gurl.HostIsIPAddress() || !gurl.SchemeIsHTTPOrHTTPS())
+ return kInvalidFormat;
+
+ /*
+ * Necessary Declarations.
+ */
+ const char* raw_url_position = url.c_str();
+
+ size_t prefix_lengths[kNumPrefixes];
+ size_t suffix_lengths[kNumSuffixes];
+ for (size_t i = 0; i < kNumPrefixes; i++) {
+ prefix_lengths[i] = strlen(kPrefixes[i]);
+ }
+ for (size_t i = 0; i < kNumSuffixes; i++) {
+ suffix_lengths[i] = strlen(kSuffixes[i]);
+ }
+
+ /*
+ * Handle prefix.
+ */
+ for (size_t i = 0; i < kNumPrefixes; i++) {
+ size_t prefix_len = prefix_lengths[i];
+ if (strncmp(raw_url_position, kPrefixes[i], prefix_len) == 0) {
+ encoded_url->push_back(static_cast<uint8_t>(i));
+ raw_url_position += prefix_len;
+ break;
+ }
+ }
+
+ /*
+ * Handle suffixes.
+ */
+ while (*raw_url_position) {
+ /* check for suffix match */
+ size_t i;
+ for (i = 0; i < kNumSuffixes; i++) {
+ size_t suffix_len = suffix_lengths[i];
+ if (strncmp(raw_url_position, kSuffixes[i], suffix_len) == 0) {
+ encoded_url->push_back(static_cast<uint8_t>(i));
+ raw_url_position += suffix_len;
+ break; /* from the for loop for checking against suffixes */
+ }
+ }
+ /* This is the default case where we've got an ordinary character which
+ * doesn't match a suffix. */
+ if (i == kNumSuffixes) {
+ encoded_url->push_back(*raw_url_position);
+ raw_url_position++;
+ }
+ }
+
+ return encoded_url->size();
+}
+}
diff --git a/chromium/components/physical_web/eddystone/eddystone_encoder.h b/chromium/components/physical_web/eddystone/eddystone_encoder.h
new file mode 100644
index 00000000000..eaff749733c
--- /dev/null
+++ b/chromium/components/physical_web/eddystone/eddystone_encoder.h
@@ -0,0 +1,34 @@
+// 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_PHYSICAL_WEB_EDDYSTONE_EDDYSTONE_ENCODER_H_
+#define COMPONENTS_PHYSICAL_WEB_EDDYSTONE_EDDYSTONE_ENCODER_H_
+
+#include <string>
+#include <vector>
+
+namespace physical_web {
+
+const size_t kEmptyUrl = static_cast<size_t>(-1);
+const size_t kInvalidUrl = static_cast<size_t>(-2);
+const size_t kInvalidFormat = static_cast<size_t>(-3);
+const size_t kNullEncodedUrl = static_cast<size_t>(-4);
+
+/*
+ * EncodeUrl takes a URL in the form of a std::string and
+ * a pointer to a uint8_t vector to populate with the eddystone
+ * encoding of the URL.
+ * Returns:
+ * kEmptyUrl If the URL parameter is empty.
+ * kInvalidUrl If the URL parameter is not a valid URL.
+ * kInvalidFormat If the URL parameter is not a standard HTTPS/HTTP URL.
+ * kNullEncodedUrl If the encoded_url vector is NULL.
+ * Length of encoded URL.
+ * Eddystone spec can be found here:
+ * https://github.com/google/eddystone/blob/master/protocol-specification.md
+ */
+size_t EncodeUrl(const std::string& url, std::vector<uint8_t>* encoded_url);
+}
+
+#endif // COMPONENTS_PHYSICAL_WEB_EDDYSTONE_EDDYSTONE_ENCODER_H_
diff --git a/chromium/components/physical_web/eddystone/eddystone_encoder_unittest.cc b/chromium/components/physical_web/eddystone/eddystone_encoder_unittest.cc
new file mode 100644
index 00000000000..60e182a42b6
--- /dev/null
+++ b/chromium/components/physical_web/eddystone/eddystone_encoder_unittest.cc
@@ -0,0 +1,422 @@
+// 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/physical_web/eddystone/eddystone_encoder.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+using std::vector;
+using std::equal;
+
+class EddystoneEncoderTest : public testing::Test {
+ public:
+ EddystoneEncoderTest() {}
+ ~EddystoneEncoderTest() override {}
+
+ void SetUp() override {}
+ void TearDown() override {}
+
+ bool ByteVectorEquals(const vector<uint8_t>& a, const vector<uint8_t>& b);
+};
+
+bool EddystoneEncoderTest::ByteVectorEquals(const vector<uint8_t>& a,
+ const vector<uint8_t>& b) {
+ if (a.size() != b.size()) {
+ return false;
+ }
+ return equal(a.begin(), a.end(), b.begin());
+}
+
+TEST_F(EddystoneEncoderTest, NullVector) {
+ string valid_url = "https://www.aurl.com/";
+
+ size_t expected_result = physical_web::kNullEncodedUrl;
+ size_t actual_result;
+
+ actual_result = physical_web::EncodeUrl(valid_url, NULL);
+
+ EXPECT_TRUE(expected_result == actual_result);
+}
+
+TEST_F(EddystoneEncoderTest, EmptyUrl) {
+ string empty_url = "";
+
+ size_t expected_result = physical_web::kEmptyUrl;
+ size_t actual_result;
+ vector<uint8_t> expected_vector;
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(empty_url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testTotallyInvalidUrl) {
+ string invalid_url = "InValidURL.duh";
+
+ size_t expected_result = physical_web::kInvalidUrl;
+ size_t actual_result;
+ vector<uint8_t> expected_vector;
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(invalid_url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testAlmostvalidUrl) {
+ string invalid_url = "https;//.com";
+
+ size_t expected_result = physical_web::kInvalidUrl;
+ size_t actual_result;
+ vector<uint8_t> expected_vector;
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(invalid_url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testIPAddressUrl) {
+ string invalid_url = "https://8.8.8.8/";
+
+ size_t expected_result = physical_web::kInvalidFormat;
+ size_t actual_result;
+ vector<uint8_t> expected_vector;
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(invalid_url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testInvalidProtocol) {
+ string invalid_url = "file://data/foo.com/it";
+
+ size_t expected_result = physical_web::kInvalidFormat;
+ size_t actual_result;
+ vector<uint8_t> expected_vector;
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(invalid_url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testShortUrl) {
+ string url = "http://a.com";
+ uint8_t expected_array[] = {0x02, // "http://"
+ 0x61, // "a"
+ 0x07}; // ".com"
+ size_t expected_array_length = sizeof(expected_array) / sizeof(uint8_t);
+
+ size_t expected_result = expected_array_length;
+ size_t actual_result;
+
+ vector<uint8_t> expected_vector(expected_array,
+ expected_array + expected_array_length);
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testStandardUrl) {
+ string url = "https://www.example.com/";
+ uint8_t expected_array[] = {0x01, // "https://www."
+ 0x65, 0x78, 0x61, 0x6d,
+ 0x70, 0x6c, 0x65, // "example"
+ 0x00}; // ".com/"
+ size_t expected_array_length = sizeof(expected_array) / sizeof(uint8_t);
+
+ size_t expected_result = expected_array_length;
+ size_t actual_result;
+
+ vector<uint8_t> expected_vector(expected_array,
+ expected_array + expected_array_length);
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testStandardHttpUrl) {
+ string url = "http://www.example.com/";
+ uint8_t expected_array[] = {0x00, // "http://www."
+ 0x65, 0x78, 0x61, 0x6d,
+ 0x70, 0x6c, 0x65, // "example"
+ 0x00}; // ".com/"
+ size_t expected_array_length = sizeof(expected_array) / sizeof(uint8_t);
+
+ size_t expected_result = expected_array_length;
+ size_t actual_result;
+
+ vector<uint8_t> expected_vector(expected_array,
+ expected_array + expected_array_length);
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testStandardHttpUrlWithoutSuffixSlash) {
+ string url = "http://www.example.com";
+ uint8_t expected_array[] = {0x00, // "http://www."
+ 0x65, 0x78, 0x61, 0x6d,
+ 0x70, 0x6c, 0x65, // "example"
+ 0x07}; // ".com"
+ size_t expected_array_length = sizeof(expected_array) / sizeof(uint8_t);
+
+ size_t expected_result = expected_array_length;
+ size_t actual_result;
+
+ vector<uint8_t> expected_vector(expected_array,
+ expected_array + expected_array_length);
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testStandardInfoUrl) {
+ string url = "https://www.example.info/";
+ uint8_t expected_array[] = {0x01, // "https://www."
+ 0x65, 0x78, 0x61, 0x6d,
+ 0x70, 0x6c, 0x65, // "example"
+ 0x04}; // ".info/"
+ size_t expected_array_length = sizeof(expected_array) / sizeof(uint8_t);
+
+ size_t expected_result = expected_array_length;
+ size_t actual_result;
+
+ vector<uint8_t> expected_vector(expected_array,
+ expected_array + expected_array_length);
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testAllowsSubDomains) {
+ string url = "https://www.example.cs.com/";
+ uint8_t expected_array[] = {0x01, // "https://www."
+ 0x65, 0x78, 0x61, 0x6d,
+ 0x70, 0x6c, 0x65, // "example"
+ 0x2e, 0x63, 0x73, // ".cs"
+ 0x00}; // ".com/"
+ size_t expected_array_length = sizeof(expected_array) / sizeof(uint8_t);
+
+ size_t expected_result = expected_array_length;
+ size_t actual_result;
+
+ vector<uint8_t> expected_vector(expected_array,
+ expected_array + expected_array_length);
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testAllowsPaths) {
+ string url = "https://www.example.cs.com/r";
+ uint8_t expected_array[] = {0x01, // "https://www."
+ 0x65, 0x78, 0x61, 0x6d,
+ 0x70, 0x6c, 0x65, // "example"
+ 0x2e, 0x63, 0x73, // ".cs"
+ 0x00, // ".com/"
+ 0x72}; // "r"
+ size_t expected_array_length = sizeof(expected_array) / sizeof(uint8_t);
+
+ size_t expected_result = expected_array_length;
+ size_t actual_result;
+
+ vector<uint8_t> expected_vector(expected_array,
+ expected_array + expected_array_length);
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testAllowsMultiplePaths) {
+ string url = "https://www.example.cs.com/r/red/it";
+ uint8_t expected_array[] = {
+ 0x01, // "https://www."
+ 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, // "example"
+ 0x2e, 0x63, 0x73, // ".cs"
+ 0x00, // ".com/"
+ 0x72, 0x2f, 0x72, 0x65, 0x64, 0x2f, 0x69, 0x74}; // "r/red/it"
+ size_t expected_array_length = sizeof(expected_array) / sizeof(uint8_t);
+
+ size_t expected_result = expected_array_length;
+ size_t actual_result;
+
+ vector<uint8_t> expected_vector(expected_array,
+ expected_array + expected_array_length);
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testHiddenCompression1) {
+ string url = "https://www.example.com/foo.com";
+ uint8_t expected_array[] = {0x01, // "https://www."
+ 0x65, 0x78, 0x61, 0x6d,
+ 0x70, 0x6c, 0x65, // "example"
+ 0x00, // ".com/"
+ 0x66, 0x6f, 0x6f, // "foo"
+ 0x07}; // ".com"
+ size_t expected_array_length = sizeof(expected_array) / sizeof(uint8_t);
+
+ size_t expected_result = expected_array_length;
+ size_t actual_result;
+
+ vector<uint8_t> expected_vector(expected_array,
+ expected_array + expected_array_length);
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testHiddenCompression2) {
+ string url = "https://www.example.com/foo.comma/";
+ uint8_t expected_array[] = {0x01, // "https://www."
+ 0x65, 0x78, 0x61, 0x6d,
+ 0x70, 0x6c, 0x65, // "example"
+ 0x00, // ".com/"
+ 0x66, 0x6f, 0x6f, // "foo"
+ 0x07, // ".com"
+ 0x6d, 0x61, 0x2f}; // "ma/"
+ size_t expected_array_length = sizeof(expected_array) / sizeof(uint8_t);
+
+ size_t expected_result = expected_array_length;
+ size_t actual_result;
+
+ vector<uint8_t> expected_vector(expected_array,
+ expected_array + expected_array_length);
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testSharedCompression) {
+ string url = "https://www.communities.com/";
+ uint8_t expected_array[] = {0x01, // "https://www."
+ 0x63, 0x6f, 0x6d, // "com"
+ 0x6d, 0x75, 0x6e, 0x69,
+ 0x74, 0x69, 0x65, 0x73, //"munities"
+ 0x00}; // ".com/"
+ size_t expected_array_length = sizeof(expected_array) / sizeof(uint8_t);
+
+ size_t expected_result = expected_array_length;
+ size_t actual_result;
+
+ vector<uint8_t> expected_vector(expected_array,
+ expected_array + expected_array_length);
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testSpecCollision) {
+ // decode(encode(".com/aURL.com")) == decode(encode("http://www.aURL.com"))
+ // without url validation
+ string invalid_url = ".com/aURL.com";
+
+ size_t invalid_expected_result = physical_web::kInvalidUrl;
+ size_t invalid_actual_result;
+ vector<uint8_t> invalid_expected_vector;
+ vector<uint8_t> invalid_actual_vector;
+
+ invalid_actual_result =
+ physical_web::EncodeUrl(invalid_url, &invalid_actual_vector);
+
+ EXPECT_TRUE(invalid_expected_result == invalid_actual_result);
+ EXPECT_TRUE(ByteVectorEquals(invalid_expected_vector, invalid_actual_vector));
+
+ // Now for the valid Url.
+ string valid_url = "http://www.aURL.com";
+ uint8_t valid_expected_array[] = {0x00, // "https://www."
+ 0x61, 0x55, 0x52, 0x4c, // "aUrl"
+ 0x07}; // ".com"
+ size_t valid_expected_array_length =
+ sizeof(valid_expected_array) / sizeof(uint8_t);
+
+ size_t valid_expected_result = valid_expected_array_length;
+ size_t valid_actual_result;
+
+ vector<uint8_t> valid_expected_vector(
+ valid_expected_array, valid_expected_array + valid_expected_array_length);
+ vector<uint8_t> valid_actual_vector;
+
+ valid_actual_result =
+ physical_web::EncodeUrl(valid_url, &valid_actual_vector);
+
+ EXPECT_TRUE(valid_expected_result == valid_actual_result);
+ EXPECT_TRUE(ByteVectorEquals(valid_expected_vector, valid_actual_vector));
+
+ EXPECT_FALSE(ByteVectorEquals(invalid_actual_vector, valid_actual_vector));
+}
+
+TEST_F(EddystoneEncoderTest, testComplexUrl) {
+ string url = "http://user:pass@google.com:99/foo;bar?q=a#ref";
+ uint8_t expected_array[] = {0x02, // "http://"
+ 0x75, 0x73, 0x65, 0x72, 0x3a, // "user:"
+ 0x70, 0x61, 0x73, 0x73, 0x40, // "pass@"
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, // "google"
+ 0x07, // ".com"
+ 0x3a, 0x39, 0x39, 0x2f, // ":99/"
+ 0x66, 0x6f, 0x6f, 0x3b, // "foo;"
+ 0x62, 0x61, 0x72, 0x3f, // "bar?"
+ 0x71, 0x3d, 0x61, 0x23, // "q=a#"
+ 0x72, 0x65, 0x66}; // "ref"
+ size_t expected_array_length = sizeof(expected_array) / sizeof(uint8_t);
+
+ size_t expected_result = expected_array_length;
+ size_t actual_result;
+
+ vector<uint8_t> expected_vector(expected_array,
+ expected_array + expected_array_length);
+ vector<uint8_t> actual_vector;
+
+ actual_result = physical_web::EncodeUrl(url, &actual_vector);
+
+ EXPECT_TRUE(expected_result == actual_result);
+ EXPECT_TRUE(ByteVectorEquals(expected_vector, actual_vector));
+}
diff --git a/chromium/components/physical_web/resources/ic_link_grey600_36dp.png b/chromium/components/physical_web/resources/ic_link_grey600_36dp.png
new file mode 100644
index 00000000000..6e39fc76fb1
--- /dev/null
+++ b/chromium/components/physical_web/resources/ic_link_grey600_36dp.png
Binary files differ
diff --git a/chromium/components/physical_web/webui/physical_web_base_message_handler.cc b/chromium/components/physical_web/webui/physical_web_base_message_handler.cc
index 68aeca7791e..dd28dc3dd22 100644
--- a/chromium/components/physical_web/webui/physical_web_base_message_handler.cc
+++ b/chromium/components/physical_web/webui/physical_web_base_message_handler.cc
@@ -13,32 +13,65 @@
namespace physical_web_ui {
-PhysicalWebBaseMessageHandler::PhysicalWebBaseMessageHandler() {}
+PhysicalWebBaseMessageHandler::PhysicalWebBaseMessageHandler()
+ : data_source_(nullptr) {}
-PhysicalWebBaseMessageHandler::~PhysicalWebBaseMessageHandler() = default;
+PhysicalWebBaseMessageHandler::~PhysicalWebBaseMessageHandler() {
+ if (data_source_)
+ data_source_->UnregisterListener(this);
+}
+
+void PhysicalWebBaseMessageHandler::OnFound(const GURL& url) {
+ PushNearbyURLs();
+}
+
+void PhysicalWebBaseMessageHandler::OnLost(const GURL& url) {
+ // do nothing
+}
+
+void PhysicalWebBaseMessageHandler::OnDistanceChanged(
+ const GURL& url,
+ double distance_estimate) {
+ // do nothing
+}
void PhysicalWebBaseMessageHandler::RegisterMessages() {
RegisterMessageCallback(
- kRequestNearbyUrls,
+ kPhysicalWebPageLoaded,
base::BindRepeating(
- &PhysicalWebBaseMessageHandler::HandleRequestNearbyURLs,
+ &PhysicalWebBaseMessageHandler::HandlePhysicalWebPageLoaded,
base::Unretained(this)));
- RegisterMessageCallback(kPhysicalWebItemClicked,
+
+ RegisterMessageCallback(
+ kPhysicalWebItemClicked,
base::BindRepeating(
&PhysicalWebBaseMessageHandler::HandlePhysicalWebItemClicked,
base::Unretained(this)));
+
+ data_source_ = GetPhysicalWebDataSource();
+ if (data_source_)
+ data_source_->RegisterListener(this, physical_web::OPPORTUNISTIC);
}
-void PhysicalWebBaseMessageHandler::HandleRequestNearbyURLs(
- const base::ListValue* args) {
+void PhysicalWebBaseMessageHandler::PushNearbyURLs() {
base::DictionaryValue results;
std::unique_ptr<physical_web::MetadataList> metadata_list =
GetPhysicalWebDataSource()->GetMetadataList();
+ // Append new metadata at the end of the list.
+ for (const auto& metadata_list_item : *metadata_list) {
+ const std::string& group_id = metadata_list_item.group_id;
+ if (metadata_map_.find(group_id) == metadata_map_.end()) {
+ ordered_group_ids_.push_back(group_id);
+ metadata_map_.insert(std::make_pair(group_id, metadata_list_item));
+ }
+ }
+
auto metadata = base::MakeUnique<base::ListValue>();
int index = 0;
- for (const auto& metadata_list_item : *metadata_list) {
+ for (const auto& group_id : ordered_group_ids_) {
+ auto metadata_list_item = metadata_map_[group_id];
auto metadata_item = base::MakeUnique<base::DictionaryValue>();
metadata_item->SetString(physical_web_ui::kResolvedUrl,
metadata_list_item.resolved_url.spec());
@@ -57,12 +90,16 @@ void PhysicalWebBaseMessageHandler::HandleRequestNearbyURLs(
results.Set(physical_web_ui::kMetadata, metadata.release());
- UMA_HISTOGRAM_EXACT_LINEAR("PhysicalWeb.TotalUrls.OnInitialDisplay",
- (int)metadata_list->size(), 50);
-
// Pass the list of Physical Web URL metadata to the WebUI. A jstemplate will
// create a list view with an item for each URL.
- CallJavaScriptFunction(physical_web_ui::kReturnNearbyUrls, results);
+ CallJavaScriptFunction(physical_web_ui::kPushNearbyUrls, results);
+}
+
+void PhysicalWebBaseMessageHandler::HandlePhysicalWebPageLoaded(
+ const base::ListValue* args) {
+ PushNearbyURLs();
+ UMA_HISTOGRAM_EXACT_LINEAR("PhysicalWeb.TotalUrls.OnInitialDisplay",
+ (int)ordered_group_ids_.size(), 50);
}
void PhysicalWebBaseMessageHandler::HandlePhysicalWebItemClicked(
@@ -82,4 +119,4 @@ void PhysicalWebBaseMessageHandler::HandlePhysicalWebItemClicked(
base::UserMetricsAction("PhysicalWeb.WebUI.ListViewUrlSelected"));
}
-} // namespace physical_web_ui
+} // namespace physical_web_ui
diff --git a/chromium/components/physical_web/webui/physical_web_base_message_handler.h b/chromium/components/physical_web/webui/physical_web_base_message_handler.h
index 190cf294b11..21b07cd08f5 100644
--- a/chromium/components/physical_web/webui/physical_web_base_message_handler.h
+++ b/chromium/components/physical_web/webui/physical_web_base_message_handler.h
@@ -5,9 +5,13 @@
#ifndef COMPONENTS_PHYSICAL_WEB_WEBUI_PHYSICAL_WEB_BASE_MESSAGE_HANDLER_H_
#define COMPONENTS_PHYSICAL_WEB_WEBUI_PHYSICAL_WEB_BASE_MESSAGE_HANDLER_H_
+#include <map>
+
#include "base/callback.h"
#include "base/macros.h"
#include "base/values.h"
+#include "components/physical_web/data_source/physical_web_data_source.h"
+#include "components/physical_web/data_source/physical_web_listener.h"
namespace physical_web {
@@ -22,14 +26,22 @@ typedef base::Callback<void(const base::ListValue*)> MessageCallback;
// The base handler for Javascript messages for the chrome://physical-web page.
// This does not implement WebUIMessageHandler or register its methods.
-class PhysicalWebBaseMessageHandler {
+class PhysicalWebBaseMessageHandler : physical_web::PhysicalWebListener {
public:
PhysicalWebBaseMessageHandler();
virtual ~PhysicalWebBaseMessageHandler();
- // Handles the RequestNearbyURLs message, returning URLs that are currently
- // being broadcasted by Physical Web transports.
- void HandleRequestNearbyURLs(const base::ListValue* args);
+ // PhysicalWebListener
+ void OnFound(const GURL& url) override;
+ void OnLost(const GURL& url) override;
+ void OnDistanceChanged(const GURL& url, double distance_estimate) override;
+
+ // Push URLs that are currently being broadcasted by Physical Web
+ // transports to WebUI.
+ void PushNearbyURLs();
+
+ // Push nearby URLs to WebUI and log UMA.
+ void HandlePhysicalWebPageLoaded(const base::ListValue* args);
// Handles a click on a Physical Web URL, recording the click and
// directing the user appropriately.
@@ -42,14 +54,17 @@ class PhysicalWebBaseMessageHandler {
// Subclasses should implement these protected methods as a pass through to
// the similarly named methods of the appropriate WebUI object (the exact
// WebUI class differs per platform).
- virtual void RegisterMessageCallback(
- const std::string& message,
- const MessageCallback& callback) = 0;
+ virtual void RegisterMessageCallback(const std::string& message,
+ const MessageCallback& callback) = 0;
virtual void CallJavaScriptFunction(const std::string& function,
const base::Value& arg) = 0;
virtual physical_web::PhysicalWebDataSource* GetPhysicalWebDataSource() = 0;
private:
+ physical_web::PhysicalWebDataSource* data_source_;
+ std::vector<std::string> ordered_group_ids_;
+ std::map<std::string, physical_web::Metadata> metadata_map_;
+
DISALLOW_COPY_AND_ASSIGN(PhysicalWebBaseMessageHandler);
};
diff --git a/chromium/components/physical_web/webui/physical_web_ui_constants.cc b/chromium/components/physical_web/webui/physical_web_ui_constants.cc
index 82d1af39dab..3e7728c578b 100644
--- a/chromium/components/physical_web/webui/physical_web_ui_constants.cc
+++ b/chromium/components/physical_web/webui/physical_web_ui_constants.cc
@@ -9,19 +9,21 @@ namespace physical_web_ui {
// Resource paths.
const char kPhysicalWebJS[] = "physical_web.js";
const char kPhysicalWebCSS[] = "physical_web.css";
+const char kPhysicalWebLinkIcon[] = "ic_link_grey600_36dp.png";
// Message handlers.
-const char kRequestNearbyUrls[] = "requestNearbyURLs";
+const char kPhysicalWebPageLoaded[] = "physicalWebPageLoaded";
const char kPhysicalWebItemClicked[] = "physicalWebItemClicked";
// Strings.
const char kTitle[] = "title";
+const char kEmptyMessage[] = "emptyMessage";
const char kPageInfoDescription[] = "pageInfoDescription";
const char kPageInfoIcon[] = "pageInfoIcon";
const char kPageInfoTitle[] = "pageInfoTitle";
const char kResolvedUrl[] = "resolvedUrl";
const char kIndex[] = "index";
-const char kReturnNearbyUrls[] = "returnNearbyURLs";
+const char kPushNearbyUrls[] = "pushNearbyURLs";
const char kMetadata[] = "metadata";
} // namespace physical_web_ui
diff --git a/chromium/components/physical_web/webui/physical_web_ui_constants.h b/chromium/components/physical_web/webui/physical_web_ui_constants.h
index 2eb85231496..6b18bbaf1bf 100644
--- a/chromium/components/physical_web/webui/physical_web_ui_constants.h
+++ b/chromium/components/physical_web/webui/physical_web_ui_constants.h
@@ -11,21 +11,23 @@ namespace physical_web_ui {
// Must match the resource file names.
extern const char kPhysicalWebJS[];
extern const char kPhysicalWebCSS[];
+extern const char kPhysicalWebLinkIcon[];
// Message handlers.
// Must match the constants used in the resource files.
-extern const char kRequestNearbyUrls[];
+extern const char kPhysicalWebPageLoaded[];
extern const char kPhysicalWebItemClicked[];
// Strings.
// Must match the constants used in the resource files.
extern const char kTitle[];
+extern const char kEmptyMessage[];
extern const char kPageInfoDescription[];
extern const char kPageInfoIcon[];
extern const char kPageInfoTitle[];
extern const char kResolvedUrl[];
extern const char kIndex[];
-extern const char kReturnNearbyUrls[];
+extern const char kPushNearbyUrls[];
extern const char kMetadata[];
} // namespace physical_web_ui
diff --git a/chromium/components/physical_web/webui/resources/physical_web.html b/chromium/components/physical_web/webui/resources/physical_web.html
index a5a0ba69884..034912ed743 100644
--- a/chromium/components/physical_web/webui/resources/physical_web.html
+++ b/chromium/components/physical_web/webui/resources/physical_web.html
@@ -20,24 +20,25 @@
<script src="chrome://physical-web/strings.js"></script>
</head>
<body>
-<div id="body-container" style="visibility:visible">
+<div id="body-container" hidden>
<h1 i18n-content="title"></h1>
-
- <a class="physicalWebTemplate" id="physicalWebTemplate" jsselect="metadata"
- jsvalues="href:resolvedUrl;onclick:'physicalWebItemClicked(' + index + ')'">
- <div class="physicalWebIcon">
- <img jsvalues="src:pageInfoIcon" />
- </div>
- <div class="physicalWebText">
- <div class="title" jscontent="pageInfoTitle"></div>
- <div class="resolvedUrl" jscontent="resolvedUrl"></div>
- <div class="description" jscontent="pageInfoDescription"></div>
- </div>
- </a>
-
+ <div id="render-container"></div>
+ <div id="empty-list-container" i18n-content="emptyMessage"></div>
</div>
+<a hidden id="render-template" class="physicalWebTemplate" jsselect="metadata"
+ jsvalues="href:resolvedUrl;onclick:'physicalWebItemClicked(' + index + ')'">
+ <div class="physicalWebIcon">
+ <img jsvalues="src:pageInfoIcon" />
+ </div>
+ <div class="physicalWebText">
+ <div class="title" jscontent="pageInfoTitle"></div>
+ <div class="resolvedUrl" jscontent="resolvedUrl"></div>
+ <div class="description" jscontent="pageInfoDescription"></div>
+ </div>
+</a>
+
<script src="chrome://resources/js/i18n_template.js"></script>
<script src="chrome://resources/js/jstemplate_compiled.js"></script>
</body>
diff --git a/chromium/components/physical_web/webui/resources/physical_web.js b/chromium/components/physical_web/webui/resources/physical_web.js
index 418dc1d6e90..86002dd5027 100644
--- a/chromium/components/physical_web/webui/resources/physical_web.js
+++ b/chromium/components/physical_web/webui/resources/physical_web.js
@@ -9,23 +9,49 @@
* nearby devices
*/
function renderTemplate(nearbyUrlsData) {
+ if (nearbyUrlsData['metadata'].length != 0) {
+ $('empty-list-container').hidden = true;
+ }
+ // This is a workaround with jstemplate. Jstemplate render only works on empty
+ // node. When we need to rerender things, we have to remove previous nodes.
+ let renderContainer = document.getElementById('render-container');
+ // Remove existing childNode.
+ while (renderContainer.hasChildNodes()) {
+ renderContainer.removeChild(renderContainer.lastChild);
+ }
+ let templateDiv = document.getElementById('render-template').cloneNode(true);
+ renderContainer.appendChild(templateDiv);
+
// This is the javascript code that processes the template:
- jstProcess(new JsEvalContext(nearbyUrlsData), $('physicalWebTemplate'));
+ jstProcess(new JsEvalContext(nearbyUrlsData), templateDiv);
+
+ assignImageLoadErrorHandlers();
+
+ let bodyContainer = $('body-container');
+ bodyContainer.hidden = false;
}
-function requestNearbyURLs() {
- chrome.send('requestNearbyURLs');
+function physicalWebPageLoaded() {
+ chrome.send('physicalWebPageLoaded');
}
function physicalWebItemClicked(index) {
chrome.send('physicalWebItemClicked', [index]);
}
-function returnNearbyURLs(nearbyUrlsData) {
- var bodyContainer = $('body-container');
+function pushNearbyURLs(nearbyUrlsData) {
renderTemplate(nearbyUrlsData);
+}
- bodyContainer.style.visibility = 'visible';
+function assignImageLoadErrorHandlers() {
+ var pwIcons = document.querySelectorAll('.physicalWebIcon');
+ pwIcons.forEach(function(e) {
+ let img = e.getElementsByTagName('img')[0];
+ img.addEventListener('error', function() {
+ img.src =
+ 'chrome://physical-web/ic_link_grey600_36dp.png';
+ });
+ });
}
-document.addEventListener('DOMContentLoaded', requestNearbyURLs);
+document.addEventListener('DOMContentLoaded', physicalWebPageLoaded);
diff --git a/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc b/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc
index 8bffae8705f..dde47c2569e 100644
--- a/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc
+++ b/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc
@@ -41,6 +41,7 @@ void LoadablePluginPlaceholder::BlockForPowerSaverPoster() {
DCHECK(!is_blocked_for_power_saver_poster_);
is_blocked_for_power_saver_poster_ = true;
+ DCHECK(render_frame());
render_frame()->RegisterPeripheralPlugin(
url::Origin(GURL(GetPluginParams().url)),
base::Bind(&LoadablePluginPlaceholder::MarkPluginEssential,
@@ -98,26 +99,26 @@ void LoadablePluginPlaceholder::ReplacePlugin(blink::WebPlugin* new_plugin) {
CHECK(plugin());
if (!new_plugin)
return;
- blink::WebPluginContainer* container = plugin()->container();
+ blink::WebPluginContainer* container = plugin()->Container();
// This can occur if the container has been destroyed.
if (!container) {
- new_plugin->destroy();
+ new_plugin->Destroy();
return;
}
- container->setPlugin(new_plugin);
+ container->SetPlugin(new_plugin);
bool plugin_needs_initialization =
!premade_throttler_ || new_plugin != premade_throttler_->GetWebPlugin();
- if (plugin_needs_initialization && !new_plugin->initialize(container)) {
- if (new_plugin->container()) {
+ if (plugin_needs_initialization && !new_plugin->Initialize(container)) {
+ if (new_plugin->Container()) {
// Since the we couldn't initialize the new plugin, but the container
// still exists, restore the placeholder and destroy the new plugin.
- container->setPlugin(plugin());
- new_plugin->destroy();
+ container->SetPlugin(plugin());
+ new_plugin->Destroy();
} else {
// The container has been destroyed, along with the new plugin. Destroy
// our placeholder plugin also.
- plugin()->destroy();
+ plugin()->Destroy();
}
return;
}
@@ -125,13 +126,13 @@ void LoadablePluginPlaceholder::ReplacePlugin(blink::WebPlugin* new_plugin) {
// During initialization, the new plugin might have replaced itself in turn
// with another plugin. Make sure not to use the passed in |new_plugin| after
// this point.
- new_plugin = container->plugin();
+ new_plugin = container->Plugin();
- container->invalidate();
- container->reportGeometry();
- container->element().setAttribute("title", plugin()->old_title());
+ container->Invalidate();
+ container->ReportGeometry();
+ container->GetElement().SetAttribute("title", plugin()->old_title());
plugin()->ReplayReceivedData(new_plugin);
- plugin()->destroy();
+ plugin()->Destroy();
}
void LoadablePluginPlaceholder::SetMessage(const base::string16& message) {
@@ -145,8 +146,8 @@ void LoadablePluginPlaceholder::UpdateMessage() {
return;
std::string script =
"window.setMessage(" + base::GetQuotedJSONString(message_) + ")";
- plugin()->web_view()->mainFrame()->executeScript(
- blink::WebScriptSource(blink::WebString::fromUTF8(script)));
+ plugin()->web_view()->MainFrame()->ExecuteScript(
+ blink::WebScriptSource(blink::WebString::FromUTF8(script)));
}
void LoadablePluginPlaceholder::PluginDestroyed() {
@@ -154,7 +155,7 @@ void LoadablePluginPlaceholder::PluginDestroyed() {
if (premade_throttler_) {
// Since the premade plugin has been detached from the container, it will
// not be automatically destroyed along with the page.
- premade_throttler_->GetWebPlugin()->destroy();
+ premade_throttler_->GetWebPlugin()->Destroy();
premade_throttler_ = nullptr;
} else if (is_blocked_for_power_saver_poster_) {
// Record the NEVER unthrottle count only if there is no throttler.
@@ -173,7 +174,7 @@ v8::Local<v8::Object> LoadablePluginPlaceholder::GetV8ScriptableObject(
v8::Isolate* isolate) const {
// Pass through JavaScript access to the underlying throttled plugin.
if (premade_throttler_ && premade_throttler_->GetWebPlugin()) {
- return premade_throttler_->GetWebPlugin()->v8ScriptableObject(isolate);
+ return premade_throttler_->GetWebPlugin()->V8ScriptableObject(isolate);
}
return v8::Local<v8::Object>();
}
@@ -181,6 +182,8 @@ v8::Local<v8::Object> LoadablePluginPlaceholder::GetV8ScriptableObject(
void LoadablePluginPlaceholder::OnUnobscuredRectUpdate(
const gfx::Rect& unobscured_rect) {
DCHECK(content::RenderThread::Get());
+ if (!render_frame())
+ return;
if (!plugin() || !finished_loading_)
return;
@@ -193,7 +196,7 @@ void LoadablePluginPlaceholder::OnUnobscuredRectUpdate(
unobscured_rect_ = unobscured_rect;
- float zoom_factor = plugin()->container()->pageZoomFactor();
+ float zoom_factor = plugin()->Container()->PageZoomFactor();
int width = roundf(unobscured_rect_.width() / zoom_factor);
int height = roundf(unobscured_rect_.height() / zoom_factor);
int x = roundf(unobscured_rect_.x() / zoom_factor);
@@ -203,7 +206,7 @@ void LoadablePluginPlaceholder::OnUnobscuredRectUpdate(
url::Origin content_origin = url::Origin(GetPluginParams().url);
RenderFrame::PeripheralContentStatus status =
render_frame()->GetPeripheralContentStatus(
- render_frame()->GetWebFrame()->top()->getSecurityOrigin(),
+ render_frame()->GetWebFrame()->Top()->GetSecurityOrigin(),
content_origin, gfx::Size(width, height),
heuristic_run_before_ ? RenderFrame::DONT_RECORD_DECISION
: RenderFrame::RECORD_DECISION);
@@ -213,7 +216,8 @@ void LoadablePluginPlaceholder::OnUnobscuredRectUpdate(
// Early exit for plugins that we've discovered to be essential.
if (!plugin_is_tiny_and_blocked &&
- status != RenderFrame::CONTENT_STATUS_PERIPHERAL) {
+ status != RenderFrame::CONTENT_STATUS_PERIPHERAL &&
+ status != RenderFrame::CONTENT_STATUS_TINY) {
MarkPluginEssential(
heuristic_run_before_
? PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_SIZE_CHANGE
@@ -245,8 +249,8 @@ void LoadablePluginPlaceholder::OnUnobscuredRectUpdate(
std::string script = base::StringPrintf(
"window.resizePoster('%dpx', '%dpx', '%dpx', '%dpx')", x, y, width,
height);
- plugin()->web_view()->mainFrame()->executeScript(
- blink::WebScriptSource(blink::WebString::fromUTF8(script)));
+ plugin()->web_view()->MainFrame()->ExecuteScript(
+ blink::WebScriptSource(blink::WebString::FromUTF8(script)));
}
}
@@ -322,8 +326,8 @@ void LoadablePluginPlaceholder::DidFinishLoadingCallback() {
// In case our initial geometry was reported before the placeholder finished
// loading, request another one. Needed for correct large poster unthrottling.
if (plugin()) {
- CHECK(plugin()->container());
- plugin()->container()->reportGeometry();
+ CHECK(plugin()->Container());
+ plugin()->Container()->ReportGeometry();
}
}
@@ -333,18 +337,21 @@ void LoadablePluginPlaceholder::DidFinishIconRepositionForTestingCallback() {
// Set an attribute and post an event, so browser tests can wait for the
// placeholder to be ready to receive simulated user input.
- blink::WebElement element = plugin()->container()->element();
- element.setAttribute("placeholderReady", "true");
+ blink::WebElement element = plugin()->Container()->GetElement();
+ element.SetAttribute("placeholderReady", "true");
std::unique_ptr<content::V8ValueConverter> converter(
content::V8ValueConverter::create());
- base::StringValue value("placeholderReady");
+ base::Value value("placeholderReady");
blink::WebSerializedScriptValue message_data =
- blink::WebSerializedScriptValue::serialize(converter->ToV8Value(
- &value, element.document().frame()->mainWorldScriptContext()));
+ blink::WebSerializedScriptValue::Serialize(
+ blink::MainThreadIsolate(),
+ converter->ToV8Value(
+ &value,
+ element.GetDocument().GetFrame()->MainWorldScriptContext()));
blink::WebDOMMessageEvent msg_event(message_data);
- plugin()->container()->enqueueMessageEvent(msg_event);
+ plugin()->Container()->EnqueueMessageEvent(msg_event);
}
void LoadablePluginPlaceholder::SetPluginInfo(
diff --git a/chromium/components/plugins/renderer/plugin_placeholder.cc b/chromium/components/plugins/renderer/plugin_placeholder.cc
index b8c9a543e82..a643433b1ef 100644
--- a/chromium/components/plugins/renderer/plugin_placeholder.cc
+++ b/chromium/components/plugins/renderer/plugin_placeholder.cc
@@ -62,9 +62,9 @@ void PluginPlaceholderBase::HidePlugin() {
hidden_ = true;
if (!plugin())
return;
- blink::WebPluginContainer* container = plugin()->container();
- blink::WebElement element = container->element();
- element.setAttribute("style", "display: none;");
+ blink::WebPluginContainer* container = plugin()->Container();
+ blink::WebElement element = container->GetElement();
+ element.SetAttribute("style", "display: none;");
// If we have a width and height, search for a parent (often <div>) with the
// same dimensions. If we find such a parent, hide that as well.
// This makes much more uncovered page content usable (including clickable)
@@ -75,16 +75,16 @@ void PluginPlaceholderBase::HidePlugin() {
// 2) Foulness is encapsulated within this single function.
// 3) Confidence in no fasle positives.
// 4) Seems to have a good / low false negative rate at this time.
- if (element.hasAttribute("width") && element.hasAttribute("height")) {
+ if (element.HasAttribute("width") && element.HasAttribute("height")) {
std::string width_str("width:[\\s]*");
- width_str += element.getAttribute("width").utf8().data();
+ width_str += element.GetAttribute("width").Utf8().data();
if (base::EndsWith(width_str, "px", base::CompareCase::INSENSITIVE_ASCII)) {
width_str = width_str.substr(0, width_str.length() - 2);
}
base::TrimWhitespaceASCII(width_str, base::TRIM_TRAILING, &width_str);
width_str += "[\\s]*px";
std::string height_str("height:[\\s]*");
- height_str += element.getAttribute("height").utf8().data();
+ height_str += element.GetAttribute("height").Utf8().data();
if (base::EndsWith(height_str, "px",
base::CompareCase::INSENSITIVE_ASCII)) {
height_str = height_str.substr(0, height_str.length() - 2);
@@ -92,16 +92,16 @@ void PluginPlaceholderBase::HidePlugin() {
base::TrimWhitespaceASCII(height_str, base::TRIM_TRAILING, &height_str);
height_str += "[\\s]*px";
blink::WebNode parent = element;
- while (!parent.parentNode().isNull()) {
- parent = parent.parentNode();
- if (!parent.isElementNode())
+ while (!parent.ParentNode().IsNull()) {
+ parent = parent.ParentNode();
+ if (!parent.IsElementNode())
continue;
- element = parent.toConst<blink::WebElement>();
- if (element.hasAttribute("style")) {
- std::string style_str = element.getAttribute("style").utf8();
+ element = parent.ToConst<blink::WebElement>();
+ if (element.HasAttribute("style")) {
+ std::string style_str = element.GetAttribute("style").Utf8();
if (RE2::PartialMatch(style_str, width_str) &&
RE2::PartialMatch(style_str, height_str))
- element.setAttribute("style", "display: none;");
+ element.SetAttribute("style", "display: none;");
}
}
}
diff --git a/chromium/components/plugins/renderer/webview_plugin.cc b/chromium/components/plugins/renderer/webview_plugin.cc
index 075515a0779..fd001151967 100644
--- a/chromium/components/plugins/renderer/webview_plugin.cc
+++ b/chromium/components/plugins/renderer/webview_plugin.cc
@@ -69,7 +69,7 @@ WebViewPlugin* WebViewPlugin::Create(content::RenderView* render_view,
const GURL& url) {
DCHECK(url.is_valid()) << "Blink requires the WebView to have a valid URL.";
WebViewPlugin* plugin = new WebViewPlugin(render_view, delegate, preferences);
- plugin->web_view()->mainFrame()->loadHTMLString(html_data, url);
+ plugin->web_view()->MainFrame()->LoadHTMLString(html_data, url);
return plugin;
}
@@ -78,30 +78,32 @@ WebViewPlugin::~WebViewPlugin() {
}
void WebViewPlugin::ReplayReceivedData(WebPlugin* plugin) {
- if (!response_.isNull()) {
- plugin->didReceiveResponse(response_);
+ if (!response_.IsNull()) {
+ plugin->DidReceiveResponse(response_);
size_t total_bytes = 0;
for (std::list<std::string>::iterator it = data_.begin(); it != data_.end();
++it) {
- plugin->didReceiveData(
- it->c_str(), base::checked_cast<int>(it->length()));
+ plugin->DidReceiveData(it->c_str(),
+ base::checked_cast<int>(it->length()));
total_bytes += it->length();
}
}
// We need to transfer the |focused_| to new plugin after it loaded.
if (focused_)
- plugin->updateFocus(true, blink::WebFocusTypeNone);
+ plugin->UpdateFocus(true, blink::kWebFocusTypeNone);
if (finished_loading_)
- plugin->didFinishLoading();
+ plugin->DidFinishLoading();
if (error_)
- plugin->didFailLoading(*error_);
+ plugin->DidFailLoading(*error_);
}
-WebPluginContainer* WebViewPlugin::container() const { return container_; }
+WebPluginContainer* WebViewPlugin::Container() const {
+ return container_;
+}
-bool WebViewPlugin::initialize(WebPluginContainer* container) {
+bool WebViewPlugin::Initialize(WebPluginContainer* container) {
DCHECK(container);
- DCHECK_EQ(this, container->plugin());
+ DCHECK_EQ(this, container->Plugin());
container_ = container;
// We must call layout again here to ensure that the container is laid
@@ -111,19 +113,19 @@ bool WebViewPlugin::initialize(WebPluginContainer* container) {
// scheduleAnimation may be invoked before this initialize call (which
// comes through the widget update process). It doesn't hurt to mark
// for animation again, and it does help us in the race-condition situation.
- container_->scheduleAnimation();
+ container_->ScheduleAnimation();
- old_title_ = container_->element().getAttribute("title");
+ old_title_ = container_->GetElement().GetAttribute("title");
// Propagate device scale and zoom level to inner webview.
- web_view()->setDeviceScaleFactor(container_->deviceScaleFactor());
- web_view()->setZoomLevel(
- blink::WebView::zoomFactorToZoomLevel(container_->pageZoomFactor()));
+ web_view()->SetDeviceScaleFactor(container_->DeviceScaleFactor());
+ web_view()->SetZoomLevel(
+ blink::WebView::ZoomFactorToZoomLevel(container_->PageZoomFactor()));
return true;
}
-void WebViewPlugin::destroy() {
+void WebViewPlugin::Destroy() {
weak_factory_.InvalidateWeakPtrs();
if (delegate_) {
@@ -135,18 +137,18 @@ void WebViewPlugin::destroy() {
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
}
-v8::Local<v8::Object> WebViewPlugin::v8ScriptableObject(v8::Isolate* isolate) {
+v8::Local<v8::Object> WebViewPlugin::V8ScriptableObject(v8::Isolate* isolate) {
if (!delegate_)
return v8::Local<v8::Object>();
return delegate_->GetV8ScriptableObject(isolate);
}
-void WebViewPlugin::updateAllLifecyclePhases() {
- web_view()->updateAllLifecyclePhases();
+void WebViewPlugin::UpdateAllLifecyclePhases() {
+ web_view()->UpdateAllLifecyclePhases();
}
-void WebViewPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
+void WebViewPlugin::Paint(WebCanvas* canvas, const WebRect& rect) {
gfx::Rect paint_rect = gfx::IntersectRects(rect_, rect);
if (paint_rect.IsEmpty())
return;
@@ -162,16 +164,16 @@ void WebViewPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
// Apply inverse device scale factor, as the outer webview has already
// applied it, and the inner webview will apply it again.
SkScalar inverse_scale =
- SkFloatToScalar(1.0 / container_->deviceScaleFactor());
+ SkFloatToScalar(1.0 / container_->DeviceScaleFactor());
canvas->scale(inverse_scale, inverse_scale);
- web_view()->paint(canvas, paint_rect);
+ web_view()->Paint(canvas, paint_rect);
canvas->restore();
}
// Coordinates are relative to the containing window.
-void WebViewPlugin::updateGeometry(const WebRect& window_rect,
+void WebViewPlugin::UpdateGeometry(const WebRect& window_rect,
const WebRect& clip_rect,
const WebRect& unobscured_rect,
const WebVector<WebRect>& cut_outs_rects,
@@ -182,7 +184,7 @@ void WebViewPlugin::updateGeometry(const WebRect& window_rect,
if (static_cast<gfx::Rect>(window_rect) != rect_) {
rect_ = window_rect;
- web_view()->resize(rect_.size());
+ web_view()->Resize(rect_.size());
}
// Plugin updates are forbidden during Blink layout. Therefore,
@@ -193,54 +195,54 @@ void WebViewPlugin::updateGeometry(const WebRect& window_rect,
weak_factory_.GetWeakPtr(), window_rect, unobscured_rect));
}
-void WebViewPlugin::updateFocus(bool focused, blink::WebFocusType focus_type) {
+void WebViewPlugin::UpdateFocus(bool focused, blink::WebFocusType focus_type) {
focused_ = focused;
}
-blink::WebInputEventResult WebViewPlugin::handleInputEvent(
+blink::WebInputEventResult WebViewPlugin::HandleInputEvent(
const WebInputEvent& event,
WebCursorInfo& cursor) {
// For tap events, don't handle them. They will be converted to
// mouse events later and passed to here.
- if (event.type() == WebInputEvent::GestureTap)
- return blink::WebInputEventResult::NotHandled;
+ if (event.GetType() == WebInputEvent::kGestureTap)
+ return blink::WebInputEventResult::kNotHandled;
// For LongPress events we return false, since otherwise the context menu will
// be suppressed. https://crbug.com/482842
- if (event.type() == WebInputEvent::GestureLongPress)
- return blink::WebInputEventResult::NotHandled;
+ if (event.GetType() == WebInputEvent::kGestureLongPress)
+ return blink::WebInputEventResult::kNotHandled;
- if (event.type() == WebInputEvent::ContextMenu) {
+ if (event.GetType() == WebInputEvent::kContextMenu) {
if (delegate_) {
const WebMouseEvent& mouse_event =
reinterpret_cast<const WebMouseEvent&>(event);
delegate_->ShowContextMenu(mouse_event);
}
- return blink::WebInputEventResult::HandledSuppressed;
+ return blink::WebInputEventResult::kHandledSuppressed;
}
current_cursor_ = cursor;
blink::WebInputEventResult handled =
- web_view()->handleInputEvent(blink::WebCoalescedInputEvent(event));
+ web_view()->HandleInputEvent(blink::WebCoalescedInputEvent(event));
cursor = current_cursor_;
return handled;
}
-void WebViewPlugin::didReceiveResponse(const WebURLResponse& response) {
- DCHECK(response_.isNull());
+void WebViewPlugin::DidReceiveResponse(const WebURLResponse& response) {
+ DCHECK(response_.IsNull());
response_ = response;
}
-void WebViewPlugin::didReceiveData(const char* data, int data_length) {
+void WebViewPlugin::DidReceiveData(const char* data, int data_length) {
data_.push_back(std::string(data, data_length));
}
-void WebViewPlugin::didFinishLoading() {
+void WebViewPlugin::DidFinishLoading() {
DCHECK(!finished_loading_);
finished_loading_ = true;
}
-void WebViewPlugin::didFailLoading(const WebURLError& error) {
+void WebViewPlugin::DidFailLoading(const WebURLError& error) {
DCHECK(!error_.get());
error_.reset(new WebURLError(error));
}
@@ -248,58 +250,69 @@ void WebViewPlugin::didFailLoading(const WebURLError& error) {
WebViewPlugin::WebViewHelper::WebViewHelper(
WebViewPlugin* plugin,
const WebPreferences& preferences) : plugin_(plugin) {
- web_view_ =
- WebView::create(this, blink::WebPageVisibilityStateVisible);
+ web_view_ = WebView::Create(this, blink::kWebPageVisibilityStateVisible);
// ApplyWebPreferences before making a WebLocalFrame so that the frame sees a
// consistent view of our preferences.
content::RenderView::ApplyWebPreferences(preferences, web_view_);
- WebLocalFrame* web_frame = WebLocalFrame::create(
- blink::WebTreeScopeType::Document, this, nullptr, nullptr);
- web_view_->setMainFrame(web_frame);
+ WebLocalFrame* web_frame = WebLocalFrame::Create(
+ blink::WebTreeScopeType::kDocument, this, nullptr, nullptr);
+ web_view_->SetMainFrame(web_frame);
// TODO(dcheng): The main frame widget currently has a special case.
// Eliminate this once WebView is no longer a WebWidget.
- WebFrameWidget::create(this, web_view_, web_frame);
+ WebFrameWidget::Create(this, web_view_, web_frame);
}
WebViewPlugin::WebViewHelper::~WebViewHelper() {
- web_view_->close();
+ web_view_->Close();
+}
+
+bool WebViewPlugin::WebViewHelper::AcceptsLoadDrops() {
+ return false;
+}
+
+bool WebViewPlugin::WebViewHelper::CanHandleGestureEvent() {
+ return true;
}
-bool WebViewPlugin::WebViewHelper::acceptsLoadDrops() { return false; }
+bool WebViewPlugin::WebViewHelper::CanUpdateLayout() {
+ return true;
+}
-void WebViewPlugin::WebViewHelper::setToolTipText(
+void WebViewPlugin::WebViewHelper::SetToolTipText(
const WebString& text,
blink::WebTextDirection hint) {
if (plugin_->container_)
- plugin_->container_->element().setAttribute("title", text);
+ plugin_->container_->GetElement().SetAttribute("title", text);
}
-void WebViewPlugin::WebViewHelper::startDragging(blink::WebReferrerPolicy,
+void WebViewPlugin::WebViewHelper::StartDragging(blink::WebReferrerPolicy,
const WebDragData&,
WebDragOperationsMask,
const WebImage&,
const WebPoint&) {
// Immediately stop dragging.
- DCHECK(web_view_->mainFrame()->isWebLocalFrame());
- web_view_->mainFrame()->toWebLocalFrame()->frameWidget()->
- dragSourceSystemDragEnded();
+ DCHECK(web_view_->MainFrame()->IsWebLocalFrame());
+ web_view_->MainFrame()
+ ->ToWebLocalFrame()
+ ->FrameWidget()
+ ->DragSourceSystemDragEnded();
}
-bool WebViewPlugin::WebViewHelper::allowsBrokenNullLayerTreeView() const {
+bool WebViewPlugin::WebViewHelper::AllowsBrokenNullLayerTreeView() const {
return true;
}
-void WebViewPlugin::WebViewHelper::didInvalidateRect(const WebRect& rect) {
+void WebViewPlugin::WebViewHelper::DidInvalidateRect(const WebRect& rect) {
if (plugin_->container_)
- plugin_->container_->invalidateRect(rect);
+ plugin_->container_->InvalidateRect(rect);
}
-void WebViewPlugin::WebViewHelper::didChangeCursor(
+void WebViewPlugin::WebViewHelper::DidChangeCursor(
const WebCursorInfo& cursor) {
plugin_->current_cursor_ = cursor;
}
-void WebViewPlugin::WebViewHelper::scheduleAnimation() {
+void WebViewPlugin::WebViewHelper::ScheduleAnimation() {
// Resizes must be self-contained: any lifecycle updating must
// be triggerd from within the WebView or this WebViewPlugin.
// This is because this WebViewPlugin is contained in another
@@ -311,18 +324,18 @@ void WebViewPlugin::WebViewHelper::scheduleAnimation() {
if (plugin_->container_) {
// This should never happen; see also crbug.com/545039 for context.
DCHECK(!plugin_->is_painting_);
- plugin_->container_->scheduleAnimation();
+ plugin_->container_->ScheduleAnimation();
}
}
-void WebViewPlugin::WebViewHelper::didClearWindowObject(
- WebLocalFrame* frame) {
+void WebViewPlugin::WebViewHelper::DidClearWindowObject(WebLocalFrame* frame) {
+ DCHECK_EQ(frame, web_view_->MainFrame());
if (!plugin_->delegate_)
return;
- v8::Isolate* isolate = blink::mainThreadIsolate();
+ v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
- v8::Local<v8::Context> context = frame->mainWorldScriptContext();
+ v8::Local<v8::Context> context = frame->MainWorldScriptContext();
DCHECK(!context.IsEmpty());
v8::Context::Scope context_scope(context);
@@ -334,8 +347,8 @@ void WebViewPlugin::WebViewHelper::didClearWindowObject(
void WebViewPlugin::OnZoomLevelChanged() {
if (container_) {
- web_view()->setZoomLevel(
- blink::WebView::zoomFactorToZoomLevel(container_->pageZoomFactor()));
+ web_view()->SetZoomLevel(
+ blink::WebView::ZoomFactorToZoomLevel(container_->PageZoomFactor()));
}
}
@@ -351,5 +364,5 @@ void WebViewPlugin::UpdatePluginForNewGeometry(
// 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.
- web_view()->updateAllLifecyclePhases();
+ web_view()->UpdateAllLifecyclePhases();
}
diff --git a/chromium/components/plugins/renderer/webview_plugin.h b/chromium/components/plugins/renderer/webview_plugin.h
index 7f4ad1045a8..16daff31f3a 100644
--- a/chromium/components/plugins/renderer/webview_plugin.h
+++ b/chromium/components/plugins/renderer/webview_plugin.h
@@ -76,35 +76,35 @@ class WebViewPlugin : public blink::WebPlugin,
void ReplayReceivedData(blink::WebPlugin* plugin);
// WebPlugin methods:
- blink::WebPluginContainer* container() const override;
+ blink::WebPluginContainer* Container() const override;
// The WebViewPlugin, by design, never fails to initialize. It's used to
// display placeholders and error messages, so it must never fail.
- bool initialize(blink::WebPluginContainer*) override;
- void destroy() override;
+ bool Initialize(blink::WebPluginContainer*) override;
+ void Destroy() override;
- v8::Local<v8::Object> v8ScriptableObject(v8::Isolate* isolate) override;
+ v8::Local<v8::Object> V8ScriptableObject(v8::Isolate* isolate) override;
- void updateAllLifecyclePhases() override;
- void paint(blink::WebCanvas* canvas, const blink::WebRect& rect) override;
+ void UpdateAllLifecyclePhases() override;
+ void Paint(blink::WebCanvas* canvas, const blink::WebRect& rect) override;
// Coordinates are relative to the containing window.
- void updateGeometry(const blink::WebRect& window_rect,
+ void UpdateGeometry(const blink::WebRect& window_rect,
const blink::WebRect& clip_rect,
const blink::WebRect& unobscured_rect,
const blink::WebVector<blink::WebRect>& cut_outs_rects,
bool is_visible) override;
- void updateFocus(bool foucsed, blink::WebFocusType focus_type) override;
- void updateVisibility(bool) override {}
+ void UpdateFocus(bool foucsed, blink::WebFocusType focus_type) override;
+ void UpdateVisibility(bool) override {}
- blink::WebInputEventResult handleInputEvent(
+ blink::WebInputEventResult HandleInputEvent(
const blink::WebInputEvent& event,
blink::WebCursorInfo& cursor_info) override;
- void didReceiveResponse(const blink::WebURLResponse& response) override;
- void didReceiveData(const char* data, int data_length) override;
- void didFinishLoading() override;
- void didFailLoading(const blink::WebURLError& error) override;
+ void DidReceiveResponse(const blink::WebURLResponse& response) override;
+ void DidReceiveData(const char* data, int data_length) override;
+ void DidFinishLoading() override;
+ void DidFailLoading(const blink::WebURLError& error) override;
private:
friend class base::DeleteHelper<WebViewPlugin>;
@@ -150,25 +150,27 @@ class WebViewPlugin : public blink::WebPlugin,
blink::WebView* web_view() { return web_view_; }
// WebViewClient methods:
- bool acceptsLoadDrops() override;
+ bool AcceptsLoadDrops() override;
+ bool CanHandleGestureEvent() override;
+ bool CanUpdateLayout() override;
// WebWidgetClient methods:
- void setToolTipText(const blink::WebString&,
+ void SetToolTipText(const blink::WebString&,
blink::WebTextDirection) override;
- void startDragging(blink::WebReferrerPolicy,
+ void StartDragging(blink::WebReferrerPolicy,
const blink::WebDragData&,
blink::WebDragOperationsMask,
const blink::WebImage&,
const blink::WebPoint&) override;
// TODO(ojan): Remove this override and have this class use a non-null
// layerTreeView.
- bool allowsBrokenNullLayerTreeView() const override;
- void didInvalidateRect(const blink::WebRect&) override;
- void didChangeCursor(const blink::WebCursorInfo& cursor) override;
- void scheduleAnimation() override;
+ bool AllowsBrokenNullLayerTreeView() const override;
+ void DidInvalidateRect(const blink::WebRect&) override;
+ void DidChangeCursor(const blink::WebCursorInfo& cursor) override;
+ void ScheduleAnimation() override;
// WebFrameClient methods:
- void didClearWindowObject(blink::WebLocalFrame* frame) override;
+ void DidClearWindowObject(blink::WebLocalFrame* frame) override;
private:
WebViewPlugin* plugin_;
diff --git a/chromium/components/policy/BUILD.gn b/chromium/components/policy/BUILD.gn
index e4c423ac4e2..3e00ac2bf7b 100644
--- a/chromium/components/policy/BUILD.gn
+++ b/chromium/components/policy/BUILD.gn
@@ -50,6 +50,9 @@ config("component_implementation") {
# for policies of the same type, so that less classes have to be generated
# and compiled.
cloud_policy_proto_path = "$target_gen_dir/proto/cloud_policy.proto"
+
+# This file is used by tools/traffic_annotation/traffic_annotation.proto as it
+# needs a version without LITE_RUNTIME optimization.
cloud_policy_full_runtime_proto_path =
"$target_gen_dir/proto/cloud_policy_full_runtime.proto"
@@ -57,6 +60,11 @@ cloud_policy_full_runtime_proto_path =
# policy. It is also the format currently used by the server.
chrome_settings_proto_path = "$target_gen_dir/proto/chrome_settings.proto"
+# This file is used by tools/traffic_annotation/traffic_annotation.proto as it
+# needs a version without LITE_RUNTIME optimization.
+chrome_settings_full_runtime_proto_path =
+ "$target_gen_dir/proto/chrome_settings_full_runtime.proto"
+
constants_header_path = "$target_gen_dir/policy_constants.h"
constants_source_path = "$target_gen_dir/policy_constants.cc"
protobuf_decoder_path = "$target_gen_dir/cloud_policy_generated.cc"
@@ -113,7 +121,7 @@ action("cloud_policy_code_generate") {
]
}
-action("cloud_policy_full_runtime_code_generate") {
+action("full_runtime_code_generate") {
script = "tools/generate_policy_source.py"
chrome_version_abspath = "//chrome/VERSION"
chrome_version_path = rebase_path(chrome_version_abspath, root_build_dir)
@@ -130,11 +138,14 @@ action("cloud_policy_full_runtime_code_generate") {
]
outputs = [
cloud_policy_full_runtime_proto_path,
+ chrome_settings_full_runtime_proto_path,
]
args = [
"--cloud-policy-full-runtime-protobuf=" +
rebase_path(cloud_policy_full_runtime_proto_path, root_build_dir),
+ "--chrome-settings-full-runtime-protobuf=" +
+ rebase_path(chrome_settings_full_runtime_proto_path, root_build_dir),
chrome_version_path,
target_os,
chromeos_flag,
@@ -146,7 +157,6 @@ policy_templates_grd_file = "resources/policy_templates.grd"
grit("grit_policy_templates") {
source = policy_templates_grd_file
- use_qualified_include = true
output_dir = "$root_gen_dir/chrome"
outputs = []
defines = []
diff --git a/chromium/components/precache/content/precache_manager.cc b/chromium/components/precache/content/precache_manager.cc
index 7732807e8f8..e758a4bbbcc 100644
--- a/chromium/components/precache/content/precache_manager.cc
+++ b/chromium/components/precache/content/precache_manager.cc
@@ -21,6 +21,7 @@
#include "components/history/core/browser/history_service.h"
#include "components/precache/core/precache_database.h"
#include "components/precache/core/precache_switches.h"
+#include "components/precache/core/proto/precache.pb.h"
#include "components/precache/core/proto/unfinished_work.pb.h"
#include "components/prefs/pref_service.h"
#include "components/sync/driver/sync_service.h"
@@ -62,12 +63,14 @@ PrecacheManager::PrecacheManager(
const history::HistoryService* const history_service,
const data_reduction_proxy::DataReductionProxySettings*
data_reduction_proxy_settings,
+ Delegate* delegate,
const base::FilePath& db_path,
std::unique_ptr<PrecacheDatabase> precache_database)
: browser_context_(browser_context),
sync_service_(sync_service),
history_service_(history_service),
data_reduction_proxy_settings_(data_reduction_proxy_settings),
+ delegate_(delegate),
is_precaching_(false) {
precache_database_ = std::move(precache_database);
BrowserThread::PostTask(
@@ -352,7 +355,6 @@ bool PrecacheManager::IsPrecaching() const {
void PrecacheManager::UpdatePrecacheMetricsAndState(
const GURL& url,
const GURL& referrer,
- const base::TimeDelta& latency,
const base::Time& fetch_time,
const net::HttpResponseInfo& info,
int64_t size,
@@ -365,8 +367,7 @@ void PrecacheManager::UpdatePrecacheMetricsAndState(
base::Bind(&PrecacheDatabase::GetLastPrecacheTimestamp,
base::Unretained(precache_database_.get())),
base::Bind(&PrecacheManager::RecordStatsForFetch, AsWeakPtr(), url,
- referrer, latency, fetch_time, info, size,
- register_synthetic_trial));
+ referrer, fetch_time, info, size, register_synthetic_trial));
if (is_user_traffic && IsPrecaching())
CancelPrecaching();
@@ -375,7 +376,6 @@ void PrecacheManager::UpdatePrecacheMetricsAndState(
void PrecacheManager::RecordStatsForFetch(
const GURL& url,
const GURL& referrer,
- const base::TimeDelta& latency,
const base::Time& fetch_time,
const net::HttpResponseInfo& info,
int64_t size,
@@ -396,13 +396,12 @@ void PrecacheManager::RecordStatsForFetch(
history_service_->HostRankIfAvailable(
referrer,
base::Bind(&PrecacheManager::RecordStatsForFetchInternal, AsWeakPtr(),
- url, referrer.host(), latency, fetch_time, info, size));
+ url, referrer.host(), fetch_time, info, size));
}
void PrecacheManager::RecordStatsForFetchInternal(
const GURL& url,
const std::string& referrer_host,
- const base::TimeDelta& latency,
const base::Time& fetch_time,
const net::HttpResponseInfo& info,
int64_t size,
@@ -416,7 +415,7 @@ void PrecacheManager::RecordStatsForFetchInternal(
BrowserThread::PostTask(
BrowserThread::DB, FROM_HERE,
base::Bind(&PrecacheDatabase::RecordURLPrefetchMetrics,
- base::Unretained(precache_database_.get()), info, latency));
+ base::Unretained(precache_database_.get()), info));
} else {
bool is_connection_cellular =
net::NetworkChangeNotifier::IsConnectionCellular(
@@ -425,8 +424,8 @@ void PrecacheManager::RecordStatsForFetchInternal(
BrowserThread::PostTask(
BrowserThread::DB, FROM_HERE,
base::Bind(&PrecacheDatabase::RecordURLNonPrefetch,
- base::Unretained(precache_database_.get()), url, latency,
- fetch_time, info, size, host_rank, is_connection_cellular));
+ base::Unretained(precache_database_.get()), url, fetch_time,
+ info, size, host_rank, is_connection_cellular));
}
}
@@ -460,6 +459,13 @@ void PrecacheManager::OnDone() {
is_precaching_ = false;
}
+void PrecacheManager::OnManifestFetched(const std::string& host,
+ const PrecacheManifest& manifest) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (delegate_)
+ delegate_->OnManifestFetched(host, manifest);
+}
+
void PrecacheManager::OnHostsReceived(
const history::TopHostsList& host_counts) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/chromium/components/precache/content/precache_manager.h b/chromium/components/precache/content/precache_manager.h
index d4bff9e9f66..3f678e9fcab 100644
--- a/chromium/components/precache/content/precache_manager.h
+++ b/chromium/components/precache/content/precache_manager.h
@@ -29,7 +29,6 @@
namespace base {
class FilePath;
class Time;
-class TimeDelta;
}
namespace content {
@@ -56,6 +55,7 @@ namespace precache {
class PrecacheDatabase;
class PrecacheUnfinishedWork;
+class PrecacheManifest;
extern const char kPrecacheFieldTrialName[];
@@ -74,6 +74,13 @@ class PrecacheManager : public KeyedService,
public PrecacheFetcher::PrecacheDelegate,
public base::SupportsWeakPtr<PrecacheManager> {
public:
+ class Delegate {
+ public:
+ // Called when a precache manifest has been successfully fetched and parsed.
+ virtual void OnManifestFetched(const std::string& host,
+ const PrecacheManifest& manifest) = 0;
+ };
+
typedef base::Callback<void(bool)> PrecacheCompletionCallback;
PrecacheManager(content::BrowserContext* browser_context,
@@ -81,6 +88,7 @@ class PrecacheManager : public KeyedService,
const history::HistoryService* history_service,
const data_reduction_proxy::DataReductionProxySettings*
data_reduction_proxy_settings,
+ Delegate* delegate,
const base::FilePath& db_path,
std::unique_ptr<PrecacheDatabase> precache_database);
~PrecacheManager() override;
@@ -123,7 +131,6 @@ class PrecacheManager : public KeyedService,
void UpdatePrecacheMetricsAndState(
const GURL& url,
const GURL& referrer,
- const base::TimeDelta& latency,
const base::Time& fetch_time,
const net::HttpResponseInfo& info,
int64_t size,
@@ -155,6 +162,8 @@ class PrecacheManager : public KeyedService,
// From PrecacheFetcher::PrecacheDelegate.
void OnDone() override;
+ void OnManifestFetched(const std::string& host,
+ const PrecacheManifest& manifest) override;
// Registers the precache synthetic field trial for users whom the precache
// task was run recently. |last_precache_time| is the last time precache task
@@ -190,7 +199,6 @@ class PrecacheManager : public KeyedService,
void RecordStatsForFetch(
const GURL& url,
const GURL& referrer,
- const base::TimeDelta& latency,
const base::Time& fetch_time,
const net::HttpResponseInfo& info,
int64_t size,
@@ -201,7 +209,6 @@ class PrecacheManager : public KeyedService,
// by RecordStatsForFetch() by way of an asynchronous HistoryService callback.
void RecordStatsForFetchInternal(const GURL& url,
const std::string& referrer_host,
- const base::TimeDelta& latency,
const base::Time& fetch_time,
const net::HttpResponseInfo& info,
int64_t size,
@@ -223,6 +230,10 @@ class PrecacheManager : public KeyedService,
const data_reduction_proxy::DataReductionProxySettings* const
data_reduction_proxy_settings_;
+ // The Delegate corresponding to the browser context. Used to notify the
+ // browser about a new available manifest. May be null.
+ Delegate* delegate_;
+
// The PrecacheFetcher used to precache resources. Should only be used on the
// UI thread.
std::unique_ptr<PrecacheFetcher> precache_fetcher_;
diff --git a/chromium/components/precache/content/precache_manager_unittest.cc b/chromium/components/precache/content/precache_manager_unittest.cc
index 8fdbe6b9d10..4c3981260a8 100644
--- a/chromium/components/precache/content/precache_manager_unittest.cc
+++ b/chromium/components/precache/content/precache_manager_unittest.cc
@@ -107,6 +107,12 @@ class MockHistoryService : public history::HistoryService {
const base::Callback<void(int)>& callback));
};
+class MockPrecacheManagerDelegate : public PrecacheManager::Delegate {
+ public:
+ MOCK_METHOD2(OnManifestFetched,
+ void(const std::string& host, const PrecacheManifest& manifest));
+};
+
ACTION_P(ReturnHosts, starting_hosts) {
arg1.Run(starting_hosts);
}
@@ -138,12 +144,14 @@ class PrecacheManagerUnderTest : public PrecacheManager {
const history::HistoryService* history_service,
const data_reduction_proxy::DataReductionProxySettings*
data_reduction_proxy_settings,
+ Delegate* delegate_,
const base::FilePath& db_path,
std::unique_ptr<PrecacheDatabase> precache_database)
: PrecacheManager(browser_context,
sync_service,
history_service,
data_reduction_proxy_settings,
+ delegate_,
db_path,
std::move(precache_database)),
control_group_(false) {}
@@ -202,7 +210,8 @@ class PrecacheManagerTest : public testing::Test {
base::FilePath(FILE_PATH_LITERAL("precache_database")));
precache_manager_.reset(new PrecacheManagerUnderTest(
&browser_context_, nullptr /* sync_service */, &history_service_,
- nullptr /* data_reduction_proxy_settings */, db_path,
+ nullptr /* data_reduction_proxy_settings */,
+ &precache_manager_delegate_, db_path,
base::WrapUnique(precache_database)));
}
@@ -210,13 +219,12 @@ class PrecacheManagerTest : public testing::Test {
void RecordStatsForFetch(const GURL& url,
const std::string& referrer_host,
- const base::TimeDelta& latency,
const base::Time& fetch_time,
const net::HttpResponseInfo& info,
int64_t size,
base::Time last_precache_time) {
precache_manager_->RecordStatsForFetch(
- url, GURL(referrer_host), latency, fetch_time, info, size,
+ url, GURL(referrer_host), fetch_time, info, size,
base::Bind(&PrecacheManagerTest::RegisterSyntheticFieldTrial,
base::Unretained(this)),
last_precache_time);
@@ -224,12 +232,11 @@ class PrecacheManagerTest : public testing::Test {
void RecordStatsForPrecacheFetch(const GURL& url,
const std::string& referrer_host,
- const base::TimeDelta& latency,
const base::Time& fetch_time,
const net::HttpResponseInfo& info,
int64_t size,
base::Time last_precache_time) {
- RecordStatsForFetch(url, referrer_host, latency, fetch_time, info, size,
+ RecordStatsForFetch(url, referrer_host, fetch_time, info, size,
last_precache_time);
precache_database_->RecordURLPrefetch(url, referrer_host, fetch_time,
info.was_cached, size);
@@ -248,6 +255,7 @@ class PrecacheManagerTest : public testing::Test {
net::FakeURLFetcherFactory factory_;
TestPrecacheCompletionCallback precache_callback_;
testing::NiceMock<MockHistoryService> history_service_;
+ testing::NiceMock<MockPrecacheManagerDelegate> precache_manager_delegate_;
base::HistogramTester histograms_;
net::HttpResponseInfo info_;
variations::testing::VariationParamsManager variation_params_;
@@ -477,28 +485,25 @@ TEST_F(PrecacheManagerTest, StartAndCancelPrecachingAfterURLsReceived) {
// PrecacheUtil::UpdatePrecacheMetricsAndState() for more test coverage.
TEST_F(PrecacheManagerTest, RecordStatsForFetchWithSizeZero) {
// Fetches with size 0 should be ignored.
- RecordStatsForPrecacheFetch(GURL("http://url.com"), "", base::TimeDelta(),
- base::Time(), info_, 0, base::Time());
+ RecordStatsForPrecacheFetch(GURL("http://url.com"), "", base::Time(), info_,
+ 0, base::Time());
base::RunLoop().RunUntilIdle();
- histograms_.ExpectTotalCount("Precache.Latency.Prefetch", 0);
histograms_.ExpectTotalCount("Precache.Freshness.Prefetch", 0);
}
TEST_F(PrecacheManagerTest, RecordStatsForFetchWithNonHTTP) {
// Fetches for URLs with schemes other than HTTP or HTTPS should be ignored.
- RecordStatsForPrecacheFetch(GURL("ftp://ftp.com"), "", base::TimeDelta(),
- base::Time(), info_, 1000, base::Time());
+ RecordStatsForPrecacheFetch(GURL("ftp://ftp.com"), "", base::Time(), info_,
+ 1000, base::Time());
base::RunLoop().RunUntilIdle();
- histograms_.ExpectTotalCount("Precache.Latency.Prefetch", 0);
histograms_.ExpectTotalCount("Precache.Freshness.Prefetch", 0);
}
TEST_F(PrecacheManagerTest, RecordStatsForFetchWithEmptyURL) {
// Fetches for empty URLs should be ignored.
- RecordStatsForPrecacheFetch(GURL(), "", base::TimeDelta(), base::Time(),
- info_, 1000, base::Time());
+ RecordStatsForPrecacheFetch(GURL(), "", base::Time(), info_, 1000,
+ base::Time());
base::RunLoop().RunUntilIdle();
- histograms_.ExpectTotalCount("Precache.Latency.Prefetch", 0);
histograms_.ExpectTotalCount("Precache.Freshness.Prefetch", 0);
}
@@ -510,8 +515,7 @@ TEST_F(PrecacheManagerTest, RecordStatsForFetchDuringPrecaching) {
EXPECT_TRUE(precache_manager_->IsPrecaching());
RecordStatsForPrecacheFetch(GURL("http://url.com"), std::string(),
- base::TimeDelta(), base::Time(), info_, 1000,
- base::Time());
+ base::Time(), info_, 1000, base::Time());
base::RunLoop().RunUntilIdle();
precache_manager_->CancelPrecaching();
@@ -526,7 +530,6 @@ TEST_F(PrecacheManagerTest, RecordStatsForFetchDuringPrecaching) {
Pair("Precache.Fetch.ResponseBytes.Network", 1),
Pair("Precache.Fetch.ResponseBytes.Total", 1),
Pair("Precache.Fetch.TimeToComplete", 1),
- Pair("Precache.Latency.Prefetch", 1),
Pair("Precache.Freshness.Prefetch", 1)));
}
@@ -541,36 +544,34 @@ TEST_F(PrecacheManagerTest, RegistersSyntheticFieldTrial) {
EXPECT_TRUE(precache_manager_->IsPrecaching());
RecordStatsForPrecacheFetch(GURL("http://url.com"), std::string(),
- base::TimeDelta(), base::Time(), info_, 1000,
+ base::Time(), info_, 1000,
now /* last_precache_time */);
base::RunLoop().RunUntilIdle();
precache_manager_->CancelPrecaching();
}
TEST_F(PrecacheManagerTest, RecordStatsForFetchHTTP) {
- RecordStatsForFetch(GURL("http://http-url.com"), "", base::TimeDelta(),
- base::Time(), info_, 1000, base::Time());
+ RecordStatsForFetch(GURL("http://http-url.com"), "", base::Time(), info_,
+ 1000, base::Time());
base::RunLoop().RunUntilIdle();
EXPECT_THAT(histograms_.GetTotalCountsForPrefix("Precache."),
UnorderedElementsAre(
Pair("Precache.DownloadedNonPrecache", 1),
Pair("Precache.CacheStatus.NonPrefetch", 1),
- Pair("Precache.Latency.NonPrefetch", 1),
- Pair("Precache.Latency.NonPrefetch.NonTopHosts", 1)));
+ Pair("Precache.CacheStatus.NonPrefetch.NonTopHosts", 1)));
}
TEST_F(PrecacheManagerTest, RecordStatsForFetchHTTPS) {
- RecordStatsForFetch(GURL("https://https-url.com"), "", base::TimeDelta(),
- base::Time(), info_, 1000, base::Time());
+ RecordStatsForFetch(GURL("https://https-url.com"), "", base::Time(), info_,
+ 1000, base::Time());
base::RunLoop().RunUntilIdle();
EXPECT_THAT(histograms_.GetTotalCountsForPrefix("Precache."),
UnorderedElementsAre(
Pair("Precache.DownloadedNonPrecache", 1),
Pair("Precache.CacheStatus.NonPrefetch", 1),
- Pair("Precache.Latency.NonPrefetch", 1),
- Pair("Precache.Latency.NonPrefetch.NonTopHosts", 1)));
+ Pair("Precache.CacheStatus.NonPrefetch.NonTopHosts", 1)));
}
TEST_F(PrecacheManagerTest, RecordStatsForFetchInTopHosts) {
@@ -581,16 +582,14 @@ TEST_F(PrecacheManagerTest, RecordStatsForFetchInTopHosts) {
callback.Run(0);
}));
RecordStatsForFetch(GURL("http://http-url.com"), "http://referrer.com",
- base::TimeDelta(), base::Time(), info_, 1000,
- base::Time());
+ base::Time(), info_, 1000, base::Time());
base::RunLoop().RunUntilIdle();
- EXPECT_THAT(
- histograms_.GetTotalCountsForPrefix("Precache."),
- UnorderedElementsAre(Pair("Precache.DownloadedNonPrecache", 1),
- Pair("Precache.CacheStatus.NonPrefetch", 1),
- Pair("Precache.Latency.NonPrefetch", 1),
- Pair("Precache.Latency.NonPrefetch.TopHosts", 1)));
+ EXPECT_THAT(histograms_.GetTotalCountsForPrefix("Precache."),
+ UnorderedElementsAre(
+ Pair("Precache.DownloadedNonPrecache", 1),
+ Pair("Precache.CacheStatus.NonPrefetch", 1),
+ Pair("Precache.CacheStatus.NonPrefetch.TopHosts", 1)));
}
TEST_F(PrecacheManagerTest, DeleteExpiredPrecacheHistory) {
@@ -607,15 +606,15 @@ TEST_F(PrecacheManagerTest, DeleteExpiredPrecacheHistory) {
EXPECT_TRUE(precache_manager_->IsPrecaching());
// Precache a bunch of URLs, with different fetch times.
- RecordStatsForPrecacheFetch(
- GURL("http://old-fetch.com"), std::string(), base::TimeDelta(),
- kCurrentTime - base::TimeDelta::FromDays(61), info_, 1000, base::Time());
- RecordStatsForPrecacheFetch(
- GURL("http://recent-fetch.com"), std::string(), base::TimeDelta(),
- kCurrentTime - base::TimeDelta::FromDays(59), info_, 1000, base::Time());
- RecordStatsForPrecacheFetch(
- GURL("http://yesterday-fetch.com"), std::string(), base::TimeDelta(),
- kCurrentTime - base::TimeDelta::FromDays(1), info_, 1000, base::Time());
+ RecordStatsForPrecacheFetch(GURL("http://old-fetch.com"), std::string(),
+ kCurrentTime - base::TimeDelta::FromDays(61),
+ info_, 1000, base::Time());
+ RecordStatsForPrecacheFetch(GURL("http://recent-fetch.com"), std::string(),
+ kCurrentTime - base::TimeDelta::FromDays(59),
+ info_, 1000, base::Time());
+ RecordStatsForPrecacheFetch(GURL("http://yesterday-fetch.com"), std::string(),
+ kCurrentTime - base::TimeDelta::FromDays(1),
+ info_, 1000, base::Time());
expected_histogram_count_map["Precache.CacheStatus.Prefetch"] += 3;
expected_histogram_count_map["Precache.CacheSize.AllEntries"]++;
expected_histogram_count_map["Precache.DownloadedPrecacheMotivated"] += 3;
@@ -623,7 +622,6 @@ TEST_F(PrecacheManagerTest, DeleteExpiredPrecacheHistory) {
expected_histogram_count_map["Precache.Fetch.ResponseBytes.Network"]++;
expected_histogram_count_map["Precache.Fetch.ResponseBytes.Total"]++;
expected_histogram_count_map["Precache.Fetch.TimeToComplete"]++;
- expected_histogram_count_map["Precache.Latency.Prefetch"] += 3;
expected_histogram_count_map["Precache.Freshness.Prefetch"] += 3;
base::RunLoop().RunUntilIdle();
@@ -659,12 +657,12 @@ TEST_F(PrecacheManagerTest, DeleteExpiredPrecacheHistory) {
// but it isn't reported as saved bytes because it had expired in the precache
// history.
info_.was_cached = true; // From now on all fetches are cached.
- RecordStatsForFetch(GURL("http://old-fetch.com"), "", base::TimeDelta(),
- kCurrentTime, info_, 1000, base::Time());
+ RecordStatsForFetch(GURL("http://old-fetch.com"), "", kCurrentTime, info_,
+ 1000, base::Time());
expected_histogram_count_map["Precache.Fetch.TimeToComplete"]++;
expected_histogram_count_map["Precache.CacheStatus.NonPrefetch"]++;
- expected_histogram_count_map["Precache.Latency.NonPrefetch"]++;
- expected_histogram_count_map["Precache.Latency.NonPrefetch.NonTopHosts"]++;
+ expected_histogram_count_map
+ ["Precache.CacheStatus.NonPrefetch.NonTopHosts"]++;
expected_histogram_count_map["Precache.TimeSinceLastPrecache"] += 1;
base::RunLoop().RunUntilIdle();
@@ -673,15 +671,15 @@ TEST_F(PrecacheManagerTest, DeleteExpiredPrecacheHistory) {
// The other precaches should not have expired, so the following fetches from
// the cache should count as saved bytes.
- RecordStatsForFetch(GURL("http://recent-fetch.com"), "", base::TimeDelta(),
- kCurrentTime, info_, 1000, base::Time());
- RecordStatsForFetch(GURL("http://yesterday-fetch.com"), "", base::TimeDelta(),
- kCurrentTime, info_, 1000, base::Time());
+ RecordStatsForFetch(GURL("http://recent-fetch.com"), "", kCurrentTime, info_,
+ 1000, base::Time());
+ RecordStatsForFetch(GURL("http://yesterday-fetch.com"), "", kCurrentTime,
+ info_, 1000, base::Time());
expected_histogram_count_map["Precache.CacheStatus.NonPrefetch"] += 2;
expected_histogram_count_map
["Precache.CacheStatus.NonPrefetch.FromPrecache"] += 2;
- expected_histogram_count_map["Precache.Latency.NonPrefetch"] += 2;
- expected_histogram_count_map["Precache.Latency.NonPrefetch.NonTopHosts"] += 2;
+ expected_histogram_count_map
+ ["Precache.CacheStatus.NonPrefetch.NonTopHosts"] += 2;
expected_histogram_count_map["Precache.Saved"] += 2;
expected_histogram_count_map["Precache.TimeSinceLastPrecache"] += 2;
expected_histogram_count_map["Precache.Saved.Freshness"] = 2;
diff --git a/chromium/components/precache/core/BUILD.gn b/chromium/components/precache/core/BUILD.gn
index 92f29ac11fe..00bde867301 100644
--- a/chromium/components/precache/core/BUILD.gn
+++ b/chromium/components/precache/core/BUILD.gn
@@ -25,6 +25,8 @@ static_library("core") {
"precache_database.h",
"precache_fetcher.cc",
"precache_fetcher.h",
+ "precache_manifest_util.cc",
+ "precache_manifest_util.h",
"precache_referrer_host_table.cc",
"precache_referrer_host_table.h",
"precache_session_table.cc",
diff --git a/chromium/components/precache/core/precache_database.cc b/chromium/components/precache/core/precache_database.cc
index c10c183db66..f30d8cb9bea 100644
--- a/chromium/components/precache/core/precache_database.cc
+++ b/chromium/components/precache/core/precache_database.cc
@@ -148,11 +148,9 @@ void PrecacheDatabase::GetURLListForReferrerHost(
}
void PrecacheDatabase::RecordURLPrefetchMetrics(
- const net::HttpResponseInfo& info,
- const base::TimeDelta& latency) {
+ const net::HttpResponseInfo& info) {
DCHECK(thread_checker_.CalledOnValidThread());
- UMA_HISTOGRAM_TIMES("Precache.Latency.Prefetch", latency);
UMA_HISTOGRAM_ENUMERATION("Precache.CacheStatus.Prefetch",
info.cache_entry_status,
net::HttpResponseInfo::CacheEntryStatus::ENTRY_MAX);
@@ -233,13 +231,11 @@ void PrecacheDatabase::RecordURLPrefetchInternal(
}
void PrecacheDatabase::RecordURLNonPrefetch(const GURL& url,
- const base::TimeDelta& latency,
const base::Time& fetch_time,
const net::HttpResponseInfo& info,
int64_t size,
int host_rank,
bool is_connection_cellular) {
- UMA_HISTOGRAM_TIMES("Precache.Latency.NonPrefetch", latency);
UMA_HISTOGRAM_ENUMERATION("Precache.CacheStatus.NonPrefetch",
info.cache_entry_status,
net::HttpResponseInfo::CacheEntryStatus::ENTRY_MAX);
@@ -247,11 +243,15 @@ void PrecacheDatabase::RecordURLNonPrefetch(const GURL& url,
if (host_rank != history::kMaxTopHosts) {
// The resource was loaded on a page that could have been affected by
// precaching.
- UMA_HISTOGRAM_TIMES("Precache.Latency.NonPrefetch.TopHosts", latency);
+ UMA_HISTOGRAM_ENUMERATION(
+ "Precache.CacheStatus.NonPrefetch.TopHosts", info.cache_entry_status,
+ net::HttpResponseInfo::CacheEntryStatus::ENTRY_MAX);
} else {
// The resource was loaded on a page that could NOT have been affected by
// precaching.
- UMA_HISTOGRAM_TIMES("Precache.Latency.NonPrefetch.NonTopHosts", latency);
+ UMA_HISTOGRAM_ENUMERATION(
+ "Precache.CacheStatus.NonPrefetch.NonTopHosts", info.cache_entry_status,
+ net::HttpResponseInfo::CacheEntryStatus::ENTRY_MAX);
}
if (!IsDatabaseAccessible()) {
diff --git a/chromium/components/precache/core/precache_database.h b/chromium/components/precache/core/precache_database.h
index 984a3754f2d..0597516d7b0 100644
--- a/chromium/components/precache/core/precache_database.h
+++ b/chromium/components/precache/core/precache_database.h
@@ -69,8 +69,7 @@ class PrecacheDatabase {
// Report precache-related metrics in response to a URL being fetched, where
// the fetch was motivated by precaching. This is called from the network
// delegate, via precache_util.
- void RecordURLPrefetchMetrics(const net::HttpResponseInfo& info,
- const base::TimeDelta& latency);
+ void RecordURLPrefetchMetrics(const net::HttpResponseInfo& info);
// Records the precache of an url |url| for top host |referrer_host|. This is
// called from PrecacheFetcher.
@@ -85,7 +84,6 @@ class PrecacheDatabase {
// indicates whether the current network connection is a cellular network.
// This is called from the network delegate, via precache_util.
void RecordURLNonPrefetch(const GURL& url,
- const base::TimeDelta& latency,
const base::Time& fetch_time,
const net::HttpResponseInfo& info,
int64_t size,
diff --git a/chromium/components/precache/core/precache_database_unittest.cc b/chromium/components/precache/core/precache_database_unittest.cc
index 98564d38b23..233c2d0ce66 100644
--- a/chromium/components/precache/core/precache_database_unittest.cc
+++ b/chromium/components/precache/core/precache_database_unittest.cc
@@ -35,7 +35,6 @@ using net::HttpResponseInfo;
const GURL kURL("http://url.com");
const int kReferrerID = 1;
-const base::TimeDelta kLatency = base::TimeDelta::FromMilliseconds(5);
const base::Time kFetchTime = base::Time() + base::TimeDelta::FromHours(1000);
const base::Time kOldFetchTime = kFetchTime - base::TimeDelta::FromDays(1);
const base::Time kNewFetchTime =
@@ -123,23 +122,19 @@ class PrecacheDatabaseTest : public testing::Test {
// Convenience methods for recording different types of URL fetches. These
// exist to improve the readability of the tests.
void RecordPrecacheFromNetwork(const GURL& url,
- base::TimeDelta latency,
const base::Time& fetch_time,
int64_t size);
void RecordPrecacheFromCache(const GURL& url,
const base::Time& fetch_time,
int64_t size);
void RecordFetchFromNetwork(const GURL& url,
- base::TimeDelta latency,
const base::Time& fetch_time,
int64_t size);
void RecordFetchFromNetwork(const GURL& url,
- base::TimeDelta latency,
const base::Time& fetch_time,
int64_t size,
int host_rank);
void RecordFetchFromNetworkCellular(const GURL& url,
- base::TimeDelta latency,
const base::Time& fetch_time,
int64_t size);
void RecordFetchFromCache(const GURL& url,
@@ -174,12 +169,11 @@ class PrecacheDatabaseTest : public testing::Test {
void PrecacheDatabaseTest::RecordPrecacheFromNetwork(
const GURL& url,
- base::TimeDelta latency,
const base::Time& fetch_time,
int64_t size) {
const HttpResponseInfo info = CreateHttpResponseInfo(
false /* was_cached */, false /* network_accessed */);
- precache_database_->RecordURLPrefetchMetrics(info, latency);
+ precache_database_->RecordURLPrefetchMetrics(info);
precache_database_->RecordURLPrefetch(url, std::string(), fetch_time,
info.was_cached, size);
}
@@ -189,43 +183,39 @@ void PrecacheDatabaseTest::RecordPrecacheFromCache(const GURL& url,
int64_t size) {
const HttpResponseInfo info = CreateHttpResponseInfo(
true /* was_cached */, false /* network_accessed */);
- precache_database_->RecordURLPrefetchMetrics(info,
- base::TimeDelta() /* latency */);
+ precache_database_->RecordURLPrefetchMetrics(info);
precache_database_->RecordURLPrefetch(url, std::string(), fetch_time,
info.was_cached, size);
}
void PrecacheDatabaseTest::RecordFetchFromNetwork(const GURL& url,
- base::TimeDelta latency,
const base::Time& fetch_time,
int64_t size) {
const HttpResponseInfo info = CreateHttpResponseInfo(
false /* was_cached */, false /* network_accessed */);
- precache_database_->RecordURLNonPrefetch(url, latency, fetch_time, info, size,
+ precache_database_->RecordURLNonPrefetch(url, fetch_time, info, size,
history::kMaxTopHosts,
false /* is_connection_cellular */);
}
void PrecacheDatabaseTest::RecordFetchFromNetwork(const GURL& url,
- base::TimeDelta latency,
const base::Time& fetch_time,
int64_t size,
int host_rank) {
const HttpResponseInfo info = CreateHttpResponseInfo(
false /* was_cached */, false /* network_accessed */);
- precache_database_->RecordURLNonPrefetch(url, latency, fetch_time, info, size,
+ precache_database_->RecordURLNonPrefetch(url, fetch_time, info, size,
host_rank,
false /* is_connection_cellular */);
}
void PrecacheDatabaseTest::RecordFetchFromNetworkCellular(
const GURL& url,
- base::TimeDelta latency,
const base::Time& fetch_time,
int64_t size) {
const HttpResponseInfo info = CreateHttpResponseInfo(
false /* was_cached */, false /* network_accessed */);
- precache_database_->RecordURLNonPrefetch(url, latency, fetch_time, info, size,
+ precache_database_->RecordURLNonPrefetch(url, fetch_time, info, size,
history::kMaxTopHosts,
true /* is_connection_cellular */);
}
@@ -235,9 +225,9 @@ void PrecacheDatabaseTest::RecordFetchFromCache(const GURL& url,
int64_t size) {
const HttpResponseInfo info = CreateHttpResponseInfo(
true /* was_cached */, false /* network_accessed */);
- precache_database_->RecordURLNonPrefetch(
- url, base::TimeDelta() /* latency */, fetch_time, info, size,
- history::kMaxTopHosts, false /* is_connection_cellular */);
+ precache_database_->RecordURLNonPrefetch(url, fetch_time, info, size,
+ history::kMaxTopHosts,
+ false /* is_connection_cellular */);
}
void PrecacheDatabaseTest::RecordFetchFromCacheCellular(
@@ -246,20 +236,19 @@ void PrecacheDatabaseTest::RecordFetchFromCacheCellular(
int64_t size) {
const HttpResponseInfo info = CreateHttpResponseInfo(
true /* was_cached */, false /* network_accessed */);
- precache_database_->RecordURLNonPrefetch(
- url, base::TimeDelta() /* latency */, fetch_time, info, size,
- history::kMaxTopHosts, true /* is_connection_cellular */);
+ precache_database_->RecordURLNonPrefetch(url, fetch_time, info, size,
+ history::kMaxTopHosts,
+ true /* is_connection_cellular */);
}
namespace {
TEST_F(PrecacheDatabaseTest, PrecacheOverNetwork) {
- RecordPrecacheFromNetwork(kURL, kLatency, kFetchTime, kSize);
+ RecordPrecacheFromNetwork(kURL, kFetchTime, kSize);
EXPECT_EQ(BuildURLTableMap(kURL, kFetchTime), GetActualURLTableMap());
ExpectNewSample("Precache.DownloadedPrecacheMotivated", kSize);
- ExpectNewSample("Precache.Latency.Prefetch", kLatency.InMilliseconds());
ExpectNewSample("Precache.CacheStatus.Prefetch", kFromNetwork);
ExpectNewSample("Precache.Freshness.Prefetch", kFreshnessBucket10K);
ExpectNoOtherSamples();
@@ -273,7 +262,6 @@ TEST_F(PrecacheDatabaseTest, PrecacheFromCacheWithURLTableEntry) {
// timestamp.
EXPECT_EQ(BuildURLTableMap(kURL, kFetchTime), GetActualURLTableMap());
- ExpectNewSample("Precache.Latency.Prefetch", 0);
ExpectNewSample("Precache.CacheStatus.Prefetch",
net::HttpResponseInfo::ENTRY_USED);
ExpectNewSample("Precache.Freshness.Prefetch", kFreshnessBucket10K);
@@ -285,7 +273,6 @@ TEST_F(PrecacheDatabaseTest, PrecacheFromCacheWithoutURLTableEntry) {
EXPECT_TRUE(GetActualURLTableMap().empty());
- ExpectNewSample("Precache.Latency.Prefetch", 0);
ExpectNewSample("Precache.CacheStatus.Prefetch",
net::HttpResponseInfo::ENTRY_USED);
ExpectNewSample("Precache.Freshness.Prefetch", kFreshnessBucket10K);
@@ -293,59 +280,51 @@ TEST_F(PrecacheDatabaseTest, PrecacheFromCacheWithoutURLTableEntry) {
}
TEST_F(PrecacheDatabaseTest, FetchOverNetwork_NonCellular) {
- RecordFetchFromNetwork(kURL, kLatency, kFetchTime, kSize);
+ RecordFetchFromNetwork(kURL, kFetchTime, kSize);
EXPECT_TRUE(GetActualURLTableMap().empty());
ExpectNewSample("Precache.DownloadedNonPrecache", kSize);
ExpectNewSample("Precache.CacheStatus.NonPrefetch", kFromNetwork);
- ExpectNewSample("Precache.Latency.NonPrefetch", kLatency.InMilliseconds());
- ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts",
- kLatency.InMilliseconds());
+ ExpectNewSample("Precache.CacheStatus.NonPrefetch.NonTopHosts", kFromNetwork);
ExpectNoOtherSamples();
}
TEST_F(PrecacheDatabaseTest, FetchOverNetwork_NonCellular_TopHosts) {
- RecordFetchFromNetwork(kURL, kLatency, kFetchTime, kSize, 0 /* host_rank */);
+ RecordFetchFromNetwork(kURL, kFetchTime, kSize, 0 /* host_rank */);
EXPECT_TRUE(GetActualURLTableMap().empty());
ExpectNewSample("Precache.DownloadedNonPrecache", kSize);
ExpectNewSample("Precache.CacheStatus.NonPrefetch", kFromNetwork);
- ExpectNewSample("Precache.Latency.NonPrefetch", kLatency.InMilliseconds());
- ExpectNewSample("Precache.Latency.NonPrefetch.TopHosts",
- kLatency.InMilliseconds());
+ ExpectNewSample("Precache.CacheStatus.NonPrefetch.TopHosts", kFromNetwork);
ExpectNoOtherSamples();
}
TEST_F(PrecacheDatabaseTest, FetchOverNetwork_Cellular) {
- RecordFetchFromNetworkCellular(kURL, kLatency, kFetchTime, kSize);
+ RecordFetchFromNetworkCellular(kURL, kFetchTime, kSize);
EXPECT_TRUE(GetActualURLTableMap().empty());
ExpectNewSample("Precache.DownloadedNonPrecache", kSize);
ExpectNewSample("Precache.DownloadedNonPrecache.Cellular", kSize);
ExpectNewSample("Precache.CacheStatus.NonPrefetch", kFromNetwork);
- ExpectNewSample("Precache.Latency.NonPrefetch", kLatency.InMilliseconds());
- ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts",
- kLatency.InMilliseconds());
+ ExpectNewSample("Precache.CacheStatus.NonPrefetch.NonTopHosts", kFromNetwork);
ExpectNoOtherSamples();
}
TEST_F(PrecacheDatabaseTest, FetchOverNetworkWithURLTableEntry) {
precache_url_table()->AddURL(kURL, kReferrerID, true, kOldFetchTime, false);
- RecordFetchFromNetwork(kURL, kLatency, kFetchTime, kSize);
+ RecordFetchFromNetwork(kURL, kFetchTime, kSize);
// The URL table entry should have been deleted.
EXPECT_TRUE(GetActualURLTableMap().empty());
ExpectNewSample("Precache.DownloadedNonPrecache", kSize);
- ExpectNewSample("Precache.Latency.NonPrefetch", kLatency.InMilliseconds());
- ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts",
- kLatency.InMilliseconds());
ExpectNewSample("Precache.CacheStatus.NonPrefetch", kFromNetwork);
ExpectNewSample("Precache.CacheStatus.NonPrefetch.FromPrecache",
kFromNetwork);
+ ExpectNewSample("Precache.CacheStatus.NonPrefetch.NonTopHosts", kFromNetwork);
ExpectNoOtherSamples();
}
@@ -356,12 +335,12 @@ TEST_F(PrecacheDatabaseTest, FetchFromCacheWithURLTableEntry_NonCellular) {
// The URL table entry should have been deleted.
EXPECT_TRUE(GetActualURLTableMap().empty());
- ExpectNewSample("Precache.Latency.NonPrefetch", 0);
- ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts", 0);
ExpectNewSample("Precache.CacheStatus.NonPrefetch",
HttpResponseInfo::CacheEntryStatus::ENTRY_USED);
ExpectNewSample("Precache.CacheStatus.NonPrefetch.FromPrecache",
HttpResponseInfo::CacheEntryStatus::ENTRY_USED);
+ ExpectNewSample("Precache.CacheStatus.NonPrefetch.NonTopHosts",
+ HttpResponseInfo::CacheEntryStatus::ENTRY_USED);
ExpectNewSample("Precache.Saved", kSize);
ExpectNewSample("Precache.Saved.Freshness", kFreshnessBucket10K);
ExpectNoOtherSamples();
@@ -374,12 +353,12 @@ TEST_F(PrecacheDatabaseTest, FetchFromCacheWithURLTableEntry_Cellular) {
// The URL table entry should have been deleted.
EXPECT_TRUE(GetActualURLTableMap().empty());
- ExpectNewSample("Precache.Latency.NonPrefetch", 0);
- ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts", 0);
ExpectNewSample("Precache.CacheStatus.NonPrefetch",
HttpResponseInfo::CacheEntryStatus::ENTRY_USED);
ExpectNewSample("Precache.CacheStatus.NonPrefetch.FromPrecache",
HttpResponseInfo::CacheEntryStatus::ENTRY_USED);
+ ExpectNewSample("Precache.CacheStatus.NonPrefetch.NonTopHosts",
+ HttpResponseInfo::CacheEntryStatus::ENTRY_USED);
ExpectNewSample("Precache.Saved", kSize);
ExpectNewSample("Precache.Saved.Cellular", kSize);
ExpectNewSample("Precache.Saved.Freshness", kFreshnessBucket10K);
@@ -391,10 +370,10 @@ TEST_F(PrecacheDatabaseTest, FetchFromCacheWithoutURLTableEntry) {
EXPECT_TRUE(GetActualURLTableMap().empty());
- ExpectNewSample("Precache.Latency.NonPrefetch", 0);
- ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts", 0);
ExpectNewSample("Precache.CacheStatus.NonPrefetch",
HttpResponseInfo::CacheEntryStatus::ENTRY_USED);
+ ExpectNewSample("Precache.CacheStatus.NonPrefetch.NonTopHosts",
+ HttpResponseInfo::CacheEntryStatus::ENTRY_USED);
ExpectNoOtherSamples();
}
@@ -426,24 +405,24 @@ TEST_F(PrecacheDatabaseTest, SampleInteraction) {
const GURL kURL5("http://url5.com");
const int64_t kSize5 = 5;
- RecordPrecacheFromNetwork(kURL1, kLatency, kFetchTime, kSize1);
- RecordPrecacheFromNetwork(kURL2, kLatency, kFetchTime, kSize2);
- RecordPrecacheFromNetwork(kURL3, kLatency, kFetchTime, kSize3);
- RecordPrecacheFromNetwork(kURL4, kLatency, kFetchTime, kSize4);
+ RecordPrecacheFromNetwork(kURL1, kFetchTime, kSize1);
+ RecordPrecacheFromNetwork(kURL2, kFetchTime, kSize2);
+ RecordPrecacheFromNetwork(kURL3, kFetchTime, kSize3);
+ RecordPrecacheFromNetwork(kURL4, kFetchTime, kSize4);
RecordFetchFromCacheCellular(kURL1, kFetchTime, kSize1);
RecordFetchFromCacheCellular(kURL1, kFetchTime, kSize1);
- RecordFetchFromNetworkCellular(kURL2, kLatency, kFetchTime, kSize2);
- RecordFetchFromNetworkCellular(kURL5, kLatency, kFetchTime, kSize5);
+ RecordFetchFromNetworkCellular(kURL2, kFetchTime, kSize2);
+ RecordFetchFromNetworkCellular(kURL5, kFetchTime, kSize5);
RecordFetchFromCacheCellular(kURL5, kFetchTime, kSize5);
RecordPrecacheFromCache(kURL1, kFetchTime, kSize1);
- RecordPrecacheFromNetwork(kURL2, kLatency, kFetchTime, kSize2);
+ RecordPrecacheFromNetwork(kURL2, kFetchTime, kSize2);
RecordPrecacheFromCache(kURL3, kFetchTime, kSize3);
RecordPrecacheFromCache(kURL4, kFetchTime, kSize4);
RecordFetchFromCache(kURL1, kFetchTime, kSize1);
- RecordFetchFromNetwork(kURL2, kLatency, kFetchTime, kSize2);
+ RecordFetchFromNetwork(kURL2, kFetchTime, kSize2);
RecordFetchFromCache(kURL3, kFetchTime, kSize3);
RecordFetchFromCache(kURL5, kFetchTime, kSize5);
@@ -458,11 +437,17 @@ TEST_F(PrecacheDatabaseTest, SampleInteraction) {
histograms_.GetAllSamples("Precache.DownloadedNonPrecache.Cellular"),
ElementsAre(Bucket(kSize2, 1), Bucket(kSize5, 1)));
- EXPECT_THAT(histograms_.GetAllSamples("Precache.Latency.Prefetch"),
- ElementsAre(Bucket(0, 3), Bucket(kLatency.InMilliseconds(), 5)));
+ EXPECT_THAT(
+ histograms_.GetAllSamples("Precache.CacheStatus.Prefetch"),
+ ElementsAre(
+ Bucket(HttpResponseInfo::CacheEntryStatus::ENTRY_USED, 3),
+ Bucket(HttpResponseInfo::CacheEntryStatus::ENTRY_UPDATED, 5)));
- EXPECT_THAT(histograms_.GetAllSamples("Precache.Latency.NonPrefetch"),
- ElementsAre(Bucket(0, 6), Bucket(kLatency.InMilliseconds(), 3)));
+ EXPECT_THAT(
+ histograms_.GetAllSamples("Precache.CacheStatus.NonPrefetch"),
+ ElementsAre(
+ Bucket(HttpResponseInfo::CacheEntryStatus::ENTRY_USED, 6),
+ Bucket(HttpResponseInfo::CacheEntryStatus::ENTRY_UPDATED, 3)));
EXPECT_THAT(histograms_.GetAllSamples("Precache.Saved"),
ElementsAre(Bucket(kSize1, 1), Bucket(kSize3, 1)));
@@ -477,10 +462,10 @@ TEST_F(PrecacheDatabaseTest, LastPrecacheTimestamp) {
base::Time() + base::TimeDelta::FromSeconds(100);
precache_database_->SetLastPrecacheTimestamp(kStartTime);
- RecordPrecacheFromNetwork(kURL, kLatency, kStartTime, kSize);
- RecordPrecacheFromNetwork(kURL, kLatency, kStartTime, kSize);
- RecordPrecacheFromNetwork(kURL, kLatency, kStartTime, kSize);
- RecordPrecacheFromNetwork(kURL, kLatency, kStartTime, kSize);
+ RecordPrecacheFromNetwork(kURL, kStartTime, kSize);
+ RecordPrecacheFromNetwork(kURL, kStartTime, kSize);
+ RecordPrecacheFromNetwork(kURL, kStartTime, kSize);
+ RecordPrecacheFromNetwork(kURL, kStartTime, kSize);
EXPECT_THAT(histograms_.GetAllSamples("Precache.TimeSinceLastPrecache"),
ElementsAre());
@@ -491,8 +476,8 @@ TEST_F(PrecacheDatabaseTest, LastPrecacheTimestamp) {
RecordFetchFromCacheCellular(kURL, kTimeA, kSize);
RecordFetchFromCacheCellular(kURL, kTimeA, kSize);
- RecordFetchFromNetworkCellular(kURL, kLatency, kTimeB, kSize);
- RecordFetchFromNetworkCellular(kURL, kLatency, kTimeB, kSize);
+ RecordFetchFromNetworkCellular(kURL, kTimeB, kSize);
+ RecordFetchFromNetworkCellular(kURL, kTimeB, kSize);
RecordFetchFromCacheCellular(kURL, kTimeB, kSize);
RecordFetchFromCacheCellular(kURL, kTimeC, kSize);
@@ -503,7 +488,7 @@ TEST_F(PrecacheDatabaseTest, LastPrecacheTimestamp) {
TEST_F(PrecacheDatabaseTest, PrecacheFreshnessPrefetch) {
auto info = CreateHttpResponseInfo(false /* was_cached */,
false /* network_accessed */);
- RecordPrecacheFromNetwork(kURL, kLatency, kFetchTime, kSize);
+ RecordPrecacheFromNetwork(kURL, kFetchTime, kSize);
EXPECT_THAT(histograms_.GetAllSamples("Precache.Freshness.Prefetch"),
ElementsAre(Bucket(kFreshnessBucket10K, 1)));
@@ -599,10 +584,9 @@ TEST_F(PrecacheDatabaseTest, GetURLListForReferrerHost) {
} else if (!resource.is_network_fetched && resource.is_cellular_fetched) {
RecordFetchFromCacheCellular(GURL(resource.url), kFetchTime, kSize);
} else if (resource.is_network_fetched && !resource.is_cellular_fetched) {
- RecordFetchFromNetwork(GURL(resource.url), kLatency, kFetchTime, kSize);
+ RecordFetchFromNetwork(GURL(resource.url), kFetchTime, kSize);
} else if (resource.is_network_fetched && resource.is_cellular_fetched) {
- RecordFetchFromNetworkCellular(GURL(resource.url), kLatency, kFetchTime,
- kSize);
+ RecordFetchFromNetworkCellular(GURL(resource.url), kFetchTime, kSize);
}
}
}
diff --git a/chromium/components/precache/core/precache_fetcher.cc b/chromium/components/precache/core/precache_fetcher.cc
index c6ee3914e25..a17c6ea199c 100644
--- a/chromium/components/precache/core/precache_fetcher.cc
+++ b/chromium/components/precache/core/precache_fetcher.cc
@@ -28,6 +28,7 @@
#include "base/task_runner_util.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/precache/core/precache_database.h"
+#include "components/precache/core/precache_manifest_util.h"
#include "components/precache/core/precache_switches.h"
#include "components/precache/core/proto/quota.pb.h"
#include "components/precache/core/proto/unfinished_work.pb.h"
@@ -125,41 +126,6 @@ bool ParseProtoFromFetchResponse(const net::URLFetcher& source,
return true;
}
-// Returns the resource selection bitset from the |manifest| for the given
-// |experiment_id|. If the experiment group is not found, then this returns
-// nullopt, in which case all resources should be selected.
-base::Optional<std::vector<bool>> GetResourceBitset(
- const PrecacheManifest& manifest,
- uint32_t experiment_id) {
- base::Optional<std::vector<bool>> ret;
- if (manifest.has_experiments()) {
- const auto& resource_bitset_map =
- manifest.experiments().resources_by_experiment_group();
- const auto& it = resource_bitset_map.find(experiment_id);
- if (it != resource_bitset_map.end()) {
- if (it->second.has_bitset()) {
- const std::string& bitset = it->second.bitset();
- ret.emplace(bitset.size() * 8);
- for (size_t i = 0; i < bitset.size(); ++i) {
- for (size_t j = 0; j < 8; ++j) {
- if ((1 << j) & bitset[i])
- ret.value()[i * 8 + j] = true;
- }
- }
- } else if (it->second.has_deprecated_bitset()) {
- uint64_t bitset = it->second.deprecated_bitset();
- ret.emplace(64);
- for (int i = 0; i < 64; ++i) {
- if ((0x1ULL << i) & bitset)
- ret.value()[i] = true;
- }
- }
- }
- }
- // Only return one variable to ensure RVO triggers.
- return ret;
-}
-
// URLFetcherResponseWriter that ignores the response body, in order to avoid
// the unnecessary memory usage. Use it rather than the default if you don't
// care about parsing the response body. We use it below as a means to populate
@@ -315,8 +281,40 @@ PrecacheFetcher::Fetcher::~Fetcher() {}
void PrecacheFetcher::Fetcher::LoadFromCache() {
fetch_stage_ = FetchStage::CACHE;
- cache_url_fetcher_ =
- net::URLFetcher::Create(url_, net::URLFetcher::GET, this);
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("wifi_prefetch_from_cache", R"(
+ semantics {
+ sender: "Wifi Prefetch"
+ description:
+ "Speeds up mobile web page loads by downloading some common static "
+ "assets (such as JS and CSS) for sites that the user browses "
+ "frequently, in advance of the browser needing them. Only applies "
+ "to users with tab sync enabled."
+ trigger:
+ "Background service that runs when the device is plugged into "
+ "power, on unmetered wifi, and Chromium is not in the foreground."
+ data:
+ "Local cache fetches; no data is sent over the network."
+ destination: OTHER
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "Users can disable this feature by several settings: Disabling tab "
+ "sync via unchecking 'Open tabs' in Chromium settings under "
+ "'Advanced sync settings'; Disabling predicting required downloads "
+ "via unchecking 'Use a prediction service to load pages more "
+ "quickly' in Chromium settings under Privacy; Enabling 'Data "
+ "Saver' in Chromium settings on Android."
+ chrome_policy {
+ NetworkPredictionOptions {
+ policy_options {mode: MANDATORY}
+ NetworkPredictionOptions: 2
+ }
+ }
+ })");
+ cache_url_fetcher_ = net::URLFetcher::Create(url_, net::URLFetcher::GET, this,
+ traffic_annotation);
data_use_measurement::DataUseUserData::AttachToFetcher(
cache_url_fetcher_.get(),
data_use_measurement::DataUseUserData::PRECACHE);
@@ -331,8 +329,80 @@ void PrecacheFetcher::Fetcher::LoadFromCache() {
void PrecacheFetcher::Fetcher::LoadFromNetwork() {
fetch_stage_ = FetchStage::NETWORK;
- network_url_fetcher_ =
- net::URLFetcher::Create(url_, net::URLFetcher::GET, this);
+ if (is_resource_request_) {
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation(
+ "wifi_prefetch_resource_from_network", R"(
+ semantics {
+ sender: "Wifi Prefetch"
+ description:
+ "Speeds up mobile web page loads by downloading common static "
+ "assets (such as JS and CSS) for sites that the user browses "
+ "frequently, in advance of the browser needing them. Only "
+ "applies to users with tab sync enabled."
+ trigger:
+ "Background service that runs when the device is plugged into "
+ "power, on unmetered wifi, and Chromium is not in the "
+ "foreground."
+ data: "Link to the requested resrouce."
+ destination: WEBSITE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "Users can disable this feature by several settings: Disabling "
+ "tab sync via unchecking 'Open tabs' in Chromium settings "
+ "under 'Advanced sync settings'; Disabling predicting required "
+ "downloads via unchecking 'Use a prediction service to load "
+ "pages more quickly' in Chromium settings under Privacy; "
+ "Enabling 'Data Saver' in Chromium settings on Android."
+ chrome_policy {
+ NetworkPredictionOptions {
+ policy_options {mode: MANDATORY}
+ NetworkPredictionOptions: 2
+ }
+ }
+ })");
+ network_url_fetcher_ = net::URLFetcher::Create(url_, net::URLFetcher::GET,
+ this, traffic_annotation);
+ } else {
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("wifi_prefetch_sites_from_network",
+ R"(
+ semantics {
+ sender: "Wifi Prefetch"
+ description:
+ "Speeds up mobile web page loads by downloading common static "
+ "assets (such as JS and CSS) for sites that the user browses "
+ "frequently, in advance of the browser needing them. The first "
+ "step is to download the list of common static assets from "
+ "Google. Only applies to users with tab sync enabled."
+ trigger:
+ "Background service that runs when the device is plugged into "
+ "power, on unmetered wifi, and Chromium is not in the foreground."
+ data: "A list of the top hosts that the user visits."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "Users can disable this feature by several settings: Disabling "
+ "tab sync via unchecking 'Open tabs' in Chromium settings under "
+ "'Advanced sync settings'; Disabling predicting required "
+ "downloads via unchecking 'Use a prediction service to load "
+ "pages more quickly' in Chromium settings under Privacy; "
+ "Enabling 'Data Saver' in Chromium settings on Android."
+ chrome_policy {
+ NetworkPredictionOptions {
+ policy_options {mode: MANDATORY}
+ NetworkPredictionOptions: 2
+ }
+ }
+ })");
+ network_url_fetcher_ = net::URLFetcher::Create(url_, net::URLFetcher::GET,
+ this, traffic_annotation);
+ }
+
data_use_measurement::DataUseUserData::AttachToFetcher(
network_url_fetcher_.get(),
data_use_measurement::DataUseUserData::PRECACHE);
@@ -778,6 +848,7 @@ void PrecacheFetcher::OnManifestFetchComplete(int64_t host_visits,
PrecacheManifest manifest;
if (ParseProtoFromFetchResponse(*source.network_url_fetcher(), &manifest)) {
+ precache_delegate_->OnManifestFetched(source.referrer(), manifest);
const base::Optional<std::vector<bool>> resource_bitset =
GetResourceBitset(manifest, experiment_id_);
const int32_t included_resources_max =
diff --git a/chromium/components/precache/core/precache_fetcher.h b/chromium/components/precache/core/precache_fetcher.h
index 9868d1c015a..b8c937abb47 100644
--- a/chromium/components/precache/core/precache_fetcher.h
+++ b/chromium/components/precache/core/precache_fetcher.h
@@ -128,6 +128,10 @@ class PrecacheFetcher : public base::SupportsWeakPtr<PrecacheFetcher> {
// were fetched or not. If the PrecacheFetcher is destroyed before OnDone is
// called, then precaching will be canceled and OnDone will not be called.
virtual void OnDone() = 0;
+
+ // Called when a precache manifest has been successfully fetched and parsed.
+ virtual void OnManifestFetched(const std::string& host,
+ const PrecacheManifest& manifest) = 0;
};
// Visible for testing.
diff --git a/chromium/components/precache/core/precache_fetcher_unittest.cc b/chromium/components/precache/core/precache_fetcher_unittest.cc
index 51ea0c17bd9..82cb8024e07 100644
--- a/chromium/components/precache/core/precache_fetcher_unittest.cc
+++ b/chromium/components/precache/core/precache_fetcher_unittest.cc
@@ -117,12 +117,22 @@ class TestPrecacheDelegate : public PrecacheFetcher::PrecacheDelegate {
on_done_was_called_ = true;
}
+ void OnManifestFetched(const std::string& host,
+ const PrecacheManifest& manifest) override {
+ hosts.push_back(host);
+ }
+
bool was_on_done_called() const {
return on_done_was_called_;
}
+ void clear_manifest_hosts() { hosts.clear(); }
+
+ std::vector<std::string> get_manifest_hosts() const { return hosts; }
+
private:
bool on_done_was_called_;
+ std::vector<std::string> hosts;
};
class MockURLFetcherFactory : public net::URLFetcherFactory {
@@ -440,9 +450,9 @@ class PrecacheFetcherTest : public testing::Test {
net::HttpResponseInfo info;
info.was_cached = true;
info.headers = new net::HttpResponseHeaders(std::string());
- precache_database_.RecordURLNonPrefetch(
- url, base::TimeDelta(), base::Time::Now(), info, 1000 /* size */,
- 0 /* host_rank */, false /* is_connection_cellular */);
+ precache_database_.RecordURLNonPrefetch(url, base::Time::Now(), info,
+ 1000 /* size */, 0 /* host_rank */,
+ false /* is_connection_cellular */);
}
protected:
@@ -568,6 +578,9 @@ TEST_F(PrecacheFetcherTest, FullPrecache) {
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ std::vector<std::string> expected_manifest_hosts = {
+ "good-manifest.com", "forced-starting-url.com"};
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
histogram.ExpectUniqueSample("Precache.Fetch.PercentCompleted", 100, 1);
@@ -654,6 +667,8 @@ TEST_P(PrecacheFetcherResourceSelectionTest, Basic) {
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ std::vector<std::string> expected_manifest_hosts = {"good-manifest.com"};
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
histogram.ExpectUniqueSample("Precache.Fetch.PercentCompleted", 100, 1);
@@ -728,6 +743,8 @@ TEST_P(PrecacheFetcherResourceSelectionTest, MissingBitset) {
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ std::vector<std::string> expected_manifest_hosts = {"good-manifest.com"};
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
histogram.ExpectUniqueSample("Precache.Fetch.PercentCompleted", 100, 1);
@@ -794,6 +811,8 @@ TEST_F(PrecacheFetcherTest, PrecachePauseResume) {
expected_requested_urls.emplace_back(
"http://manifest-url-prefix.com/manifest2.com");
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+
+ EXPECT_TRUE(precache_delegate_.get_manifest_hosts().empty());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
}
@@ -827,6 +846,9 @@ TEST_F(PrecacheFetcherTest, ResumeWithConfigOnly) {
expected_requested_urls.emplace_back(kGoodResourceURL);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+
+ std::vector<std::string> expected_manifest_hosts = {"good-manifest.com"};
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
}
@@ -866,6 +888,8 @@ TEST_F(PrecacheFetcherTest, CustomURLs) {
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ std::vector<std::string> expected_manifest_hosts = {"good-manifest.com"};
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
}
@@ -895,6 +919,8 @@ TEST_F(PrecacheFetcherTest, ConfigFetchFailure) {
expected_requested_urls.emplace_back(kGoodManifestURL);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ std::vector<std::string> expected_manifest_hosts = {"good-manifest.com"};
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
}
@@ -923,6 +949,8 @@ TEST_F(PrecacheFetcherTest, BadConfig) {
expected_requested_urls.emplace_back(kGoodManifestURL);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ std::vector<std::string> expected_manifest_hosts = {"good-manifest.com"};
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
}
@@ -959,6 +987,7 @@ TEST_F(PrecacheFetcherTest, Cancel) {
expected_requested_urls.emplace_back(kConfigURL);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ EXPECT_TRUE(precache_delegate_.get_manifest_hosts().empty());
EXPECT_FALSE(precache_delegate_.was_on_done_called());
histogram.ExpectTotalCount("Precache.Fetch.TimeToComplete", 0);
@@ -992,6 +1021,7 @@ TEST_F(PrecacheFetcherTest, PrecacheUsingDefaultConfigSettingsURL) {
expected_requested_urls.emplace_back(PRECACHE_CONFIG_SETTINGS_URL);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ EXPECT_TRUE(precache_delegate_.get_manifest_hosts().empty());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
}
@@ -1032,6 +1062,8 @@ TEST_F(PrecacheFetcherTest, PrecacheUsingDefaultManifestURLPrefix) {
expected_requested_urls.push_back(manifest_url);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ std::vector<std::string> expected_manifest_hosts = {"starting-url.com"};
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
}
@@ -1086,6 +1118,8 @@ TEST_F(PrecacheFetcherTest, TopResourcesCount) {
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ std::vector<std::string> expected_manifest_hosts = {"good-manifest.com"};
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
histogram.ExpectUniqueSample("Precache.Fetch.PercentCompleted", 100, 1);
@@ -1145,6 +1179,8 @@ TEST_F(PrecacheFetcherTest, TopResourcesCount_ResourceBitset) {
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ std::vector<std::string> expected_manifest_hosts = {"good-manifest.com"};
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
histogram.ExpectUniqueSample("Precache.Fetch.PercentCompleted", 100, 1);
@@ -1230,6 +1266,8 @@ TEST_F(PrecacheFetcherTest, MaxBytesTotal) {
// reason, we are seeing it fetch all but 4 resources. Meh, close enough.
EXPECT_EQ(1 + 1 + kNumResources - 4, url_callback_.requested_urls().size());
+ std::vector<std::string> expected_manifest_hosts = {"good-manifest.com"};
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
histogram.ExpectTotalCount("Precache.Fetch.PercentCompleted", 1);
@@ -1252,6 +1290,7 @@ TEST_F(PrecacheFetcherTest, FetcherPoolMaxLimitReached) {
PrecacheConfigurationSettings config;
std::vector<GURL> expected_requested_urls;
+ std::vector<std::string> expected_manifest_hosts;
config.set_top_sites_count(kNumTopHosts);
factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(),
@@ -1265,6 +1304,7 @@ TEST_F(PrecacheFetcherTest, FetcherPoolMaxLimitReached) {
for (size_t i = 0; i < kNumTopHosts; ++i) {
const std::string top_host_url = base::StringPrintf("top-host-%zu.com", i);
expected_requested_urls.emplace_back(kManifestURLPrefix + top_host_url);
+ expected_manifest_hosts.push_back(top_host_url);
}
for (size_t i = 0; i < kNumTopHosts; ++i) {
@@ -1306,6 +1346,7 @@ TEST_F(PrecacheFetcherTest, FetcherPoolMaxLimitReached) {
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
histogram.ExpectUniqueSample("Precache.Fetch.PercentCompleted", 100, 1);
@@ -1342,6 +1383,7 @@ TEST_F(PrecacheFetcherTest, FilterInvalidManifestUrls) {
// The config is fetched, but not the invalid manifest URL.
EXPECT_EQ(1UL, url_callback_.requested_urls().size());
+ EXPECT_TRUE(precache_delegate_.get_manifest_hosts().empty());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
// manifest.com will have been failed to complete, in this case.
@@ -1382,6 +1424,8 @@ TEST_F(PrecacheFetcherTest, FilterInvalidResourceUrls) {
// The config and manifest are fetched, but not the invalid resource URL.
EXPECT_EQ(2UL, url_callback_.requested_urls().size());
+ std::vector<std::string> expected_manifest_hosts = {"bad-manifest.com"};
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
// bad-manifest.com will have been completed.
@@ -1546,6 +1590,7 @@ TEST_P(PrecacheFetcherGlobalRankingTest, GloballyRankResources) {
const size_t kNumResources = 5;
std::vector<GURL> expected_requested_urls;
+ std::vector<std::string> expected_manifest_hosts;
PrecacheConfigurationSettings config;
config.set_top_sites_count(kNumTopHosts);
@@ -1562,6 +1607,7 @@ TEST_P(PrecacheFetcherGlobalRankingTest, GloballyRankResources) {
for (size_t i = 0; i < kNumTopHosts; ++i) {
const std::string top_host_url = base::StringPrintf("top-host-%zu.com", i);
expected_requested_urls.emplace_back(kManifestURLPrefix + top_host_url);
+ expected_manifest_hosts.push_back(top_host_url);
}
// Visit counts and weights are chosen in such a way that resource requests
@@ -1610,6 +1656,7 @@ TEST_P(PrecacheFetcherGlobalRankingTest, GloballyRankResources) {
}
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
}
@@ -1626,6 +1673,7 @@ TEST_F(PrecacheFetcherTest, GloballyRankResourcesAfterPauseResume) {
const size_t kNumResources = 5;
std::vector<GURL> expected_requested_urls;
+ std::vector<std::string> expected_manifest_hosts;
PrecacheConfigurationSettings config;
config.set_top_sites_count(kNumTopHosts);
@@ -1642,6 +1690,7 @@ TEST_F(PrecacheFetcherTest, GloballyRankResourcesAfterPauseResume) {
std::vector<std::pair<std::string, float>> resources;
for (size_t i = 0; i < kNumTopHosts; ++i) {
const std::string top_host_url = base::StringPrintf("top-host-%zu.com", i);
+ expected_manifest_hosts.push_back(top_host_url);
TopHost* top_host = unfinished_work->add_top_host();
top_host->set_hostname(top_host_url);
top_host->set_visits(kNumTopHosts - i);
@@ -1704,9 +1753,11 @@ TEST_F(PrecacheFetcherTest, GloballyRankResourcesAfterPauseResume) {
EXPECT_TRUE(cancelled_work->top_host().empty());
EXPECT_EQ(kNumTopHosts * kNumResources,
static_cast<size_t>(cancelled_work->resource().size()));
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_FALSE(precache_delegate_.was_on_done_called());
url_callback_.clear_requested_urls();
+ precache_delegate_.clear_manifest_hosts();
// Continuing with the precache should fetch all resources, as the previous
// run was cancelled before any finished. They should be fetched in global
@@ -1724,6 +1775,7 @@ TEST_F(PrecacheFetcherTest, GloballyRankResourcesAfterPauseResume) {
base::RunLoop().RunUntilIdle();
}
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ EXPECT_TRUE(precache_delegate_.get_manifest_hosts().empty());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
histogram.ExpectBucketCount("Precache.Fetch.MinWeight",
@@ -1736,6 +1788,7 @@ TEST_F(PrecacheFetcherTest, MaxTotalResources) {
const size_t kNumResources = 5;
std::vector<GURL> expected_requested_urls;
+ std::vector<std::string> expected_manifest_hosts;
PrecacheConfigurationSettings config;
config.set_total_resources_count(2);
@@ -1754,6 +1807,7 @@ TEST_F(PrecacheFetcherTest, MaxTotalResources) {
expected_requested_urls.emplace_back(kManifestURLPrefix +
top_host->hostname());
+ expected_manifest_hosts.push_back(top_host->hostname());
PrecacheManifest manifest;
for (size_t i = 0; i < kNumResources; ++i) {
@@ -1785,6 +1839,7 @@ TEST_F(PrecacheFetcherTest, MaxTotalResources) {
}
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
const float expected_min_weight =
@@ -1799,6 +1854,7 @@ TEST_F(PrecacheFetcherTest, MinWeight) {
const size_t kNumResources = 5;
std::vector<GURL> expected_requested_urls;
+ std::vector<std::string> expected_manifest_hosts;
PrecacheConfigurationSettings config;
config.set_min_weight(3);
@@ -1817,6 +1873,7 @@ TEST_F(PrecacheFetcherTest, MinWeight) {
expected_requested_urls.emplace_back(kManifestURLPrefix +
top_host->hostname());
+ expected_manifest_hosts.push_back(top_host->hostname());
PrecacheManifest manifest;
for (size_t i = 0; i < kNumResources; ++i) {
@@ -1847,6 +1904,7 @@ TEST_F(PrecacheFetcherTest, MinWeight) {
}
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
}
@@ -1860,6 +1918,7 @@ TEST_F(PrecacheFetcherTest, CancelPrecachingAfterAllManifestFetch) {
PrecacheConfigurationSettings config;
std::vector<GURL> expected_requested_urls;
+ std::vector<std::string> expected_manifest_hosts;
std::unique_ptr<PrecacheUnfinishedWork> cancelled_work;
config.set_top_sites_count(kNumTopHosts);
@@ -1874,6 +1933,7 @@ TEST_F(PrecacheFetcherTest, CancelPrecachingAfterAllManifestFetch) {
for (size_t i = 0; i < kNumTopHosts; ++i) {
const std::string top_host_url = base::StringPrintf("top-host-%zu.com", i);
expected_requested_urls.emplace_back(kManifestURLPrefix + top_host_url);
+ expected_manifest_hosts.push_back(top_host_url);
}
int num_resources = 0;
@@ -1932,13 +1992,14 @@ TEST_F(PrecacheFetcherTest, CancelPrecachingAfterAllManifestFetch) {
static_cast<size_t>(cancelled_work->resource().size()));
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
-
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_FALSE(precache_delegate_.was_on_done_called());
// Continuing with the precache should fetch all resources, as the previous
// run was cancelled before any finished.
expected_requested_urls.clear();
url_callback_.clear_requested_urls();
+ precache_delegate_.clear_manifest_hosts();
for (size_t i = 0; i < kNumTopHosts; ++i) {
for (size_t j = 0; j < kNumResources; ++j) {
expected_requested_urls.emplace_back(
@@ -1955,6 +2016,7 @@ TEST_F(PrecacheFetcherTest, CancelPrecachingAfterAllManifestFetch) {
base::RunLoop().RunUntilIdle();
}
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ EXPECT_TRUE(precache_delegate_.get_manifest_hosts().empty());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
}
@@ -1973,12 +2035,14 @@ TEST_F(PrecacheFetcherTest, DailyQuota) {
factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(),
net::HTTP_OK, net::URLRequestStatus::SUCCESS);
std::vector<GURL> expected_requested_urls;
+ std::vector<std::string> expected_manifest_hosts;
expected_requested_urls.emplace_back(kConfigURL);
for (size_t i = 0; i < kNumTopHosts; ++i) {
const std::string top_host_url = base::StringPrintf("top-host-%zu.com", i);
expected_requested_urls.emplace_back(std::string(kManifestURLPrefix) +
top_host_url);
+ expected_manifest_hosts.push_back(top_host_url);
}
for (size_t i = 0; i < kNumTopHosts; ++i) {
@@ -2016,7 +2080,7 @@ TEST_F(PrecacheFetcherTest, DailyQuota) {
}
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
-
+ EXPECT_EQ(expected_manifest_hosts, precache_delegate_.get_manifest_hosts());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
EXPECT_EQ(0, unfinished_work->top_host_size());
@@ -2030,6 +2094,7 @@ TEST_F(PrecacheFetcherTest, DailyQuota) {
// any resources.
expected_requested_urls.clear();
url_callback_.clear_requested_urls();
+ precache_delegate_.clear_manifest_hosts();
{
PrecacheFetcher precache_fetcher(
request_context_.get(), GURL(), std::string(),
@@ -2041,7 +2106,7 @@ TEST_F(PrecacheFetcherTest, DailyQuota) {
EXPECT_EQ(0U, precache_fetcher.quota_.remaining());
}
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
-
+ EXPECT_TRUE(precache_delegate_.get_manifest_hosts().empty());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
histogram.ExpectTotalCount("Precache.Fetch.PercentCompleted", 2);
diff --git a/chromium/components/precache/core/precache_manifest_util.cc b/chromium/components/precache/core/precache_manifest_util.cc
new file mode 100644
index 00000000000..668a77fecb2
--- /dev/null
+++ b/chromium/components/precache/core/precache_manifest_util.cc
@@ -0,0 +1,60 @@
+// 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/precache/core/precache_manifest_util.h"
+
+#include <string>
+
+#include "components/precache/core/proto/precache.pb.h"
+
+namespace precache {
+
+void RemoveUnknownFields(PrecacheManifest* manifest) {
+ manifest->mutable_unknown_fields()->clear();
+ for (auto& resource : *manifest->mutable_resource())
+ resource.mutable_unknown_fields()->clear();
+ if (manifest->has_experiments()) {
+ manifest->mutable_experiments()->mutable_unknown_fields()->clear();
+ for (auto& kv : *manifest->mutable_experiments()
+ ->mutable_resources_by_experiment_group()) {
+ kv.second.mutable_unknown_fields()->clear();
+ }
+ }
+ if (manifest->has_id())
+ manifest->mutable_id()->mutable_unknown_fields()->clear();
+}
+
+base::Optional<std::vector<bool>> GetResourceBitset(
+ const PrecacheManifest& manifest,
+ uint32_t experiment_id) {
+ base::Optional<std::vector<bool>> ret;
+ if (manifest.has_experiments()) {
+ const auto& resource_bitset_map =
+ manifest.experiments().resources_by_experiment_group();
+ const auto& it = resource_bitset_map.find(experiment_id);
+ if (it != resource_bitset_map.end()) {
+ if (it->second.has_bitset()) {
+ const std::string& bitset = it->second.bitset();
+ ret.emplace(bitset.size() * 8);
+ for (size_t i = 0; i < bitset.size(); ++i) {
+ for (size_t j = 0; j < 8; ++j) {
+ if ((1 << j) & bitset[i])
+ ret.value()[i * 8 + j] = true;
+ }
+ }
+ } else if (it->second.has_deprecated_bitset()) {
+ uint64_t bitset = it->second.deprecated_bitset();
+ ret.emplace(64);
+ for (int i = 0; i < 64; ++i) {
+ if ((0x1ULL << i) & bitset)
+ ret.value()[i] = true;
+ }
+ }
+ }
+ }
+ // Only return one variable to ensure RVO triggers.
+ return ret;
+}
+
+} // namespace precache
diff --git a/chromium/components/precache/core/precache_manifest_util.h b/chromium/components/precache/core/precache_manifest_util.h
new file mode 100644
index 00000000000..b3e2ec2f55b
--- /dev/null
+++ b/chromium/components/precache/core/precache_manifest_util.h
@@ -0,0 +1,30 @@
+// 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_PRECACHE_CORE_PRECACHE_MANIFEST_UTIL_H_
+#define COMPONENTS_PRECACHE_CORE_PRECACHE_MANIFEST_UTIL_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/optional.h"
+
+namespace precache {
+
+class PrecacheManifest;
+
+// Removes unknown fields from the |manifest| including embedded messages.
+void RemoveUnknownFields(PrecacheManifest* manifest);
+
+// Returns the resource selection bitset from the |manifest| for the given
+// |experiment_id|. If the experiment group is not found, then this returns
+// nullopt, in which case all resources should be selected.
+base::Optional<std::vector<bool>> GetResourceBitset(
+ const PrecacheManifest& manifest,
+ uint32_t experiment_id);
+
+} // namespace precache
+
+#endif // COMPONENTS_PRECACHE_CORE_PRECACHE_MANIFEST_UTIL_H_
diff --git a/chromium/components/precache/core/proto/precache.proto b/chromium/components/precache/core/proto/precache.proto
index 5b987e2a0ed..2e9aec257eb 100644
--- a/chromium/components/precache/core/proto/precache.proto
+++ b/chromium/components/precache/core/proto/precache.proto
@@ -33,6 +33,8 @@ message PrecacheManifestId {
};
// A manifest of cacheable resources to be precached for a specific host.
+// CAUTION: When any change is done here, bump kDatabaseVersion in
+// chrome/browser/predictors/resource_prefetch_predictor_tables.h
message PrecacheManifest {
// List of resources that we predict that the user will need if they are
// likely to fetch the host.
diff --git a/chromium/components/pref_registry/OWNERS b/chromium/components/pref_registry/OWNERS
index 2d870381cb7..e04d3d44deb 100644
--- a/chromium/components/pref_registry/OWNERS
+++ b/chromium/components/pref_registry/OWNERS
@@ -2,3 +2,5 @@ battre@chromium.org
bauerb@chromium.org
gab@chromium.org
pam@chromium.org
+
+# COMPONENT: UI>Browser>Preferences
diff --git a/chromium/components/prefs/OWNERS b/chromium/components/prefs/OWNERS
index 2d870381cb7..e04d3d44deb 100644
--- a/chromium/components/prefs/OWNERS
+++ b/chromium/components/prefs/OWNERS
@@ -2,3 +2,5 @@ battre@chromium.org
bauerb@chromium.org
gab@chromium.org
pam@chromium.org
+
+# COMPONENT: UI>Browser>Preferences
diff --git a/chromium/components/prefs/command_line_pref_store.cc b/chromium/components/prefs/command_line_pref_store.cc
index 49278c19f2a..ddaac31ebfb 100644
--- a/chromium/components/prefs/command_line_pref_store.cc
+++ b/chromium/components/prefs/command_line_pref_store.cc
@@ -22,9 +22,8 @@ void CommandLinePrefStore::ApplyStringSwitches(
for (size_t i = 0; i < size; ++i) {
if (command_line_->HasSwitch(string_switch[i].switch_name)) {
SetValue(string_switch[i].preference_path,
- base::MakeUnique<base::StringValue>(
- command_line_->GetSwitchValueASCII(
- string_switch[i].switch_name)),
+ base::MakeUnique<base::Value>(command_line_->GetSwitchValueASCII(
+ string_switch[i].switch_name)),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
}
}
@@ -35,12 +34,11 @@ void CommandLinePrefStore::ApplyPathSwitches(
size_t size) {
for (size_t i = 0; i < size; ++i) {
if (command_line_->HasSwitch(path_switch[i].switch_name)) {
- SetValue(
- path_switch[i].preference_path,
- base::MakeUnique<base::StringValue>(
- command_line_->GetSwitchValuePath(path_switch[i].switch_name)
- .value()),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ SetValue(path_switch[i].preference_path,
+ base::MakeUnique<base::Value>(
+ command_line_->GetSwitchValuePath(path_switch[i].switch_name)
+ .value()),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
}
}
}
diff --git a/chromium/components/prefs/default_pref_store_unittest.cc b/chromium/components/prefs/default_pref_store_unittest.cc
index af6a0748575..20bbba3a87f 100644
--- a/chromium/components/prefs/default_pref_store_unittest.cc
+++ b/chromium/components/prefs/default_pref_store_unittest.cc
@@ -6,7 +6,6 @@
#include "components/prefs/default_pref_store.h"
#include "testing/gtest/include/gtest/gtest.h"
-using base::StringValue;
using base::Value;
namespace {
@@ -54,17 +53,17 @@ TEST(DefaultPrefStoreTest, NotifyPrefValueChanged) {
// Setting a default value shouldn't send a change notification.
pref_store->SetDefaultValue(kPrefKey,
- std::unique_ptr<Value>(new StringValue("foo")));
+ std::unique_ptr<Value>(new Value("foo")));
EXPECT_EQ(0, observer.change_count());
// Replacing the default value should send a change notification...
- pref_store->ReplaceDefaultValue(
- kPrefKey, std::unique_ptr<Value>(new StringValue("bar")));
+ pref_store->ReplaceDefaultValue(kPrefKey,
+ std::unique_ptr<Value>(new Value("bar")));
EXPECT_EQ(1, observer.change_count());
// But only if the value actually changed.
- pref_store->ReplaceDefaultValue(
- kPrefKey, std::unique_ptr<Value>(new StringValue("bar")));
+ pref_store->ReplaceDefaultValue(kPrefKey,
+ std::unique_ptr<Value>(new Value("bar")));
EXPECT_EQ(1, observer.change_count());
}
diff --git a/chromium/components/prefs/json_pref_store.cc b/chromium/components/prefs/json_pref_store.cc
index a9a39227d3f..cf4d2a352cc 100644
--- a/chromium/components/prefs/json_pref_store.cc
+++ b/chromium/components/prefs/json_pref_store.cc
@@ -111,13 +111,7 @@ void RecordJsonDataSizeHistogram(const base::FilePath& path, size_t size) {
}
std::unique_ptr<JsonPrefStore::ReadResult> ReadPrefsFromDisk(
- const base::FilePath& path,
- const base::FilePath& alternate_path) {
- if (!base::PathExists(path) && !alternate_path.empty() &&
- base::PathExists(alternate_path)) {
- base::Move(alternate_path, path);
- }
-
+ const base::FilePath& path) {
int error_code;
std::string error_msg;
std::unique_ptr<JsonPrefStore::ReadResult> read_result(
@@ -151,18 +145,7 @@ JsonPrefStore::JsonPrefStore(
const base::FilePath& pref_filename,
const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
std::unique_ptr<PrefFilter> pref_filter)
- : JsonPrefStore(pref_filename,
- base::FilePath(),
- sequenced_task_runner,
- std::move(pref_filter)) {}
-
-JsonPrefStore::JsonPrefStore(
- const base::FilePath& pref_filename,
- const base::FilePath& pref_alternate_filename,
- const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
- std::unique_ptr<PrefFilter> pref_filter)
: path_(pref_filename),
- alternate_path_(pref_alternate_filename),
sequenced_task_runner_(sequenced_task_runner),
prefs_(new base::DictionaryValue()),
read_only_(false),
@@ -283,7 +266,7 @@ PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const {
PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
DCHECK(CalledOnValidThread());
- OnFileRead(ReadPrefsFromDisk(path_, alternate_path_));
+ OnFileRead(ReadPrefsFromDisk(path_));
return filtering_in_progress_ ? PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE
: read_error_;
}
@@ -296,9 +279,8 @@ void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
// Weakly binds the read task so that it doesn't kick in during shutdown.
base::PostTaskAndReplyWithResult(
- sequenced_task_runner_.get(),
- FROM_HERE,
- base::Bind(&ReadPrefsFromDisk, path_, alternate_path_),
+ sequenced_task_runner_.get(), FROM_HERE,
+ base::Bind(&ReadPrefsFromDisk, path_),
base::Bind(&JsonPrefStore::OnFileRead, AsWeakPtr()));
}
diff --git a/chromium/components/prefs/json_pref_store.h b/chromium/components/prefs/json_pref_store.h
index 8c1164ca8ba..6284b8d5478 100644
--- a/chromium/components/prefs/json_pref_store.h
+++ b/chromium/components/prefs/json_pref_store.h
@@ -62,22 +62,11 @@ class COMPONENTS_PREFS_EXPORT JsonPrefStore
const base::FilePath& pref_filename,
base::SequencedWorkerPool* worker_pool);
- // Same as the constructor below with no alternate filename.
- JsonPrefStore(
- const base::FilePath& pref_filename,
- const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
- std::unique_ptr<PrefFilter> pref_filter);
-
// |sequenced_task_runner| must be a shutdown-blocking task runner, ideally
// created by the GetTaskRunnerForFile() method above.
// |pref_filename| is the path to the file to read prefs from.
- // |pref_alternate_filename| is the path to an alternate file which the
- // desired prefs may have previously been written to. If |pref_filename|
- // doesn't exist and |pref_alternate_filename| does, |pref_alternate_filename|
- // will be moved to |pref_filename| before the read occurs.
JsonPrefStore(
const base::FilePath& pref_filename,
- const base::FilePath& pref_alternate_filename,
const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
std::unique_ptr<PrefFilter> pref_filter);
@@ -231,7 +220,6 @@ class COMPONENTS_PREFS_EXPORT JsonPrefStore
void ScheduleWrite(uint32_t flags);
const base::FilePath path_;
- const base::FilePath alternate_path_;
const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
std::unique_ptr<base::DictionaryValue> prefs_;
diff --git a/chromium/components/prefs/json_pref_store_unittest.cc b/chromium/components/prefs/json_pref_store_unittest.cc
index f404d2a0398..cae79d34143 100644
--- a/chromium/components/prefs/json_pref_store_unittest.cc
+++ b/chromium/components/prefs/json_pref_store_unittest.cc
@@ -166,21 +166,6 @@ TEST_F(JsonPrefStoreTest, NonExistentFile) {
EXPECT_FALSE(pref_store->ReadOnly());
}
-// Test fallback behavior for a nonexistent file and alternate file.
-TEST_F(JsonPrefStoreTest, NonExistentFileAndAlternateFile) {
- base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
- base::FilePath bogus_alternate_input_file =
- temp_dir_.GetPath().AppendASCII("read_alternate.txt");
- ASSERT_FALSE(PathExists(bogus_input_file));
- ASSERT_FALSE(PathExists(bogus_alternate_input_file));
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- bogus_input_file, bogus_alternate_input_file, message_loop_.task_runner(),
- std::unique_ptr<PrefFilter>());
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
- pref_store->ReadPrefs());
- EXPECT_FALSE(pref_store->ReadOnly());
-}
-
// Test fallback behavior for an invalid file.
TEST_F(JsonPrefStoreTest, InvalidFile) {
base::FilePath invalid_file = temp_dir_.GetPath().AppendASCII("invalid.json");
@@ -229,7 +214,7 @@ void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
base::FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
pref_store->SetValue(kSomeDirectory,
- base::MakeUnique<StringValue>(some_path.value()),
+ base::MakeUnique<Value>(some_path.value()),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
EXPECT_TRUE(actual->GetAsString(&path));
@@ -257,9 +242,10 @@ void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
EXPECT_TRUE(actual->GetAsInteger(&integer));
EXPECT_EQ(10, integer);
- pref_store->SetValue(kLongIntPref, base::MakeUnique<StringValue>(
- base::Int64ToString(214748364842LL)),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ pref_store->SetValue(
+ kLongIntPref,
+ base::MakeUnique<Value>(base::Int64ToString(214748364842LL)),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
EXPECT_TRUE(actual->GetAsString(&string_value));
int64_t value;
@@ -517,171 +503,6 @@ TEST_F(JsonPrefStoreTest, ReadAsyncWithInterceptor) {
RunBasicJsonPrefStoreTest(pref_store.get(), input_file);
}
-TEST_F(JsonPrefStoreTest, AlternateFile) {
- base::FilePath alternate_input_file =
- temp_dir_.GetPath().AppendASCII("alternate.json");
- ASSERT_LT(0, base::WriteFile(alternate_input_file,
- kReadJson, arraysize(kReadJson) - 1));
-
- // Test that the alternate file is moved to the main file and read as-is from
- // there.
- base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
- ASSERT_FALSE(PathExists(input_file));
- ASSERT_TRUE(PathExists(alternate_input_file));
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file, alternate_input_file, message_loop_.task_runner(),
- std::unique_ptr<PrefFilter>());
-
- ASSERT_FALSE(PathExists(input_file));
- ASSERT_TRUE(PathExists(alternate_input_file));
- ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
-
- ASSERT_TRUE(PathExists(input_file));
- ASSERT_FALSE(PathExists(alternate_input_file));
-
- EXPECT_FALSE(pref_store->ReadOnly());
- EXPECT_TRUE(pref_store->IsInitializationComplete());
-
- // The JSON file looks like this:
- // {
- // "homepage": "http://www.cnn.com",
- // "some_directory": "/usr/local/",
- // "tabs": {
- // "new_windows_in_tabs": true,
- // "max_tabs": 20
- // }
- // }
-
- RunBasicJsonPrefStoreTest(pref_store.get(), input_file);
-}
-
-TEST_F(JsonPrefStoreTest, AlternateFileIgnoredWhenMainFileExists) {
- base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
- ASSERT_LT(0, base::WriteFile(input_file,
- kReadJson, arraysize(kReadJson) - 1));
-
- base::FilePath alternate_input_file =
- temp_dir_.GetPath().AppendASCII("alternate.json");
- ASSERT_LT(0, base::WriteFile(alternate_input_file,
- kInvalidJson, arraysize(kInvalidJson) - 1));
-
- // Test that the alternate file is ignored and that the read occurs from the
- // existing main file. There is no attempt at even deleting the alternate
- // file as this scenario should never happen in normal user-data-dirs.
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file, alternate_input_file, message_loop_.task_runner(),
- std::unique_ptr<PrefFilter>());
-
- ASSERT_TRUE(PathExists(input_file));
- ASSERT_TRUE(PathExists(alternate_input_file));
- ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
-
- ASSERT_TRUE(PathExists(input_file));
- ASSERT_TRUE(PathExists(alternate_input_file));
-
- EXPECT_FALSE(pref_store->ReadOnly());
- EXPECT_TRUE(pref_store->IsInitializationComplete());
-
- // The JSON file looks like this:
- // {
- // "homepage": "http://www.cnn.com",
- // "some_directory": "/usr/local/",
- // "tabs": {
- // "new_windows_in_tabs": true,
- // "max_tabs": 20
- // }
- // }
-
- RunBasicJsonPrefStoreTest(pref_store.get(), input_file);
-}
-
-TEST_F(JsonPrefStoreTest, AlternateFileDNE) {
- base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
- ASSERT_LT(0, base::WriteFile(input_file,
- kReadJson, arraysize(kReadJson) - 1));
-
- // Test that the basic read works fine when an alternate file is specified but
- // does not exist.
- base::FilePath alternate_input_file =
- temp_dir_.GetPath().AppendASCII("alternate.json");
- ASSERT_TRUE(PathExists(input_file));
- ASSERT_FALSE(PathExists(alternate_input_file));
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file, alternate_input_file, message_loop_.task_runner(),
- std::unique_ptr<PrefFilter>());
-
- ASSERT_TRUE(PathExists(input_file));
- ASSERT_FALSE(PathExists(alternate_input_file));
- ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
-
- ASSERT_TRUE(PathExists(input_file));
- ASSERT_FALSE(PathExists(alternate_input_file));
-
- EXPECT_FALSE(pref_store->ReadOnly());
- EXPECT_TRUE(pref_store->IsInitializationComplete());
-
- // The JSON file looks like this:
- // {
- // "homepage": "http://www.cnn.com",
- // "some_directory": "/usr/local/",
- // "tabs": {
- // "new_windows_in_tabs": true,
- // "max_tabs": 20
- // }
- // }
-
- RunBasicJsonPrefStoreTest(pref_store.get(), input_file);
-}
-
-TEST_F(JsonPrefStoreTest, BasicAsyncWithAlternateFile) {
- base::FilePath alternate_input_file =
- temp_dir_.GetPath().AppendASCII("alternate.json");
- ASSERT_LT(0, base::WriteFile(alternate_input_file,
- kReadJson, arraysize(kReadJson) - 1));
-
- // Test that the alternate file is moved to the main file and read as-is from
- // there even when the read is made asynchronously.
- base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file, alternate_input_file, message_loop_.task_runner(),
- std::unique_ptr<PrefFilter>());
-
- ASSERT_FALSE(PathExists(input_file));
- ASSERT_TRUE(PathExists(alternate_input_file));
-
- {
- MockPrefStoreObserver mock_observer;
- pref_store->AddObserver(&mock_observer);
-
- MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
- pref_store->ReadPrefsAsync(mock_error_delegate);
-
- EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
- EXPECT_CALL(*mock_error_delegate,
- OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
- RunLoop().RunUntilIdle();
- pref_store->RemoveObserver(&mock_observer);
-
- EXPECT_FALSE(pref_store->ReadOnly());
- EXPECT_TRUE(pref_store->IsInitializationComplete());
- }
-
- ASSERT_TRUE(PathExists(input_file));
- ASSERT_FALSE(PathExists(alternate_input_file));
-
- // The JSON file looks like this:
- // {
- // "homepage": "http://www.cnn.com",
- // "some_directory": "/usr/local/",
- // "tabs": {
- // "new_windows_in_tabs": true,
- // "max_tabs": 20
- // }
- // }
-
- RunBasicJsonPrefStoreTest(pref_store.get(), input_file);
-}
-
TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
base::HistogramTester histogram_tester;
@@ -872,7 +693,7 @@ TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
// Set a normal pref and check that it gets scheduled to be written.
ASSERT_FALSE(file_writer->HasPendingWrite());
- pref_store->SetValue("normal", base::MakeUnique<base::StringValue>("normal"),
+ pref_store->SetValue("normal", base::MakeUnique<base::Value>("normal"),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
ASSERT_TRUE(file_writer->HasPendingWrite());
file_writer->DoScheduledWrite();
@@ -881,15 +702,14 @@ TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
// Set a lossy pref and check that it is not scheduled to be written.
// SetValue/RemoveValue.
- pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
+ pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
ASSERT_FALSE(file_writer->HasPendingWrite());
pref_store->RemoveValue("lossy", WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
ASSERT_FALSE(file_writer->HasPendingWrite());
// SetValueSilently/RemoveValueSilently.
- pref_store->SetValueSilently("lossy",
- base::MakeUnique<base::StringValue>("lossy"),
+ pref_store->SetValueSilently("lossy", base::MakeUnique<base::Value>("lossy"),
WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
ASSERT_FALSE(file_writer->HasPendingWrite());
pref_store->RemoveValueSilently("lossy",
@@ -897,7 +717,7 @@ TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
ASSERT_FALSE(file_writer->HasPendingWrite());
// ReportValueChanged.
- pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
+ pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
ASSERT_FALSE(file_writer->HasPendingWrite());
pref_store->ReportValueChanged("lossy",
@@ -918,12 +738,12 @@ TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossyFirst) {
// Set a lossy pref and check that it is not scheduled to be written.
ASSERT_FALSE(file_writer->HasPendingWrite());
- pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
+ pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
ASSERT_FALSE(file_writer->HasPendingWrite());
// Set a normal pref and check that it is scheduled to be written.
- pref_store->SetValue("normal", base::MakeUnique<base::StringValue>("normal"),
+ pref_store->SetValue("normal", base::MakeUnique<base::Value>("normal"),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
ASSERT_TRUE(file_writer->HasPendingWrite());
@@ -940,12 +760,12 @@ TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossySecond) {
// Set a normal pref and check that it is scheduled to be written.
ASSERT_FALSE(file_writer->HasPendingWrite());
- pref_store->SetValue("normal", base::MakeUnique<base::StringValue>("normal"),
+ pref_store->SetValue("normal", base::MakeUnique<base::Value>("normal"),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
ASSERT_TRUE(file_writer->HasPendingWrite());
// Set a lossy pref and check that the write is still scheduled.
- pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
+ pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
ASSERT_TRUE(file_writer->HasPendingWrite());
@@ -961,7 +781,7 @@ TEST_F(JsonPrefStoreLossyWriteTest, ScheduleLossyWrite) {
ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
// Set a lossy pref and check that it is not scheduled to be written.
- pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
+ pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
ASSERT_FALSE(file_writer->HasPendingWrite());
@@ -1125,7 +945,7 @@ TEST_F(JsonPrefStoreCallbackTest, TestSerializeDataCallbacks) {
EXPECT_EQ(NOT_CALLED,
write_callback_observer_.GetAndResetPostWriteObservationState());
- pref_store->SetValue("normal", base::MakeUnique<base::StringValue>("normal"),
+ pref_store->SetValue("normal", base::MakeUnique<base::Value>("normal"),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
file_writer->DoScheduledWrite();
diff --git a/chromium/components/prefs/pref_change_registrar_unittest.cc b/chromium/components/prefs/pref_change_registrar_unittest.cc
index 68b62cd2fed..15be02c869e 100644
--- a/chromium/components/prefs/pref_change_registrar_unittest.cc
+++ b/chromium/components/prefs/pref_change_registrar_unittest.cc
@@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "components/prefs/pref_change_registrar.h"
+
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "components/prefs/pref_change_registrar.h"
+#include "base/memory/ptr_util.h"
#include "components/prefs/pref_observer.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
@@ -158,9 +160,10 @@ TEST_F(ObserveSetOfPreferencesTest, IsManaged) {
std::unique_ptr<PrefChangeRegistrar> pref_set(CreatePrefChangeRegistrar());
EXPECT_FALSE(pref_set->IsManaged());
pref_service_->SetManagedPref(kHomePage,
- new StringValue("http://crbug.com"));
+ base::MakeUnique<Value>("http://crbug.com"));
EXPECT_TRUE(pref_set->IsManaged());
- pref_service_->SetManagedPref(kHomePageIsNewTabPage, new Value(true));
+ pref_service_->SetManagedPref(kHomePageIsNewTabPage,
+ base::MakeUnique<Value>(true));
EXPECT_TRUE(pref_set->IsManaged());
pref_service_->RemoveManagedPref(kHomePage);
EXPECT_TRUE(pref_set->IsManaged());
@@ -181,15 +184,18 @@ TEST_F(ObserveSetOfPreferencesTest, Observe) {
pref_set.Add(kHomePageIsNewTabPage, callback);
EXPECT_CALL(*this, OnPreferenceChanged(kHomePage));
- pref_service_->SetUserPref(kHomePage, new StringValue("http://crbug.com"));
+ pref_service_->SetUserPref(kHomePage,
+ base::MakeUnique<Value>("http://crbug.com"));
Mock::VerifyAndClearExpectations(this);
EXPECT_CALL(*this, OnPreferenceChanged(kHomePageIsNewTabPage));
- pref_service_->SetUserPref(kHomePageIsNewTabPage, new Value(true));
+ pref_service_->SetUserPref(kHomePageIsNewTabPage,
+ base::MakeUnique<Value>(true));
Mock::VerifyAndClearExpectations(this);
EXPECT_CALL(*this, OnPreferenceChanged(_)).Times(0);
- pref_service_->SetUserPref(kApplicationLocale, new StringValue("en_US.utf8"));
+ pref_service_->SetUserPref(kApplicationLocale,
+ base::MakeUnique<Value>("en_US.utf8"));
Mock::VerifyAndClearExpectations(this);
}
diff --git a/chromium/components/prefs/pref_member.cc b/chromium/components/prefs/pref_member.cc
index 8ed13ee5516..f0be267ed5d 100644
--- a/chromium/components/prefs/pref_member.cc
+++ b/chromium/components/prefs/pref_member.cc
@@ -139,7 +139,7 @@ bool PrefMemberVectorStringUpdate(const base::Value& value,
for (base::ListValue::const_iterator it = list->begin();
it != list->end(); ++it) {
std::string string_value;
- if (!(*it)->GetAsString(&string_value))
+ if (!it->GetAsString(&string_value))
return false;
local_vector.push_back(string_value);
diff --git a/chromium/components/prefs/pref_member_unittest.cc b/chromium/components/prefs/pref_member_unittest.cc
index dc7ef161d5c..df67710fd60 100644
--- a/chromium/components/prefs/pref_member_unittest.cc
+++ b/chromium/components/prefs/pref_member_unittest.cc
@@ -6,8 +6,10 @@
#include "base/bind.h"
#include "base/location.h"
+#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
@@ -26,7 +28,8 @@ void RegisterTestPrefs(PrefRegistrySimple* registry) {
registry->RegisterIntegerPref(kIntPref, 0);
registry->RegisterDoublePref(kDoublePref, 0.0);
registry->RegisterStringPref(kStringPref, "default");
- registry->RegisterListPref(kStringListPref, new base::ListValue());
+ registry->RegisterListPref(kStringListPref,
+ base::MakeUnique<base::ListValue>());
}
class GetPrefValueHelper
@@ -102,7 +105,7 @@ class PrefMemberTestClass {
} // anonymous namespace
class PrefMemberTest : public testing::Test {
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
};
TEST_F(PrefMemberTest, BasicGetAndSet) {
diff --git a/chromium/components/prefs/pref_registry.cc b/chromium/components/prefs/pref_registry.cc
index 63b5e6a823e..e80d03c46d3 100644
--- a/chromium/components/prefs/pref_registry.cc
+++ b/chromium/components/prefs/pref_registry.cc
@@ -4,6 +4,8 @@
#include "components/prefs/pref_registry.h"
+#include <utility>
+
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
@@ -50,9 +52,10 @@ void PrefRegistry::SetDefaultPrefValue(const std::string& pref_name,
defaults_->ReplaceDefaultValue(pref_name, base::WrapUnique(value));
}
-void PrefRegistry::RegisterPreference(const std::string& path,
- base::Value* default_value,
- uint32_t flags) {
+void PrefRegistry::RegisterPreference(
+ const std::string& path,
+ std::unique_ptr<base::Value> default_value,
+ uint32_t flags) {
base::Value::Type orig_type = default_value->GetType();
DCHECK(orig_type != base::Value::Type::NONE &&
orig_type != base::Value::Type::BINARY) <<
@@ -62,7 +65,7 @@ void PrefRegistry::RegisterPreference(const std::string& path,
DCHECK(!base::ContainsKey(registration_flags_, path))
<< "Trying to register a previously registered pref: " << path;
- defaults_->SetDefaultValue(path, base::WrapUnique(default_value));
+ defaults_->SetDefaultValue(path, std::move(default_value));
if (flags != NO_REGISTRATION_FLAGS)
registration_flags_[path] = flags;
}
diff --git a/chromium/components/prefs/pref_registry.h b/chromium/components/prefs/pref_registry.h
index 31a4956f793..bdb8af55a04 100644
--- a/chromium/components/prefs/pref_registry.h
+++ b/chromium/components/prefs/pref_registry.h
@@ -7,6 +7,8 @@
#include <stdint.h>
+#include <memory>
+
#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
@@ -75,7 +77,7 @@ class COMPONENTS_PREFS_EXPORT PrefRegistry
// Used by subclasses to register a default value and registration flags for
// a preference. |flags| is a bitmask of |PrefRegistrationFlags|.
void RegisterPreference(const std::string& path,
- base::Value* default_value,
+ std::unique_ptr<base::Value> default_value,
uint32_t flags);
scoped_refptr<DefaultPrefStore> defaults_;
diff --git a/chromium/components/prefs/pref_registry_simple.cc b/chromium/components/prefs/pref_registry_simple.cc
index ef15ce01d24..ee362f14628 100644
--- a/chromium/components/prefs/pref_registry_simple.cc
+++ b/chromium/components/prefs/pref_registry_simple.cc
@@ -4,7 +4,10 @@
#include "components/prefs/pref_registry_simple.h"
+#include <utility>
+
#include "base/files/file_path.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
@@ -16,145 +19,157 @@ PrefRegistrySimple::~PrefRegistrySimple() {
void PrefRegistrySimple::RegisterBooleanPref(const std::string& path,
bool default_value) {
- RegisterPrefAndNotify(path, new base::Value(default_value),
+ RegisterPrefAndNotify(path, base::MakeUnique<base::Value>(default_value),
NO_REGISTRATION_FLAGS);
}
void PrefRegistrySimple::RegisterIntegerPref(const std::string& path,
int default_value) {
- RegisterPrefAndNotify(path, new base::Value(default_value),
+ RegisterPrefAndNotify(path, base::MakeUnique<base::Value>(default_value),
NO_REGISTRATION_FLAGS);
}
void PrefRegistrySimple::RegisterDoublePref(const std::string& path,
double default_value) {
- RegisterPrefAndNotify(path, new base::Value(default_value),
+ RegisterPrefAndNotify(path, base::MakeUnique<base::Value>(default_value),
NO_REGISTRATION_FLAGS);
}
void PrefRegistrySimple::RegisterStringPref(const std::string& path,
const std::string& default_value) {
- RegisterPrefAndNotify(path, new base::StringValue(default_value),
+ RegisterPrefAndNotify(path, base::MakeUnique<base::Value>(default_value),
NO_REGISTRATION_FLAGS);
}
void PrefRegistrySimple::RegisterFilePathPref(
const std::string& path,
const base::FilePath& default_value) {
- RegisterPrefAndNotify(path, new base::StringValue(default_value.value()),
+ RegisterPrefAndNotify(path,
+ base::MakeUnique<base::Value>(default_value.value()),
NO_REGISTRATION_FLAGS);
}
void PrefRegistrySimple::RegisterListPref(const std::string& path) {
- RegisterPrefAndNotify(path, new base::ListValue(), NO_REGISTRATION_FLAGS);
+ RegisterPrefAndNotify(path, base::MakeUnique<base::ListValue>(),
+ NO_REGISTRATION_FLAGS);
}
-void PrefRegistrySimple::RegisterListPref(const std::string& path,
- base::ListValue* default_value) {
- RegisterPrefAndNotify(path, default_value, NO_REGISTRATION_FLAGS);
+void PrefRegistrySimple::RegisterListPref(
+ const std::string& path,
+ std::unique_ptr<base::ListValue> default_value) {
+ RegisterPrefAndNotify(path, std::move(default_value), NO_REGISTRATION_FLAGS);
}
void PrefRegistrySimple::RegisterDictionaryPref(const std::string& path) {
- RegisterPrefAndNotify(path, new base::DictionaryValue(),
+ RegisterPrefAndNotify(path, base::MakeUnique<base::DictionaryValue>(),
NO_REGISTRATION_FLAGS);
}
void PrefRegistrySimple::RegisterDictionaryPref(
const std::string& path,
- base::DictionaryValue* default_value) {
- RegisterPrefAndNotify(path, default_value, NO_REGISTRATION_FLAGS);
+ std::unique_ptr<base::DictionaryValue> default_value) {
+ RegisterPrefAndNotify(path, std::move(default_value), NO_REGISTRATION_FLAGS);
}
void PrefRegistrySimple::RegisterInt64Pref(const std::string& path,
int64_t default_value) {
RegisterPrefAndNotify(
- path, new base::StringValue(base::Int64ToString(default_value)),
+ path, base::MakeUnique<base::Value>(base::Int64ToString(default_value)),
NO_REGISTRATION_FLAGS);
}
void PrefRegistrySimple::RegisterUint64Pref(const std::string& path,
uint64_t default_value) {
RegisterPrefAndNotify(
- path, new base::StringValue(base::Uint64ToString(default_value)),
+ path, base::MakeUnique<base::Value>(base::Uint64ToString(default_value)),
NO_REGISTRATION_FLAGS);
}
void PrefRegistrySimple::RegisterBooleanPref(const std::string& path,
bool default_value,
uint32_t flags) {
- RegisterPrefAndNotify(path, new base::Value(default_value), flags);
+ RegisterPrefAndNotify(path, base::MakeUnique<base::Value>(default_value),
+ flags);
}
void PrefRegistrySimple::RegisterIntegerPref(const std::string& path,
int default_value,
uint32_t flags) {
- RegisterPrefAndNotify(path, new base::Value(default_value), flags);
+ RegisterPrefAndNotify(path, base::MakeUnique<base::Value>(default_value),
+ flags);
}
void PrefRegistrySimple::RegisterDoublePref(const std::string& path,
double default_value,
uint32_t flags) {
- RegisterPrefAndNotify(path, new base::Value(default_value), flags);
+ RegisterPrefAndNotify(path, base::MakeUnique<base::Value>(default_value),
+ flags);
}
void PrefRegistrySimple::RegisterStringPref(const std::string& path,
const std::string& default_value,
uint32_t flags) {
- RegisterPrefAndNotify(path, new base::StringValue(default_value), flags);
+ RegisterPrefAndNotify(path, base::MakeUnique<base::Value>(default_value),
+ flags);
}
void PrefRegistrySimple::RegisterFilePathPref(
const std::string& path,
const base::FilePath& default_value,
uint32_t flags) {
- RegisterPrefAndNotify(path, new base::StringValue(default_value.value()),
- flags);
+ RegisterPrefAndNotify(
+ path, base::MakeUnique<base::Value>(default_value.value()), flags);
}
void PrefRegistrySimple::RegisterListPref(const std::string& path,
uint32_t flags) {
- RegisterPrefAndNotify(path, new base::ListValue(), flags);
+ RegisterPrefAndNotify(path, base::MakeUnique<base::ListValue>(), flags);
}
-void PrefRegistrySimple::RegisterListPref(const std::string& path,
- base::ListValue* default_value,
- uint32_t flags) {
- RegisterPrefAndNotify(path, default_value, flags);
+void PrefRegistrySimple::RegisterListPref(
+ const std::string& path,
+ std::unique_ptr<base::ListValue> default_value,
+ uint32_t flags) {
+ RegisterPrefAndNotify(path, std::move(default_value), flags);
}
void PrefRegistrySimple::RegisterDictionaryPref(const std::string& path,
uint32_t flags) {
- RegisterPrefAndNotify(path, new base::DictionaryValue(), flags);
+ RegisterPrefAndNotify(path, base::MakeUnique<base::DictionaryValue>(), flags);
}
void PrefRegistrySimple::RegisterDictionaryPref(
const std::string& path,
- base::DictionaryValue* default_value,
+ std::unique_ptr<base::DictionaryValue> default_value,
uint32_t flags) {
- RegisterPrefAndNotify(path, default_value, flags);
+ RegisterPrefAndNotify(path, std::move(default_value), flags);
}
void PrefRegistrySimple::RegisterInt64Pref(const std::string& path,
int64_t default_value,
uint32_t flags) {
RegisterPrefAndNotify(
- path, new base::StringValue(base::Int64ToString(default_value)), flags);
+ path, base::MakeUnique<base::Value>(base::Int64ToString(default_value)),
+ flags);
}
void PrefRegistrySimple::RegisterUint64Pref(const std::string& path,
uint64_t default_value,
uint32_t flags) {
RegisterPrefAndNotify(
- path, new base::StringValue(base::Uint64ToString(default_value)), flags);
+ path, base::MakeUnique<base::Value>(base::Uint64ToString(default_value)),
+ flags);
}
void PrefRegistrySimple::OnPrefRegistered(const std::string& path,
base::Value* default_value,
uint32_t flags) {}
-void PrefRegistrySimple::RegisterPrefAndNotify(const std::string& path,
- base::Value* default_value,
- uint32_t flags) {
- RegisterPreference(path, default_value, flags);
- OnPrefRegistered(path, default_value, flags);
+void PrefRegistrySimple::RegisterPrefAndNotify(
+ const std::string& path,
+ std::unique_ptr<base::Value> default_value,
+ uint32_t flags) {
+ base::Value* default_value_weak = default_value.get();
+ RegisterPreference(path, std::move(default_value), flags);
+ OnPrefRegistered(path, default_value_weak, flags);
}
diff --git a/chromium/components/prefs/pref_registry_simple.h b/chromium/components/prefs/pref_registry_simple.h
index e3267871590..23a0ed4bcd2 100644
--- a/chromium/components/prefs/pref_registry_simple.h
+++ b/chromium/components/prefs/pref_registry_simple.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include <memory>
#include <string>
#include "base/macros.h"
@@ -34,9 +35,10 @@ class COMPONENTS_PREFS_EXPORT PrefRegistrySimple : public PrefRegistry {
void RegisterListPref(const std::string& path);
void RegisterDictionaryPref(const std::string& path);
void RegisterListPref(const std::string& path,
- base::ListValue* default_value);
- void RegisterDictionaryPref(const std::string& path,
- base::DictionaryValue* default_value);
+ std::unique_ptr<base::ListValue> default_value);
+ void RegisterDictionaryPref(
+ const std::string& path,
+ std::unique_ptr<base::DictionaryValue> default_value);
void RegisterInt64Pref(const std::string& path, int64_t default_value);
void RegisterUint64Pref(const std::string&, uint64_t default_value);
@@ -60,11 +62,12 @@ class COMPONENTS_PREFS_EXPORT PrefRegistrySimple : public PrefRegistry {
void RegisterListPref(const std::string&, uint32_t flags);
void RegisterDictionaryPref(const std::string&, uint32_t flags);
void RegisterListPref(const std::string&,
- base::ListValue* default_value,
+ std::unique_ptr<base::ListValue> default_value,
uint32_t flags);
- void RegisterDictionaryPref(const std::string&,
- base::DictionaryValue* default_value,
- uint32_t flags);
+ void RegisterDictionaryPref(
+ const std::string&,
+ std::unique_ptr<base::DictionaryValue> default_value,
+ uint32_t flags);
void RegisterInt64Pref(const std::string&,
int64_t default_value,
uint32_t flags);
@@ -82,7 +85,7 @@ class COMPONENTS_PREFS_EXPORT PrefRegistrySimple : public PrefRegistry {
private:
void RegisterPrefAndNotify(const std::string&,
- base::Value* default_value,
+ std::unique_ptr<base::Value> default_value,
uint32_t flags);
DISALLOW_COPY_AND_ASSIGN(PrefRegistrySimple);
diff --git a/chromium/components/prefs/pref_service.cc b/chromium/components/prefs/pref_service.cc
index b42529b19ce..6858839110b 100644
--- a/chromium/components/prefs/pref_service.cc
+++ b/chromium/components/prefs/pref_service.cc
@@ -385,23 +385,23 @@ void PrefService::ClearMutableValues() {
}
void PrefService::Set(const std::string& path, const base::Value& value) {
- SetUserPrefValue(path, value.DeepCopy());
+ SetUserPrefValue(path, value.CreateDeepCopy());
}
void PrefService::SetBoolean(const std::string& path, bool value) {
- SetUserPrefValue(path, new base::Value(value));
+ SetUserPrefValue(path, base::MakeUnique<base::Value>(value));
}
void PrefService::SetInteger(const std::string& path, int value) {
- SetUserPrefValue(path, new base::Value(value));
+ SetUserPrefValue(path, base::MakeUnique<base::Value>(value));
}
void PrefService::SetDouble(const std::string& path, double value) {
- SetUserPrefValue(path, new base::Value(value));
+ SetUserPrefValue(path, base::MakeUnique<base::Value>(value));
}
void PrefService::SetString(const std::string& path, const std::string& value) {
- SetUserPrefValue(path, new base::StringValue(value));
+ SetUserPrefValue(path, base::MakeUnique<base::Value>(value));
}
void PrefService::SetFilePath(const std::string& path,
@@ -410,7 +410,8 @@ void PrefService::SetFilePath(const std::string& path,
}
void PrefService::SetInt64(const std::string& path, int64_t value) {
- SetUserPrefValue(path, new base::StringValue(base::Int64ToString(value)));
+ SetUserPrefValue(path,
+ base::MakeUnique<base::Value>(base::Int64ToString(value)));
}
int64_t PrefService::GetInt64(const std::string& path) const {
@@ -431,7 +432,8 @@ int64_t PrefService::GetInt64(const std::string& path) const {
}
void PrefService::SetUint64(const std::string& path, uint64_t value) {
- SetUserPrefValue(path, new base::StringValue(base::Uint64ToString(value)));
+ SetUserPrefValue(path,
+ base::MakeUnique<base::Value>(base::Uint64ToString(value)));
}
uint64_t PrefService::GetUint64(const std::string& path) const {
@@ -491,8 +493,7 @@ void PrefService::ReportUserPrefChanged(const std::string& key) {
}
void PrefService::SetUserPrefValue(const std::string& path,
- base::Value* new_value) {
- std::unique_ptr<base::Value> owned_value(new_value);
+ std::unique_ptr<base::Value> new_value) {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
@@ -507,7 +508,7 @@ void PrefService::SetUserPrefValue(const std::string& path,
return;
}
- user_pref_store_->SetValue(path, std::move(owned_value), GetWriteFlags(pref));
+ user_pref_store_->SetValue(path, std::move(new_value), GetWriteFlags(pref));
}
void PrefService::UpdateCommandLinePrefStore(PrefStore* command_line_store) {
@@ -560,7 +561,7 @@ bool PrefService::Preference::IsManaged() const {
}
bool PrefService::Preference::IsManagedByCustodian() const {
- return pref_value_store()->PrefValueInSupervisedStore(name_.c_str());
+ return pref_value_store()->PrefValueInSupervisedStore(name_);
}
bool PrefService::Preference::IsRecommended() const {
diff --git a/chromium/components/prefs/pref_service.h b/chromium/components/prefs/pref_service.h
index d26e118d891..e08e361c40b 100644
--- a/chromium/components/prefs/pref_service.h
+++ b/chromium/components/prefs/pref_service.h
@@ -355,7 +355,8 @@ class COMPONENTS_PREFS_EXPORT PrefService : public base::NonThreadSafe {
// Sets the value for this pref path in the user pref store and informs the
// PrefNotifier of the change.
- void SetUserPrefValue(const std::string& path, base::Value* new_value);
+ void SetUserPrefValue(const std::string& path,
+ std::unique_ptr<base::Value> new_value);
// Load preferences from storage, attempting to diagnose and handle errors.
// This should only be called from the constructor.
diff --git a/chromium/components/prefs/pref_service_unittest.cc b/chromium/components/prefs/pref_service_unittest.cc
index 8c97e5e7a6d..b64ddad95f3 100644
--- a/chromium/components/prefs/pref_service_unittest.cc
+++ b/chromium/components/prefs/pref_service_unittest.cc
@@ -8,6 +8,7 @@
#include <string>
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/values.h"
#include "components/prefs/json_pref_store.h"
#include "components/prefs/mock_pref_change_callback.h"
@@ -38,7 +39,7 @@ TEST(PrefServiceTest, NoObserverFire) {
registrar.Add(pref_name, obs.GetCallback());
// This should fire the checks in MockPrefChangeCallback::OnPreferenceChanged.
- const base::StringValue expected_value(new_pref_value);
+ const base::Value expected_value(new_pref_value);
obs.Expect(pref_name, &expected_value);
prefs.SetString(pref_name, new_pref_value);
Mock::VerifyAndClearExpectations(&obs);
@@ -50,7 +51,7 @@ TEST(PrefServiceTest, NoObserverFire) {
Mock::VerifyAndClearExpectations(&obs);
// Clearing the pref should cause the pref to fire.
- const base::StringValue expected_default_value((std::string()));
+ const base::Value expected_default_value((std::string()));
obs.Expect(pref_name, &expected_default_value);
prefs.ClearPref(pref_name);
Mock::VerifyAndClearExpectations(&obs);
@@ -84,11 +85,11 @@ TEST(PrefServiceTest, Observers) {
TestingPrefServiceSimple prefs;
prefs.SetUserPref(pref_name,
- new base::StringValue("http://www.cnn.com"));
+ base::MakeUnique<base::Value>("http://www.cnn.com"));
prefs.registry()->RegisterStringPref(pref_name, std::string());
const char new_pref_value[] = "http://www.google.com/";
- const base::StringValue expected_new_pref_value(new_pref_value);
+ const base::Value expected_new_pref_value(new_pref_value);
MockPrefChangeCallback obs(&prefs);
PrefChangeRegistrar registrar;
registrar.Init(&prefs);
@@ -104,7 +105,7 @@ TEST(PrefServiceTest, Observers) {
// Now try adding a second pref observer.
const char new_pref_value2[] = "http://www.youtube.com/";
- const base::StringValue expected_new_pref_value2(new_pref_value2);
+ const base::Value expected_new_pref_value2(new_pref_value2);
MockPrefChangeCallback obs2(&prefs);
obs.Expect(pref_name, &expected_new_pref_value2);
obs2.Expect(pref_name, &expected_new_pref_value2);
@@ -115,12 +116,12 @@ TEST(PrefServiceTest, Observers) {
Mock::VerifyAndClearExpectations(&obs2);
// Set a recommended value.
- const base::StringValue recommended_pref_value("http://www.gmail.com/");
+ const base::Value recommended_pref_value("http://www.gmail.com/");
obs.Expect(pref_name, &expected_new_pref_value2);
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.DeepCopy());
+ prefs.SetRecommendedPref(pref_name, recommended_pref_value.CreateDeepCopy());
Mock::VerifyAndClearExpectations(&obs);
Mock::VerifyAndClearExpectations(&obs2);
@@ -142,8 +143,7 @@ TEST(PrefServiceTest, GetValueChangedType) {
prefs.registry()->RegisterIntegerPref(kPrefName, kTestValue);
// Check falling back to a recommended value.
- prefs.SetUserPref(kPrefName,
- new base::StringValue("not an integer"));
+ prefs.SetUserPref(kPrefName, base::MakeUnique<base::Value>("not an integer"));
const PrefService::Preference* pref = prefs.FindPreference(kPrefName);
ASSERT_TRUE(pref);
const base::Value* value = pref->GetValue();
@@ -178,7 +178,7 @@ TEST(PrefServiceTest, GetValueAndGetRecommendedValue) {
ASSERT_FALSE(value);
// Set a user-set value.
- prefs.SetUserPref(kPrefName, new base::Value(kUserValue));
+ prefs.SetUserPref(kPrefName, base::MakeUnique<base::Value>(kUserValue));
// Check that GetValue() returns the user-set value.
value = pref->GetValue();
@@ -193,7 +193,8 @@ TEST(PrefServiceTest, GetValueAndGetRecommendedValue) {
ASSERT_FALSE(value);
// Set a recommended value.
- prefs.SetRecommendedPref(kPrefName, new base::Value(kRecommendedValue));
+ prefs.SetRecommendedPref(kPrefName,
+ base::MakeUnique<base::Value>(kRecommendedValue));
// Check that GetValue() returns the user-set value.
value = pref->GetValue();
@@ -314,8 +315,9 @@ TEST(PrefServiceTest, WriteablePrefStoreFlags) {
for (size_t i = 0; i < arraysize(kRegistrationToWriteFlags); ++i) {
RegistrationToWriteFlags entry = kRegistrationToWriteFlags[i];
- registry->RegisterDictionaryPref(
- entry.pref_name, new base::DictionaryValue(), entry.registration_flags);
+ registry->RegisterDictionaryPref(entry.pref_name,
+ base::MakeUnique<base::DictionaryValue>(),
+ entry.registration_flags);
SCOPED_TRACE("Currently testing pref with name: " +
std::string(entry.pref_name));
@@ -332,7 +334,8 @@ TEST(PrefServiceTest, WriteablePrefStoreFlags) {
EXPECT_TRUE(flag_checker->last_write_flags_set());
EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear());
- prefs->SetUserPrefValue(entry.pref_name, new base::DictionaryValue());
+ prefs->SetUserPrefValue(entry.pref_name,
+ base::MakeUnique<base::DictionaryValue>());
EXPECT_TRUE(flag_checker->last_write_flags_set());
EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear());
}
@@ -354,7 +357,7 @@ const char PrefServiceSetValueTest::kValue[] = "value";
TEST_F(PrefServiceSetValueTest, SetStringValue) {
const char default_string[] = "default";
- const base::StringValue default_value(default_string);
+ const base::Value default_value(default_string);
prefs_.registry()->RegisterStringPref(kName, default_string);
PrefChangeRegistrar registrar;
@@ -370,7 +373,7 @@ TEST_F(PrefServiceSetValueTest, SetStringValue) {
prefs_.Set(kName, default_value);
Mock::VerifyAndClearExpectations(&observer_);
- base::StringValue new_value(kValue);
+ base::Value new_value(kValue);
observer_.Expect(kName, &new_value);
prefs_.Set(kName, new_value);
Mock::VerifyAndClearExpectations(&observer_);
diff --git a/chromium/components/prefs/pref_value_map.cc b/chromium/components/prefs/pref_value_map.cc
index a0352670400..1d120a8fbd9 100644
--- a/chromium/components/prefs/pref_value_map.cc
+++ b/chromium/components/prefs/pref_value_map.cc
@@ -103,7 +103,7 @@ bool PrefValueMap::GetString(const std::string& key,
void PrefValueMap::SetString(const std::string& key,
const std::string& value) {
- SetValue(key, base::MakeUnique<base::StringValue>(value));
+ SetValue(key, base::MakeUnique<base::Value>(value));
}
bool PrefValueMap::GetInteger(const std::string& key, int* value) const {
diff --git a/chromium/components/prefs/pref_value_map_unittest.cc b/chromium/components/prefs/pref_value_map_unittest.cc
index f6912da8816..0ad8cd1ef70 100644
--- a/chromium/components/prefs/pref_value_map_unittest.cc
+++ b/chromium/components/prefs/pref_value_map_unittest.cc
@@ -17,12 +17,12 @@ TEST(PrefValueMapTest, SetValue) {
EXPECT_FALSE(map.GetValue("key", &result));
EXPECT_FALSE(result);
- EXPECT_TRUE(map.SetValue("key", base::MakeUnique<StringValue>("test")));
- EXPECT_FALSE(map.SetValue("key", base::MakeUnique<StringValue>("test")));
- EXPECT_TRUE(map.SetValue("key", base::MakeUnique<StringValue>("hi mom!")));
+ EXPECT_TRUE(map.SetValue("key", base::MakeUnique<Value>("test")));
+ EXPECT_FALSE(map.SetValue("key", base::MakeUnique<Value>("test")));
+ EXPECT_TRUE(map.SetValue("key", base::MakeUnique<Value>("hi mom!")));
EXPECT_TRUE(map.GetValue("key", &result));
- EXPECT_TRUE(StringValue("hi mom!").Equals(result));
+ EXPECT_TRUE(Value("hi mom!").Equals(result));
}
TEST(PrefValueMapTest, GetAndSetIntegerValue) {
@@ -53,7 +53,7 @@ TEST(PrefValueMapTest, RemoveValue) {
PrefValueMap map;
EXPECT_FALSE(map.RemoveValue("key"));
- EXPECT_TRUE(map.SetValue("key", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(map.SetValue("key", base::MakeUnique<Value>("test")));
EXPECT_TRUE(map.GetValue("key", NULL));
EXPECT_TRUE(map.RemoveValue("key"));
@@ -64,7 +64,7 @@ TEST(PrefValueMapTest, RemoveValue) {
TEST(PrefValueMapTest, Clear) {
PrefValueMap map;
- EXPECT_TRUE(map.SetValue("key", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(map.SetValue("key", base::MakeUnique<Value>("test")));
EXPECT_TRUE(map.GetValue("key", NULL));
map.Clear();
@@ -74,9 +74,9 @@ TEST(PrefValueMapTest, Clear) {
TEST(PrefValueMapTest, GetDifferingKeys) {
PrefValueMap reference;
- EXPECT_TRUE(reference.SetValue("b", base::MakeUnique<StringValue>("test")));
- EXPECT_TRUE(reference.SetValue("c", base::MakeUnique<StringValue>("test")));
- EXPECT_TRUE(reference.SetValue("e", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(reference.SetValue("b", base::MakeUnique<Value>("test")));
+ EXPECT_TRUE(reference.SetValue("c", base::MakeUnique<Value>("test")));
+ EXPECT_TRUE(reference.SetValue("e", base::MakeUnique<Value>("test")));
PrefValueMap check;
std::vector<std::string> differing_paths;
@@ -88,9 +88,9 @@ TEST(PrefValueMapTest, GetDifferingKeys) {
expected_differing_paths.push_back("e");
EXPECT_EQ(expected_differing_paths, differing_paths);
- EXPECT_TRUE(check.SetValue("a", base::MakeUnique<StringValue>("test")));
- EXPECT_TRUE(check.SetValue("c", base::MakeUnique<StringValue>("test")));
- EXPECT_TRUE(check.SetValue("d", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(check.SetValue("a", base::MakeUnique<Value>("test")));
+ EXPECT_TRUE(check.SetValue("c", base::MakeUnique<Value>("test")));
+ EXPECT_TRUE(check.SetValue("d", base::MakeUnique<Value>("test")));
reference.GetDifferingKeys(&check, &differing_paths);
expected_differing_paths.clear();
@@ -103,14 +103,14 @@ TEST(PrefValueMapTest, GetDifferingKeys) {
TEST(PrefValueMapTest, SwapTwoMaps) {
PrefValueMap first_map;
- EXPECT_TRUE(first_map.SetValue("a", base::MakeUnique<StringValue>("test")));
- EXPECT_TRUE(first_map.SetValue("b", base::MakeUnique<StringValue>("test")));
- EXPECT_TRUE(first_map.SetValue("c", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(first_map.SetValue("a", base::MakeUnique<Value>("test")));
+ EXPECT_TRUE(first_map.SetValue("b", base::MakeUnique<Value>("test")));
+ EXPECT_TRUE(first_map.SetValue("c", base::MakeUnique<Value>("test")));
PrefValueMap second_map;
- EXPECT_TRUE(second_map.SetValue("d", base::MakeUnique<StringValue>("test")));
- EXPECT_TRUE(second_map.SetValue("e", base::MakeUnique<StringValue>("test")));
- EXPECT_TRUE(second_map.SetValue("f", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(second_map.SetValue("d", base::MakeUnique<Value>("test")));
+ EXPECT_TRUE(second_map.SetValue("e", base::MakeUnique<Value>("test")));
+ EXPECT_TRUE(second_map.SetValue("f", base::MakeUnique<Value>("test")));
first_map.Swap(&second_map);
diff --git a/chromium/components/prefs/pref_value_store.h b/chromium/components/prefs/pref_value_store.h
index 39b6bf1870e..eeab3062fbe 100644
--- a/chromium/components/prefs/pref_value_store.h
+++ b/chromium/components/prefs/pref_value_store.h
@@ -7,6 +7,7 @@
#include <map>
#include <string>
+#include <type_traits>
#include <vector>
#include "base/callback.h"
@@ -30,6 +31,30 @@ class COMPONENTS_PREFS_EXPORT PrefValueStore {
public:
typedef base::Callback<void(const std::string&)> PrefChangedCallback;
+ // PrefStores must be listed here in order from highest to lowest priority.
+ // MANAGED contains all managed preference values 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.
+ // RECOMMENDED contains all preferences that are provided by recommended
+ // policies.
+ // DEFAULT contains all application default preference values.
+ enum PrefStoreType {
+ // INVALID_STORE is not associated with an actual PrefStore but used as
+ // an invalid marker, e.g. as a return value.
+ INVALID_STORE = -1,
+ MANAGED_STORE = 0,
+ SUPERVISED_USER_STORE,
+ EXTENSION_STORE,
+ COMMAND_LINE_STORE,
+ USER_STORE,
+ RECOMMENDED_STORE,
+ DEFAULT_STORE,
+ PREF_STORE_TYPE_MAX = DEFAULT_STORE
+ };
+
// In decreasing order of precedence:
// |managed_prefs| contains all preferences from mandatory policies.
// |supervised_user_prefs| contains all preferences from supervised user
@@ -118,30 +143,6 @@ class COMPONENTS_PREFS_EXPORT PrefValueStore {
void UpdateCommandLinePrefStore(PrefStore* command_line_prefs);
private:
- // PrefStores must be listed here in order from highest to lowest priority.
- // MANAGED contains all managed preference values 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.
- // RECOMMENDED contains all preferences that are provided by recommended
- // policies.
- // DEFAULT contains all application default preference values.
- enum PrefStoreType {
- // INVALID_STORE is not associated with an actual PrefStore but used as
- // an invalid marker, e.g. as a return value.
- INVALID_STORE = -1,
- MANAGED_STORE = 0,
- SUPERVISED_USER_STORE,
- EXTENSION_STORE,
- COMMAND_LINE_STORE,
- USER_STORE,
- RECOMMENDED_STORE,
- DEFAULT_STORE,
- PREF_STORE_TYPE_MAX = DEFAULT_STORE
- };
-
// Keeps a PrefStore reference on behalf of the PrefValueStore and monitors
// the PrefStore for changes, forwarding notifications to PrefValueStore. This
// indirection is here for the sake of disambiguating notifications from the
@@ -257,4 +258,16 @@ class COMPONENTS_PREFS_EXPORT PrefValueStore {
DISALLOW_COPY_AND_ASSIGN(PrefValueStore);
};
+namespace std {
+
+template <>
+struct hash<PrefValueStore::PrefStoreType> {
+ size_t operator()(PrefValueStore::PrefStoreType type) const {
+ return std::hash<
+ std::underlying_type<PrefValueStore::PrefStoreType>::type>()(type);
+ }
+};
+
+} // namespace std
+
#endif // COMPONENTS_PREFS_PREF_VALUE_STORE_H_
diff --git a/chromium/components/prefs/testing_pref_service.h b/chromium/components/prefs/testing_pref_service.h
index 6f9171740bf..5378968d7d5 100644
--- a/chromium/components/prefs/testing_pref_service.h
+++ b/chromium/components/prefs/testing_pref_service.h
@@ -6,6 +6,7 @@
#define COMPONENTS_PREFS_TESTING_PREF_SERVICE_H_
#include <memory>
+#include <utility>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
@@ -33,8 +34,9 @@ class TestingPrefServiceBase : public SuperPrefService {
const base::Value* GetManagedPref(const std::string& path) const;
// Set a preference on the managed layer and fire observers if the preference
- // changed. Assumes ownership of |value|.
- void SetManagedPref(const std::string& path, base::Value* value);
+ // changed.
+ void SetManagedPref(const std::string& path,
+ std::unique_ptr<base::Value> value);
// Clear the preference on the managed layer and fire observers if the
// preference has been defined previously.
@@ -45,17 +47,19 @@ class TestingPrefServiceBase : public SuperPrefService {
// Useful in tests that only check that a preference is overridden by an
// extension.
const base::Value* GetExtensionPref(const std::string& path) const;
- void SetExtensionPref(const std::string& path, base::Value* value);
+ void SetExtensionPref(const std::string& path,
+ std::unique_ptr<base::Value> value);
void RemoveExtensionPref(const std::string& path);
// Similar to the above, but for user preferences.
const base::Value* GetUserPref(const std::string& path) const;
- void SetUserPref(const std::string& path, base::Value* value);
+ void SetUserPref(const std::string& path, std::unique_ptr<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, base::Value* value);
+ void SetRecommendedPref(const std::string& path,
+ std::unique_ptr<base::Value> value);
void RemoveRecommendedPref(const std::string& path);
// Do-nothing implementation for TestingPrefService.
@@ -78,7 +82,7 @@ class TestingPrefServiceBase : public SuperPrefService {
// Sets the value for |path| in |pref_store|.
void SetPref(TestingPrefStore* pref_store,
const std::string& path,
- base::Value* value);
+ std::unique_ptr<base::Value> value);
// Removes the preference identified by |path| from |pref_store|.
void RemovePref(TestingPrefStore* pref_store, const std::string& path);
@@ -133,8 +137,9 @@ const base::Value* TestingPrefServiceBase<
template <class SuperPrefService, class ConstructionPrefRegistry>
void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
- SetManagedPref(const std::string& path, base::Value* value) {
- SetPref(managed_prefs_.get(), path, value);
+ SetManagedPref(const std::string& path,
+ std::unique_ptr<base::Value> value) {
+ SetPref(managed_prefs_.get(), path, std::move(value));
}
template <class SuperPrefService, class ConstructionPrefRegistry>
@@ -152,8 +157,9 @@ const base::Value* TestingPrefServiceBase<
template <class SuperPrefService, class ConstructionPrefRegistry>
void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
- SetExtensionPref(const std::string& path, base::Value* value) {
- SetPref(extension_prefs_.get(), path, value);
+ SetExtensionPref(const std::string& path,
+ std::unique_ptr<base::Value> value) {
+ SetPref(extension_prefs_.get(), path, std::move(value));
}
template <class SuperPrefService, class ConstructionPrefRegistry>
@@ -171,8 +177,8 @@ TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::GetUserPref(
template <class SuperPrefService, class ConstructionPrefRegistry>
void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
- SetUserPref(const std::string& path, base::Value* value) {
- SetPref(user_prefs_.get(), path, value);
+ SetUserPref(const std::string& path, std::unique_ptr<base::Value> value) {
+ SetPref(user_prefs_.get(), path, std::move(value));
}
template <class SuperPrefService, class ConstructionPrefRegistry>
@@ -190,8 +196,9 @@ 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, value);
+ SetRecommendedPref(const std::string& path,
+ std::unique_ptr<base::Value> value) {
+ SetPref(recommended_prefs_.get(), path, std::move(value));
}
template <class SuperPrefService, class ConstructionPrefRegistry>
@@ -213,8 +220,8 @@ template <class SuperPrefService, class ConstructionPrefRegistry>
void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
SetPref(TestingPrefStore* pref_store,
const std::string& path,
- base::Value* value) {
- pref_store->SetValue(path, base::WrapUnique(value),
+ std::unique_ptr<base::Value> value) {
+ pref_store->SetValue(path, std::move(value),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
}
diff --git a/chromium/components/prefs/testing_pref_store.cc b/chromium/components/prefs/testing_pref_store.cc
index 8f6f2098d47..e9b04c8e54f 100644
--- a/chromium/components/prefs/testing_pref_store.cc
+++ b/chromium/components/prefs/testing_pref_store.cc
@@ -124,8 +124,7 @@ void TestingPrefStore::ReportValueChanged(const std::string& key,
void TestingPrefStore::SetString(const std::string& key,
const std::string& value) {
- SetValue(key, base::MakeUnique<base::StringValue>(value),
- DEFAULT_PREF_WRITE_FLAGS);
+ SetValue(key, base::MakeUnique<base::Value>(value), DEFAULT_PREF_WRITE_FLAGS);
}
void TestingPrefStore::SetInteger(const std::string& key, int value) {
diff --git a/chromium/components/previews/core/BUILD.gn b/chromium/components/previews/core/BUILD.gn
index 92ae912fb4f..e2f014cac8f 100644
--- a/chromium/components/previews/core/BUILD.gn
+++ b/chromium/components/previews/core/BUILD.gn
@@ -8,8 +8,6 @@ static_library("core") {
"previews_black_list.h",
"previews_black_list_item.cc",
"previews_black_list_item.h",
- "previews_data_savings.cc",
- "previews_data_savings.h",
"previews_decider.h",
"previews_experiments.cc",
"previews_experiments.h",
@@ -24,7 +22,6 @@ static_library("core") {
deps = [
"//base",
- "//components/data_reduction_proxy/core/common",
"//components/variations",
"//net:net",
"//sql",
@@ -37,7 +34,6 @@ source_set("unit_tests") {
sources = [
"previews_black_list_item_unittest.cc",
"previews_black_list_unittest.cc",
- "previews_data_savings_unittest.cc",
"previews_experiments_unittest.cc",
"previews_io_data_unittest.cc",
"previews_opt_out_store_sql_unittest.cc",
@@ -48,7 +44,6 @@ source_set("unit_tests") {
":core",
"//base",
"//base/test:test_support",
- "//components/data_reduction_proxy/core/common",
"//components/variations",
"//net:net",
"//net:test_support",
diff --git a/chromium/components/previews/core/DEPS b/chromium/components/previews/core/DEPS
index 5077fc34b96..6193f48aab1 100644
--- a/chromium/components/previews/core/DEPS
+++ b/chromium/components/previews/core/DEPS
@@ -1,6 +1,5 @@
include_rules = [
"+components/variations",
- "+components/data_reduction_proxy/core/common",
"+net",
"+sql"
]
diff --git a/chromium/components/previews/core/previews_data_savings.cc b/chromium/components/previews/core/previews_data_savings.cc
deleted file mode 100644
index 267f44b12c7..00000000000
--- a/chromium/components/previews/core/previews_data_savings.cc
+++ /dev/null
@@ -1,71 +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/previews/core/previews_data_savings.h"
-
-#include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
-#include "components/data_reduction_proxy/core/common/data_savings_recorder.h"
-
-namespace previews {
-
-PreviewsDataSavings::PreviewsDataSavings(
- data_reduction_proxy::DataSavingsRecorder* data_savings_recorder)
- : data_savings_recorder_(data_savings_recorder) {
- DCHECK(data_savings_recorder);
-}
-
-PreviewsDataSavings::~PreviewsDataSavings() {
- DCHECK(thread_checker_.CalledOnValidThread());
-}
-
-void PreviewsDataSavings::RecordDataSavings(
- const std::string& fully_qualified_domain_name,
- int64_t data_used,
- int64_t original_size) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- // Only record savings when data saver is enabled.
- if (!data_savings_recorder_->UpdateDataSavings(fully_qualified_domain_name,
- data_used, original_size)) {
- // Record metrics in KB for previews with data saver disabled.
- UMA_HISTOGRAM_COUNTS("Previews.OriginalContentLength.DataSaverDisabled",
- original_size >> 10);
- UMA_HISTOGRAM_COUNTS("Previews.ContentLength.DataSaverDisabled",
- data_used >> 10);
- if (original_size >= data_used) {
- UMA_HISTOGRAM_COUNTS("Previews.DataSavings.DataSaverDisabled",
- (original_size - data_used) >> 10);
- UMA_HISTOGRAM_PERCENTAGE(
- "Previews.DataSavingsPercent.DataSaverDisabled",
- (original_size - data_used) * 100 / original_size);
- } else {
- UMA_HISTOGRAM_COUNTS("Previews.DataInflation.DataSaverDisabled",
- (data_used - original_size) >> 10);
- UMA_HISTOGRAM_PERCENTAGE(
- "Previews.DataInflationPercent.DataSaverDisabled",
- (data_used - original_size) * 100 / data_used);
- }
- return;
- }
-
- // Record metrics in KB for previews with data saver enabled.
- UMA_HISTOGRAM_COUNTS("Previews.OriginalContentLength.DataSaverEnabled",
- original_size >> 10);
- UMA_HISTOGRAM_COUNTS("Previews.ContentLength.DataSaverEnabled",
- data_used >> 10);
- if (original_size >= data_used) {
- UMA_HISTOGRAM_COUNTS("Previews.DataSavings.DataSaverEnabled",
- (original_size - data_used) >> 10);
- UMA_HISTOGRAM_PERCENTAGE("Previews.DataSavingsPercent.DataSaverEnabled",
- (original_size - data_used) * 100 / original_size);
- } else {
- UMA_HISTOGRAM_COUNTS("Previews.DataInflation.DataSaverEnabled",
- (data_used - original_size) >> 10);
- UMA_HISTOGRAM_PERCENTAGE("Previews.DataInflationPercent.DataSaverEnabled",
- (data_used - original_size) * 100 / data_used);
- }
-}
-
-} // namespace previews
diff --git a/chromium/components/previews/core/previews_data_savings.h b/chromium/components/previews/core/previews_data_savings.h
deleted file mode 100644
index ce37cf168e9..00000000000
--- a/chromium/components/previews/core/previews_data_savings.h
+++ /dev/null
@@ -1,51 +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_PREVIEWS_CORE_PREVIEWS_DATA_SAVINGS_H_
-#define COMPONENTS_PREVIEWS_CORE_PREVIEWS_DATA_SAVINGS_H_
-
-#include <stdint.h>
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/threading/thread_checker.h"
-
-namespace data_reduction_proxy {
-class DataSavingsRecorder;
-}
-
-namespace previews {
-
-// Provides an interface for previews to report data savings.
-class PreviewsDataSavings {
- public:
- // Embedder must guarantee that |data_savings_recorder| and
- // |data_reduction_proxy_settings| outlive this instance.
- PreviewsDataSavings(
- data_reduction_proxy::DataSavingsRecorder* data_savings_recorder);
- ~PreviewsDataSavings();
-
- // Records the amount of data used by the preview, and the amount of data
- // that would have been used if the original page had been loaded instead of
- // the preview. |fully_qualified_domain_name| is the full host name to
- // attribute the data savings to (e.g., codereview.chromium.org).
- void RecordDataSavings(const std::string& fully_qualified_domain_name,
- int64_t data_used,
- int64_t original_size);
-
- private:
- // Owned by the embedder, must be valid for the lifetime of |this|.
- // Provides a method to record data savings.
- data_reduction_proxy::DataSavingsRecorder* data_savings_recorder_;
-
- // Enforce usage on the UI thread.
- base::ThreadChecker thread_checker_;
-
- DISALLOW_COPY_AND_ASSIGN(PreviewsDataSavings);
-};
-
-} // namespace previews
-
-#endif // COMPONENTS_PREVIEWS_CORE_PREVIEWS_DATA_SAVINGS_H_
diff --git a/chromium/components/previews/core/previews_data_savings_unittest.cc b/chromium/components/previews/core/previews_data_savings_unittest.cc
deleted file mode 100644
index bd749248547..00000000000
--- a/chromium/components/previews/core/previews_data_savings_unittest.cc
+++ /dev/null
@@ -1,166 +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/previews/core/previews_data_savings.h"
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/test/histogram_tester.h"
-#include "components/data_reduction_proxy/core/common/data_savings_recorder.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace previews {
-
-namespace {
-
-class TestDataSavingsRecorder
- : public data_reduction_proxy::DataSavingsRecorder {
- public:
- TestDataSavingsRecorder()
- : data_saver_enabled_(false), data_used_(0), original_size_(0) {}
- ~TestDataSavingsRecorder() {}
-
- // data_reduction_proxy::DataSavingsRecorder implementation:
- bool UpdateDataSavings(const std::string& host,
- int64_t data_used,
- int64_t original_size) override {
- if (!data_saver_enabled_) {
- return false;
- }
- last_host_ = host;
- data_used_ += data_used;
- original_size_ += original_size;
- return true;
- }
-
- void set_data_saver_enabled(bool data_saver_enabled) {
- data_saver_enabled_ = data_saver_enabled;
- }
-
- std::string last_host() const { return last_host_; }
-
- int64_t data_used() const { return data_used_; }
-
- int64_t original_size() const { return original_size_; }
-
- private:
- bool data_saver_enabled_;
- std::string last_host_;
- int64_t data_used_;
- int64_t original_size_;
-};
-
-} // namespace
-
-class PreviewsDataSavingsTest : public testing::Test {
- public:
- PreviewsDataSavingsTest()
- : test_data_savings_recorder_(new TestDataSavingsRecorder()),
- data_savings_(
- new PreviewsDataSavings(test_data_savings_recorder_.get())) {}
- ~PreviewsDataSavingsTest() override {}
-
- PreviewsDataSavings* data_savings() const { return data_savings_.get(); }
-
- TestDataSavingsRecorder* test_data_savings_recorder() const {
- return test_data_savings_recorder_.get();
- }
-
- base::HistogramTester* histogram_tester() { return &histogram_tester_; }
-
- private:
- base::HistogramTester histogram_tester_;
-
- std::unique_ptr<TestDataSavingsRecorder> test_data_savings_recorder_;
- std::unique_ptr<PreviewsDataSavings> data_savings_;
-};
-
-TEST_F(PreviewsDataSavingsTest, RecordDataSavings) {
- int64_t original_size = 200;
- int64_t data_used = 100;
- std::string host = "host";
-
- EXPECT_EQ(0, test_data_savings_recorder()->data_used());
- EXPECT_EQ(0, test_data_savings_recorder()->original_size());
- test_data_savings_recorder()->set_data_saver_enabled(false);
- data_savings()->RecordDataSavings(host, data_used, original_size);
-
- EXPECT_EQ(0, test_data_savings_recorder()->data_used());
- EXPECT_EQ(0, test_data_savings_recorder()->original_size());
- EXPECT_EQ(std::string(), test_data_savings_recorder()->last_host());
-
- test_data_savings_recorder()->set_data_saver_enabled(true);
- data_savings()->RecordDataSavings(host, data_used, original_size);
-
- EXPECT_EQ(data_used, test_data_savings_recorder()->data_used());
- EXPECT_EQ(original_size, test_data_savings_recorder()->original_size());
- EXPECT_EQ(host, test_data_savings_recorder()->last_host());
-}
-
-TEST_F(PreviewsDataSavingsTest, RecordDataSavingsHistograms) {
- int64_t twenty_kb = 20480;
- int64_t twenty = twenty_kb >> 10;
- int64_t ten_kb = 10240;
- int64_t ten = ten_kb >> 10;
- std::string host = "host";
-
- test_data_savings_recorder()->set_data_saver_enabled(false);
- data_savings()->RecordDataSavings(host, ten_kb, twenty_kb);
-
- // The histograms record bytes in KB.
- histogram_tester()->ExpectUniqueSample(
- "Previews.OriginalContentLength.DataSaverDisabled", twenty, 1);
- histogram_tester()->ExpectUniqueSample(
- "Previews.ContentLength.DataSaverDisabled", ten, 1);
- histogram_tester()->ExpectUniqueSample(
- "Previews.DataSavings.DataSaverDisabled", twenty - ten, 1);
- histogram_tester()->ExpectUniqueSample(
- "Previews.DataSavingsPercent.DataSaverDisabled",
- (twenty_kb - ten_kb) * 100 / twenty_kb, 1);
-
- data_savings()->RecordDataSavings(host, twenty_kb, ten_kb);
-
- // The histograms record bytes in KB.
- histogram_tester()->ExpectBucketCount(
- "Previews.OriginalContentLength.DataSaverDisabled", ten, 1);
- histogram_tester()->ExpectBucketCount(
- "Previews.ContentLength.DataSaverDisabled", twenty, 1);
- histogram_tester()->ExpectUniqueSample(
- "Previews.DataInflation.DataSaverDisabled", twenty - ten, 1);
- histogram_tester()->ExpectUniqueSample(
- "Previews.DataInflationPercent.DataSaverDisabled",
- (twenty_kb - ten_kb) * 100 / twenty_kb, 1);
-
- test_data_savings_recorder()->set_data_saver_enabled(true);
- data_savings()->RecordDataSavings(host, ten_kb, twenty_kb);
-
- // The histograms record bytes in KB.
- histogram_tester()->ExpectUniqueSample(
- "Previews.OriginalContentLength.DataSaverEnabled", twenty, 1);
- histogram_tester()->ExpectUniqueSample(
- "Previews.ContentLength.DataSaverEnabled", ten, 1);
- histogram_tester()->ExpectUniqueSample(
- "Previews.DataSavings.DataSaverEnabled", twenty - ten, 1);
- histogram_tester()->ExpectUniqueSample(
- "Previews.DataSavingsPercent.DataSaverEnabled",
- (twenty_kb - ten_kb) * 100 / twenty_kb, 1);
-
- data_savings()->RecordDataSavings(host, twenty_kb, ten_kb);
-
- // The histograms record bytes in KB.
- histogram_tester()->ExpectBucketCount(
- "Previews.OriginalContentLength.DataSaverEnabled", ten, 1);
- histogram_tester()->ExpectBucketCount(
- "Previews.ContentLength.DataSaverEnabled", twenty, 1);
- histogram_tester()->ExpectUniqueSample(
- "Previews.DataInflation.DataSaverEnabled", twenty - ten, 1);
- histogram_tester()->ExpectUniqueSample(
- "Previews.DataInflationPercent.DataSaverEnabled",
- (twenty_kb - ten_kb) * 100 / twenty_kb, 1);
-}
-
-} // namespace previews
diff --git a/chromium/components/previews/core/previews_experiments.cc b/chromium/components/previews/core/previews_experiments.cc
index 77b973a2da6..e8d738aa60a 100644
--- a/chromium/components/previews/core/previews_experiments.cc
+++ b/chromium/components/previews/core/previews_experiments.cc
@@ -4,14 +4,13 @@
#include "components/previews/core/previews_experiments.h"
-#include <map>
#include <string>
#include "base/logging.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_util.h"
-#include "components/variations/variations_associated_data.h"
namespace previews {
@@ -31,45 +30,6 @@ const char kOfflinePagesSlowNetwork[] = "show_offline_pages";
// result in older blacklist entries being removed.
const char kVersion[] = "version";
-// The maximum number of recent previews navigations the black list looks at to
-// determine if a host is blacklisted.
-const char kMaxStoredHistoryLengthPerHost[] =
- "per_host_max_stored_history_length";
-
-// The maximum number of recent previews navigations the black list looks at to
-// determine if all previews navigations should be disallowed.
-const char kMaxStoredHistoryLengthHostIndifferent[] =
- "host_indifferent_max_stored_history_length";
-
-// The maximum number of hosts allowed in the in memory black list.
-const char kMaxHostsInBlackList[] = "max_hosts_in_blacklist";
-
-// The number of recent navigations that were opted out of that would trigger
-// the host to be blacklisted.
-const char kPerHostOptOutThreshold[] = "per_host_opt_out_threshold";
-
-// The number of recent navigations that were opted out of that would trigger
-// all previews navigations to be disallowed.
-const char kHostIndifferentOptOutThreshold[] =
- "host_indifferent_opt_out_threshold";
-
-// The amount of time a host remains blacklisted due to opt outs.
-const char kPerHostBlackListDurationInDays[] =
- "per_host_black_list_duration_in_days";
-
-// The amount of time a host remains blacklisted due to opt outs.
-const char kHostIndifferentBlackListDurationInDays[] =
- "host_indifferent_black_list_duration_in_days";
-
-// The amount of time after any opt out that no previews should be shown.
-const char kSingleOptOutDurationInSeconds[] =
- "single_opt_out_duration_in_seconds";
-
-// The amount of time that an offline page is considered fresh enough to be
-// shown as a preview.
-const char kOfflinePreviewFreshnessDurationInDays[] =
- "offline_preview_freshness_duration_in_days";
-
// The threshold of EffectiveConnectionType above which previews will not be
// served.
// See net/nqe/effective_connection_type.h for mapping from string to value.
@@ -79,19 +39,40 @@ const char kEffectiveConnectionTypeThreshold[] =
// The string that corresponds to enabled for the variation param experiments.
const char kExperimentEnabled[] = "true";
-// Returns the ClientSidePreviews parameter value of |param| as a string.
-// If there is no value for |param|, returns an empty string.
-std::string ClientSidePreviewsParamValue(const std::string& param) {
- if (!IsIncludedInClientSidePreviewsExperimentsFieldTrial())
- return std::string();
- std::map<std::string, std::string> experiment_params;
- if (!variations::GetVariationParams(kClientSidePreviewsFieldTrial,
- &experiment_params)) {
- return std::string();
+const char kClientLoFiExperimentName[] = "PreviewsClientLoFi";
+
+size_t GetParamValueAsSizeT(const std::string& trial_name,
+ const std::string& param_name,
+ size_t default_value) {
+ size_t value;
+ if (!base::StringToSizeT(
+ base::GetFieldTrialParamValue(trial_name, param_name), &value)) {
+ return default_value;
}
- std::map<std::string, std::string>::const_iterator it =
- experiment_params.find(param);
- return it == experiment_params.end() ? std::string() : it->second;
+ return value;
+}
+
+int GetParamValueAsInt(const std::string& trial_name,
+ const std::string& param_name,
+ int default_value) {
+ int value;
+ if (!base::StringToInt(base::GetFieldTrialParamValue(trial_name, param_name),
+ &value)) {
+ return default_value;
+ }
+ return value;
+}
+
+net::EffectiveConnectionType GetParamValueAsECT(
+ const std::string& trial_name,
+ const std::string& param_name,
+ net::EffectiveConnectionType default_value) {
+ net::EffectiveConnectionType value;
+ if (!net::GetEffectiveConnectionTypeForName(
+ base::GetFieldTrialParamValue(trial_name, param_name), &value)) {
+ return default_value;
+ }
+ return value;
}
} // namespace
@@ -99,155 +80,97 @@ std::string ClientSidePreviewsParamValue(const std::string& param) {
namespace params {
size_t MaxStoredHistoryLengthForPerHostBlackList() {
- std::string param_value =
- ClientSidePreviewsParamValue(kMaxStoredHistoryLengthPerHost);
- size_t history_length;
- if (!base::StringToSizeT(param_value, &history_length))
- history_length = 4;
- return history_length;
+ return GetParamValueAsSizeT(kClientSidePreviewsFieldTrial,
+ "per_host_max_stored_history_length", 4);
}
size_t MaxStoredHistoryLengthForHostIndifferentBlackList() {
- std::string param_value =
- ClientSidePreviewsParamValue(kMaxStoredHistoryLengthHostIndifferent);
- size_t history_length;
- if (!base::StringToSizeT(param_value, &history_length))
- history_length = 10;
- return history_length;
+ return GetParamValueAsSizeT(kClientSidePreviewsFieldTrial,
+ "host_indifferent_max_stored_history_length", 10);
}
size_t MaxInMemoryHostsInBlackList() {
- std::string param_value = ClientSidePreviewsParamValue(kMaxHostsInBlackList);
- size_t max_hosts;
- if (!base::StringToSizeT(param_value, &max_hosts))
- max_hosts = 100;
- return max_hosts;
+ return GetParamValueAsSizeT(kClientSidePreviewsFieldTrial,
+ "max_hosts_in_blacklist", 100);
}
int PerHostBlackListOptOutThreshold() {
- std::string param_value =
- ClientSidePreviewsParamValue(kPerHostOptOutThreshold);
- int opt_out_threshold;
- if (!base::StringToInt(param_value, &opt_out_threshold))
- opt_out_threshold = 2;
- return opt_out_threshold;
+ return GetParamValueAsInt(kClientSidePreviewsFieldTrial,
+ "per_host_opt_out_threshold", 2);
}
int HostIndifferentBlackListOptOutThreshold() {
- std::string param_value =
- ClientSidePreviewsParamValue(kHostIndifferentOptOutThreshold);
- int opt_out_threshold;
- if (!base::StringToInt(param_value, &opt_out_threshold))
- opt_out_threshold = 4;
- return opt_out_threshold;
+ return GetParamValueAsInt(kClientSidePreviewsFieldTrial,
+ "host_indifferent_opt_out_threshold", 4);
}
base::TimeDelta PerHostBlackListDuration() {
- std::string param_value =
- ClientSidePreviewsParamValue(kPerHostBlackListDurationInDays);
- int duration;
- if (!base::StringToInt(param_value, &duration))
- duration = 30;
- return base::TimeDelta::FromDays(duration);
+ return base::TimeDelta::FromDays(
+ GetParamValueAsInt(kClientSidePreviewsFieldTrial,
+ "per_host_black_list_duration_in_days", 30));
}
base::TimeDelta HostIndifferentBlackListPerHostDuration() {
- std::string param_value =
- ClientSidePreviewsParamValue(kHostIndifferentBlackListDurationInDays);
- int duration;
- if (!base::StringToInt(param_value, &duration))
- duration = 365 * 100;
- return base::TimeDelta::FromDays(duration);
+ return base::TimeDelta::FromDays(GetParamValueAsInt(
+ kClientSidePreviewsFieldTrial,
+ "host_indifferent_black_list_duration_in_days", 365 * 100));
}
base::TimeDelta SingleOptOutDuration() {
- std::string param_value =
- ClientSidePreviewsParamValue(kSingleOptOutDurationInSeconds);
- int duration;
- if (!base::StringToInt(param_value, &duration))
- duration = 60 * 5;
- return base::TimeDelta::FromSeconds(duration);
+ return base::TimeDelta::FromSeconds(
+ GetParamValueAsInt(kClientSidePreviewsFieldTrial,
+ "single_opt_out_duration_in_seconds", 60 * 5));
}
base::TimeDelta OfflinePreviewFreshnessDuration() {
- std::string param_value =
- ClientSidePreviewsParamValue(kOfflinePreviewFreshnessDurationInDays);
- int duration;
- if (!base::StringToInt(param_value, &duration))
- duration = 7;
- return base::TimeDelta::FromDays(duration);
-}
-
-net::EffectiveConnectionType EffectiveConnectionTypeThreshold() {
- std::string param_value =
- ClientSidePreviewsParamValue(kEffectiveConnectionTypeThreshold);
- net::EffectiveConnectionType effective_connection_type;
- if (!net::GetEffectiveConnectionTypeForName(param_value,
- &effective_connection_type)) {
- effective_connection_type = net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
- }
- return effective_connection_type;
+ return base::TimeDelta::FromDays(
+ GetParamValueAsInt(kClientSidePreviewsFieldTrial,
+ "offline_preview_freshness_duration_in_days", 7));
}
-} // namespace params
-
-bool IsIncludedInClientSidePreviewsExperimentsFieldTrial() {
- // By convention, an experiment in the client-side previews study enables use
- // of at least one client-side previews optimization if its name begins with
- // "Enabled."
- return base::StartsWith(
- base::FieldTrialList::FindFullName(kClientSidePreviewsFieldTrial),
- kEnabled, base::CompareCase::SENSITIVE);
+net::EffectiveConnectionType EffectiveConnectionTypeThresholdForOffline() {
+ return GetParamValueAsECT(kClientSidePreviewsFieldTrial,
+ kEffectiveConnectionTypeThreshold,
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
}
-bool IsPreviewsTypeEnabled(PreviewsType type) {
- switch (type) {
- case PreviewsType::OFFLINE:
- return ClientSidePreviewsParamValue(kOfflinePagesSlowNetwork) ==
+bool IsOfflinePreviewsEnabled() {
+ // Check if "show_offline_pages" is set to "true".
+ return IsIncludedInClientSidePreviewsExperimentsFieldTrial() &&
+ base::GetFieldTrialParamValue(kClientSidePreviewsFieldTrial,
+ kOfflinePagesSlowNetwork) ==
kExperimentEnabled;
- default:
- NOTREACHED();
- return false;
- }
}
-int GetPreviewsTypeVersion(PreviewsType type) {
- int version = 0; // default
- switch (type) {
- case PreviewsType::OFFLINE:
- base::StringToInt(ClientSidePreviewsParamValue(kVersion), &version);
- return version;
- // List remaining enum cases vs. default to catch when new one is added.
- case PreviewsType::NONE:
- break;
- case PreviewsType::LAST:
- break;
- }
- NOTREACHED();
- return -1;
+int OfflinePreviewsVersion() {
+ return GetParamValueAsInt(kClientSidePreviewsFieldTrial, kVersion, 0);
}
-std::unique_ptr<PreviewsTypeList> GetEnabledPreviews() {
- std::unique_ptr<PreviewsTypeList> enabled_previews(new PreviewsTypeList());
+bool IsClientLoFiEnabled() {
+ return base::StartsWith(
+ base::FieldTrialList::FindFullName(kClientLoFiExperimentName), kEnabled,
+ base::CompareCase::SENSITIVE);
+}
- // Loop across all previews types (relies on sequential enum values).
- for (int i = static_cast<int>(PreviewsType::NONE) + 1;
- i < static_cast<int>(PreviewsType::LAST); ++i) {
- PreviewsType type = static_cast<PreviewsType>(i);
- if (IsPreviewsTypeEnabled(type)) {
- enabled_previews->push_back({type, GetPreviewsTypeVersion(type)});
- }
- }
- return enabled_previews;
+int ClientLoFiVersion() {
+ return GetParamValueAsInt(kClientLoFiExperimentName, kVersion, 0);
}
-bool EnableOfflinePreviewsForTesting() {
- std::map<std::string, std::string> params;
- params[kOfflinePagesSlowNetwork] = kExperimentEnabled;
- return variations::AssociateVariationParams(kClientSidePreviewsFieldTrial,
- kEnabled, params) &&
- base::FieldTrialList::CreateFieldTrial(kClientSidePreviewsFieldTrial,
- kEnabled);
+net::EffectiveConnectionType EffectiveConnectionTypeThresholdForClientLoFi() {
+ return GetParamValueAsECT(kClientLoFiExperimentName,
+ kEffectiveConnectionTypeThreshold,
+ net::EFFECTIVE_CONNECTION_TYPE_2G);
+}
+
+} // namespace params
+
+bool IsIncludedInClientSidePreviewsExperimentsFieldTrial() {
+ // By convention, an experiment in the client-side previews study enables use
+ // of at least one client-side previews optimization if its name begins with
+ // "Enabled."
+ return base::StartsWith(
+ base::FieldTrialList::FindFullName(kClientSidePreviewsFieldTrial),
+ kEnabled, base::CompareCase::SENSITIVE);
}
} // namespace previews
diff --git a/chromium/components/previews/core/previews_experiments.h b/chromium/components/previews/core/previews_experiments.h
index 0a6f3a6f9a3..7dd7bc2c42c 100644
--- a/chromium/components/previews/core/previews_experiments.h
+++ b/chromium/components/previews/core/previews_experiments.h
@@ -5,7 +5,6 @@
#ifndef COMPONENTS_PREVIEWS_CORE_PREVIEWS_EXPERIMENTS_H_
#define COMPONENTS_PREVIEWS_CORE_PREVIEWS_EXPERIMENTS_H_
-#include <memory>
#include <utility>
#include <vector>
@@ -48,18 +47,40 @@ base::TimeDelta SingleOptOutDuration();
// shown as a preview.
base::TimeDelta OfflinePreviewFreshnessDuration();
-// The threshold of EffectiveConnectionType above which previews should not be
-// served.
-net::EffectiveConnectionType EffectiveConnectionTypeThreshold();
+// The threshold of EffectiveConnectionType above which offline previews should
+// not be served.
+net::EffectiveConnectionType EffectiveConnectionTypeThresholdForOffline();
+
+// Whether offline previews are enabled.
+bool IsOfflinePreviewsEnabled();
+
+// The blacklist version for offline previews.
+int OfflinePreviewsVersion();
+
+// Whether Client LoFi previews are enabled.
+bool IsClientLoFiEnabled();
+
+// The blacklist version for Client LoFi previews.
+int ClientLoFiVersion();
+
+// The threshold of EffectiveConnectionType above which Client LoFi previews
+// should not be served.
+net::EffectiveConnectionType EffectiveConnectionTypeThresholdForClientLoFi();
} // namespace params
enum class PreviewsType {
NONE = 0,
+
+ // The user is shown an offline page as a preview.
OFFLINE = 1,
+
+ // Replace images with placeholders generated on the client.
+ CLIENT_LOFI = 2,
+
// Insert new enum values here. Keep values sequential to allow looping
// from NONE+1 to LAST-1.
- LAST = 2,
+ LAST = 3,
};
typedef std::vector<std::pair<PreviewsType, int>> PreviewsTypeList;
@@ -67,21 +88,6 @@ typedef std::vector<std::pair<PreviewsType, int>> PreviewsTypeList;
// Returns true if any client-side previews experiment is active.
bool IsIncludedInClientSidePreviewsExperimentsFieldTrial();
-// Returns true if the field trial that should enable previews for |type| for
-// prohibitvely slow networks is active.
-bool IsPreviewsTypeEnabled(PreviewsType type);
-
-// Returns the version of preview treatment |type|. Defaults to 0 if not
-// specified in field trial config.
-int GetPreviewsTypeVersion(PreviewsType type);
-
-// Returns the enabled PreviewsTypes with their version.
-std::unique_ptr<PreviewsTypeList> GetEnabledPreviews();
-
-// Sets the appropriate state for field trial and variations to imitate the
-// offline pages field trial.
-bool EnableOfflinePreviewsForTesting();
-
} // namespace previews
#endif // COMPONENTS_PREVIEWS_CORE_PREVIEWS_EXPERIMENTS_H_
diff --git a/chromium/components/previews/core/previews_experiments_unittest.cc b/chromium/components/previews/core/previews_experiments_unittest.cc
index faf92ccaa05..be81b3d7587 100644
--- a/chromium/components/previews/core/previews_experiments_unittest.cc
+++ b/chromium/components/previews/core/previews_experiments_unittest.cc
@@ -4,10 +4,11 @@
#include "components/previews/core/previews_experiments.h"
+#include <map>
#include <string>
#include "base/metrics/field_trial.h"
-#include "base/strings/string_number_conversions.h"
+#include "base/metrics/field_trial_params.h"
#include "base/strings/string_util.h"
#include "components/variations/variations_associated_data.h"
@@ -17,22 +18,33 @@ namespace previews {
namespace {
-using PreviewsExperimentsTest = testing::Test;
-
-// Used as field trial values. Somewhat random yet valid values.
-const char kMaxStoredHistoryLengthPerHost[] = "3";
-const char kMaxStoredHistoryLengthHostIndifferent[] = "4";
-const char kMaxHostsInBlackList[] = "13";
-const char kPerHostOptOutThreshold[] = "12";
-const char kHostIndifferentOptOutThreshold[] = "84";
-const char kPerHostBlackListDurationInDays[] = "99";
-const char kHostIndifferentBlackListDurationInDays[] = "64";
-const char kSingleOptOutDurationInSeconds[] = "28";
-const char kOfflinePreviewFreshnessDurationInDays[] = "12";
-const char kEffectiveConnectionTypeThreshold[] = "4G";
-
-// Verifies that the default params are the expected values.
-void VerifyDefaultParams() {
+const char kClientSidePreviewsFieldTrial[] = "ClientSidePreviews";
+const char kClientLoFiFieldTrial[] = "PreviewsClientLoFi";
+const char kEnabled[] = "Enabled";
+
+// Verifies that we can enable offline previews via field trial.
+TEST(PreviewsExperimentsTest, TestFieldTrialOfflinePage) {
+ EXPECT_FALSE(IsIncludedInClientSidePreviewsExperimentsFieldTrial());
+ EXPECT_FALSE(params::IsOfflinePreviewsEnabled());
+
+ base::FieldTrialList field_trial_list(nullptr);
+
+ std::map<std::string, std::string> params;
+ params["show_offline_pages"] = "true";
+ EXPECT_TRUE(base::AssociateFieldTrialParams(kClientSidePreviewsFieldTrial,
+ kEnabled, params));
+ EXPECT_TRUE(base::FieldTrialList::CreateFieldTrial(
+ kClientSidePreviewsFieldTrial, kEnabled));
+
+ EXPECT_TRUE(IsIncludedInClientSidePreviewsExperimentsFieldTrial());
+ EXPECT_TRUE(params::IsOfflinePreviewsEnabled());
+ variations::testing::ClearAllVariationParams();
+}
+
+// Verifies that the default params are correct, and that custom params can be
+// set, for both the previews blacklist and offline previews.
+TEST(PreviewsExperimentsTest, TestParamsForBlackListAndOffline) {
+ // Verify that the default params are correct.
EXPECT_EQ(4u, params::MaxStoredHistoryLengthForPerHostBlackList());
EXPECT_EQ(10u, params::MaxStoredHistoryLengthForHostIndifferentBlackList());
EXPECT_EQ(100u, params::MaxInMemoryHostsInBlackList());
@@ -46,126 +58,98 @@ void VerifyDefaultParams() {
EXPECT_EQ(base::TimeDelta::FromDays(7),
params::OfflinePreviewFreshnessDuration());
EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
- params::EffectiveConnectionTypeThreshold());
-}
+ params::EffectiveConnectionTypeThresholdForOffline());
+ EXPECT_EQ(0, params::OfflinePreviewsVersion());
-// Creates a map of the params names to the const string values above.
-std::map<std::string, std::string> GetFieldTrialParams() {
- std::map<std::string, std::string> params;
- // Assign different values than defaults.
- params["per_host_max_stored_history_length"] = kMaxStoredHistoryLengthPerHost;
- params["host_indifferent_max_stored_history_length"] =
- kMaxStoredHistoryLengthHostIndifferent;
- params["max_hosts_in_blacklist"] = kMaxHostsInBlackList;
- params["per_host_opt_out_threshold"] = kPerHostOptOutThreshold;
- params["host_indifferent_opt_out_threshold"] =
- kHostIndifferentOptOutThreshold;
- params["per_host_black_list_duration_in_days"] =
- kPerHostBlackListDurationInDays;
- params["host_indifferent_black_list_duration_in_days"] =
- kHostIndifferentBlackListDurationInDays;
- params["single_opt_out_duration_in_seconds"] = kSingleOptOutDurationInSeconds;
- params["offline_preview_freshness_duration_in_days"] =
- kOfflinePreviewFreshnessDurationInDays;
- params["max_allowed_effective_connection_type"] =
- kEffectiveConnectionTypeThreshold;
-
- return params;
+ base::FieldTrialList field_trial_list(nullptr);
+
+ // Set some custom params. Somewhat random yet valid values.
+ std::map<std::string, std::string> custom_params = {
+ {"per_host_max_stored_history_length", "3"},
+ {"host_indifferent_max_stored_history_length", "4"},
+ {"max_hosts_in_blacklist", "13"},
+ {"per_host_opt_out_threshold", "12"},
+ {"host_indifferent_opt_out_threshold", "84"},
+ {"per_host_black_list_duration_in_days", "99"},
+ {"host_indifferent_black_list_duration_in_days", "64"},
+ {"single_opt_out_duration_in_seconds", "28"},
+ {"offline_preview_freshness_duration_in_days", "12"},
+ {"max_allowed_effective_connection_type", "4G"},
+ {"version", "10"},
+ };
+ EXPECT_TRUE(base::AssociateFieldTrialParams(kClientSidePreviewsFieldTrial,
+ kEnabled, custom_params));
+ EXPECT_TRUE(base::FieldTrialList::CreateFieldTrial(
+ kClientSidePreviewsFieldTrial, kEnabled));
+
+ EXPECT_EQ(3u, params::MaxStoredHistoryLengthForPerHostBlackList());
+ EXPECT_EQ(4u, params::MaxStoredHistoryLengthForHostIndifferentBlackList());
+ EXPECT_EQ(13u, params::MaxInMemoryHostsInBlackList());
+ EXPECT_EQ(12, params::PerHostBlackListOptOutThreshold());
+ EXPECT_EQ(84, params::HostIndifferentBlackListOptOutThreshold());
+ EXPECT_EQ(base::TimeDelta::FromDays(99), params::PerHostBlackListDuration());
+ EXPECT_EQ(base::TimeDelta::FromDays(64),
+ params::HostIndifferentBlackListPerHostDuration());
+ EXPECT_EQ(base::TimeDelta::FromSeconds(28), params::SingleOptOutDuration());
+ EXPECT_EQ(base::TimeDelta::FromDays(12),
+ params::OfflinePreviewFreshnessDuration());
+ EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_4G,
+ params::EffectiveConnectionTypeThresholdForOffline());
+ EXPECT_EQ(10, params::OfflinePreviewsVersion());
+
+ variations::testing::ClearAllVariationParams();
}
-// Verifies that calling the params methods returns the correct values based on
-// the const string values above.
-void VerifyNewParams() {
- {
- size_t history_length;
- EXPECT_TRUE(
- base::StringToSizeT(kMaxStoredHistoryLengthPerHost, &history_length));
- EXPECT_EQ(history_length,
- params::MaxStoredHistoryLengthForPerHostBlackList());
- }
- {
- size_t history_length;
- EXPECT_TRUE(base::StringToSizeT(kMaxStoredHistoryLengthHostIndifferent,
- &history_length));
- EXPECT_EQ(history_length,
- params::MaxStoredHistoryLengthForHostIndifferentBlackList());
- }
- {
- size_t history_length;
- EXPECT_TRUE(base::StringToSizeT(kMaxHostsInBlackList, &history_length));
- EXPECT_EQ(history_length, params::MaxInMemoryHostsInBlackList());
- }
- {
- int threshold;
- EXPECT_TRUE(base::StringToInt(kPerHostOptOutThreshold, &threshold));
- EXPECT_EQ(threshold, params::PerHostBlackListOptOutThreshold());
- }
- {
- int threshold;
- EXPECT_TRUE(base::StringToInt(kHostIndifferentOptOutThreshold, &threshold));
- EXPECT_EQ(threshold, params::HostIndifferentBlackListOptOutThreshold());
- }
- {
- int days;
- EXPECT_TRUE(base::StringToInt(kPerHostBlackListDurationInDays, &days));
- EXPECT_EQ(base::TimeDelta::FromDays(days),
- params::PerHostBlackListDuration());
- }
- {
- int days;
- EXPECT_TRUE(
- base::StringToInt(kHostIndifferentBlackListDurationInDays, &days));
- EXPECT_EQ(base::TimeDelta::FromDays(days),
- params::HostIndifferentBlackListPerHostDuration());
- }
- {
- int seconds;
- EXPECT_TRUE(base::StringToInt(kSingleOptOutDurationInSeconds, &seconds));
- EXPECT_EQ(base::TimeDelta::FromSeconds(seconds),
- params::SingleOptOutDuration());
- }
- {
- int days;
- EXPECT_TRUE(
- base::StringToInt(kOfflinePreviewFreshnessDurationInDays, &days));
- EXPECT_EQ(base::TimeDelta::FromDays(days),
- params::OfflinePreviewFreshnessDuration());
- }
- {
- net::EffectiveConnectionType effective_connection_type;
- EXPECT_TRUE(net::GetEffectiveConnectionTypeForName(
- kEffectiveConnectionTypeThreshold, &effective_connection_type));
- EXPECT_EQ(effective_connection_type,
- params::EffectiveConnectionTypeThreshold());
- }
+TEST(PreviewsExperimentsTest, TestClientLoFiDisabledByDefault) {
+ base::FieldTrialList field_trial_list(nullptr);
+ EXPECT_FALSE(params::IsClientLoFiEnabled());
}
-} // namespace
+TEST(PreviewsExperimentsTest, TestClientLoFiExplicitlyDisabled) {
+ base::FieldTrialList field_trial_list(nullptr);
+ EXPECT_TRUE(
+ base::FieldTrialList::CreateFieldTrial(kClientLoFiFieldTrial, kEnabled));
+ EXPECT_TRUE(params::IsClientLoFiEnabled());
+}
-// Verifies that we can enable offline previews via field trial.
-TEST_F(PreviewsExperimentsTest, TestFieldTrialOfflinePage) {
- EXPECT_FALSE(IsIncludedInClientSidePreviewsExperimentsFieldTrial());
- EXPECT_FALSE(IsPreviewsTypeEnabled(PreviewsType::OFFLINE));
+TEST(PreviewsExperimentsTest, TestClientLoFiEnabled) {
+ base::FieldTrialList field_trial_list(nullptr);
+ EXPECT_TRUE(
+ base::FieldTrialList::CreateFieldTrial(kClientLoFiFieldTrial, kEnabled));
+ EXPECT_TRUE(params::IsClientLoFiEnabled());
+}
+TEST(PreviewsExperimentsTest, TestEnableClientLoFiWithDefaultParams) {
base::FieldTrialList field_trial_list(nullptr);
- ASSERT_TRUE(EnableOfflinePreviewsForTesting());
+ EXPECT_TRUE(
+ base::FieldTrialList::CreateFieldTrial(kClientLoFiFieldTrial, kEnabled));
- EXPECT_TRUE(IsIncludedInClientSidePreviewsExperimentsFieldTrial());
- EXPECT_TRUE(IsPreviewsTypeEnabled(PreviewsType::OFFLINE));
- variations::testing::ClearAllVariationParams();
+ EXPECT_TRUE(params::IsClientLoFiEnabled());
+ EXPECT_EQ(0, params::ClientLoFiVersion());
+ EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
+ params::EffectiveConnectionTypeThresholdForClientLoFi());
}
-// Verifies that we can enable offline previews via field trial and that the
-// default params for previews field trials are accurate.
-TEST_F(PreviewsExperimentsTest, TestAllDefaultParams) {
- VerifyDefaultParams();
+TEST(PreviewsExperimentsTest, TestEnableClientLoFiWithCustomParams) {
base::FieldTrialList field_trial_list(nullptr);
- EXPECT_TRUE(variations::AssociateVariationParams(
- "ClientSidePreviews", "Enabled", GetFieldTrialParams()));
+
+ // Set some custom params for Client LoFi.
+ std::map<std::string, std::string> custom_params = {
+ {"version", "10"}, {"max_allowed_effective_connection_type", "3G"},
+ };
+ EXPECT_TRUE(base::AssociateFieldTrialParams(kClientLoFiFieldTrial, kEnabled,
+ custom_params));
EXPECT_TRUE(
- base::FieldTrialList::CreateFieldTrial("ClientSidePreviews", "Enabled"));
- VerifyNewParams();
+ base::FieldTrialList::CreateFieldTrial(kClientLoFiFieldTrial, kEnabled));
+
+ EXPECT_TRUE(params::IsClientLoFiEnabled());
+ EXPECT_EQ(10, params::ClientLoFiVersion());
+ EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_3G,
+ params::EffectiveConnectionTypeThresholdForClientLoFi());
+
variations::testing::ClearAllVariationParams();
}
+} // namespace
+
} // namespace previews
diff --git a/chromium/components/previews/core/previews_io_data.cc b/chromium/components/previews/core/previews_io_data.cc
index 0a7af37fda2..67403a17c3d 100644
--- a/chromium/components/previews/core/previews_io_data.cc
+++ b/chromium/components/previews/core/previews_io_data.cc
@@ -33,11 +33,31 @@ void LogPreviewsEligibilityReason(PreviewsEligibilityReason status,
"Previews.EligibilityReason.Offline", static_cast<int>(status),
static_cast<int>(PreviewsEligibilityReason::LAST));
break;
+ case PreviewsType::CLIENT_LOFI:
+ UMA_HISTOGRAM_ENUMERATION(
+ "Previews.EligibilityReason.ClientLoFi", static_cast<int>(status),
+ static_cast<int>(PreviewsEligibilityReason::LAST));
+ break;
default:
NOTREACHED();
}
}
+net::EffectiveConnectionType GetEffectiveConnectionTypeThresholdForPreviewsType(
+ PreviewsType type) {
+ switch (type) {
+ case PreviewsType::OFFLINE:
+ return params::EffectiveConnectionTypeThresholdForOffline();
+ case PreviewsType::CLIENT_LOFI:
+ return params::EffectiveConnectionTypeThresholdForClientLoFi();
+ case PreviewsType::NONE:
+ case PreviewsType::LAST:
+ break;
+ }
+ NOTREACHED();
+ return net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+}
+
} // namespace
PreviewsIOData::PreviewsIOData(
@@ -51,8 +71,10 @@ PreviewsIOData::~PreviewsIOData() {}
void PreviewsIOData::Initialize(
base::WeakPtr<PreviewsUIService> previews_ui_service,
- std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store) {
+ std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store,
+ const PreviewsIsEnabledCallback& is_enabled_callback) {
DCHECK(ui_task_runner_->BelongsToCurrentThread());
+ is_enabled_callback_ = is_enabled_callback;
previews_ui_service_ = previews_ui_service;
// Set up the IO thread portion of |this|.
@@ -88,15 +110,16 @@ void PreviewsIOData::ClearBlackList(base::Time begin_time,
bool PreviewsIOData::ShouldAllowPreview(const net::URLRequest& request,
PreviewsType type) const {
- if (!IsPreviewsTypeEnabled(type))
- return false;
- // The blacklist will disallow certain hosts for periods of time based on
- // user's opting out of the preview
- if (!previews_black_list_) {
+ if (is_enabled_callback_.is_null() || !previews_black_list_) {
LogPreviewsEligibilityReason(
PreviewsEligibilityReason::BLACKLIST_UNAVAILABLE, type);
return false;
}
+ if (!is_enabled_callback_.Run(type))
+ return false;
+
+ // The blacklist will disallow certain hosts for periods of time based on
+ // user's opting out of the preview
PreviewsEligibilityReason status =
previews_black_list_->IsLoadedAndAllowed(request.url(), type);
if (status != PreviewsEligibilityReason::ALLOWED) {
@@ -112,8 +135,9 @@ bool PreviewsIOData::ShouldAllowPreview(const net::URLRequest& request,
PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE, type);
return false;
}
+
if (network_quality_estimator->GetEffectiveConnectionType() >
- params::EffectiveConnectionTypeThreshold()) {
+ GetEffectiveConnectionTypeThresholdForPreviewsType(type)) {
LogPreviewsEligibilityReason(PreviewsEligibilityReason::NETWORK_NOT_SLOW,
type);
return false;
@@ -121,8 +145,8 @@ bool PreviewsIOData::ShouldAllowPreview(const net::URLRequest& request,
// LOAD_VALIDATE_CACHE or LOAD_BYPASS_CACHE mean the user reloaded the page.
// If this is a query for offline previews, reloads should be disallowed.
if (type == PreviewsType::OFFLINE &&
- request.load_flags() &
- (net::LOAD_VALIDATE_CACHE | net::LOAD_BYPASS_CACHE)) {
+ (request.load_flags() &
+ (net::LOAD_VALIDATE_CACHE | net::LOAD_BYPASS_CACHE))) {
LogPreviewsEligibilityReason(
PreviewsEligibilityReason::RELOAD_DISALLOWED_FOR_OFFLINE, type);
return false;
diff --git a/chromium/components/previews/core/previews_io_data.h b/chromium/components/previews/core/previews_io_data.h
index a30ab6ff076..f6e85331562 100644
--- a/chromium/components/previews/core/previews_io_data.h
+++ b/chromium/components/previews/core/previews_io_data.h
@@ -8,6 +8,7 @@
#include <memory>
#include <string>
+#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
@@ -27,6 +28,8 @@ class PreviewsBlackList;
class PreviewsOptOutStore;
class PreviewsUIService;
+typedef base::Callback<bool(PreviewsType)> PreviewsIsEnabledCallback;
+
// A class to manage the IO portion of inter-thread communication between
// previews/ objects. Created on the UI thread, but used only on the IO thread
// after initialization.
@@ -40,7 +43,8 @@ class PreviewsIOData : public PreviewsDecider {
// Stores |previews_ui_service| as |previews_ui_service_| and posts a task to
// InitializeOnIOThread on the IO thread.
void Initialize(base::WeakPtr<PreviewsUIService> previews_ui_service,
- std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store);
+ std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store,
+ const PreviewsIsEnabledCallback& is_enabled_callback);
// Adds a navigation to |url| to the black list with result |opt_out|.
void AddPreviewNavigation(const GURL& url, bool opt_out, PreviewsType type);
@@ -75,6 +79,9 @@ class PreviewsIOData : public PreviewsDecider {
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+ // Whether the preview is enabled. Valid after Initialize() is called.
+ PreviewsIsEnabledCallback is_enabled_callback_;
+
base::WeakPtrFactory<PreviewsIOData> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PreviewsIOData);
diff --git a/chromium/components/previews/core/previews_io_data_unittest.cc b/chromium/components/previews/core/previews_io_data_unittest.cc
index 39a8925e618..604cb1aa060 100644
--- a/chromium/components/previews/core/previews_io_data_unittest.cc
+++ b/chromium/components/previews/core/previews_io_data_unittest.cc
@@ -4,6 +4,7 @@
#include "components/previews/core/previews_io_data.h"
+#include <initializer_list>
#include <map>
#include <memory>
#include <string>
@@ -15,6 +16,7 @@
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/test/histogram_tester.h"
@@ -28,6 +30,7 @@
#include "net/base/load_flags.h"
#include "net/nqe/effective_connection_type.h"
#include "net/nqe/network_quality_estimator_test_util.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -37,6 +40,24 @@ namespace previews {
namespace {
+// TODO(sclittle): Tests should be testing the actual prod code that checks if
+// the appropriate field trial is enabled for the preview, instead of testing
+// this function here. Consider moving that code out of
+// chrome/browser/previews/previews_service.cc and into the previews/ component.
+bool IsPreviewFieldTrialEnabled(PreviewsType type) {
+ switch (type) {
+ case PreviewsType::OFFLINE:
+ return params::IsOfflinePreviewsEnabled();
+ case PreviewsType::CLIENT_LOFI:
+ return params::IsClientLoFiEnabled();
+ case PreviewsType::NONE:
+ case PreviewsType::LAST:
+ break;
+ }
+ NOTREACHED();
+ return false;
+}
+
class TestPreviewsIOData : public PreviewsIOData {
public:
TestPreviewsIOData(
@@ -96,77 +117,102 @@ class TestPreviewsOptOutStore : public PreviewsOptOutStore {
class PreviewsIODataTest : public testing::Test {
public:
- PreviewsIODataTest() {}
+ PreviewsIODataTest()
+ : field_trial_list_(nullptr),
+ io_data_(loop_.task_runner(), loop_.task_runner()),
+ context_(true) {
+ context_.set_network_quality_estimator(&network_quality_estimator_);
+ context_.Init();
+
+ network_quality_estimator_.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
+ }
- ~PreviewsIODataTest() override {}
+ ~PreviewsIODataTest() override {
+ variations::testing::ClearAllVariationParams();
+ }
+
+ void InitializeUIServiceWithoutWaitingForBlackList() {
+ ui_service_.reset(new PreviewsUIService(
+ &io_data_, loop_.task_runner(),
+ std::unique_ptr<TestPreviewsOptOutStore>(new TestPreviewsOptOutStore()),
+ base::Bind(&IsPreviewFieldTrialEnabled)));
+ }
- void set_io_data(std::unique_ptr<TestPreviewsIOData> io_data) {
- io_data_ = std::move(io_data);
+ void InitializeUIService() {
+ InitializeUIServiceWithoutWaitingForBlackList();
+ base::RunLoop().RunUntilIdle();
}
- TestPreviewsIOData* io_data() { return io_data_.get(); }
+ std::unique_ptr<net::URLRequest> CreateRequest() const {
+ return context_.CreateRequest(GURL("http://example.com"),
+ net::DEFAULT_PRIORITY, nullptr,
+ TRAFFIC_ANNOTATION_FOR_TESTS);
+ }
- void set_ui_service(std::unique_ptr<PreviewsUIService> ui_service) {
- ui_service_ = std::move(ui_service);
+ TestPreviewsIOData* io_data() { return &io_data_; }
+ PreviewsUIService* ui_service() { return ui_service_.get(); }
+ net::TestURLRequestContext* context() { return &context_; }
+ net::TestNetworkQualityEstimator* network_quality_estimator() {
+ return &network_quality_estimator_;
}
protected:
- // Run this test on a single thread.
base::MessageLoopForIO loop_;
private:
- std::unique_ptr<TestPreviewsIOData> io_data_;
+ base::FieldTrialList field_trial_list_;
+ TestPreviewsIOData io_data_;
std::unique_ptr<PreviewsUIService> ui_service_;
+ net::TestNetworkQualityEstimator network_quality_estimator_;
+ net::TestURLRequestContext context_;
};
-} // namespace
+void CreateFieldTrialWithParams(
+ const std::string& trial_name,
+ const std::string& group_name,
+ std::initializer_list<
+ typename std::map<std::string, std::string>::value_type> params) {
+ EXPECT_TRUE(base::AssociateFieldTrialParams(trial_name, group_name, params));
+ EXPECT_TRUE(base::FieldTrialList::CreateFieldTrial(trial_name, group_name));
+}
TEST_F(PreviewsIODataTest, TestInitialization) {
- set_io_data(base::MakeUnique<TestPreviewsIOData>(loop_.task_runner(),
- loop_.task_runner()));
- set_ui_service(base::MakeUnique<PreviewsUIService>(
- io_data(), loop_.task_runner(), nullptr));
- base::RunLoop().RunUntilIdle();
+ InitializeUIService();
// After the outstanding posted tasks have run, |io_data_| should be fully
// initialized.
EXPECT_TRUE(io_data()->initialized());
}
-TEST_F(PreviewsIODataTest, TestShouldAllowPreview) {
- // Test most reasons to disallow the blacklist.
- // Excluded values are USER_RECENTLY_OPTED_OUT, USER_BLACKLISTED,
- // HOST_BLACKLISTED. These are internal to the blacklist.
- net::TestURLRequestContext context;
- GURL test_host("http://www.test_host.com");
- std::unique_ptr<net::URLRequest> request =
- context.CreateRequest(test_host, net::DEFAULT_PRIORITY, nullptr);
- set_io_data(base::MakeUnique<TestPreviewsIOData>(loop_.task_runner(),
- loop_.task_runner()));
+// Tests most of the reasons that a preview could be disallowed because of the
+// state of the blacklist. Excluded values are USER_RECENTLY_OPTED_OUT,
+// USER_BLACKLISTED, HOST_BLACKLISTED. These are internal to the blacklist.
+TEST_F(PreviewsIODataTest, TestDisallowPreviewBecauseOfBlackListState) {
+ std::unique_ptr<net::URLRequest> request = CreateRequest();
base::HistogramTester histogram_tester;
- // If not in the field trial, don't log anything, and return false.
- EXPECT_FALSE(io_data()->ShouldAllowPreview(*request, PreviewsType::OFFLINE));
- histogram_tester.ExpectTotalCount("Previews.EligibilityReason.Offline", 0);
-
- // Enable Offline previews field trial.
- base::FieldTrialList field_trial_list(nullptr);
- std::map<std::string, std::string> params;
- params["show_offline_pages"] = "true";
- variations::AssociateVariationParams("ClientSidePreviews", "Enabled", params);
- base::FieldTrialList::CreateFieldTrial("ClientSidePreviews", "Enabled");
-
// The blacklist is not created yet.
EXPECT_FALSE(io_data()->ShouldAllowPreview(*request, PreviewsType::OFFLINE));
histogram_tester.ExpectUniqueSample(
"Previews.EligibilityReason.Offline",
static_cast<int>(PreviewsEligibilityReason::BLACKLIST_UNAVAILABLE), 1);
- set_ui_service(base::WrapUnique(
- new PreviewsUIService(io_data(), loop_.task_runner(),
- base::MakeUnique<TestPreviewsOptOutStore>())));
+ InitializeUIServiceWithoutWaitingForBlackList();
+
+ // The blacklist is not created yet.
+ EXPECT_FALSE(io_data()->ShouldAllowPreview(*request, PreviewsType::OFFLINE));
+ histogram_tester.ExpectBucketCount(
+ "Previews.EligibilityReason.Offline",
+ static_cast<int>(PreviewsEligibilityReason::BLACKLIST_UNAVAILABLE), 2);
base::RunLoop().RunUntilIdle();
+ histogram_tester.ExpectTotalCount("Previews.EligibilityReason.Offline", 2);
+
+ // Enable Offline previews field trial.
+ CreateFieldTrialWithParams("ClientSidePreviews", "Enabled",
+ {{"show_offline_pages", "true"}});
+
// Return one of the failing statuses from the blacklist; cause the blacklist
// to not be loaded by clearing the blacklist.
base::Time now = base::Time::Now();
@@ -177,59 +223,197 @@ TEST_F(PreviewsIODataTest, TestShouldAllowPreview) {
"Previews.EligibilityReason.Offline",
static_cast<int>(PreviewsEligibilityReason::BLACKLIST_DATA_NOT_LOADED),
1);
+}
- // Reload the blacklist. The blacklist should allow all navigations now.
- base::RunLoop().RunUntilIdle();
+TEST_F(PreviewsIODataTest, TestDisallowOfflineByDefault) {
+ InitializeUIService();
- // NQE should be null on the context.
- EXPECT_FALSE(io_data()->ShouldAllowPreview(*request, PreviewsType::OFFLINE));
- histogram_tester.ExpectBucketCount(
- "Previews.EligibilityReason.Offline",
- static_cast<int>(PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE),
- 1);
+ base::HistogramTester histogram_tester;
+ EXPECT_FALSE(
+ io_data()->ShouldAllowPreview(*CreateRequest(), PreviewsType::OFFLINE));
+ histogram_tester.ExpectTotalCount("Previews.EligibilityReason.Offline", 0);
+}
+
+TEST_F(PreviewsIODataTest, TestDisallowOfflineWhenInDisabledGroup) {
+ InitializeUIService();
+ CreateFieldTrialWithParams("ClientSidePreviews", "Disabled",
+ {{"show_offline_pages", "true"}});
+
+ base::HistogramTester histogram_tester;
+ EXPECT_FALSE(
+ io_data()->ShouldAllowPreview(*CreateRequest(), PreviewsType::OFFLINE));
+ histogram_tester.ExpectTotalCount("Previews.EligibilityReason.Offline", 0);
+}
+
+TEST_F(PreviewsIODataTest, TestDisallowOfflineWhenDisabled) {
+ InitializeUIService();
+ CreateFieldTrialWithParams("ClientSidePreviews", "Enabled",
+ {{"show_offline_pages", "false"}});
+
+ base::HistogramTester histogram_tester;
+ EXPECT_FALSE(
+ io_data()->ShouldAllowPreview(*CreateRequest(), PreviewsType::OFFLINE));
+ histogram_tester.ExpectTotalCount("Previews.EligibilityReason.Offline", 0);
+}
- net::TestNetworkQualityEstimator network_quality_estimator(params);
- context.set_network_quality_estimator(&network_quality_estimator);
+TEST_F(PreviewsIODataTest, TestDisallowOfflineWhenNetworkQualityUnavailable) {
+ InitializeUIService();
+ CreateFieldTrialWithParams("ClientSidePreviews", "Enabled",
+ {{"show_offline_pages", "true"}});
- // Set NQE type to unknown.
- network_quality_estimator.set_effective_connection_type(
+ network_quality_estimator()->set_effective_connection_type(
net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
- EXPECT_FALSE(io_data()->ShouldAllowPreview(*request, PreviewsType::OFFLINE));
- histogram_tester.ExpectBucketCount(
+ base::HistogramTester histogram_tester;
+ EXPECT_FALSE(
+ io_data()->ShouldAllowPreview(*CreateRequest(), PreviewsType::OFFLINE));
+ histogram_tester.ExpectUniqueSample(
"Previews.EligibilityReason.Offline",
static_cast<int>(PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE),
- 2);
+ 1);
+}
- // Set NQE type to fast enough.
- network_quality_estimator.set_effective_connection_type(
- net::EFFECTIVE_CONNECTION_TYPE_2G);
- EXPECT_FALSE(io_data()->ShouldAllowPreview(*request, PreviewsType::OFFLINE));
- histogram_tester.ExpectBucketCount(
+TEST_F(PreviewsIODataTest, TestDisallowOfflineWhenNetworkQualityFast) {
+ InitializeUIService();
+ CreateFieldTrialWithParams("ClientSidePreviews", "Enabled",
+ {{"show_offline_pages", "true"},
+ {"max_allowed_effective_connection_type", "2G"}});
+
+ network_quality_estimator()->set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_3G);
+
+ base::HistogramTester histogram_tester;
+ EXPECT_FALSE(
+ io_data()->ShouldAllowPreview(*CreateRequest(), PreviewsType::OFFLINE));
+ histogram_tester.ExpectUniqueSample(
"Previews.EligibilityReason.Offline",
static_cast<int>(PreviewsEligibilityReason::NETWORK_NOT_SLOW), 1);
+}
+
+TEST_F(PreviewsIODataTest, TestDisallowOfflineOnReload) {
+ InitializeUIService();
+ CreateFieldTrialWithParams("ClientSidePreviews", "Enabled",
+ {{"show_offline_pages", "true"},
+ {"max_allowed_effective_connection_type", "2G"}});
- // Set NQE type to slow.
- network_quality_estimator.set_effective_connection_type(
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ network_quality_estimator()->set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_2G);
+ std::unique_ptr<net::URLRequest> request = CreateRequest();
request->SetLoadFlags(net::LOAD_BYPASS_CACHE);
+
+ base::HistogramTester histogram_tester;
EXPECT_FALSE(io_data()->ShouldAllowPreview(*request, PreviewsType::OFFLINE));
- histogram_tester.ExpectBucketCount(
+ histogram_tester.ExpectUniqueSample(
"Previews.EligibilityReason.Offline",
static_cast<int>(
PreviewsEligibilityReason::RELOAD_DISALLOWED_FOR_OFFLINE),
1);
+}
- request->SetLoadFlags(0);
- EXPECT_TRUE(io_data()->ShouldAllowPreview(*request, PreviewsType::OFFLINE));
- histogram_tester.ExpectBucketCount(
+TEST_F(PreviewsIODataTest, TestAllowOffline) {
+ InitializeUIService();
+ CreateFieldTrialWithParams("ClientSidePreviews", "Enabled",
+ {{"show_offline_pages", "true"},
+ {"max_allowed_effective_connection_type", "2G"}});
+
+ network_quality_estimator()->set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_2G);
+
+ base::HistogramTester histogram_tester;
+ EXPECT_TRUE(
+ io_data()->ShouldAllowPreview(*CreateRequest(), PreviewsType::OFFLINE));
+ histogram_tester.ExpectUniqueSample(
"Previews.EligibilityReason.Offline",
static_cast<int>(PreviewsEligibilityReason::ALLOWED), 1);
+}
+
+TEST_F(PreviewsIODataTest, ClientLoFiDisallowedByDefault) {
+ InitializeUIService();
+
+ base::HistogramTester histogram_tester;
+ EXPECT_FALSE(io_data()->ShouldAllowPreview(*CreateRequest(),
+ PreviewsType::CLIENT_LOFI));
+ histogram_tester.ExpectTotalCount("Previews.EligibilityReason.ClientLoFi", 0);
+}
+
+TEST_F(PreviewsIODataTest, ClientLoFiDisallowedWhenFieldTrialDisabled) {
+ InitializeUIService();
+ CreateFieldTrialWithParams("PreviewsClientLoFi", "Disabled", {});
+
+ base::HistogramTester histogram_tester;
+ EXPECT_FALSE(io_data()->ShouldAllowPreview(*CreateRequest(),
+ PreviewsType::CLIENT_LOFI));
+ histogram_tester.ExpectTotalCount("Previews.EligibilityReason.ClientLoFi", 0);
+}
+
+TEST_F(PreviewsIODataTest, ClientLoFiDisallowedWhenNetworkQualityUnavailable) {
+ InitializeUIService();
+ CreateFieldTrialWithParams("PreviewsClientLoFi", "Enabled", {});
+
+ network_quality_estimator()->set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
+
+ base::HistogramTester histogram_tester;
+ EXPECT_FALSE(io_data()->ShouldAllowPreview(*CreateRequest(),
+ PreviewsType::CLIENT_LOFI));
+ histogram_tester.ExpectUniqueSample(
+ "Previews.EligibilityReason.ClientLoFi",
+ static_cast<int>(PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE),
+ 1);
+}
+
+TEST_F(PreviewsIODataTest, ClientLoFiDisallowedWhenNetworkFast) {
+ InitializeUIService();
+ CreateFieldTrialWithParams("PreviewsClientLoFi", "Enabled",
+ {{"max_allowed_effective_connection_type", "2G"}});
+
+ network_quality_estimator()->set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_3G);
+
+ base::HistogramTester histogram_tester;
+ EXPECT_FALSE(io_data()->ShouldAllowPreview(*CreateRequest(),
+ PreviewsType::CLIENT_LOFI));
+ histogram_tester.ExpectUniqueSample(
+ "Previews.EligibilityReason.ClientLoFi",
+ static_cast<int>(PreviewsEligibilityReason::NETWORK_NOT_SLOW), 1);
+}
+
+TEST_F(PreviewsIODataTest, ClientLoFiAllowed) {
+ InitializeUIService();
+ CreateFieldTrialWithParams("PreviewsClientLoFi", "Enabled",
+ {{"max_allowed_effective_connection_type", "2G"}});
+
+ network_quality_estimator()->set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_2G);
+
+ base::HistogramTester histogram_tester;
+ EXPECT_TRUE(io_data()->ShouldAllowPreview(*CreateRequest(),
+ PreviewsType::CLIENT_LOFI));
+ histogram_tester.ExpectUniqueSample(
+ "Previews.EligibilityReason.ClientLoFi",
+ static_cast<int>(PreviewsEligibilityReason::ALLOWED), 1);
+}
+
+TEST_F(PreviewsIODataTest, ClientLoFiAllowedOnReload) {
+ InitializeUIService();
+ CreateFieldTrialWithParams("PreviewsClientLoFi", "Enabled",
+ {{"max_allowed_effective_connection_type", "2G"}});
+
+ network_quality_estimator()->set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_2G);
- histogram_tester.ExpectTotalCount("Previews.EligibilityReason.Offline", 7);
+ std::unique_ptr<net::URLRequest> request = CreateRequest();
+ request->SetLoadFlags(net::LOAD_BYPASS_CACHE);
- variations::testing::ClearAllVariationParams();
+ base::HistogramTester histogram_tester;
+ EXPECT_TRUE(
+ io_data()->ShouldAllowPreview(*request, PreviewsType::CLIENT_LOFI));
+ histogram_tester.ExpectUniqueSample(
+ "Previews.EligibilityReason.ClientLoFi",
+ static_cast<int>(PreviewsEligibilityReason::ALLOWED), 1);
}
+} // namespace
+
} // namespace previews
diff --git a/chromium/components/previews/core/previews_opt_out_store_sql.cc b/chromium/components/previews/core/previews_opt_out_store_sql.cc
index b1e4f582621..4b9b97b67d9 100644
--- a/chromium/components/previews/core/previews_opt_out_store_sql.cc
+++ b/chromium/components/previews/core/previews_opt_out_store_sql.cc
@@ -262,12 +262,12 @@ void DeleteEnabledPreviewInDataBase(sql::Connection* db, PreviewsType type) {
// Checks the current set of enabled previews (with their current version)
// and where a preview is now disabled or has a different version, cleans up
// any associated blacklist entries.
-void CheckAndReconcileEnabledPreviewsWithDataBase(sql::Connection* db) {
+void CheckAndReconcileEnabledPreviewsWithDataBase(
+ sql::Connection* db,
+ PreviewsTypeList* enabled_previews) {
std::unique_ptr<std::map<PreviewsType, int>> stored_previews(
GetStoredPreviews(db));
- std::unique_ptr<PreviewsTypeList> enabled_previews(GetEnabledPreviews());
-
for (auto enabled_it = enabled_previews->begin();
enabled_it != enabled_previews->end(); ++enabled_it) {
PreviewsType type = enabled_it->first;
@@ -297,10 +297,11 @@ void CheckAndReconcileEnabledPreviewsWithDataBase(sql::Connection* db) {
void LoadBlackListFromDataBase(
sql::Connection* db,
+ PreviewsTypeList* enabled_previews,
scoped_refptr<base::SingleThreadTaskRunner> runner,
LoadBlackListCallback callback) {
// First handle any update needed wrt enabled previews and their versions.
- CheckAndReconcileEnabledPreviewsWithDataBase(db);
+ CheckAndReconcileEnabledPreviewsWithDataBase(db, enabled_previews);
// Gets the table sorted by host and time. Limits the number of hosts using
// most recent opt_out time as the limiting function. Sorting is free due to
@@ -365,12 +366,13 @@ void LoadBlackListFromDataBase(
// and actually do the work to access the SQL data base.
void LoadBlackListSync(sql::Connection* db,
const base::FilePath& path,
+ std::unique_ptr<PreviewsTypeList> enabled_previews,
scoped_refptr<base::SingleThreadTaskRunner> runner,
LoadBlackListCallback callback) {
if (!db->is_open())
InitDatabase(db, path);
- LoadBlackListFromDataBase(db, runner, callback);
+ LoadBlackListFromDataBase(db, enabled_previews.get(), runner, callback);
}
// Deletes every row in the table that has entry time between |begin_time| and
@@ -405,10 +407,14 @@ void AddPreviewNavigationSync(bool opt_out,
PreviewsOptOutStoreSQL::PreviewsOptOutStoreSQL(
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<base::SequencedTaskRunner> background_task_runner,
- const base::FilePath& path)
+ const base::FilePath& path,
+ std::unique_ptr<PreviewsTypeList> enabled_previews)
: io_task_runner_(io_task_runner),
background_task_runner_(background_task_runner),
- db_file_path_(path) {}
+ db_file_path_(path),
+ enabled_previews_(std::move(enabled_previews)) {
+ DCHECK(enabled_previews_);
+}
PreviewsOptOutStoreSQL::~PreviewsOptOutStoreSQL() {
DCHECK(io_task_runner_->BelongsToCurrentThread());
@@ -441,8 +447,11 @@ void PreviewsOptOutStoreSQL::LoadBlackList(LoadBlackListCallback callback) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
if (!db_)
db_ = base::MakeUnique<sql::Connection>();
+ std::unique_ptr<PreviewsTypeList> enabled_previews =
+ base::MakeUnique<PreviewsTypeList>(*enabled_previews_);
background_task_runner_->PostTask(
FROM_HERE, base::Bind(&LoadBlackListSync, db_.get(), db_file_path_,
+ base::Passed(std::move(enabled_previews)),
base::ThreadTaskRunnerHandle::Get(), callback));
}
diff --git a/chromium/components/previews/core/previews_opt_out_store_sql.h b/chromium/components/previews/core/previews_opt_out_store_sql.h
index 801b8507447..0d3b6389e0f 100644
--- a/chromium/components/previews/core/previews_opt_out_store_sql.h
+++ b/chromium/components/previews/core/previews_opt_out_store_sql.h
@@ -36,7 +36,8 @@ class PreviewsOptOutStoreSQL : public PreviewsOptOutStore {
PreviewsOptOutStoreSQL(
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<base::SequencedTaskRunner> background_task_runner,
- const base::FilePath& database_dir);
+ const base::FilePath& database_dir,
+ std::unique_ptr<PreviewsTypeList> enabled_previews);
~PreviewsOptOutStoreSQL() override;
// PreviewsOptOutStore implementation:
@@ -60,6 +61,9 @@ class PreviewsOptOutStoreSQL : public PreviewsOptOutStore {
// SQL connection to the SQLite database.
std::unique_ptr<sql::Connection> db_;
+ // All enabled previews and versions.
+ const std::unique_ptr<PreviewsTypeList> enabled_previews_;
+
DISALLOW_COPY_AND_ASSIGN(PreviewsOptOutStoreSQL);
};
diff --git a/chromium/components/previews/core/previews_opt_out_store_sql_unittest.cc b/chromium/components/previews/core/previews_opt_out_store_sql_unittest.cc
index 9974885b1d8..2057eed61b7 100644
--- a/chromium/components/previews/core/previews_opt_out_store_sql_unittest.cc
+++ b/chromium/components/previews/core/previews_opt_out_store_sql_unittest.cc
@@ -64,16 +64,17 @@ class PreviewsOptOutStoreSQLTest : public testing::Test {
}
// Creates a store that operates on one thread.
- void Create() {
+ void Create(std::unique_ptr<PreviewsTypeList> enabled_previews) {
store_ = base::MakeUnique<PreviewsOptOutStoreSQL>(
base::ThreadTaskRunnerHandle::Get(),
base::ThreadTaskRunnerHandle::Get(),
- temp_dir_.GetPath().Append(kOptOutFilename));
+ temp_dir_.GetPath().Append(kOptOutFilename),
+ std::move(enabled_previews));
}
// Sets up initialization of |store_|.
- void CreateAndLoad() {
- Create();
+ void CreateAndLoad(std::unique_ptr<PreviewsTypeList> enabled_previews) {
+ Create(std::move(enabled_previews));
Load();
}
@@ -114,7 +115,9 @@ class PreviewsOptOutStoreSQLTest : public testing::Test {
TEST_F(PreviewsOptOutStoreSQLTest, TestErrorRecovery) {
// Creates the database and corrupt to test the recovery method.
std::string test_host = "host.com";
- CreateAndLoad();
+ std::unique_ptr<PreviewsTypeList> enabled_previews(new PreviewsTypeList);
+ enabled_previews->push_back({PreviewsType::OFFLINE, 0});
+ CreateAndLoad(std::move(enabled_previews));
store_->AddPreviewNavigation(true, test_host, PreviewsType::OFFLINE,
base::Time::Now());
base::RunLoop().RunUntilIdle();
@@ -125,7 +128,9 @@ TEST_F(PreviewsOptOutStoreSQLTest, TestErrorRecovery) {
temp_dir_.GetPath().Append(kOptOutFilename)));
base::RunLoop().RunUntilIdle();
- CreateAndLoad();
+ enabled_previews.reset(new PreviewsTypeList);
+ enabled_previews->push_back({PreviewsType::OFFLINE, 0});
+ CreateAndLoad(std::move(enabled_previews));
// The data should be recovered.
EXPECT_EQ(1U, black_list_map_->size());
auto iter = black_list_map_->find(test_host);
@@ -137,7 +142,9 @@ TEST_F(PreviewsOptOutStoreSQLTest, TestErrorRecovery) {
TEST_F(PreviewsOptOutStoreSQLTest, TestPersistance) {
// Tests if data is stored as expected in the SQLite database.
std::string test_host = "host.com";
- CreateAndLoad();
+ std::unique_ptr<PreviewsTypeList> enabled_previews(new PreviewsTypeList);
+ enabled_previews->push_back({PreviewsType::OFFLINE, 0});
+ CreateAndLoad(std::move(enabled_previews));
histogram_tester_.ExpectUniqueSample("Previews.OptOut.DBRowCount", 0, 1);
base::Time now = base::Time::Now();
store_->AddPreviewNavigation(true, test_host, PreviewsType::OFFLINE, now);
@@ -148,7 +155,9 @@ TEST_F(PreviewsOptOutStoreSQLTest, TestPersistance) {
DestroyStore();
// Reload and test for persistence
- CreateAndLoad();
+ enabled_previews.reset(new PreviewsTypeList);
+ enabled_previews->push_back({PreviewsType::OFFLINE, 0});
+ CreateAndLoad(std::move(enabled_previews));
EXPECT_EQ(1U, black_list_map_->size());
auto iter = black_list_map_->find(test_host);
@@ -172,7 +181,9 @@ TEST_F(PreviewsOptOutStoreSQLTest, TestMaxRows) {
std::string row_limit_string = base::SizeTToString(row_limit);
command_line->AppendSwitchASCII("previews-max-opt-out-rows",
row_limit_string);
- CreateAndLoad();
+ std::unique_ptr<PreviewsTypeList> enabled_previews(new PreviewsTypeList);
+ enabled_previews->push_back({PreviewsType::OFFLINE, 0});
+ CreateAndLoad(std::move(enabled_previews));
histogram_tester_.ExpectUniqueSample("Previews.OptOut.DBRowCount", 0, 1);
base::SimpleTestClock clock;
@@ -194,7 +205,9 @@ TEST_F(PreviewsOptOutStoreSQLTest, TestMaxRows) {
DestroyStore();
// Reload and test for persistence
- CreateAndLoad();
+ enabled_previews.reset(new PreviewsTypeList);
+ enabled_previews->push_back({PreviewsType::OFFLINE, 0});
+ CreateAndLoad(std::move(enabled_previews));
histogram_tester_.ExpectBucketCount("Previews.OptOut.DBRowCount",
static_cast<int>(row_limit) + 1, 1);
// The delete happens after the load, so it is possible to load more than
@@ -204,7 +217,9 @@ TEST_F(PreviewsOptOutStoreSQLTest, TestMaxRows) {
host_indifferent_item_->OptOutRecordsSizeForTesting());
DestroyStore();
- CreateAndLoad();
+ enabled_previews.reset(new PreviewsTypeList);
+ enabled_previews->push_back({PreviewsType::OFFLINE, 0});
+ CreateAndLoad(std::move(enabled_previews));
histogram_tester_.ExpectBucketCount("Previews.OptOut.DBRowCount",
static_cast<int>(row_limit), 1);
@@ -232,7 +247,9 @@ TEST_F(PreviewsOptOutStoreSQLTest, TestMaxRowsPerHost) {
std::string row_limit_string = base::SizeTToString(row_limit);
command_line->AppendSwitchASCII("previews-max-opt-out-rows-per-host",
row_limit_string);
- CreateAndLoad();
+ std::unique_ptr<PreviewsTypeList> enabled_previews(new PreviewsTypeList);
+ enabled_previews->push_back({PreviewsType::OFFLINE, 0});
+ CreateAndLoad(std::move(enabled_previews));
histogram_tester_.ExpectUniqueSample("Previews.OptOut.DBRowCount", 0, 1);
base::SimpleTestClock clock;
@@ -254,7 +271,9 @@ TEST_F(PreviewsOptOutStoreSQLTest, TestMaxRowsPerHost) {
DestroyStore();
// Reload and test for persistence.
- CreateAndLoad();
+ enabled_previews.reset(new PreviewsTypeList);
+ enabled_previews->push_back({PreviewsType::OFFLINE, 0});
+ CreateAndLoad(std::move(enabled_previews));
histogram_tester_.ExpectBucketCount("Previews.OptOut.DBRowCount",
static_cast<int>(row_limit), 1);
@@ -277,13 +296,10 @@ TEST_F(PreviewsOptOutStoreSQLTest, TestPreviewsDisabledClearsBlacklistEntry) {
// Tests if data is cleared for previews type when it is disabled.
// Enable offline previews and add black list entry for it.
std::map<std::string, std::string> params;
- params["show_offline_pages"] = "true";
- EXPECT_TRUE(
- base::AssociateFieldTrialParams("ClientSidePreviews", "Enabled", params));
- EXPECT_TRUE(
- base::FieldTrialList::CreateFieldTrial("ClientSidePreviews", "Enabled"));
std::string test_host = "host.com";
- CreateAndLoad();
+ std::unique_ptr<PreviewsTypeList> enabled_previews(new PreviewsTypeList);
+ enabled_previews->push_back({PreviewsType::OFFLINE, 0});
+ CreateAndLoad(std::move(enabled_previews));
histogram_tester_.ExpectUniqueSample("Previews.OptOut.DBRowCount", 0, 1);
base::Time now = base::Time::Now();
store_->AddPreviewNavigation(true, test_host, PreviewsType::OFFLINE, now);
@@ -292,41 +308,29 @@ TEST_F(PreviewsOptOutStoreSQLTest, TestPreviewsDisabledClearsBlacklistEntry) {
// Force data write to database then reload it and verify black list entry
// is present.
DestroyStore();
- CreateAndLoad();
+ enabled_previews.reset(new PreviewsTypeList);
+ enabled_previews->push_back({PreviewsType::OFFLINE, 0});
+ CreateAndLoad(std::move(enabled_previews));
auto iter = black_list_map_->find(test_host);
EXPECT_NE(black_list_map_->end(), iter);
EXPECT_EQ(1U, iter->second->OptOutRecordsSizeForTesting());
- // Now reload with offline pages previews disabled and verify black list
- // entry dropped.
- ResetFieldTrials();
- params["show_offline_pages"] = "false";
- EXPECT_TRUE(
- base::AssociateFieldTrialParams("ClientSidePreviews", "Enabled", params));
- EXPECT_TRUE(
- base::FieldTrialList::CreateFieldTrial("ClientSidePreviews", "Enabled"));
DestroyStore();
- CreateAndLoad();
+ enabled_previews.reset(new PreviewsTypeList);
+ CreateAndLoad(std::move(enabled_previews));
iter = black_list_map_->find(test_host);
EXPECT_EQ(black_list_map_->end(), iter);
- // Clean up field trials set in this test.
- ResetFieldTrials();
}
TEST_F(PreviewsOptOutStoreSQLTest,
TestPreviewsVersionUpdateClearsBlacklistEntry) {
// Tests if data is cleared for new version of previews type.
// Enable offline previews and add black list entry for it.
- std::map<std::string, std::string> params;
- params["show_offline_pages"] = "true";
- params["version"] = "1";
- EXPECT_TRUE(
- base::AssociateFieldTrialParams("ClientSidePreviews", "Enabled", params));
- EXPECT_TRUE(
- base::FieldTrialList::CreateFieldTrial("ClientSidePreviews", "Enabled"));
std::string test_host = "host.com";
- CreateAndLoad();
+ std::unique_ptr<PreviewsTypeList> enabled_previews(new PreviewsTypeList);
+ enabled_previews->push_back({PreviewsType::OFFLINE, 1});
+ CreateAndLoad(std::move(enabled_previews));
histogram_tester_.ExpectUniqueSample("Previews.OptOut.DBRowCount", 0, 1);
base::Time now = base::Time::Now();
store_->AddPreviewNavigation(true, test_host, PreviewsType::OFFLINE, now);
@@ -335,26 +339,19 @@ TEST_F(PreviewsOptOutStoreSQLTest,
// Force data write to database then reload it and verify black list entry
// is present.
DestroyStore();
- CreateAndLoad();
+ enabled_previews.reset(new PreviewsTypeList);
+ enabled_previews->push_back({PreviewsType::OFFLINE, 1});
+ CreateAndLoad(std::move(enabled_previews));
auto iter = black_list_map_->find(test_host);
EXPECT_NE(black_list_map_->end(), iter);
EXPECT_EQ(1U, iter->second->OptOutRecordsSizeForTesting());
- // Now reload with incremented previews version and verify black list
- // entry dropped.
- ResetFieldTrials();
- params["version"] = "2";
- EXPECT_TRUE(
- base::AssociateFieldTrialParams("ClientSidePreviews", "Enabled", params));
- EXPECT_TRUE(
- base::FieldTrialList::CreateFieldTrial("ClientSidePreviews", "Enabled"));
DestroyStore();
- CreateAndLoad();
+ enabled_previews.reset(new PreviewsTypeList);
+ enabled_previews->push_back({PreviewsType::OFFLINE, 2});
+ CreateAndLoad(std::move(enabled_previews));
iter = black_list_map_->find(test_host);
EXPECT_EQ(black_list_map_->end(), iter);
-
- // Clean up field trials set in this test.
- ResetFieldTrials();
}
} // namespace net
diff --git a/chromium/components/previews/core/previews_ui_service.cc b/chromium/components/previews/core/previews_ui_service.cc
index af146cc81f1..44cbb21c960 100644
--- a/chromium/components/previews/core/previews_ui_service.cc
+++ b/chromium/components/previews/core/previews_ui_service.cc
@@ -6,7 +6,6 @@
#include "base/bind.h"
#include "base/single_thread_task_runner.h"
-#include "components/previews/core/previews_io_data.h"
#include "url/gurl.h"
namespace previews {
@@ -14,10 +13,12 @@ namespace previews {
PreviewsUIService::PreviewsUIService(
PreviewsIOData* previews_io_data,
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
- std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store)
+ std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store,
+ const PreviewsIsEnabledCallback& is_enabled_callback)
: io_task_runner_(io_task_runner), weak_factory_(this) {
previews_io_data->Initialize(weak_factory_.GetWeakPtr(),
- std::move(previews_opt_out_store));
+ std::move(previews_opt_out_store),
+ is_enabled_callback);
}
PreviewsUIService::~PreviewsUIService() {
diff --git a/chromium/components/previews/core/previews_ui_service.h b/chromium/components/previews/core/previews_ui_service.h
index 12452bcacbe..85dc8d12dd6 100644
--- a/chromium/components/previews/core/previews_ui_service.h
+++ b/chromium/components/previews/core/previews_ui_service.h
@@ -13,6 +13,7 @@
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "components/previews/core/previews_experiments.h"
+#include "components/previews/core/previews_io_data.h"
#include "components/previews/core/previews_opt_out_store.h"
class GURL;
@@ -31,7 +32,8 @@ class PreviewsUIService {
PreviewsUIService(
PreviewsIOData* previews_io_data,
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
- std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store);
+ std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store,
+ const PreviewsIsEnabledCallback& is_enabled_callback);
virtual ~PreviewsUIService();
// Sets |io_data_| to |io_data| to allow calls from the UI thread to the IO
diff --git a/chromium/components/previews/core/previews_ui_service_unittest.cc b/chromium/components/previews/core/previews_ui_service_unittest.cc
index 57a1bbd8aef..0398ffd73a2 100644
--- a/chromium/components/previews/core/previews_ui_service_unittest.cc
+++ b/chromium/components/previews/core/previews_ui_service_unittest.cc
@@ -26,7 +26,8 @@ class TestPreviewsUIService : public PreviewsUIService {
std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store)
: PreviewsUIService(previews_io_data,
io_task_runner,
- std::move(previews_opt_out_store)),
+ std::move(previews_opt_out_store),
+ PreviewsIsEnabledCallback()),
io_data_set_(false) {}
~TestPreviewsUIService() override {}
diff --git a/chromium/components/printing/browser/print_manager_utils.cc b/chromium/components/printing/browser/print_manager_utils.cc
index ec383a232d2..7be67b197e5 100644
--- a/chromium/components/printing/browser/print_manager_utils.cc
+++ b/chromium/components/printing/browser/print_manager_utils.cc
@@ -23,8 +23,6 @@ void RenderParamsFromPrintSettings(const PrintSettings& settings,
params->margin_left = settings.page_setup_device_units().content_area().x();
params->dpi = settings.dpi();
params->scale_factor = settings.scale_factor();
- // Currently hardcoded at 72dpi. See PrintSettings' constructor.
- params->desired_dpi = settings.desired_dpi();
params->rasterize_pdf = settings.rasterize_pdf();
// Always use an invalid cookie.
params->document_cookie = 0;
diff --git a/chromium/components/printing/common/print_messages.cc b/chromium/components/printing/common/print_messages.cc
index a9291a2b6cd..de036345130 100644
--- a/chromium/components/printing/common/print_messages.cc
+++ b/chromium/components/printing/common/print_messages.cc
@@ -49,7 +49,6 @@ PrintMsg_Print_Params::PrintMsg_Print_Params()
margin_left(0),
dpi(0),
scale_factor(1.0f),
- desired_dpi(0),
rasterize_pdf(false),
document_cookie(0),
selection_only(false),
@@ -57,7 +56,7 @@ PrintMsg_Print_Params::PrintMsg_Print_Params()
preview_ui_id(-1),
preview_request_id(0),
is_first_request(false),
- print_scaling_option(blink::WebPrintScalingOptionSourceSize),
+ print_scaling_option(blink::kWebPrintScalingOptionSourceSize),
print_to_pdf(false),
display_header_footer(false),
title(),
@@ -77,7 +76,6 @@ void PrintMsg_Print_Params::Reset() {
margin_left = 0;
dpi = 0;
scale_factor = 1.0f;
- desired_dpi = 0;
rasterize_pdf = false;
document_cookie = 0;
selection_only = false;
@@ -85,7 +83,7 @@ void PrintMsg_Print_Params::Reset() {
preview_ui_id = -1;
preview_request_id = 0;
is_first_request = false;
- print_scaling_option = blink::WebPrintScalingOptionSourceSize;
+ print_scaling_option = blink::kWebPrintScalingOptionSourceSize;
print_to_pdf = false;
display_header_footer = false;
title = base::string16();
diff --git a/chromium/components/printing/common/print_messages.h b/chromium/components/printing/common/print_messages.h
index 9a90bc11073..d11d28dee8d 100644
--- a/chromium/components/printing/common/print_messages.h
+++ b/chromium/components/printing/common/print_messages.h
@@ -47,7 +47,6 @@ struct PrintMsg_Print_Params {
int margin_left;
double dpi;
double scale_factor;
- int desired_dpi;
bool rasterize_pdf;
int document_cookie;
bool selection_only;
@@ -101,7 +100,7 @@ struct PrintHostMsg_SetOptionsFromDocument_Params {
#define IPC_MESSAGE_START PrintMsgStart
IPC_ENUM_TRAITS_MAX_VALUE(blink::WebPrintScalingOption,
- blink::WebPrintScalingOptionLast)
+ blink::kWebPrintScalingOptionLast)
// Parameters for a render request.
IPC_STRUCT_TRAITS_BEGIN(PrintMsg_Print_Params)
@@ -127,12 +126,6 @@ IPC_STRUCT_TRAITS_BEGIN(PrintMsg_Print_Params)
// Specifies the scale factor in percent
IPC_STRUCT_TRAITS_MEMBER(scale_factor)
- // Desired apparent dpi on paper.
- IPC_STRUCT_TRAITS_MEMBER(desired_dpi)
-
- // Whether to rasterize a PDF for printing
- IPC_STRUCT_TRAITS_MEMBER(rasterize_pdf)
-
// Cookie for the document to ensure correctness.
IPC_STRUCT_TRAITS_MEMBER(document_cookie)
@@ -168,20 +161,13 @@ IPC_STRUCT_TRAITS_BEGIN(PrintMsg_Print_Params)
// URL string to be printed as footer if requested by the user.
IPC_STRUCT_TRAITS_MEMBER(url)
+ // Whether to rasterize a PDF for printing
+ IPC_STRUCT_TRAITS_MEMBER(rasterize_pdf)
+
// True if print backgrounds is requested by the user.
IPC_STRUCT_TRAITS_MEMBER(should_print_backgrounds)
IPC_STRUCT_TRAITS_END()
-IPC_STRUCT_BEGIN(PrintMsg_PrintPage_Params)
- // Parameters to render the page as a printed page. It must always be the same
- // value for all the document.
- IPC_STRUCT_MEMBER(PrintMsg_Print_Params, params)
-
- // The page number is the indicator of the square that should be rendered
- // according to the layout specified in PrintMsg_Print_Params.
- IPC_STRUCT_MEMBER(int, page_number)
-IPC_STRUCT_END()
-
IPC_STRUCT_TRAITS_BEGIN(printing::PageRange)
IPC_STRUCT_TRAITS_MEMBER(from)
IPC_STRUCT_TRAITS_MEMBER(to)
diff --git a/chromium/components/printing/renderer/print_web_view_helper.cc b/chromium/components/printing/renderer/print_web_view_helper.cc
index eaa294d97cf..ab055908eb3 100644
--- a/chromium/components/printing/renderer/print_web_view_helper.cc
+++ b/chromium/components/printing/renderer/print_web_view_helper.cc
@@ -69,10 +69,10 @@ namespace {
"mismatching enums: " #a)
// Check blink and printing enums are kept in sync.
-STATIC_ASSERT_ENUM(blink::WebUnknownDuplexMode, UNKNOWN_DUPLEX_MODE);
-STATIC_ASSERT_ENUM(blink::WebSimplex, SIMPLEX);
-STATIC_ASSERT_ENUM(blink::WebLongEdge, LONG_EDGE);
-STATIC_ASSERT_ENUM(blink::WebShortEdge, SHORT_EDGE);
+STATIC_ASSERT_ENUM(blink::kWebUnknownDuplexMode, UNKNOWN_DUPLEX_MODE);
+STATIC_ASSERT_ENUM(blink::kWebSimplex, SIMPLEX);
+STATIC_ASSERT_ENUM(blink::kWebLongEdge, LONG_EDGE);
+STATIC_ASSERT_ENUM(blink::kWebShortEdge, SHORT_EDGE);
enum PrintPreviewHelperEvents {
PREVIEW_EVENT_REQUESTED,
@@ -101,7 +101,7 @@ void ExecuteScript(blink::WebFrame* frame,
std::string json;
base::JSONWriter::Write(parameters, &json);
std::string script = base::StringPrintf(script_format, json.c_str());
- frame->executeScript(blink::WebString::fromUTF8(script));
+ frame->ExecuteScript(blink::WebString::FromUTF8(script));
}
#else
bool g_is_preview_enabled = false;
@@ -120,15 +120,14 @@ int GetDPI(const PrintMsg_Print_Params* print_params) {
bool PrintMsg_Print_Params_IsValid(const PrintMsg_Print_Params& params) {
return !params.content_size.IsEmpty() && !params.page_size.IsEmpty() &&
!params.printable_area.IsEmpty() && params.document_cookie &&
- params.desired_dpi && params.dpi && params.margin_top >= 0 &&
- params.margin_left >= 0 && params.dpi > kMinDpi &&
- params.document_cookie != 0;
+ params.dpi && params.margin_top >= 0 && params.margin_left >= 0 &&
+ params.dpi > kMinDpi && params.document_cookie != 0;
}
// Helper function to check for fit to page
bool IsWebPrintScalingOptionFitToPage(const PrintMsg_Print_Params& params) {
return params.print_scaling_option ==
- blink::WebPrintScalingOptionFitToPrintableArea;
+ blink::kWebPrintScalingOptionFitToPrintableArea;
}
PrintMsg_Print_Params GetCssPrintParams(
@@ -156,18 +155,15 @@ PrintMsg_Print_Params GetCssPrintParams(
dpi, kPixelsPerInch);
if (frame) {
- frame->pageSizeAndMarginsInPixels(page_index,
- page_size_in_pixels,
- margin_top_in_pixels,
- margin_right_in_pixels,
- margin_bottom_in_pixels,
- margin_left_in_pixels);
+ frame->PageSizeAndMarginsInPixels(
+ page_index, page_size_in_pixels, margin_top_in_pixels,
+ margin_right_in_pixels, margin_bottom_in_pixels, margin_left_in_pixels);
}
- double new_content_width = page_size_in_pixels.width() -
- margin_left_in_pixels - margin_right_in_pixels;
- double new_content_height = page_size_in_pixels.height() -
- margin_top_in_pixels - margin_bottom_in_pixels;
+ double new_content_width = page_size_in_pixels.Width() -
+ margin_left_in_pixels - margin_right_in_pixels;
+ double new_content_height = page_size_in_pixels.Height() -
+ margin_top_in_pixels - margin_bottom_in_pixels;
// Invalid page size and/or margins. We just use the default setting.
if (new_content_width < 1 || new_content_height < 1) {
@@ -177,8 +173,8 @@ PrintMsg_Print_Params GetCssPrintParams(
}
page_css_params.page_size =
- gfx::Size(ConvertUnit(page_size_in_pixels.width(), kPixelsPerInch, dpi),
- ConvertUnit(page_size_in_pixels.height(), kPixelsPerInch, dpi));
+ gfx::Size(ConvertUnit(page_size_in_pixels.Width(), kPixelsPerInch, dpi),
+ ConvertUnit(page_size_in_pixels.Height(), kPixelsPerInch, dpi));
page_css_params.content_size =
gfx::Size(ConvertUnit(new_content_width, kPixelsPerInch, dpi),
ConvertUnit(new_content_height, kPixelsPerInch, dpi));
@@ -285,42 +281,42 @@ void ComputeWebKitPrintParamsInDesiredDpi(
const PrintMsg_Print_Params& print_params,
blink::WebPrintParams* webkit_print_params) {
int dpi = GetDPI(&print_params);
- webkit_print_params->printerDPI = dpi;
- webkit_print_params->rasterizePDF = print_params.rasterize_pdf;
- webkit_print_params->printScalingOption = print_params.print_scaling_option;
-
- webkit_print_params->printContentArea.width = ConvertUnit(
- print_params.content_size.width(), dpi, print_params.desired_dpi);
- webkit_print_params->printContentArea.height = ConvertUnit(
- print_params.content_size.height(), dpi, print_params.desired_dpi);
-
- webkit_print_params->printableArea.x = ConvertUnit(
- print_params.printable_area.x(), dpi, print_params.desired_dpi);
- webkit_print_params->printableArea.y = ConvertUnit(
- print_params.printable_area.y(), dpi, print_params.desired_dpi);
- webkit_print_params->printableArea.width = ConvertUnit(
- print_params.printable_area.width(), dpi, print_params.desired_dpi);
- webkit_print_params->printableArea.height = ConvertUnit(
- print_params.printable_area.height(), dpi, print_params.desired_dpi);
-
- webkit_print_params->paperSize.width = ConvertUnit(
- print_params.page_size.width(), dpi, print_params.desired_dpi);
- webkit_print_params->paperSize.height = ConvertUnit(
- print_params.page_size.height(), dpi, print_params.desired_dpi);
+ webkit_print_params->printer_dpi = dpi;
+ webkit_print_params->rasterize_pdf = print_params.rasterize_pdf;
+ webkit_print_params->print_scaling_option = print_params.print_scaling_option;
+
+ webkit_print_params->print_content_area.width =
+ ConvertUnit(print_params.content_size.width(), dpi, kPointsPerInch);
+ webkit_print_params->print_content_area.height =
+ ConvertUnit(print_params.content_size.height(), dpi, kPointsPerInch);
+
+ webkit_print_params->printable_area.x =
+ ConvertUnit(print_params.printable_area.x(), dpi, kPointsPerInch);
+ webkit_print_params->printable_area.y =
+ ConvertUnit(print_params.printable_area.y(), dpi, kPointsPerInch);
+ webkit_print_params->printable_area.width =
+ ConvertUnit(print_params.printable_area.width(), dpi, kPointsPerInch);
+ webkit_print_params->printable_area.height =
+ ConvertUnit(print_params.printable_area.height(), dpi, kPointsPerInch);
+
+ webkit_print_params->paper_size.width =
+ ConvertUnit(print_params.page_size.width(), dpi, kPointsPerInch);
+ webkit_print_params->paper_size.height =
+ ConvertUnit(print_params.page_size.height(), dpi, kPointsPerInch);
}
blink::WebPlugin* GetPlugin(const blink::WebLocalFrame* frame) {
- return frame->document().isPluginDocument()
- ? frame->document().to<blink::WebPluginDocument>().plugin()
+ return frame->GetDocument().IsPluginDocument()
+ ? frame->GetDocument().To<blink::WebPluginDocument>().Plugin()
: NULL;
}
bool PrintingNodeOrPdfFrame(const blink::WebLocalFrame* frame,
const blink::WebNode& node) {
- if (!node.isNull())
+ if (!node.IsNull())
return true;
blink::WebPlugin* plugin = GetPlugin(frame);
- return plugin && plugin->supportsPaginatedPrint();
+ return plugin && plugin->SupportsPaginatedPrint();
}
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
@@ -338,7 +334,7 @@ bool PrintingFrameHasPageSizeStyle(blink::WebLocalFrame* frame,
return false;
bool frame_has_custom_page_size_style = false;
for (int i = 0; i < total_page_count; ++i) {
- if (frame->hasCustomPageSizeStyle(i)) {
+ if (frame->HasCustomPageSizeStyle(i)) {
frame_has_custom_page_size_style = true;
break;
}
@@ -357,10 +353,10 @@ bool PDFShouldDisableScalingBasedOnPreset(
const blink::WebPrintPresetOptions& options,
const PrintMsg_Print_Params& params,
bool ignore_page_size) {
- if (options.isScalingDisabled)
+ if (options.is_scaling_disabled)
return true;
- if (!options.isPageSizeUniform)
+ if (!options.is_page_size_uniform)
return false;
int dpi = GetDPI(&params);
@@ -376,7 +372,7 @@ bool PDFShouldDisableScalingBasedOnPreset(
blink::WebSize page_size(
ConvertUnit(params.page_size.width(), dpi, kPointsPerInch),
ConvertUnit(params.page_size.height(), dpi, kPointsPerInch));
- return options.uniformPageSize == page_size;
+ return options.uniform_page_size == page_size;
}
bool PDFShouldDisableScaling(blink::WebLocalFrame* frame,
@@ -385,7 +381,7 @@ bool PDFShouldDisableScaling(blink::WebLocalFrame* frame,
bool ignore_page_size) {
const bool kDefaultPDFShouldDisableScalingSetting = true;
blink::WebPrintPresetOptions preset_options;
- if (!frame->getPrintPresetOptionsForPlugin(node, &preset_options))
+ if (!frame->GetPrintPresetOptionsForPlugin(node, &preset_options))
return kDefaultPDFShouldDisableScalingSetting;
return PDFShouldDisableScalingBasedOnPreset(preset_options, params,
ignore_page_size);
@@ -431,18 +427,18 @@ blink::WebPrintScalingOption GetPrintScalingOption(
const base::DictionaryValue& job_settings,
const PrintMsg_Print_Params& params) {
if (params.print_to_pdf)
- return blink::WebPrintScalingOptionSourceSize;
+ return blink::kWebPrintScalingOptionSourceSize;
if (!source_is_html) {
if (!FitToPageEnabled(job_settings))
- return blink::WebPrintScalingOptionNone;
+ return blink::kWebPrintScalingOptionNone;
bool no_plugin_scaling = PDFShouldDisableScaling(frame, node, params,
true);
if (params.is_first_request && no_plugin_scaling)
- return blink::WebPrintScalingOptionNone;
+ return blink::kWebPrintScalingOptionNone;
}
- return blink::WebPrintScalingOptionFitToPrintableArea;
+ return blink::kWebPrintScalingOptionFitToPrintableArea;
}
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
@@ -540,7 +536,7 @@ FrameReference::~FrameReference() {
void FrameReference::Reset(blink::WebLocalFrame* frame) {
if (frame) {
- view_ = frame->view();
+ view_ = frame->View();
frame_ = frame;
} else {
view_ = NULL;
@@ -551,8 +547,8 @@ void FrameReference::Reset(blink::WebLocalFrame* frame) {
blink::WebLocalFrame* FrameReference::GetFrame() {
if (view_ == NULL || frame_ == NULL)
return NULL;
- for (blink::WebFrame* frame = view_->mainFrame(); frame != NULL;
- frame = frame->traverseNext()) {
+ for (blink::WebFrame* frame = view_->MainFrame(); frame != NULL;
+ frame = frame->TraverseNext()) {
if (frame == frame_)
return frame_;
}
@@ -582,22 +578,22 @@ void PrintWebViewHelper::PrintHeaderAndFooter(
page_layout.content_height);
blink::WebView* web_view =
- blink::WebView::create(nullptr, blink::WebPageVisibilityStateVisible);
- web_view->settings()->setJavaScriptEnabled(true);
+ blink::WebView::Create(nullptr, blink::kWebPageVisibilityStateVisible);
+ web_view->GetSettings()->SetJavaScriptEnabled(true);
blink::WebFrameClient frame_client;
- blink::WebLocalFrame* frame = blink::WebLocalFrame::create(
- blink::WebTreeScopeType::Document, &frame_client, nullptr, nullptr);
- web_view->setMainFrame(frame);
- blink::WebFrameWidget::create(nullptr, web_view, frame);
+ blink::WebLocalFrame* frame = blink::WebLocalFrame::Create(
+ blink::WebTreeScopeType::kDocument, &frame_client, nullptr, nullptr);
+ web_view->SetMainFrame(frame);
+ blink::WebWidgetClient web_widget_client;
+ blink::WebFrameWidget::Create(&web_widget_client, web_view, frame);
- base::StringValue html(ResourceBundle::GetSharedInstance().GetLocalizedString(
+ base::Value html(ResourceBundle::GetSharedInstance().GetLocalizedString(
IDR_PRINT_PREVIEW_PAGE));
// Load page with script to avoid async operations.
ExecuteScript(frame, kPageLoadScriptFormat, html);
- std::unique_ptr<base::DictionaryValue> options(new base::DictionaryValue());
- options.reset(new base::DictionaryValue());
+ auto options = base::MakeUnique<base::DictionaryValue>();
options->SetDouble(kSettingHeaderFooterDate, base::Time::Now().ToJsTime());
options->SetDouble("width", page_size.width);
options->SetDouble("height", page_size.height);
@@ -607,19 +603,19 @@ void PrintWebViewHelper::PrintHeaderAndFooter(
base::StringPrintf("%d/%d", page_number, total_pages));
options->SetString("url", params.url);
- base::string16 title = source_frame.document().title().utf16();
+ base::string16 title = source_frame.GetDocument().Title().Utf16();
options->SetString("title", title.empty() ? params.title : title);
ExecuteScript(frame, kPageSetupScriptFormat, *options);
blink::WebPrintParams webkit_params(page_size);
- webkit_params.printerDPI = GetDPI(&params);
+ webkit_params.printer_dpi = GetDPI(&params);
- frame->printBegin(webkit_params);
- frame->printPage(0, canvas);
- frame->printEnd();
+ frame->PrintBegin(webkit_params);
+ frame->PrintPage(0, canvas);
+ frame->PrintEnd();
- web_view->close();
+ web_view->Close();
}
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
@@ -633,7 +629,7 @@ float PrintWebViewHelper::RenderPageContent(blink::WebFrame* frame,
cc::PaintCanvasAutoRestore auto_restore(canvas, true);
canvas->translate((content_area.x() - canvas_area.x()) / scale_factor,
(content_area.y() - canvas_area.y()) / scale_factor);
- return frame->printPage(page_number, canvas);
+ return frame->PrintPage(page_number, canvas);
}
// Class that calls the Begin and End print functions on the frame and changes
@@ -665,22 +661,22 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient,
bool IsLoadingSelection() {
// It's not selection if not |owns_web_view_|.
- return owns_web_view_ && frame() && frame()->isLoading();
+ return owns_web_view_ && frame() && frame()->IsLoading();
}
private:
// blink::WebViewClient:
- void didStopLoading() override;
+ void DidStopLoading() override;
// TODO(ojan): Remove this override and have this class use a non-null
// layerTreeView.
- bool allowsBrokenNullLayerTreeView() const override;
+ bool AllowsBrokenNullLayerTreeView() const override;
// blink::WebFrameClient:
- blink::WebLocalFrame* createChildFrame(
+ blink::WebLocalFrame* CreateChildFrame(
blink::WebLocalFrame* parent,
blink::WebTreeScopeType scope,
const blink::WebString& name,
- const blink::WebString& unique_name,
+ const blink::WebString& fallback_name,
blink::WebSandboxFlags sandbox_flags,
const blink::WebFrameOwnerProperties& frame_owner_properties) override;
@@ -725,7 +721,7 @@ PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
bool fit_to_page =
ignore_css_margins && IsWebPrintScalingOptionFitToPage(print_params);
ComputeWebKitPrintParamsInDesiredDpi(params, &web_print_params_);
- frame->printBegin(web_print_params_, node_to_print_);
+ frame->PrintBegin(web_print_params_, node_to_print_);
double scale_factor = 1.0f;
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
if (print_params.scale_factor >= PrintWebViewHelper::kEpsilon)
@@ -733,7 +729,7 @@ PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
#endif
print_params = CalculatePrintParamsForCss(
frame, 0, print_params, ignore_css_margins, fit_to_page, &scale_factor);
- frame->printEnd();
+ frame->PrintEnd();
}
ComputeWebKitPrintParamsInDesiredDpi(print_params, &web_print_params_);
}
@@ -752,8 +748,8 @@ void PrepareFrameAndViewForPrint::ResizeForPrinting() {
// the number that produces output with the correct physical size for elements
// that are specified in cm, mm, pt etc.
// This is important for sites that try to fill the page.
- gfx::Size print_layout_size(web_print_params_.printContentArea.width,
- web_print_params_.printContentArea.height);
+ gfx::Size print_layout_size(web_print_params_.print_content_area.width,
+ web_print_params_.print_content_area.height);
print_layout_size.set_height(
ScaleAndRound(print_layout_size.height(), kPrintingMinimumShrinkFactor));
@@ -762,20 +758,20 @@ void PrepareFrameAndViewForPrint::ResizeForPrinting() {
// Backup size and offset if it's a local frame.
blink::WebView* web_view = frame_.view();
- if (blink::WebFrame* web_frame = web_view->mainFrame()) {
- if (web_frame->isWebLocalFrame())
- prev_scroll_offset_ = web_frame->getScrollOffset();
+ if (blink::WebFrame* web_frame = web_view->MainFrame()) {
+ if (web_frame->IsWebLocalFrame())
+ prev_scroll_offset_ = web_frame->GetScrollOffset();
}
- prev_view_size_ = web_view->size();
+ prev_view_size_ = web_view->Size();
- web_view->resize(print_layout_size);
+ web_view->Resize(print_layout_size);
}
void PrepareFrameAndViewForPrint::StartPrinting() {
blink::WebView* web_view = frame_.view();
- web_view->settings()->setShouldPrintBackgrounds(should_print_backgrounds_);
+ web_view->GetSettings()->SetShouldPrintBackgrounds(should_print_backgrounds_);
expected_pages_count_ =
- frame()->printBegin(web_print_params_, node_to_print_);
+ frame()->PrintBegin(web_print_params_, node_to_print_);
ResizeForPrinting();
is_printing_started_ = true;
}
@@ -797,7 +793,7 @@ void PrepareFrameAndViewForPrint::CopySelection(
ResizeForPrinting();
std::string url_str = "data:text/html;charset=utf-8,";
url_str.append(
- net::EscapeQueryParamValue(frame()->selectionAsMarkup().utf8(), false));
+ net::EscapeQueryParamValue(frame()->SelectionAsMarkup().Utf8(), false));
RestoreSize();
// Create a new WebView with the same settings as the current display one.
// Except that we disable javascript (don't want any active content running
@@ -806,27 +802,27 @@ void PrepareFrameAndViewForPrint::CopySelection(
prefs.javascript_enabled = false;
blink::WebView* web_view =
- blink::WebView::create(this, blink::WebPageVisibilityStateVisible);
+ blink::WebView::Create(this, blink::kWebPageVisibilityStateVisible);
owns_web_view_ = true;
content::RenderView::ApplyWebPreferences(prefs, web_view);
- blink::WebLocalFrame* main_frame = blink::WebLocalFrame::create(
- blink::WebTreeScopeType::Document, this, nullptr, nullptr);
- web_view->setMainFrame(main_frame);
- blink::WebFrameWidget::create(this, web_view, main_frame);
- frame_.Reset(web_view->mainFrame()->toWebLocalFrame());
- node_to_print_.reset();
+ blink::WebLocalFrame* main_frame = blink::WebLocalFrame::Create(
+ blink::WebTreeScopeType::kDocument, this, nullptr, nullptr);
+ web_view->SetMainFrame(main_frame);
+ blink::WebFrameWidget::Create(this, web_view, main_frame);
+ frame_.Reset(web_view->MainFrame()->ToWebLocalFrame());
+ node_to_print_.Reset();
// When loading is done this will call didStopLoading() and that will do the
// actual printing.
blink::WebURLRequest request = blink::WebURLRequest(GURL(url_str));
- frame()->loadRequest(request);
+ frame()->LoadRequest(request);
}
-bool PrepareFrameAndViewForPrint::allowsBrokenNullLayerTreeView() const {
+bool PrepareFrameAndViewForPrint::AllowsBrokenNullLayerTreeView() const {
return true;
}
-void PrepareFrameAndViewForPrint::didStopLoading() {
+void PrepareFrameAndViewForPrint::DidStopLoading() {
DCHECK(!on_ready_.is_null());
// Don't call callback here, because it can delete |this| and WebView that is
// called didStopLoading.
@@ -835,16 +831,16 @@ void PrepareFrameAndViewForPrint::didStopLoading() {
weak_ptr_factory_.GetWeakPtr()));
}
-blink::WebLocalFrame* PrepareFrameAndViewForPrint::createChildFrame(
+blink::WebLocalFrame* PrepareFrameAndViewForPrint::CreateChildFrame(
blink::WebLocalFrame* parent,
blink::WebTreeScopeType scope,
const blink::WebString& name,
- const blink::WebString& unique_name,
+ const blink::WebString& fallback_name,
blink::WebSandboxFlags sandbox_flags,
const blink::WebFrameOwnerProperties& frame_owner_properties) {
blink::WebLocalFrame* frame =
- blink::WebLocalFrame::create(scope, this, nullptr, nullptr);
- parent->appendChild(frame);
+ blink::WebLocalFrame::Create(scope, this, nullptr, nullptr);
+ parent->AppendChild(frame);
return frame;
}
@@ -856,31 +852,31 @@ void PrepareFrameAndViewForPrint::RestoreSize() {
if (!frame())
return;
- blink::WebView* web_view = frame_.GetFrame()->view();
- web_view->resize(prev_view_size_);
- if (blink::WebFrame* web_frame = web_view->mainFrame()) {
- if (web_frame->isWebLocalFrame())
- web_frame->setScrollOffset(prev_scroll_offset_);
+ blink::WebView* web_view = frame_.GetFrame()->View();
+ web_view->Resize(prev_view_size_);
+ if (blink::WebFrame* web_frame = web_view->MainFrame()) {
+ if (web_frame->IsWebLocalFrame())
+ web_frame->SetScrollOffset(prev_scroll_offset_);
}
}
void PrepareFrameAndViewForPrint::FinishPrinting() {
blink::WebLocalFrame* frame = frame_.GetFrame();
if (frame) {
- blink::WebView* web_view = frame->view();
+ blink::WebView* web_view = frame->View();
if (is_printing_started_) {
is_printing_started_ = false;
if (!owns_web_view_) {
- web_view->settings()->setShouldPrintBackgrounds(false);
+ web_view->GetSettings()->SetShouldPrintBackgrounds(false);
RestoreSize();
}
- frame->printEnd();
+ frame->PrintEnd();
}
if (owns_web_view_) {
- DCHECK(!frame->isLoading());
+ DCHECK(!frame->IsLoading());
owns_web_view_ = false;
- frame->frameWidget()->close();
- web_view->close();
+ frame->FrameWidget()->Close();
+ web_view->Close();
}
}
frame_.Reset(NULL);
@@ -895,6 +891,12 @@ bool PrintWebViewHelper::Delegate::IsScriptedPrintEnabled() {
return true;
}
+#if defined(OS_MACOSX)
+bool PrintWebViewHelper::Delegate::UseSingleMetafile() {
+ return false;
+}
+#endif
+
PrintWebViewHelper::PrintWebViewHelper(content::RenderFrame* render_frame,
std::unique_ptr<Delegate> delegate)
: content::RenderFrameObserver(render_frame),
@@ -910,6 +912,7 @@ PrintWebViewHelper::PrintWebViewHelper(content::RenderFrame* render_frame,
is_loading_(false),
is_scripted_preview_delayed_(false),
ipc_nesting_level_(0),
+ render_frame_gone_(false),
weak_ptr_factory_(this) {
if (!delegate_->IsPrintPreviewEnabled())
DisablePreview();
@@ -991,8 +994,6 @@ bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) {
// choose to ignore message or safely crash process.
++ipc_nesting_level_;
- auto self = weak_ptr_factory_.GetWeakPtr();
-
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PrintWebViewHelper, message)
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
@@ -1011,13 +1012,17 @@ bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
- // Check if |this| is still valid. e.g. when OnPrintPages() returns.
- if (self)
- --ipc_nesting_level_;
+ --ipc_nesting_level_;
+ if (ipc_nesting_level_ == 0 && render_frame_gone_)
+ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
return handled;
}
void PrintWebViewHelper::OnDestruct() {
+ if (ipc_nesting_level_ > 0) {
+ render_frame_gone_ = true;
+ return;
+ }
delete this;
}
@@ -1058,11 +1063,11 @@ void PrintWebViewHelper::OnPrintForPrintPreview(
if (prep_frame_view_)
return;
- blink::WebDocument document = render_frame()->GetWebFrame()->document();
+ blink::WebDocument document = render_frame()->GetWebFrame()->GetDocument();
// <object>/<iframe> with id="pdf-viewer" is created in
// chrome/browser/resources/print_preview/print_preview.js
- blink::WebElement pdf_element = document.getElementById("pdf-viewer");
- if (pdf_element.isNull()) {
+ blink::WebElement pdf_element = document.GetElementById("pdf-viewer");
+ if (pdf_element.IsNull()) {
NOTREACHED();
return;
}
@@ -1070,12 +1075,12 @@ void PrintWebViewHelper::OnPrintForPrintPreview(
// The out-of-process plugin element is nested within a frame. In tests, there
// may not be an iframe containing the out-of-process plugin, so continue with
// the element with ID "pdf-viewer" if it isn't an iframe.
- blink::WebLocalFrame* plugin_frame = pdf_element.document().frame();
+ blink::WebLocalFrame* plugin_frame = pdf_element.GetDocument().GetFrame();
blink::WebElement plugin_element = pdf_element;
- if (pdf_element.hasHTMLTagName("iframe")) {
- plugin_frame = blink::WebLocalFrame::fromFrameOwnerElement(pdf_element);
+ if (pdf_element.HasHTMLTagName("iframe")) {
+ plugin_frame = blink::WebLocalFrame::FromFrameOwnerElement(pdf_element);
plugin_element = delegate_->GetPdfElement(plugin_frame);
- if (plugin_element.isNull()) {
+ if (plugin_element.IsNull()) {
NOTREACHED();
return;
}
@@ -1202,13 +1207,13 @@ void PrintWebViewHelper::PrepareFrameForPreviewDocument() {
}
const PrintMsg_Print_Params& print_params = print_pages_params_->params;
- prep_frame_view_.reset(new PrepareFrameAndViewForPrint(
+ prep_frame_view_ = base::MakeUnique<PrepareFrameAndViewForPrint>(
print_params, print_preview_context_.source_frame(),
- print_preview_context_.source_node(), ignore_css_margins_));
+ print_preview_context_.source_node(), ignore_css_margins_);
prep_frame_view_->CopySelectionIfNeeded(
render_frame()->GetWebkitPreferences(),
base::Bind(&PrintWebViewHelper::OnFramePreparedForPreviewDocument,
- base::Unretained(this)));
+ weak_ptr_factory_.GetWeakPtr()));
}
void PrintWebViewHelper::OnFramePreparedForPreviewDocument() {
@@ -1257,14 +1262,14 @@ bool PrintWebViewHelper::CreatePreviewDocument() {
blink::WebLocalFrame* source_frame = print_preview_context_.source_frame();
const blink::WebNode& source_node = print_preview_context_.source_node();
blink::WebPrintPresetOptions preset_options;
- if (source_frame->getPrintPresetOptionsForPlugin(source_node,
+ if (source_frame->GetPrintPresetOptionsForPlugin(source_node,
&preset_options)) {
- if (preset_options.isPageSizeUniform) {
+ if (preset_options.is_page_size_uniform) {
// Figure out if the sizes have the same orientation
bool is_printable_area_landscape = printable_area_in_points.width() >
printable_area_in_points.height();
- bool is_preset_landscape = preset_options.uniformPageSize.width >
- preset_options.uniformPageSize.height;
+ bool is_preset_landscape = preset_options.uniform_page_size.width >
+ preset_options.uniform_page_size.height;
bool rotate = is_printable_area_landscape != is_preset_landscape;
// Match orientation for computing scaling
double printable_width = rotate ? printable_area_in_points.height()
@@ -1273,10 +1278,10 @@ bool PrintWebViewHelper::CreatePreviewDocument() {
: printable_area_in_points.height();
double scale_width =
printable_width /
- static_cast<double>(preset_options.uniformPageSize.width);
+ static_cast<double>(preset_options.uniform_page_size.width);
double scale_height =
printable_height /
- static_cast<double>(preset_options.uniformPageSize.height);
+ static_cast<double>(preset_options.uniform_page_size.height);
fit_to_page_scale_factor = std::min(scale_width, scale_height);
} else {
fit_to_page_scale_factor = 0.0f;
@@ -1335,18 +1340,16 @@ bool PrintWebViewHelper::CreatePreviewDocument() {
bool PrintWebViewHelper::RenderPreviewPage(
int page_number,
const PrintMsg_Print_Params& print_params) {
- PrintMsg_PrintPage_Params page_params;
- page_params.params = print_params;
- page_params.page_number = page_number;
std::unique_ptr<PdfMetafileSkia> draft_metafile;
PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile();
if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) {
- draft_metafile.reset(new PdfMetafileSkia(PDF_SKIA_DOCUMENT_TYPE));
+ draft_metafile = base::MakeUnique<PdfMetafileSkia>(PDF_SKIA_DOCUMENT_TYPE);
initial_render_metafile = draft_metafile.get();
}
base::TimeTicks begin_time = base::TimeTicks::Now();
- PrintPageInternal(page_params, print_preview_context_.prepared_frame(),
+ PrintPageInternal(print_params, page_number,
+ print_preview_context_.prepared_frame(),
initial_render_metafile, nullptr, nullptr, nullptr);
print_preview_context_.RenderedPreviewPage(
base::TimeTicks::Now() - begin_time);
@@ -1416,7 +1419,7 @@ void PrintWebViewHelper::OnInitiatePrintPreview(bool has_selection) {
// If we are printing a PDF extension frame, find the plugin node and print
// that instead.
auto plugin = delegate_->GetPdfElement(frame);
- if (!plugin.isNull()) {
+ if (!plugin.IsNull()) {
PrintNode(plugin);
return;
}
@@ -1432,7 +1435,7 @@ bool PrintWebViewHelper::IsPrintingEnabled() const {
}
void PrintWebViewHelper::PrintNode(const blink::WebNode& node) {
- if (node.isNull() || !node.document().frame()) {
+ if (node.IsNull() || !node.GetDocument().GetFrame()) {
// This can occur when the context menu refers to an invalid WebNode.
// See http://crbug.com/100890#c17 for a repro case.
return;
@@ -1459,7 +1462,7 @@ void PrintWebViewHelper::PrintNode(const blink::WebNode& node) {
blink::WebNode duplicate_node(node);
auto self = weak_ptr_factory_.GetWeakPtr();
- Print(duplicate_node.document().frame(), duplicate_node,
+ Print(duplicate_node.GetDocument().GetFrame(), duplicate_node,
false /* is_scripted? */);
// Check if |this| is still valid.
if (!self)
@@ -1655,10 +1658,11 @@ bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size) {
ignore_css_margins_ = false;
settings.pages.clear();
- settings.params.print_scaling_option = blink::WebPrintScalingOptionSourceSize;
+ settings.params.print_scaling_option =
+ blink::kWebPrintScalingOptionSourceSize;
if (fit_to_paper_size) {
settings.params.print_scaling_option =
- blink::WebPrintScalingOptionFitToPrintableArea;
+ blink::kWebPrintScalingOptionFitToPrintableArea;
}
SetPrintPagesParams(settings);
@@ -1691,7 +1695,7 @@ bool PrintWebViewHelper::SetOptionsFromPdfDocument(
const blink::WebNode& source_node = print_preview_context_.source_node();
blink::WebPrintPresetOptions preset_options;
- if (!source_frame->getPrintPresetOptionsForPlugin(source_node,
+ if (!source_frame->GetPrintPresetOptionsForPlugin(source_node,
&preset_options)) {
return false;
}
@@ -1702,11 +1706,11 @@ bool PrintWebViewHelper::SetOptionsFromPdfDocument(
// TODO(thestig) This should be a straight pass-through, but print preview
// does not currently support short-edge printing.
- switch (preset_options.duplexMode) {
- case blink::WebSimplex:
+ switch (preset_options.duplex_mode) {
+ case blink::kWebSimplex:
options->duplex = SIMPLEX;
break;
- case blink::WebLongEdge:
+ case blink::kWebLongEdge:
options->duplex = LONG_EDGE;
break;
default:
@@ -1802,7 +1806,7 @@ void PrintWebViewHelper::GetPrintSettingsFromUser(
PrintMsg_PrintPages_Params* print_settings) {
PrintHostMsg_ScriptedPrint_Params params;
params.cookie = print_pages_params_->params.document_cookie;
- params.has_selection = frame->hasSelection();
+ params.has_selection = frame->HasSelection();
params.expected_pages_count = expected_pages_count;
MarginType margin_type = DEFAULT_MARGINS;
if (PrintingNodeOrPdfFrame(frame, node))
@@ -1830,40 +1834,40 @@ bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame* frame,
const PrintMsg_PrintPages_Params& params = *print_pages_params_;
const PrintMsg_Print_Params& print_params = params.params;
- prep_frame_view_.reset(new PrepareFrameAndViewForPrint(
- print_params, frame, node, ignore_css_margins_));
+ prep_frame_view_ = base::MakeUnique<PrepareFrameAndViewForPrint>(
+ print_params, frame, node, ignore_css_margins_);
DCHECK(!print_pages_params_->params.selection_only ||
print_pages_params_->pages.empty());
prep_frame_view_->CopySelectionIfNeeded(
render_frame()->GetWebkitPreferences(),
base::Bind(&PrintWebViewHelper::OnFramePreparedForPrintPages,
- base::Unretained(this)));
+ weak_ptr_factory_.GetWeakPtr()));
return true;
}
#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
#if !defined(OS_MACOSX)
-void PrintWebViewHelper::PrintPageInternal(
- const PrintMsg_PrintPage_Params& params,
- blink::WebLocalFrame* frame,
- PdfMetafileSkia* metafile,
- gfx::Size* page_size_in_dpi,
- gfx::Rect* content_area_in_dpi,
- gfx::Rect* printable_area_in_dpi) {
+void PrintWebViewHelper::PrintPageInternal(const PrintMsg_Print_Params& params,
+ int page_number,
+ blink::WebLocalFrame* frame,
+ PdfMetafileSkia* metafile,
+ gfx::Size* page_size_in_dpi,
+ gfx::Rect* content_area_in_dpi,
+ gfx::Rect* printable_area_in_dpi) {
PageSizeMargins page_layout_in_points;
double css_scale_factor = 1.0f;
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
- if (params.params.scale_factor >= kEpsilon)
- css_scale_factor = params.params.scale_factor;
+ if (params.scale_factor >= kEpsilon)
+ css_scale_factor = params.scale_factor;
#endif
// Save the original page size here to avoid rounding errors incurred by
// converting to pixels and back and by scaling the page for reflow and
// scaling back. Windows uses |page_size_in_dpi| for the actual page size
// so requires an accurate value.
- gfx::Size original_page_size = params.params.page_size;
- ComputePageLayoutInPointsForCss(frame, params.page_number, params.params,
+ gfx::Size original_page_size = params.page_size;
+ ComputePageLayoutInPointsForCss(frame, page_number, params,
ignore_css_margins_, &css_scale_factor,
&page_layout_in_points);
gfx::Size page_size;
@@ -1886,12 +1890,11 @@ void PrintWebViewHelper::PrintPageInternal(
}
gfx::Rect canvas_area =
- params.params.display_header_footer ? gfx::Rect(page_size) : content_area;
+ params.display_header_footer ? gfx::Rect(page_size) : content_area;
// TODO(thestig): Figure out why Linux is different.
#if defined(OS_WIN)
- float webkit_page_shrink_factor =
- frame->getPrintPageShrink(params.page_number);
+ float webkit_page_shrink_factor = frame->GetPrintPageShrink(page_number);
float scale_factor = css_scale_factor * webkit_page_shrink_factor;
#else
float scale_factor = css_scale_factor;
@@ -1905,7 +1908,7 @@ void PrintWebViewHelper::PrintPageInternal(
MetafileSkiaWrapper::SetMetafileOnCanvas(canvas, metafile);
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
- if (params.params.display_header_footer) {
+ if (params.display_header_footer) {
// TODO(thestig): Figure out why Linux needs this. It is almost certainly
// |printingMinimumShrinkFactor| from Blink.
#if defined(OS_WIN)
@@ -1914,16 +1917,14 @@ void PrintWebViewHelper::PrintPageInternal(
const float fudge_factor = kPrintingMinimumShrinkFactor;
#endif
// |page_number| is 0-based, so 1 is added.
- PrintHeaderAndFooter(canvas, params.page_number + 1,
- print_preview_context_.total_page_count(), *frame,
- scale_factor / fudge_factor, page_layout_in_points,
- params.params);
+ PrintHeaderAndFooter(
+ canvas, page_number + 1, print_preview_context_.total_page_count(),
+ *frame, scale_factor / fudge_factor, page_layout_in_points, params);
}
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
- float webkit_scale_factor =
- RenderPageContent(frame, params.page_number, canvas_area, content_area,
- scale_factor, canvas);
+ float webkit_scale_factor = RenderPageContent(
+ frame, page_number, canvas_area, content_area, scale_factor, canvas);
DCHECK_GT(webkit_scale_factor, 0.0f);
// Done printing. Close the canvas to retrieve the compiled metafile.
@@ -1984,7 +1985,7 @@ void PrintWebViewHelper::RequestPrintPreview(PrintPreviewRequestType type) {
// DidStopLoading() is called. Defer showing the preview until then.
on_stop_loading_closure_ =
base::Bind(&PrintWebViewHelper::ShowScriptedPrintPreview,
- base::Unretained(this));
+ weak_ptr_factory_.GetWeakPtr());
} else {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&PrintWebViewHelper::ShowScriptedPrintPreview,
@@ -2007,7 +2008,7 @@ void PrintWebViewHelper::RequestPrintPreview(PrintPreviewRequestType type) {
if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
on_stop_loading_closure_ =
base::Bind(&PrintWebViewHelper::RequestPrintPreview,
- base::Unretained(this), type);
+ weak_ptr_factory_.GetWeakPtr(), type);
return;
}
@@ -2023,7 +2024,7 @@ void PrintWebViewHelper::RequestPrintPreview(PrintPreviewRequestType type) {
if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
on_stop_loading_closure_ =
base::Bind(&PrintWebViewHelper::RequestPrintPreview,
- base::Unretained(this), type);
+ weak_ptr_factory_.GetWeakPtr(), type);
return;
}
@@ -2092,10 +2093,10 @@ PrintWebViewHelper::PrintPreviewContext::PrintPreviewContext()
: total_page_count_(0),
current_page_index_(0),
generate_draft_pages_(true),
+ is_modifiable_(true),
print_ready_metafile_page_count_(0),
error_(PREVIEW_ERROR_NONE),
- state_(UNINITIALIZED) {
-}
+ state_(UNINITIALIZED) {}
PrintWebViewHelper::PrintPreviewContext::~PrintPreviewContext() {
}
@@ -2106,17 +2107,19 @@ void PrintWebViewHelper::PrintPreviewContext::InitWithFrame(
DCHECK(!IsRendering());
state_ = INITIALIZED;
source_frame_.Reset(web_frame);
- source_node_.reset();
+ source_node_.Reset();
+ CalculateIsModifiable();
}
void PrintWebViewHelper::PrintPreviewContext::InitWithNode(
const blink::WebNode& web_node) {
- DCHECK(!web_node.isNull());
- DCHECK(web_node.document().frame());
+ DCHECK(!web_node.IsNull());
+ DCHECK(web_node.GetDocument().GetFrame());
DCHECK(!IsRendering());
state_ = INITIALIZED;
- source_frame_.Reset(web_node.document().frame());
+ source_frame_.Reset(web_node.GetDocument().GetFrame());
source_node_ = web_node;
+ CalculateIsModifiable();
}
void PrintWebViewHelper::PrintPreviewContext::OnPrintPreview() {
@@ -2141,7 +2144,7 @@ bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument(
return false;
}
- metafile_.reset(new PdfMetafileSkia(PDF_SKIA_DOCUMENT_TYPE));
+ metafile_ = base::MakeUnique<PdfMetafileSkia>(PDF_SKIA_DOCUMENT_TYPE);
CHECK(metafile_->Init());
current_page_index_ = 0;
@@ -2242,13 +2245,13 @@ bool PrintWebViewHelper::PrintPreviewContext::IsRendering() const {
return state_ == RENDERING || state_ == DONE;
}
-bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() {
- // The only kind of node we can print right now is a PDF node.
- return !PrintingNodeOrPdfFrame(source_frame(), source_node_);
+bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() const {
+ DCHECK(state_ != UNINITIALIZED);
+ return is_modifiable_;
}
bool PrintWebViewHelper::PrintPreviewContext::HasSelection() {
- return IsModifiable() && source_frame()->hasSelection();
+ return IsModifiable() && source_frame()->HasSelection();
}
bool PrintWebViewHelper::PrintPreviewContext::IsLastPageOfPrintReadyMetafile()
@@ -2321,9 +2324,14 @@ void PrintWebViewHelper::PrintPreviewContext::ClearContext() {
error_ = PREVIEW_ERROR_NONE;
}
+void PrintWebViewHelper::PrintPreviewContext::CalculateIsModifiable() {
+ // The only kind of node we can print right now is a PDF node.
+ is_modifiable_ = !PrintingNodeOrPdfFrame(source_frame(), source_node_);
+}
+
void PrintWebViewHelper::SetPrintPagesParams(
const PrintMsg_PrintPages_Params& settings) {
- print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings));
+ print_pages_params_ = base::MakeUnique<PrintMsg_PrintPages_Params>(settings);
Send(new PrintHostMsg_DidGetDocumentCookie(routing_id(),
settings.params.document_cookie));
}
@@ -2363,9 +2371,9 @@ bool PrintWebViewHelper::ScriptingThrottler::IsAllowed(
}
blink::WebString message(
- blink::WebString::fromUTF8("Ignoring too frequent calls to print()."));
- frame->addMessageToConsole(blink::WebConsoleMessage(
- blink::WebConsoleMessage::LevelWarning, message));
+ blink::WebString::FromUTF8("Ignoring too frequent calls to print()."));
+ frame->AddMessageToConsole(blink::WebConsoleMessage(
+ blink::WebConsoleMessage::kLevelWarning, message));
return false;
}
diff --git a/chromium/components/printing/renderer/print_web_view_helper.h b/chromium/components/printing/renderer/print_web_view_helper.h
index d979333feb1..15d2c288e78 100644
--- a/chromium/components/printing/renderer/print_web_view_helper.h
+++ b/chromium/components/printing/renderer/print_web_view_helper.h
@@ -25,7 +25,6 @@
#include "ui/gfx/geometry/size.h"
struct PrintMsg_Print_Params;
-struct PrintMsg_PrintPage_Params;
struct PrintMsg_PrintPages_Params;
struct PrintHostMsg_SetOptionsFromDocument_Params;
@@ -108,6 +107,15 @@ class PrintWebViewHelper
// Returns true if printing is overridden and the default behavior should be
// skipped for |frame|.
virtual bool OverridePrint(blink::WebLocalFrame* frame) = 0;
+
+#if defined(OS_MACOSX)
+ // If true, all the printed pages are returned in the first
+ // PrintHostMsg_DidPrintPage metafile, like on Linux and Windows.
+ // NOTE: PrintHostMsg_DidPrintPage messages for all pages contain the same
+ // page and content area, which may lead to bug when these two parameters
+ // are different per page.
+ virtual bool UseSingleMetafile();
+#endif
};
PrintWebViewHelper(content::RenderFrame* render_frame,
@@ -283,10 +291,12 @@ class PrintWebViewHelper
// Prints the page listed in |params|.
#if defined(OS_MACOSX)
- void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
- blink::WebLocalFrame* frame);
+ void PrintPagesInternal(const PrintMsg_Print_Params& params,
+ const std::vector<int>& printed_pages,
+ blink::WebLocalFrame* frame);
#else
- void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
+ void PrintPageInternal(const PrintMsg_Print_Params& params,
+ int page_number,
blink::WebLocalFrame* frame,
PdfMetafileSkia* metafile,
gfx::Size* page_size_in_dpi,
@@ -439,7 +449,7 @@ class PrintWebViewHelper
// Helper functions
int GetNextPageNumber();
bool IsRendering() const;
- bool IsModifiable();
+ bool IsModifiable() const;
bool HasSelection();
bool IsLastPageOfPrintReadyMetafile() const;
bool IsFinalPageRendered() const;
@@ -477,6 +487,8 @@ class PrintWebViewHelper
// Reset some of the internal rendering context.
void ClearContext();
+ void CalculateIsModifiable();
+
// Specifies what to render for print preview.
FrameReference source_frame_;
blink::WebNode source_node_;
@@ -496,6 +508,9 @@ class PrintWebViewHelper
// True, when draft pages needs to be generated.
bool generate_draft_pages_;
+ // True, if the document source is modifiable. e.g. HTML and not PDF.
+ bool is_modifiable_;
+
// Specifies the total number of pages in the print ready metafile.
int print_ready_metafile_page_count_;
@@ -505,6 +520,8 @@ class PrintWebViewHelper
enum PrintPreviewErrorBuckets error_;
State state_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrintPreviewContext);
};
class ScriptingThrottler {
@@ -531,6 +548,7 @@ class PrintWebViewHelper
bool is_loading_;
bool is_scripted_preview_delayed_;
int ipc_nesting_level_;
+ bool render_frame_gone_;
// Used to fix a race condition where the source is a PDF and print preview
// hangs because RequestPrintPreview is called before DidStopLoading() is
diff --git a/chromium/components/printing/renderer/print_web_view_helper_linux.cc b/chromium/components/printing/renderer/print_web_view_helper_linux.cc
index f09e4b22c51..dac616a6bb6 100644
--- a/chromium/components/printing/renderer/print_web_view_helper_linux.cc
+++ b/chromium/components/printing/renderer/print_web_view_helper_linux.cc
@@ -54,11 +54,9 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebLocalFrame* frame,
if (printed_pages.empty())
return false;
- PrintMsg_PrintPage_Params page_params;
- page_params.params = params.params;
for (int page_number : printed_pages) {
- page_params.page_number = page_number;
- PrintPageInternal(page_params, frame, &metafile, nullptr, nullptr, nullptr);
+ PrintPageInternal(params.params, page_number, frame, &metafile, nullptr,
+ nullptr, nullptr);
}
// blink::printEnd() for PDF should be called before metafile is closed.
diff --git a/chromium/components/printing/renderer/print_web_view_helper_mac.mm b/chromium/components/printing/renderer/print_web_view_helper_mac.mm
index 6de15ad3c7a..4c1c5b9a73e 100644
--- a/chromium/components/printing/renderer/print_web_view_helper_mac.mm
+++ b/chromium/components/printing/renderer/print_web_view_helper_mac.mm
@@ -28,33 +28,35 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebLocalFrame* frame,
if (printed_pages.empty())
return false;
- PrintMsg_PrintPage_Params page_params;
- page_params.params = print_params;
- for (int page_number : printed_pages) {
- page_params.page_number = page_number;
- PrintPageInternal(page_params, frame);
+ if (delegate_->UseSingleMetafile()) {
+ PrintPagesInternal(print_params, printed_pages, frame);
+ return true;
}
+
+ for (int page_number : printed_pages)
+ PrintPagesInternal(print_params, std::vector<int>{page_number}, frame);
return true;
}
#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
-void PrintWebViewHelper::PrintPageInternal(
- const PrintMsg_PrintPage_Params& params,
+void PrintWebViewHelper::PrintPagesInternal(
+ const PrintMsg_Print_Params& params,
+ const std::vector<int>& printed_pages,
blink::WebLocalFrame* frame) {
PdfMetafileSkia metafile(PDF_SKIA_DOCUMENT_TYPE);
CHECK(metafile.Init());
- int page_number = params.page_number;
gfx::Size page_size_in_dpi;
gfx::Rect content_area_in_dpi;
- RenderPage(print_pages_params_->params, page_number, frame, false, &metafile,
- &page_size_in_dpi, &content_area_in_dpi);
+ for (int page_number : printed_pages) {
+ RenderPage(params, page_number, frame, false, &metafile, &page_size_in_dpi,
+ &content_area_in_dpi);
+ }
metafile.FinishDocument();
PrintHostMsg_DidPrintPage_Params page_params;
page_params.data_size = metafile.GetDataSize();
- page_params.page_number = page_number;
- page_params.document_cookie = params.params.document_cookie;
+ page_params.document_cookie = params.document_cookie;
page_params.page_size = page_size_in_dpi;
page_params.content_area = content_area_in_dpi;
@@ -65,7 +67,11 @@ void PrintWebViewHelper::PrintPageInternal(
page_params.data_size = 0;
}
- Send(new PrintHostMsg_DidPrintPage(routing_id(), page_params));
+ for (int page_number : printed_pages) {
+ page_params.page_number = page_number;
+ Send(new PrintHostMsg_DidPrintPage(routing_id(), page_params));
+ page_params.metafile_data_handle = base::SharedMemoryHandle();
+ }
}
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
@@ -116,7 +122,7 @@ void PrintWebViewHelper::RenderPage(const PrintMsg_Print_Params& params,
gfx::Rect* content_rect) {
double scale_factor =
params.scale_factor >= kEpsilon ? params.scale_factor : 1.0f;
- double webkit_shrink_factor = frame->getPrintPageShrink(page_number);
+ double webkit_shrink_factor = frame->GetPrintPageShrink(page_number);
PageSizeMargins page_layout_in_points;
gfx::Rect content_area;
diff --git a/chromium/components/printing/renderer/print_web_view_helper_pdf_win.cc b/chromium/components/printing/renderer/print_web_view_helper_pdf_win.cc
index acd25c2b8e6..9c61a794a4c 100644
--- a/chromium/components/printing/renderer/print_web_view_helper_pdf_win.cc
+++ b/chromium/components/printing/renderer/print_web_view_helper_pdf_win.cc
@@ -29,12 +29,10 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebLocalFrame* frame,
PdfMetafileSkia metafile(PDF_SKIA_DOCUMENT_TYPE);
CHECK(metafile.Init());
- PrintMsg_PrintPage_Params page_params;
- page_params.params = params.params;
for (size_t i = 0; i < printed_pages.size(); ++i) {
- page_params.page_number = printed_pages[i];
- PrintPageInternal(page_params, frame, &metafile, &page_size_in_dpi[i],
- &content_area_in_dpi[i], &printable_area_in_dpi[i]);
+ PrintPageInternal(params.params, printed_pages[i], frame, &metafile,
+ &page_size_in_dpi[i], &content_area_in_dpi[i],
+ &printable_area_in_dpi[i]);
}
// blink::printEnd() for PDF should be called before metafile is closed.
diff --git a/chromium/components/proximity_auth/BUILD.gn b/chromium/components/proximity_auth/BUILD.gn
index d3e6fcd2899..54800b9cb80 100644
--- a/chromium/components/proximity_auth/BUILD.gn
+++ b/chromium/components/proximity_auth/BUILD.gn
@@ -13,8 +13,6 @@ static_library("proximity_auth") {
"bluetooth_util.cc",
"bluetooth_util.h",
"bluetooth_util_chromeos.cc",
- "cryptauth_enroller_factory_impl.cc",
- "cryptauth_enroller_factory_impl.h",
"messenger.h",
"messenger_impl.cc",
"messenger_impl.h",
@@ -44,8 +42,9 @@ static_library("proximity_auth") {
"switches.h",
"throttled_bluetooth_connection_finder.cc",
"throttled_bluetooth_connection_finder.h",
- "unlock_manager.cc",
"unlock_manager.h",
+ "unlock_manager_impl.cc",
+ "unlock_manager_impl.h",
]
deps = [
@@ -74,6 +73,10 @@ static_library("test_support") {
testonly = true
sources = [
+ "fake_lock_handler.cc",
+ "fake_lock_handler.h",
+ "fake_remote_device_life_cycle.cc",
+ "fake_remote_device_life_cycle.h",
"mock_proximity_auth_client.cc",
"mock_proximity_auth_client.h",
]
@@ -102,7 +105,7 @@ source_set("unit_tests") {
"remote_device_life_cycle_impl_unittest.cc",
"remote_status_update_unittest.cc",
"throttled_bluetooth_connection_finder_unittest.cc",
- "unlock_manager_unittest.cc",
+ "unlock_manager_impl_unittest.cc",
]
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
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 a7ffcb86b3a..f8077aa9032 100644
--- a/chromium/components/proxy_config/pref_proxy_config_tracker_impl.cc
+++ b/chromium/components/proxy_config/pref_proxy_config_tracker_impl.cc
@@ -6,6 +6,9 @@
#include <stddef.h>
+#include <memory>
+#include <utility>
+
#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
@@ -205,19 +208,19 @@ net::ProxyConfigService::ConfigAvailability
// static
void PrefProxyConfigTrackerImpl::RegisterPrefs(PrefRegistrySimple* registry) {
- base::DictionaryValue* default_settings =
+ std::unique_ptr<base::DictionaryValue> default_settings =
ProxyConfigDictionary::CreateSystem();
registry->RegisterDictionaryPref(proxy_config::prefs::kProxy,
- default_settings);
+ std::move(default_settings));
}
// static
void PrefProxyConfigTrackerImpl::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* pref_service) {
- base::DictionaryValue* default_settings =
+ std::unique_ptr<base::DictionaryValue> default_settings =
ProxyConfigDictionary::CreateSystem();
pref_service->RegisterDictionaryPref(proxy_config::prefs::kProxy,
- default_settings);
+ std::move(default_settings));
pref_service->RegisterBooleanPref(proxy_config::prefs::kUseSharedProxies,
false);
}
@@ -237,7 +240,7 @@ ProxyPrefs::ConfigState PrefProxyConfigTrackerImpl::ReadPrefConfig(
const base::DictionaryValue* dict =
pref_service->GetDictionary(proxy_config::prefs::kProxy);
DCHECK(dict);
- ProxyConfigDictionary proxy_dict(dict);
+ ProxyConfigDictionary proxy_dict(dict->CreateDeepCopy());
if (PrefConfigToNetConfig(proxy_dict, config)) {
if (!pref->IsUserModifiable() || pref->HasUserSetting()) {
diff --git a/chromium/components/proxy_config/proxy_config_dictionary.cc b/chromium/components/proxy_config/proxy_config_dictionary.cc
index 1251ae68442..a55133c71be 100644
--- a/chromium/components/proxy_config/proxy_config_dictionary.cc
+++ b/chromium/components/proxy_config/proxy_config_dictionary.cc
@@ -4,7 +4,10 @@
#include "components/proxy_config/proxy_config_dictionary.h"
+#include <utility>
+
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/values.h"
#include "net/proxy/proxy_config.h"
@@ -29,9 +32,9 @@ const char kProxyBypassList[] = "bypass_list";
} // namespace
-ProxyConfigDictionary::ProxyConfigDictionary(const base::DictionaryValue* dict)
- : dict_(dict->DeepCopy()) {
-}
+ProxyConfigDictionary::ProxyConfigDictionary(
+ std::unique_ptr<base::DictionaryValue> dict)
+ : dict_(std::move(dict)) {}
ProxyConfigDictionary::~ProxyConfigDictionary() {}
@@ -70,7 +73,7 @@ const base::DictionaryValue& ProxyConfigDictionary::GetDictionary() const {
}
// static
-base::DictionaryValue* ProxyConfigDictionary::CreateDirect() {
+std::unique_ptr<base::DictionaryValue> ProxyConfigDictionary::CreateDirect() {
return CreateDictionary(ProxyPrefs::MODE_DIRECT,
std::string(),
false,
@@ -79,7 +82,8 @@ base::DictionaryValue* ProxyConfigDictionary::CreateDirect() {
}
// static
-base::DictionaryValue* ProxyConfigDictionary::CreateAutoDetect() {
+std::unique_ptr<base::DictionaryValue>
+ProxyConfigDictionary::CreateAutoDetect() {
return CreateDictionary(ProxyPrefs::MODE_AUTO_DETECT,
std::string(),
false,
@@ -88,7 +92,7 @@ base::DictionaryValue* ProxyConfigDictionary::CreateAutoDetect() {
}
// static
-base::DictionaryValue* ProxyConfigDictionary::CreatePacScript(
+std::unique_ptr<base::DictionaryValue> ProxyConfigDictionary::CreatePacScript(
const std::string& pac_url,
bool pac_mandatory) {
return CreateDictionary(ProxyPrefs::MODE_PAC_SCRIPT,
@@ -99,9 +103,9 @@ base::DictionaryValue* ProxyConfigDictionary::CreatePacScript(
}
// static
-base::DictionaryValue* ProxyConfigDictionary::CreateFixedServers(
- const std::string& proxy_server,
- const std::string& bypass_list) {
+std::unique_ptr<base::DictionaryValue>
+ProxyConfigDictionary::CreateFixedServers(const std::string& proxy_server,
+ const std::string& bypass_list) {
if (!proxy_server.empty()) {
return CreateDictionary(ProxyPrefs::MODE_FIXED_SERVERS,
std::string(),
@@ -114,7 +118,7 @@ base::DictionaryValue* ProxyConfigDictionary::CreateFixedServers(
}
// static
-base::DictionaryValue* ProxyConfigDictionary::CreateSystem() {
+std::unique_ptr<base::DictionaryValue> ProxyConfigDictionary::CreateSystem() {
return CreateDictionary(ProxyPrefs::MODE_SYSTEM,
std::string(),
false,
@@ -123,13 +127,13 @@ base::DictionaryValue* ProxyConfigDictionary::CreateSystem() {
}
// static
-base::DictionaryValue* ProxyConfigDictionary::CreateDictionary(
+std::unique_ptr<base::DictionaryValue> ProxyConfigDictionary::CreateDictionary(
ProxyPrefs::ProxyMode mode,
const std::string& pac_url,
bool pac_mandatory,
const std::string& proxy_server,
const std::string& bypass_list) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ auto dict = base::MakeUnique<base::DictionaryValue>();
dict->SetString(kProxyMode, ProxyModeToString(mode));
if (!pac_url.empty()) {
dict->SetString(kProxyPacUrl, pac_url);
diff --git a/chromium/components/proxy_config/proxy_config_dictionary.h b/chromium/components/proxy_config/proxy_config_dictionary.h
index 1faa121a392..ed7a936f1b3 100644
--- a/chromium/components/proxy_config/proxy_config_dictionary.h
+++ b/chromium/components/proxy_config/proxy_config_dictionary.h
@@ -31,8 +31,7 @@ class ProxyServer;
// See proxy_config_dictionary.cc for the structure of the respective strings.
class PROXY_CONFIG_EXPORT ProxyConfigDictionary {
public:
- // Creates a deep copy of |dict| and leaves ownership to caller.
- explicit ProxyConfigDictionary(const base::DictionaryValue* dict);
+ explicit ProxyConfigDictionary(std::unique_ptr<base::DictionaryValue> dict);
~ProxyConfigDictionary();
bool GetMode(ProxyPrefs::ProxyMode* out) const;
@@ -44,14 +43,15 @@ class PROXY_CONFIG_EXPORT ProxyConfigDictionary {
const base::DictionaryValue& GetDictionary() const;
- static base::DictionaryValue* CreateDirect();
- static base::DictionaryValue* CreateAutoDetect();
- static base::DictionaryValue* CreatePacScript(const std::string& pac_url,
- bool pac_mandatory);
- static base::DictionaryValue* CreateFixedServers(
+ static std::unique_ptr<base::DictionaryValue> CreateDirect();
+ static std::unique_ptr<base::DictionaryValue> CreateAutoDetect();
+ static std::unique_ptr<base::DictionaryValue> CreatePacScript(
+ const std::string& pac_url,
+ bool pac_mandatory);
+ static std::unique_ptr<base::DictionaryValue> CreateFixedServers(
const std::string& proxy_server,
const std::string& bypass_list);
- static base::DictionaryValue* CreateSystem();
+ static std::unique_ptr<base::DictionaryValue> CreateSystem();
// Encodes the proxy server as "<url-scheme>=<proxy-scheme>://<proxy>".
// Used to generate the |proxy_server| arg for CreateFixedServers().
@@ -60,7 +60,7 @@ class PROXY_CONFIG_EXPORT ProxyConfigDictionary {
std::string* spec);
private:
- static base::DictionaryValue* CreateDictionary(
+ static std::unique_ptr<base::DictionaryValue> CreateDictionary(
ProxyPrefs::ProxyMode mode,
const std::string& pac_url,
bool pac_mandatory,
diff --git a/chromium/components/proxy_config/proxy_config_dictionary_unittest.cc b/chromium/components/proxy_config/proxy_config_dictionary_unittest.cc
index 33f5364c14b..e7047223aac 100644
--- a/chromium/components/proxy_config/proxy_config_dictionary_unittest.cc
+++ b/chromium/components/proxy_config/proxy_config_dictionary_unittest.cc
@@ -6,6 +6,7 @@
#include <memory>
#include <string>
+#include <utility>
#include "base/values.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -18,9 +19,9 @@ struct ProxyConfigHolder {
};
TEST(ProxyConfigDictionaryTest, CreateDirect) {
- std::unique_ptr<base::DictionaryValue> dict_value(
- ProxyConfigDictionary::CreateDirect());
- ProxyConfigDictionary dict(dict_value.get());
+ std::unique_ptr<base::DictionaryValue> dict_value =
+ ProxyConfigDictionary::CreateDirect();
+ ProxyConfigDictionary dict(std::move(dict_value));
ProxyConfigHolder h;
ASSERT_TRUE(dict.GetMode(&h.mode));
@@ -31,9 +32,9 @@ TEST(ProxyConfigDictionaryTest, CreateDirect) {
}
TEST(ProxyConfigDictionaryTest, CreateAutoDetect) {
- std::unique_ptr<base::DictionaryValue> dict_value(
- ProxyConfigDictionary::CreateAutoDetect());
- ProxyConfigDictionary dict(dict_value.get());
+ std::unique_ptr<base::DictionaryValue> dict_value =
+ ProxyConfigDictionary::CreateAutoDetect();
+ ProxyConfigDictionary dict(std::move(dict_value));
ProxyConfigHolder h;
ASSERT_TRUE(dict.GetMode(&h.mode));
@@ -44,9 +45,9 @@ TEST(ProxyConfigDictionaryTest, CreateAutoDetect) {
}
TEST(ProxyConfigDictionaryTest, CreatePacScript) {
- std::unique_ptr<base::DictionaryValue> dict_value(
- ProxyConfigDictionary::CreatePacScript("pac", false));
- ProxyConfigDictionary dict(dict_value.get());
+ std::unique_ptr<base::DictionaryValue> dict_value =
+ ProxyConfigDictionary::CreatePacScript("pac", false);
+ ProxyConfigDictionary dict(std::move(dict_value));
ProxyConfigHolder h;
ASSERT_TRUE(dict.GetMode(&h.mode));
@@ -58,10 +59,9 @@ TEST(ProxyConfigDictionaryTest, CreatePacScript) {
}
TEST(ProxyConfigDictionaryTest, CreateFixedServers) {
- std::unique_ptr<base::DictionaryValue> dict_value(
- ProxyConfigDictionary::CreateFixedServers("http://1.2.3.4",
- "http://foo"));
- ProxyConfigDictionary dict(dict_value.get());
+ std::unique_ptr<base::DictionaryValue> dict_value =
+ ProxyConfigDictionary::CreateFixedServers("http://1.2.3.4", "http://foo");
+ ProxyConfigDictionary dict(std::move(dict_value));
ProxyConfigHolder h;
ASSERT_TRUE(dict.GetMode(&h.mode));
@@ -74,9 +74,9 @@ TEST(ProxyConfigDictionaryTest, CreateFixedServers) {
}
TEST(ProxyConfigDictionaryTest, CreateSystem) {
- std::unique_ptr<base::DictionaryValue> dict_value(
- ProxyConfigDictionary::CreateSystem());
- ProxyConfigDictionary dict(dict_value.get());
+ std::unique_ptr<base::DictionaryValue> dict_value =
+ ProxyConfigDictionary::CreateSystem();
+ ProxyConfigDictionary dict(std::move(dict_value));
ProxyConfigHolder h;
ASSERT_TRUE(dict.GetMode(&h.mode));
diff --git a/chromium/components/query_parser/snippet.cc b/chromium/components/query_parser/snippet.cc
index f540be5ca32..3133d8feda2 100644
--- a/chromium/components/query_parser/snippet.cc
+++ b/chromium/components/query_parser/snippet.cc
@@ -210,9 +210,16 @@ Snippet::Snippet() {
Snippet::Snippet(const Snippet& other) = default;
+// TODO(bug 706963) this should be implemented as "= default" when Android
+// toolchain is updated.
+Snippet::Snippet(Snippet&& other) noexcept
+ : text_(std::move(other.text_)), matches_(std::move(other.matches_)) {}
+
Snippet::~Snippet() {
}
+Snippet& Snippet::operator=(const Snippet&) = default;
+
void Snippet::ComputeSnippet(const MatchPositions& match_positions,
const std::string& document) {
// The length of snippets we try to produce.
diff --git a/chromium/components/query_parser/snippet.h b/chromium/components/query_parser/snippet.h
index ed6a887cb8f..11f05d6bcdc 100644
--- a/chromium/components/query_parser/snippet.h
+++ b/chromium/components/query_parser/snippet.h
@@ -48,8 +48,11 @@ class Snippet {
Snippet();
Snippet(const Snippet& other);
+ Snippet(Snippet&& other) noexcept;
~Snippet();
+ Snippet& operator=(const Snippet&);
+
// Given |matches|, the match positions within |document|, compute the snippet
// for the document.
// Note that |document| is UTF-8 and the offsets in |matches| are byte
diff --git a/chromium/components/rappor/BUILD.gn b/chromium/components/rappor/BUILD.gn
index 66b87449b24..763a05a14c2 100644
--- a/chromium/components/rappor/BUILD.gn
+++ b/chromium/components/rappor/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("//testing/test.gni")
+
static_library("rappor") {
sources = [
"bloom_filter.cc",
@@ -106,3 +108,14 @@ source_set("unit_tests") {
"//url",
]
}
+
+# Convenience testing target
+test("rappor_unittests") {
+ sources = [
+ "//components/test/run_all_unittests.cc",
+ ]
+ deps = [
+ ":unit_tests",
+ "//components/test:test_support",
+ ]
+}
diff --git a/chromium/components/rappor/OWNERS b/chromium/components/rappor/OWNERS
index 52bf7a2d012..0e9e9f183a6 100644
--- a/chromium/components/rappor/OWNERS
+++ b/chromium/components/rappor/OWNERS
@@ -1,2 +1,4 @@
asvitkine@chromium.org
holte@chromium.org
+
+# COMPONENT: Internals>Metrics
diff --git a/chromium/components/rappor/log_uploader.cc b/chromium/components/rappor/log_uploader.cc
index 7f2f0f796a1..bfc3bb8fa57 100644
--- a/chromium/components/rappor/log_uploader.cc
+++ b/chromium/components/rappor/log_uploader.cc
@@ -13,6 +13,7 @@
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h"
namespace {
@@ -113,8 +114,34 @@ void LogUploader::StartScheduledUpload() {
return;
DVLOG(2) << "Upload to " << server_url_.spec() << " starting.";
has_callback_pending_ = true;
- current_fetch_ =
- net::URLFetcher::Create(server_url_, net::URLFetcher::POST, this);
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("rappor_report", R"(
+ semantics {
+ sender: "RAPPOR"
+ description:
+ "This service sends RAPPOR anonymous usage statistics to Google."
+ trigger:
+ "Reports are automatically generated on startup and at intervals "
+ "while Chromium is running."
+ data: "A protocol buffer with RAPPOR anonymous usage statistics."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "Users can enable or disable this feature by stopping "
+ "'Automatically send usage statistics and crash reports to Google'"
+ "in Chromium's settings under Advanced Settings, Privacy. The "
+ "feature is enabled by default."
+ chrome_policy {
+ MetricsReportingEnabled {
+ policy_options {mode: MANDATORY}
+ MetricsReportingEnabled: false
+ }
+ }
+ })");
+ current_fetch_ = net::URLFetcher::Create(server_url_, net::URLFetcher::POST,
+ this, traffic_annotation);
data_use_measurement::DataUseUserData::AttachToFetcher(
current_fetch_.get(), data_use_measurement::DataUseUserData::RAPPOR);
current_fetch_->SetRequestContext(request_context_.get());
diff --git a/chromium/components/rappor/public/rappor_parameters.h b/chromium/components/rappor/public/rappor_parameters.h
index 0497615fba7..279d09ec3b4 100644
--- a/chromium/components/rappor/public/rappor_parameters.h
+++ b/chromium/components/rappor/public/rappor_parameters.h
@@ -23,20 +23,14 @@ enum NoiseLevel {
enum RapporType {
// Generic metrics from UMA opt-in users.
UMA_RAPPOR_TYPE = 0,
- // Generic metrics for SafeBrowsing users. Deprecated, replaced by
- // LOW_FREQUENCY_SAFEBROWSING_RAPPOR_TYPE.
- SAFEBROWSING_RAPPOR_TYPE,
// Deprecated: Use UMA_RAPPOR_TYPE for new metrics
ETLD_PLUS_ONE_RAPPOR_TYPE,
// Type for low-frequency metrics from UMA opt-in users.
LOW_FREQUENCY_UMA_RAPPOR_TYPE,
- // Type for low-frequency metrics from SafeBrowsing users.
- LOW_FREQUENCY_SAFEBROWSING_RAPPOR_TYPE,
// Type for low-frequency metrics from UMA opt-in users. Do not use for new
// metrics.
LOW_FREQUENCY_ETLD_PLUS_ONE_RAPPOR_TYPE,
NUM_RAPPOR_TYPES,
- COARSE_RAPPOR_TYPE = SAFEBROWSING_RAPPOR_TYPE,
};
enum Probability {
@@ -52,8 +46,6 @@ enum Probability {
enum RecordingGroup {
// Metrics for UMA users.
UMA_RAPPOR_GROUP = 1 << 0,
- // Metrics related to SafeBrowsing, for SafeBrowsing users.
- SAFEBROWSING_RAPPOR_GROUP = 1 << 1,
};
// An object describing noise probabilities for a noise level
@@ -134,14 +126,6 @@ const RapporParameters kRapporParametersForType[NUM_RAPPOR_TYPES] = {
rappor::NORMAL_NOISE /* Noise level */,
UMA_RAPPOR_GROUP /* Recording group */
},
- // SAFEBROWSING_RAPPOR_TYPE
- {
- 128 /* Num cohorts */,
- 1 /* Bloom filter size bytes */,
- 2 /* Bloom filter hash count */,
- rappor::NORMAL_NOISE /* Noise level */,
- SAFEBROWSING_RAPPOR_GROUP /* Recording group */
- },
// ETLD_PLUS_ONE_RAPPOR_TYPE
{
128 /* Num cohorts */,
@@ -158,14 +142,6 @@ const RapporParameters kRapporParametersForType[NUM_RAPPOR_TYPES] = {
rappor::SPARSE_NOISE /* Noise level */,
UMA_RAPPOR_GROUP /* Recording group */
},
- // LOW_FREQUENCY_SAFEBROWSING_RAPPOR_TYPE
- {
- 128 /* Num cohorts */,
- 1 /* Bloom filter size bytes */,
- 2 /* Bloom filter hash count */,
- rappor::SPARSE_NOISE /* Noise level */,
- SAFEBROWSING_RAPPOR_GROUP /* Recording group */
- },
// LOW_FREQUENCY_ETLD_PLUS_ONE_RAPPOR_TYPE
{
128 /* Num cohorts */,
diff --git a/chromium/components/rappor/rappor_service_impl.cc b/chromium/components/rappor/rappor_service_impl.cc
index 19bfc67f3e6..d0c85f8c7a2 100644
--- a/chromium/components/rappor/rappor_service_impl.cc
+++ b/chromium/components/rappor/rappor_service_impl.cc
@@ -59,7 +59,7 @@ RapporServiceImpl::RapporServiceImpl(
daily_event_(pref_service,
prefs::kRapporLastDailySample,
kRapporDailyEventHistogram),
- recording_groups_(0) {}
+ recording_enabled_(false) {}
RapporServiceImpl::~RapporServiceImpl() {}
@@ -84,27 +84,22 @@ void RapporServiceImpl::Initialize(
internal::LoadCohort(pref_service_), internal::LoadSecret(pref_service_));
}
-void RapporServiceImpl::Update(int recording_groups, bool may_upload) {
+void RapporServiceImpl::Update(bool may_record, bool may_upload) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(IsInitialized());
- if (recording_groups_ != recording_groups) {
- if (recording_groups == 0) {
+ if (recording_enabled_ != may_record) {
+ recording_enabled_ = may_record;
+ if (!may_record) {
DVLOG(1) << "Rappor service stopped because all groups were disabled.";
- recording_groups_ = 0;
CancelNextLogRotation();
- } else if (recording_groups_ == 0) {
- DVLOG(1) << "RapporServiceImpl started for groups: " << recording_groups;
- recording_groups_ = recording_groups;
+ } else {
+ DVLOG(1) << "RapporServiceImpl started.";
ScheduleNextLogRotation(
base::TimeDelta::FromSeconds(kInitialLogIntervalSeconds));
- } else {
- DVLOG(1) << "RapporServiceImpl recording_groups changed:"
- << recording_groups;
- recording_groups_ = recording_groups;
}
}
- DVLOG(1) << "RapporServiceImpl recording_groups=" << recording_groups_
+ DVLOG(1) << "RapporServiceImpl recording_groups=" << recording_enabled_
<< " may_upload=" << may_upload;
if (may_upload) {
uploader_->Start();
@@ -191,9 +186,8 @@ bool RapporServiceImpl::RecordingAllowed(const RapporParameters& parameters) {
return false;
}
// Skip this metric if its recording_group is not enabled.
- if (!(recording_groups_ & parameters.recording_group)) {
- DVLOG(2) << "Metric not logged due to recording_group " << recording_groups_
- << " < " << parameters.recording_group;
+ if (!recording_enabled_) {
+ DVLOG(2) << "Metric not logged due to recording_enabled_ = false.";
return false;
}
return true;
diff --git a/chromium/components/rappor/rappor_service_impl.h b/chromium/components/rappor/rappor_service_impl.h
index 625ff9d06d2..540eb44a0d2 100644
--- a/chromium/components/rappor/rappor_service_impl.h
+++ b/chromium/components/rappor/rappor_service_impl.h
@@ -56,12 +56,10 @@ class RapporServiceImpl : public RapporService {
// Updates the settings for metric recording and uploading.
// The RapporServiceImpl must be initialized before this method is called.
- // |recording_groups| should be set of flags, e.g.
- // UMA_RECORDING_GROUP | SAFEBROWSING_RECORDING_GROUP
- // If it contains any enabled groups, periodic reports will be
- // generated and queued for upload.
+ // If |may_record| is true, data will be recorded and periodic reports will
+ // be generated and queued for upload.
// If |may_upload| is true, reports will be uploaded from the queue.
- void Update(int recording_groups, bool may_upload);
+ void Update(bool may_record, bool may_upload);
// Constructs a Sample object for the caller to record fields in.
std::unique_ptr<Sample> CreateSample(RapporType) override;
@@ -154,9 +152,8 @@ class RapporServiceImpl : public RapporService {
// A private LogUploader instance for sending reports to the server.
std::unique_ptr<LogUploaderInterface> uploader_;
- // The set of recording groups that metrics are being recorded, e.g.
- // UMA_RECORDING_GROUP | SAFEBROWSING_RECORDING_GROUP
- int recording_groups_;
+ // Whether new data can be recorded.
+ bool recording_enabled_;
// We keep all registered metrics in a map, from name to metric.
std::map<std::string, std::unique_ptr<RapporMetric>> metrics_map_;
diff --git a/chromium/components/rappor/rappor_service_unittest.cc b/chromium/components/rappor/rappor_service_unittest.cc
index 825458a4996..433e961f58f 100644
--- a/chromium/components/rappor/rappor_service_unittest.cc
+++ b/chromium/components/rappor/rappor_service_unittest.cc
@@ -30,18 +30,18 @@ TEST(RapporServiceImplTest, Update) {
EXPECT_TRUE(rappor_service.test_uploader()->is_running());
// Disabling both should stop both uploads and reports.
- rappor_service.Update(0, false);
+ rappor_service.Update(false, false);
EXPECT_EQ(base::TimeDelta(), rappor_service.next_rotation());
EXPECT_FALSE(rappor_service.test_uploader()->is_running());
- // Some recording, but no reporting.
- rappor_service.Update(UMA_RAPPOR_GROUP, false);
+ // Recording, but no reporting.
+ rappor_service.Update(true, false);
// Reports generation should still be scheduled.
EXPECT_LT(base::TimeDelta(), rappor_service.next_rotation());
EXPECT_FALSE(rappor_service.test_uploader()->is_running());
- // Some recording and reporting enabled.
- rappor_service.Update(SAFEBROWSING_RAPPOR_GROUP, true);
+ // Recording and reporting enabled.
+ rappor_service.Update(true, true);
EXPECT_LT(base::TimeDelta(), rappor_service.next_rotation());
EXPECT_TRUE(rappor_service.test_uploader()->is_running());
}
@@ -66,12 +66,12 @@ TEST(RapporServiceImplTest, RecordAndExportMetrics) {
EXPECT_EQ(16u, report.bits().size());
}
-// Check that the reporting groups are respected.
+// Check that reporting_enabled_ is respected.
TEST(RapporServiceImplTest, UmaRecordingGroup) {
TestRapporServiceImpl rappor_service;
- rappor_service.Update(SAFEBROWSING_RAPPOR_GROUP, false);
+ rappor_service.Update(false, false);
- // Wrong recording group.
+ // Reporting disabled.
rappor_service.RecordSampleString("UmaMetric", UMA_RAPPOR_TYPE, "foo");
RapporReports reports;
@@ -79,20 +79,6 @@ TEST(RapporServiceImplTest, UmaRecordingGroup) {
EXPECT_EQ(0, reports.report_size());
}
-// Check that the reporting groups are respected.
-TEST(RapporServiceImplTest, SafeBrowsingRecordingGroup) {
- TestRapporServiceImpl rappor_service;
- rappor_service.Update(UMA_RAPPOR_GROUP, false);
-
- // Wrong recording group.
- rappor_service.RecordSampleString("SbMetric", SAFEBROWSING_RAPPOR_TYPE,
- "foo");
-
- RapporReports reports;
- rappor_service.GetReports(&reports);
- EXPECT_EQ(0, reports.report_size());
-}
-
// Check that GetRecordedSampleForMetric works as expected.
TEST(RapporServiceImplTest, GetRecordedSampleForMetric) {
TestRapporServiceImpl rappor_service;
@@ -118,8 +104,7 @@ TEST(RapporServiceImplTest, Incognito) {
TestRapporServiceImpl rappor_service;
rappor_service.set_is_incognito(true);
- rappor_service.RecordSampleString("MyMetric", SAFEBROWSING_RAPPOR_TYPE,
- "foo");
+ rappor_service.RecordSampleString("MyMetric", UMA_RAPPOR_TYPE, "foo");
RapporReports reports;
rappor_service.GetReports(&reports);
@@ -129,8 +114,7 @@ TEST(RapporServiceImplTest, Incognito) {
// Check that Sample objects record correctly.
TEST(RapporServiceImplTest, RecordSample) {
TestRapporServiceImpl rappor_service;
- std::unique_ptr<Sample> sample =
- rappor_service.CreateSample(SAFEBROWSING_RAPPOR_TYPE);
+ std::unique_ptr<Sample> sample = rappor_service.CreateSample(UMA_RAPPOR_TYPE);
sample->SetStringField("Url", "example.com");
sample->SetFlagsField("Flags1", 0xbcd, 12);
rappor_service.RecordSample("ObjMetric", std::move(sample));
@@ -142,7 +126,7 @@ TEST(RapporServiceImplTest, RecordSample) {
size_t url_index = reports.report(0).name_hash() == url_hash ? 0 : 1;
size_t flags_index = url_index == 0 ? 1 : 0;
EXPECT_EQ(url_hash, reports.report(url_index).name_hash());
- EXPECT_EQ(1u, reports.report(url_index).bits().size());
+ EXPECT_EQ(4u, reports.report(url_index).bits().size());
EXPECT_EQ(flags_hash, reports.report(flags_index).name_hash());
EXPECT_EQ(2u, reports.report(flags_index).bits().size());
}
diff --git a/chromium/components/rappor/test_rappor_service.cc b/chromium/components/rappor/test_rappor_service.cc
index 62da6f9c29b..3c8229f5d8a 100644
--- a/chromium/components/rappor/test_rappor_service.cc
+++ b/chromium/components/rappor/test_rappor_service.cc
@@ -70,7 +70,7 @@ TestRapporServiceImpl::TestRapporServiceImpl()
test_uploader_ = new TestLogUploader();
InitializeInternal(base::WrapUnique(test_uploader_), 0,
HmacByteVectorGenerator::GenerateEntropyInput());
- Update(UMA_RAPPOR_GROUP | SAFEBROWSING_RAPPOR_GROUP, true);
+ Update(true, true);
}
TestRapporServiceImpl::~TestRapporServiceImpl() {}
diff --git a/chromium/components/reading_list/core/BUILD.gn b/chromium/components/reading_list/core/BUILD.gn
index f45b10c0b42..a5d4f131998 100644
--- a/chromium/components/reading_list/core/BUILD.gn
+++ b/chromium/components/reading_list/core/BUILD.gn
@@ -7,13 +7,67 @@ import("//components/reading_list/core/reading_list.gni")
source_set("core") {
sources = [
+ "offline_url_utils.cc",
+ "offline_url_utils.h",
+ "reading_list_entry.cc",
+ "reading_list_entry.h",
+ "reading_list_model.cc",
+ "reading_list_model.h",
+ "reading_list_model_impl.cc",
+ "reading_list_model_impl.h",
+ "reading_list_model_observer.h",
+ "reading_list_model_storage.cc",
+ "reading_list_model_storage.h",
+ "reading_list_pref_names.cc",
+ "reading_list_pref_names.h",
+ "reading_list_store.cc",
+ "reading_list_store.h",
+ "reading_list_store_delegate.h",
+ ]
+ deps = [
+ ":flags",
+ "//base",
+ "//components/keyed_service/core",
+ "//components/prefs",
+ "//components/sync",
+ "//net",
+ "//url",
+ ]
+ public_deps = [
+ "//components/reading_list/core/proto",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "offline_url_utils_unittest.cc",
+ "reading_list_entry_unittest.cc",
+ "reading_list_model_unittest.cc",
+ "reading_list_store_unittest.cc",
+ ]
+ deps = [
+ ":core",
+ "//base",
+ "//base/test:test_support",
+ "//components/sync",
+ "//components/sync:test_support_model",
+ "//testing/gtest",
+ "//url",
+ ]
+}
+
+source_set("flags") {
+ sources = [
"reading_list_switches.cc",
"reading_list_switches.h",
]
deps = [
- ":reading_list_enable_flags",
"//base",
]
+ public_deps = [
+ ":reading_list_enable_flags",
+ ]
}
buildflag_header("reading_list_enable_flags") {
diff --git a/chromium/components/reading_list/ios/offline_url_utils.cc b/chromium/components/reading_list/core/offline_url_utils.cc
index 25b0561bdf1..15429227ffe 100644
--- a/chromium/components/reading_list/ios/offline_url_utils.cc
+++ b/chromium/components/reading_list/core/offline_url_utils.cc
@@ -2,21 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/reading_list/ios/offline_url_utils.h"
+#include "components/reading_list/core/offline_url_utils.h"
+#include "base/logging.h"
#include "base/md5.h"
#include "base/strings/stringprintf.h"
namespace {
-const char kOfflineDirectory[] = "Offline";
-const char kMainPageFileName[] = "page.html";
-const char kPDFFileName[] = "file.pdf";
+const base::FilePath::CharType kOfflineDirectory[] =
+ FILE_PATH_LITERAL("Offline");
+const base::FilePath::CharType kMainPageFileName[] =
+ FILE_PATH_LITERAL("page.html");
+const base::FilePath::CharType kPDFFileName[] = FILE_PATH_LITERAL("file.pdf");
} // namespace
namespace reading_list {
base::FilePath OfflineRootDirectoryPath(const base::FilePath& profile_path) {
- return profile_path.Append(FILE_PATH_LITERAL(kOfflineDirectory));
+ return profile_path.Append(kOfflineDirectory);
}
std::string OfflineURLDirectoryID(const GURL& url) {
@@ -27,17 +30,20 @@ base::FilePath OfflineURLDirectoryAbsolutePath(
const base::FilePath& profile_path,
const GURL& url) {
return OfflineURLAbsolutePathFromRelativePath(
- profile_path, base::FilePath(OfflineURLDirectoryID(url)));
+ profile_path, base::FilePath::FromUTF8Unsafe(OfflineURLDirectoryID(url)));
}
base::FilePath OfflinePagePath(const GURL& url, OfflineFileType type) {
- base::FilePath directory(OfflineURLDirectoryID(url));
+ base::FilePath directory =
+ base::FilePath::FromUTF8Unsafe(OfflineURLDirectoryID(url));
switch (type) {
case OFFLINE_TYPE_HTML:
- return directory.Append(FILE_PATH_LITERAL(kMainPageFileName));
+ return directory.Append(kMainPageFileName);
case OFFLINE_TYPE_PDF:
- return directory.Append(FILE_PATH_LITERAL(kPDFFileName));
+ return directory.Append(kPDFFileName);
}
+ NOTREACHED();
+ return base::FilePath();
}
base::FilePath OfflineURLAbsolutePathFromRelativePath(
diff --git a/chromium/components/reading_list/ios/offline_url_utils.h b/chromium/components/reading_list/core/offline_url_utils.h
index dc9060f61dd..4eb9ba73260 100644
--- a/chromium/components/reading_list/ios/offline_url_utils.h
+++ b/chromium/components/reading_list/core/offline_url_utils.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_READING_LIST_IOS_OFFLINE_URL_UTILS_H_
-#define COMPONENTS_READING_LIST_IOS_OFFLINE_URL_UTILS_H_
+#ifndef COMPONENTS_READING_LIST_CORE_OFFLINE_URL_UTILS_H_
+#define COMPONENTS_READING_LIST_CORE_OFFLINE_URL_UTILS_H_
#include <string>
@@ -49,4 +49,4 @@ std::string OfflineURLDirectoryID(const GURL& url);
} // namespace reading_list
-#endif // COMPONENTS_READING_LIST_IOS_OFFLINE_URL_UTILS_H_
+#endif // COMPONENTS_READING_LIST_CORE_OFFLINE_URL_UTILS_H_
diff --git a/chromium/components/reading_list/core/offline_url_utils_unittest.cc b/chromium/components/reading_list/core/offline_url_utils_unittest.cc
new file mode 100644
index 00000000000..cf5b8bc95d5
--- /dev/null
+++ b/chromium/components/reading_list/core/offline_url_utils_unittest.cc
@@ -0,0 +1,85 @@
+// 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/reading_list/core/offline_url_utils.h"
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+// Checks the root directory of offline pages.
+TEST(OfflineURLUtilsTest, OfflineRootDirectoryPathTest) {
+ base::FilePath::StringType separator(&base::FilePath::kSeparators[0], 1);
+ base::FilePath profile_path(FILE_PATH_LITERAL("profile_path"));
+ base::FilePath offline_directory =
+ reading_list::OfflineRootDirectoryPath(profile_path);
+ // Expected value: profile_path/Offline
+ std::string expected =
+ base::StringPrintf("profile_path%" PRIsFP "Offline", separator.c_str());
+ EXPECT_EQ(expected, offline_directory.AsUTF8Unsafe());
+}
+
+// Checks the offline page directory is the MD5 of the URL
+TEST(OfflineURLUtilsTest, OfflineURLDirectoryIDTest) {
+ GURL url("http://www.google.com/test");
+ // MD5 of "http://www.google.com/test"
+ std::string md5 = "0090071ef710946a1263c276284bb3b8";
+ std::string directory_id = reading_list::OfflineURLDirectoryID(url);
+ EXPECT_EQ(md5, directory_id);
+}
+
+// Checks the offline page directory is
+// |profile_path|/Offline/OfflineURLDirectoryID;
+TEST(OfflineURLUtilsTest, OfflineURLDirectoryAbsolutePathTest) {
+ base::FilePath::StringType separator(&base::FilePath::kSeparators[0], 1);
+ base::FilePath profile_path(FILE_PATH_LITERAL("profile_path"));
+ GURL url("http://www.google.com/test");
+ base::FilePath offline_directory =
+ reading_list::OfflineURLDirectoryAbsolutePath(profile_path, url);
+ // Expected value: profile_path/Offline/0090071ef710946a1263c276284bb3b8
+ std::string expected =
+ base::StringPrintf("profile_path%" PRIsFP "Offline%" PRIsFP
+ "0090071ef710946a1263c276284bb3b8",
+ separator.c_str(), separator.c_str());
+ EXPECT_EQ(expected, offline_directory.AsUTF8Unsafe());
+}
+
+// Checks the offline page directory is
+// |profile_path|/Offline/OfflineURLDirectoryID;
+TEST(OfflineURLUtilsTest, AbsolutePathForRelativePathTest) {
+ base::FilePath::StringType separator(&base::FilePath::kSeparators[0], 1);
+ base::FilePath profile_path(FILE_PATH_LITERAL("profile_path"));
+ base::FilePath relative_path(FILE_PATH_LITERAL("relative"));
+ relative_path = relative_path.Append(FILE_PATH_LITERAL("path"));
+ base::FilePath absolute_path =
+ reading_list::OfflineURLAbsolutePathFromRelativePath(profile_path,
+ relative_path);
+ // Expected value: profile_path/Offline/relative/path
+ std::string expected = base::StringPrintf(
+ "profile_path%" PRIsFP "Offline%" PRIsFP "relative%" PRIsFP "path",
+ separator.c_str(), separator.c_str(), separator.c_str());
+ EXPECT_EQ(expected, absolute_path.AsUTF8Unsafe());
+}
+
+// Checks the offline page path is OfflineURLDirectoryID/page.html;
+TEST(OfflineURLUtilsTest, OfflinePagePathTest) {
+ base::FilePath::StringType separator(&base::FilePath::kSeparators[0], 1);
+ GURL url("http://www.google.com/test");
+ base::FilePath offline_page =
+ reading_list::OfflinePagePath(url, reading_list::OFFLINE_TYPE_HTML);
+ // Expected value: 0090071ef710946a1263c276284bb3b8/page.html
+ std::string expected_html =
+ base::StringPrintf("0090071ef710946a1263c276284bb3b8%" PRIsFP "page.html",
+ separator.c_str());
+ EXPECT_EQ(expected_html, offline_page.AsUTF8Unsafe());
+ offline_page =
+ reading_list::OfflinePagePath(url, reading_list::OFFLINE_TYPE_PDF);
+ // Expected value: 0090071ef710946a1263c276284bb3b8/file.pdf
+ std::string expected_pdf = base::StringPrintf(
+ "0090071ef710946a1263c276284bb3b8%" PRIsFP "file.pdf", separator.c_str());
+ EXPECT_EQ(expected_pdf, offline_page.AsUTF8Unsafe());
+}
diff --git a/chromium/components/reading_list/ios/proto/BUILD.gn b/chromium/components/reading_list/core/proto/BUILD.gn
index 927a5eea83e..927a5eea83e 100644
--- a/chromium/components/reading_list/ios/proto/BUILD.gn
+++ b/chromium/components/reading_list/core/proto/BUILD.gn
diff --git a/chromium/components/reading_list/ios/proto/reading_list.proto b/chromium/components/reading_list/core/proto/reading_list.proto
index 412545460fa..9ca16de08a1 100644
--- a/chromium/components/reading_list/ios/proto/reading_list.proto
+++ b/chromium/components/reading_list/core/proto/reading_list.proto
@@ -35,7 +35,7 @@ message ReadingListLocal {
PROCESSING = 1;
PROCESSED = 2;
WILL_RETRY = 3;
- ERROR = 4;
+ DISTILLATION_ERROR = 4;
}
optional DistillationState distillation_state = 7;
optional string distilled_path = 8;
@@ -44,4 +44,10 @@ message ReadingListLocal {
optional string backoff = 10;
optional int64 distillation_time_us = 14;
optional int64 distillation_size = 15;
+ optional ReadingListContentSuggestionsExtra content_suggestions_extra = 16;
+}
+
+// Additional data used by the ContentSuggestions.
+message ReadingListContentSuggestionsExtra {
+ optional bool dismissed = 1;
}
diff --git a/chromium/components/reading_list/ios/reading_list_entry.cc b/chromium/components/reading_list/core/reading_list_entry.cc
index b49791f48f0..33d97a299dd 100644
--- a/chromium/components/reading_list/ios/reading_list_entry.cc
+++ b/chromium/components/reading_list/core/reading_list_entry.cc
@@ -2,16 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/reading_list/ios/reading_list_entry.h"
+#include "components/reading_list/core/reading_list_entry.h"
#include "base/json/json_string_value_serializer.h"
#include "base/memory/ptr_util.h"
-#include "components/reading_list/ios/offline_url_utils.h"
-#include "components/reading_list/ios/proto/reading_list.pb.h"
-#include "components/reading_list/ios/reading_list_store.h"
+#include "components/reading_list/core/offline_url_utils.h"
+#include "components/reading_list/core/proto/reading_list.pb.h"
+#include "components/reading_list/core/reading_list_store.h"
#include "components/sync/protocol/reading_list_specifics.pb.h"
#include "net/base/backoff_entry_serializer.h"
+namespace {
+// Converts |time| to the number of microseconds since Jan 1st 1970.
+int64_t TimeToUS(const base::Time& time) {
+ return (time - base::Time::UnixEpoch()).InMicroseconds();
+}
+}
+
// The backoff time is the following: 10min, 10min, 1h, 2h, 2h..., starting
// after the first failure.
const net::BackoffEntry::Policy ReadingListEntry::kBackoffPolicy = {
@@ -39,26 +46,30 @@ const net::BackoffEntry::Policy ReadingListEntry::kBackoffPolicy = {
true, // Don't use initial delay unless the last request was an error.
};
-ReadingListEntry::ReadingListEntry(const GURL& url, const std::string& title)
- : ReadingListEntry(url, title, nullptr){};
+ReadingListEntry::ReadingListEntry(const GURL& url,
+ const std::string& title,
+ const base::Time& now)
+ : ReadingListEntry(url, title, now, nullptr){};
ReadingListEntry::ReadingListEntry(const GURL& url,
const std::string& title,
+ const base::Time& now,
std::unique_ptr<net::BackoffEntry> backoff)
: ReadingListEntry(url,
title,
UNSEEN,
+ TimeToUS(now),
0,
- 0,
- 0,
- 0,
+ TimeToUS(now),
+ TimeToUS(now),
WAITING,
base::FilePath(),
GURL(),
0,
0,
0,
- std::move(backoff)) {}
+ std::move(backoff),
+ reading_list::ContentSuggestionsExtra()) {}
ReadingListEntry::ReadingListEntry(
const GURL& url,
@@ -74,7 +85,8 @@ ReadingListEntry::ReadingListEntry(
int64_t distillation_time,
int64_t distillation_size,
int failed_download_counter,
- std::unique_ptr<net::BackoffEntry> backoff)
+ std::unique_ptr<net::BackoffEntry> backoff,
+ const reading_list::ContentSuggestionsExtra& content_suggestions_extra)
: url_(url),
title_(title),
state_(state),
@@ -87,20 +99,16 @@ ReadingListEntry::ReadingListEntry(
update_time_us_(update_time),
update_title_time_us_(update_title_time),
distillation_time_us_(distillation_time),
- distillation_size_(distillation_size) {
+ distillation_size_(distillation_size),
+ content_suggestions_extra_(content_suggestions_extra) {
if (backoff) {
backoff_ = std::move(backoff);
} else {
backoff_ = base::MakeUnique<net::BackoffEntry>(&kBackoffPolicy);
}
- if (creation_time_us_ == 0) {
- DCHECK(update_time_us_ == 0);
- DCHECK(update_title_time_us_ == 0);
- creation_time_us_ =
- (base::Time::Now() - base::Time::UnixEpoch()).InMicroseconds();
- update_time_us_ = creation_time_us_;
- update_title_time_us_ = creation_time_us_;
- }
+ DCHECK(creation_time_us_);
+ DCHECK(update_time_us_);
+ DCHECK(update_title_time_us_);
DCHECK(!url.is_empty());
DCHECK(url.is_valid());
}
@@ -119,7 +127,8 @@ ReadingListEntry::ReadingListEntry(ReadingListEntry&& entry)
update_time_us_(std::move(entry.update_time_us_)),
update_title_time_us_(std::move(entry.update_title_time_us_)),
distillation_time_us_(std::move(entry.distillation_time_us_)),
- distillation_size_(std::move(entry.distillation_size_)) {}
+ distillation_size_(std::move(entry.distillation_size_)),
+ content_suggestions_extra_(std::move(entry.content_suggestions_extra_)) {}
ReadingListEntry::~ReadingListEntry() {}
@@ -174,6 +183,7 @@ ReadingListEntry& ReadingListEntry::operator=(ReadingListEntry&& other) {
update_title_time_us_ = std::move(other.update_title_time_us_);
distillation_time_us_ = std::move(other.distillation_time_us_);
distillation_size_ = std::move(other.distillation_size_);
+ content_suggestions_extra_ = std::move(other.content_suggestions_extra_);
return *this;
}
@@ -181,26 +191,25 @@ bool ReadingListEntry::operator==(const ReadingListEntry& other) const {
return url_ == other.url_;
}
-void ReadingListEntry::SetTitle(const std::string& title) {
+void ReadingListEntry::SetTitle(const std::string& title,
+ const base::Time& now) {
title_ = title;
- update_title_time_us_ =
- (base::Time::Now() - base::Time::UnixEpoch()).InMicroseconds();
+ update_title_time_us_ = TimeToUS(now);
}
-void ReadingListEntry::SetRead(bool read) {
+void ReadingListEntry::SetRead(bool read, const base::Time& now) {
State previous_state = state_;
state_ = read ? READ : UNREAD;
if (state_ == previous_state) {
return;
}
if (FirstReadTime() == 0 && read) {
- first_read_time_us_ =
- (base::Time::Now() - base::Time::UnixEpoch()).InMicroseconds();
+ first_read_time_us_ = TimeToUS(now);
}
if (!(previous_state == UNSEEN && state_ == UNREAD)) {
// If changing UNSEEN -> UNREAD, entry is not marked updated to preserve
// order in Reading List View.
- MarkEntryUpdated();
+ MarkEntryUpdated(now);
}
}
@@ -212,17 +221,26 @@ bool ReadingListEntry::HasBeenSeen() const {
return state_ != UNSEEN;
}
+const reading_list::ContentSuggestionsExtra*
+ReadingListEntry::ContentSuggestionsExtra() const {
+ return &content_suggestions_extra_;
+}
+
+void ReadingListEntry::SetContentSuggestionsExtra(
+ const reading_list::ContentSuggestionsExtra& extra) {
+ content_suggestions_extra_ = extra;
+}
+
void ReadingListEntry::SetDistilledInfo(const base::FilePath& path,
const GURL& distilled_url,
int64_t distilation_size,
- int64_t distilation_time) {
+ const base::Time& distilation_time) {
DCHECK(!path.empty());
DCHECK(distilled_url.is_valid());
distilled_path_ = path;
distilled_state_ = PROCESSED;
distilled_url_ = distilled_url;
- distillation_time_us_ = distilation_time;
- ;
+ distillation_time_us_ = TimeToUS(distilation_time);
distillation_size_ = distilation_size;
backoff_->Reset();
failed_download_counter_ = 0;
@@ -233,8 +251,10 @@ void ReadingListEntry::SetDistilledState(DistillationState distilled_state) {
DCHECK(distilled_state != WAITING);
// Increase time until next retry exponentially if the state change from a
// non-error state to an error state.
- if ((distilled_state == WILL_RETRY || distilled_state == ERROR) &&
- distilled_state_ != WILL_RETRY && distilled_state_ != ERROR) {
+ if ((distilled_state == WILL_RETRY ||
+ distilled_state == DISTILLATION_ERROR) &&
+ distilled_state_ != WILL_RETRY &&
+ distilled_state_ != DISTILLATION_ERROR) {
backoff_->InformOfRequest(false);
failed_download_counter_++;
}
@@ -242,6 +262,8 @@ void ReadingListEntry::SetDistilledState(DistillationState distilled_state) {
distilled_state_ = distilled_state;
distilled_path_ = base::FilePath();
distilled_url_ = GURL::EmptyGURL();
+ distillation_size_ = 0;
+ distillation_time_us_ = 0;
}
int64_t ReadingListEntry::UpdateTime() const {
@@ -260,14 +282,14 @@ int64_t ReadingListEntry::FirstReadTime() const {
return first_read_time_us_;
}
-void ReadingListEntry::MarkEntryUpdated() {
- update_time_us_ =
- (base::Time::Now() - base::Time::UnixEpoch()).InMicroseconds();
+void ReadingListEntry::MarkEntryUpdated(const base::Time& now) {
+ update_time_us_ = TimeToUS(now);
}
// static
std::unique_ptr<ReadingListEntry> ReadingListEntry::FromReadingListLocal(
- const reading_list::ReadingListLocal& pb_entry) {
+ const reading_list::ReadingListLocal& pb_entry,
+ const base::Time& now) {
if (!pb_entry.has_url()) {
return nullptr;
}
@@ -283,6 +305,8 @@ std::unique_ptr<ReadingListEntry> ReadingListEntry::FromReadingListLocal(
int64_t creation_time_us = 0;
if (pb_entry.has_creation_time_us()) {
creation_time_us = pb_entry.creation_time_us();
+ } else {
+ creation_time_us = (now - base::Time::UnixEpoch()).InMicroseconds();
}
int64_t first_read_time_us = 0;
@@ -290,7 +314,7 @@ std::unique_ptr<ReadingListEntry> ReadingListEntry::FromReadingListLocal(
first_read_time_us = pb_entry.first_read_time_us();
}
- int64_t update_time_us = 0;
+ int64_t update_time_us = creation_time_us;
if (pb_entry.has_update_time_us()) {
update_time_us = pb_entry.update_time_us();
}
@@ -299,6 +323,11 @@ std::unique_ptr<ReadingListEntry> ReadingListEntry::FromReadingListLocal(
if (pb_entry.has_update_title_time_us()) {
update_title_time_us = pb_entry.update_title_time_us();
}
+ if (update_title_time_us == 0) {
+ // Entries created before title could be modified don't have
+ // update_title_time_us. Set it to creation_time_us for consistency.
+ update_title_time_us = creation_time_us;
+ }
State state = UNSEEN;
if (pb_entry.has_status()) {
@@ -331,15 +360,15 @@ std::unique_ptr<ReadingListEntry> ReadingListEntry::FromReadingListLocal(
case reading_list::ReadingListLocal::WILL_RETRY:
distillation_state = ReadingListEntry::WILL_RETRY;
break;
- case reading_list::ReadingListLocal::ERROR:
- distillation_state = ReadingListEntry::ERROR;
+ case reading_list::ReadingListLocal::DISTILLATION_ERROR:
+ distillation_state = ReadingListEntry::DISTILLATION_ERROR;
break;
}
}
base::FilePath distilled_path;
if (pb_entry.has_distilled_path()) {
- distilled_path = base::FilePath(pb_entry.distilled_path());
+ distilled_path = base::FilePath::FromUTF8Unsafe(pb_entry.distilled_path());
}
GURL distilled_url;
@@ -369,7 +398,16 @@ std::unique_ptr<ReadingListEntry> ReadingListEntry::FromReadingListLocal(
deserializer.Deserialize(nullptr, nullptr));
if (value) {
backoff = net::BackoffEntrySerializer::DeserializeFromValue(
- *value, &kBackoffPolicy, nullptr, base::Time::Now());
+ *value, &kBackoffPolicy, nullptr, now);
+ }
+ }
+
+ reading_list::ContentSuggestionsExtra content_suggestions_extra;
+ if (pb_entry.has_content_suggestions_extra()) {
+ const reading_list::ReadingListContentSuggestionsExtra& pb_extra =
+ pb_entry.content_suggestions_extra();
+ if (pb_extra.has_dismissed()) {
+ content_suggestions_extra.dismissed = pb_extra.dismissed();
}
}
@@ -377,12 +415,13 @@ std::unique_ptr<ReadingListEntry> ReadingListEntry::FromReadingListLocal(
url, title, state, creation_time_us, first_read_time_us, update_time_us,
update_title_time_us, distillation_state, distilled_path, distilled_url,
distillation_time_us, distillation_size, failed_download_counter,
- std::move(backoff)));
+ std::move(backoff), content_suggestions_extra));
}
// static
std::unique_ptr<ReadingListEntry> ReadingListEntry::FromReadingListSpecifics(
- const sync_pb::ReadingListSpecifics& pb_entry) {
+ const sync_pb::ReadingListSpecifics& pb_entry,
+ const base::Time& now) {
if (!pb_entry.has_url()) {
return nullptr;
}
@@ -395,7 +434,7 @@ std::unique_ptr<ReadingListEntry> ReadingListEntry::FromReadingListSpecifics(
title = pb_entry.title();
}
- int64_t creation_time_us = 0;
+ int64_t creation_time_us = TimeToUS(now);
if (pb_entry.has_creation_time_us()) {
creation_time_us = pb_entry.creation_time_us();
}
@@ -405,7 +444,7 @@ std::unique_ptr<ReadingListEntry> ReadingListEntry::FromReadingListSpecifics(
first_read_time_us = pb_entry.first_read_time_us();
}
- int64_t update_time_us = 0;
+ int64_t update_time_us = creation_time_us;
if (pb_entry.has_update_time_us()) {
update_time_us = pb_entry.update_time_us();
}
@@ -414,6 +453,11 @@ std::unique_ptr<ReadingListEntry> ReadingListEntry::FromReadingListSpecifics(
if (pb_entry.has_update_title_time_us()) {
update_title_time_us = pb_entry.update_title_time_us();
}
+ if (update_title_time_us == 0) {
+ // Entries created before title could be modified don't have
+ // update_title_time_us. Set it to creation_time_us for consistency.
+ update_title_time_us = creation_time_us;
+ }
State state = UNSEEN;
if (pb_entry.has_status()) {
@@ -432,8 +476,8 @@ std::unique_ptr<ReadingListEntry> ReadingListEntry::FromReadingListSpecifics(
return base::WrapUnique<ReadingListEntry>(new ReadingListEntry(
url, title, state, creation_time_us, first_read_time_us, update_time_us,
- update_title_time_us, WAITING, base::FilePath(), GURL(), 0, 0, 0,
- nullptr));
+ update_title_time_us, WAITING, base::FilePath(), GURL(), 0, 0, 0, nullptr,
+ reading_list::ContentSuggestionsExtra()));
}
void ReadingListEntry::MergeWithEntry(const ReadingListEntry& other) {
@@ -489,7 +533,7 @@ void ReadingListEntry::MergeWithEntry(const ReadingListEntry& other) {
}
std::unique_ptr<reading_list::ReadingListLocal>
-ReadingListEntry::AsReadingListLocal() const {
+ReadingListEntry::AsReadingListLocal(const base::Time& now) const {
std::unique_ptr<reading_list::ReadingListLocal> pb_entry =
base::MakeUnique<reading_list::ReadingListLocal>();
@@ -515,7 +559,8 @@ ReadingListEntry::AsReadingListLocal() const {
break;
}
- reading_list::ReadingListLocal::DistillationState distilation_state;
+ reading_list::ReadingListLocal::DistillationState distilation_state =
+ reading_list::ReadingListLocal::WAITING;
switch (DistilledState()) {
case ReadingListEntry::WAITING:
distilation_state = reading_list::ReadingListLocal::WAITING;
@@ -529,13 +574,13 @@ ReadingListEntry::AsReadingListLocal() const {
case ReadingListEntry::WILL_RETRY:
distilation_state = reading_list::ReadingListLocal::WILL_RETRY;
break;
- case ReadingListEntry::ERROR:
- distilation_state = reading_list::ReadingListLocal::ERROR;
+ case ReadingListEntry::DISTILLATION_ERROR:
+ distilation_state = reading_list::ReadingListLocal::DISTILLATION_ERROR;
break;
}
pb_entry->set_distillation_state(distilation_state);
if (!DistilledPath().empty()) {
- pb_entry->set_distilled_path(DistilledPath().value());
+ pb_entry->set_distilled_path(DistilledPath().AsUTF8Unsafe());
}
if (DistilledURL().is_valid()) {
pb_entry->set_distilled_url(DistilledURL().spec());
@@ -551,14 +596,18 @@ ReadingListEntry::AsReadingListLocal() const {
if (backoff_) {
std::unique_ptr<base::Value> backoff =
- net::BackoffEntrySerializer::SerializeToValue(*backoff_,
- base::Time::Now());
+ net::BackoffEntrySerializer::SerializeToValue(*backoff_, now);
std::string output;
JSONStringValueSerializer serializer(&output);
serializer.Serialize(*backoff);
pb_entry->set_backoff(output);
}
+
+ reading_list::ReadingListContentSuggestionsExtra* pb_extra =
+ pb_entry->mutable_content_suggestions_extra();
+ pb_extra->set_dismissed(content_suggestions_extra_.dismissed);
+
return pb_entry;
}
diff --git a/chromium/components/reading_list/ios/reading_list_entry.h b/chromium/components/reading_list/core/reading_list_entry.h
index fc73f39f0e5..878278b71e2 100644
--- a/chromium/components/reading_list/ios/reading_list_entry.h
+++ b/chromium/components/reading_list/core/reading_list_entry.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_READING_LIST_IOS_READING_LIST_ENTRY_H_
-#define COMPONENTS_READING_LIST_IOS_READING_LIST_ENTRY_H_
+#ifndef COMPONENTS_READING_LIST_CORE_READING_LIST_ENTRY_H_
+#define COMPONENTS_READING_LIST_CORE_READING_LIST_ENTRY_H_
#include <string>
@@ -22,6 +22,13 @@ class ReadingListLocal;
// |ADDED_VIA_EXTENSION| is when the entry was added via the share extension.
// |ADDED_VIA_SYNC| is when the entry was added with sync.
enum EntrySource { ADDED_VIA_CURRENT_APP, ADDED_VIA_EXTENSION, ADDED_VIA_SYNC };
+
+// Contains additional data used by the ContentSuggestions.
+struct ContentSuggestionsExtra {
+ // Whether the Reading List Entry has been dismissed in the Content
+ // Suggestions.
+ bool dismissed = false;
+};
}
namespace sync_pb {
@@ -33,11 +40,28 @@ class ReadingListEntry;
// An entry in the reading list. The URL is a unique identifier for an entry, as
// such it should not be empty and is the only thing considered when comparing
// entries.
+// A word about timestamp usage in this class:
+// - The backing store uses int64 values to code timestamps. We use internally
+// the same type to avoid useless conversions. This values represent the
+// number of micro seconds since Jan 1st 1970.
+// - As most timestamp are used to sort entries, operations on int64_t are
+// faster than operations on base::Time. So Getter return the int64_t values.
+// - However, to ensure all the conversions are done the same way, and because
+// the Now time is alway retrieved using base::Time::Now(), all the timestamp
+// parameter are passed as base::Time. These parameters are internally
+// converted in int64_t.
class ReadingListEntry {
public:
- ReadingListEntry(const GURL& url, const std::string& title);
+ // Creates a ReadingList entry. |url| and |title| are the main fields of the
+ // entry.
+ // |now| is used to fill the |creation_time_us_| and all the update timestamp
+ // fields.
ReadingListEntry(const GURL& url,
const std::string& title,
+ const base::Time& now);
+ ReadingListEntry(const GURL& url,
+ const std::string& title,
+ const base::Time& now,
std::unique_ptr<net::BackoffEntry> backoff);
ReadingListEntry(ReadingListEntry&& entry);
~ReadingListEntry();
@@ -45,8 +69,14 @@ class ReadingListEntry {
// Entries are created in WAITING state. At some point they will be PROCESSING
// into one of the three state: PROCESSED, the only state a distilled URL
// would be set, WILL_RETRY, similar to wait, but with exponential delays or
- // ERROR where the system will not retry at all.
- enum DistillationState { WAITING, PROCESSING, PROCESSED, WILL_RETRY, ERROR };
+ // DISTILLATION_ERROR where the system will not retry at all.
+ enum DistillationState {
+ WAITING,
+ PROCESSING,
+ PROCESSED,
+ WILL_RETRY,
+ DISTILLATION_ERROR
+ };
static const net::BackoffEntry::Policy kBackoffPolicy;
@@ -78,6 +108,9 @@ class ReadingListEntry {
// Returns if an entry has ever been seen.
bool HasBeenSeen() const;
+ // Extra information about this entry for the Content Suggestions.
+ const reading_list::ContentSuggestionsExtra* ContentSuggestionsExtra() const;
+
// The last update time of the entry. This value may be used to sort the
// entries. The value is in microseconds since Jan 1st 1970.
int64_t UpdateTime() const;
@@ -94,23 +127,28 @@ class ReadingListEntry {
// microseconds since Jan 1st 1970.
int64_t FirstReadTime() const;
- // Set the update time to now.
- void MarkEntryUpdated();
+ // Set the update time to |now|.
+ void MarkEntryUpdated(const base::Time& now);
// Returns a protobuf encoding the content of this ReadingListEntry for local
- // storage.
- std::unique_ptr<reading_list::ReadingListLocal> AsReadingListLocal() const;
+ // storage. Use |now| to serialize the backoff_entry.
+ std::unique_ptr<reading_list::ReadingListLocal> AsReadingListLocal(
+ const base::Time& now) const;
// Returns a protobuf encoding the content of this ReadingListEntry for sync.
std::unique_ptr<sync_pb::ReadingListSpecifics> AsReadingListSpecifics() const;
// Created a ReadingListEntry from the protobuf format.
+ // Use |now| to deserialize the backoff_entry.
static std::unique_ptr<ReadingListEntry> FromReadingListLocal(
- const reading_list::ReadingListLocal& pb_entry);
+ const reading_list::ReadingListLocal& pb_entry,
+ const base::Time& now);
// Created a ReadingListEntry from the protobuf format.
+ // If creation time is not set, it will be set to |now|.
static std::unique_ptr<ReadingListEntry> FromReadingListSpecifics(
- const sync_pb::ReadingListSpecifics& pb_entry);
+ const sync_pb::ReadingListSpecifics& pb_entry,
+ const base::Time& now);
// Merge |this| and |other| into this.
// Local fields are kept from |this|.
@@ -129,36 +167,43 @@ class ReadingListEntry {
bool operator==(const ReadingListEntry& other) const;
- // Sets the title.
- void SetTitle(const std::string& title);
+ // Sets |title_| to |title|. Sets |update_title_time_us_| to |now|.
+ void SetTitle(const std::string& title, const base::Time& now);
// Sets the distilled info (offline path, online URL, size and date of the
// stored files) about distilled page, switch the state to PROCESSED and reset
// the time until the next try.
void SetDistilledInfo(const base::FilePath& path,
const GURL& distilled_url,
int64_t distilation_size,
- int64_t distilation_time);
+ const base::Time& distilation_time);
// Sets the state to one of PROCESSING, WILL_RETRY or ERROR.
void SetDistilledState(DistillationState distilled_state);
// Sets the read state of the entry. Will set the UpdateTime of the entry.
- void SetRead(bool read);
+ // If |first_read_time_us_| is 0 and read is READ, sets |first_read_time_us_|
+ // to |now|.
+ void SetRead(bool read, const base::Time& now);
+ // Sets extra information about this entry used by Content Suggestions.
+ void SetContentSuggestionsExtra(
+ const reading_list::ContentSuggestionsExtra& extra);
private:
enum State { UNSEEN, UNREAD, READ };
- ReadingListEntry(const GURL& url,
- const std::string& title,
- State state,
- int64_t creation_time,
- int64_t first_read_time,
- int64_t update_time,
- int64_t update_title_time,
- ReadingListEntry::DistillationState distilled_state,
- const base::FilePath& distilled_path,
- const GURL& distilled_url,
- int64_t distillation_time,
- int64_t distillation_size,
- int failed_download_counter,
- std::unique_ptr<net::BackoffEntry> backoff);
+ ReadingListEntry(
+ const GURL& url,
+ const std::string& title,
+ State state,
+ int64_t creation_time,
+ int64_t first_read_time,
+ int64_t update_time,
+ int64_t update_title_time,
+ ReadingListEntry::DistillationState distilled_state,
+ const base::FilePath& distilled_path,
+ const GURL& distilled_url,
+ int64_t distillation_time,
+ int64_t distillation_size,
+ int failed_download_counter,
+ std::unique_ptr<net::BackoffEntry> backoff,
+ const reading_list::ContentSuggestionsExtra& content_suggestions_extra);
GURL url_;
std::string title_;
State state_;
@@ -179,7 +224,9 @@ class ReadingListEntry {
int64_t distillation_time_us_;
int64_t distillation_size_;
+ reading_list::ContentSuggestionsExtra content_suggestions_extra_;
+
DISALLOW_COPY_AND_ASSIGN(ReadingListEntry);
};
-#endif // COMPONENTS_READING_LIST_IOS_READING_LIST_ENTRY_H_
+#endif // COMPONENTS_READING_LIST_CORE_READING_LIST_ENTRY_H_
diff --git a/chromium/components/reading_list/ios/reading_list_entry_unittest.cc b/chromium/components/reading_list/core/reading_list_entry_unittest.cc
index a4e38b534d5..6a0e8c805c0 100644
--- a/chromium/components/reading_list/ios/reading_list_entry_unittest.cc
+++ b/chromium/components/reading_list/core/reading_list_entry_unittest.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/reading_list/ios/reading_list_entry.h"
+#include "components/reading_list/core/reading_list_entry.h"
#include "base/memory/ptr_util.h"
-#include "base/test/ios/wait_util.h"
#include "base/test/simple_test_tick_clock.h"
-#include "components/reading_list/ios/proto/reading_list.pb.h"
+#include "components/reading_list/core/proto/reading_list.pb.h"
#include "components/sync/protocol/reading_list_specifics.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,82 +20,102 @@ const int kFifthBackoff = 120;
} // namespace
TEST(ReadingListEntry, CompareIgnoreTitle) {
- const ReadingListEntry e1(GURL("http://example.com"), "bar");
- const ReadingListEntry e2(GURL("http://example.com"), "foo");
+ const ReadingListEntry e1(GURL("http://example.com"), "bar",
+ base::Time::FromTimeT(10));
+ const ReadingListEntry e2(GURL("http://example.com"), "foo",
+ base::Time::FromTimeT(20));
EXPECT_EQ(e1, e2);
}
-TEST(ReadingListEntry, CompareFailureIgnoreTitle) {
- const ReadingListEntry e1(GURL("http://example.com"), "bar");
- const ReadingListEntry e2(GURL("http://example.org"), "bar");
+TEST(ReadingListEntry, CompareFailureIgnoreTitleAndCreationTime) {
+ const ReadingListEntry e1(GURL("http://example.com"), "bar",
+ base::Time::FromTimeT(10));
+ const ReadingListEntry e2(GURL("http://example.org"), "bar",
+ base::Time::FromTimeT(10));
EXPECT_FALSE(e1 == e2);
}
TEST(ReadingListEntry, MovesAreEquals) {
- ReadingListEntry e1(GURL("http://example.com"), "bar");
- ReadingListEntry e2(GURL("http://example.com"), "bar");
- ASSERT_EQ(e1, e2);
- ASSERT_EQ(e1.Title(), e2.Title());
+ ReadingListEntry e1(GURL("http://example.com"), "bar",
+ base::Time::FromTimeT(10));
+ ReadingListEntry e2(GURL("http://example.com"), "bar",
+ base::Time::FromTimeT(10));
+ EXPECT_EQ(e1, e2);
+ EXPECT_EQ(e1.Title(), e2.Title());
+ EXPECT_EQ(e1.CreationTime(), e2.CreationTime());
ReadingListEntry e3(std::move(e1));
EXPECT_EQ(e3, e2);
EXPECT_EQ(e3.Title(), e2.Title());
+ EXPECT_EQ(e3.CreationTime(), e2.CreationTime());
}
TEST(ReadingListEntry, ReadState) {
- ReadingListEntry e(GURL("http://example.com"), "bar");
+ ReadingListEntry e(GURL("http://example.com"), "bar",
+ base::Time::FromTimeT(10));
EXPECT_FALSE(e.HasBeenSeen());
EXPECT_FALSE(e.IsRead());
- e.SetRead(false);
+ e.SetRead(false, base::Time::FromTimeT(20));
+ EXPECT_EQ(e.CreationTime(), 10 * base::Time::kMicrosecondsPerSecond);
+ EXPECT_EQ(e.UpdateTime(), 10 * base::Time::kMicrosecondsPerSecond);
+ EXPECT_EQ(e.UpdateTitleTime(), 10 * base::Time::kMicrosecondsPerSecond);
EXPECT_TRUE(e.HasBeenSeen());
EXPECT_FALSE(e.IsRead());
- e.SetRead(true);
+ e.SetRead(true, base::Time::FromTimeT(30));
+ EXPECT_EQ(e.CreationTime(), 10 * base::Time::kMicrosecondsPerSecond);
+ EXPECT_EQ(e.UpdateTime(), 30 * base::Time::kMicrosecondsPerSecond);
+ EXPECT_EQ(e.UpdateTitleTime(), 10 * base::Time::kMicrosecondsPerSecond);
EXPECT_TRUE(e.HasBeenSeen());
EXPECT_TRUE(e.IsRead());
}
TEST(ReadingListEntry, UpdateTitle) {
- ReadingListEntry e(GURL("http://example.com"), "bar");
- ASSERT_EQ("bar", e.Title());
- ASSERT_EQ(e.CreationTime(), e.UpdateTitleTime());
-
- base::test::ios::SpinRunLoopWithMinDelay(
- base::TimeDelta::FromMilliseconds(5));
- e.SetTitle("foo");
- EXPECT_GT(e.UpdateTitleTime(), e.CreationTime());
+ ReadingListEntry e(GURL("http://example.com"), "bar",
+ base::Time::FromTimeT(10));
+ EXPECT_EQ("bar", e.Title());
+ // Getters are in microseconds.
+ EXPECT_EQ(e.CreationTime(), 10 * base::Time::kMicrosecondsPerSecond);
+ EXPECT_EQ(e.UpdateTitleTime(), 10 * base::Time::kMicrosecondsPerSecond);
+
+ e.SetTitle("foo", base::Time::FromTimeT(15));
+ EXPECT_EQ(e.UpdateTitleTime(), 15 * base::Time::kMicrosecondsPerSecond);
EXPECT_EQ("foo", e.Title());
}
TEST(ReadingListEntry, DistilledInfo) {
- ReadingListEntry e(GURL("http://example.com"), "bar");
+ ReadingListEntry e(GURL("http://example.com"), "bar",
+ base::Time::FromTimeT(10));
EXPECT_TRUE(e.DistilledPath().empty());
- const base::FilePath distilled_path("distilled/page.html");
+ const base::FilePath distilled_path(FILE_PATH_LITERAL("distilled/page.html"));
const GURL distilled_url("http://example.com/distilled");
int64_t size = 50;
int64_t time = 100;
- e.SetDistilledInfo(distilled_path, distilled_url, size, time);
+ e.SetDistilledInfo(distilled_path, distilled_url, size,
+ base::Time::FromTimeT(time));
EXPECT_EQ(distilled_path, e.DistilledPath());
EXPECT_EQ(distilled_url, e.DistilledURL());
EXPECT_EQ(size, e.DistillationSize());
- EXPECT_EQ(e.DistillationTime(), time);
+ EXPECT_EQ(e.DistillationTime(), time * base::Time::kMicrosecondsPerSecond);
}
TEST(ReadingListEntry, DistilledState) {
- ReadingListEntry e(GURL("http://example.com"), "bar");
+ ReadingListEntry e(GURL("http://example.com"), "bar",
+ base::Time::FromTimeT(10));
EXPECT_EQ(ReadingListEntry::WAITING, e.DistilledState());
- e.SetDistilledState(ReadingListEntry::ERROR);
- EXPECT_EQ(ReadingListEntry::ERROR, e.DistilledState());
+ e.SetDistilledState(ReadingListEntry::DISTILLATION_ERROR);
+ EXPECT_EQ(ReadingListEntry::DISTILLATION_ERROR, e.DistilledState());
- const base::FilePath distilled_path("distilled/page.html");
+ const base::FilePath distilled_path(FILE_PATH_LITERAL("distilled/page.html"));
const GURL distilled_url("http://example.com/distilled");
- e.SetDistilledInfo(distilled_path, distilled_url, 50, 100);
+ e.SetDistilledInfo(distilled_path, distilled_url, 50,
+ base::Time::FromTimeT(100));
EXPECT_EQ(ReadingListEntry::PROCESSED, e.DistilledState());
}
@@ -108,14 +127,16 @@ TEST(ReadingListEntry, TimeUntilNextTry) {
base::MakeUnique<net::BackoffEntry>(&ReadingListEntry::kBackoffPolicy,
&clock);
- ReadingListEntry e(GURL("http://example.com"), "bar", std::move(backoff));
+ ReadingListEntry e(GURL("http://example.com"), "bar",
+ base::Time::FromTimeT(10), std::move(backoff));
- double fuzzing = ReadingListEntry::kBackoffPolicy.jitter_factor;
+ // Allow twice the jitter as test is not instantaneous.
+ double fuzzing = 2 * ReadingListEntry::kBackoffPolicy.jitter_factor;
- ASSERT_EQ(0, e.TimeUntilNextTry().InSeconds());
+ EXPECT_EQ(0, e.TimeUntilNextTry().InSeconds());
// First error.
- e.SetDistilledState(ReadingListEntry::ERROR);
+ e.SetDistilledState(ReadingListEntry::DISTILLATION_ERROR);
int nextTry = e.TimeUntilNextTry().InMinutes();
EXPECT_NEAR(kFirstBackoff, nextTry, kFirstBackoff * fuzzing);
e.SetDistilledState(ReadingListEntry::WILL_RETRY);
@@ -128,7 +149,7 @@ TEST(ReadingListEntry, TimeUntilNextTry) {
e.SetDistilledState(ReadingListEntry::WILL_RETRY);
nextTry = e.TimeUntilNextTry().InMinutes();
EXPECT_NEAR(kSecondBackoff, nextTry, kSecondBackoff * fuzzing);
- e.SetDistilledState(ReadingListEntry::ERROR);
+ e.SetDistilledState(ReadingListEntry::DISTILLATION_ERROR);
EXPECT_EQ(nextTry, e.TimeUntilNextTry().InMinutes());
e.SetDistilledState(ReadingListEntry::PROCESSING);
@@ -141,13 +162,13 @@ TEST(ReadingListEntry, TimeUntilNextTry) {
// Fourth error.
e.SetDistilledState(ReadingListEntry::PROCESSING);
- e.SetDistilledState(ReadingListEntry::ERROR);
+ e.SetDistilledState(ReadingListEntry::DISTILLATION_ERROR);
EXPECT_NEAR(kFourthBackoff, e.TimeUntilNextTry().InMinutes(),
kFourthBackoff * fuzzing);
// Fifth error.
e.SetDistilledState(ReadingListEntry::PROCESSING);
- e.SetDistilledState(ReadingListEntry::ERROR);
+ e.SetDistilledState(ReadingListEntry::DISTILLATION_ERROR);
EXPECT_NEAR(kFifthBackoff, e.TimeUntilNextTry().InMinutes(),
kFifthBackoff * fuzzing);
}
@@ -159,10 +180,11 @@ TEST(ReadingListEntry, TimeUntilNextTryInThePast) {
std::unique_ptr<net::BackoffEntry> backoff =
base::MakeUnique<net::BackoffEntry>(&ReadingListEntry::kBackoffPolicy,
&clock);
- ReadingListEntry e(GURL("http://example.com"), "bar", std::move(backoff));
+ ReadingListEntry e(GURL("http://example.com"), "bar",
+ base::Time::FromTimeT(10), std::move(backoff));
double fuzzing = ReadingListEntry::kBackoffPolicy.jitter_factor;
- e.SetDistilledState(ReadingListEntry::ERROR);
+ e.SetDistilledState(ReadingListEntry::DISTILLATION_ERROR);
ASSERT_NEAR(kFirstBackoff, e.TimeUntilNextTry().InMinutes(),
kFirstBackoff * fuzzing);
@@ -180,21 +202,23 @@ TEST(ReadingListEntry, ResetTimeUntilNextTry) {
std::unique_ptr<net::BackoffEntry> backoff =
base::MakeUnique<net::BackoffEntry>(&ReadingListEntry::kBackoffPolicy,
&clock);
- ReadingListEntry e(GURL("http://example.com"), "bar", std::move(backoff));
+ ReadingListEntry e(GURL("http://example.com"), "bar",
+ base::Time::FromTimeT(10), std::move(backoff));
double fuzzing = ReadingListEntry::kBackoffPolicy.jitter_factor;
- e.SetDistilledState(ReadingListEntry::ERROR);
+ e.SetDistilledState(ReadingListEntry::DISTILLATION_ERROR);
ASSERT_NEAR(kFirstBackoff, e.TimeUntilNextTry().InMinutes(),
kFirstBackoff * fuzzing);
// Action.
- const base::FilePath distilled_path("distilled/page.html");
+ const base::FilePath distilled_path(FILE_PATH_LITERAL("distilled/page.html"));
const GURL distilled_url("http://example.com/distilled");
- e.SetDistilledInfo(distilled_path, distilled_url, 50, 100);
+ e.SetDistilledInfo(distilled_path, distilled_url, 50,
+ base::Time::FromTimeT(100));
// Test.
EXPECT_EQ(0, e.TimeUntilNextTry().InSeconds());
- e.SetDistilledState(ReadingListEntry::ERROR);
+ e.SetDistilledState(ReadingListEntry::DISTILLATION_ERROR);
ASSERT_NEAR(kFirstBackoff, e.TimeUntilNextTry().InMinutes(),
kFirstBackoff * fuzzing);
}
@@ -202,11 +226,12 @@ TEST(ReadingListEntry, ResetTimeUntilNextTry) {
// Tests that the failed download counter is incremented when the state change
// from non-error to error.
TEST(ReadingListEntry, FailedDownloadCounter) {
- ReadingListEntry e(GURL("http://example.com"), "bar");
+ ReadingListEntry e(GURL("http://example.com"), "bar",
+ base::Time::FromTimeT(10));
- ASSERT_EQ(0, e.FailedDownloadCounter());
+ EXPECT_EQ(0, e.FailedDownloadCounter());
- e.SetDistilledState(ReadingListEntry::ERROR);
+ e.SetDistilledState(ReadingListEntry::DISTILLATION_ERROR);
EXPECT_EQ(1, e.FailedDownloadCounter());
e.SetDistilledState(ReadingListEntry::WILL_RETRY);
EXPECT_EQ(1, e.FailedDownloadCounter());
@@ -216,14 +241,15 @@ TEST(ReadingListEntry, FailedDownloadCounter) {
e.SetDistilledState(ReadingListEntry::WILL_RETRY);
EXPECT_EQ(2, e.FailedDownloadCounter());
- e.SetDistilledState(ReadingListEntry::ERROR);
+ e.SetDistilledState(ReadingListEntry::DISTILLATION_ERROR);
EXPECT_EQ(2, e.FailedDownloadCounter());
}
// Tests that the reading list entry is correctly encoded to
// sync_pb::ReadingListSpecifics.
TEST(ReadingListEntry, AsReadingListSpecifics) {
- ReadingListEntry entry(GURL("http://example.com/"), "bar");
+ ReadingListEntry entry(GURL("http://example.com"), "bar",
+ base::Time::FromTimeT(10));
int64_t creation_time_us = entry.UpdateTime();
std::unique_ptr<sync_pb::ReadingListSpecifics> pb_entry(
@@ -235,8 +261,10 @@ TEST(ReadingListEntry, AsReadingListSpecifics) {
EXPECT_EQ(pb_entry->update_time_us(), entry.UpdateTime());
EXPECT_EQ(pb_entry->status(), sync_pb::ReadingListSpecifics::UNSEEN);
- entry.SetRead(true);
- EXPECT_NE(entry.UpdateTime(), creation_time_us);
+ entry.SetRead(true, base::Time::FromTimeT(15));
+ // Getters are in microseconds.
+ EXPECT_EQ(entry.CreationTime(), 10 * base::Time::kMicrosecondsPerSecond);
+ EXPECT_EQ(entry.UpdateTime(), 15 * base::Time::kMicrosecondsPerSecond);
std::unique_ptr<sync_pb::ReadingListSpecifics> updated_pb_entry(
entry.AsReadingListSpecifics());
EXPECT_EQ(updated_pb_entry->creation_time_us(), creation_time_us);
@@ -254,24 +282,31 @@ TEST(ReadingListEntry, FromReadingListSpecifics) {
pb_entry->set_title("title");
pb_entry->set_creation_time_us(1);
pb_entry->set_update_time_us(2);
+ pb_entry->set_update_title_time_us(3);
pb_entry->set_status(sync_pb::ReadingListSpecifics::UNREAD);
std::unique_ptr<ReadingListEntry> entry(
- ReadingListEntry::FromReadingListSpecifics(*pb_entry));
+ ReadingListEntry::FromReadingListSpecifics(*pb_entry,
+ base::Time::FromTimeT(10)));
EXPECT_EQ(entry->URL().spec(), "http://example.com/");
EXPECT_EQ(entry->Title(), "title");
+ EXPECT_EQ(entry->CreationTime(), 1);
EXPECT_EQ(entry->UpdateTime(), 2);
+ EXPECT_EQ(entry->UpdateTitleTime(), 3);
EXPECT_EQ(entry->FailedDownloadCounter(), 0);
}
// Tests that the reading list entry is correctly encoded to
// reading_list::ReadingListLocal.
TEST(ReadingListEntry, AsReadingListLocal) {
- ReadingListEntry entry(GURL("http://example.com/"), "bar");
+ ReadingListEntry entry(GURL("http://example.com/"), "foo",
+ base::Time::FromTimeT(10));
int64_t creation_time_us = entry.UpdateTime();
+ entry.SetTitle("bar", base::Time::FromTimeT(20));
+ entry.MarkEntryUpdated(base::Time::FromTimeT(30));
std::unique_ptr<reading_list::ReadingListLocal> pb_entry(
- entry.AsReadingListLocal());
+ entry.AsReadingListLocal(base::Time::FromTimeT(40)));
EXPECT_EQ(pb_entry->entry_id(), "http://example.com/");
EXPECT_EQ(pb_entry->url(), "http://example.com/");
EXPECT_EQ(pb_entry->title(), "bar");
@@ -283,24 +318,31 @@ TEST(ReadingListEntry, AsReadingListLocal) {
EXPECT_EQ(pb_entry->distilled_path(), "");
EXPECT_EQ(pb_entry->failed_download_counter(), 0);
EXPECT_NE(pb_entry->backoff(), "");
+ EXPECT_FALSE(pb_entry->content_suggestions_extra().dismissed());
entry.SetDistilledState(ReadingListEntry::WILL_RETRY);
std::unique_ptr<reading_list::ReadingListLocal> will_retry_pb_entry(
- entry.AsReadingListLocal());
+ entry.AsReadingListLocal(base::Time::FromTimeT(50)));
EXPECT_EQ(will_retry_pb_entry->distillation_state(),
reading_list::ReadingListLocal::WILL_RETRY);
EXPECT_EQ(will_retry_pb_entry->failed_download_counter(), 1);
- const base::FilePath distilled_path("distilled/page.html");
+ const base::FilePath distilled_path(FILE_PATH_LITERAL("distilled/page.html"));
const GURL distilled_url("http://example.com/distilled");
int64_t size = 50;
- entry.SetDistilledInfo(distilled_path, distilled_url, size, 100);
+ entry.SetDistilledInfo(distilled_path, distilled_url, size,
+ base::Time::FromTimeT(100));
+
+ entry.SetRead(true, base::Time::FromTimeT(20));
+ entry.MarkEntryUpdated(base::Time::FromTimeT(30));
+
+ reading_list::ContentSuggestionsExtra extra;
+ extra.dismissed = true;
+ entry.SetContentSuggestionsExtra(extra);
- entry.SetRead(true);
- entry.MarkEntryUpdated();
EXPECT_NE(entry.UpdateTime(), creation_time_us);
std::unique_ptr<reading_list::ReadingListLocal> distilled_pb_entry(
- entry.AsReadingListLocal());
+ entry.AsReadingListLocal(base::Time::FromTimeT(40)));
EXPECT_EQ(distilled_pb_entry->creation_time_us(), creation_time_us);
EXPECT_EQ(distilled_pb_entry->update_time_us(), entry.UpdateTime());
EXPECT_NE(distilled_pb_entry->backoff(), "");
@@ -312,16 +354,18 @@ TEST(ReadingListEntry, AsReadingListLocal) {
EXPECT_EQ(distilled_pb_entry->distillation_time_us(),
entry.DistillationTime());
EXPECT_EQ(distilled_pb_entry->distillation_size(), entry.DistillationSize());
+ EXPECT_TRUE(distilled_pb_entry->content_suggestions_extra().dismissed());
}
// Tests that the reading list entry is correctly parsed from
// sync_pb::ReadingListLocal.
TEST(ReadingListEntry, FromReadingListLocal) {
- ReadingListEntry entry(GURL("http://example.com/"), "title");
- entry.SetDistilledState(ReadingListEntry::ERROR);
+ ReadingListEntry entry(GURL("http://example.com/"), "title",
+ base::Time::FromTimeT(10));
+ entry.SetDistilledState(ReadingListEntry::DISTILLATION_ERROR);
std::unique_ptr<reading_list::ReadingListLocal> pb_entry(
- entry.AsReadingListLocal());
+ entry.AsReadingListLocal(base::Time::FromTimeT(10)));
int64_t now = 12345;
pb_entry->set_entry_id("http://example.com/");
@@ -329,23 +373,32 @@ TEST(ReadingListEntry, FromReadingListLocal) {
pb_entry->set_title("title");
pb_entry->set_creation_time_us(1);
pb_entry->set_update_time_us(2);
+ pb_entry->set_update_title_time_us(3);
pb_entry->set_status(reading_list::ReadingListLocal::UNREAD);
pb_entry->set_distillation_state(reading_list::ReadingListLocal::WAITING);
pb_entry->set_failed_download_counter(2);
pb_entry->set_distillation_time_us(now);
pb_entry->set_distillation_size(50);
+ reading_list::ReadingListContentSuggestionsExtra* pb_extra =
+ pb_entry->mutable_content_suggestions_extra();
+ pb_extra->set_dismissed(true);
+
std::unique_ptr<ReadingListEntry> waiting_entry(
- ReadingListEntry::FromReadingListLocal(*pb_entry));
+ ReadingListEntry::FromReadingListLocal(*pb_entry,
+ base::Time::FromTimeT(20)));
EXPECT_EQ(waiting_entry->URL().spec(), "http://example.com/");
EXPECT_EQ(waiting_entry->Title(), "title");
EXPECT_EQ(waiting_entry->UpdateTime(), 2);
+ EXPECT_EQ(waiting_entry->UpdateTitleTime(), 3);
EXPECT_EQ(waiting_entry->FailedDownloadCounter(), 2);
EXPECT_EQ(waiting_entry->DistilledState(), ReadingListEntry::WAITING);
EXPECT_EQ(waiting_entry->DistilledPath(), base::FilePath());
EXPECT_EQ(waiting_entry->DistillationSize(), 50);
EXPECT_EQ(waiting_entry->DistillationTime(), now);
- double fuzzing = ReadingListEntry::kBackoffPolicy.jitter_factor;
+ EXPECT_TRUE(waiting_entry->ContentSuggestionsExtra()->dismissed);
+ // Allow twice the jitter as test is not instantaneous.
+ double fuzzing = 2 * ReadingListEntry::kBackoffPolicy.jitter_factor;
int nextTry = waiting_entry->TimeUntilNextTry().InMinutes();
EXPECT_NEAR(kFirstBackoff, nextTry, kFirstBackoff * fuzzing);
}
@@ -354,22 +407,28 @@ TEST(ReadingListEntry, FromReadingListLocal) {
// Additional merging tests are done in
// ReadingListStoreTest.CompareEntriesForSync
TEST(ReadingListEntry, MergeWithEntry) {
- ReadingListEntry local_entry(GURL("http://example.com/"), "title");
- local_entry.SetDistilledState(ReadingListEntry::ERROR);
+ ReadingListEntry local_entry(GURL("http://example.com/"), "title",
+ base::Time::FromTimeT(10));
+ local_entry.SetDistilledState(ReadingListEntry::DISTILLATION_ERROR);
+ local_entry.SetTitle("title updated", base::Time::FromTimeT(30));
int64_t local_update_time_us = local_entry.UpdateTime();
- ReadingListEntry sync_entry(GURL("http://example.com/"), "title2");
- sync_entry.SetDistilledState(ReadingListEntry::ERROR);
+ ReadingListEntry sync_entry(GURL("http://example.com/"), "title2",
+ base::Time::FromTimeT(20));
+ sync_entry.SetDistilledState(ReadingListEntry::DISTILLATION_ERROR);
int64_t sync_update_time_us = sync_entry.UpdateTime();
EXPECT_NE(local_update_time_us, sync_update_time_us);
local_entry.MergeWithEntry(sync_entry);
EXPECT_EQ(local_entry.URL().spec(), "http://example.com/");
- EXPECT_EQ(local_entry.Title(), "title2");
+ EXPECT_EQ(local_entry.Title(), "title updated");
+ EXPECT_EQ(local_entry.UpdateTitleTime(),
+ 30 * base::Time::kMicrosecondsPerSecond);
EXPECT_FALSE(local_entry.HasBeenSeen());
EXPECT_EQ(local_entry.UpdateTime(), sync_update_time_us);
EXPECT_EQ(local_entry.FailedDownloadCounter(), 1);
- EXPECT_EQ(local_entry.DistilledState(), ReadingListEntry::ERROR);
- double fuzzing = ReadingListEntry::kBackoffPolicy.jitter_factor;
+ EXPECT_EQ(local_entry.DistilledState(), ReadingListEntry::DISTILLATION_ERROR);
+ // Allow twice the jitter as test is not instantaneous.
+ double fuzzing = 2 * ReadingListEntry::kBackoffPolicy.jitter_factor;
int nextTry = local_entry.TimeUntilNextTry().InMinutes();
EXPECT_NEAR(kFirstBackoff, nextTry, kFirstBackoff * fuzzing);
}
diff --git a/chromium/components/reading_list/ios/reading_list_model.cc b/chromium/components/reading_list/core/reading_list_model.cc
index ede2f8d7a69..d3d2829a553 100644
--- a/chromium/components/reading_list/ios/reading_list_model.cc
+++ b/chromium/components/reading_list/core/reading_list_model.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/reading_list/ios/reading_list_model.h"
+#include "components/reading_list/core/reading_list_model.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
diff --git a/chromium/components/reading_list/ios/reading_list_model.h b/chromium/components/reading_list/core/reading_list_model.h
index 42e536f8ef9..d0031588b7f 100644
--- a/chromium/components/reading_list/ios/reading_list_model.h
+++ b/chromium/components/reading_list/core/reading_list_model.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_READING_LIST_IOS_READING_LIST_MODEL_H_
-#define COMPONENTS_READING_LIST_IOS_READING_LIST_MODEL_H_
+#ifndef COMPONENTS_READING_LIST_CORE_READING_LIST_MODEL_H_
+#define COMPONENTS_READING_LIST_CORE_READING_LIST_MODEL_H_
#include <memory>
#include <string>
@@ -12,8 +12,8 @@
#include "base/callback.h"
#include "base/observer_list.h"
#include "base/threading/non_thread_safe.h"
-#include "components/reading_list/ios/reading_list_entry.h"
-#include "components/reading_list/ios/reading_list_model_observer.h"
+#include "components/reading_list/core/reading_list_entry.h"
+#include "components/reading_list/core/reading_list_model_observer.h"
class GURL;
class ReadingListModel;
@@ -128,8 +128,12 @@ class ReadingListModel : public base::NonThreadSafe {
const base::FilePath& distilled_path,
const GURL& distilled_url,
int64_t distilation_size,
- int64_t distilation_time) = 0;
+ const base::Time& distilation_time) = 0;
+ // Sets the extra info for the entry |url|.
+ virtual void SetContentSuggestionsExtra(
+ const GURL& url,
+ const reading_list::ContentSuggestionsExtra& extra) = 0;
// Observer registration methods. The model will remove all observers upon
// destruction automatically.
void AddObserver(ReadingListModelObserver* observer);
@@ -172,4 +176,4 @@ class ReadingListModel : public base::NonThreadSafe {
DISALLOW_COPY_AND_ASSIGN(ReadingListModel);
};
-#endif // COMPONENTS_READING_LIST_IOS_READING_LIST_MODEL_H_
+#endif // COMPONENTS_READING_LIST_CORE_READING_LIST_MODEL_H_
diff --git a/chromium/components/reading_list/ios/reading_list_model_impl.cc b/chromium/components/reading_list/core/reading_list_model_impl.cc
index 441f02eb4e7..d1ed193f0b5 100644
--- a/chromium/components/reading_list/ios/reading_list_model_impl.cc
+++ b/chromium/components/reading_list/core/reading_list_model_impl.cc
@@ -2,37 +2,38 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/reading_list/ios/reading_list_model_impl.h"
+#include "components/reading_list/core/reading_list_model_impl.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
+#include "base/time/clock.h"
#include "components/prefs/pref_service.h"
-#include "components/reading_list/ios/reading_list_model_storage.h"
-#include "components/reading_list/ios/reading_list_pref_names.h"
+#include "components/reading_list/core/reading_list_model_storage.h"
+#include "components/reading_list/core/reading_list_pref_names.h"
#include "url/gurl.h"
-ReadingListModelImpl::ReadingListModelImpl()
- : ReadingListModelImpl(nullptr, nullptr) {}
-
ReadingListModelImpl::ReadingListModelImpl(
std::unique_ptr<ReadingListModelStorage> storage,
- PrefService* pref_service)
- : unread_entry_count_(0),
+ PrefService* pref_service,
+ std::unique_ptr<base::Clock> clock)
+ : entries_(base::MakeUnique<ReadingListEntries>()),
+ unread_entry_count_(0),
read_entry_count_(0),
unseen_entry_count_(0),
+ clock_(std::move(clock)),
pref_service_(pref_service),
has_unseen_(false),
loaded_(false),
weak_ptr_factory_(this) {
DCHECK(CalledOnValidThread());
+ DCHECK(clock_);
if (storage) {
storage_layer_ = std::move(storage);
- storage_layer_->SetReadingListModel(this, this);
+ storage_layer_->SetReadingListModel(this, this, clock_.get());
} else {
loaded_ = true;
- entries_ = base::MakeUnique<ReadingListEntries>();
}
has_unseen_ = GetPersistentHasUnseen();
}
@@ -42,6 +43,7 @@ ReadingListModelImpl::~ReadingListModelImpl() {}
void ReadingListModelImpl::StoreLoaded(
std::unique_ptr<ReadingListEntries> entries) {
DCHECK(CalledOnValidThread());
+ DCHECK(entries);
entries_ = std::move(entries);
for (auto& iterator : *entries_) {
UpdateEntryStateCountersOnEntryInsertion(iterator.second);
@@ -108,7 +110,9 @@ bool ReadingListModelImpl::GetLocalUnseenFlag() const {
void ReadingListModelImpl::ResetLocalUnseenFlag() {
DCHECK(CalledOnValidThread());
- DCHECK(loaded());
+ if (!loaded()) {
+ return;
+ }
has_unseen_ = false;
if (!IsPerformingBatchUpdates())
SetPersistentHasUnseen(false);
@@ -131,7 +135,7 @@ void ReadingListModelImpl::MarkAllSeen() {
observer.ReadingListWillUpdateEntry(this, iterator.first);
}
UpdateEntryStateCountersOnEntryRemoval(entry);
- entry.SetRead(false);
+ entry.SetRead(false, clock_->Now());
UpdateEntryStateCountersOnEntryInsertion(entry);
if (storage_layer_) {
storage_layer_->SaveEntry(entry);
@@ -327,7 +331,7 @@ const ReadingListEntry& ReadingListModelImpl::AddEntry(
std::string trimmed_title = base::CollapseWhitespaceASCII(title, false);
- ReadingListEntry entry(url, trimmed_title);
+ ReadingListEntry entry(url, trimmed_title, clock_->Now());
for (auto& observer : observers_)
observer.ReadingListWillAddEntry(this, entry);
UpdateEntryStateCountersOnEntryInsertion(entry);
@@ -361,8 +365,8 @@ void ReadingListModelImpl::SetReadStatus(const GURL& url, bool read) {
observer.ReadingListWillMoveEntry(this, url);
}
UpdateEntryStateCountersOnEntryRemoval(entry);
- entry.SetRead(read);
- entry.MarkEntryUpdated();
+ entry.SetRead(read, clock_->Now());
+ entry.MarkEntryUpdated(clock_->Now());
UpdateEntryStateCountersOnEntryInsertion(entry);
if (storage_layer_) {
@@ -391,7 +395,7 @@ void ReadingListModelImpl::SetEntryTitle(const GURL& url,
for (ReadingListModelObserver& observer : observers_) {
observer.ReadingListWillUpdateEntry(this, url);
}
- entry.SetTitle(trimmed_title);
+ entry.SetTitle(trimmed_title, clock_->Now());
if (storage_layer_) {
storage_layer_->SaveEntry(entry);
}
@@ -405,7 +409,7 @@ void ReadingListModelImpl::SetEntryDistilledInfo(
const base::FilePath& distilled_path,
const GURL& distilled_url,
int64_t distillation_size,
- int64_t distillation_date) {
+ const base::Time& distillation_date) {
DCHECK(CalledOnValidThread());
DCHECK(loaded());
auto iterator = entries_->find(url);
@@ -457,6 +461,28 @@ void ReadingListModelImpl::SetEntryDistilledState(
}
}
+void ReadingListModelImpl::SetContentSuggestionsExtra(
+ const GURL& url,
+ const reading_list::ContentSuggestionsExtra& extra) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(loaded());
+ ReadingListEntry* entry = GetMutableEntryFromURL(url);
+ if (!entry) {
+ return;
+ }
+
+ for (ReadingListModelObserver& observer : observers_) {
+ observer.ReadingListWillUpdateEntry(this, url);
+ }
+ entry->SetContentSuggestionsExtra(extra);
+ if (storage_layer_) {
+ storage_layer_->SaveEntry(*entry);
+ }
+ for (ReadingListModelObserver& observer : observers_) {
+ observer.ReadingListDidApplyChanges(this);
+ }
+}
+
std::unique_ptr<ReadingListModel::ScopedReadingListBatchUpdate>
ReadingListModelImpl::CreateBatchToken() {
return base::MakeUnique<ReadingListModelImpl::ScopedReadingListBatchUpdate>(
@@ -509,7 +535,6 @@ bool ReadingListModelImpl::GetPersistentHasUnseen() {
}
syncer::ModelTypeSyncBridge* ReadingListModelImpl::GetModelTypeSyncBridge() {
- DCHECK(loaded());
if (!storage_layer_)
return nullptr;
return storage_layer_.get();
diff --git a/chromium/components/reading_list/ios/reading_list_model_impl.h b/chromium/components/reading_list/core/reading_list_model_impl.h
index b8beb664945..9e91e1ebb5b 100644
--- a/chromium/components/reading_list/ios/reading_list_model_impl.h
+++ b/chromium/components/reading_list/core/reading_list_model_impl.h
@@ -2,17 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_READING_LIST_IOS_READING_LIST_MODEL_IMPL_H_
-#define COMPONENTS_READING_LIST_IOS_READING_LIST_MODEL_IMPL_H_
+#ifndef COMPONENTS_READING_LIST_CORE_READING_LIST_MODEL_IMPL_H_
+#define COMPONENTS_READING_LIST_CORE_READING_LIST_MODEL_IMPL_H_
#include <map>
#include <memory>
#include "components/keyed_service/core/keyed_service.h"
-#include "components/reading_list/ios/reading_list_entry.h"
-#include "components/reading_list/ios/reading_list_model.h"
-#include "components/reading_list/ios/reading_list_model_storage.h"
-#include "components/reading_list/ios/reading_list_store_delegate.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"
+#include "components/reading_list/core/reading_list_store_delegate.h"
+
+namespace base {
+class Clock;
+}
class PrefService;
@@ -24,12 +28,14 @@ class ReadingListModelImpl : public ReadingListModel,
using ReadingListEntries = std::map<GURL, ReadingListEntry>;
// Initialize a ReadingListModelImpl to load and save data in
- // |persistence_layer|.
+ // |storage_layer|. Passing null to |storage_layer| will create a
+ // ReadingListModelImpl without persistence. Data will not be persistent
+ // across sessions.
+ // |clock| will be used to timestamp all the operations.
ReadingListModelImpl(std::unique_ptr<ReadingListModelStorage> storage_layer,
- PrefService* pref_service);
+ PrefService* pref_service,
+ std::unique_ptr<base::Clock> clock_);
- // Initialize a ReadingListModelImpl without persistence. Data will not be
- // persistent across sessions.
ReadingListModelImpl();
syncer::ModelTypeSyncBridge* GetModelTypeSyncBridge() override;
@@ -73,7 +79,10 @@ class ReadingListModelImpl : public ReadingListModel,
const base::FilePath& distilled_path,
const GURL& distilled_url,
int64_t distillation_size,
- int64_t distillation_date) override;
+ const base::Time& distillation_date) override;
+ void SetContentSuggestionsExtra(
+ const GURL& url,
+ const reading_list::ContentSuggestionsExtra& extra) override;
void SyncAddEntry(std::unique_ptr<ReadingListEntry> entry) override;
ReadingListEntry* SyncMergeEntry(
@@ -132,12 +141,16 @@ class ReadingListModelImpl : public ReadingListModel,
// Set the unseen flag to true.
void SetUnseenFlag();
+ // |storage_layer_| depends on |clock_| so keep the order.
+ std::unique_ptr<base::Clock> clock_;
std::unique_ptr<ReadingListModelStorage> storage_layer_;
PrefService* pref_service_;
bool has_unseen_;
bool loaded_;
+
base::WeakPtrFactory<ReadingListModelImpl> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(ReadingListModelImpl);
};
-#endif // COMPONENTS_READING_LIST_IOS_READING_LIST_MODEL_IMPL_H_
+#endif // COMPONENTS_READING_LIST_CORE_READING_LIST_MODEL_IMPL_H_
diff --git a/chromium/components/reading_list/ios/reading_list_model_observer.h b/chromium/components/reading_list/core/reading_list_model_observer.h
index ffaaed806e0..061d1cc3ac9 100644
--- a/chromium/components/reading_list/ios/reading_list_model_observer.h
+++ b/chromium/components/reading_list/core/reading_list_model_observer.h
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_READING_LIST_IOS_READING_LIST_MODEL_OBSERVER_H_
-#define COMPONENTS_READING_LIST_IOS_READING_LIST_MODEL_OBSERVER_H_
+#ifndef COMPONENTS_READING_LIST_CORE_READING_LIST_MODEL_OBSERVER_H_
+#define COMPONENTS_READING_LIST_CORE_READING_LIST_MODEL_OBSERVER_H_
#include <set>
#include <vector>
-#include "components/reading_list/ios/reading_list_entry.h"
+#include "components/reading_list/core/reading_list_entry.h"
class GURL;
class ReadingListModel;
@@ -80,4 +80,4 @@ class ReadingListModelObserver {
DISALLOW_COPY_AND_ASSIGN(ReadingListModelObserver);
};
-#endif // COMPONENTS_READING_LIST_IOS_READING_LIST_MODEL_OBSERVER_H_
+#endif // COMPONENTS_READING_LIST_CORE_READING_LIST_MODEL_OBSERVER_H_
diff --git a/chromium/components/reading_list/ios/reading_list_model_storage.cc b/chromium/components/reading_list/core/reading_list_model_storage.cc
index c1dbd05ca47..ee7c4ab4c56 100644
--- a/chromium/components/reading_list/ios/reading_list_model_storage.cc
+++ b/chromium/components/reading_list/core/reading_list_model_storage.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/reading_list/ios/reading_list_model_storage.h"
+#include "components/reading_list/core/reading_list_model_storage.h"
ReadingListModelStorage::ReadingListModelStorage(
const ChangeProcessorFactory& change_processor_factory,
diff --git a/chromium/components/reading_list/ios/reading_list_model_storage.h b/chromium/components/reading_list/core/reading_list_model_storage.h
index f0ac31a9a33..5edc30d08d9 100644
--- a/chromium/components/reading_list/ios/reading_list_model_storage.h
+++ b/chromium/components/reading_list/core/reading_list_model_storage.h
@@ -2,19 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_READING_LIST_IOS_READING_LIST_MODEL_STORAGE_H_
-#define COMPONENTS_READING_LIST_IOS_READING_LIST_MODEL_STORAGE_H_
+#ifndef COMPONENTS_READING_LIST_CORE_READING_LIST_MODEL_STORAGE_H_
+#define COMPONENTS_READING_LIST_CORE_READING_LIST_MODEL_STORAGE_H_
#include <vector>
#include "base/macros.h"
-#include "components/reading_list/ios/reading_list_entry.h"
+#include "components/reading_list/core/reading_list_entry.h"
#include "components/sync/base/model_type.h"
#include "components/sync/model/model_type_sync_bridge.h"
class ReadingListModel;
class ReadingListStoreDelegate;
+namespace base {
+class Clock;
+}
+
namespace syncer {
class ModelTypeSyncBridge;
}
@@ -32,8 +36,11 @@ class ReadingListModelStorage : public syncer::ModelTypeSyncBridge {
// Sets the model the Storage is backing.
// This will trigger store initalization and load persistent entries.
+ // Pass the |clock| from the |model| to ensure synchroization when loading
+ // entries.
virtual void SetReadingListModel(ReadingListModel* model,
- ReadingListStoreDelegate* delegate) = 0;
+ ReadingListStoreDelegate* delegate,
+ base::Clock* clock) = 0;
// Starts a transaction. All Save/Remove entry will be delayed until the
// transaction is commited.
@@ -64,4 +71,4 @@ class ReadingListModelStorage : public syncer::ModelTypeSyncBridge {
DISALLOW_COPY_AND_ASSIGN(ReadingListModelStorage);
};
-#endif // COMPONENTS_READING_LIST_IOS_READING_LIST_MODEL_STORAGE_H_
+#endif // COMPONENTS_READING_LIST_CORE_READING_LIST_MODEL_STORAGE_H_
diff --git a/chromium/components/reading_list/ios/reading_list_model_unittest.mm b/chromium/components/reading_list/core/reading_list_model_unittest.cc
index b8bc5c11970..a2b2b57fe46 100644
--- a/chromium/components/reading_list/ios/reading_list_model_unittest.mm
+++ b/chromium/components/reading_list/core/reading_list_model_unittest.cc
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/reading_list/ios/reading_list_model.h"
+#include "components/reading_list/core/reading_list_model.h"
#include "base/bind.h"
#include "base/memory/ptr_util.h"
-#import "base/test/ios/wait_util.h"
-#include "components/reading_list/ios/reading_list_model_impl.h"
-#include "components/reading_list/ios/reading_list_model_storage.h"
-#include "components/reading_list/ios/reading_list_store_delegate.h"
+#include "base/test/simple_test_clock.h"
+#include "components/reading_list/core/reading_list_model_impl.h"
+#include "components/reading_list/core/reading_list_model_storage.h"
+#include "components/reading_list/core/reading_list_store_delegate.h"
#include "components/sync/model/metadata_change_list.h"
#include "components/sync/model/model_error.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -19,6 +19,11 @@ namespace {
const GURL callback_url("http://example.com");
const std::string callback_title("test title");
+base::Time AdvanceAndGetTime(base::SimpleTestClock* clock) {
+ clock->Advance(base::TimeDelta::FromMilliseconds(10));
+ return clock->Now();
+}
+
class TestReadingListStorageObserver {
public:
virtual void ReadingListDidSaveEntry() = 0;
@@ -27,66 +32,63 @@ class TestReadingListStorageObserver {
class TestReadingListStorage : public ReadingListModelStorage {
public:
- TestReadingListStorage(TestReadingListStorageObserver* observer)
+ TestReadingListStorage(TestReadingListStorageObserver* observer,
+ base::SimpleTestClock* clock)
: ReadingListModelStorage(
base::Bind(&syncer::ModelTypeChangeProcessor::Create,
base::RepeatingClosure()),
syncer::READING_LIST),
entries_(new ReadingListStoreDelegate::ReadingListEntries()),
- observer_(observer) {}
+ observer_(observer),
+ clock_(clock) {}
void AddSampleEntries() {
// Adds timer and interlace read/unread entry creation to avoid having two
// entries with the same creation timestamp.
- ReadingListEntry unread_a(GURL("http://unread_a.com"), "unread_a");
+ ReadingListEntry unread_a(GURL("http://unread_a.com"), "unread_a",
+ AdvanceAndGetTime(clock_));
entries_->insert(
std::make_pair(GURL("http://unread_a.com"), std::move(unread_a)));
- base::test::ios::SpinRunLoopWithMinDelay(
- base::TimeDelta::FromMilliseconds(5));
- ReadingListEntry read_a(GURL("http://read_a.com"), "read_a");
- read_a.SetRead(true);
+ ReadingListEntry read_a(GURL("http://read_a.com"), "read_a",
+ AdvanceAndGetTime(clock_));
+ read_a.SetRead(true, AdvanceAndGetTime(clock_));
entries_->insert(
std::make_pair(GURL("http://read_a.com"), std::move(read_a)));
- base::test::ios::SpinRunLoopWithMinDelay(
- base::TimeDelta::FromMilliseconds(5));
- ReadingListEntry unread_b(GURL("http://unread_b.com"), "unread_b");
+ ReadingListEntry unread_b(GURL("http://unread_b.com"), "unread_b",
+ AdvanceAndGetTime(clock_));
entries_->insert(
std::make_pair(GURL("http://unread_b.com"), std::move(unread_b)));
- base::test::ios::SpinRunLoopWithMinDelay(
- base::TimeDelta::FromMilliseconds(5));
- ReadingListEntry read_b(GURL("http://read_b.com"), "read_b");
- read_b.SetRead(true);
+ ReadingListEntry read_b(GURL("http://read_b.com"), "read_b",
+ AdvanceAndGetTime(clock_));
+ read_b.SetRead(true, AdvanceAndGetTime(clock_));
entries_->insert(
std::make_pair(GURL("http://read_b.com"), std::move(read_b)));
- base::test::ios::SpinRunLoopWithMinDelay(
- base::TimeDelta::FromMilliseconds(5));
- ReadingListEntry unread_c(GURL("http://unread_c.com"), "unread_c");
+ ReadingListEntry unread_c(GURL("http://unread_c.com"), "unread_c",
+ AdvanceAndGetTime(clock_));
entries_->insert(
std::make_pair(GURL("http://unread_c.com"), std::move(unread_c)));
- base::test::ios::SpinRunLoopWithMinDelay(
- base::TimeDelta::FromMilliseconds(5));
- ReadingListEntry read_c(GURL("http://read_c.com"), "read_c");
- read_c.SetRead(true);
+ ReadingListEntry read_c(GURL("http://read_c.com"), "read_c",
+ AdvanceAndGetTime(clock_));
+ read_c.SetRead(true, AdvanceAndGetTime(clock_));
entries_->insert(
std::make_pair(GURL("http://read_c.com"), std::move(read_c)));
- base::test::ios::SpinRunLoopWithMinDelay(
- base::TimeDelta::FromMilliseconds(5));
- ReadingListEntry unread_d(GURL("http://unread_d.com"), "unread_d");
+ ReadingListEntry unread_d(GURL("http://unread_d.com"), "unread_d",
+ AdvanceAndGetTime(clock_));
entries_->insert(
std::make_pair(GURL("http://unread_d.com"), std::move(unread_d)));
- base::test::ios::SpinRunLoopWithMinDelay(
- base::TimeDelta::FromMilliseconds(5));
}
void SetReadingListModel(ReadingListModel* model,
- ReadingListStoreDelegate* delegate) override {
+ ReadingListStoreDelegate* delegate,
+ base::Clock* clock) override {
delegate->StoreLoaded(std::move(entries_));
+ clock_ = static_cast<base::SimpleTestClock*>(clock);
}
// Saves or updates an entry. If the entry is not yet in the database, it is
@@ -148,22 +150,28 @@ class TestReadingListStorage : public ReadingListModelStorage {
private:
std::unique_ptr<ReadingListStoreDelegate::ReadingListEntries> entries_;
TestReadingListStorageObserver* observer_;
+ base::SimpleTestClock* clock_;
};
class ReadingListModelTest : public ReadingListModelObserver,
public TestReadingListStorageObserver,
public testing::Test {
public:
- ReadingListModelTest()
- : callback_called_(false), model_(new ReadingListModelImpl()) {
+ ReadingListModelTest() : callback_called_(false) {
+ auto clock = base::MakeUnique<base::SimpleTestClock>();
+ clock_ = clock.get();
+ model_ = base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr,
+ std::move(clock));
ClearCounts();
model_->AddObserver(this);
}
~ReadingListModelTest() override {}
- void SetStorage(std::unique_ptr<TestReadingListStorage> storage) {
- model_ =
- base::MakeUnique<ReadingListModelImpl>(std::move(storage), nullptr);
+ void SetStorage(std::unique_ptr<TestReadingListStorage> storage,
+ std::unique_ptr<base::SimpleTestClock> clock) {
+ clock_ = clock.get();
+ model_ = base::MakeUnique<ReadingListModelImpl>(std::move(storage), nullptr,
+ std::move(clock));
ClearCounts();
model_->AddObserver(this);
}
@@ -294,6 +302,8 @@ class ReadingListModelTest : public ReadingListModelObserver,
bool callback_called_;
std::unique_ptr<ReadingListModelImpl> model_;
+ // Owned by |model_|;
+ base::SimpleTestClock* clock_;
};
// Tests creating an empty model.
@@ -310,9 +320,10 @@ TEST_F(ReadingListModelTest, EmptyLoaded) {
// Tests load model.
TEST_F(ReadingListModelTest, ModelLoaded) {
ClearCounts();
- auto storage = base::MakeUnique<TestReadingListStorage>(this);
+ auto clock = base::MakeUnique<base::SimpleTestClock>();
+ auto storage = base::MakeUnique<TestReadingListStorage>(this, clock.get());
storage->AddSampleEntries();
- SetStorage(std::move(storage));
+ SetStorage(std::move(storage), std::move(clock));
AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0);
std::map<GURL, std::string> loaded_entries;
@@ -334,8 +345,9 @@ TEST_F(ReadingListModelTest, ModelLoaded) {
// Tests adding entry.
TEST_F(ReadingListModelTest, AddEntry) {
- auto storage = base::MakeUnique<TestReadingListStorage>(this);
- SetStorage(std::move(storage));
+ auto clock = base::MakeUnique<base::SimpleTestClock>();
+ auto storage = base::MakeUnique<TestReadingListStorage>(this, clock.get());
+ SetStorage(std::move(storage), std::move(clock));
ClearCounts();
const ReadingListEntry& entry =
@@ -360,11 +372,12 @@ TEST_F(ReadingListModelTest, AddEntry) {
// Tests addin entry from sync.
TEST_F(ReadingListModelTest, SyncAddEntry) {
- auto storage = base::MakeUnique<TestReadingListStorage>(this);
- SetStorage(std::move(storage));
- auto entry =
- base::MakeUnique<ReadingListEntry>(GURL("http://example.com"), "sample");
- entry->SetRead(true);
+ auto clock = base::MakeUnique<base::SimpleTestClock>();
+ auto storage = base::MakeUnique<TestReadingListStorage>(this, clock.get());
+ SetStorage(std::move(storage), std::move(clock));
+ auto entry = base::MakeUnique<ReadingListEntry>(
+ GURL("http://example.com"), "sample", AdvanceAndGetTime(clock_));
+ entry->SetRead(true, AdvanceAndGetTime(clock_));
ClearCounts();
model_->SyncAddEntry(std::move(entry));
@@ -377,25 +390,25 @@ TEST_F(ReadingListModelTest, SyncAddEntry) {
// Tests updating entry from sync.
TEST_F(ReadingListModelTest, SyncMergeEntry) {
- auto storage = base::MakeUnique<TestReadingListStorage>(this);
- SetStorage(std::move(storage));
+ auto clock = base::MakeUnique<base::SimpleTestClock>();
+ auto storage = base::MakeUnique<TestReadingListStorage>(this, clock.get());
+ SetStorage(std::move(storage), std::move(clock));
model_->AddEntry(GURL("http://example.com"), "sample",
reading_list::ADDED_VIA_CURRENT_APP);
- const base::FilePath distilled_path("distilled/page.html");
+ const base::FilePath distilled_path(FILE_PATH_LITERAL("distilled/page.html"));
const GURL distilled_url("http://example.com/distilled");
int64_t size = 50;
int64_t time = 100;
model_->SetEntryDistilledInfo(GURL("http://example.com"), distilled_path,
- distilled_url, size, time);
+ distilled_url, size,
+ base::Time::FromTimeT(time));
const ReadingListEntry* local_entry =
model_->GetEntryByURL(GURL("http://example.com"));
int64_t local_update_time = local_entry->UpdateTime();
- base::test::ios::SpinRunLoopWithMinDelay(
- base::TimeDelta::FromMilliseconds(10));
- auto sync_entry =
- base::MakeUnique<ReadingListEntry>(GURL("http://example.com"), "sample");
- sync_entry->SetRead(true);
+ auto sync_entry = base::MakeUnique<ReadingListEntry>(
+ GURL("http://example.com"), "sample", AdvanceAndGetTime(clock_));
+ sync_entry->SetRead(true, AdvanceAndGetTime(clock_));
ASSERT_GT(sync_entry->UpdateTime(), local_update_time);
int64_t sync_update_time = sync_entry->UpdateTime();
EXPECT_TRUE(sync_entry->DistilledPath().empty());
@@ -408,16 +421,18 @@ TEST_F(ReadingListModelTest, SyncMergeEntry) {
EXPECT_EQ(0ul, UnreadSize());
EXPECT_EQ(1ul, ReadSize());
EXPECT_EQ(merged_entry->DistilledPath(),
- base::FilePath("distilled/page.html"));
+ base::FilePath(FILE_PATH_LITERAL("distilled/page.html")));
EXPECT_EQ(merged_entry->UpdateTime(), sync_update_time);
EXPECT_EQ(size, merged_entry->DistillationSize());
- EXPECT_EQ(time, merged_entry->DistillationTime());
+ EXPECT_EQ(time * base::Time::kMicrosecondsPerSecond,
+ merged_entry->DistillationTime());
}
// Tests deleting entry.
TEST_F(ReadingListModelTest, RemoveEntryByUrl) {
- auto storage = base::MakeUnique<TestReadingListStorage>(this);
- SetStorage(std::move(storage));
+ auto clock = base::MakeUnique<base::SimpleTestClock>();
+ auto storage = base::MakeUnique<TestReadingListStorage>(this, clock.get());
+ SetStorage(std::move(storage), std::move(clock));
model_->AddEntry(GURL("http://example.com"), "sample",
reading_list::ADDED_VIA_CURRENT_APP);
ClearCounts();
@@ -448,8 +463,9 @@ TEST_F(ReadingListModelTest, RemoveEntryByUrl) {
// Tests deleting entry from sync.
TEST_F(ReadingListModelTest, RemoveSyncEntryByUrl) {
- auto storage = base::MakeUnique<TestReadingListStorage>(this);
- SetStorage(std::move(storage));
+ auto clock = base::MakeUnique<base::SimpleTestClock>();
+ auto storage = base::MakeUnique<TestReadingListStorage>(this, clock.get());
+ SetStorage(std::move(storage), std::move(clock));
model_->AddEntry(GURL("http://example.com"), "sample",
reading_list::ADDED_VIA_CURRENT_APP);
ClearCounts();
@@ -626,18 +642,20 @@ TEST_F(ReadingListModelTest, UpdateDistilledInfo) {
model_->AddEntry(gurl, "sample", reading_list::ADDED_VIA_CURRENT_APP);
ClearCounts();
- const base::FilePath distilled_path("distilled/page.html");
+ const base::FilePath distilled_path(FILE_PATH_LITERAL("distilled/page.html"));
const GURL distilled_url("http://example.com/distilled");
int64_t size = 50;
int64_t time = 100;
model_->SetEntryDistilledInfo(GURL("http://example.com"), distilled_path,
- distilled_url, size, time);
+ distilled_url, size,
+ base::Time::FromTimeT(time));
AssertObserverCount(0, 0, 0, 0, 0, 0, 0, 1, 1);
EXPECT_EQ(ReadingListEntry::PROCESSED, entry.DistilledState());
EXPECT_EQ(distilled_path, entry.DistilledPath());
EXPECT_EQ(distilled_url, entry.DistilledURL());
EXPECT_EQ(size, entry.DistillationSize());
- EXPECT_EQ(time, entry.DistillationTime());
+ EXPECT_EQ(time * base::Time::kMicrosecondsPerSecond,
+ entry.DistillationTime());
}
// Tests setting title on read entry.
@@ -674,18 +692,35 @@ TEST_F(ReadingListModelTest, UpdateReadDistilledInfo) {
const ReadingListEntry* entry = model_->GetEntryByURL(gurl);
ClearCounts();
- const base::FilePath distilled_path("distilled/page.html");
+ const base::FilePath distilled_path(FILE_PATH_LITERAL("distilled/page.html"));
const GURL distilled_url("http://example.com/distilled");
int64_t size = 50;
int64_t time = 100;
model_->SetEntryDistilledInfo(GURL("http://example.com"), distilled_path,
- distilled_url, size, time);
+ distilled_url, size,
+ base::Time::FromTimeT(time));
AssertObserverCount(0, 0, 0, 0, 0, 0, 0, 1, 1);
EXPECT_EQ(ReadingListEntry::PROCESSED, entry->DistilledState());
EXPECT_EQ(distilled_path, entry->DistilledPath());
EXPECT_EQ(distilled_url, entry->DistilledURL());
EXPECT_EQ(size, entry->DistillationSize());
- EXPECT_EQ(time, entry->DistillationTime());
+ EXPECT_EQ(time * base::Time::kMicrosecondsPerSecond,
+ entry->DistillationTime());
+}
+
+// Tests setting ContentSuggestionsExtra info on entry.
+TEST_F(ReadingListModelTest, UpdateContentSuggestionsExtra) {
+ const GURL gurl("http://example.com");
+ model_->AddEntry(gurl, "sample", reading_list::ADDED_VIA_CURRENT_APP);
+ const ReadingListEntry* entry = model_->GetEntryByURL(gurl);
+ ClearCounts();
+
+ reading_list::ContentSuggestionsExtra extra;
+ extra.dismissed = true;
+
+ model_->SetContentSuggestionsExtra(gurl, extra);
+ AssertObserverCount(0, 0, 0, 0, 0, 0, 0, 1, 1);
+ EXPECT_EQ(extra.dismissed, entry->ContentSuggestionsExtra()->dismissed);
}
// Tests that ReadingListModel calls CallbackModelBeingDeleted when destroyed.
diff --git a/chromium/components/reading_list/ios/reading_list_pref_names.cc b/chromium/components/reading_list/core/reading_list_pref_names.cc
index 0c160945a86..9e434352c4a 100644
--- a/chromium/components/reading_list/ios/reading_list_pref_names.cc
+++ b/chromium/components/reading_list/core/reading_list_pref_names.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/reading_list/ios/reading_list_pref_names.h"
+#include "components/reading_list/core/reading_list_pref_names.h"
namespace reading_list {
namespace prefs {
diff --git a/chromium/components/reading_list/ios/reading_list_pref_names.h b/chromium/components/reading_list/core/reading_list_pref_names.h
index c9afb6013b5..997da56128f 100644
--- a/chromium/components/reading_list/ios/reading_list_pref_names.h
+++ b/chromium/components/reading_list/core/reading_list_pref_names.h
@@ -4,8 +4,8 @@
// Constants for the names of various reading list preferences.
-#ifndef COMPONENTS_READING_LIST_IOS_READING_LIST_PREF_NAMES_H_
-#define COMPONENTS_READING_LIST_IOS_READING_LIST_PREF_NAMES_H_
+#ifndef COMPONENTS_READING_LIST_CORE_READING_LIST_PREF_NAMES_H_
+#define COMPONENTS_READING_LIST_CORE_READING_LIST_PREF_NAMES_H_
namespace reading_list {
namespace prefs {
@@ -15,4 +15,4 @@ extern const char kReadingListHasUnseenEntries[];
} // namespace prefs
} // namespace reading_list
-#endif // COMPONENTS_READING_LIST_IOS_READING_LIST_PREF_NAMES_H_
+#endif // COMPONENTS_READING_LIST_CORE_READING_LIST_PREF_NAMES_H_
diff --git a/chromium/components/reading_list/ios/reading_list_store.cc b/chromium/components/reading_list/core/reading_list_store.cc
index 087ad621f0c..a9af371a3f0 100644
--- a/chromium/components/reading_list/ios/reading_list_store.cc
+++ b/chromium/components/reading_list/core/reading_list_store.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/reading_list/ios/reading_list_store.h"
+#include "components/reading_list/core/reading_list_store.h"
#include <set>
#include <utility>
@@ -10,8 +10,9 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
-#include "components/reading_list/ios/proto/reading_list.pb.h"
-#include "components/reading_list/ios/reading_list_model_impl.h"
+#include "base/time/clock.h"
+#include "components/reading_list/core/proto/reading_list.pb.h"
+#include "components/reading_list/core/reading_list_model_impl.h"
#include "components/sync/model/entity_change.h"
#include "components/sync/model/metadata_batch.h"
#include "components/sync/model/metadata_change_list.h"
@@ -32,10 +33,12 @@ ReadingListStore::~ReadingListStore() {
}
void ReadingListStore::SetReadingListModel(ReadingListModel* model,
- ReadingListStoreDelegate* delegate) {
+ ReadingListStoreDelegate* delegate,
+ base::Clock* clock) {
DCHECK(CalledOnValidThread());
model_ = model;
delegate_ = delegate;
+ clock_ = clock;
create_store_callback_.Run(
base::Bind(&ReadingListStore::OnStoreCreated, base::AsWeakPtr(this)));
}
@@ -79,7 +82,7 @@ void ReadingListStore::SaveEntry(const ReadingListEntry& entry) {
auto token = EnsureBatchCreated();
std::unique_ptr<reading_list::ReadingListLocal> pb_entry =
- entry.AsReadingListLocal();
+ entry.AsReadingListLocal(clock_->Now());
batch_->WriteData(entry.URL().spec(), pb_entry->SerializeAsString());
@@ -137,7 +140,7 @@ void ReadingListStore::OnDatabaseLoad(
}
std::unique_ptr<ReadingListEntry> entry(
- ReadingListEntry::FromReadingListLocal(proto));
+ ReadingListEntry::FromReadingListLocal(proto, clock_->Now()));
if (!entry) {
continue;
}
@@ -218,7 +221,7 @@ base::Optional<syncer::ModelError> ReadingListStore::MergeSyncData(
kv.second.value().specifics.reading_list();
// Deserialize entry.
std::unique_ptr<ReadingListEntry> entry(
- ReadingListEntry::FromReadingListSpecifics(specifics));
+ ReadingListEntry::FromReadingListSpecifics(specifics, clock_->Now()));
const ReadingListEntry* existing_entry =
model_->GetEntryByURL(entry->URL());
@@ -227,7 +230,7 @@ base::Optional<syncer::ModelError> ReadingListStore::MergeSyncData(
// This entry is new. Add it to the store and model.
// Convert to local store format and write to store.
std::unique_ptr<reading_list::ReadingListLocal> entry_pb =
- entry->AsReadingListLocal();
+ entry->AsReadingListLocal(clock_->Now());
batch_->WriteData(entry->URL().spec(), entry_pb->SerializeAsString());
// Notify model about updated entry.
@@ -239,7 +242,7 @@ base::Optional<syncer::ModelError> ReadingListStore::MergeSyncData(
// Write to the store.
std::unique_ptr<reading_list::ReadingListLocal> entry_local_pb =
- merged_entry->AsReadingListLocal();
+ merged_entry->AsReadingListLocal(clock_->Now());
batch_->WriteData(merged_entry->URL().spec(),
entry_local_pb->SerializeAsString());
@@ -305,7 +308,7 @@ base::Optional<syncer::ModelError> ReadingListStore::ApplySyncChanges(
const sync_pb::ReadingListSpecifics& specifics =
change.data().specifics.reading_list();
std::unique_ptr<ReadingListEntry> entry(
- ReadingListEntry::FromReadingListSpecifics(specifics));
+ ReadingListEntry::FromReadingListSpecifics(specifics, clock_->Now()));
const ReadingListEntry* existing_entry =
model_->GetEntryByURL(entry->URL());
@@ -314,7 +317,7 @@ base::Optional<syncer::ModelError> ReadingListStore::ApplySyncChanges(
// This entry is new. Add it to the store and model.
// Convert to local store format and write to store.
std::unique_ptr<reading_list::ReadingListLocal> entry_pb =
- entry->AsReadingListLocal();
+ entry->AsReadingListLocal(clock_->Now());
batch_->WriteData(entry->URL().spec(), entry_pb->SerializeAsString());
// Notify model about updated entry.
@@ -326,7 +329,7 @@ base::Optional<syncer::ModelError> ReadingListStore::ApplySyncChanges(
// Write to the store.
std::unique_ptr<reading_list::ReadingListLocal> entry_local_pb =
- merged_entry->AsReadingListLocal();
+ merged_entry->AsReadingListLocal(clock_->Now());
batch_->WriteData(merged_entry->URL().spec(),
entry_local_pb->SerializeAsString());
diff --git a/chromium/components/reading_list/ios/reading_list_store.h b/chromium/components/reading_list/core/reading_list_store.h
index 2b780073749..9f6eef8abfd 100644
--- a/chromium/components/reading_list/ios/reading_list_store.h
+++ b/chromium/components/reading_list/core/reading_list_store.h
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_READING_LIST_IOS_READING_LIST_STORE_H_
-#define COMPONENTS_READING_LIST_IOS_READING_LIST_STORE_H_
+#ifndef COMPONENTS_READING_LIST_CORE_READING_LIST_STORE_H_
+#define COMPONENTS_READING_LIST_CORE_READING_LIST_STORE_H_
#include <memory>
#include <string>
#include "base/threading/non_thread_safe.h"
-#include "components/reading_list/ios/reading_list_model_storage.h"
-#include "components/reading_list/ios/reading_list_store_delegate.h"
+#include "components/reading_list/core/reading_list_model_storage.h"
+#include "components/reading_list/core/reading_list_store_delegate.h"
#include "components/sync/model/model_error.h"
#include "components/sync/model/model_type_store.h"
@@ -35,7 +35,8 @@ class ReadingListStore : public ReadingListModelStorage,
// ReadingListModelStorage implementation
void SetReadingListModel(ReadingListModel* model,
- ReadingListStoreDelegate* delegate) override;
+ ReadingListStoreDelegate* delegate,
+ base::Clock* clock) override;
void SaveEntry(const ReadingListEntry& entry) override;
void RemoveEntry(const ReadingListEntry& entry) override;
@@ -164,6 +165,10 @@ class ReadingListStore : public ReadingListModelStorage,
int pending_transaction_count_;
std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch_;
+
+ base::Clock* clock_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReadingListStore);
};
-#endif // COMPONENTS_READING_LIST_IOS_READING_LIST_STORE_H_
+#endif // COMPONENTS_READING_LIST_CORE_READING_LIST_STORE_H_
diff --git a/chromium/components/reading_list/ios/reading_list_store_delegate.h b/chromium/components/reading_list/core/reading_list_store_delegate.h
index d95100c353f..ad960d2e136 100644
--- a/chromium/components/reading_list/ios/reading_list_store_delegate.h
+++ b/chromium/components/reading_list/core/reading_list_store_delegate.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_READING_LIST_IOS_READING_LIST_STORE_DELEGATE_H_
-#define COMPONENTS_READING_LIST_IOS_READING_LIST_STORE_DELEGATE_H_
+#ifndef COMPONENTS_READING_LIST_CORE_READING_LIST_STORE_DELEGATE_H_
+#define COMPONENTS_READING_LIST_CORE_READING_LIST_STORE_DELEGATE_H_
#include <map>
@@ -42,4 +42,4 @@ class ReadingListStoreDelegate {
DISALLOW_COPY_AND_ASSIGN(ReadingListStoreDelegate);
};
-#endif // COMPONENTS_READING_LIST_IOS_READING_LIST_STORE_DELEGATE_H_
+#endif // COMPONENTS_READING_LIST_CORE_READING_LIST_STORE_DELEGATE_H_
diff --git a/chromium/components/reading_list/ios/reading_list_store_unittest.mm b/chromium/components/reading_list/core/reading_list_store_unittest.cc
index 9ba369d41bd..7006ed358c6 100644
--- a/chromium/components/reading_list/ios/reading_list_store_unittest.mm
+++ b/chromium/components/reading_list/core/reading_list_store_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/reading_list/ios/reading_list_store.h"
+#include "components/reading_list/core/reading_list_store.h"
#include <map>
#include <set>
@@ -11,12 +11,14 @@
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
-#import "base/test/ios/wait_util.h"
-#include "components/reading_list/ios/reading_list_model_impl.h"
+#include "base/test/simple_test_clock.h"
+#include "components/reading_list/core/reading_list_model_impl.h"
#include "components/sync/model/fake_model_type_change_processor.h"
#include "components/sync/model/model_type_store_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace {
+
// Tests that the transition from |entryA| to |entryB| is possible (|possible|
// is true) or not.
void ExpectAB(const sync_pb::ReadingListSpecifics& entryA,
@@ -24,9 +26,11 @@ void ExpectAB(const sync_pb::ReadingListSpecifics& entryA,
bool possible) {
EXPECT_EQ(ReadingListStore::CompareEntriesForSync(entryA, entryB), possible);
std::unique_ptr<ReadingListEntry> a =
- ReadingListEntry::FromReadingListSpecifics(entryA);
+ ReadingListEntry::FromReadingListSpecifics(entryA,
+ base::Time::FromTimeT(10));
std::unique_ptr<ReadingListEntry> b =
- ReadingListEntry::FromReadingListSpecifics(entryB);
+ ReadingListEntry::FromReadingListSpecifics(entryB,
+ base::Time::FromTimeT(10));
a->MergeWithEntry(*b);
std::unique_ptr<sync_pb::ReadingListSpecifics> mergedEntry =
a->AsReadingListSpecifics();
@@ -41,6 +45,13 @@ void ExpectAB(const sync_pb::ReadingListSpecifics& entryA,
}
}
+base::Time AdvanceAndGetTime(base::SimpleTestClock* clock) {
+ clock->Advance(base::TimeDelta::FromMilliseconds(10));
+ return clock->Now();
+}
+
+} // namespace
+
class FakeModelTypeChangeProcessorObserver {
public:
virtual void Put(const std::string& client_tag,
@@ -85,8 +96,11 @@ class ReadingListStoreTest : public testing::Test,
base::Passed(&store_)),
base::Bind(&ReadingListStoreTest::CreateModelTypeChangeProcessor,
base::Unretained(this)));
- model_ = base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr);
- reading_list_store_->SetReadingListModel(model_.get(), this);
+ auto clock = base::MakeUnique<base::SimpleTestClock>();
+ clock_ = clock.get();
+ model_ = base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr,
+ std::move(clock));
+ reading_list_store_->SetReadingListModel(model_.get(), this, clock_);
base::RunLoop().RunUntilIdle();
}
@@ -163,6 +177,7 @@ class ReadingListStoreTest : public testing::Test,
std::unique_ptr<syncer::ModelTypeStore> store_;
std::unique_ptr<ReadingListModelImpl> model_;
+ base::SimpleTestClock* clock_;
std::unique_ptr<ReadingListStore> reading_list_store_;
int put_called_;
int delete_called_;
@@ -181,8 +196,10 @@ TEST_F(ReadingListStoreTest, CheckEmpties) {
}
TEST_F(ReadingListStoreTest, SaveOneRead) {
- ReadingListEntry entry(GURL("http://read.example.com/"), "read title");
- entry.SetRead(true);
+ ReadingListEntry entry(GURL("http://read.example.com/"), "read title",
+ AdvanceAndGetTime(clock_));
+ entry.SetRead(true, AdvanceAndGetTime(clock_));
+ AdvanceAndGetTime(clock_);
reading_list_store_->SaveEntry(entry);
AssertCounts(1, 0, 0, 0, 0);
syncer::EntityData* data = put_multimap_["http://read.example.com/"].get();
@@ -194,7 +211,8 @@ TEST_F(ReadingListStoreTest, SaveOneRead) {
}
TEST_F(ReadingListStoreTest, SaveOneUnread) {
- ReadingListEntry entry(GURL("http://unread.example.com/"), "unread title");
+ ReadingListEntry entry(GURL("http://unread.example.com/"), "unread title",
+ AdvanceAndGetTime(clock_));
reading_list_store_->SaveEntry(entry);
AssertCounts(1, 0, 0, 0, 0);
syncer::EntityData* data = put_multimap_["http://unread.example.com/"].get();
@@ -207,8 +225,9 @@ TEST_F(ReadingListStoreTest, SaveOneUnread) {
TEST_F(ReadingListStoreTest, SyncMergeOneEntry) {
syncer::EntityDataMap remote_input;
- ReadingListEntry entry(GURL("http://read.example.com/"), "read title");
- entry.SetRead(true);
+ ReadingListEntry entry(GURL("http://read.example.com/"), "read title",
+ AdvanceAndGetTime(clock_));
+ entry.SetRead(true, AdvanceAndGetTime(clock_));
std::unique_ptr<sync_pb::ReadingListSpecifics> specifics =
entry.AsReadingListSpecifics();
@@ -230,8 +249,9 @@ TEST_F(ReadingListStoreTest, SyncMergeOneEntry) {
TEST_F(ReadingListStoreTest, ApplySyncChangesOneAdd) {
syncer::EntityDataMap remote_input;
- ReadingListEntry entry(GURL("http://read.example.com/"), "read title");
- entry.SetRead(true);
+ ReadingListEntry entry(GURL("http://read.example.com/"), "read title",
+ AdvanceAndGetTime(clock_));
+ entry.SetRead(true, AdvanceAndGetTime(clock_));
std::unique_ptr<sync_pb::ReadingListSpecifics> specifics =
entry.AsReadingListSpecifics();
syncer::EntityData data;
@@ -252,14 +272,13 @@ TEST_F(ReadingListStoreTest, ApplySyncChangesOneAdd) {
TEST_F(ReadingListStoreTest, ApplySyncChangesOneMerge) {
syncer::EntityDataMap remote_input;
+ AdvanceAndGetTime(clock_);
model_->AddEntry(GURL("http://unread.example.com/"), "unread title",
reading_list::ADDED_VIA_CURRENT_APP);
- base::test::ios::SpinRunLoopWithMinDelay(
- base::TimeDelta::FromMilliseconds(10));
- ReadingListEntry new_entry(GURL("http://unread.example.com/"),
- "unread title");
- new_entry.SetRead(true);
+ ReadingListEntry new_entry(GURL("http://unread.example.com/"), "unread title",
+ AdvanceAndGetTime(clock_));
+ new_entry.SetRead(true, AdvanceAndGetTime(clock_));
std::unique_ptr<sync_pb::ReadingListSpecifics> specifics =
new_entry.AsReadingListSpecifics();
syncer::EntityData data;
@@ -280,12 +299,11 @@ TEST_F(ReadingListStoreTest, ApplySyncChangesOneMerge) {
TEST_F(ReadingListStoreTest, ApplySyncChangesOneIgnored) {
// Read entry but with unread URL as it must update the other one.
ReadingListEntry old_entry(GURL("http://unread.example.com/"),
- "old unread title");
- old_entry.SetRead(true);
+ "old unread title", AdvanceAndGetTime(clock_));
+ old_entry.SetRead(true, AdvanceAndGetTime(clock_));
- base::test::ios::SpinRunLoopWithMinDelay(
- base::TimeDelta::FromMilliseconds(10));
syncer::EntityDataMap remote_input;
+ AdvanceAndGetTime(clock_);
model_->AddEntry(GURL("http://unread.example.com/"), "new unread title",
reading_list::ADDED_VIA_CURRENT_APP);
AssertCounts(0, 0, 0, 0, 0);
diff --git a/chromium/components/reading_list/ios/BUILD.gn b/chromium/components/reading_list/ios/BUILD.gn
index 683640ef929..5d605fbb7b2 100644
--- a/chromium/components/reading_list/ios/BUILD.gn
+++ b/chromium/components/reading_list/ios/BUILD.gn
@@ -5,54 +5,11 @@
source_set("ios") {
sources = [
"favicon_web_state_dispatcher.h",
- "offline_url_utils.cc",
- "offline_url_utils.h",
- "reading_list_entry.cc",
- "reading_list_entry.h",
- "reading_list_model.cc",
- "reading_list_model.h",
"reading_list_model_bridge_observer.h",
"reading_list_model_bridge_observer.mm",
- "reading_list_model_impl.cc",
- "reading_list_model_impl.h",
- "reading_list_model_observer.h",
- "reading_list_model_storage.cc",
- "reading_list_model_storage.h",
- "reading_list_pref_names.cc",
- "reading_list_pref_names.h",
- "reading_list_store.cc",
- "reading_list_store.h",
- "reading_list_store_delegate.h",
]
deps = [
"//base",
- "//components/keyed_service/core",
- "//components/prefs",
"//components/reading_list/core",
- "//components/sync",
- "//net",
- "//url",
- ]
- public_deps = [
- "//components/reading_list/ios/proto",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "offline_url_utils_unittest.cc",
- "reading_list_entry_unittest.cc",
- "reading_list_model_unittest.mm",
- "reading_list_store_unittest.mm",
- ]
- deps = [
- ":ios",
- "//base",
- "//base/test:test_support",
- "//components/sync",
- "//components/sync:test_support_model",
- "//testing/gtest",
- "//url",
]
}
diff --git a/chromium/components/reading_list/ios/offline_url_utils_unittest.cc b/chromium/components/reading_list/ios/offline_url_utils_unittest.cc
deleted file mode 100644
index 8d9199ab957..00000000000
--- a/chromium/components/reading_list/ios/offline_url_utils_unittest.cc
+++ /dev/null
@@ -1,61 +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/reading_list/ios/offline_url_utils.h"
-
-#include <string>
-
-#include "base/files/file_path.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-// Checks the root directory of offline pages.
-TEST(OfflineURLUtilsTest, OfflineRootDirectoryPathTest) {
- base::FilePath profile_path("/profile_path");
- base::FilePath offline_directory =
- reading_list::OfflineRootDirectoryPath(profile_path);
- EXPECT_EQ("/profile_path/Offline", offline_directory.value());
-}
-
-// Checks the offline page directory is the MD5 of the URL
-TEST(OfflineURLUtilsTest, OfflineURLDirectoryIDTest) {
- GURL url("http://www.google.com/test");
- // MD5 of "http://www.google.com/test"
- std::string md5 = "0090071ef710946a1263c276284bb3b8";
- std::string directory_id = reading_list::OfflineURLDirectoryID(url);
- EXPECT_EQ(md5, directory_id);
-}
-
-// Checks the offline page directory is
-// |profile_path|/Offline/OfflineURLDirectoryID;
-TEST(OfflineURLUtilsTest, OfflineURLDirectoryAbsolutePathTest) {
- base::FilePath profile_path("/profile_path");
- GURL url("http://www.google.com/test");
- base::FilePath offline_directory =
- reading_list::OfflineURLDirectoryAbsolutePath(profile_path, url);
- EXPECT_EQ("/profile_path/Offline/0090071ef710946a1263c276284bb3b8",
- offline_directory.value());
-}
-
-// Checks the offline page directory is
-// |profile_path|/Offline/OfflineURLDirectoryID;
-TEST(OfflineURLUtilsTest, AbsolutePathForRelativePathTest) {
- base::FilePath profile_path("/profile_path");
- base::FilePath relative_path("relative/path");
- base::FilePath absolute_path =
- reading_list::OfflineURLAbsolutePathFromRelativePath(profile_path,
- relative_path);
- EXPECT_EQ("/profile_path/Offline/relative/path", absolute_path.value());
-}
-
-// Checks the offline page path is OfflineURLDirectoryID/page.html;
-TEST(OfflineURLUtilsTest, OfflinePagePathTest) {
- GURL url("http://www.google.com/test");
- base::FilePath offline_page =
- reading_list::OfflinePagePath(url, reading_list::OFFLINE_TYPE_HTML);
- EXPECT_EQ("0090071ef710946a1263c276284bb3b8/page.html", offline_page.value());
- offline_page =
- reading_list::OfflinePagePath(url, reading_list::OFFLINE_TYPE_PDF);
- EXPECT_EQ("0090071ef710946a1263c276284bb3b8/file.pdf", offline_page.value());
-}
diff --git a/chromium/components/reading_list/ios/reading_list_model_bridge_observer.h b/chromium/components/reading_list/ios/reading_list_model_bridge_observer.h
index f19e09e20ff..9b34e4939dd 100644
--- a/chromium/components/reading_list/ios/reading_list_model_bridge_observer.h
+++ b/chromium/components/reading_list/ios/reading_list_model_bridge_observer.h
@@ -9,7 +9,7 @@
#import <Foundation/Foundation.h>
#include "base/macros.h"
-#include "components/reading_list/ios/reading_list_model_observer.h"
+#include "components/reading_list/core/reading_list_model_observer.h"
// Protocol duplicating all Reading List Model Observer methods in Objective-C.
@protocol ReadingListModelBridgeObserver<NSObject>
diff --git a/chromium/components/reading_list/ios/reading_list_model_bridge_observer.mm b/chromium/components/reading_list/ios/reading_list_model_bridge_observer.mm
index 3595d3890c1..f295c7fdf63 100644
--- a/chromium/components/reading_list/ios/reading_list_model_bridge_observer.mm
+++ b/chromium/components/reading_list/ios/reading_list_model_bridge_observer.mm
@@ -4,8 +4,8 @@
#import "components/reading_list/ios/reading_list_model_bridge_observer.h"
-#include "components/reading_list/ios/reading_list_entry.h"
-#include "components/reading_list/ios/reading_list_model.h"
+#include "components/reading_list/core/reading_list_entry.h"
+#include "components/reading_list/core/reading_list_model.h"
ReadingListModelBridge::ReadingListModelBridge(
id<ReadingListModelBridgeObserver> observer,
diff --git a/chromium/components/renderer_context_menu/context_menu_content_type.cc b/chromium/components/renderer_context_menu/context_menu_content_type.cc
index 9ecd12322b0..d62e040cf78 100644
--- a/chromium/components/renderer_context_menu/context_menu_content_type.cc
+++ b/chromium/components/renderer_context_menu/context_menu_content_type.cc
@@ -84,7 +84,7 @@ bool ContextMenuContentType::SupportsGroupInternal(int group) {
case ITEM_GROUP_PAGE: {
bool is_candidate =
- params_.media_type == WebContextMenuData::MediaTypeNone &&
+ params_.media_type == WebContextMenuData::kMediaTypeNone &&
!has_link && !params_.is_editable && !has_selection;
if (!is_candidate && params_.page_url.is_empty())
@@ -104,27 +104,27 @@ bool ContextMenuContentType::SupportsGroupInternal(int group) {
return has_link;
case ITEM_GROUP_MEDIA_IMAGE:
- return params_.media_type == WebContextMenuData::MediaTypeImage;
+ return params_.media_type == WebContextMenuData::kMediaTypeImage;
case ITEM_GROUP_SEARCHWEBFORIMAGE:
// Image menu items imply search web for image item.
return SupportsGroupInternal(ITEM_GROUP_MEDIA_IMAGE);
case ITEM_GROUP_MEDIA_VIDEO:
- return params_.media_type == WebContextMenuData::MediaTypeVideo;
+ return params_.media_type == WebContextMenuData::kMediaTypeVideo;
case ITEM_GROUP_MEDIA_AUDIO:
- return params_.media_type == WebContextMenuData::MediaTypeAudio;
+ return params_.media_type == WebContextMenuData::kMediaTypeAudio;
case ITEM_GROUP_MEDIA_CANVAS:
- return params_.media_type == WebContextMenuData::MediaTypeCanvas;
+ return params_.media_type == WebContextMenuData::kMediaTypeCanvas;
case ITEM_GROUP_MEDIA_PLUGIN:
- return params_.media_type == WebContextMenuData::MediaTypePlugin;
+ return params_.media_type == WebContextMenuData::kMediaTypePlugin;
case ITEM_GROUP_MEDIA_FILE:
#if defined(WEBCONTEXT_MEDIATYPEFILE_DEFINED)
- return params_.media_type == WebContextMenuData::MediaTypeFile;
+ return params_.media_type == WebContextMenuData::kMediaTypeFile;
#else
return false;
#endif
@@ -164,7 +164,7 @@ bool ContextMenuContentType::SupportsGroupInternal(int group) {
case ITEM_GROUP_PASSWORD:
return params_.input_field_type ==
- blink::WebContextMenuData::InputFieldTypePassword;
+ blink::WebContextMenuData::kInputFieldTypePassword;
default:
NOTREACHED();
diff --git a/chromium/components/resources/BUILD.gn b/chromium/components/resources/BUILD.gn
index e33ac509962..6ead4c71c74 100644
--- a/chromium/components/resources/BUILD.gn
+++ b/chromium/components/resources/BUILD.gn
@@ -18,7 +18,6 @@ group("resources") {
grit("components_resources") {
source = "components_resources.grd"
- use_qualified_include = true
# TODO(hashimoto): Remove this line.
output_name = "components_resources_new"
@@ -42,9 +41,6 @@ grit("components_resources") {
grit("components_scaled_resources") {
source = "components_scaled_resources.grd"
- # TODO(thakis): Enable this, https://crbug.com/401588
- #use_qualified_include = true
-
# TODO(hashimoto): Remove this line.
output_name = "components_scaled_resources_new"
outputs = [
diff --git a/chromium/components/resources/OWNERS b/chromium/components/resources/OWNERS
index eb2ef926c60..6b8b3768a21 100644
--- a/chromium/components/resources/OWNERS
+++ b/chromium/components/resources/OWNERS
@@ -19,10 +19,7 @@ per-file neterror*=juliatuttle@chromium.org
per-file neterror*=mmenke@chromium.org
per-file ntp_tiles_resources.grdp=file://components/ntp_tiles/OWNERS
per-file proximity_auth*=tengs@chromium.org
-per-file supervised_user_error_page.grpd=aberent@chromium.org
-per-file supervised_user_error_page.grpd=bauerb@chromium.org
-per-file supervised_user_error_page.grpd=pam@chromium.org
-per-file supervised_user_error_page.grpd=reib@chromium.org
+per-file supervised_user_error_page.grpd=file://components/supervised_user_error_page/OWNERS
per-file version_ui*=achuith@chromium.org
per-file version_ui*=bauerb@chromium.org
per-file version_ui*=dbeam@chromium.org
diff --git a/chromium/components/resources/ntp_tiles_resources.grdp b/chromium/components/resources/ntp_tiles_resources.grdp
index 750d7d163cc..7d8d6c0a63c 100644
--- a/chromium/components/resources/ntp_tiles_resources.grdp
+++ b/chromium/components/resources/ntp_tiles_resources.grdp
@@ -7,14 +7,14 @@
<if expr="_google_chrome">
<then>
<include name="IDR_DEFAULT_POPULAR_SITES_JSON" file="../ntp_tiles/resources/internal/default_popular_sites.json" type="BINDATA" />
- <include name="IDR_DEFAULT_POPULAR_SITES_ICON0" file="../ntp_tiles/resources/internal/icon0.png" type="BINDATA" />
- <include name="IDR_DEFAULT_POPULAR_SITES_ICON1" file="../ntp_tiles/resources/internal/icon1.png" type="BINDATA" />
- <include name="IDR_DEFAULT_POPULAR_SITES_ICON2" file="../ntp_tiles/resources/internal/icon2.png" type="BINDATA" />
- <include name="IDR_DEFAULT_POPULAR_SITES_ICON3" file="../ntp_tiles/resources/internal/icon3.png" type="BINDATA" />
- <include name="IDR_DEFAULT_POPULAR_SITES_ICON4" file="../ntp_tiles/resources/internal/icon4.png" type="BINDATA" />
- <include name="IDR_DEFAULT_POPULAR_SITES_ICON5" file="../ntp_tiles/resources/internal/icon5.png" type="BINDATA" />
- <include name="IDR_DEFAULT_POPULAR_SITES_ICON6" file="../ntp_tiles/resources/internal/icon6.png" type="BINDATA" />
- <include name="IDR_DEFAULT_POPULAR_SITES_ICON7" file="../ntp_tiles/resources/internal/icon7.png" type="BINDATA" />
+ <include name="IDR_DEFAULT_POPULAR_SITES_ICON0" file="../ntp_tiles/resources/internal/icon0.webp" type="BINDATA" />
+ <include name="IDR_DEFAULT_POPULAR_SITES_ICON1" file="../ntp_tiles/resources/internal/icon1.webp" type="BINDATA" />
+ <include name="IDR_DEFAULT_POPULAR_SITES_ICON2" file="../ntp_tiles/resources/internal/icon2.webp" type="BINDATA" />
+ <include name="IDR_DEFAULT_POPULAR_SITES_ICON3" file="../ntp_tiles/resources/internal/icon3.webp" type="BINDATA" />
+ <include name="IDR_DEFAULT_POPULAR_SITES_ICON4" file="../ntp_tiles/resources/internal/icon4.webp" type="BINDATA" />
+ <include name="IDR_DEFAULT_POPULAR_SITES_ICON5" file="../ntp_tiles/resources/internal/icon5.webp" type="BINDATA" />
+ <include name="IDR_DEFAULT_POPULAR_SITES_ICON6" file="../ntp_tiles/resources/internal/icon6.webp" type="BINDATA" />
+ <include name="IDR_DEFAULT_POPULAR_SITES_ICON7" file="../ntp_tiles/resources/internal/icon7.webp" type="BINDATA" />
</then>
<else>
<!-- Fall back to a local resource so popular sites can be tested properly. -->
diff --git a/chromium/components/resources/physical_web_ui_resources.grdp b/chromium/components/resources/physical_web_ui_resources.grdp
index 0da84164a18..6a069f3ba5d 100644
--- a/chromium/components/resources/physical_web_ui_resources.grdp
+++ b/chromium/components/resources/physical_web_ui_resources.grdp
@@ -3,4 +3,5 @@
<include name="IDR_PHYSICAL_WEB_UI_HTML" file="../physical_web/webui/resources/physical_web.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
<include name="IDR_PHYSICAL_WEB_UI_JS" file="../physical_web/webui/resources/physical_web.js" type="BINDATA" />
<include name="IDR_PHYSICAL_WEB_UI_CSS" file="../physical_web/webui/resources/physical_web.css" type="BINDATA" />
+ <include name="IDR_PHYSICAL_WEB_UI_LINK_ICON" file="../physical_web/resources/ic_link_grey600_36dp.png" type="BINDATA" />
</grit-part> \ No newline at end of file
diff --git a/chromium/components/resources/proximity_auth_resources.grdp b/chromium/components/resources/proximity_auth_resources.grdp
index 6798b6c9b01..e793ff23a4c 100644
--- a/chromium/components/resources/proximity_auth_resources.grdp
+++ b/chromium/components/resources/proximity_auth_resources.grdp
@@ -1,47 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<grit-part>
- <include name="IDR_PROXIMITY_AUTH_UI_HTML" file="../proximity_auth/webui/resources/proximity_auth.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_UI_CSS" file="../proximity_auth/webui/resources/proximity_auth.css" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_LOG_PANEL_HTML"
- file="../proximity_auth/webui/resources/log-panel.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_LOG_PANEL_JS"
- file="../proximity_auth/webui/resources/log-panel.js" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_CONTENT_PANEL_HTML"
- file="../proximity_auth/webui/resources/content-panel.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_CONTENT_PANEL_JS"
- file="../proximity_auth/webui/resources/content-panel.js" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_LOCAL_STATE_HTML"
- file="../proximity_auth/webui/resources/local-state.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_LOCAL_STATE_JS"
- file="../proximity_auth/webui/resources/local-state.js" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_DEVICE_LIST_HTML"
- file="../proximity_auth/webui/resources/device-list.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_DEVICE_LIST_JS"
- file="../proximity_auth/webui/resources/device-list.js" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_LOG_BUFFER_HTML"
- file="../proximity_auth/webui/resources/log-buffer.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_LOG_BUFFER_JS"
- file="../proximity_auth/webui/resources/log-buffer.js" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_ELIGIBLE_DEVICES_HTML"
- file="../proximity_auth/webui/resources/eligible-devices.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_ELIGIBLE_DEVICES_JS"
- file="../proximity_auth/webui/resources/eligible-devices.js" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_REACHABLE_DEVICES_HTML"
- file="../proximity_auth/webui/resources/reachable-devices.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_REACHABLE_DEVICES_JS"
- file="../proximity_auth/webui/resources/reachable-devices.js" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_CRYPTAUTH_INTERFACE_JS"
- file="../proximity_auth/webui/resources/cryptauth_interface.js" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+ <!-- Shared resources. -->
+ <include name="IDR_PROXIMITY_AUTH_INDEX_HTML"
+ file="../proximity_auth/webui/resources/index.html"
+ flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+ <include name="IDR_PROXIMITY_AUTH_COMMON_CSS"
+ file="../proximity_auth/webui/resources/common.css" type="BINDATA" />
+ <include name="IDR_PROXIMITY_AUTH_LOGS_JS"
+ file="../proximity_auth/webui/resources/logs.js" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+ <include name="IDR_PROXIMITY_AUTH_WEBUI_JS"
+ file="../proximity_auth/webui/resources/webui.js" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+
+ <!-- Resources for ProximityAuth debug page. -->
+ <include name="IDR_PROXIMITY_AUTH_PROXIMITY_AUTH_HTML"
+ file="../proximity_auth/webui/resources/proximity_auth.html"
+ flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+ <include name="IDR_PROXIMITY_AUTH_PROXIMITY_AUTH_CSS"
+ file="../proximity_auth/webui/resources/proximity_auth.css" type="BINDATA" />
+ <include name="IDR_PROXIMITY_AUTH_PROXIMITY_AUTH_JS"
+ file="../proximity_auth/webui/resources/proximity_auth.js"
+ flattenhtml="true" allowexternalscript="true" type="BINDATA" />
<!-- Resources for Pollux debug page. -->
- <include name="IDR_PROXIMITY_AUTH_POLLUX_DEBUG_HTML"
- file="../proximity_auth/webui/resources/pollux/pollux_debug.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_POLLUX_DEBUG_CSS"
- file="../proximity_auth/webui/resources/pollux/pollux_debug.css" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_POLLUX_DEBUG_JS"
- file="../proximity_auth/webui/resources/pollux/pollux_debug.js" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_POLLUX_LOGS_CONTROLLER_JS"
- file="../proximity_auth/webui/resources/pollux/logs_controller.js" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_PROXIMITY_AUTH_POLLUX_WEBUI_JS"
- file="../proximity_auth/webui/resources/pollux/webui.js" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+ <include name="IDR_PROXIMITY_AUTH_POLLUX_HTML"
+ file="../proximity_auth/webui/resources/pollux.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+ <include name="IDR_PROXIMITY_AUTH_POLLUX_CSS"
+ file="../proximity_auth/webui/resources/pollux.css" type="BINDATA" />
+ <include name="IDR_PROXIMITY_AUTH_POLLUX_JS"
+ file="../proximity_auth/webui/resources/pollux.js" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
</grit-part>
diff --git a/chromium/components/safe_browsing/BUILD.gn b/chromium/components/safe_browsing/BUILD.gn
index ca816664d7b..ff80235e0f2 100644
--- a/chromium/components/safe_browsing/BUILD.gn
+++ b/chromium/components/safe_browsing/BUILD.gn
@@ -2,6 +2,14 @@
# 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("csd_proto") {
+ sources = [
+ "csd.proto",
+ ]
+}
+
source_set("safe_browsing") {
sources = [
"base_blocking_page.cc",
diff --git a/chromium/components/safe_browsing/DEPS b/chromium/components/safe_browsing/DEPS
index ac3d8bb7a89..36b6e0f8aec 100644
--- a/chromium/components/safe_browsing/DEPS
+++ b/chromium/components/safe_browsing/DEPS
@@ -11,4 +11,5 @@ include_rules = [
"+net/log",
"+net/url_request",
"+testing/gtest",
+ "+third_party/protobuf",
]
diff --git a/chromium/components/safe_browsing/OWNERS b/chromium/components/safe_browsing/OWNERS
index c417a096456..599d7d6b457 100644
--- a/chromium/components/safe_browsing/OWNERS
+++ b/chromium/components/safe_browsing/OWNERS
@@ -1,7 +1,6 @@
jialiul@chromium.org
mattm@chromium.org
nparker@chromium.org
-shess@chromium.org
# For componentization
timvolodine@chromium.org
diff --git a/chromium/components/safe_browsing/base_blocking_page.cc b/chromium/components/safe_browsing/base_blocking_page.cc
index f424b282c41..3f91702ab29 100644
--- a/chromium/components/safe_browsing/base_blocking_page.cc
+++ b/chromium/components/safe_browsing/base_blocking_page.cc
@@ -14,10 +14,8 @@
#include "components/security_interstitials/core/metrics_helper.h"
#include "content/public/browser/interstitial_page.h"
#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents.h"
-using base::UserMetricsAction;
using content::InterstitialPage;
using content::WebContents;
using security_interstitials::SafeBrowsingErrorUI;
@@ -71,14 +69,16 @@ BaseBlockingPage::~BaseBlockingPage() {}
// static
const SafeBrowsingErrorUI::SBErrorDisplayOptions
-BaseBlockingPage::CreateDefaultDisplayOptions() {
+BaseBlockingPage::CreateDefaultDisplayOptions(
+ const UnsafeResourceList& unsafe_resources) {
return SafeBrowsingErrorUI::SBErrorDisplayOptions(
- true, // IsMainPageLoadBlocked()
- false, // kSafeBrowsingExtendedReportingOptInAllowed
- false, // is_off_the_record
- false, // is_extended_reporting
- false, // is_scout
- false); // kSafeBrowsingProceedAnywayDisabled
+ IsMainPageLoadBlocked(unsafe_resources),
+ false, // kSafeBrowsingExtendedReportingOptInAllowed
+ false, // is_off_the_record
+ false, // is_extended_reporting
+ false, // is_scout
+ false, // kSafeBrowsingProceedAnywayDisabled
+ true); // is_resource_cancellable
}
// static
@@ -103,7 +103,7 @@ void BaseBlockingPage::ShowBlockingPage(
ui_manager, web_contents, entry ? entry->GetURL() : GURL(),
unsafe_resources,
CreateControllerClient(web_contents, unsafe_resources, ui_manager),
- CreateDefaultDisplayOptions());
+ CreateDefaultDisplayOptions(unsafe_resources));
blocking_page->Show();
}
}
diff --git a/chromium/components/safe_browsing/base_blocking_page.h b/chromium/components/safe_browsing/base_blocking_page.h
index 436745a3292..055bd0d429d 100644
--- a/chromium/components/safe_browsing/base_blocking_page.h
+++ b/chromium/components/safe_browsing/base_blocking_page.h
@@ -32,7 +32,7 @@ class BaseBlockingPage
~BaseBlockingPage() override;
static const SafeBrowsingErrorUI::SBErrorDisplayOptions
- CreateDefaultDisplayOptions();
+ CreateDefaultDisplayOptions(const UnsafeResourceList& unsafe_resources);
// Shows a blocking page warning the user about phishing/malware for a
// specific resource.
diff --git a/chromium/components/safe_browsing/base_resource_throttle.cc b/chromium/components/safe_browsing/base_resource_throttle.cc
index 333a2a09fa2..ff2cf8e34f3 100644
--- a/chromium/components/safe_browsing/base_resource_throttle.cc
+++ b/chromium/components/safe_browsing/base_resource_throttle.cc
@@ -4,11 +4,6 @@
#include "components/safe_browsing/base_resource_throttle.h"
-#include <iterator>
-#include <utility>
-
-#include "base/debug/alias.h"
-#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.h"
#include "base/values.h"
@@ -234,18 +229,9 @@ void BaseResourceThrottle::OnCheckBrowseUrlResult(
SBThreatType threat_type,
const ThreatMetadata& metadata) {
CHECK_EQ(state_, STATE_CHECKING_URL);
- // TODO(vakh): The following base::debug::Alias() and CHECK calls should be
- // removed after http://crbug.com/660293 is fixed.
CHECK(url.is_valid());
CHECK(url_being_checked_.is_valid());
- if (url != url_being_checked_) {
- bool url_had_timed_out = timed_out_urls_.count(url) > 0;
- char buf[1000];
- snprintf(buf, sizeof(buf), "sbtr::ocbur:%d:%s -- %s\n", url_had_timed_out,
- url.spec().c_str(), url_being_checked_.spec().c_str());
- base::debug::Alias(buf);
- CHECK(false) << "buf: " << buf;
- }
+ CHECK_EQ(url, url_being_checked_);
timer_.Stop(); // Cancel the timeout timer.
threat_type_ = threat_type;
@@ -431,8 +417,6 @@ void BaseResourceThrottle::OnCheckUrlTimeout() {
OnCheckBrowseUrlResult(url_being_checked_, safe_browsing::SB_THREAT_TYPE_SAFE,
ThreatMetadata());
-
- timed_out_urls_.insert(url_being_checked_);
}
void BaseResourceThrottle::ResumeRequest() {
diff --git a/chromium/components/safe_browsing/base_resource_throttle.h b/chromium/components/safe_browsing/base_resource_throttle.h
index adb4d3d0da5..1fe92f31603 100644
--- a/chromium/components/safe_browsing/base_resource_throttle.h
+++ b/chromium/components/safe_browsing/base_resource_throttle.h
@@ -5,8 +5,6 @@
#ifndef COMPONENTS_SAFE_BROWSING_BASE_RESOURCE_THROTTLE_H_
#define COMPONENTS_SAFE_BROWSING_BASE_RESOURCE_THROTTLE_H_
-#include <set>
-#include <string>
#include <vector>
#include "base/macros.h"
@@ -188,11 +186,6 @@ class BaseResourceThrottle
const content::ResourceType resource_type_;
net::NetLogWithSource net_log_with_source_;
- // TODO(vakh): The following set should be removed after fixing
- // http://crbug.com/660293
- // URLs that timed out waiting for a SafeBrowsing reputation check.
- std::set<GURL> timed_out_urls_;
-
DISALLOW_COPY_AND_ASSIGN(BaseResourceThrottle);
};
diff --git a/chromium/components/safe_browsing/common/BUILD.gn b/chromium/components/safe_browsing/common/BUILD.gn
index 47587637f13..4e32332c949 100644
--- a/chromium/components/safe_browsing/common/BUILD.gn
+++ b/chromium/components/safe_browsing/common/BUILD.gn
@@ -11,6 +11,7 @@ source_set("common") {
"safebrowsing_messages.h",
"safebrowsing_switches.cc",
"safebrowsing_switches.h",
+ "safebrowsing_types.h",
]
deps = [
diff --git a/chromium/components/safe_browsing/common/safebrowsing_messages.h b/chromium/components/safe_browsing/common/safebrowsing_messages.h
index 1e55f1a7577..1e03fa10f45 100644
--- a/chromium/components/safe_browsing/common/safebrowsing_messages.h
+++ b/chromium/components/safe_browsing/common/safebrowsing_messages.h
@@ -7,6 +7,7 @@
#include <string>
#include <vector>
+#include "components/safe_browsing/common/safebrowsing_types.h"
#include "ipc/ipc_message_macros.h"
#include "url/gurl.h"
#include "url/ipc/url_param_traits.h"
@@ -36,6 +37,9 @@ IPC_STRUCT_BEGIN(SafeBrowsingHostMsg_ThreatDOMDetails_Node)
// The unique IDs of the child nodes. Can be empty if there are no children.
IPC_STRUCT_MEMBER(std::vector<int>, child_node_ids)
+
+ // The node's attributes, as a collection of name-value pairs.
+ IPC_STRUCT_MEMBER(std::vector<safe_browsing::AttributeNameValue>, attributes)
IPC_STRUCT_END()
// SafeBrowsing client-side detection messages sent from the renderer to the
diff --git a/chromium/components/safe_browsing/common/safebrowsing_types.h b/chromium/components/safe_browsing/common/safebrowsing_types.h
new file mode 100644
index 00000000000..9b6428f21b9
--- /dev/null
+++ b/chromium/components/safe_browsing/common/safebrowsing_types.h
@@ -0,0 +1,16 @@
+// 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_COMMON_SAFEBROWSING_TYPES_H_
+#define COMPONENTS_SAFE_BROWSING_COMMON_SAFEBROWSING_TYPES_H_
+
+#include <string>
+
+namespace safe_browsing {
+
+// Used to store the name and value of an HTML Element's attribute.
+using AttributeNameValue = std::pair<std::string, std::string>;
+}
+
+#endif // COMPONENTS_SAFE_BROWSING_COMMON_SAFEBROWSING_TYPES_H_
diff --git a/chromium/components/safe_browsing/csd.proto b/chromium/components/safe_browsing/csd.proto
new file mode 100644
index 00000000000..023abe4ffbd
--- /dev/null
+++ b/chromium/components/safe_browsing/csd.proto
@@ -0,0 +1,1032 @@
+// 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 proto file includes:
+// (1) Client side phishing and malware detection request and response
+// protocol buffers. Those protocol messages should be kept in sync
+// with the server implementation.
+//
+// (2) Safe Browsing reporting protocol buffers.
+// A ClientSafeBrowsingReportRequest is sent when a user opts-in to
+// sending detailed threat reports from the safe browsing interstitial page.
+// It is a list of Resource messages, which may contain the url of a
+// resource such as the page in the address bar or any other resource
+// that was loaded for this page.
+// In addition to the url, a resource can contain HTTP request and response
+// headers and bodies.
+//
+// If you want to change this protocol definition or you have questions
+// regarding its format please contact chrome-anti-phishing@googlegroups.com.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package safe_browsing;
+
+// Protocol buffer describing the Chrome user population of the user reporting
+// data.
+message ChromeUserPopulation {
+ enum UserPopulation {
+ UNKNOWN_USER_POPULATION = 0;
+ SAFE_BROWSING = 1;
+ EXTENDED_REPORTING = 2;
+ }
+ optional UserPopulation user_population = 1;
+}
+
+message ClientPhishingRequest {
+ // URL that the client visited. The CGI parameters are stripped by the
+ // client.
+ optional string url = 1;
+
+ // A 5-byte SHA-256 hash prefix of the URL. Before hashing the URL is
+ // canonicalized, converted to a suffix-prefix expression and broadened
+ // (www prefix is removed and everything past the last '/' is stripped).
+ //
+ // Marked OBSOLETE because the URL is sent for all users, making the hash
+ // prefix unnecessary.
+ optional bytes OBSOLETE_hash_prefix = 10;
+
+ // Score that was computed on the client. Value is between 0.0 and 1.0.
+ // The larger the value the more likely the url is phishing.
+ required float client_score = 2;
+
+ // Note: we're skipping tag 3 because it was previously used.
+
+ // Is true if the features for this URL were classified as phishing.
+ // Currently, this will always be true for all client-phishing requests
+ // that are sent to the server.
+ optional bool is_phishing = 4;
+
+ message Feature {
+ // Feature name. E.g., 'PageHasForms'.
+ required string name = 1;
+
+ // Feature value is always in the range [0.0, 1.0]. Boolean features
+ // have value 1.0.
+ required double value = 2;
+ }
+
+ // List of features that were extracted. Those are the features that were
+ // sent to the scorer and which resulted in client_score being computed.
+ repeated Feature feature_map = 5;
+
+ // The version number of the model that was used to compute the client-score.
+ // Copied from ClientSideModel.version().
+ optional int32 model_version = 6;
+
+ // Field 7 is only used on the server.
+
+ // List of features that are extracted in the client but are not used in the
+ // machine learning model.
+ repeated Feature non_model_feature_map = 8;
+
+ // The referrer URL. This field might not be set, for example, in the case
+ // where the referrer uses HTTPs.
+ // OBSOLETE: Use feature 'Referrer=<referrer>' instead.
+ optional string OBSOLETE_referrer_url = 9;
+
+ // Field 11 is only used on the server.
+
+ // List of shingle hashes we extracted.
+ repeated uint32 shingle_hashes = 12 [packed = true];
+
+ // The model filename (basename) that was used by the client.
+ optional string model_filename = 13;
+
+ // Population that the reporting user is part of.
+ optional ChromeUserPopulation population = 14;
+}
+
+message ClientPhishingResponse {
+ required bool phishy = 1;
+
+ // A list of SafeBrowsing host-suffix / path-prefix expressions that
+ // are whitelisted. The client must match the current top-level URL
+ // against these whitelisted expressions and only apply a positive
+ // phishing verdict above if the URL does not match any expression
+ // on this whitelist. The client must not cache these whitelisted
+ // expressions. This whitelist will be empty for the vast majority
+ // of the responses but might contain up to 100 entries in emergency
+ // situations.
+ //
+ // Marked OBSOLETE because the URL is sent for all users, so the server
+ // can do whitelist matching.
+ repeated string OBSOLETE_whitelist_expression = 2;
+}
+
+message ClientMalwareRequest {
+ // URL that the client visited. The CGI parameters are stripped by the
+ // client.
+ required string url = 1;
+
+ // Field 2 is deleted and no longer in use.
+
+ // Field 3 is only used on the server.
+
+ // The referrer URL. This field might not be set, for example, in the case
+ // where the referrer uses HTTPS.
+ optional string referrer_url = 4;
+
+ // Field 5 and 6 are only used on the server.
+
+ message UrlInfo {
+ required string ip = 1;
+ required string url = 2;
+ optional string method = 3;
+ optional string referrer = 4;
+ // Resource type, the int value is a direct cast from the Type enum
+ // of ResourceType class defined in //src/webkit/commom/resource_type.h
+ optional int32 resource_type = 5;
+ }
+
+ // List of resource urls that match the malware IP list.
+ repeated UrlInfo bad_ip_url_info = 7;
+
+ // Population that the reporting user is part of.
+ optional ChromeUserPopulation population = 9;
+}
+
+// The message is used for client request to determine whether the provided URL
+// is safe for the purposes of entering user credentials for logging in.
+message LoginReputationClientRequest {
+ // The top level frame URL of the webpage that hosts the login form.
+ // The client will strip CGI parameters.
+ optional string page_url = 1;
+
+ // Type for the request.
+ // It could be low reputation request or password reuse request.
+ enum TriggerType {
+ TRIGGER_TYPE_UNSPECIFIED = 0;
+ UNFAMILIAR_LOGIN_PAGE = 1;
+ PASSWORD_REUSE_EVENT = 2;
+ }
+ optional TriggerType trigger_type = 2;
+
+ // The message contains features which can describe a frame. A frame can be
+ // a top level web page or an iframe.
+ message Frame {
+ // Id of a frame. The frame whose index = 0 is the top level web page.
+ optional int32 frame_index = 1;
+
+ // Id of the parent frame.
+ optional int32 parent_frame_index = 2;
+
+ // Url of the frame. If could be top level url (from web page) or url of
+ // the iframe.
+ optional string url = 3;
+
+ // Whether the frame contains password field.
+ optional bool has_password_field = 4;
+
+ // URLs transitions in reverse chronological order, i.e. the top level url
+ // or the url of the iframe comes first in the list.
+ repeated ReferrerChainEntry referrer_chain = 5;
+
+ // The message contains features of a form.
+ message Form {
+ // Action url of the form.
+ optional string action_url = 1;
+
+ // Whether the form contains password field.
+ optional bool has_password_field = 2;
+ }
+
+ repeated Form forms = 6;
+ }
+
+ repeated Frame frames = 3;
+
+ // The message contains fields needed for a password reuse event.
+ message PasswordReuseEvent {
+ // Origins that the reused password had been used on. The origins are
+ // maintained by Chrome password manager.
+ // The field is filled in only when TriggerType is PASSWORD_REUSE_EVENT.
+ repeated string password_reused_original_origins = 1;
+
+ // The frame that the password reuse is detected.
+ optional int32 frame_id = 2;
+ }
+
+ optional PasswordReuseEvent password_reuse_event = 4;
+
+ // The number of verdicts stored on the client.
+ optional int32 stored_verdict_cnt = 5;
+}
+
+// The message is used for client response for login reputation requests.
+message LoginReputationClientResponse {
+ // Type of verdicts issued by the server.
+ enum VerdictType {
+ VERDICT_TYPE_UNSPECIFIED = 0;
+ // No warning will be displayed.
+ SAFE = 1;
+ // The site has low reputation or low popularity.
+ LOW_REPUTATION = 2;
+ // The url matches with blacklist entries.
+ PHISHING = 3;
+ }
+ optional VerdictType verdict_type = 1;
+
+ // TTL of the verdict in seconds.
+ optional int64 cache_duration_sec = 2;
+
+ // A host-suffix/path-prefix expression which defines a collections of pages
+ // with common ownership from the same domain.
+ // Generally, the pattern is defined on the granularity of domains.
+ // For domains managed by multiple parties, especially in the case of large
+ // hosting sites (e.g., geocities.com), we further divide the domains.
+ //
+ // Examples:
+ // www.google.com/foo/bar?param=val -> google.com
+ // www.geocities.com/foo/bar.html -> geocities.com/foo
+ // adwords.blogspot.com/index.html -> adwords.blogspot.com
+ //
+ // The pattern will always match the page_url of the request, and will be
+ // a substring of page_url.
+ optional string cache_expression = 3;
+
+ // Deprecated.
+ optional bool DEPRECATED_cache_expression_exact_match = 4 [deprecated = true];
+}
+
+message ClientMalwareResponse {
+ required bool blacklist = 1;
+ // The confirmed blacklisted bad IP and its url, which will be shown in
+ // malware warning, if the blacklist verdict is true.
+ // This IP string could be either in IPv4 or IPv6 format, which is the same
+ // as the ones client sent to server.
+ optional string bad_ip = 2;
+ optional string bad_url = 3;
+}
+
+message ClientDownloadRequest {
+ // The final URL of the download (after all redirects).
+ required string url = 1;
+
+ // This message contains various binary digests of the download payload.
+ message Digests {
+ optional bytes sha256 = 1;
+ optional bytes sha1 = 2;
+ optional bytes md5 = 3;
+ }
+ required Digests digests = 2;
+
+ // This is the length in bytes of the download payload.
+ required int64 length = 3;
+
+ // Type of the resources stored below.
+ enum ResourceType {
+ // The final URL of the download payload. The resource URL should
+ // correspond to the URL field above.
+ DOWNLOAD_URL = 0;
+ // A redirect URL that was fetched before hitting the final DOWNLOAD_URL.
+ DOWNLOAD_REDIRECT = 1;
+ // The final top-level URL of the tab that triggered the download.
+ TAB_URL = 2;
+ // A redirect URL thas was fetched before hitting the final TAB_URL.
+ TAB_REDIRECT = 3;
+ // The document URL for a PPAPI plugin instance that initiated the download.
+ // This is the document.url for the container element for the plugin
+ // instance.
+ PPAPI_DOCUMENT = 4;
+ // The plugin URL for a PPAPI plugin instance that initiated the download.
+ PPAPI_PLUGIN = 5;
+ }
+
+ message Resource {
+ required string url = 1;
+ required ResourceType type = 2;
+ optional bytes remote_ip = 3;
+ // This will only be set if the referrer is available and if the
+ // resource type is either TAB_URL or DOWNLOAD_URL.
+ optional string referrer = 4;
+
+ // TODO(noelutz): add the transition type?
+ }
+
+ // This repeated field will store all the redirects as well as the
+ // final URLs for the top-level tab URL (i.e., the URL that
+ // triggered the download) as well as for the download URL itself.
+ repeated Resource resources = 4;
+
+ // A trust chain of certificates. Each chain begins with the signing
+ // certificate of the binary, and ends with a self-signed certificate,
+ // typically from a trusted root CA. This structure is analogous to
+ // CERT_CHAIN_CONTEXT on Windows.
+ message CertificateChain {
+ // A single link in the chain.
+ message Element {
+ // DER-encoded X.509 representation of the certificate.
+ optional bytes certificate = 1;
+ // Fields 2 - 7 are only used on the server.
+ }
+ repeated Element element = 1;
+ }
+
+ // This is an OS X only message to report extended attribute informations.
+ // Extended attributes on OS X are used for various security mechanisms,
+ // which makes them interesting to Chrome.
+ message ExtendedAttr {
+ // This is the name of the extended attribute.
+ required string key = 1;
+ // This is the value of the extended attribute.
+ optional bytes value = 2;
+ }
+
+ message SignatureInfo {
+ // All certificate chains for each of the binary's signers. Multiple chains
+ // may be present if the binary or any certificate has multiple signers.
+ // Absence of certificate chains does not imply that the binary is not
+ // signed (in that case, SignedData blobs extracted from the binary may be
+ // preset), but does mean that trust has not been verified.
+ repeated CertificateChain certificate_chain = 1;
+
+ // True if the signature was trusted on the client.
+ optional bool trusted = 2;
+
+ // On Windows, PKCS#7 SignedData blobs extracted from a portable executable
+ // image's attribute certificate table. The presence of these does not imply
+ // that the signatures were deemed trusted by the client.
+ // On Mac, this is the code signature blob referenced by the
+ // LC_CODE_SIGNATURE load command.
+ repeated bytes signed_data = 3;
+
+ // On OS X, code signing data can be contained in the extended attributes of
+ // a file. As Gatekeeper respects this signature, we look for it and collect
+ // it.
+ repeated ExtendedAttr xattr = 4;
+ }
+
+ // This field will only be set if the binary is signed.
+ optional SignatureInfo signature = 5;
+
+ // True if the download was user initiated.
+ optional bool user_initiated = 6;
+
+ // Fields 7 and 8 are only used on the server.
+
+ // Name of the file where the download would be stored if the
+ // download completes. E.g., "bla.exe".
+ optional string file_basename = 9;
+
+ // Starting with Chrome M19 we're also sending back pings for Chrome
+ // extensions that get downloaded by users.
+ enum DownloadType {
+ WIN_EXECUTABLE = 0; // Currently all .exe, .cab and .msi files.
+ CHROME_EXTENSION = 1; // .crx files.
+ ANDROID_APK = 2; // .apk files.
+ // .zip files containing one of the other executable types.
+ ZIPPED_EXECUTABLE = 3;
+ MAC_EXECUTABLE = 4; // .dmg, .pkg, etc.
+ ZIPPED_ARCHIVE = 5; // .zip file containing another archive.
+ ARCHIVE = 6; // Archive that doesn't have a specific DownloadType.
+ // A .zip that Chrome failed to unpack to the point of finding exe/zips.
+ INVALID_ZIP = 7;
+ // A .dmg, .pkg, etc, that Chrome failed to unpack to the point of finding
+ // Mach O's.
+ INVALID_MAC_ARCHIVE = 8;
+ // A download request initiated via PPAPI. Typically the requestor is
+ // a Flash applet.
+ PPAPI_SAVE_REQUEST = 9;
+ // A file we don't support, but we've decided to sample and send
+ // a light-ping.
+ SAMPLED_UNSUPPORTED_FILE = 10;
+ }
+ optional DownloadType download_type = 10 [default = WIN_EXECUTABLE];
+
+ // Locale of the device, eg en, en_US.
+ optional string locale = 11;
+
+ message PEImageHeaders {
+ // IMAGE_DOS_HEADER.
+ optional bytes dos_header = 1;
+ // IMAGE_FILE_HEADER.
+ optional bytes file_header = 2;
+ // IMAGE_OPTIONAL_HEADER32. Present only for 32-bit PE images.
+ optional bytes optional_headers32 = 3;
+ // IMAGE_OPTIONAL_HEADER64. Present only for 64-bit PE images.
+ optional bytes optional_headers64 = 4;
+ // IMAGE_SECTION_HEADER.
+ repeated bytes section_header = 5;
+ // Contents of the .edata section.
+ optional bytes export_section_data = 6;
+
+ message DebugData {
+ // IMAGE_DEBUG_DIRECTORY.
+ optional bytes directory_entry = 1;
+ optional bytes raw_data = 2;
+ }
+
+ repeated DebugData debug_data = 7;
+ }
+
+ message MachOHeaders {
+ // The mach_header or mach_header_64 struct.
+ required bytes mach_header = 1;
+
+ message LoadCommand {
+ // |command_id| is the first uint32 of |command| as well, but is
+ // extracted for easier processing.
+ required uint32 command_id = 1;
+ // The entire data stream of the load command.
+ required bytes command = 2;
+ }
+
+ // All the load commands of the Mach-O file.
+ repeated LoadCommand load_commands = 2;
+ }
+
+ message ImageHeaders {
+ // Windows Portable Executable image headers.
+ optional PEImageHeaders pe_headers = 1;
+
+ // OS X Mach-O image headers.
+ repeated MachOHeaders mach_o_headers = 2;
+ };
+
+ // Fields 12-17 are reserved for server-side use and are never sent by the
+ // client.
+
+ optional ImageHeaders image_headers = 18;
+
+ // Fields 19-21 are reserved for server-side use and are never sent by the
+ // client.
+
+ // A binary contained in an archive (e.g., a .zip archive).
+ message ArchivedBinary {
+ optional string file_basename = 1;
+ optional DownloadType download_type = 2;
+ optional Digests digests = 3;
+ optional int64 length = 4;
+ optional SignatureInfo signature = 5;
+ optional ImageHeaders image_headers = 6;
+ }
+
+ repeated ArchivedBinary archived_binary = 22;
+
+ // Population that the reporting user is part of.
+ optional ChromeUserPopulation population = 24;
+
+ // True if the .zip or DMG, etc, was 100% successfully unpacked.
+ optional bool archive_valid = 26;
+
+ // True if this ClientDownloadRequest is from a whitelisted domain.
+ optional bool skipped_url_whitelist = 28;
+
+ // True if this ClientDownloadRequest contains a whitelisted certificate.
+ optional bool skipped_certificate_whitelist = 31;
+
+ // PPAPI_SAVE_REQUEST type messages may have more than one suggested filetype.
+ // Each element in this collection indicates an alternate extension including
+ // the leading extension separator.
+ repeated string alternate_extensions = 35;
+
+ // URLs transitions from landing referrer to download in reverse chronological
+ // order, i.e. download url comes first in this list, and landing referrer
+ // comes last.
+ repeated ReferrerChainEntry referrer_chain = 36;
+
+ // Whether DownloadAttribution Finch experiment is enabled for this ping.
+ optional bool download_attribution_finch_enabled = 39;
+}
+
+message ReferrerChainEntry {
+ enum URLType {
+ // URL of safe browsing events that are at the end of the referrer chain.
+ // e.g. URL of a download, URL of a low reputation login page, etc.
+ EVENT_URL = 1; // e.g.
+
+ // Landing page is the page user directly interacts with to trigger the
+ // above event, e.g. the page where user clicks a download button.
+ LANDING_PAGE = 2;
+
+ // Landing referrer is the one user directly interacts with right before
+ // navigating to the landing page.
+ LANDING_REFERRER = 3;
+
+ // Client redirect refers to committed navigation between landing page and
+ // the targeted event, or between landing referrer page and landing page.
+ // Client redirect is not triggered by user gesture.
+ CLIENT_REDIRECT = 4;
+
+ DEPRECATED_SERVER_REDIRECT = 5; // Deprecated
+ }
+
+ message ServerRedirect {
+ // [required] server redirect url
+ optional string url = 1;
+
+ // Additional fields for future expansion.
+ }
+
+ // [required] The url of this Entry.
+ optional string url = 1;
+
+ // Only set if it is different from |url|.
+ optional string main_frame_url = 9;
+
+ // Type of URLs, such as event url, landing page, etc.
+ optional URLType type = 2 [default = CLIENT_REDIRECT];
+
+ // IP addresses corresponding to this host.
+ repeated string ip_addresses = 3;
+
+ // Referrer url of this entry.
+ optional string referrer_url = 4;
+
+ // Main frame URL of referrer.
+ // Only set if it is different from |referrer_url|.
+ optional string referrer_main_frame_url = 5;
+
+ // If this URL loads in a different tab/frame from previous one.
+ optional bool is_retargeting = 6;
+
+ optional double navigation_time_msec = 7;
+
+ // Set only if server redirects happened in navigation.
+ // The first entry in |server_redirect_chain| should be the original request
+ // url, and the last entry should be the same as |url|.
+ repeated ServerRedirect server_redirect_chain = 8;
+} // End of ReferrerChainEntry
+
+message ClientDownloadResponse {
+ enum Verdict {
+ // Download is considered safe.
+ SAFE = 0;
+ // Download is considered dangerous. Chrome should show a warning to the
+ // user.
+ DANGEROUS = 1;
+ // Download is uncommon. Chrome should display a less severe warning.
+ UNCOMMON = 2;
+ // The download is potentially unwanted.
+ POTENTIALLY_UNWANTED = 3;
+ // The download is from a dangerous host.
+ DANGEROUS_HOST = 4;
+ // The backend doesn't have confidence in its verdict of this file.
+ // Chrome should show the default warning if configured for this file type.
+ UNKNOWN = 5;
+ }
+ optional Verdict verdict = 1 [default = SAFE];
+
+ message MoreInfo {
+ // A human-readable string describing the nature of the warning.
+ // Only if verdict != SAFE. Localized based on request.locale.
+ optional string description = 1;
+
+ // A URL to get more information about this warning, if available.
+ optional string url = 2;
+ }
+ optional MoreInfo more_info = 2;
+
+ // An arbitrary token that should be sent along for further server requests.
+ optional bytes token = 3;
+
+ // Whether the server requests that this binary be uploaded.
+ optional bool upload = 5;
+}
+
+// The following protocol buffer holds the feedback report gathered
+// from the user regarding the download.
+message ClientDownloadReport {
+ // The information of user who provided the feedback.
+ // This is going to be useful for handling appeals.
+ message UserInformation { optional string email = 1; }
+
+ enum Reason {
+ SHARE = 0;
+ FALSE_POSITIVE = 1;
+ APPEAL = 2;
+ }
+
+ // The type of feedback for this report.
+ optional Reason reason = 1;
+
+ // The original download ping
+ optional ClientDownloadRequest download_request = 2;
+
+ // Stores the information of the user who provided the feedback.
+ optional UserInformation user_information = 3;
+
+ // Unstructed comments provided by the user.
+ optional bytes comment = 4;
+
+ // The original download response sent from the verdict server.
+ optional ClientDownloadResponse download_response = 5;
+}
+
+// This is used to send back upload status to the client after upload completion
+message ClientUploadResponse {
+ enum UploadStatus {
+ // The upload was successful and a complete response can be expected
+ SUCCESS = 0;
+
+ // The upload was unsuccessful and the response is incomplete.
+ UPLOAD_FAILURE = 1;
+ }
+
+ // Holds the upload status
+ optional UploadStatus status = 1;
+
+ // Holds the permalink where the results of scanning the binary are available
+ optional string permalink = 2;
+}
+
+message ClientIncidentReport {
+ message IncidentData {
+ message TrackedPreferenceIncident {
+ enum ValueState {
+ UNKNOWN = 0;
+ CLEARED = 1;
+ WEAK_LEGACY_OBSOLETE = 2;
+ CHANGED = 3;
+ UNTRUSTED_UNKNOWN_VALUE = 4;
+ BYPASS_CLEARED = 5;
+ BYPASS_CHANGED = 6;
+ }
+
+ optional string path = 1;
+ optional string atomic_value = 2;
+ repeated string split_key = 3;
+ optional ValueState value_state = 4;
+ }
+
+ message BinaryIntegrityIncident {
+ optional string file_basename = 1;
+ optional ClientDownloadRequest.SignatureInfo signature = 2;
+ optional ClientDownloadRequest.ImageHeaders image_headers = 3;
+ optional int32 sec_error = 4;
+
+ message ContainedFile {
+ optional string relative_path = 1;
+ optional ClientDownloadRequest.SignatureInfo signature = 2;
+ optional ClientDownloadRequest.ImageHeaders image_headers = 3;
+ }
+ repeated ContainedFile contained_file = 5;
+ }
+
+ message BlacklistLoadIncident {
+ optional string path = 1;
+ optional ClientDownloadRequest.Digests digest = 2;
+ optional string version = 3;
+ optional bool blacklist_initialized = 4;
+ optional ClientDownloadRequest.SignatureInfo signature = 5;
+ optional ClientDownloadRequest.ImageHeaders image_headers = 6;
+ }
+ message VariationsSeedSignatureIncident {
+ optional string variations_seed_signature = 1;
+ }
+ message ResourceRequestIncident {
+ enum Type {
+ UNKNOWN = 0;
+ TYPE_PATTERN = 3;
+ }
+ optional bytes digest = 1;
+ optional string origin = 2;
+ optional Type type = 3 [default = UNKNOWN];
+ }
+ message SuspiciousModuleIncident {
+ optional string path = 1;
+ optional ClientDownloadRequest.Digests digest = 2;
+ optional string version = 3;
+ optional ClientDownloadRequest.SignatureInfo signature = 4;
+ optional ClientDownloadRequest.ImageHeaders image_headers = 5;
+ }
+ optional int64 incident_time_msec = 1;
+ optional TrackedPreferenceIncident tracked_preference = 2;
+ optional BinaryIntegrityIncident binary_integrity = 3;
+ optional BlacklistLoadIncident blacklist_load = 4;
+ // Note: skip tag 5 because it was previously used.
+ optional VariationsSeedSignatureIncident variations_seed_signature = 6;
+ optional ResourceRequestIncident resource_request = 7;
+ optional SuspiciousModuleIncident suspicious_module = 8;
+ }
+
+ repeated IncidentData incident = 1;
+
+ message DownloadDetails {
+ optional bytes token = 1;
+ optional ClientDownloadRequest download = 2;
+ optional int64 download_time_msec = 3;
+ optional int64 open_time_msec = 4;
+ }
+
+ optional DownloadDetails download = 2;
+
+ message EnvironmentData {
+ message OS {
+ optional string os_name = 1;
+ optional string os_version = 2;
+
+ message RegistryValue {
+ optional string name = 1;
+ optional uint32 type = 2;
+ optional bytes data = 3;
+ }
+
+ message RegistryKey {
+ optional string name = 1;
+ repeated RegistryValue value = 2;
+ repeated RegistryKey key = 3;
+ }
+
+ repeated RegistryKey registry_key = 3;
+
+ optional bool is_enrolled_to_domain = 4;
+ }
+ optional OS os = 1;
+ message Machine {
+ optional string cpu_architecture = 1;
+ optional string cpu_vendor = 2;
+ optional uint32 cpuid = 3;
+ }
+ optional Machine machine = 2;
+ message Process {
+ optional string version = 1;
+ repeated string OBSOLETE_dlls = 2;
+ message Patch {
+ optional string function = 1;
+ optional string target_dll = 2;
+ }
+ repeated Patch patches = 3;
+ message NetworkProvider {}
+ repeated NetworkProvider network_providers = 4;
+ enum Channel {
+ CHANNEL_UNKNOWN = 0;
+ CHANNEL_CANARY = 1;
+ CHANNEL_DEV = 2;
+ CHANNEL_BETA = 3;
+ CHANNEL_STABLE = 4;
+ }
+ optional Channel chrome_update_channel = 5;
+ optional int64 uptime_msec = 6;
+ optional bool metrics_consent = 7;
+ // Obsolete: extended consent is now required for incident reporting.
+ optional bool OBSOLETE_extended_consent = 8;
+ message Dll {
+ enum Feature {
+ UNKNOWN = 0;
+ LSP = 1;
+ }
+ optional string path = 1;
+ optional uint64 base_address = 2;
+ optional uint32 length = 3;
+ repeated Feature feature = 4;
+ optional ClientDownloadRequest.ImageHeaders image_headers = 5;
+ }
+ repeated Dll dll = 9;
+ repeated string blacklisted_dll = 10;
+ message ModuleState {
+ enum ModifiedState {
+ UNKNOWN = 0;
+ MODULE_STATE_UNKNOWN = 1;
+ MODULE_STATE_UNMODIFIED = 2;
+ MODULE_STATE_MODIFIED = 3;
+ }
+ optional string name = 1;
+ optional ModifiedState modified_state = 2;
+ repeated string OBSOLETE_modified_export = 3;
+
+ message Modification {
+ optional uint32 file_offset = 1;
+ optional int32 byte_count = 2;
+ optional bytes modified_bytes = 3;
+ optional string export_name = 4;
+ }
+ repeated Modification modification = 4;
+ }
+ repeated ModuleState module_state = 11;
+ // Obsolete: field trials no longer enable incident reporting.
+ optional bool OBSOLETE_field_trial_participant = 12;
+ }
+ optional Process process = 3;
+ }
+
+ message ExtensionData {
+ message ExtensionInfo {
+ enum ExtensionState {
+ STATE_UNKNOWN = 0;
+ STATE_ENABLED = 1;
+ STATE_DISABLED = 2;
+ STATE_BLACKLISTED = 3;
+ STATE_BLOCKED = 4;
+ STATE_TERMINATED = 5;
+ }
+
+ optional string id = 1;
+ optional string version = 2;
+ optional string name = 3;
+ optional string description = 4;
+ optional ExtensionState state = 5 [default = STATE_UNKNOWN];
+ optional int32 type = 6;
+ optional string update_url = 7;
+ optional bool has_signature_validation = 8;
+ optional bool signature_is_valid = 9;
+ optional bool installed_by_custodian = 10;
+ optional bool installed_by_default = 11;
+ optional bool installed_by_oem = 12;
+ optional bool from_bookmark = 13;
+ optional bool from_webstore = 14;
+ optional bool converted_from_user_script = 15;
+ optional bool may_be_untrusted = 16;
+ optional int64 install_time_msec = 17;
+ optional int32 manifest_location_type = 18;
+ optional string manifest = 19;
+ }
+
+ optional ExtensionInfo last_installed_extension = 1;
+ }
+
+ optional EnvironmentData environment = 3;
+
+ // Population that the reporting user is part of.
+ optional ChromeUserPopulation population = 7;
+
+ optional ExtensionData extension_data = 8;
+
+ message NonBinaryDownloadDetails {
+ optional string file_type = 1;
+ optional bytes url_spec_sha256 = 2;
+ optional string host = 3;
+ optional int64 length = 4;
+ }
+
+ optional NonBinaryDownloadDetails non_binary_download = 9;
+}
+
+message ClientIncidentResponse {
+ optional bytes token = 1;
+ optional bool download_requested = 2;
+
+ message EnvironmentRequest { optional int32 dll_index = 1; }
+
+ repeated EnvironmentRequest environment_requests = 3;
+}
+
+message DownloadMetadata {
+ optional uint32 download_id = 1;
+
+ optional ClientIncidentReport.DownloadDetails download = 2;
+}
+
+// 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: 17
+message ClientSafeBrowsingReportRequest {
+ // Note: A lot of the "optional" fields would make sense to be
+ // "required" instead. However, having them as optional allows the
+ // clients to send "stripped down" versions of the message in the
+ // future, if we want to.
+
+ enum ReportType {
+ UNKNOWN = 0;
+ URL_PHISHING = 1;
+ URL_MALWARE = 2;
+ URL_UNWANTED = 3;
+ CLIENT_SIDE_PHISHING_URL = 4;
+ CLIENT_SIDE_MALWARE_URL = 5;
+ DANGEROUS_DOWNLOAD_RECOVERY = 6;
+ DANGEROUS_DOWNLOAD_WARNING = 7;
+ DANGEROUS_DOWNLOAD_BY_API = 10;
+ }
+
+ message HTTPHeader {
+ required bytes name = 1;
+ optional bytes value = 2;
+ }
+
+ message HTTPRequest {
+ message FirstLine {
+ optional bytes verb = 1;
+ optional bytes uri = 2;
+ optional bytes version = 3;
+ }
+
+ optional FirstLine firstline = 1;
+ repeated HTTPHeader headers = 2;
+ optional bytes body = 3;
+
+ // bodydigest and bodylength can be useful if the report does not
+ // contain the body itself.
+ optional bytes bodydigest = 4; // 32-byte hex md5 digest of body.
+ optional int32 bodylength = 5; // length of body.
+ }
+
+ message HTTPResponse {
+ message FirstLine {
+ optional int32 code = 1;
+ optional bytes message = 2;
+ optional bytes version = 3;
+ }
+
+ optional FirstLine firstline = 1;
+ repeated HTTPHeader headers = 2;
+ optional bytes body = 3;
+ optional bytes bodydigest = 4; // 32-byte hex md5 digest of body.
+ optional int32 bodylength = 5; // length of body.
+ optional bytes remote_ip = 6; // IP of the server.
+ }
+
+ message Resource {
+ required int32 id = 1;
+ optional string url = 2;
+ optional HTTPRequest request = 3;
+ optional HTTPResponse response = 4;
+ optional int32 parent_id = 5;
+ repeated int32 child_ids = 6;
+ optional string tag_name = 7;
+ }
+
+ optional ReportType type = 10;
+
+ // Only set if ReportType is DANGEROUS_DOWNLOAD_RECOVERY,
+ // DANGEROUS_DOWNLOAD_WARNING or DANGEROUS_DOWNLOAD_BY_API.
+ optional ClientDownloadResponse.Verdict download_verdict = 11;
+
+ // URL of the page in the address bar.
+ optional string url = 1;
+ optional string page_url = 2;
+ optional string referrer_url = 3;
+
+ repeated Resource resources = 4;
+
+ // Contains the hierarchy of elements on the page (ie: the DOM). Some
+ // elements can be Resources and will refer to the resources list (above).
+ repeated HTMLElement dom = 16;
+
+ // Whether the report is complete.
+ optional bool complete = 5;
+
+ // The ASN and country of the client IP. These fields are filled up by
+ // csd_frontend
+ repeated string client_asn = 6;
+ optional string client_country = 7;
+
+ // Whether user chose to proceed.
+ optional bool did_proceed = 8;
+
+ // Whether user visited this origin before.
+ optional bool repeat_visit = 9;
+
+ // The same token in ClientDownloadResponse. This field is only set if its
+ // report type is DANGEROUS_DOWNLOAD_RECOVERY, DANGEROUS_DOWNLOAD_WARNING or
+ // DANGEROUS_DOWNLOAD_BY_API.
+ optional bytes token = 15;
+}
+
+// An HTML Element on the page (eg: iframe, div, script, etc).
+message HTMLElement {
+ // Id of this element.
+ optional int32 id = 1;
+
+ // The tag type of this element (eg: iframe, div, script, etc).
+ optional string tag = 2;
+
+ // IDs of elements that are children of this element.
+ repeated int32 child_ids = 3;
+
+ // If this element represents a Resource then this is the id of the
+ // Resource, which contains additional data about the Resource. Otherwise
+ // unset.
+ optional int32 resource_id = 5;
+
+ // An Attribute of the element (eg: id, border, foo etc) and its value.
+ message Attribute {
+ optional string name = 1;
+ optional string value = 2;
+ }
+ repeated Attribute attribute = 6;
+}
+
+// Canonical representation of raster image data.
+message ImageData {
+ // Image bitmap, after downscaling to <= 512x512.
+ optional bytes data = 1;
+
+ // Encoding scheme for the bitmap.
+ optional string mime_type = 2;
+
+ message Dimensions {
+ optional int32 width = 1;
+ optional int32 height = 2;
+ }
+
+ // Dimensions of the image stored in |data|.
+ optional Dimensions dimensions = 3;
+ optional Dimensions original_dimensions = 4; // iff downscaled
+}
+
+// Reporting protobuf for an image served as part of a browser notification.
+// There is no response (an empty body) to this request.
+message NotificationImageReportRequest {
+ optional string notification_origin = 1; // Src-origin of the notification.
+ optional ImageData image = 2; // The bitmap of the image.
+
+ // Note that the image URL is deliberately omitted as it would be untrusted,
+ // since the notification image fetch may be intercepted by a Service Worker
+ // (even if the image URL is cross-origin). Otherwise a website could mislead
+ // Safe Browsing into associating phishing image bitmaps with safe image URLs.
+}
diff --git a/chromium/components/safe_browsing/password_protection/BUILD.gn b/chromium/components/safe_browsing/password_protection/BUILD.gn
index 1f2b234359f..a7be564812e 100644
--- a/chromium/components/safe_browsing/password_protection/BUILD.gn
+++ b/chromium/components/safe_browsing/password_protection/BUILD.gn
@@ -4,15 +4,26 @@
source_set("password_protection") {
sources = [
+ "password_protection_request.cc",
+ "password_protection_request.h",
"password_protection_service.cc",
"password_protection_service.h",
]
+ public_deps = [
+ "//google_apis:google_apis",
+ ]
+
deps = [
"//base:base",
+ "//components/content_settings/core/browser:browser",
+ "//components/data_use_measurement/core:core",
"//components/history/core/browser:browser",
+ "//components/safe_browsing:csd_proto",
"//components/safe_browsing_db:database_manager",
+ "//components/safe_browsing_db:v4_protocol_manager_util",
"//content/public/browser:browser",
+ "//net:net",
"//third_party/protobuf:protobuf_lite",
]
}
@@ -26,8 +37,12 @@ source_set("password_protection_unittest") {
":password_protection",
"//base",
"//base/test:test_support",
+ "//components/content_settings/core/browser:browser",
+ "//components/history/core/browser:browser",
"//components/safe_browsing_db:test_database_manager",
+ "//components/sync_preferences:test_support",
"//content/test:test_support",
+ "//net:test_support",
"//testing/gmock",
"//testing/gtest",
"//third_party/protobuf:protobuf_lite",
diff --git a/chromium/components/safe_browsing/password_protection/DEPS b/chromium/components/safe_browsing/password_protection/DEPS
index 47aa0d524d5..f04e7f6794a 100644
--- a/chromium/components/safe_browsing/password_protection/DEPS
+++ b/chromium/components/safe_browsing/password_protection/DEPS
@@ -1,7 +1,12 @@
include_rules = [
"-content",
+ "+components/content_settings/core/browser",
+ "+components/history/core/browser",
+ "+components/safe_browsing/csd.pb.h",
"+components/safe_browsing_db",
+ "+components/sync_preferences/testing_pref_service_syncable.h",
"+content/public/browser",
"+content/public/test",
+ "+net",
]
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_request.cc b/chromium/components/safe_browsing/password_protection/password_protection_request.cc
new file mode 100644
index 00000000000..e7db6e05543
--- /dev/null
+++ b/chromium/components/safe_browsing/password_protection/password_protection_request.cc
@@ -0,0 +1,217 @@
+// 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/password_protection/password_protection_request.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "base/metrics/histogram_macros.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/escape.h"
+#include "net/base/load_flags.h"
+#include "net/base/url_util.h"
+#include "net/http/http_status_code.h"
+
+using content::BrowserThread;
+
+namespace safe_browsing {
+
+PasswordProtectionRequest::PasswordProtectionRequest(
+ const GURL& main_frame_url,
+ LoginReputationClientRequest::TriggerType type,
+ bool is_extended_reporting,
+ bool is_incognito,
+ base::WeakPtr<PasswordProtectionService> pps,
+ int request_timeout_in_ms)
+ : main_frame_url_(main_frame_url),
+ request_type_(type),
+ is_extended_reporting_(is_extended_reporting),
+ is_incognito_(is_incognito),
+ password_protection_service_(pps),
+ request_timeout_in_ms_(request_timeout_in_ms),
+ weakptr_factory_(this) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+PasswordProtectionRequest::~PasswordProtectionRequest() {
+ weakptr_factory_.InvalidateWeakPtrs();
+}
+
+void PasswordProtectionRequest::Start() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // Initially we only send ping for Safe Browsing Extended Reporting users when
+ // they are not in incognito mode. We may loose these conditions later.
+ if (is_incognito_) {
+ Finish(RequestOutcome::INCOGNITO, nullptr);
+ return;
+ }
+ if (!is_extended_reporting_) {
+ Finish(RequestOutcome::NO_EXTENDED_REPORTING, nullptr);
+ return;
+ }
+
+ CheckWhitelistsOnUIThread();
+}
+
+void PasswordProtectionRequest::CheckWhitelistsOnUIThread() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(password_protection_service_);
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PasswordProtectionService::CheckCsdWhitelistOnIOThread,
+ password_protection_service_, main_frame_url_,
+ base::Bind(&PasswordProtectionRequest::OnWhitelistCheckDone,
+ GetWeakPtr())));
+}
+
+void PasswordProtectionRequest::OnWhitelistCheckDone(bool match_whitelist) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (match_whitelist)
+ Finish(RequestOutcome::MATCHED_WHITELIST, nullptr);
+ else
+ CheckCachedVerdicts();
+}
+
+void PasswordProtectionRequest::CheckCachedVerdicts() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!password_protection_service_) {
+ Finish(RequestOutcome::SERVICE_DESTROYED, nullptr);
+ return;
+ }
+
+ std::unique_ptr<LoginReputationClientResponse> cached_response =
+ base::MakeUnique<LoginReputationClientResponse>();
+ auto verdict = password_protection_service_->GetCachedVerdict(
+ main_frame_url_, cached_response.get());
+ if (verdict != LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED)
+ Finish(RequestOutcome::RESPONSE_ALREADY_CACHED, std::move(cached_response));
+ else
+ SendRequest();
+}
+
+void PasswordProtectionRequest::FillRequestProto() {
+ request_proto_ = base::MakeUnique<LoginReputationClientRequest>();
+ request_proto_->set_page_url(main_frame_url_.spec());
+ request_proto_->set_trigger_type(request_type_);
+ request_proto_->set_stored_verdict_cnt(
+ password_protection_service_->GetStoredVerdictCount());
+ LoginReputationClientRequest::Frame* main_frame =
+ request_proto_->add_frames();
+ main_frame->set_url(main_frame_url_.spec());
+ password_protection_service_->FillReferrerChain(
+ main_frame_url_, -1 /* tab id not available */, main_frame);
+ // TODO(jialiul): Add sub-frame information and password form information.
+}
+
+void PasswordProtectionRequest::SendRequest() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ FillRequestProto();
+
+ std::string serialized_request;
+ if (!request_proto_->SerializeToString(&serialized_request)) {
+ Finish(RequestOutcome::REQUEST_MALFORMED, nullptr);
+ return;
+ }
+
+ // In case the request take too long, we set a timer to cancel this request.
+ StartTimeout();
+
+ fetcher_ = net::URLFetcher::Create(
+ 0, PasswordProtectionService::GetPasswordProtectionRequestUrl(),
+ net::URLFetcher::POST, this);
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ fetcher_.get(), data_use_measurement::DataUseUserData::SAFE_BROWSING);
+ fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE);
+ fetcher_->SetAutomaticallyRetryOn5xx(false);
+ fetcher_->SetRequestContext(
+ password_protection_service_->request_context_getter().get());
+ fetcher_->SetUploadData("application/octet-stream", serialized_request);
+ request_start_time_ = base::TimeTicks::Now();
+ fetcher_->Start();
+}
+
+void PasswordProtectionRequest::StartTimeout() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // If request is not done withing 10 seconds, we cancel this request.
+ // The weak pointer used for the timeout will be invalidated (and
+ // hence would prevent the timeout) if the check completes on time and
+ // execution reaches Finish().
+ BrowserThread::PostDelayedTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&PasswordProtectionRequest::Cancel, GetWeakPtr(), true),
+ base::TimeDelta::FromMilliseconds(request_timeout_in_ms_));
+}
+
+void PasswordProtectionRequest::OnURLFetchComplete(
+ const net::URLFetcher* source) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ net::URLRequestStatus status = source->GetStatus();
+ const bool is_success = status.is_success();
+ const int response_code = source->GetResponseCode();
+
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "PasswordProtection.PasswordProtectionResponseOrErrorCode",
+ is_success ? response_code : status.error());
+
+ if (!is_success || net::HTTP_OK != response_code) {
+ Finish(RequestOutcome::FETCH_FAILED, nullptr);
+ return;
+ }
+
+ std::unique_ptr<LoginReputationClientResponse> response =
+ base::MakeUnique<LoginReputationClientResponse>();
+ std::string response_body;
+ bool received_data = source->GetResponseAsString(&response_body);
+ DCHECK(received_data);
+ fetcher_.reset(); // We don't need it anymore.
+ UMA_HISTOGRAM_TIMES("PasswordProtection.RequestNetworkDuration",
+ base::TimeTicks::Now() - request_start_time_);
+ if (response->ParseFromString(response_body)) {
+ Finish(RequestOutcome::SUCCEEDED, std::move(response));
+ } else {
+ Finish(RequestOutcome::RESPONSE_MALFORMED, nullptr);
+ }
+}
+
+void PasswordProtectionRequest::Finish(
+ RequestOutcome outcome,
+ std::unique_ptr<LoginReputationClientResponse> response) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ UMA_HISTOGRAM_ENUMERATION("PasswordProtection.RequestOutcome", outcome,
+ RequestOutcome::MAX_OUTCOME);
+
+ if (response) {
+ switch (request_type_) {
+ case LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE:
+ UMA_HISTOGRAM_ENUMERATION(
+ "PasswordProtection.UnfamiliarLoginPageVerdict",
+ response->verdict_type(),
+ LoginReputationClientResponse_VerdictType_VerdictType_MAX + 1);
+ break;
+ case LoginReputationClientRequest::PASSWORD_REUSE_EVENT:
+ UMA_HISTOGRAM_ENUMERATION(
+ "PasswordProtection.PasswordReuseEventVerdict",
+ response->verdict_type(),
+ LoginReputationClientResponse_VerdictType_VerdictType_MAX + 1);
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ DCHECK(password_protection_service_);
+ password_protection_service_->RequestFinished(this, std::move(response));
+}
+
+void PasswordProtectionRequest::Cancel(bool timed_out) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ fetcher_.reset();
+
+ Finish(timed_out ? TIMEDOUT : CANCELED, nullptr);
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_request.h b/chromium/components/safe_browsing/password_protection/password_protection_request.h
new file mode 100644
index 00000000000..52be0c11eb4
--- /dev/null
+++ b/chromium/components/safe_browsing/password_protection/password_protection_request.h
@@ -0,0 +1,128 @@
+// 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_PASSWORD_PROTECTION_PASSWORD_PROTECTION_REQUEST_H_
+#define COMPONENTS_SAFE_BROWSING_PASSWORD_PROTECTION_PASSWORD_PROTECTION_REQUEST_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "components/safe_browsing/password_protection/password_protection_service.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_request_status.h"
+
+class GURL;
+
+namespace safe_browsing {
+
+// A request for checking if an unfamiliar login form or a password reuse event
+// is safe. PasswordProtectionRequest objects are owned by
+// PasswordProtectionService indicated by |password_protection_service_|.
+class PasswordProtectionRequest : public net::URLFetcherDelegate {
+ public:
+ // The outcome of the request. These values are used for UMA.
+ // DO NOT CHANGE THE ORDERING OF THESE VALUES.
+ enum RequestOutcome {
+ UNKNOWN = 0,
+ SUCCEEDED = 1,
+ CANCELED = 2,
+ TIMEDOUT = 3,
+ MATCHED_WHITELIST = 4,
+ RESPONSE_ALREADY_CACHED = 5,
+ NO_EXTENDED_REPORTING = 6,
+ INCOGNITO = 7,
+ REQUEST_MALFORMED = 8,
+ FETCH_FAILED = 9,
+ RESPONSE_MALFORMED = 10,
+ SERVICE_DESTROYED = 11,
+ MAX_OUTCOME
+ };
+
+ PasswordProtectionRequest(const GURL& main_frame_url,
+ LoginReputationClientRequest::TriggerType type,
+ bool is_extended_reporting,
+ bool is_incognito,
+ base::WeakPtr<PasswordProtectionService> pps,
+ int request_timeout_in_ms);
+
+ ~PasswordProtectionRequest() override;
+
+ base::WeakPtr<PasswordProtectionRequest> GetWeakPtr() {
+ return weakptr_factory_.GetWeakPtr();
+ }
+
+ // Starts processing request by checking extended reporting and incognito
+ // conditions.
+ void Start();
+
+ // Cancels the current request. |timed_out| indicates if this cancellation is
+ // due to timeout. This function will call Finish() to destroy |this|.
+ void Cancel(bool timed_out);
+
+ // net::URLFetcherDelegate override.
+ // Processes the received response.
+ void OnURLFetchComplete(const net::URLFetcher* source) override;
+
+ GURL main_frame_url() const { return main_frame_url_; }
+
+ bool is_incognito() const { return is_incognito_; }
+
+ private:
+ // If |main_frame_url_| matches whitelist, call Finish() immediately;
+ // otherwise call CheckCachedVerdicts().
+ void OnWhitelistCheckDone(bool match_whitelist);
+
+ // Looks up cached verdicts. If verdict is already cached, call SendRequest();
+ // otherwise call Finish().
+ void CheckCachedVerdicts();
+
+ // Fill |request_proto_| with appropriate values.
+ void FillRequestProto();
+
+ // Initiates network request to Safe Browsing backend.
+ void SendRequest();
+
+ // Start a timer to cancel the request if it takes too long.
+ void StartTimeout();
+
+ // |this| will be destroyed after calling this function.
+ void Finish(RequestOutcome outcome,
+ std::unique_ptr<LoginReputationClientResponse> response);
+
+ void CheckWhitelistsOnUIThread();
+
+ // Main frame URL of the login form.
+ GURL main_frame_url_;
+
+ // If this request is for unfamiliar login page or for a password reuse event.
+ const LoginReputationClientRequest::TriggerType request_type_;
+
+ // If user is opted-in Safe Browsing Extended Reporting.
+ const bool is_extended_reporting_;
+
+ // If current session is in incognito mode.
+ const bool is_incognito_;
+
+ // When request is sent.
+ base::TimeTicks request_start_time_;
+
+ // URLFetcher instance for sending request and receiving response.
+ std::unique_ptr<net::URLFetcher> fetcher_;
+
+ // The PasswordProtectionService instance owns |this|.
+ base::WeakPtr<PasswordProtectionService> password_protection_service_;
+
+ // If we haven't receive response after this period of time, we cancel this
+ // request.
+ const int request_timeout_in_ms_;
+
+ std::unique_ptr<LoginReputationClientRequest> request_proto_;
+
+ base::WeakPtrFactory<PasswordProtectionRequest> weakptr_factory_;
+ DISALLOW_COPY_AND_ASSIGN(PasswordProtectionRequest);
+};
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_PASSWORD_PROTECTION_PASSWORD_PROTECTION_REQUEST_H_
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_service.cc b/chromium/components/safe_browsing/password_protection/password_protection_service.cc
index d0331fc4d30..3aee7ac1141 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_service.cc
+++ b/chromium/components/safe_browsing/password_protection/password_protection_service.cc
@@ -6,21 +6,82 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/safe_browsing/password_protection/password_protection_request.h"
#include "components/safe_browsing_db/database_manager.h"
+#include "components/safe_browsing_db/v4_protocol_manager_util.h"
#include "content/public/browser/browser_thread.h"
+#include "google_apis/google_api_keys.h"
+#include "net/base/escape.h"
using content::BrowserThread;
+using history::HistoryService;
namespace safe_browsing {
+namespace {
+
+// Keys for storing password protection verdict into a DictionaryValue.
+const char kCacheCreationTime[] = "cache_creation_time";
+const char kVerdictProto[] = "verdict_proto";
+const int kRequestTimeoutMs = 10000;
+const char kPasswordProtectionRequestUrl[] =
+ "https://sb-ssl.google.com/safebrowsing/clientreport/login";
+
+// Helper function to determine if the given origin matches content settings
+// map's patterns.
+bool OriginMatchPrimaryPattern(
+ const GURL& origin,
+ const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern_unused) {
+ return ContentSettingsPattern::FromURLNoWildcard(origin) == primary_pattern;
+}
+
+// Returns the number of path segments in |cache_expression_path|.
+// For example, return 0 for "/", since there is no path after the leading
+// slash; return 3 for "/abc/def/gh.html".
+size_t GetPathDepth(const std::string& cache_expression_path) {
+ return base::SplitString(base::StringPiece(cache_expression_path), "/",
+ base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)
+ .size();
+}
+
+// Given a URL of either http or https scheme, return its scheme://hostname.
+// e.g., "https://www.foo.com:80/bar/test.cgi" -> "http://www.foo.com".
+GURL GetHostNameWithHTTPScheme(const GURL& url) {
+ DCHECK(url.SchemeIsHTTPOrHTTPS());
+ std::string result(url::kHttpScheme);
+ result.append(url::kStandardSchemeSeparator).append(url.HostNoBrackets());
+ return GURL(result);
+}
+
+} // namespace
+
PasswordProtectionService::PasswordProtectionService(
- const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager)
- : database_manager_(database_manager), weak_factory_(this) {
+ const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ HistoryService* history_service,
+ HostContentSettingsMap* host_content_settings_map)
+ : stored_verdict_count_(-1),
+ database_manager_(database_manager),
+ request_context_getter_(request_context_getter),
+ history_service_observer_(this),
+ content_settings_(host_content_settings_map),
+ weak_factory_(this) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (history_service)
+ history_service_observer_.Add(history_service);
}
PasswordProtectionService::~PasswordProtectionService() {
+ CancelPendingRequests();
+ history_service_observer_.RemoveAll();
weak_factory_.InvalidateWeakPtrs();
}
@@ -30,20 +91,345 @@ void PasswordProtectionService::RecordPasswordReuse(const GURL& url) {
if (!url.is_valid())
return;
- BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::Bind(&SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl,
- database_manager_, url),
- base::Bind(&PasswordProtectionService::OnMatchCsdWhiteListResult,
- GetWeakPtr()));
+ base::Bind(
+ &PasswordProtectionService::CheckCsdWhitelistOnIOThread, GetWeakPtr(),
+ url,
+ base::Bind(&PasswordProtectionService::OnMatchCsdWhiteListResult,
+ base::Unretained(this))));
+}
+
+void PasswordProtectionService::CheckCsdWhitelistOnIOThread(
+ const GURL& url,
+ const CheckCsdWhitelistCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(database_manager_);
+ bool check_result = database_manager_->MatchCsdWhitelistUrl(url);
+ DCHECK(callback);
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, check_result));
+}
+
+LoginReputationClientResponse::VerdictType
+PasswordProtectionService::GetCachedVerdict(
+ const GURL& url,
+ LoginReputationClientResponse* out_response) {
+ if (!url.is_valid())
+ return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED;
+
+ DCHECK(content_settings_);
+
+ GURL hostname = GetHostNameWithHTTPScheme(url);
+ std::unique_ptr<base::DictionaryValue> verdict_dictionary =
+ base::DictionaryValue::From(content_settings_->GetWebsiteSetting(
+ hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
+ std::string(), nullptr));
+ // Return early if there is no verdict cached for this origin.
+ if (!verdict_dictionary.get() || verdict_dictionary->empty())
+ return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED;
+
+ std::vector<std::string> paths;
+ GeneratePathVariantsWithoutQuery(url, &paths);
+ int max_path_depth = -1;
+ LoginReputationClientResponse::VerdictType most_matching_verdict =
+ LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED;
+ // For all the verdicts of the same origin, we key them by |cache_expression|.
+ // Its corresponding value is a DictionaryValue contains its creation time and
+ // the serialized verdict proto.
+ for (base::DictionaryValue::Iterator it(*verdict_dictionary.get());
+ !it.IsAtEnd(); it.Advance()) {
+ base::DictionaryValue* verdict_entry = nullptr;
+ CHECK(verdict_dictionary->GetDictionaryWithoutPathExpansion(
+ it.key() /* cache_expression */, &verdict_entry));
+ int verdict_received_time;
+ LoginReputationClientResponse verdict;
+ CHECK(ParseVerdictEntry(verdict_entry, &verdict_received_time, &verdict));
+ // Since password protection content settings are keyed by origin, we only
+ // need to compare the path part of the cache_expression and the given url.
+ std::string cache_expression_path =
+ GetCacheExpressionPath(verdict.cache_expression());
+
+ // Finds the most specific match.
+ int path_depth = static_cast<int>(GetPathDepth(cache_expression_path));
+ if (path_depth > max_path_depth &&
+ PathVariantsMatchCacheExpression(paths, cache_expression_path)) {
+ max_path_depth = path_depth;
+ // If the most matching verdict is expired, set the result to
+ // VERDICT_TYPE_UNSPECIFIED.
+ most_matching_verdict =
+ IsCacheExpired(verdict_received_time, verdict.cache_duration_sec())
+ ? LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED
+ : verdict.verdict_type();
+ out_response->CopyFrom(verdict);
+ }
+ }
+ return most_matching_verdict;
+}
+
+void PasswordProtectionService::CacheVerdict(
+ const GURL& url,
+ LoginReputationClientResponse* verdict,
+ const base::Time& receive_time) {
+ DCHECK(verdict);
+ DCHECK(content_settings_);
+
+ GURL hostname = GetHostNameWithHTTPScheme(url);
+ std::unique_ptr<base::DictionaryValue> verdict_dictionary =
+ base::DictionaryValue::From(content_settings_->GetWebsiteSetting(
+ hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
+ std::string(), nullptr));
+
+ if (!verdict_dictionary.get())
+ verdict_dictionary = base::MakeUnique<base::DictionaryValue>();
+
+ std::unique_ptr<base::DictionaryValue> verdict_entry =
+ CreateDictionaryFromVerdict(verdict, receive_time);
+
+ // Increases stored verdict count if we haven't seen this cache expression
+ // before.
+ if (!verdict_dictionary->HasKey(verdict->cache_expression()))
+ stored_verdict_count_ = GetStoredVerdictCount() + 1;
+ // If same cache_expression is already in this verdict_dictionary, we simply
+ // override it.
+ verdict_dictionary->SetWithoutPathExpansion(verdict->cache_expression(),
+ std::move(verdict_entry));
+ content_settings_->SetWebsiteSettingDefaultScope(
+ hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
+ std::string(), std::move(verdict_dictionary));
+}
+
+void PasswordProtectionService::StartRequest(
+ const GURL& main_frame_url,
+ LoginReputationClientRequest::TriggerType type) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!IsPingingEnabled())
+ return;
+ std::unique_ptr<PasswordProtectionRequest> request =
+ base::MakeUnique<PasswordProtectionRequest>(
+ main_frame_url, type, IsExtendedReporting(), IsIncognito(),
+ GetWeakPtr(), GetRequestTimeoutInMS());
+ DCHECK(request);
+ request->Start();
+ requests_.insert(std::move(request));
+}
+
+void PasswordProtectionService::RequestFinished(
+ PasswordProtectionRequest* request,
+ std::unique_ptr<LoginReputationClientResponse> response) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ DCHECK(request);
+ // TODO(jialiul): We don't cache verdict for incognito mode for now.
+ // Later we may consider temporarily caching verdict.
+ if (!request->is_incognito() && response)
+ CacheVerdict(request->main_frame_url(), response.get(), base::Time::Now());
+
+ // Finished processing this request. Remove it from pending list.
+ for (auto it = requests_.begin(); it != requests_.end(); it++) {
+ if (it->get() == request) {
+ requests_.erase(it);
+ break;
+ }
+ }
+}
+
+void PasswordProtectionService::CancelPendingRequests() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ for (auto it = requests_.begin(); it != requests_.end();) {
+ // We need to advance the iterator before we cancel because canceling
+ // the request will invalidate it when RequestFinished is called.
+ PasswordProtectionRequest* request = it->get();
+ it++;
+ request->Cancel(false);
+ }
+ DCHECK(requests_.empty());
+}
+
+GURL PasswordProtectionService::GetPasswordProtectionRequestUrl() {
+ GURL url(kPasswordProtectionRequestUrl);
+ std::string api_key = google_apis::GetAPIKey();
+ DCHECK(!api_key.empty());
+ return url.Resolve("?key=" + net::EscapeQueryParamValue(api_key, true));
+}
+
+int PasswordProtectionService::GetStoredVerdictCount() {
+ DCHECK(content_settings_);
+ // If we have already computed this, return its value.
+ if (stored_verdict_count_ >= 0)
+ return stored_verdict_count_;
+
+ ContentSettingsForOneType password_protection_settings;
+ content_settings_->GetSettingsForOneType(
+ CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(),
+ &password_protection_settings);
+ stored_verdict_count_ = 0;
+ if (password_protection_settings.empty())
+ return 0;
+
+ for (const ContentSettingPatternSource& source :
+ password_protection_settings) {
+ std::unique_ptr<base::DictionaryValue> verdict_dictionary =
+ base::DictionaryValue::From(content_settings_->GetWebsiteSetting(
+ GURL(source.primary_pattern.ToString()), GURL(),
+ CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(), nullptr));
+ if (verdict_dictionary.get() && !verdict_dictionary->empty())
+ stored_verdict_count_ += static_cast<int>(verdict_dictionary->size());
+ }
+ return stored_verdict_count_;
+}
+
+int PasswordProtectionService::GetRequestTimeoutInMS() {
+ return kRequestTimeoutMs;
}
void PasswordProtectionService::OnMatchCsdWhiteListResult(
bool match_whitelist) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
UMA_HISTOGRAM_BOOLEAN(
"PasswordManager.PasswordReuse.MainFrameMatchCsdWhitelist",
match_whitelist);
}
+void PasswordProtectionService::OnURLsDeleted(
+ history::HistoryService* history_service,
+ bool all_history,
+ bool expired,
+ const history::URLRows& deleted_rows,
+ const std::set<GURL>& favicon_urls) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&PasswordProtectionService::RemoveContentSettingsOnURLsDeleted,
+ GetWeakPtr(), all_history, deleted_rows));
+}
+
+void PasswordProtectionService::HistoryServiceBeingDeleted(
+ history::HistoryService* history_service) {
+ history_service_observer_.RemoveAll();
+}
+
+void PasswordProtectionService::RemoveContentSettingsOnURLsDeleted(
+ bool all_history,
+ const history::URLRows& deleted_rows) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(content_settings_);
+
+ if (all_history) {
+ content_settings_->ClearSettingsForOneType(
+ CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION);
+ stored_verdict_count_ = 0;
+ return;
+ }
+
+ // For now, if a URL is deleted from history, we simply remove all the
+ // cached verdicts of the same origin. This is a pretty aggressive deletion.
+ // We might revisit this logic later to decide if we want to only delete the
+ // cached verdict whose cache expression matches this URL.
+ for (const history::URLRow& row : deleted_rows) {
+ if (!row.url().SchemeIsHTTPOrHTTPS())
+ continue;
+ GURL url_key = GetHostNameWithHTTPScheme(row.url());
+ std::unique_ptr<base::DictionaryValue> verdict_dictionary =
+ base::DictionaryValue::From(content_settings_->GetWebsiteSetting(
+ url_key, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
+ std::string(), nullptr));
+
+ // Move on if we have no cached verdict for this deleted history row.
+ if (!verdict_dictionary.get() || verdict_dictionary->empty())
+ continue;
+
+ int verdict_count = static_cast<int>(verdict_dictionary->size());
+ stored_verdict_count_ = GetStoredVerdictCount() - verdict_count;
+ content_settings_->ClearSettingsForOneTypeWithPredicate(
+ CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
+ base::Bind(&OriginMatchPrimaryPattern, url_key));
+ }
+}
+
+// static
+bool PasswordProtectionService::ParseVerdictEntry(
+ base::DictionaryValue* verdict_entry,
+ int* out_verdict_received_time,
+ LoginReputationClientResponse* out_verdict) {
+ base::Value* binary_value = nullptr;
+ bool result = verdict_entry && out_verdict &&
+ verdict_entry->GetInteger(kCacheCreationTime,
+ out_verdict_received_time) &&
+ verdict_entry->Get(kVerdictProto, &binary_value);
+ if (!result)
+ return false;
+ DCHECK(result);
+ DCHECK_EQ(base::Value::Type::BINARY, binary_value->type());
+ const auto blob = binary_value->GetBlob();
+ const std::string serialized_verdict_proto(blob.begin(), blob.end());
+ return out_verdict->ParseFromString(serialized_verdict_proto);
+}
+
+bool PasswordProtectionService::PathVariantsMatchCacheExpression(
+ const std::vector<std::string>& generated_paths,
+ const std::string& cache_expression_path) {
+ for (const auto& path : generated_paths) {
+ if (cache_expression_path == path)
+ return true;
+ }
+ return false;
+}
+
+bool PasswordProtectionService::IsCacheExpired(int cache_creation_time,
+ int cache_duration) {
+ // TODO(jialiul): For now, we assume client's clock is accurate or almost
+ // accurate. Need some logic to handle cases where client's clock is way
+ // off.
+ return base::Time::Now().ToDoubleT() >
+ static_cast<double>(cache_creation_time + cache_duration);
+}
+
+// Generate path variants of the given URL.
+void PasswordProtectionService::GeneratePathVariantsWithoutQuery(
+ const GURL& url,
+ std::vector<std::string>* paths) {
+ std::string canonical_path;
+ V4ProtocolManagerUtil::CanonicalizeUrl(url, nullptr, &canonical_path,
+ nullptr);
+ V4ProtocolManagerUtil::GeneratePathVariantsToCheck(canonical_path,
+ std::string(), paths);
+}
+
+// Return the path of the cache expression. e.g.:
+// "www.google.com" -> "/"
+// "www.google.com/abc" -> "/abc/"
+// "foo.com/foo/bar/" -> "/foo/bar/"
+std::string PasswordProtectionService::GetCacheExpressionPath(
+ const std::string& cache_expression) {
+ DCHECK(!cache_expression.empty());
+ std::string out_put(cache_expression);
+ // Append a trailing slash if needed.
+ if (out_put[out_put.length() - 1] != '/')
+ out_put.append("/");
+
+ size_t first_slash_pos = out_put.find_first_of("/");
+ DCHECK_NE(std::string::npos, first_slash_pos);
+ return out_put.substr(first_slash_pos);
+}
+
+// Convert a LoginReputationClientResponse proto into a DictionaryValue.
+std::unique_ptr<base::DictionaryValue>
+PasswordProtectionService::CreateDictionaryFromVerdict(
+ const LoginReputationClientResponse* verdict,
+ const base::Time& receive_time) {
+ std::unique_ptr<base::DictionaryValue> result =
+ base::MakeUnique<base::DictionaryValue>();
+ result->SetInteger(kCacheCreationTime,
+ static_cast<int>(receive_time.ToDoubleT()));
+ // Because DictionaryValue cannot take non-UTF8 string, we need to store
+ // serialized proto in its allowed binary format instead.
+ const std::string serialized_proto(verdict->SerializeAsString());
+ const std::vector<char> verdict_blob(serialized_proto.begin(),
+ serialized_proto.end());
+ std::unique_ptr<base::Value> binary_value =
+ base::MakeUnique<base::Value>(verdict_blob);
+ DCHECK_EQ(base::Value::Type::BINARY, binary_value->type());
+ result->Set(kVerdictProto, std::move(binary_value));
+ return result;
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_service.h b/chromium/components/safe_browsing/password_protection/password_protection_service.h
index 32afe41496b..d025871b422 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_service.h
+++ b/chromium/components/safe_browsing/password_protection/password_protection_service.h
@@ -5,39 +5,186 @@
#ifndef COMPONENTS_SAFE_BROWSING_PASSWORD_PROTECTION_PASSWORD_PROTECTION_SERVICE_H_
#define COMPONENTS_SAFE_BROWSING_PASSWORD_PROTECTION_PASSWORD_PROTECTION_SERVICE_H_
+#include <unordered_set>
+
+#include "base/callback.h"
+#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/scoped_observer.h"
+#include "base/values.h"
+#include "components/history/core/browser/history_service_observer.h"
+#include "components/safe_browsing/csd.pb.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace history {
+class HistoryService;
+}
class GURL;
+class HostContentSettingsMap;
namespace safe_browsing {
class SafeBrowsingDatabaseManager;
+class PasswordProtectionRequest;
-class PasswordProtectionService {
+// Manage password protection pings and verdicts. There is one instance of this
+// class per profile. Therefore, every PasswordProtectionService instance is
+// associated with a unique HistoryService instance and a unique
+// HostContentSettingsMap instance.
+class PasswordProtectionService : history::HistoryServiceObserver {
public:
- explicit PasswordProtectionService(
- const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager);
+ using CheckCsdWhitelistCallback = base::Callback<void(bool)>;
- virtual ~PasswordProtectionService();
+ PasswordProtectionService(
+ const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ history::HistoryService* history_service,
+ HostContentSettingsMap* host_content_settings_map);
- // Check if |url| matches CSD whitelist and record UMA metric accordingly.
- // Currently called by PasswordReuseDetectionManager on UI thread.
- void RecordPasswordReuse(const GURL& url);
+ ~PasswordProtectionService() override;
base::WeakPtr<PasswordProtectionService> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
+ // Checks if |url| matches CSD whitelist and record UMA metric accordingly.
+ // Currently called by PasswordReuseDetectionManager on UI thread.
+ void RecordPasswordReuse(const GURL& url);
+
+ // Looks up |settings| to find the cached verdict response. If verdict is not
+ // available or is expired, return VERDICT_TYPE_UNSPECIFIED. Can be called on
+ // any thread.
+ LoginReputationClientResponse::VerdictType GetCachedVerdict(
+ const GURL& url,
+ LoginReputationClientResponse* out_response);
+
+ // Stores |verdict| in |settings| based on |url|, |verdict| and
+ // |receive_time|.
+ void CacheVerdict(const GURL& url,
+ LoginReputationClientResponse* verdict,
+ const base::Time& receive_time);
+
+ // Creates an instance of PasswordProtectionRequest and call Start() on that
+ // instance. This function also insert this request object in |requests_| for
+ // record keeping.
+ void StartRequest(const GURL& main_frame_url,
+ LoginReputationClientRequest::TriggerType type);
+
protected:
- // Called on UI thread.
+ friend class PasswordProtectionRequest;
+
+ // Called by a PasswordProtectionRequest instance when it finishes to remove
+ // itself from |requests_|.
+ virtual void RequestFinished(
+ PasswordProtectionRequest* request,
+ std::unique_ptr<LoginReputationClientResponse> response);
+
+ // Cancels all requests in |requests_|, empties it, and releases references to
+ // the requests.
+ void CancelPendingRequests();
+
+ // Gets the total number of verdict (no matter expired or not) we cached for
+ // current active profile.
+ virtual int GetStoredVerdictCount();
+
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter() {
+ return request_context_getter_;
+ }
+
+ // Returns the URL where PasswordProtectionRequest instances send requests.
+ static GURL GetPasswordProtectionRequestUrl();
+
+ // Gets the request timeout in milliseconds.
+ static int GetRequestTimeoutInMS();
+
+ // Obtains referrer chain of |event_url| and |event_tab_id| and adds this
+ // info into |frame|.
+ virtual void FillReferrerChain(
+ const GURL& event_url,
+ int event_tab_id, // -1 if tab id is not available.
+ LoginReputationClientRequest::Frame* frame) = 0;
+
+ virtual bool IsExtendedReporting() = 0;
+ virtual bool IsIncognito() = 0;
+
+ // If we can send ping to Safe Browsing backend.
+ virtual bool IsPingingEnabled() = 0;
+
+ void CheckCsdWhitelistOnIOThread(const GURL& url,
+ const CheckCsdWhitelistCallback& callback);
+
// Increases "PasswordManager.PasswordReuse.MainFrameMatchCsdWhitelist" UMA
// metric based on input.
void OnMatchCsdWhiteListResult(bool match_whitelist);
private:
+ friend class PasswordProtectionServiceTest;
+ FRIEND_TEST_ALL_PREFIXES(PasswordProtectionServiceTest,
+ TestParseInvalidVerdictEntry);
+ FRIEND_TEST_ALL_PREFIXES(PasswordProtectionServiceTest,
+ TestParseValidVerdictEntry);
+ FRIEND_TEST_ALL_PREFIXES(PasswordProtectionServiceTest,
+ TestPathVariantsMatchCacheExpression);
+ FRIEND_TEST_ALL_PREFIXES(PasswordProtectionServiceTest,
+ TestCleanUpCachedVerdicts);
+
+ // Overridden from history::HistoryServiceObserver.
+ void OnURLsDeleted(history::HistoryService* history_service,
+ bool all_history,
+ bool expired,
+ const history::URLRows& deleted_rows,
+ const std::set<GURL>& favicon_urls) override;
+
+ void HistoryServiceBeingDeleted(
+ history::HistoryService* history_service) override;
+
+ // Posted to UI thread by OnURLsDeleted(..). This function cleans up password
+ // protection content settings related to deleted URLs.
+ void RemoveContentSettingsOnURLsDeleted(bool all_history,
+ const history::URLRows& deleted_rows);
+
+ static bool ParseVerdictEntry(base::DictionaryValue* verdict_entry,
+ int* out_verdict_received_time,
+ LoginReputationClientResponse* out_verdict);
+
+ static bool PathVariantsMatchCacheExpression(
+ const std::vector<std::string>& generated_paths,
+ const std::string& cache_expression_path);
+
+ static bool IsCacheExpired(int cache_creation_time, int cache_duration);
+
+ static void GeneratePathVariantsWithoutQuery(const GURL& url,
+ std::vector<std::string>* paths);
+
+ static std::string GetCacheExpressionPath(
+ const std::string& cache_expression);
+
+ static std::unique_ptr<base::DictionaryValue> CreateDictionaryFromVerdict(
+ const LoginReputationClientResponse* verdict,
+ const base::Time& receive_time);
+
+ // Number of verdict stored for this profile.
+ int stored_verdict_count_;
+
scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
+
+ // The context we use to issue network requests. This request_context_getter
+ // is obtained from SafeBrowsingService so that we can use the Safe Browsing
+ // cookie store.
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+
+ // Set of pending PasswordProtectionRequests.
+ std::unordered_set<std::unique_ptr<PasswordProtectionRequest>> requests_;
+
+ ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
+ history_service_observer_;
+
+ // Content settings map associated with this instance.
+ HostContentSettingsMap* content_settings_;
+
base::WeakPtrFactory<PasswordProtectionService> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PasswordProtectionService);
};
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc
index 4901dc6ce2c..e792f617c78 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -5,9 +5,15 @@
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
#include "base/test/histogram_tester.h"
+#include "base/test/null_task_runner.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/safe_browsing/password_protection/password_protection_request.h"
#include "components/safe_browsing_db/test_database_manager.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/url_request/test_url_fetcher_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -17,6 +23,8 @@ const char kPasswordReuseMatchWhitelistHistogramName[] =
"PasswordManager.PasswordReuse.MainFrameMatchCsdWhitelist";
const char kWhitelistedUrl[] = "http://inwhitelist.com";
const char kNoneWhitelistedUrl[] = "http://notinwhitelist.com";
+const char kRequestOutcomeHistogramName[] = "PasswordProtection.RequestOutcome";
+const char kTargetUrl[] = "http://foo.com";
} // namespace
@@ -35,14 +43,136 @@ class MockSafeBrowsingDatabaseManager : public TestSafeBrowsingDatabaseManager {
DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager);
};
+class DummyURLRequestContextGetter : public net::URLRequestContextGetter {
+ public:
+ DummyURLRequestContextGetter()
+ : dummy_task_runner_(new base::NullTaskRunner) {}
+
+ net::URLRequestContext* GetURLRequestContext() override { return nullptr; }
+
+ scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
+ const override {
+ return dummy_task_runner_;
+ }
+
+ private:
+ ~DummyURLRequestContextGetter() override {}
+
+ scoped_refptr<base::SingleThreadTaskRunner> dummy_task_runner_;
+};
+
+class TestPasswordProtectionService : public PasswordProtectionService {
+ public:
+ TestPasswordProtectionService(
+ const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ scoped_refptr<HostContentSettingsMap> content_setting_map)
+ : PasswordProtectionService(database_manager,
+ request_context_getter,
+ nullptr,
+ content_setting_map.get()),
+ is_extended_reporting_(true),
+ is_incognito_(false) {}
+
+ void RequestFinished(
+ PasswordProtectionRequest* request,
+ std::unique_ptr<LoginReputationClientResponse> response) override {
+ latest_response_ = std::move(response);
+ }
+
+ // Intentionally do nothing.
+ void FillReferrerChain(const GURL& event_url,
+ int event_tab_id,
+ LoginReputationClientRequest::Frame* frame) override {}
+
+ bool IsExtendedReporting() override { return is_extended_reporting_; }
+
+ bool IsIncognito() override { return is_incognito_; }
+
+ void set_extended_reporting(bool enabled) {
+ is_extended_reporting_ = enabled;
+ }
+
+ void set_incognito(bool enabled) { is_incognito_ = enabled; }
+
+ bool IsPingingEnabled() override { return true; }
+
+ LoginReputationClientResponse* latest_response() {
+ return latest_response_.get();
+ }
+
+ private:
+ bool is_extended_reporting_;
+ bool is_incognito_;
+ std::unique_ptr<LoginReputationClientResponse> latest_response_;
+ DISALLOW_COPY_AND_ASSIGN(TestPasswordProtectionService);
+};
+
class PasswordProtectionServiceTest : public testing::Test {
public:
PasswordProtectionServiceTest(){};
+ LoginReputationClientResponse CreateVerdictProto(
+ LoginReputationClientResponse::VerdictType verdict,
+ int cache_duration_sec,
+ const std::string& cache_expression) {
+ LoginReputationClientResponse verdict_proto;
+ verdict_proto.set_verdict_type(verdict);
+ verdict_proto.set_cache_duration_sec(cache_duration_sec);
+ verdict_proto.set_cache_expression(cache_expression);
+ return verdict_proto;
+ }
+
void SetUp() override {
+ HostContentSettingsMap::RegisterProfilePrefs(test_pref_service_.registry());
+ content_setting_map_ = new HostContentSettingsMap(
+ &test_pref_service_, false /* incognito */, false /* guest_profile */);
database_manager_ = new MockSafeBrowsingDatabaseManager();
+ dummy_request_context_getter_ = new DummyURLRequestContextGetter();
password_protection_service_ =
- base::MakeUnique<PasswordProtectionService>(database_manager_);
+ base::MakeUnique<TestPasswordProtectionService>(
+ database_manager_, dummy_request_context_getter_,
+ content_setting_map_);
+ }
+
+ void TearDown() override { content_setting_map_->ShutdownOnUIThread(); }
+
+ // Sets up |database_manager_| and |requests_| as needed.
+ void InitializeAndStartRequest(bool match_whitelist, int timeout_in_ms) {
+ GURL target_url(kTargetUrl);
+ EXPECT_CALL(*database_manager_.get(), MatchCsdWhitelistUrl(target_url))
+ .WillRepeatedly(testing::Return(match_whitelist));
+
+ request_ = base::MakeUnique<PasswordProtectionRequest>(
+ target_url, LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
+ password_protection_service_->IsExtendedReporting(),
+ password_protection_service_->IsIncognito(),
+ password_protection_service_->GetWeakPtr(), timeout_in_ms);
+ request_->Start();
+ }
+
+ bool PathVariantsMatchCacheExpression(const GURL& url,
+ const std::string& cache_expression) {
+ std::vector<std::string> paths;
+ PasswordProtectionService::GeneratePathVariantsWithoutQuery(url, &paths);
+ return PasswordProtectionService::PathVariantsMatchCacheExpression(
+ paths,
+ PasswordProtectionService::GetCacheExpressionPath(cache_expression));
+ }
+
+ void CacheVerdict(const GURL& url,
+ LoginReputationClientResponse::VerdictType verdict,
+ int cache_duration_sec,
+ const std::string& cache_expression,
+ const base::Time& verdict_received_time) {
+ LoginReputationClientResponse response(
+ CreateVerdictProto(verdict, cache_duration_sec, cache_expression));
+ password_protection_service_->CacheVerdict(url, &response,
+ verdict_received_time);
+ }
+
+ size_t GetStoredVerdictCount() {
+ return password_protection_service_->GetStoredVerdictCount();
}
protected:
@@ -50,7 +180,12 @@ class PasswordProtectionServiceTest : public testing::Test {
// threads.
content::TestBrowserThreadBundle thread_bundle_;
scoped_refptr<MockSafeBrowsingDatabaseManager> database_manager_;
- std::unique_ptr<PasswordProtectionService> password_protection_service_;
+ sync_preferences::TestingPrefServiceSyncable test_pref_service_;
+ scoped_refptr<HostContentSettingsMap> content_setting_map_;
+ scoped_refptr<DummyURLRequestContextGetter> dummy_request_context_getter_;
+ std::unique_ptr<TestPasswordProtectionService> password_protection_service_;
+ std::unique_ptr<PasswordProtectionRequest> request_;
+ base::HistogramTester histograms_;
};
TEST_F(PasswordProtectionServiceTest,
@@ -62,27 +197,336 @@ TEST_F(PasswordProtectionServiceTest,
EXPECT_CALL(*database_manager_.get(),
MatchCsdWhitelistUrl(not_whitelisted_url))
.WillOnce(testing::Return(false));
- base::HistogramTester histograms;
- histograms.ExpectTotalCount(kPasswordReuseMatchWhitelistHistogramName, 0);
+ histograms_.ExpectTotalCount(kPasswordReuseMatchWhitelistHistogramName, 0);
// Empty url should not increment metric.
password_protection_service_->RecordPasswordReuse(GURL());
base::RunLoop().RunUntilIdle();
- histograms.ExpectTotalCount(kPasswordReuseMatchWhitelistHistogramName, 0);
+ histograms_.ExpectTotalCount(kPasswordReuseMatchWhitelistHistogramName, 0);
// Whitelisted url should increase "True" bucket by 1.
password_protection_service_->RecordPasswordReuse(whitelisted_url);
base::RunLoop().RunUntilIdle();
EXPECT_THAT(
- histograms.GetAllSamples(kPasswordReuseMatchWhitelistHistogramName),
+ histograms_.GetAllSamples(kPasswordReuseMatchWhitelistHistogramName),
testing::ElementsAre(base::Bucket(1, 1)));
// Non-whitelisted url should increase "False" bucket by 1.
password_protection_service_->RecordPasswordReuse(not_whitelisted_url);
base::RunLoop().RunUntilIdle();
EXPECT_THAT(
- histograms.GetAllSamples(kPasswordReuseMatchWhitelistHistogramName),
+ histograms_.GetAllSamples(kPasswordReuseMatchWhitelistHistogramName),
testing::ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1)));
}
+TEST_F(PasswordProtectionServiceTest, TestParseInvalidVerdictEntry) {
+ std::unique_ptr<base::DictionaryValue> invalid_verdict_entry =
+ base::MakeUnique<base::DictionaryValue>();
+ invalid_verdict_entry->SetString("cache_creation_time", "invalid_time");
+
+ int cache_creation_time;
+ LoginReputationClientResponse response;
+ // ParseVerdictEntry fails if input is empty.
+ EXPECT_FALSE(PasswordProtectionService::ParseVerdictEntry(
+ nullptr, &cache_creation_time, &response));
+
+ // ParseVerdictEntry fails if the input dict value is invalid.
+ EXPECT_FALSE(PasswordProtectionService::ParseVerdictEntry(
+ invalid_verdict_entry.get(), &cache_creation_time, &response));
+}
+
+TEST_F(PasswordProtectionServiceTest, TestParseValidVerdictEntry) {
+ base::Time expected_creation_time = base::Time::Now();
+ LoginReputationClientResponse expected_verdict(CreateVerdictProto(
+ LoginReputationClientResponse::SAFE, 10 * 60, "test.com/foo"));
+ std::unique_ptr<base::DictionaryValue> valid_verdict_entry =
+ PasswordProtectionService::CreateDictionaryFromVerdict(
+ &expected_verdict, expected_creation_time);
+
+ int actual_cache_creation_time;
+ LoginReputationClientResponse actual_verdict;
+ ASSERT_TRUE(PasswordProtectionService::ParseVerdictEntry(
+ valid_verdict_entry.get(), &actual_cache_creation_time, &actual_verdict));
+
+ EXPECT_EQ(static_cast<int>(expected_creation_time.ToDoubleT()),
+ actual_cache_creation_time);
+ EXPECT_EQ(expected_verdict.cache_duration_sec(),
+ actual_verdict.cache_duration_sec());
+ EXPECT_EQ(expected_verdict.verdict_type(), actual_verdict.verdict_type());
+ EXPECT_EQ(expected_verdict.cache_expression(),
+ actual_verdict.cache_expression());
+}
+
+TEST_F(PasswordProtectionServiceTest, TestPathVariantsMatchCacheExpression) {
+ // Cache expression without path.
+ std::string cache_expression("google.com");
+ std::string cache_expression_with_slash("google.com/");
+ EXPECT_TRUE(PathVariantsMatchCacheExpression(GURL("https://www.google.com"),
+ cache_expression));
+ EXPECT_TRUE(PathVariantsMatchCacheExpression(GURL("https://www.google.com"),
+ cache_expression_with_slash));
+ EXPECT_TRUE(PathVariantsMatchCacheExpression(GURL("https://www.google.com/"),
+ cache_expression));
+ EXPECT_TRUE(PathVariantsMatchCacheExpression(GURL("https://www.google.com/"),
+ cache_expression_with_slash));
+ EXPECT_TRUE(PathVariantsMatchCacheExpression(
+ GURL("https://www.google.com/maps/local/"), cache_expression));
+ EXPECT_TRUE(PathVariantsMatchCacheExpression(
+ GURL("https://www.google.com/maps/local/"), cache_expression_with_slash));
+
+ // Cache expression with path.
+ cache_expression = "evil.com/bad";
+ cache_expression_with_slash = "evil.com/bad/";
+ EXPECT_TRUE(PathVariantsMatchCacheExpression(GURL("http://evil.com/bad/"),
+ cache_expression));
+ EXPECT_TRUE(PathVariantsMatchCacheExpression(GURL("http://evil.com/bad/"),
+ cache_expression_with_slash));
+ EXPECT_TRUE(PathVariantsMatchCacheExpression(
+ GURL("http://evil.com/bad/index.html"), cache_expression));
+ EXPECT_TRUE(PathVariantsMatchCacheExpression(
+ GURL("http://evil.com/bad/index.html"), cache_expression_with_slash));
+ EXPECT_TRUE(PathVariantsMatchCacheExpression(
+ GURL("http://evil.com/bad/foo/index.html"), cache_expression));
+ EXPECT_TRUE(PathVariantsMatchCacheExpression(
+ GURL("http://evil.com/bad/foo/index.html"), cache_expression_with_slash));
+ EXPECT_FALSE(PathVariantsMatchCacheExpression(
+ GURL("http://evil.com/worse/index.html"), cache_expression));
+ EXPECT_FALSE(PathVariantsMatchCacheExpression(
+ GURL("http://evil.com/worse/index.html"), cache_expression_with_slash));
+}
+
+TEST_F(PasswordProtectionServiceTest, TestCachedVerdicts) {
+ ASSERT_EQ(0U, GetStoredVerdictCount());
+ // Assume each verdict has a TTL of 10 minutes.
+ // Cache a verdict for http://www.test.com/foo/index.html
+ CacheVerdict(GURL("http://www.test.com/foo/index.html"),
+ LoginReputationClientResponse::SAFE, 10 * 60, "test.com/foo",
+ base::Time::Now());
+
+ EXPECT_EQ(1U, GetStoredVerdictCount());
+
+ // Cache another verdict with the some origin and cache_expression should
+ // override the cache.
+ CacheVerdict(GURL("http://www.test.com/foo/index2.html"),
+ LoginReputationClientResponse::PHISHING, 10 * 60, "test.com/foo",
+ base::Time::Now());
+ EXPECT_EQ(1U, GetStoredVerdictCount());
+ LoginReputationClientResponse out_verdict;
+ EXPECT_EQ(LoginReputationClientResponse::PHISHING,
+ password_protection_service_->GetCachedVerdict(
+ GURL("http://www.test.com/foo/index2.html"), &out_verdict));
+
+ // Cache another verdict with the same origin but different cache_expression
+ // will not increase setting count, but will increase the number of verdicts
+ // in the given origin.
+ CacheVerdict(GURL("http://www.test.com/bar/index2.html"),
+ LoginReputationClientResponse::SAFE, 10 * 60, "test.com/bar",
+ base::Time::Now());
+ EXPECT_EQ(2U, GetStoredVerdictCount());
+}
+
+TEST_F(PasswordProtectionServiceTest, TestGetCachedVerdicts) {
+ ASSERT_EQ(0U, GetStoredVerdictCount());
+ // Prepare 2 verdicts of the same origin with different cache expressions,
+ // one is expired, the other is not.
+ base::Time now = base::Time::Now();
+ CacheVerdict(GURL("http://test.com/login.html"),
+ LoginReputationClientResponse::SAFE, 10 * 60, "test.com", now);
+ CacheVerdict(
+ GURL("http://test.com/def/index.jsp"),
+ LoginReputationClientResponse::PHISHING, 10 * 60, "test.com/def",
+ base::Time::FromDoubleT(now.ToDoubleT() -
+ 24.0 * 60.0 * 60.0)); // Yesterday, expired.
+ ASSERT_EQ(2U, GetStoredVerdictCount());
+
+ // Return VERDICT_TYPE_UNSPECIFIED if look up for a URL with unknown origin.
+ LoginReputationClientResponse actual_verdict;
+ EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
+ password_protection_service_->GetCachedVerdict(
+ GURL("http://www.unknown.com/"), &actual_verdict));
+
+ // Return SAFE if look up for a URL that matches "test.com" cache expression.
+ EXPECT_EQ(LoginReputationClientResponse::SAFE,
+ password_protection_service_->GetCachedVerdict(
+ GURL("http://test.com/xyz/foo.jsp"), &actual_verdict));
+
+ // Return VERDICT_TYPE_UNSPECIFIED if look up for a URL whose variants match
+ // test.com/def, but the corresponding verdict is expired.
+ EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
+ password_protection_service_->GetCachedVerdict(
+ GURL("http://test.com/def/ghi/index.html"), &actual_verdict));
+}
+
+TEST_F(PasswordProtectionServiceTest, TestCleanUpCachedVerdicts) {
+ ASSERT_EQ(0U, GetStoredVerdictCount());
+ // Prepare 2 verdicts. One is for origin "http://foo.com", and the other is
+ // for "http://bar.com".
+ base::Time now = base::Time::Now();
+ CacheVerdict(GURL("http://foo.com/abc/index.jsp"),
+ LoginReputationClientResponse::LOW_REPUTATION, 10 * 60,
+ "foo.com/abc", now);
+ CacheVerdict(GURL("http://bar.com/index.jsp"),
+ LoginReputationClientResponse::PHISHING, 10 * 60, "bar.com",
+ now);
+ ASSERT_EQ(2U, GetStoredVerdictCount());
+
+ // Delete a bar.com URL. Corresponding content setting keyed on
+ // origin "http://bar.com" should be removed,
+ history::URLRows deleted_urls;
+ deleted_urls.push_back(history::URLRow(GURL("http://bar.com")));
+
+ // Delete an arbitrary data URL, to ensure the service is robust against
+ // filtering only http/s URLs. See crbug.com/709758.
+ deleted_urls.push_back(history::URLRow(GURL("data:text/html, <p>hellow")));
+
+ password_protection_service_->RemoveContentSettingsOnURLsDeleted(
+ false /* all_history */, deleted_urls);
+ EXPECT_EQ(1U, GetStoredVerdictCount());
+ LoginReputationClientResponse actual_verdict;
+ EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
+ password_protection_service_->GetCachedVerdict(
+ GURL("http://bar.com"), &actual_verdict));
+
+ // If delete all history. All password protection content settings should be
+ // gone.
+ password_protection_service_->RemoveContentSettingsOnURLsDeleted(
+ true /* all_history */, history::URLRows());
+ EXPECT_EQ(0U, GetStoredVerdictCount());
+}
+
+TEST_F(PasswordProtectionServiceTest, TestNoRequestSentForIncognito) {
+ histograms_.ExpectTotalCount(kRequestOutcomeHistogramName, 0);
+ password_protection_service_->set_incognito(true);
+ password_protection_service_->StartRequest(
+ GURL(kTargetUrl), LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(nullptr, password_protection_service_->latest_response());
+ EXPECT_THAT(histograms_.GetAllSamples(kRequestOutcomeHistogramName),
+ testing::ElementsAre(base::Bucket(7 /* INCOGNITO */, 1)));
+}
+
+TEST_F(PasswordProtectionServiceTest,
+ TestNoRequestSentForNonExtendedReporting) {
+ histograms_.ExpectTotalCount(kRequestOutcomeHistogramName, 0);
+ password_protection_service_->set_extended_reporting(false);
+ password_protection_service_->StartRequest(
+ GURL(kTargetUrl), LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(nullptr, password_protection_service_->latest_response());
+ EXPECT_THAT(
+ histograms_.GetAllSamples(kRequestOutcomeHistogramName),
+ testing::ElementsAre(base::Bucket(6 /* NO_EXTENDED_REPORTING */, 1)));
+}
+
+TEST_F(PasswordProtectionServiceTest, TestNoRequestSentForWhitelistedURL) {
+ histograms_.ExpectTotalCount(kRequestOutcomeHistogramName, 0);
+ InitializeAndStartRequest(true /* match whitelist */,
+ 10000 /* timeout in ms*/);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(nullptr, password_protection_service_->latest_response());
+ EXPECT_THAT(histograms_.GetAllSamples(kRequestOutcomeHistogramName),
+ testing::ElementsAre(base::Bucket(4 /* MATCHED_WHITELIST */, 1)));
+}
+
+TEST_F(PasswordProtectionServiceTest, TestNoRequestSentIfVerdictAlreadyCached) {
+ histograms_.ExpectTotalCount(kRequestOutcomeHistogramName, 0);
+ CacheVerdict(GURL(kTargetUrl), LoginReputationClientResponse::LOW_REPUTATION,
+ 600, GURL(kTargetUrl).host(), base::Time::Now());
+ InitializeAndStartRequest(false /* match whitelist */,
+ 10000 /* timeout in ms*/);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_THAT(
+ histograms_.GetAllSamples(kRequestOutcomeHistogramName),
+ testing::ElementsAre(base::Bucket(5 /* RESPONSE_ALREADY_CACHED */, 1)));
+ EXPECT_EQ(LoginReputationClientResponse::LOW_REPUTATION,
+ password_protection_service_->latest_response()->verdict_type());
+}
+
+TEST_F(PasswordProtectionServiceTest, TestResponseFetchFailed) {
+ histograms_.ExpectTotalCount(kRequestOutcomeHistogramName, 0);
+ net::TestURLFetcher failed_fetcher(0, GURL("http://bar.com"), nullptr);
+ // Set up failed response.
+ failed_fetcher.set_status(
+ net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED));
+
+ InitializeAndStartRequest(false /* match whitelist */,
+ 10000 /* timeout in ms*/);
+ request_->OnURLFetchComplete(&failed_fetcher);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(nullptr, password_protection_service_->latest_response());
+ EXPECT_THAT(histograms_.GetAllSamples(kRequestOutcomeHistogramName),
+ testing::ElementsAre(base::Bucket(9 /* FETCH_FAILED */, 1)));
+}
+
+TEST_F(PasswordProtectionServiceTest, TestMalformedResponse) {
+ histograms_.ExpectTotalCount(kRequestOutcomeHistogramName, 0);
+ // Set up malformed response.
+ net::TestURLFetcher fetcher(0, GURL("http://bar.com"), nullptr);
+ fetcher.set_status(
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
+ fetcher.set_response_code(200);
+ fetcher.SetResponseString("invalid response");
+
+ InitializeAndStartRequest(false /* match whitelist */,
+ 10000 /* timeout in ms*/);
+ request_->OnURLFetchComplete(&fetcher);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(nullptr, password_protection_service_->latest_response());
+ EXPECT_THAT(
+ histograms_.GetAllSamples(kRequestOutcomeHistogramName),
+ testing::ElementsAre(base::Bucket(10 /* RESPONSE_MALFORMED */, 1)));
+}
+
+TEST_F(PasswordProtectionServiceTest, TestRequestTimedout) {
+ histograms_.ExpectTotalCount(kRequestOutcomeHistogramName, 0);
+ InitializeAndStartRequest(false /* match whitelist */,
+ 0 /* timeout immediately */);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(nullptr, password_protection_service_->latest_response());
+ EXPECT_THAT(histograms_.GetAllSamples(kRequestOutcomeHistogramName),
+ testing::ElementsAre(base::Bucket(3 /* TIMEDOUT */, 1)));
+}
+
+TEST_F(PasswordProtectionServiceTest, TestRequestAndResponseSuccessfull) {
+ histograms_.ExpectTotalCount(kRequestOutcomeHistogramName, 0);
+ // Set up valid response.
+ net::TestURLFetcher fetcher(0, GURL("http://bar.com"), nullptr);
+ fetcher.set_status(
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
+ fetcher.set_response_code(200);
+ LoginReputationClientResponse expected_response = CreateVerdictProto(
+ LoginReputationClientResponse::PHISHING, 600, GURL(kTargetUrl).host());
+ fetcher.SetResponseString(expected_response.SerializeAsString());
+
+ InitializeAndStartRequest(false /* match whitelist */,
+ 10000 /* timeout in ms*/);
+ request_->OnURLFetchComplete(&fetcher);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_THAT(histograms_.GetAllSamples(kRequestOutcomeHistogramName),
+ testing::ElementsAre(base::Bucket(1 /* SUCCEEDED */, 1)));
+ LoginReputationClientResponse* actual_response =
+ password_protection_service_->latest_response();
+ EXPECT_EQ(expected_response.verdict_type(), actual_response->verdict_type());
+ EXPECT_EQ(expected_response.cache_expression(),
+ actual_response->cache_expression());
+ EXPECT_EQ(expected_response.cache_duration_sec(),
+ actual_response->cache_duration_sec());
+}
+
+TEST_F(PasswordProtectionServiceTest, TestTearDownWithPendingRequests) {
+ histograms_.ExpectTotalCount(kRequestOutcomeHistogramName, 0);
+ GURL target_url(kTargetUrl);
+ EXPECT_CALL(*database_manager_.get(), MatchCsdWhitelistUrl(target_url))
+ .WillRepeatedly(testing::Return(false));
+ password_protection_service_->StartRequest(
+ target_url, LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE);
+
+ // Destroy password_protection_service_ while there is one request pending.
+ password_protection_service_.reset();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_THAT(histograms_.GetAllSamples(kRequestOutcomeHistogramName),
+ testing::ElementsAre(base::Bucket(2 /* CANCELED */, 1)));
+}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/renderer/BUILD.gn b/chromium/components/safe_browsing/renderer/BUILD.gn
new file mode 100644
index 00000000000..03dbfe67f5b
--- /dev/null
+++ b/chromium/components/safe_browsing/renderer/BUILD.gn
@@ -0,0 +1,22 @@
+# 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("//build/config/features.gni")
+
+source_set("renderer") {
+ if (safe_browsing_mode != 0) {
+ sources = [
+ "threat_dom_details.cc",
+ "threat_dom_details.h",
+ ]
+ deps = [
+ "//base",
+ "//components/safe_browsing/common:common",
+ "//content/public/renderer",
+ "//ipc",
+ "//third_party/WebKit/public:blink",
+ "//url/ipc:url_ipc",
+ ]
+ }
+}
diff --git a/chromium/components/safe_browsing/renderer/DEPS b/chromium/components/safe_browsing/renderer/DEPS
new file mode 100644
index 00000000000..04ab6a902c4
--- /dev/null
+++ b/chromium/components/safe_browsing/renderer/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+content/public/renderer",
+ "+third_party/WebKit/public/platform",
+ "+third_party/WebKit/public/web",
+] \ No newline at end of file
diff --git a/chromium/components/safe_browsing/renderer/threat_dom_details.cc b/chromium/components/safe_browsing/renderer/threat_dom_details.cc
new file mode 100644
index 00000000000..b790b965ff2
--- /dev/null
+++ b/chromium/components/safe_browsing/renderer/threat_dom_details.cc
@@ -0,0 +1,307 @@
+// 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/safe_browsing/renderer/threat_dom_details.h"
+
+#include <algorithm>
+#include <map>
+#include <unordered_set>
+
+#include "base/compiler_specific.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "components/safe_browsing/common/safebrowsing_messages.h"
+#include "components/safe_browsing/common/safebrowsing_types.h"
+#include "content/public/renderer/render_frame.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebElementCollection.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+
+namespace safe_browsing {
+
+// A map for keeping track of the identity of DOM Elements, used to generate
+// unique IDs for each element and lookup elements IDs by parent Element, to
+// maintain proper parent/child relationships.
+// They key is a WebNode from the DOM, which is basically a pointer so can be
+// copied into the map when inserting new elements.
+// The values are indices into the resource vector, and are used to retrieve IPC
+// messages generated by ThreatDOMDetails.
+using ElementToNodeMap = std::map<blink::WebNode, size_t>;
+
+// This Feature specifies which non-resource HTML Elements to collect based on
+// their tag and attributes. It's a single param containing a comma-separated
+// list of pairs. For example: "tag1,id,tag1,height,tag2,foo" - this will
+// collect elements with tag "tag1" that have attribute "id" or "height" set,
+// and elements of tag "tag2" if they have attribute "foo" set. All tag names
+// and attributes should be lower case.
+const base::Feature kThreatDomDetailsTagAndAttributeFeature{
+ "ThreatDomDetailsTagAttributes", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// The name of the param containing the tags and attributes list.
+const char kTagAndAttributeParamName[] = "tag_attribute_csv";
+
+namespace {
+
+// Predicate used to search |tag_and_attributes_list_| by tag_name.
+class TagNameIs {
+ public:
+ explicit TagNameIs(const std::string& tag) : tag_(tag) {}
+ bool operator()(const TagAndAttributesItem& tag_and_attribute) {
+ return tag_ == tag_and_attribute.tag_name;
+ }
+
+ private:
+ std::string tag_;
+};
+
+void ParseTagAndAttributeParams(
+ std::vector<TagAndAttributesItem>* tag_and_attributes_list) {
+ DCHECK(tag_and_attributes_list);
+ if (!base::FeatureList::IsEnabled(kThreatDomDetailsTagAndAttributeFeature)) {
+ return;
+ }
+ tag_and_attributes_list->clear();
+ const std::string& tag_attribute_csv_param =
+ base::GetFieldTrialParamValueByFeature(
+ kThreatDomDetailsTagAndAttributeFeature, kTagAndAttributeParamName);
+ if (tag_attribute_csv_param.empty()) {
+ return;
+ }
+
+ std::vector<std::string> split =
+ base::SplitString(tag_attribute_csv_param, ",", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+ // If we don't have the right number of pairs in the csv then don't bother
+ // parsing further.
+ if (split.size() % 2 != 0) {
+ return;
+ }
+ for (size_t i = 0; i < split.size(); i += 2) {
+ const std::string& tag_name = split[i];
+ const std::string& attribute = split[i + 1];
+ auto item_iter =
+ std::find_if(tag_and_attributes_list->begin(),
+ tag_and_attributes_list->end(), TagNameIs(tag_name));
+ if (item_iter == tag_and_attributes_list->end()) {
+ TagAndAttributesItem item;
+ item.tag_name = tag_name;
+ item.attributes.push_back(attribute);
+ tag_and_attributes_list->push_back(item);
+ } else {
+ item_iter->attributes.push_back(attribute);
+ }
+ }
+
+ std::sort(tag_and_attributes_list->begin(), tag_and_attributes_list->end(),
+ [](const TagAndAttributesItem& a, const TagAndAttributesItem& b) {
+ return a.tag_name < b.tag_name;
+ });
+}
+
+SafeBrowsingHostMsg_ThreatDOMDetails_Node* GetNodeForElement(
+ const blink::WebNode& element,
+ const safe_browsing::ElementToNodeMap& element_to_node_map,
+ std::vector<SafeBrowsingHostMsg_ThreatDOMDetails_Node>* resources) {
+ DCHECK(element_to_node_map.count(element) > 0);
+ size_t resource_index = element_to_node_map.at(element);
+ return &(resources->at(resource_index));
+}
+
+std::string TruncateAttributeString(const std::string& input) {
+ if (input.length() <= ThreatDOMDetails::kMaxAttributeStringLength) {
+ return input;
+ }
+
+ std::string truncated;
+ base::TruncateUTF8ToByteSize(
+ input, ThreatDOMDetails::kMaxAttributeStringLength - 3, &truncated);
+ truncated.append("...");
+ return truncated;
+}
+
+// Handler for the various HTML elements that we extract URLs from.
+void HandleElement(
+ const blink::WebElement& element,
+ const std::vector<TagAndAttributesItem>& tag_and_attributes_list,
+ SafeBrowsingHostMsg_ThreatDOMDetails_Node* summary_node,
+ std::vector<SafeBrowsingHostMsg_ThreatDOMDetails_Node>* resources,
+ safe_browsing::ElementToNodeMap* element_to_node_map) {
+ // Retrieve the link and resolve the link in case it's relative.
+ blink::WebURL full_url =
+ element.GetDocument().CompleteURL(element.GetAttribute("src"));
+
+ const GURL& child_url = GURL(full_url);
+ if (!child_url.is_empty() && child_url.is_valid()) {
+ summary_node->children.push_back(child_url);
+ }
+
+ SafeBrowsingHostMsg_ThreatDOMDetails_Node child_node;
+ child_node.url = child_url;
+ child_node.tag_name = element.TagName().Utf8();
+ child_node.parent = summary_node->url;
+
+ // Populate the element's attributes, but only collect the ones that are
+ // configured in the finch study.
+ const auto& tag_attribute_iter = std::find_if(
+ tag_and_attributes_list.begin(), tag_and_attributes_list.end(),
+ TagNameIs(base::ToLowerASCII(child_node.tag_name)));
+ if (tag_attribute_iter != tag_and_attributes_list.end()) {
+ const std::vector<std::string> attributes_to_collect =
+ tag_attribute_iter->attributes;
+ for (const std::string& attribute : attributes_to_collect) {
+ blink::WebString attr_webstring = blink::WebString::FromASCII(attribute);
+ if (!element.HasAttribute(attr_webstring)) {
+ continue;
+ }
+ child_node.attributes.push_back(std::make_pair(
+ attribute, TruncateAttributeString(
+ element.GetAttribute(attr_webstring).Ascii())));
+ if (child_node.attributes.size() == ThreatDOMDetails::kMaxAttributes) {
+ break;
+ }
+ }
+ }
+
+ // Update the ID mapping. First generate the ID for the current node.
+ // Then, if its parent is available, set the current node's parent ID, and
+ // also update the parent's children with the current node's ID.
+ const int child_id = static_cast<int>(element_to_node_map->size()) + 1;
+ child_node.node_id = child_id;
+ blink::WebNode cur_parent_element = element.ParentNode();
+ while (!cur_parent_element.IsNull()) {
+ if (element_to_node_map->count(cur_parent_element) > 0) {
+ SafeBrowsingHostMsg_ThreatDOMDetails_Node* parent_node =
+ GetNodeForElement(cur_parent_element, *element_to_node_map,
+ resources);
+ child_node.parent_node_id = parent_node->node_id;
+ parent_node->child_node_ids.push_back(child_id);
+
+ // TODO(lpz): Consider also updating the URL-level parent/child mapping
+ // here. Eg: child_node.parent=parent_node.url, and
+ // parent_node.children.push_back(child_url).
+ break;
+ } else {
+ // It's possible that the direct parent of this node wasn't handled, so it
+ // isn't represented in |element_to_node_map|. Try walking up the
+ // hierarchy to see if a parent further up was handled.
+ cur_parent_element = cur_parent_element.ParentNode();
+ }
+ }
+ // Add the child node to the list of resources.
+ resources->push_back(child_node);
+ // .. and remember which index it was inserted at so we can look it up later.
+ (*element_to_node_map)[element] = resources->size() - 1;
+}
+
+bool ShouldHandleElement(
+ const blink::WebElement& element,
+ const std::vector<TagAndAttributesItem>& tag_and_attributes_list) {
+ // Resources with a SRC are always handled.
+ if ((element.HasHTMLTagName("iframe") || element.HasHTMLTagName("frame") ||
+ element.HasHTMLTagName("embed") || element.HasHTMLTagName("script")) &&
+ element.HasAttribute("src")) {
+ return true;
+ }
+
+ std::string tag_name_lower = base::ToLowerASCII(element.TagName().Ascii());
+ const auto& tag_attribute_iter =
+ std::find_if(tag_and_attributes_list.begin(),
+ tag_and_attributes_list.end(), TagNameIs(tag_name_lower));
+ if (tag_attribute_iter == tag_and_attributes_list.end()) {
+ return false;
+ }
+
+ const std::vector<std::string>& valid_attributes =
+ tag_attribute_iter->attributes;
+ for (const std::string& attribute : valid_attributes) {
+ if (element.HasAttribute(blink::WebString::FromASCII(attribute))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+TagAndAttributesItem::TagAndAttributesItem() {}
+TagAndAttributesItem::TagAndAttributesItem(const TagAndAttributesItem& item)
+ : tag_name(item.tag_name), attributes(item.attributes) {}
+TagAndAttributesItem::~TagAndAttributesItem() {}
+
+uint32_t ThreatDOMDetails::kMaxNodes = 500;
+uint32_t ThreatDOMDetails::kMaxAttributes = 100;
+uint32_t ThreatDOMDetails::kMaxAttributeStringLength = 100;
+
+// static
+ThreatDOMDetails* ThreatDOMDetails::Create(content::RenderFrame* render_frame) {
+ // Private constructor and public static Create() method to facilitate
+ // stubbing out this class for binary-size reduction purposes.
+ return new ThreatDOMDetails(render_frame);
+}
+
+ThreatDOMDetails::ThreatDOMDetails(content::RenderFrame* render_frame)
+ : content::RenderFrameObserver(render_frame) {
+ ParseTagAndAttributeParams(&tag_and_attributes_list_);
+}
+
+ThreatDOMDetails::~ThreatDOMDetails() {}
+
+bool ThreatDOMDetails::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(ThreatDOMDetails, message)
+ IPC_MESSAGE_HANDLER(SafeBrowsingMsg_GetThreatDOMDetails,
+ OnGetThreatDOMDetails)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void ThreatDOMDetails::OnGetThreatDOMDetails() {
+ std::vector<SafeBrowsingHostMsg_ThreatDOMDetails_Node> resources;
+ ExtractResources(&resources);
+ // Notify the browser.
+ Send(new SafeBrowsingHostMsg_ThreatDOMDetails(routing_id(), resources));
+}
+
+void ThreatDOMDetails::ExtractResources(
+ std::vector<SafeBrowsingHostMsg_ThreatDOMDetails_Node>* resources) {
+ blink::WebFrame* frame = render_frame()->GetWebFrame();
+ if (!frame)
+ return;
+ SafeBrowsingHostMsg_ThreatDOMDetails_Node details_node;
+ blink::WebDocument document = frame->GetDocument();
+ details_node.url = GURL(document.Url());
+ if (document.IsNull()) {
+ // Nothing in this frame. Just report its URL.
+ resources->push_back(details_node);
+ return;
+ }
+
+ ElementToNodeMap element_to_node_map;
+ blink::WebElementCollection elements = document.All();
+ blink::WebElement element = elements.FirstItem();
+ for (; !element.IsNull(); element = elements.NextItem()) {
+ if (ShouldHandleElement(element, tag_and_attributes_list_)) {
+ HandleElement(element, tag_and_attributes_list_, &details_node, resources,
+ &element_to_node_map);
+ if (resources->size() >= kMaxNodes) {
+ // We have reached kMaxNodes, exit early.
+ resources->push_back(details_node);
+ return;
+ }
+ }
+ }
+ resources->push_back(details_node);
+}
+
+void ThreatDOMDetails::OnDestruct() {
+ delete this;
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/renderer/threat_dom_details.h b/chromium/components/safe_browsing/renderer/threat_dom_details.h
new file mode 100644
index 00000000000..0f48d0b16f6
--- /dev/null
+++ b/chromium/components/safe_browsing/renderer/threat_dom_details.h
@@ -0,0 +1,81 @@
+// 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.
+//
+// ThreatDOMDetails iterates over a document's frames and gathers
+// interesting URLs such as those of scripts and frames. When done, it sends
+// them to the ThreatDetails that requested them.
+
+#ifndef COMPONENTS_SAFE_BROWSING_RENDERER_THREAT_DOM_DETAILS_H_
+#define COMPONENTS_SAFE_BROWSING_RENDERER_THREAT_DOM_DETAILS_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/feature_list.h"
+#include "content/public/renderer/render_frame_observer.h"
+
+struct SafeBrowsingHostMsg_ThreatDOMDetails_Node;
+
+namespace safe_browsing {
+
+extern const base::Feature kThreatDomDetailsTagAndAttributeFeature;
+extern const char kTagAndAttributeParamName[];
+
+// Represents the tag name of an HTML Element and its associated attributes.
+// Used to determine which elements to collect. Populated from the param value
+// of |kThreatDomDetailsTagAndAttributeFeature|.
+class TagAndAttributesItem {
+ public:
+ TagAndAttributesItem();
+ TagAndAttributesItem(const TagAndAttributesItem& item);
+ ~TagAndAttributesItem();
+
+ std::string tag_name;
+ std::vector<std::string> attributes;
+};
+
+// There is one ThreatDOMDetails per RenderFrame.
+class ThreatDOMDetails : public content::RenderFrameObserver {
+ public:
+ // An upper limit on the number of nodes we collect. Not const for the test.
+ static uint32_t kMaxNodes;
+
+ // An upper limit on the number of attributes to collect per node. Not const
+ // for the test.
+ static uint32_t kMaxAttributes;
+
+ // An upper limit on the length of an attribute string.
+ static uint32_t kMaxAttributeStringLength;
+
+ static ThreatDOMDetails* Create(content::RenderFrame* render_frame);
+ ~ThreatDOMDetails() override;
+
+ // Begins extracting resource urls for the page currently loaded in
+ // this object's RenderFrame.
+ // Exposed for testing.
+ void ExtractResources(
+ std::vector<SafeBrowsingHostMsg_ThreatDOMDetails_Node>* resources);
+
+ private:
+ // Creates a ThreatDOMDetails for the specified RenderFrame.
+ // The ThreatDOMDetails should be destroyed prior to destroying
+ // the RenderFrame.
+ explicit ThreatDOMDetails(content::RenderFrame* render_frame);
+
+ // RenderFrameObserver implementation.
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OnDestruct() override;
+
+ void OnGetThreatDOMDetails();
+
+ // A list of tag names and associates attributes, used to determine which
+ // elements need to be collected.
+ std::vector<TagAndAttributesItem> tag_and_attributes_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreatDOMDetails);
+};
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_RENDERER_THREAT_DOM_DETAILS_H_
diff --git a/chromium/components/safe_browsing_db/android/safe_browsing_api_handler_bridge.cc b/chromium/components/safe_browsing_db/android/safe_browsing_api_handler_bridge.cc
index 6798dd032e4..a4dd994d16c 100644
--- a/chromium/components/safe_browsing_db/android/safe_browsing_api_handler_bridge.cc
+++ b/chromium/components/safe_browsing_db/android/safe_browsing_api_handler_bridge.cc
@@ -28,15 +28,12 @@ using content::BrowserThread;
namespace safe_browsing {
namespace {
-// Takes ownership of callback ptr.
void RunCallbackOnIOThread(
- SafeBrowsingApiHandler::URLCheckCallbackMeta* callback,
+ const SafeBrowsingApiHandler::URLCheckCallbackMeta& callback,
SBThreatType threat_type,
const ThreatMetadata& metadata) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&SafeBrowsingApiHandler::URLCheckCallbackMeta::Run,
- base::Owned(callback), threat_type, metadata));
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(callback, threat_type, metadata));
}
void ReportUmaResult(safe_browsing::UmaRemoteCallResult result) {
@@ -109,16 +106,14 @@ void OnUrlCheckDone(JNIEnv* env,
DCHECK_EQ(result_status, RESULT_STATUS_INTERNAL_ERROR);
ReportUmaResult(UMA_STATUS_INTERNAL_ERROR);
}
- RunCallbackOnIOThread(callback.release(), SB_THREAT_TYPE_SAFE,
- ThreatMetadata());
+ RunCallbackOnIOThread(*callback, SB_THREAT_TYPE_SAFE, ThreatMetadata());
return;
}
// Shortcut for safe, so we don't have to parse JSON.
if (metadata_str == "{}") {
ReportUmaResult(UMA_STATUS_SAFE);
- RunCallbackOnIOThread(callback.release(), SB_THREAT_TYPE_SAFE,
- ThreatMetadata());
+ RunCallbackOnIOThread(*callback, SB_THREAT_TYPE_SAFE, ThreatMetadata());
} else {
// Unsafe, assuming we can parse the JSON.
SBThreatType worst_threat;
@@ -129,7 +124,7 @@ void OnUrlCheckDone(JNIEnv* env,
DVLOG(1) << "Check " << callback_id << " marked as UNSAFE";
}
- RunCallbackOnIOThread(callback.release(), worst_threat, threat_metadata);
+ RunCallbackOnIOThread(*callback, worst_threat, threat_metadata);
}
}
@@ -161,8 +156,7 @@ void SafeBrowsingApiHandlerBridge::StartURLCheck(
if (!CheckApiIsSupported()) {
// Mark all requests as safe. Only users who have an old, broken GMSCore or
// have sideloaded Chrome w/o PlayStore should land here.
- RunCallbackOnIOThread(new URLCheckCallbackMeta(callback),
- SB_THREAT_TYPE_SAFE, ThreatMetadata());
+ RunCallbackOnIOThread(callback, SB_THREAT_TYPE_SAFE, ThreatMetadata());
ReportUmaResult(UMA_STATUS_UNSUPPORTED);
return;
}
diff --git a/chromium/components/safe_browsing_db/safe_browsing_prefs_unittest.cc b/chromium/components/safe_browsing_db/safe_browsing_prefs_unittest.cc
index 303f87826a5..b6b3a088b45 100644
--- a/chromium/components/safe_browsing_db/safe_browsing_prefs_unittest.cc
+++ b/chromium/components/safe_browsing_db/safe_browsing_prefs_unittest.cc
@@ -6,6 +6,7 @@
#include <vector>
#include "base/command_line.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/test/scoped_feature_list.h"
#include "components/prefs/pref_registry_simple.h"
@@ -41,8 +42,8 @@ class SafeBrowsingPrefsTest : public ::testing::Test {
}
void ResetExperiments(bool can_show_scout, bool only_show_scout) {
- std::vector<std::string> enabled_features;
- std::vector<std::string> disabled_features;
+ std::vector<base::StringPiece> enabled_features;
+ std::vector<base::StringPiece> disabled_features;
auto* target_vector =
can_show_scout ? &enabled_features : &disabled_features;
diff --git a/chromium/components/safe_browsing_db/v4_database.cc b/chromium/components/safe_browsing_db/v4_database.cc
index 343e85ae024..c1c7b3eedcd 100644
--- a/chromium/components/safe_browsing_db/v4_database.cc
+++ b/chromium/components/safe_browsing_db/v4_database.cc
@@ -5,8 +5,8 @@
#include <memory>
#include "base/callback.h"
-#include "base/debug/leak_annotations.h"
#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -22,13 +22,15 @@ namespace {
const char kV4DatabaseSizeMetric[] = "SafeBrowsing.V4Database.Size";
-} // namespace
+// The factory that controls the creation of the V4Database object.
+base::LazyInstance<std::unique_ptr<V4DatabaseFactory>>::Leaky g_db_factory =
+ LAZY_INSTANCE_INITIALIZER;
-// static
-V4DatabaseFactory* V4Database::db_factory_ = NULL;
+// The factory that controls the creation of V4Store objects.
+base::LazyInstance<std::unique_ptr<V4StoreFactory>>::Leaky g_store_factory =
+ LAZY_INSTANCE_INITIALIZER;
-// static
-V4StoreFactory* V4Database::store_factory_ = NULL;
+} // namespace
std::unique_ptr<V4Database> V4DatabaseFactory::Create(
const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
@@ -65,14 +67,11 @@ void V4Database::CreateOnTaskRunner(
const TimeTicks create_start_time) {
DCHECK(db_task_runner->RunsTasksOnCurrentThread());
- if (!store_factory_) {
- store_factory_ = new V4StoreFactory();
- ANNOTATE_LEAKING_OBJECT_PTR(store_factory_);
- }
+ if (!g_store_factory.Get())
+ g_store_factory.Get() = base::MakeUnique<V4StoreFactory>();
- if (!base::CreateDirectory(base_path)) {
+ if (!base::CreateDirectory(base_path))
NOTREACHED();
- }
std::unique_ptr<StoreMap> store_map = base::MakeUnique<StoreMap>();
for (const auto& it : list_infos) {
@@ -82,16 +81,15 @@ void V4Database::CreateOnTaskRunner(
}
const base::FilePath store_path = base_path.AppendASCII(it.filename());
- (*store_map)[it.list_id()].reset(
- store_factory_->CreateV4Store(db_task_runner, store_path));
+ (*store_map)[it.list_id()] =
+ g_store_factory.Get()->CreateV4Store(db_task_runner, store_path);
}
- if (!db_factory_) {
- db_factory_ = new V4DatabaseFactory();
- ANNOTATE_LEAKING_OBJECT_PTR(db_factory_);
- }
- std::unique_ptr<V4Database> v4_database(
- db_factory_->Create(db_task_runner, std::move(store_map)));
+ if (!g_db_factory.Get())
+ g_db_factory.Get() = base::MakeUnique<V4DatabaseFactory>();
+
+ std::unique_ptr<V4Database> v4_database =
+ g_db_factory.Get()->Create(db_task_runner, std::move(store_map));
// Database is done loading, pass it to the new_db_callback on the caller's
// thread. This would unblock resource loads.
@@ -105,19 +103,13 @@ void V4Database::CreateOnTaskRunner(
// static
void V4Database::RegisterDatabaseFactoryForTest(
std::unique_ptr<V4DatabaseFactory> factory) {
- if (db_factory_) {
- delete db_factory_;
- }
- db_factory_ = factory.release();
+ g_db_factory.Get() = std::move(factory);
}
// static
void V4Database::RegisterStoreFactoryForTest(
std::unique_ptr<V4StoreFactory> factory) {
- if (store_factory_) {
- delete store_factory_;
- }
- store_factory_ = factory.release();
+ g_store_factory.Get() = std::move(factory);
}
V4Database::V4Database(
diff --git a/chromium/components/safe_browsing_db/v4_database.h b/chromium/components/safe_browsing_db/v4_database.h
index acb1855a147..0fc398dcfb9 100644
--- a/chromium/components/safe_browsing_db/v4_database.h
+++ b/chromium/components/safe_browsing_db/v4_database.h
@@ -5,6 +5,11 @@
#ifndef COMPONENTS_SAFE_BROWSING_DB_V4_DATABASE_H_
#define COMPONENTS_SAFE_BROWSING_DB_V4_DATABASE_H_
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
@@ -14,41 +19,46 @@
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
#include "components/safe_browsing_db/v4_store.h"
+namespace subresource_filter {
+class SubresourceFilterBrowserTestImpl;
+}
+
namespace safe_browsing {
class V4Database;
// Scheduled when the database has been read from disk and is ready to process
// resource reputation requests.
-typedef base::Callback<void(std::unique_ptr<V4Database>)>
- NewDatabaseReadyCallback;
+using NewDatabaseReadyCallback =
+ base::Callback<void(std::unique_ptr<V4Database>)>;
// Scheduled when the checksum for all the stores in the database has been
// verified to match the expected value. Stores for which the checksum did not
// match are passed as the argument and need to be reset.
-typedef base::Callback<void(const std::vector<ListIdentifier>&)>
- DatabaseReadyForUpdatesCallback;
+using DatabaseReadyForUpdatesCallback =
+ base::Callback<void(const std::vector<ListIdentifier>&)>;
// This callback is scheduled once the database has finished processing the
// update requests for all stores and is ready to process the next set of update
// requests.
-typedef base::Callback<void()> DatabaseUpdatedCallback;
+using DatabaseUpdatedCallback = base::Closure;
// Maps the ListIdentifiers to their corresponding in-memory stores, which
// contain the hash prefixes for that ListIdentifier as well as manage their
// storage on disk.
-typedef base::hash_map<ListIdentifier, std::unique_ptr<V4Store>> StoreMap;
+using StoreMap = std::unordered_map<ListIdentifier, std::unique_ptr<V4Store>>;
// Associates metadata for a list with its ListIdentifier.
-struct ListInfo {
+class ListInfo {
+ public:
ListInfo(const bool fetch_updates,
const std::string& filename,
const ListIdentifier& list_id,
const SBThreatType sb_threat_type);
~ListInfo();
- ListIdentifier list_id() const { return list_id_; }
- std::string filename() const { return filename_; }
+ const ListIdentifier& list_id() const { return list_id_; }
+ const std::string& filename() const { return filename_; }
SBThreatType sb_threat_type() const { return sb_threat_type_; }
bool fetch_updates() const { return fetch_updates_; }
@@ -68,10 +78,10 @@ struct ListInfo {
// The threat type enum value for this store.
SBThreatType sb_threat_type_;
- ListInfo();
+ ListInfo() = delete;
};
-typedef std::vector<ListInfo> ListInfos;
+using ListInfos = std::vector<ListInfo>;
// Factory for creating V4Database. Tests implement this factory to create fake
// databases for testing.
@@ -151,7 +161,11 @@ class V4Database {
V4Database(const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
std::unique_ptr<StoreMap> store_map);
+ // Map of ListIdentifier to the V4Store.
+ const std::unique_ptr<StoreMap> store_map_;
+
private:
+ friend class subresource_filter::SubresourceFilterBrowserTestImpl;
friend class V4DatabaseFactory;
friend class V4DatabaseTest;
friend class V4SafeBrowsingServiceTest;
@@ -195,21 +209,10 @@ class V4Database {
const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner,
DatabaseReadyForUpdatesCallback db_ready_for_updates_callback);
- protected:
- // Map of ListIdentifier to the V4Store.
- const std::unique_ptr<StoreMap> store_map_;
-
- private:
const scoped_refptr<base::SequencedTaskRunner> db_task_runner_;
DatabaseUpdatedCallback db_updated_callback_;
- // The factory that controls the creation of the V4Database object.
- static V4DatabaseFactory* db_factory_;
-
- // The factory that controls the creation of V4Store objects.
- static V4StoreFactory* store_factory_;
-
// The number of stores for which the update request is pending. When this
// goes down to 0, that indicates that the database has updated all the stores
// that needed updating and is ready for the next update. It should only be
diff --git a/chromium/components/safe_browsing_db/v4_database_unittest.cc b/chromium/components/safe_browsing_db/v4_database_unittest.cc
index 6b83138a19c..431204551a8 100644
--- a/chromium/components/safe_browsing_db/v4_database_unittest.cc
+++ b/chromium/components/safe_browsing_db/v4_database_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <utility>
+
#include "base/bind.h"
#include "base/debug/leak_annotations.h"
#include "base/files/scoped_temp_dir.h"
@@ -44,17 +46,18 @@ class FakeV4Store : public V4Store {
// |GetStoresMatchingFullHash()| method in |V4Database|.
class FakeV4StoreFactory : public V4StoreFactory {
public:
- FakeV4StoreFactory(bool hash_prefix_matches)
+ explicit FakeV4StoreFactory(bool hash_prefix_matches)
: hash_prefix_should_match_(hash_prefix_matches) {}
- V4Store* CreateV4Store(
+ std::unique_ptr<V4Store> CreateV4Store(
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
const base::FilePath& store_path) override {
- return new FakeV4Store(task_runner, store_path, hash_prefix_should_match_);
+ return base::MakeUnique<FakeV4Store>(task_runner, store_path,
+ hash_prefix_should_match_);
}
private:
- bool hash_prefix_should_match_;
+ const bool hash_prefix_should_match_;
};
class V4DatabaseTest : public PlatformTest {
@@ -138,11 +141,10 @@ class V4DatabaseTest : public PlatformTest {
std::unique_ptr<ParsedServerResponse> CreateFakeServerResponse(
StoreStateMap store_state_map,
bool use_valid_response_type) {
- std::unique_ptr<ParsedServerResponse> parsed_server_response(
- new ParsedServerResponse);
+ auto parsed_server_response = base::MakeUnique<ParsedServerResponse>();
for (const auto& store_state_iter : store_state_map) {
ListIdentifier identifier = store_state_iter.first;
- ListUpdateResponse* lur = new ListUpdateResponse;
+ auto lur = base::MakeUnique<ListUpdateResponse>();
lur->set_platform_type(identifier.platform_type());
lur->set_threat_entry_type(identifier.threat_entry_type());
lur->set_threat_type(identifier.threat_type());
@@ -152,7 +154,7 @@ class V4DatabaseTest : public PlatformTest {
} else {
lur->set_response_type(ListUpdateResponse::RESPONSE_TYPE_UNSPECIFIED);
}
- parsed_server_response->push_back(base::WrapUnique(lur));
+ parsed_server_response->push_back(std::move(lur));
}
return parsed_server_response;
}
@@ -303,8 +305,7 @@ TEST_F(V4DatabaseTest, TestApplyUpdateWithEmptyUpdate) {
old_stores_map_[store_iter.first] = store;
}
- std::unique_ptr<ParsedServerResponse> parsed_server_response(
- new ParsedServerResponse);
+ auto parsed_server_response = base::MakeUnique<ParsedServerResponse>();
v4_database_->ApplyUpdate(std::move(parsed_server_response),
callback_db_updated_);
@@ -489,8 +490,7 @@ TEST_F(V4DatabaseTest, UsingWeakPtrDropsCallback) {
// Step 2: Try to update the database. This posts V4Store::ApplyUpdate on the
// task runner.
- std::unique_ptr<ParsedServerResponse> parsed_server_response(
- new ParsedServerResponse);
+ auto parsed_server_response = base::MakeUnique<ParsedServerResponse>();
auto lur = base::MakeUnique<ListUpdateResponse>();
lur->set_platform_type(linux_malware_id_.platform_type());
lur->set_threat_entry_type(linux_malware_id_.threat_entry_type());
diff --git a/chromium/components/safe_browsing_db/v4_local_database_manager.cc b/chromium/components/safe_browsing_db/v4_local_database_manager.cc
index 53c5d8c6061..6644f662d80 100644
--- a/chromium/components/safe_browsing_db/v4_local_database_manager.cc
+++ b/chromium/components/safe_browsing_db/v4_local_database_manager.cc
@@ -94,6 +94,7 @@ ThreatSeverity GetThreatSeverity(const ListIdentifier& list_id) {
return 1;
case API_ABUSE:
case CLIENT_INCIDENT:
+ case SUBRESOURCE_FILTER:
return 2;
default:
NOTREACHED() << "Unexpected ThreatType encountered: "
@@ -571,8 +572,8 @@ bool V4LocalDatabaseManager::HandleCheck(std::unique_ptr<PendingCheck> check) {
// Post on the IO thread to enforce async behavior.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::Bind(&V4LocalDatabaseManager::PerformFullHashCheck, this,
- base::Passed(std::move(check)),
+ base::Bind(&V4LocalDatabaseManager::PerformFullHashCheck,
+ weak_factory_.GetWeakPtr(), base::Passed(std::move(check)),
full_hash_to_store_and_hash_prefixes));
return false;
diff --git a/chromium/components/safe_browsing_db/v4_local_database_manager_unittest.cc b/chromium/components/safe_browsing_db/v4_local_database_manager_unittest.cc
index be6a792bea9..595feec8aa7 100644
--- a/chromium/components/safe_browsing_db/v4_local_database_manager_unittest.cc
+++ b/chromium/components/safe_browsing_db/v4_local_database_manager_unittest.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "components/safe_browsing_db/v4_local_database_manager.h"
-#include "base/base64.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
@@ -159,16 +158,24 @@ class TestClient : public SafeBrowsingDatabaseManager::Client {
const GURL& url,
V4LocalDatabaseManager* manager_to_cancel = nullptr)
: expected_sb_threat_type(sb_threat_type),
- expected_url(url),
+ expected_urls(1, url),
on_check_browse_url_result_called_(false),
+ on_check_download_urls_result_called_(false),
on_check_resource_url_result_called_(false),
manager_to_cancel_(manager_to_cancel) {}
+ TestClient(SBThreatType sb_threat_type, const std::vector<GURL>& url_chain)
+ : expected_sb_threat_type(sb_threat_type),
+ expected_urls(url_chain),
+ on_check_browse_url_result_called_(false),
+ on_check_download_urls_result_called_(false),
+ on_check_resource_url_result_called_(false) {}
+
void OnCheckBrowseUrlResult(const GURL& url,
SBThreatType threat_type,
const ThreatMetadata& metadata) override {
- DCHECK_EQ(expected_url, url);
- DCHECK_EQ(expected_sb_threat_type, threat_type);
+ ASSERT_EQ(expected_urls[0], url);
+ ASSERT_EQ(expected_sb_threat_type, threat_type);
on_check_browse_url_result_called_ = true;
if (manager_to_cancel_) {
manager_to_cancel_->CancelCheck(this);
@@ -178,15 +185,22 @@ class TestClient : public SafeBrowsingDatabaseManager::Client {
void OnCheckResourceUrlResult(const GURL& url,
SBThreatType threat_type,
const std::string& threat_hash) override {
- DCHECK_EQ(expected_url, url);
- DCHECK_EQ(expected_sb_threat_type, threat_type);
- DCHECK_EQ(threat_type == SB_THREAT_TYPE_SAFE, threat_hash.empty());
+ ASSERT_EQ(expected_urls[0], url);
+ ASSERT_EQ(expected_sb_threat_type, threat_type);
+ ASSERT_EQ(threat_type == SB_THREAT_TYPE_SAFE, threat_hash.empty());
on_check_resource_url_result_called_ = true;
}
+ void OnCheckDownloadUrlResult(const std::vector<GURL>& url_chain,
+ SBThreatType threat_type) override {
+ ASSERT_EQ(expected_urls, url_chain);
+ ASSERT_EQ(expected_sb_threat_type, threat_type);
+ on_check_download_urls_result_called_ = true;
+ }
SBThreatType expected_sb_threat_type;
- GURL expected_url;
+ std::vector<GURL> expected_urls;
bool on_check_browse_url_result_called_;
+ bool on_check_download_urls_result_called_;
bool on_check_resource_url_result_called_;
V4LocalDatabaseManager* manager_to_cancel_;
};
@@ -391,14 +405,15 @@ TEST_F(V4LocalDatabaseManagerTest, TestCheckBrowseUrlWithFakeDbReturnsMatch) {
WaitForTasksOnTaskRunner();
net::TestURLFetcherFactory factory;
+ std::string url_bad_no_scheme("example.com/bad/");
+ FullHash bad_full_hash(crypto::SHA256HashString(url_bad_no_scheme));
+ const HashPrefix bad_hash_prefix(bad_full_hash.substr(0, 5));
StoreAndHashPrefixes store_and_hash_prefixes;
- store_and_hash_prefixes.emplace_back(GetUrlMalwareId(),
- HashPrefix("eW\x1A\xF\xA9"));
+ store_and_hash_prefixes.emplace_back(GetUrlMalwareId(), bad_hash_prefix);
ReplaceV4Database(store_and_hash_prefixes);
- // The fake database returns a matched hash prefix.
- EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(
- GURL("http://example.com/a/"), nullptr));
+ const GURL url_bad("https://" + url_bad_no_scheme);
+ EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(url_bad, nullptr));
// Wait for PerformFullHashCheck to complete.
WaitForTasksOnTaskRunner();
@@ -493,19 +508,19 @@ TEST_F(V4LocalDatabaseManagerTest, CancelPending) {
ResetLocalDatabaseManager();
WaitForTasksOnTaskRunner();
- // An URL and matching prefix.
- const GURL url("http://example.com/a/");
- const HashPrefix hash_prefix("eW\x1A\xF\xA9");
-
// Put a match in the db that will cause a protocol-manager request.
+ std::string url_bad_no_scheme("example.com/bad/");
+ FullHash bad_full_hash(crypto::SHA256HashString(url_bad_no_scheme));
+ const HashPrefix bad_hash_prefix(bad_full_hash.substr(0, 5));
StoreAndHashPrefixes store_and_hash_prefixes;
- store_and_hash_prefixes.emplace_back(GetUrlMalwareId(), hash_prefix);
+ store_and_hash_prefixes.emplace_back(GetUrlMalwareId(), bad_hash_prefix);
ReplaceV4Database(store_and_hash_prefixes);
+ const GURL url_bad("https://" + url_bad_no_scheme);
// Test that a request flows through to the callback.
{
- TestClient client(SB_THREAT_TYPE_SAFE, url);
- EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(url, &client));
+ TestClient client(SB_THREAT_TYPE_SAFE, url_bad);
+ EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(url_bad, &client));
EXPECT_FALSE(client.on_check_browse_url_result_called_);
WaitForTasksOnTaskRunner();
EXPECT_TRUE(client.on_check_browse_url_result_called_);
@@ -513,8 +528,8 @@ TEST_F(V4LocalDatabaseManagerTest, CancelPending) {
// Test that cancel prevents the callback from being called.
{
- TestClient client(SB_THREAT_TYPE_SAFE, url);
- EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(url, &client));
+ TestClient client(SB_THREAT_TYPE_SAFE, url_bad);
+ EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(url_bad, &client));
v4_local_database_manager_->CancelCheck(&client);
EXPECT_FALSE(client.on_check_browse_url_result_called_);
WaitForTasksOnTaskRunner();
@@ -547,14 +562,16 @@ TEST_F(V4LocalDatabaseManagerTest, PerformFullHashCheckCalledAsync) {
SetupFakeManager();
net::TestURLFetcherFactory factory;
+ std::string url_bad_no_scheme("example.com/bad/");
+ FullHash bad_full_hash(crypto::SHA256HashString(url_bad_no_scheme));
+ const HashPrefix bad_hash_prefix(bad_full_hash.substr(0, 5));
StoreAndHashPrefixes store_and_hash_prefixes;
- store_and_hash_prefixes.emplace_back(GetUrlMalwareId(),
- HashPrefix("eW\x1A\xF\xA9"));
+ store_and_hash_prefixes.emplace_back(GetUrlMalwareId(), bad_hash_prefix);
ReplaceV4Database(store_and_hash_prefixes);
+ const GURL url_bad("https://" + url_bad_no_scheme);
// The fake database returns a matched hash prefix.
- EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(
- GURL("http://example.com/a/"), nullptr));
+ EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(url_bad, nullptr));
EXPECT_FALSE(FakeV4LocalDatabaseManager::PerformFullHashCheckCalled(
v4_local_database_manager_));
@@ -570,14 +587,15 @@ TEST_F(V4LocalDatabaseManagerTest, UsingWeakPtrDropsCallback) {
SetupFakeManager();
net::TestURLFetcherFactory factory;
+ std::string url_bad_no_scheme("example.com/bad/");
+ FullHash bad_full_hash(crypto::SHA256HashString(url_bad_no_scheme));
+ const HashPrefix bad_hash_prefix(bad_full_hash.substr(0, 5));
StoreAndHashPrefixes store_and_hash_prefixes;
- store_and_hash_prefixes.emplace_back(GetUrlMalwareId(),
- HashPrefix("eW\x1A\xF\xA9"));
+ store_and_hash_prefixes.emplace_back(GetUrlMalwareId(), bad_hash_prefix);
ReplaceV4Database(store_and_hash_prefixes);
- // The fake database returns a matched hash prefix.
- EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(
- GURL("http://example.com/a/"), nullptr));
+ const GURL url_bad("https://" + url_bad_no_scheme);
+ EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(url_bad, nullptr));
v4_local_database_manager_->StopOnIOThread(true);
// Release the V4LocalDatabaseManager object right away before the callback
@@ -735,7 +753,7 @@ TEST_F(V4LocalDatabaseManagerTest, TestCheckBrowseUrlWithSameClientAndCancel) {
v4_local_database_manager_->CancelCheck(&client);
// Now, re-use that client but for |second_url|.
- client.expected_url = second_url;
+ client.expected_urls.assign(1, second_url);
EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(second_url, &client));
// Wait for PerformFullHashCheck to complete.
@@ -755,18 +773,17 @@ TEST_F(V4LocalDatabaseManagerTest, TestCheckResourceUrl) {
ResetLocalDatabaseManager();
WaitForTasksOnTaskRunner();
- // An URL and matching prefix.
- const GURL url("http://example.com/a/");
- const HashPrefix hash_prefix("eW\x1A\xF\xA9");
-
- // Put a match in the db that will cause a protocol-manager request.
+ std::string url_bad_no_scheme("example.com/bad/");
+ FullHash bad_full_hash(crypto::SHA256HashString(url_bad_no_scheme));
+ const HashPrefix bad_hash_prefix(bad_full_hash.substr(0, 5));
StoreAndHashPrefixes store_and_hash_prefixes;
store_and_hash_prefixes.emplace_back(GetChromeUrlClientIncidentId(),
- hash_prefix);
+ bad_hash_prefix);
ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */);
- TestClient client(SB_THREAT_TYPE_SAFE, url);
- EXPECT_FALSE(v4_local_database_manager_->CheckResourceUrl(url, &client));
+ const GURL url_bad("https://" + url_bad_no_scheme);
+ TestClient client(SB_THREAT_TYPE_SAFE, url_bad);
+ EXPECT_FALSE(v4_local_database_manager_->CheckResourceUrl(url_bad, &client));
EXPECT_FALSE(client.on_check_resource_url_result_called_);
WaitForTasksOnTaskRunner();
EXPECT_TRUE(client.on_check_resource_url_result_called_);
@@ -780,21 +797,22 @@ TEST_F(V4LocalDatabaseManagerTest, TestSubresourceFilterCallback) {
ResetLocalDatabaseManager();
WaitForTasksOnTaskRunner();
- // An URL and matching prefix.
- const GURL url("http://example.com/a/");
- const HashPrefix hash_prefix("eW\x1A\xF\xA9");
+ std::string url_bad_no_scheme("example.com/bad/");
+ FullHash bad_full_hash(crypto::SHA256HashString(url_bad_no_scheme));
+ const HashPrefix bad_hash_prefix(bad_full_hash.substr(0, 5));
// Put a match in the db that will cause a protocol-manager request.
StoreAndHashPrefixes store_and_hash_prefixes;
store_and_hash_prefixes.emplace_back(GetUrlSubresourceFilterId(),
- hash_prefix);
+ bad_hash_prefix);
ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */);
+ const GURL url_bad("https://" + url_bad_no_scheme);
// Test that a request flows through to the callback.
{
- TestClient client(SB_THREAT_TYPE_SAFE, url);
- EXPECT_FALSE(
- v4_local_database_manager_->CheckUrlForSubresourceFilter(url, &client));
+ TestClient client(SB_THREAT_TYPE_SAFE, url_bad);
+ EXPECT_FALSE(v4_local_database_manager_->CheckUrlForSubresourceFilter(
+ url_bad, &client));
EXPECT_FALSE(client.on_check_browse_url_result_called_);
WaitForTasksOnTaskRunner();
EXPECT_TRUE(client.on_check_browse_url_result_called_);
@@ -802,31 +820,26 @@ TEST_F(V4LocalDatabaseManagerTest, TestSubresourceFilterCallback) {
}
TEST_F(V4LocalDatabaseManagerTest, TestCheckResourceUrlReturnsBad) {
- std::string base64_encoded = "ZVcaD6lke9GaaZEf07X3CpuEgMAqbpAyPw3sX/7eK9M=";
- std::string base64_decoded;
- base::Base64Decode(base64_encoded, &base64_decoded);
- FullHashInfo fhi(base64_decoded, GetChromeUrlClientIncidentId(),
- base::Time());
-
// Setup to receive full-hash hit.
+ std::string url_bad_no_scheme("example.com/bad/");
+ FullHash bad_full_hash(crypto::SHA256HashString(url_bad_no_scheme));
+ FullHashInfo fhi(bad_full_hash, GetChromeUrlClientIncidentId(), base::Time());
ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({fhi}));
// Reset the database manager so it picks up the replacement protocol manager.
ResetLocalDatabaseManager();
WaitForTasksOnTaskRunner();
- // An URL and matching prefix.
- const GURL url("http://example.com/a/");
- const HashPrefix hash_prefix("eW\x1A\xF\xA9");
-
// Put a match in the db that will cause a protocol-manager request.
+ const HashPrefix bad_hash_prefix(bad_full_hash.substr(0, 5));
StoreAndHashPrefixes store_and_hash_prefixes;
store_and_hash_prefixes.emplace_back(GetChromeUrlClientIncidentId(),
- hash_prefix);
+ bad_hash_prefix);
ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */);
- TestClient client(SB_THREAT_TYPE_BLACKLISTED_RESOURCE, url);
- EXPECT_FALSE(v4_local_database_manager_->CheckResourceUrl(url, &client));
+ const GURL url_bad("https://" + url_bad_no_scheme);
+ TestClient client(SB_THREAT_TYPE_BLACKLISTED_RESOURCE, url_bad);
+ EXPECT_FALSE(v4_local_database_manager_->CheckResourceUrl(url_bad, &client));
EXPECT_FALSE(client.on_check_resource_url_result_called_);
WaitForTasksOnTaskRunner();
EXPECT_TRUE(client.on_check_resource_url_result_called_);
@@ -889,7 +902,61 @@ TEST_F(V4LocalDatabaseManagerTest, TestCheckExtensionIDsOneIsBlacklisted) {
EXPECT_TRUE(client.on_check_extensions_result_called_);
}
-// TODO(vakh): By 03/15/2017: Add tests for
-// CheckDownloadUrl()
+TEST_F(V4LocalDatabaseManagerTest, TestCheckDownloadUrlNothingBlacklisted) {
+ // Setup to receive full-hash misses.
+ ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({}));
+
+ // Reset the database manager so it picks up the replacement protocol manager.
+ ResetLocalDatabaseManager();
+ WaitForTasksOnTaskRunner();
+
+ // Put a match in the db that will cause a protocol-manager request.
+ std::string url_bad_no_scheme("example.com/bad/");
+ FullHash bad_full_hash(crypto::SHA256HashString(url_bad_no_scheme));
+ const HashPrefix bad_hash_prefix(bad_full_hash.substr(0, 5));
+ StoreAndHashPrefixes store_and_hash_prefixes;
+ store_and_hash_prefixes.emplace_back(GetUrlMalBinId(), bad_hash_prefix);
+ ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */);
+
+ const GURL url_bad("https://" + url_bad_no_scheme),
+ url_good("https://example.com/good/");
+ const std::vector<GURL> url_chain({url_good, url_bad});
+
+ TestClient client(SB_THREAT_TYPE_SAFE, url_chain);
+ EXPECT_FALSE(
+ v4_local_database_manager_->CheckDownloadUrl(url_chain, &client));
+ EXPECT_FALSE(client.on_check_download_urls_result_called_);
+ WaitForTasksOnTaskRunner();
+ EXPECT_TRUE(client.on_check_download_urls_result_called_);
+}
+
+TEST_F(V4LocalDatabaseManagerTest, TestCheckDownloadUrlWithOneBlacklisted) {
+ // Setup to receive full-hash hit.
+ std::string url_bad_no_scheme("example.com/bad/");
+ FullHash bad_full_hash(crypto::SHA256HashString(url_bad_no_scheme));
+ FullHashInfo fhi(bad_full_hash, GetUrlMalBinId(), base::Time());
+ ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({fhi}));
+
+ // Reset the database manager so it picks up the replacement protocol manager.
+ ResetLocalDatabaseManager();
+ WaitForTasksOnTaskRunner();
+
+ const GURL url_bad("https://" + url_bad_no_scheme),
+ url_good("https://example.com/good/");
+ const std::vector<GURL> url_chain({url_good, url_bad});
+
+ // Put a match in the db that will cause a protocol-manager request.
+ const HashPrefix bad_hash_prefix(bad_full_hash.substr(0, 5));
+ StoreAndHashPrefixes store_and_hash_prefixes;
+ store_and_hash_prefixes.emplace_back(GetUrlMalBinId(), bad_hash_prefix);
+ ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */);
+
+ TestClient client(SB_THREAT_TYPE_BINARY_MALWARE_URL, url_chain);
+ EXPECT_FALSE(
+ v4_local_database_manager_->CheckDownloadUrl(url_chain, &client));
+ EXPECT_FALSE(client.on_check_download_urls_result_called_);
+ WaitForTasksOnTaskRunner();
+ EXPECT_TRUE(client.on_check_download_urls_result_called_);
+}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_protocol_manager_util.cc b/chromium/components/safe_browsing_db/v4_protocol_manager_util.cc
index e210f975171..9a97b0e4229 100644
--- a/chromium/components/safe_browsing_db/v4_protocol_manager_util.cc
+++ b/chromium/components/safe_browsing_db/v4_protocol_manager_util.cc
@@ -78,65 +78,65 @@ PlatformType GetCurrentPlatformType() {
#elif defined(OS_MACOSX)
return OSX_PLATFORM;
#else
-// This should ideally never compile but it is getting compiled on Android.
-// See: https://bugs.chromium.org/p/chromium/issues/detail?id=621647
-// TODO(vakh): Once that bug is fixed, this should be removed. If we leave
-// the platform_type empty, the server won't recognize the request and
-// return an error response which will pollute our UMA metrics.
-return LINUX_PLATFORM;
+ // This should ideally never compile but it is getting compiled on Android.
+ // See: https://bugs.chromium.org/p/chromium/issues/detail?id=621647
+ // TODO(vakh): Once that bug is fixed, this should be removed. If we leave
+ // the platform_type empty, the server won't recognize the request and
+ // return an error response which will pollute our UMA metrics.
+ return LINUX_PLATFORM;
#endif
}
-const ListIdentifier GetCertCsdDownloadWhitelistId() {
+ListIdentifier GetCertCsdDownloadWhitelistId() {
return ListIdentifier(GetCurrentPlatformType(), CERT, CSD_DOWNLOAD_WHITELIST);
}
-const ListIdentifier GetChromeExtMalwareId() {
+ListIdentifier GetChromeExtMalwareId() {
return ListIdentifier(CHROME_PLATFORM, CHROME_EXTENSION, MALWARE_THREAT);
}
-const ListIdentifier GetChromeUrlApiId() {
+ListIdentifier GetChromeUrlApiId() {
return ListIdentifier(CHROME_PLATFORM, URL, API_ABUSE);
}
-const ListIdentifier GetChromeFilenameClientIncidentId() {
+ListIdentifier GetChromeFilenameClientIncidentId() {
return ListIdentifier(CHROME_PLATFORM, FILENAME, CLIENT_INCIDENT);
}
-const ListIdentifier GetChromeUrlClientIncidentId() {
+ListIdentifier GetChromeUrlClientIncidentId() {
return ListIdentifier(CHROME_PLATFORM, URL, CLIENT_INCIDENT);
}
-const ListIdentifier GetIpMalwareId() {
+ListIdentifier GetIpMalwareId() {
return ListIdentifier(GetCurrentPlatformType(), IP_RANGE, MALWARE_THREAT);
}
-const ListIdentifier GetUrlCsdDownloadWhitelistId() {
+ListIdentifier GetUrlCsdDownloadWhitelistId() {
return ListIdentifier(GetCurrentPlatformType(), URL, CSD_DOWNLOAD_WHITELIST);
}
-const ListIdentifier GetUrlCsdWhitelistId() {
+ListIdentifier GetUrlCsdWhitelistId() {
return ListIdentifier(GetCurrentPlatformType(), URL, CSD_WHITELIST);
}
-const ListIdentifier GetUrlMalwareId() {
+ListIdentifier GetUrlMalwareId() {
return ListIdentifier(GetCurrentPlatformType(), URL, MALWARE_THREAT);
}
-const ListIdentifier GetUrlMalBinId() {
+ListIdentifier GetUrlMalBinId() {
return ListIdentifier(GetCurrentPlatformType(), URL, MALICIOUS_BINARY);
}
-const ListIdentifier GetUrlSocEngId() {
+ListIdentifier GetUrlSocEngId() {
return ListIdentifier(GetCurrentPlatformType(), URL,
SOCIAL_ENGINEERING_PUBLIC);
}
-const ListIdentifier GetUrlSubresourceFilterId() {
+ListIdentifier GetUrlSubresourceFilterId() {
return ListIdentifier(GetCurrentPlatformType(), URL, SUBRESOURCE_FILTER);
}
-const ListIdentifier GetUrlUwsId() {
+ListIdentifier GetUrlUwsId() {
return ListIdentifier(GetCurrentPlatformType(), URL, UNWANTED_SOFTWARE);
}
@@ -144,7 +144,7 @@ const ListIdentifier GetUrlUwsId() {
const char kSbV4UrlPrefix[] = "https://safebrowsing.googleapis.com/v4";
StoreAndHashPrefix::StoreAndHashPrefix(ListIdentifier list_id,
- HashPrefix hash_prefix)
+ const HashPrefix& hash_prefix)
: list_id(list_id), hash_prefix(hash_prefix) {}
StoreAndHashPrefix::~StoreAndHashPrefix() {}
@@ -183,8 +183,6 @@ size_t ListIdentifier::hash() const {
return base::HashInts(interim, third);
}
-ListIdentifier::ListIdentifier() {}
-
ListIdentifier::ListIdentifier(PlatformType platform_type,
ThreatEntryType threat_entry_type,
ThreatType threat_type)
@@ -215,8 +213,6 @@ V4ProtocolConfig::V4ProtocolConfig(const V4ProtocolConfig& other) = default;
V4ProtocolConfig::~V4ProtocolConfig() {}
// static
-// Backoff interval is MIN(((2^(n-1))*15 minutes) * (RAND + 1), 24 hours) where
-// n is the number of consecutive errors.
base::TimeDelta V4ProtocolManagerUtil::GetNextBackOffInterval(
size_t* error_count,
size_t* multiplier) {
@@ -229,13 +225,8 @@ base::TimeDelta V4ProtocolManagerUtil::GetNextBackOffInterval(
}
base::TimeDelta next =
base::TimeDelta::FromMinutes(*multiplier * (1 + base::RandDouble()) * 15);
-
base::TimeDelta day = base::TimeDelta::FromHours(24);
-
- if (next < day)
- return next;
- else
- return day;
+ return next < day ? next : day;
}
// static
diff --git a/chromium/components/safe_browsing_db/v4_protocol_manager_util.h b/chromium/components/safe_browsing_db/v4_protocol_manager_util.h
index 4ebb78304f0..882fb4a45cc 100644
--- a/chromium/components/safe_browsing_db/v4_protocol_manager_util.h
+++ b/chromium/components/safe_browsing_db/v4_protocol_manager_util.h
@@ -8,11 +8,14 @@
// A class that implements the stateless methods used by the GetHashUpdate and
// GetFullHash stubby calls made by Chrome using the SafeBrowsing V4 protocol.
+#include <memory>
#include <ostream>
#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
#include "base/gtest_prod_util.h"
-#include "base/hash.h"
#include "base/strings/string_piece.h"
#include "components/safe_browsing_db/safebrowsing.pb.h"
#include "net/url_request/url_request_status.h"
@@ -27,7 +30,7 @@ namespace safe_browsing {
// The size of the hash prefix, in bytes. It should be between 4 to 32 (full
// hash).
-typedef size_t PrefixSize;
+using PrefixSize = size_t;
// The minimum expected size (in bytes) of a hash-prefix.
const PrefixSize kMinHashPrefixLength = 4;
@@ -37,13 +40,13 @@ const PrefixSize kMinHashPrefixLength = 4;
const PrefixSize kMaxHashPrefixLength = 32;
// A hash prefix sent by the SafeBrowsing PVer4 service.
-typedef std::string HashPrefix;
+using HashPrefix = std::string;
// A full SHA256 hash.
-typedef HashPrefix FullHash;
+using FullHash = HashPrefix;
-typedef FetchThreatListUpdatesRequest::ListUpdateRequest ListUpdateRequest;
-typedef FetchThreatListUpdatesResponse::ListUpdateResponse ListUpdateResponse;
+using ListUpdateRequest = FetchThreatListUpdatesRequest::ListUpdateRequest;
+using ListUpdateResponse = FetchThreatListUpdatesResponse::ListUpdateResponse;
// Config passed to the constructor of a V4 protocol manager.
struct V4ProtocolConfig {
@@ -67,7 +70,7 @@ struct V4ProtocolConfig {
~V4ProtocolConfig();
private:
- V4ProtocolConfig();
+ V4ProtocolConfig() = delete;
};
// Different types of threats that SafeBrowsing protects against. This is the
@@ -120,9 +123,11 @@ enum SBThreatType {
// platform_type = WINDOWS,
// threat_entry_type = EXECUTABLE,
// threat_type = MALWARE
-struct ListIdentifier {
+class ListIdentifier {
public:
- ListIdentifier(PlatformType, ThreatEntryType, ThreatType);
+ ListIdentifier(PlatformType platform_type,
+ ThreatEntryType threat_entry_type,
+ ThreatType threat_type);
explicit ListIdentifier(const ListUpdateResponse&);
bool operator==(const ListIdentifier& other) const;
@@ -138,31 +143,31 @@ struct ListIdentifier {
ThreatEntryType threat_entry_type_;
ThreatType threat_type_;
- ListIdentifier();
+ ListIdentifier() = delete;
};
std::ostream& operator<<(std::ostream& os, const ListIdentifier& id);
PlatformType GetCurrentPlatformType();
-const ListIdentifier GetCertCsdDownloadWhitelistId();
-const ListIdentifier GetChromeExtMalwareId();
-const ListIdentifier GetChromeFilenameClientIncidentId();
-const ListIdentifier GetChromeUrlApiId();
-const ListIdentifier GetChromeUrlClientIncidentId();
-const ListIdentifier GetIpMalwareId();
-const ListIdentifier GetUrlCsdDownloadWhitelistId();
-const ListIdentifier GetUrlCsdWhitelistId();
-const ListIdentifier GetUrlMalBinId();
-const ListIdentifier GetUrlMalwareId();
-const ListIdentifier GetUrlSocEngId();
-const ListIdentifier GetUrlSubresourceFilterId();
-const ListIdentifier GetUrlUwsId();
+ListIdentifier GetCertCsdDownloadWhitelistId();
+ListIdentifier GetChromeExtMalwareId();
+ListIdentifier GetChromeFilenameClientIncidentId();
+ListIdentifier GetChromeUrlApiId();
+ListIdentifier GetChromeUrlClientIncidentId();
+ListIdentifier GetIpMalwareId();
+ListIdentifier GetUrlCsdDownloadWhitelistId();
+ListIdentifier GetUrlCsdWhitelistId();
+ListIdentifier GetUrlMalBinId();
+ListIdentifier GetUrlMalwareId();
+ListIdentifier GetUrlSocEngId();
+ListIdentifier GetUrlSubresourceFilterId();
+ListIdentifier GetUrlUwsId();
// Represents the state of each store.
-typedef base::hash_map<ListIdentifier, std::string> StoreStateMap;
+using StoreStateMap = std::unordered_map<ListIdentifier, std::string>;
// Sever response, parsed in vector form.
-typedef std::vector<std::unique_ptr<ListUpdateResponse>> ParsedServerResponse;
+using ParsedServerResponse = std::vector<std::unique_ptr<ListUpdateResponse>>;
// Holds the hash prefix and the store that it matched in.
struct StoreAndHashPrefix {
@@ -170,7 +175,7 @@ struct StoreAndHashPrefix {
ListIdentifier list_id;
HashPrefix hash_prefix;
- explicit StoreAndHashPrefix(ListIdentifier, HashPrefix);
+ StoreAndHashPrefix(ListIdentifier list_id, const HashPrefix& hash_prefix);
~StoreAndHashPrefix();
bool operator==(const StoreAndHashPrefix& other) const;
@@ -178,12 +183,12 @@ struct StoreAndHashPrefix {
size_t hash() const;
private:
- StoreAndHashPrefix();
+ StoreAndHashPrefix() = delete;
};
// Used to track the hash prefix and the store in which a full hash's prefix
// matched.
-typedef std::vector<StoreAndHashPrefix> StoreAndHashPrefixes;
+using StoreAndHashPrefixes = std::vector<StoreAndHashPrefix>;
// Enumerate failures for histogramming purposes. DO NOT CHANGE THE
// ORDERING OF THESE VALUES.
@@ -257,6 +262,8 @@ class V4ProtocolManagerUtil {
// Worker function for calculating the backoff times.
// |multiplier| is doubled for each consecutive error after the
// first, and |error_count| is incremented with each call.
+ // Backoff interval is MIN(((2^(n-1))*15 minutes) * (RAND + 1), 24 hours)
+ // where n is the number of consecutive errors.
static base::TimeDelta GetNextBackOffInterval(size_t* error_count,
size_t* multiplier);
@@ -297,7 +304,8 @@ class V4ProtocolManagerUtil {
FullHash* hashed_encoded_ip);
private:
- V4ProtocolManagerUtil(){};
+ V4ProtocolManagerUtil() {}
+
FRIEND_TEST_ALL_PREFIXES(V4ProtocolManagerUtilTest, TestBackOffLogic);
FRIEND_TEST_ALL_PREFIXES(V4ProtocolManagerUtilTest,
TestGetRequestUrlAndUpdateHeaders);
@@ -330,11 +338,12 @@ class V4ProtocolManagerUtil {
DISALLOW_COPY_AND_ASSIGN(V4ProtocolManagerUtil);
};
-typedef std::unordered_set<ListIdentifier> StoresToCheck;
+using StoresToCheck = std::unordered_set<ListIdentifier>;
} // namespace safe_browsing
namespace std {
+
template <>
struct hash<safe_browsing::PlatformType> {
std::size_t operator()(const safe_browsing::PlatformType& p) const {
@@ -362,6 +371,7 @@ struct hash<safe_browsing::ListIdentifier> {
return id.hash();
}
};
-}
+
+} // namespace std
#endif // COMPONENTS_SAFE_BROWSING_DB_V4_PROTOCOL_MANAGER_UTIL_H_
diff --git a/chromium/components/safe_browsing_db/v4_rice.h b/chromium/components/safe_browsing_db/v4_rice.h
index 4f095ca16ee..8d3f816fd76 100644
--- a/chromium/components/safe_browsing_db/v4_rice.h
+++ b/chromium/components/safe_browsing_db/v4_rice.h
@@ -12,12 +12,7 @@
#include <string>
#include <vector>
#include "base/gtest_prod_util.h"
-
-#if defined(USE_SYSTEM_PROTOBUF)
-#include <google/protobuf/repeated_field.h>
-#else
#include "third_party/protobuf/src/google/protobuf/repeated_field.h"
-#endif
namespace safe_browsing {
diff --git a/chromium/components/safe_browsing_db/v4_store.cc b/chromium/components/safe_browsing_db/v4_store.cc
index c46dc584097..fe3220a1f2b 100644
--- a/chromium/components/safe_browsing_db/v4_store.cc
+++ b/chromium/components/safe_browsing_db/v4_store.cc
@@ -178,10 +178,10 @@ std::ostream& operator<<(std::ostream& os, const V4Store& store) {
return os;
}
-V4Store* V4StoreFactory::CreateV4Store(
+std::unique_ptr<V4Store> V4StoreFactory::CreateV4Store(
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
const base::FilePath& store_path) {
- V4Store* new_store = new V4Store(task_runner, store_path, 0);
+ auto new_store = base::MakeUnique<V4Store>(task_runner, store_path);
new_store->Initialize();
return new_store;
}
diff --git a/chromium/components/safe_browsing_db/v4_store.h b/chromium/components/safe_browsing_db/v4_store.h
index 1a6b14a3514..3fb74edf5f9 100644
--- a/chromium/components/safe_browsing_db/v4_store.h
+++ b/chromium/components/safe_browsing_db/v4_store.h
@@ -5,6 +5,10 @@
#ifndef COMPONENTS_SAFE_BROWSING_DB_V4_STORE_H_
#define COMPONENTS_SAFE_BROWSING_DB_V4_STORE_H_
+#include <memory>
+#include <string>
+#include <unordered_map>
+
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
@@ -15,21 +19,22 @@ namespace safe_browsing {
class V4Store;
-typedef base::Callback<void(std::unique_ptr<V4Store> new_store)>
- UpdatedStoreReadyCallback;
+using UpdatedStoreReadyCallback =
+ base::Callback<void(std::unique_ptr<V4Store> new_store)>;
// The sorted list of hash prefixes.
-typedef std::string HashPrefixes;
+using HashPrefixes = std::string;
// Stores the list of sorted hash prefixes, by size.
// For instance: {4: ["abcd", "bcde", "cdef", "gggg"], 5: ["fffff"]}
-typedef base::hash_map<PrefixSize, HashPrefixes> HashPrefixMap;
+using HashPrefixMap = std::unordered_map<PrefixSize, HashPrefixes>;
// Stores the iterator to the last element merged from the HashPrefixMap for a
// given prefix size.
// For instance: {4:iter(3), 5:iter(1)} means that we have already merged
// 3 hash prefixes of length 4, and 1 hash prefix of length 5.
-typedef base::hash_map<PrefixSize, HashPrefixes::const_iterator> IteratorMap;
+using IteratorMap =
+ std::unordered_map<PrefixSize, HashPrefixes::const_iterator>;
// Enumerate different failure events while parsing the file read from disk for
// histogramming purposes. DO NOT CHANGE THE ORDERING OF THESE VALUES.
@@ -148,7 +153,8 @@ enum ApplyUpdateResult {
class V4StoreFactory {
public:
virtual ~V4StoreFactory() {}
- virtual V4Store* CreateV4Store(
+
+ virtual std::unique_ptr<V4Store> CreateV4Store(
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
const base::FilePath& store_path);
};
@@ -165,9 +171,21 @@ class V4Store {
// applying an update.
V4Store(const scoped_refptr<base::SequencedTaskRunner>& task_runner,
const base::FilePath& store_path,
- const int64_t old_file_size = 0);
+ int64_t old_file_size = 0);
virtual ~V4Store();
+ // Schedules the destruction of the V4Store object pointed to by |v4_store|,
+ // on the task runner.
+ static void Destroy(std::unique_ptr<V4Store> v4_store);
+
+ // If a hash prefix in this store matches |full_hash|, returns that hash
+ // prefix; otherwise returns an empty hash prefix.
+ virtual HashPrefix GetMatchingHashPrefix(const FullHash& full_hash);
+
+ // True if this store has valid contents, either from a successful read
+ // from disk or a full update. This does not mean the checksum was verified.
+ virtual bool HasValidData() const;
+
const std::string& state() const { return state_; }
const base::FilePath& store_path() const { return store_path_; }
@@ -180,24 +198,12 @@ class V4Store {
// store using |base_metric| as prefix and the filename as suffix.
int64_t RecordAndReturnFileSize(const std::string& base_metric);
- // If a hash prefix in this store matches |full_hash|, returns that hash
- // prefix; otherwise returns an empty hash prefix.
- virtual HashPrefix GetMatchingHashPrefix(const FullHash& full_hash);
-
std::string DebugString() const;
- // Schedules the destruction of the V4Store object pointed to by |v4_store|,
- // on the task runner.
- static void Destroy(std::unique_ptr<V4Store> v4_store);
-
// Reads the store file from disk and populates the in-memory representation
// of the hash prefixes.
void Initialize();
- // True if this store has valid contents, either from a successful read
- // from disk or a full update. This does not mean the checksum was verified.
- virtual bool HasValidData() const;
-
// Reset internal state.
void Reset();
@@ -209,6 +215,9 @@ class V4Store {
// which blocks resource loads.
bool VerifyChecksum();
+ protected:
+ HashPrefixMap hash_prefix_map_;
+
private:
FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestReadFromEmptyFile);
FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestReadFromAbsentFile);
@@ -391,10 +400,6 @@ class V4Store {
// |checksum| is used to set the |checksum| field in the final proto.
StoreWriteResult WriteToDisk(const Checksum& checksum);
- protected:
- HashPrefixMap hash_prefix_map_;
-
- private:
// The checksum value as read from the disk, until it is verified. Once
// verified, it is cleared.
std::string expected_checksum_;
diff --git a/chromium/components/search_engines/default_search_manager_unittest.cc b/chromium/components/search_engines/default_search_manager_unittest.cc
index f2a12757b92..5e72128e705 100644
--- a/chromium/components/search_engines/default_search_manager_unittest.cc
+++ b/chromium/components/search_engines/default_search_manager_unittest.cc
@@ -7,9 +7,11 @@
#include <stddef.h>
#include <memory>
+#include <utility>
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -30,8 +32,8 @@ namespace {
void SetOverrides(sync_preferences::TestingPrefServiceSyncable* prefs,
bool update) {
prefs->SetUserPref(prefs::kSearchProviderOverridesVersion,
- new base::Value(1));
- base::ListValue* overrides = new base::ListValue;
+ base::MakeUnique<base::Value>(1));
+ auto overrides = base::MakeUnique<base::ListValue>();
std::unique_ptr<base::DictionaryValue> entry(new base::DictionaryValue);
entry->SetString("name", update ? "new_foo" : "foo");
@@ -59,7 +61,7 @@ void SetOverrides(sync_preferences::TestingPrefServiceSyncable* prefs,
entry->SetString("keyword", "bazk");
entry->SetString("encoding", "UTF-8");
overrides->Append(entry->CreateDeepCopy());
- prefs->SetUserPref(prefs::kSearchProviderOverrides, overrides);
+ prefs->SetUserPref(prefs::kSearchProviderOverrides, std::move(overrides));
}
void SetPolicy(sync_preferences::TestingPrefServiceSyncable* prefs,
@@ -74,7 +76,7 @@ void SetPolicy(sync_preferences::TestingPrefServiceSyncable* prefs,
entry->SetBoolean(DefaultSearchManager::kDisabledByPolicy, !enabled);
prefs->SetManagedPref(
DefaultSearchManager::kDefaultSearchProviderDataPrefName,
- entry.release());
+ std::move(entry));
}
} // namespace
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 02b9dcdf5cc..a8c86e13def 100644
--- a/chromium/components/search_engines/default_search_policy_handler_unittest.cc
+++ b/chromium/components/search_engines/default_search_policy_handler_unittest.cc
@@ -84,19 +84,19 @@ void DefaultSearchPolicyHandlerTest::
base::MakeUnique<base::Value>(true), nullptr);
policy->Set(key::kDefaultSearchProviderSearchURL, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::MakeUnique<base::StringValue>(kSearchURL), nullptr);
+ base::MakeUnique<base::Value>(kSearchURL), nullptr);
policy->Set(key::kDefaultSearchProviderName, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::MakeUnique<base::StringValue>(kName), nullptr);
+ base::MakeUnique<base::Value>(kName), nullptr);
policy->Set(key::kDefaultSearchProviderKeyword, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::MakeUnique<base::StringValue>(kKeyword), nullptr);
+ base::MakeUnique<base::Value>(kKeyword), nullptr);
policy->Set(key::kDefaultSearchProviderSuggestURL, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::MakeUnique<base::StringValue>(kSuggestURL), nullptr);
+ base::MakeUnique<base::Value>(kSuggestURL), nullptr);
policy->Set(key::kDefaultSearchProviderIconURL, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::MakeUnique<base::StringValue>(kIconURL), nullptr);
+ base::MakeUnique<base::Value>(kIconURL), nullptr);
policy->Set(key::kDefaultSearchProviderEncodings, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
base::WrapUnique(encodings), nullptr);
@@ -105,16 +105,16 @@ void DefaultSearchPolicyHandlerTest::
default_alternate_urls_.CreateDeepCopy(), nullptr);
policy->Set(key::kDefaultSearchProviderSearchTermsReplacementKey,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::MakeUnique<base::StringValue>(kReplacementKey), nullptr);
+ base::MakeUnique<base::Value>(kReplacementKey), nullptr);
policy->Set(key::kDefaultSearchProviderImageURL, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::MakeUnique<base::StringValue>(kImageURL), nullptr);
+ base::MakeUnique<base::Value>(kImageURL), nullptr);
policy->Set(key::kDefaultSearchProviderImageURLPostParams,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::MakeUnique<base::StringValue>(kImageParams), nullptr);
+ base::MakeUnique<base::Value>(kImageParams), nullptr);
policy->Set(key::kDefaultSearchProviderNewTabURL, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::MakeUnique<base::StringValue>(kNewTabURL), nullptr);
+ base::MakeUnique<base::Value>(kNewTabURL), nullptr);
}
// Checks that if the default search policy is missing, that no elements of the
@@ -138,7 +138,7 @@ TEST_F(DefaultSearchPolicyHandlerTest, Invalid) {
const char bad_search_url[] = "http://test.com/noSearchTerms";
policy.Set(key::kDefaultSearchProviderSearchURL, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::WrapUnique(new base::StringValue(bad_search_url)), nullptr);
+ base::WrapUnique(new base::Value(bad_search_url)), nullptr);
UpdateProviderPolicy(policy);
const base::Value* temp = nullptr;
@@ -285,7 +285,7 @@ TEST_F(DefaultSearchPolicyHandlerTest, MinimallyDefined) {
base::WrapUnique(new base::Value(true)), nullptr);
policy.Set(key::kDefaultSearchProviderSearchURL, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::WrapUnique(new base::StringValue(kSearchURL)), nullptr);
+ base::WrapUnique(new base::Value(kSearchURL)), nullptr);
UpdateProviderPolicy(policy);
const base::Value* temp = NULL;
@@ -344,7 +344,7 @@ TEST_F(DefaultSearchPolicyHandlerTest, FileURL) {
base::WrapUnique(new base::Value(true)), nullptr);
policy.Set(key::kDefaultSearchProviderSearchURL, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::WrapUnique(new base::StringValue(kFileSearchURL)), nullptr);
+ base::WrapUnique(new base::Value(kFileSearchURL)), nullptr);
UpdateProviderPolicy(policy);
const base::Value* temp = NULL;
diff --git a/chromium/components/search_engines/keyword_table.cc b/chromium/components/search_engines/keyword_table.cc
index 8ca529c1fb1..a9348870641 100644
--- a/chromium/components/search_engines/keyword_table.cc
+++ b/chromium/components/search_engines/keyword_table.cc
@@ -13,6 +13,7 @@
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -37,7 +38,7 @@ namespace {
const char kBuiltinKeywordVersion[] = "Builtin Keyword Version";
const std::string ColumnsForVersion(int version, bool concatenated) {
- std::vector<std::string> columns;
+ std::vector<base::StringPiece> columns;
columns.push_back("id");
columns.push_back("short_name");
diff --git a/chromium/components/search_engines/prepopulated_engines.json b/chromium/components/search_engines/prepopulated_engines.json
index 3409ecc4a77..3ebf56b8918 100644
--- a/chromium/components/search_engines/prepopulated_engines.json
+++ b/chromium/components/search_engines/prepopulated_engines.json
@@ -30,7 +30,7 @@
// Increment this if you change the data in ways that mean users with
// existing data should get a new version.
- "kCurrentDataVersion": 97
+ "kCurrentDataVersion": 98
},
// The following engines are included in country lists and are added to the
@@ -39,8 +39,8 @@
"aol": {
"name": "AOL",
"keyword": "aol.com",
- "favicon_url": "http://search.aol.com/favicon.ico",
- "search_url": "http://search.aol.com/aol/search?q={searchTerms}",
+ "favicon_url": "https://search.aol.com/favicon.ico",
+ "search_url": "https://search.aol.com/aol/search?q={searchTerms}",
"suggest_url": "http://autocomplete.search.aol.com/autocomplete/get?output=json&it=&q={searchTerms}",
"type": "SEARCH_ENGINE_AOL",
"id": 35
@@ -78,8 +78,8 @@
"baidu": {
"name": "\u767e\u5ea6",
"keyword": "baidu.com",
- "favicon_url": "http://www.baidu.com/favicon.ico",
- "search_url": "http://www.baidu.com/#ie={inputEncoding}&wd={searchTerms}",
+ "favicon_url": "https://www.baidu.com/favicon.ico",
+ "search_url": "https://www.baidu.com/#ie={inputEncoding}&wd={searchTerms}",
"suggest_url": "http://suggestion.baidu.com/su?wd={searchTerms}&action=opensearch&ie={inputEncoding}",
"type": "SEARCH_ENGINE_BAIDU",
"id": 21
@@ -134,8 +134,8 @@
"kvasir": {
"name": "Kvasir",
"keyword": "kvasir.no",
- "favicon_url": "http://kvasir.no/grafikk/favicon.ico",
- "search_url": "http://kvasir.no/alle?q={searchTerms}",
+ "favicon_url": "https://kvasir.no/grafikk/favicon.ico",
+ "search_url": "https://kvasir.no/alle?q={searchTerms}",
"type": "SEARCH_ENGINE_KVASIR",
"id": 73
},
@@ -143,10 +143,10 @@
"mail_ru": {
"name": "@MAIL.RU",
"keyword": "mail.ru",
- "favicon_url": "http://go.imgsmail.ru/favicon.ico",
- "search_url": "http://go.mail.ru/search?q={searchTerms}",
+ "favicon_url": "https://go.imgsmail.ru/favicon.ico",
+ "search_url": "https://go.mail.ru/search?q={searchTerms}",
"encoding": "windows-1251",
- "suggest_url": "http://suggests.go.mail.ru/chrome?q={searchTerms}",
+ "suggest_url": "https://suggests.go.mail.ru/chrome?q={searchTerms}",
"type": "SEARCH_ENGINE_MAILRU",
"id": 83
},
@@ -154,8 +154,8 @@
"najdi": {
"name": "Najdi.si",
"keyword": "najdi.si",
- "favicon_url": "http://www.najdi.si/assets/PROD-1.4.10/ctx/images/favicon.ico",
- "search_url": "http://www.najdi.si/search.jsp?q={searchTerms}",
+ "favicon_url": "https://www.najdi.si/assets/PROD-1.5.16/ctx/images/favicon.ico",
+ "search_url": "https://www.najdi.si/search.jsp?q={searchTerms}",
"type": "SEARCH_ENGINE_NAJDI",
"id": 87
},
@@ -182,9 +182,9 @@
"seznam": {
"name": "Seznam",
"keyword": "seznam.cz",
- "favicon_url": "http://search.seznam.cz/r/img/favicon.ico",
- "search_url": "http://search.seznam.cz/?q={searchTerms}",
- "suggest_url": "http://suggest.fulltext.seznam.cz/fulltext_ff?phrase={searchTerms}",
+ "favicon_url": "https://search.seznam.cz/r/img/favicon.ico",
+ "search_url": "https://search.seznam.cz/?q={searchTerms}",
+ "suggest_url": "https://suggest.fulltext.seznam.cz/fulltext_ff?phrase={searchTerms}",
"type": "SEARCH_ENGINE_SEZNAM",
"id": 25
},
@@ -212,8 +212,8 @@
"vinden": {
"name": "Vinden.nl",
"keyword": "vinden.nl",
- "favicon_url": "http://www.vinden.nl/favicon.ico",
- "search_url": "http://www.vinden.nl/?q={searchTerms}",
+ "favicon_url": "https://www.vinden.nl/favicon.ico",
+ "search_url": "https://www.vinden.nl/?q={searchTerms}",
"type": "SEARCH_ENGINE_VINDEN",
"id": 53
},
@@ -412,9 +412,9 @@
"yahoo_jp": {
"name": "Yahoo! JAPAN",
"keyword": "yahoo.co.jp",
- "favicon_url": "http://search.yahoo.co.jp/favicon.ico",
- "search_url": "http://search.yahoo.co.jp/search?ei={inputEncoding}&fr=crmas&p={searchTerms}",
- "suggest_url": "http://search.yahooapis.jp/AssistSearchService/V2/webassistSearch?p={searchTerms}&appid=oQsoxcyxg66enp0TYoirkKoryq6rF8bK76mW0KYxZ0v0WPLtn.Lix6wy8F_LwGWHUII-&output=fxjson&fr=crmas",
+ "favicon_url": "https://search.yahoo.co.jp/favicon.ico",
+ "search_url": "https://search.yahoo.co.jp/search?ei={inputEncoding}&fr=crmas&p={searchTerms}",
+ "suggest_url": "https://search.yahooapis.jp/AssistSearchService/V2/webassistSearch?p={searchTerms}&appid=oQsoxcyxg66enp0TYoirkKoryq6rF8bK76mW0KYxZ0v0WPLtn.Lix6wy8F_LwGWHUII-&output=fxjson&fr=crmas",
"type": "SEARCH_ENGINE_YAHOO",
"id": 2
},
@@ -683,7 +683,9 @@
"search_url": "http://search.avg.com/search?q={searchTerms}",
"alternate_urls": [
"http://isearch.avg.com/search?q={searchTerms}",
- "http://search.avg.com/route/?q={searchTerms}&lng={language}"
+ "http://search.avg.com/route/?q={searchTerms}&lng={language}",
+ "https://isearch.avg.com/search?q={searchTerms}",
+ "https://search.avg.com/route/?q={searchTerms}&lng={language}"
],
"type": "SEARCH_ENGINE_AVG",
"id": 50
@@ -767,9 +769,13 @@
"goo": {
"name": "goo",
"keyword": "search.goo.ne.jp",
- "favicon_url": "http://goo.ne.jp/favicon.ico",
- "search_url": "http://search.goo.ne.jp/web.jsp?MT={searchTerms}&IE={inputEncoding}",
- "suggest_url": "http://search.goo.ne.jp/sgt.jsp?MT={searchTerms}&CL=plugin&FM=json&IE={inputEncoding}",
+ "favicon_url": "https://search.goo.ne.jp/cdn/common/img/favicon.ico",
+ "search_url": "https://search.goo.ne.jp/web.jsp?MT={searchTerms}&IE={inputEncoding}",
+ "suggest_url": "https://search.goo.ne.jp/sgt.jsp?MT={searchTerms}&CL=plugin&FM=json&IE={inputEncoding}",
+ "alternate_urls": [
+ "http://search.goo.ne.jp/web.jsp?MT={searchTerms}&IE={inputEncoding}",
+ "http://search.goo.ne.jp/sgt.jsp?MT={searchTerms}&CL=plugin&FM=json&IE={inputEncoding}"
+ ],
"encoding": "EUC-JP",
"type": "SEARCH_ENGINE_GOO",
"id": 23
@@ -837,6 +843,10 @@
"favicon_url": "http://www.neti.ee/favicon.ico",
"search_url": "http://www.neti.ee/cgi-bin/otsing?query={searchTerms}",
"suggest_url": "http://www.neti.ee/api/suggestOS?suggestQuery={searchTerms}",
+ "alternate_urls": [
+ "https://www.neti.ee/cgi-bin/otsing?query={searchTerms}&src=web",
+ "https://www.neti.ee/api/suggestOS?suggestVersion=1&suggestQuery={searchTerms}"
+ ],
"encoding": "ISO-8859-1",
"type": "SEARCH_ENGINE_NETI",
"id": 44
@@ -865,9 +875,13 @@
"rambler": {
"name": "\u0420\u0430\u043c\u0431\u043b\u0435\u0440",
"keyword": "rambler.ru",
- "favicon_url": "http://nova.rambler.ru/static/blocks/images/favicon.ico",
+ "favicon_url": "http://i.rl0.ru/2011/icons/rambler.ico",
"search_url": "http://nova.rambler.ru/search?query={searchTerms}",
"suggest_url": "http://nova.rambler.ru/suggest?v=3&query={searchTerms}",
+ "alternate_urls": [
+ "https://nova.rambler.ru/search?query={searchTerms}",
+ "https://nova.rambler.ru/suggest?v=3&query={searchTerms}"
+ ],
"type": "SEARCH_ENGINE_RAMBLER",
"id": 16
},
@@ -927,7 +941,13 @@
"http://www.softonic.com/s/{searchTerms}",
"http://www.softonic.com.br/s/{searchTerms}",
"http://buscador.softonic.com/?q={searchTerms}",
- "http://nl.softonic.com/s/{searchTerms}"
+ "http://nl.softonic.com/s/{searchTerms}",
+ "https://search.softonic.com/?q={searchTerms}",
+ "https://en.softonic.com/s/{searchTerms}",
+ "https://www.softonic.com/s/{searchTerms}",
+ "https://www.softonic.com.br/s/{searchTerms}",
+ "https://buscador.softonic.com/?q={searchTerms}",
+ "https://nl.softonic.com/s/{searchTerms}"
],
"type": "SEARCH_ENGINE_SOFTONIC",
"id": 80
@@ -960,6 +980,9 @@
"keyword": "terra.com.ar",
"favicon_url": "http://buscar.terra.com.ar/favicon.ico",
"search_url": "http://buscar.terra.com.ar/Default.aspx?source=Search&ca=s&query={searchTerms}",
+ "alternate_urls": [
+ "https://buscador.terra.com.ar/Default.aspx?source=Search&ca=s&query={searchTerms}"
+ ],
"encoding": "ISO-8859-1",
"type": "SEARCH_ENGINE_TERRA",
"id": 90
@@ -970,6 +993,9 @@
"keyword": "terra.es",
"favicon_url": "http://buscador.terra.es/favicon.ico",
"search_url": "http://buscador.terra.es/Default.aspx?source=Search&ca=s&query={searchTerms}",
+ "alternate_urls": [
+ "https://buscador.terra.es/Default.aspx?source=Search&ca=s&query={searchTerms}"
+ ],
"encoding": "ISO-8859-1",
"type": "SEARCH_ENGINE_TERRA",
"id": 90
@@ -990,6 +1016,9 @@
"keyword": "walla.co.il",
"favicon_url": "http://www.walla.co.il/favicon.ico",
"search_url": "http://search.walla.co.il/?q={searchTerms}",
+ "alternate_urls": [
+ "https://search.walla.co.il/?q={searchTerms}"
+ ],
"type": "SEARCH_ENGINE_WALLA",
"id": 55
},
diff --git a/chromium/components/search_engines/search_engines_test_util.cc b/chromium/components/search_engines/search_engines_test_util.cc
index 1d54c7cce1d..b1b005d680e 100644
--- a/chromium/components/search_engines/search_engines_test_util.cc
+++ b/chromium/components/search_engines/search_engines_test_util.cc
@@ -4,6 +4,8 @@
#include "components/search_engines/search_engines_test_util.h"
+#include <utility>
+
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -66,7 +68,7 @@ void SetExtensionDefaultSearchInPrefs(
TemplateURLDataToDictionary(data);
prefs->SetExtensionPref(
DefaultSearchManager::kDefaultSearchProviderDataPrefName,
- entry.release());
+ std::move(entry));
}
void RemoveExtensionDefaultSearchFromPrefs(
diff --git a/chromium/components/search_engines/template_url.cc b/chromium/components/search_engines/template_url.cc
index da62aaa3c13..a3a162a0a26 100644
--- a/chromium/components/search_engines/template_url.cc
+++ b/chromium/components/search_engines/template_url.cc
@@ -505,7 +505,9 @@ bool TemplateURLRef::ExtractSearchTermsFromURL(
// suffix, then this is not a match.
base::StringPiece search_term =
base::StringPiece(source).substr(value.begin, value.len);
- if (!search_term.starts_with(search_term_value_prefix_) ||
+ if (search_term.size() < (search_term_value_prefix_.size() +
+ search_term_value_suffix_.size()) ||
+ !search_term.starts_with(search_term_value_prefix_) ||
!search_term.ends_with(search_term_value_suffix_))
continue;
diff --git a/chromium/components/search_engines/template_url_data_util.cc b/chromium/components/search_engines/template_url_data_util.cc
index ab76c92ab57..fd3138b7bc7 100644
--- a/chromium/components/search_engines/template_url_data_util.cc
+++ b/chromium/components/search_engines/template_url_data_util.cc
@@ -90,7 +90,7 @@ std::unique_ptr<TemplateURLData> TemplateURLDataFromDictionary(
if (dict.GetList(DefaultSearchManager::kAlternateURLs, &alternate_urls)) {
for (const auto& it : *alternate_urls) {
std::string alternate_url;
- if (it->GetAsString(&alternate_url))
+ if (it.GetAsString(&alternate_url))
result->alternate_urls.push_back(std::move(alternate_url));
}
}
@@ -99,7 +99,7 @@ std::unique_ptr<TemplateURLData> TemplateURLDataFromDictionary(
if (dict.GetList(DefaultSearchManager::kInputEncodings, &encodings)) {
for (const auto& it : *encodings) {
std::string encoding;
- if (it->GetAsString(&encoding))
+ if (it.GetAsString(&encoding))
result->input_encodings.push_back(std::move(encoding));
}
}
diff --git a/chromium/components/search_engines/template_url_fetcher.cc b/chromium/components/search_engines/template_url_fetcher.cc
index 0db1184388f..eb9e90af07e 100644
--- a/chromium/components/search_engines/template_url_fetcher.cc
+++ b/chromium/components/search_engines/template_url_fetcher.cc
@@ -32,7 +32,7 @@ constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
"corresponding search engine is added to the list in the browser "
"settings (chrome://settings/searchEngines)."
trigger:
- "User visits a web page containing a <link rel="search"> tag."
+ "User visits a web page containing a <link rel=\"search\"> tag."
data: "None"
destination: WEBSITE
}
diff --git a/chromium/components/search_engines/template_url_prepopulate_data_unittest.cc b/chromium/components/search_engines/template_url_prepopulate_data_unittest.cc
index 44ac82702f9..08c323e07c3 100644
--- a/chromium/components/search_engines/template_url_prepopulate_data_unittest.cc
+++ b/chromium/components/search_engines/template_url_prepopulate_data_unittest.cc
@@ -120,8 +120,8 @@ TEST_F(TemplateURLPrepopulateDataTest, UniqueIDs) {
// override the built-in ones.
TEST_F(TemplateURLPrepopulateDataTest, ProvidersFromPrefs) {
prefs_.SetUserPref(prefs::kSearchProviderOverridesVersion,
- new base::Value(1));
- base::ListValue* overrides = new base::ListValue;
+ base::MakeUnique<base::Value>(1));
+ auto overrides = base::MakeUnique<base::ListValue>();
std::unique_ptr<base::DictionaryValue> entry(new base::DictionaryValue);
// Set only the minimal required settings for a search provider configuration.
entry->SetString("name", "foo");
@@ -131,7 +131,7 @@ TEST_F(TemplateURLPrepopulateDataTest, ProvidersFromPrefs) {
entry->SetString("encoding", "UTF-8");
entry->SetInteger("id", 1001);
overrides->Append(entry->CreateDeepCopy());
- prefs_.SetUserPref(prefs::kSearchProviderOverrides, overrides);
+ prefs_.SetUserPref(prefs::kSearchProviderOverrides, std::move(overrides));
int version = TemplateURLPrepopulateData::GetDataVersion(&prefs_);
EXPECT_EQ(1, version);
@@ -163,9 +163,9 @@ TEST_F(TemplateURLPrepopulateDataTest, ProvidersFromPrefs) {
alternate_urls->AppendString("http://foo.com/alternate?q={searchTerms}");
entry->Set("alternate_urls", alternate_urls);
entry->SetString("search_terms_replacement_key", "espv");
- overrides = new base::ListValue;
+ overrides = base::MakeUnique<base::ListValue>();
overrides->Append(entry->CreateDeepCopy());
- prefs_.SetUserPref(prefs::kSearchProviderOverrides, overrides);
+ prefs_.SetUserPref(prefs::kSearchProviderOverrides, std::move(overrides));
t_urls = TemplateURLPrepopulateData::GetPrepopulatedEngines(
&prefs_, &default_index);
@@ -187,7 +187,7 @@ TEST_F(TemplateURLPrepopulateDataTest, ProvidersFromPrefs) {
// Test that subsequent providers are loaded even if an intermediate
// provider has an incomplete configuration.
- overrides = new base::ListValue;
+ overrides = base::MakeUnique<base::ListValue>();
overrides->Append(entry->CreateDeepCopy());
entry->SetInteger("id", 1002);
entry->SetString("name", "bar");
@@ -199,7 +199,7 @@ TEST_F(TemplateURLPrepopulateDataTest, ProvidersFromPrefs) {
entry->SetString("keyword", "bazk");
entry->SetString("encoding", "UTF-8");
overrides->Append(entry->CreateDeepCopy());
- prefs_.SetUserPref(prefs::kSearchProviderOverrides, overrides);
+ prefs_.SetUserPref(prefs::kSearchProviderOverrides, std::move(overrides));
t_urls =
TemplateURLPrepopulateData::GetPrepopulatedEngines(&prefs_,
@@ -209,8 +209,8 @@ TEST_F(TemplateURLPrepopulateDataTest, ProvidersFromPrefs) {
TEST_F(TemplateURLPrepopulateDataTest, ClearProvidersFromPrefs) {
prefs_.SetUserPref(prefs::kSearchProviderOverridesVersion,
- new base::Value(1));
- base::ListValue* overrides = new base::ListValue;
+ base::MakeUnique<base::Value>(1));
+ auto overrides = base::MakeUnique<base::ListValue>();
std::unique_ptr<base::DictionaryValue> entry(new base::DictionaryValue);
// Set only the minimal required settings for a search provider configuration.
entry->SetString("name", "foo");
@@ -220,7 +220,7 @@ TEST_F(TemplateURLPrepopulateDataTest, ClearProvidersFromPrefs) {
entry->SetString("encoding", "UTF-8");
entry->SetInteger("id", 1001);
overrides->Append(std::move(entry));
- prefs_.SetUserPref(prefs::kSearchProviderOverrides, overrides);
+ prefs_.SetUserPref(prefs::kSearchProviderOverrides, std::move(overrides));
int version = TemplateURLPrepopulateData::GetDataVersion(&prefs_);
EXPECT_EQ(1, version);
diff --git a/chromium/components/search_engines/template_url_service.cc b/chromium/components/search_engines/template_url_service.cc
index bd5e5d66486..a4db5e184d0 100644
--- a/chromium/components/search_engines/template_url_service.cc
+++ b/chromium/components/search_engines/template_url_service.cc
@@ -11,6 +11,8 @@
#include "base/callback.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
+#include "base/debug/crash_logging.h"
+#include "base/format_macros.h"
#include "base/guid.h"
#include "base/i18n/case_conversion.h"
#include "base/memory/ptr_util.h"
@@ -18,6 +20,7 @@
#include "base/profiler/scoped_tracker.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
@@ -364,12 +367,12 @@ bool TemplateURLService::CanAddAutogeneratedKeyword(
}
bool TemplateURLService::IsPrepopulatedOrCreatedByPolicy(
- const TemplateURL* t_url) {
+ const TemplateURL* t_url) const {
return (t_url->prepopulate_id() > 0 || t_url->created_by_policy()) &&
t_url->SupportsReplacement(search_terms_data());
}
-bool TemplateURLService::ShowInDefaultList(const TemplateURL* t_url) {
+bool TemplateURLService::ShowInDefaultList(const TemplateURL* t_url) const {
return t_url == default_search_provider_ ||
IsPrepopulatedOrCreatedByPolicy(t_url);
}
@@ -567,7 +570,7 @@ void TemplateURLService::ResetTemplateURL(TemplateURL* url,
NotifyObservers();
}
-bool TemplateURLService::CanMakeDefault(const TemplateURL* url) {
+bool TemplateURLService::CanMakeDefault(const TemplateURL* url) const {
return
((default_search_provider_source_ == DefaultSearchManager::FROM_USER) ||
(default_search_provider_source_ ==
@@ -618,7 +621,7 @@ bool TemplateURLService::IsSearchResultsPageFromDefaultSearchProvider(
default_provider->IsSearchURL(url, search_terms_data());
}
-bool TemplateURLService::IsExtensionControlledDefaultSearch() {
+bool TemplateURLService::IsExtensionControlledDefaultSearch() const {
return default_search_provider_source_ ==
DefaultSearchManager::FROM_EXTENSION;
}
@@ -668,18 +671,7 @@ void TemplateURLService::RepairPrepopulatedSearchEngines() {
default_search_manager_.ClearUserSelectedDefaultSearchEngine();
- if (!default_search_provider_) {
- // If the default search provider came from a user pref we would have been
- // notified of the new (fallback-provided) value in
- // ClearUserSelectedDefaultSearchEngine() above. Since we are here, the
- // value was presumably originally a fallback value (which may have been
- // repaired).
- DefaultSearchManager::Source source;
- const TemplateURLData* new_dse =
- default_search_manager_.GetDefaultSearchEngine(&source);
- // ApplyDefaultSearchChange will notify observers once it is done.
- ApplyDefaultSearchChange(new_dse, source);
- } else {
+ if (default_search_provider_) {
// Set fallback engine as user selected, because repair is considered a user
// action and we are expected to sync new fallback engine to other devices.
const TemplateURLData* fallback_engine_data =
@@ -689,7 +681,7 @@ void TemplateURLService::RepairPrepopulatedSearchEngines() {
FindPrepopulatedTemplateURL(fallback_engine_data->prepopulate_id);
// The fallback engine is created from built-in/override data that should
// always have a prepopulate ID, so this engine should always exist after
- // a repair."
+ // a repair.
DCHECK(fallback_engine);
// Write the fallback engine's GUID to prefs, which will cause
// OnSyncedDefaultSearchProviderGUIDChanged() to set it as the new
@@ -698,6 +690,18 @@ void TemplateURLService::RepairPrepopulatedSearchEngines() {
fallback_engine->sync_guid());
}
NotifyObservers();
+ RequestGoogleURLTrackerServerCheckIfNecessary();
+ } else {
+ // If the default search provider came from a user pref we would have been
+ // notified of the new (fallback-provided) value in
+ // ClearUserSelectedDefaultSearchEngine() above. Since we are here, the
+ // value was presumably originally a fallback value (which may have been
+ // repaired).
+ DefaultSearchManager::Source source;
+ const TemplateURLData* new_dse =
+ default_search_manager_.GetDefaultSearchEngine(&source);
+ // ApplyDefaultSearchChange will notify observers once it is done.
+ ApplyDefaultSearchChange(new_dse, source);
}
}
@@ -846,8 +850,11 @@ void TemplateURLService::OnWebDataServiceRequestDone(
base::string16 TemplateURLService::GetKeywordShortName(
const base::string16& keyword,
- bool* is_omnibox_api_extension_keyword) {
- const TemplateURL* template_url = GetTemplateURLForKeyword(keyword);
+ bool* is_omnibox_api_extension_keyword) const {
+ // TODO(jeffschiller): Make GetTemplateURLForKeyword const and remove the
+ // const_cast.
+ const TemplateURL* template_url =
+ const_cast<TemplateURLService*>(this)->GetTemplateURLForKeyword(keyword);
// TODO(sky): Once LocationBarView adds a listener to the TemplateURLService
// to track changes to the model, this should become a DCHECK.
@@ -868,6 +875,9 @@ void TemplateURLService::OnHistoryURLVisited(const URLVisitedDetails& details) {
}
void TemplateURLService::Shutdown() {
+ for (auto& observer : model_observers_)
+ observer.OnTemplateURLServiceShuttingDown();
+
if (client_)
client_->Shutdown();
// This check has to be done at Shutdown() instead of in the dtor to ensure
@@ -1437,6 +1447,10 @@ TemplateURL* TemplateURLService::BestEngineForKeyword(TemplateURL* engine1,
DCHECK(engine2);
DCHECK_EQ(engine1->keyword(), engine2->keyword());
+ // We should only have overlapping keywords when at least one comes from
+ // an extension.
+ DCHECK(IsCreatedByExtension(engine1) || IsCreatedByExtension(engine2));
+
// TODO(a-v-y) Remove following code for non extension engines when reasons
// for crash https://bugs.chromium.org/p/chromium/issues/detail?id=697745
// become clear.
@@ -1462,11 +1476,9 @@ void TemplateURLService::RemoveFromMaps(TemplateURL* template_url) {
DCHECK_NE(0U, keyword_to_turl_and_length_.count(keyword));
if (keyword_to_turl_and_length_[keyword].first == template_url) {
// We need to check whether the keyword can now be provided by another
- // TemplateURL. See the comments in AddToMaps() for more information on
- // extension keywords and how they can coexist with non-extension keywords.
- // In the case of more than one extension, we use the most recently
- // installed (which will be the most recently added, which will have the
- // highest ID).
+ // TemplateURL. See the comments for BestEngineForKeyword() for more
+ // information on extension keywords and how they can coexist with
+ // non-extension keywords.
TemplateURL* best_fallback = nullptr;
for (const auto& turl : template_urls_) {
if ((turl.get() != template_url) && (turl->keyword() == keyword)) {
@@ -1507,6 +1519,7 @@ void TemplateURLService::AddToMaps(TemplateURL* template_url) {
AddToDomainMap(template_url);
} else {
TemplateURL* existing_url = i->second.first;
+ DCHECK_NE(existing_url, template_url);
if (BestEngineForKeyword(existing_url, template_url) != existing_url) {
RemoveFromDomainMap(existing_url);
AddToMap(template_url);
@@ -1619,7 +1632,7 @@ void TemplateURLService::ChangeToLoadedState() {
}
bool TemplateURLService::CanAddAutogeneratedKeywordForHost(
- const std::string& host) {
+ const std::string& host) const {
const TemplateURLSet* urls = provider_map_->GetURLsForHost(host);
if (!urls)
return true;
@@ -1630,7 +1643,7 @@ bool TemplateURLService::CanAddAutogeneratedKeywordForHost(
return true;
}
-bool TemplateURLService::CanReplace(const TemplateURL* t_url) {
+bool TemplateURLService::CanReplace(const TemplateURL* t_url) const {
return !ShowInDefaultList(t_url) && t_url->safe_for_autoreplace();
}
@@ -1652,80 +1665,60 @@ TemplateURL* TemplateURLService::FindNonExtensionTemplateURLForKeyword(
bool TemplateURLService::UpdateNoNotify(TemplateURL* existing_turl,
const TemplateURL& new_values) {
DCHECK(existing_turl);
+ DCHECK(!IsCreatedByExtension(existing_turl));
if (!Contains(&template_urls_, existing_turl))
return false;
- DCHECK(!IsCreatedByExtension(existing_turl));
-
- base::string16 old_keyword(existing_turl->keyword());
- keyword_to_turl_and_length_.erase(old_keyword);
- RemoveFromDomainMap(existing_turl);
- if (!existing_turl->sync_guid().empty())
- guid_to_turl_.erase(existing_turl->sync_guid());
-
- // |provider_map_| is only initialized after loading has completed.
- if (loaded_)
- provider_map_->Remove(existing_turl);
-
+ base::string16 old_keyword = existing_turl->keyword();
TemplateURLID previous_id = existing_turl->id();
+ RemoveFromMaps(existing_turl);
+
+ // Check if new keyword conflicts with another normal engine.
+ // This is possible when autogeneration of the keyword for a Google default
+ // search provider at load time causes it to conflict with an existing
+ // keyword. In this case we delete the existing keyword if it's replaceable,
+ // or else undo the change in keyword for |existing_turl|.
+ // Conflicts with extension engines are handled in AddToMaps/RemoveFromMaps
+ // functions.
+ // Search for conflicting keyword turl before updating values of
+ // existing_turl.
+ TemplateURL* conflicting_keyword_turl =
+ FindNonExtensionTemplateURLForKeyword(new_values.keyword());
+
+ // Update existing turl with new values.
existing_turl->CopyFrom(new_values);
existing_turl->data_.id = previous_id;
- if (loaded_) {
- provider_map_->Add(existing_turl, search_terms_data());
+ if (conflicting_keyword_turl && conflicting_keyword_turl != existing_turl) {
+ if (CanReplace(conflicting_keyword_turl))
+ RemoveNoNotify(conflicting_keyword_turl);
+ else
+ existing_turl->data_.SetKeyword(old_keyword);
}
- const base::string16& keyword = existing_turl->keyword();
- KeywordToTURLAndMeaningfulLength::const_iterator i =
- keyword_to_turl_and_length_.find(keyword);
- if (i == keyword_to_turl_and_length_.end()) {
- AddToMap(existing_turl);
- AddToDomainMap(existing_turl);
- } else {
- // We can theoretically reach here in two cases:
- // * There is an existing extension keyword and sync brings in a rename of
- // a non-extension keyword to match. In this case we just need to pick
- // which keyword has priority to update the keyword map.
- // * Autogeneration of the keyword for a Google default search provider
- // at load time causes it to conflict with an existing keyword. In this
- // case we delete the existing keyword if it's replaceable, or else undo
- // the change in keyword for |existing_turl|.
- TemplateURL* existing_keyword_turl = i->second.first;
- if (existing_keyword_turl->type() != TemplateURL::NORMAL) {
- if (!CanReplace(existing_turl)) {
- AddToMap(existing_turl);
- AddToDomainMap(existing_turl);
- }
- } else {
- if (CanReplace(existing_keyword_turl)) {
- RemoveNoNotify(existing_keyword_turl);
- } else {
- existing_turl->data_.SetKeyword(old_keyword);
- AddToMap(existing_turl);
- AddToDomainMap(existing_turl);
- }
- }
- }
- if (!existing_turl->sync_guid().empty())
- guid_to_turl_[existing_turl->sync_guid()] = existing_turl;
+ AddToMaps(existing_turl);
- if (web_data_service_.get())
- web_data_service_->UpdateKeyword(existing_turl->data());
+ if (existing_turl->type() == TemplateURL::NORMAL) {
+ if (web_data_service_)
+ web_data_service_->UpdateKeyword(existing_turl->data());
- // Inform sync of the update.
- ProcessTemplateURLChange(
- FROM_HERE, existing_turl, syncer::SyncChange::ACTION_UPDATE);
+ // Inform sync of the update.
+ ProcessTemplateURLChange(FROM_HERE, existing_turl,
+ syncer::SyncChange::ACTION_UPDATE);
+ }
if (default_search_provider_ == existing_turl &&
default_search_provider_source_ == DefaultSearchManager::FROM_USER) {
default_search_manager_.SetUserSelectedDefaultSearchEngine(
default_search_provider_->data());
}
+
+ DCHECK(!HasDuplicateKeywords());
return true;
}
bool TemplateURLService::Update(TemplateURL* existing_turl,
- const TemplateURL& new_values) {
+ const TemplateURL& new_values) {
const bool updated = UpdateNoNotify(existing_turl, new_values);
if (updated)
NotifyObservers();
@@ -1791,7 +1784,8 @@ void TemplateURLService::UpdateKeywordSearchTermsForURL(
// later after iteration.
// Note: UpdateNoNotify() will replace the entry from the container of
// this iterator, so update here directly will cause an error about it.
- visited_url = *i;
+ if (!IsCreatedByExtension(*i))
+ visited_url = *i;
}
}
if (visited_url)
@@ -1829,7 +1823,7 @@ void TemplateURLService::RequestGoogleURLTrackerServerCheckIfNecessary() {
if (default_search_provider_ &&
default_search_provider_->HasGoogleBaseURLs(search_terms_data()) &&
google_url_tracker_)
- google_url_tracker_->RequestServerCheck(false);
+ google_url_tracker_->RequestServerCheck();
}
void TemplateURLService::GoogleBaseURLChanged() {
@@ -2055,6 +2049,7 @@ TemplateURL* TemplateURLService::AddNoNotify(
// |initial_default_search_provider_| and the web data version of itself.
TemplateURL* existing_turl =
FindNonExtensionTemplateURLForKeyword(template_url->keyword());
+
if (existing_turl && Contains(&template_urls_, existing_turl)) {
DCHECK_NE(existing_turl, template_url.get());
if (CanReplace(existing_turl)) {
@@ -2066,6 +2061,7 @@ TemplateURL* TemplateURLService::AddNoNotify(
base::string16 new_keyword = UniquifyKeyword(*existing_turl, false);
ResetTemplateURLNoNotify(existing_turl, existing_turl->short_name(),
new_keyword, existing_turl->url());
+ DCHECK_EQ(new_keyword, existing_turl->keyword());
}
}
}
@@ -2082,7 +2078,7 @@ TemplateURL* TemplateURLService::AddNoNotify(
ProcessTemplateURLChange(FROM_HERE, template_url_ptr,
syncer::SyncChange::ACTION_ADD);
}
-
+ DCHECK(!HasDuplicateKeywords());
return template_url_ptr;
}
@@ -2121,6 +2117,7 @@ bool TemplateURLService::ResetTemplateURLNoNotify(
const base::string16& title,
const base::string16& keyword,
const std::string& search_url) {
+ DCHECK(!IsCreatedByExtension(url));
DCHECK(!keyword.empty());
DCHECK(!search_url.empty());
TemplateURLData data(url->data());
@@ -2216,8 +2213,7 @@ base::string16 TemplateURLService::UniquifyKeyword(const TemplateURL& turl,
if (!GetTemplateURLForKeyword(turl.keyword()))
return turl.keyword();
- // First, try to return the generated keyword for the TemplateURL (except
- // for extensions, as their keywords are not associated with their URLs).
+ // First, try to return the generated keyword for the TemplateURL.
GURL gurl(turl.url());
if (gurl.is_valid()) {
base::string16 keyword_candidate = TemplateURL::GenerateKeyword(gurl);
@@ -2237,10 +2233,14 @@ base::string16 TemplateURLService::UniquifyKeyword(const TemplateURL& turl,
return keyword_candidate;
}
-bool TemplateURLService::IsLocalTemplateURLBetter(const TemplateURL* local_turl,
- const TemplateURL* sync_turl,
- bool prefer_local_default) {
- DCHECK(GetTemplateURLForGUID(local_turl->sync_guid()));
+bool TemplateURLService::IsLocalTemplateURLBetter(
+ const TemplateURL* local_turl,
+ const TemplateURL* sync_turl,
+ bool prefer_local_default) const {
+ // TODO(jeffschiller): Make GetTemplateURLForKeyword const and remove the
+ // const_cast.
+ DCHECK(const_cast<TemplateURLService*>(this)->GetTemplateURLForGUID(
+ local_turl->sync_guid()));
return local_turl->last_modified() > sync_turl->last_modified() ||
local_turl->created_by_policy() ||
(prefer_local_default && local_turl == GetDefaultSearchProvider());
@@ -2482,3 +2482,18 @@ TemplateURL* TemplateURLService::FindMatchingDefaultExtensionTemplateURL(
}
return nullptr;
}
+
+bool TemplateURLService::HasDuplicateKeywords() const {
+ std::map<base::string16, TemplateURL*> keyword_to_template_url;
+ for (const auto& template_url : template_urls_) {
+ // Validate no duplicate normal engines with same keyword.
+ if (!IsCreatedByExtension(template_url.get())) {
+ if (keyword_to_template_url.find(template_url->keyword()) !=
+ keyword_to_template_url.end()) {
+ return true;
+ }
+ keyword_to_template_url[template_url->keyword()] = template_url.get();
+ }
+ }
+ return false;
+}
diff --git a/chromium/components/search_engines/template_url_service.h b/chromium/components/search_engines/template_url_service.h
index ca11382e5e1..4187327f06a 100644
--- a/chromium/components/search_engines/template_url_service.h
+++ b/chromium/components/search_engines/template_url_service.h
@@ -135,14 +135,14 @@ class TemplateURLService : public WebDataServiceConsumer,
// Returns whether the engine is a "pre-existing" engine, either from the
// prepopulate list or created by policy.
- bool IsPrepopulatedOrCreatedByPolicy(const TemplateURL* template_url);
+ bool IsPrepopulatedOrCreatedByPolicy(const TemplateURL* template_url) const;
// Returns whether |template_url| should be shown in the list of engines
// most likely to be selected as a default engine. This is meant to highlight
// the current default, as well as the other most likely choices of default
// engine, separately from a full list of all TemplateURLs (which might be
// very long).
- bool ShowInDefaultList(const TemplateURL* template_url);
+ bool ShowInDefaultList(const TemplateURL* template_url) const;
// Adds to |matches| all TemplateURLs whose keywords begin with |prefix|,
// sorted shortest-keyword-first. If |supports_replacement_only| is true, only
@@ -248,7 +248,7 @@ class TemplateURLService : public WebDataServiceConsumer,
// Return true if the given |url| can be made the default. This returns false
// regardless of |url| if the default search provider is managed by policy or
// controlled by an extension.
- bool CanMakeDefault(const TemplateURL* url);
+ bool CanMakeDefault(const TemplateURL* url) const;
// Set the default search provider. |url| may be null.
// This will assert if the default search is managed; the UI should not be
@@ -274,7 +274,7 @@ class TemplateURLService : public WebDataServiceConsumer,
}
// Returns true if the default search provider is controlled by an extension.
- bool IsExtensionControlledDefaultSearch();
+ bool IsExtensionControlledDefaultSearch() const;
// Returns the default search specified in the prepopulated data, if it
// exists. If not, returns first URL in |template_urls_|, or NULL if that's
@@ -330,8 +330,9 @@ class TemplateURLService : public WebDataServiceConsumer,
// Returns the locale-direction-adjusted short name for the given keyword.
// Also sets the out param to indicate whether the keyword belongs to an
// Omnibox extension.
- base::string16 GetKeywordShortName(const base::string16& keyword,
- bool* is_omnibox_api_extension_keyword);
+ base::string16 GetKeywordShortName(
+ const base::string16& keyword,
+ bool* is_omnibox_api_extension_keyword) const;
// Called by the history service when a URL is visited.
void OnHistoryURLVisited(const URLVisitedDetails& details);
@@ -543,13 +544,13 @@ class TemplateURLService : public WebDataServiceConsumer,
// Returns false if there is a TemplateURL that has a search url with the
// specified host and that TemplateURL has been manually modified.
- bool CanAddAutogeneratedKeywordForHost(const std::string& host);
+ bool CanAddAutogeneratedKeywordForHost(const std::string& host) const;
// Returns true if the TemplateURL is replaceable. This doesn't look at the
// uniqueness of the keyword or host and is intended to be called after those
// checks have been done. This returns true if the TemplateURL doesn't appear
// in the default list and is marked as safe_for_autoreplace.
- bool CanReplace(const TemplateURL* t_url);
+ bool CanReplace(const TemplateURL* t_url) const;
// Like GetTemplateURLForKeyword(), but ignores extension-provided keywords.
TemplateURL* FindNonExtensionTemplateURLForKeyword(
@@ -661,7 +662,7 @@ class TemplateURLService : public WebDataServiceConsumer,
// search provider
bool IsLocalTemplateURLBetter(const TemplateURL* local_turl,
const TemplateURL* sync_turl,
- bool prefer_local_default = true);
+ bool prefer_local_default = true) const;
// Given two synced TemplateURLs with a conflicting keyword, one of which
// needs to be added to or updated in the local model (|unapplied_sync_turl|)
@@ -725,6 +726,11 @@ class TemplateURLService : public WebDataServiceConsumer,
TemplateURL* FindMatchingDefaultExtensionTemplateURL(
const TemplateURLData& data);
+ // Returns whether |template_urls_| contains more than one normal engine with
+ // same keyword. Used to validate state after search engines are
+ // added/updated.
+ bool HasDuplicateKeywords() const;
+
// ---------- Browser state related members ---------------------------------
PrefService* prefs_;
diff --git a/chromium/components/search_engines/template_url_service_observer.h b/chromium/components/search_engines/template_url_service_observer.h
index acd016f583d..eb3ba6667d0 100644
--- a/chromium/components/search_engines/template_url_service_observer.h
+++ b/chromium/components/search_engines/template_url_service_observer.h
@@ -12,6 +12,11 @@ class TemplateURLServiceObserver {
// Notification that the template url model has changed in some way.
virtual void OnTemplateURLServiceChanged() = 0;
+ // Notification that the template url service is shutting down. Observers that
+ // might outlive the service can use this to clear out any raw pointers to the
+ // service.
+ virtual void OnTemplateURLServiceShuttingDown() {}
+
protected:
virtual ~TemplateURLServiceObserver() {}
};
diff --git a/chromium/components/search_engines/template_url_unittest.cc b/chromium/components/search_engines/template_url_unittest.cc
index 170807f17f3..31774626760 100644
--- a/chromium/components/search_engines/template_url_unittest.cc
+++ b/chromium/components/search_engines/template_url_unittest.cc
@@ -1267,6 +1267,14 @@ TEST_F(TemplateURLTest, ExtractSearchTermsWithPrefixAndSuffix) {
// Don't match if the prefix and suffix aren't there.
EXPECT_FALSE(url.ExtractSearchTermsFromURL(
GURL("http://www.example.com/?q=invalid"), search_terms_data_, &result));
+
+ // Don't match if the prefix and suffix overlap.
+ TemplateURLData data_with_overlap;
+ data.alternate_urls.push_back(
+ "http://www.example.com/?q=goo{searchTerms}oogle");
+ TemplateURL url_with_overlap(data);
+ EXPECT_FALSE(url_with_overlap.ExtractSearchTermsFromURL(
+ GURL("http://www.example.com/?q=google"), search_terms_data_, &result));
}
TEST_F(TemplateURLTest, HasSearchTermsReplacementKey) {
diff --git a/chromium/components/search_provider_logos/google_logo_api.cc b/chromium/components/search_provider_logos/google_logo_api.cc
index 40fc1e8d596..f0ab64f4c5e 100644
--- a/chromium/components/search_provider_logos/google_logo_api.cc
+++ b/chromium/components/search_provider_logos/google_logo_api.cc
@@ -11,6 +11,7 @@
#include "base/base64.h"
#include "base/json/json_reader.h"
#include "base/memory/ref_counted_memory.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/values.h"
@@ -23,7 +24,7 @@ const char kResponsePreamble[] = ")]}'";
GURL GoogleAppendQueryparamsToLogoURL(const GURL& logo_url,
const std::string& fingerprint,
bool wants_cta,
- bool transparent) {
+ bool gray_background) {
// Note: we can't just use net::AppendQueryParameter() because it escapes
// ":" to "%3A", but the server requires the colon not to be escaped.
// See: http://crbug.com/413845
@@ -36,14 +37,17 @@ GURL GoogleAppendQueryparamsToLogoURL(const GURL& logo_url,
query += "&";
query += "async=";
- std::vector<std::string> params;
- if (!fingerprint.empty())
- params.push_back("es_dfp:" + fingerprint);
+ std::vector<base::StringPiece> params;
+ std::string fingerprint_param;
+ if (!fingerprint.empty()) {
+ fingerprint_param = "es_dfp:" + fingerprint;
+ params.push_back(fingerprint_param);
+ }
if (wants_cta)
params.push_back("cta:1");
- if (transparent) {
+ if (gray_background) {
params.push_back("transp:1");
params.push_back("graybg:1");
}
diff --git a/chromium/components/search_provider_logos/google_logo_api.h b/chromium/components/search_provider_logos/google_logo_api.h
index 7415c6cb290..d1d85b9ba6f 100644
--- a/chromium/components/search_provider_logos/google_logo_api.h
+++ b/chromium/components/search_provider_logos/google_logo_api.h
@@ -19,7 +19,7 @@ namespace search_provider_logos {
GURL GoogleAppendQueryparamsToLogoURL(const GURL& logo_url,
const std::string& fingerprint,
bool wants_cta,
- bool transparent);
+ bool gray_background);
// Implements ParseLogoResponse, defined in logo_tracker.h, for Google doodles.
std::unique_ptr<EncodedLogo> GoogleParseLogoResponse(
diff --git a/chromium/components/search_provider_logos/logo_tracker.cc b/chromium/components/search_provider_logos/logo_tracker.cc
index d5e10a61eb8..a2fc7f9e9e4 100644
--- a/chromium/components/search_provider_logos/logo_tracker.cc
+++ b/chromium/components/search_provider_logos/logo_tracker.cc
@@ -17,6 +17,7 @@
#include "components/search_provider_logos/switches.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_status.h"
@@ -95,7 +96,7 @@ void LogoTracker::SetServerAPI(
const ParseLogoResponse& parse_logo_response_func,
const AppendQueryparamsToLogoURL& append_queryparams_func,
bool wants_cta,
- bool transparent) {
+ bool gray_background) {
if (logo_url == logo_url_)
return;
@@ -105,7 +106,7 @@ void LogoTracker::SetServerAPI(
parse_logo_response_func_ = parse_logo_response_func;
append_queryparams_func_ = append_queryparams_func;
wants_cta_ = wants_cta;
- transparent_ = transparent;
+ gray_background_ = gray_background;
}
void LogoTracker::GetLogo(LogoObserver* observer) {
@@ -222,11 +223,35 @@ void LogoTracker::FetchLogo() {
if (command_line->HasSwitch(switches::kGoogleDoodleUrl)) {
url = GURL(command_line->GetSwitchValueASCII(switches::kGoogleDoodleUrl));
} else {
- url = append_queryparams_func_.Run(
- logo_url_, fingerprint, wants_cta_, transparent_);
+ url = append_queryparams_func_.Run(logo_url_, fingerprint, wants_cta_,
+ gray_background_);
}
- fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("logo_tracker", R"(
+ semantics {
+ sender: "Logo Tracker"
+ description:
+ "Provides the logo image (aka Doodle) if Google is your configured "
+ "search provider."
+ trigger: "Displaying the new tab page on iOS or Android."
+ data:
+ "Logo ID, and the user's Google cookies to show for example "
+ "birthday doodles at appropriate times."
+ destination: OTHER
+ }
+ policy {
+ cookies_allowed: true
+ cookies_store: "user"
+ setting:
+ "Choosing a non-Google search engine in Chromium settings under "
+ "'Search Engine' will disable this feature."
+ policy_exception_justification:
+ "Not implemented, considered not useful as it does not upload any"
+ "data and just downloads a logo image."
+ })");
+ fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this,
+ traffic_annotation);
fetcher_->SetRequestContext(request_context_getter_.get());
data_use_measurement::DataUseUserData::AttachToFetcher(
fetcher_.get(),
@@ -236,6 +261,7 @@ void LogoTracker::FetchLogo() {
}
void LogoTracker::OnFreshLogoParsed(bool* parsing_failed,
+ bool from_http_cache,
std::unique_ptr<EncodedLogo> logo) {
DCHECK(!is_idle_);
@@ -243,7 +269,8 @@ void LogoTracker::OnFreshLogoParsed(bool* parsing_failed,
logo->metadata.source_url = logo_url_.spec();
if (!logo || !logo->encoded_image.get()) {
- OnFreshLogoAvailable(std::move(logo), *parsing_failed, SkBitmap());
+ OnFreshLogoAvailable(std::move(logo), *parsing_failed, from_http_cache,
+ SkBitmap());
} else {
// Store the value of logo->encoded_image for use below. This ensures that
// logo->encoded_image is evaulated before base::Passed(&logo), which sets
@@ -252,15 +279,15 @@ void LogoTracker::OnFreshLogoParsed(bool* parsing_failed,
logo_delegate_->DecodeUntrustedImage(
encoded_image,
base::Bind(&LogoTracker::OnFreshLogoAvailable,
- weak_ptr_factory_.GetWeakPtr(),
- base::Passed(&logo),
- *parsing_failed));
+ weak_ptr_factory_.GetWeakPtr(), base::Passed(&logo),
+ *parsing_failed, from_http_cache));
}
}
void LogoTracker::OnFreshLogoAvailable(
std::unique_ptr<EncodedLogo> encoded_logo,
bool parsing_failed,
+ bool from_http_cache,
const SkBitmap& image) {
DCHECK(!is_idle_);
@@ -282,6 +309,8 @@ void LogoTracker::OnFreshLogoAvailable(
std::unique_ptr<Logo> logo;
// Check if the server returned a valid, non-empty response.
if (encoded_logo) {
+ UMA_HISTOGRAM_BOOLEAN("NewTabPage.LogoImageDownloaded", from_http_cache);
+
DCHECK(!image.isNull());
logo.reset(new Logo());
logo->metadata = encoded_logo->metadata;
@@ -335,13 +364,16 @@ void LogoTracker::OnURLFetchComplete(const net::URLFetcher* source) {
source->GetResponseAsString(response.get());
base::Time response_time = clock_->Now();
+ bool from_http_cache = source->WasCached();
+
bool* parsing_failed = new bool(false);
base::PostTaskAndReplyWithResult(
background_task_runner_.get(), FROM_HERE,
base::Bind(parse_logo_response_func_, base::Passed(&response),
response_time, parsing_failed),
base::Bind(&LogoTracker::OnFreshLogoParsed,
- weak_ptr_factory_.GetWeakPtr(), base::Owned(parsing_failed)));
+ weak_ptr_factory_.GetWeakPtr(), base::Owned(parsing_failed),
+ from_http_cache));
}
void LogoTracker::OnURLFetchDownloadProgress(const net::URLFetcher* source,
diff --git a/chromium/components/search_provider_logos/logo_tracker.h b/chromium/components/search_provider_logos/logo_tracker.h
index 851e1bc5a03..402b6401ecb 100644
--- a/chromium/components/search_provider_logos/logo_tracker.h
+++ b/chromium/components/search_provider_logos/logo_tracker.h
@@ -80,7 +80,8 @@ typedef base::Callback<std::unique_ptr<EncodedLogo>(
typedef base::Callback<GURL(const GURL& logo_url,
const std::string& fingerprint,
bool wants_cta,
- bool transparent)> AppendQueryparamsToLogoURL;
+ bool gray_background)>
+ AppendQueryparamsToLogoURL;
// This class provides the logo for a search provider. Logos are downloaded from
// the search provider's logo URL and cached on disk.
@@ -124,7 +125,8 @@ class LogoTracker : public net::URLFetcherDelegate {
// server's response into a EncodedLogo object. |append_queryparams_func| is a
// callback that will return the URL from which to download the logo.
// |wants_cta| determines if the url should return a call to action image.
- // |transparent| determines whether to request a transparent logo.
+ // |gray_background| determines whether to request a logo with a gray
+ // background. The gray will match the NTP background color.
// Note: |parse_logo_response_func| and |append_queryparams_func| must be
// suitable for running multiple times, concurrently, and on multiple threads.
// TODO(ianwen): remove wants_cta from parameter.
@@ -132,7 +134,7 @@ class LogoTracker : public net::URLFetcherDelegate {
const ParseLogoResponse& parse_logo_response_func,
const AppendQueryparamsToLogoURL& append_queryparams_func,
bool wants_cta,
- bool transparent);
+ bool gray_background);
// Retrieves the current search provider's logo from the local cache and/or
// over the network, and registers |observer| to be called when the cached
@@ -192,12 +194,14 @@ class LogoTracker : public net::URLFetcherDelegate {
// Called when the logo has been downloaded and parsed. |logo| will be NULL
// if the server's response was invalid.
void OnFreshLogoParsed(bool* parsing_failed,
+ bool from_http_cache,
std::unique_ptr<EncodedLogo> logo);
// Called when the fresh logo has been decoded into an SkBitmap. |image| will
// be NULL if decoding failed.
void OnFreshLogoAvailable(std::unique_ptr<EncodedLogo> logo,
bool parsing_failed,
+ bool from_http_cache,
const SkBitmap& image);
// net::URLFetcherDelegate:
@@ -220,8 +224,8 @@ class LogoTracker : public net::URLFetcherDelegate {
// If |true| request call to action in server API.
bool wants_cta_;
- // If |true| request transparent doodle.
- bool transparent_;
+ // If |true| request a doodle with a gray background.
+ bool gray_background_;
// False if an asynchronous task is currently running.
bool is_idle_;
diff --git a/chromium/components/search_provider_logos/logo_tracker_unittest.cc b/chromium/components/search_provider_logos/logo_tracker_unittest.cc
index b1243424251..7181eca4afb 100644
--- a/chromium/components/search_provider_logos/logo_tracker_unittest.cc
+++ b/chromium/components/search_provider_logos/logo_tracker_unittest.cc
@@ -427,7 +427,7 @@ TEST_F(LogoTrackerTest, CTAURLHasComma) {
EXPECT_EQ("http://logourl.com/?a=b&async=cta:1", url_with_fp.spec());
}
-TEST_F(LogoTrackerTest, CTATransparentHasCommas) {
+TEST_F(LogoTrackerTest, CTAGrayBackgroundHasCommas) {
GURL url_with_fp = GoogleAppendQueryparamsToLogoURL(
GURL("http://logourl.com/path"), "abc123", true, true);
EXPECT_EQ(
diff --git a/chromium/components/security_interstitials/OWNERS b/chromium/components/security_interstitials/OWNERS
index f8671b11b0f..1f083c521ef 100644
--- a/chromium/components/security_interstitials/OWNERS
+++ b/chromium/components/security_interstitials/OWNERS
@@ -7,3 +7,5 @@ palmer@chromium.org
# For componentization purpose
jialiul@chromium.org
+
+# COMPONENT: UI>Browser>Interstitials
diff --git a/chromium/components/security_interstitials/core/bad_clock_ui.cc b/chromium/components/security_interstitials/core/bad_clock_ui.cc
index 1ac1f1e9a1d..dafdd148ab9 100644
--- a/chromium/components/security_interstitials/core/bad_clock_ui.cc
+++ b/chromium/components/security_interstitials/core/bad_clock_ui.cc
@@ -42,7 +42,6 @@ void BadClockUI::PopulateStringsForHTML(base::DictionaryValue* load_time_data) {
common_string_util::PopulateSSLLayoutStrings(cert_error_, load_time_data);
common_string_util::PopulateSSLDebuggingStrings(ssl_info_, time_triggered_,
load_time_data);
- common_string_util::PopulateNewIconStrings(load_time_data);
// Clock-specific strings.
PopulateClockStrings(load_time_data);
diff --git a/chromium/components/security_interstitials/core/browser/resources/images/1x/brokenssl_red.png b/chromium/components/security_interstitials/core/browser/resources/images/1x/brokenssl_red.png
deleted file mode 100644
index cc4b1b39159..00000000000
--- a/chromium/components/security_interstitials/core/browser/resources/images/1x/brokenssl_red.png
+++ /dev/null
Binary files differ
diff --git a/chromium/components/security_interstitials/core/browser/resources/images/1x/stop_sign.png b/chromium/components/security_interstitials/core/browser/resources/images/1x/stop_sign.png
deleted file mode 100644
index f260d3310b3..00000000000
--- a/chromium/components/security_interstitials/core/browser/resources/images/1x/stop_sign.png
+++ /dev/null
Binary files differ
diff --git a/chromium/components/security_interstitials/core/browser/resources/images/2x/brokenssl_red.png b/chromium/components/security_interstitials/core/browser/resources/images/2x/brokenssl_red.png
deleted file mode 100644
index bc4fa0a8578..00000000000
--- a/chromium/components/security_interstitials/core/browser/resources/images/2x/brokenssl_red.png
+++ /dev/null
Binary files differ
diff --git a/chromium/components/security_interstitials/core/browser/resources/images/2x/stop_sign.png b/chromium/components/security_interstitials/core/browser/resources/images/2x/stop_sign.png
deleted file mode 100644
index d91aa9cf6ee..00000000000
--- a/chromium/components/security_interstitials/core/browser/resources/images/2x/stop_sign.png
+++ /dev/null
Binary files differ
diff --git a/chromium/components/security_interstitials/core/browser/resources/interstitial_ui.html b/chromium/components/security_interstitials/core/browser/resources/interstitial_ui.html
index 4f425e52f39..852be930ad0 100644
--- a/chromium/components/security_interstitials/core/browser/resources/interstitial_ui.html
+++ b/chromium/components/security_interstitials/core/browser/resources/interstitial_ui.html
@@ -51,5 +51,11 @@
Captive Portal, WiFi with network name "CoffeeShopWiFi"
</a>
</div>
+ <h3>Supervised Users</h3>
+ <div>
+ <a href="supervised_user">
+ Supervised User
+ </a
+ </div>>
</body>
</html>
diff --git a/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.css b/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.css
index 34d2c9d089f..ebb5e48d58c 100644
--- a/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.css
+++ b/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.css
@@ -202,35 +202,23 @@ input[type=checkbox]:focus ~ .checkbox {
display: none;
}
-.safe-browsing .new-icons {
+.safe-browsing .icon {
background-image: -webkit-image-set(
url(images/1x/triangle_white.png) 1x,
url(images/2x/triangle_white.png) 2x);
}
-.safe-browsing .old-icons {
- background-image: -webkit-image-set(
- url(images/1x/stop_sign.png) 1x,
- url(images/2x/stop_sign.png) 2x);
-}
-
.small-link {
color: #696969;
font-size: .875em;
}
-.ssl .new-icons {
+.ssl .icon {
background-image: -webkit-image-set(
url(images/1x/triangle_red.png) 1x,
url(images/2x/triangle_red.png) 2x);
}
-.ssl .old-icons {
- background-image: -webkit-image-set(
- url(images/1x/brokenssl_red.png) 1x,
- url(images/2x/brokenssl_red.png) 2x);
-}
-
.captive-portal .icon {
background-image: -webkit-image-set(
url(images/1x/captive_portal_page_icon.png) 1x,
diff --git a/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.js b/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.js
index e46279d279e..4fa48eac865 100644
--- a/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.js
+++ b/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.js
@@ -115,10 +115,7 @@ function setupEvents() {
$('body').classList.add('safe-browsing');
}
- if (loadTimeData.getBoolean('iconUpdate') === true)
- $('icon').classList.add('new-icons');
- else
- $('icon').classList.add('old-icons');
+ $('icon').classList.add('icon');
if (hidePrimaryButton) {
$('primary-button').classList.add('hidden');
diff --git a/chromium/components/security_interstitials/core/common_string_util.cc b/chromium/components/security_interstitials/core/common_string_util.cc
index b2297c1d770..bb7400601c5 100644
--- a/chromium/components/security_interstitials/core/common_string_util.cc
+++ b/chromium/components/security_interstitials/core/common_string_util.cc
@@ -4,7 +4,6 @@
#include "components/security_interstitials/core/common_string_util.h"
-#include "base/feature_list.h"
#include "base/i18n/rtl.h"
#include "base/i18n/time_formatting.h"
#include "base/strings/string_util.h"
@@ -13,11 +12,6 @@
#include "net/base/net_errors.h"
#include "ui/base/l10n/l10n_util.h"
-namespace {
- const base::Feature kSecurityWarningIconUpdate{
- "SecurityWarningIconUpdate", base::FEATURE_DISABLED_BY_DEFAULT};
-} // namespace
-
namespace security_interstitials {
namespace common_string_util {
@@ -56,11 +50,6 @@ void PopulateSSLDebuggingStrings(const net::SSLInfo ssl_info,
"pem", base::JoinString(encoded_chain, base::StringPiece()));
}
-void PopulateNewIconStrings(base::DictionaryValue* load_time_data) {
- load_time_data->SetBoolean(
- "iconUpdate", base::FeatureList::IsEnabled(kSecurityWarningIconUpdate));
-}
-
} // namespace common_string_util
} // namespace security_interstitials
diff --git a/chromium/components/security_interstitials/core/safe_browsing_error_ui.cc b/chromium/components/security_interstitials/core/safe_browsing_error_ui.cc
index 06dfd42f8cb..38566d65e6c 100644
--- a/chromium/components/security_interstitials/core/safe_browsing_error_ui.cc
+++ b/chromium/components/security_interstitials/core/safe_browsing_error_ui.cc
@@ -95,8 +95,6 @@ void SafeBrowsingErrorUI::PopulateStringsForHTML(
l10n_util::GetStringUTF16(IDS_SAFEBROWSING_OVERRIDABLE_SAFETY_BUTTON));
load_time_data->SetBoolean("overridable",
!display_options_.is_proceed_anyway_disabled);
- security_interstitials::common_string_util::PopulateNewIconStrings(
- load_time_data);
switch (interstitial_reason_) {
case SB_REASON_MALWARE:
@@ -129,7 +127,7 @@ void SafeBrowsingErrorUI::HandleCommand(SecurityInterstitialCommands command) {
// User pressed on the button to return to safety.
// Don't record the user action here because there are other ways of
// triggering DontProceed, like clicking the back button.
- if (display_options_.is_main_frame_load_blocked) {
+ if (display_options_.is_resource_cancellable) {
// If the load is blocked, we want to close the interstitial and discard
// the pending entry.
controller_->GoBack();
diff --git a/chromium/components/security_interstitials/core/safe_browsing_error_ui.h b/chromium/components/security_interstitials/core/safe_browsing_error_ui.h
index 3124ee3bd4d..ed1a90584f4 100644
--- a/chromium/components/security_interstitials/core/safe_browsing_error_ui.h
+++ b/chromium/components/security_interstitials/core/safe_browsing_error_ui.h
@@ -30,14 +30,16 @@ class SafeBrowsingErrorUI {
bool is_off_the_record,
bool is_extended_reporting_enabled,
bool is_scout_reporting_enabled,
- bool is_proceed_anyway_disabled)
+ bool is_proceed_anyway_disabled,
+ bool is_resource_cancellable)
: is_main_frame_load_blocked(is_main_frame_load_blocked),
is_extended_reporting_opt_in_allowed(
is_extended_reporting_opt_in_allowed),
is_off_the_record(is_off_the_record),
is_extended_reporting_enabled(is_extended_reporting_enabled),
is_scout_reporting_enabled(is_scout_reporting_enabled),
- is_proceed_anyway_disabled(is_proceed_anyway_disabled) {}
+ is_proceed_anyway_disabled(is_proceed_anyway_disabled),
+ is_resource_cancellable(is_resource_cancellable) {}
// Indicates if this SB interstitial is blocking main frame load.
bool is_main_frame_load_blocked;
@@ -56,6 +58,10 @@ class SafeBrowsingErrorUI {
// Indicates if kSafeBrowsingProceedAnywayDisabled preference is set.
bool is_proceed_anyway_disabled;
+
+ // Indicates if "back to safety" should cancel the pending navigation or
+ // navigate back after it's committed.
+ bool is_resource_cancellable;
};
SafeBrowsingErrorUI(const GURL& request_url,
diff --git a/chromium/components/security_interstitials/core/ssl_error_ui.cc b/chromium/components/security_interstitials/core/ssl_error_ui.cc
index f4ff8abcb95..e438bc601e2 100644
--- a/chromium/components/security_interstitials/core/ssl_error_ui.cc
+++ b/chromium/components/security_interstitials/core/ssl_error_ui.cc
@@ -66,7 +66,6 @@ void SSLErrorUI::PopulateStringsForHTML(base::DictionaryValue* load_time_data) {
common_string_util::PopulateSSLLayoutStrings(cert_error_, load_time_data);
common_string_util::PopulateSSLDebuggingStrings(ssl_info_, time_triggered_,
load_time_data);
- common_string_util::PopulateNewIconStrings(load_time_data);
// Shared values for both the overridable and non-overridable versions.
load_time_data->SetBoolean("bad_clock", false);
diff --git a/chromium/components/security_state/OWNERS b/chromium/components/security_state/OWNERS
index 04d0330aa61..d1ce6be7571 100644
--- a/chromium/components/security_state/OWNERS
+++ b/chromium/components/security_state/OWNERS
@@ -1,3 +1,5 @@
estark@chromium.org
felt@chromium.org
-palmer@chromium.org \ No newline at end of file
+palmer@chromium.org
+
+# COMPONENT: Internals>PageSecurityState
diff --git a/chromium/components/security_state/content/content_utils.cc b/chromium/components/security_state/content/content_utils.cc
index d5689987e97..0464d59e4a1 100644
--- a/chromium/components/security_state/content/content_utils.cc
+++ b/chromium/components/security_state/content/content_utils.cc
@@ -19,7 +19,6 @@
#include "content/public/browser/security_style_explanations.h"
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/common/content_client.h"
#include "net/base/net_errors.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_cipher_suite_names.h"
@@ -38,19 +37,19 @@ blink::WebSecurityStyle SecurityLevelToSecurityStyle(
switch (security_level) {
case security_state::NONE:
case security_state::HTTP_SHOW_WARNING:
- return blink::WebSecurityStyleUnauthenticated;
+ return blink::kWebSecurityStyleNeutral;
case security_state::SECURITY_WARNING:
case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
- return blink::WebSecurityStyleWarning;
+ return blink::kWebSecurityStyleWarning;
case security_state::EV_SECURE:
case security_state::SECURE:
- return blink::WebSecurityStyleAuthenticated;
+ return blink::kWebSecurityStyleSecure;
case security_state::DANGEROUS:
- return blink::WebSecurityStyleAuthenticationBroken;
+ return blink::kWebSecurityStyleInsecure;
}
NOTREACHED();
- return blink::WebSecurityStyleUnknown;
+ return blink::kWebSecurityStyleUnknown;
}
void AddConnectionExplanation(
@@ -168,6 +167,9 @@ std::unique_ptr<security_state::VisibleSecurityState> GetVisibleSecurityState(
content::SSLStatus::DISPLAYED_CONTENT_WITH_CERT_ERRORS);
state->ran_content_with_cert_errors =
!!(ssl.content_status & content::SSLStatus::RAN_CONTENT_WITH_CERT_ERRORS);
+ state->contained_mixed_form =
+ !!(ssl.content_status &
+ content::SSLStatus::DISPLAYED_FORM_WITH_INSECURE_ACTION);
state->displayed_password_field_on_http =
!!(ssl.content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP);
@@ -189,7 +191,7 @@ blink::WebSecurityStyle GetSecurityStyle(
if (security_info.security_level == security_state::HTTP_SHOW_WARNING &&
(security_info.displayed_password_field_on_http ||
security_info.displayed_credit_card_field_on_http)) {
- security_style_explanations->unauthenticated_explanations.push_back(
+ security_style_explanations->neutral_explanations.push_back(
content::SecurityStyleExplanation(
l10n_util::GetStringUTF8(IDS_PRIVATE_USER_DATA_INPUT),
l10n_util::GetStringUTF8(IDS_PRIVATE_USER_DATA_INPUT_DESCRIPTION)));
@@ -220,7 +222,7 @@ blink::WebSecurityStyle GetSecurityStyle(
}
if (security_info.sha1_in_chain) {
- security_style_explanations->unauthenticated_explanations.push_back(
+ security_style_explanations->neutral_explanations.push_back(
content::SecurityStyleExplanation(
l10n_util::GetStringUTF8(IDS_SHA1),
l10n_util::GetStringUTF8(IDS_SHA1_DESCRIPTION),
@@ -228,7 +230,7 @@ blink::WebSecurityStyle GetSecurityStyle(
}
if (security_info.cert_missing_subject_alt_name) {
- security_style_explanations->broken_explanations.push_back(
+ security_style_explanations->insecure_explanations.push_back(
content::SecurityStyleExplanation(
l10n_util::GetStringUTF8(IDS_SUBJECT_ALT_NAME_MISSING),
l10n_util::GetStringUTF8(IDS_SUBJECT_ALT_NAME_MISSING_DESCRIPTION),
@@ -248,6 +250,9 @@ blink::WebSecurityStyle GetSecurityStyle(
security_info.mixed_content_status ==
security_state::CONTENT_STATUS_DISPLAYED_AND_RAN;
+ security_style_explanations->contained_mixed_form =
+ security_info.contained_mixed_form;
+
bool is_cert_status_error = net::IsCertStatusError(security_info.cert_status);
bool is_cert_status_minor_error =
net::IsCertStatusMinorError(security_info.cert_status);
@@ -282,10 +287,9 @@ blink::WebSecurityStyle GetSecurityStyle(
!!security_info.certificate);
if (is_cert_status_minor_error) {
- security_style_explanations->unauthenticated_explanations.push_back(
- explanation);
+ security_style_explanations->neutral_explanations.push_back(explanation);
} else {
- security_style_explanations->broken_explanations.push_back(explanation);
+ security_style_explanations->insecure_explanations.push_back(explanation);
}
} else {
// If the certificate does not have errors and is not using SHA1, then add
diff --git a/chromium/components/security_state/content/content_utils_unittest.cc b/chromium/components/security_state/content/content_utils_unittest.cc
index 9e53bae4a9a..a9b5bbdcced 100644
--- a/chromium/components/security_state/content/content_utils_unittest.cc
+++ b/chromium/components/security_state/content/content_utils_unittest.cc
@@ -127,6 +127,27 @@ TEST(SecurityStateContentUtilsTest,
EXPECT_FALSE(explanations.displayed_content_with_cert_errors);
}
+// Tests that SecurityInfo flags for mixed content are reflected in the
+// SecurityStyleExplanations produced by GetSecurityStyle.
+TEST(SecurityStateContentUtilsTest, GetSecurityStyleForMixedContent) {
+ content::SecurityStyleExplanations explanations;
+ security_state::SecurityInfo security_info;
+ security_info.cert_status = 0;
+ security_info.scheme_is_cryptographic = true;
+
+ security_info.contained_mixed_form = true;
+ GetSecurityStyle(security_info, &explanations);
+ EXPECT_TRUE(explanations.contained_mixed_form);
+ EXPECT_FALSE(explanations.ran_mixed_content);
+ EXPECT_FALSE(explanations.displayed_mixed_content);
+
+ security_info.contained_mixed_form = false;
+ security_info.mixed_content_status = security_state::CONTENT_STATUS_DISPLAYED;
+ GetSecurityStyle(security_info, &explanations);
+ EXPECT_FALSE(explanations.contained_mixed_form);
+ EXPECT_TRUE(explanations.displayed_mixed_content);
+}
+
bool FindSecurityStyleExplanation(
const std::vector<content::SecurityStyleExplanation>& explanations,
const char* summary,
@@ -205,33 +226,33 @@ TEST(SecurityStateContentUtilsTest, ConnectionExplanation) {
}
// Tests that a security level of HTTP_SHOW_WARNING produces
-// blink::WebSecurityStyleUnauthenticated and an explanation if appropriate.
+// blink::WebSecurityStyleNeutral and an explanation if appropriate.
TEST(SecurityStateContentUtilsTest, HTTPWarning) {
security_state::SecurityInfo security_info;
content::SecurityStyleExplanations explanations;
security_info.security_level = security_state::HTTP_SHOW_WARNING;
blink::WebSecurityStyle security_style =
GetSecurityStyle(security_info, &explanations);
- EXPECT_EQ(blink::WebSecurityStyleUnauthenticated, security_style);
+ EXPECT_EQ(blink::kWebSecurityStyleNeutral, security_style);
// Verify no explanation was shown, because Form Not Secure was not triggered.
- EXPECT_EQ(0u, explanations.unauthenticated_explanations.size());
+ EXPECT_EQ(0u, explanations.neutral_explanations.size());
- explanations.unauthenticated_explanations.clear();
+ explanations.neutral_explanations.clear();
security_info.displayed_credit_card_field_on_http = true;
security_style = GetSecurityStyle(security_info, &explanations);
- EXPECT_EQ(blink::WebSecurityStyleUnauthenticated, security_style);
+ EXPECT_EQ(blink::kWebSecurityStyleNeutral, security_style);
// Verify one explanation was shown, because Form Not Secure was triggered.
- EXPECT_EQ(1u, explanations.unauthenticated_explanations.size());
+ EXPECT_EQ(1u, explanations.neutral_explanations.size());
// Check that when both password and credit card fields get displayed, only
// one explanation is added.
- explanations.unauthenticated_explanations.clear();
+ explanations.neutral_explanations.clear();
security_info.displayed_credit_card_field_on_http = true;
security_info.displayed_password_field_on_http = true;
security_style = GetSecurityStyle(security_info, &explanations);
- EXPECT_EQ(blink::WebSecurityStyleUnauthenticated, security_style);
+ EXPECT_EQ(blink::kWebSecurityStyleNeutral, security_style);
// Verify only one explanation was shown when Form Not Secure is triggered.
- EXPECT_EQ(1u, explanations.unauthenticated_explanations.size());
+ EXPECT_EQ(1u, explanations.neutral_explanations.size());
}
// Tests that an explanation is provided if a certificate is missing a
@@ -249,13 +270,13 @@ TEST(SecurityStateContentUtilsTest, SubjectAltNameWarning) {
security_info.cert_missing_subject_alt_name = true;
GetSecurityStyle(security_info, &explanations);
// Verify that an explanation was shown for a missing subjectAltName.
- EXPECT_EQ(1u, explanations.broken_explanations.size());
+ EXPECT_EQ(1u, explanations.insecure_explanations.size());
- explanations.broken_explanations.clear();
+ explanations.insecure_explanations.clear();
security_info.cert_missing_subject_alt_name = false;
GetSecurityStyle(security_info, &explanations);
// Verify that no explanation is shown if the subjectAltName is present.
- EXPECT_EQ(0u, explanations.broken_explanations.size());
+ EXPECT_EQ(0u, explanations.insecure_explanations.size());
}
} // namespace
diff --git a/chromium/components/security_state/core/BUILD.gn b/chromium/components/security_state/core/BUILD.gn
index bb28c1f81b4..091df2041ad 100644
--- a/chromium/components/security_state/core/BUILD.gn
+++ b/chromium/components/security_state/core/BUILD.gn
@@ -17,9 +17,10 @@ static_library("core") {
"switches.h",
]
- deps = [
+ public_deps = [
"//base",
"//net",
+ "//url",
]
}
diff --git a/chromium/components/security_state/core/security_state.cc b/chromium/components/security_state/core/security_state.cc
index 00368ec74a8..0843ff8e567 100644
--- a/chromium/components/security_state/core/security_state.cc
+++ b/chromium/components/security_state/core/security_state.cc
@@ -156,7 +156,8 @@ SecurityLevel GetSecurityLevelForRequest(
DCHECK_NE(CONTENT_STATUS_RAN, mixed_content_status);
DCHECK_NE(CONTENT_STATUS_DISPLAYED_AND_RAN, mixed_content_status);
- if (mixed_content_status == CONTENT_STATUS_DISPLAYED ||
+ if (visible_security_state.contained_mixed_form ||
+ mixed_content_status == CONTENT_STATUS_DISPLAYED ||
content_with_cert_errors_status == CONTENT_STATUS_DISPLAYED) {
return kDisplayedInsecureContentLevel;
}
@@ -228,6 +229,9 @@ void SecurityInfoForRequest(
nullptr);
}
+ security_info->contained_mixed_form =
+ visible_security_state.contained_mixed_form;
+
security_info->security_level = GetSecurityLevelForRequest(
visible_security_state, used_policy_installed_certificate,
is_origin_secure_callback, security_info->sha1_in_chain,
@@ -255,6 +259,7 @@ SecurityInfo::SecurityInfo()
pkp_bypassed(false),
displayed_password_field_on_http(false),
displayed_credit_card_field_on_http(false),
+ contained_mixed_form(false),
cert_missing_subject_alt_name(false) {}
SecurityInfo::~SecurityInfo() {}
@@ -281,6 +286,7 @@ VisibleSecurityState::VisibleSecurityState()
key_exchange_group(0),
security_bits(-1),
displayed_mixed_content(false),
+ contained_mixed_form(false),
ran_mixed_content(false),
displayed_content_with_cert_errors(false),
ran_content_with_cert_errors(false),
@@ -308,7 +314,8 @@ bool VisibleSecurityState::operator==(const VisibleSecurityState& other) const {
displayed_password_field_on_http ==
other.displayed_password_field_on_http &&
displayed_credit_card_field_on_http ==
- other.displayed_credit_card_field_on_http);
+ other.displayed_credit_card_field_on_http &&
+ contained_mixed_form == other.contained_mixed_form);
}
} // namespace security_state
diff --git a/chromium/components/security_state/core/security_state.h b/chromium/components/security_state/core/security_state.h
index 480d25ae6f0..aa5e8d48c1c 100644
--- a/chromium/components/security_state/core/security_state.h
+++ b/chromium/components/security_state/core/security_state.h
@@ -133,16 +133,14 @@ struct SecurityInfo {
// key exchange, or cipher for the connection is considered
// obsolete. See net::ObsoleteSSLMask for specific mask values.
int obsolete_ssl_status;
-
// True if pinning was bypassed due to a local trust anchor.
bool pkp_bypassed;
-
// True if the page displayed password field on an HTTP page.
bool displayed_password_field_on_http;
-
// True if the page displayed credit card field on an HTTP page.
bool displayed_credit_card_field_on_http;
-
+ // True if the secure page contained a form with a nonsecure target.
+ bool contained_mixed_form;
// True if the server's certificate does not contain a
// subjectAltName extension with a domain name or IP address.
bool cert_missing_subject_alt_name;
@@ -175,6 +173,8 @@ struct VisibleSecurityState {
std::vector<net::ct::SCTVerifyStatus> sct_verify_statuses;
// True if the page displayed passive mixed content.
bool displayed_mixed_content;
+ // True if the secure page contained a form with a nonsecure target.
+ bool contained_mixed_form;
// True if the page ran active mixed content.
bool ran_mixed_content;
// True if the page displayed passive subresources with certificate errors.
diff --git a/chromium/components/security_state/core/security_state_unittest.cc b/chromium/components/security_state/core/security_state_unittest.cc
index 5a9bbc7cc30..201a91d0b64 100644
--- a/chromium/components/security_state/core/security_state_unittest.cc
+++ b/chromium/components/security_state/core/security_state_unittest.cc
@@ -45,6 +45,7 @@ class TestSecurityStateHelper {
<< net::SSL_CONNECTION_VERSION_SHIFT),
cert_status_(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT),
displayed_mixed_content_(false),
+ contained_mixed_form_(false),
ran_mixed_content_(false),
malicious_content_status_(MALICIOUS_CONTENT_STATUS_NONE),
displayed_password_field_on_http_(false),
@@ -63,10 +64,13 @@ class TestSecurityStateHelper {
void AddCertStatus(net::CertStatus cert_status) {
cert_status_ |= cert_status;
}
- void SetDisplayedMixedContent(bool displayed_mixed_content) {
+ void set_displayed_mixed_content(bool displayed_mixed_content) {
displayed_mixed_content_ = displayed_mixed_content;
}
- void SetRanMixedContent(bool ran_mixed_content) {
+ void set_contained_mixed_form(bool contained_mixed_form) {
+ contained_mixed_form_ = contained_mixed_form;
+ }
+ void set_ran_mixed_content(bool ran_mixed_content) {
ran_mixed_content_ = ran_mixed_content;
}
void set_malicious_content_status(
@@ -93,6 +97,7 @@ class TestSecurityStateHelper {
state->connection_status = connection_status_;
state->security_bits = 256;
state->displayed_mixed_content = displayed_mixed_content_;
+ state->contained_mixed_form = contained_mixed_form_;
state->ran_mixed_content = ran_mixed_content_;
state->malicious_content_status = malicious_content_status_;
state->displayed_password_field_on_http = displayed_password_field_on_http_;
@@ -114,6 +119,7 @@ class TestSecurityStateHelper {
int connection_status_;
net::CertStatus cert_status_;
bool displayed_mixed_content_;
+ bool contained_mixed_form_;
bool ran_mixed_content_;
MaliciousContentStatus malicious_content_status_;
bool displayed_password_field_on_http_;
@@ -148,15 +154,15 @@ TEST(SecurityStateTest, SHA1Warning) {
// with the handling of mixed content.
TEST(SecurityStateTest, SHA1WarningMixedContent) {
TestSecurityStateHelper helper;
- helper.SetDisplayedMixedContent(true);
+ helper.set_displayed_mixed_content(true);
SecurityInfo security_info1;
helper.GetSecurityInfo(&security_info1);
EXPECT_TRUE(security_info1.sha1_in_chain);
EXPECT_EQ(CONTENT_STATUS_DISPLAYED, security_info1.mixed_content_status);
EXPECT_EQ(NONE, security_info1.security_level);
- helper.SetDisplayedMixedContent(false);
- helper.SetRanMixedContent(true);
+ helper.set_displayed_mixed_content(false);
+ helper.set_ran_mixed_content(true);
SecurityInfo security_info2;
helper.GetSecurityInfo(&security_info2);
EXPECT_TRUE(security_info2.sha1_in_chain);
@@ -389,4 +395,29 @@ TEST(SecurityStateTest, DetectSubjectAltName) {
EXPECT_TRUE(no_san_security_info.cert_missing_subject_alt_name);
}
+// Tests that a mixed form is reflected in the SecurityInfo.
+TEST(SecurityStateTest, MixedForm) {
+ TestSecurityStateHelper helper;
+
+ SecurityInfo no_mixed_form_security_info;
+ helper.GetSecurityInfo(&no_mixed_form_security_info);
+ EXPECT_FALSE(no_mixed_form_security_info.contained_mixed_form);
+
+ helper.set_contained_mixed_form(true);
+
+ SecurityInfo mixed_form_security_info;
+ helper.GetSecurityInfo(&mixed_form_security_info);
+ EXPECT_TRUE(mixed_form_security_info.contained_mixed_form);
+ EXPECT_EQ(CONTENT_STATUS_NONE, mixed_form_security_info.mixed_content_status);
+ EXPECT_EQ(NONE, mixed_form_security_info.security_level);
+
+ helper.set_ran_mixed_content(true);
+ SecurityInfo mixed_form_and_active_security_info;
+ helper.GetSecurityInfo(&mixed_form_and_active_security_info);
+ EXPECT_TRUE(mixed_form_and_active_security_info.contained_mixed_form);
+ EXPECT_EQ(CONTENT_STATUS_RAN,
+ mixed_form_and_active_security_info.mixed_content_status);
+ EXPECT_EQ(DANGEROUS, mixed_form_and_active_security_info.security_level);
+}
+
} // namespace security_state
diff --git a/chromium/components/session_manager/core/session_manager.cc b/chromium/components/session_manager/core/session_manager.cc
index d2387452bfe..def0fa65998 100644
--- a/chromium/components/session_manager/core/session_manager.cc
+++ b/chromium/components/session_manager/core/session_manager.cc
@@ -62,6 +62,14 @@ void SessionManager::SessionStarted() {
session_started_ = true;
}
+bool SessionManager::HasSessionForAccountId(
+ const AccountId& user_account_id) const {
+ return std::find_if(sessions_.begin(), sessions_.end(),
+ [user_account_id](const Session& session) {
+ return session.user_account_id == user_account_id;
+ }) != sessions_.end();
+}
+
bool SessionManager::IsInSecondaryLoginScreen() const {
return session_state_ == SessionState::LOGIN_SECONDARY;
}
@@ -99,11 +107,7 @@ void SessionManager::SetInstance(SessionManager* session_manager) {
void SessionManager::CreateSessionInternal(const AccountId& user_account_id,
const std::string& user_id_hash,
bool browser_restart) {
- DCHECK(std::find_if(sessions_.begin(), sessions_.end(),
- [user_account_id](const Session& session) {
- return session.user_account_id == user_account_id;
- }) == sessions_.end());
-
+ DCHECK(!HasSessionForAccountId(user_account_id));
sessions_.push_back({next_id_++, user_account_id});
NotifyUserLoggedIn(user_account_id, user_id_hash, browser_restart);
}
diff --git a/chromium/components/session_manager/core/session_manager.h b/chromium/components/session_manager/core/session_manager.h
index 27dc34b719d..666cc73a8f8 100644
--- a/chromium/components/session_manager/core/session_manager.h
+++ b/chromium/components/session_manager/core/session_manager.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_SESSION_MANAGER_CORE_SESSION_MANAGER_H_
#define COMPONENTS_SESSION_MANAGER_CORE_SESSION_MANAGER_H_
+#include <string>
#include <vector>
#include "base/macros.h"
@@ -49,6 +50,9 @@ class SESSION_EXPORT SessionManager {
// before the session has been started.
virtual void SessionStarted();
+ // Returns true if the session for the given user was started.
+ bool HasSessionForAccountId(const AccountId& user_account_id) const;
+
// Convenience wrapps of session state.
bool IsInSecondaryLoginScreen() const;
bool IsScreenLocked() const;
diff --git a/chromium/components/sessions/content/content_live_tab.cc b/chromium/components/sessions/content/content_live_tab.cc
index 7b1dff013ee..3f1ef66e042 100644
--- a/chromium/components/sessions/content/content_live_tab.cc
+++ b/chromium/components/sessions/content/content_live_tab.cc
@@ -62,10 +62,6 @@ ContentLiveTab::GetPlatformSpecificTabData() {
web_contents());
}
-void ContentLiveTab::LoadIfNecessary() {
- navigation_controller().LoadIfNecessary();
-}
-
const std::string& ContentLiveTab::GetUserAgentOverride() const {
return web_contents()->GetUserAgentOverride();
}
diff --git a/chromium/components/sessions/content/content_live_tab.h b/chromium/components/sessions/content/content_live_tab.h
index f4324411ea1..5c04ba15f9f 100644
--- a/chromium/components/sessions/content/content_live_tab.h
+++ b/chromium/components/sessions/content/content_live_tab.h
@@ -41,7 +41,6 @@ class SESSIONS_EXPORT ContentLiveTab
int GetEntryCount() override;
std::unique_ptr<PlatformSpecificTabData> GetPlatformSpecificTabData()
override;
- void LoadIfNecessary() override;
const std::string& GetUserAgentOverride() const override;
content::WebContents* web_contents() { return web_contents_; }
diff --git a/chromium/components/sessions/content/content_serialized_navigation_driver.cc b/chromium/components/sessions/content/content_serialized_navigation_driver.cc
index d9e4b1c7b21..20ec2d02090 100644
--- a/chromium/components/sessions/content/content_serialized_navigation_driver.cc
+++ b/chromium/components/sessions/content/content_serialized_navigation_driver.cc
@@ -4,27 +4,23 @@
#include "components/sessions/content/content_serialized_navigation_driver.h"
+#include <utility>
+
#include "base/memory/singleton.h"
-#include "build/build_config.h"
#include "components/sessions/core/serialized_navigation_entry.h"
-#include "content/public/common/content_features.h"
#include "content/public/common/page_state.h"
-#include "content/public/common/referrer.h"
-#include "content/public/common/url_constants.h"
+#include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
namespace sessions {
namespace {
+
const int kObsoleteReferrerPolicyAlways = 0;
const int kObsoleteReferrerPolicyDefault = 1;
const int kObsoleteReferrerPolicyNever = 2;
const int kObsoleteReferrerPolicyOrigin = 3;
-bool IsUberOrUberReplacementURL(const GURL& url) {
- return url.SchemeIs(content::kChromeUIScheme) &&
- (url.host_piece() == content::kChromeUIHistoryHost ||
- url.host_piece() == content::kChromeUIUberHost);
-}
+ContentSerializedNavigationDriver* g_instance = nullptr;
} // namespace
@@ -36,9 +32,21 @@ SerializedNavigationDriver* SerializedNavigationDriver::Get() {
// static
ContentSerializedNavigationDriver*
ContentSerializedNavigationDriver::GetInstance() {
- return base::Singleton<
+ if (g_instance)
+ return g_instance;
+
+ auto* instance = base::Singleton<
ContentSerializedNavigationDriver,
base::LeakySingletonTraits<ContentSerializedNavigationDriver>>::get();
+ g_instance = instance;
+ return instance;
+}
+
+// static
+void ContentSerializedNavigationDriver::SetInstance(
+ ContentSerializedNavigationDriver* instance) {
+ DCHECK(!g_instance || !instance);
+ g_instance = instance;
}
ContentSerializedNavigationDriver::ContentSerializedNavigationDriver() {
@@ -48,20 +56,20 @@ ContentSerializedNavigationDriver::~ContentSerializedNavigationDriver() {
}
int ContentSerializedNavigationDriver::GetDefaultReferrerPolicy() const {
- return blink::WebReferrerPolicyDefault;
+ return blink::kWebReferrerPolicyDefault;
}
bool ContentSerializedNavigationDriver::MapReferrerPolicyToOldValues(
int referrer_policy,
int* mapped_referrer_policy) const {
switch (referrer_policy) {
- case blink::WebReferrerPolicyAlways:
- case blink::WebReferrerPolicyDefault:
+ case blink::kWebReferrerPolicyAlways:
+ case blink::kWebReferrerPolicyDefault:
// "always" and "default" are the same value in all versions.
*mapped_referrer_policy = referrer_policy;
return true;
- case blink::WebReferrerPolicyOrigin:
+ case blink::kWebReferrerPolicyOrigin:
// "origin" exists in the old encoding.
*mapped_referrer_policy = kObsoleteReferrerPolicyOrigin;
return true;
@@ -85,7 +93,7 @@ bool ContentSerializedNavigationDriver::MapReferrerPolicyToNewValues(
default:
// Since we don't know what encoding was used, we map the rest to "never".
- *mapped_referrer_policy = blink::WebReferrerPolicyNever;
+ *mapped_referrer_policy = blink::kWebReferrerPolicyNever;
return false;
}
}
@@ -93,74 +101,16 @@ bool ContentSerializedNavigationDriver::MapReferrerPolicyToNewValues(
std::string
ContentSerializedNavigationDriver::GetSanitizedPageStateForPickle(
const SerializedNavigationEntry* navigation) const {
- if (!navigation->has_post_data_) {
- return navigation->encoded_page_state_;
- }
- content::PageState page_state =
- content::PageState::CreateFromEncodedData(
- navigation->encoded_page_state_);
+ if (!navigation->has_post_data())
+ return navigation->encoded_page_state();
+
+ content::PageState page_state = content::PageState::CreateFromEncodedData(
+ navigation->encoded_page_state());
return page_state.RemovePasswordData().ToEncodedData();
}
void ContentSerializedNavigationDriver::Sanitize(
SerializedNavigationEntry* navigation) const {
- content::Referrer old_referrer(
- navigation->referrer_url_,
- static_cast<blink::WebReferrerPolicy>(navigation->referrer_policy_));
- content::Referrer new_referrer =
- content::Referrer::SanitizeForRequest(navigation->virtual_url_,
- old_referrer);
-
- // Clear any Uber UI page state so that these pages are reloaded rather than
- // restored from page state. This fixes session restore when WebUI URLs
- // change.
- if (IsUberOrUberReplacementURL(navigation->virtual_url_) &&
- IsUberOrUberReplacementURL(navigation->original_request_url_)) {
- navigation->encoded_page_state_ = std::string();
- }
-
- // No need to compare the policy, as it doesn't change during
- // sanitization. If there has been a change, the referrer needs to be
- // stripped from the page state as well.
- if (navigation->referrer_url_ != new_referrer.url) {
- navigation->referrer_url_ = GURL();
- navigation->referrer_policy_ = GetDefaultReferrerPolicy();
- navigation->encoded_page_state_ =
- StripReferrerFromPageState(navigation->encoded_page_state_);
- }
-
-#if defined(OS_ANDROID)
- // Rewrite the old new tab and welcome page URLs to the new NTP URL.
- if (navigation->virtual_url_.SchemeIs(content::kChromeUIScheme) &&
- (navigation->virtual_url_.host_piece() == "welcome" ||
- navigation->virtual_url_.host_piece() == "newtab")) {
- navigation->virtual_url_ = GURL("chrome-native://newtab/");
- navigation->original_request_url_ = navigation->virtual_url_;
- navigation->encoded_page_state_ = content::PageState::CreateFromURL(
- navigation->virtual_url_).ToEncodedData();
- }
-
- if (base::FeatureList::IsEnabled(features::kNativeAndroidHistoryManager) &&
- navigation->virtual_url_.SchemeIs(content::kChromeUIScheme) &&
- (navigation->virtual_url_.host_piece() == content::kChromeUIHistoryHost ||
- navigation->virtual_url_.host_piece() ==
- content::kChromeUIHistoryFrameHost)) {
- // Rewrite the old history Web UI to the new android native history.
- navigation->virtual_url_ = GURL(content::kChromeUINativeHistoryURL);
- navigation->original_request_url_ = navigation->virtual_url_;
- navigation->encoded_page_state_ = content::PageState::CreateFromURL(
- navigation->virtual_url_).ToEncodedData();
- } else if (
- !base::FeatureList::IsEnabled(features::kNativeAndroidHistoryManager) &&
- navigation->virtual_url_.SchemeIs(content::kChromeNativeUIScheme) &&
- navigation->virtual_url_.host_piece() == content::kChromeUIHistoryHost) {
- // If the android native history UI has been disabled, redirect
- // chrome-native://history to the old web UI.
- navigation->virtual_url_ = GURL(content::kChromeUIHistoryURL);
- navigation->original_request_url_ = navigation->virtual_url_;
- navigation->encoded_page_state_ = std::string();
- }
-#endif // defined(OS_ANDROID)
}
std::string ContentSerializedNavigationDriver::StripReferrerFromPageState(
diff --git a/chromium/components/sessions/content/content_serialized_navigation_driver.h b/chromium/components/sessions/content/content_serialized_navigation_driver.h
index 768300dd1c8..ec732a70766 100644
--- a/chromium/components/sessions/content/content_serialized_navigation_driver.h
+++ b/chromium/components/sessions/content/content_serialized_navigation_driver.h
@@ -5,14 +5,13 @@
#ifndef COMPONENTS_SESSIONS_CONTENT_CONTENT_SERIALIZED_NAVIGATION_DRIVER_H_
#define COMPONENTS_SESSIONS_CONTENT_CONTENT_SERIALIZED_NAVIGATION_DRIVER_H_
-#include "components/sessions/core/serialized_navigation_driver.h"
-
#include <map>
#include <memory>
#include <string>
#include "base/macros.h"
#include "components/sessions/content/extended_info_handler.h"
+#include "components/sessions/core/serialized_navigation_driver.h"
#include "components/sessions/core/sessions_export.h"
namespace base {
@@ -32,6 +31,9 @@ class SESSIONS_EXPORT ContentSerializedNavigationDriver
// callers should use SerializedNavigationDriver::Get() instead.
static ContentSerializedNavigationDriver* GetInstance();
+ // Allows an embedder to override the instance returned by GetInstance().
+ static void SetInstance(ContentSerializedNavigationDriver* instance);
+
// SerializedNavigationDriver implementation.
int GetDefaultReferrerPolicy() const override;
bool MapReferrerPolicyToOldValues(int referrer_policy,
@@ -58,12 +60,13 @@ class SESSIONS_EXPORT ContentSerializedNavigationDriver
// Returns all the registered handlers to deal with the extended info.
const ExtendedInfoHandlerMap& GetAllExtendedInfoHandlers() const;
+ protected:
+ ContentSerializedNavigationDriver();
+
private:
friend struct base::DefaultSingletonTraits<ContentSerializedNavigationDriver>;
friend class ContentSerializedNavigationBuilderTest;
- ContentSerializedNavigationDriver();
-
ExtendedInfoHandlerMap extended_info_handler_map_;
DISALLOW_COPY_AND_ASSIGN(ContentSerializedNavigationDriver);
diff --git a/chromium/components/sessions/content/content_serialized_navigation_driver_unittest.cc b/chromium/components/sessions/content/content_serialized_navigation_driver_unittest.cc
index 67a34512d8c..74e4addef9c 100644
--- a/chromium/components/sessions/content/content_serialized_navigation_driver_unittest.cc
+++ b/chromium/components/sessions/content/content_serialized_navigation_driver_unittest.cc
@@ -6,10 +6,7 @@
#include "components/sessions/core/serialized_navigation_entry.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
-#include "content/public/common/page_state.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
-#include "ui/base/page_transition_types.h"
namespace sessions {
@@ -41,80 +38,4 @@ TEST(ContentSerializedNavigationDriverTest, PickleSanitizationNoPostData) {
EXPECT_EQ(test_data::kEncodedPageState, sanitized_page_state);
}
-// Tests that the input data is left unsanitized when the referrer policy is
-// Always.
-TEST(ContentSerializedNavigationDriverTest, SanitizeWithReferrerPolicyAlways) {
- ContentSerializedNavigationDriver* driver =
- ContentSerializedNavigationDriver::GetInstance();
- SerializedNavigationEntry navigation =
- SerializedNavigationEntryTestHelper::CreateNavigationForTest();
- SerializedNavigationEntryTestHelper::SetReferrerPolicy(
- blink::WebReferrerPolicyAlways, &navigation);
-
- content::PageState page_state =
- content::PageState::CreateFromURL(test_data::kVirtualURL);
- SerializedNavigationEntryTestHelper::SetEncodedPageState(
- page_state.ToEncodedData(), &navigation);
-
- driver->Sanitize(&navigation);
- EXPECT_EQ(test_data::kIndex, navigation.index());
- EXPECT_EQ(test_data::kUniqueID, navigation.unique_id());
- EXPECT_EQ(test_data::kReferrerURL, navigation.referrer_url());
- EXPECT_EQ(blink::WebReferrerPolicyAlways, navigation.referrer_policy());
- EXPECT_EQ(test_data::kVirtualURL, navigation.virtual_url());
- EXPECT_EQ(test_data::kTitle, navigation.title());
- EXPECT_EQ(page_state.ToEncodedData(), navigation.encoded_page_state());
- EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
- navigation.transition_type(), test_data::kTransitionType));
- EXPECT_EQ(test_data::kHasPostData, navigation.has_post_data());
- EXPECT_EQ(test_data::kPostID, navigation.post_id());
- EXPECT_EQ(test_data::kOriginalRequestURL, navigation.original_request_url());
- EXPECT_EQ(test_data::kIsOverridingUserAgent,
- navigation.is_overriding_user_agent());
- EXPECT_EQ(test_data::kTimestamp, navigation.timestamp());
- EXPECT_EQ(test_data::kSearchTerms, navigation.search_terms());
- EXPECT_EQ(test_data::kFaviconURL, navigation.favicon_url());
- EXPECT_EQ(test_data::kHttpStatusCode, navigation.http_status_code());
-}
-
-// Tests that the input data is properly sanitized when the referrer policy is
-// Never.
-TEST(ContentSerializedNavigationDriverTest, SanitizeWithReferrerPolicyNever) {
- ContentSerializedNavigationDriver* driver =
- ContentSerializedNavigationDriver::GetInstance();
- SerializedNavigationEntry navigation =
- SerializedNavigationEntryTestHelper::CreateNavigationForTest();
- SerializedNavigationEntryTestHelper::SetReferrerPolicy(
- blink::WebReferrerPolicyNever, &navigation);
-
- content::PageState page_state =
- content::PageState::CreateFromURL(test_data::kVirtualURL);
- SerializedNavigationEntryTestHelper::SetEncodedPageState(
- page_state.ToEncodedData(), &navigation);
-
- driver->Sanitize(&navigation);
-
- // Fields that should remain untouched.
- EXPECT_EQ(test_data::kIndex, navigation.index());
- EXPECT_EQ(test_data::kUniqueID, navigation.unique_id());
- EXPECT_EQ(test_data::kVirtualURL, navigation.virtual_url());
- EXPECT_EQ(test_data::kTitle, navigation.title());
- EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
- navigation.transition_type(), test_data::kTransitionType));
- EXPECT_EQ(test_data::kHasPostData, navigation.has_post_data());
- EXPECT_EQ(test_data::kPostID, navigation.post_id());
- EXPECT_EQ(test_data::kOriginalRequestURL, navigation.original_request_url());
- EXPECT_EQ(test_data::kIsOverridingUserAgent,
- navigation.is_overriding_user_agent());
- EXPECT_EQ(test_data::kTimestamp, navigation.timestamp());
- EXPECT_EQ(test_data::kSearchTerms, navigation.search_terms());
- EXPECT_EQ(test_data::kFaviconURL, navigation.favicon_url());
- EXPECT_EQ(test_data::kHttpStatusCode, navigation.http_status_code());
-
- // Fields that were sanitized.
- EXPECT_EQ(GURL(), navigation.referrer_url());
- EXPECT_EQ(blink::WebReferrerPolicyDefault, navigation.referrer_policy());
- EXPECT_EQ(page_state.ToEncodedData(), navigation.encoded_page_state());
-}
-
} // namespace sessions
diff --git a/chromium/components/sessions/core/live_tab.h b/chromium/components/sessions/core/live_tab.h
index bd6129395a4..490219941e3 100644
--- a/chromium/components/sessions/core/live_tab.h
+++ b/chromium/components/sessions/core/live_tab.h
@@ -32,10 +32,6 @@ class SESSIONS_EXPORT LiveTab {
// implementation returns null.
virtual std::unique_ptr<PlatformSpecificTabData> GetPlatformSpecificTabData();
- // Loads the current page if necessary (where "necessary" is defined on a
- // platform-specific basis).
- virtual void LoadIfNecessary() = 0;
-
// Returns the user agent override, if any.
virtual const std::string& GetUserAgentOverride() const = 0;
};
diff --git a/chromium/components/sessions/core/serialized_navigation_driver.h b/chromium/components/sessions/core/serialized_navigation_driver.h
index 5fc261e4a95..74bbfefe1cb 100644
--- a/chromium/components/sessions/core/serialized_navigation_driver.h
+++ b/chromium/components/sessions/core/serialized_navigation_driver.h
@@ -18,8 +18,6 @@ class SerializedNavigationEntry;
// must be provided by the driver on each platform.
class SESSIONS_EXPORT SerializedNavigationDriver {
public:
- virtual ~SerializedNavigationDriver() {}
-
// Returns the singleton SerializedNavigationDriver.
static SerializedNavigationDriver* Get();
@@ -50,6 +48,9 @@ class SESSIONS_EXPORT SerializedNavigationDriver {
// Removes the referrer from the encoded page state.
virtual std::string StripReferrerFromPageState(
const std::string& page_state) const = 0;
+
+ protected:
+ virtual ~SerializedNavigationDriver() {}
};
} // namespace sessions
diff --git a/chromium/components/sessions/core/serialized_navigation_entry.h b/chromium/components/sessions/core/serialized_navigation_entry.h
index 3a8e665ff02..51171b4984f 100644
--- a/chromium/components/sessions/core/serialized_navigation_entry.h
+++ b/chromium/components/sessions/core/serialized_navigation_entry.h
@@ -88,20 +88,15 @@ class SESSIONS_EXPORT SerializedNavigationEntry {
// Accessors for some fields taken from NavigationEntry.
int unique_id() const { return unique_id_; }
- const GURL& virtual_url() const { return virtual_url_; }
const base::string16& title() const { return title_; }
- const std::string& encoded_page_state() const { return encoded_page_state_; }
const base::string16& search_terms() const { return search_terms_; }
const GURL& favicon_url() const { return favicon_url_; }
int http_status_code() const { return http_status_code_; }
- const GURL& referrer_url() const { return referrer_url_; }
- int referrer_policy() const { return referrer_policy_; }
ui::PageTransition transition_type() const {
return transition_type_;
}
bool has_post_data() const { return has_post_data_; }
int64_t post_id() const { return post_id_; }
- const GURL& original_request_url() const { return original_request_url_; }
bool is_overriding_user_agent() const { return is_overriding_user_agent_; }
base::Time timestamp() const { return timestamp_; }
@@ -115,6 +110,29 @@ class SESSIONS_EXPORT SerializedNavigationEntry {
password_state_ = password_state;
}
+ const GURL& virtual_url() const { return virtual_url_; }
+ void set_virtual_url(const GURL& virtual_url) { virtual_url_ = virtual_url; }
+
+ const std::string& encoded_page_state() const { return encoded_page_state_; }
+ void set_encoded_page_state(const std::string& encoded_page_state) {
+ encoded_page_state_ = encoded_page_state;
+ }
+
+ const GURL& original_request_url() const { return original_request_url_; }
+ void set_original_request_url(const GURL& original_request_url) {
+ original_request_url_ = original_request_url;
+ }
+
+ const GURL& referrer_url() const { return referrer_url_; }
+ void set_referrer_url(const GURL& referrer_url) {
+ referrer_url_ = referrer_url;
+ }
+
+ int referrer_policy() const { return referrer_policy_; }
+ void set_referrer_policy(int referrer_policy) {
+ referrer_policy_ = referrer_policy;
+ }
+
std::set<std::string> content_pack_categories() const {
return content_pack_categories_;
}
@@ -132,7 +150,6 @@ class SESSIONS_EXPORT SerializedNavigationEntry {
private:
friend class ContentSerializedNavigationBuilder;
- friend class ContentSerializedNavigationDriver;
friend class SerializedNavigationEntryTestHelper;
friend class IOSSerializedNavigationBuilder;
friend class IOSSerializedNavigationDriver;
diff --git a/chromium/components/sessions/core/session_service_commands.cc b/chromium/components/sessions/core/session_service_commands.cc
index d066372deaa..790a5001f03 100644
--- a/chromium/components/sessions/core/session_service_commands.cc
+++ b/chromium/components/sessions/core/session_service_commands.cc
@@ -114,7 +114,7 @@ enum PersistedWindowShowState {
PERSISTED_SHOW_STATE_FULLSCREEN = 5,
PERSISTED_SHOW_STATE_DETACHED_DEPRECATED = 6,
PERSISTED_SHOW_STATE_DOCKED_DEPRECATED = 7,
- PERSISTED_SHOW_STATE_END = 7
+ PERSISTED_SHOW_STATE_END = 8,
};
using IdToSessionTab =
@@ -125,9 +125,10 @@ using IdToSessionWindow =
// Assert to ensure PersistedWindowShowState is updated if ui::WindowShowState
// is changed.
static_assert(ui::SHOW_STATE_END ==
- static_cast<ui::WindowShowState>(PERSISTED_SHOW_STATE_END),
- "SHOW_STATE_END must equal PERSISTED_SHOW_STATE_END");
-
+ (static_cast<ui::WindowShowState>(PERSISTED_SHOW_STATE_END) -
+ 2),
+ "SHOW_STATE_END must equal PERSISTED_SHOW_STATE_END minus the "
+ "deprecated entries");
// Returns the show state to store to disk based |state|.
PersistedWindowShowState ShowStateToPersistedShowState(
ui::WindowShowState state) {
@@ -140,11 +141,6 @@ PersistedWindowShowState ShowStateToPersistedShowState(
return PERSISTED_SHOW_STATE_MAXIMIZED;
case ui::SHOW_STATE_FULLSCREEN:
return PERSISTED_SHOW_STATE_FULLSCREEN;
-
- // TODO(afakhry): Remove Docked Windows in M58.
- case ui::SHOW_STATE_DOCKED:
- return PERSISTED_SHOW_STATE_DOCKED_DEPRECATED;
-
case ui::SHOW_STATE_DEFAULT:
case ui::SHOW_STATE_INACTIVE:
return PERSISTED_SHOW_STATE_NORMAL;
@@ -167,9 +163,8 @@ ui::WindowShowState PersistedShowStateToShowState(int state) {
return ui::SHOW_STATE_MAXIMIZED;
case PERSISTED_SHOW_STATE_FULLSCREEN:
return ui::SHOW_STATE_FULLSCREEN;
- case PERSISTED_SHOW_STATE_DOCKED_DEPRECATED:
- return ui::SHOW_STATE_DOCKED;
case PERSISTED_SHOW_STATE_DETACHED_DEPRECATED:
+ case PERSISTED_SHOW_STATE_DOCKED_DEPRECATED:
return ui::SHOW_STATE_NORMAL;
}
NOTREACHED();
diff --git a/chromium/components/sessions/core/session_types.cc b/chromium/components/sessions/core/session_types.cc
index db020bf0b83..4b7ced980ca 100644
--- a/chromium/components/sessions/core/session_types.cc
+++ b/chromium/components/sessions/core/session_types.cc
@@ -39,9 +39,6 @@ void SessionTab::SetFromSyncData(const sync_pb::SessionTab& sync_data,
SerializedNavigationEntry::FromSyncData(i, sync_data.navigation(i)));
}
session_storage_persistent_id.clear();
- variation_ids.clear();
- for (int i = 0; i < sync_data.variation_id_size(); ++i)
- variation_ids.push_back(sync_data.variation_id(i));
}
sync_pb::SessionTab SessionTab::ToSyncData() const {
@@ -55,9 +52,6 @@ sync_pb::SessionTab SessionTab::ToSyncData() const {
for (const SerializedNavigationEntry& navigation : navigations) {
*sync_data.add_navigation() = navigation.ToSyncData();
}
- for (const variations::VariationID variation_id : variation_ids) {
- sync_data.add_variation_id(variation_id);
- }
return sync_data;
}
@@ -71,27 +65,4 @@ SessionWindow::SessionWindow()
SessionWindow::~SessionWindow() {}
-sync_pb::SessionWindow SessionWindow::ToSyncData() const {
- sync_pb::SessionWindow sync_data;
- sync_data.set_window_id(window_id.id());
- sync_data.set_selected_tab_index(selected_tab_index);
- switch (type) {
- case SessionWindow::TYPE_TABBED:
- sync_data.set_browser_type(
- sync_pb::SessionWindow_BrowserType_TYPE_TABBED);
- break;
- case SessionWindow::TYPE_POPUP:
- sync_data.set_browser_type(
- sync_pb::SessionWindow_BrowserType_TYPE_POPUP);
- break;
- default:
- NOTREACHED() << "Unhandled browser type.";
- }
-
- for (const auto& tab : tabs)
- sync_data.add_tab(tab->tab_id.id());
-
- return sync_data;
-}
-
} // namespace sessions
diff --git a/chromium/components/sessions/core/session_types.h b/chromium/components/sessions/core/session_types.h
index dbaabe6e24e..5ac0325d691 100644
--- a/chromium/components/sessions/core/session_types.h
+++ b/chromium/components/sessions/core/session_types.h
@@ -103,9 +103,6 @@ struct SESSIONS_EXPORT SessionTab {
// For reassociating sessionStorage.
std::string session_storage_persistent_id;
- // Ids of the currently assigned variations which should be sent to sync.
- std::vector<variations::VariationID> variation_ids;
-
private:
DISALLOW_COPY_AND_ASSIGN(SessionTab);
};
@@ -124,11 +121,6 @@ struct SESSIONS_EXPORT SessionWindow {
TYPE_POPUP = 1
};
- // Convert this object into its sync protocol buffer equivalent. Note that
- // not all fields are synced here, because they don't all make sense or
- // translate when restoring a SessionWindow on another device.
- sync_pb::SessionWindow ToSyncData() const;
-
// Identifier of the window.
SessionID window_id;
diff --git a/chromium/components/sessions/core/session_types_unittest.cc b/chromium/components/sessions/core/session_types_unittest.cc
index e7ef985bf58..a9aeee56c36 100644
--- a/chromium/components/sessions/core/session_types_unittest.cc
+++ b/chromium/components/sessions/core/session_types_unittest.cc
@@ -37,8 +37,6 @@ TEST(SessionTab, FromSyncData) {
navigation->set_title("title");
navigation->set_page_transition(sync_pb::SyncEnums_PageTransition_TYPED);
}
- sync_data.add_variation_id(3312238);
- sync_data.add_variation_id(3312242);
sessions::SessionTab tab;
tab.window_id.set_id(100);
@@ -71,9 +69,6 @@ TEST(SessionTab, FromSyncData) {
EXPECT_EQ(GURL("http://foo/" + base::IntToString(i)),
tab.navigations[i].virtual_url());
}
- ASSERT_EQ(2u, tab.variation_ids.size());
- EXPECT_EQ(3312238, tab.variation_ids[0]);
- EXPECT_EQ(3312242, tab.variation_ids[1]);
EXPECT_TRUE(tab.session_storage_persistent_id.empty());
}
@@ -93,8 +88,6 @@ TEST(SessionTab, ToSyncData) {
"http://foo/" + base::IntToString(i), "title"));
}
tab.session_storage_persistent_id = "fake";
- tab.variation_ids.push_back(3312238);
- tab.variation_ids.push_back(3312242);
const sync_pb::SessionTab& sync_data = tab.ToSyncData();
EXPECT_EQ(5, sync_data.tab_id());
@@ -113,10 +106,6 @@ TEST(SessionTab, ToSyncData) {
EXPECT_FALSE(sync_data.has_favicon());
EXPECT_FALSE(sync_data.has_favicon_type());
EXPECT_FALSE(sync_data.has_favicon_source());
-
- ASSERT_EQ(2, sync_data.variation_id_size());
- EXPECT_EQ(3312238u, sync_data.variation_id(0));
- EXPECT_EQ(3312242u, sync_data.variation_id(1));
}
} // namespace
diff --git a/chromium/components/sessions/core/tab_restore_service_client.h b/chromium/components/sessions/core/tab_restore_service_client.h
index a6aa4a8f4c6..b5d3b97671f 100644
--- a/chromium/components/sessions/core/tab_restore_service_client.h
+++ b/chromium/components/sessions/core/tab_restore_service_client.h
@@ -12,18 +12,18 @@
#include "components/sessions/core/session_id.h"
#include "components/sessions/core/sessions_export.h"
+class GURL;
+
namespace base {
class CancelableTaskTracker;
class SequencedWorkerPool;
}
-class GURL;
-
namespace sessions {
class LiveTab;
-struct SessionWindow;
class LiveTabContext;
+struct SessionWindow;
// Callback from TabRestoreServiceClient::GetLastSession.
// The second parameter is the id of the window that was last active.
diff --git a/chromium/components/sessions/core/tab_restore_service_helper.cc b/chromium/components/sessions/core/tab_restore_service_helper.cc
index c140cda055a..e792dd6b67f 100644
--- a/chromium/components/sessions/core/tab_restore_service_helper.cc
+++ b/chromium/components/sessions/core/tab_restore_service_helper.cc
@@ -209,7 +209,6 @@ std::vector<LiveTab*> TabRestoreServiceHelper::RestoreEntryById(
tab.from_last_session, tab.platform_data.get(),
tab.user_agent_override);
if (restored_tab) {
- restored_tab->LoadIfNecessary();
client_->OnTabRestored(
tab.navigations.at(tab.current_navigation_index).virtual_url());
live_tabs.push_back(restored_tab);
@@ -411,16 +410,11 @@ void TabRestoreServiceHelper::PopulateTab(Tab* tab,
int index,
LiveTabContext* context,
LiveTab* live_tab) {
- const int pending_index = live_tab->GetPendingEntryIndex();
int entry_count =
live_tab->IsInitialBlankNavigation() ? 0 : live_tab->GetEntryCount();
- if (entry_count == 0 && pending_index == 0)
- entry_count++;
tab->navigations.resize(static_cast<int>(entry_count));
for (int i = 0; i < entry_count; ++i) {
- SerializedNavigationEntry entry = (i == pending_index)
- ? live_tab->GetPendingEntry()
- : live_tab->GetEntryAtIndex(i);
+ SerializedNavigationEntry entry = live_tab->GetEntryAtIndex(i);
tab->navigations[i] = entry;
}
tab->timestamp = TimeNow();
@@ -482,7 +476,6 @@ LiveTabContext* TabRestoreServiceHelper::RestoreTab(
disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB, tab.pinned,
tab.from_last_session, tab.platform_data.get(),
tab.user_agent_override);
- restored_tab->LoadIfNecessary();
}
client_->OnTabRestored(
tab.navigations.at(tab.current_navigation_index).virtual_url());
diff --git a/chromium/components/sessions/ios/ios_live_tab.h b/chromium/components/sessions/ios/ios_live_tab.h
index d4363a517a8..17b6fe54f60 100644
--- a/chromium/components/sessions/ios/ios_live_tab.h
+++ b/chromium/components/sessions/ios/ios_live_tab.h
@@ -35,7 +35,6 @@ class SESSIONS_EXPORT IOSLiveTab : public LiveTab,
sessions::SerializedNavigationEntry GetEntryAtIndex(int index) override;
sessions::SerializedNavigationEntry GetPendingEntry() override;
int GetEntryCount() override;
- void LoadIfNecessary() override;
const std::string& GetUserAgentOverride() const override;
web::WebState* web_state() { return web_state_; }
diff --git a/chromium/components/sessions/ios/ios_live_tab.mm b/chromium/components/sessions/ios/ios_live_tab.mm
index 5f8f7dda6be..584b5238dfc 100644
--- a/chromium/components/sessions/ios/ios_live_tab.mm
+++ b/chromium/components/sessions/ios/ios_live_tab.mm
@@ -33,7 +33,7 @@ bool IOSLiveTab::IsInitialBlankNavigation() {
}
int IOSLiveTab::GetCurrentEntryIndex() {
- return navigation_manager()->GetCurrentItemIndex();
+ return navigation_manager()->GetLastCommittedItemIndex();
}
int IOSLiveTab::GetPendingEntryIndex() {
@@ -54,10 +54,6 @@ int IOSLiveTab::GetEntryCount() {
return navigation_manager()->GetItemCount();
}
-void IOSLiveTab::LoadIfNecessary() {
- navigation_manager()->LoadIfNecessary();
-}
-
const std::string& IOSLiveTab::GetUserAgentOverride() const {
// Dynamic user agent overrides are not supported on iOS.
return user_agent_override_;
diff --git a/chromium/components/signin/OWNERS b/chromium/components/signin/OWNERS
index b3c82866293..11e357ed8c4 100644
--- a/chromium/components/signin/OWNERS
+++ b/chromium/components/signin/OWNERS
@@ -1,2 +1,4 @@
msarda@chromium.org
rogerta@chromium.org
+
+# COMPONENT: Services>SignIn
diff --git a/chromium/components/signin/core/browser/about_signin_internals.cc b/chromium/components/signin/core/browser/about_signin_internals.cc
index d925e375482..da7be07b13c 100644
--- a/chromium/components/signin/core/browser/about_signin_internals.cc
+++ b/chromium/components/signin/core/browser/about_signin_internals.cc
@@ -188,7 +188,7 @@ void AboutSigninInternals::RegisterPrefs(
for (int i = UNTIMED_FIELDS_BEGIN; i < UNTIMED_FIELDS_END; ++i) {
const std::string pref_path =
SigninStatusFieldToString(static_cast<UntimedSigninStatusField>(i));
- user_prefs->RegisterStringPref(pref_path.c_str(), std::string());
+ user_prefs->RegisterStringPref(pref_path, std::string());
}
for (int i = TIMED_FIELDS_BEGIN; i < TIMED_FIELDS_END; ++i) {
@@ -198,8 +198,8 @@ void AboutSigninInternals::RegisterPrefs(
const std::string time =
SigninStatusFieldToString(static_cast<TimedSigninStatusField>(i)) +
".time";
- user_prefs->RegisterStringPref(value.c_str(), std::string());
- user_prefs->RegisterStringPref(time.c_str(), std::string());
+ user_prefs->RegisterStringPref(value, std::string());
+ user_prefs->RegisterStringPref(time, std::string());
}
}
@@ -466,7 +466,7 @@ AboutSigninInternals::TokenInfo::ToValue() const {
scopes_str += *it + "<br/>";
}
token_info->SetString("scopes", scopes_str);
- token_info->SetString("request_time", GetTimeStr(request_time).c_str());
+ token_info->SetString("request_time", GetTimeStr(request_time));
if (removed_) {
token_info->SetString("status", "Token was revoked.");
@@ -537,8 +537,6 @@ AboutSigninInternals::SigninStatus::ToValue(
// A summary of signin related info first.
base::ListValue* basic_info = AddSection(signin_info, "Basic Information");
AddSectionEntry(basic_info, "Chrome Version", product_version);
- AddSectionEntry(basic_info, "New Profile Management?",
- switches::IsNewProfileManagement() == true ? "On" : "Off");
AddSectionEntry(basic_info, "Account Consistency?",
switches::IsEnableAccountConsistency() == true ? "On" : "Off");
AddSectionEntry(basic_info, "Signin Status",
diff --git a/chromium/components/signin/core/browser/account_tracker_service.cc b/chromium/components/signin/core/browser/account_tracker_service.cc
index dd3f339588f..129b124288c 100644
--- a/chromium/components/signin/core/browser/account_tracker_service.cc
+++ b/chromium/components/signin/core/browser/account_tracker_service.cc
@@ -350,7 +350,7 @@ void AccountTrackerService::LoadFromPrefs() {
contains_deprecated_service_flags = true;
std::string flag_string;
for (const auto& flag : *service_flags_list) {
- if (flag->GetAsString(&flag_string) &&
+ if (flag.GetAsString(&flag_string) &&
flag_string == kChildAccountServiceFlag) {
is_child_account = true;
break;
@@ -407,6 +407,8 @@ void AccountTrackerService::SaveToPrefs(const AccountState& state) {
if (!dict) {
dict = new base::DictionaryValue();
update->Append(base::WrapUnique(dict));
+ // |dict| is invalidated at this point, so it needs to be reset.
+ update->GetDictionary(update->GetSize() - 1, &dict);
dict->SetString(kAccountKeyPath, account_id_16);
}
diff --git a/chromium/components/signin/core/browser/android/BUILD.gn b/chromium/components/signin/core/browser/android/BUILD.gn
index 400ccabe384..20aac14c374 100644
--- a/chromium/components/signin/core/browser/android/BUILD.gn
+++ b/chromium/components/signin/core/browser/android/BUILD.gn
@@ -15,6 +15,7 @@ android_library("java") {
deps = [
"//base:base_java",
"//net/android:net_java",
+ "//third_party/android_tools:android_support_annotations_java",
google_play_services_library,
]
@@ -47,6 +48,7 @@ android_library("signin_java_test_support") {
":java",
"//base:base_java",
"//base:base_java_test_support",
+ "//third_party/android_tools:android_support_annotations_java",
"//third_party/jsr-305:jsr_305_javalib",
]
diff --git a/chromium/components/signin/core/browser/child_account_info_fetcher_impl.cc b/chromium/components/signin/core/browser/child_account_info_fetcher_impl.cc
index 22b904859a3..1ada5f27b9b 100644
--- a/chromium/components/signin/core/browser/child_account_info_fetcher_impl.cc
+++ b/chromium/components/signin/core/browser/child_account_info_fetcher_impl.cc
@@ -84,8 +84,8 @@ void ChildAccountInfoFetcherImpl::FetchIfNotInProgress() {
fetch_in_progress_ = true;
OAuth2TokenService::ScopeSet scopes;
scopes.insert(GaiaConstants::kOAuth1LoginScope);
- login_token_request_.reset(
- token_service_->StartRequest(account_id_, scopes, this).release());
+ login_token_request_ =
+ token_service_->StartRequest(account_id_, scopes, this);
}
void ChildAccountInfoFetcherImpl::OnGetTokenSuccess(
@@ -96,9 +96,8 @@ void ChildAccountInfoFetcherImpl::OnGetTokenSuccess(
"OnGetTokenSuccess");
DCHECK_EQ(request, login_token_request_.get());
- gaia_auth_fetcher_.reset(
- fetcher_service_->signin_client_->CreateGaiaAuthFetcher(
- this, GaiaConstants::kChromeSource, request_context_getter_));
+ gaia_auth_fetcher_ = fetcher_service_->signin_client_->CreateGaiaAuthFetcher(
+ this, GaiaConstants::kChromeSource, request_context_getter_);
gaia_auth_fetcher_->StartOAuthLogin(access_token,
GaiaConstants::kGaiaService);
}
diff --git a/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc b/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
index 28f30f1d2ff..a3aa65fe8ee 100644
--- a/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -8,6 +8,7 @@
#include <queue>
+#include "base/format_macros.h"
#include "base/json/json_reader.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
@@ -57,6 +58,7 @@ const net::BackoffEntry::Policy kBackoffPolicy = {
false,
};
+// The maximum number of retries for a fetcher used in this class.
const int kMaxFetcherRetries = 8;
// Name of the GAIA cookie that is being observed to detect when available
@@ -130,14 +132,13 @@ GaiaCookieManagerService::ExternalCcResultFetcher::GetExternalCcResult() {
}
void GaiaCookieManagerService::ExternalCcResultFetcher::Start() {
+ DCHECK(!helper_->external_cc_result_fetched_);
m_external_cc_result_start_time_ = base::Time::Now();
CleanupTransientState();
results_.clear();
- helper_->gaia_auth_fetcher_.reset(
- helper_->signin_client_->CreateGaiaAuthFetcher(
- this, helper_->GetDefaultSourceForRequest(),
- helper_->request_context()));
+ helper_->gaia_auth_fetcher_ = helper_->signin_client_->CreateGaiaAuthFetcher(
+ this, helper_->GetDefaultSourceForRequest(), helper_->request_context());
helper_->gaia_auth_fetcher_->StartGetCheckConnectionInfo();
// Some fetches may timeout. Start a timer to decide when the result fetcher
@@ -150,7 +151,8 @@ void GaiaCookieManagerService::ExternalCcResultFetcher::Start() {
}
bool GaiaCookieManagerService::ExternalCcResultFetcher::IsRunning() {
- return helper_->gaia_auth_fetcher_ || fetchers_.size() > 0u;
+ return helper_->gaia_auth_fetcher_ || fetchers_.size() > 0u ||
+ timer_.IsRunning();
}
void GaiaCookieManagerService::ExternalCcResultFetcher::TimeoutForTests() {
@@ -159,8 +161,6 @@ void GaiaCookieManagerService::ExternalCcResultFetcher::TimeoutForTests() {
void GaiaCookieManagerService::ExternalCcResultFetcher::
OnGetCheckConnectionInfoSuccess(const std::string& data) {
- helper_->fetcher_backoff_.InformOfRequest(true);
- gaia_auth_fetcher_timer_.Stop();
std::unique_ptr<base::Value> value = base::JSONReader::Read(data);
const base::ListValue* list;
if (!value || !value->GetAsList(&list)) {
@@ -195,15 +195,17 @@ void GaiaCookieManagerService::ExternalCcResultFetcher::
void GaiaCookieManagerService::ExternalCcResultFetcher::
OnGetCheckConnectionInfoError(const GoogleServiceAuthError& error) {
- if (++helper_->fetcher_retries_ < kMaxFetcherRetries &&
- error.IsTransientError()) {
- helper_->fetcher_backoff_.InformOfRequest(false);
- gaia_auth_fetcher_timer_.Start(
- FROM_HERE, helper_->fetcher_backoff_.GetTimeUntilRelease(),
- this, &GaiaCookieManagerService::ExternalCcResultFetcher::Start);
- return;
- }
-
+ VLOG(1) << "GaiaCookieManagerService::ExternalCcResultFetcher::"
+ << "OnGetCheckConnectionInfoError " << error.ToString();
+
+ // Chrome does not have any retry logic for fetching ExternalCcResult. The
+ // ExternalCcResult is only used to inform Gaia that Chrome has already
+ // checked the connection to other sites.
+ //
+ // In case fetching the ExternalCcResult fails:
+ // * The result of merging accounts to Gaia cookies will not be affected.
+ // * Gaia will need make its own call about whether to check them itself,
+ // of make some other assumptions.
CleanupTransientState();
GetCheckConnectionInfoCompleted(false);
}
@@ -256,6 +258,7 @@ void GaiaCookieManagerService::ExternalCcResultFetcher::OnURLFetchComplete(
}
void GaiaCookieManagerService::ExternalCcResultFetcher::Timeout() {
+ VLOG(1) << " GaiaCookieManagerService::ExternalCcResultFetcher::Timeout";
CleanupTransientState();
GetCheckConnectionInfoCompleted(false);
}
@@ -298,7 +301,12 @@ GaiaCookieManagerService::GaiaCookieManagerService(
fetcher_retries_(0),
source_(source),
external_cc_result_fetched_(false),
- list_accounts_stale_(true) {
+ list_accounts_stale_(true),
+ // |GaiaCookieManagerService| is created as soon as the profle is
+ // initialized so it is acceptable to use of this
+ // |GaiaCookieManagerService| as the time when the profile is loaded.
+ profile_load_time_(base::Time::Now()),
+ list_accounts_request_counter_(0) {
DCHECK(!source_.empty());
}
@@ -468,8 +476,21 @@ void GaiaCookieManagerService::CancelAll() {
std::string GaiaCookieManagerService::GetSourceForRequest(
const GaiaCookieManagerService::GaiaCookieRequest& request) {
- return request.source().empty() ? GetDefaultSourceForRequest() :
- request.source();
+ std::string source = request.source().empty() ? GetDefaultSourceForRequest()
+ : request.source();
+ if (request.request_type() != LIST_ACCOUNTS)
+ return source;
+
+ // For list accounts requests, the source also includes the time since the
+ // profile was loaded and the number of the request in order to debug channel
+ // ID issues observed on Gaia.
+ // TODO(msarda): Remove this debug code once the investigations on Gaia side
+ // are over.
+ std::string source_with_debug_info = base::StringPrintf(
+ "%s,counter:%" PRId32 ",load_time_ms:%" PRId64, source.c_str(),
+ list_accounts_request_counter_++,
+ (base::Time::Now() - profile_load_time_).InMilliseconds());
+ return source_with_debug_info;
}
std::string GaiaCookieManagerService::GetDefaultSourceForRequest() {
@@ -735,9 +756,9 @@ void GaiaCookieManagerService::StartFetchingUbertoken() {
void GaiaCookieManagerService::StartFetchingMergeSession() {
DCHECK(!uber_token_.empty());
- gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
+ gaia_auth_fetcher_ = signin_client_->CreateGaiaAuthFetcher(
this, GetSourceForRequest(requests_.front()),
- signin_client_->GetURLRequestContext()));
+ signin_client_->GetURLRequestContext());
gaia_auth_fetcher_->StartMergeSession(uber_token_,
external_cc_result_fetcher_.GetExternalCcResult());
@@ -746,17 +767,18 @@ void GaiaCookieManagerService::StartFetchingMergeSession() {
void GaiaCookieManagerService::StartFetchingLogOut() {
DCHECK(requests_.front().request_type() == GaiaCookieRequestType::LOG_OUT);
VLOG(1) << "GaiaCookieManagerService::StartFetchingLogOut";
- gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
+ gaia_auth_fetcher_ = signin_client_->CreateGaiaAuthFetcher(
this, GetSourceForRequest(requests_.front()),
- signin_client_->GetURLRequestContext()));
+ signin_client_->GetURLRequestContext());
gaia_auth_fetcher_->StartLogOut();
}
void GaiaCookieManagerService::StartFetchingListAccounts() {
VLOG(1) << "GaiaCookieManagerService::ListAccounts";
- gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
+
+ gaia_auth_fetcher_ = signin_client_->CreateGaiaAuthFetcher(
this, GetSourceForRequest(requests_.front()),
- signin_client_->GetURLRequestContext()));
+ signin_client_->GetURLRequestContext());
gaia_auth_fetcher_->StartListAccounts();
}
diff --git a/chromium/components/signin/core/browser/gaia_cookie_manager_service.h b/chromium/components/signin/core/browser/gaia_cookie_manager_service.h
index ae4246422c1..30d0562f6b0 100644
--- a/chromium/components/signin/core/browser/gaia_cookie_manager_service.h
+++ b/chromium/components/signin/core/browser/gaia_cookie_manager_service.h
@@ -163,8 +163,6 @@ class GaiaCookieManagerService : public KeyedService,
ResultMap results_;
base::Time m_external_cc_result_start_time_;
- base::OneShotTimer gaia_auth_fetcher_timer_;
-
DISALLOW_COPY_AND_ASSIGN(ExternalCcResultFetcher);
};
@@ -327,6 +325,14 @@ class GaiaCookieManagerService : public KeyedService,
bool list_accounts_stale_;
+ // The time when the profile was loaded and used to compute the time passed
+ // between the moment the profile was loaded and the moment a new list
+ // account request is started.
+ base::Time profile_load_time_;
+
+ // Counter for list account requests.
+ int list_accounts_request_counter_;
+
DISALLOW_COPY_AND_ASSIGN(GaiaCookieManagerService);
};
diff --git a/chromium/components/signin/core/browser/signin_client.cc b/chromium/components/signin/core/browser/signin_client.cc
index 9473e0bb59c..6ca524206ed 100644
--- a/chromium/components/signin/core/browser/signin_client.cc
+++ b/chromium/components/signin/core/browser/signin_client.cc
@@ -32,7 +32,9 @@ std::string SigninClient::GetOrCreateScopedDeviceIdPref(PrefService* prefs) {
return signin_scoped_device_id;
}
-void SigninClient::PreSignOut(const base::Callback<void()>& sign_out) {
+void SigninClient::PreSignOut(
+ const base::Callback<void()>& sign_out,
+ signin_metrics::ProfileSignout signout_source_metric) {
sign_out.Run();
}
diff --git a/chromium/components/signin/core/browser/signin_client.h b/chromium/components/signin/core/browser/signin_client.h
index a4910c154df..b39959330d0 100644
--- a/chromium/components/signin/core/browser/signin_client.h
+++ b/chromium/components/signin/core/browser/signin_client.h
@@ -5,11 +5,14 @@
#ifndef COMPONENTS_SIGNIN_CORE_BROWSER_SIGNIN_CLIENT_H_
#define COMPONENTS_SIGNIN_CORE_BROWSER_SIGNIN_CLIENT_H_
+#include <memory>
+
#include "base/callback.h"
#include "base/callback_list.h"
#include "base/time/time.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/signin/core/browser/account_info.h"
+#include "components/signin/core/browser/signin_metrics.h"
#include "components/signin/core/browser/webdata/token_web_data.h"
#include "google_apis/gaia/gaia_auth_fetcher.h"
#include "net/cookies/cookie_store.h"
@@ -98,7 +101,8 @@ class SigninClient : public KeyedService {
// Called before Google signout started, call |sign_out| to start the sign out
// process.
- virtual void PreSignOut(const base::Callback<void()>& sign_out);
+ virtual void PreSignOut(const base::Callback<void()>& sign_out,
+ signin_metrics::ProfileSignout signout_source_metric);
virtual bool IsFirstRun() const = 0;
virtual base::Time GetInstallDate() = 0;
@@ -116,9 +120,8 @@ class SigninClient : public KeyedService {
// Execute |callback| if and when there is a network connection.
virtual void DelayNetworkCall(const base::Closure& callback) = 0;
- // Creates and returns a new platform-specific GaiaAuthFetcher. It is the
- // responsability of the caller to delete the returned object.
- virtual GaiaAuthFetcher* CreateGaiaAuthFetcher(
+ // Creates a new platform-specific GaiaAuthFetcher.
+ virtual std::unique_ptr<GaiaAuthFetcher> CreateGaiaAuthFetcher(
GaiaAuthConsumer* consumer,
const std::string& source,
net::URLRequestContextGetter* getter) = 0;
diff --git a/chromium/components/signin/core/browser/signin_error_controller.cc b/chromium/components/signin/core/browser/signin_error_controller.cc
index 6dbaf23b151..4b56f34761d 100644
--- a/chromium/components/signin/core/browser/signin_error_controller.cc
+++ b/chromium/components/signin/core/browser/signin_error_controller.cc
@@ -59,7 +59,7 @@ void SigninErrorController::AuthStatusChanged() {
// Ignore the states we don't want to elevate to the user.
if (error.state() == GoogleServiceAuthError::NONE ||
- error.state() == GoogleServiceAuthError::CONNECTION_FAILED) {
+ error.IsTransientError()) {
continue;
}
diff --git a/chromium/components/signin/core/browser/signin_error_controller_unittest.cc b/chromium/components/signin/core/browser/signin_error_controller_unittest.cc
index 7a3b3e85008..f8822d39a88 100644
--- a/chromium/components/signin/core/browser/signin_error_controller_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_error_controller_unittest.cc
@@ -150,9 +150,9 @@ TEST_F(SigninErrorControllerTest, AuthStatusEnumerateAllErrors) {
{ GoogleServiceAuthError::CAPTCHA_REQUIRED, true },
{ GoogleServiceAuthError::ACCOUNT_DELETED, true },
{ GoogleServiceAuthError::ACCOUNT_DISABLED, true },
- { GoogleServiceAuthError::SERVICE_UNAVAILABLE, true },
+ { GoogleServiceAuthError::SERVICE_UNAVAILABLE, false },
{ GoogleServiceAuthError::TWO_FACTOR, true },
- { GoogleServiceAuthError::REQUEST_CANCELED, true },
+ { GoogleServiceAuthError::REQUEST_CANCELED, false },
{ GoogleServiceAuthError::HOSTED_NOT_ALLOWED_DEPRECATED, false },
{ GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE, true },
{ GoogleServiceAuthError::SERVICE_ERROR, true },
@@ -200,7 +200,7 @@ TEST_F(SigninErrorControllerTest, AuthStatusChange) {
// the set. But if another error crops up...
//
// | provider0 | provider1 | ...
- // | SERVICE_UNAVAILABLE | INVALID_GAIA_CREDENTIALS | ...
+ // | SERVICE_ERROR | INVALID_GAIA_CREDENTIALS | ...
//
// we want the controller to still use the original error.
@@ -229,9 +229,8 @@ TEST_F(SigninErrorControllerTest, AuthStatusChange) {
// Change the 1st provider's error.
provider1->SetAuthError(
kOtherTestAccountId,
- GoogleServiceAuthError(
- GoogleServiceAuthError::SERVICE_UNAVAILABLE));
- ASSERT_EQ(GoogleServiceAuthError::SERVICE_UNAVAILABLE,
+ GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_ERROR));
+ ASSERT_EQ(GoogleServiceAuthError::SERVICE_ERROR,
error_controller_->auth_error().state());
ASSERT_STREQ(kOtherTestAccountId,
error_controller_->error_account_id().c_str());
@@ -241,7 +240,7 @@ TEST_F(SigninErrorControllerTest, AuthStatusChange) {
kTestAccountId,
GoogleServiceAuthError(
GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE));
- ASSERT_EQ(GoogleServiceAuthError::SERVICE_UNAVAILABLE,
+ ASSERT_EQ(GoogleServiceAuthError::SERVICE_ERROR,
error_controller_->auth_error().state());
ASSERT_STREQ(kOtherTestAccountId,
error_controller_->error_account_id().c_str());
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 239b0a57e96..1c67727627d 100644
--- a/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
@@ -10,6 +10,7 @@
#include "components/signin/core/browser/signin_header_helper.h"
#include "components/signin/core/common/signin_switches.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -42,7 +43,8 @@ class SigninHeaderHelperTest : public testing::Test {
const std::string& expected_request) {
bool expected_result = !expected_request.empty();
std::unique_ptr<net::URLRequest> url_request =
- url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr);
+ url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr,
+ TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(signin::AppendOrRemoveMirrorRequestHeaderIfPossible(
url_request.get(), GURL(), account_id, cookie_settings_.get(),
signin::PROFILE_MODE_DEFAULT),
@@ -117,11 +119,13 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleCom) {
// Tests that the Mirror request is returned with the GAIA Id on Drive origin,
// even if account consistency is disabled.
+//
+// Account consistency if always enabled on Android and iOS, so this test is
+// only relevant on Desktop.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
TEST_F(SigninHeaderHelperTest, TestMirrorRequestDrive) {
DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableAccountConsistency));
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kDisableAccountConsistency);
CheckMirrorHeaderRequest(
GURL("https://docs.google.com/document"), "0123456789",
"id=0123456789,mode=0,enable_account_consistency=false");
@@ -139,6 +143,7 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestDrive) {
GURL("https://drive.google.com/drive"), "0123456789",
"id=0123456789:mode=0:enable_account_consistency=true");
}
+#endif
// Tests that the Mirror header request is returned normally when the redirect
// URL is eligible.
@@ -150,7 +155,8 @@ TEST_F(SigninHeaderHelperTest, TestMirrorHeaderEligibleRedirectURL) {
const GURL redirect_url("https://www.google.com");
const std::string account_id = "0123456789";
std::unique_ptr<net::URLRequest> url_request =
- url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr);
+ url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr,
+ TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_TRUE(signin::AppendOrRemoveMirrorRequestHeaderIfPossible(
url_request.get(), redirect_url, account_id, cookie_settings_.get(),
signin::PROFILE_MODE_DEFAULT));
@@ -168,7 +174,8 @@ TEST_F(SigninHeaderHelperTest, TestMirrorHeaderNonEligibleRedirectURL) {
const GURL redirect_url("http://www.foo.com");
const std::string account_id = "0123456789";
std::unique_ptr<net::URLRequest> url_request =
- url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr);
+ url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr,
+ TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_FALSE(signin::AppendOrRemoveMirrorRequestHeaderIfPossible(
url_request.get(), redirect_url, account_id, cookie_settings_.get(),
signin::PROFILE_MODE_DEFAULT));
@@ -187,7 +194,8 @@ TEST_F(SigninHeaderHelperTest, TestIgnoreMirrorHeaderNonEligibleURLs) {
const std::string account_id = "0123456789";
const std::string fake_header = "foo,bar";
std::unique_ptr<net::URLRequest> url_request =
- url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr);
+ url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr,
+ TRAFFIC_ANNOTATION_FOR_TESTS);
url_request->SetExtraRequestHeaderByName(signin::kChromeConnectedHeader,
fake_header, false);
EXPECT_FALSE(signin::AppendOrRemoveMirrorRequestHeaderIfPossible(
diff --git a/chromium/components/signin/core/browser/signin_manager.cc b/chromium/components/signin/core/browser/signin_manager.cc
index 27fce040ba6..d27931d6a30 100644
--- a/chromium/components/signin/core/browser/signin_manager.cc
+++ b/chromium/components/signin/core/browser/signin_manager.cc
@@ -149,9 +149,10 @@ void SigninManager::HandleAuthError(const GoogleServiceAuthError& error) {
void SigninManager::SignOut(
signin_metrics::ProfileSignout signout_source_metric,
signin_metrics::SignoutDelete signout_delete_metric) {
- client_->PreSignOut(base::Bind(&SigninManager::DoSignOut,
- base::Unretained(this), signout_source_metric,
- signout_delete_metric));
+ client_->PreSignOut(
+ base::Bind(&SigninManager::DoSignOut, base::Unretained(this),
+ signout_source_metric, signout_delete_metric),
+ signout_source_metric);
}
void SigninManager::DoSignOut(
diff --git a/chromium/components/signin/core/browser/signin_manager_base.cc b/chromium/components/signin/core/browser/signin_manager_base.cc
index b36d21d0f56..df125732094 100644
--- a/chromium/components/signin/core/browser/signin_manager_base.cc
+++ b/chromium/components/signin/core/browser/signin_manager_base.cc
@@ -8,6 +8,7 @@
#include <vector>
#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -58,7 +59,7 @@ void SigninManagerBase::RegisterProfilePrefs(
registry->RegisterBooleanPref(prefs::kAutologinEnabled, true);
registry->RegisterBooleanPref(prefs::kReverseAutologinEnabled, true);
registry->RegisterListPref(prefs::kReverseAutologinRejectedEmailList,
- new base::ListValue);
+ base::MakeUnique<base::ListValue>());
registry->RegisterBooleanPref(prefs::kSigninAllowed, true);
registry->RegisterInt64Pref(prefs::kSignedInTime,
base::Time().ToInternalValue());
diff --git a/chromium/components/signin/core/browser/signin_metrics.cc b/chromium/components/signin/core/browser/signin_metrics.cc
index 279371a6024..8010b84ac51 100644
--- a/chromium/components/signin/core/browser/signin_metrics.cc
+++ b/chromium/components/signin/core/browser/signin_metrics.cc
@@ -8,7 +8,6 @@
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics.h"
#include "base/time/time.h"
namespace signin_metrics {
diff --git a/chromium/components/signin/core/browser/signin_metrics.h b/chromium/components/signin/core/browser/signin_metrics.h
index 0ba0eb04b0d..061a4145ba4 100644
--- a/chromium/components/signin/core/browser/signin_metrics.h
+++ b/chromium/components/signin/core/browser/signin_metrics.h
@@ -46,7 +46,8 @@ enum ProfileSignout {
// The credentials are being transfered to a new profile, so the old one is
// signed out.
TRANSFER_CREDENTIALS,
-
+ // Signed out because credentials are invalid and force-sign-in is enabled.
+ AUTHENTICATION_FAILED_WITH_FORCE_SIGNIN,
// Keep this as the last enum.
NUM_PROFILE_SIGNOUT_METRICS,
};
diff --git a/chromium/components/signin/core/browser/test_signin_client.cc b/chromium/components/signin/core/browser/test_signin_client.cc
index ad301a6e487..2aba3b9c649 100644
--- a/chromium/components/signin/core/browser/test_signin_client.cc
+++ b/chromium/components/signin/core/browser/test_signin_client.cc
@@ -103,9 +103,9 @@ void TestSigninClient::DelayNetworkCall(const base::Closure& callback) {
callback.Run();
}
-GaiaAuthFetcher* TestSigninClient::CreateGaiaAuthFetcher(
+std::unique_ptr<GaiaAuthFetcher> TestSigninClient::CreateGaiaAuthFetcher(
GaiaAuthConsumer* consumer,
const std::string& source,
net::URLRequestContextGetter* getter) {
- return new GaiaAuthFetcher(consumer, source, getter);
+ return base::MakeUnique<GaiaAuthFetcher>(consumer, source, getter);
}
diff --git a/chromium/components/signin/core/browser/test_signin_client.h b/chromium/components/signin/core/browser/test_signin_client.h
index a97233bc301..e0506367a90 100644
--- a/chromium/components/signin/core/browser/test_signin_client.h
+++ b/chromium/components/signin/core/browser/test_signin_client.h
@@ -87,7 +87,7 @@ class TestSigninClient : public SigninClient {
void RemoveContentSettingsObserver(
content_settings::Observer* observer) override;
void DelayNetworkCall(const base::Closure& callback) override;
- GaiaAuthFetcher* CreateGaiaAuthFetcher(
+ std::unique_ptr<GaiaAuthFetcher> CreateGaiaAuthFetcher(
GaiaAuthConsumer* consumer,
const std::string& source,
net::URLRequestContextGetter* getter) override;
diff --git a/chromium/components/signin/core/common/profile_management_switches.cc b/chromium/components/signin/core/common/profile_management_switches.cc
index bf1cd842176..733ea083103 100644
--- a/chromium/components/signin/core/common/profile_management_switches.cc
+++ b/chromium/components/signin/core/common/profile_management_switches.cc
@@ -12,123 +12,28 @@
#include "build/build_config.h"
#include "components/signin/core/common/signin_switches.h"
-namespace {
-
-const char kNewProfileManagementFieldTrialName[] = "NewProfileManagement";
-
-// Different state of new profile management/identity consistency. The code
-// below assumes the order of the values in this enum. That is, new profile
-// management is included in consistent identity.
-enum State {
- STATE_NEW_AVATAR_MENU,
- STATE_NEW_PROFILE_MANAGEMENT,
- STATE_ACCOUNT_CONSISTENCY,
-};
-
-State GetProcessState() {
- // Find the state of both command line args.
- bool is_new_profile_management =
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableNewProfileManagement);
- bool is_consistent_identity =
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableAccountConsistency);
- bool not_new_profile_management =
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableNewProfileManagement);
- bool not_consistent_identity =
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableAccountConsistency);
- int count_args = (is_new_profile_management ? 1 : 0) +
- (is_consistent_identity ? 1 : 0) +
- (not_new_profile_management ? 1 : 0) +
- (not_consistent_identity ? 1 : 0);
- bool invalid_commandline = count_args > 1;
-
- // At most only one of the command line args should be specified, otherwise
- // the finch group assignment is undefined. If this is the case, disable
- // the field trial so that data is not collected in the wrong group.
- std::string trial_type;
- if (invalid_commandline) {
- base::FieldTrial* field_trial =
- base::FieldTrialList::Find(kNewProfileManagementFieldTrialName);
- if (field_trial)
- field_trial->Disable();
-
- trial_type.clear();
- } else {
- // Since the experiment is not being disabled, get the full name of the
- // field trial which will initialize the underlying mechanism.
- trial_type =
- base::FieldTrialList::FindFullName(kNewProfileManagementFieldTrialName);
- }
-
- // Enable command line args take precedent over disable command line args.
- // Consistent identity args take precedent over new profile management args.
- if (is_consistent_identity) {
- return STATE_ACCOUNT_CONSISTENCY;
- } else if (is_new_profile_management) {
- return STATE_NEW_PROFILE_MANAGEMENT;
- } else if (not_new_profile_management) {
- return STATE_NEW_AVATAR_MENU;
- } else if (not_consistent_identity) {
- return STATE_NEW_PROFILE_MANAGEMENT;
- }
+namespace switches {
- // Set the default state
+bool IsEnableAccountConsistency() {
#if defined(OS_ANDROID) || defined(OS_IOS)
- State state = STATE_ACCOUNT_CONSISTENCY;
-#else
- State state = STATE_NEW_PROFILE_MANAGEMENT;
+ // Account consistency is enabled on Android and iOS.
+ return true;
#endif
- if (!trial_type.empty()) {
- if (trial_type == "Enabled") {
- state = STATE_NEW_PROFILE_MANAGEMENT;
- } else if (trial_type == "AccountConsistency") {
- state = STATE_ACCOUNT_CONSISTENCY;
- } else if (trial_type == "NewAvatarMenu") {
- state = STATE_NEW_AVATAR_MENU;
- } else {
- state = STATE_NEW_PROFILE_MANAGEMENT;
- }
- }
-
- return state;
-}
-
-bool CheckFlag(const std::string& command_switch, State min_state) {
- // Individiual flag settings take precedence.
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(command_switch))
- return true;
-
- return GetProcessState() >= min_state;
-}
-
-} // namespace
-
-namespace switches {
-
-bool IsEnableAccountConsistency() {
- return GetProcessState() >= STATE_ACCOUNT_CONSISTENCY;
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableAccountConsistency);
}
bool IsExtensionsMultiAccount() {
- return CheckFlag(switches::kExtensionsMultiAccount,
- STATE_ACCOUNT_CONSISTENCY);
-}
-
-bool IsGoogleProfileInfo() {
- return CheckFlag(switches::kGoogleProfileInfo, STATE_NEW_AVATAR_MENU);
-}
-
-bool IsNewProfileManagement() {
- return GetProcessState() >= STATE_NEW_PROFILE_MANAGEMENT;
-}
-
-bool IsNewProfileManagementPreviewEnabled() {
- // No promotion to Enable Account Consistency.
+#if defined(OS_ANDROID) || defined(OS_IOS)
+ NOTREACHED() << "Extensions are not enabled on Android or iOS";
+ // Account consistency is enabled on Android and iOS.
return false;
+#endif
+
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kExtensionsMultiAccount) ||
+ IsEnableAccountConsistency();
}
bool UsePasswordSeparatedSigninFlow() {
@@ -136,18 +41,8 @@ bool UsePasswordSeparatedSigninFlow() {
switches::kUsePasswordSeparatedSigninFlow);
}
-bool IsMaterialDesignUserMenu() {
- return base::FeatureList::IsEnabled(switches::kMaterialDesignUserMenu);
-}
-
-void EnableNewProfileManagementForTesting(base::CommandLine* command_line) {
- command_line->AppendSwitch(switches::kEnableNewProfileManagement);
- DCHECK(!command_line->HasSwitch(switches::kDisableNewProfileManagement));
-}
-
void EnableAccountConsistencyForTesting(base::CommandLine* command_line) {
command_line->AppendSwitch(switches::kEnableAccountConsistency);
- DCHECK(!command_line->HasSwitch(switches::kDisableAccountConsistency));
}
} // namespace switches
diff --git a/chromium/components/signin/core/common/profile_management_switches.h b/chromium/components/signin/core/common/profile_management_switches.h
index 26cb06471d5..7ed543d0967 100644
--- a/chromium/components/signin/core/common/profile_management_switches.h
+++ b/chromium/components/signin/core/common/profile_management_switches.h
@@ -22,24 +22,10 @@ bool IsEnableAccountConsistency();
// Whether the chrome.identity API should be multi-account.
bool IsExtensionsMultiAccount();
-// Enables using GAIA information to populate profile name and icon.
-bool IsGoogleProfileInfo();
-
-// Use new profile management system, including profile sign-out and new
-// choosers.
-bool IsNewProfileManagement();
-
-// Whether the new profile management preview has been enabled.
-bool IsNewProfileManagementPreviewEnabled();
-
// Checks whether the new gaia password separated sign in flow is enabled.
bool UsePasswordSeparatedSigninFlow();
-// Whether the material design user menu should be displayed.
-bool IsMaterialDesignUserMenu();
-
-// Called in tests to force enabling different modes.
-void EnableNewProfileManagementForTesting(base::CommandLine* command_line);
+// Called in tests to force enable account consistency.
void EnableAccountConsistencyForTesting(base::CommandLine* command_line);
} // namespace switches
diff --git a/chromium/components/signin/core/common/signin_switches.cc b/chromium/components/signin/core/common/signin_switches.cc
index bf1d0ee8914..f31bc2c7010 100644
--- a/chromium/components/signin/core/common/signin_switches.cc
+++ b/chromium/components/signin/core/common/signin_switches.cc
@@ -10,11 +10,8 @@ namespace switches {
// expiration of credentials during testing.
const char kClearTokenService[] = "clear-token-service";
-// Disables consistent identity features.
-const char kDisableAccountConsistency[] = "disable-account-consistency";
-
-// Disables new profile management system, including new profile chooser UI.
-const char kDisableNewProfileManagement[] = "disable-new-profile-management";
+// Disables sign-in promo.
+const char kDisableSigninPromo[] = "disable-signin-promo";
// Disables sending signin scoped device id to LSO with refresh token request.
const char kDisableSigninScopedDeviceId[] = "disable-signin-scoped-device-id";
@@ -22,24 +19,16 @@ const char kDisableSigninScopedDeviceId[] = "disable-signin-scoped-device-id";
// Enables consistent identity features.
const char kEnableAccountConsistency[] = "enable-account-consistency";
-// Enables new profile management system, including lock mode.
-const char kEnableNewProfileManagement[] = "new-profile-management";
-
// Enables sending EnableRefreshTokenAnnotationRequest.
extern const char kEnableRefreshTokenAnnotationRequest[] =
"enable-refresh-token-annotation-request";
+// Enables sign-in promo.
+const char kEnableSigninPromo[] = "enable-signin-promo";
+
// Enables multiple account versions of chrome.identity APIs.
const char kExtensionsMultiAccount[] = "extensions-multi-account";
-// Enables using GAIA information to populate profile name and icon.
-const char kGoogleProfileInfo[] = "google-profile-info";
-
-// Enables or disables the material design desktop user menu.
-const base::Feature kMaterialDesignUserMenu {
- "MaterialDesignUserMenu", base::FEATURE_ENABLED_BY_DEFAULT
-};
-
// Enables or disables the new password separated sign in flow in a tab modal
// dialog.
const base::Feature kUsePasswordSeparatedSigninFlow {
diff --git a/chromium/components/signin/core/common/signin_switches.h b/chromium/components/signin/core/common/signin_switches.h
index f7d1bb29be5..c2dd7384193 100644
--- a/chromium/components/signin/core/common/signin_switches.h
+++ b/chromium/components/signin/core/common/signin_switches.h
@@ -16,16 +16,13 @@ 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 kDisableAccountConsistency[];
-extern const char kDisableNewProfileManagement[];
+extern const char kDisableSigninPromo[];
extern const char kDisableSigninScopedDeviceId[];
extern const char kEnableAccountConsistency[];
-extern const char kEnableNewProfileManagement[];
extern const char kEnableRefreshTokenAnnotationRequest[];
+extern const char kEnableSigninPromo[];
extern const char kExtensionsMultiAccount[];
-extern const char kGoogleProfileInfo[];
-extern const base::Feature kMaterialDesignUserMenu;
extern const base::Feature kUsePasswordSeparatedSigninFlow;
} // namespace switches
diff --git a/chromium/components/signin/ios/OWNERS b/chromium/components/signin/ios/OWNERS
index f5e9e657262..d45210b7871 100644
--- a/chromium/components/signin/ios/OWNERS
+++ b/chromium/components/signin/ios/OWNERS
@@ -1,2 +1,4 @@
bzanotti@chromium.org
msarda@chromium.org
+
+# COMPONENT: Services>SignIn
diff --git a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
index 163fb03295b..d70d591f1cc 100644
--- a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
+++ b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
@@ -288,13 +288,12 @@ TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
base::RunLoop().RunUntilIdle();
ResetObserverCounts();
- GoogleServiceAuthError cancelled_error(
- GoogleServiceAuthError::REQUEST_CANCELED);
- oauth2_delegate_->UpdateAuthError(GetAccountId(account1), cancelled_error);
+ GoogleServiceAuthError error(GoogleServiceAuthError::SERVICE_ERROR);
+ oauth2_delegate_->UpdateAuthError(GetAccountId(account1), error);
EXPECT_EQ(1, error_changed_count_);
oauth2_delegate_->RevokeAllCredentials();
ResetObserverCounts();
- oauth2_delegate_->UpdateAuthError(GetAccountId(account1), cancelled_error);
+ oauth2_delegate_->UpdateAuthError(GetAccountId(account1), error);
EXPECT_EQ(0, error_changed_count_);
}
diff --git a/chromium/components/signin/public/interfaces/account_id_traits.h b/chromium/components/signin/public/interfaces/account_id_traits.h
index cc1d39de917..a2107cbb30b 100644
--- a/chromium/components/signin/public/interfaces/account_id_traits.h
+++ b/chromium/components/signin/public/interfaces/account_id_traits.h
@@ -100,6 +100,10 @@ struct StructTraits<signin::mojom::AccountIdDataView, AccountId> {
return out->is_valid();
}
+
+ static bool IsNull(const AccountId& input) { return !input.is_valid(); }
+
+ static void SetToNull(AccountId* output) { *output = EmptyAccountId(); }
};
} // namespace mojo
diff --git a/chromium/components/spellcheck/browser/spelling_service_client.cc b/chromium/components/spellcheck/browser/spelling_service_client.cc
index d9791b3cfde..86eda34d958 100644
--- a/chromium/components/spellcheck/browser/spelling_service_client.cc
+++ b/chromium/components/spellcheck/browser/spelling_service_client.cc
@@ -107,16 +107,16 @@ bool SpellingServiceClient::RequestTextCheck(
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("spellcheck_lookup", R"(
semantics {
- sender: "spellcheck"
+ sender: "Online Spellcheck"
description:
- "Google Chrome can provide smarter spell-checking by sending "
- "text you type into the browser to Google's servers, allowing "
- "you to use the same spell-checking technology used by Google "
- "products, such as Docs. If the feature is enabled, Chrome will "
- "send the entire contents of text fields as you type in them to "
- "Google along with the browser’s default language. Google "
- "returns a list of suggested spellings, which will be displayed "
- "in the context menu."
+ "Chromium can provide smarter spell-checking, by sending the text "
+ "that the users type into the browser, to Google's servers. This"
+ "allows users to use the same spell-checking technology used by "
+ "Google products, such as Docs. If the feature is enabled, "
+ "Chromium will send the entire contents of text fields as user "
+ "types them to Google, along with the browser’s default language. "
+ "Google returns a list of suggested spellings, which will be "
+ "displayed in the context menu."
trigger: "User types text into a text field or asks to correct a "
"misspelled word."
data: "Text a user has typed into a text field. No user identifier "
@@ -126,13 +126,13 @@ bool SpellingServiceClient::RequestTextCheck(
policy {
cookies_allowed: false
setting:
- "You can enable or disable this feature via 'Use a web service to "
- "help resolve spelling errors.' in Chrome's settings under "
+ "Users can enable or disable this feature via 'Use a web service "
+ "to help resolve spelling errors.' in Chromium's settings under "
"Advanced. The feature is disabled by default."
- policy {
+ chrome_policy {
SpellCheckServiceEnabled {
policy_options {mode: MANDATORY}
- value: false
+ SpellCheckServiceEnabled: false
}
}
})");
diff --git a/chromium/components/spellcheck/renderer/BUILD.gn b/chromium/components/spellcheck/renderer/BUILD.gn
index 40fd2e1038c..1c3e482f24d 100644
--- a/chromium/components/spellcheck/renderer/BUILD.gn
+++ b/chromium/components/spellcheck/renderer/BUILD.gn
@@ -16,6 +16,8 @@ source_set("renderer") {
"spellcheck.h",
"spellcheck_language.cc",
"spellcheck_language.h",
+ "spellcheck_panel.cc",
+ "spellcheck_panel.h",
"spellcheck_provider.cc",
"spellcheck_provider.h",
"spellcheck_worditerator.cc",
diff --git a/chromium/components/spellcheck/renderer/spellcheck.cc b/chromium/components/spellcheck/renderer/spellcheck.cc
index db53a8c51b0..cd1a39774bd 100644
--- a/chromium/components/spellcheck/renderer/spellcheck.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck.cc
@@ -26,6 +26,8 @@
#include "components/spellcheck/renderer/spellcheck_language.h"
#include "components/spellcheck/renderer/spellcheck_provider.h"
#include "components/spellcheck/spellcheck_build_features.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_frame_visitor.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
#include "content/public/renderer/render_view_visitor.h"
@@ -46,18 +48,18 @@ namespace {
const int kNoOffset = 0;
const int kNoTag = 0;
-class UpdateSpellcheckEnabled : public content::RenderViewVisitor {
+class UpdateSpellcheckEnabled : public content::RenderFrameVisitor {
public:
explicit UpdateSpellcheckEnabled(bool enabled) : enabled_(enabled) {}
- bool Visit(content::RenderView* render_view) override;
+ bool Visit(content::RenderFrame* render_frame) override;
private:
bool enabled_; // New spellcheck-enabled state.
DISALLOW_COPY_AND_ASSIGN(UpdateSpellcheckEnabled);
};
-bool UpdateSpellcheckEnabled::Visit(content::RenderView* render_view) {
- SpellCheckProvider* provider = SpellCheckProvider::Get(render_view);
+bool UpdateSpellcheckEnabled::Visit(content::RenderFrame* render_frame) {
+ SpellCheckProvider* provider = SpellCheckProvider::Get(render_frame);
DCHECK(provider);
provider->EnableSpellcheck(enabled_);
return true;
@@ -78,12 +80,12 @@ DocumentMarkersRemover::DocumentMarkersRemover(
const std::set<std::string>& words)
: words_(words.size()) {
std::transform(words.begin(), words.end(), words_.begin(),
- [](const std::string& w) { return WebString::fromUTF8(w); });
+ [](const std::string& w) { return WebString::FromUTF8(w); });
}
bool DocumentMarkersRemover::Visit(content::RenderView* render_view) {
if (render_view && render_view->GetWebView())
- render_view->GetWebView()->removeSpellingMarkersUnderWords(words_);
+ render_view->GetWebView()->RemoveSpellingMarkersUnderWords(words_);
return true;
}
@@ -224,7 +226,7 @@ void SpellCheck::OnCustomDictionaryChanged(
void SpellCheck::OnEnableSpellCheck(bool enable) {
spellcheck_enabled_ = enable;
UpdateSpellcheckEnabled updater(enable);
- content::RenderView::ForEach(&updater);
+ content::RenderFrame::ForEach(&updater);
}
// TODO(groby): Make sure we always have a spelling engine, even before
@@ -359,19 +361,19 @@ bool SpellCheck::SpellCheckParagraph(
&misspelling_start,
&misspelling_length,
NULL)) {
- results->assign(textcheck_results);
+ results->Assign(textcheck_results);
return true;
}
if (!custom_dictionary_.SpellCheckWord(
text, misspelling_start, misspelling_length)) {
textcheck_results.push_back(
- WebTextCheckingResult(blink::WebTextDecorationTypeSpelling,
+ WebTextCheckingResult(blink::kWebTextDecorationTypeSpelling,
misspelling_start, misspelling_length));
}
position_in_text = misspelling_start + misspelling_length;
}
- results->assign(textcheck_results);
+ results->Assign(textcheck_results);
return false;
#else
// This function is only invoked for spell checker functionality that runs
@@ -388,7 +390,7 @@ void SpellCheck::RequestTextChecking(
blink::WebTextCheckingCompletion* completion) {
// Clean up the previous request before starting a new request.
if (pending_request_param_.get())
- pending_request_param_->completion()->didCancelCheckingText();
+ pending_request_param_->completion()->DidCancelCheckingText();
pending_request_param_.reset(new SpellcheckRequest(
text, completion));
@@ -433,11 +435,11 @@ void SpellCheck::PerformSpellCheck(SpellcheckRequest* param) {
[](std::unique_ptr<SpellcheckLanguage>& language) {
return !language->IsEnabled();
}) != languages_.end()) {
- param->completion()->didCancelCheckingText();
+ param->completion()->DidCancelCheckingText();
} else {
WebVector<blink::WebTextCheckingResult> results;
SpellCheckParagraph(param->text(), &results);
- param->completion()->didFinishCheckingText(results);
+ param->completion()->DidFinishCheckingText(results);
}
}
#endif
@@ -494,10 +496,10 @@ void SpellCheck::CreateTextCheckingResults(
results.push_back(WebTextCheckingResult(
static_cast<WebTextDecorationType>(decoration),
line_offset + spellcheck_result.location, spellcheck_result.length,
- blink::WebString::fromUTF16(replacement)));
+ blink::WebString::FromUTF16(replacement)));
}
- textcheck_results->assign(results);
+ textcheck_results->Assign(results);
}
bool SpellCheck::IsSpellcheckEnabled() {
diff --git a/chromium/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc
index 7ebe4bae8ee..f7c45d31209 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/path_service.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -80,8 +81,8 @@ class MultilingualSpellCheckTest : public testing::Test {
for (size_t i = 0; i < num_test_cases; ++i) {
int misspelling_start = 0;
int misspelling_length = 0;
- static_cast<blink::WebSpellCheckClient*>(provider())
- ->checkSpelling(blink::WebString::fromUTF16(
+ static_cast<blink::WebTextCheckClient*>(provider())
+ ->CheckSpelling(blink::WebString::FromUTF16(
base::WideToUTF16(test_cases[i].input)),
misspelling_start, misspelling_length, nullptr);
@@ -103,7 +104,7 @@ class MultilingualSpellCheckTest : public testing::Test {
EXPECT_EQ(expected.size(), results.size());
size_t size = std::min(results.size(), expected.size());
for (size_t i = 0; i < size; ++i) {
- EXPECT_EQ(blink::WebTextDecorationTypeSpelling, results[i].decoration);
+ EXPECT_EQ(blink::kWebTextDecorationTypeSpelling, results[i].decoration);
EXPECT_EQ(expected[i].location, results[i].location);
EXPECT_EQ(expected[i].length, results[i].length);
}
@@ -137,12 +138,13 @@ TEST_F(MultilingualSpellCheckTest, MultilingualSpellCheckWord) {
// A sorted list of languages. This must start sorted to get all possible
// permutations.
std::string languages = "el-GR,en-US,es-ES,ru-RU";
- std::vector<std::string> permuted_languages = base::SplitString(
+ std::vector<base::StringPiece> permuted_languages = base::SplitStringPiece(
languages, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
do {
- languages = base::JoinString(permuted_languages, ",");
- ExpectSpellCheckWordResults(languages, kTestCases, arraysize(kTestCases));
+ std::string reordered_languages = base::JoinString(permuted_languages, ",");
+ ExpectSpellCheckWordResults(reordered_languages, kTestCases,
+ arraysize(kTestCases));
} while (std::next_permutation(permuted_languages.begin(),
permuted_languages.end()));
}
@@ -233,9 +235,9 @@ TEST_F(MultilingualSpellCheckTest, MultilingualSpellCheckSuggestions) {
blink::WebVector<blink::WebString> suggestions;
int misspelling_start;
int misspelling_length;
- static_cast<blink::WebSpellCheckClient*>(provider())
- ->checkSpelling(
- blink::WebString::fromUTF16(base::WideToUTF16(kTestCases[i].input)),
+ static_cast<blink::WebTextCheckClient*>(provider())
+ ->CheckSpelling(
+ blink::WebString::FromUTF16(base::WideToUTF16(kTestCases[i].input)),
misspelling_start, misspelling_length, &suggestions);
EXPECT_EQ(kTestCases[i].expected_misspelling_start, misspelling_start);
@@ -252,7 +254,7 @@ TEST_F(MultilingualSpellCheckTest, MultilingualSpellCheckSuggestions) {
EXPECT_EQ(expected_suggestions.size(), suggestions.size());
for (size_t j = 0;
j < std::min(expected_suggestions.size(), suggestions.size()); j++) {
- EXPECT_EQ(expected_suggestions[j], suggestions[j].utf16());
+ EXPECT_EQ(expected_suggestions[j], suggestions[j].Utf16());
}
}
}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_panel.cc b/chromium/components/spellcheck/renderer/spellcheck_panel.cc
new file mode 100644
index 00000000000..0e96ef4fe15
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_panel.cc
@@ -0,0 +1,80 @@
+// 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/spellcheck/renderer/spellcheck_panel.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "components/spellcheck/common/spellcheck_messages.h"
+#include "content/public/renderer/render_view.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "third_party/WebKit/public/web/WebView.h"
+
+using blink::WebString;
+
+SpellCheckPanel::SpellCheckPanel(content::RenderView* render_view)
+ : content::RenderViewObserver(render_view),
+ content::RenderViewObserverTracker<SpellCheckPanel>(render_view),
+ spelling_panel_visible_(false) {
+ render_view->GetWebView()->SetSpellCheckClient(this);
+}
+
+SpellCheckPanel::~SpellCheckPanel() = default;
+
+void SpellCheckPanel::ShowSpellingUI(bool show) {
+#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ UMA_HISTOGRAM_BOOLEAN("SpellCheck.api.showUI", show);
+ Send(new SpellCheckHostMsg_ShowSpellingPanel(routing_id(), show));
+#endif
+}
+
+bool SpellCheckPanel::IsShowingSpellingUI() {
+ return spelling_panel_visible_;
+}
+
+void SpellCheckPanel::UpdateSpellingUIWithMisspelledWord(
+ const WebString& word) {
+#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ Send(new SpellCheckHostMsg_UpdateSpellingPanelWithMisspelledWord(
+ routing_id(), word.Utf16()));
+#endif
+}
+
+bool SpellCheckPanel::OnMessageReceived(const IPC::Message& message) {
+#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ return false;
+#endif
+#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(SpellCheckPanel, message)
+ IPC_MESSAGE_HANDLER(SpellCheckMsg_AdvanceToNextMisspelling,
+ OnAdvanceToNextMisspelling)
+ IPC_MESSAGE_HANDLER(SpellCheckMsg_ToggleSpellPanel, OnToggleSpellPanel)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+#endif
+}
+
+#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+void SpellCheckPanel::OnAdvanceToNextMisspelling() {
+ if (!render_view()->GetWebView())
+ return;
+ render_view()->GetWebView()->FocusedFrame()->ExecuteCommand(
+ WebString::FromUTF8("AdvanceToNextMisspelling"));
+}
+
+void SpellCheckPanel::OnToggleSpellPanel(bool is_currently_visible) {
+ if (!render_view()->GetWebView())
+ return;
+ // We need to tell the webView whether the spelling panel is visible or not so
+ // that it won't need to make ipc calls later.
+ spelling_panel_visible_ = is_currently_visible;
+ render_view()->GetWebView()->FocusedFrame()->ExecuteCommand(
+ WebString::FromUTF8("ToggleSpellPanel"));
+}
+#endif
+
+void SpellCheckPanel::OnDestruct() {
+ delete this;
+}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_panel.h b/chromium/components/spellcheck/renderer/spellcheck_panel.h
new file mode 100644
index 00000000000..87c42f6c82f
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_panel.h
@@ -0,0 +1,49 @@
+// 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_SPELLCHECK_RENDERER_SPELLCHECK_PANEL_H
+#define COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_PANEL_H
+
+#include "base/macros.h"
+#include "components/spellcheck/spellcheck_build_features.h"
+#include "content/public/renderer/render_view_observer.h"
+#include "content/public/renderer/render_view_observer_tracker.h"
+#include "third_party/WebKit/public/web/WebSpellCheckClient.h"
+
+// TODO(xiaochengh): Only Mac has spelling panel. Remove the #if checks in this
+// class, which seem unnecessary, and make sure that this class is compiled and
+// used only on Mac.
+class SpellCheckPanel
+ : public content::RenderViewObserver,
+ public content::RenderViewObserverTracker<SpellCheckPanel>,
+ public blink::WebSpellCheckClient {
+ public:
+ explicit SpellCheckPanel(content::RenderView* render_view);
+ ~SpellCheckPanel() override;
+
+ // RenderViewObserver implementation.
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ private:
+ // RenderViewObserver implementation.
+ void OnDestruct() override;
+
+ // blink::WebSpellCheckClient implementation.
+ void ShowSpellingUI(bool show) override;
+ bool IsShowingSpellingUI() override;
+ void UpdateSpellingUIWithMisspelledWord(
+ const blink::WebString& word) override;
+
+#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ void OnAdvanceToNextMisspelling();
+ void OnToggleSpellPanel(bool is_currently_visible);
+#endif
+
+ // True if the browser is showing the spelling panel for us.
+ bool spelling_panel_visible_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpellCheckPanel);
+};
+
+#endif
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider.cc b/chromium/components/spellcheck/renderer/spellcheck_provider.cc
index bddbfaaa543..abd2cd5422f 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider.cc
@@ -4,14 +4,13 @@
#include "components/spellcheck/renderer/spellcheck_provider.h"
-#include "base/command_line.h"
#include "base/metrics/histogram_macros.h"
#include "components/spellcheck/common/spellcheck_messages.h"
#include "components/spellcheck/common/spellcheck_result.h"
#include "components/spellcheck/renderer/spellcheck.h"
#include "components/spellcheck/renderer/spellcheck_language.h"
#include "components/spellcheck/spellcheck_build_features.h"
-#include "content/public/renderer/render_view.h"
+#include "content/public/renderer/render_frame.h"
#include "third_party/WebKit/public/platform/WebVector.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebElement.h"
@@ -19,7 +18,6 @@
#include "third_party/WebKit/public/web/WebTextCheckingCompletion.h"
#include "third_party/WebKit/public/web/WebTextCheckingResult.h"
#include "third_party/WebKit/public/web/WebTextDecorationType.h"
-#include "third_party/WebKit/public/web/WebView.h"
using blink::WebElement;
using blink::WebLocalFrame;
@@ -29,23 +27,21 @@ using blink::WebTextCheckingResult;
using blink::WebTextDecorationType;
using blink::WebVector;
-static_assert(int(blink::WebTextDecorationTypeSpelling) ==
- int(SpellCheckResult::SPELLING), "mismatching enums");
-static_assert(int(blink::WebTextDecorationTypeGrammar) ==
- int(SpellCheckResult::GRAMMAR), "mismatching enums");
-
-SpellCheckProvider::SpellCheckProvider(
- content::RenderView* render_view,
- SpellCheck* spellcheck)
- : content::RenderViewObserver(render_view),
- content::RenderViewObserverTracker<SpellCheckProvider>(render_view),
- spelling_panel_visible_(false),
+static_assert(int(blink::kWebTextDecorationTypeSpelling) ==
+ int(SpellCheckResult::SPELLING),
+ "mismatching enums");
+static_assert(int(blink::kWebTextDecorationTypeGrammar) ==
+ int(SpellCheckResult::GRAMMAR),
+ "mismatching enums");
+
+SpellCheckProvider::SpellCheckProvider(content::RenderFrame* render_frame,
+ SpellCheck* spellcheck)
+ : content::RenderFrameObserver(render_frame),
+ content::RenderFrameObserverTracker<SpellCheckProvider>(render_frame),
spellcheck_(spellcheck) {
DCHECK(spellcheck_);
- if (render_view) { // NULL in unit tests.
- render_view->GetWebView()->setSpellCheckClient(this);
- EnableSpellcheck(spellcheck_->IsSpellcheckEnabled());
- }
+ if (render_frame) // NULL in unit tests.
+ render_frame->GetWebFrame()->SetTextCheckClient(this);
}
SpellCheckProvider::~SpellCheckProvider() {
@@ -56,7 +52,7 @@ void SpellCheckProvider::RequestTextChecking(
WebTextCheckingCompletion* completion) {
// Ignore invalid requests.
if (text.empty() || !HasWordCharacters(text, 0)) {
- completion->didCancelCheckingText();
+ completion->DidCancelCheckingText();
return;
}
@@ -67,7 +63,7 @@ void SpellCheckProvider::RequestTextChecking(
// Send this text to a browser. A browser checks the user profile and send
// this text to the Spelling service only if a user enables this feature.
last_request_.clear();
- last_results_.assign(blink::WebVector<blink::WebTextCheckingResult>());
+ last_results_.Assign(blink::WebVector<blink::WebTextCheckingResult>());
#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Text check (unified request for grammar and spell check) is only
@@ -91,10 +87,7 @@ bool SpellCheckProvider::OnMessageReceived(const IPC::Message& message) {
OnRespondSpellingService)
#endif
#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
- IPC_MESSAGE_HANDLER(SpellCheckMsg_AdvanceToNextMisspelling,
- OnAdvanceToNextMisspelling)
IPC_MESSAGE_HANDLER(SpellCheckMsg_RespondTextCheck, OnRespondTextCheck)
- IPC_MESSAGE_HANDLER(SpellCheckMsg_ToggleSpellPanel, OnToggleSpellPanel)
#endif
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -103,22 +96,23 @@ bool SpellCheckProvider::OnMessageReceived(const IPC::Message& message) {
void SpellCheckProvider::FocusedNodeChanged(const blink::WebNode& unused) {
#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
- WebLocalFrame* frame = render_view()->GetWebView()->focusedFrame();
- WebElement element = frame->document().isNull() ? WebElement() :
- frame->document().focusedElement();
- bool enabled = !element.isNull() && element.isEditable();
- bool checked = enabled && frame->isSpellCheckingEnabled();
+ WebLocalFrame* frame = render_frame()->GetWebFrame();
+ WebElement element = frame->GetDocument().IsNull()
+ ? WebElement()
+ : frame->GetDocument().FocusedElement();
+ bool enabled = !element.IsNull() && element.IsEditable();
+ bool checked = enabled && frame->IsSpellCheckingEnabled();
Send(new SpellCheckHostMsg_ToggleSpellCheck(routing_id(), enabled, checked));
#endif // USE_BROWSER_SPELLCHECKER
}
-void SpellCheckProvider::checkSpelling(
+void SpellCheckProvider::CheckSpelling(
const WebString& text,
int& offset,
int& length,
WebVector<WebString>* optional_suggestions) {
- base::string16 word = text.utf16();
+ base::string16 word = text.Utf16();
std::vector<base::string16> suggestions;
const int kWordStart = 0;
spellcheck_->SpellCheckWord(
@@ -128,7 +122,7 @@ void SpellCheckProvider::checkSpelling(
WebVector<WebString> web_suggestions(suggestions.size());
std::transform(
suggestions.begin(), suggestions.end(), web_suggestions.begin(),
- [](const base::string16& s) { return WebString::fromUTF16(s); });
+ [](const base::string16& s) { return WebString::FromUTF16(s); });
*optional_suggestions = web_suggestions;
UMA_HISTOGRAM_COUNTS("SpellCheck.api.check.suggestions", word.size());
} else {
@@ -139,40 +133,21 @@ void SpellCheckProvider::checkSpelling(
}
}
-void SpellCheckProvider::requestCheckingOfText(
+void SpellCheckProvider::RequestCheckingOfText(
const WebString& text,
WebTextCheckingCompletion* completion) {
- RequestTextChecking(text.utf16(), completion);
+ RequestTextChecking(text.Utf16(), completion);
UMA_HISTOGRAM_COUNTS("SpellCheck.api.async", text.length());
}
-void SpellCheckProvider::cancelAllPendingRequests() {
+void SpellCheckProvider::CancelAllPendingRequests() {
for (WebTextCheckCompletions::iterator iter(&text_check_completions_);
!iter.IsAtEnd(); iter.Advance()) {
- iter.GetCurrentValue()->didCancelCheckingText();
+ iter.GetCurrentValue()->DidCancelCheckingText();
}
text_check_completions_.Clear();
}
-void SpellCheckProvider::showSpellingUI(bool show) {
-#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
- UMA_HISTOGRAM_BOOLEAN("SpellCheck.api.showUI", show);
- Send(new SpellCheckHostMsg_ShowSpellingPanel(routing_id(), show));
-#endif
-}
-
-bool SpellCheckProvider::isShowingSpellingUI() {
- return spelling_panel_visible_;
-}
-
-void SpellCheckProvider::updateSpellingUIWithMisspelledWord(
- const WebString& word) {
-#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
- Send(new SpellCheckHostMsg_UpdateSpellingPanelWithMisspelledWord(
- routing_id(), word.utf16()));
-#endif
-}
-
#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
void SpellCheckProvider::OnRespondSpellingService(
int identifier,
@@ -199,11 +174,11 @@ void SpellCheckProvider::OnRespondSpellingService(
line,
results,
&textcheck_results);
- completion->didFinishCheckingText(textcheck_results);
+ completion->DidFinishCheckingText(textcheck_results);
// Cache the request and the converted results.
last_request_ = line;
- last_results_.swap(textcheck_results);
+ last_results_.Swap(textcheck_results);
}
#endif
@@ -223,13 +198,6 @@ bool SpellCheckProvider::HasWordCharacters(
}
#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
-void SpellCheckProvider::OnAdvanceToNextMisspelling() {
- if (!render_view()->GetWebView())
- return;
- render_view()->GetWebView()->focusedFrame()->executeCommand(
- WebString::fromUTF8("AdvanceToNextMisspelling"));
-}
-
void SpellCheckProvider::OnRespondTextCheck(
int identifier,
const base::string16& line,
@@ -247,37 +215,19 @@ void SpellCheckProvider::OnRespondTextCheck(
line,
results,
&textcheck_results);
- completion->didFinishCheckingText(textcheck_results);
+ completion->DidFinishCheckingText(textcheck_results);
// Cache the request and the converted results.
last_request_ = line;
- last_results_.swap(textcheck_results);
-}
-
-void SpellCheckProvider::OnToggleSpellPanel(bool is_currently_visible) {
- if (!render_view()->GetWebView())
- return;
- // We need to tell the webView whether the spelling panel is visible or not so
- // that it won't need to make ipc calls later.
- spelling_panel_visible_ = is_currently_visible;
- render_view()->GetWebView()->focusedFrame()->executeCommand(
- WebString::fromUTF8("ToggleSpellPanel"));
+ last_results_.Swap(textcheck_results);
}
#endif
void SpellCheckProvider::EnableSpellcheck(bool enable) {
- if (!render_view()->GetWebView())
- return;
-
- WebLocalFrame* frame = render_view()->GetWebView()->focusedFrame();
- // TODO(yabinh): The null check should be unnecessary.
- // See crbug.com/625068
- if (!frame)
- return;
-
- frame->enableSpellChecking(enable);
+ WebLocalFrame* frame = render_frame()->GetWebFrame();
+ frame->EnableSpellChecking(enable);
if (!enable)
- frame->removeSpellingMarkers();
+ frame->RemoveSpellingMarkers();
}
bool SpellCheckProvider::SatisfyRequestFromCache(
@@ -297,7 +247,7 @@ bool SpellCheckProvider::SatisfyRequestFromCache(
if (text_length >= last_length &&
!request.compare(0, last_length, last_request_)) {
if (text_length == last_length || !HasWordCharacters(text, last_length)) {
- completion->didFinishCheckingText(last_results_);
+ completion->DidFinishCheckingText(last_results_);
return true;
}
}
@@ -313,9 +263,9 @@ bool SpellCheckProvider::SatisfyRequestFromCache(
if (start <= text_length && end <= text_length)
++result_size;
}
- blink::WebVector<blink::WebTextCheckingResult> results(last_results_.data(),
+ blink::WebVector<blink::WebTextCheckingResult> results(last_results_.Data(),
result_size);
- completion->didFinishCheckingText(results);
+ completion->DidFinishCheckingText(results);
return true;
}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider.h b/chromium/components/spellcheck/renderer/spellcheck_provider.h
index 24fa02197bc..cead10758dc 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider.h
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider.h
@@ -13,16 +13,14 @@
#include "base/id_map.h"
#include "base/macros.h"
#include "components/spellcheck/spellcheck_build_features.h"
-#include "content/public/renderer/render_view_observer.h"
-#include "content/public/renderer/render_view_observer_tracker.h"
-#include "third_party/WebKit/public/web/WebSpellCheckClient.h"
+#include "content/public/renderer/render_frame_observer.h"
+#include "content/public/renderer/render_frame_observer_tracker.h"
+#include "third_party/WebKit/public/web/WebTextCheckClient.h"
-class RenderView;
class SpellCheck;
struct SpellCheckResult;
namespace blink {
-class WebString;
class WebTextCheckingCompletion;
struct WebTextCheckingResult;
}
@@ -30,13 +28,13 @@ struct WebTextCheckingResult;
// This class deals with invoking browser-side spellcheck mechanism
// which is done asynchronously.
class SpellCheckProvider
- : public content::RenderViewObserver,
- public content::RenderViewObserverTracker<SpellCheckProvider>,
- public blink::WebSpellCheckClient {
+ : public content::RenderFrameObserver,
+ public content::RenderFrameObserverTracker<SpellCheckProvider>,
+ public blink::WebTextCheckClient {
public:
using WebTextCheckCompletions = IDMap<blink::WebTextCheckingCompletion*>;
- SpellCheckProvider(content::RenderView* render_view,
+ SpellCheckProvider(content::RenderFrame* render_frame,
SpellCheck* spellcheck);
~SpellCheckProvider() override;
@@ -58,7 +56,7 @@ class SpellCheckProvider
// Enables document-wide spellchecking.
void EnableSpellcheck(bool enabled);
- // RenderViewObserver implementation.
+ // RenderFrameObserver implementation.
bool OnMessageReceived(const IPC::Message& message) override;
void FocusedNodeChanged(const blink::WebNode& node) override;
@@ -71,25 +69,19 @@ class SpellCheckProvider
bool SatisfyRequestFromCache(const base::string16& text,
blink::WebTextCheckingCompletion* completion);
- // RenderViewObserver implementation.
+ // RenderFrameObserver implementation.
void OnDestruct() override;
- // blink::WebSpellCheckClient implementation.
- void checkSpelling(
+ // blink::WebTextCheckClient implementation.
+ void CheckSpelling(
const blink::WebString& text,
int& offset,
int& length,
blink::WebVector<blink::WebString>* optional_suggestions) override;
-
- void requestCheckingOfText(
+ void RequestCheckingOfText(
const blink::WebString& text,
blink::WebTextCheckingCompletion* completion) override;
-
- void cancelAllPendingRequests() override;
- void showSpellingUI(bool show) override;
- bool isShowingSpellingUI() override;
- void updateSpellingUIWithMisspelledWord(
- const blink::WebString& word) override;
+ void CancelAllPendingRequests() override;
#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
void OnRespondSpellingService(
@@ -104,12 +96,10 @@ class SpellCheckProvider
bool HasWordCharacters(const base::string16& text, int index) const;
#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
- void OnAdvanceToNextMisspelling();
void OnRespondTextCheck(
int identifier,
const base::string16& line,
const std::vector<SpellCheckResult>& results);
- void OnToggleSpellPanel(bool is_currently_visible);
#endif
// Holds ongoing spellchecking operations, assigns IDs for the IPC routing.
@@ -120,9 +110,6 @@ class SpellCheckProvider
base::string16 last_request_;
blink::WebVector<blink::WebTextCheckingResult> last_results_;
- // True if the browser is showing the spelling panel for us.
- bool spelling_panel_visible_;
-
// Weak pointer to shared (per RenderView) spellcheck data.
SpellCheck* spellcheck_;
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc b/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc
index 963e112cc8b..ffba9d14b0c 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc
@@ -21,12 +21,12 @@ FakeTextCheckingCompletion::FakeTextCheckingCompletion()
FakeTextCheckingCompletion::~FakeTextCheckingCompletion() {}
-void FakeTextCheckingCompletion::didFinishCheckingText(
+void FakeTextCheckingCompletion::DidFinishCheckingText(
const blink::WebVector<blink::WebTextCheckingResult>& results) {
++completion_count_;
}
-void FakeTextCheckingCompletion::didCancelCheckingText() {
+void FakeTextCheckingCompletion::DidCancelCheckingText() {
++completion_count_;
++cancellation_count_;
}
@@ -84,9 +84,8 @@ void TestingSpellCheckProvider::OnCallSpellingService(
text_check_completions_.Remove(identifier);
std::vector<blink::WebTextCheckingResult> results;
results.push_back(blink::WebTextCheckingResult(
- blink::WebTextDecorationTypeSpelling,
- 0, 5, blink::WebString("hello")));
- completion->didFinishCheckingText(results);
+ blink::kWebTextDecorationTypeSpelling, 0, 5, blink::WebString("hello")));
+ completion->DidFinishCheckingText(results);
last_request_ = text;
last_results_ = results;
#endif
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_test.h b/chromium/components/spellcheck/renderer/spellcheck_provider_test.h
index 43d73dbc33a..89a354e1662 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider_test.h
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_test.h
@@ -26,9 +26,9 @@ class FakeTextCheckingCompletion : public blink::WebTextCheckingCompletion {
FakeTextCheckingCompletion();
~FakeTextCheckingCompletion();
- void didFinishCheckingText(
+ void DidFinishCheckingText(
const blink::WebVector<blink::WebTextCheckingResult>& results) override;
- void didCancelCheckingText() override;
+ void DidCancelCheckingText() override;
size_t completion_count_;
size_t cancellation_count_;
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc
index a3b00a13460..478fe21a132 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc
@@ -30,8 +30,8 @@ TEST_F(SpellCheckProviderCacheTest, SubstringWithMisspellings) {
blink::WebVector<blink::WebTextCheckingResult> last_results;
std::vector<blink::WebTextCheckingResult> results;
results.push_back(blink::WebTextCheckingResult(
- blink::WebTextDecorationTypeSpelling, 5, 3, blink::WebString("isq")));
- last_results.assign(results);
+ blink::kWebTextDecorationTypeSpelling, 5, 3, blink::WebString("isq")));
+ last_results.Assign(results);
provider_.SetLastResults(base::ASCIIToUTF16("This isq a test"), last_results);
EXPECT_TRUE(provider_.SatisfyRequestFromCache(
base::ASCIIToUTF16("This isq a"), &completion));
diff --git a/chromium/components/spellcheck/renderer/spellcheck_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_unittest.cc
index 2a1dc3e118c..ef73f2d36d1 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_unittest.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_unittest.cc
@@ -116,7 +116,7 @@ class SpellCheckTest : public testing::Test {
EXPECT_EQ(results.size(), expected.size());
size_t size = std::min(results.size(), expected.size());
for (size_t j = 0; j < size; ++j) {
- EXPECT_EQ(results[j].decoration, blink::WebTextDecorationTypeSpelling);
+ EXPECT_EQ(results[j].decoration, blink::kWebTextDecorationTypeSpelling);
EXPECT_EQ(results[j].location, expected[j].location);
EXPECT_EQ(results[j].length, expected[j].length);
}
@@ -135,15 +135,13 @@ class MockTextCheckingCompletion : public blink::WebTextCheckingCompletion {
: completion_count_(0) {
}
- void didFinishCheckingText(
+ void DidFinishCheckingText(
const blink::WebVector<blink::WebTextCheckingResult>& results) override {
completion_count_++;
last_results_ = results;
}
- void didCancelCheckingText() override {
- completion_count_++;
- }
+ void DidCancelCheckingText() override { completion_count_++; }
size_t completion_count_;
blink::WebVector<blink::WebTextCheckingResult> last_results_;
@@ -490,14 +488,7 @@ TEST_F(SpellCheckTest, SpellCheckSuggestions_EN_US) {
// This test verifies our spellchecker can split a text into words and check
// the spelling of each word in the text.
-#if defined(OS_WIN)
-// SpellCheckTest.SpellCheckText fails on Windows.
-// See http://crbug.com/689101.
-#define MAYBE_SpellCheckText DISABLED_SpellCheckText
-#else
-#define MAYBE_SpellCheckText SpellCheckText
-#endif // OS_WIN
-TEST_F(SpellCheckTest, MAYBE_SpellCheckText) {
+TEST_F(SpellCheckTest, SpellCheckText) {
static const struct {
const char* language;
const wchar_t* input;
@@ -634,6 +625,7 @@ TEST_F(SpellCheckTest, MAYBE_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)
// Hungarian
"hu-HU",
L"A Google azt a k\x00FCldet\x00E9st v\x00E1llalta mag\x00E1ra, "
@@ -641,6 +633,7 @@ TEST_F(SpellCheckTest, MAYBE_SpellCheckText) {
L"rendszerezze \x00E9s \x00E1ltal\x00E1nosan el\x00E9rhet\x0151v\x00E9, "
L"illetve haszn\x00E1lhat\x00F3v\x00E1 tegye."
}, {
+#endif // !defined(OS_WIN)
// Croatian
"hr-HR",
// L"Googleova " - to be added.
@@ -686,6 +679,7 @@ TEST_F(SpellCheckTest, MAYBE_SpellCheckText) {
L"zasob\x00F3w informacji, aby sta\x0142y si\x0119 one powszechnie "
L"dost\x0119pne i u\x017Cyteczne."
}, {
+#if !defined(OS_WIN)
// Portuguese (Brazil)
"pt-BR",
L"A miss\x00E3o do "
@@ -699,6 +693,7 @@ TEST_F(SpellCheckTest, MAYBE_SpellCheckText) {
#endif
L"acess\x00EDveis e \x00FAteis em car\x00E1ter universal."
}, {
+#endif // !defined(OS_WIN)
// Portuguese (Portugal)
"pt-PT",
L"O "
@@ -768,6 +763,7 @@ TEST_F(SpellCheckTest, MAYBE_SpellCheckText) {
L"Googles m\x00E5ls\x00E4ttning \x00E4r att ordna v\x00E4rldens "
L"samlade information och g\x00F6ra den tillg\x00E4nglig f\x00F6r alla."
}, {
+#if !defined(OS_WIN)
// Turkish
"tr-TR",
// L"Google\x2019\x0131n " - to be added.
@@ -775,6 +771,7 @@ TEST_F(SpellCheckTest, MAYBE_SpellCheckText) {
L"organize etmek ve evrensel olarak eri\x015Filebilir ve "
L"kullan\x0131\x015Fl\x0131 k\x0131lmakt\x0131r."
}, {
+#endif // !defined(OS_WIN)
// Ukranian
"uk-UA",
L"\x041c\x0456\x0441\x0456\x044f "
@@ -798,6 +795,7 @@ TEST_F(SpellCheckTest, MAYBE_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)
// Korean
"ko",
L"Google\xC758 \xBAA9\xD45C\xB294 \xC804\xC138\xACC4\xC758 "
@@ -805,6 +803,7 @@ TEST_F(SpellCheckTest, MAYBE_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
"sq",
L"Misioni i Google \x00EBsht\x00EB q\x00EB t\x00EB organizoj\x00EB "
@@ -1147,7 +1146,7 @@ TEST_F(SpellCheckTest, CreateTextCheckingResultsKeepsMarkers) {
text, spellcheck_results,
&textcheck_results);
ASSERT_EQ(spellcheck_results.size(), textcheck_results.size());
- EXPECT_EQ(blink::WebTextDecorationTypeSpelling,
+ EXPECT_EQ(blink::kWebTextDecorationTypeSpelling,
textcheck_results[0].decoration);
EXPECT_EQ(spellcheck_results[0].location, textcheck_results[0].location);
EXPECT_EQ(spellcheck_results[0].length, textcheck_results[0].length);
@@ -1165,7 +1164,7 @@ TEST_F(SpellCheckTest, CreateTextCheckingResultsAddsGrammarMarkers) {
text, spellcheck_results,
&textcheck_results);
ASSERT_EQ(spellcheck_results.size(), textcheck_results.size());
- EXPECT_EQ(blink::WebTextDecorationTypeGrammar,
+ EXPECT_EQ(blink::kWebTextDecorationTypeGrammar,
textcheck_results[0].decoration);
EXPECT_EQ(spellcheck_results[0].location, textcheck_results[0].location);
EXPECT_EQ(spellcheck_results[0].length, textcheck_results[0].length);
@@ -1231,9 +1230,9 @@ TEST_F(SpellCheckTest, CreateTextCheckingResultsKeepsTypographicalApostrophe) {
ASSERT_EQ(arraysize(kExpectedReplacements), textcheck_results.size());
for (size_t i = 0; i < arraysize(kExpectedReplacements); ++i) {
EXPECT_EQ(base::WideToUTF16(kExpectedReplacements[i]),
- textcheck_results[i].replacement.utf16())
+ textcheck_results[i].replacement.Utf16())
<< "i=" << i << "\nactual: \""
- << textcheck_results[i].replacement.utf16() << "\"";
+ << textcheck_results[i].replacement.Utf16() << "\"";
}
}
diff --git a/chromium/components/ssl_config/OWNERS b/chromium/components/ssl_config/OWNERS
index 42d0d3b58b3..019db92cacc 100644
--- a/chromium/components/ssl_config/OWNERS
+++ b/chromium/components/ssl_config/OWNERS
@@ -1,3 +1,5 @@
agl@chromium.org
davidben@chromium.org
rsleevi@chromium.org
+
+# COMPONENT: Internals>Network>SSL
diff --git a/chromium/components/ssl_config/ssl_config_service_manager_pref.cc b/chromium/components/ssl_config/ssl_config_service_manager_pref.cc
index ee6304743c0..df78e589992 100644
--- a/chromium/components/ssl_config/ssl_config_service_manager_pref.cc
+++ b/chromium/components/ssl_config/ssl_config_service_manager_pref.cc
@@ -41,7 +41,7 @@ std::vector<std::string> ListValueToStringVector(const base::ListValue* value) {
std::string s;
for (base::ListValue::const_iterator it = value->begin(); it != value->end();
++it) {
- if (!(*it)->GetAsString(&s))
+ if (!it->GetAsString(&s))
continue;
results.push_back(s);
}
@@ -197,7 +197,7 @@ SSLConfigServiceManagerPref::SSLConfigServiceManagerPref(
if (base::FeatureList::IsEnabled(kTLS13Feature)) {
local_state->SetDefaultPrefValue(
ssl_config::prefs::kSSLVersionMax,
- new base::StringValue(switches::kSSLVersionTLSv13));
+ new base::Value(switches::kSSLVersionTLSv13));
}
PrefChangeRegistrar::NamedChangeCallback local_state_callback =
diff --git a/chromium/components/ssl_config/ssl_config_service_manager_pref_unittest.cc b/chromium/components/ssl_config/ssl_config_service_manager_pref_unittest.cc
index 12edb50c937..bb94f68f3f0 100644
--- a/chromium/components/ssl_config/ssl_config_service_manager_pref_unittest.cc
+++ b/chromium/components/ssl_config/ssl_config_service_manager_pref_unittest.cc
@@ -6,6 +6,7 @@
#include <utility>
#include "base/feature_list.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
@@ -67,10 +68,11 @@ TEST_F(SSLConfigServiceManagerPrefTest, GoodDisabledCipherSuites) {
config_service->GetSSLConfig(&old_config);
EXPECT_TRUE(old_config.disabled_cipher_suites.empty());
- base::ListValue* list_value = new base::ListValue();
+ auto list_value = base::MakeUnique<base::ListValue>();
list_value->AppendString("0x0004");
list_value->AppendString("0x0005");
- local_state.SetUserPref(ssl_config::prefs::kCipherSuiteBlacklist, list_value);
+ local_state.SetUserPref(ssl_config::prefs::kCipherSuiteBlacklist,
+ std::move(list_value));
// Pump the message loop to notify the SSLConfigServiceManagerPref that the
// preferences changed.
@@ -103,12 +105,13 @@ TEST_F(SSLConfigServiceManagerPrefTest, BadDisabledCipherSuites) {
config_service->GetSSLConfig(&old_config);
EXPECT_TRUE(old_config.disabled_cipher_suites.empty());
- base::ListValue* list_value = new base::ListValue();
+ auto list_value = base::MakeUnique<base::ListValue>();
list_value->AppendString("0x0004");
list_value->AppendString("TLS_NOT_WITH_A_CIPHER_SUITE");
list_value->AppendString("0x0005");
list_value->AppendString("0xBEEFY");
- local_state.SetUserPref(ssl_config::prefs::kCipherSuiteBlacklist, list_value);
+ local_state.SetUserPref(ssl_config::prefs::kCipherSuiteBlacklist,
+ std::move(list_value));
// Pump the message loop to notify the SSLConfigServiceManagerPref that the
// preferences changed.
@@ -163,7 +166,7 @@ TEST_F(SSLConfigServiceManagerPrefTest, NoSSL3) {
TestingPrefServiceSimple local_state;
local_state.SetUserPref(ssl_config::prefs::kSSLVersionMin,
- new base::StringValue("ssl3"));
+ base::MakeUnique<base::Value>("ssl3"));
SSLConfigServiceManager::RegisterPrefs(local_state.registry());
std::unique_ptr<SSLConfigServiceManager> config_manager(
@@ -185,7 +188,7 @@ TEST_F(SSLConfigServiceManagerPrefTest, SSLVersionMax) {
TestingPrefServiceSimple local_state;
local_state.SetUserPref(ssl_config::prefs::kSSLVersionMax,
- new base::StringValue("tls1.3"));
+ base::MakeUnique<base::Value>("tls1.3"));
SSLConfigServiceManager::RegisterPrefs(local_state.registry());
std::unique_ptr<SSLConfigServiceManager> config_manager(
@@ -206,7 +209,7 @@ TEST_F(SSLConfigServiceManagerPrefTest, NoTLS11Max) {
TestingPrefServiceSimple local_state;
local_state.SetUserPref(ssl_config::prefs::kSSLVersionMax,
- new base::StringValue("tls1.1"));
+ base::MakeUnique<base::Value>("tls1.1"));
SSLConfigServiceManager::RegisterPrefs(local_state.registry());
std::unique_ptr<SSLConfigServiceManager> config_manager(
@@ -252,7 +255,7 @@ TEST_F(SSLConfigServiceManagerPrefTest, TLS13SSLVersionMax) {
TestingPrefServiceSimple local_state;
local_state.SetUserPref(ssl_config::prefs::kSSLVersionMax,
- new base::StringValue("tls1.2"));
+ base::MakeUnique<base::Value>("tls1.2"));
SSLConfigServiceManager::RegisterPrefs(local_state.registry());
std::unique_ptr<SSLConfigServiceManager> config_manager(
@@ -295,7 +298,7 @@ TEST_F(SSLConfigServiceManagerPrefTest, SHA1ForLocalAnchors) {
// Enabling the local preference should result in SHA-1 local trust anchors
// being enabled.
local_state.SetUserPref(ssl_config::prefs::kCertEnableSha1LocalAnchors,
- new base::Value(true));
+ base::MakeUnique<base::Value>(true));
// Pump the message loop to notify the SSLConfigServiceManagerPref that the
// preferences changed.
base::RunLoop().RunUntilIdle();
@@ -307,7 +310,7 @@ TEST_F(SSLConfigServiceManagerPrefTest, SHA1ForLocalAnchors) {
// Disabling the local preference should result in SHA-1 local trust
// anchors being disabled.
local_state.SetUserPref(ssl_config::prefs::kCertEnableSha1LocalAnchors,
- new base::Value(false));
+ base::MakeUnique<base::Value>(false));
// Pump the message loop to notify the SSLConfigServiceManagerPref that the
// preferences changed.
base::RunLoop().RunUntilIdle();
diff --git a/chromium/components/ssl_errors/OWNERS b/chromium/components/ssl_errors/OWNERS
index 3f66a8d3ebd..db0d6582bef 100644
--- a/chromium/components/ssl_errors/OWNERS
+++ b/chromium/components/ssl_errors/OWNERS
@@ -4,3 +4,5 @@ felt@chromium.org
meacer@chromium.org
palmer@chromium.org
rsleevi@chromium.org
+
+# COMPONENT: Security>UX
diff --git a/chromium/components/ssl_errors/error_classification.cc b/chromium/components/ssl_errors/error_classification.cc
index 52827fe1565..da10872be42 100644
--- a/chromium/components/ssl_errors/error_classification.cc
+++ b/chromium/components/ssl_errors/error_classification.cc
@@ -95,7 +95,8 @@ bool IsWWWSubDomainMatch(const GURL& request_url,
}
// The time to use when doing build time operations in browser tests.
-base::LazyInstance<base::Time> g_testing_build_time = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::Time>::DestructorAtExit g_testing_build_time =
+ LAZY_INSTANCE_INITIALIZER;
} // namespace
diff --git a/chromium/components/storage_monitor/volume_mount_watcher_win.cc b/chromium/components/storage_monitor/volume_mount_watcher_win.cc
index 8c11a0a629b..5ac0b111395 100644
--- a/chromium/components/storage_monitor/volume_mount_watcher_win.cc
+++ b/chromium/components/storage_monitor/volume_mount_watcher_win.cc
@@ -30,7 +30,6 @@
#include "components/storage_monitor/media_storage_util.h"
#include "components/storage_monitor/storage_info.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/user_metrics.h"
using content::BrowserThread;
diff --git a/chromium/components/strings/BUILD.gn b/chromium/components/strings/BUILD.gn
index c9896e8e339..a299d38baf7 100644
--- a/chromium/components/strings/BUILD.gn
+++ b/chromium/components/strings/BUILD.gn
@@ -67,7 +67,6 @@ group("strings") {
grit("components_strings") {
source = "../components_strings.grd"
- use_qualified_include = true
defines = [ "enable_plugins=$enable_plugins" ]
outputs = [
@@ -95,7 +94,6 @@ if (is_android) {
grit("components_chromium_strings") {
source = "../components_chromium_strings.grd"
- use_qualified_include = true
outputs = [
"grit/components_chromium_strings.h",
]
@@ -106,7 +104,6 @@ grit("components_chromium_strings") {
grit("components_google_chrome_strings") {
source = "../components_google_chrome_strings.grd"
- use_qualified_include = true
outputs = [
"grit/components_google_chrome_strings.h",
]
@@ -166,7 +163,6 @@ if (is_android) {
grit("components_locale_settings") {
source = "../components_locale_settings.grd"
- use_qualified_include = true
outputs = [
"grit/components_locale_settings.h",
]
diff --git a/chromium/components/strings/components_chromium_strings_ca.xtb b/chromium/components/strings/components_chromium_strings_ca.xtb
index 461062b0fa8..8818aa60a9b 100644
--- a/chromium/components/strings/components_chromium_strings_ca.xtb
+++ b/chromium/components/strings/components_chromium_strings_ca.xtb
@@ -36,7 +36,7 @@
Si això no resol el problema, us recomanem que torneu a seleccionar
aquesta opció per obtenir un rendiment millorat.</translation>
<translation id="8187289872471304532">Aneu a
- Aplicacions &gt; Preferències del sistema &gt; Xarxa &gt; Opcions avançades &gt; Servidors intermediaris
+ Aplicacions &gt; Preferències del sistema &gt; Xarxa &gt; Configuració avançada &gt; Servidors intermediaris
i desmarqueu tots els servidors intermediaris que s'hagin seleccionat.</translation>
<translation id="8684913864886094367">Chromium no s'ha tancat correctament.</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_chromium_strings_es.xtb b/chromium/components/strings/components_chromium_strings_es.xtb
index 4d33552be11..8aabfa86432 100644
--- a/chromium/components/strings/components_chromium_strings_es.xtb
+++ b/chromium/components/strings/components_chromium_strings_es.xtb
@@ -36,7 +36,7 @@
Si esto no soluciona el problema, te recomendamos que vuelvas a seleccionar esta opción
para conseguir un mejor rendimiento.</translation>
<translation id="8187289872471304532">Accede a
- Aplicaciones &gt; Preferencias del Sistema &gt; Red &gt; Avanzado &gt; Proxies
+ Aplicaciones &gt; Preferencias del Sistema &gt; Red &gt; Configuración avanzada &gt; Proxies
y desactiva las casillas de verificación de los proxies seleccionados.</translation>
<translation id="8684913864886094367">Chromium no se ha cerrado correctamente.</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_chromium_strings_id.xtb b/chromium/components/strings/components_chromium_strings_id.xtb
index 18845a68a6c..ead6779c345 100644
--- a/chromium/components/strings/components_chromium_strings_id.xtb
+++ b/chromium/components/strings/components_chromium_strings_id.xtb
@@ -5,7 +5,7 @@
<translation id="275588974610408078">Pelaporan kerusakan tidak tersedia di Chromium.</translation>
<translation id="3064346599913645280">Anda melihat halaman Chromium yang aman</translation>
<translation id="3550966579244642892">Chromium OS belum menyelesaikan penyiapan awal.</translation>
-<translation id="4365115785552740256">Chromium tercipta berkat proyek sumber terbuka <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> dan berbagai <ph name="BEGIN_LINK_OSS" />perangkat lunak sumber terbuka<ph name="END_LINK_OSS" /> lainnya.</translation>
+<translation id="4365115785552740256">Chromium tercipta berkat proyek sumber terbuka <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> dan berbagai <ph name="BEGIN_LINK_OSS" />software sumber terbuka<ph name="END_LINK_OSS" /> lainnya.</translation>
<translation id="4559775032954821361">Buka
menu Chromium &gt;
<ph name="SETTINGS_TITLE" />
diff --git a/chromium/components/strings/components_chromium_strings_zh-TW.xtb b/chromium/components/strings/components_chromium_strings_zh-TW.xtb
index 89b63af93be..250483f5ecc 100644
--- a/chromium/components/strings/components_chromium_strings_zh-TW.xtb
+++ b/chromium/components/strings/components_chromium_strings_zh-TW.xtb
@@ -1,7 +1,7 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zh-TW">
-<translation id="130631256467250065">您的變更會在下次é‡æ–°å•Ÿå‹•è£ç½®æ™‚生效。</translation>
+<translation id="130631256467250065">你的變更會在下次é‡æ–°å•Ÿå‹•è£ç½®æ™‚生效。</translation>
<translation id="275588974610408078">Chromium ä¸æ”¯æ´ç•¶æ©Ÿå›žå ±åŠŸèƒ½ã€‚</translation>
<translation id="3064346599913645280">ç›®å‰é¡¯ç¤ºçš„是安全型 Chromium 網é </translation>
<translation id="3550966579244642892">Chromium 作業系統未完æˆåˆå§‹è¨­å®šã€‚</translation>
@@ -15,7 +15,7 @@
[<ph name="PROXIES_TITLE" />]
&gt;
[å€åŸŸç¶²è·¯è¨­å®š]
- 然後å–æ¶ˆå‹¾é¸ [在您的å€åŸŸç¶²è·¯ä½¿ç”¨ Proxy 伺æœå™¨] æ ¸å–方塊。</translation>
+ 然後å–æ¶ˆå‹¾é¸ [在你的å€åŸŸç¶²è·¯ä½¿ç”¨ Proxy 伺æœå™¨] æ ¸å–方塊。</translation>
<translation id="48558539577516920">å…許 Chromium å­˜å–å—到防ç«ç‰†æˆ–防毒軟體設定所阻擋的
網路。</translation>
<translation id="580822234363523061">å‰å¾€
@@ -25,15 +25,15 @@
[<ph name="ADVANCED_TITLE" />]
&gt;
[<ph name="PROXIES_TITLE" />]
- 並確èªæ‚¨çš„設定為 [ä¸ä½¿ç”¨ Proxy] 或 [直接連線]。</translation>
-<translation id="6613594504749178791">您的變更將於下次é‡æ–°å•Ÿå‹• Chromium 時生效。</translation>
+ 並確èªä½ çš„設定為 [ä¸ä½¿ç”¨ Proxy] 或 [直接連線]。</translation>
+<translation id="6613594504749178791">你的變更將於下次é‡æ–°å•Ÿå‹• Chromium 時生效。</translation>
<translation id="7861509383340276692">å‰å¾€
Chromium é¸å–® &gt;
[<ph name="SETTINGS_TITLE" />]
&gt;
[<ph name="ADVANCED_TITLE" />]
然後å–æ¶ˆå‹¾é¸ [<ph name="NO_PREFETCH_DESCRIPTION" />]。
- 如果ä»ç„¶ç„¡æ³•è§£æ±ºå•é¡Œï¼Œå»ºè­°æ‚¨é‡æ–°å‹¾é¸é€™å€‹é¸é …
+ 如果ä»ç„¶ç„¡æ³•è§£æ±ºå•é¡Œï¼Œå»ºè­°ä½ é‡æ–°å‹¾é¸é€™å€‹é¸é …
以增進效能。</translation>
<translation id="8187289872471304532">å‰å¾€
[應用程å¼] &gt; [系統å好設定] &gt; [網路] &gt; [進階] &gt; [Proxy]
diff --git a/chromium/components/strings/components_google_chrome_strings_ca.xtb b/chromium/components/strings/components_google_chrome_strings_ca.xtb
index dfa8968ffe6..3ae104a89fa 100644
--- a/chromium/components/strings/components_google_chrome_strings_ca.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_ca.xtb
@@ -37,6 +37,6 @@
Configuració de LAN
i desmarqueu Utilitza un servidor intermediari per a la LAN.</translation>
<translation id="8187289872471304532">Aneu a
- Aplicacions &gt; Preferències del sistema &gt; Xarxa &gt; Opcions avançades &gt; Servidors intermediaris
+ Aplicacions &gt; Preferències del sistema &gt; Xarxa &gt; Configuració avançada &gt; Servidors intermediaris
i desmarqueu tots els servidors intermediaris que s'hagin seleccionat.</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_google_chrome_strings_es.xtb b/chromium/components/strings/components_google_chrome_strings_es.xtb
index a01cc9c7ddc..e3b5b2b94cd 100644
--- a/chromium/components/strings/components_google_chrome_strings_es.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_es.xtb
@@ -37,6 +37,6 @@
Configuración de LAN
y desactiva la opción Usar un servidor proxy para la LAN.</translation>
<translation id="8187289872471304532">Accede a
- Aplicaciones &gt; Preferencias del Sistema &gt; Red &gt; Avanzado &gt; Proxies
+ Aplicaciones &gt; Preferencias del Sistema &gt; Red &gt; Configuración avanzada &gt; Proxies
y desactiva las casillas de verificación de los proxies seleccionados.</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_google_chrome_strings_id.xtb b/chromium/components/strings/components_google_chrome_strings_id.xtb
index d942281bb04..3fb47959e96 100644
--- a/chromium/components/strings/components_google_chrome_strings_id.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_id.xtb
@@ -3,7 +3,7 @@
<translationbundle lang="id">
<translation id="1016765312371154165">Chrome tidak dinonaktifkan dengan benar.</translation>
<translation id="130631256467250065">Perubahan Anda akan diterapkan pada saat Anda nanti menyalakan ulang perangkat.</translation>
-<translation id="2874156562296220396">Google Chrome bisa ada berkat proyek sumber terbuka yaitu <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> dan berbagai <ph name="BEGIN_LINK_OSS" />perangkat lunak sumber terbuka<ph name="END_LINK_OSS" /> lainnya.</translation>
+<translation id="2874156562296220396">Google Chrome bisa ada berkat proyek sumber terbuka yaitu <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> dan berbagai <ph name="BEGIN_LINK_OSS" />software sumber terbuka<ph name="END_LINK_OSS" /> lainnya.</translation>
<translation id="3140883423282498090">Perubahan Anda akan berlaku pada peluncuran ulang Google Chrome selanjutnya.</translation>
<translation id="3444832043240812445">Laman 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
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 aa1f46847ea..434ce4f2b4e 100644
--- a/chromium/components/strings/components_google_chrome_strings_zh-TW.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_zh-TW.xtb
@@ -2,10 +2,10 @@
<!DOCTYPE translationbundle>
<translationbundle lang="zh-TW">
<translation id="1016765312371154165">Chrome 未正確關閉。</translation>
-<translation id="130631256467250065">您的變更會在下次é‡æ–°å•Ÿå‹•è£ç½®æ™‚生效。</translation>
+<translation id="130631256467250065">你的變更會在下次é‡æ–°å•Ÿå‹•è£ç½®æ™‚生效。</translation>
<translation id="2874156562296220396">Google 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="3140883423282498090">您的變更將於下次é‡æ–°å•Ÿå‹• Google Chrome 時生效。</translation>
-<translation id="3444832043240812445">如果您<ph name="BEGIN_LINK" />啟用當機報告功能<ph name="END_LINK" />,這個é é¢åƒ…會顯示最近的當機資訊。</translation>
+<translation id="3140883423282498090">你的變更將於下次é‡æ–°å•Ÿå‹• Google Chrome 時生效。</translation>
+<translation id="3444832043240812445">如果你<ph name="BEGIN_LINK" />啟用當機報告功能<ph name="END_LINK" />,這個é é¢åƒ…會顯示最近的當機資訊。</translation>
<translation id="3875312571075912821">å…許 Chrome å­˜å–å—到防ç«ç‰†æˆ–防毒軟體設定所阻擋的
網路。</translation>
<translation id="4010643444566880169">Chrome 作業系統未完æˆåˆå§‹è¨­å®šã€‚</translation>
@@ -17,14 +17,14 @@
[<ph name="ADVANCED_TITLE" />]
&gt;
[<ph name="PROXIES_TITLE" />]
- 並確èªæ‚¨çš„設定為 [ä¸ä½¿ç”¨ Proxy] 或 [直接連線]。</translation>
+ 並確èªä½ çš„設定為 [ä¸ä½¿ç”¨ Proxy] 或 [直接連線]。</translation>
<translation id="6341737370356890233">å‰å¾€
Chrome é¸å–® &gt;
[<ph name="SETTINGS_TITLE" />]
&gt;
[<ph name="ADVANCED_TITLE" />]
然後å–æ¶ˆå‹¾é¸ [<ph name="NO_PREFETCH_DESCRIPTION" />]。
- 如果ä»ç„¶ç„¡æ³•è§£æ±ºå•é¡Œï¼Œå»ºè­°æ‚¨é‡æ–°å‹¾é¸é€™å€‹é¸é …
+ 如果ä»ç„¶ç„¡æ³•è§£æ±ºå•é¡Œï¼Œå»ºè­°ä½ é‡æ–°å‹¾é¸é€™å€‹é¸é …
以增進效能。</translation>
<translation id="6855094794438142393">å‰å¾€
Chrome é¸å–® &gt;
@@ -35,7 +35,7 @@
[<ph name="PROXIES_TITLE" />]
&gt;
[å€åŸŸç¶²è·¯è¨­å®š]
- 然後å–æ¶ˆå‹¾é¸ [在您的å€åŸŸç¶²è·¯ä½¿ç”¨ Proxy 伺æœå™¨] æ ¸å–方塊。</translation>
+ 然後å–æ¶ˆå‹¾é¸ [在你的å€åŸŸç¶²è·¯ä½¿ç”¨ Proxy 伺æœå™¨] æ ¸å–方塊。</translation>
<translation id="8187289872471304532">å‰å¾€
[應用程å¼] &gt; [系統å好設定] &gt; [網路] &gt; [進階] &gt; [Proxy]
然後å–消勾é¸æ‰€æœ‰å·²é¸å–çš„ Proxy。</translation>
diff --git a/chromium/components/strings/components_strings_am.xtb b/chromium/components/strings/components_strings_am.xtb
index 1f7325bccd2..dfa80b4fd58 100644
--- a/chromium/components/strings/components_strings_am.xtb
+++ b/chromium/components/strings/components_strings_am.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="am">
<translation id="1008557486741366299">አáˆáŠ• አይደለáˆ</translation>
<translation id="1015730422737071372">ተጨማሪ á‹áˆ­á‹áˆ®á‰½áŠ• ያቅርቡ</translation>
+<translation id="1021110881106174305">ተቀባይáŠá‰µ ያላቸዠካርዶች</translation>
<translation id="1032854598605920125">በሰዓት አቅጣጫ አሽከርክር</translation>
<translation id="1038842779957582377">á‹«áˆá‰³á‹ˆá‰€ ስáˆ</translation>
<translation id="1050038467049342496">ሌሎች መተáŒá‰ áˆªá‹«á‹Žá‰½áŠ• á‹­á‹áŒ‰</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">እሴት ይደብá‰</translation>
<translation id="1228893227497259893">የተሳሳተ የáˆáŠ•áŠá‰µ ለዪ</translation>
<translation id="1232569758102978740">ርዕስ አáˆá‰£</translation>
+<translation id="1263231323834454256">የንባብ á‹áˆ­á‹áˆ­</translation>
<translation id="1264126396475825575">በ<ph name="CRASH_TIME" /> ላይ የብáˆáˆ½á‰µ ሪá–ርት ተይዟሠ(እስካáˆáŠ• አáˆá‰°áˆ°á‰€áˆˆáˆ ወይሠችላ አáˆá‰°á‰£áˆˆáˆ)</translation>
<translation id="1285320974508926690">ይህን ጣቢያ በጭራሽ አትተርጉáˆ</translation>
<translation id="129553762522093515">በቅርብ ጊዜ የተዘጉ</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">የChromium ራስ-ሙላ ቅንብሮች...</translation>
<translation id="1374468813861204354">የቀረቡ የጥቆማ አስተያየቶች</translation>
<translation id="1375198122581997741">ስለ ስሪት</translation>
+<translation id="1377321085342047638">የካርድ á‰áŒ¥áˆ­</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> áˆáŠ•áˆ á‹áˆ‚ብ አáˆáˆ‹áŠ¨áˆá¢</translation>
<translation id="1407135791313364759">áˆáˆ‰áŠ•áˆ ክáˆá‰µ</translation>
<translation id="1413809658975081374">የáŒáˆ‹á‹ŠáŠá‰µ ስህተት</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">ታሪክ</translation>
<translation id="1645368109819982629">የማይደገá á•áˆ®á‰¶áŠ®áˆ</translation>
<translation id="1656489000284462475">መá‹áˆ°áŒƒ</translation>
+<translation id="1663943134801823270">ካርዶች እና አድራሻዎች ከChrome የመጡ ናቸá‹á¢ በ<ph name="BEGIN_LINK" />ቅንብሮች<ph name="END_LINK" /> á‹áˆµáŒ¥ ሊያስተዳድሯቸዠይችላሉá¢</translation>
<translation id="1676269943528358898"><ph name="SITE" /> የእርስዎን መረጃ ለመጠበቅ በመደበáŠáŠá‰µ áˆáˆµáŒ áˆ« ይጠቀማáˆá¢ Google Chrome አáˆáŠ• ከ<ph name="SITE" /> ጋር ለመገናኘት ሲሞክር ድር ጣቢያዠያáˆá‰°áˆˆáˆ˜á‹± እና ትክክሠያáˆáˆ†áŠ‘ áˆáˆµáŠ­áˆ­áŠá‰¶á‰½áŠ• መáˆáˆ·áˆá¢ ይህ አንድ አጥቂ <ph name="SITE" />ን አስመስሎ ለመቅረብ ሲሞክር áŠá‹ ወይሠአንድ የWi-Fi መáŒá‰¢á‹« ገጽ áŒáŠ•áŠ™áŠá‰±áŠ• ሲያቋረጥ ሊከሰት ይችላáˆá¢ Google Chrome ማንኛá‹áˆ የá‹áˆ‚ብ áˆá‹á‹áŒ¥ ከመካሄዱ በáŠá‰µ áŒáŠ•áŠ™áŠá‰±áŠ• ስላቋረጠዠየእርስዎ መረጃ ደህንáŠá‰µ አáˆáŠ•áˆ የተጠበቀ áŠá‹á¢</translation>
<translation id="168328519870909584">በአáˆáŠ‘ ጊዜ በ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ላይ ያሉ አጥቂዎች መረጃዎን (ለáˆáˆ³áˆŒá¦ áŽá‰¶á‹Žá‰½á£ የይለá ቃላትᣠመáˆá‹•áŠ­á‰¶á‰½ እና ክሬዲት ካርዶች) የሚሰርበወይሠየሚሰርዙ አደገኛ መተáŒá‰ áˆªá‹«á‹Žá‰½áŠ• ለመጫን ሊሞክሩ ይችላሉá¢</translation>
<translation id="168841957122794586">የአገáˆáŒ‹á‹­ እá‹á‰…ና ማረጋገጫዠደካማ የሆአባለስá‹áˆ­ መረጃ á‰áˆá áŠá‹ ያለá‹á¢</translation>
<translation id="1710259589646384581">ስርዓተ ክወና</translation>
<translation id="1721312023322545264">ይህን ጣቢያ ለመጎብኘት ከ<ph name="NAME" /> áˆá‰ƒá‹µ ያስáˆáˆáŒˆá‹Žá‰³áˆ</translation>
+<translation id="1721424275792716183">* መስክ ያስáˆáˆáŒ‹áˆ</translation>
<translation id="1728677426644403582">የአንድ ድረ-ገጽ áˆáŠ•áŒ­ እየተመለከቱ áŠá‹</translation>
+<translation id="173080396488393970">የዚህ á‹“á‹­áŠá‰± ካርድ አይደገááˆ</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">የሥርዓት አስተዳዳሪá‹áŠ• ለማáŠáŒ‹áŒˆáˆ­ ይሞክሩá¢</translation>
+<translation id="1740951997222943430">ትክክለኛ የአገáˆáŒáˆŽá‰µ ማብቂያ ወር ያስገቡ</translation>
<translation id="1745358365027406341">ገጹን በኋላ አá‹áˆ­á‹µ</translation>
<translation id="17513872634828108">ትሮችን ክáˆá‰µ</translation>
<translation id="1753706481035618306">የገጽ á‰áŒ¥áˆ­</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">እባክዎ የማመሳሰሠይለá áˆáˆ¨áŒá‹ŽáŠ• ያዘáˆáŠ‘á¢</translation>
<translation id="1787142507584202372">የእርስዎ ክáት ትሮች እዚህ ይመጣሉ</translation>
<translation id="1791429645902722292">Google ዘመናዊ á‰áˆá</translation>
-<translation id="1797835274315207060">የመላኪያ ስáˆá‰¶á‰½áŠ• እና መስáˆáˆ­á‰¶á‰½áŠ• ለመáˆá‰°áˆ½ አንድ የመላኪያ አድራሻ á‹­áˆáˆ¨áŒ¡á¢</translation>
+<translation id="1803264062614276815">የካርድ ያዢዠስáˆ</translation>
<translation id="1803678881841855883">Google የጥንቃቄ አሰሳ በቅርቡ በ<ph name="SITE" /> ላይ <ph name="BEGIN_LINK" />ተንኮáˆ-አዘሠዌር<ph name="END_LINK" /> እንዳለ ደርሶበታáˆá¢ በመደበኛ ጊዜ ደህንáŠá‰³á‰¸á‹ የተጠበበድር ጣቢያዎች አንዳንድ ጊዜ በተንኮáˆ-አዘሠዌር ሊጠበይችላሉᢠበተንኮáˆ-አዘሠዌር አሰራጭáŠá‰µ ከሚታወቀዠ<ph name="SUBRESOURCE_HOST" /> የመጣ áŠá‹á¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="1806541873155184440"><ph name="ADDED_TO_AUTOFILL_MONTH" /> ላይ ታክáˆáˆ</translation>
<translation id="1821930232296380041">áˆáŠ­ á‹«áˆáˆ†áŠ ጥያቄ ወይሠየጥያቄ áˆáŠ¬á‰¶á‰½</translation>
<translation id="1826516787628120939">በመáˆá‰°áˆ¸ ላይ</translation>
<translation id="1834321415901700177">ይህ ጣቢያ ጎጂ á•áˆ®áŒáˆ«áˆžá‰½áŠ• á‹­á‹Ÿáˆ</translation>
<translation id="1842969606798536927">ይክáˆáˆ‰</translation>
-<translation id="1864455488461349376">የመላኪያ አማራጭ</translation>
<translation id="1871208020102129563">የ.pac ስክሪá•á‰µ ዩአርኤሠሳይሆን ተኪ አገáˆáŒ‹á‹®á‰½áŠ• እንዲጠቀሠáŠá‹ ተኪ የተዋቀረá‹á¢</translation>
<translation id="1871284979644508959">የሚያስáˆáˆáŒ መስክ</translation>
<translation id="187918866476621466">የመáŠáˆ» ገጾችን ክáˆá‰µ</translation>
<translation id="1883255238294161206">á‹áˆ­á‹áˆ­ ሰብስብ</translation>
<translation id="1898423065542865115">በማጣራት ላይ</translation>
<translation id="194030505837763158">ወደ <ph name="LINK" /> ሂድ</translation>
-<translation id="1946821392246652573">ተቀባይáŠá‰µ ያገኙ ካርዶች</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> እáˆá‰£á‰¶á‰½</translation>
<translation id="1973335181906896915">የመለያ á‰áŒ¥áˆ­ መስጠት ላይ ስህተት</translation>
<translation id="1974060860693918893">የላቀ</translation>
<translation id="1978555033938440688">የጽኑ ትዕዛዠስሪት</translation>
+<translation id="1995859865337580572">እባክዎ የካርድ ማረጋገጫ ኮድዎን ያረጋáŒáŒ¡</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{እና 1 ተጨማሪ}one{እና # ተጨማሪ}other{እና # ተጨማሪ}}</translation>
-<translation id="2020194265157481222">በካርድ ላይ ስሠያስáˆáˆáŒ‹áˆ</translation>
<translation id="2025186561304664664">ተኪ ወደ ራስ-á‹á‰…ር ተዋቅሯáˆá¢</translation>
<translation id="2030481566774242610"><ph name="LINK" />ን ማለትዎ áŠá‹?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />ወኪሉን እና ኬላá‹áŠ• መáˆá‰°áˆ½<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">ዛሬ</translation>
<translation id="2154054054215849342">ስáˆáˆ¨á‰µ ለእርስዎ ጎራ አይገáŠáˆ</translation>
<translation id="2154484045852737596">ካርትን ያርትዑ</translation>
-<translation id="2156993118928861787">áˆáŠ­ á‹«áˆáŠ¾áŠ አድራሻ</translation>
<translation id="2166049586286450108">ሙሉ የአስተዳደር መድረሻ</translation>
<translation id="2166378884831602661">ይህ ጣቢያ ደህንáŠá‰± አስተማማአየሆአáŒáŠ•áŠ™áŠá‰µ ማቅረብ አይችáˆáˆ</translation>
<translation id="2181821976797666341">መáˆáˆªá‹«á‹Žá‰½</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 አድራሻ}one{# አድራሻዎች}other{# አድራሻዎች}}</translation>
+<translation id="2202020181578195191">ትክክለኛ የአገáˆáŒáˆŽá‰µ ማብቂያ ዓመት ያስገቡ</translation>
<translation id="2212735316055980242">መመሪያ አáˆá‰°áŒˆáŠ˜áˆ</translation>
<translation id="2213606439339815911">áŒá‰¤á‰¶á‰½áŠ• በማáˆáŒ£á‰µ ላይ...</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />የመመርመሪያ መተáŒá‰ áˆªá‹«á‹áŠ•<ph name="END_LINK" /> በመጠቀሠáŒáŠ•áŠ™áŠá‰µá‹ŽáŠ• ያስተካክሉት</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">የእርስዎ የበየáŠáˆ˜áˆ¨á‰¥ መዳረሻ ታáŒá‹·áˆ</translation>
<translation id="230155334948463882">አዲስ ካርድ?</translation>
<translation id="2305919008529760154">ይህ አገáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆኑን ማረጋገጥ አáˆá‰»áˆˆáˆá¤ የደህንáŠá‰µ á‹•á‹á‰…ና ማረገጫዠበተጭበረበረ መáˆáŠ© የወጣ ሊሆን ይችላáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየእርስዎን áŒáŠ•áŠ™áŠá‰µ በጠለሠአጥቂ áˆáŠ­áŠ•á‹«á‰µ የተáˆáŒ áˆ¨ ሊሆን ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
-<translation id="230697611605700222">ካርድ እና የአድራሻ አማራጮ ከእርስዎ የGoogle መለያ (<ph name="ACCOUNT_EMAIL" />) እና Chrome የተገኙ ናቸá‹á¢ ይህንን በ<ph name="BEGIN_LINK" />ቅንብሮች<ph name="END_LINK" /> á‹áˆµáŒ¥ ማቀናበር ይችላሉá¢</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> የተጠቃሚ ስሠእና የይለá ቃሠያስáˆáˆáŒˆá‹‹áˆá¢</translation>
<translation id="2318774815570432836">የድር ጣቢያዠHSTS ስለሚጠቀሠአáˆáŠ• <ph name="SITE" /> መጎብኘት አይችሉáˆá¢ የአá‹á‰³áˆ¨ መረብ ስህተቶች እና ጥቃቶች አብዛኛዠጊዜ ጊዜያዊ ናቸá‹á£ ስለዚህ ይህ ገጽ በኋላ ላይ ሊሠራ ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="2354001756790975382">ሌላ እáˆá‰£á‰¶á‰½</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">የንáŒá‹µ ድርጅት áŠá‰£áˆª</translation>
<translation id="2386255080630008482">የአገáˆáŒ‹á‹­ እá‹á‰…ና ማረጋገጫ ተሽሯáˆá¢</translation>
<translation id="2392959068659972793">áˆáŠ•áˆ እሴት á‹«áˆá‰°á‹‹á‰€áˆ¨áˆ‹á‰¸á‹ መáˆáˆªá‹«á‹Žá‰½áŠ• አሳይ</translation>
+<translation id="239429038616798445">ይህ የመላኪያ ዘዴ አይገáŠáˆá¢ የተለየ ዘዴ ይሞክሩá¢</translation>
<translation id="2396249848217231973">&amp;ስረዛን ቀáˆá‰¥áˆµ</translation>
<translation id="2460160116472764928">Google የጥንቃቄ አሰሳ በቅርብ ጊዜ በ<ph name="SITE" /> ላይ <ph name="BEGIN_LINK" />ተንኮáˆ-አዘሠዌር<ph name="END_LINK" /> ላይ አáŒáŠá‰·áˆá¢ በመደበኛ ጊዜ ደህንáŠá‰³á‰¸á‹ የተጠበበድር ጣቢያዎች አንዳንድ ጊዜ በተንኮáˆ-አዘሠዌር ሊጠበይችላሉᢠ<ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2463739503403862330">ሙላ</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />የአá‹á‰³áˆ¨ መረብ መመርመሪያን በማሄድ ላይ<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">áˆáŠ­ á‹«áˆáˆ†áŠ የáለጋ ዩአርኤáˆá¢</translation>
<translation id="2491120439723279231">የአገáˆáŒ‹á‹­ እá‹á‰…ና ማረጋገጫ ስህተቶችን á‹­á‹Ÿáˆá¢</translation>
-<translation id="24943777258388405">áˆáŠ­ á‹«áˆáˆ†áŠ ስáˆáŠ­ á‰áŒ¥áˆ­</translation>
<translation id="2495083838625180221">JSON ተንታáŠ</translation>
<translation id="2495093607237746763">áˆáˆáŠ­á‰µ ከተደረገበት Chromium ለተሻለ የቅጽ አሞላሠáጥáŠá‰µ የካርድዎን ቅጂ በዚህ መሣሪያ ላይ ያከማቻáˆá¢</translation>
<translation id="2498091847651709837">አዲስ ካርድ ቃáŠ</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> áˆáŠ­ á‹«áˆáŠ¾áŠ áˆáˆ‹áˆ½ áˆáŠ³áˆá¢</translation>
<translation id="2552545117464357659">በጣሠአዲስ</translation>
<translation id="2556876185419854533">&amp;አርትዕን ቀáˆá‰¥áˆµ</translation>
+<translation id="2587730715158995865">ከ<ph name="ARTICLE_PUBLISHER" />ᢠይህን እና <ph name="OTHER_ARTICLE_COUNT" /> ሌሎች ዘገባዎችን ያንብቡá¢</translation>
<translation id="2587841377698384444">የማá‹áŒ« የኤá’አይ መታወቂያá¦</translation>
<translation id="2597378329261239068">ይህ ሰáŠá‹µ በይለá ቃሠየተጠበቀ áŠá‹á¢ እባክዎ የይለá ቃሠያስገቡá¢</translation>
<translation id="2609632851001447353">áˆá‹©áŠá‰¶á‰½</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />የáŒáŠ•áŠ™áŠá‰µ መመርመሪያን በማሄድ ላይ<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">እሺ</translation>
<translation id="2742870351467570537">የተመረጡትን ንጥሎች አስወáŒá‹µ</translation>
+<translation id="277133753123645258">የመላኪያ ዘዴ</translation>
<translation id="277499241957683684">የሚጎድሠየመሣሪያ መá‹áŒˆá‰¥</translation>
<translation id="2784949926578158345">áŒáŠ•áŠ™áŠá‰± ዳáŒáˆ እንዲጀáˆáˆ­ ተደርጓáˆá¢</translation>
<translation id="2794233252405721443">ጣቢያ ታáŒá‹·áˆ</translation>
-<translation id="2812680587231492111">ይህ የመá‹áˆ°áŒƒ አማራጭ አይገáŠáˆá¢ የተለየ አማራጭ ይሞክሩá¢</translation>
<translation id="2824775600643448204">የአድራሻ እና áለጋ አሞሌ</translation>
<translation id="2826760142808435982">áŒáŠ•áŠ™áŠá‰± የተመሰጠረ እና <ph name="CIPHER" />ን በመጠቀሠየተረጋገጠ áŠá‹á£ እና <ph name="KX" />ን እንደ የá‰áˆá መቀያየሪያ ስáˆá‰µ ይጠቀáˆá‰ á‰³áˆá¢</translation>
<translation id="2835170189407361413">ቅጽ አጽዳ</translation>
-<translation id="2849041323157393173">ይህ የማድረሻ አማራጭ አይገáŠáˆá¢ የተለየ አማራጭ ይሞክሩá¢</translation>
<translation id="2889159643044928134">ዳáŒáˆ አትጫን</translation>
<translation id="2900469785430194048">Google Chrome ይህን ድረ-ገጽ ለማሳየት በሚሞክርበት ጊዜ ማኅደረ ትá‹áˆµá‰³ አáˆá‰†á‰ á‰³áˆá¢</translation>
<translation id="2909946352844186028">የአá‹á‰³áˆ¨ መረብ ለá‹áŒ¥ ተገáŠá‰·áˆá¢</translation>
<translation id="2916038427272391327">ሌሎች á•áˆ®áŒáˆ«áˆžá‰½áŠ• á‹­á‹áŒ‰</translation>
<translation id="2922350208395188000">የአገáˆáŒ‹á‹­ እá‹á‰…ና ማረጋገጫ ሊረጋገጥ አáˆá‰»áˆˆáˆá¢</translation>
+<translation id="2928905813689894207">ክáá‹« የሚጠየቅበት አድራሻ</translation>
<translation id="2948083400971632585">ከቅንብሮች ገጽ ሆáŠá‹ ማናቸá‹áŠ•áˆ ለáŒáŠ•áŠ™áŠá‰µ የተዋቀሩ ተኪዎችን ማሰናከሠይችላሉá¢</translation>
<translation id="2955913368246107853">አáŒáŠ አሞሌን á‹áŒ‹</translation>
<translation id="2958431318199492670">የአá‹á‰³áˆ¨ መረብ á‹á‰…ሩ በኦ ኤን ሲ መስáˆáˆ­á‰± አይገዛáˆá¢ አንዳንድ የá‹á‰…ሩ ክáሎች ላይመጡ ይችላሉá¢</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">ደህንáŠá‰± የተጠበቀ áŒáŠ•áŠ™áŠá‰µ ለመመስረት የእርስዎ ሰዓት በትክክሠመዋቀር አለበትᢠይሄ የሆáŠá‰ á‰µ áˆáŠ­áŠ•á‹«á‰µ ድር ጣቢያዎች ራሳቸá‹áŠ• ለማሳወቅ የሚጠቀሙባቸዠየእá‹á‰…ና ማረጋገጫዎች የሚሰሩት ለተወሰኑ ጊዜዎች ብቻ ስለሆአáŠá‹á¢ የእርስዎ መሣሪያ ሰዓት ትክክሠእንዳለመሆኑ መጠን Google Chrome እáŠá‹šáˆ…ን የእá‹á‰…ና ማረጋገጫዎች ሊያረጋáŒáŒ¥ አይችáˆáˆá¢</translation>
<translation id="2972581237482394796">&amp;ድገáˆ</translation>
<translation id="2985306909656435243">ከáŠá‰ƒ Chromium ለተሻለ የቅጽ አሞላሠáጥáŠá‰µ ሲባሠበዚህ መሣሪያ ላይ ያለዠየካርድዎን ቅጂ ያከማቻáˆá¢</translation>
+<translation id="2985398929374701810">የሚሰራ አድራሻ ያስገቡ</translation>
+<translation id="2986368408720340940">ይህ የመá‹áˆ°áŒƒ ዘዴ አይደገááˆá¢ የተለየ ዘዴ á‹­áˆáˆ¨áŒ¡á¢</translation>
<translation id="2991174974383378012">ከድረ ገጾች ጋር ማጋራት</translation>
<translation id="3005723025932146533">የተቀመጠ ቅጂ አሳይ</translation>
<translation id="3008447029300691911">የ<ph name="CREDIT_CARD" /> ሲቪሲ ያስገቡᢠአንዴ ካረጋገጡ በኋላ የካርድ á‹áˆ­á‹áˆ®á‰½á‹Ž ለዚህ ጣቢያ ይጋራሉá¢</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{በተሰመሩ መሣሪያዎች ላይ ቢያንስ 1 ንጥáˆ}=1{1 ንጥሠ(እና ተጨማሪ የተሰመሩ መሣሪያዎች ላይ)}one{# ንጥሎች (እና ተጨማሪ የተሰመሩ መሣሪያዎች ላይ)}other{# ንጥሎች (እና ተጨማሪ የተሰመሩ መሣሪያዎች ላይ)}}</translation>
<translation id="3041612393474885105">የሰርቲáŠáŠ¬á‰µ መረጃ</translation>
<translation id="3063697135517575841">Chrome በዚህ ጊዜ የእርስዎን ካርድ ማረጋገጥ አáˆá‰»áˆˆáˆá¢ እባክዎ ቆይተዠእንደገና ይሞክሩá¢</translation>
+<translation id="3064966200440839136">በá‹áŒ«á‹Š ማከማቻ በኩሠለማጫወት ማንáŠá‰µ ከማያሳá‹á‰… áˆáŠá‰³ በመá‹áŒ£á‰µ ላይᢠይቀጥáˆ?</translation>
<translation id="3093245981617870298">ከመስመር á‹áŒª áŠá‹Žá‰µá¢</translation>
<translation id="3105172416063519923">የእሴት መታወቂያá¦</translation>
<translation id="3109728660330352905">ይህን ገጽ ለማየት áቃድ የለዎትáˆá¢</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />የáŒáŠ•áŠ™áŠá‰µ መመርመሪያን አሂደዠይሞክሩ<ph name="END_LINK" /></translation>
<translation id="3145945101586104090">áˆáˆ‹áˆ¹áŠ• መáŒáˆˆáŒ¥ አáˆá‰°áˆ³áŠ«áˆ</translation>
-<translation id="3149891296864842641">የመላኪያ አማራጭ</translation>
<translation id="3150653042067488994">ጊዜያዊ የአገáˆáŒ‹á‹­ ስህተት</translation>
+<translation id="3154506275960390542">ይህ ገጽ ደህንáŠá‰± አስተማማአባáˆáˆ†áŠ መንገድ ላይገባ የሚችሠቅጽ ያካትታáˆá¢ እርስዎ የሚáˆáŠ©á‰µ á‹áˆ‚ብ በሽáŒáŒáˆ­ ላይ እያለ በሌሎች ሊታይ ወይሠአገáˆáŒ‹á‹© የሚቀበለá‹áŠ• ለመለወጥ በአጥቂ ሊቀየር ይችላáˆá¢</translation>
<translation id="3157931365184549694">እáŠá‰ áˆ¨á‰ á‰µ መáˆáˆµ</translation>
<translation id="3167968892399408617">ማንáŠá‰µáŠ• በማያሳá‹á‰… ትሮች á‹áˆµáŒ¥ የሚያዩዋቸዠገጾች áˆáˆ‰áŠ•áˆ ማንáŠá‰µ የማያሳá‹á‰ ትሮችዎን ከዘጉ በኋላ በአሳሽዎ ታሪክᣠየኩኪ ማከማቻᣠወይሠየáለጋ ታሪክ á‹áˆµáŒ¥ አይቀመጡáˆá¢ ማንáŠá‰µ በማያስá‹á‰… áˆáŠá‰³ መሥራት የሌሎች ሰዎችᣠአገáˆáŒ‹á‹®á‰½á£ ሶáትዌሮች ወይሠከጀርባዎ የቆሙ የሌሎች ሰዎች ባህሪይ ላይ ለá‹áŒ¥ አያመጣáˆá¢</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -262,11 +270,13 @@
<translation id="3345135638360864351">ይህን ጣቢያ ለመድረስ ያቀረቡት ጥያቄ ወደ <ph name="NAME" /> ሊላክ አáˆá‰°á‰»áˆˆáˆá¢ እባክዎ እንደገና ይሞክሩá¢</translation>
<translation id="3355823806454867987">የተኪ ቅንብሮችን በመቀየር ላይ...</translation>
<translation id="3369192424181595722">የሰዓት ስህተት</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> ተጨማሪ ንጥሎች...</translation>
<translation id="337363190475750230">አቅርቦት ተቋርጧáˆ</translation>
<translation id="3377188786107721145">የመáˆáˆªá‹« ትንተና ስህተት</translation>
<translation id="3380365263193509176">á‹«áˆá‰³á‹ˆá‰€ ስህተት</translation>
<translation id="3380864720620200369">የደንበኛ መታወቂያá¦</translation>
<translation id="3391030046425686457">የመላኪያ አድራሻ</translation>
+<translation id="3395827396354264108">የመá‹áˆ°áŒƒ ዘዴ</translation>
<translation id="340013220407300675">ጥቃት የሚያደርሱ አካላት መረጃዎን ከ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ለመስረቅ እየሞከሩ ሊሆን ይችላሠ(ለáˆáˆ³áˆŒá£ የይለá ቃሎችንᣠመáˆá‹•áŠ­á‰¶á‰½áŠ• ወይሠክሬዲት ካርዶችን)á¢</translation>
<translation id="3422248202833853650">የማህደረ ትá‹áˆµá‰³ ቦታን ለማስለቀቅ ከሌሎች á•áˆ®áŒáˆ«áˆžá‰½ ዘáŒá‰°á‹ ለመá‹áŒ£á‰µ á‹­á‹áŒ¡á¢</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> አáˆáŠ• ላይ ሊደረስበት አይችáˆáˆá¢</translation>
@@ -277,12 +287,13 @@
<translation id="3450660100078934250">Mastercard</translation>
<translation id="3452404311384756672">የሚመጣዠበየá¦</translation>
<translation id="3462200631372590220">የላበደብቅ</translation>
+<translation id="3467763166455606212">የካርድ á‹«á‹¥ ስሠያስáˆáˆáŒ‹áˆ</translation>
+<translation id="3478058380795961209">ጊዜዠየሚያáˆáበት ወር</translation>
<translation id="3479539252931486093">ይህ á‹«áˆá‰°áŒ á‰ á‰€ áŠá‰ áˆ­? <ph name="BEGIN_LINK" />ያሳá‹á‰áŠ•<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">አáˆáŠ• አይደለáˆ</translation>
<translation id="348000606199325318">የብáˆáˆ½á‰µ መታወቂያ <ph name="CRASH_LOCAL_ID" /> (የአገáˆáŒ‹á‹­ መታወቂያᦠ<ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">በዚህ ጊዜ ላይ ወላጅህን ማáŒáŠ˜á‰µ አáˆá‰»áˆáŠ•áˆá¢ እባክህ እንደገና ሞክርá¢</translation>
<translation id="3528171143076753409">የአገáˆáŒ‹á‹­ እá‹á‰…ና ማረጋገጫ የታመአአይደለáˆá¢</translation>
-<translation id="3538531656504267329">áˆáŠ­ á‹«áˆáˆ†áŠ የአገáˆáŒáˆŽá‰µ ማብቂያ ዓመት</translation>
<translation id="3539171420378717834">የዚህን ካርድ ቅጂ በዚህ መሣሪያ ላይ አቆይ</translation>
<translation id="3542684924769048008">የይለá ቃሠይጠቀሙ ለá¦</translation>
<translation id="3549644494707163724">áˆáˆ‰áˆ የተመሳሰለ á‹áˆ‚ብ ከእራስዎ የተመሳሰለ ይለá áˆáˆ¨áŒ ጋር ያመስጥሩ</translation>
@@ -295,6 +306,7 @@
<translation id="3586931643579894722">á‹áˆ­á‹áˆ­ ደብቅ</translation>
<translation id="3587482841069643663">áˆáˆ‰áˆ</translation>
<translation id="3600246354004376029"><ph name="TITLE" />ᣠ<ph name="DOMAIN" />ᣠ<ph name="TIME" /></translation>
+<translation id="3615877443314183785">ትክክለኛ የአገáˆáŒáˆŽá‰µ ማብቂያ ቀን ያስገቡ</translation>
<translation id="36224234498066874">የአሰሳ á‹áˆ‚ብ አስወáŒá‹µâ€¦</translation>
<translation id="362276910939193118">ሙሉ ታሪክ አሳይ</translation>
<translation id="3623476034248543066">እሴት አሳይ</translation>
@@ -311,7 +323,6 @@
<translation id="3693415264595406141">የይለá ቃáˆá¦</translation>
<translation id="3696411085566228381">áˆáŠ•áˆ</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">የመላኪያ ዘዴዎችን እና መስáርቶችን ለማረጋገጥ የመላኪያ አድራሻ á‹­áˆáˆ¨áŒ¡á¢</translation>
<translation id="370665806235115550">በመጫን ላይ…</translation>
<translation id="3712624925041724820">áˆáˆ‰áˆ áቃዶች ተሞክረዋáˆ</translation>
<translation id="3714780639079136834">የሞባይሠá‹áˆ‚ብ ወይሠWi-Fi ማብራት</translation>
@@ -320,6 +331,7 @@
<translation id="3739623965217189342">እርስዎ የቀዱት አገናáŠ</translation>
<translation id="375403751935624634">በአገáˆáŒ‹á‹­ ስህተት áˆáŠ­áŠ•á‹«á‰µ የትርጉሠስራዠተሰናክáˆáˆá¢</translation>
<translation id="3759461132968374835">በቅርብ ጊዜ ሪá–ርት የተደረጉ ብáˆáˆ½á‰¶á‰½ የለዎትáˆá¢ የብáˆáˆ½á‰µ ሪá–ርት ማድረጠተሰናክሎ ሳለ የተከሰቱ ብáˆáˆ½á‰¶á‰½ እዚህ አይታዩáˆá¢</translation>
+<translation id="3787705759683870569">በ<ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /> ላይ የአገáˆáŒáˆŽá‰µ ጊዜዠያበቃáˆ</translation>
<translation id="382518646247711829">ተኪ አገáˆáŒ‹á‹­ የሚጠቀሙ ከሆኑ...</translation>
<translation id="3828924085048779000">ባዶ የይለá áˆáˆ¨áŒ አይáˆá‰€á‹µáˆá¢</translation>
<translation id="3845539888601087042">ታሪክን ወደ መለያዎ ከገቡ መሣሪያዎችዎ በማሳየት ላይᢠ<ph name="BEGIN_LINK" />የበለጠ ለመረዳት<ph name="END_LINK" /></translation>
@@ -355,7 +367,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chromium ይህን ካርድ እንዲያስቀáˆáŒ¥áˆá‹Žá‰µ á‹­áˆáˆáŒ‹áˆ‰?</translation>
<translation id="4171400957073367226">መጥᎠየማረጋገጫ áŠáˆ­áˆ›</translation>
-<translation id="4176463684765177261">ተሰናክáˆáˆ</translation>
<translation id="4196861286325780578">&amp;á‹áˆ°á‹µáŠ• ድገáˆ</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />የኬላ እና የጸረ-ቫይረስ á‹á‰…ረቶችን መáˆá‰°áˆ½<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{áˆáŠ•áˆ}=1{1 መተáŒá‰ áˆªá‹« ($1)}=2{2 መተáŒá‰ áˆªá‹«á‹Žá‰½ ($1ᣠ$2)}one{# መተáŒá‰ áˆªá‹«á‹Žá‰½ ($1ᣠ$2ᣠ$3)}other{# መተáŒá‰ áˆªá‹«á‹Žá‰½ ($1ᣠ$2ᣠ$3)}}</translation>
@@ -382,11 +393,11 @@
<translation id="4406896451731180161">የáለጋ á‹áŒ¤á‰¶á‰½</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> የመáŒá‰¢á‹« እá‹á‰…ና ማረጋገጫዎን አáˆá‰°á‰€á‰ áˆˆáˆá£ ወይሠገና አáˆá‰°áˆ°áŒ á‹Žá‰µ ይሆናáˆá¢</translation>
<translation id="443673843213245140">የተኪ መጠቀሠተሰናክáˆáˆ áŒáŠ• áŒáˆáŒ½ የሆአየተኪ á‹á‰…ር ተገáˆáŒ¿áˆá¢</translation>
-<translation id="4446242550670694251">አáˆáŠ• በáŒáˆ ማሰስ ይችላሉᣠእና ይህን መሣሪያ የሚጠቀሙ ሰዎች የእርስዎን እንቅስቃሴ አይመለከቱáˆá¢</translation>
<translation id="4492190037599258964">የáለጋ á‹áŒ¤á‰¶á‰½ ለ'<ph name="SEARCH_STRING" />'</translation>
<translation id="4506176782989081258">የማረጋገጥ ስህተትᦠ<ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">የሥርዓት አስተዳዳሪá‹áŠ• ማáŠáŒ‹áŒˆáˆ­</translation>
<translation id="450710068430902550">ከአስተዳዳሪ ጋር ማጋራት</translation>
+<translation id="4515275063822566619">ካርዶች እና አድራሻዎች ከChrome እና ከGoogle መለያዎ (<ph name="ACCOUNT_EMAIL" />) የተገኙ ናቸá‹á¢ በ<ph name="BEGIN_LINK" />ቅንብሮች<ph name="END_LINK" /> á‹áˆµáŒ¥ ሊያቀናብሯቸዠይችላሉá¢</translation>
<translation id="4522570452068850558">á‹áˆ­á‹áˆ®á‰½</translation>
<translation id="4558551763791394412">ቅጥያዎችዎን አሰናክለዠይሞክሩá¢</translation>
<translation id="457875822857220463">መላኪያ</translation>
@@ -416,6 +427,7 @@
<translation id="4816492930507672669">ገጹን አመጣጥን</translation>
<translation id="483020001682031208">áˆáŠ•áˆ የሚታዩ አካላዊ ድረ-ገጾች የሉáˆ</translation>
<translation id="4850886885716139402">አሳይ</translation>
+<translation id="4854362297993841467">የማድረሻ ዘዴዠአይገáŠáˆá¢ የተለየ ዘዴ ይሞክሩá¢</translation>
<translation id="4858792381671956233">ይህን ገጽ መጎብኘት ችáŒáˆ­ ካለዠወላጆችዎንጠይቀዋáˆ</translation>
<translation id="4880827082731008257">የáለጋ ታሪክ</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />ᣠ<ph name="TYPE_2" />á£, <ph name="TYPE_3" /></translation>
@@ -423,7 +435,6 @@
<translation id="4923417429809017348">ገጹ ከማይታወቅ ቋንቋ ወደ <ph name="LANGUAGE_LANGUAGE" /> ተተርጉሟáˆ</translation>
<translation id="4923459931733593730">ክáá‹«</translation>
<translation id="4926049483395192435">መገለጽ አለበትá¢</translation>
-<translation id="4941291666397027948">* የሚያስáˆáˆáŒ መስክ መሆኑን ያመለክታáˆ</translation>
<translation id="495170559598752135">እርáˆáŒƒá‹Žá‰½</translation>
<translation id="4958444002117714549">á‹áˆ­á‹áˆ©áŠ• ዘርጋ</translation>
<translation id="4962322354953122629">ይህ አገáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆኑን ማረጋገጥ አáˆá‰»áˆˆáˆá¤ የዕá‹á‰…ና ማረጋገጫዠበChrome የታመአአይደለáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየእርስዎን áŒáŠ•áŠ™áŠá‰µ በሚጠáˆá አጥቂ áˆáŠ­áŠ•á‹«á‰µ የተáˆáŒ áˆ¨ ሊሆን ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
@@ -438,6 +449,7 @@
<translation id="5045550434625856497">ትክክሠያáˆáˆ†áŠ የይለá ቃáˆ</translation>
<translation id="5056549851600133418">ለእርስዎ የሚሆኑ ጽሑáŽá‰½</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />የወኪሉን አድራሻ መáˆá‰°áˆ½<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{áˆáŠ•áˆ ኩኪዎች የሉáˆ}=1{1 ጣቢያ ኩኪዎችን ይጠቀማáˆá¢ }one{# ጣቢያዎች ኩኪዎችን ይጠቀማሉᢠ}other{# ጣቢያዎች ኩኪዎችን ይጠቀማሉᢠ}}</translation>
<translation id="5087286274860437796">የአገáˆáŒ‹á‹­ የዕá‹á‰…ና ማረጋገጫ በዚህ ጊዜ ላይ የሚሰራ አይደለáˆá¢</translation>
<translation id="5087580092889165836">ካርድ አክáˆ</translation>
<translation id="5089810972385038852">áŒá‹›á‰µ</translation>
@@ -460,10 +472,8 @@
<translation id="5300589172476337783">አሳይ</translation>
<translation id="5308689395849655368">የብáˆáˆ½á‰µ ሪá–ርት ማድረጠተሰናክáˆáˆá¢</translation>
<translation id="5317780077021120954">አስቀáˆáŒ¥</translation>
-<translation id="5326702247179446998">ተቀባይ ያስáˆáˆáŒ‹áˆ</translation>
<translation id="5327248766486351172">ስáˆ</translation>
<translation id="5337705430875057403">በ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ላይ ያሉ አጥቂዎች እንደ ሶáትዌር መጫን ወይሠየáŒáˆ መረጃዎን (ለáˆáˆ³áˆŒá¦ የይለá ቃሎችᣠየስáˆáŠ­ á‰áŒ¥áˆ®á‰½ ወይሠክሬዲት ካርዶች) አሳáˆáŽ መáŒáˆˆáŒ½ ያሉ አደገኛ áŠáŒˆáˆ®á‰½áŠ• እንዲያደርጉ ሊያታáˆáˆ‰á‹Žá‰µ ይችሉ ይሆናáˆá¢</translation>
-<translation id="53553865750799677">የማይደገá የመá‹áˆ°áŒƒ አድራሻᢠየተለየ አድራሻ á‹­áˆáˆ¨áŒ¡á¢</translation>
<translation id="5359637492792381994">ይህ አገáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆኑን ማረጋገጥ አáˆá‰»áˆˆáˆá¤ የዕá‹á‰…ና ማረጋገጫዠበዚህ ጊዜ ላይ የሚሠራ አይደለáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየእርስዎን áŒáŠ•áŠ™áŠá‰µ በሚጠáˆá አጥቂ áˆáŠ­áŠ•á‹«á‰µ የተáˆáŒ áˆ¨ ሊሆን ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="536296301121032821">የመáˆáˆªá‹« ቅንብሮችን ማከማቸት አáˆá‰°áˆ³áŠ«áˆ</translation>
<translation id="5386426401304769735">የዚህ ጣቢያ የዕá‹á‰…ና ማረጋገጫ ሰንሰለቱ SHA-1 በመጠቀሠየተáˆáˆ¨áˆ˜ የዕá‹á‰…ና ማረጋገጫን ያካትታáˆá¢</translation>
@@ -491,8 +501,8 @@ nil</translation>
<translation id="5544037170328430102"><ph name="SITE" /> ላይ የተካተተ ገጽ እንዲህ ይላáˆá¦</translation>
<translation id="5556459405103347317">ዳáŒáˆ ጫን</translation>
<translation id="5565735124758917034">ገባሪ</translation>
+<translation id="5571083550517324815">ከዚህ አድራሻ ላይ መá‹áˆ°á‹µ አይቻáˆáˆá¢ የተለየ አድራሻ á‹­áˆáˆ¨áŒ¡á¢</translation>
<translation id="5572851009514199876">Chrome እርስዎ ይህን ጣቢያ እንዲደርሱ የተáˆá‰€á‹°áˆá‹Ž መሆኑን ወይሠአለመሆኑን እንዲያረጋáŒáŒ¥ እባክዎ ይጀáˆáˆ©áŠ“ ወደ Chrome á‹­áŒá‰¡á¢</translation>
-<translation id="5575380383496039204">የማይደገá የመላኪያ አድራሻᢠየተለየ አድራሻ á‹­áˆáˆ¨áŒ¡á¢</translation>
<translation id="5580958916614886209">የእርስዎን የአገáˆáŒáˆŽá‰µ ማብቂያ ወር ይመáˆáŠ¨á‰± እና እንደገና ይሞክሩ</translation>
<translation id="560412284261940334">አስተዳደር አይደገááˆ</translation>
<translation id="5610142619324316209">áŒáŠ•áŠ™áŠá‰±áŠ• መáˆá‰°áˆ½</translation>
@@ -508,7 +518,8 @@ nil</translation>
<translation id="5710435578057952990">የዚህ ድረ-ገጽ ማንáŠá‰µ አáˆá‰°áˆ¨áŒ‹áŒˆáŒ áˆá¢</translation>
<translation id="5720705177508910913">የአáˆáŠ‘ ተጠቃሚ</translation>
<translation id="5732392974455271431">የእርስዎ ወላጆች እገዳá‹áŠ• ሊያáŠáˆ±áˆá‹Ž ይችላሉ</translation>
-<translation id="57586589942790530">áˆáŠ­ á‹«áˆáˆ†áŠ የካርድ á‰áŒ¥áˆ­</translation>
+<translation id="5763042198335101085">ትክክለኛ የኢሜይሠአድራሻ ያስገቡ</translation>
+<translation id="5765072501007116331">የማድረሻ ዘዴዎችን እና መስáˆáˆ­á‰¶á‰½áŠ• ለመመáˆáŠ¨á‰µ አድራሻ á‹­áˆáˆ¨áŒ¡</translation>
<translation id="5784606427469807560">የእርስዎን ካርድ ማረጋገጥ ላይ አንድ ችáŒáˆ­ áŠá‰ áˆ­á¢ የበይáŠáˆ˜áˆ¨á‰¥ áŒáŠ•áŠ™áŠá‰µá‹ŽáŠ• á‹­áˆá‰µáˆ¹á‰µ እና እንደገና ይሞክሩá¢</translation>
<translation id="5785756445106461925">በተጨማሪᣠይህ ገጽ ደህንáŠá‰³á‰¸á‹ á‹«áˆá‰°áŒ á‰ á‰€ ሌሎች ንብረቶችን አካትቷáˆá¢ እáŠá‹šáˆ… ንብረቶች በሽáŒáŒáˆ­ ወቅት በሌሎች ሊታዩ ይችላሉᣠእናሠየገጹን መáˆáŠ­ ለመለወጥ በአጥቂዎች ሊቀየሩ ይችላሉá¢</translation>
<translation id="5786044859038896871">የካርድዎን መረጃ መሙላት á‹­áˆáˆáŒ‹áˆ‰?</translation>
@@ -521,22 +532,20 @@ nil</translation>
<translation id="5869405914158311789">ይህ ጣቢያ ሊደረስበት አይችáˆáˆ</translation>
<translation id="5869522115854928033">የተቀመጡ የይለá ቃሎች</translation>
<translation id="5872918882028971132">የወላጅ አስተያየት ጥቆማዎች</translation>
-<translation id="587760065310675640">የማይደገá የመላኪያ አድራሻᢠየተለየ አድራሻ á‹­áˆáˆ¨áŒ¡á¢</translation>
<translation id="5901630391730855834">ቢጫ</translation>
-<translation id="59174027418879706">áŠá‰…ቷáˆ</translation>
<translation id="5926846154125914413">ከአንዳንድ ጣቢያዎች የመጣ የá•áˆªáˆšá‹¨áˆ ይዘት መዳረሻ ሊያጡ ይችላሉá¢</translation>
<translation id="5959728338436674663">አደገኛ መተáŒá‰ áˆªá‹«á‹Žá‰½áŠ• እና ጣቢያዎችን ማáŒáŠ˜á‰µ እንዲያáŒá‹ አንዳንድ <ph name="BEGIN_WHITEPAPER_LINK" />የሥርዓት መረጃ እና የገጽ ይዘት<ph name="END_WHITEPAPER_LINK" />ን በራስ-ሰር ወደ Google ይላኩᢠ<ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">ሳáˆáŠ•á‰µ</translation>
<translation id="5967867314010545767">ከታሪክ አስወáŒá‹µ</translation>
<translation id="5975083100439434680">አሳንስ</translation>
+<translation id="598637245381783098">የክáá‹« መተáŒá‰ áˆªá‹«áŠ• መክáˆá‰µ አይቻáˆáˆ</translation>
<translation id="5989320800837274978">ቋሚ ተኪ አገáˆáŒ‹á‹®á‰½áˆ ሆኑ የ.pac ስክሪá•á‰µ ዩአርኤሠአáˆá‰°áŒˆáˆˆáŒ¹áˆá¢</translation>
<translation id="5990559369517809815">ወደ አገáˆáŒ‹á‹© የተላኩ ጥያቄዎች በአንድ ቅጥያ ታáŒá‹°á‹‹áˆá¢</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">የካርድ እና የአድራሻ አማራጮች ከChrome የተገኙ ናቸá‹á¢ እáŠá‹šáˆ…ን በ<ph name="BEGIN_LINK" />ቅንብሮች<ph name="END_LINK" /> á‹áˆµáŒ¥ ማቀናበር ይችላሉá¢</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{ገጽ 1}one{ገጽ #}other{ገጽ #}}</translation>
<translation id="6017514345406065928">አረንጓዴ</translation>
+<translation id="6027201098523975773">ስሠያስገቡ</translation>
<translation id="6040143037577758943">á‹áŒ‹</translation>
-<translation id="604124094241169006">ራስ-ሰር</translation>
<translation id="6042308850641462728">ተጨማሪ</translation>
<translation id="6060685159320643512">ይጠንቀá‰á£ እáŠá‹šáˆ… ሙከራዎች ሊያስቸáŒáˆ© ይችላሉ</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{áˆáŠ•áˆ}=1{1}one{#}other{#}}</translation>
@@ -544,9 +553,10 @@ nil</translation>
ሞደሞችን ወይሠሌላ አá‹á‰³áˆ¨ መረብ መሣሪያዎችን ዳáŒáˆ ያስጀáˆáˆ©á¢</translation>
<translation id="614940544461990577">ይሞክሩá¦</translation>
<translation id="6151417162996330722">የአገáˆáŒ‹á‹­ እá‹á‰…ና ማረጋገጫዠበጣሠረጅሠየሆአየማረጋገጫ ጊዜ አለá‹á¢</translation>
-<translation id="615643356032862689">የወረዱ á‹á‹­áˆŽá‰½ እና á‹•áˆá‰£á‰¶á‰½ እንዳሉ ይቀመጣሉá¢</translation>
+<translation id="6157877588268064908">የመላኪያ ዘዴዎችን እና መስáˆáˆ­á‰¶á‰½áŠ• ለመመáˆáŠ¨á‰µ አድራሻ á‹­áˆáˆ¨áŒ¡</translation>
<translation id="6165508094623778733">ተጨማሪ ለመረዳት</translation>
<translation id="6177128806592000436">ወደዚህ ጣቢያ á‹«áˆá‹Žá‰µ áŒáŠ•áŠ™áŠá‰µ ደህንáŠá‰± አስተማማአአይደለáˆ</translation>
+<translation id="6184817833369986695">(የተመሳሳይ ሰዎች ስብስብᦠ<ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">የበይáŠáˆ˜áˆ¨á‰¥ áŒáŠ‘áŠáŠá‰µá‹ŽáŠ• ያረጋáŒáŒ¡</translation>
<translation id="6218753634732582820">ከChromium ላይ አድራሻ ይወገድ?</translation>
<translation id="6251924700383757765">የáŒáˆ‹á‹ŠáŠá‰µ መመሪያ</translation>
@@ -555,6 +565,8 @@ nil</translation>
<translation id="6259156558325130047">&amp;ዳáŒáˆ ደርድርን ድገáˆ</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> እáˆá‰£á‰¶á‰½</translation>
<translation id="6264485186158353794">ወደ አስተማማአተመለስ</translation>
+<translation id="6276112860590028508">ከእርስዎ የንባብ á‹áˆ­á‹áˆ­ የመጡ ገጾች እዚህ ይታያሉ</translation>
+<translation id="6280223929691119688">ወደዚህ አድራሻ ማድረስ አይቻáˆáˆá¢ የተለየ አድራሻ á‹­áˆáˆ¨áŒ¡á¢</translation>
<translation id="6282194474023008486">የá–ስታ ኮድ</translation>
<translation id="6290238015253830360">የእርስዎ የተጠቆሙ ዘገባዎች እዚህ ይመጣሉ</translation>
<translation id="6305205051461490394"><ph name="URL" /> ሊደረስበት አይችáˆáˆá¢</translation>
@@ -576,7 +588,6 @@ nil</translation>
<translation id="6417515091412812850">የእá‹á‰…ና ማረጋገጫዠተሽሮ እንደሆአማረጋገጥ አáˆá‰°á‰»áˆˆáˆá¢</translation>
<translation id="6433490469411711332">የዕá‹á‰‚á‹« መረጃን ያርትዑ</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> ማገናኘት አሻáˆáˆ¨áŠ ብáˆáˆá¢</translation>
-<translation id="6443118737398455446">áˆáŠ­ á‹«áˆáˆ†áŠ የአገáˆáŒáˆŽá‰µ ማብቂያ ቀን</translation>
<translation id="6446608382365791566">ተጨማሪ መረጃ ያክሉ</translation>
<translation id="6451458296329894277">እንደገና ለማስገባት የማረጋገጫ ቅጽ</translation>
<translation id="6456339708790392414">የእርስዎ ክáá‹«</translation>
@@ -584,10 +595,8 @@ nil</translation>
<translation id="6462969404041126431">ይህ አገáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆኑን ማረጋገጥ አáˆá‰»áˆˆáˆá¤ የደህንáŠá‰µ á‹•á‹á‰…ና ማረጋገጫዠተሽሮ ሊሆን ይችላáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየእርስዎን áŒáŠ•áŠ™áŠá‰µ በሚጠáˆá አጥቂ áˆáŠ­áŠ•á‹«á‰µ የተáˆáŒ áˆ¨ ሊሆን ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="647261751007945333">የመሣሪያ መáˆáˆªá‹«á‹Žá‰½</translation>
<translation id="6477321094435799029">Chrome በዚህ ገጽ ላይ á‹«áˆá‰°áˆˆáˆ˜á‹° ኮድ አáŒáŠá‰·áˆá£ እና የእርስዎን የáŒáˆ መረጃ (ለáˆáˆ³áˆŒá¦ የይለá ቃላትᣠስáˆáŠ­ á‰áŒ¥áˆ®á‰½ እና ክሬዲት ካርዶች) ለመጠበቅ ሲባሠአáŒá‹¶á‰³áˆá¢</translation>
-<translation id="6477460825583319731">áˆáŠ­ á‹«áˆáˆ†áŠ የኢሜይሠአድራሻ</translation>
<translation id="6489534406876378309">ድáˆáˆµáˆ¶á‰½áŠ• መስቀሠጀáˆáˆ­</translation>
<translation id="6508722015517270189">Chromeን ዳáŒáˆ ያስጀáˆáˆ©á‰µ</translation>
-<translation id="6525462735697194615">áˆáŠ­ á‹«áˆáˆ†áŠ የአገáˆáŒáˆŽá‰µ ማብቂያ ወር</translation>
<translation id="6529602333819889595">&amp;ሰርá‹áŠ• ድገáˆ</translation>
<translation id="6534179046333460208">የአካላዊ ድር ጥቆማዎች</translation>
<translation id="6550675742724504774">አማራጮች</translation>
@@ -602,7 +611,6 @@ nil</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> áለጋ</translation>
<translation id="6644283850729428850">ይህ መመሪያ ተቋርጧáˆá¢</translation>
<translation id="6652240803263749613">ይህ አገáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆኑን ማረጋገጥ አáˆá‰»áˆˆáˆá¤ የደህንáŠá‰µ á‹•á‹á‰…ና ማረጋገጫዠበእርስዎ ኮáˆá’á‹á‰°áˆ­ ሥርዓተ ክá‹áŠ“ የታመአአይደለáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየእርስዎን áŒáŠ•áŠ™áŠá‰µ በሚጠáˆá አጥቂ áˆáŠ­áŠ•á‹«á‰µ የተáˆáŒ áˆ¨ ሊሆን ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
-<translation id="6665267558048410100">ይህ የመላኪያ አማራጭ አይገáŠáˆá¢ የተለየ አማራጭ ይሞክሩá¢</translation>
<translation id="6671697161687535275">የአስተያየት ጥቆማ ከChromium ይወገድ?</translation>
<translation id="6685834062052613830">ዘáŒá‰°á‹ á‹­á‹áŒ¡ እና ቅንብርን ያጠናቅá‰</translation>
<translation id="6710213216561001401">ቀዳሚ</translation>
@@ -610,13 +618,13 @@ nil</translation>
<translation id="6711464428925977395">በተኪ አገáˆáŒ‹á‹© ላይ የሆአችáŒáˆ­ አለ ወይሠአድራሻዠትክክሠአይደለáˆá¢</translation>
<translation id="6727102863431372879">አዘጋጅ</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{áˆáŠ•áˆ}=1{1 ንጥáˆ}one{# ንጥሎች}other{# ንጥሎች}}</translation>
-<translation id="6743044928064272573">የመá‹áˆ°áŒƒ አማራጭ</translation>
<translation id="674375294223700098">á‹«áˆá‰³á‹ˆá‰€ የአገáˆáŒ‹á‹­ እá‹á‰…ና ማረጋገጫ ስህተትá¢</translation>
<translation id="6753269504797312559">የመáˆáˆªá‹« እሴት</translation>
<translation id="6757797048963528358">የእርስዎ መሣሪያ ተáŠá‰·áˆá¢</translation>
<translation id="6778737459546443941">የእርስዎ ወላጅ ገና አላጸደá‰á‰µáˆ</translation>
<translation id="6810899417690483278">የብáŒáŠá‰µ መታወቂያ</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">የክáˆáˆŽá‰½ á‹áˆ‚ብን መጫን አáˆá‰°áˆ³áŠ«áˆ</translation>
<translation id="6831043979455480757">መተርጎáˆ</translation>
<translation id="6839929833149231406">አካባቢ</translation>
<translation id="6874604403660855544">&amp;አክáˆáŠ• ድገáˆ</translation>
@@ -624,6 +632,7 @@ nil</translation>
<translation id="6895330447102777224">የእርስዎ ካርድ ተረጋáŒáŒ§áˆ</translation>
<translation id="6897140037006041989">የተጠቀሚ ተወካይ</translation>
<translation id="6915804003454593391">ተጠቃሚá¦</translation>
+<translation id="6948701128805548767">የመá‹áˆ°áŒƒ ዘዴዎችን እና መስáˆáˆ­á‰¶á‰½áŠ• ለመመáˆáŠ¨á‰µ አድራሻ á‹­áˆáˆ¨áŒ¡</translation>
<translation id="6957887021205513506">የአገáˆáŒ‹á‹© እá‹á‰…ና ማረጋገጫ የተጭበረበረ ይመስላáˆá¢</translation>
<translation id="6965382102122355670">እሺ</translation>
<translation id="6965978654500191972">መሣሪያ</translation>
@@ -631,7 +640,6 @@ nil</translation>
<translation id="6973656660372572881">áˆáˆˆá‰±áˆ ቋሚ ተኪ አገáˆáŒ‹á‹®á‰½ እና የ.pac ስክሪá•á‰µ ዩአርኤሠተገáˆáŒ¸á‹‹áˆá¢</translation>
<translation id="6989763994942163495">የላበቅንብሮችን አሳይ...</translation>
<translation id="7000990526846637657">áˆáŠ•áˆ የታሪክ áŒá‰¤á‰¶á‰½ አáˆá‰°áŒˆáŠ™áˆ</translation>
-<translation id="7001663382399377034">ተቀባይ አክáˆ</translation>
<translation id="7009986207543992532">ወደ <ph name="DOMAIN" /> ለመድረስ ሞክረዋáˆá£ áŠáŒˆáˆ­ áŒáŠ• አገáˆáŒ‹á‹© የሚሠራበት ክáለ ጊዜ የታመአእንዳይሆን ከáˆáŠ­ በላይ ረዥሠጊዜ የሆአየዕá‹á‰…ና ማረጋገጫን አቅርቧáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">የእርስዎ Google መለያ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ላይ ሌሎች የአሰሳ ታሪክ á‹“á‹­áŠá‰¶á‰½ ሊኖረዠይችላáˆ</translation>
@@ -642,12 +650,15 @@ nil</translation>
<translation id="7088615885725309056">የቆየ</translation>
<translation id="7090678807593890770"><ph name="LINK" />ን በGoogle ላይ á‹­áˆáˆáŒ‰</translation>
<translation id="7119414471315195487">ሌሎች ትሮችን ወይሠá•áˆ®áŒáˆ«áˆžá‰½áŠ• á‹­á‹áŒ‰</translation>
+<translation id="7129409597930077180">ወደዚህ አድራሻ መላክ አይቻáˆáˆá¢ የተለየ አድራሻ á‹­áˆáˆ¨áŒ¡á¢</translation>
+<translation id="7138472120740807366">የማድረሻ ስáˆá‰µ</translation>
<translation id="7139724024395191329">ኤሚሬት</translation>
<translation id="7155487117670177674">ክáá‹« ደህንáŠá‰± የተጠበቀ አይደለáˆ</translation>
<translation id="7179921470347911571">አáˆáŠ• ዳáŒáˆ ያስጀáˆáˆ©</translation>
<translation id="7180611975245234373">አድስ</translation>
<translation id="7182878459783632708">áˆáŠ•áˆ መáˆáˆªá‹«á‹Žá‰½ አáˆá‰°á‹‹á‰€áˆ©áˆ</translation>
<translation id="7186367841673660872">ይህ ገጽ ከ<ph name="ORIGINAL_LANGUAGE" />ወደ<ph name="LANGUAGE_LANGUAGE" />ተተርጉሟáˆ</translation>
+<translation id="7192203810768312527">እስከ <ph name="SIZE" /> ያስለቅቃáˆá¢ አንዳንድ ጣቢያዎች በሚቀጥለዠጉብáŠá‰µá‹Ž ላይ ይበáˆáŒ¥ በá‹áŒá‰³ ሊጫኑ ይችላሉá¢</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> የደህንáŠá‰µ መስáˆáˆ­á‰¶á‰½áŠ• አያከብርáˆá¢</translation>
<translation id="721197778055552897">ስለዚህ ችáŒáˆ­ <ph name="BEGIN_LINK" />ተጨማሪ ለመረዳት<ph name="END_LINK" /> á¢</translation>
@@ -676,7 +687,6 @@ nil</translation>
<translation id="7424977062513257142">በዚህ ድረ-ገጽ ላይ ያለ የተካተተ ገጽ እንዲህ ይላáˆá¦</translation>
<translation id="7441627299479586546">የተሳሳተ የመáˆáˆªá‹« ርዕሰ ጉዳይ</translation>
<translation id="7444046173054089907">ይህ ጣቢያ ታáŒá‹·áˆ</translation>
-<translation id="7444238235002594607">የመá‹áˆ°áŒƒ ስáˆá‰¶á‰½áŠ• እና መስáˆáˆ­á‰¶á‰½áŠ• ለመáˆá‰°áˆ½ የመá‹áˆ°áŒƒ አድራሻ á‹­áˆáˆ¨áŒ¡á¢</translation>
<translation id="7445762425076701745">የተገናኙት የአገáˆáŒ‹á‹­ ማንáŠá‰µ ሙሉ ለሙሉ ሊረጋገጥ አáˆá‰»áˆˆáˆá¢ ስሙ በአá‹á‰³áˆ¨ መረብዎ á‹áˆµáŒ¥ ብቻ áˆáŠ­ ከሆአአገáˆáŒ‹á‹­ ጋር áŠá‹ የተገናኙትᣠእና ባለቤትáŠá‰± በá‹áŒ«á‹Š የእá‹á‰…ና ማረጋገጫ ሊረጋገጥ አይችáˆáˆá¢ አንዳንድ የእá‹á‰…ና ማረጋገጫ ባለስáˆáŒ£áŠ“ት á‹­áˆáŠ• ብለዠለእáŠá‹šáˆ… ስሞች የእá‹á‰…ና ማረጋገጫዎች መስጠታቸዠየማይቀር እንደመሆኑ መጠንᣠከአጥቂ ሳይሆን ከታሰበዠድር ጣቢያ ጋር መገናኘትዎን የሚረጋገጥበት áˆáŠ•áˆ መንገድ የለáˆá¢</translation>
<translation id="7451311239929941790">ስለዚህ ችáŒáˆ­ <ph name="BEGIN_LINK" />ይበáˆáŒ¥ በመረዳት ላይ<ph name="END_LINK" />á¢</translation>
<translation id="7460163899615895653">ከሌሎች መሣሪያዎች የመጡ የቅርብ ጊዜ ትሮችዎ እዚህ ይመጣሉ</translation>
@@ -720,6 +730,7 @@ nil</translation>
<translation id="7755287808199759310">የእርስዎ ወላጅ እገዳá‹áŠ• ሊያáŠáˆ±áˆá‹Ž ይችላሉ</translation>
<translation id="7758069387465995638">የኬላ ወይሠየá€áˆ¨-ቫይረስ ሶáትዌር áŒáŠ•áŠ™áŠá‰±áŠ• አáŒá‹¶á‰µ ሊሆን ይችላáˆá¢</translation>
<translation id="7761701407923456692">የአገáˆáŒ‹á‹­ እá‹á‰…ና ማረጋገጫ ከዩ አር ኤሉ ጋር አይዛመድáˆá¢</translation>
+<translation id="7763386264682878361">የክáá‹« á‹áˆ­á‹áˆ­ ሰáŠá‹µ ተንታáŠ</translation>
<translation id="7764225426217299476">አድራሻ አክáˆ</translation>
<translation id="777702478322588152">የá•áˆªáŒáŠ­á‰µ ስáˆáŒ£áŠ•</translation>
<translation id="7791543448312431591">አክáˆ</translation>
@@ -733,6 +744,7 @@ nil</translation>
<translation id="785549533363645510">ሆኖሠáŒáŠ• የማይታዩ አይደሉáˆá¢ ማንáŠá‰µ የማያሳá‹á‰… áˆáŠá‰³ መጠቀሠየእርስዎን አሰሳᣠየበይáŠáˆ˜áˆ¨á‰¥ አገáˆáŒáˆŽá‰µ አቅራቢ ወይሠየሚጎበኟቸዠድር ጣቢያዎች ከአሰሪዎ አይደብቃቸá‹áˆá¢</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">የእርስዎን CVC á‹­áˆá‰µáˆ¹ እና እንደገና ይሞክሩ</translation>
+<translation id="79338296614623784">የሚሰራ ስáˆáŠ­ á‰áŒ¥áˆ­ ያስገቡ</translation>
<translation id="7935318582918952113">የDOM ማጣሪያ</translation>
<translation id="7938958445268990899">የአገáˆáŒ‹á‹­ እá‹á‰…ና ማረጋገጫ ገና አáˆáŒ¸áŠ“áˆá¢</translation>
<translation id="7942349550061667556">ቀይ</translation>
@@ -752,6 +764,7 @@ nil</translation>
<translation id="8088680233425245692">ጽሑá‰áŠ• ማየት አáˆá‰°á‰»áˆˆáˆá¢</translation>
<translation id="8089520772729574115">ከ1 ሜባ á‹«áŠáˆ°</translation>
<translation id="8091372947890762290">ማáŒá‰ áˆ­ በአገáˆáŒ‹á‹© ላይ በመጠባበቅ ላይ áŠá‹</translation>
+<translation id="8118489163946903409">የመክáˆá‹« ዘዴ</translation>
<translation id="8131740175452115882">አረጋáŒáŒ¥</translation>
<translation id="8134994873729925007">የ<ph name="HOST_NAME" /> አገáˆáŒ‹á‹­ <ph name="BEGIN_ABBR" />ዲኤንኤስ አድራሻ<ph name="END_ABBR" /> ሊገአአáˆá‰°á‰»áˆˆáˆá¢</translation>
<translation id="8149426793427495338">የእርስዎ ኮáˆá’á‹á‰° ተáŠá‰·áˆá¢</translation>
@@ -777,6 +790,7 @@ nil</translation>
<translation id="8349305172487531364">የዕáˆá‰£á‰¶á‰½ አሞሌ</translation>
<translation id="8363502534493474904">የአá‹áˆ®á•áˆ‹áŠ• áˆáŠá‰³áŠ• ማጥá‹á‰µ</translation>
<translation id="8364627913115013041">አáˆá‰°á‹‹á‰€áˆ¨áˆá¢</translation>
+<translation id="8368476060205742148">Google Play አገáˆáŒáˆŽá‰¶á‰½</translation>
<translation id="8380941800586852976">አደገኛ</translation>
<translation id="8382348898565613901">በቅርቡ የጎበኟቸዠዕáˆá‰£á‰¶á‰½ እዚህ ይመጣሉ</translation>
<translation id="8398259832188219207">የብáˆáˆ½á‰µ ሪá–ርት <ph name="UPLOAD_TIME" /> ላይ ተሰቅáˆáˆ</translation>
@@ -785,32 +799,30 @@ nil</translation>
<translation id="8428213095426709021">ቅንብሮች</translation>
<translation id="8433057134996913067">ይህ ከአብዛኛዎቹ የድር ጣቢያዎች ዘáŒá‰¶ ያስወጣዎታáˆá¢</translation>
<translation id="8437238597147034694">&amp;á‹áˆ°á‹µáŠ• ቀáˆá‰¥áˆµ</translation>
-<translation id="8456681095658380701">áˆáŠ­ á‹«áˆáˆ†áŠ ስáˆ</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 ክሬዲት ካርድ}one{# ክሬዲት ካርዶች}other{# ክሬዲት ካርዶች}}</translation>
<translation id="8483780878231876732">ከእርስዎ የGoogle መለያ ካርዶችን ለመጠቀሠወደ Chrome በመለያ á‹­áŒá‰¡</translation>
<translation id="8488350697529856933">የሚመለከተዠለ</translation>
-<translation id="8492969205326575646">የማይደገá የካርድ á‹“á‹­áŠá‰µ</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> áˆáˆ‹áˆ½ ለመስጠት ከáˆáŠ­ በላይ ረዥሠጊዜ ወስዷáˆá¢</translation>
<translation id="852346902619691059">ይህ አገáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆኑን ማረጋገጥ አáˆá‰»áˆˆáˆá¤ የዕá‹á‰…ና ማረጋገጫዠበእርስዎ መሣሪያ ሥርዓተ ክወና የታመአአይደለáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየእርስዎን áŒáŠ•áŠ™áŠá‰µ በሚጠáˆá አጥቂ áˆáŠ­áŠ•á‹«á‰µ የተáˆáŒ áˆ¨ ሊሆን ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
+<translation id="8532105204136943229">ጊዜዠየሚያáˆáበት ዓመት</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />የáˆáˆáŒŽ ማáŒáŠ˜á‰µ ችáŒáˆ­áŠ• ሪá–ርት ማድረáŒ<ph name="END_ERROR_LINK" />ᣠወይሠደáŒáˆž በእርስዎ ደህንáŠá‰µ ላይ ሊያስከትሠየሚችለá‹áŠ• አደጋ ከተረዱ <ph name="BEGIN_LINK" />ይህን ደህንáŠá‰± á‹«áˆá‰°áŒ á‰ á‰€ ጣቢያ መጎብኘት<ph name="END_LINK" /> ይችላሉá¢</translation>
<translation id="8553075262323480129">የገጹ ቋንቋ ሊታወቅ ስላáˆá‰»áˆˆ ትርጉሙ አáˆá‰°áˆ³áŠ«áˆá¢</translation>
<translation id="8559762987265718583">የእርስዎ መሣሪያ ቀን (<ph name="DATE_AND_TIME" />) áˆáŠ­ ስላáˆáˆ†áŠ ወደ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> የáŒáˆ áŒáŠ•áŠ™áŠá‰µ መመስረት አይቻáˆáˆá¢</translation>
-<translation id="8570229484593575558">ይህ መረጃ |አይቀመጥáˆ|á¦#የእርስዎ የአሰሳ ታሪክ#የእርስዎ áለጋዎች#የኩኪ á‹áˆ‚ብ</translation>
<translation id="8571890674111243710">ገጽ ወደ <ph name="LANGUAGE" /> በመተርጎሠላይ...</translation>
-<translation id="8584539743998202583">የእርስዎ እንቅስቃሴ ለሚከተሉት |አáˆáŠ•áˆ የሚታዩ ሊሆኑ ይችላሉ|á¦#እርስዎ የሚጎበኟቸዠጣቢያዎች#የእርስዎ አሠሪ#የእርስዎ የበይáŠáˆ˜áˆ¨á‰¥ አቅራቢ</translation>
<translation id="858637041960032120">ስáˆáŠ­ á‰áŒ¥áˆ­ ያክሉ
</translation>
<translation id="859285277496340001">የእá‹á‰…ና ማረጋገጫዠተሽሮ እንደሆአየሚታይበት áˆáŠ•áˆ ስáˆá‰µ አይገáˆáŒ½áˆá¢</translation>
<translation id="8620436878122366504">የእርስዎ ወላጆች ገና አላጸደá‰á‰µáˆ</translation>
<translation id="8647750283161643317">áˆáˆ‰áŠ•áˆ ወደ áŠá‰£áˆª ዳáŒáˆ አስጀáˆáˆ­</translation>
<translation id="8703575177326907206">ከ<ph name="DOMAIN" /> ጋር ያለዎት áŒáŠ•áŠ™áŠá‰µ አáˆá‰°áˆ˜áˆ°áŒ áˆ¨áˆ</translation>
+<translation id="8718314106902482036">ክáá‹« አáˆá‰°áŒ áŠ“ቀቀáˆ</translation>
<translation id="8725066075913043281">እንደገና ይሞክሩ</translation>
<translation id="8728672262656704056">ማንáŠá‰µ የማያሳá‹á‰… áˆáŠá‰³ á‹áˆµáŒ¥ ገብተዋáˆ</translation>
<translation id="8730621377337864115">ተከናá‹áŠ—áˆ</translation>
<translation id="8738058698779197622">ደህንáŠá‰± የተጠበቀ áŒáŠ•áŠ™áŠá‰µ ለመመስረትᣠየእርስዎ ሰዓት በትክክሠመቀናበር ያስáˆáˆáŒˆá‹‹áˆá¢ ይህን የሆáŠá‰ á‰µ áˆáŠ­áŠ•á‹«á‰µ የድር ጣቢያዎች ራሳቸá‹áŠ• ለማሳወቅ የሚጠቀሙባቸዠየáˆáˆµáŠ­áˆ­ ወረቀቶች የሚሰሩት ለተወሰኑ ክáለ ጊዜያቶች ብቻ ስለሆአáŠá‹á¢ የእርስዎ መሣሪያ ሰዓት áˆáŠ­ እንዳለመሆኑ መጠን Chromium እáŠá‹šáˆ…ን áˆáˆµáŠ­áˆ­ ወረቀቶች ሊያረጋáŒáŒ£á‰¸á‹ አይችáˆáˆá¢</translation>
<translation id="8740359287975076522">የ<ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;የዲኤንኤስ አድራሻ&lt;/abbr&gt; ሊገአአáˆá‰°á‰»áˆˆáˆá¢ ችáŒáˆ©áŠ• በመመርመር ላይá¢</translation>
+<translation id="8759274551635299824">ይህ ካርድ የአገáˆáŒáˆŽá‰µ ጊዜዠአብቅቷáˆ</translation>
<translation id="8790007591277257123">&amp;ሰርá‹áŠ• ድገáˆ</translation>
-<translation id="8798099450830957504">እንደወረደ</translation>
<translation id="8800988563907321413">በአቅራቢያዎ ያሉ የአስተያየት ጥቆማዎች እዚህ ይመጣሉ</translation>
<translation id="8820817407110198400">á‹•áˆá‰£á‰¶á‰½</translation>
<translation id="883848425547221593">ሌላ እáˆá‰£á‰¶á‰½</translation>
@@ -820,6 +832,7 @@ nil</translation>
<translation id="8866481888320382733">የመáˆáˆªá‹« ቅንብሮችን መተንተን ላይ ስህተት</translation>
<translation id="8866959479196209191">ይህ ገጽ እንዲህ ይላáˆá¦</translation>
<translation id="8870413625673593573">በቅርብ ጊዜ የተዘጉ</translation>
+<translation id="8874824191258364635">የሚሰራ የካርድ á‰áŒ¥áˆ­ ያስገቡ</translation>
<translation id="8876793034577346603">የአá‹á‰³áˆ¨ መረብ á‹á‰…ር ሊተáŠá‰°áŠ• አáˆá‰»áˆˆáˆá¢</translation>
<translation id="8877192140621905067">አንዴ ካረጋገጡ በኋላ የካርድ á‹áˆ­á‹áˆ®á‰½á‹Ž ለዚህ ጣቢያ ይጋራሉ</translation>
<translation id="8889402386540077796">ለይ ቀለáˆ</translation>
@@ -829,7 +842,6 @@ nil</translation>
<translation id="8931333241327730545">ይህን ካርድ በእርስዎ የGoogle መለያ ላይ ማስቀመጥ á‹­áˆáˆáŒ‹áˆ‰?</translation>
<translation id="8932102934695377596">የእርስዎ ሰዓት ወደ ኋላ ቀርቷáˆ</translation>
<translation id="8954894007019320973">(ቀጣይ)</translation>
-<translation id="895548565263634352">ከ<ph name="ARTICLE_PUBLISHER" /> እና <ph name="OTHER_ARTICLE_COUNT" /> ተጨማሪ የመጡ ዘገባዎችን ያንብቡ</translation>
<translation id="8971063699422889582">የአገáˆáŒ‹á‹­ እá‹á‰…ና ማረጋገጫ ጊዜዠአáˆáŽá‰ á‰³áˆá¢</translation>
<translation id="8986494364107987395">የአጠቃቀሠስታስቲክስ እና የብáˆáˆ½á‰µ ሪá–ርቶች በራስ ሰር ወደ Google ይላኩá¢</translation>
<translation id="8987927404178983737">ወር</translation>
@@ -847,7 +859,6 @@ nil</translation>
<translation id="9068849894565669697">ቀለሠይáˆáˆ¨áŒ¡</translation>
<translation id="9076283476770535406">ለአዋቂ ብቻ የሚሆን ይዘት ሊኖረዠይችላáˆ</translation>
<translation id="9078964945751709336">ተጨማሪ መረጃ ያስáˆáˆáŒ‹áˆ</translation>
-<translation id="9094175695478007090">የክáá‹« መተáŒá‰ áˆªá‹«á‹áŠ• ማስጀመር አáˆá‰°á‰»áˆˆáˆá¢</translation>
<translation id="9103872766612412690"><ph name="SITE" /> የእርስዎን መረጃ ለመጠበቅ በመደበáŠáŠá‰µ áˆáˆµáŒ áˆ«áŠ• ይጠቀማáˆá¢ Chromium አáˆáŠ• ከ<ph name="SITE" /> ጋር ለመገናኘት ሲሞክር ድር ጣቢያዠያáˆá‰°áˆˆáˆ˜á‹± እና ትክክሠያáˆáˆ†áŠ‘ áˆáˆµáŠ­áˆ­áŠá‰¶á‰½áŠ• መáˆáˆ·áˆá¢ ይህ አንድ አጥቂ <ph name="SITE" />ን አስመስሎ ለመቅረብ ሲሞክር áŠá‹ ወይሠአንድ የWi-Fi መáŒá‰¢á‹« ገጽ áŒáŠ•áŠ™áŠá‰±áŠ• ሲቋረጥ ሊከሰት ይችላáˆá¢ Chromium ማንኛá‹áˆ የá‹áˆ‚ብ áˆá‹á‹áŒ¥ ከመካሄዱ በáŠá‰µ áŒáŠ•áŠ™áŠá‰±áŠ• ስላቋረጠዠአáˆáŠ•áˆ የእርስዎ መረጃ ደህንáŠá‰µ የተጠበቀ áŠá‹á¢</translation>
<translation id="9137013805542155359">የመጀመሪያá‹áŠ• አሳይ</translation>
<translation id="9137248913990643158">ይህን መተáŒá‰ áˆªá‹« ከመጠቀáˆá‹Ž በáŠá‰µ እባክዎ ይጀáˆáˆ©áŠ“ ወደ Chrome á‹­áŒá‰¡á¢</translation>
diff --git a/chromium/components/strings/components_strings_ar.xtb b/chromium/components/strings/components_strings_ar.xtb
index 8e44a9db7da..88c9218ff6e 100644
--- a/chromium/components/strings/components_strings_ar.xtb
+++ b/chromium/components/strings/components_strings_ar.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="ar">
<translation id="1008557486741366299">ليس الآن</translation>
<translation id="1015730422737071372">تقديم تÙاصيل إضاÙية</translation>
+<translation id="1021110881106174305">البطاقات المقبولة</translation>
<translation id="1032854598605920125">تدوير ÙÙŠ اتجاه عقارب الساعة</translation>
<translation id="1038842779957582377">اسم غير معروÙ</translation>
<translation id="1050038467049342496">إغلاق التطبيقات الأخرى</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">إخÙاء القيمة</translation>
<translation id="1228893227497259893">معر٠الكيان خاطئ</translation>
<translation id="1232569758102978740">بلا عنوان</translation>
+<translation id="1263231323834454256">قائمة القراءة</translation>
<translation id="1264126396475825575">تقرير الأعطال الذي تم الحصول عليه ÙÙŠ <ph name="CRASH_TIME" /> (لم يتم تحميله بعد أو تجاهله)</translation>
<translation id="1285320974508926690">عدم ترجمة هذا الموقع مطلقًا</translation>
<translation id="129553762522093515">المغلقة حديثًا</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">â€Ø¥Ø¹Ø¯Ø§Ø¯Ø§Øª الملء التلقائي ÙÙŠ Chromium...</translation>
<translation id="1374468813861204354">اقتراحات</translation>
<translation id="1375198122581997741">معلومات عن الإصدار</translation>
+<translation id="1377321085342047638">رقم البطاقة</translation>
<translation id="139305205187523129">لم يرسل <ph name="HOST_NAME" /> أي بيانات.</translation>
<translation id="1407135791313364759">Ùتح الكل</translation>
<translation id="1413809658975081374">خطأ ÙÙŠ الخصوصية</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">السجل</translation>
<translation id="1645368109819982629">بروتوكول غير معتمد</translation>
<translation id="1656489000284462475">الاستلام</translation>
+<translation id="1663943134801823270">â€ØªØ£ØªÙŠ البطاقات والعناوين من Chrome. ويمكنك إدارتها ÙÙŠ <ph name="BEGIN_LINK" />الإعدادات<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">â€ÙŠØ³ØªØ®Ø¯Ù… <ph name="SITE" /> التشÙير عادة لحماية معلوماتك. عندما حاول Google Chrome الاتصال بموقع <ph name="SITE" /> هذه المرة، أرجَع موقع الويب بيانات اعتماد غير عادية وغير صحيحة. وقد يحدث هذا عندما يحاول أحد المهاجمين التظاهر بأنه موقع <ph name="SITE" />ØŒ أو إذا قاطعت شاشة تسجيل دخول Wi-Fi الاتصال. ولكن لا تزال معلوماتك آمنة نظرًا لأن Google Chrome أوقَ٠الاتصال قبل تبادل أي بيانات.</translation>
<translation id="168328519870909584">قد يحاول المهاجمون الموجودون حاليًا على <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> تثبيت تطبيقات خطيرة على جهازك والتي تسرق معلوماتك أو تحذÙها (على سبيل المثال، الصور وكلمات المرور والرسائل وبطاقات الائتمان).</translation>
<translation id="168841957122794586">تحتوي شهادة الخادم على Ù…Ùتاح تشÙير ضعيÙ.</translation>
<translation id="1710259589646384581">نظام التشغيل</translation>
<translation id="1721312023322545264">أنت بحاجة لإذن من <ph name="NAME" /> لزيارة هذا الموقع</translation>
+<translation id="1721424275792716183">* هناك حقل مطلوب</translation>
<translation id="1728677426644403582">أنت تعرض مصدر صÙحة ويب</translation>
+<translation id="173080396488393970">لا يتم دعم هذا النوع من البطاقات</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">جرّب الاتصال بمشر٠النظام.</translation>
+<translation id="1740951997222943430">أدخÙÙ„ شهر انتهاء صلاحية صحيح</translation>
<translation id="1745358365027406341">تنزيل الصÙحة لاحقًا</translation>
<translation id="17513872634828108">علامات التبويب المÙتوحة</translation>
<translation id="1753706481035618306">رقم الصÙحة</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">الرجاء تحديث عبارة مرور المزامنة.</translation>
<translation id="1787142507584202372">تظهر علامات التبويب المÙتوحة هنا</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">حدد عنوان التسليم للتحقق من متطلبات وطرق التسليم.</translation>
+<translation id="1803264062614276815">اسم حامل البطاقة</translation>
<translation id="1803678881841855883">â€Ø§ÙƒØªØ´Ù التصÙØ­ الآمن من Google‬ مؤخرًا <ph name="BEGIN_LINK" />برامج ضارة<ph name="END_LINK" /> على <ph name="SITE" />. أحيانًا تÙصاب مواقع الويب الآمنة ÙÙŠ الوضع العادي ببرامج ضارة. ويÙعد مصدر محتوى البرامج الضارة هو <ph name="SUBRESOURCE_HOST" />ØŒ وهو موزع معرو٠للبرامج الضارة. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">تمت الإضاÙØ© ÙÙŠ <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">طلب غير صالح، أو معلمات طلب غير صالحة</translation>
<translation id="1826516787628120939">حساب شيكات</translation>
<translation id="1834321415901700177">يحتوي هذا الموقع على برامج ضارة</translation>
<translation id="1842969606798536927">الدÙع</translation>
-<translation id="1864455488461349376">خيار التسليم</translation>
<translation id="1871208020102129563">â€ØªÙ… تعيين الخادم الوكيل لاستخدام الخوادم الوكيلة الثابتة وليس عنوان URL لنص برمجي pac.</translation>
<translation id="1871284979644508959">حقل مطلوب</translation>
<translation id="187918866476621466">Ùتح صÙحات بدء التشغيل</translation>
<translation id="1883255238294161206">تصغير القائمة</translation>
<translation id="1898423065542865115">التصÙية</translation>
<translation id="194030505837763158">الانتقال إلى <ph name="LINK" /></translation>
-<translation id="1946821392246652573">البطاقات المقبولة</translation>
<translation id="1962204205936693436">إشارات <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">خطأ أثناء التسلسل</translation>
<translation id="1974060860693918893">إعدادات متقدمة</translation>
<translation id="1978555033938440688">إصدار البرامج الثابتة</translation>
+<translation id="1995859865337580572">â€ÙŠÙرجى التحقق من رمز التحقق من البطاقة (CVC)</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{وتطبيق آخر}zero{و# تطبيق آخر}two{وتطبيقان (#) آخران}few{و# تطبيقات أخرى}many{و# تطبيقًا آخر}other{و# تطبيق آخر}}</translation>
-<translation id="2020194265157481222">الاسم الوارد ÙÙŠ البطاقة مطلوب</translation>
<translation id="2025186561304664664">تم تعيين الخادم الوكيل على التهيئة التلقائية.</translation>
<translation id="2030481566774242610">هل تقصد <ph name="LINK" />؟</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />التحقق من الخادم الوكيل والجدار الناري<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">اليوم</translation>
<translation id="2154054054215849342">المزامنة غير متاحة لنطاقك</translation>
<translation id="2154484045852737596">تعديل البطاقة</translation>
-<translation id="2156993118928861787">العنوان غير صالح</translation>
<translation id="2166049586286450108">الوصول الكامل للمشرÙ</translation>
<translation id="2166378884831602661">لا يمكن لموقع الويب هذا توÙير اتصال آمن</translation>
<translation id="2181821976797666341">السياسات</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{عنوان واحد}zero{# عنوان}two{عنوانان (#)}few{# عناوين}many{# عنوانًا}other{# عنوان}}</translation>
+<translation id="2202020181578195191">أدخÙÙ„ سنة تاريخ انتهاء صلاحية صحيحة</translation>
<translation id="2212735316055980242">تعذر العثور على السياسة</translation>
<translation id="2213606439339815911">جار٠جلب الإدخالات...</translation>
<translation id="2230458221926704099">إصلاح الاتصال باستخدام <ph name="BEGIN_LINK" />تطبيق بيانات التشخيص<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">تم حظر دخولك إلى الإنترنت</translation>
<translation id="230155334948463882">بطاقة جديدة؟</translation>
<translation id="2305919008529760154">هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› قد يكون تم إصدار شهادة أمانه عن طريق الاحتيال. وربما يكون سبب ذلك خطأً ÙÙŠ التهيئة أو مهاجمًا يعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">â€ØªØªÙˆÙر خيارات البطاقة والعنوان ÙÙŠ حسابك ÙÙŠ Google (<ph name="ACCOUNT_EMAIL" />) ÙˆChrome. يمكنك إدارة هذه الخيارات ÙÙŠ <ph name="BEGIN_LINK" />الإعدادات<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535">يتطلَّب <ph name="DOMAIN" /> اسم مستخدم وكلمة مرور.</translation>
<translation id="2318774815570432836">â€Ù„ا يمكنك زيارة <ph name="SITE" /> الآن نظرًا لأن موقع الويب يستخدم HSTS. أخطاء الشبكة والهجمات عليها عادةً ما تكون مؤقتة، لذا ستعمل هذه الصÙحة لاحقًا على الأرجح. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">الإشارات الأخرى</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">السياسة اÙتراضية ÙÙŠ المؤسسة ويمكن إلغاؤها</translation>
<translation id="2386255080630008482">تم إبطال شهادة الخادم.</translation>
<translation id="2392959068659972793">عرض السياسات التي لم يتم تعيين قيم لها</translation>
+<translation id="239429038616798445">طريقة الشحن هذه غير متاحة، جرّÙب طريقة أخرى.</translation>
<translation id="2396249848217231973">تراجع عن الحذ&amp;Ù</translation>
<translation id="2460160116472764928">â€Ø§ÙƒØªØ´Ù التصÙØ­ الآمن من Google‬ مؤخرًا <ph name="BEGIN_LINK" />برامج ضارة<ph name="END_LINK" /> على <ph name="SITE" />. أحيانًا تÙصاب مواقع الويب الآمنة ÙÙŠ الوضع العادي ببرامج ضارة. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">ملء</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />تشغيل بيانات تشخيص الشبكة<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">â€Ø¹Ù†ÙˆØ§Ù† URL للبحث غير صالح.</translation>
<translation id="2491120439723279231">تحتوي شهادة الخادم على أخطاء.</translation>
-<translation id="24943777258388405">رقم الهات٠غير صالح</translation>
<translation id="2495083838625180221">â€Ù…حلل JSON اللغوي</translation>
<translation id="2495093607237746763">â€Ø¹Ù†Ø¯ وضع علامة على هذا الخيار، سيخزّن Chromium نسخة من بطاقتك على هذا الجهاز لتعبئة النماذج بشكل أسرع.</translation>
<translation id="2498091847651709837">Ùحص بطاقة جديدة</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027">أرسل <ph name="HOST_NAME" /> استجابة غير صالحة.</translation>
<translation id="2552545117464357659">أحدث</translation>
<translation id="2556876185419854533">تراجع عن ا&amp;لتحرير</translation>
+<translation id="2587730715158995865">من <ph name="ARTICLE_PUBLISHER" />. يمكنك قراءة هذه المقالة و<ph name="OTHER_ARTICLE_COUNT" /> قصص أخرى.</translation>
<translation id="2587841377698384444">رقم تعري٠واجهة برمجة التطبيقات الدليل:</translation>
<translation id="2597378329261239068">هذا المستند محمي بكلمة المرور. الرجاء إدخال كلمة مرور.</translation>
<translation id="2609632851001447353">الاختلاÙات</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />تشغيل بيانات تشخيص الاتصال<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">مواÙÙ‚</translation>
<translation id="2742870351467570537">إزالة العناصر المحددة</translation>
+<translation id="277133753123645258">طريقة الشحن</translation>
<translation id="277499241957683684">سجÙلّ الجهاز Ù…Ùقود</translation>
<translation id="2784949926578158345">تمت إعادة تعيين الاتصال.</translation>
<translation id="2794233252405721443">تم حظر الموقع</translation>
-<translation id="2812680587231492111">خيار الاستلام هذا غير متاح؛ جرّÙب خيارًا مختلÙًا.</translation>
<translation id="2824775600643448204">شريط العناوين والبحث</translation>
<translation id="2826760142808435982">تم تشÙير الاتصال ومصادقته باستخدام <ph name="CIPHER" />ØŒ ويستخدم <ph name="KX" /> كآلية التبادل الرئيسية.</translation>
<translation id="2835170189407361413">محو النموذج</translation>
-<translation id="2849041323157393173">خيار التسليم هذا غير متاح؛ جرّÙب خيارًا مختلÙًا.</translation>
<translation id="2889159643044928134">إلغاء إعادة التحميل</translation>
<translation id="2900469785430194048">â€Ù†Ùدت ذاكرة Google Chrome أثناء محاولة عرض صÙحة الويب هذه.</translation>
<translation id="2909946352844186028">تم اكتشا٠حدوث تغيير ÙÙŠ الشبكة.</translation>
<translation id="2916038427272391327">إغلاق البرامج الأخرى</translation>
<translation id="2922350208395188000">لا يمكن التحقق من شهادة الخادم.</translation>
+<translation id="2928905813689894207">عنوان إرسال الÙواتير</translation>
<translation id="2948083400971632585">يمكنك تعطيل أي خوادم وكيلة تمت تهيئتها لاتصال من صÙحة الإعدادات.</translation>
<translation id="2955913368246107853">إغلاق شريط البحث</translation>
<translation id="2958431318199492670">â€Ù„ا تتواÙÙ‚ تهيئة الشبكة مع معيار ONC. قد لا يتم استيراد بعض أجزاء التهيئة.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">â€Ù„إنشاء اتصال آمن، Ùإنك بحاجة إلى ضبط ساعتك بشكل صحيح. وذلك لأن الشهادات التي تستخدمها مواقع الويب لتعري٠نÙسها تكون صالحة Ùقط Ù„Ùترات محددة من الوقت. Ùإذا كانت ساعة جهازك غير صحيحة، Ùلن يتمكن Google Chrome من التحقق من هذه الشهادات.</translation>
<translation id="2972581237482394796">إعا&amp;دة</translation>
<translation id="2985306909656435243">â€Ø¹Ù†Ø¯ التمكين، سيÙخزن Chromium نسخة من بطاقتك على هذا الجهاز لتعبئة النماذج بشكل أسرع.</translation>
+<translation id="2985398929374701810">أدخÙÙ„ عنوانًا صحيحًا</translation>
+<translation id="2986368408720340940">طريقة الاستلام هذه غير متاحة. جرّÙب طريقة أخرى.</translation>
<translation id="2991174974383378012">المشاركة مع مواقع الويب</translation>
<translation id="3005723025932146533">عرض نسخة محÙوظة</translation>
<translation id="3008447029300691911">â€Ø£Ø¯Ø®Ù„ رمز التحقق من البطاقة (CVC) لـ <ph name="CREDIT_CARD" />. بعد تأكيدك، ستتم مشاركة تÙاصيل بطاقتك مع هذا الموقع.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{عنصر واحد على الأقل على الأجهزة المتزامنة}=1{عنصر واحد (1) (وأكثر على الأجهزة المتزامنة)}two{عنصران (#) (وأكثر على الأجهزة المتزامنة)}few{# عناصر (وأكثر على الأجهزة المتزامنة)}many{# عنصرًا (وأكثر على الأجهزة المتزامنة)}other{# عنصر (وأكثر على الأجهزة المتزامنة)}}</translation>
<translation id="3041612393474885105">معلومات الشهادة</translation>
<translation id="3063697135517575841">â€Ù„Ù… يتمكن Chrome من التأكد من بطاقتك ÙÙŠ الوقت الحالي. ÙŠÙرجى إعادة المحاولة ÙÙŠ وقت لاحق.</translation>
+<translation id="3064966200440839136">ستتم مغادرة وضع التصÙØ­ المتخÙÙŠ للدÙع عبر تطبيق خارجي. هل تريد المتابعة؟</translation>
<translation id="3093245981617870298">أنت غير متصل.</translation>
<translation id="3105172416063519923">رقم تعري٠الأصل:</translation>
<translation id="3109728660330352905">ليس لديك إذن بعرض هذه الصÙحة.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />تجربة تشغيل بيانات تشخيص الاتصال<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">تعذّر ÙÙƒ تشÙير الاستجابة</translation>
-<translation id="3149891296864842641">خيار الشحن</translation>
<translation id="3150653042067488994">خطأ مؤقت ÙÙŠ الخادم</translation>
+<translation id="3154506275960390542">تتضمّن هذه الصÙحة نموذجًا قد لا يتم إرساله بصورة آمنة، ويستطيع الآخرون مشاهدة البيانات التي ترسلها أثناء نقلها، كما يستطيع أي مهاجم تعديلها لتغيير ما يتلقاه الخادم.</translation>
<translation id="3157931365184549694">استعادة</translation>
<translation id="3167968892399408617">لن يتم تسجيل الصÙحات التي تعرضها ÙÙŠ علامات تبويب التصÙØ­ المتخÙÙŠ ÙÙŠ سجل المتصÙØ­ أو مخزن ملÙات تعري٠الارتباط أو سجل البحث بعد إغلاق جميع علامات التبويب ÙÙŠ وضع التصÙØ­ المتخÙÙŠ. ولكن سيتم الاحتÙاظ بأي ملÙات تنزلها أو إشارات مرجعية تنشئها.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">تعذر إرسال طلبك للوصول إلى هذا الموقع إلى <ph name="NAME" />. ÙŠÙرجى إعادة المحاولة مرة أخرى.</translation>
<translation id="3355823806454867987">تغيير إعدادات الخادم الوكيل...</translation>
<translation id="3369192424181595722">خطأ ÙÙŠ الساعة</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> من العناصر الأخرى...</translation>
<translation id="337363190475750230">تم إلغاء التوÙير</translation>
<translation id="3377188786107721145">خطأ ÙÙŠ تحليل السياسة</translation>
<translation id="3380365263193509176">خطأ غير معروÙ</translation>
<translation id="3380864720620200369">معرّÙ٠العميل:</translation>
<translation id="3391030046425686457">عنوان التسليم</translation>
+<translation id="3395827396354264108">طريقة الاستلام</translation>
<translation id="340013220407300675">قد يحاول المهاجمون سرقة معلوماتك من <ph name="BEGIN_BOLD" /> <ph name="SITE" /> <ph name="END_BOLD" /> (على سبيل المثال: كلمات المرور أو الرسائل، أو بطاقات الائتمان).</translation>
<translation id="3422248202833853650">جرّب الخروج من البرامج الأخرى لتÙريغ مساحة من الذاكرة.</translation>
<translation id="3422472998109090673">يتعذر الوصول إلى <ph name="HOST_NAME" /> حاليًا.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">الÙاصل الزمني للجلب:</translation>
<translation id="3462200631372590220">الإخÙاء (خيار متقدم)</translation>
+<translation id="3467763166455606212">اسم حامل البطاقة مطلوب</translation>
+<translation id="3478058380795961209">شهر انتهاء الصلاحية</translation>
<translation id="3479539252931486093">ألم تتوقَّع هذا؟ <ph name="BEGIN_LINK" />أطلÙعنا على الأمر<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">ليس الآن</translation>
<translation id="348000606199325318">معرّ٠التعطّÙÙ„ <ph name="CRASH_LOCAL_ID" /> (معرّ٠الخادم: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">لم نتمكن من الوصول إلى أحد والديك ÙÙŠ الوقت الحالي. ÙŠÙرجى إعادة المحاولة مرة أخرى.</translation>
<translation id="3528171143076753409">شهادة الخادم غير موثوق Ùيها.</translation>
-<translation id="3538531656504267329">عام انتهاء الصلاحية غير صالح</translation>
<translation id="3539171420378717834">الاحتÙاظ بنسخة من هذه البطاقة على هذا الجهاز</translation>
<translation id="3542684924769048008">استخدام كلمة مرور لـ:</translation>
<translation id="3549644494707163724">تشÙير جميع البيانات المتزامنة باستخدام عبارة مرور المزامنة</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">إخÙاء التÙاصيل</translation>
<translation id="3587482841069643663">الكل</translation>
<translation id="3600246354004376029"><ph name="TITLE" />، و<ph name="DOMAIN" />، و<ph name="TIME" /></translation>
+<translation id="3615877443314183785">أدخÙÙ„ تاريخ انتهاء صلاحية صحيحًا</translation>
<translation id="36224234498066874">مسح بيانات التصÙØ­...</translation>
<translation id="362276910939193118">عرض السجل بكامله</translation>
<translation id="3623476034248543066">عرض القيمة</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">كلمة المرور:</translation>
<translation id="3696411085566228381">بدون</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">اختر عنوان شحن للتحقّق من متطلبات وطرق الشحن.</translation>
<translation id="370665806235115550">جار٠التحميل...</translation>
<translation id="3712624925041724820">التراخيص مستنÙذة</translation>
<translation id="3714780639079136834">â€ØªØ´ØºÙŠÙ„ بيانات شبكة الجوّال أو Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">الرابط الذي نسخته</translation>
<translation id="375403751935624634">أخÙقت الترجمة بسبب حدوث خطأ ÙÙŠ الخادم.</translation>
<translation id="3759461132968374835">ليس لديك أي أعطال تم الإبلاغ عنها مؤخرًا. الأعطال التي حدثت عندما تم تعطيل الإبلاغ عن الأعطال لن تظهر هنا.</translation>
+<translation id="3787705759683870569">تنتهي ÙÙŠ <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">إذا كنت تستخدم خادمًا وكيلاً...</translation>
<translation id="3828924085048779000">غير مسموح باستخدام عبارة مرور Ùارغة.</translation>
<translation id="3845539888601087042">عرض السجلّ من الأجهزة التي تم تسجيل الدخول عليها. <ph name="BEGIN_LINK" />مزيد من المعلومات<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">â€Ù‡Ù„ تريد من Chromium Ø­Ùظ هذه البطاقة؟</translation>
<translation id="4171400957073367226">توقيع تحقق سيئ</translation>
-<translation id="4176463684765177261">معطل</translation>
<translation id="4196861286325780578">إ&amp;عادة النقل</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />التحقق من عمليات تهيئة الجدار الناري وبرامج مكاÙحة الÙيروسات<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{لا شيء}=1{تطبيق واحد ($1)}=2{تطبيقان (2) ($1، $2)}few{# تطبيقات ($1، $2، $3)}many{# تطبيقًا ($1، $2، $3)}other{# تطبيق ($1، $2، $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">نتائج البحث</translation>
<translation id="4432688616882109544">لم يقبل <ph name="HOST_NAME" /> شهادة تسجيل الدخول أو من المحتمل ألا يكون قد تم تقديم واحدة.</translation>
<translation id="443673843213245140">تم تعطيل استخدام الخادم الوكيل ولكن تم تحديد تهيئة صريحة للخادم الوكيل.</translation>
-<translation id="4446242550670694251">يمكنك الآن التصÙØ­ بشكل٠سري، ولن يتمكن الأشخاص الآخرين الذين يستخدمون هذا الجهاز من مشاهدة نشاطك.</translation>
<translation id="4492190037599258964">نتائج البحث عن '<ph name="SEARCH_STRING" />'</translation>
<translation id="4506176782989081258">خطأ ÙÙŠ عملية التحقق: <ph name="VALIDATION_ERROR" />.</translation>
<translation id="4506599922270137252">الاتصال بمشر٠النظام</translation>
<translation id="450710068430902550">المشاركة مع المشرÙ</translation>
+<translation id="4515275063822566619">â€ØªØ£ØªÙŠ البطاقات والعناوين من Chrome وحسابك ÙÙŠ Google (<ph name="ACCOUNT_EMAIL" />). ويمكنك إدارتها ÙÙŠ <ph name="BEGIN_LINK" />الإعدادات<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">التÙاصيل</translation>
<translation id="4558551763791394412">جرّب تعطيل الإضاÙات.</translation>
<translation id="457875822857220463">التسليم</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">احتواء ضمن الصÙحة</translation>
<translation id="483020001682031208">لا توجد صÙحات شبكة مادية متاحة للعرض</translation>
<translation id="4850886885716139402">عرض</translation>
+<translation id="4854362297993841467">طريقة التسليم هذه غير متاحة. جرّÙب طريقة أخرى.</translation>
<translation id="4858792381671956233">لقد سألت والديك ما إذا كانت زيارة هذا الموقع مناسبةً لك</translation>
<translation id="4880827082731008257">سجلّ البحث</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />، <ph name="TYPE_2" />، <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">تمت ترجمة هذه الصÙحة من لغة غير معروÙØ© إلى اللغة <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">الدÙع</translation>
<translation id="4926049483395192435">يجب تحديدها.</translation>
-<translation id="4941291666397027948">* تشير إلى حقل مطلوب</translation>
<translation id="495170559598752135">إجراءات</translation>
<translation id="4958444002117714549">توسيع القائمة</translation>
<translation id="4962322354953122629">â€Ù‡Ø°Ø§ الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إن شهادة أمانه غير موثوقة من Ù‚Ùبل Chrome. وربما يكون السبب ÙÙŠ ذلك خطأً ÙÙŠ التهيئة أو مهاجمًا يعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">كلمة مرور غير صحيحة</translation>
<translation id="5056549851600133418">مقالات من أجلك</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />التحقق من عنوان الخادم الوكيل<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{لا توجد ملÙات تعري٠ارتباط}=1{يستخدم موقع ويب واحد ملÙات تعري٠الارتباط. }two{يستخدم موقعا ويب (#) ملÙات تعري٠الارتباط. }few{تستخدم # مواقع ويب ملÙات تعري٠الارتباط. }many{يستخدم # موقعًا من مواقع الويب ملÙات تعري٠الارتباط. }other{يستخدم # موقع ويب ملÙات تعري٠الارتباط. }}</translation>
<translation id="5087286274860437796">شهادة الخادم ليست صالحة حاليًا.</translation>
<translation id="5087580092889165836">إضاÙØ© بطاقة</translation>
<translation id="5089810972385038852">بلد/دولة</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">عرض</translation>
<translation id="5308689395849655368">ميزة الإبلاغ عن الأعطال معطلة.</translation>
<translation id="5317780077021120954">Ø­Ùظ</translation>
-<translation id="5326702247179446998">يلزم وجود مستلم</translation>
<translation id="5327248766486351172">الاسم</translation>
<translation id="5337705430875057403">قد يخدعك المخترقون الموجودون على <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> بÙعل شيء خطير كتثبيت البرامج أو الكش٠عن معلوماتك الشخصية (على سبيل المثال، كلمات المرور، أرقام الهواتÙØŒ أو بطاقات الائتمان).</translation>
-<translation id="53553865750799677">عنوان الاستلام غير مدعوم. حدّد عنوانًا آخر.</translation>
<translation id="5359637492792381994">هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />ØŒ بل إن شهادة أمانه غير صالحة حاليًا. وربما يكون السبب ÙÙŠ ذلك خطأً ÙÙŠ التهيئة أو مهاجمًا يعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">تعذّر تخزين إعدادات السياسة</translation>
<translation id="5386426401304769735">â€ØªØªØ¶Ù…Ù† سلسلة الشهادات لهذا الموقع شهادة موقعة باستخدام SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">صÙحة Ù…Ùضمنة ÙÙŠ <ph name="SITE" /> تعرض:</translation>
<translation id="5556459405103347317">إعادة تحميل</translation>
<translation id="5565735124758917034">نشط</translation>
+<translation id="5571083550517324815">لا يمكن الاستلام من هذا العنوان. حدّÙد عنوانًا آخر.</translation>
<translation id="5572851009514199876">â€ÙŠÙرجى البدء وتسجيل الدخول إلى Chrome لكي يتأكد Chrome مما إذا كان مسموحًا لك الوصول إلى موقع الويب هذا أم لا.</translation>
-<translation id="5575380383496039204">عنوان التسليم غير مدعوم. حدّد عنوانًا آخر.</translation>
<translation id="5580958916614886209">تحقق من شهر انتهاء الصلاحية وأعÙد المحاولة مرة أخرى</translation>
<translation id="560412284261940334">الإدارة غير متوÙرة</translation>
<translation id="5610142619324316209">التحقق من الاتصال</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">لم يتمّ التحقق من هوية هذا الموقع.</translation>
<translation id="5720705177508910913">المستخدم الحالي</translation>
<translation id="5732392974455271431">يمكن لوالديك إلغاء الحظر لك</translation>
-<translation id="57586589942790530">رقم البطاقة غير صالح</translation>
+<translation id="5763042198335101085">أدخÙÙ„ عنوان بريد إلكتروني صحيحًا</translation>
+<translation id="5765072501007116331">لعرض طرق التسليم ومتطلباته، حدّÙد عنوانًا</translation>
<translation id="5784606427469807560">حدثت مشكلة أثناء التأكد من بطاقتك. تحقق من اتصالك بالإنترنت وأعد المحاولة.</translation>
<translation id="5785756445106461925">إضاÙØ© إلى ذلك، تتضمن هذه الصÙحة موارد أخرى غير آمنة. ويستطيع الآخرون مشاهدة هذه الموارد أثناء نقلها، كما يستطيع أي مهاجم تعديلها لتغيير مظهر الصÙحة.</translation>
<translation id="5786044859038896871">هل تريد ملء معلومات بطاقتك؟</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">لا يمكن الوصول إلى موقع الويب هذا</translation>
<translation id="5869522115854928033">كلمات المرور المحÙوظة</translation>
<translation id="5872918882028971132">اقتراحات الآباء</translation>
-<translation id="587760065310675640">عنوان الشحن غير مدعوم. حدّد عنوانًا آخر.</translation>
<translation id="5901630391730855834">أصÙر</translation>
-<translation id="59174027418879706">تم التمكين</translation>
<translation id="5926846154125914413">قد تÙقد إمكانية الدخول إلى محتوى متميز من بعض المواقع.</translation>
<translation id="5959728338436674663">â€ÙŠÙ…كنك إرسال بعض <ph name="BEGIN_WHITEPAPER_LINK" />معلومات النظام ومحتوى الصÙحة<ph name="END_WHITEPAPER_LINK" /> إلى Google تلقائيًا للمساعدة ÙÙŠ اكتشا٠التطبيقات والمواقع الضارة. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">الأسبوع</translation>
<translation id="5967867314010545767">إزالة من السجل</translation>
<translation id="5975083100439434680">تصغير</translation>
+<translation id="598637245381783098">لا يمكن Ùتح تطبيق الدÙع</translation>
<translation id="5989320800837274978">â€Ù„Ù… يتم تحديد أي من الخوادم الوكيلة الثابتة ولا عنوان URL للنص البرمجي pac.</translation>
<translation id="5990559369517809815">تم حظر الطلبات المقدمة إلى الخادم بواسطة إحدى الإضاÙات.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">â€ØªØªÙˆÙر خيارات البطاقة والعنوان ÙÙŠ متصÙØ­ Chrome. يمكنك إدارة هذه الخيارات ÙÙŠ <ph name="BEGIN_LINK" />الإعدادات<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{صÙحة 1}zero{صÙحة #}two{صÙحة #}few{صÙحة #}many{صÙحة #}other{صÙحة #}}</translation>
<translation id="6017514345406065928">أخضر</translation>
+<translation id="6027201098523975773">أدخÙÙ„ اسمًا</translation>
<translation id="6040143037577758943">إغلاق</translation>
-<translation id="604124094241169006">تلقائي</translation>
<translation id="6042308850641462728">المزيد</translation>
<translation id="6060685159320643512">احذر، هذه التجارب غير مضمونة النتائج</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{لا شيء}=1{1}two{#}few{#}many{#}other{#}}</translation>
@@ -543,9 +552,10 @@
أخرى ربما تستخدمها.</translation>
<translation id="614940544461990577">جرّب:</translation>
<translation id="6151417162996330722">Ùترة صلاحية شهادة الخادم طويلة جدًا.</translation>
-<translation id="615643356032862689">سيتم الاحتÙاظ بالملÙات والإشارات المرجعية التي تم تنزيلها.</translation>
+<translation id="6157877588268064908">لعرض طرق الشحن ومتطلباته، حدّÙد عنوانًا</translation>
<translation id="6165508094623778733">مزيد من المعلومات</translation>
<translation id="6177128806592000436">إن اتصالك بهذا الموقع غير آمن</translation>
+<translation id="6184817833369986695">(مجموعة نموذجية: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">التحقق من اتصالك بالإنترنت</translation>
<translation id="6218753634732582820">â€Ù‡Ù„ تريد إزالة العنوان من ChromiumØŸ</translation>
<translation id="6251924700383757765">سياسة الخصوصية</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">إعادة إ&amp;جراء الترتيب</translation>
<translation id="6263376278284652872">إشعارات <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">الرجوع إلى وضع الأمان</translation>
+<translation id="6276112860590028508">تظهر الصÙحات من قائمة القراءة التابعة لك هنا</translation>
+<translation id="6280223929691119688">لا يمكن التسليم على هذا العنوان. حدّÙد عنوانًا آخر.</translation>
<translation id="6282194474023008486">الرمز البريدي</translation>
<translation id="6290238015253830360">تظهر مقالاتك المقترحة هنا</translation>
<translation id="6305205051461490394">يتعذر الوصول إلى <ph name="URL" />.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">تعذر التحقق مما إذا كانت الشهادة قد تم إبطالها.</translation>
<translation id="6433490469411711332">تعديل معلومات الاتصال</translation>
<translation id="6433595998831338502">رÙض <ph name="HOST_NAME" /> الاتصال.</translation>
-<translation id="6443118737398455446">تاريخ انتهاء الصلاحية غير صالح</translation>
<translation id="6446608382365791566">إضاÙØ© مزيد من المعلومات</translation>
<translation id="6451458296329894277">تأكيد إعادة إرسال النموذج</translation>
<translation id="6456339708790392414">دÙعتك</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />ØŒ قد يكون تم إبطال شهادة أمانه. وربما يكون سبب ذلك خطأً ÙÙŠ التهيئة أو مهاجمًا يعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">سياسات الأجهزة</translation>
<translation id="6477321094435799029">â€Ø§ÙƒØªØ´Ù Chrome وجود رمز غير عادي على هذه الصÙحة وأجرى حظرًا لهذا الرمز لحماية معلوماتك الشخصية (على سبيل المثال، كلمات المرور، وأرقام الهواتÙØŒ وبطاقات الائتمان).</translation>
-<translation id="6477460825583319731">عنوان البريد الإلكتروني غير صالح</translation>
<translation id="6489534406876378309">بدء تحميل الأعطال</translation>
<translation id="6508722015517270189">â€Ø¥Ø¹Ø§Ø¯Ø© تشغيل Chrome</translation>
-<translation id="6525462735697194615">شهر انتهاء الصلاحية غير صالح</translation>
<translation id="6529602333819889595">إعادة الح&amp;Ø°Ù</translation>
<translation id="6534179046333460208">اقتراحات الشبكة المادية</translation>
<translation id="6550675742724504774">خيارات</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685">بحث <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">تم تجاهل هذه السياسة.</translation>
<translation id="6652240803263749613">هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />ØŒ بل إن شهادة أمانه غير موثوقة من Ù‚Ùبل نظام تشغيل الكمبيوتر. وربما يكون السبب ÙÙŠ ذلك خطأً ÙÙŠ التهيئة أو مهاجمًا يعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">خيار الشحن هذا غير متاح؛ جرّÙب خيارًا مختلÙًا.</translation>
<translation id="6671697161687535275">â€Ù‡Ù„ تريد إزالة اقتراح النموذج من ChromiumØŸ</translation>
<translation id="6685834062052613830">الخروج وإكمال الإعداد</translation>
<translation id="6710213216561001401">السابق</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">هناك خطأ ما ÙÙŠ الخادم الوكيل، أو العنوان غير صحيح.</translation>
<translation id="6727102863431372879">تعيين</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{لا شيء}=1{عنصر واحد}two{عنصران (#)}few{# عناصر}many{# عنصرًا}other{# عنصر}}</translation>
-<translation id="6743044928064272573">خيار الاستلام</translation>
<translation id="674375294223700098">حدث خطأ غير معرو٠ÙÙŠ شهادة الخادم.</translation>
<translation id="6753269504797312559">قيمة السياسة</translation>
<translation id="6757797048963528358">خضع جهازك إلى وضع السكون.</translation>
<translation id="6778737459546443941">لم يواÙÙ‚ عليه والداك حتى الآن</translation>
<translation id="6810899417690483278">رقم تعري٠التخصيص</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">تعذَّر تحميل بيانات المناطق</translation>
<translation id="6831043979455480757">ترجمة</translation>
<translation id="6839929833149231406">المنطقة</translation>
<translation id="6874604403660855544">إعا&amp;دة الإضاÙØ©</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">تم التأكد من بطاقتك</translation>
<translation id="6897140037006041989">وكيل المستخدم</translation>
<translation id="6915804003454593391">المستخدم:</translation>
+<translation id="6948701128805548767">لعرض طرق الاستلام ومتطلباته، حدّÙد عنوانًا</translation>
<translation id="6957887021205513506">يبدو أن شهادة الخادم مزيÙØ©.</translation>
<translation id="6965382102122355670">مواÙÙ‚</translation>
<translation id="6965978654500191972">جهاز</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">â€ØªÙ… تحديد كل من الخوادم الوكيلة الثابتة وعنوان URL للنص البرمجي pac.</translation>
<translation id="6989763994942163495">عرض الإعدادات المتقدمة...</translation>
<translation id="7000990526846637657">لم يتم العثور على أي إدخالات ÙÙŠ السجلّ</translation>
-<translation id="7001663382399377034">إضاÙØ© مستلم</translation>
<translation id="7009986207543992532">لقد حاولت الوصول إلى <ph name="DOMAIN" />، ولكن الخادم قدّم شهادة مدة صلاحيتها طويلة جدًا مما يجعلها غير جديرة بالثقة. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">â€Ù‚د يتضمن حسابك ÙÙŠ Google نماذج أخرى من سجلّ التصÙØ­ ÙÙŠ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">أقدم</translation>
<translation id="7090678807593890770">â€Ø§Ù„بحث ÙÙŠ Google عن <ph name="LINK" /></translation>
<translation id="7119414471315195487">إغلاق علامات التبويب أو البرامج الأخرى</translation>
+<translation id="7129409597930077180">لا يمكن الشحن على هذا العنوان. حدّÙد عنوانًا آخر.</translation>
+<translation id="7138472120740807366">طريقة التسليم</translation>
<translation id="7139724024395191329">الإمارة</translation>
<translation id="7155487117670177674">عملية الدÙع غير آمنة</translation>
<translation id="7179921470347911571">إعادة التشغيل الآن</translation>
<translation id="7180611975245234373">تحديث</translation>
<translation id="7182878459783632708">لم يتم تعيين أية سياسات</translation>
<translation id="7186367841673660872">تمت ترجمة هذه الصÙحة من اللغة<ph name="ORIGINAL_LANGUAGE" />إلى اللغة<ph name="LANGUAGE_LANGUAGE" /></translation>
+<translation id="7192203810768312527">يوÙÙ‘Ùر <ph name="SIZE" />. قد يتم تحميل بعض مواقع الويب بشكل أبطأ عند زيارتها ÙÙŠ المرة القادمة.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423">لا يلتزم <ph name="HOST_NAME" /> بمعايير الأمان.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />مزيد من المعلومات<ph name="END_LINK" /> حول هذه المشكلة.</translation>
@@ -675,7 +686,6 @@
<translation id="7424977062513257142">صÙحة Ù…Ùضمنة ÙÙŠ صÙحة الويب هذه تعرض:</translation>
<translation id="7441627299479586546">موضوع السياسة غير صحيح</translation>
<translation id="7444046173054089907">تم حظر هذا الموقع</translation>
-<translation id="7444238235002594607">حدّد عنوان الاستلام للتحقق من متطلبات وطرق الاستلام.</translation>
<translation id="7445762425076701745">لا يمكن التحقق بصورة كاملة من صحة هوية الخادم الذي تتصل به. Ùأنت متصل بخادم باستخدام اسم صالح Ùقط ضمن شبكتك، والذي لن يتمكن المرجع المصدق الخارجي من التحقق من ملكيته. وحيث إن بعض المراجع المصدقة تÙصدر الشهادات لهذه الأسماء على أي حال، Ùليست هناك طريقة للتأكد من أنك متصل بموقع الويب المقصود وليس بأحد المهاجمين.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />مزيد من المعلومات<ph name="END_LINK" /> حول هذه المشكلة.</translation>
<translation id="7460163899615895653">تظهر علامات التبويب الأخيرة من الأجهزة الأخرى هنا</translation>
@@ -719,6 +729,7 @@
<translation id="7755287808199759310">قد يلغي والداك الحظر لك</translation>
<translation id="7758069387465995638">ربما حظر الجدار الناري أو برامج مكاÙحة الÙيروسات الاتصال.</translation>
<translation id="7761701407923456692">â€Ù„ا تتطابق شهادة الخادم مع عنوان URL.</translation>
+<translation id="7763386264682878361">المحلل اللغوي لبيان الدÙع</translation>
<translation id="7764225426217299476">إضاÙØ© عنوان</translation>
<translation id="777702478322588152">الإدارة الأمنية</translation>
<translation id="7791543448312431591">إضاÙØ©</translation>
@@ -732,6 +743,7 @@
<translation id="785549533363645510">ومع ذلك، أنت غير مرئي. لا يخÙÙŠ الانتقال إلى وضع التخÙÙŠ التصÙØ­ من صاحب العمل أو مزود خدمة الإنترنت أو المواقع التي تزورها.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">â€ØªØ­Ù‚Ù‚ من رمز التحقق من البطاقة (CVC) ثم أعد المحاولة.</translation>
+<translation id="79338296614623784">أدخÙÙ„ رقم هات٠صحيحًا</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">شهادة الخادم ليست صالحة بعد.</translation>
<translation id="7942349550061667556">أحمر</translation>
@@ -751,6 +763,7 @@
<translation id="8088680233425245692">تعذّر عرض المقالة.</translation>
<translation id="8089520772729574115">أقل من ميغابايت واحدة</translation>
<translation id="8091372947890762290">التنشيط قيد الانتظار ÙÙŠ الخادم</translation>
+<translation id="8118489163946903409">طريقة الدÙع</translation>
<translation id="8131740175452115882">التأكيد</translation>
<translation id="8134994873729925007">تعذر العثور على <ph name="BEGIN_ABBR" />عنوان نظام أسماء النطاقات<ph name="END_ABBR" /> للخادم <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">خضع جهاز الكمبيوتر إلى وضع السكون.</translation>
@@ -776,6 +789,7 @@
<translation id="8349305172487531364">شريط الإشارات</translation>
<translation id="8363502534493474904">إيقا٠تشغيل وضع الطائرة</translation>
<translation id="8364627913115013041">لم يتم تعيينها.</translation>
+<translation id="8368476060205742148">â€Ø®Ø¯Ù…ات Google Play</translation>
<translation id="8380941800586852976">ضارة</translation>
<translation id="8382348898565613901">تظهر الإشارات المرجعية التي زرتها مؤخرًا هنا</translation>
<translation id="8398259832188219207">تم تحميل تقرير الأعطال ÙÙŠ <ph name="UPLOAD_TIME" /></translation>
@@ -784,32 +798,30 @@
<translation id="8428213095426709021">إعدادات</translation>
<translation id="8433057134996913067">سيؤدي هذا إلى خروجك من معظم مواقع الويب.</translation>
<translation id="8437238597147034694">تراجع عن ال&amp;نقل</translation>
-<translation id="8456681095658380701">اسم غير صالح</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{بطاقة ائتمان واحدة}zero{# بطاقة ائتمان}two{بطاقتا ائتمان (#)}few{# بطاقات ائتمان}many{# بطاقة ائتمان}other{# بطاقة ائتمان}}</translation>
<translation id="8483780878231876732">â€Ù„استخدام البطاقات من حسابك ÙÙŠ GoogleØŒ ÙŠÙرجى تسجيل الدخول إلى Chrome</translation>
<translation id="8488350697529856933">تنطبق على</translation>
-<translation id="8492969205326575646">نوع البطاقة غير متواÙÙ‚</translation>
<translation id="8498891568109133222">استغرق <ph name="HOST_NAME" /> وقتًا أطول مما يجب للاستجابة.</translation>
<translation id="852346902619691059">هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إن شهادة أمانه غير موثوقة من Ù‚Ùبل نظام تشغيل جهازك. وربما يكون السبب ÙÙŠ ذلك خطأً ÙÙŠ التهيئة أو مهاجمًا يعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">عام انتهاء الصلاحية</translation>
<translation id="8543181531796978784">يمكنك <ph name="BEGIN_ERROR_LINK" />الإبلاغ عن اكتشا٠مشكلة<ph name="END_ERROR_LINK" /> أو، إذا كنت تدرك المخاطر المتعلقة بالأمان، يمكنك <ph name="BEGIN_LINK" />زيارة هذا الموقع غير الآمن<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">أخÙقت الترجمة لتعذر تحديد لغة الصÙحة.</translation>
<translation id="8559762987265718583">تعذر إنشاء اتصال خاص بـ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> نظرًا لأن التاريخ والوقت للجهاز (<ph name="DATE_AND_TIME" />) غير صحيحين.</translation>
-<translation id="8570229484593575558">هذه المعلومات |لن يتم الاحتÙاظ بها|:#سجل تصÙحك#عمليات بحثك#بيانات مل٠تعري٠الارتباط</translation>
<translation id="8571890674111243710">جار٠ترجمة الصÙحة إلى <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">نشاطك |قد يظل مرئيًا| إلى:#مواقع الويب التي زرتها#صاحب العمل#مزوّد خدمة الإنترنت</translation>
<translation id="858637041960032120">إضاÙØ© رقم هاتÙ
</translation>
<translation id="859285277496340001">لا تحدد الشهادة آلية للتحقق مما إذا كانت الشهادة قد تم إبطالها.</translation>
<translation id="8620436878122366504">لم يواÙÙ‚ عليه والداك حتى الآن</translation>
<translation id="8647750283161643317">إعادة التعيين على الإعدادات الاÙتراضية</translation>
<translation id="8703575177326907206">الاتصال بالموقع <ph name="DOMAIN" /> غير محميّ بنظام تشÙير.</translation>
+<translation id="8718314106902482036">لم تكتمل عملية الدÙع</translation>
<translation id="8725066075913043281">أعد المحاولة</translation>
-<translation id="8728672262656704056">لقد انتقلت إلى وضع التصÙØ­ المتخÙÙŠ</translation>
+<translation id="8728672262656704056">لقد انتقلت إلى التصÙّح المتخÙÙŠ</translation>
<translation id="8730621377337864115">تم</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="8759274551635299824">هذه البطاقة منتهية الصلاحية</translation>
<translation id="8790007591277257123">إعادة الح&amp;Ø°Ù</translation>
-<translation id="8798099450830957504">الاÙتراضي</translation>
<translation id="8800988563907321413">تظهر اقتراحاتك "المجاورة" هنا</translation>
<translation id="8820817407110198400">إشارات</translation>
<translation id="883848425547221593">إشارات أخرى</translation>
@@ -819,6 +831,7 @@
<translation id="8866481888320382733">خطأ ÙÙŠ إعدادات تحليل السياسة</translation>
<translation id="8866959479196209191">تعرض هذه الصÙحة:</translation>
<translation id="8870413625673593573">العناصر المغلقة مؤخرًا</translation>
+<translation id="8874824191258364635">أدخÙÙ„ رقم بطاقة صحيحًا</translation>
<translation id="8876793034577346603">تعذّر تحليل تهيئة الشبكة</translation>
<translation id="8877192140621905067">بعد تأكيدك، ستتم مشاركة تÙاصيل بطاقتك مع هذا الموقع</translation>
<translation id="8889402386540077796">تدرج اللون</translation>
@@ -828,7 +841,6 @@
<translation id="8931333241327730545">â€Ù‡Ù„ تريد Ø­Ùظ هذه البطاقة إلى حسابك ÙÙŠ GoogleØŸ</translation>
<translation id="8932102934695377596">توقيت ساعتك متأخر عن الوقت الحالي</translation>
<translation id="8954894007019320973">(يتبع)</translation>
-<translation id="895548565263634352">قراءة مقالات من <ph name="ARTICLE_PUBLISHER" /> Ùˆ<ph name="OTHER_ARTICLE_COUNT" /> إضاÙية</translation>
<translation id="8971063699422889582">انتهت صلاحية شهادة الخادم.</translation>
<translation id="8986494364107987395">â€Ø¥Ø±Ø³Ø§Ù„ إحصائيات الاستخدام وتقارير الأعطال إلى Google تلقائيًا</translation>
<translation id="8987927404178983737">شهر</translation>
@@ -846,7 +858,6 @@
<translation id="9068849894565669697">اختيار اللون</translation>
<translation id="9076283476770535406">قد يتضمن محتوى للبالغين</translation>
<translation id="9078964945751709336">مطلوب مزيد من المعلومات</translation>
-<translation id="9094175695478007090">يتعذَّر إطلاق تطبيق الدÙع.</translation>
<translation id="9103872766612412690">â€ÙŠØ³ØªØ®Ø¯Ù… <ph name="SITE" /> التشÙير عادة لحماية معلوماتك. عندما حاول Chromium الاتصال بموقع <ph name="SITE" /> هذه المرة، أرجَع موقع الويب بيانات اعتماد غير عادية وغير صحيحة. وقد يحدث هذا عندما يحاول أحد المهاجمين التظاهر بأنه موقع <ph name="SITE" />ØŒ أو إذا قاطعت شاشة تسجيل دخول Wi-Fi الاتصال. ولكن لا تزال معلوماتك آمنة نظرًا لأن Chromium أوقَÙÙŽ الاتصال قبل تبادل أي بيانات.</translation>
<translation id="9137013805542155359">إظهار الصÙحة الأصلية</translation>
<translation id="9137248913990643158">â€ÙŠÙرجى البدء وتسجيل الدخول إلى Chrome قبل استخدام هذا التطبيق.</translation>
diff --git a/chromium/components/strings/components_strings_bg.xtb b/chromium/components/strings/components_strings_bg.xtb
index c57b4526d80..f786ce8cba1 100644
--- a/chromium/components/strings/components_strings_bg.xtb
+++ b/chromium/components/strings/components_strings_bg.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="bg">
<translation id="1008557486741366299">Ðе Ñега</translation>
<translation id="1015730422737071372">Въвеждане на допълнителни подробноÑти</translation>
+<translation id="1021110881106174305">Приемани карти</translation>
<translation id="1032854598605920125">Завъртане по чаÑовниковата Ñтрелка</translation>
<translation id="1038842779957582377">неизвеÑтно име</translation>
<translation id="1050038467049342496">Затворете другите приложениÑ.</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Скриване на ÑтойноÑтта</translation>
<translation id="1228893227497259893">Грешен идентификатор на обект</translation>
<translation id="1232569758102978740">Ðеозаглавен</translation>
+<translation id="1263231323834454256">СпиÑък за четене</translation>
<translation id="1264126396475825575">Сигнал за Ñрив, запиÑан в/ъв <ph name="CRASH_TIME" /> (още не е качен или пренебрегнат)</translation>
<translation id="1285320974508926690">Този Ñайт да не Ñе превежда никога</translation>
<translation id="129553762522093515">ÐаÑкоро затворени</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">ÐаÑтройки за Ðвтоматично попълване в Chromium...</translation>
<translation id="1374468813861204354">предложениÑ</translation>
<translation id="1375198122581997741">Ð’Ñичко за верÑиÑта</translation>
+<translation id="1377321085342047638">№ на картата</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> не изпрати данни.</translation>
<translation id="1407135791313364759">ОтварÑне на вÑички</translation>
<translation id="1413809658975081374">Грешка, Ñвързана в поверителноÑтта</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">ИÑториÑ</translation>
<translation id="1645368109819982629">Ðеподдържан протокол</translation>
<translation id="1656489000284462475">Вземане</translation>
+<translation id="1663943134801823270">Картите и адреÑите Ñа от Chrome. Можете да ги управлÑвате от <ph name="BEGIN_LINK" />наÑтройките<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">Обикновено <ph name="SITE" /> използва шифроване за защита на информациÑта ви. Когато Google Chrome опита да уÑтанови връзка Ñ/ÑŠÑ <ph name="SITE" /> този път, уебÑайтът върна необичайни и неправилни идентификационни данни. Това може да Ñе Ñлучи, когато извършител на атака пробва да Ñе предÑтави за <ph name="SITE" /> или връзката е прекъÑната от екран за вход в Wi-Fi. ИнформациÑта ви продължава да е защитена, тъй като Chrome ÑÐ¿Ñ€Ñ Ð²Ñ€ÑŠÐ·ÐºÐ°Ñ‚Ð°, преди да бъдат обменени данни.</translation>
<translation id="168328519870909584">ПонаÑтоÑщем извършители на атака Ñрещу <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> може да опитат да инÑталират опаÑни Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð½Ð° уÑтройÑтвото ви, които крадат или изтриват Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ (например Ñнимки, пароли, ÑÑŠÐ¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸ номера на кредитни карти).</translation>
<translation id="168841957122794586">Сертификатът на Ñървъра Ñъдържа Ñлаб криптографÑки ключ.</translation>
<translation id="1710259589646384581">ОС</translation>
<translation id="1721312023322545264">Ðеобходимо ви е разрешение от <ph name="NAME" />, за да поÑетите този Ñайт</translation>
+<translation id="1721424275792716183">* Полето е задължително</translation>
<translation id="1728677426644403582">Преглеждате Ð¸Ð·Ñ…Ð¾Ð´Ð½Ð¸Ñ ÐºÐ¾Ð´ на уеб Ñтраница</translation>
+<translation id="173080396488393970">Този тип карта не Ñе поддържа</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Свържете Ñе ÑÑŠÑ ÑиÑÑ‚ÐµÐ¼Ð½Ð¸Ñ Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñтратор.</translation>
+<translation id="1740951997222943430">Въведете валиден меÑец на изтичане</translation>
<translation id="1745358365027406341">ИзтеглÑне на Ñтраницата по-къÑно</translation>
<translation id="17513872634828108">Отворени раздели</translation>
<translation id="1753706481035618306">Ðомер на Ñтраницата</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">МолÑ, актуализирайте пропуÑка Ñи за Ñинхронизиране.</translation>
<translation id="1787142507584202372">Тук ще Ñе показват отворените ви раздели</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Изберете Ð°Ð´Ñ€ÐµÑ Ð·Ð° бърза доÑтавка, за да проверите Ñъответните начини и изиÑкваниÑ.</translation>
+<translation id="1803264062614276815">Име на титулÑÑ€Ñ Ð½Ð° картата</translation>
<translation id="1803678881841855883">Google БезопаÑно Ñърфиране наÑкоро <ph name="BEGIN_LINK" />откри злонамерен Ñофтуер<ph name="END_LINK" /> на <ph name="SITE" />. УебÑайтовете, които обикновено Ñа безопаÑни, понÑкога Ñе заразÑват Ñ Ñ‚Ð°ÐºÑŠÐ² Ñофтуер. Източникът на Ñъответното Ñъдържание е <ph name="SUBRESOURCE_HOST" /> – извеÑтен разпроÑтранител на злонамерен Ñофтуер. <ph name="BEGIN_LEARN_MORE_LINK" />Ðаучете повече<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Добавено: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">ЗаÑвката или параметрите й Ñа невалидни</translation>
<translation id="1826516787628120939">Извършва Ñе проверка</translation>
<translation id="1834321415901700177">Този Ñайт Ñъдържа опаÑни програми</translation>
<translation id="1842969606798536927">Плащане</translation>
-<translation id="1864455488461349376">ÐžÐ¿Ñ†Ð¸Ñ Ð·Ð° бърза доÑтавка</translation>
<translation id="1871208020102129563">За прокÑи Ñървъра е зададено да използва фикÑирани прокÑи Ñървъри, а не URL Ð°Ð´Ñ€ÐµÑ Ð½Ð° Ñкрипт във формат .pac.</translation>
<translation id="1871284979644508959">Задължително поле</translation>
<translation id="187918866476621466">ОтварÑне на Ñтраниците при Ñтартиране</translation>
<translation id="1883255238294161206">Свиване на ÑпиÑъка</translation>
<translation id="1898423065542865115">Филтриране</translation>
<translation id="194030505837763158">Към <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Приемани карти</translation>
<translation id="1962204205936693436">Отметки от <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Грешка при Ñериализирането</translation>
<translation id="1974060860693918893">Разширени</translation>
<translation id="1978555033938440688">ВерÑÐ¸Ñ Ð½Ð° фърмуера</translation>
+<translation id="1995859865337580572">МолÑ, потвърдете кода Ñи за проверка</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{и още 1}other{и още #}}</translation>
-<translation id="2020194265157481222">Името на ÐºÐ°Ñ€Ñ‚Ð¾Ð´ÑŠÑ€Ð¶Ð°Ñ‚ÐµÐ»Ñ Ðµ задължително</translation>
<translation id="2025186561304664664">За прокÑи Ñървъра е зададена автоматична конфигурациÑ.</translation>
<translation id="2030481566774242610">Може би имахте предвид <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Проверете прокÑи Ñървъра и защитната Ñтена<ph name="END_LINK" />.</translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">ДнеÑ</translation>
<translation id="2154054054215849342">Синхронизирането не е налице за Ð²ÑŠÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾Ñ‚ Ð²Ð°Ñ Ð´Ð¾Ð¼ÐµÐ¹Ð½</translation>
<translation id="2154484045852737596">Редактиране на картата</translation>
-<translation id="2156993118928861787">Ðевалиден адреÑ</translation>
<translation id="2166049586286450108">Пълен админиÑтраторÑки доÑтъп</translation>
<translation id="2166378884831602661">Този Ñайт не може да оÑигури защитена връзка</translation>
<translation id="2181821976797666341">Правила</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 адреÑ}other{# адреÑа}}</translation>
+<translation id="2202020181578195191">Въведете валидна година на изтичане</translation>
<translation id="2212735316055980242">Правилото не е намерено</translation>
<translation id="2213606439339815911">ЗапиÑите Ñе извличат...</translation>
<translation id="2230458221926704099">Поправете връзката Ñи поÑредÑтвом <ph name="BEGIN_LINK" />приложението за диагноÑтика<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">ДоÑтъпът ви до интернет е блокиран</translation>
<translation id="230155334948463882">Ðова карта?</translation>
<translation id="2305919008529760154">Сървърът не можа да докаже, че е <ph name="DOMAIN" />. Възможно е Ñертификатът му за ÑигурноÑÑ‚ да е издаден измамничеÑки. Това може да Ñе дължи на неправилно конфигуриране или на прехващане на връзката ви от извършител на атака. <ph name="BEGIN_LEARN_MORE_LINK" />Ðаучете повече<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Опциите за карти и адреÑи Ñа от профила ви в Google (<ph name="ACCOUNT_EMAIL" />) и Chrome. Можете да ги управлÑвате от <ph name="BEGIN_LINK" />наÑтройките<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535">ИзиÑкват Ñе потребителÑко име и парола за <ph name="DOMAIN" />.</translation>
<translation id="2318774815570432836">Ð’ момента не можете да поÑетите <ph name="SITE" />, защото уебÑайтът използва HSTS. Обикновено мрежовите грешки и атаки Ñа временни, така че тази Ñтраница вероÑтно ще работи по-къÑно. <ph name="BEGIN_LEARN_MORE_LINK" />Ðаучете повече<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Други отметки</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Зададено по подразбиране в корпоративна Ñреда</translation>
<translation id="2386255080630008482">Сертификатът на Ñървъра е анулиран.</translation>
<translation id="2392959068659972793">Да Ñе показват правилата без зададена ÑтойноÑÑ‚</translation>
+<translation id="239429038616798445">Този начин на доÑтавка не Ñе поддържа. Опитайте Ñ Ð´Ñ€ÑƒÐ³.</translation>
<translation id="2396249848217231973">&amp;ОтмÑна на изтриването</translation>
<translation id="2460160116472764928">Google БезопаÑно Ñърфиране наÑкоро <ph name="BEGIN_LINK" />откри злонамерен Ñофтуер<ph name="END_LINK" /> на <ph name="SITE" />. УебÑайтовете, които обикновено Ñа безопаÑни, понÑкога Ñе заразÑват Ñ Ñ‚Ð°ÐºÑŠÐ² Ñофтуер. <ph name="BEGIN_LEARN_MORE_LINK" />Ðаучете повече<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Попълване</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Стартирайте мрежова диагноÑтика<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Ðевалиден URL Ð°Ð´Ñ€ÐµÑ Ð·Ð° Ñ‚ÑŠÑ€Ñене.</translation>
<translation id="2491120439723279231">Сертификатът на Ñървъра Ñъдържа грешки.</translation>
-<translation id="24943777258388405">ТелефонниÑÑ‚ номер е невалиден</translation>
<translation id="2495083838625180221">Синтактичен анализ на JSON</translation>
<translation id="2495093607237746763">Ðко поÑтавите отметка, Chromium ще ÑъхранÑва на това уÑтройÑтво копие на картата ви Ñ Ñ†ÐµÐ» по-бързо попълване на формулÑри.</translation>
<translation id="2498091847651709837">Сканиране на нова карта</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> изпрати невалиден отговор.</translation>
<translation id="2552545117464357659">По-нова</translation>
<translation id="2556876185419854533">&amp;ОтмÑна на редактирането</translation>
+<translation id="2587730715158995865">От <ph name="ARTICLE_PUBLISHER" />. Прочетете тази и още <ph name="OTHER_ARTICLE_COUNT" /> Ñтатии.</translation>
<translation id="2587841377698384444">ID на API за директории:</translation>
<translation id="2597378329261239068">Този документ е защитен Ñ Ð¿Ð°Ñ€Ð¾Ð»Ð°. МолÑ, въведете Ñ.</translation>
<translation id="2609632851001447353">Вариации</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Стартирайте диагноÑтика на ÑвързаноÑтта<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">Премахване на избраните елементи</translation>
+<translation id="277133753123645258">Ðачин на доÑтавка</translation>
<translation id="277499241957683684">ЛипÑващ Ð·Ð°Ð¿Ð¸Ñ Ð·Ð° уÑтройÑтвото</translation>
<translation id="2784949926578158345">Връзката бе възÑтановена.</translation>
<translation id="2794233252405721443">Сайтът е блокиран</translation>
-<translation id="2812680587231492111">Тази Ð¾Ð¿Ñ†Ð¸Ñ Ð·Ð° вземане не Ñе поддържа. Опитайте Ñ Ð´Ñ€ÑƒÐ³Ð°.</translation>
<translation id="2824775600643448204">Лента за адреÑи и за Ñ‚ÑŠÑ€Ñене</translation>
<translation id="2826760142808435982">Връзката е шифрована и удоÑтоверена поÑредÑтвом <ph name="CIPHER" /> и използва <ph name="KX" /> като механизъм за обмен на ключове.</translation>
<translation id="2835170189407361413">ИзчиÑтване на формулÑра</translation>
-<translation id="2849041323157393173">Тази Ð¾Ð¿Ñ†Ð¸Ñ Ð·Ð° бърза доÑтавка не Ñе поддържа. Опитайте Ñ Ð´Ñ€ÑƒÐ³Ð°.</translation>
<translation id="2889159643044928134">Без презареждане</translation>
<translation id="2900469785430194048">Паметта на Google Chrome Ñе изчерпа, докато браузърът опитваше да покаже тази уеб Ñтраница.</translation>
<translation id="2909946352844186028">УÑтановена бе промÑна в мрежата.</translation>
<translation id="2916038427272391327">Затворете другите програми.</translation>
<translation id="2922350208395188000">Сертификатът на Ñървъра не може да бъде проверен.</translation>
+<translation id="2928905813689894207">ÐÐ´Ñ€ÐµÑ Ð·Ð° фактуриране</translation>
<translation id="2948083400971632585">Можете да деактивирате вÑички конфигурирани за дадена връзка прокÑи Ñървъри от Ñтраницата „ÐаÑтройки“.</translation>
<translation id="2955913368246107853">ЗатварÑне на лентата за Ñ‚ÑŠÑ€Ñене</translation>
<translation id="2958431318199492670">КонфигурациÑта на мрежата не Ñпазва Ñтандарта на ONC. Възможно е чаÑти от Ð½ÐµÑ Ð´Ð° не Ñа импортирани.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">За уÑтановÑване на Ñигурна връзка е необходимо чаÑовникът ви да е верен. Това е така, защото Ñертификатите, Ñ ÐºÐ¾Ð¸Ñ‚Ð¾ уебÑайтовете Ñе идентифицират, Ñа валидни Ñамо за конкретни периоди от време. Тъй като чаÑовникът на уÑтройÑтвото ви не е верен, Google Chrome не може да потвърди тези Ñертификати.</translation>
<translation id="2972581237482394796">&amp;ВъзÑтановÑване</translation>
<translation id="2985306909656435243">Ðко наÑтройката е активирана, Chromium ще ÑъхранÑва на това уÑтройÑтво копие на картата ви Ñ Ñ†ÐµÐ» по-бързо попълване на формулÑри.</translation>
+<translation id="2985398929374701810">Въведете валиден адреÑ</translation>
+<translation id="2986368408720340940">Този начин на вземане не Ñе поддържа. Опитайте Ñ Ð´Ñ€ÑƒÐ³.</translation>
<translation id="2991174974383378012">СподелÑне Ñ ÑƒÐµÐ±Ñайтове</translation>
<translation id="3005723025932146533">Показване на запазено копие</translation>
<translation id="3008447029300691911">Въведете кода за проверка за <ph name="CREDIT_CARD" />. След като потвърдите картата Ñи, данните за Ð½ÐµÑ Ñ‰Ðµ бъдат Ñподелени Ñ Ñ‚Ð¾Ð·Ð¸ Ñайт.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{поне 1 елемент на Ñинхронизирани уÑтройÑтва}=1{1 елемент (и други на Ñинхронизирани уÑтройÑтва)}other{# елемента (и други на Ñинхронизирани уÑтройÑтва)}}</translation>
<translation id="3041612393474885105">Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° Ñертификата</translation>
<translation id="3063697135517575841">Chrome не можа да потвърди картата ви. МолÑ, опитайте отново по-къÑно.</translation>
+<translation id="3064966200440839136">Ще напуÑнете режим „инкогнито“, за да платите във външно приложение. ИÑкате ли да продължите?</translation>
<translation id="3093245981617870298">ПонаÑтоÑщем Ñте офлайн.</translation>
<translation id="3105172416063519923">ID на актива:</translation>
<translation id="3109728660330352905">ÐÑмате Ð¿ÑŠÐ»Ð½Ð¾Ð¼Ð¾Ñ‰Ð¸Ñ Ð·Ð° преглед на тази Ñтраница.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Опитайте да Ñтартирате диагноÑтика на ÑвързаноÑтта<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Декодирането на отговора не бе уÑпешно</translation>
-<translation id="3149891296864842641">ÐžÐ¿Ñ†Ð¸Ñ Ð·Ð° доÑтавка</translation>
<translation id="3150653042067488994">Временна грешка в Ñървъра</translation>
+<translation id="3154506275960390542">Тази Ñтраница включва формулÑÑ€, който не може да Ñе изпрати по Ñигурен начин. Данните, които изпращате, могат да бъдат преглеждани от други хора, докато Ñе прехвърлÑÑ‚, или модифицирани от извършител на атака, така че да Ñе промени това, което Ñървърът получава.</translation>
<translation id="3157931365184549694">ВъзÑтановÑване</translation>
<translation id="3167968892399408617">Страниците, които преглеждате в разделите в режим „инкогнито“, нÑма да оÑтанат в иÑториÑта на браузъра, хранилището за „биÑквитки“ или иÑториÑта на Ñ‚ÑŠÑ€Ñенето, Ñлед като затворите вÑички раздели в този режим. Изтеглените от Ð²Ð°Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð²Ðµ или Ñъздадените от Ð²Ð°Ñ Ð¾Ñ‚Ð¼ÐµÑ‚ÐºÐ¸ обаче ще бъдат запазени.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">ЗаÑвката ви за доÑтъп до този Ñайт не можа да Ñе изпрати до <ph name="NAME" />. МолÑ, опитайте отново.</translation>
<translation id="3355823806454867987">ПромÑна на наÑтройките на прокÑи Ñървъра...</translation>
<translation id="3369192424181595722">Грешка в чаÑовника</translation>
+<translation id="337311366426640088">Още <ph name="ITEM_COUNT" /> елемента...</translation>
<translation id="337363190475750230">Обезпечаването е отменено</translation>
<translation id="3377188786107721145">Грешка при ÑÐ¸Ð½Ñ‚Ð°ÐºÑ‚Ð¸Ñ‡Ð½Ð¸Ñ Ð°Ð½Ð°Ð»Ð¸Ð· на правилото</translation>
<translation id="3380365263193509176">ÐеизвеÑтна грешка</translation>
<translation id="3380864720620200369">Идент. â„– на клиентÑката програма:</translation>
<translation id="3391030046425686457">ÐÐ´Ñ€ÐµÑ Ð·Ð° бърза доÑтавка</translation>
+<translation id="3395827396354264108">Ðачин на вземане</translation>
<translation id="340013220407300675">Възможно е извършители на атака да опитват да откраднат ваша Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ñ‚ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (например пароли, ÑÑŠÐ¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ данни за кредитни карти).</translation>
<translation id="3422248202833853650">Затворете другите програми, за да оÑвободите памет.</translation>
<translation id="3422472998109090673">ПонаÑтоÑщем нÑма доÑтъп до <ph name="HOST_NAME" />.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Интервал на извличане:</translation>
<translation id="3462200631372590220">Скриване на подробноÑтите</translation>
+<translation id="3467763166455606212">ТрÑбва да въведете името на титулÑÑ€Ñ Ð½Ð° картата</translation>
+<translation id="3478058380795961209">МеÑец на валидноÑÑ‚</translation>
<translation id="3479539252931486093">Това неочаквано ли беше? <ph name="BEGIN_LINK" />Уведомете ни<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Ðе Ñега</translation>
<translation id="348000606199325318">Идентификатор на Ñрива: <ph name="CRASH_LOCAL_ID" /> (Идентификатор на Ñървъра: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Ðе можахме да Ñе Ñвържем Ñ Ñ€Ð¾Ð´Ð¸Ñ‚ÐµÐ»Ñ Ð²Ð¸. МолÑ, опитайте отново.</translation>
<translation id="3528171143076753409">Сертификатът на Ñървъра не е надежден.</translation>
-<translation id="3538531656504267329">Ðеправилна година на валидноÑÑ‚</translation>
<translation id="3539171420378717834">СъхранÑване на копие на картата на това уÑтройÑтво</translation>
<translation id="3542684924769048008">Използване на паролата за:</translation>
<translation id="3549644494707163724">Ð’Ñички Ñинхронизирани данни да Ñе шифроват ÑÑŠÑ ÑобÑÑ‚Ð²ÐµÐ½Ð¸Ñ Ð²Ð¸ пропуÑк за Ñинхронизиране</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Скриване на подробноÑтите</translation>
<translation id="3587482841069643663">Ð’Ñички</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Въведете валидна дата на изтичане</translation>
<translation id="36224234498066874">ИзчиÑтване на данните за Ñърфирането...</translation>
<translation id="362276910939193118">Показване на пълната иÑториÑ</translation>
<translation id="3623476034248543066">Показване на ÑтойноÑтта</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Парола:</translation>
<translation id="3696411085566228381">нÑма</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> „<ph name="TITLE" />“ <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Изберете Ð°Ð´Ñ€ÐµÑ Ð·Ð° доÑтавка, за да проверите начините и изиÑкваниÑта за доÑтавÑне.</translation>
<translation id="370665806235115550">Зарежда Ñе...</translation>
<translation id="3712624925041724820">Лицензите Ñа изчерпани</translation>
<translation id="3714780639079136834">Включете мобилните данни или Wi-Fi.</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Копирана от Ð²Ð°Ñ Ð²Ñ€ÑŠÐ·ÐºÐ°</translation>
<translation id="375403751935624634">Преводът не бе уÑпешен поради грешка в Ñървъра.</translation>
<translation id="3759461132968374835">ÐаÑкоро не Ñте Ñъобщавали за Ñривове. Тези, възникнали при деактивирано изпращане на Ñигнали за Ñривове, не Ñе показват тук.</translation>
+<translation id="3787705759683870569">Изтича на <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Ðко използвате прокÑи Ñървър...</translation>
<translation id="3828924085048779000">Ðе може пропуÑкът да не Ñе попълни.</translation>
<translation id="3845539888601087042">Показва Ñе иÑториÑта от уÑтройÑтвата, на които Ñте влезли в профила Ñи. <ph name="BEGIN_LINK" />Ðаучете повече<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">ИÑкате ли Chromium да запази тази карта?</translation>
<translation id="4171400957073367226">Ðевалиден Ð¿Ð¾Ð´Ð¿Ð¸Ñ Ð·Ð° потвърждаване</translation>
-<translation id="4176463684765177261">Деактивирано</translation>
<translation id="4196861286325780578">&amp;ВъзÑтановÑване на премеÑтването</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Проверете конфигурациÑта на защитната Ñтена и антивируÑÐ½Ð¸Ñ Ñофтуер<ph name="END_LINK" />.</translation>
<translation id="4206349416402437184">{COUNT,plural, =0{нÑма}=1{1 приложение ($1)}=2{2 Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ($1, $2)}other{# Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">резултата от Ñ‚ÑŠÑ€Ñенето</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> не прие Ñертификата ви за вход или е възможно да не е предоÑтавен такъв.</translation>
<translation id="443673843213245140">Използването на прокÑи Ñървър е деактивирано, но е поÑочена изрична негова конфигурациÑ.</translation>
-<translation id="4446242550670694251">Вече можете да Ñърфирате чаÑтно. Така другите хора, които използват това уÑтройÑтво, нÑма да виждат активноÑтта ви.</translation>
<translation id="4492190037599258964">Резултати от Ñ‚ÑŠÑ€Ñенето на „<ph name="SEARCH_STRING" />“</translation>
<translation id="4506176782989081258">Грешка при потвърждаването: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Свържете Ñе ÑÑŠÑ ÑиÑÑ‚ÐµÐ¼Ð½Ð¸Ñ Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñтратор.</translation>
<translation id="450710068430902550">СподелÑне Ñ Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñтратор</translation>
+<translation id="4515275063822566619">Картите и адреÑите Ñа от Chrome и профила ви в Google (<ph name="ACCOUNT_EMAIL" />). Можете да ги управлÑвате от <ph name="BEGIN_LINK" />наÑтройките<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">ПодробноÑти</translation>
<translation id="4558551763791394412">Опитайте да деактивирате разширениÑта.</translation>
<translation id="457875822857220463">Бърза доÑтавка</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Да Ñе побере в Ñтраницата</translation>
<translation id="483020001682031208">ÐÑма Ñтраници във ФизичеÑката мрежа, които да ви покажем</translation>
<translation id="4850886885716139402">Изглед</translation>
+<translation id="4854362297993841467">Този начин на бърза доÑтавка не Ñе поддържа. Опитайте Ñ Ð´Ñ€ÑƒÐ³.</translation>
<translation id="4858792381671956233">Попитахте родителите Ñи дали може да поÑетите този Ñайт</translation>
<translation id="4880827082731008257">ТърÑене в иÑториÑта</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> и <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Тази Ñтраница е преведена от непознат език на <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Плащане</translation>
<translation id="4926049483395192435">ТрÑбва да Ñе поÑочи.</translation>
-<translation id="4941291666397027948">* указва задължително поле</translation>
<translation id="495170559598752135">ДейÑтвиÑ</translation>
<translation id="4958444002117714549">Разгъване на ÑпиÑъка</translation>
<translation id="4962322354953122629">Сървърът не можа да докаже, че е <ph name="DOMAIN" />. Сертификатът му за ÑигурноÑÑ‚ не Ñе Ñчита за надежден от Chrome. Това може да Ñе дължи на неправилно конфигуриране или на прехващане на връзката ви от извършител на атака. <ph name="BEGIN_LEARN_MORE_LINK" />Ðаучете повече<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Грешна парола</translation>
<translation id="5056549851600133418">Статии за ваÑ</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Проверете адреÑа на прокÑи Ñървъра<ph name="END_LINK" />.</translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{ÐÑма „биÑквитки“}=1{1 Ñайт използва „биÑквитки“. }other{# Ñайта използват „биÑквитки“. }}</translation>
<translation id="5087286274860437796">ПонаÑтоÑщем Ñертификатът на Ñървъра не е валиден.</translation>
<translation id="5087580092889165836">ДобавÑне на карта</translation>
<translation id="5089810972385038852">Щат</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Показване</translation>
<translation id="5308689395849655368">Изпращането на Ñигнали за Ñривове е деактивирано.</translation>
<translation id="5317780077021120954">Запазване</translation>
-<translation id="5326702247179446998">ТрÑбва да въведете получател</translation>
<translation id="5327248766486351172">Име</translation>
<translation id="5337705430875057403">Извършителите на атака Ñрещу <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> може да ви подведат да направите нещо опаÑно, като например да инÑталирате Ñофтуер или да разкриете лична Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ (например пароли, телефонни номера или номера на кредитни карти).</translation>
-<translation id="53553865750799677">ÐдреÑÑŠÑ‚ за вземане не Ñе поддържа. Изберете друг.</translation>
<translation id="5359637492792381994">Сървърът не можа да докаже, че е <ph name="DOMAIN" />. ПонаÑтоÑщем Ñертификатът му за ÑигурноÑÑ‚ не е валиден. Това може да Ñе дължи на неправилно конфигуриране или на прехващане на връзката ви от извършител на атака. <ph name="BEGIN_LEARN_MORE_LINK" />Ðаучете повече<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">СъхранÑването на наÑтройките за правилото не бе уÑпешно</translation>
<translation id="5386426401304769735">Веригата от Ñертификати за този Ñайт Ñъдържа Ñертификат, подпиÑан Ñ SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">Вградена Ñтраница на Ð°Ð´Ñ€ÐµÑ <ph name="SITE" /> изпраща подкана:</translation>
<translation id="5556459405103347317">Повторно зареждане</translation>
<translation id="5565735124758917034">Ðктивно</translation>
+<translation id="5571083550517324815">Този Ð°Ð´Ñ€ÐµÑ Ð·Ð° вземане не Ñе поддържа. Изберете друг.</translation>
<translation id="5572851009514199876">МолÑ, Ñтартирайте браузъра Chrome и влезте в него, за да Ñе провери дали имате доÑтъп до този Ñайт.</translation>
-<translation id="5575380383496039204">ÐдреÑÑŠÑ‚ за бърза доÑтавка не Ñе поддържа. Изберете друг.</translation>
<translation id="5580958916614886209">Проверете меÑеца на валидноÑÑ‚ и опитайте отново</translation>
<translation id="560412284261940334">Управлението не Ñе поддържа</translation>
<translation id="5610142619324316209">Проверете връзката.</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">СамоличноÑтта на този уебÑайт не е потвърдена.</translation>
<translation id="5720705177508910913">ТекущиÑÑ‚ потребител</translation>
<translation id="5732392974455271431">Родителите ви могат да го отблокират за ваÑ</translation>
-<translation id="57586589942790530">Ðевалиден номер на карта</translation>
+<translation id="5763042198335101085">Въведете валиден имейл адреÑ</translation>
+<translation id="5765072501007116331">За да видите начините на бърза доÑтавка и изиÑкваниÑта, изберете адреÑ</translation>
<translation id="5784606427469807560">При потвърждаването на картата ви възникна проблем. Проверете връзката Ñи Ñ Ð¸Ð½Ñ‚ÐµÑ€Ð½ÐµÑ‚ и опитайте отново.</translation>
<translation id="5785756445106461925">ОÑвен това тази Ñтраница включва други реÑурÑи, които не Ñа защитени. Докато Ñе предават, те могат да бъдат видени от други хора и да бъдат модифицирани от извършител на атака, така че да Ñе промени изгледът на Ñтраницата.</translation>
<translation id="5786044859038896871">ИÑкате ли да Ñе попълнÑÑ‚ данните за кредитната ви карта?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">ÐÑма доÑтъп до този Ñайт</translation>
<translation id="5869522115854928033">Запазени пароли</translation>
<translation id="5872918882028971132">ОÑновни предложениÑ</translation>
-<translation id="587760065310675640">ÐдреÑÑŠÑ‚ за доÑтавка не Ñе поддържа. Изберете друг.</translation>
<translation id="5901630391730855834">жълто</translation>
-<translation id="59174027418879706">Ðктивирано</translation>
<translation id="5926846154125914413">Може да загубите доÑтъп до платено Ñъдържание от нÑкои Ñайтове.</translation>
<translation id="5959728338436674663">Ðвтоматично изпращане до Google на <ph name="BEGIN_WHITEPAPER_LINK" />ÑиÑтемна Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¸ чаÑÑ‚ от Ñъдържанието на Ñтраниците<ph name="END_WHITEPAPER_LINK" /> Ñ Ñ†ÐµÐ» по-леÑно откриване на опаÑни Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸ Ñайтове. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Седмица</translation>
<translation id="5967867314010545767">Премахване от иÑториÑта</translation>
<translation id="5975083100439434680">ÐамалÑване на мащаба</translation>
+<translation id="598637245381783098">Приложението за плащане не може да Ñе отвори</translation>
<translation id="5989320800837274978">Ðе Ñа поÑочени нито фикÑирани прокÑи Ñървъри, нито URL Ð°Ð´Ñ€ÐµÑ Ð½Ð° Ñкрипт във формат .pac.</translation>
<translation id="5990559369517809815">ЗаÑвките към Ñървъра Ñа блокирани от разширение.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Опциите за карти и адреÑи Ñа от Chrome. Можете да ги управлÑвате от <ph name="BEGIN_LINK" />наÑтройките<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Страница 1}other{Страница #}}</translation>
<translation id="6017514345406065928">зелено</translation>
+<translation id="6027201098523975773">Въведете име</translation>
<translation id="6040143037577758943">ЗатварÑне</translation>
-<translation id="604124094241169006">Ðвтоматично</translation>
<translation id="6042308850641462728">Още</translation>
<translation id="6060685159320643512">Внимавайте, тези екÑперименти може да Ñа опаÑни</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{нÑма}=1{1}other{#}}</translation>
@@ -543,9 +552,10 @@
уÑтройÑтва, които може да използвате.</translation>
<translation id="614940544461990577">Изпробвайте Ñледното:</translation>
<translation id="6151417162996330722">Сертификатът на Ñървъра има твърде дълъг период на валидноÑÑ‚.</translation>
-<translation id="615643356032862689">Изтеглените файлове и отметки ще бъдат Ñъхранени.</translation>
+<translation id="6157877588268064908">За да видите начините на доÑтавка и изиÑкваниÑта, изберете адреÑ</translation>
<translation id="6165508094623778733">Ðаучете повече</translation>
<translation id="6177128806592000436">Връзката ви Ñ Ñ‚Ð¾Ð·Ð¸ Ñайт не е защитена</translation>
+<translation id="6184817833369986695">(кохорта: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Проверете връзката Ñи Ñ Ð¸Ð½Ñ‚ÐµÑ€Ð½ÐµÑ‚</translation>
<translation id="6218753634732582820">ÐдреÑÑŠÑ‚ да Ñе премахне ли от Chromium?</translation>
<translation id="6251924700383757765">Ð”ÐµÐºÐ»Ð°Ñ€Ð°Ñ†Ð¸Ñ Ð·Ð° поверителноÑÑ‚</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;ВъзÑтановÑване на пренареждането</translation>
<translation id="6263376278284652872">Отметки от <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Ðазад към безопаÑната Ñтраница</translation>
+<translation id="6276112860590028508">Страниците от ÑпиÑъка ви за четене Ñе показват тук</translation>
+<translation id="6280223929691119688">Този Ð°Ð´Ñ€ÐµÑ Ð·Ð° бърза доÑтавка не Ñе поддържа. Изберете друг.</translation>
<translation id="6282194474023008486">ПощенÑки код</translation>
<translation id="6290238015253830360">Предложените ви Ñтатии ще Ñе показват тук</translation>
<translation id="6305205051461490394">ÐÑма доÑтъп до <ph name="URL" />.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Ðе може да Ñе провери дали Ñертификатът е анулиран.</translation>
<translation id="6433490469411711332">Редактиране на информациÑта за връзка</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> отказа да уÑтанови връзка.</translation>
-<translation id="6443118737398455446">Датата на валидноÑÑ‚ е недейÑтвителна</translation>
<translation id="6446608382365791566">ДобавÑне на още информациÑ</translation>
<translation id="6451458296329894277">Потвърдете повторното изпращане на формулÑра</translation>
<translation id="6456339708790392414">Вашето плащане</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Сървърът не можа да докаже, че е <ph name="DOMAIN" />. Възможно е Ñертификатът му за ÑигурноÑÑ‚ да е анулиран. Това може да Ñе дължи на неправилно конфигуриране или на прехващане на връзката ви от извършител на атака. <ph name="BEGIN_LEARN_MORE_LINK" />Ðаучете повече<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Правила за уÑтройÑтвото</translation>
<translation id="6477321094435799029">Chrome откри необичаен код на тази Ñтраница и Ñ Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð°, за да защити личната ви Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ (например пароли, телефонни номера и номера на кредитни карти).</translation>
-<translation id="6477460825583319731">Имейл адреÑÑŠÑ‚ е невалиден</translation>
<translation id="6489534406876378309">Стартиране на качването на Ñривове</translation>
<translation id="6508722015517270189">РеÑтартирайте Chrome.</translation>
-<translation id="6525462735697194615">Ðеправилен меÑец на валидноÑÑ‚</translation>
<translation id="6529602333819889595">&amp;ВъзÑтановÑване на изтриването</translation>
<translation id="6534179046333460208">ÐŸÑ€ÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¾Ñ‚ ФизичеÑката мрежа</translation>
<translation id="6550675742724504774">Опции</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685">ТърÑене Ñ/ÑŠÑ <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Това правило е оттеглено.</translation>
<translation id="6652240803263749613">Сървърът не можа да докаже, че е <ph name="DOMAIN" />. Сертификатът му за ÑигурноÑÑ‚ не Ñе Ñчита за надежден от операционната ÑиÑтема на компютъра ви. Това може да Ñе дължи на неправилно конфигуриране или на прехващане на връзката ви от извършител на атака. <ph name="BEGIN_LEARN_MORE_LINK" />Ðаучете повече<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Тази Ð¾Ð¿Ñ†Ð¸Ñ Ð·Ð° доÑтавка не Ñе поддържа. Опитайте Ñ Ð´Ñ€ÑƒÐ³Ð°.</translation>
<translation id="6671697161687535275">Предложението за формулÑри да Ñе премахне ли от Chromium?</translation>
<translation id="6685834062052613830">Излизане от профила и завършване на наÑтройването</translation>
<translation id="6710213216561001401">Предишна</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Ðещо не е наред Ñ Ð¿Ñ€Ð¾ÐºÑи Ñървъра или адреÑÑŠÑ‚ е неправилен.</translation>
<translation id="6727102863431372879">Задаване</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{нÑма}=1{1 елемент}other{# елемента}}</translation>
-<translation id="6743044928064272573">ÐžÐ¿Ñ†Ð¸Ñ Ð·Ð° вземане</translation>
<translation id="674375294223700098">ÐеизвеÑтна грешка в Ñертификата на Ñървъра.</translation>
<translation id="6753269504797312559">СтойноÑÑ‚ за правилото</translation>
<translation id="6757797048963528358">УÑтройÑтвото ви премина в ÑпÑщ режим.</translation>
<translation id="6778737459546443941">РодителÑÑ‚ ви вÑе още не е одобрил заÑвката</translation>
<translation id="6810899417690483278">Идент. â„– на перÑонализирането</translation>
<translation id="6820686453637990663">Код за ÑигурноÑÑ‚</translation>
+<translation id="6824266427216888781">Зареждането на данните за регионите не бе уÑпешно</translation>
<translation id="6831043979455480757">Превод</translation>
<translation id="6839929833149231406">Район</translation>
<translation id="6874604403660855544">&amp;ВъзÑтановÑване на добавÑнето</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Картата ви е потвърдена</translation>
<translation id="6897140037006041989">ПотребителÑки агент</translation>
<translation id="6915804003454593391">Потребител:</translation>
+<translation id="6948701128805548767">За да видите начините на вземане и изиÑкваниÑта, изберете адреÑ</translation>
<translation id="6957887021205513506">Изглежда, че Ñертификатът на Ñървъра е подправен.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">УÑтройÑтво</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">ПоÑочени Ñа както фикÑирани прокÑи Ñървъри, така и URL Ð°Ð´Ñ€ÐµÑ Ð½Ð° Ñкрипт във формат .pac.</translation>
<translation id="6989763994942163495">Показване на разширените наÑтройки...</translation>
<translation id="7000990526846637657">ÐÑма намерени запиÑи в иÑториÑта</translation>
-<translation id="7001663382399377034">ДобавÑне на получател</translation>
<translation id="7009986207543992532">Опитахте да Ñе Ñвържете Ñ/ÑŠÑ <ph name="DOMAIN" />, но Ñървърът предоÑтави Ñертификат, чийто период на валидноÑÑ‚ е твърде дълъг, за да е надежден. <ph name="BEGIN_LEARN_MORE_LINK" />Ðаучете повече<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Възможно е в профила ви в Google да има други видове иÑÑ‚Ð¾Ñ€Ð¸Ñ Ð½Ð° Ñърфиране, ÑъхранÑвани на Ð°Ð´Ñ€ÐµÑ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">По-Ñтара</translation>
<translation id="7090678807593890770">ПотърÑете „<ph name="LINK" />“ Ñ Google</translation>
<translation id="7119414471315195487">Затворете другите раздели или програми.</translation>
+<translation id="7129409597930077180">Този Ð°Ð´Ñ€ÐµÑ Ð·Ð° доÑтавка не Ñе поддържа. Изберете друг.</translation>
+<translation id="7138472120740807366">Ðачин на бърза доÑтавка</translation>
<translation id="7139724024395191329">ЕмирÑтво</translation>
<translation id="7155487117670177674">Страницата за плащане не е защитена</translation>
<translation id="7179921470347911571">Стартиране отново Ñега</translation>
<translation id="7180611975245234373">ОпреÑнÑване</translation>
<translation id="7182878459783632708">ÐÑма зададени правила</translation>
<translation id="7186367841673660872">Тази Ñтраница е преведена от<ph name="ORIGINAL_LANGUAGE" />на<ph name="LANGUAGE_LANGUAGE" /></translation>
+<translation id="7192203810768312527">Ще оÑвободите <ph name="SIZE" />. ÐÑкои Ñайтове може да Ñе заредÑÑ‚ по-бавно при Ñледващото ви поÑещение.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> не Ñе придържа към Ñтандартите за ÑигурноÑÑ‚.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Ðаучете повече<ph name="END_LINK" /> за този проблем.</translation>
@@ -675,7 +686,6 @@
<translation id="7424977062513257142">Страница, вградена в тази уеб Ñтраница, изпраща подкана:</translation>
<translation id="7441627299479586546">Грешен предмет на правилото</translation>
<translation id="7444046173054089907">Този Ñайт е блокиран</translation>
-<translation id="7444238235002594607">Изберете Ð°Ð´Ñ€ÐµÑ Ð·Ð° вземане, за да проверите Ñъответните начини и изиÑкваниÑ.</translation>
<translation id="7445762425076701745">ИдентичноÑтта на Ñървъра, към който Ñте Ñвързани, не може да бъде потвърдена изцÑло. Свързани Ñте към Ñървър чрез име, което е валидно Ñамо във вашата мрежа и чиÑто ÑобÑтвеноÑÑ‚ нÑма начин да Ñе потвърди от външен Ñертифициращ орган. Тъй като нÑкои Ñертифициращи органи въпреки това издават Ñертификати за такива имена, не е възможно да Ñе гарантира, че Ñте Ñвързани към Ð¶ÐµÐ»Ð°Ð½Ð¸Ñ Ñайт, а не към атакуващ.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Ðаучете повече<ph name="END_LINK" /> за този проблем.</translation>
<translation id="7460163899615895653">Тук Ñе показват Ñкорошните раздели от други уÑтройÑтва</translation>
@@ -719,6 +729,7 @@
<translation id="7755287808199759310">РодителÑÑ‚ ви може да го отблокира за ваÑ</translation>
<translation id="7758069387465995638">Възможно е връзката да е блокирана от защитна Ñтена или антивируÑен Ñофтуер.</translation>
<translation id="7761701407923456692">Сертификатът на Ñървъра не ÑъответÑтва на URL адреÑа.</translation>
+<translation id="7763386264682878361">ИнÑтрумент за Ñинтактичен анализ на манифеÑти за плащаниÑ</translation>
<translation id="7764225426217299476">ДобавÑне на адреÑ</translation>
<translation id="777702478322588152">Префектура</translation>
<translation id="7791543448312431591">ДобавÑне</translation>
@@ -732,6 +743,7 @@
<translation id="785549533363645510">Сърфирането ви обаче не е невидимо. При преминаване в режим „инкогнито“ то не Ñе Ñкрива от Ñ€Ð°Ð±Ð¾Ñ‚Ð¾Ð´Ð°Ñ‚ÐµÐ»Ñ Ð²Ð¸ и от доÑтавчика ви на интернет уÑлуги, нито от уебÑайтовете, които поÑещавате.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Прегледайте кода за проверка и опитайте отново</translation>
+<translation id="79338296614623784">Въведете валиден телефонен номер</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Сертификатът на Ñървъра още не е валиден.</translation>
<translation id="7942349550061667556">червено</translation>
@@ -751,6 +763,7 @@
<translation id="8088680233425245692">Преглеждането на ÑтатиÑта не бе уÑпешно.</translation>
<translation id="8089520772729574115">по-малко от 1 МБ</translation>
<translation id="8091372947890762290">Ð’ Ñървъра Ñе изчаква активиране</translation>
+<translation id="8118489163946903409">Ðачин на плащане</translation>
<translation id="8131740175452115882">Потвърждаване</translation>
<translation id="8134994873729925007">Ðе можа да бъде намерен <ph name="BEGIN_ABBR" />DNS адреÑÑŠÑ‚<ph name="END_ABBR" /> на Ñървъра на <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Компютърът ви премина в ÑпÑщ режим.</translation>
@@ -776,6 +789,7 @@
<translation id="8349305172487531364">Лента на отметките</translation>
<translation id="8363502534493474904">Изключете ÑÐ°Ð¼Ð¾Ð»ÐµÑ‚Ð½Ð¸Ñ Ñ€ÐµÐ¶Ð¸Ð¼.</translation>
<translation id="8364627913115013041">Ðе е зададено.</translation>
+<translation id="8368476060205742148">УÑлуги за Google Play</translation>
<translation id="8380941800586852976">ОпаÑно</translation>
<translation id="8382348898565613901">ÐаÑкоро поÑетените от Ð²Ð°Ñ Ð¾Ñ‚Ð¼ÐµÑ‚ÐºÐ¸ ще Ñе показват тук</translation>
<translation id="8398259832188219207">Сигналът за Ñрив е качен в/ъв <ph name="UPLOAD_TIME" /></translation>
@@ -784,31 +798,29 @@
<translation id="8428213095426709021">ÐаÑтройки</translation>
<translation id="8433057134996913067">Ще излезете от повечето уебÑайтове.</translation>
<translation id="8437238597147034694">&amp;ОтмÑна на премеÑтването</translation>
-<translation id="8456681095658380701">Ðевалидно име</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 кредитна карта}other{# кредитни карти}}</translation>
<translation id="8483780878231876732">За да използвате картите от профила Ñи в Google, влезте в Chrome</translation>
<translation id="8488350697529856933">Прилага Ñе към</translation>
-<translation id="8492969205326575646">Ðеподдържан тип карта</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> не Ð¾Ñ‚Ð³Ð¾Ð²Ð°Ñ€Ñ Ñ‚Ð²ÑŠÑ€Ð´Ðµ дълго време.</translation>
<translation id="852346902619691059">Сървърът не можа да докаже, че е <ph name="DOMAIN" />. Сертификатът му за ÑигурноÑÑ‚ не Ñе Ñчита за надежден от операционната ÑиÑтема на уÑтройÑтвото ви. Това може да Ñе дължи на неправилно конфигуриране или на прехващане на връзката ви от извършител на атака. <ph name="BEGIN_LEARN_MORE_LINK" />Ðаучете повече<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Година на валидноÑÑ‚</translation>
<translation id="8543181531796978784">Можете да <ph name="BEGIN_ERROR_LINK" />подадете Ñигнал за проблем при откриването<ph name="END_ERROR_LINK" /> или, ако разбирате риÑковете за ÑигурноÑтта Ñи, да <ph name="BEGIN_LINK" />поÑетите този небезопаÑен Ñайт<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Преводът не бе уÑпешен, защото езикът на Ñтраницата не можа да бъде определен.</translation>
<translation id="8559762987265718583">Ðе може да Ñе уÑтанови чаÑтна връзка Ñ/ÑŠÑ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, тъй като датата и чаÑÑŠÑ‚ на уÑтройÑтвото ви (<ph name="DATE_AND_TIME" />) Ñа неправилни.</translation>
-<translation id="8570229484593575558">Следната Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ |нÑма да бъде запазена|:#иÑториÑта ви на Ñърфиране;#Ñ‚ÑŠÑ€ÑениÑта ви;#данните в „биÑквитките“.</translation>
<translation id="8571890674111243710">Превод на Ñтраницата на <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">ÐктивноÑтта ви |може да оÑтане видима| за:#уебÑайтовете, които поÑещавате;#Ñ€Ð°Ð±Ð¾Ñ‚Ð¾Ð´Ð°Ñ‚ÐµÐ»Ñ Ð²Ð¸;#доÑтавчика ви на интернет уÑлуги.</translation>
<translation id="858637041960032120">+ тел. номер</translation>
<translation id="859285277496340001">Сертификатът не поÑочва механизъм за проверка дали е бил анулиран.</translation>
<translation id="8620436878122366504">Родителите ви вÑе още не Ñа одобрили заÑвката</translation>
<translation id="8647750283161643317">ВъзÑтановÑване на вÑичко към Ñтандартното ÑÑŠÑтоÑние</translation>
<translation id="8703575177326907206">Връзката ви Ñ <ph name="DOMAIN" /> не е шифрована.</translation>
+<translation id="8718314106902482036">Плащането не е завършено</translation>
<translation id="8725066075913043281">Опитайте отново</translation>
<translation id="8728672262656704056">Преминахте в режим „инкогнито“</translation>
<translation id="8730621377337864115">Готово</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="8759274551635299824">Тази карта е изтекла</translation>
<translation id="8790007591277257123">&amp;ВъзÑтановÑване на изтриването</translation>
-<translation id="8798099450830957504">По подразбиране</translation>
<translation id="8800988563907321413">Тук ще Ñе показват Ð¿Ñ€ÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° неща в близоÑÑ‚</translation>
<translation id="8820817407110198400">Отметки</translation>
<translation id="883848425547221593">Други отметки</translation>
@@ -818,6 +830,7 @@
<translation id="8866481888320382733">Грешка при ÑÐ¸Ð½Ñ‚Ð°ÐºÑ‚Ð¸Ñ‡Ð½Ð¸Ñ Ð°Ð½Ð°Ð»Ð¸Ð· на наÑтройките за правилото</translation>
<translation id="8866959479196209191">Тази Ñтраница изпраща подкана:</translation>
<translation id="8870413625673593573">ÐаÑкоро затворени</translation>
+<translation id="8874824191258364635">Въведете валиден номер на карта</translation>
<translation id="8876793034577346603">СинтактичниÑÑ‚ анализ на конфигурациÑта на мрежата не бе уÑпешен.</translation>
<translation id="8877192140621905067">След като потвърдите картата Ñи, данните за Ð½ÐµÑ Ñ‰Ðµ бъдат Ñподелени Ñ Ñ‚Ð¾Ð·Ð¸ Ñайт</translation>
<translation id="8889402386540077796">Цветови тон</translation>
@@ -827,7 +840,6 @@
<translation id="8931333241327730545">ИÑкате ли да запазите тази карта в профила Ñи в Google?</translation>
<translation id="8932102934695377596">ЧаÑовникът ви е назад</translation>
<translation id="8954894007019320973">(Прод.)</translation>
-<translation id="895548565263634352">Прочетете ÑÑ‚Ð°Ñ‚Ð¸Ñ Ð¾Ñ‚ <ph name="ARTICLE_PUBLISHER" /> и още <ph name="OTHER_ARTICLE_COUNT" /></translation>
<translation id="8971063699422889582">Сертификатът на Ñървъра е Ñ Ð¸Ð·Ñ‚ÐµÐºÐ»Ð° валидноÑÑ‚.</translation>
<translation id="8986494364107987395">Ðвтоматично изпращане до Google на ÑтатиÑтичеÑки данни за използването на Chrome и Ñигнали за Ñривове</translation>
<translation id="8987927404178983737">МеÑец</translation>
@@ -845,7 +857,6 @@
<translation id="9068849894565669697">Избор на цвÑÑ‚</translation>
<translation id="9076283476770535406">Възможно е да има Ñъдържание за пълнолетни</translation>
<translation id="9078964945751709336">ИзиÑква Ñе още информациÑ</translation>
-<translation id="9094175695478007090">Приложението за плащане не може да Ñе Ñтартира.</translation>
<translation id="9103872766612412690">Обикновено <ph name="SITE" /> използва шифроване за защита на информациÑта ви. Когато Chromium опита да уÑтанови връзка Ñ/ÑŠÑ <ph name="SITE" /> този път, уебÑайтът върна необичайни и неправилни идентификационни данни. Това може да Ñе Ñлучи, когато извършител на атака пробва да Ñе предÑтави за <ph name="SITE" /> или връзката е прекъÑната от екран за вход в Wi-Fi. ИнформациÑта ви продължава да е защитена, тъй като Chromium ÑÐ¿Ñ€Ñ Ð²Ñ€ÑŠÐ·ÐºÐ°Ñ‚Ð°, преди да бъдат обменени данни.</translation>
<translation id="9137013805542155359">Показване на оригинала</translation>
<translation id="9137248913990643158">МолÑ, Ñтартирайте браузъра Chrome и влезте в него, преди да използвате това приложение.</translation>
diff --git a/chromium/components/strings/components_strings_bn.xtb b/chromium/components/strings/components_strings_bn.xtb
index c6bbf07a53d..41b1c904228 100644
--- a/chromium/components/strings/components_strings_bn.xtb
+++ b/chromium/components/strings/components_strings_bn.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="bn">
<translation id="1008557486741366299">à¦à¦–নই নয়</translation>
<translation id="1015730422737071372">অতিরিকà§à¦¤ বিবরণ দিন</translation>
+<translation id="1021110881106174305">à¦à¦‡ কারà§à¦¡à¦—à§à¦²à¦¿ গà§à¦°à¦¹à¦£ করা হয়</translation>
<translation id="1032854598605920125">ঘড়ির কাà¦à¦Ÿà¦¾à¦° দিকে ঘোরান</translation>
<translation id="1038842779957582377">অজানা নাম</translation>
<translation id="1050038467049342496">অনà§à¦¯à¦¾à¦¨à§à¦¯ অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨à¦—à§à¦²à¦¿ বনà§à¦§ করà§à¦¨</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">মান লà§à¦•à¦¾à¦¨</translation>
<translation id="1228893227497259893">ভà§à¦² সতà§à¦¤à¦¾ সনাকà§à¦¤à¦•à¦¾à¦°à§€</translation>
<translation id="1232569758102978740">শিরোনামহীন</translation>
+<translation id="1263231323834454256">পড়ার তালিকা</translation>
<translation id="1264126396475825575">কà§à¦°à§à¦¯à¦¾à¦¶ পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨ <ph name="CRASH_TIME" /> ঠকà§à¦¯à¦¾à¦ªà¦šà¦¾à¦° করা হয়েছে (à¦à¦–নো আপলোড করা বা উপেকà§à¦·à¦¾ করা হয়নি)</translation>
<translation id="1285320974508926690">কখনই à¦à¦‡ সাইটটিকে অনà§à¦¬à¦¾à¦¦ করবেন না</translation>
<translation id="129553762522093515">সমà§à¦ªà§à¦°à¦¤à¦¿ বনà§à¦§ হয়েছে</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromium সà§à¦¬à¦¤à¦ƒà¦ªà§‚রà§à¦£ সেটিংস...</translation>
<translation id="1374468813861204354">পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¨à¦¾à¦—à§à¦²à¦¿</translation>
<translation id="1375198122581997741">সংসà§à¦•à¦°à¦£ সমà§à¦ªà¦°à§à¦•à§‡</translation>
+<translation id="1377321085342047638">কারà§à¦¡ নমà§à¦¬à¦°</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> কোনো তথà§à¦¯ পাঠায়নি।</translation>
<translation id="1407135791313364759">সব খà§à¦²à§à¦¨</translation>
<translation id="1413809658975081374">গোপনীয়তা তà§à¦°à§à¦Ÿà¦¿</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">ইতিহাস</translation>
<translation id="1645368109819982629">অসমরà§à¦¥à¦¿à¦¤ পà§à¦°à§‹à¦Ÿà§‹à¦•à¦²</translation>
<translation id="1656489000284462475">তà§à¦²à§‡ নিন</translation>
+<translation id="1663943134801823270">Chrome থেকে কারà§à¦¡ à¦à¦¬à¦‚ ঠিকানাগà§à¦²à¦¿ à¦à¦¸à§‡à¦›à§‡à¥¤ আপনি <ph name="BEGIN_LINK" />সেটিংস<ph name="END_LINK" /> ঠà¦à¦—à§à¦²à¦¿ পরিচালনা করতে পারবেন।</translation>
<translation id="1676269943528358898"><ph name="SITE" /> সাধারণত আপনার তথà§à¦¯ সà§à¦°à¦•à§à¦·à¦¿à¦¤ রাখতে à¦à¦¨à¦•à§à¦°à¦¿à¦ªà¦¶à¦¾à¦¨ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে। à¦à¦‡à¦¬à¦¾à¦° যখন Google Chrome <ph name="SITE" /> à¦à¦° সাথে সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ করার চেষà§à¦Ÿà¦¾ করেছে, তখন ওয়েবসাইটটি অসà§à¦¬à¦¾à¦­à¦¾à¦¬à¦¿à¦• à¦à¦¬à¦‚ ভà§à¦² শংসাপতà§à¦° পাঠিয়েছে। হয় à¦à¦•à¦œà¦¨ আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ <ph name="SITE" /> হওয়ার ভান করছে, অথবা কোনো ওয়াই-ফাই পà§à¦°à¦¬à§‡à¦¶ করà§à¦¨ সà§à¦•à§à¦°à§€à¦£ সংযোগকে বাধা দেওয়া হয়েছে। আপনার তথà§à¦¯ à¦à¦–নো নিরাপদ আছে কারণ কোনো ডেটা আদানপà§à¦°à¦¦à¦¾à¦¨à§‡à¦° আগেই Google Chrome সংযোগটিকে বনà§à¦§ করে দিয়েছে।</translation>
<translation id="168328519870909584">বরà§à¦¤à¦®à¦¾à¦¨à§‡ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ঠথাকা আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦°à¦¾ আপনার ডিভাইসে বিপদজনক অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨ ইনà§à¦¸à¦Ÿà¦² করার চেষà§à¦Ÿà¦¾ করতে পারে, যা আপনার তথà§à¦¯ (উদাহরণসà§à¦¬à¦°à§‚প, ফটো, পাসওয়ারà§à¦¡, বারà§à¦¤à¦¾, à¦à¦¬à¦‚ কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡) চà§à¦°à¦¿ করতে বা মà§à¦›à§‡ দিতে পারে।</translation>
<translation id="168841957122794586">সারà§à¦­à¦¾à¦° শংসাপতà§à¦°à§‡ à¦à¦•à¦Ÿà¦¿ দà§à¦°à§à¦¬à¦² কপিরাইট কী আছে৷</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">à¦à¦‡ সাইটে যেতে আপনাকে <ph name="NAME" /> à¦à¦° কাছ থেকে অনà§à¦®à¦¤à¦¿ নিতে হবে</translation>
+<translation id="1721424275792716183">* à¦à¦‡ ফিলà§à¦¡à§‡ কিছৠলেখা পà§à¦°à§Ÿà§‹à¦œà¦¨</translation>
<translation id="1728677426644403582">আপনি à¦à¦•à¦Ÿà¦¿ ওয়েব পৃষà§à¦ à¦¾à¦° উৎস কোড দেখছেন</translation>
+<translation id="173080396488393970">à¦à¦–ানে à¦à¦‡ ধরনের কারà§à¦¡ কাজ করে না</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">সিসà§à¦Ÿà§‡à¦® পà§à¦°à¦¶à¦¾à¦¸à¦•à§‡à¦° সাথে যোগাযোগ করে দেখà§à¦¨à¥¤</translation>
+<translation id="1740951997222943430">মেয়াদ শেষ হওয়ার মাসের সঠিক মান লিখà§à¦¨</translation>
<translation id="1745358365027406341">পৃষà§à¦ à¦¾à¦Ÿà¦¿ পরে ডাউনলোড করà§à¦¨</translation>
<translation id="17513872634828108">খোলা টà§à¦¯à¦¾à¦¬</translation>
<translation id="1753706481035618306">পৃষà§à¦ à¦¾ সংখà§à¦¯à¦¾</translation>
@@ -88,14 +95,13 @@
<translation id="1783075131180517613">দয়া করে আপনার সিঙà§à¦• পাসফà§à¦°à§‡à¦œ আপডেট করà§à¦¨à§·</translation>
<translation id="1787142507584202372">আপনার খোলা টà§à¦¯à¦¾à¦¬à¦—à§à¦²à¦¿ à¦à¦–ানে দেখা যাবে</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">পৌà¦à¦›à§‡ দেওয়ার পদà§à¦§à¦¤à¦¿ ও পà§à¦°à¦¯à¦¼à§‹à¦œà¦¨à§€à¦¯à¦¼à¦¤à¦¾à¦—à§à¦²à¦¿ দেখার জনà§à¦¯ পৌà¦à¦›à§‡ দেওয়ার à¦à¦•à¦Ÿà¦¿ ঠিকানা নিরà§à¦¬à¦¾à¦šà¦¨ করà§à¦¨à¥¤</translation>
+<translation id="1803264062614276815">কারà§à¦¡ হোলà§à¦¡à¦¾à¦°à§‡à¦° নাম</translation>
<translation id="1803678881841855883">Google নিরাপদ বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ সমà§à¦ªà§à¦°à¦¤à¦¿ <ph name="SITE" /> ঠ<ph name="BEGIN_LINK" />মালওয়ের শনাকà§à¦¤ করেছে<ph name="END_LINK" />। যেসব ওয়েবসাইট সাধারণত নিরাপদ থাকে, সেগà§à¦²à¦¿ কখনও কখনও মালওয়ের দà§à¦¬à¦¾à¦°à¦¾ আকà§à¦°à¦¾à¦¨à§à¦¤ হয়। à¦à¦•à¦Ÿà¦¿ পরিচিত মালওয়ের বিতরণকারী, <ph name="SUBRESOURCE_HOST" /> থেকে কà§à¦·à¦¤à¦¿à¦•à¦¾à¦°à¦• সামগà§à¦°à§€à¦Ÿà¦¿ à¦à¦¸à§‡à¦›à§‡à¥¤ <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="1806541873155184440">যোগ করা হয়েছে <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">অবৈধ অনà§à¦°à§‹à¦§ বা অনà§à¦°à§‹à¦§ মাপকাঠিগà§à¦²à¦¿</translation>
<translation id="1826516787628120939">চেক করা হচà§à¦›à§‡</translation>
<translation id="1834321415901700177">à¦à¦‡ সাইটটিতে কà§à¦·à¦¤à¦¿à¦•à¦° পà§à¦°à§‹à¦—à§à¦°à¦¾à¦® রয়েছে</translation>
<translation id="1842969606798536927">অরà§à¦¥ পà§à¦°à¦¦à¦¾à¦¨ করà§à¦¨</translation>
-<translation id="1864455488461349376">পৌà¦à¦›à§‡ দেওয়ার বিকলà§à¦ª</translation>
<translation id="1871208020102129563">
পà§à¦°à¦•à§à¦¸à¦¿ সà§à¦¥à¦¿à¦° পà§à¦°à¦•à§à¦¸à¦¿ সারà§à¦­à¦¾à¦°à¦—à§à¦²à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে সেট করা আছে কোনো .pac সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ URL নয়৷</translation>
<translation id="1871284979644508959">আবশà§à¦¯à¦• কà§à¦·à§‡à¦¤à§à¦°</translation>
@@ -103,13 +109,12 @@
<translation id="1883255238294161206">তালিকা সঙà§à¦•à§à¦šà¦¿à¦¤ করà§à¦¨</translation>
<translation id="1898423065542865115">ফিলà§à¦Ÿà¦¾à¦° হচà§à¦›à§‡</translation>
<translation id="194030505837763158"><ph name="LINK" /> ঠযান</translation>
-<translation id="1946821392246652573">কারà§à¦¡ গà§à¦°à¦¹à¦£ করা হয়েছে</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> বà§à¦•à¦®à¦¾à¦°à§à¦•à¦—à§à¦²à¦¿</translation>
<translation id="1973335181906896915">ধারাবাহিকতাতে তà§à¦°à§à¦Ÿà¦¿</translation>
<translation id="1974060860693918893">উনà§à¦¨à¦¤</translation>
<translation id="1978555033938440688">ফারà§à¦®à¦“য়ের সংসà§à¦•à¦°à¦£</translation>
+<translation id="1995859865337580572">অনà§à¦—à§à¦°à¦¹ করে আপনার CVC যাচাই করà§à¦¨</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{à¦à¦¬à¦‚ আরো ১টি}one{à¦à¦¬à¦‚ আরো #টি}other{à¦à¦¬à¦‚ আরো #টি}}</translation>
-<translation id="2020194265157481222">কারà§à¦¡à§‡ থাকা নাম আবশà§à¦¯à¦•</translation>
<translation id="2025186561304664664">সà§à¦¬à¦¤à¦ƒ কনফিগার করতে পà§à¦°à¦•à§à¦¸à¦¿ সেট করা হয়৷</translation>
<translation id="2030481566774242610">আপনি কি <ph name="LINK" /> বোà¦à¦¾à¦¤à§‡ চেয়েছিলেন?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />পà§à¦°à¦•à§à¦¸à¦¿ à¦à¦¬à¦‚ ফায়ারওয়াল পরীকà§à¦·à¦¾ করে দেখà§à¦¨<ph name="END_LINK" /></translation>
@@ -129,11 +134,11 @@
<translation id="2148716181193084225">আজ</translation>
<translation id="2154054054215849342">আপনার ডোমেনের জনà§à¦¯ সিঙà§à¦• উপলবà§à¦§ নেই</translation>
<translation id="2154484045852737596">কারà§à¦¡ সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ করà§à¦¨</translation>
-<translation id="2156993118928861787">অবৈধ ঠিকানা</translation>
<translation id="2166049586286450108">পূরà§à¦£ পà§à¦°à¦¶à¦¾à¦¸à¦• অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸</translation>
<translation id="2166378884831602661">à¦à¦‡ সাইটটি à¦à¦•à¦Ÿà¦¿ সà§à¦°à¦•à§à¦·à¦¿à¦¤ সংযোগ দিতে পারছে না</translation>
<translation id="2181821976797666341">নীতিসমূহ</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{১টি ঠিকানা}one{ #টি ঠিকানা}other{ #টি ঠিকানা}}</translation>
+<translation id="2202020181578195191">মেয়াদ শেষ হওয়ার বছরের সঠিক মান লিখà§à¦¨</translation>
<translation id="2212735316055980242">নীতি পাওয়া যায়নি</translation>
<translation id="2213606439339815911">à¦à¦¨à§à¦Ÿà§à¦°à¦¿à¦—à§à¦²à¦¿ আনা হচà§à¦›à§‡...</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />ডায়াগনসà§à¦Ÿà¦¿à¦• অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨<ph name="END_LINK" /> বà§à¦¯à¦¬à¦¹à¦¾à¦° করে আপনার সংযোগ ঠিক করà§à¦¨</translation>
@@ -144,7 +149,6 @@
<translation id="2292556288342944218">আপনার ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ অবরà§à¦¦à§à¦§ করা হয়েছে</translation>
<translation id="230155334948463882">নতà§à¦¨ কারà§à¦¡?</translation>
<translation id="2305919008529760154">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ পà§à¦°à¦¤à¦¾à¦°à¦£à¦¾à¦ªà§‚রà§à¦£ উপায়ে জারি করা হতে পারে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিচà§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
-<translation id="230697611605700222">কারà§à¦¡ à¦à¦¬à¦‚ ঠিকানার বিকলà§à¦ªà¦—à§à¦²à¦¿ Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ (<ph name="ACCOUNT_EMAIL" />) à¦à¦¬à¦‚ Chrome থেকে পাওয়া। আপনি <ph name="BEGIN_LINK" />সেটিংস<ph name="END_LINK" /> থেকে à¦à¦—à§à¦²à¦¿ পরিচালনা করতে পারেন।</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> à¦à¦° জনà§à¦¯ à¦à¦•à¦Ÿà¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€à¦° নাম à¦à¦¬à¦‚ পাসওয়ারà§à¦¡ পà§à¦°à¦¯à¦¼à§‹à¦œà¦¨à¥¤</translation>
<translation id="2318774815570432836">আপনি à¦à¦–ন <ph name="SITE" /> ঠযেতে পারবেন না কারণ ওয়েবসাইটটি HSTS বà§à¦¯à¦¬à¦¹à¦¾à¦° করছে। নেটওয়ারà§à¦• তà§à¦°à§à¦Ÿà¦¿ à¦à¦¬à¦‚ আকà§à¦°à¦®à¦£ সাধারণত সাময়িকভাবে হয়ে থাকে, তাই à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ সমà§à¦­à¦¬à¦¤ পরে কাজ করবে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="2354001756790975382">অনà§à¦¯ বà§à¦•à¦®à¦¾à¦°à§à¦•à¦¸</translation>
@@ -157,13 +161,13 @@
<translation id="2384307209577226199">à¦à¦¨à§à¦Ÿà¦¾à¦°à¦ªà§à¦°à¦¾à¦‡à¦œ ডিফলà§à¦Ÿ</translation>
<translation id="2386255080630008482">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦°à¦Ÿà¦¿ পà§à¦°à¦¤à§à¦¯à¦¾à¦¹à¦¾à¦° করা হয়েছে৷</translation>
<translation id="2392959068659972793">কোনো মান সেট করা নেই à¦à¦®à¦¨ নীতিগà§à¦²à¦¿ দেখান</translation>
+<translation id="239429038616798445">à¦à¦‡ পদà§à¦§à¦¤à¦¿à¦¤à§‡ শিপিং করা যাবে না। অনà§à¦¯ পদà§à¦§à¦¤à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨à¥¤</translation>
<translation id="2396249848217231973">&amp;মà§à¦›à§‡ ফেলাকে পূরà§à¦¬à¦¾à¦¬à¦¸à§à¦¥à¦¾à¦¯à¦¼ ফেরান</translation>
<translation id="2460160116472764928">Google নিরাপদ বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ সমà§à¦ªà§à¦°à¦¤à¦¿ <ph name="SITE" /> ঠ<ph name="BEGIN_LINK" />মালওয়ের শনাকà§à¦¤ করেছে<ph name="END_LINK" />। যেসব ওয়েবসাইট সাধারণত নিরাপদ থাকে, সেগà§à¦²à¦¿ কখনও কখনও মালওয়ের দà§à¦¬à¦¾à¦°à¦¾ আকà§à¦°à¦¾à¦¨à§à¦¤ হয়। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="2463739503403862330">পূরণ করà§à¦¨</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />নেটওয়ারà§à¦• ডায়গনিসà§à¦Ÿà¦¿à¦•à§à¦¸ চালান<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">অবৈধ অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨à§‡à¦° URL৷</translation>
<translation id="2491120439723279231">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦°à§‡ তà§à¦°à§à¦Ÿà¦¿ আছে৷</translation>
-<translation id="24943777258388405">অবৈধ ফোন নমà§à¦¬à¦°</translation>
<translation id="2495083838625180221">JSON বিশà§à¦²à§‡à¦·à¦•</translation>
<translation id="2495093607237746763">টিক চিহà§à¦£ দেওয়া থাকলে, ফরà§à¦® পূরনের কাজ দà§à¦°à§à¦¤ করতে Chromium à¦à¦‡ ডিভাইসে আপনার কারà§à¦¡à§‡à¦° à¦à¦•à¦Ÿà¦¿ পà§à¦°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ সঞà§à¦šà§Ÿ করবে।</translation>
<translation id="2498091847651709837">নতà§à¦¨ কারà§à¦¡ সà§à¦•à§à¦¯à¦¾à¦¨ করà§à¦¨</translation>
@@ -173,6 +177,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> à¦à¦•à¦Ÿà¦¿ অবৈধ পà§à¦°à¦¤à¦¿à¦•à§à¦°à¦¿à¦¯à¦¼à¦¾ পাঠিয়েছে।</translation>
<translation id="2552545117464357659">নবীনতর</translation>
<translation id="2556876185419854533">&amp;সমà§à¦ªà¦¾à¦¦à¦¨à¦¾à¦•à§‡ পূরà§à¦¬à¦¾à¦¬à¦¸à§à¦¥à¦¾à¦¯à¦¼ ফেরান</translation>
+<translation id="2587730715158995865"><ph name="ARTICLE_PUBLISHER" /> থেকে পাওয়া। à¦à¦Ÿà¦¿ à¦à¦¬à¦‚ আরো <ph name="OTHER_ARTICLE_COUNT" />টি গলà§à¦ª পড়à§à¦¨à¥¤</translation>
<translation id="2587841377698384444">ডিরেকà§à¦Ÿà¦°à¦¿ API আইডি:</translation>
<translation id="2597378329261239068">à¦à¦‡ দসà§à¦¤à¦¾à¦¬à§‡à¦œà¦Ÿà¦¿ পাসওয়ারà§à¦¡ সà§à¦°à¦•à§à¦·à¦¿à¦¤à§· দয়া করে à¦à¦•à¦Ÿà¦¿ পাসওয়ারà§à¦¡ লিখà§à¦¨à§·</translation>
<translation id="2609632851001447353">বৈচিতà§à¦°à¦¤à¦¾</translation>
@@ -198,19 +203,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />সংযোগের ডায়গনিসà§à¦Ÿà¦¿à¦•à§à¦¸ চালান<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">ঠিক আছে</translation>
<translation id="2742870351467570537">নিরà§à¦¬à¦¾à¦šà¦¿à¦¤ আইটেমগà§à¦²à¦¿ সরান</translation>
+<translation id="277133753123645258">শিপিংয়ের পদà§à¦§à¦¤à¦¿</translation>
<translation id="277499241957683684">ডিভাইস রেকরà§à¦¡ অনà§à¦ªà¦¸à§à¦¥à¦¿à¦¤</translation>
<translation id="2784949926578158345">সংযোগ পà§à¦¨à¦ƒà¦¸à§‡à¦Ÿ করা হয়েছে৷</translation>
<translation id="2794233252405721443">সাইট অবরà§à¦¦à§à¦§ করা হয়েছে</translation>
-<translation id="2812680587231492111">পিকআপ বিকলà§à¦ªà¦Ÿà¦¿ উপলবà§à¦§ নেই। অনà§à¦¯ à¦à¦•à¦Ÿà¦¿ বিকলà§à¦ª বà§à¦¯à¦¬à¦¹à¦¾à¦° করে দেখà§à¦¨à¥¤</translation>
<translation id="2824775600643448204">ঠিকানা à¦à¦¬à¦‚ অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ দণà§à¦¡</translation>
<translation id="2826760142808435982"><ph name="CIPHER" /> বà§à¦¯à¦¬à¦¹à¦¾à¦° করে à¦à¦‡ সংযোগটি à¦à¦¨à¦•à§à¦°à¦¿à¦ªà§à¦Ÿà§‡à¦¡ à¦à¦¬à¦‚ পà§à¦°à¦®à¦¾à¦£à§€à¦•à§ƒà¦¤ করা হয়েছে à¦à¦¬à¦‚ কী à¦à¦•à§à¦¸à¦šà§‡à¦žà§à¦œ পà§à¦°à¦•à§à¦°à¦¿à§Ÿà¦¾ হিসাবে <ph name="KX" /> বà§à¦¯à¦¬à¦¹à¦¾à¦° করে৷</translation>
<translation id="2835170189407361413">ফরà§à¦® সাফ করà§à¦¨</translation>
-<translation id="2849041323157393173">ডেলিভারির বিকলà§à¦ªà¦Ÿà¦¿ উপলবà§à¦§ নেই। অনà§à¦¯ à¦à¦•à¦Ÿà¦¿ বিকলà§à¦ª বà§à¦¯à¦¬à¦¹à¦¾à¦° করে দেখà§à¦¨à¥¤</translation>
<translation id="2889159643044928134">আবার লোড করবেন না</translation>
<translation id="2900469785430194048">à¦à¦‡ ওয়েবপৃষà§à¦ à¦¾ পà§à¦°à¦¦à¦°à§à¦¶à¦¨ করার সময় Google Chrome à¦à¦° মেমরি শেষ হয়ে গেছে।</translation>
<translation id="2909946352844186028">à¦à¦•à¦Ÿà¦¿ নেটওয়ারà§à¦• পরিবরà§à¦¤à¦¨ সনাকà§à¦¤ হয়েছে৷</translation>
<translation id="2916038427272391327">অনà§à¦¯à¦¾à¦¨à§à¦¯ পà§à¦°à§‹à¦—à§à¦°à¦¾à¦®à¦—à§à¦²à¦¿ বনà§à¦§ করà§à¦¨</translation>
<translation id="2922350208395188000">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦° চেক করা যাবে না৷</translation>
+<translation id="2928905813689894207">বিলিংয়ের ঠিকানা</translation>
<translation id="2948083400971632585">আপনি সেটিংস পৃষà§à¦ à¦¾ থেকে সংযোগের জনà§à¦¯ কনফিগার করা যেকোনো পà§à¦°à¦•à§à¦¸à¦¿ নিষà§à¦•à§à¦°à¦¿à¦¯à¦¼ করতে পারেন৷</translation>
<translation id="2955913368246107853">খোà¦à¦œ দণà§à¦¡ বনà§à¦§ করà§à¦¨</translation>
<translation id="2958431318199492670">নেটওয়ারà§à¦• কনফিগারেশন ONC মানকের সাথে সমà§à¦®à¦¤ নয়৷ কনফিগারেশনের অংশগà§à¦²à¦¿ আমদানিকৃত নাও হতে পারে৷</translation>
@@ -219,6 +224,8 @@
<translation id="2969319727213777354">নিরাপদ নেটওয়ারà§à¦• সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ করতে আপনার ঘড়িকে সঠিকভাবে সেট করতে হবে। à¦à¦®à¦¨ হওয়ার কারণ হলো, নিরাপদ সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ করার জনà§à¦¯ নিজেদের সনাকà§à¦¤ করার জনà§à¦¯ ওয়েবসাইটগà§à¦²à¦¿ যে শংসাপতà§à¦°à¦—à§à¦²à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে, সেগà§à¦²à¦¿ শà§à¦§à§à¦®à¦¾à¦¤à§à¦° নিরà§à¦¦à¦¿à¦·à§à¦Ÿ সময়ের জনà§à¦¯ বৈধ থাকে। যেহেতৠআপনার ডিভাইসের ঘড়িটি ভà§à¦², সেই জনà§à¦¯ Google Chrome সঠিকভাবে শংসাপতà§à¦°à¦—à§à¦²à¦¿ পরীকà§à¦·à¦¾ করতে পারছে না।</translation>
<translation id="2972581237482394796">&amp;পà§à¦¨à¦°à¦¾à§Ÿ করà§à¦¨</translation>
<translation id="2985306909656435243">সকà§à¦·à¦® করা হলে, ফরà§à¦® পূরনের কাজ দà§à¦°à§à¦¤ করতে Chromium à¦à¦‡ ডিভাইসে আপনার কারà§à¦¡à§‡à¦° à¦à¦•à¦Ÿà¦¿ পà§à¦°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ সংরকà§à¦·à¦£ করবে।</translation>
+<translation id="2985398929374701810">à¦à¦•à¦Ÿà¦¿ সঠিক ঠিকানা লিখà§à¦¨</translation>
+<translation id="2986368408720340940">à¦à¦‡ পদà§à¦§à¦¤à¦¿à¦¤à§‡ পিক-আপ করা যাবে না। অনà§à¦¯ পদà§à¦§à¦¤à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨à¥¤</translation>
<translation id="2991174974383378012">ওয়েবসাইটের সাথে ভাগ করছে</translation>
<translation id="3005723025932146533">সংরকà§à¦·à¦¿à¦¤ পà§à¦°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ দেখান</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> à¦à¦° CVC লিখà§à¦¨à¥¤ আপনি নিশà§à¦šà¦¿à¦¤ করলে, আপনার কারà§à¦¡à§‡à¦° বিবরণ à¦à¦‡ সাইটের সাথে শেয়ার করা হবে।</translation>
@@ -229,13 +236,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{সিঙà§à¦• করা ডিভাইসে নà§à¦¯à§‚নতম ১টি আইটেম}=1{১টি আইটেম (à¦à¦¬à¦‚ সিঙà§à¦• করা ডিভাইসে আরো)}one{#টি আইটেম (à¦à¦¬à¦‚ সিঙà§à¦• করা ডিভাইসে আরো)}other{#টি আইটেম (à¦à¦¬à¦‚ সিঙà§à¦• করা ডিভাইসে আরো)}}</translation>
<translation id="3041612393474885105">শংসাপতà§à¦° তথà§à¦¯</translation>
<translation id="3063697135517575841">Chrome à¦à¦‡ মà§à¦¹à§‚রà§à¦¤à§‡ আপনার কারà§à¦¡ নিশà§à¦šà¦¿à¦¤ করতে পারছে না৷ অনà§à¦—à§à¦°à¦¹ করে পরে আবার চেষà§à¦Ÿà¦¾ করà§à¦¨à§·</translation>
+<translation id="3064966200440839136">বহিরাগত অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨à§‡à¦° মাধà§à¦¯à¦®à§‡ অরà§à¦¥à¦ªà§à¦°à¦¦à¦¾à¦¨ করার জনà§à¦¯ ছদà§à¦®à¦¬à§‡à¦¶à§€ মোড থেকে বেরিয়ে যাচà§à¦›à§‡à¥¤ চালিয়ে যাবেন?</translation>
<translation id="3093245981617870298">আপনি অফলাইনে আছেন৷</translation>
<translation id="3105172416063519923">সমà§à¦ªà¦¦ আইডি:</translation>
<translation id="3109728660330352905">আপনার à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ দেখার জনà§à¦¯ অনà§à¦®à§‹à¦¦à¦¨ নেই।</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />সংযোগের ডায়গনিসà§à¦Ÿà¦¿à¦•à§à¦¸ চালিয়ে দেখà§à¦¨<ph name="END_LINK" />।</translation>
<translation id="3145945101586104090">পà§à¦°à¦¤à¦¿à¦•à§à¦°à¦¿à¦¯à¦¼à¦¾ ডিকোড করতে বà§à¦¯à¦°à§à¦¥ হয়েছে</translation>
-<translation id="3149891296864842641">পাঠানোর বিকলà§à¦ª</translation>
<translation id="3150653042067488994">সাময়িক সারà§à¦­à¦¾à¦° তà§à¦°à§à¦Ÿà¦¿</translation>
+<translation id="3154506275960390542">à¦à¦‡ পৃষà§à¦ à¦¾à¦¤à§‡ à¦à¦•à¦Ÿà¦¿ ফরà§à¦® আছে যেটি জমা দেওয়া নিরাপদ নাও হতে পারে। আপনার পাঠানো ডেটা সারà§à¦­à¦¾à¦°à§‡ পৌà¦à¦›à¦¾à¦¨à§‹à¦° আগে অনà§à¦¯à¦°à¦¾ সেটি দেখতে পেতে পারেন, অথবা কেউ সেটি পরিবরà§à¦¤à¦¨ করে দিতে পারেন যাতে আপনার ডেটা সঠিকভাবে সারà§à¦­à¦¾à¦°à§‡ না পৌà¦à¦›à¦¾à§Ÿà¥¤</translation>
<translation id="3157931365184549694">পà§à¦¨à¦°à§à¦¦à§à¦§à¦¾à¦° করà§à¦¨</translation>
<translation id="3167968892399408617">ছদà§à¦®à¦¬à§‡à¦¶à§€ টà§à¦¯à¦¾à¦¬à¦—à§à¦²à¦¿à¦¤à§‡ আপনি যে পৃষà§à¦ à¦¾à¦—à§à¦²à¦¿ দেখেন সেগà§à¦²à¦¿ আপনার সব ছদà§à¦®à¦¬à§‡à¦¶à§€ টà§à¦¯à¦¾à¦¬ বনà§à¦§ করে দেওয়ার পর বà§à¦°à¦¾à¦‰à¦œà¦¾à¦°à§‡à¦° ইতিহাস, কà§à¦•à¦¿ সà§à¦Ÿà§‹à¦° বা অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ ইতিহাসে থাকবে না। আপনি ডাউনলোড করেছেন à¦à¦®à¦¨ ফাইল বা বà§à¦•à¦®à¦¾à¦°à§à¦• তৈরি করছেন à¦à¦®à¦¨ সবগà§à¦²à¦¿ রেখে দেওয়া হবে।</translation>
<translation id="3169472444629675720">আবিষà§à¦•à¦¾à¦° করà§à¦¨</translation>
@@ -264,11 +272,13 @@
<translation id="3345135638360864351">à¦à¦‡ সাইটটি অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করার জনà§à¦¯ আপনার অনà§à¦°à§‹à¦§ <ph name="NAME" /> ঠপাঠানো যায়নি৷ অনà§à¦—à§à¦°à¦¹ করে আবার চেষà§à¦Ÿà¦¾ করà§à¦¨à§·</translation>
<translation id="3355823806454867987">পà§à¦°à¦•à§à¦¸à¦¿ সেটিংস পরিবরà§à¦¤à¦¨ করà§à¦¨...</translation>
<translation id="3369192424181595722">ঘড়ির তà§à¦°à§à¦Ÿà¦¿</translation>
+<translation id="337311366426640088">আরো <ph name="ITEM_COUNT" />টি আইটেম...</translation>
<translation id="337363190475750230">পà§à¦°à¦¦à¦¾à¦¨ করবে না</translation>
<translation id="3377188786107721145">নীতি বিশà§à¦²à§‡à¦·à¦£ তà§à¦°à§à¦Ÿà¦¿</translation>
<translation id="3380365263193509176">অজানা তà§à¦°à§à¦Ÿà¦¿</translation>
<translation id="3380864720620200369">কà§à¦²à¦¾à§Ÿà§‡à¦¨à§à¦Ÿ ID:</translation>
<translation id="3391030046425686457">পৌà¦à¦›à§‡ দেওয়ার ঠিকানা</translation>
+<translation id="3395827396354264108">পিকআপের পদà§à¦§à¦¤à¦¿</translation>
<translation id="340013220407300675">আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦°à¦¾ <ph name="BEGIN_BOLD" /> <ph name="SITE" /> <ph name="END_BOLD" /> (যেমন, পাসওয়ারà§à¦¡, বারà§à¦¤à¦¾ বা কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡) থেকে আপনার তথà§à¦¯ চà§à¦°à¦¿ করার চেষà§à¦Ÿà¦¾ করতে পারে।</translation>
<translation id="3422248202833853650">মেমরি ফাà¦à¦•à¦¾ করতে অনà§à¦¯à¦¾à¦¨à§à¦¯ পà§à¦°à§‹à¦—à§à¦°à¦¾à¦® থেকে বেরিয়ে যাওয়ার চেষà§à¦Ÿà¦¾ করà§à¦¨à¥¤</translation>
<translation id="3422472998109090673">বরà§à¦¤à¦®à¦¾à¦¨à§‡ <ph name="HOST_NAME" /> পাওয়া যাচà§à¦›à§‡ না।</translation>
@@ -279,12 +289,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">বিরামকাল পà§à¦°à¦¾à¦ªà§à¦¤ করà§à¦¨:</translation>
<translation id="3462200631372590220">উনà§à¦¨à¦¤ করার বিশদ বিবরণ, লà§à¦•à¦¾à¦¨</translation>
+<translation id="3467763166455606212">কারà§à¦¡à¦¹à§‹à¦²à§à¦¡à¦¾à¦°à§‡à¦° নাম পà§à¦°à§Ÿà§‹à¦œà¦¨</translation>
+<translation id="3478058380795961209">মেয়াদপূরà§à¦¤à¦¿à¦° মাস</translation>
<translation id="3479539252931486093">à¦à¦Ÿà¦¿ কি অপà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¿à¦¤ ছিল? <ph name="BEGIN_LINK" />আমাদেরকে জানান<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">à¦à¦–নই নয়</translation>
<translation id="348000606199325318">কà§à¦°à§à¦¯à¦¾à¦¶ আইডি <ph name="CRASH_LOCAL_ID" /> (সারà§à¦­à¦¾à¦° আইডি: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">আমরা à¦à¦‡ মà§à¦¹à§‚রà§à¦¤à§‡ আপনার পিতামাতার সাথে যোগাযোগ করতে পারিনি৷ অনà§à¦—à§à¦°à¦¹ করে আবার চেষà§à¦Ÿà¦¾ করà§à¦¨à§·</translation>
<translation id="3528171143076753409">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦° বিশà§à¦¬à¦¸à§à¦¤ নয়৷</translation>
-<translation id="3538531656504267329">মেয়াদ শেষের বছর ভà§à¦²</translation>
<translation id="3539171420378717834">à¦à¦‡ ডিভাইসে কারà§à¦¡à¦Ÿà¦¿à¦° à¦à¦•à¦Ÿà¦¿ পà§à¦°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ রাখà§à¦¨</translation>
<translation id="3542684924769048008">à¦à¦° জনà§à¦¯ পাসওয়ারà§à¦¡ বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨:</translation>
<translation id="3549644494707163724">আপনার নিজসà§à¦¬ সিঙà§à¦• পাসফà§à¦°à§‡à¦œà§‡à¦° মাধà§à¦¯à¦®à§‡ সমসà§à¦¤ সিঙà§à¦• হওয়া ডেটা à¦à¦¨à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ করà§à¦¨</translation>
@@ -297,6 +308,7 @@
<translation id="3586931643579894722">বিশদ বিবরণ লà§à¦•à¦¾à¦¨</translation>
<translation id="3587482841069643663">সকল</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">মেয়াদ শেষ হওয়ার তারিখের সঠিক মান লিখà§à¦¨</translation>
<translation id="36224234498066874">বà§à¦°à¦¾à¦‰à¦œ করা ডেটা সাফ করà§à¦¨...</translation>
<translation id="362276910939193118">সমà§à¦ªà§‚রà§à¦£ ইতিহাস দেখান</translation>
<translation id="3623476034248543066">মান দেখান</translation>
@@ -313,7 +325,6 @@
<translation id="3693415264595406141">পাসওয়ারà§à¦¡:</translation>
<translation id="3696411085566228381">কিছà§à¦‡ নেই</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">শিপিংয়ের পদà§à¦§à¦¤à¦¿ ও পà§à¦°à¦¯à¦¼à§‹à¦œà¦¨à§€à¦¯à¦¼à¦¤à¦¾à¦—à§à¦²à¦¿ দেখার জনà§à¦¯ পাঠানোর à¦à¦•à¦Ÿà¦¿ ঠিকানা নিরà§à¦¬à¦¾à¦šà¦¨ করà§à¦¨à¥¤</translation>
<translation id="370665806235115550">লোড হচà§à¦›à§‡...</translation>
<translation id="3712624925041724820">লাইসেনà§à¦¸à¦—à§à¦²à¦¿à¦° মেয়াদ শেষ হয়ে গেছে</translation>
<translation id="3714780639079136834">মোবাইল ডেটা বা ওয়াই-ফাই চালৠকরে দেখà§à¦¨</translation>
@@ -322,6 +333,7 @@
<translation id="3739623965217189342">আপনার অনà§à¦²à¦¿à¦ªà¦¿ করা লিঙà§à¦•</translation>
<translation id="375403751935624634">à¦à¦•à¦Ÿà¦¿ সারà§à¦­à¦¾à¦° তà§à¦°à§à¦Ÿà¦¿à¦° কারণে অনà§à¦¬à¦¾à¦¦ বà§à¦¯à¦°à§à¦¥ হয়েছে৷</translation>
<translation id="3759461132968374835">আপনার কাছে সামà§à¦ªà§à¦°à¦¤à¦¿à¦• পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨ করা কোনও কà§à¦°à§à¦¯à¦¾à¦¶ নেই৷ কà§à¦°à§à¦¯à¦¾à¦¶ পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨ অকà§à¦·à¦® থাকাকালীন ঘটা কà§à¦°à§à¦¯à¦¾à¦¶ à¦à¦–ানে উপসà§à¦¥à¦¿à¦¤ হবে না৷</translation>
+<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /> ঠমেয়াদ শেষ হবে</translation>
<translation id="382518646247711829">যদি আপনি à¦à¦•à¦Ÿà¦¿ পà§à¦°à¦•à§à¦¸à¦¿ সারà§à¦­à¦¾à¦° বà§à¦¯à¦¬à¦¹à¦¾à¦° করেন...</translation>
<translation id="3828924085048779000">ফাà¦à¦•à¦¾ পাসফà§à¦°à§‡à¦œà§‡à¦° অনà§à¦®à¦¤à¦¿ নেই৷</translation>
<translation id="3845539888601087042">আপনার পà§à¦°à¦¬à§‡à¦¶ করা ডিভাইসগà§à¦²à¦¿ থেকে ইতিহাস দেখাচà§à¦›à§‡à¥¤ <ph name="BEGIN_LINK" />আরো জানà§à¦¨<ph name="END_LINK" />।</translation>
@@ -357,7 +369,6 @@
<translation id="4148925816941278100">আমেরিকান à¦à¦•à§à¦¸à¦ªà§à¦°à§‡à¦¸</translation>
<translation id="4169947484918424451">আপনি কি চান যে Chromium à¦à¦‡ কারà§à¦¡ সংরকà§à¦·à¦£ করà§à¦•?</translation>
<translation id="4171400957073367226">খারাপ যাচাইকরণের সà§à¦¬à¦¾à¦•à§à¦·à¦°</translation>
-<translation id="4176463684765177261">অকà§à¦·à¦®</translation>
<translation id="4196861286325780578">&amp;সরানোর কাজটি আবার করà§à¦¨</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ফায়ারওয়াল à¦à¦¬à¦‚ অà§à¦¯à¦¾à¦¨à§à¦Ÿà¦¿à¦­à¦¾à¦‡à¦°à¦¾à¦¸ কনফিগারেশন পরীকà§à¦·à¦¾ করে দেখà§à¦¨<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{কিছà§à¦‡ নেই}=1{১টি অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨ ($1)}=2{২টি অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨ ($1, $2)}one{#টি অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨ ($1, $2, $3)}other{#টি অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨ ($1, $2, $3)}}</translation>
@@ -384,11 +395,11 @@
<translation id="4406896451731180161">অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨à§‡à¦° ফলাফলগà§à¦²à¦¿</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> আপনার লগইন শংসাপতà§à¦°à¦Ÿà¦¿ সà§à¦¬à§€à¦•à¦¾à¦° করেনি, অথবা কোনো শংসাপতà§à¦° দেওয়া হয়নি।</translation>
<translation id="443673843213245140">পà§à¦°à¦•à§à¦¸à¦¿à¦° বà§à¦¯à¦¬à¦¹à¦¾à¦° অকà§à¦·à¦® করা হয়েছে কিনà§à¦¤à§ কোনো সà§à¦ªà¦·à§à¦Ÿ পà§à¦°à¦•à§à¦¸à¦¿ কনফিগারেশান নিরà§à¦¦à¦¿à¦·à§à¦Ÿ করা হয়েছে৷</translation>
-<translation id="4446242550670694251">à¦à¦–ন আপনি à¦à¦•à¦¾à¦¨à§à¦¤à§‡ বà§à¦°à¦¾à¦‰à¦œ করতে পারেন, à¦à¦¬à¦‚ অনà§à¦¯ যেসব বকà§à¦¤à¦¿ à¦à¦‡ ডিভাইস বà§à¦¯à¦¬à¦¹à¦¾à¦° করেন তারা আপনার কারà§à¦¯à¦•à¦²à¦¾à¦ª দেখতে পাবেন না।</translation>
<translation id="4492190037599258964">'<ph name="SEARCH_STRING" />'-à¦à¦° অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ ফলাফল</translation>
<translation id="4506176782989081258">যাচাইকরণের তà§à¦°à§à¦Ÿà¦¿: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">সিসà§à¦Ÿà§‡à¦® পà§à¦°à¦¶à¦¾à¦¸à¦•à§‡à¦° সাথে যোগাযোগ করে দেখà§à¦¨</translation>
<translation id="450710068430902550">পà§à¦°à¦¶à¦¾à¦¸à¦•à§‡à¦° সাথে ভাগ করছে</translation>
+<translation id="4515275063822566619">কারà§à¦¡ ও ঠিকানাগà§à¦²à¦¿ Chrome à¦à¦¬à¦‚ আপনার Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ (<ph name="ACCOUNT_EMAIL" />) থেকে à¦à¦¸à§‡à¦›à§‡à¥¤ আপনি <ph name="BEGIN_LINK" />সেটিংস<ph name="END_LINK" /> ঠগিয়ে সেগà§à¦²à¦¿ পরিচালনা করতে পারবেন।</translation>
<translation id="4522570452068850558">বিশদ বিবরণ</translation>
<translation id="4558551763791394412">আপনার à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à¦¾à¦¨à¦—à§à¦²à¦¿ অকà§à¦·à¦® করে দেখà§à¦¨à¥¤</translation>
<translation id="457875822857220463">পৌà¦à¦›à§‡ দেওয়া</translation>
@@ -418,6 +429,7 @@
<translation id="4816492930507672669">পৃষà§à¦ à¦¾à¦¤à§‡ মানানসই</translation>
<translation id="483020001682031208">দেখানোর মতো কোনো বাসà§à¦¤à¦¬à¦¿à¦• ওয়েব পৃষà§à¦ à¦¾ নেই</translation>
<translation id="4850886885716139402">দেখà§à¦¨</translation>
+<translation id="4854362297993841467">à¦à¦‡ পদà§à¦§à¦¤à¦¿à¦¤à§‡ ডেলিভারি করা যাবে না। অনà§à¦¯ পদà§à¦§à¦¤à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨à¥¤</translation>
<translation id="4858792381671956233">à¦à¦‡ সাইটটি দেখার জনà§à¦¯ উপযà§à¦•à§à¦¤ কিনা তা আপনি আপনার পিতামাতাকে জিজà§à¦žà¦¾à¦¸à¦¾ করেছেন</translation>
<translation id="4880827082731008257">ইতিহাস অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -425,7 +437,6 @@
<translation id="4923417429809017348">à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ কোন অজানা ভাষা থেকে <ph name="LANGUAGE_LANGUAGE" />-ঠঅনà§à¦¬à¦¾à¦¦ করা হয়েছে</translation>
<translation id="4923459931733593730">অরà§à¦¥à¦ªà§à¦°à¦¦à¦¾à¦¨</translation>
<translation id="4926049483395192435">নিরà§à¦¦à¦¿à¦·à§à¦Ÿ করা উচিত৷</translation>
-<translation id="4941291666397027948">* পà§à¦°à¦¯à¦¼à§‹à¦œà¦¨à§€à¦¯à¦¼ কà§à¦·à§‡à¦¤à§à¦° নিরà§à¦¦à§‡à¦¶ করে</translation>
<translation id="495170559598752135">কà§à¦°à¦¿à§Ÿà¦¾à¦¸à¦®à§‚হ</translation>
<translation id="4958444002117714549">তালিকা পà§à¦°à¦¸à¦¾à¦°à¦¿à¦¤ করà§à¦¨</translation>
<translation id="4962322354953122629">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; Chrome à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿à¦•à§‡ বিশà§à¦¬à¦¾à¦¸ করে না। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিচà§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
@@ -440,6 +451,7 @@
<translation id="5045550434625856497">ভà§à¦² পাসওয়ারà§à¦¡</translation>
<translation id="5056549851600133418">আপনার জনà§à¦¯ নিবনà§à¦§à¦—à§à¦²à¦¿</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />পà§à¦°à¦•à§à¦¸à¦¿ ঠিকানা পরীকà§à¦·à¦¾ করে দেখà§à¦¨<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{কোনো কà§à¦•à¦¿ নেই}=1{১টি সাইট কà§à¦•à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে। }one{#টি সাইট কà§à¦•à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে। }other{#টি সাইট কà§à¦•à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে। }}</translation>
<translation id="5087286274860437796">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦° à¦à¦‡ সময়ে বৈধ নয়৷</translation>
<translation id="5087580092889165836">কারà§à¦¡ জà§à¦¡à¦¼à§à¦¨</translation>
<translation id="5089810972385038852">রাজà§à¦¯</translation>
@@ -462,10 +474,8 @@
<translation id="5300589172476337783">দেখান</translation>
<translation id="5308689395849655368">কà§à¦°à§à¦¯à¦¾à¦¶ পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨ অকà§à¦·à¦® আছে৷</translation>
<translation id="5317780077021120954">সংরকà§à¦·à¦£ করà§à¦¨</translation>
-<translation id="5326702247179446998">পà§à¦°à¦¾à¦ªà¦• যোগ করা পà§à¦°à§Ÿà§‹à¦œà¦¨</translation>
<translation id="5327248766486351172">নাম</translation>
<translation id="5337705430875057403"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ঠআকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦°à¦¾ আপনাকে ধোà¦à¦•à¦¾ দিয়ে সফটওয়à§à¦¯à¦¾à¦° ইনসà§à¦Ÿà¦² করা বা আপনার বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত তথà§à¦¯ (উদাহরণসà§à¦¬à¦°à§‚প, পাসওয়ারà§à¦¡, ফোন নমà§à¦¬à¦°, বা কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡) পà§à¦°à¦•à¦¾à¦¶ করার মত বিপজà§à¦œà¦¨à¦• কিছৠকরাতে পারে।</translation>
-<translation id="53553865750799677">তà§à¦²à§‡ নেওয়ার ঠিকানাটি অসমরà§à¦¥à¦¿à¦¤à¥¤ আলাদা কোনো ঠিকানা নিরà§à¦¬à¦¾à¦šà¦¨ করà§à¦¨à¥¤</translation>
<translation id="5359637492792381994">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; বরà§à¦¤à¦®à¦¾à¦¨à§‡ à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ বৈধ না। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিচà§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="536296301121032821">নীতি সেটিংস সংরকà§à¦·à¦£ করতে বà§à¦¯à¦°à§à¦¥ হয়েছে</translation>
<translation id="5386426401304769735">à¦à¦‡ সাইটের শংসাপতà§à¦° শৃঙà§à¦–লে SHA-1 বà§à¦¯à¦¬à¦¹à¦¾à¦° করে সà§à¦¬à¦¾à¦•à§à¦·à¦° করা à¦à¦•à¦Ÿà¦¿ শংসাপতà§à¦° রয়েছে।</translation>
@@ -491,8 +501,8 @@
<translation id="5544037170328430102"><ph name="SITE" /> ঠà¦à¦•à¦Ÿà¦¿ à¦à¦®à§à¦¬à§‡à¦¡à§‡à¦¡ পৃষà§à¦ à¦¾ বলছে:</translation>
<translation id="5556459405103347317">আবার লোড করà§à¦¨</translation>
<translation id="5565735124758917034">সকà§à¦°à¦¿à§Ÿ</translation>
+<translation id="5571083550517324815">à¦à¦‡ ঠিকানা থেকে পিক-আপ করা যাবে না। অনà§à¦¯ ঠিকানা বেছে নিন।</translation>
<translation id="5572851009514199876">আপনার à¦à¦‡ সাইটে অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করার অনà§à¦®à¦¤à¦¿ আছে কিনা তা Chrome পরীকà§à¦·à¦¾ করার জনà§à¦¯ অনà§à¦—à§à¦°à¦¹ করে শà§à¦°à§ করà§à¦¨ à¦à¦¬à¦‚ Chrome ঠপà§à¦°à¦¬à§‡à¦¶ করà§à¦¨à¥¤</translation>
-<translation id="5575380383496039204">পৌà¦à¦›à§‡ দেওয়ার ঠিকানাটি অসমরà§à¦¥à¦¿à¦¤à¥¤ আলাদা কোনো ঠিকানা নিরà§à¦¬à¦¾à¦šà¦¨ করà§à¦¨à¥¤</translation>
<translation id="5580958916614886209">আপনার মেয়াদ শেষের মাস পরীকà§à¦·à¦¾ করে আবার চেষà§à¦Ÿà¦¾ করà§à¦¨</translation>
<translation id="560412284261940334">পরিচালনা সমরà§à¦¥à¦¿à¦¤ নয়</translation>
<translation id="5610142619324316209">সংযোগ পরীকà§à¦·à¦¾ করে দেখà§à¦¨</translation>
@@ -508,7 +518,8 @@
<translation id="5710435578057952990">à¦à¦‡ ওয়েবসাইটির পরিচয় যাচাই করা হয় নি৷</translation>
<translation id="5720705177508910913">বরà§à¦¤à¦®à¦¾à¦¨ বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€</translation>
<translation id="5732392974455271431">আপনার পিতামাতা à¦à¦Ÿà¦¿ আপনার জনà§à¦¯ অবরোধ মà§à¦•à§à¦¤ করতে পারবেন</translation>
-<translation id="57586589942790530">অবৈধ কারà§à¦¡ নমà§à¦¬à¦°</translation>
+<translation id="5763042198335101085">à¦à¦•à¦Ÿà¦¿ সঠিক ইমেল ঠিকানা লিখà§à¦¨</translation>
+<translation id="5765072501007116331">ডেলিভারির পদà§à¦§à¦¤à¦¿ à¦à¦¬à¦‚ পà§à¦°à§Ÿà§‹à¦œà¦¨à§€à§Ÿà¦¤à¦¾à¦—à§à¦²à¦¿ দেখতে à¦à¦•à¦Ÿà¦¿ ঠিকানা বেছে নিন</translation>
<translation id="5784606427469807560">আপনার কারà§à¦¡à¦Ÿà¦¿ নিশà§à¦šà¦¿à¦¤ করতে à¦à¦•à¦Ÿà¦¿ সমসà§à¦¯à¦¾ হয়েছিল৷আপনার ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ সংযোগ পরীকà§à¦·à¦¾ করে আবার চেষà§à¦Ÿà¦¾ করà§à¦¨à§·</translation>
<translation id="5785756445106461925">উপরনà§à¦¤à§, à¦à¦‡ পৃষà§à¦ à¦¾à¦¤à§‡ অনà§à¦¯à¦¾à¦¨à§à¦¯ সংসà§à¦¥à¦¾à¦¨ অনà§à¦¤à¦°à§à¦­à§à¦•à§à¦¤ রয়েছে যা নিরাপদ নয়৷ à¦à¦‡ সংসà§à¦¥à¦¾à¦¨à¦—à§à¦²à¦¿ টà§à¦°à¦¾à¦¨à¦œà¦¿à¦Ÿà§‡à¦° সময় অনà§à¦¯à¦°à¦¾ দেখতে পাবে à¦à¦¬à¦‚ পৃষà§à¦ à¦¾à¦Ÿà¦¿à¦° চেহারাটি পরিবরà§à¦¤à¦¨ করতে কোনও আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ à¦à¦° পরিবরà§à¦¤à¦¨ করতে পারেন৷</translation>
<translation id="5786044859038896871">আপনি কি আপনার কারà§à¦¡à§‡à¦° তথà§à¦¯ পূরণ করতে চান?</translation>
@@ -521,31 +532,30 @@
<translation id="5869405914158311789">à¦à¦‡ সাইটটিতে পৌছানো যাচà§à¦›à§‡ না</translation>
<translation id="5869522115854928033">সংরকà§à¦·à¦¿à¦¤ পাসওয়ারà§à¦¡</translation>
<translation id="5872918882028971132">মূল পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¨à¦¾à¦—à§à¦²à¦¿</translation>
-<translation id="587760065310675640">অসমরà§à¦¥à¦¿à¦¤ শিপিং ঠিকানা। আলাদা কোনো ঠিকানা নিরà§à¦¬à¦¾à¦šà¦¨ করà§à¦¨à¥¤</translation>
<translation id="5901630391730855834">হলà§à¦¦</translation>
-<translation id="59174027418879706">সকà§à¦·à¦® করা হযেছে</translation>
<translation id="5926846154125914413">আপনি কিছৠসাইট থেকে পà§à¦°à¦¿à¦®à¦¿à¦¯à¦¼à¦¾à¦® সামগà§à¦°à§€à¦¤à§‡ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ হারাতে পারেন।</translation>
<translation id="5959728338436674663">বিপজà§à¦œà¦¨à¦• অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨ ও সাইটগà§à¦²à¦¿ সনাকà§à¦¤ করতে Google à¦à¦° কাছে কিছà§<ph name="BEGIN_WHITEPAPER_LINK" /> সিসà§à¦Ÿà§‡à¦® তথà§à¦¯ ও পৃষà§à¦ à¦¾à¦° সামগà§à¦°à§€<ph name="END_WHITEPAPER_LINK" /> সà§à¦¬à§Ÿà¦‚কà§à¦°à¦¿à§Ÿà¦­à¦¾à¦¬à§‡ পাঠান। <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">সপà§à¦¤à¦¾à¦¹</translation>
<translation id="5967867314010545767">ইতিহাস থেকে সরান</translation>
<translation id="5975083100439434680">জà§à¦® কমান</translation>
+<translation id="598637245381783098">পেমেনà§à¦Ÿ অà§à¦¯à¦¾à¦ª খোলা যাচà§à¦›à§‡ না</translation>
<translation id="5989320800837274978">কোনো নিরà§à¦§à¦¾à¦°à¦¿à¦¤ পà§à¦°à¦•à§à¦¸à¦¿ সারà§à¦­à¦¾à¦° অথবা à¦à¦•à¦Ÿà¦¿.pac সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ UR সà§à¦°à§à¦¨à¦¿à¦¦à¦¿à¦·à§à¦Ÿà¦­à¦¾à¦¬à§‡ উলà§à¦²à§‡à¦– করা হয়নি৷</translation>
<translation id="5990559369517809815">সারà§à¦­à¦¾à¦°à§‡ অনà§à¦°à§‹à¦§à¦—à§à¦²à¦¿ à¦à¦•à¦Ÿà¦¿ à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à¦¾à¦¨ দিয়ে অবরà§à¦¦à§à¦§ করা আছে৷</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">কারà§à¦¡ à¦à¦¬à¦‚ ঠিকানার বিকলà§à¦ªà¦—à§à¦²à¦¿ Chrome থেকে পাওয়া। আপনি <ph name="BEGIN_LINK" />সেটিংস<ph name="END_LINK" /> থেকে à¦à¦—à§à¦²à¦¿ পরিচালনা করতে পারেন।</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{পৃষà§à¦ à¦¾ ১}one{পৃষà§à¦ à¦¾ #}other{পৃষà§à¦ à¦¾ #}}</translation>
<translation id="6017514345406065928">সবà§à¦œ</translation>
+<translation id="6027201098523975773">à¦à¦•à¦Ÿà¦¿ নাম লিখà§à¦¨</translation>
<translation id="6040143037577758943">বনà§à¦§</translation>
-<translation id="604124094241169006">সà§à¦¬à§Ÿà¦‚কà§à¦°à¦¿à§Ÿ</translation>
<translation id="6042308850641462728">আরো</translation>
<translation id="6060685159320643512">সাবধান হন, à¦à¦‡ পরীকà§à¦·à¦¾à¦—à§à¦²à¦¿ সমসà§à¦¯à¦¾ সৃষà§à¦Ÿà¦¿ করতে পারে</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{কিছà§à¦‡ নেই}=1{১}one{#}other{#}}</translation>
<translation id="6146055958333702838">সব কেবল পরীকà§à¦·à¦¾ করà§à¦¨ à¦à¦¬à¦‚ আপনি বà§à¦¯à¦¬à¦¹à¦¾à¦° করছেন à¦à¦®à¦¨ যেকোনো রাউটার, মডেম বা অনà§à¦¯à¦¾à¦¨à§à¦¯ নেটওয়ারà§à¦• ডিভাইসগà§à¦²à¦¿ আবার চালৠকরà§à¦¨à¥¤</translation>
<translation id="614940544461990577">à¦à¦Ÿà¦¿ করে দেখà§à¦¨:</translation>
<translation id="6151417162996330722">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦°à§‡à¦° বৈধতার সময়সীমা আছে যা খà§à¦¬à¦‡ দীরà§à¦˜à¥¤</translation>
-<translation id="615643356032862689">ডাউনলোড করা ফাইল à¦à¦¬à¦‚ বà§à¦•à¦®à¦¾à¦°à§à¦•à¦—à§à¦²à¦¿ রেখে দেওয়া হবে।</translation>
+<translation id="6157877588268064908">শিপিং à¦à¦° পদà§à¦§à¦¤à¦¿ à¦à¦¬à¦‚ পà§à¦°à§Ÿà§‹à¦œà¦¨à§€à§Ÿà¦¤à¦¾ দেখতে à¦à¦•à¦Ÿà¦¿ ঠিকানা বেছে নিন</translation>
<translation id="6165508094623778733">আরো জানà§à¦¨</translation>
<translation id="6177128806592000436">à¦à¦‡ সাইটে আপনার সংযোগ নিরাপদ নয়</translation>
+<translation id="6184817833369986695">(দল: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">আপনার ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ সংযোগ পরীকà§à¦·à¦¾ করà§à¦¨</translation>
<translation id="6218753634732582820">Chromium থেকে ঠিকানা সরাবেন?</translation>
<translation id="6251924700383757765">গোপনীয়তা নীতি</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;পà§à¦¨à¦°à§à¦¬à¦¿à¦¨à§à¦¯à¦¾à¦¸à¦•à§‡ আবার করà§à¦¨</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> বà§à¦•à¦®à¦¾à¦°à§à¦•à¦—à§à¦²à¦¿</translation>
<translation id="6264485186158353794">সà§à¦°à¦•à§à¦·à¦¾à¦¤à§‡ ফিরà§à¦¨</translation>
+<translation id="6276112860590028508">পড়ার তালিকার পৃষà§à¦ à¦¾à¦—à§à¦²à¦¿ à¦à¦–ানে দেখা যাবে</translation>
+<translation id="6280223929691119688">à¦à¦‡ ঠিকানায় ডেলিভারি করা যাবে না। অনà§à¦¯ ঠিকানা বেছে নিন।</translation>
<translation id="6282194474023008486">পোসà§à¦Ÿà¦¾à¦² কোড</translation>
<translation id="6290238015253830360">আপনার পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤ নিবনà§à¦§à¦—à§à¦²à¦¿ à¦à¦–ানে দেখা যাবে</translation>
<translation id="6305205051461490394"><ph name="URL" /> ঠপৌà¦à¦›à¦¾à¦¨à§‹ যাচà§à¦›à§‡ না</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">শংসাপতà§à¦°à¦•à¦°à¦£à¦Ÿà¦¿ পà§à¦°à¦¤à§à¦¯à¦¾à¦¹à¦¾à¦° করা হয়েছে কিনা তা যাচাইয়ে অকà§à¦·à¦®à§·</translation>
<translation id="6433490469411711332">পরিচিতি তথà§à¦¯ সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ করà§à¦¨</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> সংযোগ করতে পà§à¦°à¦¤à§à¦¯à¦¾à¦–à§à¦¯à¦¾à¦¨ করেছে।</translation>
-<translation id="6443118737398455446">মেয়াদ শেষের তারিখ অবৈধ</translation>
<translation id="6446608382365791566">আরো তথà§à¦¯ যোগ করà§à¦¨</translation>
<translation id="6451458296329894277">ফরà§à¦® পà§à¦¨à¦ƒà¦œà¦®à¦¾ নিশà§à¦šà¦¿à¦¤ করà§à¦¨</translation>
<translation id="6456339708790392414">আপনার অরà§à¦¥à¦ªà§à¦°à¦¦à¦¾à¦¨</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ হয়ত পà§à¦°à¦¤à§à¦¯à¦¾à¦¹à¦¾à¦° করা হয়েছে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিচà§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="647261751007945333">ডিভাইস নীতিগà§à¦²à¦¿</translation>
<translation id="6477321094435799029">Chrome à¦à¦‡ পৃষà§à¦ à¦¾à¦¤à§‡ অসà§à¦¬à¦¾à¦­à¦¾à¦¬à¦¿à¦• কোড পেয়েছে à¦à¦¬à¦‚ আপনার বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত তথà§à¦¯à§‡à¦° (উদাহরণসà§à¦¬à¦°à§‚প, পাসওয়ারà§à¦¡, ফোন নমà§à¦¬à¦°, à¦à¦¬à¦‚ কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡) সà§à¦°à¦•à§à¦·à¦¾à¦° জনà§à¦¯ à¦à¦Ÿà¦¿ অবরà§à¦¦à§à¦§ করেছে।</translation>
-<translation id="6477460825583319731">অবৈধ ইমেল ঠিকানা</translation>
<translation id="6489534406876378309">কà§à¦°à§à¦¯à¦¾à¦¶à¦—à§à¦²à¦¿ আপলোড করা শà§à¦°à§ করà§à¦¨</translation>
<translation id="6508722015517270189">Chrome পà§à¦¨à¦°à¦¾à§Ÿ চালৠকরà§à¦¨</translation>
-<translation id="6525462735697194615">মেয়াদ শেষের মাস ভà§à¦²</translation>
<translation id="6529602333819889595">&amp;মà§à¦›à§‡ ফেলাকে আবার করà§à¦¨</translation>
<translation id="6534179046333460208">বাসà§à¦¤à¦¬à¦¿à¦• ওয়েব পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¨à¦¾à¦—à§à¦²à¦¿</translation>
<translation id="6550675742724504774">বিকলà§à¦ªà¦¸à¦®à§‚হ</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨</translation>
<translation id="6644283850729428850">à¦à¦‡ নীতিটি অসমরà§à¦¥à¦¿à¦¤ হয়েছে৷</translation>
<translation id="6652240803263749613">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦°à§‡à¦° অপারেটিং সিসà§à¦Ÿà§‡à¦® à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿à¦•à§‡ বিশà§à¦¬à¦¾à¦¸ করে না। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিচà§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
-<translation id="6665267558048410100">শিপিং বিকলà§à¦ªà¦Ÿà¦¿ উপলবà§à¦§ নেই। অনà§à¦¯ à¦à¦•à¦Ÿà¦¿ বিকলà§à¦ª বà§à¦¯à¦¬à¦¹à¦¾à¦° করে দেখà§à¦¨à¥¤</translation>
<translation id="6671697161687535275">Chromium থেকে ফরà§à¦® পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¨à¦¾ সরাবেন?</translation>
<translation id="6685834062052613830">পà§à¦°à¦¸à§à¦¥à¦¾à¦¨ করà§à¦¨ করে সেটআপ সমà§à¦ªà§‚রà§à¦£ করà§à¦¨</translation>
<translation id="6710213216561001401">পূরà§à¦¬à¦¬à¦°à§à¦¤à§€</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">পà§à¦°à¦•à§à¦¸à§€ সারà§à¦­à¦¾à¦°à§‡à¦° কোনো সমসà§à¦¯à¦¾ হয়েছে, অথবা ঠিকানাটি ভà§à¦²à¥¤</translation>
<translation id="6727102863431372879">সেট</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{কিছà§à¦‡ নেই}=1{১টি আইটেম}one{#টি আইটেম}other{#টি আইটেম}}</translation>
-<translation id="6743044928064272573">তà§à¦²à§‡ নেওয়ার বিকলà§à¦ª</translation>
<translation id="674375294223700098">অজানা সারà§à¦­à¦¾à¦° শংসাপতà§à¦° তà§à¦°à§à¦Ÿà¦¿à§·</translation>
<translation id="6753269504797312559">নীতি মান</translation>
<translation id="6757797048963528358">আপনার ডিভাইস নিদà§à¦°à¦¾ মোডে গিয়েছে।</translation>
<translation id="6778737459546443941">আপনার পিতামাতা à¦à¦–নও à¦à¦Ÿà¦¿ অনà§à¦®à§‹à¦¦à¦¨ করেন নি</translation>
<translation id="6810899417690483278">কাসà§à¦Ÿà¦®à¦¾à¦‡à¦œà§‡à¦¶à¦¨ আইডি</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">আঞà§à¦šà¦²à¦¿à¦• ডেটা লোড করা যায়নি</translation>
<translation id="6831043979455480757">অনà§à¦¬à¦¾à¦¦</translation>
<translation id="6839929833149231406">à¦à¦²à¦¾à¦•à¦¾</translation>
<translation id="6874604403660855544">&amp;যোগ করাকে পà§à¦¨à¦°à¦¾à¦¯à¦¼ করà§à¦¨</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">আপনার কারà§à¦¡à¦Ÿà¦¿ নিশà§à¦šà¦¿à¦¤ করা হয়েছে</translation>
<translation id="6897140037006041989">বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€ à¦à¦œà§‡à¦¨à§à¦Ÿ</translation>
<translation id="6915804003454593391">বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€:</translation>
+<translation id="6948701128805548767">পিকআপ à¦à¦° পদà§à¦§à¦¤à¦¿ à¦à¦¬à¦‚ পà§à¦°à§Ÿà§‹à¦œà¦¨à§€à§Ÿà¦¤à¦¾ দেখতে à¦à¦•à¦Ÿà¦¿ ঠিকানা বেছে নিন</translation>
<translation id="6957887021205513506">সারà§à¦­à¦¾à¦°à¦Ÿà¦¿à¦° শংসাপতà§à¦°à¦Ÿà¦¿ à¦à¦•à¦Ÿà¦¿ জাল হিসাবে উপসà§à¦¥à¦¿à¦¤ হয়েছে৷</translation>
<translation id="6965382102122355670">ঠিক আছে</translation>
<translation id="6965978654500191972">ডিভাইস</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">সà§à¦¥à¦¿à¦° পà§à¦°à¦•à§à¦¸à¦¿ সারà§à¦­à¦¾à¦° à¦à¦¬à¦‚ .pac সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ URL-à¦à¦° উভয়ই নিরà§à¦¦à¦¿à¦·à§à¦Ÿ আছে৷</translation>
<translation id="6989763994942163495">উনà§à¦¨à¦¤ সেটিংস দেখান ...</translation>
<translation id="7000990526846637657">কোনো ইতিহাস à¦à¦¨à§à¦Ÿà§à¦°à¦¿ পাওয়া যায়নি</translation>
-<translation id="7001663382399377034">পà§à¦°à¦¾à¦ªà¦• যোগ করà§à¦¨</translation>
<translation id="7009986207543992532">আপনি <ph name="DOMAIN" /> ঠপৌà¦à¦›à¦¾à¦¨à§‹à¦° পà§à¦°à¦šà§‡à¦·à§à¦Ÿà¦¾ করেছেন, কিনà§à¦¤à§ সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ à¦à¦®à¦¨ à¦à¦•à¦Ÿà¦¿ শংসাপতà§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে যার মেয়াদ খà§à¦¬ বেশি সময়ের যা বিশà§à¦¬à¦¾à¦¸à¦¯à§‹à¦—à§à¦¯ নয়। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985"><ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ঠআপনার Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡à¦° অনà§à¦¯à¦¾à¦¨à§à¦¯ ধরনের বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ ইতিহাস থাকতে পারে</translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">পূরà§à¦¬à¦¤à¦°</translation>
<translation id="7090678807593890770">Google ঠ<ph name="LINK" /> à¦à¦° অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ করà§à¦¨</translation>
<translation id="7119414471315195487">অনà§à¦¯à¦¾à¦¨à§à¦¯ টà§à¦¯à¦¾à¦¬ বা পà§à¦°à§‹à¦—à§à¦°à¦¾à¦® বনà§à¦§ করà§à¦¨</translation>
+<translation id="7129409597930077180">à¦à¦‡ ঠিকানায় শিপিং করা যাবে না। অনà§à¦¯ ঠিকানা বেছে নিন।</translation>
+<translation id="7138472120740807366">ডেলিভারির পদà§à¦§à¦¤à¦¿</translation>
<translation id="7139724024395191329">à¦à¦®à¦¿à¦°à§‡à¦Ÿ</translation>
<translation id="7155487117670177674">পেমেনà§à¦Ÿ সà§à¦°à¦•à§à¦·à¦¿à¦¤ নয়</translation>
<translation id="7179921470347911571">à¦à¦–নই পà§à¦¨à¦ƒà¦²à¦žà§à¦š করà§à¦¨</translation>
<translation id="7180611975245234373">রিফà§à¦°à§‡à¦¶ করà§à¦¨</translation>
<translation id="7182878459783632708">কোন নীতি সেট করা নেই</translation>
<translation id="7186367841673660872">à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿<ph name="ORIGINAL_LANGUAGE" />থেকে<ph name="LANGUAGE_LANGUAGE" />তে অনà§à¦¬à¦¾à¦¦ করা হয়েছে</translation>
+<translation id="7192203810768312527"><ph name="SIZE" /> জায়গা খালি করে। পরের বার যখন দেখবেন তখন কিছৠসাইট লোড হতে দেরি হতে পারে।</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> নিরাপতà§à¦¤à¦¾ মান মেনে চলে না।</translation>
<translation id="721197778055552897">à¦à¦‡ সমসà§à¦¯à¦¾à¦Ÿà¦¿ সমà§à¦ªà¦°à§à¦•à§‡ <ph name="BEGIN_LINK" />আরো জানà§à¦¨<ph name="END_LINK" />৷</translation>
@@ -675,7 +686,6 @@
<translation id="7424977062513257142">à¦à¦‡ ওয়েব পৃষà§à¦ à¦¾à§Ÿ à¦à¦•à¦Ÿà¦¿ à¦à¦®à§à¦¬à§‡à¦¡à§‡à¦¡ পৃষà§à¦ à¦¾ বলছে:</translation>
<translation id="7441627299479586546">ভà§à¦² বিষয় বিশিষà§à¦Ÿ নীতি</translation>
<translation id="7444046173054089907">সাইটটি অবরà§à¦¦à§à¦§</translation>
-<translation id="7444238235002594607">তà§à¦²à§‡ নেওয়ার পদà§à¦§à¦¤à¦¿ ও পà§à¦°à¦¯à¦¼à§‹à¦œà¦¨à§€à¦¯à¦¼à¦¤à¦¾à¦—à§à¦²à¦¿ দেখার জনà§à¦¯ তà§à¦²à§‡ নেওয়ার à¦à¦•à¦Ÿà¦¿ ঠিকানা নিরà§à¦¬à¦¾à¦šà¦¨ করà§à¦¨à¥¤</translation>
<translation id="7445762425076701745">আপনি যে সারà§à¦­à¦¾à¦°à§‡ সংযà§à¦•à§à¦¤ রয়েছে সেটিকে সমà§à¦ªà§‚রà§à¦£ যাচাই করতে পারা যায় না৷ আপনি নামগà§à¦²à¦¿ দিয়ে à¦à¦®à¦¨ à¦à¦•à¦Ÿà¦¿ সারà§à¦­à¦¾à¦°à§‡ সংযà§à¦•à§à¦¤ রয়েছেন যা আপনার নেটওয়ারà§à¦•à§‡ বৈধ, যেটি à¦à¦•à¦Ÿà¦¿ বাহà§à¦¯à¦¿à¦• শংসাকরণ করà§à¦¤à§ƒà¦ªà¦•à§à¦· যার à¦à¦Ÿà¦¿à¦° মালিকানা যাচাই করার কোনও উপায় নেই৷ কিছৠশংসাপতà§à¦° করà§à¦¤à§ƒà¦ªà¦•à§à¦· à¦à¦‡ নামগà§à¦²à¦¿ নিরà§à¦¬à¦¿à¦šà¦¾à¦°à§‡ শংসাপতà§à¦°à¦—à§à¦²à¦¿ ইসà§à¦¯à§ করবে, আপনি উদà§à¦¦à¦¿à¦·à§à¦Ÿ ওয়েবসাইটে সংযà§à¦•à§à¦¤ রয়েছেন কোনও আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦¤à§‡ নয় তা নিশà§à¦šà¦¿à¦¤ করার কোনও উপায় নেই৷</translation>
<translation id="7451311239929941790">à¦à¦‡ সমসà§à¦¯à¦¾ সমà§à¦ªà¦°à§à¦•à§‡ <ph name="BEGIN_LINK" />আরো জানà§à¦¨<ph name="END_LINK" />।</translation>
<translation id="7460163899615895653">অনà§à¦¯à¦¾à¦¨à§à¦¯ ডিভাইসগà§à¦²à¦¿ থেকে আপনার সামà§à¦ªà§à¦°à¦¤à¦¿à¦• টà§à¦¯à¦¾à¦¬à¦—à§à¦²à¦¿ à¦à¦–ানে দেখা যাবে</translation>
@@ -719,6 +729,7 @@
<translation id="7755287808199759310">আপনার পিতামাতা à¦à¦Ÿà¦¿ আপনার জনà§à¦¯ অবরোধ মà§à¦•à§à¦¤ করতে পারবেন</translation>
<translation id="7758069387465995638">ফায়ারওয়াল বা অà§à¦¯à¦¾à¦¨à§à¦Ÿà¦¿à¦­à¦¾à¦‡à¦°à¦¾à¦¸ সফটওয়à§à¦¯à¦¾à¦° সংযোগকে অবরà§à¦¦à§à¦§ করে থাকতে পারে।</translation>
<translation id="7761701407923456692">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦° URL-à¦à¦° সাথে মেলে না৷</translation>
+<translation id="7763386264682878361">পেমেনà§à¦Ÿ মà§à¦¯à¦¾à¦¨à¦¿à¦«à§‡à¦¸à§à¦Ÿ বিশà§à¦²à§‡à¦·à¦•</translation>
<translation id="7764225426217299476">ঠিকানা যোগ করà§à¦¨</translation>
<translation id="777702478322588152">জেলা</translation>
<translation id="7791543448312431591">যà§à¦•à§à¦¤ করà§à¦¨</translation>
@@ -732,6 +743,7 @@
<translation id="785549533363645510">আপনি অবশà§à¦¯ অদৃশà§à¦¯ থাকবেন না। ছদà§à¦®à¦¬à§‡à¦¶à§€ মোডে গেলেও তা আপনার নিয়োগকরà§à¦¤à¦¾, আপনার ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ পরিষেবা পà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ অথবা আপনার পরিদরà§à¦¶à¦¨ করা ওয়েবসাইট থেকে আপনার বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚কে আড়াল করবে না।</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">আপনার CVC পরীকà§à¦·à¦¾ করà§à¦¨ à¦à¦¬à¦‚ আবার চেষà§à¦Ÿà¦¾ করà§à¦¨</translation>
+<translation id="79338296614623784">à¦à¦•à¦Ÿà¦¿ সঠিক ফোন নমà§à¦¬à¦° লিখà§à¦¨</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦° à¦à¦–নও কারà§à¦¯à¦•à¦° নয়.</translation>
<translation id="7942349550061667556">লাল</translation>
@@ -751,6 +763,7 @@
<translation id="8088680233425245692">নিবনà§à¦§ দেখতে বà§à¦¯à¦°à§à¦¥ হয়েছে৷</translation>
<translation id="8089520772729574115">১ মেগাবাইটের কম</translation>
<translation id="8091372947890762290">সারà§à¦­à¦¾à¦°à§‡ সকà§à¦°à¦¿à§Ÿà¦•à¦°à¦£ বাকি আছে</translation>
+<translation id="8118489163946903409">পেমেনà§à¦Ÿà§‡à¦° পদà§à¦§à¦¤à¦¿</translation>
<translation id="8131740175452115882">নিশà§à¦šà¦¿à¦¤ হন</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> à¦à¦° সারà§à¦­à¦¾à¦° <ph name="BEGIN_ABBR" />DNS ঠিকানা<ph name="END_ABBR" />খà§à¦à¦œà§‡ পাওয়া যায়নি।</translation>
<translation id="8149426793427495338">আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦°à¦Ÿà¦¿ নিদà§à¦°à¦¾ মোডে গিয়েছে।</translation>
@@ -776,6 +789,7 @@
<translation id="8349305172487531364">বà§à¦•à¦®à¦¾à¦°à§à¦•à¦¸ দণà§à¦¡</translation>
<translation id="8363502534493474904">বিমান মোড বনà§à¦§ করে দেখà§à¦¨</translation>
<translation id="8364627913115013041">সেট করা নেই৷</translation>
+<translation id="8368476060205742148">Google Play পরিষেবাদি</translation>
<translation id="8380941800586852976">বিপজà§à¦œà¦¨à¦•</translation>
<translation id="8382348898565613901">আপনার সমà§à¦ªà§à¦°à¦¤à¦¿ ঘà§à¦°à§‡ দেখা বà§à¦•à¦®à¦¾à¦°à§à¦•à¦—à§à¦²à¦¿ à¦à¦–ানে দেখা যাবে</translation>
<translation id="8398259832188219207">কà§à¦°à§à¦¯à¦¾à¦¶ পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨ <ph name="UPLOAD_TIME" /> ঠআপলোড করা হয়েছে</translation>
@@ -784,31 +798,29 @@
<translation id="8428213095426709021">সেটিংস</translation>
<translation id="8433057134996913067">à¦à¦Ÿà¦¿ বেশিরভাগ ওয়েবসাইট থেকে আপনাকে পà§à¦°à¦¸à§à¦¥à¦¾à¦¨ করà§à¦¨ করবে।</translation>
<translation id="8437238597147034694">&amp;সরানোকে পূরà§à¦¬à¦¾à¦¬à¦¸à§à¦¥à¦¾à¦¯à¦¼ ফেরান</translation>
-<translation id="8456681095658380701">অবৈধ নাম</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{১টি কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡}one{#টি কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡}other{#টি কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡}}</translation>
<translation id="8483780878231876732">আপনার Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ থেকে কারà§à¦¡ বà§à¦¯à¦¬à¦¹à¦¾à¦° করার জনà§à¦¯ Chrome ঠসাইন ইন করà§à¦¨</translation>
<translation id="8488350697529856933">à¦à¦¤à§‡ পà§à¦°à§Ÿà§‹à¦— হয়</translation>
-<translation id="8492969205326575646">অসমরà§à¦¥à¦¿à¦¤ পà§à¦°à¦•à¦¾à¦°à§‡à¦° কারà§à¦¡</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> সাড়া দিতে খà§à¦¬à§‡ বেশি সময় নিয়েছে।</translation>
<translation id="852346902619691059">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; আপনার ডিভাইসের অপারেটিং সিসà§à¦Ÿà§‡à¦® à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿à¦•à§‡ বিশà§à¦¬à¦¾à¦¸ করে না। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিচà§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
+<translation id="8532105204136943229">মেয়াদপূরà§à¦¤à¦¿à¦° বছর</translation>
<translation id="8543181531796978784">আপনি <ph name="BEGIN_ERROR_LINK" />à¦à¦•à¦Ÿà¦¿ সনাকà§à¦¤à¦•à¦°à¦£ সমসà§à¦¯à¦¾ পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨ করতে পারেন<ph name="END_ERROR_LINK" /> অথবা, আপনি আপনার নিরাপতà§à¦¤à¦¾ à¦à§à¦à¦•à¦¿ বà§à¦à¦¤à§‡ পারলে, <ph name="BEGIN_LINK" />à¦à¦‡ অনিরাপদ সাইটটি ঘà§à¦°à§‡ দেখà§à¦¨<ph name="END_LINK" />।</translation>
<translation id="8553075262323480129">পৃষà§à¦ à¦¾à¦° ভাষা নিরà§à¦§à¦¾à¦°à¦£ না করতে পারার কারণে অনà§à¦¬à¦¾à¦¦ বà§à¦¯à¦°à§à¦¥ হয়েছে৷</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ঠà¦à¦•à¦Ÿà¦¿ বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ করা যায়নি কারণ আপনার ডিভাইসের তারিখ à¦à¦¬à¦‚ সময় (<ph name="DATE_AND_TIME" />) সঠিক নয়৷</translation>
-<translation id="8570229484593575558">à¦à¦‡ তথà§à¦¯ |সংরকà§à¦·à¦£ করা হবে না|:#আপনার বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ ইতিহাস#আপনার অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨#কà§à¦•à¦¿ ডেটা</translation>
<translation id="8571890674111243710">পৃষà§à¦ à¦¾à¦Ÿà¦¿<ph name="LANGUAGE" />তে অনà§à¦¬à¦¾à¦¦ করà§à¦¨...</translation>
-<translation id="8584539743998202583">আপনার কারà§à¦¯à¦•à¦²à¦¾à¦ª à¦à¦¦à§‡à¦° কাছে |à¦à¦–নও দৃশà§à¦¯à¦®à¦¾à¦¨ হতে পারে|:#আপনি যেসব ওয়েবসাইট ঘà§à¦°à§‡ দেখেনt#আপনার নিয়োগকরà§à¦¤à¦¾#আপনার ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ পরিষেবা পà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€</translation>
<translation id="858637041960032120">ফোননমà§à¦¬à¦° জà§à¦¡à¦¼à§à¦¨</translation>
<translation id="859285277496340001">শংসাপতà§à¦°à¦Ÿà¦¿ পà§à¦°à¦¤à§à¦¯à¦¾à¦¹à¦¾à¦° করা হয়েছে কিনা তা যাচাই করতে শংসাপতà§à¦°à¦Ÿà¦¿ কোনও কারিগরীকে নিরà§à¦¦à¦¿à¦·à§à¦Ÿ করে না৷</translation>
<translation id="8620436878122366504">আপনার পিতামাতা à¦à¦–নও à¦à¦Ÿà¦¿ অনà§à¦®à§‹à¦¦à¦¨ করেন নি</translation>
<translation id="8647750283161643317">সবগà§à¦²à¦¿à¦•à§‡ ডিফলà§à¦Ÿà§‡ আবার সেট করà§à¦¨</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" />-ঠআপনার কানেকশন à¦à¦¨à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ হয় নি৷</translation>
+<translation id="8718314106902482036">পেমেনà§à¦Ÿ করা যায়নি</translation>
<translation id="8725066075913043281">আবার চেষà§à¦Ÿà¦¾ করà§à¦¨</translation>
-<translation id="8728672262656704056">আপনি ছদà§à¦®à¦¬à§‡à¦¶à§‡ রয়েছেন৷</translation>
+<translation id="8728672262656704056">আপনি গà§à¦ªà§à¦¤ মোডে চলে গেছেন</translation>
<translation id="8730621377337864115">সমà§à¦ªà¦¨à§à¦¨ হয়েছে</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="8759274551635299824">à¦à¦‡ কারà§à¦¡à¦Ÿà¦¿à¦° মেয়াদ শেষ হয়েছে</translation>
<translation id="8790007591277257123">&amp;মà§à¦›à§‡ ফেলাকে আবার করà§à¦¨</translation>
-<translation id="8798099450830957504">ডিফলà§à¦Ÿ</translation>
<translation id="8800988563907321413">আপনার জনà§à¦¯ আশেপাশের পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¨à¦¾à¦—à§à¦²à¦¿ à¦à¦–ানে দেখা যাবে</translation>
<translation id="8820817407110198400">বà§à¦•à¦®à¦¾à¦°à§à¦•à¦¸</translation>
<translation id="883848425547221593">অনà§à¦¯à¦¾à¦¨à§à¦¯ বà§à¦•à¦®à¦¾à¦°à§à¦•</translation>
@@ -818,6 +830,7 @@
<translation id="8866481888320382733">নীতি সেটিংস বিশà§à¦²à§‡à¦·à¦£ করার সময় তà§à¦°à§à¦Ÿà¦¿</translation>
<translation id="8866959479196209191">à¦à¦‡ পৃষà§à¦ à¦¾ বলছে:</translation>
<translation id="8870413625673593573">সমà§à¦ªà§à¦°à¦¤à¦¿ বনà§à¦§ হয়েছে</translation>
+<translation id="8874824191258364635">à¦à¦•à¦Ÿà¦¿ সঠিক কারà§à¦¡ নমà§à¦¬à¦° লিখà§à¦¨</translation>
<translation id="8876793034577346603">নেটওয়ারà§à¦• কনফিগারেশন বিশà§à¦²à§‡à¦·à¦£ করতে বà§à¦¯à¦°à§à¦¥ হয়েছে৷</translation>
<translation id="8877192140621905067">আপনি নিশà§à¦šà¦¿à¦¤ করলে, আপনার কারà§à¦¡à§‡à¦° বিবরণ à¦à¦‡ সাইটের সাথে শেয়ার করা হবে</translation>
<translation id="8889402386540077796">রঙ বিনà§à¦¯à¦¾à¦¸</translation>
@@ -827,7 +840,6 @@
<translation id="8931333241327730545">আপনি কি আপনার Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡ à¦à¦‡ কারà§à¦¡ সংরকà§à¦·à¦£ করতে চান?</translation>
<translation id="8932102934695377596">আপনার ঘড়ির সময় পিছিয়ে রয়েছে</translation>
<translation id="8954894007019320973">(চলছে)</translation>
-<translation id="895548565263634352"><ph name="ARTICLE_PUBLISHER" /> à¦à¦¬à¦‚ আরো <ph name="OTHER_ARTICLE_COUNT" />টি নিবনà§à¦§ থেকে গলà§à¦ª পড়à§à¦¨</translation>
<translation id="8971063699422889582">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦°à§‡à¦° মেয়াদ ফà§à¦°à¦¿à§Ÿà§‡à¦›à§‡à§·</translation>
<translation id="8986494364107987395">বà§à¦¯à¦¬à¦¹à¦¾à¦°à§‡à¦° পরিসংখà§à¦¯à¦¾à¦¨ à¦à¦¬à¦‚ কà§à¦°à§à¦¯à¦¾à¦¶ পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨à¦—à§à¦²à¦¿ সà§à¦¬à§Ÿà¦‚কà§à¦°à¦¿à§Ÿà¦­à¦¾à¦¬à§‡ Google-ঠপাঠান</translation>
<translation id="8987927404178983737">মাস</translation>
@@ -845,7 +857,6 @@
<translation id="9068849894565669697">রঙ নিরà§à¦¬à¦¾à¦šà¦¨ করà§à¦¨</translation>
<translation id="9076283476770535406">à¦à¦¤à§‡ পà§à¦°à¦¾à¦ªà§à¦¤à¦¬à§Ÿà¦¸à§à¦•à¦¦à§‡à¦° সামগà§à¦°à§€ থাকতে পারে</translation>
<translation id="9078964945751709336">আরো তথà§à¦¯ পà§à¦°à¦¯à¦¼à§‹à¦œà¦¨</translation>
-<translation id="9094175695478007090">পেমেনà§à¦Ÿ অà§à¦¯à¦¾à¦ª লঞà§à¦š করা যায়নি।</translation>
<translation id="9103872766612412690"><ph name="SITE" /> সাধারণত আপনার তথà§à¦¯ সà§à¦°à¦•à§à¦·à¦¿à¦¤ রাখতে à¦à¦¨à¦•à§à¦°à¦¿à¦ªà¦¶à¦¾à¦¨ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে। à¦à¦‡à¦¬à¦¾à¦° যখন Chromium <ph name="SITE" /> à¦à¦° সাথে সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ করার চেষà§à¦Ÿà¦¾ করেছে, তখন ওয়েবসাইটটি অসà§à¦¬à¦¾à¦­à¦¾à¦¬à¦¿à¦• à¦à¦¬à¦‚ ভà§à¦² শংসাপতà§à¦° পাঠিয়েছে। হয় à¦à¦•à¦œà¦¨ আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ <ph name="SITE" /> হওয়ার ভান করছে, অথবা à¦à¦•à¦Ÿà¦¿ ওয়াই-ফাই পà§à¦°à¦¬à§‡à¦¶ করà§à¦¨ সà§à¦•à§à¦°à§€à¦£ সংযোগকে বাধাপà§à¦°à¦¦à¦¾à¦¨ করেছে। আপনার তথà§à¦¯ à¦à¦–নো নিরাপদ আছে কারণ কোনো ডেটা আদানপà§à¦°à¦¦à¦¾à¦¨à§‡à¦° আগেই Chromium সংযোগটিকে বনà§à¦§ করে দিয়েছে।</translation>
<translation id="9137013805542155359">পà§à¦°à¦•à§ƒà¦¤ রূপ দেখান</translation>
<translation id="9137248913990643158">à¦à¦‡ অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨à¦Ÿà¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করার আগে অনà§à¦—à§à¦°à¦¹ করে শà§à¦°à§ করà§à¦¨ à¦à¦¬à¦‚ Chrome ঠপà§à¦°à¦¬à§‡à¦¶ করà§à¦¨à¥¤</translation>
diff --git a/chromium/components/strings/components_strings_ca.xtb b/chromium/components/strings/components_strings_ca.xtb
index 01478fd732b..0b009baa947 100644
--- a/chromium/components/strings/components_strings_ca.xtb
+++ b/chromium/components/strings/components_strings_ca.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="ca">
<translation id="1008557486741366299">Ara no</translation>
<translation id="1015730422737071372">Proporcioneu més informació</translation>
+<translation id="1021110881106174305">Targetes acceptades</translation>
<translation id="1032854598605920125">Gira en el sentit de les agulles del rellotge</translation>
<translation id="1038842779957582377">nom desconegut</translation>
<translation id="1050038467049342496">Tanca altres aplicacions</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Amaga el valor</translation>
<translation id="1228893227497259893">Identificador d'entitat incorrecte</translation>
<translation id="1232569758102978740">Sense títol</translation>
+<translation id="1263231323834454256">Llista de lectura</translation>
<translation id="1264126396475825575">S'ha capturat un informe d'error (<ph name="CRASH_TIME" />) (encara no s'ha penjat ni ignorat)</translation>
<translation id="1285320974508926690">No tradueixis mai aquest lloc</translation>
<translation id="129553762522093515">Tancades recentment</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Configuració d'Emplenament automàtic de Chromium...</translation>
<translation id="1374468813861204354">suggeriments</translation>
<translation id="1375198122581997741">Quan a la versió</translation>
+<translation id="1377321085342047638">Número de targeta</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> no ha enviat dades.</translation>
<translation id="1407135791313364759">Obre-les totes</translation>
<translation id="1413809658975081374">Error de privadesa</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Historial</translation>
<translation id="1645368109819982629">Protocol no admès</translation>
<translation id="1656489000284462475">Recollida</translation>
+<translation id="1663943134801823270">Les targetes i les adreces s'obtenen de Chrome. Pots gestionar-les des de <ph name="BEGIN_LINK" />Configuració<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> utilitza normalment l'encriptació per protegir la vostra informació. En aquesta ocasió, quan Google Chrome ha provat de connectar-se a <ph name="SITE" />, el lloc web ha enviat credencials poc comunes i incorrectes. Pot ser que un atacant estigui provant de fer-se passar per <ph name="SITE" /> o que una pantalla d'inici de sessió a la xarxa Wi-Fi hagi interromput la connexió. En qualsevol cas, la vostra informació continua estant segura, perquè Google Chrome ha aturat la connexió abans no s'intercanviés cap dada.</translation>
<translation id="168328519870909584">Els atacants que actualment són al lloc <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> poden provar d'instal·lar aplicacions perilloses al dispositiu per robar o suprimir la teva informació (com ara fotos, contrasenyes, missatges i targetes de crèdit).</translation>
<translation id="168841957122794586">El certificat de servidor conté una clau criptogràfica dèbil.</translation>
<translation id="1710259589646384581">SO</translation>
<translation id="1721312023322545264">Cal que <ph name="NAME" /> et doni permís per visitar aquest lloc</translation>
+<translation id="1721424275792716183">* El camp és obligatori</translation>
<translation id="1728677426644403582">Estàs consultant el codi font d'una pàgina web</translation>
+<translation id="173080396488393970">Aquest tipus de targeta no s'admet</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Proveu de contactar amb l'administrador del sistema.</translation>
+<translation id="1740951997222943430">Introdueix un mes de caducitat vàlid</translation>
<translation id="1745358365027406341">Baixa la pàgina més tard</translation>
<translation id="17513872634828108">Pestanyes obertes</translation>
<translation id="1753706481035618306">Número de pàgina</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Actualitzeu la frase de contrasenya de sincronització.</translation>
<translation id="1787142507584202372">Les pestanyes obertes es mostren aquí</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Selecciona una adreça d'entrega per veure els mètodes d'entrega i els requisits.</translation>
+<translation id="1803264062614276815">Nom del titular de la targeta</translation>
<translation id="1803678881841855883">Fa poc, la funció Navegació segura de Google <ph name="BEGIN_LINK" />ha detectat programari maliciós<ph name="END_LINK" /> a <ph name="SITE" />. De vegades, els llocs web que acostumen a ser segurs s'infecten amb programari maliciós. El contingut maliciós prové de l'amfitrió <ph name="SUBRESOURCE_HOST" />, un distribuïdor conegut de programari maliciós. <ph name="BEGIN_LEARN_MORE_LINK" />Obtén més informació<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Afegida el dia <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Sol·licitud o paràmetres de la sol·licitud no vàlids</translation>
<translation id="1826516787628120939">S'està comprovant</translation>
<translation id="1834321415901700177">Aquest lloc conté programes perjudicials</translation>
<translation id="1842969606798536927">Pagament</translation>
-<translation id="1864455488461349376">Opció d'entrega</translation>
<translation id="1871208020102129563">El servidor intermediari està configurat perquè utilitzi servidors intermediaris fixos, en lloc d'un URL d'script .pac.</translation>
<translation id="1871284979644508959">Camp obligatori</translation>
<translation id="187918866476621466">Obre les pàgines d'inici</translation>
<translation id="1883255238294161206">Redueix la llista</translation>
<translation id="1898423065542865115">Filtratge</translation>
<translation id="194030505837763158">Vés a <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Targetes acceptades</translation>
<translation id="1962204205936693436">Adreces d'interès de <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Error de serialització</translation>
<translation id="1974060860693918893">Configuració avançada</translation>
<translation id="1978555033938440688">Versió del microprogramari</translation>
+<translation id="1995859865337580572">Verifica el CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{i 1 aplicació més}other{i # aplicacions més}}</translation>
-<translation id="2020194265157481222">Cal indicar el titular de la targeta</translation>
<translation id="2025186561304664664">El servidor intermediari està definit perquè es configuri automàticament.</translation>
<translation id="2030481566774242610">Volíeu dir <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Comproveu el servidor intermediari i el tallafoc<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Avui</translation>
<translation id="2154054054215849342">La sincronització no està disponible per al teu domini</translation>
<translation id="2154484045852737596">Edita la targeta</translation>
-<translation id="2156993118928861787">Adreça no vàlida</translation>
<translation id="2166049586286450108">Accés complet d'administrador</translation>
<translation id="2166378884831602661">Aquest lloc no pot proporcionar una connexió segura</translation>
<translation id="2181821976797666341">Polítiques</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adreça}other{# adreces}}</translation>
+<translation id="2202020181578195191">Introdueix un any de caducitat vàlid</translation>
<translation id="2212735316055980242">No es troba la política</translation>
<translation id="2213606439339815911">S'estan recuperant les entrades...</translation>
<translation id="2230458221926704099">Repareu la connexió amb l'<ph name="BEGIN_LINK" />aplicació de diagnòstic<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">El vostre accés a Internet està bloquejat</translation>
<translation id="230155334948463882">És una targeta nova?</translation>
<translation id="2305919008529760154">Aquest servidor no ha pogut demostrar que és <ph name="DOMAIN" />. És possible que el seu certificat de seguretat s'hagi emès de manera fraudulenta. Això pot ser a causa d'una configuració incorrecta o d'un atacant que ha interceptat la teva connexió. <ph name="BEGIN_LEARN_MORE_LINK" />Obtén més informació<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Les opcions de targetes i adreces provenen del teu compte de Google (<ph name="ACCOUNT_EMAIL" />) i de Chrome. Pots gestionar-les a <ph name="BEGIN_LINK" />Configuració<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> requereix un nom d'usuari i una contrasenya.</translation>
<translation id="2318774815570432836">En aquest moment no pots visitar <ph name="SITE" /> perquè el lloc web fa servir HSTS. 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. <ph name="BEGIN_LEARN_MORE_LINK" />Obtén més informació<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Altres adreces d'interès</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Predeterminada de l'empresa</translation>
<translation id="2386255080630008482">El certificat del servidor s'ha revocat.</translation>
<translation id="2392959068659972793">Mostra les polítiques sense valors definits</translation>
+<translation id="239429038616798445">Aquest mètode d'enviament no està disponible. Prova'n un altre.</translation>
<translation id="2396249848217231973">&amp;Desfés la supressió</translation>
<translation id="2460160116472764928">Fa poc, la funció Navegació segura de Google <ph name="BEGIN_LINK" />ha detectat programari maliciós<ph name="END_LINK" /> a <ph name="SITE" />. De vegades, els llocs web que acostumen a ser segurs s'infecten amb programari maliciós. <ph name="BEGIN_LEARN_MORE_LINK" />Obtén més informació<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Emplena</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Executar el Diagnòstic de xarxa<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL de cerca no vàlid.</translation>
<translation id="2491120439723279231">El certificat del servidor conté errors.</translation>
-<translation id="24943777258388405">El número de telèfon no és vàlid</translation>
<translation id="2495083838625180221">Analitzador JSON</translation>
<translation id="2495093607237746763">Si s'activa aquesta casella, Chromium desa una còpia de la vostra targeta al dispositiu per agilitzar l'emplenament de formularis.</translation>
<translation id="2498091847651709837">Escaneja una targeta nova</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> ha enviat una resposta que no és vàlida.</translation>
<translation id="2552545117464357659">Més nova</translation>
<translation id="2556876185419854533">&amp;Desfés la modificació</translation>
+<translation id="2587730715158995865">Publicat per <ph name="ARTICLE_PUBLISHER" />. Llegeix aquesta història i <ph name="OTHER_ARTICLE_COUNT" /> més.</translation>
<translation id="2587841377698384444">Identificador de l'API de directoris:</translation>
<translation id="2597378329261239068">Aquest document està protegit mitjançant contrasenya. Introduïu una contrasenya.</translation>
<translation id="2609632851001447353">Variacions</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Executar el Diagnòstic de connectivitat<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">D'acord</translation>
<translation id="2742870351467570537">Suprimeix els elements seleccionats</translation>
+<translation id="277133753123645258">Mètode d'enviament</translation>
<translation id="277499241957683684">Falta el registre del dispositiu</translation>
<translation id="2784949926578158345">S'ha restablert la connexió.</translation>
<translation id="2794233252405721443">Lloc bloquejat</translation>
-<translation id="2812680587231492111">Aquesta opció de recollida no està disponible. Prova'n una altra.</translation>
<translation id="2824775600643448204">Barra d'adreces i de cerca</translation>
<translation id="2826760142808435982">La connexió s'ha encriptat i autenticat mitjançant <ph name="CIPHER" /> i fa servir <ph name="KX" /> com a mecanisme d'intercanvi clau.</translation>
<translation id="2835170189407361413">Esborra el formulari</translation>
-<translation id="2849041323157393173">Aquesta opció d'entrega no està disponible. Prova'n una altra.</translation>
<translation id="2889159643044928134">No tornis a carregar</translation>
<translation id="2900469785430194048">Google Chrome s'ha quedat sense memòria en provar de mostrar aquesta pàgina web.</translation>
<translation id="2909946352844186028">S'ha detectat un canvi a la xarxa.</translation>
<translation id="2916038427272391327">Tanca altres programes</translation>
<translation id="2922350208395188000">No es pot comprovar el certificat del servidor.</translation>
+<translation id="2928905813689894207">Adreça de facturació</translation>
<translation id="2948083400971632585">Podeu desactivar qualsevol servidor intermediari configurat per a una connexió des de la pàgina de configuració.</translation>
<translation id="2955913368246107853">Tanca la barra de cerca</translation>
<translation id="2958431318199492670">La configuració de la xarxa no compleix l'estàndard ONC. Pot ser que algunes opcions de configuració no s'hagin importat.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Per establir una connexió segura, heu de tenir el rellotge ben configurat, ja que els certificats que els llocs web fan servir per identificar-se només són vàlids durant períodes de temps concrets. Com que el rellotge del dispositiu no està ben configurat, Google Chrome no pot verificar aquests certificats.</translation>
<translation id="2972581237482394796">&amp;Refés</translation>
<translation id="2985306909656435243">Si s'activa aquesta opció, Chromium desa una còpia de la vostra targeta en aquest dispositiu per agilitzar l'emplenament de formularis.</translation>
+<translation id="2985398929374701810">Introdueix una adreça vàlida</translation>
+<translation id="2986368408720340940">Aquest mètode de recollida no està disponible. Prova'n un altre.</translation>
<translation id="2991174974383378012">Comparteix informació amb llocs web</translation>
<translation id="3005723025932146533">Mostra la còpia desada</translation>
<translation id="3008447029300691911">Introdueix el CVC de la targeta <ph name="CREDIT_CARD" />. Un cop confirmada, els detalls de la targeta es compartiran amb aquest lloc.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{almenys 1 element als dispositius sincronitzats}=1{1 element (i altres elements als dispositius sincronitzats)}other{# elements (i altres elements als dispositius sincronitzats)}}</translation>
<translation id="3041612393474885105">Informació del certificat</translation>
<translation id="3063697135517575841">Chrome no ha pogut confirmar la teva targeta. Torna-ho a provar més tard.</translation>
+<translation id="3064966200440839136">Per pagar amb una aplicació externa sortiràs del mode d'incògnit. Vols continuar?</translation>
<translation id="3093245981617870298">Esteu fora de línia.</translation>
<translation id="3105172416063519923">Identificador de l'element:</translation>
<translation id="3109728660330352905">No teniu permís per veure aquesta pàgina.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Proveu d'executar el Diagnòstic de connectivitat<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">No s'ha pogut descodificar la resposta</translation>
-<translation id="3149891296864842641">Opció d'enviament</translation>
<translation id="3150653042067488994">Error temporal del servidor</translation>
+<translation id="3154506275960390542">Aquesta pàgina inclou un formulari que pot ser que no s'enviï de manera segura. La resta d'usuaris poden veure les dades que enviïs mentre estiguin en trànsit o un atacant podria modificar-les per canviar el contingut que rep el servidor.</translation>
<translation id="3157931365184549694">Restaura</translation>
<translation id="3167968892399408617">Les pàgines que consulteu en pestanyes d'incògnit no s'emmagatzemaran a l'historial del navegador, al magatzem de galetes ni a l'historial de cerca després d'haver tancat totes les pestanyes d'incògnit. Els fitxers que baixeu i les adreces d'interès que creeu sí que es desaran.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">La sol·licitud per accedir al lloc no s'ha pogut enviar a <ph name="NAME" />. Torneu-ho a provar.</translation>
<translation id="3355823806454867987">Canvia la configuració del servidor intermediari...</translation>
<translation id="3369192424181595722">Error de rellotge</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> elements més...</translation>
<translation id="337363190475750230">No administrat</translation>
<translation id="3377188786107721145">S'ha produït un error en analitzar la política</translation>
<translation id="3380365263193509176">Error desconegut</translation>
<translation id="3380864720620200369">Identificador de client:</translation>
<translation id="3391030046425686457">Adreça d'entrega</translation>
+<translation id="3395827396354264108">Mètode de recollida</translation>
<translation id="340013220407300675">És possible que hi hagi atacants que estiguin provant de robar-vos informació de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (per exemple, contrasenyes, missatges o targetes de crèdit).</translation>
<translation id="3422248202833853650">Prova de sortir d'altres programes per alliberar memòria.</translation>
<translation id="3422472998109090673">Actualment no es pot accedir a <ph name="HOST_NAME" />.</translation>
@@ -277,13 +287,14 @@
<translation id="3447661539832366887">El propietari d'aquest dispositiu ha desactivat el joc de dinosaures.</translation>
<translation id="3450660100078934250">Mastercard</translation>
<translation id="3452404311384756672">Obtén l'interval:</translation>
-<translation id="3462200631372590220">Amaga la informació avançada</translation>
+<translation id="3462200631372590220">Amaga la configuració avançada</translation>
+<translation id="3467763166455606212">El nom del titular de la targeta és obligatori</translation>
+<translation id="3478058380795961209">Mes de caducitat</translation>
<translation id="3479539252931486093">Heu trobat el lloc bloquejat de manera inesperada? <ph name="BEGIN_LINK" />Informeu-nos-en<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Ara no</translation>
<translation id="348000606199325318">Identificador d'error <ph name="CRASH_LOCAL_ID" /> (identificador de servidor: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">En aquests moments no ens hem pogut posar en contacte amb els pares. Torneu-ho a provar.</translation>
<translation id="3528171143076753409">El certificat del servidor no és de confiança.</translation>
-<translation id="3538531656504267329">L'any de caducitat no és vàlid</translation>
<translation id="3539171420378717834">Desa una còpia d'aquesta targeta al dispositiu</translation>
<translation id="3542684924769048008">Utilitzar la contrasenya per a:</translation>
<translation id="3549644494707163724">Encripta totes les dades sincronitzades amb la teva frase de contrasenya de sincronització</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Oculta els detalls</translation>
<translation id="3587482841069643663">Tots</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Introdueix una data de caducitat vàlida</translation>
<translation id="36224234498066874">Esborra les dades de navegació</translation>
<translation id="362276910939193118">Mostra l'historial complet</translation>
<translation id="3623476034248543066">Mostra el valor</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Contrasenya:</translation>
<translation id="3696411085566228381">cap</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Selecciona una adreça d'enviament per veure els mètodes d'enviament i els requisits.</translation>
<translation id="370665806235115550">S'està carregant...</translation>
<translation id="3712624925041724820">Llicències exhaurides</translation>
<translation id="3714780639079136834">Activeu les dades mòbils o la Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Enllaç que heu copiat</translation>
<translation id="375403751935624634">S'ha produït un error en el procés de traducció a causa d'un error del servidor.</translation>
<translation id="3759461132968374835">No heu informat de cap bloqueig recentment. Els bloquejos que es van produir mentre la creació d'informes de bloqueig estava desactivada no apareixeran aquí.</translation>
+<translation id="3787705759683870569">Data de caducitat: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Si feu servir un servidor intermediari...</translation>
<translation id="3828924085048779000">Les frases de contrasenya no poder estar buides.</translation>
<translation id="3845539888601087042">Es mostra l'historial dels dispositius en què heu iniciat la sessió. <ph name="BEGIN_LINK" />Obteniu més informació<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Voleu que Chromium desi aquesta targeta?</translation>
<translation id="4171400957073367226">La signatura de verificació és incorrecta</translation>
-<translation id="4176463684765177261">Desactivat</translation>
<translation id="4196861286325780578">&amp;Refés el moviment</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Comproveu la configuració del tallafoc i de l'antivirus<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{cap}=1{1 aplicació ($1)}=2{2 aplicacions ($1, $2)}other{# aplicacions ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">resultats de la cerca</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> no ha acceptat el certificat d'inici de sessió o pot ser que no se n'hagi proporcionat cap.</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="4446242550670694251">Ara pots navegar de manera privada i les altres persones que utilitzin aquest dispositiu no veuran la teva activitat.</translation>
<translation id="4492190037599258964">Resultats de la cerca per a "<ph name="SEARCH_STRING" />"</translation>
<translation id="4506176782989081258">Error de validació: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Contacteu amb l'administrador del sistema</translation>
<translation id="450710068430902550">Comparteix informació amb l'administrador</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="4522570452068850558">Detalls</translation>
<translation id="4558551763791394412">Desactiveu les extensions</translation>
<translation id="457875822857220463">Entrega</translation>
@@ -416,7 +427,8 @@
<translation id="4813512666221746211">Error de xarxa</translation>
<translation id="4816492930507672669">Ajusta a la mida de la pàgina</translation>
<translation id="483020001682031208">No es pot mostrar cap pàgina del Web físic</translation>
-<translation id="4850886885716139402">Visualització</translation>
+<translation id="4850886885716139402">Mostra</translation>
+<translation id="4854362297993841467">Aquest mètode d'entrega no està disponible. Prova'n un altre.</translation>
<translation id="4858792381671956233">Has demanat permís als teus pares per visitar aquest lloc</translation>
<translation id="4880827082731008257">Cerca a l'historial</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Aquesta pàgina s'ha traduït des d'un idioma desconegut a: <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Pagament</translation>
<translation id="4926049483395192435">S'ha d'especificar.</translation>
-<translation id="4941291666397027948">* indica que el camp és obligatori</translation>
<translation id="495170559598752135">Accions</translation>
<translation id="4958444002117714549">Desplega la llista</translation>
<translation id="4962322354953122629">Aquest servidor no ha pogut demostrar que és <ph name="DOMAIN" />. Chrome no confia en el certificat de seguretat presentat. Això pot ser a causa d'una configuració incorrecta o d'un atacant que ha interceptat la teva connexió. <ph name="BEGIN_LEARN_MORE_LINK" />Obtén més informació<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Contrasenya incorrecta</translation>
<translation id="5056549851600133418">Articles que us poden interessar</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Comproveu l'adreça del servidor intermediari<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{No s'utilitzen galetes}=1{1 lloc utilitza galetes. }other{# llocs utilitzen galetes. }}</translation>
<translation id="5087286274860437796">En aquest moment el certificat del servidor no és vàlid.</translation>
<translation id="5087580092889165836">Afegiu una targeta</translation>
<translation id="5089810972385038852">Estat</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Mostra</translation>
<translation id="5308689395849655368">La creació d'informes de bloqueig està desactivada.</translation>
<translation id="5317780077021120954">Desa</translation>
-<translation id="5326702247179446998">Cal indicar un destinatari</translation>
<translation id="5327248766486351172">Nom</translation>
<translation id="5337705430875057403">Els atacants de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> us poden enganyar perquè feu alguna acció perillosa, com ara instal·lar programari o revelar informació personal (per exemple, contrasenyes, números de telèfon o targetes de crèdit).</translation>
-<translation id="53553865750799677">L'adreça de recollida no s'admet. Selecciona'n una altra.</translation>
<translation id="5359637492792381994">Aquest servidor no ha pogut demostrar que és <ph name="DOMAIN" /> perquè el seu certificat de seguretat no és vàlid en aquest moment. Això pot ser a causa d'una configuració incorrecta o d'un atacant que ha interceptat la teva connexió. <ph name="BEGIN_LEARN_MORE_LINK" />Obtén més informació<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">No s'ha pogut emmagatzemar la configuració de la política</translation>
<translation id="5386426401304769735">La cadena de certificats d'aquest lloc conté un certificat que s'ha signat amb SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">Una pàgina inserida a <ph name="SITE" /> diu:</translation>
<translation id="5556459405103347317">Torna a carregar</translation>
<translation id="5565735124758917034">Actiu</translation>
+<translation id="5571083550517324815">No es pot fer la recollida en aquesta adreça. Selecciona'n una altra.</translation>
<translation id="5572851009514199876">Obre Chrome i inicia-hi la sessió perquè Chrome pugui comprovar si tens permís per accedir a aquest lloc.</translation>
-<translation id="5575380383496039204">L'adreça d'entrega no s'admet. Selecciona'n una altra.</translation>
<translation id="5580958916614886209">Comprova el mes de caducitat i torna-ho a provar</translation>
<translation id="560412284261940334">Gestió no compatible</translation>
<translation id="5610142619324316209">Comproveu la connexió</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">La identitat d'aquest lloc web no ha estat verificada.</translation>
<translation id="5720705177508910913">Usuari actual</translation>
<translation id="5732392974455271431">Els teus pares te'l poden desbloquejar</translation>
-<translation id="57586589942790530">El número de targeta no és vàlid</translation>
+<translation id="5763042198335101085">Introdueix una adreça electrònica vàlida</translation>
+<translation id="5765072501007116331">Per veure els mètodes i els requisits d'entrega, selecciona una adreça</translation>
<translation id="5784606427469807560">S'ha produït un problema en confirmar la targeta. Comprova la connexió a Internet i torna-ho a provar.</translation>
<translation id="5785756445106461925">A més, aquesta pàgina conté altres recursos que no són segurs. La resta d'usuaris poden visualitzar-los mentre estan en trànsit, i algun atacant podria modificar-los per canviar l'aparença de la pàgina.</translation>
<translation id="5786044859038896871">Vols emplenar la informació de la teva targeta?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">No es pot accedir a aquest lloc</translation>
<translation id="5869522115854928033">Contrasenyes desades</translation>
<translation id="5872918882028971132">Suggeriments per als responsables</translation>
-<translation id="587760065310675640">L'adreça d'enviament no s'admet. Selecciona'n una altra.</translation>
<translation id="5901630391730855834">Groc</translation>
-<translation id="59174027418879706">Activada</translation>
<translation id="5926846154125914413">Pot ser que perdis l'accés al contingut prèmium d'alguns llocs.</translation>
<translation id="5959728338436674663">Envia automàticament algunes <ph name="BEGIN_WHITEPAPER_LINK" />dades del sistema i contingut de les pàgines<ph name="END_WHITEPAPER_LINK" /> a Google per ajudar a detectar les aplicacions i els llocs perillosos. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Setmana</translation>
<translation id="5967867314010545767">Elimina de l'historial</translation>
<translation id="5975083100439434680">Redueix</translation>
+<translation id="598637245381783098">No es pot obrir l'aplicació de pagament</translation>
<translation id="5989320800837274978">No s'especifiquen servidors intermediaris ni URL d'script .pac.</translation>
<translation id="5990559369517809815">Una extensió ha bloquejat les peticions al servidor.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Les opcions de targetes i adreces provenen de Chrome. Pots gestionar-les a <ph name="BEGIN_LINK" />Configuració<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Pàgina 1}other{Pàgina #}}</translation>
<translation id="6017514345406065928">Verd</translation>
+<translation id="6027201098523975773">Escriu un nom</translation>
<translation id="6040143037577758943">Tanca</translation>
-<translation id="604124094241169006">Automàtic</translation>
<translation id="6042308850641462728">Més</translation>
<translation id="6060685159320643512">Compte! Aquests experiments mosseguen</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{cap}=1{1}other{#}}</translation>
@@ -543,9 +552,10 @@
dispositius de xarxa que feu servir.</translation>
<translation id="614940544461990577">Proveu aquestes solucions:</translation>
<translation id="6151417162996330722">El període de validesa del certificat del servidor és massa gran.</translation>
-<translation id="615643356032862689">Les adreces d'interès i els fitxers baixats es mantindran.</translation>
+<translation id="6157877588268064908">Per veure els mètodes i els requisits d'enviament, selecciona una adreça</translation>
<translation id="6165508094623778733">Més informació</translation>
<translation id="6177128806592000436">La teva connexió amb aquest lloc no és segura</translation>
+<translation id="6184817833369986695">(cohort: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Comprovació de la connexió a Internet</translation>
<translation id="6218753634732582820">Voleu suprimir l'adreça de Chromium?</translation>
<translation id="6251924700383757765">Política de privadesa</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Refés el canvi d'ordre</translation>
<translation id="6263376278284652872">Adreces d'interès de <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Torna a l'àrea de seguretat</translation>
+<translation id="6276112860590028508">Les pàgines de la teva llista de lectura es mostren aquí</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="6290238015253830360">Els suggeriments d'articles es mostren aquí</translation>
<translation id="6305205051461490394">No es pot accedir a <ph name="URL" />.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">No es pot comprovar si s'ha revocat el certificat.</translation>
<translation id="6433490469411711332">Edita la informació de contacte</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> no ens ha permès establir la connexió.</translation>
-<translation id="6443118737398455446">La data de caducitat no és vàlida</translation>
<translation id="6446608382365791566">Afegeix més informació</translation>
<translation id="6451458296329894277">Confirma el reenviament del formulari</translation>
<translation id="6456339708790392414">El teu pagament</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Aquest servidor no ha pogut demostrar que és <ph name="DOMAIN" />. É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 ha interceptat la teva connexió. <ph name="BEGIN_LEARN_MORE_LINK" />Obtén més informació<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Polítiques de dispositius</translation>
<translation id="6477321094435799029">Chrome ha detectat codi poc comú en aquesta pàgina i, per tant, l'ha bloquejat per protegir la teva informació personal (per exemple, contrasenyes, números de telèfon i targetes de crèdit).</translation>
-<translation id="6477460825583319731">L'adreça electrònica no és vàlida</translation>
<translation id="6489534406876378309">Comença a penjar els errors</translation>
<translation id="6508722015517270189">Reinicia Chrome</translation>
-<translation id="6525462735697194615">El mes de caducitat no és vàlid</translation>
<translation id="6529602333819889595">&amp;Refés la supressió</translation>
<translation id="6534179046333460208">Suggeriments del Web físic</translation>
<translation id="6550675742724504774">Opcions</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685">Cerca de <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Aquesta política ha quedat obsoleta.</translation>
<translation id="6652240803263749613">Aquest servidor no ha pogut demostrar que és <ph name="DOMAIN" />. El sistema operatiu del teu ordinador no confia en el certificat de seguretat presentat. Això pot ser a causa d'una configuració incorrecta o d'un atacant que ha interceptat la teva connexió. <ph name="BEGIN_LEARN_MORE_LINK" />Obtén més informació<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Aquesta opció d'enviament no està disponible. Prova'n una altra.</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="6710213216561001401">Anterior</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Hi ha hagut algun problema amb el servidor intermediari o l'adreça no és correcta.</translation>
<translation id="6727102863431372879">Configura</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{cap}=1{1 element}other{# elements}}</translation>
-<translation id="6743044928064272573">Opció de recollida</translation>
<translation id="674375294223700098">Error de certificat del servidor desconegut.</translation>
<translation id="6753269504797312559">Valor de la política</translation>
<translation id="6757797048963528358">El dispositiu ha entrat en mode de repòs.</translation>
<translation id="6778737459546443941">El teu pare o la teva mare encara no ho han aprovat</translation>
<translation id="6810899417690483278">Identificador de personalització</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">No s'han pogut carregar les dades de la regió</translation>
<translation id="6831043979455480757">Tradueix</translation>
<translation id="6839929833149231406">Àrea</translation>
<translation id="6874604403660855544">&amp;Refés l'addició</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">La teva targeta s'ha confirmat</translation>
<translation id="6897140037006041989">Agent d'usuari</translation>
<translation id="6915804003454593391">Usuari:</translation>
+<translation id="6948701128805548767">Per veure els mètodes i els requisits de recollida, selecciona una adreça</translation>
<translation id="6957887021205513506">Sembla que el certificat del servidor és una falsificació.</translation>
<translation id="6965382102122355670">D'acord</translation>
<translation id="6965978654500191972">Dispositiu</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">S'especifiquen tant els servidors intermediaris fixos com un URL d'script .pac.</translation>
<translation id="6989763994942163495">Mostra la configuració avançada...</translation>
<translation id="7000990526846637657">No s'ha trobat cap entrada a l'historial</translation>
-<translation id="7001663382399377034">Afegeix un destinatari</translation>
<translation id="7009986207543992532">Has provat d'accedir a <ph name="DOMAIN" />, però el servidor ha presentat un certificat amb un període de validesa massa llarg per poder confiar-hi. <ph name="BEGIN_LEARN_MORE_LINK" />Obtén més informació<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">És possible que el teu compte de Google tingui altres formes de l'historial de navegació a <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Més antic</translation>
<translation id="7090678807593890770">Cerqueu <ph name="LINK" /> a Google</translation>
<translation id="7119414471315195487">Tanca altres pestanyes o programes</translation>
+<translation id="7129409597930077180">No es pot enviar a aquesta adreça. Selecciona'n una altra.</translation>
+<translation id="7138472120740807366">Mètode d'entrega</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7155487117670177674">El pagament no és segur</translation>
<translation id="7179921470347911571">Torna'l a iniciar ara</translation>
<translation id="7180611975245234373">Actualitza</translation>
<translation id="7182878459783632708">Cap política definida</translation>
<translation id="7186367841673660872">Aquesta pàgina s'ha traduït de:<ph name="ORIGINAL_LANGUAGE" />a:<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> no compleix la normativa de seguretat.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Més informació<ph name="END_LINK" /> sobre aquest problema.</translation>
@@ -675,7 +686,6 @@ El mode d'incògnit, <ph name="SHORTCUT_KEY" />, us pot resultar pràctic la pro
<translation id="7424977062513257142">Una pàgina inserida en aquesta pàgina web diu:</translation>
<translation id="7441627299479586546">Usuari de la política incorrecte</translation>
<translation id="7444046173054089907">Aquest lloc està bloquejat</translation>
-<translation id="7444238235002594607">Selecciona una adreça de recollida per veure els mètodes de recollida i els requisits.</translation>
<translation id="7445762425076701745">La identitat del servidor al qual esteu connectat no es pot acabar de validar. Esteu connectat a un servidor que utilitza un nom que només és vàlid dins la vostra xarxa, de manera que una autoritat de certificació externa no en pot validar la propietat. Com que de tota manera algunes autoritats de certificació emetran certificats per a aquests noms, no es pot assegurar que estigueu connectat al lloc web previst i no a un atacant.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Obtenir més informació<ph name="END_LINK" /> sobre aquest problema</translation>
<translation id="7460163899615895653">Les teves pestanyes recents d'altres dispositius es mostraran aquí</translation>
@@ -719,6 +729,7 @@ El mode d'incògnit, <ph name="SHORTCUT_KEY" />, us pot resultar pràctic la pro
<translation id="7755287808199759310">El teu pare o la teva mare et poden desbloquejar el lloc</translation>
<translation id="7758069387465995638">És possible que l'antivirus o el tallafoc hagi bloquejat la connexió.</translation>
<translation id="7761701407923456692">El certificat del servidor no coincideix amb l'URL.</translation>
+<translation id="7763386264682878361">Analitzador de fitxers de manifest de pagament</translation>
<translation id="7764225426217299476">Afegeix una adreça</translation>
<translation id="777702478322588152">Prefectura</translation>
<translation id="7791543448312431591">Afegeix</translation>
@@ -732,6 +743,7 @@ El mode d'incògnit, <ph name="SHORTCUT_KEY" />, us pot resultar pràctic la pro
<translation id="785549533363645510">Tanmateix, no sou invisible. La vostra empresa, el vostre proveïdor de serveis d'Internet i els llocs web que visiteu poden veure la vostra navegació d'incògnit.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" />: <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Comproveu el CVC i torneu-ho a provar</translation>
+<translation id="79338296614623784">Introdueix un número de telèfon vàlid</translation>
<translation id="7935318582918952113">Destil·lador DOM</translation>
<translation id="7938958445268990899">El certificat del servidor encara no és vàlid.</translation>
<translation id="7942349550061667556">Vermell</translation>
@@ -751,6 +763,7 @@ El mode d'incògnit, <ph name="SHORTCUT_KEY" />, us pot resultar pràctic la pro
<translation id="8088680233425245692">No s'ha pogut consultar l'article.</translation>
<translation id="8089520772729574115">menys d'1 MB</translation>
<translation id="8091372947890762290">L'activació està pendent al servidor</translation>
+<translation id="8118489163946903409">Mètode de pagament</translation>
<translation id="8131740175452115882">Confirma</translation>
<translation id="8134994873729925007">No s'ha trobat l'<ph name="BEGIN_ABBR" />adreça DNS<ph name="END_ABBR" /> del servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">L'ordinador ha entrat en mode de repòs.</translation>
@@ -776,6 +789,7 @@ El mode d'incògnit, <ph name="SHORTCUT_KEY" />, us pot resultar pràctic la pro
<translation id="8349305172487531364">Barra d'adreces d'interès</translation>
<translation id="8363502534493474904">Desactiveu el mode d'avió</translation>
<translation id="8364627913115013041">No s'ha definit.</translation>
+<translation id="8368476060205742148">Serveis de Google Play</translation>
<translation id="8380941800586852976">Perillosa</translation>
<translation id="8382348898565613901">Les adreces d'interès que has visitat fa poc es mostren aquí</translation>
<translation id="8398259832188219207">Informe d'error penjat el <ph name="UPLOAD_TIME" /></translation>
@@ -784,31 +798,29 @@ El mode d'incògnit, <ph name="SHORTCUT_KEY" />, us pot resultar pràctic la pro
<translation id="8428213095426709021">Configuració</translation>
<translation id="8433057134996913067">Amb aquesta acció es tancarà la sessió a la majoria de llocs web.</translation>
<translation id="8437238597147034694">&amp;Desfés el moviment</translation>
-<translation id="8456681095658380701">El nom no és vàlid</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 targeta de crèdit}other{# targetes de crèdit}}</translation>
<translation id="8483780878231876732">Per poder utilitzar targetes del teu compte de Google, inicia la sessió a Chrome</translation>
<translation id="8488350697529856933">Objectiu d'aplicació</translation>
-<translation id="8492969205326575646">Tipus de targeta no compatible</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ha tardat massa a respondre.</translation>
<translation id="852346902619691059">Aquest servidor no ha pogut demostrar que és <ph name="DOMAIN" />. El sistema operatiu del teu dispositiu no confia en el certificat de seguretat presentat. Això pot ser a causa d'una configuració incorrecta o d'un atacant que ha interceptat la teva connexió. <ph name="BEGIN_LEARN_MORE_LINK" />Obtén més informació<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Any de caducitat</translation>
<translation id="8543181531796978784">Podeu <ph name="BEGIN_ERROR_LINK" />informar d'un problema de detecció<ph name="END_ERROR_LINK" /> o, si enteneu els riscos que això comporta per a la vostra seguretat, <ph name="BEGIN_LINK" />visiteu aquest lloc no segur<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">S'ha produït un error en fer la traducció perquè no s'ha pogut determinar l'idioma de la pàgina.</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="8570229484593575558">Aquesta informació |no es desarà|:#L'historial de navegació#Les cerques#Dades de les galetes</translation>
<translation id="8571890674111243710">S'està traduint la pàgina a l'idioma <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">És possible que la teva activitat |continuï sent visible| en:#Els llocs web que visitis#La teva empresa#El proveïdor de serveis d'Internet</translation>
<translation id="858637041960032120">Afegeix un número de telèfon</translation>
<translation id="859285277496340001">El certificat no especifica un mecanisme per comprovar si s'ha revocat.</translation>
<translation id="8620436878122366504">Els teus pares encara no ho han aprovat</translation>
<translation id="8647750283161643317">Restableix-ho tot als valors predeterminats</translation>
<translation id="8703575177326907206">La teva connexió a <ph name="DOMAIN" /> no està xifrada.</translation>
+<translation id="8718314106902482036">No s'ha completat el pagament</translation>
<translation id="8725066075913043281">Torna-ho a provar</translation>
-<translation id="8728672262656704056">Heu passat al mode d'incògnit.</translation>
+<translation id="8728672262656704056">Has passat al mode d'incògnit</translation>
<translation id="8730621377337864115">Fet</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="8759274551635299824">Aquesta targeta ha caducat</translation>
<translation id="8790007591277257123">&amp;Refés la supressió</translation>
-<translation id="8798099450830957504">Predeterminat</translation>
<translation id="8800988563907321413">Els suggeriments més propers es mostren aquí</translation>
<translation id="8820817407110198400">Adreces d'interès</translation>
<translation id="883848425547221593">Altres adreces d'interès</translation>
@@ -818,6 +830,7 @@ El mode d'incògnit, <ph name="SHORTCUT_KEY" />, us pot resultar pràctic la pro
<translation id="8866481888320382733">S'ha produït un error en analitzar la configuració de la política</translation>
<translation id="8866959479196209191">Aquesta pàgina diu:</translation>
<translation id="8870413625673593573">Tancades recentment</translation>
+<translation id="8874824191258364635">Introdueix un número de targeta vàlid</translation>
<translation id="8876793034577346603">No s'ha pogut analitzar la configuració de la xarxa.</translation>
<translation id="8877192140621905067">Un cop confirmada, els detalls de la targeta es compartiran amb aquest lloc</translation>
<translation id="8889402386540077796">To</translation>
@@ -827,7 +840,6 @@ El mode d'incògnit, <ph name="SHORTCUT_KEY" />, us pot resultar pràctic la pro
<translation id="8931333241327730545">Voleu desar aquesta targeta al vostre compte de Google?</translation>
<translation id="8932102934695377596">El rellotge està endarrerit</translation>
<translation id="8954894007019320973">(Cont.)</translation>
-<translation id="895548565263634352">Llegeix les històries publicades per <ph name="ARTICLE_PUBLISHER" /> i <ph name="OTHER_ARTICLE_COUNT" /> històries més</translation>
<translation id="8971063699422889582">El certificat del servidor ha caducat.</translation>
<translation id="8986494364107987395">Envia automàticament estadístiques d'ús i informes d'error a Google</translation>
<translation id="8987927404178983737">Mes</translation>
@@ -845,7 +857,6 @@ El mode d'incògnit, <ph name="SHORTCUT_KEY" />, us pot resultar pràctic la pro
<translation id="9068849894565669697">Selecció de color</translation>
<translation id="9076283476770535406">Pot incloure contingut per a adults</translation>
<translation id="9078964945751709336">Necessitem més informació</translation>
-<translation id="9094175695478007090">No es pot executar l'aplicació de pagament.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> utilitza normalment l'encriptació per protegir la vostra informació. En aquesta ocasió, quan Chromium ha provat de connectar-se a <ph name="SITE" />, el lloc web ha enviat credencials poc comunes i incorrectes. Pot ser que un atacant estigui provant de fer-se passar per <ph name="SITE" /> o que una pantalla d'inici de sessió a la xarxa Wi-Fi hagi interromput la connexió. En qualsevol cas, la vostra informació continua estant segura, perquè Chromium ha aturat la connexió abans no s'intercanviés cap dada.</translation>
<translation id="9137013805542155359">Mostra l'original</translation>
<translation id="9137248913990643158">Obre Chrome i inicia-hi la sessió abans d'utilitzar aquesta aplicació.</translation>
diff --git a/chromium/components/strings/components_strings_cs.xtb b/chromium/components/strings/components_strings_cs.xtb
index a4c36f1be7d..e7b47222fb0 100644
--- a/chromium/components/strings/components_strings_cs.xtb
+++ b/chromium/components/strings/components_strings_cs.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="cs">
<translation id="1008557486741366299">Nyní ne</translation>
<translation id="1015730422737071372">Zadejte další podrobnosti</translation>
+<translation id="1021110881106174305">Přijímané karty</translation>
<translation id="1032854598605920125">OtoÄit ve smÄ›ru hodinových ruÄiÄek</translation>
<translation id="1038842779957582377">neznámé jméno</translation>
<translation id="1050038467049342496">Zavřete ostatní aplikace</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Skrýt hodnotu</translation>
<translation id="1228893227497259893">Nesprávný identifikátor subjektu</translation>
<translation id="1232569758102978740">Bez názvu</translation>
+<translation id="1263231323834454256">Seznam Äetby</translation>
<translation id="1264126396475825575">Zpráva o selhání pořízená <ph name="CRASH_TIME" /> (dosud nenahrána nebo ignorována)</translation>
<translation id="1285320974508926690">Tento web nikdy nepřekládat</translation>
<translation id="129553762522093515">Nedávno zavřené</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Nastavení Automatického vyplňování v prohlížeÄi Chromium...</translation>
<translation id="1374468813861204354">návrhy</translation>
<translation id="1375198122581997741">O verzi aplikace</translation>
+<translation id="1377321085342047638">Číslo karty</translation>
<translation id="139305205187523129">Web <ph name="HOST_NAME" /> neodeslal žádná data.</translation>
<translation id="1407135791313364759">Otevřít vše</translation>
<translation id="1413809658975081374">Chyba ochrany soukromí</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Historie</translation>
<translation id="1645368109819982629">Nepodporovaný protokol</translation>
<translation id="1656489000284462475">Vyzvednutí</translation>
+<translation id="1663943134801823270">Karty a adresy pocházejí z Chromu. Můžete je spravovat v <ph name="BEGIN_LINK" />Nastavení<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">Web <ph name="SITE" /> vaÅ¡e informace běžnÄ› chrání Å¡ifrováním. Když se prohlížeÄ Chrome k webu <ph name="SITE" /> pokusil pÅ™ipojit tentokrát, web vrátil neobvyklé a nesprávné identifikaÄní údaje. K tomuto problému může dojít, pokud se za web <ph name="SITE" /> pokouší vydávat nÄ›jaký útoÄník nebo pokud bylo pÅ™ipojení pÅ™eruÅ¡eno pÅ™ihlaÅ¡ovací obrazovkou sítÄ› Wi-Fi. VaÅ¡e informace jsou i nadále v bezpeÄí, protože prohlížeÄ Google Chrome pÅ™ipojení pÅ™eruÅ¡il dříve, než doÅ¡lo k odeslání jakýchkoliv dat.</translation>
<translation id="168328519870909584">ÚtoÄníci, kteří se aktuálnÄ› nacházejí na webu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, se mohou pokusit nainstalovat do vaÅ¡eho zařízení nebezpeÄné aplikace, které mohou ukrást nebo smazat vaÅ¡e informace (například fotky, hesla, zprávy nebo platební karty).</translation>
<translation id="168841957122794586">Certifikát serveru obsahuje slabý kryptografický klíÄ.</translation>
<translation id="1710259589646384581">OperaÄní systém</translation>
<translation id="1721312023322545264">Zdá se, že k návštěvě tohoto webu potřebujete povolení od správce <ph name="NAME" /></translation>
+<translation id="1721424275792716183">* Pole je povinné</translation>
<translation id="1728677426644403582">Prohlížíte si zdrojový kód webové stránky</translation>
+<translation id="173080396488393970">Tento typ karty není podporován</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Zkuste kontaktovat administrátora systému.</translation>
+<translation id="1740951997222943430">Zadejte platný měsíc vypršení platnosti</translation>
<translation id="1745358365027406341">Stáhnout stránku později</translation>
<translation id="17513872634828108">Otevřené karty</translation>
<translation id="1753706481035618306">Číslo stránky</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Aktualizujte prosím heslovou frázi pro synchronizaci.</translation>
<translation id="1787142507584202372">Zde se zobrazí otevřené karty</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Chcete-li zkontrolovat způsoby doruÄení a požadavky, vyberte adresu doruÄení.</translation>
+<translation id="1803264062614276815">Jméno držitele karty</translation>
<translation id="1803678881841855883">Služba BezpeÄné prohlížení Google na webu <ph name="SITE" /> nedávno <ph name="BEGIN_LINK" />zjistila malware<ph name="END_LINK" />. NÄ›kdy mohou být malwarem nakaženy i weby, které jsou obvykle bezpeÄné. Tento Å¡kodlivý obsah pochází z webu <ph name="SUBRESOURCE_HOST" />, který je distribucí malwaru známý. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1806541873155184440">Přidáno <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Neplatný požadavek nebo parametry požadavku</translation>
<translation id="1826516787628120939">Probíhá kontrola</translation>
<translation id="1834321415901700177">Tento web obsahuje škodlivé programy</translation>
<translation id="1842969606798536927">Zaplatit</translation>
-<translation id="1864455488461349376">Možnost doruÄení</translation>
<translation id="1871208020102129563">Proxy je nastaveno na používání pevně daných serverů proxy, nikoliv adresy URL skriptu PAC.</translation>
<translation id="1871284979644508959">Povinné pole</translation>
<translation id="187918866476621466">Otevřít poÄáteÄní stránky</translation>
<translation id="1883255238294161206">Sbalit seznam</translation>
<translation id="1898423065542865115">Filtrování</translation>
<translation id="194030505837763158">Přejít na odkaz <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Přijímané karty</translation>
<translation id="1962204205936693436">Záložky domény <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Chyba serializace</translation>
<translation id="1974060860693918893">Rozšířená nastavení</translation>
<translation id="1978555033938440688">Verze firmwaru</translation>
+<translation id="1995859865337580572">Ověřte kód CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{a 1 další}few{a # další}many{a # další}other{a # dalších}}</translation>
-<translation id="2020194265157481222">Jméno na kartě je vyžadováno</translation>
<translation id="2025186561304664664">Proxy server je nastaven na automatickou konfiguraci.</translation>
<translation id="2030481566774242610">Měli jste na mysli <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Zkontrolovat proxy server a firewall<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Dnes</translation>
<translation id="2154054054215849342">Synchronizace není pro vaši doménu k dispozici</translation>
<translation id="2154484045852737596">Úprava karty</translation>
-<translation id="2156993118928861787">Neplatná adresa</translation>
<translation id="2166049586286450108">Úplný přístup administrátora</translation>
<translation id="2166378884831602661">Tento web nemůže poskytnout zabezpeÄené pÅ™ipojení</translation>
<translation id="2181821976797666341">Zásady</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresa}few{# adresy}many{# adresy}other{# adres}}</translation>
+<translation id="2202020181578195191">Zadejte platný rok vypršení platnosti</translation>
<translation id="2212735316055980242">Zásada nebyla nalezena</translation>
<translation id="2213606439339815911">NaÄítání záznamů...</translation>
<translation id="2230458221926704099">Opravte připojení pomocí <ph name="BEGIN_LINK" />diagnostické aplikace<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Vaše připojení k internetu je blokováno</translation>
<translation id="230155334948463882">Nová karta?</translation>
<translation id="2305919008529760154">Server nedokázal prokázat, že patří doménÄ› <ph name="DOMAIN" />. Je možné, že jeho bezpeÄnostní certifikát byl vydán podvodnÄ›. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaÅ¡e pÅ™ipojení zachytává útoÄník. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="230697611605700222">Možnosti karet a adres pocházejí z vaÅ¡eho úÄtu Google (<ph name="ACCOUNT_EMAIL" />) a z Chromu. Můžete je spravovat v <ph name="BEGIN_LINK" />Nastavení<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535">Doména <ph name="DOMAIN" /> vyžaduje zadání uživatelského jména a hesla.</translation>
<translation id="2318774815570432836">Web <ph name="SITE" /> nyní nemůžete navÅ¡tívit, protože používá zabezpeÄení HSTS. Síťové chyby a útoky jsou obvykle doÄasné, tato stránka pravdÄ›podobnÄ› pozdÄ›ji bude fungovat. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2354001756790975382">Ostatní záložky</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Výchozí podnikové nastavení</translation>
<translation id="2386255080630008482">Certifikát serveru byl zamítnut.</translation>
<translation id="2392959068659972793">Zobrazit zásady bez nastavených hodnot</translation>
+<translation id="239429038616798445">Tento způsob dopravy není k dispozici. Zkuste použít jiný způsob.</translation>
<translation id="2396249848217231973">&amp;Vrátit smazání zpět</translation>
<translation id="2460160116472764928">Služba BezpeÄné prohlížení Google na webu <ph name="SITE" /> nedávno <ph name="BEGIN_LINK" />zjistila malware<ph name="END_LINK" />. NÄ›kdy mohou být malwarem nakaženy i weby, které jsou obvykle bezpeÄné. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2463739503403862330">Vyplnit</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Spustit Diagnostiku sítě<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Neplatná adresa URL vyhledávání.</translation>
<translation id="2491120439723279231">Certifikát serveru obsahuje chyby.</translation>
-<translation id="24943777258388405">Neplatné telefonní Äíslo</translation>
<translation id="2495083838625180221">Analyzátor souborů JSON</translation>
<translation id="2495093607237746763">Pokud je tato možnost zaÅ¡krtnuta, prohlížeÄ Chromium do zařízení uloží kopii karty za úÄelem rychlejšího vyplňování formulářů.</translation>
<translation id="2498091847651709837">Naskenovat novou kartu</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027">Web <ph name="HOST_NAME" /> vrátil neplatnou odpovÄ›Ä.</translation>
<translation id="2552545117464357659">Novější</translation>
<translation id="2556876185419854533">&amp;Vrátit úpravy zpět</translation>
+<translation id="2587730715158995865">Vydavatel: <ph name="ARTICLE_PUBLISHER" />. PÅ™eÄtÄ›te si tento Älánek a další (<ph name="OTHER_ARTICLE_COUNT" />).</translation>
<translation id="2587841377698384444">ID rozhraní Directory API:</translation>
<translation id="2597378329261239068">Tento dokument je chráněn heslem. Zadejte prosím heslo.</translation>
<translation id="2609632851001447353">Varianty</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Spustit Diagnostiku připojení<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">Odstranit vybrané položky</translation>
+<translation id="277133753123645258">Způsob dopravy</translation>
<translation id="277499241957683684">Chybějící záznam zařízení</translation>
<translation id="2784949926578158345">Připojení bylo resetováno.</translation>
<translation id="2794233252405721443">Web je blokován</translation>
-<translation id="2812680587231492111">Tato možnost vyzvednutí není k dispozici. Zkuste jinou možnost.</translation>
<translation id="2824775600643448204">Adresní a vyhledávací řádek</translation>
<translation id="2826760142808435982">PÅ™ipojení je Å¡ifrováno a ověřeno pomocí Å¡ifry <ph name="CIPHER" /> a jako mechanismus výmÄ›ny klíÄů používá <ph name="KX" />.</translation>
<translation id="2835170189407361413">Vymazat formulář</translation>
-<translation id="2849041323157393173">Tato možnost dodání není k dispozici. Zkuste jinou možnost.</translation>
<translation id="2889159643044928134">NenaÄítat znovu</translation>
<translation id="2900469785430194048">ProhlížeÄ Google Chrome k zobrazení této webové stránky nemÄ›l dostatek pamÄ›ti.</translation>
<translation id="2909946352844186028">Byla zjištěna změna sítě.</translation>
<translation id="2916038427272391327">Zavřete ostatní programy</translation>
<translation id="2922350208395188000">Certifikát serveru nelze zkontrolovat.</translation>
+<translation id="2928905813689894207">FakturaÄní adresa</translation>
<translation id="2948083400971632585">Libovolné servery proxy nakonfigurované pro připojení můžete zakázat na stránce Nastavení.</translation>
<translation id="2955913368246107853">Zavřít vyhledávací lištu</translation>
<translation id="2958431318199492670">Konfigurace sítÄ› nesplňuje standard ONC. Může se stát, že nÄ›které Äásti konfigurace nebudou importovány.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Aby bylo možné navázat zabezpeÄené spojení, musejí být správnÄ› nastaveny hodiny. Důvodem je, že certifikáty, pomocí kterých se weby identifikují, platí pouze pro konkrétní období. Jelikož hodiny v zařízení nejsou nastaveny správnÄ›, Google Chrome tyto certifikáty nemůže ověřit.</translation>
<translation id="2972581237482394796">&amp;Opakovat</translation>
<translation id="2985306909656435243">Pokud je tato možnost aktivována, prohlížeÄ Chromium do zařízení uloží kopii karty za úÄelem rychlejšího vyplňování formulářů.</translation>
+<translation id="2985398929374701810">Zadejte platnou adresu</translation>
+<translation id="2986368408720340940">Tento způsob vyzvednutí není k dispozici. Zkuste použít jiný způsob.</translation>
<translation id="2991174974383378012">Sdílení s weby</translation>
<translation id="3005723025932146533">Zobrazit uloženou kopii</translation>
<translation id="3008447029300691911">Zadejte kód CVC karty <ph name="CREDIT_CARD" />. Po ověření budou údaje o kartě sdíleny s tímto webem.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{alespoň jedna položka v synchronizovaných zařízeních}=1{1 položka (a další v synchronizovaných zařízeních)}few{# položky (a další v synchronizovaných zařízeních)}many{# položky (a další v synchronizovaných zařízeních)}other{# položek (a další v synchronizovaných zařízeních)}}</translation>
<translation id="3041612393474885105">Informace o certifikátu</translation>
<translation id="3063697135517575841">Chrome vaši kartu aktuálně nemohl ověřit. Zkuste to prosím znovu později.</translation>
+<translation id="3064966200440839136">Chystáte se opustit anonymní režim, abyste mohli zaplatit v externí aplikaci. Chcete pokraÄovat?</translation>
<translation id="3093245981617870298">Nejste připojeni k síti.</translation>
<translation id="3105172416063519923">ID díla:</translation>
<translation id="3109728660330352905">K zobrazení této stránky nemáte oprávnění.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Zkuste spustit Diagnostiku připojení<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Dekódování odpovědi se nezdařilo</translation>
-<translation id="3149891296864842641">Způsob dopravy</translation>
<translation id="3150653042067488994">DoÄasná chyba serveru</translation>
+<translation id="3154506275960390542">Tato stránka obsahuje formulář, který zÅ™ejmÄ› nebude možné bezpeÄnÄ› odeslat. Odeslaná data mohou pÅ™i pÅ™enosu zobrazit jiní uživatelé a případný útoÄník je může zmÄ›nit, a server tudíž pÅ™ijme nÄ›co jiného, než jste odeslali.</translation>
<translation id="3157931365184549694">Obnovit</translation>
<translation id="3167968892399408617">Stránky, které otevÅ™ete na anonymních kartách, po zavÅ™ení vÅ¡ech anonymních karet nezanechají žádné stopy v historii prohlížeÄe, v úložiÅ¡ti souborů cookie ani v historii vyhledávání. Zachovány vÅ¡ak zůstanou vÅ¡echny stažené soubory a vytvoÅ™ené záložky.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -260,11 +268,13 @@
<translation id="3345135638360864351">Odeslání žádosti o přístup k tomuto webu uživateli <ph name="NAME" /> se nezdařilo. Zkuste to prosím znovu.</translation>
<translation id="3355823806454867987">Změna nastavení proxy...</translation>
<translation id="3369192424181595722">Chyba hodin</translation>
+<translation id="337311366426640088">Další položky: <ph name="ITEM_COUNT" /></translation>
<translation id="337363190475750230">Vyřazeno</translation>
<translation id="3377188786107721145">Chyba analýzy zásady</translation>
<translation id="3380365263193509176">Neznámá chyba</translation>
<translation id="3380864720620200369">Číslo klienta:</translation>
<translation id="3391030046425686457">Adresa doruÄení</translation>
+<translation id="3395827396354264108">Způsob vyzvednutí</translation>
<translation id="340013220407300675">ÚtoÄníci se mohou pokusit ukrást 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).</translation>
<translation id="3422248202833853650">Zkuste uvolnit paměť ukonÄením jiných programů.</translation>
<translation id="3422472998109090673">Web <ph name="HOST_NAME" /> momentálně není dostupný.</translation>
@@ -275,12 +285,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Interval naÄtení:</translation>
<translation id="3462200631372590220">Skrýt rozšířené</translation>
+<translation id="3467763166455606212">Je nutné zadat jméno držitele karty</translation>
+<translation id="3478058380795961209">Měsíc vypršení platnosti</translation>
<translation id="3479539252931486093">Nebylo toto oÄekáváno? <ph name="BEGIN_LINK" />Informujte nás<ph name="END_LINK" />.</translation>
<translation id="3479552764303398839">Nyní ne</translation>
<translation id="348000606199325318">ID selhání <ph name="CRASH_LOCAL_ID" /> (ID serveru: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">V tuto chvíli se nám s vaším rodiÄem nepodaÅ™ilo spojit. Zkuste to prosím znovu.</translation>
<translation id="3528171143076753409">Certifikát serveru není důvěryhodný.</translation>
-<translation id="3538531656504267329">Neplatný rok vypršení platnosti</translation>
<translation id="3539171420378717834">Uchovat kopii této karty v tomto zařízení</translation>
<translation id="3542684924769048008">Použít heslo pro:</translation>
<translation id="3549644494707163724">Šifrovat synchronizovaná data pomocí vlastní heslové fráze pro synchronizaci.</translation>
@@ -293,6 +304,7 @@
<translation id="3586931643579894722">Skrýt podrobnosti</translation>
<translation id="3587482841069643663">VÅ¡e</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Zadejte platné datum vypršení platnosti</translation>
<translation id="36224234498066874">Smazat údaje o prohlížení...</translation>
<translation id="362276910939193118">Zobrazit celou historii</translation>
<translation id="3623476034248543066">Zobrazit hodnotu</translation>
@@ -308,7 +320,6 @@
<translation id="3693415264595406141">Heslo:</translation>
<translation id="3696411085566228381">žádné</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Chcete-li zobrazit způsoby dopravy a požadavky, vyberte dodací adresu.</translation>
<translation id="370665806235115550">NaÄítání...</translation>
<translation id="3712624925041724820">Byly vyÄerpány licence</translation>
<translation id="3714780639079136834">Zapnout mobilní datové připojení nebo Wi-Fi</translation>
@@ -317,6 +328,7 @@
<translation id="3739623965217189342">Zkopírovaný odkaz</translation>
<translation id="375403751935624634">Z důvodu chyby serveru se překlad nezdařil.</translation>
<translation id="3759461132968374835">Nemáte žádná nedávno hlášená selhání. Selhání, ke kterým došlo, když byla služba hlášení o selháních vypnutá, se zde nezobrazují.</translation>
+<translation id="3787705759683870569">Platnost do: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Pokud používáte proxy server...</translation>
<translation id="3828924085048779000">Prázdná heslová fráze není povolena.</translation>
<translation id="3845539888601087042">Zobrazuje se historie z vašich přihlášených zařízení. <ph name="BEGIN_LINK" />Další informace<ph name="END_LINK" /></translation>
@@ -352,7 +364,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chcete, aby prohlížeÄ Chromium tuto kartu uložil?</translation>
<translation id="4171400957073367226">Chybný ověřovací podpis</translation>
-<translation id="4176463684765177261">Deaktivováno</translation>
<translation id="4196861286325780578">&amp;Opakovat přesunutí</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Zkontrolovat konfiguraci firewallu a antivirového softwaru<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{žádná aplikace}=1{1 aplikace ($1)}=2{2 aplikace ($1, $2)}few{# aplikace ($1, $2 $3)}many{# aplikace ($1, $2 $3)}other{# aplikací ($1, $2 $3)}}</translation>
@@ -379,11 +390,11 @@
<translation id="4406896451731180161">výsledky vyhledávání</translation>
<translation id="4432688616882109544">Web <ph name="HOST_NAME" /> nepřijal přihlašovací certifikát, případně žádný certifikát nebyl poskytnut.</translation>
<translation id="443673843213245140">Využití proxy serveru je zakázáno, je vÅ¡ak urÄena explicitní konfigurace proxy serveru.</translation>
-<translation id="4446242550670694251">Nyní můžete procházet internet v soukromí a ostatní uživatelé tohoto zařízení vaši aktivitu neuvidí.</translation>
<translation id="4492190037599258964">Výsledky vyhledávání pro výraz „<ph name="SEARCH_STRING" />“</translation>
<translation id="4506176782989081258">Chyba ověřování: <ph name="VALIDATION_ERROR" />.</translation>
<translation id="4506599922270137252">Kontaktovat administrátora systému</translation>
<translation id="450710068430902550">Sdílení s administrátorem</translation>
+<translation id="4515275063822566619">Karty a adresy pocházejí z Chromu a z vaÅ¡eho úÄtu Google (<ph name="ACCOUNT_EMAIL" />). Můžete je spravovat v <ph name="BEGIN_LINK" />Nastavení<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Podrobnosti</translation>
<translation id="4558551763791394412">Zkuste zakázat rozšíření.</translation>
<translation id="457875822857220463">DoruÄení</translation>
@@ -413,6 +424,7 @@
<translation id="4816492930507672669">Přizpůsobit na stránku</translation>
<translation id="483020001682031208">Nejsou k dispozici žádné stránky fyzického webu, které by bylo možné zobrazit</translation>
<translation id="4850886885716139402">Zobrazit</translation>
+<translation id="4854362297993841467">Tento způsob doruÄení není k dispozici. Zkuste použít jiný způsob.</translation>
<translation id="4858792381671956233">Požádal(a) jsi rodiÄe o povolení návÅ¡tÄ›vy tohoto webu.</translation>
<translation id="4880827082731008257">Hledat v historii</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -420,7 +432,6 @@
<translation id="4923417429809017348">Tato stránka byla přeložena z neznámého jazyka do jazyka <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Platba</translation>
<translation id="4926049483395192435">Musí být uvedeno</translation>
-<translation id="4941291666397027948">* oznaÄuje povinné pole.</translation>
<translation id="495170559598752135">Akce</translation>
<translation id="4958444002117714549">Rozbalit seznam</translation>
<translation id="4962322354953122629">Server nedokázal prokázat, že patří doménÄ› <ph name="DOMAIN" />. Chrome jeho bezpeÄnostnímu certifikátu nedůvěřuje. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaÅ¡e pÅ™ipojení zachytává útoÄník. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -435,6 +446,7 @@
<translation id="5045550434625856497">Nesprávné heslo</translation>
<translation id="5056549851600133418">Články pro vás</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Zkontrolovat adresu proxy serveru<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Žádné soubory cookie}=1{Soubory cookie používá 1 web. }few{Soubory cookie používají # weby. }many{Soubory cookie používá # webu. }other{Soubory cookie používá # webů. }}</translation>
<translation id="5087286274860437796">Certifikát serveru v tuto chvíli není platný.</translation>
<translation id="5087580092889165836">Přidat kartu</translation>
<translation id="5089810972385038852">Stát/kraj</translation>
@@ -457,10 +469,8 @@
<translation id="5300589172476337783">Zobrazit</translation>
<translation id="5308689395849655368">Zprávy o selhání jsou zakázány.</translation>
<translation id="5317780077021120954">Uložit</translation>
-<translation id="5326702247179446998">Je vyžadován příjemce</translation>
<translation id="5327248766486351172">Název</translation>
<translation id="5337705430875057403">ÚtoÄníci na webu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> vás mohou podvodem pÅ™imÄ›t k nebezpeÄnému chování, jako je instalace softwaru nebo vyzrazení osobních údajů (například hesel, telefonních Äísel nebo platebních karet).</translation>
-<translation id="53553865750799677">Nepodporovaná adresa vyzvednutí. Vyberte jinou adresu.</translation>
<translation id="5359637492792381994">Server nedokázal prokázat, že patří doménÄ› <ph name="DOMAIN" />. Jeho bezpeÄnostní certifikát v tuto chvíli není platný. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaÅ¡e pÅ™ipojení zachytává útoÄník. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Ukládání nastavení zásady se nezdařilo</translation>
<translation id="5386426401304769735">Řetězec certifikátů tohoto webu obsahuje certifikát podepsaný algoritmem SHA-1.</translation>
@@ -486,8 +496,8 @@ Kontaktujte administrátora systému.</translation>
<translation id="5544037170328430102">Vložená stránka na webu <ph name="SITE" /> říká:</translation>
<translation id="5556459405103347317">NaÄíst znovu</translation>
<translation id="5565735124758917034">Aktivní</translation>
+<translation id="5571083550517324815">Vyzvednutí na této adrese není možné. Vyberte jinou adresu.</translation>
<translation id="5572851009514199876">Přihlaste se do Chromu, aby bylo možné ověřit, zda máte povolení tento web navštívit.</translation>
-<translation id="5575380383496039204">Nepodporovaná adresa doruÄení. Vyberte jinou adresu.</translation>
<translation id="5580958916614886209">Zkontrolujte měsíc vypršení platnosti a zkuste to znovu.</translation>
<translation id="560412284261940334">Správa není podporována</translation>
<translation id="5610142619324316209">Zkontrolovat připojení</translation>
@@ -503,7 +513,8 @@ Kontaktujte administrátora systému.</translation>
<translation id="5710435578057952990">Identita těchto webových stránek nebyla ověřena.</translation>
<translation id="5720705177508910913">Aktuální uživatel</translation>
<translation id="5732392974455271431">RodiÄe ti jej mohou odblokovat.</translation>
-<translation id="57586589942790530">Neplatné Äíslo karty</translation>
+<translation id="5763042198335101085">Zadejte platnou e-mailovou adresu</translation>
+<translation id="5765072501007116331">Chcete-li zobrazit způsoby doruÄení a požadavky, vyberte adresu</translation>
<translation id="5784606427469807560">Při ověřování vaší karty došlo k problému. Zkontrolujte připojení k internetu a zkuste to znovu.</translation>
<translation id="5785756445106461925">Tato stránka obsahuje jeÅ¡tÄ› další nezabezpeÄené zdroje. Tyto zdroje budou bÄ›hem pÅ™enosu moci zobrazit jiní uživatelé a případní útoÄníci je mohou upravit a zmÄ›nit tak vzhled stránky.</translation>
<translation id="5786044859038896871">Chcete vyplnit informace o kartě?</translation>
@@ -516,31 +527,30 @@ Kontaktujte administrátora systému.</translation>
<translation id="5869405914158311789">Tento web není dostupný</translation>
<translation id="5869522115854928033">Uložená hesla</translation>
<translation id="5872918882028971132">Návrhy rodiÄů</translation>
-<translation id="587760065310675640">Nepodporovaná dodací adresa. Vyberte jinou adresu.</translation>
<translation id="5901630391730855834">Žlutá</translation>
-<translation id="59174027418879706">Aktivní</translation>
<translation id="5926846154125914413">Můžete ztratit přístup k prémiovému obsahu z některých webů.</translation>
<translation id="5959728338436674663">Automaticky odesílat Äást <ph name="BEGIN_WHITEPAPER_LINK" />informací o systému a obsahu stránek<ph name="END_WHITEPAPER_LINK" /> do Googlu s cílem pomoci rozpoznávat nebezpeÄné aplikace a weby. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Týden</translation>
<translation id="5967867314010545767">Odstranit z historie</translation>
<translation id="5975083100439434680">Oddálit</translation>
+<translation id="598637245381783098">Platební aplikaci nelze otevřít</translation>
<translation id="5989320800837274978">Nejsou urÄeny pevnÄ› dané servery proxy ani adresa URL skriptu PAC.</translation>
<translation id="5990559369517809815">Žádosti na tento server jsou blokovány rozšířením.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Možnosti karet a adres pocházejí z Chromu. Můžete je spravovat v <ph name="BEGIN_LINK" />Nastavení<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Stránka 1}few{Stránka #}many{Stránka #}other{Stránka #}}</translation>
<translation id="6017514345406065928">Zelená</translation>
+<translation id="6027201098523975773">Zadejte jméno</translation>
<translation id="6040143037577758943">Zavřít</translation>
-<translation id="604124094241169006">Automaticky</translation>
<translation id="6042308850641462728">Více</translation>
<translation id="6060685159320643512">Pozor, tyto experimenty mohou skonÄit vÅ¡elijak.</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{žádná aplikace}=1{1}few{#}many{#}other{#}}</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="6151417162996330722">Certifikát serveru má příliš dlouhé období platnosti.</translation>
-<translation id="615643356032862689">Stažené soubory a záložky budou zachovány.</translation>
+<translation id="6157877588268064908">Chcete-li zobrazit způsoby dopravy a požadavky, vyberte adresu</translation>
<translation id="6165508094623778733">Další informace</translation>
<translation id="6177128806592000436">Spojení s tímto webem není bezpeÄné</translation>
+<translation id="6184817833369986695">(kohorta: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Zkontrolujte připojení k internetu</translation>
<translation id="6218753634732582820">Odstranit adresu z prohlížeÄe Chromium?</translation>
<translation id="6251924700383757765">Zásady ochrany soukromí</translation>
@@ -549,6 +559,8 @@ Kontaktujte administrátora systému.</translation>
<translation id="6259156558325130047">&amp;Opakovat změnu uspořádání</translation>
<translation id="6263376278284652872">Záložky webu <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">ZpÄ›t na bezpeÄnÄ›jší stránku</translation>
+<translation id="6276112860590028508">Zde naleznete stránky ze seznamu Äetby</translation>
+<translation id="6280223929691119688">DoruÄení na tuto adresu není možné. Vyberte jinou adresu.</translation>
<translation id="6282194474023008486">PSČ</translation>
<translation id="6290238015253830360">Zde se zobrazí navrhované Älánky</translation>
<translation id="6305205051461490394">Web <ph name="URL" /> není dostupný.</translation>
@@ -570,7 +582,6 @@ Kontaktujte administrátora systému.</translation>
<translation id="6417515091412812850">Nelze ověřit, zda byl certifikát zrušen.</translation>
<translation id="6433490469411711332">Upravit kontaktní údaje</translation>
<translation id="6433595998831338502">Web <ph name="HOST_NAME" /> odmítl připojení.</translation>
-<translation id="6443118737398455446">Neplatné datum vypršení platnosti.</translation>
<translation id="6446608382365791566">Přidání dalších informací</translation>
<translation id="6451458296329894277">Potvrdit nové odeslání formuláře</translation>
<translation id="6456339708790392414">Vaše platba</translation>
@@ -578,10 +589,8 @@ Kontaktujte administrátora systému.</translation>
<translation id="6462969404041126431">Server nedokázal prokázat, že patří doménÄ› <ph name="DOMAIN" />. Je možné, že jeho bezpeÄnostní certifikát byl 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. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">Zásady zařízení</translation>
<translation id="6477321094435799029">Chrome na této stránce zjistil neobvyklý kód a z důvodu ochrany vaÅ¡ich osobních údajů (například hesel, telefonních Äísel a platebních karet) ji zablokoval.</translation>
-<translation id="6477460825583319731">Neplatná e-mailová adresa</translation>
<translation id="6489534406876378309">ZaÄít nahrávat zprávy o selhání</translation>
<translation id="6508722015517270189">Restartujte Chrome</translation>
-<translation id="6525462735697194615">Neplatný měsíc vypršení platnosti</translation>
<translation id="6529602333819889595">&amp;Opakovat smazání</translation>
<translation id="6534179046333460208">Návrhy fyzického webu</translation>
<translation id="6550675742724504774">Možnosti</translation>
@@ -596,7 +605,6 @@ Kontaktujte administrátora systému.</translation>
<translation id="6628463337424475685">Vyhledávání <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Tato zásada se již nepoužívá.</translation>
<translation id="6652240803263749613">Server nedokázal prokázat, že patří doménÄ› <ph name="DOMAIN" />. OperaÄní systém vaÅ¡eho poÄítaÄe jeho bezpeÄnostnímu certifikátu nedůvěřuje. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaÅ¡e pÅ™ipojení zachytává útoÄník. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="6665267558048410100">Tato možnost dodání není k dispozici. Zkuste jinou možnost.</translation>
<translation id="6671697161687535275">Odstranit návrh položky formuláře z prohlížeÄe Chromium?</translation>
<translation id="6685834062052613830">Odhlaste se a dokonÄete nastavení</translation>
<translation id="6710213216561001401">Předchozí</translation>
@@ -604,13 +612,13 @@ Kontaktujte administrátora systému.</translation>
<translation id="6711464428925977395">Došlo k chybě proxy serveru nebo jste zadali nesprávnou adresu.</translation>
<translation id="6727102863431372879">Nastavit</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{žádné položky}=1{1 položka}few{# položky}many{# položky}other{# položek}}</translation>
-<translation id="6743044928064272573">Možnost vyzvednutí</translation>
<translation id="674375294223700098">Neznámá chyba certifikátu serveru.</translation>
<translation id="6753269504797312559">Hodnota zásady</translation>
<translation id="6757797048963528358">Zařízení přešlo do režimu spánku.</translation>
<translation id="6778737459546443941">RodiÄ ti přístup na web dosud neschválil.</translation>
<translation id="6810899417690483278">ID přizpůsobení</translation>
<translation id="6820686453637990663">BezpeÄnostní kód platební karty (CVC)</translation>
+<translation id="6824266427216888781">Údaje o oblastech se nepodaÅ™ilo naÄíst</translation>
<translation id="6831043979455480757">Přeložit</translation>
<translation id="6839929833149231406">Region</translation>
<translation id="6874604403660855544">&amp;Opakovat přidání</translation>
@@ -618,6 +626,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="6895330447102777224">Vaše karta je ověřena</translation>
<translation id="6897140037006041989">User agent</translation>
<translation id="6915804003454593391">Uživatel:</translation>
+<translation id="6948701128805548767">Chcete-li zobrazit způsoby vyzvednutí a požadavky, vyberte adresu</translation>
<translation id="6957887021205513506">Zdá se, že certifikát serveru je podvrh.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Zařízení</translation>
@@ -625,7 +634,6 @@ Kontaktujte administrátora systému.</translation>
<translation id="6973656660372572881">UrÄeny jsou pevnÄ› dané servery proxy i adresa URL skriptu PAC.</translation>
<translation id="6989763994942163495">Zobrazit rozšířená nastavení...</translation>
<translation id="7000990526846637657">Nebyly nalezeny žádné historické záznamy</translation>
-<translation id="7001663382399377034">Přidání příjemce</translation>
<translation id="7009986207543992532">Pokusili jste se připojit k doméně <ph name="DOMAIN" />, ale server předložil certifikát, který má příliš dlouhé období platnosti, a je proto nedůvěryhodný. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Na adrese <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> mohou být k dispozici další formy historie prohlížení zaznamenané ve vaÅ¡em úÄtu Google</translation>
@@ -636,12 +644,15 @@ Kontaktujte administrátora systému.</translation>
<translation id="7088615885725309056">Starší</translation>
<translation id="7090678807593890770">Vyhledejte na Googlu <ph name="LINK" /></translation>
<translation id="7119414471315195487">Zavřete ostatní karty nebo programy</translation>
+<translation id="7129409597930077180">Dodání na tuto adresu není možné. Vyberte jinou adresu.</translation>
+<translation id="7138472120740807366">Způsob doruÄení</translation>
<translation id="7139724024395191329">Emirát</translation>
<translation id="7155487117670177674">Platba není zabezpeÄená</translation>
<translation id="7179921470347911571">Spustit znovu</translation>
<translation id="7180611975245234373">Obnovit</translation>
<translation id="7182878459783632708">Nebyly nastaveny žádné zásady</translation>
<translation id="7186367841673660872">Tato stránka byla přeložena z jazyka<ph name="ORIGINAL_LANGUAGE" />do jazyka<ph name="LANGUAGE_LANGUAGE" /></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="7210863904660874423">Web <ph name="HOST_NAME" /> nevyhovuje bezpeÄnostním standardům.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Další informace<ph name="END_LINK" /> o tomto problému.</translation>
@@ -670,7 +681,6 @@ Pssst! Příště by se vám mohl hodit anonymní režim (<ph name="SHORTCUT_KEY
<translation id="7424977062513257142">Stránka vložená na této webové stránce říká:</translation>
<translation id="7441627299479586546">Chybný předmět zásady</translation>
<translation id="7444046173054089907">Tento web je blokován</translation>
-<translation id="7444238235002594607">Chcete-li zkontrolovat způsoby vyzvednutí a požadavky, vyberte adresu vyzvednutí.</translation>
<translation id="7445762425076701745">Totožnost serveru, k nÄ›muž jste pÅ™ipojeni, nelze plnÄ› ověřit. Jste pÅ™ipojeni k serveru, který používá název platný pouze v rámci vaší sítÄ›. Externí certifikaÄní autorita nemůže vlastnictví názvu nijak ověřit. NÄ›které certifikaÄní autority vÅ¡ak vydají certifikát i pro takové názvy, a nelze tedy zaruÄit, že jste pÅ™ipojeni k požadovanému webu a nikoli k webu útoÄníka.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Další informace<ph name="END_LINK" /> o tomto problému.</translation>
<translation id="7460163899615895653">Zde se zobrazují nedávno otevřené karty z jiných zařízení.</translation>
@@ -714,6 +724,7 @@ Pssst! Příště by se vám mohl hodit anonymní režim (<ph name="SHORTCUT_KEY
<translation id="7755287808199759310">RodiÄ ti jej může odblokovat.</translation>
<translation id="7758069387465995638">Připojení mohlo být zablokováno firewallem nebo antivirovým softwarem.</translation>
<translation id="7761701407923456692">Certifikát serveru neodpovídá adrese URL.</translation>
+<translation id="7763386264682878361">Analyzátor manifestů plateb</translation>
<translation id="7764225426217299476">Přidat adresu</translation>
<translation id="777702478322588152">Prefektura</translation>
<translation id="7791543448312431591">Přidat</translation>
@@ -727,6 +738,7 @@ Pssst! Příště by se vám mohl hodit anonymní režim (<ph name="SHORTCUT_KEY
<translation id="785549533363645510">To neznamená, že jste neviditelní. Anonymní režim neskryje vaši aktivitu před vaším zaměstnavatelem, poskytovatelem internetových služeb ani webovými stránkami, které navštívíte.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Zkontrolujte kód CVC a zkuste to znovu</translation>
+<translation id="79338296614623784">Zadejte platné telefonní Äíslo</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Certifikát serveru ještě není platný.</translation>
<translation id="7942349550061667556">Červená</translation>
@@ -746,6 +758,7 @@ Pssst! Příště by se vám mohl hodit anonymní režim (<ph name="SHORTCUT_KEY
<translation id="8088680233425245692">Zobrazení Älánku se nezdaÅ™ilo.</translation>
<translation id="8089520772729574115">méně než 1 MB</translation>
<translation id="8091372947890762290">Čeká se na aktivaci na serveru</translation>
+<translation id="8118489163946903409">Platební metoda</translation>
<translation id="8131740175452115882">Potvrdit</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Adresa DNS<ph name="END_ABBR" /> serveru <ph name="HOST_NAME" /> nebyla nalezena.</translation>
<translation id="8149426793427495338">PoÄítaÄ pÅ™eÅ¡el do režimu spánku.</translation>
@@ -771,6 +784,7 @@ Pssst! Příště by se vám mohl hodit anonymní režim (<ph name="SHORTCUT_KEY
<translation id="8349305172487531364">Lišta záložek</translation>
<translation id="8363502534493474904">Vypnout režim Letadlo</translation>
<translation id="8364627913115013041">Nenastaveno.</translation>
+<translation id="8368476060205742148">Služby Google Play</translation>
<translation id="8380941800586852976">NebezpeÄné</translation>
<translation id="8382348898565613901">Zde se zobrazí nedávno navštívené záložky</translation>
<translation id="8398259832188219207">Zpráva o selhání nahraná <ph name="UPLOAD_TIME" /></translation>
@@ -779,32 +793,30 @@ Pssst! Příště by se vám mohl hodit anonymní režim (<ph name="SHORTCUT_KEY
<translation id="8428213095426709021">Nastavení</translation>
<translation id="8433057134996913067">Budete odhlášeni z většiny webů.</translation>
<translation id="8437238597147034694">&amp;Vrátit přesunutí zpět</translation>
-<translation id="8456681095658380701">Neplatný název</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 platební karta}few{# platební karty}many{# platební karty}other{# platebních karet}}</translation>
<translation id="8483780878231876732">Chcete-li používat karty z úÄtu Google, pÅ™ihlaste se do Chromu.</translation>
<translation id="8488350697529856933">Platí pro</translation>
-<translation id="8492969205326575646">Nepodporovaný typ karty</translation>
<translation id="8498891568109133222">OdpovÄ›Ä webu <ph name="HOST_NAME" /> trvala příliÅ¡ dlouho.</translation>
<translation id="852346902619691059">Server nedokázal prokázat, že patří doménÄ› <ph name="DOMAIN" />. OperaÄní systém vaÅ¡eho zařízení jeho bezpeÄnostnímu certifikátu nedůvěřuje. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaÅ¡e pÅ™ipojení zachytává útoÄník. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="8532105204136943229">Rok vypršení platnosti</translation>
<translation id="8543181531796978784">Můžete <ph name="BEGIN_ERROR_LINK" />nahlásit problém se zjiÅ¡tÄ›ným webem<ph name="END_ERROR_LINK" />. Pokud bezpeÄnostní rizika chápete, můžete <ph name="BEGIN_LINK" />tento nespolehlivý web navÅ¡tívit<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Překlad se nezdařil. Nepodařilo se rozpoznat jazyk stránky.</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="8570229484593575558">Tyto informace se |neuloží|:#historie procházení,#vyhledávací dotazy,#soubory cookie.</translation>
<translation id="8571890674111243710">Překlad stránky do jazyka: <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Vaši aktivitu |i nadále mohou sledovat|:#navštívené weby,#váš zaměstnavatel,#váš poskytovatel internetových služeb.</translation>
<translation id="858637041960032120">Přidat telefon
</translation>
<translation id="859285277496340001">V certifikátu není uvedeno, jakým způsobem lze zkontrolovat, zda nebyl zrušen.</translation>
<translation id="8620436878122366504">RodiÄe přístup dosud neschválili.</translation>
<translation id="8647750283161643317">Obnovit u všech experimentů výchozí nastavení</translation>
<translation id="8703575177326907206">Vaše spojení se serverem <ph name="DOMAIN" /> není šifrované.</translation>
+<translation id="8718314106902482036">Platba nebyla dokonÄena</translation>
<translation id="8725066075913043281">Zkusit znovu</translation>
<translation id="8728672262656704056">Jste v anonymním režimu</translation>
<translation id="8730621377337864115">Hotovo</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="8759274551635299824">Platnost této karty vypršela</translation>
<translation id="8790007591277257123">&amp;Opakovat smazání</translation>
-<translation id="8798099450830957504">Výchozí</translation>
<translation id="8800988563907321413">Zde se zobrazí návrhy funkce Nablízku</translation>
<translation id="8820817407110198400">Záložky</translation>
<translation id="883848425547221593">Jiné záložky</translation>
@@ -814,6 +826,7 @@ Pssst! Příště by se vám mohl hodit anonymní režim (<ph name="SHORTCUT_KEY
<translation id="8866481888320382733">Při analýze nastavení zásady došlo k chybě</translation>
<translation id="8866959479196209191">Tato stránka říká:</translation>
<translation id="8870413625673593573">Nedávno zavřené</translation>
+<translation id="8874824191258364635">Zadejte platné Äíslo karty</translation>
<translation id="8876793034577346603">Analýza konfigurace sítě se nezdařila.</translation>
<translation id="8877192140621905067">Po ověření budou údaje o kartě sdíleny s tímto webem.</translation>
<translation id="8889402386540077796">Odstín</translation>
@@ -823,7 +836,6 @@ Pssst! Příště by se vám mohl hodit anonymní režim (<ph name="SHORTCUT_KEY
<translation id="8931333241327730545">Chcete tuto kartu uložit do úÄtu Google?</translation>
<translation id="8932102934695377596">VaÅ¡e hodiny se zpožÄují</translation>
<translation id="8954894007019320973">(pokraÄování)</translation>
-<translation id="895548565263634352">PÅ™eÄtÄ›te si příbÄ›hy od vydavatele <ph name="ARTICLE_PUBLISHER" /> a <ph name="OTHER_ARTICLE_COUNT" /> dalších</translation>
<translation id="8971063699422889582">Platnost certifikátu serveru vypršela.</translation>
<translation id="8986494364107987395">Automaticky posílat spoleÄnosti Google statistiky používání a zprávy o selhání</translation>
<translation id="8987927404178983737">Měsíc</translation>
@@ -841,7 +853,6 @@ Pssst! Příště by se vám mohl hodit anonymní režim (<ph name="SHORTCUT_KEY
<translation id="9068849894565669697">Výběr barvy</translation>
<translation id="9076283476770535406">Může obsahovat materiály pouze pro dospělé</translation>
<translation id="9078964945751709336">Jsou potřeba další informace</translation>
-<translation id="9094175695478007090">Platební aplikaci nelze spustit.</translation>
<translation id="9103872766612412690">Web <ph name="SITE" /> vaÅ¡e informace běžnÄ› chrání Å¡ifrováním. Když se prohlížeÄ Chromium k webu <ph name="SITE" /> pokusil pÅ™ipojit tentokrát, web vrátil neobvyklé a nesprávné identifikaÄní údaje. K tomuto problému může dojít, pokud se za web <ph name="SITE" /> pokouší vydávat nÄ›jaký útoÄník nebo pokud bylo pÅ™ipojení pÅ™eruÅ¡eno pÅ™ihlaÅ¡ovací obrazovkou sítÄ› Wi-Fi. VaÅ¡e informace jsou i nadále v bezpeÄí, protože prohlížeÄ Chromium pÅ™ipojení pÅ™eruÅ¡il dříve, než doÅ¡lo k odeslání jakýchkoliv dat.</translation>
<translation id="9137013805542155359">Zobrazit originál</translation>
<translation id="9137248913990643158">Chcete-li tuto aplikaci použít, přihlaste se do Chromu.</translation>
diff --git a/chromium/components/strings/components_strings_da.xtb b/chromium/components/strings/components_strings_da.xtb
index 390e3fb01f2..349c4a87a1d 100644
--- a/chromium/components/strings/components_strings_da.xtb
+++ b/chromium/components/strings/components_strings_da.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="da">
<translation id="1008557486741366299">Ikke nu</translation>
<translation id="1015730422737071372">Angiv yderligere oplysninger</translation>
+<translation id="1021110881106174305">Accepterede kort</translation>
<translation id="1032854598605920125">Rotér med uret</translation>
<translation id="1038842779957582377">ukendt navn</translation>
<translation id="1050038467049342496">Luk andre apps</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Skjul værdi</translation>
<translation id="1228893227497259893">Forkert enheds-id</translation>
<translation id="1232569758102978740">Unavngivet</translation>
+<translation id="1263231323834454256">Læseliste</translation>
<translation id="1264126396475825575">Der blev registreret en nedbrudsrapport <ph name="CRASH_TIME" /> (endnu ikke uploadet eller ignoreret)</translation>
<translation id="1285320974508926690">Oversæt aldrig dette website</translation>
<translation id="129553762522093515">Senest lukkede</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Indstillinger for AutoFyld i Chromium...</translation>
<translation id="1374468813861204354">forslag</translation>
<translation id="1375198122581997741">Om version</translation>
+<translation id="1377321085342047638">Kortnummer</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> har ikke sendt nogen data.</translation>
<translation id="1407135791313364759">Ã…bn alle</translation>
<translation id="1413809658975081374">Fejl i forbindelse med beskyttelse af personlige oplysninger</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Historik</translation>
<translation id="1645368109819982629">Ikke-understøttet protokol</translation>
<translation id="1656489000284462475">Afhentning</translation>
+<translation id="1663943134801823270">Kort og adresser er fra Chrome. Du kan administrere dem i <ph name="BEGIN_LINK" />Indstillinger<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> bruger normalt kryptering til at beskytte dine oplysninger. Da Google Chrome forsøgte at oprette forbindelse til <ph name="SITE" /> denne gang, returnerede websitet usædvanlige og forkerte legitimationsoplysninger. Dette kan skyldes, at en hacker forsøger at udgive sig for at være <ph name="SITE" />, eller at en Wi-Fi-loginskærm har forstyrret forbindelsen. Dine oplysninger er stadig sikre, idet Google Chrome afbrød forbindelsen, inden der blev udvekslet data.</translation>
<translation id="168328519870909584">Hackere, der i øjeblikket befinder sig på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, vil muligvis forsøge at installere farlige apps på din enhed for at stjæle eller slette dine oplysninger (f.eks. billeder, adgangskoder, beskeder og kreditkortoplysninger).</translation>
<translation id="168841957122794586">Servercertifikatet indeholder en svag kryptografisk nøgle.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Du skal have tilladelse fra <ph name="NAME" /> til at besøge dette website</translation>
+<translation id="1721424275792716183">* Feltet skal udfyldes</translation>
<translation id="1728677426644403582">Du ser kilden for en webside</translation>
+<translation id="173080396488393970">Denne korttype understøttes ikke</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Prøv at kontakte systemadministratoren.</translation>
+<translation id="1740951997222943430">Angiv en gyldig udløbsmåned</translation>
<translation id="1745358365027406341">Download siden senere</translation>
<translation id="17513872634828108">Ã…bne faner</translation>
<translation id="1753706481035618306">Sidetal</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Opdater din adgangssætning til synkronisering.</translation>
<translation id="1787142507584202372">Dine åbne faner vises her</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Vælg en leveringsadresse for at se leveringsmetoder og krav.</translation>
+<translation id="1803264062614276815">Kortindehaverens navn</translation>
<translation id="1803678881841855883">Google Beskyttet browsing har for nylig <ph name="BEGIN_LINK" />registreret malware<ph name="END_LINK" /> på <ph name="SITE" />. Websites, der normalt er sikre, bliver undertiden inficeret med malware. Det skadelige indhold kommer fra <ph name="SUBRESOURCE_HOST" />, som er en kendt malwaredistributør. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Tilføjet <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Ugyldig anmodning eller anmodningsparametre</translation>
<translation id="1826516787628120939">Kontrollerer</translation>
<translation id="1834321415901700177">Dette website indeholder skadelige programmer</translation>
<translation id="1842969606798536927">Betal</translation>
-<translation id="1864455488461349376">Leveringsmulighed</translation>
<translation id="1871208020102129563">Proxy er indstillet til at bruge faste proxyservere, ikke webadresser til .pac-scripts.</translation>
<translation id="1871284979644508959">Obligatorisk felt</translation>
<translation id="187918866476621466">Ã…bn opstartssider</translation>
<translation id="1883255238294161206">Skjul liste</translation>
<translation id="1898423065542865115">Filtrering</translation>
<translation id="194030505837763158">GÃ¥ til <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Kort, der accepteres</translation>
<translation id="1962204205936693436">Bogmærker fra <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Serialiseringsfejl</translation>
<translation id="1974060860693918893">Avanceret</translation>
<translation id="1978555033938440688">Firmwareversion</translation>
+<translation id="1995859865337580572">Bekræft din kontrolkode</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{og 1 mere}one{og # mere}other{og # mere}}</translation>
-<translation id="2020194265157481222">Navn på kort er obligatorisk</translation>
<translation id="2025186561304664664">Proxyen konfigureres automatisk.</translation>
<translation id="2030481566774242610">Mente du <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Kontrollere din proxy og din firewall<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">I dag</translation>
<translation id="2154054054215849342">Synkronisering er ikke tilgængelig for dit domæne</translation>
<translation id="2154484045852737596">Rediger kort</translation>
-<translation id="2156993118928861787">Ugyldig adresse</translation>
<translation id="2166049586286450108">Fuld administratoradgang</translation>
<translation id="2166378884831602661">Dette website kan ikke levere en sikker forbindelse</translation>
<translation id="2181821976797666341">Politikker</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresse}one{# adresse}other{# adresser}}</translation>
+<translation id="2202020181578195191">Angiv et gyldigt udløbsår</translation>
<translation id="2212735316055980242">Politikken blev ikke fundet</translation>
<translation id="2213606439339815911">Indlæg hentes...</translation>
<translation id="2230458221926704099">Ret problemerne med din forbindelse ved hjælp af <ph name="BEGIN_LINK" />diagnoseappen<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Din internetadgang er blokeret</translation>
<translation id="230155334948463882">Har du fået nyt kort?</translation>
<translation id="2305919008529760154">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet kan være udstedt på ulovlig vis. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Kort- og adresseindstillingerne er fra din Google-konto (<ph name="ACCOUNT_EMAIL" />) og Chrome. Du kan administrere dem i <ph name="BEGIN_LINK" />Indstillinger<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> kræver et brugernavn og en adgangskode.</translation>
<translation id="2318774815570432836">Du kan ikke gå til <ph name="SITE" /> lige nu, fordi websitet bruger HSTS. Netværksfejl og hackerangreb er normalt midlertidige, så siden vil sandsynligvis fungere senere. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Andre bogmærker</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Virksomhedsstandard</translation>
<translation id="2386255080630008482">Serverens certifikat er blevet tilbagekaldt.</translation>
<translation id="2392959068659972793">Vis politikker uden nogen værdier</translation>
+<translation id="239429038616798445">Denne forsendelsesmetode er ikke tilgængelig. Prøv en anden metode.</translation>
<translation id="2396249848217231973">&amp;Fortryd sletning</translation>
<translation id="2460160116472764928">Google Beskyttet browsing har for nylig <ph name="BEGIN_LINK" />registreret malware<ph name="END_LINK" /> på <ph name="SITE" />. Websites, der normalt er sikre, bliver undertiden inficeret med malware. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Udfyld</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Køre Netværksdiagnosticering<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Ugyldig søgewebadresse.</translation>
<translation id="2491120439723279231">Serverens certifikat indeholder fejl.</translation>
-<translation id="24943777258388405">Ugyldigt telefonnummer</translation>
<translation id="2495083838625180221">Værktøj til parsing af JSON-filer</translation>
<translation id="2495093607237746763">Hvis dette felt er markeret, gemmer Chromium en kopi af dit kort på denne enhed for at gøre det hurtigere at udfylde formularer.</translation>
<translation id="2498091847651709837">Scan et nyt kort</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> sendte et ugyldigt svar.</translation>
<translation id="2552545117464357659">Nyere</translation>
<translation id="2556876185419854533">&amp;Fortryd redigering</translation>
+<translation id="2587730715158995865">Fra <ph name="ARTICLE_PUBLISHER" />. Læs denne og <ph name="OTHER_ARTICLE_COUNT" /> andre historier.</translation>
<translation id="2587841377698384444">Id for Directory API:</translation>
<translation id="2597378329261239068">Dette dokument er adgangskodebeskyttet. Indtast en adgangskode.</translation>
<translation id="2609632851001447353">Varianter</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Køre Diagnosticering af forbindelse<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">Fjern valgte elementer</translation>
+<translation id="277133753123645258">Forsendelsesmetode</translation>
<translation id="277499241957683684">Manglende enhedsregistrering</translation>
<translation id="2784949926578158345">Forbindelsen blev nulstillet.</translation>
<translation id="2794233252405721443">Websitet er blokeret</translation>
-<translation id="2812680587231492111">Den pågældende afhentningsmulighed er ikke tilgængelig. Prøv en anden mulighed.</translation>
<translation id="2824775600643448204">Adresse og søgelinje</translation>
<translation id="2826760142808435982">Forbindelsen er krypteret og godkendt ved hjælp af <ph name="CIPHER" />, og den anvender <ph name="KX" /> som primær udvekslingsmekanisme.</translation>
<translation id="2835170189407361413">Ryd formular</translation>
-<translation id="2849041323157393173">Den pågældende leveringsmulighed er ikke tilgængelig. Prøv en anden mulighed.</translation>
<translation id="2889159643044928134">Genindlæs ikke siden</translation>
<translation id="2900469785430194048">Google Chrome løb tør for hukommelse, da websiden skulle vises.</translation>
<translation id="2909946352844186028">Der blev registreret en netværksændring.</translation>
<translation id="2916038427272391327">Luk andre programmer</translation>
<translation id="2922350208395188000">Serverens certifikat kan ikke kontrolleres.</translation>
+<translation id="2928905813689894207">Faktureringsadresse</translation>
<translation id="2948083400971632585">Du kan deaktivere alle proxyer, der er konfigureret for en forbindelse, fra siden Indstillinger.</translation>
<translation id="2955913368246107853">Luk søgefeltet</translation>
<translation id="2958431318199492670">Netværkskonfigurationen overholder ikke ONC-standarden. Dele af konfiguration kan muligvis ikke importeres.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Uret på din enhed skal være indstillet korrekt, før du kan oprette en sikker forbindelse. Dette er vigtigt, da de certifikater, websites bruger til at identificere sig selv, kun er gyldige i bestemte perioder. Da uret på din enhed er indstillet forkert, kan Chrome ikke bekræfte disse certifikater.</translation>
<translation id="2972581237482394796">&amp;Annuller fortryd</translation>
<translation id="2985306909656435243">Hvis denne indstilling er slået til, gemmer Chromium en kopi af dit kort på denne enhed for at gøre det hurtigere at udfylde formularer.</translation>
+<translation id="2985398929374701810">Angiv en gyldig adresse</translation>
+<translation id="2986368408720340940">Denne afhentningsmetode er ikke tilgængelig. Prøv en anden metode.</translation>
<translation id="2991174974383378012">Deling med websites</translation>
<translation id="3005723025932146533">Vis gemt kopi</translation>
<translation id="3008447029300691911">Indtast kontrolkoden for <ph name="CREDIT_CARD" />. Når du bekræfter, deles dine kortoplysninger med dette website.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{mindst 1 element på synkroniserede enheder}=1{1 element (og flere på synkroniserede enheder)}one{# element (og flere på synkroniserede enheder)}other{# elementer (og flere på synkroniserede enheder)}}</translation>
<translation id="3041612393474885105">Certifikatoplysninger</translation>
<translation id="3063697135517575841">Chrome kan ikke bekræfte dit kort i øjeblikket. Prøv igen senere.</translation>
+<translation id="3064966200440839136">Du forlader inkognitotilstand for at betale via en ekstern applikation. Vil du fortsætte?</translation>
<translation id="3093245981617870298">Du er offline.</translation>
<translation id="3105172416063519923">Aktiv-id:</translation>
<translation id="3109728660330352905">Du har ikke tilladelse til at se denne side.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Prøv at køre Diagnosticering af forbindelse<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Svaret kunne ikke afkodes</translation>
-<translation id="3149891296864842641">Forsendelsesmuligheder</translation>
<translation id="3150653042067488994">Midlertidig serverfejl</translation>
+<translation id="3154506275960390542">Denne side indeholder en formular, der muligvis ikke kan indsendes sikkert. Dine indsendte data kan ses af andre eller kan blive ændret af en hacker, så serveren, du sender til, modtager forkerte oplysninger.</translation>
<translation id="3157931365184549694">Gendan</translation>
<translation id="3167968892399408617">Når du har lukket alle dine inkognitofaner, gemmes der hverken cookies, browser- eller søgehistorik for de sider, du besøger i inkognitotilstand. Dog gemmes alle de filer, du downloader, og bogmærker, du opretter.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Din anmodning om at få adgang til dette website kunne ikke sendes til <ph name="NAME" />. Prøv igen.</translation>
<translation id="3355823806454867987">Skift indstillinger for proxy...</translation>
<translation id="3369192424181595722">Urfejl</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> elementer mere...</translation>
<translation id="337363190475750230">Fjernet</translation>
<translation id="3377188786107721145">Det opstod en fejl ved parsing af politik</translation>
<translation id="3380365263193509176">Ukendt fejl</translation>
<translation id="3380864720620200369">Klient-id:</translation>
<translation id="3391030046425686457">Leveringsadresse</translation>
+<translation id="3395827396354264108">Afhentningsmetode</translation>
<translation id="340013220407300675">Angriberen prøver muligvis at stjæle dine oplysninger fra <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (f.eks. adgangskoder, beskeder eller kreditkort).</translation>
<translation id="3422248202833853650">Prøv at lukke programmer for at frigøre hukommelse.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> kan ikke læses i øjeblikket.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Hent interval:</translation>
<translation id="3462200631372590220">Skjul avanceret</translation>
+<translation id="3467763166455606212">Kortindehavers navn skal angives</translation>
+<translation id="3478058380795961209">Udløbsmåned:</translation>
<translation id="3479539252931486093">Var dette uventet? <ph name="BEGIN_LINK" />Giv os gerne feedback<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Ikke nu</translation>
<translation id="348000606199325318">Nedbruds-id <ph name="CRASH_LOCAL_ID" /> (server-id: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Vi kan ikke få fat i din forælder på nuværende tidspunkt. Prøv igen.</translation>
<translation id="3528171143076753409">Serverens certifikat er ikke troværdigt.</translation>
-<translation id="3538531656504267329">Ugyldigt udløbsår</translation>
<translation id="3539171420378717834">Gem en kopi af dette kort på denne enhed</translation>
<translation id="3542684924769048008">Brug adgangskode til:</translation>
<translation id="3549644494707163724">Krypter alle synkroniserede data med din egen adgangssætning til synkronisering</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Skjul oplysninger</translation>
<translation id="3587482841069643663">Alle</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Angiv en gyldig udløbsdato</translation>
<translation id="36224234498066874">Ryd browserdata...</translation>
<translation id="362276910939193118">Vis hele historikken</translation>
<translation id="3623476034248543066">Vis værdi</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Adgangskode:</translation>
<translation id="3696411085566228381">ingen</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Vælg en leveringsadresse for at se forsendelsesmetoder og -krav.</translation>
<translation id="370665806235115550">Indlæser...</translation>
<translation id="3712624925041724820">Licenserne er opbrugt</translation>
<translation id="3714780639079136834">Tænde for mobildata eller Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Link, du har kopieret</translation>
<translation id="375403751935624634">Oversættelsen mislykkedes på grund af en serverfejl.</translation>
<translation id="3759461132968374835">Du har ingen nyligt rapporterede nedbrud. Nedbrud, der opstod, mens rapportering om nedbrud var deaktiveret, vises ikke her.</translation>
+<translation id="3787705759683870569">Udløber <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Hvis du bruger en proxyserver...</translation>
<translation id="3828924085048779000">Tomme adgangssætninger er ikke tilladt.</translation>
<translation id="3845539888601087042">Viser historik fra de enheder, hvor du er logget ind. <ph name="BEGIN_LINK" />FÃ¥ flere oplysninger<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Skal Chromium gemme dette kort?</translation>
<translation id="4171400957073367226">Ugyldig verifikationssignatur</translation>
-<translation id="4176463684765177261">Deaktiveret</translation>
<translation id="4196861286325780578">&amp;Annuller fortryd flytning</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Kontrollere firewall- og antiviruskonfigurationer<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{ingen}=1{1 app ($1)}=2{2 apps ($1, $2)}one{# app ($1, $2, $3)}other{# apps ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">søgeresultater</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> accepterede ikke dit logincertifikat, eller der er ikke angivet et.</translation>
<translation id="443673843213245140">Brug af en proxy er deaktiveret, men en eksplicit proxykonfiguration er angivet.</translation>
-<translation id="4446242550670694251">Nu kan du gå på nettet privat, og andre personer, som bruger denne enhed, kan ikke se din aktivitet.</translation>
<translation id="4492190037599258964">Søgeresultater for '<ph name="SEARCH_STRING" />'</translation>
<translation id="4506176782989081258">Valideringsfejl: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Kontakte systemadministratoren</translation>
<translation id="450710068430902550">Deling med administrator</translation>
+<translation id="4515275063822566619">Kort og adresser er fra Chrome og din Google-konto (<ph name="ACCOUNT_EMAIL" />). Du kan administrere dem i <ph name="BEGIN_LINK" />Indstillinger<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Detaljer</translation>
<translation id="4558551763791394412">Prøv at deaktivere dine udvidelser.</translation>
<translation id="457875822857220463">Levering</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Tilpas til siden</translation>
<translation id="483020001682031208">Der er ingen Fysisk web-sider at vise</translation>
<translation id="4850886885716139402">Vis</translation>
+<translation id="4854362297993841467">Denne leveringsmetode er ikke tilgængelig. Prøv en anden metode.</translation>
<translation id="4858792381671956233">Du har spurgt dine forældre, om det er i orden at besøge dette website.</translation>
<translation id="4880827082731008257">Søg i historikken</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Denne side er oversat fra et ukendt sprog til <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Betaling</translation>
<translation id="4926049483395192435">Skal angives.</translation>
-<translation id="4941291666397027948">* angiver et obligatorisk felt</translation>
<translation id="495170559598752135">Handlinger</translation>
<translation id="4958444002117714549">Udvid liste</translation>
<translation id="4962322354953122629">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da Chrome ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Ugyldig adgangskode</translation>
<translation id="5056549851600133418">Artikler til dig</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Tjekke proxy-adressen<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Ingen cookies}=1{1 website bruger cookies. }one{# website bruger cookies. }other{# websites bruger cookies. }}</translation>
<translation id="5087286274860437796">Serverens certifikatet er ikke gyldigt i øjeblikket.</translation>
<translation id="5087580092889165836">Tilføj kort</translation>
<translation id="5089810972385038852">Delstat</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Vis</translation>
<translation id="5308689395849655368">Rapportering af nedbrud er deaktiveret.</translation>
<translation id="5317780077021120954">Gem</translation>
-<translation id="5326702247179446998">Modtager skal udfyldes</translation>
<translation id="5327248766486351172">Navn</translation>
<translation id="5337705430875057403">Hackere på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> kan narre dig til at gøre noget farligt, såsom at installere software eller afsløre dine personlige oplysninger (f.eks. adgangskoder, telefonnumre eller kreditkort).</translation>
-<translation id="53553865750799677">Afhentningsadressen understøttes ikke. Vælg en anden adresse.</translation>
<translation id="5359637492792381994">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet ikke er gyldigt i øjeblikket. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Der kunne ikke gemmes indstillinger for politik</translation>
<translation id="5386426401304769735">Certifikatkæden for dette website indeholder et certifikat, der er signeret med SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">En integreret side på <ph name="SITE" /> siger:</translation>
<translation id="5556459405103347317">Genindlæs</translation>
<translation id="5565735124758917034">Aktiv</translation>
+<translation id="5571083550517324815">Der kan ikke afhentes på denne adresse. Vælg en anden adresse.</translation>
<translation id="5572851009514199876">Start og log ind på Chrome, så Chrome kan kontrollere, om du har adgang til dette website.</translation>
-<translation id="5575380383496039204">Leveringsadressen understøttes ikke. Vælg en anden adresse.</translation>
<translation id="5580958916614886209">Kontrollér, om udløbsmåneden er korrekt, og prøv igen.</translation>
<translation id="560412284261940334">Administration er ikke understøttet</translation>
<translation id="5610142619324316209">Kontrollere forbindelsen</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">Dette websites identitet er ikke blevet bekræftet.</translation>
<translation id="5720705177508910913">Aktuel bruger</translation>
<translation id="5732392974455271431">Dine forældre kan fjerne blokeringen for dig</translation>
-<translation id="57586589942790530">Ugyldigt kortnummer</translation>
+<translation id="5763042198335101085">Angiv en gyldig mailadresse</translation>
+<translation id="5765072501007116331">Vælg en adresse for at se leveringsmetoder og -krav</translation>
<translation id="5784606427469807560">Der opstod et problem under bekræftelsen af dit kort. Kontrollér, at du har forbindelse til internettet, og prøv igen.</translation>
<translation id="5785756445106461925">Desuden indeholder denne side andre ressourcer, som ikke er sikre. Disse ressourcer kan ses af andre under overførslen og kan ændres af en hacker, så siden ser anderledes ud.</translation>
<translation id="5786044859038896871">Skal dine kortoplysninger udfyldes?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">Der kan ikke oprettes forbindelse til dette website</translation>
<translation id="5869522115854928033">Gemte adgangskoder</translation>
<translation id="5872918882028971132">Forslag fra forældre</translation>
-<translation id="587760065310675640">Forsendelsesadressen understøttes ikke. Vælg en anden adresse.</translation>
<translation id="5901630391730855834">Gul</translation>
-<translation id="59174027418879706">Aktiveret</translation>
<translation id="5926846154125914413">Du kan miste adgangen til Premium-indhold på visse websites.</translation>
<translation id="5959728338436674663">Send automatisk <ph name="BEGIN_WHITEPAPER_LINK" />nogle systemoplysninger og noget sideindhold<ph name="END_WHITEPAPER_LINK" /> til Google som en hjælp til at registrere skadelige apps og websites. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Uge</translation>
<translation id="5967867314010545767">Fjern fra historik</translation>
<translation id="5975083100439434680">Zoom ud</translation>
+<translation id="598637245381783098">Betalingsappen kan ikke åbnes</translation>
<translation id="5989320800837274978">Der er hverken angivet faste proxyservere eller en .pac-scriptwebadresse.</translation>
<translation id="5990559369517809815">Anmodninger til serveren er blokeret af en udvidelse.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Kort- og adresseindstillingerne er fra Chrome. Du kan administrere dem i <ph name="BEGIN_LINK" />Indstillinger<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Side 1}one{Side #}other{Side #}}</translation>
<translation id="6017514345406065928">Grøn</translation>
+<translation id="6027201098523975773">Angiv et navn</translation>
<translation id="6040143037577758943">Luk</translation>
-<translation id="604124094241169006">Automatisk</translation>
<translation id="6042308850641462728">Mere</translation>
<translation id="6060685159320643512">Vær forsigtig. Disse eksperimenter kan være farlige</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{ingen}=1{1}one{#}other{#}}</translation>
@@ -543,9 +552,10 @@
netværksenheder, du bruger.</translation>
<translation id="614940544461990577">Prøv at:</translation>
<translation id="6151417162996330722">Servercertifikatet har en gyldighedsperiode, der er for lang.</translation>
-<translation id="615643356032862689">Downloadede filer og bogmærker beholdes.</translation>
+<translation id="6157877588268064908">Vælg en adresse for at se forsendelsesmetoder og -krav</translation>
<translation id="6165508094623778733">Flere oplysninger</translation>
<translation id="6177128806592000436">Din forbindelse til dette website er ikke sikker.</translation>
+<translation id="6184817833369986695">(kohorte: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Kontrollér din internetforbindelse</translation>
<translation id="6218753634732582820">Vil du fjerne adressen fra Chromium?</translation>
<translation id="6251924700383757765">Privatlivspolitik</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Annuller fortryd omarrangering</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" />-bogmærker</translation>
<translation id="6264485186158353794">Tilbage i sikkerhed</translation>
+<translation id="6276112860590028508">Sider fra din læseliste vises her</translation>
+<translation id="6280223929691119688">Der kan ikke leveres til denne adresse. Vælg en anden adresse.</translation>
<translation id="6282194474023008486">Postnummer</translation>
<translation id="6290238015253830360">Forslag til artikler til dig vises her</translation>
<translation id="6305205051461490394"><ph name="URL" /> kan ikke nås.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Kan ikke kontrollere, om certifikatet er tilbagekaldt.</translation>
<translation id="6433490469411711332">Rediger kontaktoplysninger</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> nægtede at oprette forbindelse.</translation>
-<translation id="6443118737398455446">Udløbsdatoen er ugyldig</translation>
<translation id="6446608382365791566">Tilføj flere oplysninger</translation>
<translation id="6451458296329894277">Bekræft genindsendelse af formular</translation>
<translation id="6456339708790392414">Din betaling</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet muligvis er blevet tilbagekaldt. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Enhedspolitikker</translation>
<translation id="6477321094435799029">Chrome registrerede usædvanlig kode på denne side og blokerede den for at beskytte dine personlige oplysninger (f.eks. adgangskoder, telefonnumre eller kreditkort).</translation>
-<translation id="6477460825583319731">Ugyldig e-mailadresse</translation>
<translation id="6489534406876378309">Start upload af nedbrud</translation>
<translation id="6508722015517270189">Genstart Chrome</translation>
-<translation id="6525462735697194615">Ugyldig udløbsmåned</translation>
<translation id="6529602333819889595">&amp;Annuller fortryd slet</translation>
<translation id="6534179046333460208">Forslag til Fysisk web</translation>
<translation id="6550675742724504774">Valgmuligheder</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> -søgning</translation>
<translation id="6644283850729428850">Denne politik er forældet.</translation>
<translation id="6652240803263749613">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da din computers operativsystem ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Den pågældende forsendelsesmulighed er ikke tilgængelig. Prøv en anden mulighed.</translation>
<translation id="6671697161687535275">Vil du fjerne formularforslag fra Chromium?</translation>
<translation id="6685834062052613830">Log ud, og fuldfør konfigurationen</translation>
<translation id="6710213216561001401">Forrige</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Der er noget galt med proxyserveren, eller adressen er forkert.</translation>
<translation id="6727102863431372879">Angiv</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{ingen}=1{1 element}one{# element}other{# elementer}}</translation>
-<translation id="6743044928064272573">Afhentningsmetode</translation>
<translation id="674375294223700098">Ukendt fejl i servercertifikatet.</translation>
<translation id="6753269504797312559">Politikkens værdi</translation>
<translation id="6757797048963528358">Din enhed gik i dvale.</translation>
<translation id="6778737459546443941">Din forælder har ikke godkendt det endnu</translation>
<translation id="6810899417690483278">Tilpasnings-id</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Områdedata kunne ikke indlæses</translation>
<translation id="6831043979455480757">Oversæt</translation>
<translation id="6839929833149231406">Område</translation>
<translation id="6874604403660855544">&amp;Annuller fortryd tilføjelse</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Dit kort er bekræftet</translation>
<translation id="6897140037006041989">Brugeragent</translation>
<translation id="6915804003454593391">Bruger:</translation>
+<translation id="6948701128805548767">Vælg en adresse for at se afhentningsmetoder og -krav</translation>
<translation id="6957887021205513506">Serverens certifikat ser ud til at være en forfalskning.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Enhed</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">BÃ¥de faste proxyservere og en webadresse for .pac-script angives.</translation>
<translation id="6989763994942163495">Vis avancerede indstillinger...</translation>
<translation id="7000990526846637657">Der blev ikke fundet nogen poster i historikken</translation>
-<translation id="7001663382399377034">Tilføj modtager</translation>
<translation id="7009986207543992532">Du forsøgte at få forbindelse til <ph name="DOMAIN" />, men serveren præsenterede et certifikat, hvis gyldighedsperiode er for lang til at være pålidelig. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Din Google-konto kan have andre former for browserhistorik på <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Ældre</translation>
<translation id="7090678807593890770">Søg efter <ph name="LINK" /> på Google</translation>
<translation id="7119414471315195487">Luk andre faner eller programmer</translation>
+<translation id="7129409597930077180">Der kan ikke sendes til denne adresse. Vælg en anden adresse.</translation>
+<translation id="7138472120740807366">Leveringsmetode</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7155487117670177674">Betaling er ikke sikkert</translation>
<translation id="7179921470347911571">Genstart nu</translation>
<translation id="7180611975245234373">Opdater</translation>
<translation id="7182878459783632708">Ingen politikker er indstillet</translation>
<translation id="7186367841673660872">Denne side er oversat fra<ph name="ORIGINAL_LANGUAGE" />til<ph name="LANGUAGE_LANGUAGE" /></translation>
+<translation id="7192203810768312527">Frigør <ph name="SIZE" />. Nogle websites indlæses muligvis langsommere, næste gang du går til websitet.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> overholder ikke sikkerhedsstandarderne.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />FÃ¥ flere oplysninger<ph name="END_LINK" /> om dette problem.</translation>
@@ -675,7 +686,6 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="7424977062513257142">En integreret side på denne webside siger:</translation>
<translation id="7441627299479586546">Forkert emne for politik</translation>
<translation id="7444046173054089907">Dette website er blokeret</translation>
-<translation id="7444238235002594607">Vælg en afhentningsadresse for at se afhentningsmetoder og krav.</translation>
<translation id="7445762425076701745">Identiteten på den server, som du er tilknyttet, kan ikke bekræftes. Du er tilknyttet en server via et navn, der kun er gyldigt i dit netværk, og som en ekstern certifikatautoritet derfor ikke har mulighed for at bekræfte ejerskabet på. Da enkelte certifikatautoriteter alligevel udsteder certifikater for disse navne, kan vi på ingen måde sikre, at du er tilknyttet det tilsigtede website og ikke til en forbryder.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />FÃ¥ flere oplysninger<ph name="END_LINK" /> om dette problem.</translation>
<translation id="7460163899615895653">Dine seneste faner fra andre enheder vises her</translation>
@@ -719,6 +729,7 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="7755287808199759310">Din forælder kan fjerne blokeringen for dig</translation>
<translation id="7758069387465995638">Firewall- eller antivirussoftware kan have blokeret forbindelsen.</translation>
<translation id="7761701407923456692">Serverens certifikat passer ikke til webadressen.</translation>
+<translation id="7763386264682878361">Værktøj til parsing af betalingsmanifester</translation>
<translation id="7764225426217299476">Tilføj adresse</translation>
<translation id="777702478322588152">Præfektur</translation>
<translation id="7791543448312431591">Tilføj</translation>
@@ -732,6 +743,7 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="785549533363645510">Du er dog ikke usynlig. Inkognitotilstand skjuler ikke din browserhistorik over for din arbejdsgiver, din internetudbyder eller de websites, du besøger.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Kontrollér, om din kontrolkode er korrekt, og prøv igen.</translation>
+<translation id="79338296614623784">Angiv et gyldigt telefonnummer</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Serverens certifikatet er endnu ikke gyldigt.</translation>
<translation id="7942349550061667556">Rød</translation>
@@ -751,6 +763,7 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="8088680233425245692">Artiklen kunne ikke vises.</translation>
<translation id="8089520772729574115">mindre end 1 MB</translation>
<translation id="8091372947890762290">Aktivering afventer serveren</translation>
+<translation id="8118489163946903409">Betalingsmetode</translation>
<translation id="8131740175452115882">Bekræft</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />DNS-adressen<ph name="END_ABBR" /> for <ph name="HOST_NAME" />s server blev ikke fundet.</translation>
<translation id="8149426793427495338">Din computer gik i dvale.</translation>
@@ -776,6 +789,7 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="8349305172487531364">Bogmærkelinje</translation>
<translation id="8363502534493474904">Deaktivere flytilstand</translation>
<translation id="8364627913115013041">Ikke angivet.</translation>
+<translation id="8368476060205742148">Google Play-tjenester</translation>
<translation id="8380941800586852976">Farlig</translation>
<translation id="8382348898565613901">De bogmærker, du har besøgt for nylig, vises her</translation>
<translation id="8398259832188219207">Nedbrudsrapporten blev uploadet <ph name="UPLOAD_TIME" /></translation>
@@ -784,32 +798,30 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="8428213095426709021">Indstillinger</translation>
<translation id="8433057134996913067">Dette logger dig ud af de fleste websites.</translation>
<translation id="8437238597147034694">&amp;Fortryd flytning</translation>
-<translation id="8456681095658380701">Ugyldigt navn</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 kreditkort}one{# kreditkort}other{# kreditkort}}</translation>
<translation id="8483780878231876732">Hvis du vil bruge kort fra din Google-konto, skal du logge ind i Chrome</translation>
<translation id="8488350697529856933">Gælder for</translation>
-<translation id="8492969205326575646">Ikke-understøttet korttype</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> var for lang tid om at svare.</translation>
<translation id="852346902619691059">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da din enheds operativsystem ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Udløbsår</translation>
<translation id="8543181531796978784">Du kan <ph name="BEGIN_ERROR_LINK" />rapportere et registreringsproblem<ph name="END_ERROR_LINK" /> eller, hvis du forstår den sikkerhedsrisiko, du udsætter dig for, <ph name="BEGIN_LINK" />kan du gå til dette usikre website<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Oversættelsen mislykkedes, fordi sidens sprog ikke kunne fastslås.</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="8570229484593575558">Disse oplysninger |gemmes ikke|:#Din browserhistorik#Dine søgninger#Cookiedata</translation>
<translation id="8571890674111243710">Oversætter siden til <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Din aktivitet |er muligvis stadig synlig| for:#Websites, du besøger#Din arbejdsgiver#Din internetudbyder</translation>
<translation id="858637041960032120">Tilføj tlf.nr.
</translation>
<translation id="859285277496340001">Certifikatet angiver ikke en mekanisme, der kontrollerer, om den har været tilbagekaldt.</translation>
<translation id="8620436878122366504">Dine forældre har ikke godkendt det endnu</translation>
<translation id="8647750283161643317">Nulstil alle til standard</translation>
<translation id="8703575177326907206">Din forbindelse til <ph name="DOMAIN" /> er ikke krypteret.</translation>
+<translation id="8718314106902482036">Betalingen blev ikke gennemført</translation>
<translation id="8725066075913043281">Forsøg igen</translation>
-<translation id="8728672262656704056">Du er nu i inkognitotilstand</translation>
+<translation id="8728672262656704056">Du er nu i inkognito</translation>
<translation id="8730621377337864115">Udfør</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="8759274551635299824">Kortet er udløbet</translation>
<translation id="8790007591277257123">&amp;Annuller fortryd sletning</translation>
-<translation id="8798099450830957504">Standard</translation>
<translation id="8800988563907321413">Her vises de forslag, der er tæt på dig</translation>
<translation id="8820817407110198400">Bogmærker</translation>
<translation id="883848425547221593">Andre bogmærker</translation>
@@ -819,6 +831,7 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="8866481888320382733">Der opstod en fejl ved parsing af indstillinger for politik</translation>
<translation id="8866959479196209191">Denne side siger:</translation>
<translation id="8870413625673593573">Senest lukkede</translation>
+<translation id="8874824191258364635">Angiv et gyldigt kortnummer</translation>
<translation id="8876793034577346603">Netværkskonfiguration kunne ikke parses.</translation>
<translation id="8877192140621905067">Når du har bekræftet, deles dine kortoplysninger med dette website</translation>
<translation id="8889402386540077796">Farvetone</translation>
@@ -828,7 +841,6 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="8931333241327730545">Vil du gemme dette kort på din Google-konto?</translation>
<translation id="8932102934695377596">Dit ur er bagud</translation>
<translation id="8954894007019320973">(Forts.)</translation>
-<translation id="895548565263634352">Læs nyheder fra <ph name="ARTICLE_PUBLISHER" /> og <ph name="OTHER_ARTICLE_COUNT" /> andre</translation>
<translation id="8971063699422889582">Serverens certifikat er udløbet.</translation>
<translation id="8986494364107987395">Send automatisk brugsstatistikker og nedbrudsrapporter til Google</translation>
<translation id="8987927404178983737">MÃ¥ned</translation>
@@ -844,9 +856,8 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="9050666287014529139">Adgangssætning</translation>
<translation id="9065203028668620118">Rediger</translation>
<translation id="9068849894565669697">Vælg farve</translation>
-<translation id="9076283476770535406">Der er muligvis voksenindhold på websitet</translation>
+<translation id="9076283476770535406">Der er muligvis indhold for voksne på websitet</translation>
<translation id="9078964945751709336">Flere oplysninger kræves</translation>
-<translation id="9094175695478007090">Betalingsappen kunne ikke åbnes.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> bruger normalt kryptering til at beskytte dine oplysninger. Da Chromium forsøgte at oprette forbindelse til <ph name="SITE" /> denne gang, returnerede websitet usædvanlige og forkerte loginoplysninger. Dette kan skyldes, at en hacker forsøger at udgive sig for at være <ph name="SITE" />, eller at en Wi-Fi-loginskærm har forstyrret forbindelsen. Dine oplysninger er stadig sikre, idet Chromium afbrød forbindelsen, inden der blev udvekslet data.</translation>
<translation id="9137013805542155359">Vis oprindelig</translation>
<translation id="9137248913990643158">Start og log ind på Chrome, inden du bruger denne app.</translation>
diff --git a/chromium/components/strings/components_strings_de.xtb b/chromium/components/strings/components_strings_de.xtb
index b16e87ba4c2..9488eb2f1a8 100644
--- a/chromium/components/strings/components_strings_de.xtb
+++ b/chromium/components/strings/components_strings_de.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="de">
<translation id="1008557486741366299">Jetzt nicht</translation>
<translation id="1015730422737071372">Weitere Details angeben</translation>
+<translation id="1021110881106174305">Akzeptierte Karten</translation>
<translation id="1032854598605920125">Im Uhrzeigersinn drehen</translation>
<translation id="1038842779957582377">Unbekannter Name</translation>
<translation id="1050038467049342496">Andere Apps schließen</translation>
@@ -14,7 +15,7 @@
<translation id="1080116354587839789">An Breite anpassen</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> immer übersetzen</translation>
<translation id="1107591249535594099">Bei Aktivierung speichert Chrome eine Kopie Ihrer Karte auf diesem Gerät, damit Formulare schneller ausgefüllt werden können.</translation>
-<translation id="1111153019813902504">Vor Kurzem gespeicherte Lesezeichen</translation>
+<translation id="1111153019813902504">Vor Kurzem aufgerufene Lesezeichen</translation>
<translation id="1113869188872983271">&amp;Neu anordnen rückgängig machen</translation>
<translation id="1126551341858583091">Die Größe auf dem lokalen Speicher ist <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Richtlinien-Cache einwandfrei</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Wert ausblenden</translation>
<translation id="1228893227497259893">Falsche Entitätskennung</translation>
<translation id="1232569758102978740">Unbenannt</translation>
+<translation id="1263231323834454256">Leseliste</translation>
<translation id="1264126396475825575">Absturzbericht erfasst am <ph name="CRASH_TIME" />, wurde noch nicht hochgeladen oder wurde ignoriert</translation>
<translation id="1285320974508926690">Diese Website nie übersetzen</translation>
<translation id="129553762522093515">Kürzlich geschlossen</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">AutoFill-Einstellungen für Chromium...</translation>
<translation id="1374468813861204354">Vorschläge</translation>
<translation id="1375198122581997741">Informationen zur Version</translation>
+<translation id="1377321085342047638">Kartennummer</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> hat keine Daten gesendet.</translation>
<translation id="1407135791313364759">Alle öffnen</translation>
<translation id="1413809658975081374">Datenschutzfehler</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Verlauf</translation>
<translation id="1645368109819982629">Nicht unterstütztes Protokoll</translation>
<translation id="1656489000284462475">Abholung</translation>
+<translation id="1663943134801823270">Die Karten und Adressen stammen aus Chrome. Sie werden in den <ph name="BEGIN_LINK" />Einstellungen<ph name="END_LINK" /> verwaltet.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> schützt Ihre Daten in der Regel durch Verschlüsselung. Als Google 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 Google Chrome die Verbindung vor dem Austausch von Daten unterbrochen hat, sind Ihre Informationen weiterhin sicher.</translation>
<translation id="168328519870909584">Hacker, die derzeit auf <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> zugreifen, versuchen unter Umständen, gefährliche Programme auf Ihrem Gerät zu installieren, um Ihre Daten zu stehlen oder zu löschen, zum Beispiel Fotos, Passwörter, Nachrichten und Kreditkartendaten.</translation>
<translation id="168841957122794586">Das Serverzertifikat weist einen schwachen kryptografischen Schlüssel auf.</translation>
<translation id="1710259589646384581">Betriebssystem</translation>
<translation id="1721312023322545264">Du benötigst die Berechtigung von <ph name="NAME" />, um diese Website zu besuchen</translation>
+<translation id="1721424275792716183">* Pflichtfeld</translation>
<translation id="1728677426644403582">Dies ist die Quelle einer Webseite</translation>
+<translation id="173080396488393970">Dieser Kartentyp wird nicht unterstützt</translation>
<translation id="1734864079702812349">American Express</translation>
<translation id="1734878702283171397">Setzen Sie sich mit dem Systemadministrator in Verbindung.</translation>
+<translation id="1740951997222943430">Geben Sie einen gültigen Ablaufmonat ein</translation>
<translation id="1745358365027406341">Seite später herunterladen</translation>
<translation id="17513872634828108">Geöffnete Tabs</translation>
<translation id="1753706481035618306">Seitennummer</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Synchronisierungs-Passphrase aktualisieren</translation>
<translation id="1787142507584202372">Hier werden Ihre offenen Tabs angezeigt</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Wählen Sie eine Lieferadresse aus, um die Liefermethoden und -anforderungen zu sehen.</translation>
+<translation id="1803264062614276815">Name des Karteninhabers</translation>
<translation id="1803678881841855883">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. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1806541873155184440">Hinzugefügt: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Anfrage oder Anfrageparameter ungültig</translation>
<translation id="1826516787628120939">Überprüfung läuft</translation>
<translation id="1834321415901700177">Diese Website enthält schädliche Programme</translation>
<translation id="1842969606798536927">Bezahlen</translation>
-<translation id="1864455488461349376">Lieferoption</translation>
<translation id="1871208020102129563">Der Proxy ist zur Verwendung von festen Proxyservern konfiguriert, nicht zur Verwendung einer PAC-Skript-URL.</translation>
<translation id="1871284979644508959">Pflichtfeld</translation>
<translation id="187918866476621466">"Beim Start"-Seiten öffnen</translation>
<translation id="1883255238294161206">Liste ausblenden</translation>
<translation id="1898423065542865115">Filtern</translation>
<translation id="194030505837763158">Besuchen Sie die Seite <ph name="LINK" />.</translation>
-<translation id="1946821392246652573">Akzeptierte Karten</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" />-Lesezeichen</translation>
<translation id="1973335181906896915">Fehler bei der Serialisierung</translation>
<translation id="1974060860693918893">Erweitert</translation>
<translation id="1978555033938440688">Firmwareversion</translation>
+<translation id="1995859865337580572">Bitte geben Sie Ihren CVC ein</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{und 1 weitere}other{und # weitere}}</translation>
-<translation id="2020194265157481222">"Name auf der Karte" ist ein Pflichtfeld</translation>
<translation id="2025186561304664664">Proxy ist auf automatische Konfiguration eingestellt.</translation>
<translation id="2030481566774242610">Meinten Sie <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Proxy und Firewall prüfen<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Heute</translation>
<translation id="2154054054215849342">Die Synchronisierung ist für Ihre Domain nicht verfügbar</translation>
<translation id="2154484045852737596">Karte bearbeiten</translation>
-<translation id="2156993118928861787">Ungültige Adresse</translation>
<translation id="2166049586286450108">Vollständiger Administratorzugriff</translation>
<translation id="2166378884831602661">Diese Website kann keine sichere Verbindung bereitstellen</translation>
<translation id="2181821976797666341">Richtlinien</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 Adresse}other{# Adressen}}</translation>
+<translation id="2202020181578195191">Geben Sie ein gültiges Ablaufjahr ein</translation>
<translation id="2212735316055980242">Richtlinie nicht gefunden</translation>
<translation id="2213606439339815911">Einträge werden abgerufen...</translation>
<translation id="2230458221926704099">Beheben Sie den Verbindungsfehler mithilfe der <ph name="BEGIN_LINK" />Diagnose-App<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Ihre Internetverbindung ist gesperrt</translation>
<translation id="230155334948463882">Neue Karte?</translation>
<translation id="2305919008529760154">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. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="230697611605700222">Karten- und Adressoptionen stammen von Ihrem Google-Konto (<ph name="ACCOUNT_EMAIL" />) und Chrome. <ph name="BEGIN_LINK" />Sie können diese in den Einstellungen verwalten.<ph name="END_LINK" /></translation>
<translation id="2317259163369394535">Für <ph name="DOMAIN" /> sind ein Nutzername und ein Passwort erforderlich.</translation>
<translation id="2318774815570432836">Sie können <ph name="SITE" /> zurzeit 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. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2354001756790975382">Weitere Lesezeichen</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Standardeinstellung durch Unternehmen</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="2396249848217231973">&amp;Löschen rückgängig machen</translation>
<translation id="2460160116472764928">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. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2463739503403862330">Ausfüllen</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Netzwerkdiagnose ausführen<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Ungültige Such-URL</translation>
<translation id="2491120439723279231">Das Serverzertifikat enthält Fehler.</translation>
-<translation id="24943777258388405">Ungültige Telefonnummer</translation>
<translation id="2495083838625180221">JSON-Parser</translation>
<translation id="2495093607237746763">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="2498091847651709837">Neue Karte scannen</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> hat eine ungültige Antwort gesendet.</translation>
<translation id="2552545117464357659">Neuer</translation>
<translation id="2556876185419854533">&amp;Bearbeiten rückgängig machen</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="2597378329261239068">Dieses Dokument ist passwortgeschützt. Geben Sie ein Passwort ein.</translation>
<translation id="2609632851001447353">Varianten</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Verbindungsdiagnose ausführen<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">Ausgewählte Einträge entfernen</translation>
+<translation id="277133753123645258">Versandart</translation>
<translation id="277499241957683684">Fehlender Gerätedatensatz</translation>
<translation id="2784949926578158345">Verbindung wurde zurückgesetzt.</translation>
<translation id="2794233252405721443">Website blockiert</translation>
-<translation id="2812680587231492111">Diese Abholfunktion ist nicht verfügbar. Wählen Sie eine andere Option aus.</translation>
<translation id="2824775600643448204">Adress- und Suchleiste</translation>
<translation id="2826760142808435982">Die Verbindung ist mit <ph name="CIPHER" /> verschlüsselt und authentifiziert und verwendet <ph name="KX" /> als Mechanismus für den Schlüsselaustausch.</translation>
<translation id="2835170189407361413">Formular leeren</translation>
-<translation id="2849041323157393173">Diese Lieferoption ist nicht verfügbar. Wählen Sie eine andere Option aus.</translation>
<translation id="2889159643044928134">Nicht neu laden</translation>
<translation id="2900469785430194048">Beim Versuch, diese Webseite aufzurufen, hat Google Chrome das Arbeitsspeicherlimit erreicht.</translation>
<translation id="2909946352844186028">Eine Netzwerkänderung ist aufgetreten.</translation>
<translation id="2916038427272391327">Andere Programme schließen</translation>
<translation id="2922350208395188000">Das Serverzertifikat kann nicht überprüft werden.</translation>
+<translation id="2928905813689894207">Rechnungsadresse</translation>
<translation id="2948083400971632585">Sie können alle für eine Verbindung konfigurierten Proxys auf der Seite "Einstellungen" deaktivieren.</translation>
<translation id="2955913368246107853">Suchleiste schließen</translation>
<translation id="2958431318199492670">Die Netzwerkkonfiguration stimmt nicht mit dem ONC-Standard überein. Die Konfiguration wird unter Umständen nicht vollständig importiert.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Zum Herstellen 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 Google Chrome diese Zertifikate nicht bestätigen.</translation>
<translation id="2972581237482394796">&amp;Wiederholen</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="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="2991174974383378012">Datenfreigabe an Websites</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>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{mindestens 1 Inhalt auf synchronisierten Geräten}=1{1 Inhalt (und weitere auf synchronisierten Geräten)}other{# Inhalte (und weitere auf synchronisierten Geräten)}}</translation>
<translation id="3041612393474885105">Zertifikatinformationen</translation>
<translation id="3063697135517575841">Ihre Karte kann von Chrome zurzeit nicht bestätigt werden. Bitte versuchen Sie es später noch einmal.</translation>
+<translation id="3064966200440839136">Der Inkognitomodus wird beendet, um über eine externe Anwendung zu zahlen. Fortfahren?</translation>
<translation id="3093245981617870298">Sie sind offline.</translation>
<translation id="3105172416063519923">Geräte-ID:</translation>
<translation id="3109728660330352905">Sie sind nicht zum Aufrufen dieser Seite autorisiert.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Versuchen Sie, die Verbindungsdiagnose auszuführen.<ph name="END_LINK" /></translation>
<translation id="3145945101586104090">Fehler beim Dekodieren der Antwort</translation>
-<translation id="3149891296864842641">Versandoption</translation>
<translation id="3150653042067488994">Vorübergehender Serverfehler</translation>
+<translation id="3154506275960390542">Auf dieser Seite befindet sich ein Formular, das Daten möglicherweise unsicher überträgt. Gesendete Daten können während der Übertragung von anderen gelesen oder von Angreifern geändert werden, sodass der Server modifizierte Daten erhält.</translation>
<translation id="3157931365184549694">Wiederherstellen</translation>
<translation id="3167968892399408617">Seiten, die Sie sich auf Inkognito-Tabs ansehen, werden nach dem Schließen aller Inkognito-Tabs nicht in Ihrem Browserverlauf, Cookiespeicher oder Suchverlauf gespeichert. Ihre Lesezeichen und heruntergeladenen Dateien bleiben erhalten.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Ihre Zugriffsanfrage für diese Website konnte nicht an <ph name="NAME" /> gesendet werden. Bitte versuchen Sie es erneut.</translation>
<translation id="3355823806454867987">Proxy-Einstellungen ändern...</translation>
<translation id="3369192424181595722">Fehler bei der Uhrzeit</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> weitere Elemente…</translation>
<translation id="337363190475750230">Bereitstellung aufgehoben</translation>
<translation id="3377188786107721145">Fehler beim Parsen der Richtlinie</translation>
<translation id="3380365263193509176">Unbekannter Fehler</translation>
<translation id="3380864720620200369">Client-ID:</translation>
<translation id="3391030046425686457">Lieferadresse</translation>
+<translation id="3395827396354264108">Abholoption</translation>
<translation id="340013220407300675">Unbefugte Dritte könnten versuchen, Ihre Informationen von <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> zu stehlen, z. B. Passwörter, Nachrichten oder Kreditkartendaten.</translation>
<translation id="3422248202833853650">Versuchen Sie, andere Programme zu beenden, um Speicher freizugeben.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> ist momentan nicht erreichbar.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Abrufintervall:</translation>
<translation id="3462200631372590220">Erweiterte Informationen ausblenden</translation>
+<translation id="3467763166455606212">Name des Karteninhabers erforderlich</translation>
+<translation id="3478058380795961209">Ablaufmonat</translation>
<translation id="3479539252931486093">Geschah dies unerwartet? <ph name="BEGIN_LINK" />Informieren Sie uns<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Jetzt nicht</translation>
<translation id="348000606199325318">Absturz-ID <ph name="CRASH_LOCAL_ID" /> (Server-ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Wir können deinen Vater bzw. deine Mutter momentan nicht erreichen. Bitte versuche es später erneut.</translation>
<translation id="3528171143076753409">Serverzertifikat ist nicht vertrauenswürdig.</translation>
-<translation id="3538531656504267329">Ungültiges Ablaufjahr</translation>
<translation id="3539171420378717834">Kopie dieser Karte auf diesem Gerät speichern</translation>
<translation id="3542684924769048008">Passwort verwenden für:</translation>
<translation id="3549644494707163724">Alle synchronisierten Daten mit Ihrer eigenen Synchronisierungspassphrase verschlüsseln</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Details ausblenden</translation>
<translation id="3587482841069643663">Alle</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Geben Sie ein gültiges Ablaufdatum ein</translation>
<translation id="36224234498066874">Browserdaten löschen...</translation>
<translation id="362276910939193118">Gesamtverlauf anzeigen</translation>
<translation id="3623476034248543066">Wert zeigen</translation>
@@ -311,7 +323,6 @@
<translation id="3693415264595406141">Passwort:</translation>
<translation id="3696411085566228381">keine</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Wählen Sie eine Versandadresse aus, um die Versandmethoden und -anforderungen zu sehen.</translation>
<translation id="370665806235115550">Wird geladen...</translation>
<translation id="3712624925041724820">Lizenzen aufgebraucht</translation>
<translation id="3714780639079136834">Mobile Daten oder WLAN aktivieren</translation>
@@ -320,6 +331,7 @@
<translation id="3739623965217189342">Von Ihnen kopierter Link</translation>
<translation id="375403751935624634">Aufgrund eines Serverfehlers ist die Ãœbersetzung fehlgeschlagen.</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="3787705759683870569">Ablaufdatum: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Falls Sie einen Proxyserver verwenden...</translation>
<translation id="3828924085048779000">Eine leere Passphrase ist nicht zulässig.</translation>
<translation id="3845539888601087042">Der Verlauf für alle Geräte, auf denen Sie angemeldet sind, wird angezeigt. <ph name="BEGIN_LINK" />Weitere Informationen.<ph name="END_LINK" /></translation>
@@ -355,7 +367,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Möchten Sie, dass Chromium diese Karte speichert?</translation>
<translation id="4171400957073367226">Ungültige Bestätigungssignatur</translation>
-<translation id="4176463684765177261">Deaktiviert</translation>
<translation id="4196861286325780578">&amp;Verschieben wiederholen</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Firewall und Antivirenkonfiguration prüfen<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{keine}=1{1 App ($1)}=2{2 Apps ($1, $2)}other{# Apps ($1, $2, $3)}}</translation>
@@ -382,11 +393,11 @@
<translation id="4406896451731180161">Suchergebnisse</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> hat Ihr Anmeldezertifikat nicht akzeptiert oder es wurde keines bereitgestellt.</translation>
<translation id="443673843213245140">Die Proxy-Nutzung ist deaktiviert, es ist jedoch eine explizite Proxy-Konfiguration festgelegt.</translation>
-<translation id="4446242550670694251">Sie können jetzt privat surfen. Für andere Personen, die dieses Gerät nutzen, sind Ihre Aktivitäten nicht sichtbar.</translation>
<translation id="4492190037599258964">Suchergebnisse für "<ph name="SEARCH_STRING" />"</translation>
<translation id="4506176782989081258">Fehler bei der Überprüfung: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Kontakt mit dem Systemadministrator aufnehmen</translation>
<translation id="450710068430902550">Datenfreigabe an Administrator</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="4522570452068850558">Details</translation>
<translation id="4558551763791394412">Deaktivieren Sie Ihre Erweiterungen.</translation>
<translation id="457875822857220463">Lieferung</translation>
@@ -416,6 +427,7 @@
<translation id="4816492930507672669">An Seite anpassen</translation>
<translation id="483020001682031208">Keine Physical Web-Seiten verfügbar</translation>
<translation id="4850886885716139402">Anzeigen</translation>
+<translation id="4854362297993841467">Diese Lieferoption ist nicht verfügbar. Bitte wählen Sie eine andere Option aus.</translation>
<translation id="4858792381671956233">Du hast deine Eltern gefragt, ob du diese Website besuchen darfst</translation>
<translation id="4880827082731008257">Im Verlauf suchen</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -423,7 +435,6 @@
<translation id="4923417429809017348">Diese Seite wurde von einer unbekannten Sprache in <ph name="LANGUAGE_LANGUAGE" /> übersetzt.</translation>
<translation id="4923459931733593730">Zahlung</translation>
<translation id="4926049483395192435">Angabe erforderlich</translation>
-<translation id="4941291666397027948">* Pflichtfeld</translation>
<translation id="495170559598752135">Aktionen</translation>
<translation id="4958444002117714549">Liste einblenden</translation>
<translation id="4962322354953122629">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird von Chrome nicht als vertrauenswürdig eingestuft. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -438,6 +449,7 @@
<translation id="5045550434625856497">Falsches Passwort</translation>
<translation id="5056549851600133418">Artikel für Sie</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Proxyadresse prüfen<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Keine Cookies}=1{1 Website verwendet Cookies. }other{# Websites verwenden Cookies. }}</translation>
<translation id="5087286274860437796">Das Serverzertifikat ist zurzeit ungültig.</translation>
<translation id="5087580092889165836">Karte hinzufügen</translation>
<translation id="5089810972385038852">Bundesstaat/-land</translation>
@@ -460,10 +472,8 @@
<translation id="5300589172476337783">Anzeigen</translation>
<translation id="5308689395849655368">Die Absturzberichtsfunktion ist deaktiviert.</translation>
<translation id="5317780077021120954">Speichern</translation>
-<translation id="5326702247179446998">Empfänger erforderlich</translation>
<translation id="5327248766486351172">Name</translation>
<translation id="5337705430875057403">Angreifer auf <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 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="53553865750799677">Nicht unterstützte Abholadresse. Wählen Sie eine andere Adresse aus.</translation>
<translation id="5359637492792381994">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. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Fehler beim Speichern der Richtlinieneinstellungen</translation>
<translation id="5386426401304769735">Die Zertifikatskette für diese Website enthält ein Zertifikat mit SHA-1-Signatur.</translation>
@@ -489,8 +499,8 @@
<translation id="5544037170328430102">Auf einer in <ph name="SITE" /> eingebetteten Seite wird Folgendes angezeigt:</translation>
<translation id="5556459405103347317">Neu laden</translation>
<translation id="5565735124758917034">Aktiv</translation>
+<translation id="5571083550517324815">Diese Abholadresse wird nicht unterstützt. Bitte wählen Sie eine andere Adresse aus.</translation>
<translation id="5572851009514199876">Melden Sie sich zuerst in Chrome an, damit überprüft werden kann, ob Sie auf diese Website zugreifen dürfen.</translation>
-<translation id="5575380383496039204">Nicht unterstützte Lieferadresse. 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="560412284261940334">Verwaltung wird nicht unterstützt.</translation>
<translation id="5610142619324316209">Verbindung prüfen</translation>
@@ -506,7 +516,8 @@
<translation id="5710435578057952990">Die Identität dieser Website wurde nicht verifiziert.</translation>
<translation id="5720705177508910913">Aktueller Nutzer</translation>
<translation id="5732392974455271431">Deine Eltern können die Blockierung aufheben</translation>
-<translation id="57586589942790530">Ungültige Kartennummer</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="5784606427469807560">Beim Bestätigen Ihrer Karte ist ein Problem aufgetreten. Überprüfen Sie Ihre Internetverbindung und versuchen Sie 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>
@@ -519,22 +530,20 @@
<translation id="5869405914158311789">Diese Website ist nicht erreichbar</translation>
<translation id="5869522115854928033">Gespeicherte Passwörter</translation>
<translation id="5872918882028971132">Vorschläge für Eltern</translation>
-<translation id="587760065310675640">Nicht unterstützte Versandadresse. Wählen Sie eine andere Adresse aus.</translation>
<translation id="5901630391730855834">Gelb</translation>
-<translation id="59174027418879706">Aktiviert</translation>
<translation id="5926846154125914413">Eventuell verlieren Sie den Zugriff auf Premiuminhalte von einigen Websites.</translation>
<translation id="5959728338436674663"><ph name="BEGIN_WHITEPAPER_LINK" />Ich möchte automatisch einige Systeminformationen und Seiteninhalte an Google senden<ph name="END_WHITEPAPER_LINK" />, um bei der Erfassung schädlicher Apps und Websites zu helfen. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Woche</translation>
<translation id="5967867314010545767">Aus Verlauf entfernen</translation>
<translation id="5975083100439434680">Verkleinern</translation>
+<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="5990559369517809815">Anfragen an den Server wurden durch eine Erweiterung blockiert.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Karten- und Adressoptionen stammen von Chrome. <ph name="BEGIN_LINK" />Sie können diese in den Einstellungen verwalten.<ph name="END_LINK" /></translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Seite 1}other{Seite #}}</translation>
<translation id="6017514345406065928">Grün</translation>
+<translation id="6027201098523975773">Geben Sie einen Namen ein</translation>
<translation id="6040143037577758943">Schließen</translation>
-<translation id="604124094241169006">Automatisch</translation>
<translation id="6042308850641462728">Mehr</translation>
<translation id="6060685159320643512">Vorsichtig, diese Experimente können gefährlich sein!</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{keine}=1{1}other{#}}</translation>
@@ -542,9 +551,10 @@
anderen Netzwerkgeräte neu.</translation>
<translation id="614940544461990577">Versuchen Sie Folgendes:</translation>
<translation id="6151417162996330722">Die Gültigkeitsdauer des Serverzertifikats ist zu lang.</translation>
-<translation id="615643356032862689">Die heruntergeladenen Dateien und Lesezeichen werden gespeichert.</translation>
+<translation id="6157877588268064908">Wählen Sie eine Adresse aus, um Versandoptionen und -anforderungen zu sehen</translation>
<translation id="6165508094623778733">Weitere Informationen</translation>
<translation id="6177128806592000436">Die Verbindung zu dieser Website ist nicht sicher</translation>
+<translation id="6184817833369986695">(Kohorte: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Bitte überprüfen Sie Ihre Internetverbindung.</translation>
<translation id="6218753634732582820">Adresse aus Chromium entfernen?</translation>
<translation id="6251924700383757765">Datenschutzerklärung</translation>
@@ -553,6 +563,8 @@
<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="6276112860590028508">Seiten von Ihrer Leseliste werden hier angezeigt</translation>
+<translation id="6280223929691119688">Die Lieferadresse wird nicht unterstützt. Bitte wählen Sie eine andere Adresse aus.</translation>
<translation id="6282194474023008486">Postleitzahl</translation>
<translation id="6290238015253830360">Hier werden Ihre vorgeschlagenen Artikel angezeigt</translation>
<translation id="6305205051461490394"><ph name="URL" /> ist nicht erreichbar.</translation>
@@ -574,7 +586,6 @@
<translation id="6417515091412812850">Überprüfung, ob das Zertifikat zurückgerufen wurde, nicht möglich</translation>
<translation id="6433490469411711332">Kontaktdaten bearbeiten</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> hat die Verbindung abgelehnt.</translation>
-<translation id="6443118737398455446">Ungültiges Ablaufdatum</translation>
<translation id="6446608382365791566">Weitere Informationen hinzufügen</translation>
<translation id="6451458296329894277">Erneute Formular-Übermittlung bestätigen</translation>
<translation id="6456339708790392414">Bezahlung</translation>
@@ -582,10 +593,8 @@
<translation id="6462969404041126431">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. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">Geräterichtlinien</translation>
<translation id="6477321094435799029">Chrome hat auf dieser Seite ungewöhnlichen Code erfasst und diese Seite daher blockiert, um Ihre personenbezogenen Daten wie Passwörter, Telefonnummern oder Kreditkarteninformationen zu schützen.</translation>
-<translation id="6477460825583319731">Ungültige E-Mail-Adresse</translation>
<translation id="6489534406876378309">Hochladen von Abstürzen starten</translation>
<translation id="6508722015517270189">Chrome neu starten</translation>
-<translation id="6525462735697194615">Ungültiger Ablaufmonat</translation>
<translation id="6529602333819889595">&amp;Löschen wiederholen</translation>
<translation id="6534179046333460208">Physical Web-Vorschläge</translation>
<translation id="6550675742724504774">Optionen</translation>
@@ -600,7 +609,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" />-Suche</translation>
<translation id="6644283850729428850">Diese Richtlinie ist veraltet.</translation>
<translation id="6652240803263749613">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird vom Betriebssystem Ihres Computers nicht als vertrauenswürdig eingestuft. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="6665267558048410100">Diese Versandoption ist nicht verfügbar. Wählen Sie eine andere Option aus.</translation>
<translation id="6671697161687535275">Vorschlag für das Formular aus Chromium entfernen?</translation>
<translation id="6685834062052613830">Abmelden und Einrichtung abschließen</translation>
<translation id="6710213216561001401">Zurück</translation>
@@ -608,13 +616,13 @@
<translation id="6711464428925977395">Mit dem Proxyserver ist ein Problem aufgetreten oder die Adresse ist falsch.</translation>
<translation id="6727102863431372879">Festlegen</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{keine}=1{1 Inhalt}other{# Inhalte}}</translation>
-<translation id="6743044928064272573">Abholoption</translation>
<translation id="674375294223700098">Fehler wegen unbekanntem Serverzertifikat</translation>
<translation id="6753269504797312559">Wert der Richtlinie</translation>
<translation id="6757797048963528358">Ihr Gerät ist im Ruhemodus.</translation>
<translation id="6778737459546443941">Dein Elternteil hat die Berechtigung noch nicht erteilt</translation>
<translation id="6810899417690483278">Personalisierungs-ID</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Fehler beim Laden der Regionsdaten</translation>
<translation id="6831043979455480757">Ãœbersetzen</translation>
<translation id="6839929833149231406">Stadtteil</translation>
<translation id="6874604403660855544">&amp;Hinzufügen wiederholen</translation>
@@ -622,6 +630,7 @@
<translation id="6895330447102777224">Ihre Karte wurde bestätigt</translation>
<translation id="6897140037006041989">User-Agent</translation>
<translation id="6915804003454593391">Nutzer:</translation>
+<translation id="6948701128805548767">Wählen Sie eine Adresse aus, um Abholoptionen und -anforderungen zu sehen</translation>
<translation id="6957887021205513506">Das Zertifikat des Servers ist möglicherweise eine Fälschung.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Gerät</translation>
@@ -629,7 +638,6 @@
<translation id="6973656660372572881">Sowohl feste Proxyserver als auch eine PAC-Skript-URL sind festgelegt.</translation>
<translation id="6989763994942163495">Erweiterte Einstellungen anzeigen</translation>
<translation id="7000990526846637657">Keine Verlaufseinträge gefunden</translation>
-<translation id="7001663382399377034">Empfänger hinzufügen</translation>
<translation id="7009986207543992532">Sie haben versucht, <ph name="DOMAIN" /> aufzurufen. Der Server hat jedoch ein Zertifikat präsentiert, dessen Gültigkeitsdauer zu lang ist, um vertrauenswürdig zu sein.<ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Möglicherweise sind in Ihrem Google-Konto noch andere Formen des Browserverlaufs unter <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> vorhanden</translation>
@@ -640,12 +648,15 @@
<translation id="7088615885725309056">Älter</translation>
<translation id="7090678807593890770">Auf Google nach <ph name="LINK" /> suchen</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="7138472120740807366">Lieferoption</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7155487117670177674">Zahlung nicht sicher</translation>
<translation id="7179921470347911571">Jetzt neu starten</translation>
<translation id="7180611975245234373">Aktualisieren</translation>
<translation id="7182878459783632708">Keine Richtlinien festgelegt</translation>
<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="7210863904660874423"><ph name="HOST_NAME" /> erfüllt die Sicherheitsstandards nicht.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /> zu diesem Problem.</translation>
@@ -674,7 +685,6 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="7424977062513257142">Auf einer in dieser Webseite eingebetteten Seite wird Folgendes angezeigt:</translation>
<translation id="7441627299479586546">Falsche(r) Nutzername/Domain der Richtlinie</translation>
<translation id="7444046173054089907">Diese Website ist blockiert</translation>
-<translation id="7444238235002594607">Wählen Sie eine Abholadresse aus, um die Abholmethoden und -anforderungen zu sehen.</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 Inhaberschaft 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="7451311239929941790"><ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /> zu diesem Problem.</translation>
<translation id="7460163899615895653">Ihre zuletzt geöffneten Tabs von anderen Geräten erscheinen hier</translation>
@@ -718,6 +728,7 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="7755287808199759310">Deine Eltern können die Blockierung aufheben</translation>
<translation id="7758069387465995638">Möglicherweise wurde die Verbindung von einer Firewall oder Antivirensoftware blockiert.</translation>
<translation id="7761701407923456692">Das Serverzertifikat stimmt nicht mit der URL überein.</translation>
+<translation id="7763386264682878361">Zahlungsmanifest-Parser</translation>
<translation id="7764225426217299476">Adresse hinzufügen</translation>
<translation id="777702478322588152">Präfektur</translation>
<translation id="7791543448312431591">Hinzufügen</translation>
@@ -731,6 +742,7 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="785549533363645510">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="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Prüfen Sie Ihren CVC und versuchen Sie es dann erneut.</translation>
+<translation id="79338296614623784">Geben Sie eine gültige Telefonnummer ein</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Serverzertifikat ist noch nicht gültig.</translation>
<translation id="7942349550061667556">Rot</translation>
@@ -750,6 +762,7 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="8088680233425245692">Der Artikel kann nicht angezeigt werden.</translation>
<translation id="8089520772729574115">weniger als 1 MB</translation>
<translation id="8091372947890762290">Aktivierung auf dem Server steht noch aus.</translation>
+<translation id="8118489163946903409">Zahlungsmethode</translation>
<translation id="8131740175452115882">Bestätigen</translation>
<translation id="8134994873729925007">Die <ph name="BEGIN_ABBR" />DNS-Adresse<ph name="END_ABBR" /> des Servers von <ph name="HOST_NAME" /> wurde nicht gefunden.</translation>
<translation id="8149426793427495338">Ihr Computer ist im Ruhemodus.</translation>
@@ -775,6 +788,7 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="8349305172487531364">Lesezeichenleiste</translation>
<translation id="8363502534493474904">Flugmodus ausschalten</translation>
<translation id="8364627913115013041">Nicht eingerichtet</translation>
+<translation id="8368476060205742148">Google Play-Dienste</translation>
<translation id="8380941800586852976">Schädlich</translation>
<translation id="8382348898565613901">Hier werden Ihre kürzlich aufgerufenen Lesezeichen angezeigt</translation>
<translation id="8398259832188219207">Absturzbericht hochgeladen am <ph name="UPLOAD_TIME" /></translation>
@@ -783,32 +797,30 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="8428213095426709021">Einstellungen</translation>
<translation id="8433057134996913067">Dadurch werden Sie von den meisten Websites abgemeldet.</translation>
<translation id="8437238597147034694">&amp;Verschieben rückgängig machen</translation>
-<translation id="8456681095658380701">Ungültiger Name</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 Kreditkarte}other{# Kreditkarten}}</translation>
<translation id="8483780878231876732">Melden Sie sich in Chrome an, um in Ihrem Google-Konto gespeicherte Kreditkarten zu verwenden</translation>
<translation id="8488350697529856933">Gilt für</translation>
-<translation id="8492969205326575646">Nicht unterstützter Kartentyp</translation>
<translation id="8498891568109133222">Die Antwort von <ph name="HOST_NAME" /> hat zu lange gedauert.</translation>
<translation id="852346902619691059">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird vom Betriebssystem Ihres Geräts nicht als vertrauenswürdig eingestuft. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="8532105204136943229">Ablaufjahr</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="8553075262323480129">Die Ãœbersetzung ist fehlgeschlagen, weil die Sprache der Seite nicht ermittelt werden konnte.</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="8570229484593575558">Diese Informationen |werden nicht gespeichert|:#Ihr Browserverlauf#Ihre Suchanfragen#Cookiedaten</translation>
<translation id="8571890674111243710">Seite wird in folgende Sprache übersetzt: <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Ihre Aktivitäten |sind eventuell weiterhin sichtbar| für:#Von Ihnen besuchte Websites#Ihren Arbeitgeber#Ihren Internetanbieter</translation>
<translation id="858637041960032120">Weitere Nummer
</translation>
<translation id="859285277496340001">In dem Zertifikat ist kein Mechanismus angegeben, mit dem geprüft werden kann, ob es zurückgerufen wurde.</translation>
<translation id="8620436878122366504">Deine Eltern haben die Berechtigung noch nicht erteilt</translation>
<translation id="8647750283161643317">Alle auf Standardeinstellung zurücksetzen</translation>
<translation id="8703575177326907206">Die Verbindung zu <ph name="DOMAIN" /> ist nicht verschlüsselt.</translation>
+<translation id="8718314106902482036">Zahlung nicht abgeschlossen</translation>
<translation id="8725066075913043281">Erneut versuchen</translation>
<translation id="8728672262656704056">Sie haben den Inkognitomodus aktiviert</translation>
<translation id="8730621377337864115">Fertig</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="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="8759274551635299824">Diese Karte ist abgelaufen</translation>
<translation id="8790007591277257123">&amp;Löschen wiederholen</translation>
-<translation id="8798099450830957504">Standardeinstellung</translation>
<translation id="8800988563907321413">Hier werden Ihre Vorschläge in der Nähe angezeigt</translation>
<translation id="8820817407110198400">Lesezeichen</translation>
<translation id="883848425547221593">Andere Lesezeichen</translation>
@@ -818,6 +830,7 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="8866481888320382733">Fehler beim Parsen der Richtlinieneinstellungen</translation>
<translation id="8866959479196209191">Auf dieser Seite wird Folgendes angezeigt:</translation>
<translation id="8870413625673593573">Kürzlich geschlossen</translation>
+<translation id="8874824191258364635">Geben Sie eine gültige Kartennummer ein</translation>
<translation id="8876793034577346603">Fehler beim Parsen der Netzwerkkonfiguration</translation>
<translation id="8877192140621905067">Nach erfolgter Bestätigung werden die Kartendetails an diese Website weitergegeben</translation>
<translation id="8889402386540077796">Farbton</translation>
@@ -827,7 +840,6 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="8931333241327730545">Möchten Sie diese Karte in Ihrem Google-Konto speichern?</translation>
<translation id="8932102934695377596">Ihre Uhr geht nach.</translation>
<translation id="8954894007019320973">(Fortsetzung)</translation>
-<translation id="895548565263634352">Lesen Sie Artikel von <ph name="ARTICLE_PUBLISHER" /> und <ph name="OTHER_ARTICLE_COUNT" /> weitere</translation>
<translation id="8971063699422889582">Das Serverzertifikat ist abgelaufen.</translation>
<translation id="8986494364107987395">Nutzungsstatistiken und Absturzberichte automatisch an Google senden</translation>
<translation id="8987927404178983737">Monat</translation>
@@ -845,7 +857,6 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="9068849894565669697">Farbe auswählen</translation>
<translation id="9076283476770535406">Eventuell enthält sie nicht jugendfreie Inhalte</translation>
<translation id="9078964945751709336">Weitere Informationen erforderlich</translation>
-<translation id="9094175695478007090">Zahlungs-App kann nicht gestartet werden.</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="9137013805542155359">Original anzeigen</translation>
<translation id="9137248913990643158">Melden Sie sich in Chrome an, bevor Sie diese App nutzen.</translation>
diff --git a/chromium/components/strings/components_strings_el.xtb b/chromium/components/strings/components_strings_el.xtb
index 50f6146ea0f..2742d0f9b52 100644
--- a/chromium/components/strings/components_strings_el.xtb
+++ b/chromium/components/strings/components_strings_el.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="el">
<translation id="1008557486741366299">Όχι Ï„ÏŽÏα</translation>
<translation id="1015730422737071372">ΚαταχωÏίστε επιπλέον λεπτομέÏειες</translation>
+<translation id="1021110881106174305">Αποδεκτές κάÏτες</translation>
<translation id="1032854598605920125">ΠεÏιστÏοφή Ï€Ïος τα δεξιά</translation>
<translation id="1038842779957582377">άγνωστο όνομα</translation>
<translation id="1050038467049342496">Κλείστε τις άλλες εφαÏμογές</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">ΑπόκÏυψη τιμής</translation>
<translation id="1228893227497259893">Εσφαλμένο αναγνωÏιστικό οντότητας</translation>
<translation id="1232569758102978740">ΧωÏίς τίτλο</translation>
+<translation id="1263231323834454256">Λίστα ανάγνωσης</translation>
<translation id="1264126396475825575">ΚαταγÏάφηκαν αναφοÏές σφαλμάτων <ph name="CRASH_TIME" /> (δεν έχουν ακόμη μεταφοÏτωθεί ή παÏαβλεφθεί)</translation>
<translation id="1285320974508926690">Îα μην γίνεται ποτέ μετάφÏαση Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… ιστότοπου</translation>
<translation id="129553762522093515">Έκλεισαν Ï€Ïόσφατα</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Ρυθμίσεις αυτόματης συμπλήÏωσης Chromium…</translation>
<translation id="1374468813861204354">Ï€Ïοτάσεις</translation>
<translation id="1375198122581997741">Σχετικά με την έκδοση</translation>
+<translation id="1377321085342047638">ΑÏ.κάÏτας</translation>
<translation id="139305205187523129">Ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> δεν έστειλε δεδομένα.</translation>
<translation id="1407135791313364759">Άνοιγμα όλων</translation>
<translation id="1413809658975081374">Σφάλμα αποÏÏήτου</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">ΙστοÏικό</translation>
<translation id="1645368109819982629">Μη υποστηÏιζόμενο Ï€Ïωτόκολλο</translation>
<translation id="1656489000284462475">ΠαÏαλαβή</translation>
+<translation id="1663943134801823270">Οι κάÏτες και οι διευθÏνσεις Ï€ÏοέÏχονται από το Chrome. ΜποÏείτε να τις διαχειÏιστείτε στις <ph name="BEGIN_LINK" />Ρυθμίσεις<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">Κανονικά, ο ιστότοπος <ph name="SITE" /> χÏησιμοποιεί κÏυπτογÏάφηση για να Ï€ÏοστατεÏει τα στοιχεία σας. Όταν το Google Chrome επιχείÏησε Ï€Ïόσφατα να συνδεθεί στο <ph name="SITE" />, ο ιστότοπος ανταποκÏίθηκε δημιουÏγώντας ασυνήθιστα και εσφαλμένα διαπιστευτήÏια. Αυτό μποÏεί να συμβεί όταν κάποιος εισβολέας Ï€Ïοσπαθεί να υποκÏιθεί ότι είναι ο ιστότοπος <ph name="SITE" /> ή όταν κάποια οθόνη σÏνδεσης Wi-Fi έχει διακόψει τη σÏνδεσή σας. Τα στοιχεία σας εξακολουθοÏν να είναι ασφαλή επειδή το Google Chrome διέκοψε τη σÏνδεση Ï€Ïιν από την ανταλλαγή δεδομένων.</translation>
<translation id="168328519870909584">Οι εισβολείς που βÏίσκονται αυτήν τη στιγμή στον ιστότοπο <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />ενδέχεται να επιχειÏήσουν να εγκαταστήσουν επικίνδυνες εφαÏμογές στη συσκευή σας, οι οποίες μποÏοÏν να υποκλέψουν ή να διαγÏάψουν τα δεδομένα σας (για παÏάδειγμα, φωτογÏαφίες, κωδικοÏÏ‚ Ï€Ïόσβασης, μηνÏματα και στοιχεία πιστωτικών καÏτών).</translation>
<translation id="168841957122794586">Το πιστοποιητικό διακομιστή πεÏιέχει ένα αδÏναμο κÏυπτογÏαφικό κλειδί.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Για να επισκεφτείτε αυτήν τη σελίδα, χÏειάζεστε άδεια από τον διαχειÏιστή <ph name="NAME" /></translation>
+<translation id="1721424275792716183">* Το πεδίο είναι υποχÏεωτικό</translation>
<translation id="1728677426644403582">Βλέπετε την πηγή μιας ιστοσελίδας</translation>
+<translation id="173080396488393970">Αυτός ο Ï„Ïπος κάÏτας δεν υποστηÏίζεται</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">ΠÏοσπαθήστε να επικοινωνήσετε με το διαχειÏιστή συστήματος.</translation>
+<translation id="1740951997222943430">Εισαγάγετε έναν έγκυÏο μήνα λήξης</translation>
<translation id="1745358365027406341">Λήψη σελίδας αÏγότεÏα</translation>
<translation id="17513872634828108">Ανοικτές καÏτέλες</translation>
<translation id="1753706481035618306">ΑÏιθμός σελίδας</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">ΕνημεÏώστε την κωδική φÏάση Ï€Ïόσβασης συγχÏονισμοÏ.</translation>
<translation id="1787142507584202372">Οι ανοιχτές καÏτέλες σας εμφανίζονται εδώ</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Επιλέξτε μια διεÏθυνση παÏάδοσης, για να δείτε τις απαιτήσεις και τις μεθόδους παÏάδοσης.</translation>
+<translation id="1803264062614276815">Όνομα κατόχου κάÏτας</translation>
<translation id="1803678881841855883">Η Ασφαλής πεÏιήγηση Google <ph name="BEGIN_LINK" />εντόπισε κακόβουλο Ï€ÏόγÏαμμα<ph name="END_LINK" /> Ï€Ïόσφατα στον ιστότοπο <ph name="SITE" />. Οι ιστότοποι που είναι συνήθως ασφαλείς Ï€Ïοσβάλλονται οÏισμένες φοÏές από κακόβουλο λογισμικό. Το κακόβουλο λογισμικό Ï€ÏοέÏχεται από τον κεντÏικό υπολογιστή <ph name="SUBRESOURCE_HOST" />, γνωστό διανομέα κακόβουλου λογισμικοÏ. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">ΠÏοστέθηκε <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Μη έγκυÏο αίτημα ή παÏάμετÏοι αιτήματος</translation>
<translation id="1826516787628120939">Έλεγχος</translation>
<translation id="1834321415901700177">Αυτός ο ιστότοπος πεÏιέχει κακόβουλα Ï€ÏογÏάμματα</translation>
<translation id="1842969606798536927">ΠληÏωμή</translation>
-<translation id="1864455488461349376">Επιλογή παÏάδοσης</translation>
<translation id="1871208020102129563">Ο διακομιστής μεσολάβησης έχει Ïυθμιστεί να χÏησιμοποιεί διακομιστές μεσολάβησης και όχι μια διεÏθυνση URL σεναÏίου .pac.</translation>
<translation id="1871284979644508959">ΑπαιτοÏμενο πεδίο</translation>
<translation id="187918866476621466">Άνοιγμα σελίδων εκκίνησης</translation>
<translation id="1883255238294161206">ΣÏμπτυξη λίστας</translation>
<translation id="1898423065542865115">ΦιλτÏάÏισμα</translation>
<translation id="194030505837763158">Μετάβαση στο σÏνδεσμο <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Αποδεκτές κάÏτες</translation>
<translation id="1962204205936693436">Σελιδοδείκτες <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Σφάλμα σειÏιοποίησης</translation>
<translation id="1974060860693918893">ΣÏνθετες</translation>
<translation id="1978555033938440688">Έκδοση υλικολογισμικοÏ</translation>
+<translation id="1995859865337580572">ΕπαληθεÏστε τον κωδικό CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{και άλλο 1 άτομο}other{και άλλα # άτομα}}</translation>
-<translation id="2020194265157481222">Απαιτείται το όνομα στην κάÏτα</translation>
<translation id="2025186561304664664">Ο διακομιστής μεσολάβησης έχει Ïυθμιστεί σε αυτόματη διαμόÏφωση.</translation>
<translation id="2030481566774242610">Μήπως εννοείτε <ph name="LINK" />;</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Ελέγξτε το διακομιστή μεσολάβησης και το τείχος Ï€Ïοστασίας<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">ΣήμεÏα</translation>
<translation id="2154054054215849342">Ο συγχÏονισμός δεν είναι διαθέσιμος για τον τομέα σας</translation>
<translation id="2154484045852737596">ΕπεξεÏγασία κάÏτας</translation>
-<translation id="2156993118928861787">Μη έγκυÏη διεÏθυνση</translation>
<translation id="2166049586286450108">ΠλήÏης Ï€Ïόσβαση διαχειÏιστή</translation>
<translation id="2166378884831602661">Αυτός ο ιστότοπος δεν μποÏεί να Ï€ÏοσφέÏει ασφαλή σÏνδεση</translation>
<translation id="2181821976797666341">Πολιτικές</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 διεÏθυνση}other{# διευθÏνσεις}}</translation>
+<translation id="2202020181578195191">Εισαγάγετε ένα έγκυÏο έτος λήξης</translation>
<translation id="2212735316055980242">Η πολιτική δε βÏέθηκε</translation>
<translation id="2213606439339815911">Ανάκτηση καταχωÏίσεων…</translation>
<translation id="2230458221926704099">ΕπιδιοÏθώστε τη σÏνδεσή σας χÏησιμοποιώντας την <ph name="BEGIN_LINK" />εφαÏμογή διαγνωστικών ελέγχων<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Η Ï€Ïόσβασή σας στο διαδίκτυο είναι αποκλεισμένη</translation>
<translation id="230155334948463882">Îέα κάÏτα;</translation>
<translation id="2305919008529760154">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του μποÏεί να εκδόθηκε παÏάνομα. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Οι επιλογές κάÏτας και διεÏθυνσης Ï€ÏοέÏχονται από τον ΛογαÏιασμό σας Google (<ph name="ACCOUNT_EMAIL" />) και το Chrome. ΜποÏείτε να διαχειÏιστείτε αυτές τις επιλογές στις <ph name="BEGIN_LINK" />Ρυθμίσεις<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535">Ο τομέας <ph name="DOMAIN" /> απαιτεί ένα όνομα χÏήστη και έναν κωδικό Ï€Ïόσβασης.</translation>
<translation id="2318774815570432836">Δεν μποÏείτε να επισκεφτείτε τον ιστότοπο <ph name="SITE" /> αυτήν τη στιγμή γιατί ο ιστότοπος χÏησιμοποιεί HSTS. Τα σφάλματα δικτÏου και οι επιθέσεις είναι συνήθως Ï€ÏοσωÏινά, συνεπώς αυτή η σελίδα πιθανότατα θα λειτουÏγήσει αÏγότεÏα. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Άλλοι σελιδοδείκτες</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">ΠÏοεπιλογή επιχείÏησης</translation>
<translation id="2386255080630008482">Το πιστοποιητικό του διακομιστή ανακλήθηκε.</translation>
<translation id="2392959068659972793">Εμφάνιση πολιτικών χωÏίς τιμή που να έχει οÏιστεί.</translation>
+<translation id="239429038616798445">Αυτός ο Ï„Ïόπος αποστολής δεν είναι διαθέσιμος. Δοκιμάστε έναν άλλο Ï„Ïόπο.</translation>
<translation id="2396249848217231973">&amp;ΑναίÏεση διαγÏαφής</translation>
<translation id="2460160116472764928">Η ασφαλής πεÏιήγηση Google <ph name="BEGIN_LINK" />εντόπισε κακόβουλο Ï€ÏόγÏαμμα<ph name="END_LINK" /> Ï€Ïόσφατα στον ιστότοπο <ph name="SITE" />. Οι ιστότοποι που είναι ασφαλείς υπό φυσιολογικές συνθήκες μεÏικές φοÏές Ï€Ïοσβάλλονται από κακόβουλα λογισμικά. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">ΣυμπλήÏωση</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Îα εκτελέσετε τον Διαγνωστικό έλεγχο δικτÏου<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Μη έγκυÏη διεÏθυνση URL αναζήτησης.</translation>
<translation id="2491120439723279231">Το πιστοποιητικό του διακομιστή πεÏιέχει σφάλματα.</translation>
-<translation id="24943777258388405">Μη έγκυÏος αÏιθμός τηλεφώνου</translation>
<translation id="2495083838625180221">Συντακτικός αναλυτής JSON</translation>
<translation id="2495093607237746763">Εάν επιλεγεί, το Chromium θα αποθηκεÏσει ένα αντίγÏαφο της κάÏτας σας σε αυτήν τη συσκευή για ταχÏτεÏη συμπλήÏωση φοÏμών.</translation>
<translation id="2498091847651709837">ΣάÏωση νέας κάÏτας</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027">Ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> έστειλε μια μη έγκυÏη απόκÏιση.</translation>
<translation id="2552545117464357659">ÎεότεÏη</translation>
<translation id="2556876185419854533">&amp;ΑναίÏεση επεξεÏγασίας</translation>
+<translation id="2587730715158995865">Από <ph name="ARTICLE_PUBLISHER" />. Διαβάστε αυτό το άÏθÏο και <ph name="OTHER_ARTICLE_COUNT" /> ακόμα ιστοÏίες.</translation>
<translation id="2587841377698384444">ΑναγνωÏιστικό API καταλόγου:</translation>
<translation id="2597378329261239068">Αυτό το έγγÏαφο Ï€ÏοστατεÏεται με κωδικό Ï€Ïόσβασης. ΠληκτÏολογήστε έναν κωδικό Ï€Ïόσβασης.</translation>
<translation id="2609632851001447353">ΠαÏαλλαγές</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Îα εκτελέσετε τα Διαγνωστικά στοιχεία συνδεσιμότητας<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">ΟK</translation>
<translation id="2742870351467570537">ΚατάÏγηση επιλεγμένων στοιχείων</translation>
+<translation id="277133753123645258">ΤÏόπος αποστολής</translation>
<translation id="277499241957683684">Λείπει κάποιο αÏχείο συσκευής</translation>
<translation id="2784949926578158345">Έγινε επαναφοÏά της σÏνδεσης.</translation>
<translation id="2794233252405721443">Ο ιστότοπος έχει αποκλειστεί</translation>
-<translation id="2812680587231492111">Αυτή η επιλογή παÏαλαβής δεν είναι διαθέσιμη. Δοκιμάστε μια διαφοÏετική επιλογή.</translation>
<translation id="2824775600643448204">ΓÏαμμή διευθÏνσεων και αναζήτησης</translation>
<translation id="2826760142808435982">Η κÏυπτογÏάφηση και ο έλεγχος ταυτότητας της σÏνδεσης γίνονται με <ph name="CIPHER" /> και χÏησιμοποιεί το <ph name="KX" /> ως μηχανισμό ανταλλαγής κλειδιών.</translation>
<translation id="2835170189407361413">ΔιαγÏαφή φόÏμας</translation>
-<translation id="2849041323157393173">Αυτή η επιλογή παÏάδοσης δεν είναι διαθέσιμη. Δοκιμάστε μια διαφοÏετική επιλογή.</translation>
<translation id="2889159643044928134">Îα μην γίνει επανάληψη φόÏτωσης</translation>
<translation id="2900469785430194048">Η διαθέσιμη μνήμη του Google Chrome εξαντλήθηκε, κατά την Ï€Ïοσπάθεια Ï€Ïοβολής αυτής της ιστοσελίδας.</translation>
<translation id="2909946352844186028">Εντοπίστηκε μια αλλαγή δικτÏου.</translation>
<translation id="2916038427272391327">Κλείστε τα άλλα Ï€ÏογÏάμματα</translation>
<translation id="2922350208395188000">Δεν είναι δυνατός ο έλεγχος του Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï Ï„Î¿Ï… διακομιστή.</translation>
+<translation id="2928905813689894207">ΔιεÏθυνση χÏέωσης</translation>
<translation id="2948083400971632585">ΜποÏείτε να απενεÏγοποιήσετε τυχόν διακομιστές μεσολάβησης που έχουν διαμοÏφωθεί για μια σÏνδεση από τη σελίδα Ïυθμίσεων.</translation>
<translation id="2955913368246107853">Κλείσιμο γÏαμμής εÏÏεσης</translation>
<translation id="2958431318199492670">Η διαμόÏφωση δικτÏου δεν συμμοÏφώνεται με το Ï€Ïότυπο ONC. ΟÏισμένα τμήματα αυτής της διαμόÏφωσης ενδέχεται να μην εισαχθοÏν.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Για την επίτευξη μιας ασφαλοÏÏ‚ σÏνδεσης, θα Ï€Ïέπει να γίνει σωστή ÏÏθμιση του ÏÎ¿Î»Î¿Î³Î¹Î¿Ï ÏƒÎ±Ï‚. Αυτό οφείλεται στο γεγονός ότι τα πιστοποιητικά που χÏησιμοποιοÏν οι ιστότοποι για την ταυτοποίησή τους είναι έγκυÏα μόνο για συγκεκÏιμένες χÏονικές πεÏιόδους. Εφόσον το Ïολόι της συσκευής σας δεν είναι σωστά Ïυθμισμένο, το Google Chrome δεν μποÏεί να επαληθεÏσει αυτά τα πιστοποιητικά.</translation>
<translation id="2972581237482394796">&amp;Επανάληψη ενέÏγειας</translation>
<translation id="2985306909656435243">Εάν ενεÏγοποιηθεί, το Chromium θα αποθηκεÏσει ένα αντίγÏαφο της κάÏτας σας σε αυτήν τη συσκευή για ταχÏτεÏη συμπλήÏωση φοÏμών.</translation>
+<translation id="2985398929374701810">Εισαγάγετε μια έγκυÏη διεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου</translation>
+<translation id="2986368408720340940">Ο Ï„Ïόπος παÏαλαβής δεν είναι διαθέσιμος. Δοκιμάστε έναν άλλο Ï„Ïόπο.</translation>
<translation id="2991174974383378012">Κοινοποίηση σε ιστότοπους</translation>
<translation id="3005723025932146533">Εμφάνιση αποθηκευμένου αντιγÏάφου</translation>
<translation id="3008447029300691911">Εισαγάγετε τον κωδικό CVC για την πιστωτική κάÏτα <ph name="CREDIT_CARD" />. Μετά την επιβεβαίωση, θα γίνει κοινή χÏήση των στοιχείων της κάÏτας σας με αυτόν τον ιστότοπο.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{τουλάχιστον ένα στοιχείο στις συγχÏονισμένες συσκευές}=1{1 στοιχείο (και πεÏισσότεÏα στις συγχÏονισμένες συσκευές)}other{# στοιχεία (και πεÏισσότεÏα στις συγχÏονισμένες συσκευές)}}</translation>
<translation id="3041612393474885105">ΠληÏοφοÏίες πιστοποιητικοÏ</translation>
<translation id="3063697135517575841">Δεν ήταν δυνατή η επιβεβαίωση της κάÏτας σας από το Chrome αυτήν τη στιγμή. Δοκιμάστε ξανά αÏγότεÏα.</translation>
+<translation id="3064966200440839136">ΑποχώÏηση από την κατάσταση ανώνυμης πεÏιήγησης για πληÏωμή μέσω εξωτεÏικής εφαÏμογής. Συνέχεια;</translation>
<translation id="3093245981617870298">Είστε εκτός σÏνδεσης.</translation>
<translation id="3105172416063519923">ΑναγνωÏιστικό στοιχείο:</translation>
<translation id="3109728660330352905">Δεν έχετε εξουσιοδότηση για την Ï€Ïοβολή αυτής της σελίδας.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Δοκιμάστε να εκτελέσετε τα Διαγνωστικά στοιχεία συνδεσιμότητας<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Αποτυχία αποκωδικοποίησης απόκÏισης</translation>
-<translation id="3149891296864842641">Επιλογή αποστολής</translation>
<translation id="3150653042067488994">ΠÏοσωÏινό σφάλμα διακομιστή</translation>
+<translation id="3154506275960390542">Αυτή η σελίδα πεÏιέχει μια φόÏμα η οποία πιθανώς να μην υποβληθεί με ασφάλεια. Τα δεδομένα που στέλνετε μποÏοÏν να Ï€ÏοβληθοÏν από άλλους κατά την αποστολή ή μποÏοÏν να Ï„ÏοποποιηθοÏν από κάποιον εισβολέα ώστε να αλλάξει το πεÏιεχόμενο που θα λάβει ο διακομιστής.</translation>
<translation id="3157931365184549694">ΕπαναφοÏά</translation>
<translation id="3167968892399408617">Οι σελίδες που Ï€Ïοβάλλετε στις καÏτέλες της ανώνυμης πεÏιήγησης δεν διατηÏοÏνται στο ιστοÏικό του Ï€ÏογÏάμματος πεÏιήγησης, στα cookie ή στο ιστοÏικό αναζήτησης, Î±Ï†Î¿Ï ÎºÎ»ÎµÎ¯ÏƒÎµÏ„Îµ όλες τις καÏτέλες της ανώνυμης πεÏιήγησης. Τα αÏχεία που κατεβάζετε ή οι σελιδοδείκτες που δημιουÏγείτε θα διατηÏοÏνται.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Δεν ήταν δυνατή η αποστολή του αιτήματος Ï€Ïόσβασής σας σε αυτόν τον ιστότοπο σε <ph name="NAME" />. Δοκιμάστε ξανά.</translation>
<translation id="3355823806454867987">Αλλαγή Ïυθμίσεων διακομιστή μεσολάβησης...</translation>
<translation id="3369192424181595722">Σφάλμα ÏολογιοÏ</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> ακόμη στοιχεία…</translation>
<translation id="337363190475750230">ΚατάÏγηση παÏοχής</translation>
<translation id="3377188786107721145">Σφάλμα ανάλυσης πολιτικής</translation>
<translation id="3380365263193509176">Άγνωστο σφάλμα</translation>
<translation id="3380864720620200369">ΑναγνωÏιστικό πελάτη:</translation>
<translation id="3391030046425686457">ΔιεÏθυνση παÏάδοσης</translation>
+<translation id="3395827396354264108">ΤÏόπος παÏαλαβής</translation>
<translation id="340013220407300675">Οι εισβολείς ενδέχεται να Ï€ÏοσπαθοÏν να υποκλέψουν τα στοιχεία σας από <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (για παÏάδειγμα κωδικοÏÏ‚ Ï€Ïόσβασης, μηνÏματα ή πιστωτικές κάÏτες).</translation>
<translation id="3422248202833853650">Δοκιμάστε να εξέλθετε από τα άλλα Ï€ÏογÏάμματα για να απελευθεÏώσετε μνήμη.</translation>
<translation id="3422472998109090673">ΠÏος το παÏόν, δεν είναι δυνατή η Ï€Ïόσβαση στον κεντÏικό υπολογιστή <ph name="HOST_NAME" />.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Διάστημα ανάκτησης:</translation>
<translation id="3462200631372590220">ΑπόκÏυψη σÏνθετων</translation>
+<translation id="3467763166455606212">Απαιτείται το όνομα κατόχου κάÏτας</translation>
+<translation id="3478058380795961209">Μήνας λήξης</translation>
<translation id="3479539252931486093">Δεν το πεÏιμένατε; <ph name="BEGIN_LINK" />ΕνημεÏώστε μας<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Όχι Ï„ÏŽÏα</translation>
<translation id="348000606199325318">ΑναγνωÏιστικό σφάλματος <ph name="CRASH_LOCAL_ID" /> (ΑναγνωÏιστικό διακομιστή: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Δεν ήταν δυνατή η επικοινωνία με τον γονέα σας αυτήν τη στιγμή. Δοκιμάστε ξανά.</translation>
<translation id="3528171143076753409">Το πιστοποιητικό του διακομιστή δεν είναι αξιόπιστο.</translation>
-<translation id="3538531656504267329">Μη έγκυÏο έτος λήξης</translation>
<translation id="3539171420378717834">ΔιατήÏηση αντιγÏάφου αυτής της κάÏτας σε αυτήν τη συσκευή</translation>
<translation id="3542684924769048008">ΧÏήση ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης για:</translation>
<translation id="3549644494707163724">ΚÏυπτογÏάφηση όλων των συγχÏονισμένων δεδομένων με τη δική σας φÏάση Ï€Ïόσβασης συγχÏονισμοÏ</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">ΑπόκÏυψη λεπτομεÏειών</translation>
<translation id="3587482841069643663">Όλες</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Εισαγάγετε μια έγκυÏη ημεÏομηνία λήξης</translation>
<translation id="36224234498066874">ΔιαγÏαφή Δεδομένων ΠεÏιήγησης...</translation>
<translation id="362276910939193118">Εμφάνιση πλήÏους ιστοÏικοÏ</translation>
<translation id="3623476034248543066">Εμφάνιση τιμής</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Κωδικός Ï€Ïόσβασης:</translation>
<translation id="3696411085566228381">κανένα</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Επιλέξτε μια διεÏθυνση αποστολής, για να ελέγξετε τους Ï„Ïόπους και τις απαιτήσεις αποστολής.</translation>
<translation id="370665806235115550">ΦόÏτωση...</translation>
<translation id="3712624925041724820">Οι άδειες έχουν εξαντληθεί</translation>
<translation id="3714780639079136834">ΕνεÏγοποιήστε τα δεδομένα κινητής τηλεφωνίας ή το Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">ΣÏνδεσμος που αντιγÏ.</translation>
<translation id="375403751935624634">Η μετάφÏαση απέτυχε λόγω σφάλματος διακομιστή.</translation>
<translation id="3759461132968374835">Δεν έχετε Ï€Ïόσφατα αναφεÏθέντα σφάλματα. Τα σφάλματα που Ï€Ïοέκυψαν όταν η αναφοÏά σφαλμάτων ήταν απενεÏγοποιημένη δεν θα εμφανιστοÏν εδώ.</translation>
+<translation id="3787705759683870569">Λήγει <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Εάν χÏησιμοποιείτε διακομιστή μεσολάβησης…</translation>
<translation id="3828924085048779000">Δεν επιτÏέπεται να είναι κενή η φÏάση Ï€Ïόσβασης.</translation>
<translation id="3845539888601087042">Εμφάνιση ιστοÏÎ¹ÎºÎ¿Ï Î±Ï€ÏŒ τις συνδεδεμένες συσκευές σας. <ph name="BEGIN_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Θέλετε το Chromium να αποθηκεÏσει αυτήν την κάÏτα;</translation>
<translation id="4171400957073367226">Εσφαλμένη υπογÏαφή επαλήθευσης</translation>
-<translation id="4176463684765177261">ΑπενεÏγοποιημένη</translation>
<translation id="4196861286325780578">&amp;Επανάληψη μετακίνησης</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Ελέγξτε τις διαμοÏφώσεις του τείχους Ï€Ïοστασίας και της Ï€Ïοστασίας από ιοÏÏ‚<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{καμία}=1{1 εφαÏμογή ($1)}=2{2 εφαÏμογές ($1, $2)}other{# εφαÏμογές ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">αποτελέσματα αναζήτησης</translation>
<translation id="4432688616882109544">Ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> δεν αποδέχτηκε το πιστοποιητικό σÏνδεσής σας ή μποÏεί να μην διατέθηκε πιστοποιητικό σÏνδεσης.</translation>
<translation id="443673843213245140">Η χÏήση ενός διακομιστή μεσολάβησης είναι απενεÏγοποιημένη, αλλά έχει καθοÏιστεί μια Ïητή διαμόÏφωση διακομιστή μεσολάβησης.</translation>
-<translation id="4446242550670694251">Στο εξής μποÏείτε να πεÏιηγηθείτε ανώνυμα και η δÏαστηÏιότητά σας δεν θα είναι οÏατή στα άλλα άτομα που χÏησιμοποιοÏν αυτήν τη συσκευή.</translation>
<translation id="4492190037599258964">Αποτελέσματα αναζήτησης για "<ph name="SEARCH_STRING" />"</translation>
<translation id="4506176782989081258">Σφάλμα επικÏÏωσης: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Επικοινωνήστε με το διαχειÏιστή συστήματος</translation>
<translation id="450710068430902550">Κοινοποίηση στο διαχειÏιστή</translation>
+<translation id="4515275063822566619">Οι κάÏτες και οι διευθÏνσεις Ï€ÏοέÏχονται από το Chrome και τον ΛογαÏιασμό σας Google (<ph name="ACCOUNT_EMAIL" />). ΜποÏείτε να τις διαχειÏιστείτε στις <ph name="BEGIN_LINK" />Ρυθμίσεις<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">ΛεπτομέÏειες</translation>
<translation id="4558551763791394412">Δοκιμάστε να απενεÏγοποιήσετε τις επεκτάσεις σας.</translation>
<translation id="457875822857220463">ΠαÏάδοση</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">ΠÏοσαÏμογή στη σελίδα</translation>
<translation id="483020001682031208">Δεν υπάÏχουν σελίδες του Î¦Ï…ÏƒÎ¹ÎºÎ¿Ï Î´Î¹ÎºÏ„Ïου για εμφάνιση</translation>
<translation id="4850886885716139402">ΠÏοβολή</translation>
+<translation id="4854362297993841467">Αυτός ο Ï„Ïόπος παÏάδοσης δεν είναι διαθέσιμος. Δοκιμάστε έναν άλλο Ï„Ïόπο.</translation>
<translation id="4858792381671956233">Ρώτησες τους γονείς σου εάν σου επιτÏέπουν να επισκεφτείς αυτόν τον ιστότοπο</translation>
<translation id="4880827082731008257">ΙστοÏικό αναζήτησης</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Αυτή η σελίδα έχει μεταφÏαστεί από μια άγνωστη γλώσσας στα <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">ΠληÏωμή</translation>
<translation id="4926049483395192435">ΠÏέπει να καθοÏιστεί.</translation>
-<translation id="4941291666397027948">Το * υποδεικνÏει απαιτοÏμενο πεδίο</translation>
<translation id="495170559598752135">ΕνέÏγειες</translation>
<translation id="4958444002117714549">Ανάπτυξη λίστας</translation>
<translation id="4962322354953122629">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωÏείται έμπιστο από το Chrome. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Λανθασμένος κωδικός Ï€Ïόσβασης</translation>
<translation id="5056549851600133418">ΆÏθÏα για εσάς</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Ελέγξτε τη διεÏθυνση του διακομιστή μεσολάβησης<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{ΧωÏίς cookie}=1{1 ιστότοπος χÏησιμοποιεί cookie. }other{# ιστότοποι χÏησιμοποιοÏν cookie. }}</translation>
<translation id="5087286274860437796">Το πιστοποιητικό του διακομιστή δεν είναι έγκυÏο αυτήν τη στιγμή.</translation>
<translation id="5087580092889165836">ΠÏοσθήκη κάÏτας</translation>
<translation id="5089810972385038852">Πολιτεία</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Εμφάνιση</translation>
<translation id="5308689395849655368">Η αναφοÏά σφαλμάτων είναι απενεÏγοποιημένη.</translation>
<translation id="5317780077021120954">Αποθήκευση</translation>
-<translation id="5326702247179446998">Απαιτείται παÏαλήπτης</translation>
<translation id="5327248766486351172">Όνομα</translation>
<translation id="5337705430875057403">Οι εισβολείς στον ιστότοπο <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> μποÏεί να σας ξεγελάσουν και να κάνετε κάτι επικίνδυνο, όπως να εγκαταστήσετε κάποιο λογισμικό ή να αποκαλÏψετε Ï€Ïοσωπικά σας στοιχεία (για παÏάδειγμα, κωδικοÏÏ‚ Ï€Ïόσβασης, αÏιθμοÏÏ‚ τηλεφώνου ή πιστωτικές κάÏτες).</translation>
-<translation id="53553865750799677">Μη υποστηÏιζόμενη διεÏθυνση παÏαλαβής. Επιλέξτε διαφοÏετική διεÏθυνση.</translation>
<translation id="5359637492792381994">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν είναι έγκυÏο αυτήν τη στιγμή. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Αποτυχία αποθήκευσης Ïυθμίσεων πολιτικής</translation>
<translation id="5386426401304769735">Η αλυσίδα Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï Î³Î¹Î± αυτόν τον ιστότοπο πεÏιέχει ένα πιστοποιητικό το οποίο είναι υπογεγÏαμμένο με χÏήση SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">Μια ενσωματωμένη σελίδα στον ιστότοπο <ph name="SITE" /> λέει:</translation>
<translation id="5556459405103347317">ΕπαναφόÏτωση</translation>
<translation id="5565735124758917034">ΕνεÏγό</translation>
+<translation id="5571083550517324815">Δεν είναι δυνατή η παÏαλαβή από αυτήν τη διεÏθυνση. Επιλέξτε μια άλλη διεÏθυνση.</translation>
<translation id="5572851009514199876">Εκκινήστε και συνδεθείτε στο Chrome, έτσι ώστε το Chrome να μποÏεί να ελέγξει εάν έχετε δικαίωμα Ï€Ïόσβασης σε αυτόν τον ιστότοπο.</translation>
-<translation id="5575380383496039204">Μη υποστηÏιζόμενη διεÏθυνση παÏάδοσης. Επιλέξτε διαφοÏετική διεÏθυνση.</translation>
<translation id="5580958916614886209">Ελέγξτε τον μήνα λήξης σας και δοκιμάστε ξανά</translation>
<translation id="560412284261940334">Η διαχείÏιση δεν υποστηÏίζεται</translation>
<translation id="5610142619324316209">Ελέγξτε τη σÏνδεση</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">Η ταυτότητα Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… ιστότοπου δεν έχει επαληθευτεί.</translation>
<translation id="5720705177508910913">ΤÏέχων χÏήστης</translation>
<translation id="5732392974455271431">Οι γονείς σου μποÏοÏν να καταÏγήσουν τον αποκλεισμό του</translation>
-<translation id="57586589942790530">Μη έγκυÏος αÏιθμός κάÏτας</translation>
+<translation id="5763042198335101085">Εισαγάγετε μια έγκυÏη διεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου</translation>
+<translation id="5765072501007116331">Για να δείτε Ï„Ïόπους και απαιτήσεις παÏάδοσης, επιλέξτε μια διεÏθυνση</translation>
<translation id="5784606427469807560">ΠαÏουσιάστηκε κάποιο Ï€Ïόβλημα κατά την επιβεβαίωση της κάÏτας σας. Ελέγξτε τη σÏνδεσή σας στο διαδίκτυο και δοκιμάστε ξανά.</translation>
<translation id="5785756445106461925">Επίσης, αυτή η σελίδα πεÏιέχει άλλους πόÏους, οι οποίοι δεν είναι ασφαλείς. Αυτοί οι πόÏοι μποÏοÏν να Ï€ÏοβληθοÏν από άλλους χÏήστες κατά τη μετάβαση και μποÏοÏν να Ï„ÏοποποιηθοÏν από έναν εισβολέα ώστε να αλλάξει η εμφάνιση της σελίδας.</translation>
<translation id="5786044859038896871">Θέλετε να συμπληÏωθοÏν τα στοιχεία της κάÏτας σας;</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">Δεν είναι δυνατή η Ï€Ïόσβαση σε αυτόν τον ιστότοπο</translation>
<translation id="5869522115854928033">Αποθηκευμένοι κωδικοί Ï€Ïόσβασης</translation>
<translation id="5872918882028971132">Γονικές Ï€Ïοτάσεις</translation>
-<translation id="587760065310675640">Μη υποστηÏιζόμενη διεÏθυνση αποστολής. Επιλέξτε διαφοÏετική διεÏθυνση.</translation>
<translation id="5901630391730855834">ΚίτÏινο</translation>
-<translation id="59174027418879706">ΕνεÏγή</translation>
<translation id="5926846154125914413">Ενδέχεται να χάσετε την Ï€Ïόσβαση σε Ï€Ïονομιακό πεÏιεχόμενο από οÏισμένους ιστότοπους.</translation>
<translation id="5959728338436674663">Αυτόματη αποστολή οÏισμένων <ph name="BEGIN_WHITEPAPER_LINK" />πληÏοφοÏιών συστήματος και πεÏιεχομένου σελίδων<ph name="END_WHITEPAPER_LINK" /> στην Google για διευκόλυνση του ÎµÎ½Ï„Î¿Ï€Î¹ÏƒÎ¼Î¿Ï ÎµÏ€Î¹ÎºÎ¯Î½Î´Ï…Î½Ï‰Î½ εφαÏμογών και ιστοτόπων<ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Εβδομάδα</translation>
<translation id="5967867314010545767">ΚατάÏγηση από το ιστοÏικό</translation>
<translation id="5975083100439434680">ΣμίκÏυνση</translation>
+<translation id="598637245381783098">Δεν είναι δυνατό το άνοιγμα της εφαÏμογής πληÏωμής</translation>
<translation id="5989320800837274978">Δεν Ï€ÏοσδιοÏίζονται οÏτε οι σταθεÏοί διακομιστές μεσολάβησης οÏτε μια διεÏθυνση URL σεναÏίου .pac.</translation>
<translation id="5990559369517809815">Τα αιτήματα για τον διακομιστή έχουν αποκλειστεί από μια επέκταση.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Οι επιλογές κάÏτας και διεÏθυνσης Ï€ÏοέÏχονται από το Chrome. ΜποÏείτε να διαχειÏιστείτε αυτές τις επιλογές στις <ph name="BEGIN_LINK" />Ρυθμίσεις<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1 σελίδα}other{# σελίδες}}</translation>
<translation id="6017514345406065928">ΠÏάσινο</translation>
+<translation id="6027201098523975773">Εισαγωγή ονόματος</translation>
<translation id="6040143037577758943">Κλείσιμο</translation>
-<translation id="604124094241169006">Αυτόματη</translation>
<translation id="6042308850641462728">ΠεÏισσότεÏα</translation>
<translation id="6060685159320643512">ΠÏοσοχή, τέτοια πειÏάματα είναι επικÏνδυνα</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{καμία}=1{1}other{#}}</translation>
@@ -543,9 +552,10 @@
του δικτÏου που ενδεχομένως χÏησιμοποιείτε.</translation>
<translation id="614940544461990577">Δοκιμάστε να κάνετε τα εξής:</translation>
<translation id="6151417162996330722">Το πιστοποιητικό του διακομιστή έχει Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î· πεÏίοδο εγκυÏότητας.</translation>
-<translation id="615643356032862689">Τα ληφθέντα αÏχεία και οι σελιδοδείκτες θα διατηÏηθοÏν.</translation>
+<translation id="6157877588268064908">Για να δείτε Ï„Ïόπους και απαιτήσεις αποστολής, επιλέξτε μια διεÏθυνση</translation>
<translation id="6165508094623778733">Μάθετε πεÏισσότεÏα</translation>
<translation id="6177128806592000436">Η σÏνδεσή σας σε αυτόν τον ιστότοπο δεν είναι ασφαλής</translation>
+<translation id="6184817833369986695">(κοόÏτη: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Ελέγξτε τη σÏνδεσή σας στο Internet</translation>
<translation id="6218753634732582820">Îα καταÏγηθεί η διεÏθυνση από το Chromium;</translation>
<translation id="6251924700383757765">Πολιτική αποÏÏήτου</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Επανάληψη αναδιάταξης</translation>
<translation id="6263376278284652872">Σελιδοδείκτες <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Πίσω στην ασφάλεια</translation>
+<translation id="6276112860590028508">Εδώ εμφανίζονται οι σελίδες από τη λίστα ανάγνωσής σας</translation>
+<translation id="6280223929691119688">Δεν είναι δυνατή η παÏάδοση σε αυτήν τη διεÏθυνση. Επιλέξτε μια άλλη διεÏθυνση.</translation>
<translation id="6282194474023008486">ΤαχυδÏομικός κώδικας</translation>
<translation id="6290238015253830360">Τα Ï€Ïοτεινόμενα άÏθÏα σας εμφανίζονται εδώ</translation>
<translation id="6305205051461490394">Δεν είναι δυνατή η Ï€Ïόσβαση στο <ph name="URL" />.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Δεν είναι δυνατόν να ελεγχθεί αν το πιστοποιητικό έχει ακυÏωθεί.</translation>
<translation id="6433490469411711332">ΕπεξεÏγασία στοιχείων επαφής</translation>
<translation id="6433595998831338502">Ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> απέÏÏιψε τη σÏνδεση.</translation>
-<translation id="6443118737398455446">Μη έγκυÏη ημεÏομηνία λήξης</translation>
<translation id="6446608382365791566">ΠÏοσθήκη πεÏισσότεÏων πληÏοφοÏιών</translation>
<translation id="6451458296329894277">Επιβεβαίωση νέας υποβολής φόÏμας</translation>
<translation id="6456339708790392414">Η πληÏωμή σας</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του μποÏεί να ανακληθεί. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Πολιτικές συσκευών </translation>
<translation id="6477321094435799029">Το Chrome εντόπισε ασυνήθιστο κώδικα σε αυτήν τη σελίδα και τον απέκλεισε για να Ï€ÏοστατεÏσει τα Ï€Ïοσωπικά σας στοιχεία (για παÏάδειγμα, κωδικοÏÏ‚ Ï€Ïόσβασης, αÏιθμοÏÏ‚ τηλεφώνου ή πιστωτικές κάÏτες).</translation>
-<translation id="6477460825583319731">Μη έγκυÏη διεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου</translation>
<translation id="6489534406876378309">ΈναÏξη μεταφόÏτωσης σφαλμάτων</translation>
<translation id="6508722015517270189">Επανεκκινήστε το Chrome</translation>
-<translation id="6525462735697194615">Μη έγκυÏος μήνας λήξης</translation>
<translation id="6529602333819889595">&amp;Επανάληψη διαγÏαφής</translation>
<translation id="6534179046333460208">ΠÏοτάσεις Î¦Ï…ÏƒÎ¹ÎºÎ¿Ï Î´Î¹ÎºÏ„Ïου</translation>
<translation id="6550675742724504774">Επιλογές</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685">Αναζήτηση <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Αυτή η πολιτική έχει αποσυÏθεί.</translation>
<translation id="6652240803263749613">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωÏείται έμπιστο από το λειτουÏγικό σÏστημα του υπολογιστή σας. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Αυτή η επιλογή αποστολής δεν είναι διαθέσιμη. Δοκιμάστε μια διαφοÏετική επιλογή.</translation>
<translation id="6671697161687535275">Îα καταÏγηθεί η Ï€Ïόταση φόÏμας από το Chromium;</translation>
<translation id="6685834062052613830">Αποσυνδεθείτε και ολοκληÏώστε την εγκατάσταση</translation>
<translation id="6710213216561001401">ΠÏοηγοÏμενο</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">ΥπάÏχει κάποιο Ï€Ïόβλημα με το διακομιστή μεσολάβησης ή η διεÏθυνση είναι εσφαλμένη.</translation>
<translation id="6727102863431372879">ΟÏισμός</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{καμία}=1{1 στοιχείο}other{# στοιχεία}}</translation>
-<translation id="6743044928064272573">Επιλογή παÏαλαβής</translation>
<translation id="674375294223700098">Άγνωστο σφάλμα Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï Î´Î¹Î±ÎºÎ¿Î¼Î¹ÏƒÏ„Î®</translation>
<translation id="6753269504797312559">Τιμή πολιτικής</translation>
<translation id="6757797048963528358">Η συσκευή σας τέθηκε σε αδÏάνεια.</translation>
<translation id="6778737459546443941">Ο γονέας σου δεν τον έχει εγκÏίνει ακόμα</translation>
<translation id="6810899417690483278">ΑναγνωÏιστικό Ï€ÏοσαÏμογής</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Δεν ήταν δυνατή η φόÏτωση των δεδομένων πεÏιοχών</translation>
<translation id="6831043979455480757">ΜετάφÏαση</translation>
<translation id="6839929833149231406">ΠεÏιοχή</translation>
<translation id="6874604403660855544">&amp;Επανάληψη Ï€Ïοσθήκης</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Η κάÏτα σας επιβεβαιώθηκε</translation>
<translation id="6897140037006041989">ΠαÏάγοντας χÏήστη</translation>
<translation id="6915804003454593391">ΧÏήστης</translation>
+<translation id="6948701128805548767">Για να δείτε Ï„Ïόπους και απαιτήσεις παÏαλαβής, επιλέξτε μια διεÏθυνση</translation>
<translation id="6957887021205513506">Το πιστοποιητικό του διακομιστή φαίνεται να είναι πλαστό.</translation>
<translation id="6965382102122355670">ΕÎΤΑΞΕΙ</translation>
<translation id="6965978654500191972">Συσκευή</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">ΚαθοÏίζονται τόσο οι σταθεÏοί διακομιστές μεσολάβησης όσο και μια διεÏθυνση URL σεναÏίου .pac.</translation>
<translation id="6989763994942163495">Εμφάνιση σÏνθετων Ïυθμίσεων…</translation>
<translation id="7000990526846637657">Δεν βÏέθηκαν καταχωÏίσεις ιστοÏικοÏ</translation>
-<translation id="7001663382399377034">ΠÏοσθήκη παÏαλήπτη</translation>
<translation id="7009986207543992532">ΠÏοσπαθήσατε να μεταβείτε στον τομέα <ph name="DOMAIN" />, αλλά ο διακομιστής παÏουσίασε ένα πιστοποιητικό με πεÏίοδο εγκυÏότητας η οποία είναι Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î· για να θεωÏηθεί αξιόπιστη. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Ο ΛογαÏιασμός σας Google ενδέχεται να διαθέτει άλλες μοÏφές ιστοÏÎ¹ÎºÎ¿Ï Ï€ÎµÏιήγησης στη διεÏθυνση <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">ΠαλαιότεÏο</translation>
<translation id="7090678807593890770">Αναζητήστε στο Google για <ph name="LINK" /></translation>
<translation id="7119414471315195487">Κλείστε τις άλλες καÏτέλες ή τα Ï€ÏογÏάμματα</translation>
+<translation id="7129409597930077180">Δεν είναι δυνατή η αποστολή σε αυτήν τη διεÏθυνση. Επιλέξτε μια άλλη διεÏθυνση.</translation>
+<translation id="7138472120740807366">Μέθοδος Ï€Ïοβολής</translation>
<translation id="7139724024395191329">ΕμιÏάτο</translation>
<translation id="7155487117670177674">Μη ασφαλής πληÏωμή</translation>
<translation id="7179921470347911571">Επανεκκίνηση Ï„ÏŽÏα</translation>
<translation id="7180611975245234373">Ανανέωση</translation>
<translation id="7182878459783632708">Δεν έχουν οÏιστεί πολιτικές</translation>
<translation id="7186367841673660872">Αυτή η σελίδα έχει μεταφÏαστεί από τα<ph name="ORIGINAL_LANGUAGE" />στα<ph name="LANGUAGE_LANGUAGE" /></translation>
+<translation id="7192203810768312527">ΑπελευθεÏώνει <ph name="SIZE" />. ΟÏισμένοι ιστότοποι μποÏεί να φοÏτωθοÏν πιο αÏγά κατά την επόμενη επίσκεψή σας.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423">Ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> δεν συμμοÏφώνεται με τα Ï€Ïότυπα ασφάλειας.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LINK" /> σχετικά με αυτό το Ï€Ïόβλημα.</translation>
@@ -675,7 +686,6 @@
<translation id="7424977062513257142">Μια ενσωματωμένη σελίδα σε αυτό τον ιστότοπο λέει:</translation>
<translation id="7441627299479586546">Εσφαλμένο θέμα πολιτικής</translation>
<translation id="7444046173054089907">Αυτός ο ιστότοπος είναι αποκλεισμένος</translation>
-<translation id="7444238235002594607">Επιλέξτε διεÏθυνση παÏαλαβής, για να δείτε τις απαιτήσεις και τις μεθόδους παÏαλαβής.</translation>
<translation id="7445762425076701745">Η ταυτότητα του διακομιστή στον οποίο έχετε συνδεθεί δεν μποÏεί να επικυÏωθεί πλήÏως. Είστε συδεδεμένοι σε ένα διακομιστή χÏησιμοποιώντας ένα όνομα που είναι έγκυÏο μόνο εντός του δικτÏου σας, την κατοχή του οποίου δεν έχει Ï„Ïόπο να επικυÏώσει μια εξωτεÏική αÏχή πιστοποίησης. Καθώς οÏισμένες αÏχές πιστοποιητικών εκδίδουν πιστοποιητικά για αυτά τα ονόματα οÏτως ή άλλως, δεν υπάÏχει Ï„Ïόπος να βεβαιωθείτε ότι είστε συνδεδεμένοι στον ιστότοπο που επιθυμείτε και όχι σε έναν εισβολέα.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Îα μάθετε πεÏισσότεÏα<ph name="END_LINK" /> σχετικά με αυτό το Ï€Ïόβλημα.</translation>
<translation id="7460163899615895653">Οι Ï€Ïόσφατες καÏτέλες σας από άλλες συσκευές εμφανίζονται εδώ</translation>
@@ -719,6 +729,7 @@
<translation id="7755287808199759310">Ο γονέας σας μποÏεί να καταÏγήσει τον αποκλεισμό του για εσάς</translation>
<translation id="7758069387465995638">Το τείχος Ï€Ïοστασίας ή το λογισμικό Ï€Ïοστασίας από ιοÏÏ‚ ενδέχεται να έχει αποκλείσει τη σÏνδεση.</translation>
<translation id="7761701407923456692">Το πιστοποιητικό του διακομιστή δεν συμφωνεί με τη διεÏθυνση URL.</translation>
+<translation id="7763386264682878361">Συντακτικός αναλυτής διακήÏυξης πληÏωμών</translation>
<translation id="7764225426217299476">ΠÏοσθήκη διεÏθυνσης</translation>
<translation id="777702478322588152">ÎομαÏχία</translation>
<translation id="7791543448312431591">ΠÏοσθήκη</translation>
@@ -732,6 +743,7 @@
<translation id="785549533363645510">Ωστόσο, δεν είστε αόÏατος/η. Με την κατάσταση ανώνυμης πεÏιήγησης δεν μποÏείτε να αποκÏÏψετε τα στοιχεία της πεÏιήγησής σας από τους εÏγοδότες σας, τον πάÏοχο υπηÏεσιών διαδικτÏου που χÏησιμοποιείτε ή τους ιστότοπους που επισκέπτεστε.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Ελέγξτε τον κωδικό σας CVC και δοκιμάστε ξανά</translation>
+<translation id="79338296614623784">Εισαγάγετε έναν έγκυÏο αÏιθμό τηλεφώνου</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Το πιστοποιητικό του διακομιστή δεν είναι ακόμα έγκυÏο.</translation>
<translation id="7942349550061667556">Κόκκινο</translation>
@@ -751,6 +763,7 @@
<translation id="8088680233425245692">Αποτυχία Ï€Ïοβολής άÏθÏου.</translation>
<translation id="8089520772729574115">λιγότεÏο από 1 MB</translation>
<translation id="8091372947890762290">Η ενεÏγοποίηση στο διακομιστή εκκÏεμεί</translation>
+<translation id="8118489163946903409">ΤÏόπος πληÏωμής</translation>
<translation id="8131740175452115882">Επιβεβαίωση</translation>
<translation id="8134994873729925007">Δεν ήταν δυνατή η εÏÏεση της <ph name="BEGIN_ABBR" />διεÏθυνσης DNS<ph name="END_ABBR" /> του διακομιστή <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Ο υπολογιστής σας τέθηκε σε αδÏάνεια.</translation>
@@ -776,6 +789,7 @@
<translation id="8349305172487531364">ΓÏαμμή σελιδοδεικτών</translation>
<translation id="8363502534493474904">ΑπενεÏγοποιήστε τη λειτουÏγία πτήσης</translation>
<translation id="8364627913115013041">Δεν έχει οÏιστεί.</translation>
+<translation id="8368476060205742148">ΥπηÏεσίες Google Play</translation>
<translation id="8380941800586852976">Επικίνδυνο</translation>
<translation id="8382348898565613901">Οι σελιδοδείκτες που επισκεφτήκατε Ï€Ïόσφατα εμφανίζονται εδώ.</translation>
<translation id="8398259832188219207">Η αναφοÏά σφαλμάτων μεταφοÏτώθηκε στις <ph name="UPLOAD_TIME" /></translation>
@@ -784,32 +798,30 @@
<translation id="8428213095426709021">Ρυθμίσεις</translation>
<translation id="8433057134996913067">Αυτή η ενέÏγεια θα σας αποσυνδέσει από τους πεÏισσότεÏους ιστότοπους.</translation>
<translation id="8437238597147034694">&amp;ΑναίÏεση μετακίνησης</translation>
-<translation id="8456681095658380701">Μη έγκυÏο όνομα</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 πιστωτική κάÏτα}other{# πιστωτικές κάÏτες}}</translation>
<translation id="8483780878231876732">Για να χÏησιμοποιήσετε κάÏτες από τον ΛογαÏιασμό σας Google, συνδεθείτε στο Chrome</translation>
<translation id="8488350697529856933">ΙσχÏει για</translation>
-<translation id="8492969205326575646">Μη υποστηÏιζόμενος Ï„Ïπος κάÏτας</translation>
<translation id="8498891568109133222">Ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> άÏγησε Ï€Î¿Î»Ï Î½Î± ανταποκÏιθεί.</translation>
<translation id="852346902619691059">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωÏείται έμπιστο από το λειτουÏγικό σÏστημα της συσκευής σας. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Έτος λήξης</translation>
<translation id="8543181531796978784">ΜποÏείτε να <ph name="BEGIN_ERROR_LINK" />αναφέÏετε ένα Ï€Ïόβλημα εντοπισμοÏ<ph name="END_ERROR_LINK" /> ή, εάν κατανοείτε τους κινδÏνους ασφαλείας, να <ph name="BEGIN_LINK" />επισκεφτείτε αυτόν τον μη ασφαλή ιστότοπο<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Η μετάφÏαση απέτυχε επειδή δεν ήταν δυνατός ο Ï€ÏοσδιοÏισμός της σελίδας.</translation>
<translation id="8559762987265718583">Δεν είναι δυνατή η επίτευξη ιδιωτικής σÏνδεσης με τον τομέα <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> επειδή η ημεÏομηνία και η ÏŽÏα (<ph name="DATE_AND_TIME" />) της συσκευής σας είναι λανθασμένες.</translation>
-<translation id="8570229484593575558">Αυτές οι πληÏοφοÏίες |δεν θα αποθηκευτοÏν|:#Το ιστοÏικό πεÏιήγησής σας#Οι αναζητήσεις σας#Τα δεδομένα cookie</translation>
<translation id="8571890674111243710">ΜετάφÏαση σελίδας σε <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Η δÏαστηÏιότητά σας |ενδέχεται να εξακολουθεί να είναι οÏατή|:#Στους ιστοτόπους που επισκέπτεστε#Στον εÏγοδότη σας#Στον παÏοχέα υπηÏεσιών διαδικτÏου</translation>
<translation id="858637041960032120">ΠÏοσθ. τηλεφ.
</translation>
<translation id="859285277496340001">Αυτό το πιστοποιητικό δεν καθοÏίζει κάποιο μηχανισμό για να ελέγχεται εάν έχει ανακληθεί.</translation>
<translation id="8620436878122366504">Οι γονείς σας δεν τον έχουν εγκÏίνει ακόμα</translation>
<translation id="8647750283161643317">ΕπαναφοÏά Ï€Ïοεπιλογών</translation>
<translation id="8703575177326907206">Η σÏνδεσή σας με τον τομέα <ph name="DOMAIN" /> δεν είναι κÏυπτογÏαφημένη.</translation>
+<translation id="8718314106902482036">Η πληÏωμή δεν ολοκληÏώθηκε</translation>
<translation id="8725066075913043281">ΠÏοσπαθήστε ξανά</translation>
<translation id="8728672262656704056">ΠÏαγματοποιείτε ανώνυμη πεÏιήγηση</translation>
<translation id="8730621377337864115">ΟλοκληÏώθηκε</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="8759274551635299824">Αυτή η κάÏτα έχει λήξει</translation>
<translation id="8790007591277257123">&amp;Επανάληψη διαγÏαφής</translation>
-<translation id="8798099450830957504">ΠÏοεπιλογή</translation>
<translation id="8800988563907321413">Οι Ï€Ïοτάσεις σε κοντινή απόσταση εμφανίζονται εδώ</translation>
<translation id="8820817407110198400">Σελιδοδείκτες</translation>
<translation id="883848425547221593">Άλλοι σελιδοδείκτες</translation>
@@ -819,6 +831,7 @@
<translation id="8866481888320382733">Σφάλμα ανάλυσης Ïυθμίσεων πολιτικής</translation>
<translation id="8866959479196209191">Αυτή η σελίδα λέει:</translation>
<translation id="8870413625673593573">Έκλεισαν Ï€Ïόσφατα</translation>
+<translation id="8874824191258364635">Εισαγάγετε έναν έγκυÏο αÏιθμό κάÏτας</translation>
<translation id="8876793034577346603">Αποτυχία ανάλυσης της διαμόÏφωσης δικτÏου</translation>
<translation id="8877192140621905067">Μετά την επιβεβαίωση, θα γίνει κοινή χÏήση των στοιχείων της κάÏτας σας με αυτόν τον ιστότοπο</translation>
<translation id="8889402386540077796">ΑπόχÏωση</translation>
@@ -828,7 +841,6 @@
<translation id="8931333241327730545">Θέλετε να αποθηκεÏσετε αυτήν την κάÏτα στο ΛογαÏιασμό σας Google;</translation>
<translation id="8932102934695377596">Το Ïολόι σας πάει πίσω</translation>
<translation id="8954894007019320973">(ΠεÏιεχ.)</translation>
-<translation id="895548565263634352">Διαβάστε ιστοÏίες από <ph name="ARTICLE_PUBLISHER" /> και <ph name="OTHER_ARTICLE_COUNT" /> ακόμη</translation>
<translation id="8971063699422889582">Το πιστοποιητικό του διακομιστή έχει λήξει.</translation>
<translation id="8986494364107987395">Αυτόματη αποστολή στατιστικών στοιχείων χÏήσης και αναφοÏών σφαλμάτων στην Google</translation>
<translation id="8987927404178983737">Μήνας</translation>
@@ -846,7 +858,6 @@
<translation id="9068849894565669697">Επιλογή χÏώματος</translation>
<translation id="9076283476770535406">ΜποÏεί να διαθέτει πεÏιεχόμενο για ενηλίκους</translation>
<translation id="9078964945751709336">ΑπαιτοÏνται πεÏισσότεÏες πληÏοφοÏίες</translation>
-<translation id="9094175695478007090">Δεν είναι δυνατή η εκκίνηση της εφαÏμογής πληÏωμών.</translation>
<translation id="9103872766612412690">Κανονικά, ο ιστότοπος <ph name="SITE" /> χÏησιμοποιεί κÏυπτογÏάφηση για να Ï€ÏοστατεÏει τα στοιχεία σας. Όταν το Chromium επιχείÏησε Ï€Ïόσφατα να συνδεθεί στο <ph name="SITE" />, ο ιστότοπος ανταποκÏίθηκε δημιουÏγώντας ασυνήθιστα και εσφαλμένα διαπιστευτήÏια. Αυτό μποÏεί να συμβεί όταν κάποιος εισβολέας Ï€Ïοσπαθεί να υποκÏιθεί ότι είναι ο ιστότοπος <ph name="SITE" /> ή όταν κάποια οθόνη σÏνδεσης Wi-Fi έχει διακόψει τη σÏνδεσή σας. Τα στοιχεία σας εξακολουθοÏν να είναι ασφαλή επειδή το Chromium διέκοψε τη σÏνδεση Ï€Ïιν από την ανταλλαγή δεδομένων.</translation>
<translation id="9137013805542155359">Εμφάνιση Ï€ÏωτοτÏπου</translation>
<translation id="9137248913990643158">Εκκινήστε και συνδεθείτε στο Chrome Ï€Ïιν χÏησιμοποιήσετε αυτήν την εφαÏμογή.</translation>
diff --git a/chromium/components/strings/components_strings_en-GB.xtb b/chromium/components/strings/components_strings_en-GB.xtb
index 4060871fe6d..09b6b0d398f 100644
--- a/chromium/components/strings/components_strings_en-GB.xtb
+++ b/chromium/components/strings/components_strings_en-GB.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="en-GB">
<translation id="1008557486741366299">Not Now</translation>
<translation id="1015730422737071372">Provide additional details.</translation>
+<translation id="1021110881106174305">Accepted cards</translation>
<translation id="1032854598605920125">Rotate clockwise</translation>
<translation id="1038842779957582377">unknown name</translation>
<translation id="1050038467049342496">Close other apps</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Hide value</translation>
<translation id="1228893227497259893">Wrong entity identifier</translation>
<translation id="1232569758102978740">Untitled</translation>
+<translation id="1263231323834454256">Reading list</translation>
<translation id="1264126396475825575">Crash report captured on <ph name="CRASH_TIME" /> (not yet uploaded or ignored)</translation>
<translation id="1285320974508926690">Never translate this site</translation>
<translation id="129553762522093515">Recently closed</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromium Auto-fill settings...</translation>
<translation id="1374468813861204354">suggestions</translation>
<translation id="1375198122581997741">About Version</translation>
+<translation id="1377321085342047638">Card Number</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> didn’t send any data.</translation>
<translation id="1407135791313364759">Open all</translation>
<translation id="1413809658975081374">Privacy error</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">History</translation>
<translation id="1645368109819982629">Unsupported protocol</translation>
<translation id="1656489000284462475">Pick up</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>
<translation id="1676269943528358898"><ph name="SITE" /> normally uses encryption to protect your information. When Google Chrome tried to connect to <ph name="SITE" /> this time, the website sent back unusual and incorrect credentials. This may happen when an attacker is trying to pretend to be <ph name="SITE" />, or a Wi-Fi sign-in screen has interrupted the connection. Your information is still secure because Google Chrome stopped the connection before any data was exchanged.</translation>
<translation id="168328519870909584">Attackers currently on <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> might attempt to install dangerous apps on your device that steal or delete your information (for example, photos, passwords, messages and credit cards).</translation>
<translation id="168841957122794586">The server certificate contains a weak cryptographic key.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">You need permission from <ph name="NAME" /> to visit this site</translation>
+<translation id="1721424275792716183">* Field is required</translation>
<translation id="1728677426644403582">You're viewing the source of a web page</translation>
+<translation id="173080396488393970">This type of card isn’t supported</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Try contacting the system admin.</translation>
+<translation id="1740951997222943430">Enter a valid expiry month</translation>
<translation id="1745358365027406341">Download page later</translation>
<translation id="17513872634828108">Open tabs</translation>
<translation id="1753706481035618306">Page number</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Please update your sync passphrase.</translation>
<translation id="1787142507584202372">Your open tabs appear here</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Select a delivery address to check delivery methods and requirements.</translation>
+<translation id="1803264062614276815">Cardholder Name</translation>
<translation id="1803678881841855883">Google Safe Browsing recently <ph name="BEGIN_LINK" />detected malware<ph name="END_LINK" /> on <ph name="SITE" />. Websites that are normally safe are sometimes infected with malware. The malicious content comes from <ph name="SUBRESOURCE_HOST" />, a known malware distributor. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Added <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Invalid request or request parameters</translation>
<translation id="1826516787628120939">Checking</translation>
<translation id="1834321415901700177">This site contains harmful programs</translation>
<translation id="1842969606798536927">Pay</translation>
-<translation id="1864455488461349376">Delivery option</translation>
<translation id="1871208020102129563">Proxy is set to use fixed proxy servers, not a .pac script URL.</translation>
<translation id="1871284979644508959">Required field</translation>
<translation id="187918866476621466">Open startup pages</translation>
<translation id="1883255238294161206">Collapse list</translation>
<translation id="1898423065542865115">Filtering</translation>
<translation id="194030505837763158">Go to <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Cards accepted</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> Bookmarks</translation>
<translation id="1973335181906896915">Serialisation error</translation>
<translation id="1974060860693918893">Advanced</translation>
<translation id="1978555033938440688">Firmware Version</translation>
+<translation id="1995859865337580572">Please verify your CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{and 1 more}other{and # more}}</translation>
-<translation id="2020194265157481222">Name on card required</translation>
<translation id="2025186561304664664">Proxy is set to auto-configured.</translation>
<translation id="2030481566774242610">Did you mean <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Checking the proxy and the firewall<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Today</translation>
<translation id="2154054054215849342">Sync is not available for your domain</translation>
<translation id="2154484045852737596">Edit card</translation>
-<translation id="2156993118928861787">Invalid address</translation>
<translation id="2166049586286450108">Full Admin Access</translation>
<translation id="2166378884831602661">This site can’t provide a secure connection</translation>
<translation id="2181821976797666341">Policies</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 address}other{# addresses}}</translation>
+<translation id="2202020181578195191">Enter a valid expiry year</translation>
<translation id="2212735316055980242">Policy not found</translation>
<translation id="2213606439339815911">Fetching entries...</translation>
<translation id="2230458221926704099">Fix your connection using the <ph name="BEGIN_LINK" />diagnostics app<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Your Internet access is blocked</translation>
<translation id="230155334948463882">New card?</translation>
<translation id="2305919008529760154">This server could not prove that it is <ph name="DOMAIN" />; its security certificate might have been issued fraudulently. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Card and address options are from your Google account (<ph name="ACCOUNT_EMAIL" />) and Chrome. You can manage these in <ph name="BEGIN_LINK" />Settings<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> requires a username and password.</translation>
<translation id="2318774815570432836">You cannot visit <ph name="SITE" /> at the moment because the website uses HSTS. Network errors and attacks are usually temporary, so this page will probably work later. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Other bookmarks</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Enterprise default</translation>
<translation id="2386255080630008482">Server's certificate has been revoked</translation>
<translation id="2392959068659972793">Show policies with no value set</translation>
+<translation id="239429038616798445">This delivery method isn’t available. Try a different method.</translation>
<translation id="2396249848217231973">&amp;Undo delete</translation>
<translation id="2460160116472764928">Google Safe Browsing recently <ph name="BEGIN_LINK" />detected malware<ph name="END_LINK" /> on <ph name="SITE" />. Websites that are normally safe are sometimes infected with malware. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Fill in</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Running Network Diagnostics<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Invalid search URL.</translation>
<translation id="2491120439723279231">Server's certificate contains errors.</translation>
-<translation id="24943777258388405">Invalid phone number</translation>
<translation id="2495083838625180221">JSON Parser</translation>
<translation id="2495093607237746763">If ticked, Chromium will store a copy of your card on this device for faster form filling.</translation>
<translation id="2498091847651709837">Scan new card</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> sent an invalid response.</translation>
<translation id="2552545117464357659">Newer</translation>
<translation id="2556876185419854533">&amp;Undo Edit</translation>
+<translation id="2587730715158995865">From <ph name="ARTICLE_PUBLISHER" />. Read this and <ph name="OTHER_ARTICLE_COUNT" /> other stories.</translation>
<translation id="2587841377698384444">Directory API ID:</translation>
<translation id="2597378329261239068">This document is password-protected. Please enter a password.</translation>
<translation id="2609632851001447353">Variations</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Running Connectivity Diagnostics<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">Remove selected items</translation>
+<translation id="277133753123645258">Delivery method</translation>
<translation id="277499241957683684">Missing device record</translation>
<translation id="2784949926578158345">The connection was reset.</translation>
<translation id="2794233252405721443">Site blocked</translation>
-<translation id="2812680587231492111">That pickup option isn’t available. Try a different option.</translation>
<translation id="2824775600643448204">Address and search bar</translation>
<translation id="2826760142808435982">The connection is encrypted and authenticated using <ph name="CIPHER" /> and uses <ph name="KX" /> as the key exchange mechanism.</translation>
<translation id="2835170189407361413">Clear form</translation>
-<translation id="2849041323157393173">That delivery option isn’t available. Try a different option.</translation>
<translation id="2889159643044928134">Don't reload</translation>
<translation id="2900469785430194048">Google Chrome ran out of memory while trying to display this web page.</translation>
<translation id="2909946352844186028">A network change was detected.</translation>
<translation id="2916038427272391327">Close other programmes</translation>
<translation id="2922350208395188000">Server's certificate cannot be checked.</translation>
+<translation id="2928905813689894207">Billing Address</translation>
<translation id="2948083400971632585">You can disable any proxies configured for a connection from the settings page.</translation>
<translation id="2955913368246107853">Close find bar</translation>
<translation id="2958431318199492670">The network configuration doesn't comply to the ONC standard. Parts of the configuration may not be imported.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">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, Google Chrome cannot verify these certificates.</translation>
<translation id="2972581237482394796">&amp;Redo</translation>
<translation id="2985306909656435243">If enabled, Chromium will store a copy of your card on this device for faster form filling.</translation>
+<translation id="2985398929374701810">Enter a valid address</translation>
+<translation id="2986368408720340940">This pickup method isn’t available. Try a different method.</translation>
<translation id="2991174974383378012">Sharing with Websites</translation>
<translation id="3005723025932146533">Show saved copy</translation>
<translation id="3008447029300691911">Enter the CVC for <ph name="CREDIT_CARD" />. Once you confirm, your card details will be shared with this site.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{at least 1 item on synced devices}=1{1 item (and more on synced devices)}other{# items (and more on synced devices)}}</translation>
<translation id="3041612393474885105">Certificate Information</translation>
<translation id="3063697135517575841">Chrome was unable to confirm your card at this time. Please try again later.</translation>
+<translation id="3064966200440839136">Leaving incognito mode to pay via an external application. Continue?</translation>
<translation id="3093245981617870298">You are offline</translation>
<translation id="3105172416063519923">Asset ID:</translation>
<translation id="3109728660330352905">You don't have authorisation to view this page.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Try running Connectivity Diagnostics<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Failed to decode response</translation>
-<translation id="3149891296864842641">Delivery option</translation>
<translation id="3150653042067488994">Temporary server error</translation>
+<translation id="3154506275960390542">This page includes a form that may not submit securely. Data that you send can be viewed by others while in transit or could be modified by an attacker to change what the server receives.</translation>
<translation id="3157931365184549694">Restore</translation>
<translation id="3167968892399408617">Pages that you view in incognito tabs won’t stick around in your browser’s history, cookie store or search history after you’ve closed all of your incognito tabs. Any files you download or bookmarks you create will be kept.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Your request to access this site could not be sent to <ph name="NAME" />. Please try again.</translation>
<translation id="3355823806454867987">Change proxy settings...</translation>
<translation id="3369192424181595722">Clock error</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> more items...</translation>
<translation id="337363190475750230">Deprovisioned</translation>
<translation id="3377188786107721145">Policy parse error</translation>
<translation id="3380365263193509176">Unknown error</translation>
<translation id="3380864720620200369">Client ID:</translation>
<translation id="3391030046425686457">Delivery address</translation>
+<translation id="3395827396354264108">Pickup method</translation>
<translation id="340013220407300675">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).</translation>
<translation id="3422248202833853650">Try exiting other programmes to free up memory.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> is currently unreachable.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Fetch interval:</translation>
<translation id="3462200631372590220">Hide advanced</translation>
+<translation id="3467763166455606212">Cardholder name required</translation>
+<translation id="3478058380795961209">Month of Expiry</translation>
<translation id="3479539252931486093">Was this unexpected? <ph name="BEGIN_LINK" />Let us know<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Not now</translation>
<translation id="348000606199325318">Crash ID <ph name="CRASH_LOCAL_ID" /> (Server ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">We could not reach your parent at the moment. Please try again.</translation>
<translation id="3528171143076753409">Server's certificate is not trusted</translation>
-<translation id="3538531656504267329">Invalid expiry year</translation>
<translation id="3539171420378717834">Keep a copy of this card on this device</translation>
<translation id="3542684924769048008">Use password for:</translation>
<translation id="3549644494707163724">Encrypt all synced data with your own sync passphrase</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Hide details</translation>
<translation id="3587482841069643663">All</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Enter a valid expiry date</translation>
<translation id="36224234498066874">Clear Browsing Data...</translation>
<translation id="362276910939193118">Show Full History</translation>
<translation id="3623476034248543066">Show value</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Password:</translation>
<translation id="3696411085566228381">none</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Select a delivery address to check delivery methods and requirements.</translation>
<translation id="370665806235115550">Loading...</translation>
<translation id="3712624925041724820">Licenses exhausted</translation>
<translation id="3714780639079136834">Turning on mobile data or Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Link that you copied</translation>
<translation id="375403751935624634">The translation failed because of a server error.</translation>
<translation id="3759461132968374835">You have no recently reported crashes. Crashes that occurred when crash reporting was disabled will not appear here.</translation>
+<translation id="3787705759683870569">Expires <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">If you use a proxy server...</translation>
<translation id="3828924085048779000">Empty passphrase is not allowed.</translation>
<translation id="3845539888601087042">Showing history from your signed-in devices. <ph name="BEGIN_LINK" />Find out more<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Do you want Chromium to save this card?</translation>
<translation id="4171400957073367226">Bad verification signature</translation>
-<translation id="4176463684765177261">Disabled</translation>
<translation id="4196861286325780578">&amp;Redo move</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Checking firewall and antivirus configurations<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{none}=1{1 app ($1)}=2{2 apps ($1, $2)}other{# apps ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">search results</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> didn’t accept your login certificate, or one may not have been provided.</translation>
<translation id="443673843213245140">Use of a proxy is disabled but an explicit proxy configuration is specified.</translation>
-<translation id="4446242550670694251">Now you can browse in private and other people who use this device won’t see your activity.</translation>
<translation id="4492190037599258964">Search results for '<ph name="SEARCH_STRING" />'</translation>
<translation id="4506176782989081258">Validation error: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Contacting the system admin</translation>
<translation id="450710068430902550">Sharing with Administrator</translation>
+<translation id="4515275063822566619">Cards and addresses are from Chrome and your Google account (<ph name="ACCOUNT_EMAIL" />). You can manage them in <ph name="BEGIN_LINK" />Settings<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Details</translation>
<translation id="4558551763791394412">Try disabling your extensions.</translation>
<translation id="457875822857220463">Delivery</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Fit to page</translation>
<translation id="483020001682031208">No Physical Web pages to show</translation>
<translation id="4850886885716139402">View</translation>
+<translation id="4854362297993841467">This delivery method isn’t available. Try a different method.</translation>
<translation id="4858792381671956233">You asked your parents if it's OK to visit this site</translation>
<translation id="4880827082731008257">Search history</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">This page has been translated from an unknown language into <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Payment</translation>
<translation id="4926049483395192435">Must be specified.</translation>
-<translation id="4941291666397027948">* indicates required field</translation>
<translation id="495170559598752135">Actions</translation>
<translation id="4958444002117714549">Expand list</translation>
<translation id="4962322354953122629">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not trusted by Chrome. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Incorrect password</translation>
<translation id="5056549851600133418">Articles for you</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Checking the proxy address<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{No cookies}=1{1 site uses cookies. }other{# sites use cookies. }}</translation>
<translation id="5087286274860437796">Server's certificate is not valid at this time.</translation>
<translation id="5087580092889165836">Add card</translation>
<translation id="5089810972385038852">County</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Show</translation>
<translation id="5308689395849655368">Crash reporting is disabled.</translation>
<translation id="5317780077021120954">Save</translation>
-<translation id="5326702247179446998">Recipient required</translation>
<translation id="5327248766486351172">Name</translation>
<translation id="5337705430875057403">Attackers on <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> may trick you into doing something dangerous like installing software or revealing your personal information (for example, passwords, phone numbers or credit cards).</translation>
-<translation id="53553865750799677">Unsupported pickup address. Select a different address.</translation>
<translation id="5359637492792381994">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not valid at this time. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Failed to store policy settings</translation>
<translation id="5386426401304769735">The certificate chain for this site contains a certificate signed using SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">An embedded page at <ph name="SITE" /> says:</translation>
<translation id="5556459405103347317">Reload</translation>
<translation id="5565735124758917034">Active</translation>
+<translation id="5571083550517324815">Can’t pick up from this address. Select a different address.</translation>
<translation id="5572851009514199876">Please start and sign in to Chrome so that Chrome can check whether you are allowed to access this site.</translation>
-<translation id="5575380383496039204">Unsupported delivery address. Select a different address.</translation>
<translation id="5580958916614886209">Check your expiry month and try again</translation>
<translation id="560412284261940334">Management not supported</translation>
<translation id="5610142619324316209">Checking the connection</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">The identity of this website has not been verified.</translation>
<translation id="5720705177508910913">Current user</translation>
<translation id="5732392974455271431">Your parents can unblock it for you</translation>
-<translation id="57586589942790530">Invalid card number</translation>
+<translation id="5763042198335101085">Enter a valid email address</translation>
+<translation id="5765072501007116331">To see delivery methods and requirements, select an address</translation>
<translation id="5784606427469807560">There was a problem confirming your card. Check your Internet connection and try again.</translation>
<translation id="5785756445106461925">Further, this page includes other resources which are not secure. These resources can be viewed by others while in transit, and can be modified by an attacker to change the look of the page.</translation>
<translation id="5786044859038896871">Do you want to fill in your card info?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">This site can’t be reached</translation>
<translation id="5869522115854928033">Saved passwords</translation>
<translation id="5872918882028971132">Parent Suggestions</translation>
-<translation id="587760065310675640">Unsupported delivery address. Select a different address.</translation>
<translation id="5901630391730855834">Yellow</translation>
-<translation id="59174027418879706">Enabled</translation>
<translation id="5926846154125914413">You may lose access to premium content from some sites.</translation>
<translation id="5959728338436674663">Automatically send some <ph name="BEGIN_WHITEPAPER_LINK" />system information and page content<ph name="END_WHITEPAPER_LINK" /> to Google to help detect dangerous apps and sites. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Week</translation>
<translation id="5967867314010545767">Remove from history</translation>
<translation id="5975083100439434680">Zoom out</translation>
+<translation id="598637245381783098">Can’t open payment app</translation>
<translation id="5989320800837274978">Neither fixed proxy servers nor a .pac script URL are specified.</translation>
<translation id="5990559369517809815">Requests to the server have been blocked by an extension.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Card and address options are from Chrome. You can manage these in <ph name="BEGIN_LINK" />Settings<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Page 1}other{Page #}}</translation>
<translation id="6017514345406065928">Green</translation>
+<translation id="6027201098523975773">Enter a name</translation>
<translation id="6040143037577758943">Close</translation>
-<translation id="604124094241169006">Automatic</translation>
<translation id="6042308850641462728">More</translation>
<translation id="6060685159320643512">Careful, these experiments may bite</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{none}=1{1}other{#}}</translation>
@@ -543,9 +552,10 @@
devices you may be using.</translation>
<translation id="614940544461990577">Try:</translation>
<translation id="6151417162996330722">The server certificate has a validity period that is too long.</translation>
-<translation id="615643356032862689">Downloaded files and bookmarks will be kept.</translation>
+<translation id="6157877588268064908">To see delivery methods and requirements, select an address</translation>
<translation id="6165508094623778733">Learn more</translation>
<translation id="6177128806592000436">Your connection to this site is not secure</translation>
+<translation id="6184817833369986695">(cohort: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Check your Internet connection</translation>
<translation id="6218753634732582820">Remove address from Chromium?</translation>
<translation id="6251924700383757765">Privacy Policy</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Redo Reorder</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> bookmarks</translation>
<translation id="6264485186158353794">Back to safety</translation>
+<translation id="6276112860590028508">Pages from your reading list appear here</translation>
+<translation id="6280223929691119688">Can’t deliver to this address. Select a different address.</translation>
<translation id="6282194474023008486">Postcode</translation>
<translation id="6290238015253830360">Your suggested articles appear here</translation>
<translation id="6305205051461490394"><ph name="URL" /> is unreachable.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Unable to check whether the certificate has been revoked.</translation>
<translation id="6433490469411711332">Edit contact info</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> refused to connect.</translation>
-<translation id="6443118737398455446">Invalid expiry date</translation>
<translation id="6446608382365791566">Add more information</translation>
<translation id="6451458296329894277">Confirm Form Resubmission</translation>
<translation id="6456339708790392414">Your Payment</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">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. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Device policies</translation>
<translation id="6477321094435799029">Chrome detected unusual code on this page and blocked it to protect your personal information (for example, passwords, phone numbers and credit cards).</translation>
-<translation id="6477460825583319731">Invalid email address</translation>
<translation id="6489534406876378309">Start uploading crashes</translation>
<translation id="6508722015517270189">Restart Chrome</translation>
-<translation id="6525462735697194615">Invalid expiration month</translation>
<translation id="6529602333819889595">&amp;Redo Delete</translation>
<translation id="6534179046333460208">Physical Web suggestions</translation>
<translation id="6550675742724504774">Options</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Search</translation>
<translation id="6644283850729428850">This policy has been deprecated.</translation>
<translation id="6652240803263749613">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. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">That delivery option isn’t available. Try a different option.</translation>
<translation id="6671697161687535275">Remove form suggestion from Chromium?</translation>
<translation id="6685834062052613830">Sign out and complete setup</translation>
<translation id="6710213216561001401">Previous</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">There is something wrong with the proxy server or the address is incorrect.</translation>
<translation id="6727102863431372879">Set</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{none}=1{1 item}other{# items}}</translation>
-<translation id="6743044928064272573">Pickup option</translation>
<translation id="674375294223700098">Unknown server certificate error.</translation>
<translation id="6753269504797312559">Policy Value</translation>
<translation id="6757797048963528358">Your device went to sleep.</translation>
<translation id="6778737459546443941">Your parent hasn't approved it yet</translation>
<translation id="6810899417690483278">Customisation ID</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Failed loading regions data</translation>
<translation id="6831043979455480757">Translate</translation>
<translation id="6839929833149231406">Area</translation>
<translation id="6874604403660855544">&amp;Redo add</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Your card is confirmed</translation>
<translation id="6897140037006041989">User Agent</translation>
<translation id="6915804003454593391">User:</translation>
+<translation id="6948701128805548767">To see pickup methods and requirements, select an address</translation>
<translation id="6957887021205513506">The server's certificate appears to be a forgery.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Device</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">Both fixed proxy servers and a .pac script URL are specified.</translation>
<translation id="6989763994942163495">+ Show advanced settings</translation>
<translation id="7000990526846637657">No history entries found</translation>
-<translation id="7001663382399377034">Add recipient</translation>
<translation id="7009986207543992532">You attempted to reach <ph name="DOMAIN" />, but the server presented a certificate whose validity period is too long to be trustworthy. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Your Google account may have other forms of browsing history at <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Older</translation>
<translation id="7090678807593890770">Search Google for <ph name="LINK" /></translation>
<translation id="7119414471315195487">Close other tabs or programmes</translation>
+<translation id="7129409597930077180">Can’t deliver to this address. Select a different address.</translation>
+<translation id="7138472120740807366">Delivery method</translation>
<translation id="7139724024395191329">Emirate</translation>
<translation id="7155487117670177674">Payment not secure</translation>
<translation id="7179921470347911571">Relaunch Now</translation>
<translation id="7180611975245234373">Refresh</translation>
<translation id="7182878459783632708">No policies set</translation>
<translation id="7186367841673660872">This page has been translated from<ph name="ORIGINAL_LANGUAGE" />to<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> doesn't adhere to security standards.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Learn more<ph name="END_LINK" /> about this problem.</translation>
@@ -675,7 +686,6 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="7424977062513257142">An embedded page on this webpage says:</translation>
<translation id="7441627299479586546">Wrong policy subject</translation>
<translation id="7444046173054089907">This site is blocked</translation>
-<translation id="7444238235002594607">Select a pickup address to check pickup methods and requirements.</translation>
<translation id="7445762425076701745">The identity of the server to which you are connected cannot be fully validated. You are connected to a server using a name valid only within your network, and an external certificate authority has no way to validate ownership. As some certificate authorities will issue certificates for these names regardless, there is no way to ensure that you are connected to the intended website and not to an attacker.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Find out more<ph name="END_LINK" /> about this problem.</translation>
<translation id="7460163899615895653">Your recent tabs from other devices appear here</translation>
@@ -719,6 +729,7 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="7755287808199759310">Your parent can unblock it for you</translation>
<translation id="7758069387465995638">Firewall or antivirus software may have blocked the connection.</translation>
<translation id="7761701407923456692">Server's certificate does not match the URL.</translation>
+<translation id="7763386264682878361">Payment Manifest Parser</translation>
<translation id="7764225426217299476">Add address</translation>
<translation id="777702478322588152">Prefecture</translation>
<translation id="7791543448312431591">Add</translation>
@@ -732,6 +743,7 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="785549533363645510">However, you aren’t invisible. Going incognito doesn’t hide your browsing from your employer, your Internet service provider or the websites that you visit.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Check your CVC and try again</translation>
+<translation id="79338296614623784">Enter a valid phone number</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Server's certificate is not yet valid.</translation>
<translation id="7942349550061667556">Red</translation>
@@ -751,6 +763,7 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="8088680233425245692">Failed to view article.</translation>
<translation id="8089520772729574115">less than 1 MB</translation>
<translation id="8091372947890762290">Activation is pending on the server</translation>
+<translation id="8118489163946903409">Payment method</translation>
<translation id="8131740175452115882">Confirm</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" />’s server <ph name="BEGIN_ABBR" />DNS address<ph name="END_ABBR" /> could not be found.</translation>
<translation id="8149426793427495338">Your computer went to sleep.</translation>
@@ -776,6 +789,7 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="8349305172487531364">Bookmarks bar</translation>
<translation id="8363502534493474904">Turning off aeroplane mode</translation>
<translation id="8364627913115013041">Not set.</translation>
+<translation id="8368476060205742148">Google Play services</translation>
<translation id="8380941800586852976">Dangerous</translation>
<translation id="8382348898565613901">Your recently visited bookmarks appear here</translation>
<translation id="8398259832188219207">Crash report uploaded on <ph name="UPLOAD_TIME" /></translation>
@@ -784,31 +798,29 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="8428213095426709021">Settings</translation>
<translation id="8433057134996913067">This will sign you out of most websites.</translation>
<translation id="8437238597147034694">&amp;Undo move</translation>
-<translation id="8456681095658380701">Invalid name</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 credit card}other{# credit cards}}</translation>
<translation id="8483780878231876732">To use cards from your Google account, sign in to Chrome</translation>
<translation id="8488350697529856933">Applies to</translation>
-<translation id="8492969205326575646">Unsupported card type</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> took too long to respond.</translation>
<translation id="852346902619691059">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not trusted by your device's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Year of Expiry</translation>
<translation id="8543181531796978784">You can <ph name="BEGIN_ERROR_LINK" />report a detection problem<ph name="END_ERROR_LINK" /> or, if you understand the risks to your security, <ph name="BEGIN_LINK" />visit this unsafe site<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">The translation failed because the page's language could not be determined.</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="8570229484593575558">This information |won’t be saved|:#Your browsing history#Your searches#Cookie data</translation>
<translation id="8571890674111243710">Translating page into <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Your activity |might still be visible| to:#Websites you visit#Your employer#Your internet service provider</translation>
<translation id="858637041960032120">Add phone no.</translation>
<translation id="859285277496340001">The certificate does not specify a mechanism to check whether it has been revoked.</translation>
<translation id="8620436878122366504">Your parents haven't approved it yet</translation>
<translation id="8647750283161643317">Reset all to default</translation>
<translation id="8703575177326907206">Your connection to <ph name="DOMAIN" /> is not encrypted.</translation>
+<translation id="8718314106902482036">Payment not completed</translation>
<translation id="8725066075913043281">Try again</translation>
<translation id="8728672262656704056">You’ve gone incognito</translation>
<translation id="8730621377337864115">Finished</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="8759274551635299824">This card has expired</translation>
<translation id="8790007591277257123">&amp;Redo delete</translation>
-<translation id="8798099450830957504">Default</translation>
<translation id="8800988563907321413">Your nearby suggestions appear here</translation>
<translation id="8820817407110198400">Bookmarks</translation>
<translation id="883848425547221593">Other Bookmarks</translation>
@@ -818,6 +830,7 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="8866481888320382733">Error parsing policy settings</translation>
<translation id="8866959479196209191">This page says:</translation>
<translation id="8870413625673593573">Recently Closed</translation>
+<translation id="8874824191258364635">Enter a valid card number</translation>
<translation id="8876793034577346603">Network configuration failed to be parsed.</translation>
<translation id="8877192140621905067">Once you've confirm, your card details will be shared with this site</translation>
<translation id="8889402386540077796">Hue</translation>
@@ -827,7 +840,6 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="8931333241327730545">Do you want to save this card to your Google Account?</translation>
<translation id="8932102934695377596">Your clock is behind</translation>
<translation id="8954894007019320973">(Cont.)</translation>
-<translation id="895548565263634352">Read stories from <ph name="ARTICLE_PUBLISHER" /> and <ph name="OTHER_ARTICLE_COUNT" /> more</translation>
<translation id="8971063699422889582">Server's certificate has expired.</translation>
<translation id="8986494364107987395">Automatically send usage statistics and crash reports to Google</translation>
<translation id="8987927404178983737">Month</translation>
@@ -845,7 +857,6 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="9068849894565669697">Select colour</translation>
<translation id="9076283476770535406">It may have mature content</translation>
<translation id="9078964945751709336">More information required</translation>
-<translation id="9094175695478007090">Unable to launch payment app.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> normally uses encryption to protect your information. When Chromium tried to connect to <ph name="SITE" /> this time, the website sent back unusual and incorrect credentials. This may happen when an attacker is trying to pretend to be <ph name="SITE" />, or a Wi-Fi sign-in screen has interrupted the connection. Your information is still secure because Chromium stopped the connection before any data was exchanged.</translation>
<translation id="9137013805542155359">Show original</translation>
<translation id="9137248913990643158">Please start and sign in to Chrome before using this app.</translation>
diff --git a/chromium/components/strings/components_strings_es-419.xtb b/chromium/components/strings/components_strings_es-419.xtb
index 800bfd8759e..5b747a1b6b3 100644
--- a/chromium/components/strings/components_strings_es-419.xtb
+++ b/chromium/components/strings/components_strings_es-419.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="es-419">
<translation id="1008557486741366299">Ahora no</translation>
<translation id="1015730422737071372">Proporciona más detalles</translation>
+<translation id="1021110881106174305">Tarjetas aceptadas</translation>
<translation id="1032854598605920125">Girar a la derecha</translation>
<translation id="1038842779957582377">nombre desconocido</translation>
<translation id="1050038467049342496">Cierra las demás apps.</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Ocultar valor</translation>
<translation id="1228893227497259893">El identificador de la entidad es incorrecto.</translation>
<translation id="1232569758102978740">Sin título</translation>
+<translation id="1263231323834454256">Lista de lectura</translation>
<translation id="1264126396475825575">El informe de fallos se capturó el <ph name="CRASH_TIME" /> (todavía no se cargó ni se ignoró)</translation>
<translation id="1285320974508926690">Nunca traducir este sitio</translation>
<translation id="129553762522093515">Cerrado recientemente</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Configuración de la función Autocompletar de Chromium…</translation>
<translation id="1374468813861204354">sugerencias</translation>
<translation id="1375198122581997741">Acerca de la versión</translation>
+<translation id="1377321085342047638">N. tarjeta</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> no envió ningún dato.</translation>
<translation id="1407135791313364759">Abrir todas</translation>
<translation id="1413809658975081374">Error de privacidad</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Historial</translation>
<translation id="1645368109819982629">Protocolo no compatible</translation>
<translation id="1656489000284462475">Retiro</translation>
+<translation id="1663943134801823270">Las tarjetas y direcciones provienen de Chrome. Puedes administrarlas en <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> suele utilizar la encriptación para proteger la información. Cuando Google Chrome intentó conectarse a <ph name="SITE" />, el sitio web devolvió credenciales incorrectas y poco comunes. Es posible que un atacante quiera suplantar a <ph name="SITE" /> o que una pantalla de acceso Wi-Fi haya interrumpido la conexión. Tu información permanece segura porque Google Chrome detuvo la conexión para evitar el intercambio de datos.</translation>
<translation id="168328519870909584">Los atacantes que se encuentran actualmente en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podrían intentar instalar aplicaciones peligrosas en tu dispositivo con el objetivo de robarte información o borrarla (por ejemplo, fotos, contraseñas, mensajes y tarjetas de crédito).</translation>
<translation id="168841957122794586">El certificado del servidor contiene una clave criptográfica no segura.</translation>
<translation id="1710259589646384581">SO</translation>
<translation id="1721312023322545264">Necesitas permiso de <ph name="NAME" /> para visitar este sitio</translation>
+<translation id="1721424275792716183">* El campo es obligatorio</translation>
<translation id="1728677426644403582">Estás viendo la fuente de una página web</translation>
+<translation id="173080396488393970">No se acepta este tipo de tarjeta</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Intenta comunicarte con el administrador del sistema.</translation>
+<translation id="1740951997222943430">Ingresa una fecha de vencimiento válida</translation>
<translation id="1745358365027406341">Descargar la página más tarde</translation>
<translation id="17513872634828108">Pestañas abiertas</translation>
<translation id="1753706481035618306">Número de página</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Actualiza tu frase de contraseña de sincronización.</translation>
<translation id="1787142507584202372">Tus pestañas abiertas aparecen aquí</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Selecciona una dirección de entrega para comprobar los requisitos y medios de entrega.</translation>
+<translation id="1803264062614276815">Nombre del titular de la tarjeta</translation>
<translation id="1803678881841855883">Navegación segura de Google <ph name="BEGIN_LINK" />detectó software malicioso<ph name="END_LINK" /> en <ph name="SITE" /> recientemente. Los sitios web que por lo general son seguros a veces se infectan con software malicioso. El contenido malicioso proviene de <ph name="SUBRESOURCE_HOST" />, un conocido distribuidor de software malicioso. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1806541873155184440">Agregada: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Solicitud o parámetros de solicitud no válidos</translation>
<translation id="1826516787628120939">Comprobando</translation>
<translation id="1834321415901700177">Este sitio contiene programas dañinos</translation>
<translation id="1842969606798536927">Pagar</translation>
-<translation id="1864455488461349376">Opción de entrega</translation>
<translation id="1871208020102129563">El proxy está configurado para usar servidores proxy fijos, no una URL de script .pac.</translation>
<translation id="1871284979644508959">Campo obligatorio</translation>
<translation id="187918866476621466">Abrir páginas de inicio</translation>
<translation id="1883255238294161206">Ocultar lista</translation>
<translation id="1898423065542865115">Filtrado</translation>
<translation id="194030505837763158">Ir a <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Las tarjetas que se aceptan</translation>
<translation id="1962204205936693436">Favoritos de <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Error de serialización</translation>
<translation id="1974060860693918893">Avanzada</translation>
<translation id="1978555033938440688">Versión de firmware</translation>
+<translation id="1995859865337580572">Verifica tu CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{y 1 más}other{y # más}}</translation>
-<translation id="2020194265157481222">Se requiere el nombre en la tarjeta</translation>
<translation id="2025186561304664664">El proxy se estableció en configuración automática.</translation>
<translation id="2030481566774242610">¿Quisiste decir: <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Comprobar el proxy y el firewall<ph name="END_LINK" />.</translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Hoy</translation>
<translation id="2154054054215849342">El servicio de sincronización no está disponible para tu dominio</translation>
<translation id="2154484045852737596">Editar tarjeta</translation>
-<translation id="2156993118928861787">Dirección no válida</translation>
<translation id="2166049586286450108">Acceso de administrador completo</translation>
<translation id="2166378884831602661">Este sitio no puede proporcionar una conexión segura</translation>
<translation id="2181821976797666341">Políticas</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 dirección}other{# direcciones}}</translation>
+<translation id="2202020181578195191">Ingresa un año de vencimiento válido</translation>
<translation id="2212735316055980242">No se encontró la política.</translation>
<translation id="2213606439339815911">Recuperando entradas…</translation>
<translation id="2230458221926704099">Corregir la conexión con la <ph name="BEGIN_LINK" />app de diagnóstico<ph name="END_LINK" />.</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Se bloqueó tu acceso a Internet</translation>
<translation id="230155334948463882">¿Una tarjeta nueva?</translation>
<translation id="2305919008529760154">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el certificado de seguridad podría haberse emitido de forma fraudulenta. Es posible que se deba a una configuración incorrecta o a que un atacante haya interceptado tu conexión. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="230697611605700222">Las opciones de tarjeta y dirección son de tu cuenta de Google (<ph name="ACCOUNT_EMAIL" />) y Chrome. Puedes administrarlas en <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> requiere un nombre de usuario y una contraseña.</translation>
<translation id="2318774815570432836">No puedes visitar <ph name="SITE" /> ahora mismo porque el sitio web usa HSTS. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta página funcione más tarde. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2354001756790975382">Otros favoritos</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Empresa (predeterminada)</translation>
<translation id="2386255080630008482">Se ha revocado el certificado del servidor.</translation>
<translation id="2392959068659972793">Mostrar políticas sin valor establecido</translation>
+<translation id="239429038616798445">El método de envío no está disponible. Prueba otro método.</translation>
<translation id="2396249848217231973">&amp;Deshacer Eliminar</translation>
<translation id="2460160116472764928">Navegación segura de Google <ph name="BEGIN_LINK" />detectó software malicioso<ph name="END_LINK" /> en <ph name="SITE" /> recientemente. Los sitios web que por lo general son seguros a veces se infectan con software malicioso. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2463739503403862330">Llenar</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Ejecución del Diagnóstico de red<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL de búsqueda no válida</translation>
<translation id="2491120439723279231">El certificado del servidor contiene errores.</translation>
-<translation id="24943777258388405">Número de teléfono no válido</translation>
<translation id="2495083838625180221">Analizador de JSON</translation>
<translation id="2495093607237746763">Si marcas esta opción, Chromium almacenará una copia de la tarjeta en el dispositivo para completar más rápidamente los formularios.</translation>
<translation id="2498091847651709837">Escanear tarjeta nueva</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> envió una respuesta no válida.</translation>
<translation id="2552545117464357659">Reciente</translation>
<translation id="2556876185419854533">&amp;Deshacer Editar</translation>
+<translation id="2587730715158995865">De <ph name="ARTICLE_PUBLISHER" />. Lee este artículo y <ph name="OTHER_ARTICLE_COUNT" /> más.</translation>
<translation id="2587841377698384444">ID de API de directorio:</translation>
<translation id="2597378329261239068">Este documento está protegido por contraseña. Ingresa una contraseña.</translation>
<translation id="2609632851001447353">Variaciones</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Ejecución del Diagnóstico de conectividad<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">Aceptar</translation>
<translation id="2742870351467570537">Eliminar elementos seleccionados</translation>
+<translation id="277133753123645258">Método de envío</translation>
<translation id="277499241957683684">Falta un registro de dispositivo.</translation>
<translation id="2784949926578158345">Se ha restablecido la conexión.</translation>
<translation id="2794233252405721443">Sitio bloqueado</translation>
-<translation id="2812680587231492111">Esa opción no está disponible. Prueba con otra.</translation>
<translation id="2824775600643448204">Barra de direcciones y de búsqueda</translation>
<translation id="2826760142808435982">La conexión se encriptó y autenticó con <ph name="CIPHER" />, y utiliza <ph name="KX" /> como el mecanismo de intercambio de claves.</translation>
<translation id="2835170189407361413">Eliminar formulario</translation>
-<translation id="2849041323157393173">Esa opción de entrega no está disponible. Prueba con otra.</translation>
<translation id="2889159643044928134">No volver a cargar</translation>
<translation id="2900469785430194048">Google Chrome se quedó sin memoria cuando intentaba mostrar esta página web.</translation>
<translation id="2909946352844186028">Se detectó un cambio de red.</translation>
<translation id="2916038427272391327">Cierra los demás programas.</translation>
<translation id="2922350208395188000">No se puede comprobar el certificado del servidor.</translation>
+<translation id="2928905813689894207">Dirección de facturación</translation>
<translation id="2948083400971632585">Puedes inhabilitar los servidores proxy configurados para una conexión desde la página de configuración.</translation>
<translation id="2955913368246107853">Cerrar la barra de búsqueda</translation>
<translation id="2958431318199492670">La configuración de red no cumple con el estándar ONC. Es posible que no se importen algunas partes de la configuración.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Para establecer una conexión segura, el reloj se debe configurar 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, Google Chrome no puede verificar estos certificados.</translation>
<translation id="2972581237482394796">&amp;Rehacer</translation>
<translation id="2985306909656435243">Si se habilita esta opción, Chromium almacenará una copia de la tarjeta en el dispositivo para completar más rápidamente los formularios.</translation>
+<translation id="2985398929374701810">Ingresa una dirección válida</translation>
+<translation id="2986368408720340940">El método de retiro no está disponible. Prueba otro método.</translation>
<translation id="2991174974383378012">Compartir con los sitios web</translation>
<translation id="3005723025932146533">Mostrar copia guardada</translation>
<translation id="3008447029300691911">Ingresa el CVC de la tarjeta <ph name="CREDIT_CARD" />. Después de confirmarla, los datos de tu tarjeta se compartirán con este sitio.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{al menos 1 elemento en dispositivos sincronizados}=1{1 elemento (y más en dispositivos sincronizados)}other{# elementos (y más en dispositivos sincronizados)}}</translation>
<translation id="3041612393474885105">Información sobre el certificado</translation>
<translation id="3063697135517575841">Chrome no pudo confirmar tu tarjeta en este momento. Vuelve a intentarlo más tarde.</translation>
+<translation id="3064966200440839136">Saldrás del modo de navegación incógnito para pagar mediante una aplicación externa. ¿Deseas continuar?</translation>
<translation id="3093245981617870298">No estás conectado.</translation>
<translation id="3105172416063519923">ID de recurso:</translation>
<translation id="3109728660330352905">No tienes autorización para ver esta página.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Intenta ejecutar el Diagnóstico de conectividad<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Se produjo un error al decodificar respuesta.</translation>
-<translation id="3149891296864842641">Opción de envío</translation>
<translation id="3150653042067488994">Error temporal del servidor</translation>
+<translation id="3154506275960390542">Esta página incluye un formulario cuyo envío no es seguro. Es posible que otras personas vean los datos que envíes mientras están en tránsito o que un atacante los modifique antes de que los reciba el servidor.</translation>
<translation id="3157931365184549694">Restaurar</translation>
<translation id="3167968892399408617">Una vez que cierres todas las pestañas de incógnito, las páginas que hayas visitado en ese modo no se guardarán en el historial del navegador, en la lista de cookies ni en el historial de búsquedas. Se guardarán los archivos que descargues y los favoritos que crees.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -264,11 +272,13 @@
<translation id="3345135638360864351">No se pudo enviar la solicitud de acceso al sitio a <ph name="NAME" />. Vuelve a intentarlo.</translation>
<translation id="3355823806454867987">Cambiar la configuración del proxy...</translation>
<translation id="3369192424181595722">Error de reloj</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> artículos más…</translation>
<translation id="337363190475750230">Desaprovisionado</translation>
<translation id="3377188786107721145">Error al analizar la política</translation>
<translation id="3380365263193509176">Error desconocido</translation>
<translation id="3380864720620200369">ID de cliente:</translation>
<translation id="3391030046425686457">Dirección de entrega</translation>
+<translation id="3395827396354264108">Método de retiro</translation>
<translation id="340013220407300675">Es posible que usuarios no autorizados 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).</translation>
<translation id="3422248202833853650">Prueba cerrar los demás programas para liberar memoria.</translation>
<translation id="3422472998109090673">No se puede acceder a <ph name="HOST_NAME" /> en este momento.</translation>
@@ -279,12 +289,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Obtener intervalo:</translation>
<translation id="3462200631372590220">Ocultar detalles avanzados</translation>
+<translation id="3467763166455606212">Se requiere el nombre del titular de la tarjeta</translation>
+<translation id="3478058380795961209">Mes vencimiento</translation>
<translation id="3479539252931486093">¿Ocurrió algo inesperado? <ph name="BEGIN_LINK" />Cuéntanos<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Ahora no</translation>
<translation id="348000606199325318">ID de fallo <ph name="CRASH_LOCAL_ID" /> (ID de servidor: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">No pudimos comunicarnos con ninguno de tus padres. Vuelve a intentarlo.</translation>
<translation id="3528171143076753409">El certificado del servidor no es de confianza.</translation>
-<translation id="3538531656504267329">El año de vencimiento no es válido</translation>
<translation id="3539171420378717834">Conservar una copia de la tarjeta en el dispositivo.</translation>
<translation id="3542684924769048008">Utilizar la contraseña para:</translation>
<translation id="3549644494707163724">Encriptar todos los datos sincronizados con tu propia frase de contraseña para sincronización</translation>
@@ -297,6 +308,7 @@
<translation id="3586931643579894722">Ocultar detalles</translation>
<translation id="3587482841069643663">Todos</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Ingresa una fecha de vencimiento válida</translation>
<translation id="36224234498066874">Eliminar datos de navegación...</translation>
<translation id="362276910939193118">Mostrar historial completo</translation>
<translation id="3623476034248543066">Mostrar valor</translation>
@@ -313,7 +325,6 @@
<translation id="3693415264595406141">Contraseña:</translation>
<translation id="3696411085566228381">ninguno</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Selecciona una dirección de envío para comprobar los métodos y requisitos de envío.</translation>
<translation id="370665806235115550">Cargando...</translation>
<translation id="3712624925041724820">Licencias agotadas</translation>
<translation id="3714780639079136834">Activar los datos móviles o la conexión Wi-Fi.</translation>
@@ -322,6 +333,7 @@
<translation id="3739623965217189342">Vínculo copiado</translation>
<translation id="375403751935624634">Falló la traducción debido a un error de servidor.</translation>
<translation id="3759461132968374835">No has notificado ningún bloqueo recientemente. Los bloqueos que se hayan producido mientras la función de notificación de bloqueos estaba desactivada no aparecerán en esta página.</translation>
+<translation id="3787705759683870569">Vencimiento: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Si utilizas un servidor proxy...</translation>
<translation id="3828924085048779000">No se permite una frase de contraseña vacía.</translation>
<translation id="3845539888601087042">Se muestra el historial de los dispositivos a los que accediste. <ph name="BEGIN_LINK" />Más información<ph name="END_LINK" />.</translation>
@@ -357,7 +369,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">¿Quieres que Chromium guarde esta tarjeta?</translation>
<translation id="4171400957073367226">La firma de verificación no es válida.</translation>
-<translation id="4176463684765177261">Deshabilitado</translation>
<translation id="4196861286325780578">&amp;Rehacer Mover</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Comprobar las configuraciones de firewall y antivirus<ph name="END_LINK" />.</translation>
<translation id="4206349416402437184">{COUNT,plural, =0{ninguna}=1{1 app ($1)}=2{2 apps ($1, $2)}other{# apps ($1, $2, $3)}}</translation>
@@ -384,11 +395,11 @@
<translation id="4406896451731180161">resultados de búsqueda</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> no aceptó tu certificado de acceso o es posible que no se haya proporcionado.</translation>
<translation id="443673843213245140">Se inhabilitó el uso de un proxy, pero se especificó una configuración explícita de proxy.</translation>
-<translation id="4446242550670694251">Ahora puedes navegar de forma privada; las otras personas que usen este dispositivo no verán tu actividad.</translation>
<translation id="4492190037599258964">Resultados de búsqueda de '<ph name="SEARCH_STRING" />'</translation>
<translation id="4506176782989081258">Error de validación: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Comunicarse con el administrador del sistema.</translation>
<translation id="450710068430902550">Compartir con el administrador</translation>
+<translation id="4515275063822566619">Las tarjetas y direcciones provienen de Chrome y de tu cuenta de Google (<ph name="ACCOUNT_EMAIL" />). Puedes administrar esta información en <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Detalles</translation>
<translation id="4558551763791394412">Intenta inhabilitar tus extensiones.</translation>
<translation id="457875822857220463">Entrega</translation>
@@ -418,6 +429,7 @@
<translation id="4816492930507672669">Ajustar a la página</translation>
<translation id="483020001682031208">No hay páginas web físicas para mostrar</translation>
<translation id="4850886885716139402">Ver</translation>
+<translation id="4854362297993841467">Este método de entrega no está disponible. Prueba otro método.</translation>
<translation id="4858792381671956233">Les preguntaste a tus padres si puedes visitar este sitio</translation>
<translation id="4880827082731008257">Buscar historial</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -425,7 +437,6 @@
<translation id="4923417429809017348">Esta página ha sido traducida desde un idioma desconocido a <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Pago</translation>
<translation id="4926049483395192435">Debe especificarse un valor.</translation>
-<translation id="4941291666397027948">* indica que es un campo obligatorio</translation>
<translation id="495170559598752135">Acciones</translation>
<translation id="4958444002117714549">Mostrar lista</translation>
<translation id="4962322354953122629">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; Chrome no confía en el certificado de seguridad. Es posible que se deba a una configuración incorrecta o a que un atacante haya interceptado tu conexión. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -440,6 +451,7 @@
<translation id="5045550434625856497">Contraseña incorrecta</translation>
<translation id="5056549851600133418">Artículos para ti</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Comprobar la dirección de proxy<ph name="END_LINK" />.</translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Sin cookies}=1{1 sitio usa cookies. }other{# sitios usan cookies. }}</translation>
<translation id="5087286274860437796">El certificado del servidor no es válido en este momento.</translation>
<translation id="5087580092889165836">Agregar tarjeta</translation>
<translation id="5089810972385038852">Estado</translation>
@@ -462,10 +474,8 @@
<translation id="5300589172476337783">Mostrar</translation>
<translation id="5308689395849655368">Notificación de fallas desactivada.</translation>
<translation id="5317780077021120954">Guardar</translation>
-<translation id="5326702247179446998">Se requiere un destinatario</translation>
<translation id="5327248766486351172">Nombre</translation>
<translation id="5337705430875057403">Los atacantes de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podrían engañarte para que hagas algo peligroso, como instalar software o divulgar información personal (por ejemplo, contraseñas, números de teléfono o tarjetas de crédito).</translation>
-<translation id="53553865750799677">La dirección de retiro no es compatible. Selecciona otra dirección.</translation>
<translation id="5359637492792381994">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; su certificado de seguridad no es válido en este momento. Es posible que se deba a una configuración incorrecta o a que un atacante haya interceptado tu conexión. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Error al almacenar la configuración de la política</translation>
<translation id="5386426401304769735">La cadena del certificado de este sitio web contiene un certificado que se firmó con SHA-1.</translation>
@@ -491,8 +501,8 @@
<translation id="5544037170328430102">Una página incrustada en <ph name="SITE" /> dice:</translation>
<translation id="5556459405103347317">Cargar de nuevo</translation>
<translation id="5565735124758917034">Activo</translation>
+<translation id="5571083550517324815">No se puede retirar el artículo en esta dirección. Selecciona una diferente.</translation>
<translation id="5572851009514199876">Abre Chrome y accede a tu cuenta para que el programa pueda comprobar si puedes acceder a este sitio.</translation>
-<translation id="5575380383496039204">La dirección de entrega no es compatible. Selecciona otra dirección.</translation>
<translation id="5580958916614886209">Comprueba el mes de vencimiento y vuelve a intentarlo</translation>
<translation id="560412284261940334">No se admite la administración.</translation>
<translation id="5610142619324316209">Comprobar la conexión.</translation>
@@ -508,7 +518,8 @@
<translation id="5710435578057952990">No se ha verificado la identidad de este sitio web.</translation>
<translation id="5720705177508910913">Usuario actual</translation>
<translation id="5732392974455271431">Tus padres pueden desbloquearlo por ti</translation>
-<translation id="57586589942790530">Número de tarjeta no válido</translation>
+<translation id="5763042198335101085">Escribe una dirección de correo electrónico válida</translation>
+<translation id="5765072501007116331">Para ver los requisitos y métodos de entrega, selecciona una dirección</translation>
<translation id="5784606427469807560">Se produjo un problema al confirmar tu tarjeta. Comprueba tu conexión a Internet y vuelve a intentarlo.</translation>
<translation id="5785756445106461925">Además, esta página incluye otros recursos que no son seguros. Otras personas pueden ver estos recursos mientras se encuentran en tránsito, y un atacante puede modificarlos para cambiar la apariencia de la página.</translation>
<translation id="5786044859038896871">¿Deseas llenar los campos con la información de tu tarjeta?</translation>
@@ -521,22 +532,20 @@
<translation id="5869405914158311789">No se puede acceder a este sitio</translation>
<translation id="5869522115854928033">Contraseñas almacenadas</translation>
<translation id="5872918882028971132">Sugerencias para padres</translation>
-<translation id="587760065310675640">La dirección de envío no es compatible. Selecciona otra dirección.</translation>
<translation id="5901630391730855834">Amarillo</translation>
-<translation id="59174027418879706">Activado</translation>
<translation id="5926846154125914413">Es posible que ya no puedas acceder al contenido premium de otros sitios.</translation>
<translation id="5959728338436674663">Enviar automáticamente <ph name="BEGIN_WHITEPAPER_LINK" />determinado contenido de la página e información del sistema<ph name="END_WHITEPAPER_LINK" /> a Google para detectar apps y sitios peligrosos <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Semana</translation>
<translation id="5967867314010545767">Eliminar del historial</translation>
<translation id="5975083100439434680">Alejar</translation>
+<translation id="598637245381783098">No se puede abrir la app de pago</translation>
<translation id="5989320800837274978">No se especifican servidores proxy fijos ni URL de secuencias de comandos .pac.</translation>
<translation id="5990559369517809815">Una extensión bloqueó las solicitudes al servidor.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Las opciones de tarjeta y dirección son de Chrome. Puedes administrarlas en <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Página 1}other{Página #}}</translation>
<translation id="6017514345406065928">Verde</translation>
+<translation id="6027201098523975773">Ingresa un nombre</translation>
<translation id="6040143037577758943">Cerrar</translation>
-<translation id="604124094241169006">Automático</translation>
<translation id="6042308850641462728">Más</translation>
<translation id="6060685159320643512">Cuidado, estos experimentos pueden dañarte</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{ninguna}=1{1}other{#}}</translation>
@@ -544,9 +553,10 @@
de red que estés usando.</translation>
<translation id="614940544461990577">Intenta:</translation>
<translation id="6151417162996330722">El certificado de servidor tiene un período de validez demasiado extenso.</translation>
-<translation id="615643356032862689">Se mantendrán los archivos que descargues y los favoritos que agregues.</translation>
+<translation id="6157877588268064908">Para ver los requisitos y métodos de envío, selecciona una dirección</translation>
<translation id="6165508094623778733">Más información</translation>
<translation id="6177128806592000436">Tu conexión con este sitio no es segura</translation>
+<translation id="6184817833369986695">(cohorte: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Comprueba tu conexión a Internet.</translation>
<translation id="6218753634732582820">¿Confirmas que quieres quitar la dirección de Chromium?</translation>
<translation id="6251924700383757765">Política de privacidad</translation>
@@ -555,6 +565,8 @@
<translation id="6259156558325130047">&amp;Rehacer Reorganizar</translation>
<translation id="6263376278284652872">Favoritos de <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Volver a seguridad</translation>
+<translation id="6276112860590028508">Las páginas de tu lista de lectura aparecen aquí</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="6290238015253830360">Tus artículos sugeridos aparecen aquí</translation>
<translation id="6305205051461490394">No se puede acceder a <ph name="URL" />.</translation>
@@ -576,7 +588,6 @@
<translation id="6417515091412812850">No se pudo verificar si el certificado ha sido revocado.</translation>
<translation id="6433490469411711332">Editar la información de contacto</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> rechazó la conexión.</translation>
-<translation id="6443118737398455446">Fecha de caducidad no válida</translation>
<translation id="6446608382365791566">Agregar más información</translation>
<translation id="6451458296329894277">Confirmar reenvío del formulario</translation>
<translation id="6456339708790392414">Tu pago</translation>
@@ -584,10 +595,8 @@
<translation id="6462969404041126431">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; es posible que su certificado de seguridad se haya revocado. Es posible que se deba a una configuración incorrecta o a que un atacante haya interceptado tu conexión. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">Políticas de dispositivos</translation>
<translation id="6477321094435799029">Chrome detectó código inusual en esta página y la bloqueó para proteger tu información personal (p. ej.: contraseñas, números de teléfono y tarjetas de crédito).</translation>
-<translation id="6477460825583319731">Dirección de correo electrónico no válida</translation>
<translation id="6489534406876378309">Comenzar a cargar fallos</translation>
<translation id="6508722015517270189">Reinicia Chrome.</translation>
-<translation id="6525462735697194615">El mes de vencimiento no es válido</translation>
<translation id="6529602333819889595">&amp;Rehacer Eliminar</translation>
<translation id="6534179046333460208">Sugerencias de la Web física</translation>
<translation id="6550675742724504774">Opciones</translation>
@@ -602,7 +611,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Búsqueda</translation>
<translation id="6644283850729428850">Esta política no ha sido aprobada.</translation>
<translation id="6652240803263749613">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el sistema operativo de tu computadora no confía en el certificado de seguridad. Es posible que se deba a una configuración incorrecta o a que un atacante haya interceptado tu conexión. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="6665267558048410100">Esa opción de entrega no está disponible. Prueba con otra.</translation>
<translation id="6671697161687535275">¿Confirmas que quieres quitar la sugerencia de formulario de Chromium?</translation>
<translation id="6685834062052613830">Salir y completar la configuración</translation>
<translation id="6710213216561001401">Anterior</translation>
@@ -610,13 +618,13 @@
<translation id="6711464428925977395">Hay un error en el servidor proxy o la dirección es incorrecta.</translation>
<translation id="6727102863431372879">Establecer</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{ninguno}=1{1 elemento}other{# elementos}}</translation>
-<translation id="6743044928064272573">Opción de retiro</translation>
<translation id="674375294223700098">Error de certificado de servidor desconocido.</translation>
<translation id="6753269504797312559">Valor de la política</translation>
<translation id="6757797048963528358">El dispositivo se suspendió.</translation>
<translation id="6778737459546443941">Uno de tus padres aún no lo aprobó</translation>
<translation id="6810899417690483278">ID de personalización</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">No se pudo cargar los datos de las regiones</translation>
<translation id="6831043979455480757">Traducir</translation>
<translation id="6839929833149231406">Ãrea</translation>
<translation id="6874604403660855544">&amp;Rehacer Agregar</translation>
@@ -624,6 +632,7 @@
<translation id="6895330447102777224">Tu tarjeta se confirmó</translation>
<translation id="6897140037006041989">User agent</translation>
<translation id="6915804003454593391">Usuario:</translation>
+<translation id="6948701128805548767">Para ver los requisitos y métodos de retiro, selecciona una dirección</translation>
<translation id="6957887021205513506">El certificado del servidor parece falso.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Dispositivo</translation>
@@ -631,7 +640,6 @@
<translation id="6973656660372572881">Se especifican servidores proxy fijos y URL de secuencias de comandos .pac.</translation>
<translation id="6989763994942163495">Mostrar configuración avanzada...</translation>
<translation id="7000990526846637657">No se encontraron entradas en el historial</translation>
-<translation id="7001663382399377034">Agregar un destinatario</translation>
<translation id="7009986207543992532">Intentaste acceder a <ph name="DOMAIN" />, pero el certificado de servidor tenía un período de validez demasiado extenso para ser fiable. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Es posible que tu cuenta de Google tenga otros formularios del historial de navegación en <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -642,12 +650,15 @@
<translation id="7088615885725309056">Anterior</translation>
<translation id="7090678807593890770">Buscar <ph name="LINK" /> en Google</translation>
<translation id="7119414471315195487">Cierra las demás pestañas o programas.</translation>
+<translation id="7129409597930077180">No se pueden realizar envíos a esa dirección. Selecciona una dirección diferente.</translation>
+<translation id="7138472120740807366">Método de entrega</translation>
<translation id="7139724024395191329">Emirato</translation>
<translation id="7155487117670177674">Pago no seguro</translation>
<translation id="7179921470347911571">Reiniciar ahora</translation>
<translation id="7180611975245234373">Actualizar</translation>
<translation id="7182878459783632708">No hay políticas establecidas.</translation>
<translation id="7186367841673660872">Esta página se tradujo de<ph name="ORIGINAL_LANGUAGE" />a<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> no cumple con los estándares de seguridad.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Más información<ph name="END_LINK" /> acerca de este problema.</translation>
@@ -676,7 +687,6 @@
<translation id="7424977062513257142">Una página incrustada en esta página web dice:</translation>
<translation id="7441627299479586546">Nombre de usuario o dominio de política incorrecto</translation>
<translation id="7444046173054089907">Este sitio está bloqueado</translation>
-<translation id="7444238235002594607">Selecciona una dirección de retiro para comprobar los métodos y requisitos de retiro.</translation>
<translation id="7445762425076701745">La identidad del servidor al que estás conectado no se puede validar en su totalidad. Estás conectado a un servidor utilizando un nombre que sólo es válido dentro de tu red y cuya propiedad no puede validar una entidad externa de certificación. Debido a que algunas entidades emiten certificados aún para estos nombres, no hay manera de asegurar que estás conectado al sitio web que pretendías o a un atacante.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Más información<ph name="END_LINK" /> acerca de este problema</translation>
<translation id="7460163899615895653">Aquí aparecen tus pestañas recientes de otros dispositivos</translation>
@@ -720,6 +730,7 @@
<translation id="7755287808199759310">Uno de tus padres puede desbloquearlo por ti</translation>
<translation id="7758069387465995638">Es posible que un software antivirus o un firewarll hayan bloqueado la conexión.</translation>
<translation id="7761701407923456692">El certificado del servidor no coincide con la dirección URL.</translation>
+<translation id="7763386264682878361">Analizador del manifiesto de pagos</translation>
<translation id="7764225426217299476">Agregar dirección</translation>
<translation id="777702478322588152">Prefectura</translation>
<translation id="7791543448312431591">Agregar</translation>
@@ -733,6 +744,7 @@
<translation id="785549533363645510">Sin embargo, no eres invisible. El modo de navegación de incógnito no oculta tu navegación de tu empleador, de tu proveedor de servicios de Internet, ni de los sitios web que visitas.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Verifica tu CVC y vuelve a intentarlo.</translation>
+<translation id="79338296614623784">Ingresa un número de teléfono válido</translation>
<translation id="7935318582918952113">Filtro de DOM</translation>
<translation id="7938958445268990899">El certificado del servidor aún no es válido.</translation>
<translation id="7942349550061667556">Rojo</translation>
@@ -752,6 +764,7 @@
<translation id="8088680233425245692">Error al visualizar artículo</translation>
<translation id="8089520772729574115">menos de 1 Mb</translation>
<translation id="8091372947890762290">La activación está pendiente en el servidor.</translation>
+<translation id="8118489163946903409">Forma de pago</translation>
<translation id="8131740175452115882">Confirmar</translation>
<translation id="8134994873729925007">No se encontró la <ph name="BEGIN_ABBR" />dirección DNS<ph name="END_ABBR" /> del servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">La computadora se suspendió.</translation>
@@ -777,6 +790,7 @@
<translation id="8349305172487531364">Barra de favoritos</translation>
<translation id="8363502534493474904">Desactivar el modo de avión.</translation>
<translation id="8364627913115013041">Sin establecer</translation>
+<translation id="8368476060205742148">Servicios de Google Play</translation>
<translation id="8380941800586852976">Peligrosa</translation>
<translation id="8382348898565613901">Los favoritos que visitaste recientemente aparecen aquí</translation>
<translation id="8398259832188219207">El informe de fallos se cargó el <ph name="UPLOAD_TIME" /></translation>
@@ -785,32 +799,30 @@
<translation id="8428213095426709021">Configuración</translation>
<translation id="8433057134996913067">Si realizas esta acción, saldrás de la mayoría de los sitios web.</translation>
<translation id="8437238597147034694">&amp;Deshacer Mover</translation>
-<translation id="8456681095658380701">Nombre no válido</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 tarjeta de crédito}other{# tarjetas de crédito}}</translation>
<translation id="8483780878231876732">Para usar tarjetas de tu cuenta de Google, accede a tu cuenta en Chrome</translation>
<translation id="8488350697529856933">Se aplica a</translation>
-<translation id="8492969205326575646">Este tipo de tarjeta no es compatible</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> tardó demasiado en responder.</translation>
<translation id="852346902619691059">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el sistema operativo de tu dispositivo no confía en el certificado de seguridad. Es posible que se deba a una configuración incorrecta o a que un atacante haya interceptado tu conexión. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="8532105204136943229">Año vencimiento</translation>
<translation id="8543181531796978784">Puedes <ph name="BEGIN_ERROR_LINK" />informar un problema de detección<ph name="END_ERROR_LINK" /> o, si comprendes los riesgos de seguridad, puedes <ph name="BEGIN_LINK" />visitar el sitio no seguro<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Falló la traducción debido a que no se pudo determinar el idioma de la página.</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="8570229484593575558">Esta información |no se guardará|:#tu historial de navegación#tus búsquedas#los datos de cookies</translation>
<translation id="8571890674111243710">Traduciendo página a <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Es posible que tu actividad |no sea visible| para:#los sitios web que visitas#tu empleador#tu proveedor de servicios de Internet</translation>
<translation id="858637041960032120">Agregar teléfono
</translation>
<translation id="859285277496340001">El certificado no especifica un mecanismo para verificar si ha sido revocado.</translation>
<translation id="8620436878122366504">Tus padres aún no lo aprobaron</translation>
<translation id="8647750283161643317">Restablecer todos los valores predeterminados</translation>
<translation id="8703575177326907206">Tu conexión a <ph name="DOMAIN" /> no está cifrada.</translation>
+<translation id="8718314106902482036">No se completó el pago</translation>
<translation id="8725066075913043281">Intentar nuevamente</translation>
<translation id="8728672262656704056">Estás en modo incógnito</translation>
<translation id="8730621377337864115">Listo</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="8759274551635299824">La tarjeta está vencida</translation>
<translation id="8790007591277257123">&amp;Rehacer Eliminar</translation>
-<translation id="8798099450830957504">Predeterminado</translation>
<translation id="8800988563907321413">Las sugerencias de la sección Cercanas aparecen aquí</translation>
<translation id="8820817407110198400">Favoritos</translation>
<translation id="883848425547221593">Otros favoritos</translation>
@@ -820,6 +832,7 @@
<translation id="8866481888320382733">Error al analizar la configuración de la política</translation>
<translation id="8866959479196209191">Esta página dice:</translation>
<translation id="8870413625673593573">Cerrado recientemente</translation>
+<translation id="8874824191258364635">Ingresa un número de tarjeta válido</translation>
<translation id="8876793034577346603">No se pudo analizar la configuración de red.</translation>
<translation id="8877192140621905067">Después de que se confirme, los datos de tu tarjeta se compartirán con este sitio</translation>
<translation id="8889402386540077796">Tono</translation>
@@ -829,7 +842,6 @@
<translation id="8931333241327730545">¿Quieres guardar esta tarjeta en tu cuenta de Google?</translation>
<translation id="8932102934695377596">El reloj está atrasado</translation>
<translation id="8954894007019320973">(Cont.)</translation>
-<translation id="895548565263634352">Leer historias de <ph name="ARTICLE_PUBLISHER" /> y <ph name="OTHER_ARTICLE_COUNT" /> artículos más</translation>
<translation id="8971063699422889582">El certificado del servidor ha caducado.</translation>
<translation id="8986494364107987395">Enviar automáticamente estadísticas de uso e informes sobre fallos a Google</translation>
<translation id="8987927404178983737">Mes</translation>
@@ -847,7 +859,6 @@
<translation id="9068849894565669697">Seleccionar color</translation>
<translation id="9076283476770535406">Es posible que incluya contenido para adultos</translation>
<translation id="9078964945751709336">Se requiere más información</translation>
-<translation id="9094175695478007090">No se puede lanzar la app de pago.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> suele utilizar la encriptación para proteger la información. Cuando Chromium intentó conectarse a <ph name="SITE" />, el sitio web devolvió credenciales incorrectas y poco comunes. Es posible que un atacante quiera suplantar a <ph name="SITE" /> o que una pantalla de acceso Wi-Fi haya interrumpido la conexión. Tu información permanece segura porque Chromium detuvo la conexión para evitar el intercambio de datos.</translation>
<translation id="9137013805542155359">Mostrar original</translation>
<translation id="9137248913990643158">Abre Chrome y accede a tu cuenta antes de usar esta app.</translation>
diff --git a/chromium/components/strings/components_strings_es.xtb b/chromium/components/strings/components_strings_es.xtb
index 262ea2fa385..0c8ec0efe8d 100644
--- a/chromium/components/strings/components_strings_es.xtb
+++ b/chromium/components/strings/components_strings_es.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="es">
<translation id="1008557486741366299">Ahora no</translation>
<translation id="1015730422737071372">Proporciónanos más detalles</translation>
+<translation id="1021110881106174305">Tarjetas aceptadas</translation>
<translation id="1032854598605920125">Girar hacia la derecha</translation>
<translation id="1038842779957582377">nombre desconocido</translation>
<translation id="1050038467049342496">Cierra otras aplicaciones</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Ocultar valor</translation>
<translation id="1228893227497259893">Identificador de entidad incorrecto</translation>
<translation id="1232569758102978740">Sin título</translation>
+<translation id="1263231323834454256">Lista de lectura</translation>
<translation id="1264126396475825575">Informe sobre fallos registrado el <ph name="CRASH_TIME" /> (todavía no se ha subido ni ignorado)</translation>
<translation id="1285320974508926690">No traducir nunca este sitio</translation>
<translation id="129553762522093515">Cerrado recientemente</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Configuración de la función Autocompletar de Chromium...</translation>
<translation id="1374468813861204354">sugerencias</translation>
<translation id="1375198122581997741">Información de la versión</translation>
+<translation id="1377321085342047638">Número de tarjeta</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> no ha enviado ningún dato.</translation>
<translation id="1407135791313364759">Abrir todas</translation>
<translation id="1413809658975081374">Error de privacidad</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Historial</translation>
<translation id="1645368109819982629">Protocolo no admitido</translation>
<translation id="1656489000284462475">Recogida</translation>
+<translation id="1663943134801823270">Las tarjetas y las direcciones proceden de Chrome. Puedes gestionarlas en <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> utiliza normalmente el cifrado para proteger tu información. Cuando Google Chrome intentó establecer conexión con <ph name="SITE" />, el sitio web devolvió unas credenciales inusuales e incorrectas. Esto puede ocurrir si un atacante intenta suplantar la identidad de <ph name="SITE" /> o si una pantalla de inicio de sesión Wi-Fi interrumpe la conexión. Tu información sigue estando protegida, ya que Google Chrome detuvo la conexión antes de que se intercambiaran datos.</translation>
<translation id="168328519870909584">Los atacantes que se encuentran actualmente en el sitio <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podrían intentar instalar aplicaciones peligrosas en tu dispositivo para robar o eliminar tu información (como fotos, contraseñas, mensajes y tarjetas de crédito).</translation>
<translation id="168841957122794586">El certificado del servidor contiene una clave criptográfica no segura.</translation>
<translation id="1710259589646384581">Sistema operativo</translation>
<translation id="1721312023322545264">Necesitas permiso de <ph name="NAME" /> para acceder a este sitio web</translation>
+<translation id="1721424275792716183">* El campo es obligatorio</translation>
<translation id="1728677426644403582">Estás viendo el código fuente de una página web</translation>
+<translation id="173080396488393970">No se admite este tipo de tarjeta</translation>
<translation id="1734864079702812349">American Express</translation>
<translation id="1734878702283171397">Intenta ponerte en contacto con el administrador del sistema.</translation>
+<translation id="1740951997222943430">Introduce un mes de vencimiento válido</translation>
<translation id="1745358365027406341">Descargar la página más tarde</translation>
<translation id="17513872634828108">Pestañas abiertas</translation>
<translation id="1753706481035618306">Número de página</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Actualiza tu frase de contraseña de sincronización.</translation>
<translation id="1787142507584202372">Las pestañas abiertas aparecen aquí</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Selecciona una dirección de envío para consultar los métodos de envío y los requisitos.</translation>
+<translation id="1803264062614276815">Nombre del titular de la tarjeta</translation>
<translation id="1803678881841855883">La función de Navegación Segura de Google <ph name="BEGIN_LINK" />detectó software malicioso<ph name="END_LINK" /> recientemente en <ph name="SITE" />. En ocasiones, los sitios web que suelen ser seguros contienen software malicioso. Este contenido procede de <ph name="SUBRESOURCE_HOST" />, un conocido distribuidor de este tipo de software. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1806541873155184440">Añadida el <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Parámetros de solicitud o solicitud no válidos</translation>
<translation id="1826516787628120939">Comprobando</translation>
<translation id="1834321415901700177">Este sitio web contiene programas dañinos</translation>
<translation id="1842969606798536927">Pagar</translation>
-<translation id="1864455488461349376">Opción de envío</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>
<translation id="1871284979644508959">Campo obligatorio</translation>
<translation id="187918866476621466">Abrir páginas de inicio</translation>
<translation id="1883255238294161206">Contraer lista</translation>
<translation id="1898423065542865115">Filtrado</translation>
<translation id="194030505837763158">Ir a <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Tarjetas aceptadas</translation>
<translation id="1962204205936693436">Marcadores de <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Error de serialización</translation>
-<translation id="1974060860693918893">Opciones avanzadas</translation>
+<translation id="1974060860693918893">Configuración avanzada</translation>
<translation id="1978555033938440688">Versión de firmware</translation>
+<translation id="1995859865337580572">Verifica el CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{y una más}other{y # más}}</translation>
-<translation id="2020194265157481222">Se necesita el nombre de la tarjeta</translation>
<translation id="2025186561304664664">Se ha establecido que el proxy se configure automáticamente.</translation>
<translation id="2030481566774242610">¿Querías decir <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Comprobar el proxy y el cortafuegos<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Hoy</translation>
<translation id="2154054054215849342">La sincronización no está disponible para tu dominio</translation>
<translation id="2154484045852737596">Editar tarjeta</translation>
-<translation id="2156993118928861787">Dirección no válida</translation>
<translation id="2166049586286450108">Acceso de administrador completo</translation>
<translation id="2166378884831602661">Este sitio web no puede proporcionar una conexión segura</translation>
<translation id="2181821976797666341">Políticas</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{Una dirección}other{# direcciones}}</translation>
+<translation id="2202020181578195191">Introduce un año de vencimiento válido</translation>
<translation id="2212735316055980242">Política no encontrada</translation>
<translation id="2213606439339815911">Recuperando entradas...</translation>
<translation id="2230458221926704099">Soluciona los problemas de tu conexión con la <ph name="BEGIN_LINK" />aplicación de diagnóstico<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Tu acceso a Internet está bloqueado</translation>
<translation id="230155334948463882">¿Nueva tarjeta?</translation>
<translation id="2305919008529760154">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; su certificado de seguridad podría haberse emitido de forma fraudulenta. Este problema puede deberse a una configuración incorrecta o a que un atacante ha interceptado la conexión. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="230697611605700222">Las opciones de tarjetas y direcciones pertenecen a tu cuenta de Google (<ph name="ACCOUNT_EMAIL" />) y a Chrome. Puedes gestionarlas en <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> necesita un nombre de usuario y una contraseña.</translation>
<translation id="2318774815570432836">No puedes acceder a <ph name="SITE" /> en este momento por que el sitio web utiliza HSTS. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta página funcione más tarde. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2354001756790975382">Otros marcadores</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Empresa (con valores predeterminados)</translation>
<translation id="2386255080630008482">Se ha revocado el certificado de servidor.</translation>
<translation id="2392959068659972793">Mostrar políticas sin valores establecidos</translation>
+<translation id="239429038616798445">Este método de envío no está disponible. Selecciona otro.</translation>
<translation id="2396249848217231973">&amp;Deshacer eliminación</translation>
<translation id="2460160116472764928">La función de Navegación Segura de Google <ph name="BEGIN_LINK" />detectó software malicioso<ph name="END_LINK" /> recientemente en <ph name="SITE" />. En ocasiones, los sitios web que suelen ser seguros contienen software malicioso. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2463739503403862330">Rellenar</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Ejecutar Diagnósticos de red<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">La URL de búsqueda no es válida.</translation>
<translation id="2491120439723279231">El certificado del servidor contiene errores.</translation>
-<translation id="24943777258388405">Número de teléfono no válido</translation>
<translation id="2495083838625180221">Analizador de archivos JSON</translation>
<translation id="2495093607237746763">Si se activa esta opción, Chromium guardará una copia de tu tarjeta en este dispositivo para completar formularios más rápidamente.</translation>
<translation id="2498091847651709837">Escanear nueva tarjeta</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> ha enviado una respuesta no válida.</translation>
<translation id="2552545117464357659">Más recientes</translation>
<translation id="2556876185419854533">&amp;Deshacer edición</translation>
+<translation id="2587730715158995865">De <ph name="ARTICLE_PUBLISHER" />. Lee este y <ph name="OTHER_ARTICLE_COUNT" /> artículos más.</translation>
<translation id="2587841377698384444">ID de la API del directorio:</translation>
<translation id="2597378329261239068">Este documento está protegido por contraseña. Introduce una contraseña.</translation>
<translation id="2609632851001447353">Variaciones</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Ejecutar Diagnóstico de conectividad<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">Aceptar</translation>
<translation id="2742870351467570537">Eliminar elementos seleccionados</translation>
+<translation id="277133753123645258">Método de envío</translation>
<translation id="277499241957683684">Falta un registro de dispositivo.</translation>
<translation id="2784949926578158345">Se ha restablecido la conexión.</translation>
<translation id="2794233252405721443">Sito web bloqueado</translation>
-<translation id="2812680587231492111">Esa opción de recogida no está disponible. Prueba una diferente.</translation>
<translation id="2824775600643448204">Barra de direcciones y de búsqueda </translation>
<translation id="2826760142808435982">La conexión se ha encriptado y autenticado con <ph name="CIPHER" />, y utiliza <ph name="KX" /> como el mecanismo de intercambio clave.</translation>
<translation id="2835170189407361413">Eliminar formulario</translation>
-<translation id="2849041323157393173">Esa opción de envío no está disponible. Prueba una diferente.</translation>
<translation id="2889159643044928134">No volver a cargar</translation>
<translation id="2900469785430194048">Google Chrome se ha quedado sin memoria al intentar mostrar esta página web.</translation>
<translation id="2909946352844186028">Se ha detectado un cambio de red.</translation>
<translation id="2916038427272391327">Cierra otros programas</translation>
<translation id="2922350208395188000">No es posible comprobar el certificado del servidor.</translation>
+<translation id="2928905813689894207">Dirección de facturación</translation>
<translation id="2948083400971632585">Puedes inhabilitar los servidores proxy configurados para una conexión en la página de configuración.</translation>
<translation id="2955913368246107853">Cerrar la barra de búsqueda</translation>
<translation id="2958431318199492670">La configuración de red no cumple el estándar ONC. Es posible que no se importen partes de la configuración.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Para establecer una conexión segura, el reloj debe estar configurado correctamente. Esto se debe a que los certificados que utilizan los sitios web para identificarse solo son válidos para períodos de tiempo específicos. Como el reloj de tu dispositivo no está configurado correctamente, Google Chrome no puede verificar estos certificados.</translation>
<translation id="2972581237482394796">&amp;Rehacer</translation>
<translation id="2985306909656435243">Si se habilita esta opción, Chromium guardará una copia de tu tarjeta en este dispositivo para completar formularios más rápidamente.</translation>
+<translation id="2985398929374701810">Introduce una dirección válida</translation>
+<translation id="2986368408720340940">Este método de recogida no está disponible. Selecciona otro.</translation>
<translation id="2991174974383378012">Compartir con otros sitios web</translation>
<translation id="3005723025932146533">Mostrar copia guardada</translation>
<translation id="3008447029300691911">Introduce el código CVC de la tarjeta <ph name="CREDIT_CARD" />. Cuando la confirmes, su información se compartirá con este sitio web.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{al menos un elemento en dispositivos sincronizados}=1{un elemento (y otros elementos más en dispositivos sincronizados)}other{# elementos (y otros elementos más en dispositivos sincronizados)}}</translation>
<translation id="3041612393474885105">Datos del certificado</translation>
<translation id="3063697135517575841">Chrome no ha podido confirmar tu tarjeta en este momento. Vuelve a intentarlo más tarde.</translation>
+<translation id="3064966200440839136">Saldrás del modo incógnito para realizar un pago en una aplicación externa. ¿Quieres continuar?</translation>
<translation id="3093245981617870298">No tienes conexión.</translation>
<translation id="3105172416063519923">ID de recurso:</translation>
<translation id="3109728660330352905">No tienes autorización para ver esta página.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Prueba a ejecutar Diagnóstico de conectividad<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Error al decodificar respuesta</translation>
-<translation id="3149891296864842641">Opción de envío</translation>
<translation id="3150653042067488994">Error de servidor temporal</translation>
+<translation id="3154506275960390542">Es posible que un formulario de esta página no se envíe de forma segura. Otros usuarios pueden ver los datos que envías mientras estén en circulación y un atacante podría modificar lo que recibe el servidor.</translation>
<translation id="3157931365184549694">Restaurar</translation>
<translation id="3167968892399408617">Las páginas que aparezcan en las pestañas de incógnito no se guardarán en el historial del navegador, en el almacén de cookies ni en el historial de búsquedas una vez que hayas cerrado todas tus pestañas de incógnito. Se mantendrán los archivos que descargues o los marcadores que crees.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">No se ha podido enviar la solicitud de acceso a este sitio a <ph name="NAME" />. Vuelve a intentarlo.</translation>
<translation id="3355823806454867987">Cambiar la configuración de proxy...</translation>
<translation id="3369192424181595722">Error del reloj</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> elementos más...</translation>
<translation id="337363190475750230">Desaprovisionado</translation>
<translation id="3377188786107721145">Error al analizar la política</translation>
<translation id="3380365263193509176">Error desconocido</translation>
<translation id="3380864720620200369">ID de cliente:</translation>
<translation id="3391030046425686457">Dirección de entrega</translation>
+<translation id="3395827396354264108">Método de recogida</translation>
<translation id="340013220407300675">Es posible que los piratas informáticos 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).</translation>
<translation id="3422248202833853650">Prueba a salir de otros programas para liberar memoria.</translation>
<translation id="3422472998109090673">No se puede acceder a la página <ph name="HOST_NAME" /> en este momento.</translation>
@@ -277,13 +287,14 @@
<translation id="3447661539832366887">El propietario de este dispositivo ha desactivado el juego del dinosaurio.</translation>
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Intervalo de comprobación:</translation>
-<translation id="3462200631372590220">Ocultar opciones avanzadas</translation>
+<translation id="3462200631372590220">Ocultar configuración avanzada</translation>
+<translation id="3467763166455606212">El nombre del titular de la tarjeta es obligatorio</translation>
+<translation id="3478058380795961209">Mes de caducidad</translation>
<translation id="3479539252931486093">¿No te lo esperabas? <ph name="BEGIN_LINK" />Notifícanoslo<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Ahora no</translation>
<translation id="348000606199325318">ID de bloqueo <ph name="CRASH_LOCAL_ID" /> (ID de servidor: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">No hemos podido contactar con tu padre/madre/tutor. Vuelve a intentarlo.</translation>
<translation id="3528171143076753409">El certificado de servidor no es de confianza.</translation>
-<translation id="3538531656504267329">Año de caducidad no válido</translation>
<translation id="3539171420378717834">Guardar una copia de la tarjeta en este dispositivo</translation>
<translation id="3542684924769048008">Utilizar contraseña para:</translation>
<translation id="3549644494707163724">Cifrar todos los datos sincronizados con tu propia frase de contraseña de sincronización</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Ocultar detalles</translation>
<translation id="3587482841069643663">Todo</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Introduce una fecha de vencimiento válida</translation>
<translation id="36224234498066874">Borrar datos de navegación...</translation>
<translation id="362276910939193118">Mostrar historial completo</translation>
<translation id="3623476034248543066">Mostrar valor</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Contraseña:</translation>
<translation id="3696411085566228381">ninguno</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Selecciona una dirección de envío para consultar los métodos de envío y los requisitos.</translation>
<translation id="370665806235115550">Cargando...</translation>
<translation id="3712624925041724820">Licencias agotadas</translation>
<translation id="3714780639079136834">Activar los datos móviles o la conexión Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Enlace copiado</translation>
<translation id="375403751935624634">Se ha producido un error de traducción debido a un problema con el servidor.</translation>
<translation id="3759461132968374835">No se ha notificado ningún fallo recientemente. Los fallos que se hayan producido cuando la función de notificación de fallos estaba inhabilitada no aparecerán en esta página.</translation>
+<translation id="3787705759683870569">Vencimiento: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Si utilizas un servidor proxy...</translation>
<translation id="3828924085048779000">La frase de contraseña no puede estar vacía.</translation>
<translation id="3845539888601087042">Mostrando historial de dispositivos en los que has iniciado sesión. <ph name="BEGIN_LINK" />Más información<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">¿Quieres que Chromium guarde esta tarjeta?</translation>
<translation id="4171400957073367226">La firma de verificación no es válida</translation>
-<translation id="4176463684765177261">Inhabilitado</translation>
<translation id="4196861286325780578">&amp;Rehacer movimiento</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Comprobar la configuración del cortafuegos y del antivirus<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{ninguna}=1{Una aplicación ($1)}=2{Dos aplicaciones ($1, $2)}other{# aplicaciones ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">resultados de la búsqueda</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> no ha aceptado el certificado de inicio de sesión o es posible que no se haya proporcionado ninguno.</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="4446242550670694251">Ahora puedes navegar en privado para que los demás usuarios de este dispositivo no puedan ver tu actividad.</translation>
<translation id="4492190037599258964">Resultados de búsqueda de "<ph name="SEARCH_STRING" />"</translation>
<translation id="4506176782989081258">Error de validación: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Ponerte en contacto con el administrador del sistema</translation>
<translation id="450710068430902550">Compartir con el administrador</translation>
+<translation id="4515275063822566619">Las tarjetas y las direcciones proceden de Chrome y tu cuenta de Google (<ph name="ACCOUNT_EMAIL" />). Puedes gestionarlas en <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Detalles</translation>
<translation id="4558551763791394412">Inhabilita las extensiones.</translation>
<translation id="457875822857220463">Envío</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Ajustar a página</translation>
<translation id="483020001682031208">No hay páginas de la Web física para mostrarse.</translation>
<translation id="4850886885716139402">Ver</translation>
+<translation id="4854362297993841467">Este método de entrega no está disponible. Selecciona otro.</translation>
<translation id="4858792381671956233">Has solicitado permiso a tus padres para poder acceder a este sitio web</translation>
<translation id="4880827082731008257">Buscar en el historial</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> y <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Esta página se ha traducido de un idioma desconocido al <ph name="LANGUAGE_LANGUAGE" />.</translation>
<translation id="4923459931733593730">Pago</translation>
<translation id="4926049483395192435">Se debe especificar un valor.</translation>
-<translation id="4941291666397027948">* indica que el campo es obligatorio</translation>
<translation id="495170559598752135">Acciones</translation>
<translation id="4958444002117714549">Expandir lista</translation>
<translation id="4962322354953122629">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; Chrome no confía en su certificado de seguridad. Este problema puede deberse a una configuración incorrecta o a que un atacante ha interceptado la conexión. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Contraseña incorrecta</translation>
<translation id="5056549851600133418">Artículos recomendados para ti</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Comprobar la dirección del proxy<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{No hay cookies}=1{1 sitio web usa cookies. }other{# sitios web usan cookies. }}</translation>
<translation id="5087286274860437796">El certificado del servidor no es válido en este momento.</translation>
<translation id="5087580092889165836">Añadir tarjeta</translation>
<translation id="5089810972385038852">Estado</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Mostrar</translation>
<translation id="5308689395849655368">Notificación de fallos inhabilitada</translation>
<translation id="5317780077021120954">Guardar</translation>
-<translation id="5326702247179446998">Es obligatorio indicar el destinatario</translation>
<translation id="5327248766486351172">Nombre</translation>
<translation id="5337705430875057403">Los atacantes del <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podrían engañarte para que hagas algo peligroso, como instalar software o revelar tu información personal (por ejemplo, contraseñas, números de teléfono o datos de tarjetas de crédito).</translation>
-<translation id="53553865750799677">Dirección de recogida no admitida. Selecciona otra dirección.</translation>
<translation id="5359637492792381994">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; su certificado de seguridad no es válido en este momento. Este problema puede deberse a una configuración incorrecta o a que un atacante ha interceptado la conexión. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Error al almacenar la configuración de la política</translation>
<translation id="5386426401304769735">La cadena de certificados de este sitio web contiene un certificado firmado con SHA-1.</translation>
@@ -488,10 +498,10 @@
<translation id="552553974213252141">¿Se ha extraído el texto correctamente?</translation>
<translation id="5540224163453853">No se ha podido encontrar el artículo solicitado.</translation>
<translation id="5544037170328430102">Una página insertada en <ph name="SITE" /> dice:</translation>
-<translation id="5556459405103347317">Cargar de nuevo</translation>
+<translation id="5556459405103347317">Volver a cargar</translation>
<translation id="5565735124758917034">Activo</translation>
+<translation id="5571083550517324815">Los pedidos no se pueden recoger en esta dirección. Selecciona otra.</translation>
<translation id="5572851009514199876">Abre Chrome e inicia sesión en el navegador para que compruebe si tienes permiso para acceder a este sitio web.</translation>
-<translation id="5575380383496039204">Dirección de entrega no admitida. Selecciona otra dirección.</translation>
<translation id="5580958916614886209">Consulta el mes de vencimiento y vuelve a intentarlo</translation>
<translation id="560412284261940334">Administración no admitida</translation>
<translation id="5610142619324316209">Comprobar la conexión</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">No se ha verificado la identidad de este sitio web.</translation>
<translation id="5720705177508910913">Usuario actual</translation>
<translation id="5732392974455271431">Tus padres pueden desbloquearlo</translation>
-<translation id="57586589942790530">Número de tarjeta no válido</translation>
+<translation id="5763042198335101085">Introduce una dirección de correo electrónico válida</translation>
+<translation id="5765072501007116331">Selecciona una dirección para ver los métodos de entrega y los requisitos</translation>
<translation id="5784606427469807560">Se ha producido un problema al confirmar tu tarjeta. Comprueba tu conexión a Internet y vuelve a intentarlo.</translation>
<translation id="5785756445106461925">Además, esta página incluye otros recursos que no son seguros. Otros usuarios pueden acceder a estos recursos mientras están en circulación y un atacante puede modificarlos para cambiar el aspecto de la página.</translation>
<translation id="5786044859038896871">¿Quieres rellenar la información de la tarjeta?</translation>
@@ -520,32 +531,31 @@
<translation id="5869405914158311789">No se puede acceder a este sitio web</translation>
<translation id="5869522115854928033">Contraseñas guardadas</translation>
<translation id="5872918882028971132">Sugerencias de padres</translation>
-<translation id="587760065310675640">Dirección de envío no admitida. Selecciona otra dirección.</translation>
<translation id="5901630391730855834">Amarillo</translation>
-<translation id="59174027418879706">Habilitada</translation>
<translation id="5926846154125914413">Es posible que dejes de tener acceso al contenido premium de algunos sitios web.</translation>
<translation id="5959728338436674663">Enviar automáticamente <ph name="BEGIN_WHITEPAPER_LINK" />información del sistema y contenido de las páginas<ph name="END_WHITEPAPER_LINK" /> a Google para facilitar la detección de aplicaciones y sitios web peligrosos. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Semana</translation>
<translation id="5967867314010545767">Eliminar del historial</translation>
<translation id="5975083100439434680">Reducir</translation>
+<translation id="598637245381783098">No se ha podido abrir la aplicación de pago</translation>
<translation id="5989320800837274978">No se han especificado servidores proxy fijos ni una URL de secuencia de comandos .pac.</translation>
<translation id="5990559369517809815">Una extensión ha bloqueado el envío de solicitudes al servidor.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Las opciones de tarjetas y direcciones pertenecen a Chrome. Puedes gestionarlas en <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Página 1}other{Página #}}</translation>
<translation id="6017514345406065928">Verde</translation>
+<translation id="6027201098523975773">Introduce un nombre</translation>
<translation id="6040143037577758943">Cerrar</translation>
-<translation id="604124094241169006">Automático</translation>
<translation id="6042308850641462728">Más</translation>
<translation id="6060685159320643512">¡Atención! Estos experimentos pueden ser peligrosos</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{ninguna}=1{1}other{#}}</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>
-<translation id="6151417162996330722">El certificado del servidor tiene un período de validez demasiado largo.</translation>
-<translation id="615643356032862689">No se eliminarán los archivos descargados ni los marcadores añadidos.</translation>
+<translation id="6151417162996330722">El certificado del servidor tiene un periodo de validez demasiado largo.</translation>
+<translation id="6157877588268064908">Selecciona una dirección para ver los métodos de envío y los requisitos</translation>
<translation id="6165508094623778733">Más información</translation>
<translation id="6177128806592000436">Tu conexión con este sitio web no es segura</translation>
+<translation id="6184817833369986695">(cohorte: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Comprueba tu conexión a Internet</translation>
<translation id="6218753634732582820">¿Quitar dirección de Chromium?</translation>
<translation id="6251924700383757765">Política de Privacidad</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Rehacer reorganización</translation>
<translation id="6263376278284652872">Marcadores de <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Volver para estar a salvo</translation>
+<translation id="6276112860590028508">Las páginas de tu lista de lectura aparecen aquí</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="6290238015253830360">Los artículos sugeridos aparecen aquí</translation>
<translation id="6305205051461490394">No se puede acceder a <ph name="URL" />.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">No se ha podido comprobar si se ha revocado el certificado.</translation>
<translation id="6433490469411711332">Editar información de contacto</translation>
<translation id="6433595998831338502">La página <ph name="HOST_NAME" /> ha rechazado la conexión.</translation>
-<translation id="6443118737398455446">La fecha de caducidad no es válida</translation>
<translation id="6446608382365791566">Añadir más información</translation>
<translation id="6451458296329894277">Confirmar reenvío del formulario</translation>
<translation id="6456339708790392414">Tu pago</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; es posible que su certificado de seguridad se revoque. Este problema puede deberse a una configuración incorrecta o a que un atacante ha interceptado la conexión. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">Políticas de dispositivos</translation>
<translation id="6477321094435799029">Chrome ha detectado un código inusual en esta página y lo ha bloqueado para proteger tu información personal (por ejemplo, contraseñas, números de teléfono y tarjetas de crédito).</translation>
-<translation id="6477460825583319731">Dirección de correo electrónico no válida</translation>
<translation id="6489534406876378309">Empezar a subir errores</translation>
<translation id="6508722015517270189">Reinicia Chrome</translation>
-<translation id="6525462735697194615">Mes de caducidad no válido</translation>
<translation id="6529602333819889595">&amp;Rehacer eliminación</translation>
<translation id="6534179046333460208">Sugerencias de la Web física</translation>
<translation id="6550675742724504774">Configuración</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685">Búsqueda de <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Esta política está obsoleta.</translation>
<translation id="6652240803263749613">Este servidor no ha podido demostrar que 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 ha interceptado la conexión. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="6665267558048410100">Ese método de envío no está disponible. Prueba una opción diferente.</translation>
<translation id="6671697161687535275">¿Quitar sugerencia de formulario de Chromium?</translation>
<translation id="6685834062052613830">Cierra sesión y completa la configuración</translation>
<translation id="6710213216561001401">Anterior</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Se ha producido un error con el servidor proxy o la dirección es incorrecta.</translation>
<translation id="6727102863431372879">Establecer</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{ninguno}=1{Un elemento}other{# elementos}}</translation>
-<translation id="6743044928064272573">Opción de recogida</translation>
<translation id="674375294223700098">Error de certificado de servidor desconocido</translation>
<translation id="6753269504797312559">Valor de la política</translation>
<translation id="6757797048963528358">El dispositivo se ha suspendido.</translation>
<translation id="6778737459546443941">Uno de tus padres aún no lo ha aprobado</translation>
<translation id="6810899417690483278">ID de personalización</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">No se han podido cargar los datos de las regiones</translation>
<translation id="6831043979455480757">Traducir</translation>
<translation id="6839929833149231406">Ãrea</translation>
<translation id="6874604403660855544">&amp;Rehacer acción de añadir</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Tu tarjeta se ha confirmado</translation>
<translation id="6897140037006041989">Agente de usuario</translation>
<translation id="6915804003454593391">Usuario:</translation>
+<translation id="6948701128805548767">Selecciona una dirección para ver los métodos de recogida y los requisitos</translation>
<translation id="6957887021205513506">El certificado del servidor parece ser falso.</translation>
<translation id="6965382102122355670">Aceptar</translation>
<translation id="6965978654500191972">Dispositivo</translation>
@@ -630,8 +639,7 @@
<translation id="6973656660372572881">Se especifican tanto servidores proxy fijos como una URL de secuencia de comandos .pac.</translation>
<translation id="6989763994942163495">Mostrar configuración avanzada...</translation>
<translation id="7000990526846637657">No se han encontrado entradas del historial</translation>
-<translation id="7001663382399377034">Añadir destinatario</translation>
-<translation id="7009986207543992532">Has intentado acceder a <ph name="DOMAIN" />, pero el servidor ha presentado un certificado cuyo período de validez es demasiado largo para que se considere de confianza. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="7009986207543992532">Has intentado acceder a <ph name="DOMAIN" />, pero el servidor ha presentado un certificado cuyo periodo de validez es demasiado largo para que se considere de confianza. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Es posible que en tu cuenta de Google haya otros datos de navegación registrados, que puedes consultar en la página <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Contraseñas</translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Más antiguos</translation>
<translation id="7090678807593890770">Busca <ph name="LINK" /> en Google</translation>
<translation id="7119414471315195487">Cierra otros programas o pestañas</translation>
+<translation id="7129409597930077180">Los pedidos no se pueden enviar a esta dirección. Selecciona otra.</translation>
+<translation id="7138472120740807366">Método de entrega</translation>
<translation id="7139724024395191329">Emirato</translation>
<translation id="7155487117670177674">Pago no seguro</translation>
<translation id="7179921470347911571">Reiniciar ahora</translation>
<translation id="7180611975245234373">Actualizar</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 web pueden tardar más en cargarse la próxima vez que accedas a ellos.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423">La página <ph name="HOST_NAME" /> no cumple los estándares de seguridad.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Más información<ph name="END_LINK" /> sobre este problema.</translation>
@@ -675,7 +686,6 @@
<translation id="7424977062513257142">Una página insertada en este sitio web dice:</translation>
<translation id="7441627299479586546">Asunto de política incorrecto</translation>
<translation id="7444046173054089907">Este sitio web se ha bloqueado</translation>
-<translation id="7444238235002594607">Selecciona una dirección de recogida para consultar los métodos de recogida y los requisitos.</translation>
<translation id="7445762425076701745">La identidad del servidor al que estás conectado no se puede validar por completo. Estás conectado a un servidor con un nombre que solo es válido en tu red y cuya propiedad no puede validar en modo alguno una entidad emisora de certificados externa. A pesar de ello, algunas entidades emisoras emiten certificados para esos nombres, por lo que no es posible garantizar que estés conectado al sitio web deseado, en lugar de a un atacante.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Consultar más información<ph name="END_LINK" /> sobre este problema</translation>
<translation id="7460163899615895653">Las pestañas recientes de otros dispositivos aparecen aquí</translation>
@@ -719,6 +729,7 @@
<translation id="7755287808199759310">Uno de tus padres puede desbloquearlo</translation>
<translation id="7758069387465995638">Puede que el cortafuegos o el software antivirus hayan bloqueado la conexión.</translation>
<translation id="7761701407923456692">El certificado del servidor no coincide con la URL.</translation>
+<translation id="7763386264682878361">Analizador de archivos de manifiesto de pagos</translation>
<translation id="7764225426217299476">Añadir dirección</translation>
<translation id="777702478322588152">Prefectura</translation>
<translation id="7791543448312431591">Añadir</translation>
@@ -732,6 +743,7 @@
<translation id="785549533363645510">Ten en cuenta que tus acciones no serán totalmente invisibles. El uso del modo incógnito no te permite ocultar tu actividad de navegación a tu empresa, a tu proveedor de servicios de Internet o a los sitios web que visites.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Comprueba el código CVC y vuelve a intentarlo</translation>
+<translation id="79338296614623784">Introduce un número de teléfono válido</translation>
<translation id="7935318582918952113">Extractor de DOM</translation>
<translation id="7938958445268990899">Aún no es válido el certificado de servidor.</translation>
<translation id="7942349550061667556">Rojo</translation>
@@ -751,6 +763,7 @@
<translation id="8088680233425245692">Se ha producido un error al ver el artículo.</translation>
<translation id="8089520772729574115">menos de 1 MB</translation>
<translation id="8091372947890762290">La activación está pendiente en el servidor.</translation>
+<translation id="8118489163946903409">Forma de pago</translation>
<translation id="8131740175452115882">Confirmar</translation>
<translation id="8134994873729925007">No se ha podido encontrar la <ph name="BEGIN_ABBR" />dirección DNS<ph name="END_ABBR" /> del servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">El ordenador se ha suspendido.</translation>
@@ -776,6 +789,7 @@
<translation id="8349305172487531364">Barra de marcadores</translation>
<translation id="8363502534493474904">Desactivar el modo avión</translation>
<translation id="8364627913115013041">No establecida</translation>
+<translation id="8368476060205742148">Servicios de Google Play</translation>
<translation id="8380941800586852976">Peligroso</translation>
<translation id="8382348898565613901">Los marcadores a los que hayas accedido recientemente aparecen aquí</translation>
<translation id="8398259832188219207">Informe sobre fallos subido el <ph name="UPLOAD_TIME" /></translation>
@@ -784,31 +798,29 @@
<translation id="8428213095426709021">Ajustes</translation>
<translation id="8433057134996913067">Con esta opción, tu sesión se cerrará en la mayoría de sitios web.</translation>
<translation id="8437238597147034694">&amp;Deshacer movimiento</translation>
-<translation id="8456681095658380701">El nombre no es válido</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{Una tarjeta de crédito}other{# tarjetas de crédito}}</translation>
<translation id="8483780878231876732">Inicia sesión en Chrome para utilizar tarjetas de tu cuenta de Google</translation>
<translation id="8488350697529856933">Aplicable a</translation>
-<translation id="8492969205326575646">Tipo de tarjeta no admitido</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ha tardado demasiado tiempo en responder.</translation>
<translation id="852346902619691059">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; el sistema operativo de tu dispositivo no confía en su certificado de seguridad. Este problema puede deberse a una configuración incorrecta o a que un atacante ha interceptado la conexión. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="8532105204136943229">Año de caducidad</translation>
<translation id="8543181531796978784">Puedes <ph name="BEGIN_ERROR_LINK" />informar de un problema de detección<ph name="END_ERROR_LINK" /> o, si comprendes los riesgos que conlleva esta acción para tu seguridad, <ph name="BEGIN_LINK" />accede a este sitio web no seguro<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">La traducción no se ha realizado correctamente porque no se ha podido determinar el idioma de la página.</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="8570229484593575558">La siguiente información |no se guardará|:#Tu historial de navegación#Tus búsquedas#Los datos de cookies</translation>
<translation id="8571890674111243710">Traduciendo página a <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Es posible que tu actividad |todavía sea visible| para:#Los sitios web que visites#Tu empresa#Tu proveedor de servicios de Internet</translation>
<translation id="858637041960032120">Añade un teléfono</translation>
<translation id="859285277496340001">El certificado no especifica ningún mecanismo para comprobar si se ha revocado.</translation>
<translation id="8620436878122366504">Tus padres aún no lo han aprobado</translation>
<translation id="8647750283161643317">Restablecer todo a su estado predeterminado</translation>
<translation id="8703575177326907206">Tu conexión a <ph name="DOMAIN" /> no está cifrada.</translation>
+<translation id="8718314106902482036">El pago no se ha completado</translation>
<translation id="8725066075913043281">Volver a intentarlo</translation>
<translation id="8728672262656704056">Has iniciado una sesión de incógnito</translation>
<translation id="8730621377337864115">Listo</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="8759274551635299824">La tarjeta ha caducado</translation>
<translation id="8790007591277257123">&amp;Rehacer eliminación</translation>
-<translation id="8798099450830957504">Predeterminado</translation>
<translation id="8800988563907321413">Las sugerencias de la sección Cercanas aparecen aquí</translation>
<translation id="8820817407110198400">Marcadores</translation>
<translation id="883848425547221593">Otros marcadores</translation>
@@ -818,6 +830,7 @@
<translation id="8866481888320382733">Error al analizar la configuración de la política</translation>
<translation id="8866959479196209191">Esta página dice:</translation>
<translation id="8870413625673593573">Cerrado recientemente</translation>
+<translation id="8874824191258364635">Introduce un número de tarjeta válido</translation>
<translation id="8876793034577346603">No se ha podido analizar la configuración de red.</translation>
<translation id="8877192140621905067">Cuando confirmes la tarjeta, su información se compartirá con este sitio web</translation>
<translation id="8889402386540077796">Matiz</translation>
@@ -827,7 +840,6 @@
<translation id="8931333241327730545">¿Quieres guardar esta tarjeta en tu cuenta de Google?</translation>
<translation id="8932102934695377596">Tu reloj está atrasado</translation>
<translation id="8954894007019320973">(Cont.)</translation>
-<translation id="895548565263634352">Leer noticias de <ph name="ARTICLE_PUBLISHER" /> y <ph name="OTHER_ARTICLE_COUNT" /> más</translation>
<translation id="8971063699422889582">El certificado del servidor ha caducado.</translation>
<translation id="8986494364107987395">Enviar automáticamente estadísticas de uso e informes sobre fallos a Google</translation>
<translation id="8987927404178983737">Mes</translation>
@@ -845,7 +857,6 @@
<translation id="9068849894565669697">Seleccionar color</translation>
<translation id="9076283476770535406">Es posible que incluya contenido para adultos</translation>
<translation id="9078964945751709336">Se necesita más información</translation>
-<translation id="9094175695478007090">No se ha podido iniciar la aplicación de pago.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> utiliza normalmente el cifrado para proteger tu información. Cuando Chromium intentó establecer conexión con <ph name="SITE" />, el sitio web devolvió unas credenciales inusuales e incorrectas. Esto puede ocurrir si un atacante intenta suplantar la identidad de <ph name="SITE" /> o si una pantalla de inicio de sesión Wi-Fi interrumpe la conexión. Tu información sigue estando protegida, ya que Chromium detuvo la conexión antes de que se intercambiaran datos.</translation>
<translation id="9137013805542155359">Mostrar original</translation>
<translation id="9137248913990643158">Abre Chrome e inicia sesión en el navegador para usar esta aplicación.</translation>
diff --git a/chromium/components/strings/components_strings_et.xtb b/chromium/components/strings/components_strings_et.xtb
index 634c35302fb..9c53a53099f 100644
--- a/chromium/components/strings/components_strings_et.xtb
+++ b/chromium/components/strings/components_strings_et.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="et">
<translation id="1008557486741366299">Mitte praegu</translation>
<translation id="1015730422737071372">Esitage lisateavet</translation>
+<translation id="1021110881106174305">Aktsepteeritud kaardid</translation>
<translation id="1032854598605920125">Pööra päripäeva</translation>
<translation id="1038842779957582377">tundmatu nimi</translation>
<translation id="1050038467049342496">Sulgege muud rakendused</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Peida väärtus</translation>
<translation id="1228893227497259893">Ãœksuse vale identifikaator</translation>
<translation id="1232569758102978740">Pealkirjata</translation>
+<translation id="1263231323834454256">Lugemisloend</translation>
<translation id="1264126396475825575">Krahhiaruanne talletati <ph name="CRASH_TIME" /> (ei ole veel üles laaditud ega eiratud)</translation>
<translation id="1285320974508926690">Ära kunagi seda saiti tõlgi</translation>
<translation id="129553762522093515">Viimati suletud</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromiumi automaattäite seaded ...</translation>
<translation id="1374468813861204354">soovitused</translation>
<translation id="1375198122581997741">Teave versiooni kohta</translation>
+<translation id="1377321085342047638">Kaardinr</translation>
<translation id="139305205187523129">Host <ph name="HOST_NAME" /> ei saatnud andmeid.</translation>
<translation id="1407135791313364759">Ava kõik</translation>
<translation id="1413809658975081374">Privaatsuse viga</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Ajalugu</translation>
<translation id="1645368109819982629">Toetuseta protokoll</translation>
<translation id="1656489000284462475">Kättesaamine</translation>
+<translation id="1663943134801823270">Kaardid ja aadressid pärinevad Chrome'ist. Neid saate hallata menüüs <ph name="BEGIN_LINK" />Seaded<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">Sait <ph name="SITE" /> kasutab teie teabe kaitsmiseks tavaliselt krüpteerimist. Kui Google Chrome püüdis seekord saidiga <ph name="SITE" /> ühendust luua, tagastas veebisait ebatavalised ja valed mandaadid. See võib juhtuda siis, kui ründaja proovib teeselda, et on sait <ph name="SITE" />, või WiFi sisselogimisekraan on ühenduse katkestanud. Teie teave on endiselt kaitstud, sest Google Chrome peatas ühenduse enne andmevahetust.</translation>
<translation id="168328519870909584">Saidil <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> olevad ründajad võivad proovida installida teie seadmesse ohtlikke rakendusi, mis varastavad teie teavet või kustutavad selle (nt fotod, paroolid, sõnumid ja krediitkaardiandmed).</translation>
<translation id="168841957122794586">Serveri sertifikaat sisaldab nõrka krüptograafilist võtit.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Vajate saidi külastamiseks halduri <ph name="NAME" /> luba</translation>
+<translation id="1721424275792716183">* Kohustuslik väli</translation>
<translation id="1728677426644403582">Vaatate veebilehe lähtekoodi</translation>
+<translation id="173080396488393970">Seda tüüpi kaarti ei toetata</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Proovige ühendust võtta süsteemiadministraatoriga.</translation>
+<translation id="1740951997222943430">Sisestage kehtiv aegumiskuu</translation>
<translation id="1745358365027406341">Laadi leht hiljem alla</translation>
<translation id="17513872634828108">Avatud vahelehed</translation>
<translation id="1753706481035618306">Lk</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Värskendage sünkroonimise parooli.</translation>
<translation id="1787142507584202372">Teie avatud vahelehed kuvatakse siin</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Valige kohaletoimetamise aadress, et vaadata kohaletoimetamise viise ja nõudeid.</translation>
+<translation id="1803264062614276815">Kaardiomaniku nimi</translation>
<translation id="1803678881841855883">Google'i ohutu sirvimine avastas saidilt <ph name="SITE" /> hiljuti <ph name="BEGIN_LINK" />pahavara<ph name="END_LINK" />. Tavaliselt ohutud veebisaidid nakatuvad mõnikord pahavaraga. Pahatahtliku sisu allikas on tuntud pahavaralevitaja <ph name="SUBRESOURCE_HOST" />. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Lisati kuupäeval <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Taotlus või selle parameetrid on kehtetud</translation>
<translation id="1826516787628120939">Kontrollimine</translation>
<translation id="1834321415901700177">See sait sisaldab kahjulikke programme</translation>
<translation id="1842969606798536927">Maksmine</translation>
-<translation id="1864455488461349376">Kohaletoimetamise viis</translation>
<translation id="1871208020102129563">Puhverserver on seatud kasutama fikseeritud puhverservereid, mitte pac-skripti URL-i.</translation>
<translation id="1871284979644508959">Kohustuslik väli</translation>
<translation id="187918866476621466">Ava käivitamisel avatavad lehed</translation>
<translation id="1883255238294161206">Ahenda loend</translation>
<translation id="1898423065542865115">Filtreerimine</translation>
<translation id="194030505837763158">Avage <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Aktsepteeritud kaardid</translation>
<translation id="1962204205936693436">Domeeni <ph name="DOMAIN" /> järjehoidjad</translation>
<translation id="1973335181906896915">Viga jadaks teisendamisel</translation>
<translation id="1974060860693918893">Täpsemad</translation>
<translation id="1978555033938440688">Püsivara versioon</translation>
+<translation id="1995859865337580572">Kinnitage oma CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{ja veel 1}other{ja veel #}}</translation>
-<translation id="2020194265157481222">Kaardil olev nimi on nõutav</translation>
<translation id="2025186561304664664">Puhverserver seadistatakse automaatselt.</translation>
<translation id="2030481566774242610">Kas mõtlesite aadressi <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Kontrollige puhverserverit ja tulemüüri<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Täna</translation>
<translation id="2154054054215849342">Sünkroonimisteenus pole domeeni jaoks saadaval</translation>
<translation id="2154484045852737596">Kaardi muutmine</translation>
-<translation id="2156993118928861787">Sobimatu aadress</translation>
<translation id="2166049586286450108">Täielik administraatorijuurdepääs</translation>
<translation id="2166378884831602661">See sait ei saa turvalist ühendust luua</translation>
<translation id="2181821976797666341">Reeglid</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 aadress}other{# aadressi}}</translation>
+<translation id="2202020181578195191">Sisestage kehtiv aegumisaasta</translation>
<translation id="2212735316055980242">Reeglit ei leitud</translation>
<translation id="2213606439339815911">Kirjete toomine ...</translation>
<translation id="2230458221926704099">Parandage oma ühendus <ph name="BEGIN_LINK" />diagnostikarakenduse<ph name="END_LINK" /> abil</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Teie juurdepääs Internetile on blokeeritud</translation>
<translation id="230155334948463882">Uus kaart?</translation>
<translation id="2305919008529760154">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Selle turvasertifikaat võib olla väljastatud petturlikul moel. Selle põhjuseks võib olla vale seadistus või teie ühendust segav ründaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Kaardi ja aadressi valikud pärinevad teie Google'i kontolt (<ph name="ACCOUNT_EMAIL" />) ning Chrome'ist. Neid saate hallata menüüs <ph name="BEGIN_LINK" />Seaded<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535">Domeen <ph name="DOMAIN" /> nõuab kasutajanime ja parooli.</translation>
<translation id="2318774815570432836">Te ei saa saiti <ph name="SITE" /> praegu külastada, sest veebisait kasutab HSTS-i. Võrguvead ja -rünnakud on tavaliselt ajutised, nii et leht on tõenäoliselt hiljem töökorras. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Muud järjehoidjad</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Ettevõtte vaikeseade</translation>
<translation id="2386255080630008482">Serveri sertifikaat on tühistatud.</translation>
<translation id="2392959068659972793">Kuva reeglid, mille väärtusi pole määratud</translation>
+<translation id="239429038616798445">See tarneviis pole saadaval. Proovige mõnda teist tarneviisi.</translation>
<translation id="2396249848217231973">&amp;Võta kustutamine tagasi</translation>
<translation id="2460160116472764928">Google'i ohutu sirvimine avastas saidilt <ph name="SITE" /> hiljuti <ph name="BEGIN_LINK" />pahavara<ph name="END_LINK" />. Tavaliselt ohutud veebisaidid nakatuvad mõnikord pahavaraga. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Täida</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Võrgudiagnostika käitamine<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Kehtetu otsingu URL.</translation>
<translation id="2491120439723279231">Serveri sertifikaat sisaldab vigu.</translation>
-<translation id="24943777258388405">Vigane telefoninumber</translation>
<translation id="2495083838625180221">JSON-i parser</translation>
<translation id="2495093607237746763">Kui see on märgitud, salvestab Chromium teie kaardi koopia vormide kiiremaks täitmiseks sellesse seadmesse.</translation>
<translation id="2498091847651709837">Uue kaardi skannimine</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027">Host <ph name="HOST_NAME" /> saatis sobimatu vastuse.</translation>
<translation id="2552545117464357659">Uuemad</translation>
<translation id="2556876185419854533">&amp;Võta muudatus tagasi</translation>
+<translation id="2587730715158995865">Avaldajalt <ph name="ARTICLE_PUBLISHER" />. Lugege seda ja <ph name="OTHER_ARTICLE_COUNT" /> teist lugu.</translation>
<translation id="2587841377698384444">Kataloogi API ID:</translation>
<translation id="2597378329261239068">Dokument on parooliga kaitstud. Sisestage parool.</translation>
<translation id="2609632851001447353">Variatsioonid</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Ühenduvusdiagnostika käitamine<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">Ok</translation>
<translation id="2742870351467570537">Eemalda valitud üksused</translation>
+<translation id="277133753123645258">Tarneviis</translation>
<translation id="277499241957683684">Seadme kirje puudub</translation>
<translation id="2784949926578158345">Ühendus lähtestati.</translation>
<translation id="2794233252405721443">Sait on blokeeritud</translation>
-<translation id="2812680587231492111">See kättesaamise valik ei ole saadaval. Proovige teist valikut.</translation>
<translation id="2824775600643448204">Aadressi- ja otsinguriba</translation>
<translation id="2826760142808435982">Ühendus on krüptitud ja autenditud üksusega <ph name="CIPHER" /> ning kasutab peamise vahetusmehhanismina üksust <ph name="KX" />.</translation>
<translation id="2835170189407361413">Tühjenda vorm</translation>
-<translation id="2849041323157393173">See kohaletoimetamise valik ei ole saadaval. Proovige teist valikut.</translation>
<translation id="2889159643044928134">Ära laadi uuesti</translation>
<translation id="2900469785430194048">Google Chrome'il pole selle veebilehe kuvamiseks piisavalt mälu.</translation>
<translation id="2909946352844186028">Tuvastati võrgumuudatus.</translation>
<translation id="2916038427272391327">Sulgege muud programmid</translation>
<translation id="2922350208395188000">Serveri sertifikaati ei saa kontrollida.</translation>
+<translation id="2928905813689894207">Arveldusaadress</translation>
<translation id="2948083400971632585">Seadete lehel saate keelata kõik ühenduse jaoks konfigureeritud puhverserverid.</translation>
<translation id="2955913368246107853">Sule leiuriba</translation>
<translation id="2958431318199492670">Võrgu seadistus ei vasta ONC standardile. On võimalik, et seadistuse mõnd osa ei saa importida.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Turvalise ühenduse loomiseks peab kell olema õigesti seadistatud, kuna sertifikaadid, mida veebisaidid kasutavad enda tuvastamiseks, kehtivad ainult teatud perioodi jooksul. Kuna teie seadme kell on vale, ei saa Chrome neid sertifikaate kinnitada.</translation>
<translation id="2972581237482394796">&amp;Tee uuesti</translation>
<translation id="2985306909656435243">Kui see on lubatud, salvestab Chromium teie kaardi koopia vormide kiiremaks täitmiseks sellesse seadmesse.</translation>
+<translation id="2985398929374701810">Sisestage kehtiv aadress</translation>
+<translation id="2986368408720340940">See kättesaamisviis pole saadaval. Proovige mõnda teist kättesaamisviisi.</translation>
<translation id="2991174974383378012">Veebisaitidega jagamine</translation>
<translation id="3005723025932146533">Kuva salvestatud koopia</translation>
<translation id="3008447029300691911">Sisestage krediitkaardi <ph name="CREDIT_CARD" /> CVC. Kui selle kinnitate, jagatakse teie kaardi üksikasju selle saidiga.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{vähemalt 1 üksus sünkroonitud seadmetes}=1{1 üksus (ja rohkem sünkroonitud seadmetes)}other{# üksust (ja rohkem sünkroonitud seadmetes)}}</translation>
<translation id="3041612393474885105">Sertifikaadi andmed</translation>
<translation id="3063697135517575841">Chrome ei saanud praegu teie kaarti kinnitada. Proovige hiljem uuesti.</translation>
+<translation id="3064966200440839136">Väljute inkognito režiimist, et välise rakenduse kaudu maksta. Kas soovite jätkata?</translation>
<translation id="3093245981617870298">Olete võrguühenduseta.</translation>
<translation id="3105172416063519923">Vara ID:</translation>
<translation id="3109728660330352905">Teil pole volitust selle lehe vaatamiseks.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Proovige käitada ühenduvusdiagnostikat<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Vastuse dekodeerimine ebaõnnestus</translation>
-<translation id="3149891296864842641">Tarnevalik</translation>
<translation id="3150653042067488994">Serveris ilmnes ajutine viga</translation>
+<translation id="3154506275960390542">See leht sisaldab vormi, mille esitamine ei pruugi olla turvaline. Teised võivad andmete edastamisel neid vaadata või ründaja võib serverile saadetavaid andmeid muuta.</translation>
<translation id="3157931365184549694">Taasta</translation>
<translation id="3167968892399408617">Inkognito vahelehtedel kuvatavaid lehti ei talletata pärast vahelehtede sulgemist brauseri ajalukku, küpsistefailide salve ega otsinguajalukku. Allalaaditavad failid ja järjehoidjatesse lisatud sisu säilitatakse.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Saidi külastamise taotlust ei õnnestunud saata kontaktile <ph name="NAME" />. Proovige uuesti.</translation>
<translation id="3355823806454867987">Muuda puhverserveri seadeid ...</translation>
<translation id="3369192424181595722">Kella viga</translation>
+<translation id="337311366426640088">Veel <ph name="ITEM_COUNT" /> üksust …</translation>
<translation id="337363190475750230">Eraldatud</translation>
<translation id="3377188786107721145">Viga reegli sõelumisel</translation>
<translation id="3380365263193509176">Tundmatu viga</translation>
<translation id="3380864720620200369">Kliendi ID:</translation>
<translation id="3391030046425686457">Kohaletoimetamise aadress</translation>
+<translation id="3395827396354264108">Kättesaamisviis</translation>
<translation id="340013220407300675">Ründajad võivad üritada saidilt <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> varastada teie teavet (näiteks paroole, sõnumeid või krediitkaardiandmeid).</translation>
<translation id="3422248202833853650">Proovige mälu vabastamiseks väljuda muudest programmidest.</translation>
<translation id="3422472998109090673">Hostiga <ph name="HOST_NAME" /> ei saa praegu ühendust.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Hankimise intervall:</translation>
<translation id="3462200631372590220">Peida täpsemad üksikasjad</translation>
+<translation id="3467763166455606212">Kaardiomaniku nimi on kohustuslik</translation>
+<translation id="3478058380795961209">Aegumiskuu</translation>
<translation id="3479539252931486093">Kas see oli ootamatu? <ph name="BEGIN_LINK" />Andke meile sellest teada<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Mitte praegu</translation>
<translation id="348000606199325318">Krahhi ID <ph name="CRASH_LOCAL_ID" /> (serveri ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Teie vanemaga ei õnnestunud praegu ühendust võtta. Proovige hiljem uuesti.</translation>
<translation id="3528171143076753409">Serveri sertifikaat ei ole usaldusväärne.</translation>
-<translation id="3538531656504267329">Sobimatu aegumisaasta</translation>
<translation id="3539171420378717834">Säilita kaardi koopia seadmes</translation>
<translation id="3542684924769048008">Kasuta parooli:</translation>
<translation id="3549644494707163724">Krüpteerige kõik sünkroonitud andmed oma sünkroonimise parooliga</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Peida üksikasjad</translation>
<translation id="3587482841069643663">Kõik</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Sisestage kehtiv aegumiskuupäev</translation>
<translation id="36224234498066874">Kustuta sirvimise andmed...</translation>
<translation id="362276910939193118">Näita kogu ajalugu</translation>
<translation id="3623476034248543066">Kuva väärtused</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Parool:</translation>
<translation id="3696411085566228381">puudub</translation>
<translation id="3704609568417268905"><ph name="TIME" />, <ph name="BOOKMARKED" />, <ph name="TITLE" />, <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Tarneviiside ja nõuete vaatamiseks valige tarneaadress.</translation>
<translation id="370665806235115550">Laadimine...</translation>
<translation id="3712624925041724820">Litsentsid on ammendunud</translation>
<translation id="3714780639079136834">Lülitage sisse mobiilne andmeside või WiFi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Teie kopeeritud link</translation>
<translation id="375403751935624634">Tõlkimine ebaõnnestus serverivea tõttu.</translation>
<translation id="3759461132968374835">Hiljuti teatatud krahhe ei ole. Siin ei ilmu krahhid, mis toimusid siis, kui krahhide aruandlus oli keelatud.</translation>
+<translation id="3787705759683870569">Aegub: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Kui kasutate puhverserverit ...</translation>
<translation id="3828924085048779000">Tühi parool ei ole lubatud.</translation>
<translation id="3845539888601087042">Kuvatakse ajalugu teie sisselogitud seadmetest. <ph name="BEGIN_LINK" />Lisateave<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Kas soovite, et Chromium salvestaks selle kaardi?</translation>
<translation id="4171400957073367226">Sobimatu kinnitusallkiri</translation>
-<translation id="4176463684765177261">Keelatud</translation>
<translation id="4196861286325780578">&amp;Teisalda uuesti</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Kontrollige tulemüüri ja viirusetõrje seadistusi<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{mitte ühtegi}=1{1 rakendus ($1)}=2{2 rakendust ($1, $2)}other{# rakendust ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">otsingutulemused</translation>
<translation id="4432688616882109544">Host <ph name="HOST_NAME" /> ei aktsepteerinud teie sisselogimise sertifikaati või te ei esitanud seda.</translation>
<translation id="443673843213245140">Puhverserveri kasutamine on keelatud, kuid määratud on ka konkreetne puhverserveri konfigureerimine.</translation>
-<translation id="4446242550670694251">Nüüd saate sirvida privaatselt ja teised seadme kasutajad ei näe teie tegevusi.</translation>
<translation id="4492190037599258964">Otsingutulemused „<ph name="SEARCH_STRING" />“ kohta</translation>
<translation id="4506176782989081258">Valideerimisviga: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Võtke ühendust süsteemiadministraatoriga</translation>
<translation id="450710068430902550">Administraatoriga jagamine</translation>
+<translation id="4515275063822566619">Kaardid ja aadressid pärinevad Chrome'ist ning teie Google'i kontolt (<ph name="ACCOUNT_EMAIL" />). Neid saate hallata menüüs <ph name="BEGIN_LINK" />Seaded<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Ãœksikasjad</translation>
<translation id="4558551763791394412">Keelake laiendused.</translation>
<translation id="457875822857220463">Kohaletoimetamine</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Sobita lehele</translation>
<translation id="483020001682031208">Kuvamiseks pole ühtegi füüsilise veebi lehte</translation>
<translation id="4850886885716139402">Kuva</translation>
+<translation id="4854362297993841467">See kohaletoimetamisviis pole saadaval. Proovige mõnda teist kohaletoimetamisviisi.</translation>
<translation id="4858792381671956233">Küsisite oma vanematelt, kas võite seda lehte külastada</translation>
<translation id="4880827082731008257">Otsi ajaloost</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Leht on tõlgitud teadmata keelest <ph name="LANGUAGE_LANGUAGE" /> keelde</translation>
<translation id="4923459931733593730">Makse</translation>
<translation id="4926049483395192435">Tuleb määrata.</translation>
-<translation id="4941291666397027948">* näitab kohustuslikku välja</translation>
<translation id="495170559598752135">Toimingud</translation>
<translation id="4958444002117714549">Laienda loendit</translation>
<translation id="4962322354953122629">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Chrome ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või teie ühendust segav ründaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Vale salasõna</translation>
<translation id="5056549851600133418">Teile soovitatud artiklid</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Kontrollige puhverserveri aadressi<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Küpsisefaile pole}=1{1 sait kasutab küpsisefaile. }other{# saiti kasutab küpsisefaile. }}</translation>
<translation id="5087286274860437796">Serveri sertifikaat pole praegu kehtiv.</translation>
<translation id="5087580092889165836">Lisa kaart</translation>
<translation id="5089810972385038852">Osariik</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Kuva</translation>
<translation id="5308689395849655368">Krahhide aruandlus on keelatud.</translation>
<translation id="5317780077021120954">Salvesta</translation>
-<translation id="5326702247179446998">Saaja on kohustuslik</translation>
<translation id="5327248766486351172">Nimi</translation>
<translation id="5337705430875057403">Ründajad saidil <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> võivad teid meelitada ohtlikele tegevustele, nagu tarkvara installimine või isiklike andmete avaldamine (nt paroolid, telefoninumbrid või krediitkaardid).</translation>
-<translation id="53553865750799677">Toetamata kättesaamise aadress. Valige muu aadress.</translation>
<translation id="5359637492792381994">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Selle turvasertifikaat on praegu kehtetu. Selle põhjuseks võib olla vale seadistus või teie ühendust segav ründaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Reegli seadete talletamine ebaõnnestus</translation>
<translation id="5386426401304769735">Selle saidi sertifikaadiahel sisaldab sertifikaati, mis on allkirjastatud SHA-1-ga.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">Manustatud leht saidil <ph name="SITE" /> ütleb:</translation>
<translation id="5556459405103347317">Laadi uuesti</translation>
<translation id="5565735124758917034">Aktiivne</translation>
+<translation id="5571083550517324815">Sellelt aadressilt ei saa kaupa kätte. Valige mõni teine aadress.</translation>
<translation id="5572851009514199876">Alustage ja logige Chrome'i sisse, et Chrome saaks kontrollida, kas teil on luba sellele saidile juurdepääsemiseks.</translation>
-<translation id="5575380383496039204">Toetamata kohaletoimetamise aadress. Valige muu aadress.</translation>
<translation id="5580958916614886209">Kontrollige aegumiskuud ja proovige uuesti</translation>
<translation id="560412284261940334">Haldust ei toetata</translation>
<translation id="5610142619324316209">Kontrollige ühendust</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">Selle veebisaidi identiteeti pole kinnitanud.</translation>
<translation id="5720705177508910913">Praegune kasutaja</translation>
<translation id="5732392974455271431">Vanemad saavad blokeeringu teie eest tühistada</translation>
-<translation id="57586589942790530">Kehtetu kaardinumber</translation>
+<translation id="5763042198335101085">Sisestage kehtiv e-posti aadress</translation>
+<translation id="5765072501007116331">Kohaletoimetamisviiside ja nõuete nägemiseks valige aadress</translation>
<translation id="5784606427469807560">Kaardi kinnitamisel tekkis probleem. Kontrollige Interneti-ühendust ja proovige uuesti.</translation>
<translation id="5785756445106461925">Lisaks sisaldab see leht teisi ressursse, mis pole turvalised. Edastamise ajal võivad ressursse vaadata ka teised ja ründajad saavad lehe välimuse muutmiseks ressursse muuta.</translation>
<translation id="5786044859038896871">Kas soovite sisestada oma kaarditeabe?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">Selle saidiga ei saa ühendust</translation>
<translation id="5869522115854928033">Salvestatud paroolid</translation>
<translation id="5872918882028971132">Vanema soovitused</translation>
-<translation id="587760065310675640">Toetamata tarneaadress. Valige muu aadress.</translation>
<translation id="5901630391730855834">Kollane</translation>
-<translation id="59174027418879706">Lubatud</translation>
<translation id="5926846154125914413">Võite kaotada juurdepääsu mõnede saitide tasulisele sisule.</translation>
<translation id="5959728338436674663">Saatke Google'ile automaatselt <ph name="BEGIN_WHITEPAPER_LINK" />süsteemiteavet ja lehe sisu<ph name="END_WHITEPAPER_LINK" />, et aidata tuvastada ohtlikke rakendusi ja saite. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Nädal</translation>
<translation id="5967867314010545767">Eemalda ajaloost</translation>
<translation id="5975083100439434680">Suumib välja</translation>
+<translation id="598637245381783098">Makserakendust ei saa avada</translation>
<translation id="5989320800837274978">Määratud ei ole fikseeritud puhverservereid ega pac-skriptiga URL-i.</translation>
<translation id="5990559369517809815">Laiendus blokeeris serverisse saadetavad päringud.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Kaardi ja aadressi valikud pärinevad Chrome'ist. Neid saate hallata menüüs <ph name="BEGIN_LINK" />Seaded<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Lk 1}other{Lk #}}</translation>
<translation id="6017514345406065928">Roheline</translation>
+<translation id="6027201098523975773">Sisestage nimi</translation>
<translation id="6040143037577758943">Sulge</translation>
-<translation id="604124094241169006">Automaatne</translation>
<translation id="6042308850641462728">Rohkem</translation>
<translation id="6060685159320643512">Ettevaatust, need katsed võivad hammustada.</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{mitte ühtegi}=1{1}other{#}}</translation>
@@ -543,9 +552,10 @@
kasutuses olevad võrguseadmed.</translation>
<translation id="614940544461990577">Proovige järgmist.</translation>
<translation id="6151417162996330722">Serveri sertifikaadi kehtivusaeg on liiga pikk.</translation>
-<translation id="615643356032862689">Allalaaditud failid ja järjehoidjad hoitakse alles.</translation>
+<translation id="6157877588268064908">Tarneviiside ja nõuete nägemiseks valige aadress</translation>
<translation id="6165508094623778733">Lisateave</translation>
<translation id="6177128806592000436">Teie ühendus selle saidiga pole turvaline</translation>
+<translation id="6184817833369986695">(rühm: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Kontrollige Interneti-ühendust</translation>
<translation id="6218753634732582820">Kas eemaldada Chromiumist aadress?</translation>
<translation id="6251924700383757765">Privaatsuseeskirjad</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Korrasta uuesti</translation>
<translation id="6263376278284652872">Domeeni <ph name="DOMAIN" /> järjehoidjad</translation>
<translation id="6264485186158353794">Tagasi turvalisusse</translation>
+<translation id="6276112860590028508">Siin kuvatakse teie lugemisloendis olevad lehed</translation>
+<translation id="6280223929691119688">Sellele aadressile ei saa kaupa kohale toimetada. Valige mõni teine aadress.</translation>
<translation id="6282194474023008486">Sihtnumber</translation>
<translation id="6290238015253830360">Teie soovitatud artiklid kuvatakse siin</translation>
<translation id="6305205051461490394">URL-iga <ph name="URL" /> ei saa ühendust.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Ei saa kontrollida sertifikaadi võimalikku tühistamist.</translation>
<translation id="6433490469411711332">Kontaktandmete muutmine</translation>
<translation id="6433595998831338502">Host <ph name="HOST_NAME" /> keeldus ühendamast.</translation>
-<translation id="6443118737398455446">Sobimatu aegumiskuupäev</translation>
<translation id="6446608382365791566">Lisateabe lisamine</translation>
<translation id="6451458296329894277">Kinnita vormi uuestiesitamist</translation>
<translation id="6456339708790392414">Teie makse</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Selle turvasertifikaat on võib-olla tühistatud. Selle põhjuseks võib olla vale seadistus või teie ühendust segav ründaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Seadme reeglid</translation>
<translation id="6477321094435799029">Chrome tuvastas sellel lehel ebatavalise koodi ja blokeeris selle, et teie isiklikke andmeid (nt paroolid, telefoninumbrid ja krediitkaardiandmed) kaitsta.</translation>
-<translation id="6477460825583319731">Sobimatu e-posti aadress</translation>
<translation id="6489534406876378309">Krahhide üleslaadimise alustamine</translation>
<translation id="6508722015517270189">Taaskäivitage Chrome</translation>
-<translation id="6525462735697194615">Sobimatu aegumiskuu</translation>
<translation id="6529602333819889595">&amp;Kustuta uuesti</translation>
<translation id="6534179046333460208">Füüsilise veebi soovitused</translation>
<translation id="6550675742724504774">Valikud</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" />'i otsing</translation>
<translation id="6644283850729428850">See reegel on aegunud.</translation>
<translation id="6652240803263749613">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Teie arvuti operatsioonisüsteem ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või teie ühendust segav ründaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">See tarnevalik ei ole saadaval. Proovige teist valikut.</translation>
<translation id="6671697161687535275">Kas eemaldada Chromiumist vormi soovitus?</translation>
<translation id="6685834062052613830">Logige välja ja viige seadistus lõpule</translation>
<translation id="6710213216561001401">Eelmine</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Puhverserveriga on midagi valesti või aadress on vale.</translation>
<translation id="6727102863431372879">Määra</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{mitte ühtegi}=1{1 üksus}other{# üksust}}</translation>
-<translation id="6743044928064272573">Kättesaamise viis</translation>
<translation id="674375294223700098">Serveri sertifikaadi tundmatu viga.</translation>
<translation id="6753269504797312559">Reegli väärtus</translation>
<translation id="6757797048963528358">Teie seade lülitus unerežiimile.</translation>
<translation id="6778737459546443941">Vanem ei ole seda veel kinnitanud</translation>
<translation id="6810899417690483278">Kohandamise ID</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Piirkondade andmete laadimine ebaõnnestus</translation>
<translation id="6831043979455480757">Tõlgi</translation>
<translation id="6839929833149231406">Piirkond</translation>
<translation id="6874604403660855544">&amp;Lisa uuesti</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Teie kaart on kinnitatud</translation>
<translation id="6897140037006041989">Kasutajaagent</translation>
<translation id="6915804003454593391">Kasutaja:</translation>
+<translation id="6948701128805548767">Kättesaamisviiside ja nõuete nägemiseks valige aadress</translation>
<translation id="6957887021205513506">Serveri sertifikaat näib olevat võltsing.</translation>
<translation id="6965382102122355670">Ok</translation>
<translation id="6965978654500191972">Seade</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">Määratud on nii fikseeritud puhverserverid kui ka pac-skriptiga URL.</translation>
<translation id="6989763994942163495">Kuva täpsemad seaded ...</translation>
<translation id="7000990526846637657">Ajalookirjeid ei leitud</translation>
-<translation id="7001663382399377034">Saaja lisamine</translation>
<translation id="7009986207543992532">Püüdsite jõuda domeenile <ph name="DOMAIN" />, ent server esitas sertifikaadi, mille kehtivusperiood on liiga pikk, et olla usaldusväärne. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">Hiina UnionPay</translation>
<translation id="7012372675181957985">Aadressil <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> võib teie Google'i kontol olla muus vormis sirvimisajalugu</translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Vanemad</translation>
<translation id="7090678807593890770">Sisestage Google'isse otsing <ph name="LINK" /></translation>
<translation id="7119414471315195487">Sulgege muud vahelehed või programmid</translation>
+<translation id="7129409597930077180">Sellele aadressile ei saa tarnida. Valige mõni teine aadress.</translation>
+<translation id="7138472120740807366">Kohaletoimetamisviis</translation>
<translation id="7139724024395191329">Emiraat</translation>
<translation id="7155487117670177674">Makse pole turvaline</translation>
<translation id="7179921470347911571">Taaskäivita kohe</translation>
<translation id="7180611975245234373">Värskenda</translation>
<translation id="7182878459783632708">Reegleid pole määratud</translation>
<translation id="7186367841673660872">See leht on tõlgitud keelest<ph name="ORIGINAL_LANGUAGE" />keelde<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423">Host <ph name="HOST_NAME" /> ei pea turvastandarditest kinni.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Lisateave<ph name="END_LINK" /> selle probleemi kohta.</translation>
@@ -675,7 +686,6 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="7424977062513257142">Selle veebilehe manustatud leht ütleb:</translation>
<translation id="7441627299479586546">Reegli objekt on vale</translation>
<translation id="7444046173054089907">See sait on blokeeritud</translation>
-<translation id="7444238235002594607">Valige kättesaamise aadress, et vaadata kättesaamise viise ja nõudeid.</translation>
<translation id="7445762425076701745">Serveri identiteeti, millega olete ühenduses, ei saa täielikult valideerida. Olete ühenduses serveriga nime abil, mis kehtib ainult teie võrgus, mistõttu ei saa väline sertifitseerimisorgan selle omandiõigust valideerida. Kuna mõni sertifitseerimisorgan väljastab sertifikaate hoolimata nende nimedest, puudub igasugune võimalus tagada, et olete ühenduses soovitud veebisaidi, mitte ründajaga.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Vaadake lisateavet<ph name="END_LINK" /> probleemi kohta.</translation>
<translation id="7460163899615895653">Siin kuvatakse teie hiljutised vahelehed teistest seadmetest</translation>
@@ -719,6 +729,7 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="7755287808199759310">Vanem saab blokeeringu teie eest tühistada</translation>
<translation id="7758069387465995638">Tulemüür või viirusetõrjetarkvara võis ühenduse blokeerida.</translation>
<translation id="7761701407923456692">Serveri sertifikaat ei vasta URL-ile.</translation>
+<translation id="7763386264682878361">Makse manifesti parser</translation>
<translation id="7764225426217299476">Lisage aadress</translation>
<translation id="777702478322588152">Prefektuur</translation>
<translation id="7791543448312431591">Lisa</translation>
@@ -732,6 +743,7 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="785549533363645510">Te pole siiski nähtamatu. Inkognito režiimi kasutamine ei varja teie sirvimist tööandja, Interneti-teenuse pakkuja ega külastatavate veebisaitide eest.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Kontrollige CVC-d ja proovige uuesti</translation>
+<translation id="79338296614623784">Sisestage kehtiv telefoninumber</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Serveri sertifikaat ei kehti veel.</translation>
<translation id="7942349550061667556">Punane</translation>
@@ -751,6 +763,7 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="8088680233425245692">Artikli kuvamine ebaõnnestus.</translation>
<translation id="8089520772729574115">vähem kui 1 MB</translation>
<translation id="8091372947890762290">Aktiveerimine on serveris ootel</translation>
+<translation id="8118489163946903409">Makseviis</translation>
<translation id="8131740175452115882">Kinnita</translation>
<translation id="8134994873729925007">Hosti <ph name="HOST_NAME" /> serveri <ph name="BEGIN_ABBR" />DNS-aadressi<ph name="END_ABBR" /> ei leitud.</translation>
<translation id="8149426793427495338">Teie arvuti lülitus unerežiimile.</translation>
@@ -774,8 +787,9 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="834457929814110454">Kui mõistate, kuidas teie turvalisust ohustatakse, siis võite <ph name="BEGIN_LINK" />seda saiti külastada<ph name="END_LINK" /> enne, kui kahjulikud programmid on eemaldatud.</translation>
<translation id="8344669043927012510">Avage leht inkognito režiimis (⇧ + ⌘ + N)</translation>
<translation id="8349305172487531364">Järjehoidjariba</translation>
-<translation id="8363502534493474904">Lülitage lennukirežiim välja</translation>
+<translation id="8363502534493474904">Lülitage lennurežiim välja</translation>
<translation id="8364627913115013041">Määramata.</translation>
+<translation id="8368476060205742148">Google Play teenused</translation>
<translation id="8380941800586852976">Ohtlik</translation>
<translation id="8382348898565613901">Teie hiljuti külastatud järjehoidjad kuvatakse siin</translation>
<translation id="8398259832188219207">Krahhiaruanne laaditi üles ajal <ph name="UPLOAD_TIME" /></translation>
@@ -784,31 +798,29 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="8428213095426709021">Seaded</translation>
<translation id="8433057134996913067">See logib teid välja enamikult veebisaitidelt.</translation>
<translation id="8437238597147034694">&amp;Võta teisaldamine tagasi</translation>
-<translation id="8456681095658380701">Kehtetu nimi</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 krediitkaart}other{# krediitkaarti}}</translation>
<translation id="8483780878231876732">Google'i konto kaartide kasutamiseks logige sisse Chrome'i</translation>
<translation id="8488350697529856933">Kehtib:</translation>
-<translation id="8492969205326575646">Toetamata kaarditüüp</translation>
<translation id="8498891568109133222">Hostil <ph name="HOST_NAME" /> kulus vastamiseks liiga kaua aega.</translation>
<translation id="852346902619691059">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Teie seadme operatsioonisüsteem ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või teie ühendust segav ründaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Aegumisaasta</translation>
<translation id="8543181531796978784">Võite <ph name="BEGIN_ERROR_LINK" />teavitada tuvastusprobleemist<ph name="END_ERROR_LINK" />. Kui mõistate ohtusid oma turvalisusele, võite <ph name="BEGIN_LINK" />seda ebaturvalist saiti külastada<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Tõlkimine nurjus, kuna lehe keelt ei õnnestunud määrata.</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="8570229484593575558">Seda teavet |ei salvestata|:#teie sirvimisajalugu#teie otsingud#küpsisefailide andmed</translation>
<translation id="8571890674111243710">Lehe tõlkimine <ph name="LANGUAGE" /> keelde...</translation>
-<translation id="8584539743998202583">Teie tegevused |võivad siiski olla nähtavad|:#külastatud veebisaitidele#teie tööandjale#teie Interneti-teenuse pakkujale</translation>
<translation id="858637041960032120">Lisage telefoninumber</translation>
<translation id="859285277496340001">Sertifikaat ei määratle mehhanismi enda võimaliku tühistamise kontrollimiseks.</translation>
<translation id="8620436878122366504">Vanemad ei ole seda veel kinnitanud</translation>
<translation id="8647750283161643317">Lähtesta kõik vaikeolekusse</translation>
<translation id="8703575177326907206">Teie ühendus <ph name="DOMAIN" />'ga pole krüptitud.</translation>
+<translation id="8718314106902482036">Makset ei viidud lõpule</translation>
<translation id="8725066075913043281">Proovi uuesti</translation>
<translation id="8728672262656704056">Olete inkognito režiimis</translation>
<translation id="8730621377337864115">Valmis</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="8759274551635299824">See kaart on aegunud</translation>
<translation id="8790007591277257123">&amp;Kustuta uuesti</translation>
-<translation id="8798099450830957504">Vaikimisi</translation>
<translation id="8800988563907321413">Teie lähedalasuvad soovitused kuvatakse siin</translation>
<translation id="8820817407110198400">Järjehoidjad</translation>
<translation id="883848425547221593">Muud järjehoidjad</translation>
@@ -818,6 +830,7 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="8866481888320382733">Reegli seadete sõelumisel ilmnes viga</translation>
<translation id="8866959479196209191">Leht ütleb:</translation>
<translation id="8870413625673593573">Viimati suletud</translation>
+<translation id="8874824191258364635">Sisestaeg kehtiv kaardinumber</translation>
<translation id="8876793034577346603">Võrgu seadistust ei õnnestunud sõeluda.</translation>
<translation id="8877192140621905067">Kui selle kinnitate, jagatakse teie kaardi üksikasju selle saidiga</translation>
<translation id="8889402386540077796">Värvitoon</translation>
@@ -827,7 +840,6 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="8931333241327730545">Kas soovite selle kaardi salvestada oma Google'i kontole?</translation>
<translation id="8932102934695377596">Teie kell on taga</translation>
<translation id="8954894007019320973">(Jätkub)</translation>
-<translation id="895548565263634352">Lugege lugusid väljaandjalt <ph name="ARTICLE_PUBLISHER" /> ja veel <ph name="OTHER_ARTICLE_COUNT" /> artiklit</translation>
<translation id="8971063699422889582">Serveri sertifikaat on aegunud.</translation>
<translation id="8986494364107987395">Saada kasutusstatistika ja krahhiaruanded automaatselt Google'ile</translation>
<translation id="8987927404178983737">kuu</translation>
@@ -845,7 +857,6 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="9068849894565669697">Värvi valimine</translation>
<translation id="9076283476770535406">See võib sisaldada täiskasvanutele mõeldud sisu</translation>
<translation id="9078964945751709336">Vaja on rohkem teavet</translation>
-<translation id="9094175695478007090">Makserakendust ei õnnestu käivitada.</translation>
<translation id="9103872766612412690">Sait <ph name="SITE" /> kasutab teie teabe kaitsmiseks tavaliselt krüpteerimist. Kui Chromium püüdis seekord saidiga <ph name="SITE" /> ühendust luua, tagastas veebisait ebatavalised ja valed mandaadid. See võib juhtuda siis, kui ründaja proovib teeselda, et on sait <ph name="SITE" />, või WiFi sisselogimisekraan on ühenduse katkestanud. Teie teave on endiselt kaitstud, sest Chromium peatas ühenduse enne andmevahetust.</translation>
<translation id="9137013805542155359">Kuva originaal</translation>
<translation id="9137248913990643158">Enne selle rakenduse kasutamist alustage ja logige Chrome'i sisse.</translation>
diff --git a/chromium/components/strings/components_strings_fa.xtb b/chromium/components/strings/components_strings_fa.xtb
index cd3846dc77b..acefe3e0c0d 100644
--- a/chromium/components/strings/components_strings_fa.xtb
+++ b/chromium/components/strings/components_strings_fa.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="fa">
<translation id="1008557486741366299">اکنون نه</translation>
<translation id="1015730422737071372">جزئیات بیشتری ارائه دهید</translation>
+<translation id="1021110881106174305">کارت‌های قابل‌ قبول</translation>
<translation id="1032854598605920125">چرخش در جهت عقربه‌های ساعت</translation>
<translation id="1038842779957582377">نام ناشناس</translation>
<translation id="1050038467049342496">برنامه‌های دیگر را ببندید</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">پنهان کردن مقدار</translation>
<translation id="1228893227497259893">â€Ø´Ù†Ø§Ø³Ù‡ entity نادرست</translation>
<translation id="1232569758102978740">بدون عنوان</translation>
+<translation id="1263231323834454256">Ùهرست خواندن</translation>
<translation id="1264126396475825575">گزارش خرابی ثبت‌شده در <ph name="CRASH_TIME" /> (هنوز بارگذاری نشده است یا نادیده‌ گرÙته شده است)</translation>
<translation id="1285320974508926690">این سایت هرگز ترجمه نشود</translation>
<translation id="129553762522093515">اخیراً بسته‌شده</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">â€ØªÙ†Ø¸ÛŒÙ…ات تکمیل خودکار Chromium...</translation>
<translation id="1374468813861204354">پیشنهادات</translation>
<translation id="1375198122581997741">درباره نسخه</translation>
+<translation id="1377321085342047638">شماره کارت</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> داده‌ای ارسال نکرد.</translation>
<translation id="1407135791313364759">باز کردن همه</translation>
<translation id="1413809658975081374">خطای حریم خصوصی</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">سابقه</translation>
<translation id="1645368109819982629">پروتکل پشتیبانی‌نشده</translation>
<translation id="1656489000284462475">تحویل گرÙتن</translation>
+<translation id="1663943134801823270">â€Ú©Ø§Ø±Øªâ€ŒÙ‡Ø§ Ùˆ نشانی‌ها از Chrome‌ هستند. می‌توانید آن‌ها را در <ph name="BEGIN_LINK" />تنظیمات<ph name="END_LINK" /> مدیریت کنید.</translation>
<translation id="1676269943528358898">â€<ph name="SITE" /> معمولاً برای محاÙظت از اطلاعات شما از رمزگذاری استÙاده می‌کند. اما این بار Ú©Ù‡ Chrome تلاش کرد به <ph name="SITE" /> متصل شود، وب‌سایت اعتبارنامه‌ای نامعمول Ùˆ نادرست را برگرداند. ممکن است مهاجمی در تلاش باشد خود را به‌جای <ph name="SITE" /> معرÙÛŒ کند یا یک صÙحه ورود به سیستم Wi-Fi در ارتباط اختلال ایجاد کرده باشد. اطلاعات شما همچنان ایمن است، زیرا Google Chrome قبل از هرگونه تبادل داده، اتصال را متوق٠کرد.</translation>
<translation id="168328519870909584">مهاجم‌ها در <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> درحال‌حاضر ممکن است تلاش کنند تا برنامه‌های خطرناکی در دستگاهتان نصب کنند که اطلاعات شما (مانند کارت‌های اعتباری، عکس‌ها، گذرواژه‌ها و پیام‌هایتان) را سرقت یا حذ٠می‌کنند.</translation>
<translation id="168841957122794586">گواهی‌نامه سرور دارای یک کلید رمزنگاری ضعی٠است.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">برای بازدید این سایت باید از <ph name="NAME" /> اجازه بگیرید</translation>
+<translation id="1721424275792716183">* این Ùیلد اجباری است</translation>
<translation id="1728677426644403582">درحال مشاهده منبع یک صÙحه وب هستید</translation>
+<translation id="173080396488393970">این نوع کارت پشتیبانی نمی‌شود</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">با سرپرست سیستم تماس بگیرید.</translation>
+<translation id="1740951997222943430">ماه انقضای معتبری وارد کنید</translation>
<translation id="1745358365027406341">بارگیری صÙحه در Ùرصت دیگری</translation>
<translation id="17513872634828108">بازکردن برگه‌ها</translation>
<translation id="1753706481035618306">شماره صÙحه</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">لطÙاً «رمز عبارتی همگام‌سازی» خود را به‌روزرسانی کنید.</translation>
<translation id="1787142507584202372">برگه‌های بازتان در اینجا نشان داده می‌شوند</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">برای بررسی شرایط لازم و روش‌های ارسال کالا، آدرس ارسال کالا را انتخاب کنید.</translation>
+<translation id="1803264062614276815">نام صاحب کارت</translation>
<translation id="1803678881841855883">â€Â«Ù…رور ایمن Google» به‌تازگی در <ph name="SITE" />ØŒ â€<ph name="BEGIN_LINK" />بداÙزار شناسایی کرده است<ph name="END_LINK" />. گاهی اوقات وب‌سایت‌هایی Ú©Ù‡ معمولاً امن هستند با بداÙزار آلوده می‌شوند. منبع محتوای مخرب <ph name="SUBRESOURCE_HOST" /> (یک توزیع‌کننده بداÙزار شناخته شده) است. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">تاریخ اضاÙÙ‡ شدن: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">پارامترهای درخواست یا درخواست نامعتبر</translation>
<translation id="1826516787628120939">در حال بررسی</translation>
<translation id="1834321415901700177">این سایت محتوی برنامه‌های مضر است</translation>
<translation id="1842969606798536927">پرداخت</translation>
-<translation id="1864455488461349376">گزینه ارسال</translation>
<translation id="1871208020102129563">â€ØªÙ†Ø¸ÛŒÙ… پروکسی به گونه‌ای است Ú©Ù‡ از سرورهای ثابت پروکسی استÙاده کند Ùˆ از آدرس اسکریپت pac. استÙاده نکند.</translation>
<translation id="1871284979644508959">قسمت الزامی</translation>
<translation id="187918866476621466">باز کردن صÙحه‌های شروع</translation>
<translation id="1883255238294161206">Ú©ÙˆÚ†Ú© کردن Ùهرست</translation>
<translation id="1898423065542865115">Ùیلتر کردن</translation>
<translation id="194030505837763158">رÙتن به <ph name="LINK" /></translation>
-<translation id="1946821392246652573">کارت‌های پذیرÙته‌شده</translation>
<translation id="1962204205936693436">نشانک‌های <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">خطای ترتیب</translation>
<translation id="1974060860693918893">پیشرÙته</translation>
<translation id="1978555033938440688">نسخه میان‌اÙزار</translation>
+<translation id="1995859865337580572">â€Ù„Ø·Ùاً CVC خود را تأیید کنید</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{و ۱ برنامه دیگر}one{و # برنامه دیگر}other{و # برنامه دیگر}}</translation>
-<translation id="2020194265157481222">نام روی کارت لازم است</translation>
<translation id="2025186561304664664">پروکسی بر روی پیکربندی خودکار تنظیم شده است.</translation>
<translation id="2030481566774242610">منظورتان <ph name="LINK" /> بود؟</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />بررسی پروکسی و دیوار آتش<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">امروز</translation>
<translation id="2154054054215849342">همگام‌سازی برای دامنه شما در دسترس نیست</translation>
<translation id="2154484045852737596">ویرایش کارت</translation>
-<translation id="2156993118928861787">نشانی نامعتبر</translation>
<translation id="2166049586286450108">دسترسی کامل سرپرست</translation>
<translation id="2166378884831602661">این سایت نمی‌تواند اتصالی ایمن ارائه دهد</translation>
<translation id="2181821976797666341">خط‌ مشی‌ها</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{۱ نشانی}one{# نشانی}other{# نشانی}}</translation>
+<translation id="2202020181578195191">سال انقضای معتبری وارد کنید</translation>
<translation id="2212735316055980242">خط‌مشی یاÙت نشد</translation>
<translation id="2213606439339815911">در حال واکشی موارد...</translation>
<translation id="2230458221926704099">با استÙاده از <ph name="BEGIN_LINK" />برنامه عیب‌یابی<ph name="END_LINK" />ØŒ مشکل اتصالتان را برطر٠کنید</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">دسترسی شما به اینترنت مسدود است</translation>
<translation id="230155334948463882">کارت جدید؟</translation>
<translation id="2305919008529760154">این سرور نتوانست اثبات کند <ph name="DOMAIN" /> است؛ شاید گواهینامه امنیتی آن متقلبانه صادر شده باشد. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">â€Ú¯Ø²ÛŒÙ†Ù‡â€ŒÙ‡Ø§ÛŒ کارت Ùˆ نشانی از حساب Google شما (<ph name="ACCOUNT_EMAIL" />) Ùˆ Chrome هستند. می‌توانید در <ph name="BEGIN_LINK" />تنظیمات<ph name="END_LINK" />ØŒ این گزینه‌ها را مدیریت کنید.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> به نام کاربری و گذرواژه نیاز دارد.</translation>
<translation id="2318774815570432836">â€Ø¯Ø±Ø­Ø§Ù„‌حاضر نمی‌توانید از <ph name="SITE" /> دیدن کنید، زیرا این وب‌سایت از HSTS استÙاده می‌کند. خطاها Ùˆ حمله‌های شبکه معمولاً موقتی هستند، بنابراین احتمالاً این صÙحه بعداً کار خواهد کرد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">نشانک‌های دیگر</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">پیش‌Ùرض شرکتی</translation>
<translation id="2386255080630008482">گواهی سرور باطل شده است.</translation>
<translation id="2392959068659972793">نمایش خط‌مشی‌ها با مقدار تنظیم نشده</translation>
+<translation id="239429038616798445">این روش ارسال در دسترس نیست. روش دیگری را امتحان کنید.</translation>
<translation id="2396249848217231973">&amp;واگرد حذÙ</translation>
<translation id="2460160116472764928">â€Â«Ù…رور ایمن Google» به‌تازگی در <ph name="SITE" />ØŒ â€<ph name="BEGIN_LINK" />بداÙزار شناسایی کرده است<ph name="END_LINK" />. گاهی اوقات وب‌سایت‌هایی Ú©Ù‡ معمولاً امن هستند با بداÙزار آلوده می‌شوند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">تکمیل</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />در حال اجرای عیب‌یابی شبکه<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">â€URL جستجو نامعتبر است.</translation>
<translation id="2491120439723279231">گواهی سرور دارای چندین خطاست.</translation>
-<translation id="24943777258388405">شماره تلÙÙ† نامعتبر</translation>
<translation id="2495083838625180221">â€ØªØ¬Ø²ÛŒÙ‡â€ŒÚ©Ù†Ù†Ø¯Ù‡ JSON</translation>
<translation id="2495093607237746763">â€Ø§Ú¯Ø± علامت زده شود، Chromium برای پر کردن سریع‌تر Ùرم، یک Ú©Ù¾ÛŒ از کارت شما در این دستگاه ذخیره می‌کند.</translation>
<translation id="2498091847651709837">اسکن کارت جدید</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> پاسخی نامعتبر ارسال کرد.</translation>
<translation id="2552545117464357659">جدیدتر</translation>
<translation id="2556876185419854533">&amp;واگرد ویرایش</translation>
+<translation id="2587730715158995865">از <ph name="ARTICLE_PUBLISHER" />. این داستان و <ph name="OTHER_ARTICLE_COUNT" /> داستان دیگر را بخوانید.</translation>
<translation id="2587841377698384444">â€Ø´Ù†Ø§Ø³Ù‡ Directory API:</translation>
<translation id="2597378329261239068">این سند توسط گذرواژه محاÙظت می‌شود. لطÙاً یک گذرواژه وارد کنید.</translation>
<translation id="2609632851001447353">انواع مختلÙ</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />در حال اجرای عیب‌یابی اتصال<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">تأیید</translation>
<translation id="2742870351467570537">حذ٠آیتم های انتخاب شده</translation>
+<translation id="277133753123645258">روش ارسال</translation>
<translation id="277499241957683684">ثبت دستگاه موجود نیست</translation>
<translation id="2784949926578158345">اتصال مجدداً برقرار شد.</translation>
<translation id="2794233252405721443">سایت مسدودشده</translation>
-<translation id="2812680587231492111">این گزینه انتخاب دردسترس نیست. گزینه دیگری را امتحان کنید.</translation>
<translation id="2824775600643448204">نوار جستجو و آدرس</translation>
<translation id="2826760142808435982">اتصال با استÙاده از <ph name="CIPHER" /> رمزگذاری Ùˆ راستی‌آزمایی شده است Ùˆ از <ph name="KX" /> به عنوان مکانیسم تبادل کلید استÙاده می‌کند.</translation>
<translation id="2835170189407361413">پاک کردن Ùرم</translation>
-<translation id="2849041323157393173">این گزینه ارائه دردسترس نیست. گزینه دیگری را امتحان کنید.</translation>
<translation id="2889159643044928134">تازه‌سازی نشود</translation>
<translation id="2900469785430194048">â€Google Chrome هنگام تلاش برای نمایش این صÙحه با کمبود حاÙظه روبرو شد.</translation>
<translation id="2909946352844186028">تغییر شبکه تشخیص داده شد.</translation>
<translation id="2916038427272391327">برنامه‌های دیگر را ببندید</translation>
<translation id="2922350208395188000">گواهی سرور بررسی نمی‌شود.</translation>
+<translation id="2928905813689894207">نشانی صورت‌حساب</translation>
<translation id="2948083400971632585">در صÙحه تنظیمات می‌توانید همه پراکسی‌های پیکربندی شده برای هر اتصال را از کار بیاندازید.</translation>
<translation id="2955913368246107853">بستن نوار یاÙتن</translation>
<translation id="2958431318199492670">â€Ù¾ÛŒÚ©Ø±Ø¨Ù†Ø¯ÛŒ شبکه با استاندارد ONC تطابق ندارد. بخشی از پیکربندی ممکن است وارد نشود.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">â€Ø¨Ø±Ø§ÛŒ برقراری یک اتصال امن، لازم است ساعت شما درست تنظیم شده باشد. زیرا گواهی‌هایی Ú©Ù‡ وب‌سایت‌ها برای شناسایی خودشان استÙاده می‌کنند، تنها برای دوره‌های زمانی خاصی معتبرند. از آنجا Ú©Ù‡ ساعت دستگاه شما نادرست است، Google Chrome نمی‌تواند این گواهی‌ها را تأیید کند.</translation>
<translation id="2972581237482394796">انجام مجدد</translation>
<translation id="2985306909656435243">â€Ø§Ú¯Ø± Ùعال شود، Chromium برای پر کردن سریع‌تر Ùرم، یک Ú©Ù¾ÛŒ از کارت شما در این دستگاه ذخیره می‌کند.</translation>
+<translation id="2985398929374701810">نشانی معتبری وارد کنید</translation>
+<translation id="2986368408720340940">این روش تحویل گرÙتن در دسترس نیست. روش دیگری را امتحان کنید.</translation>
<translation id="2991174974383378012">اشتراک‌گذاری با وب‌سایت‌ها</translation>
<translation id="3005723025932146533">نمایش کپی ذخیره شده</translation>
<translation id="3008447029300691911">â€CVC کارت <ph name="CREDIT_CARD" /> را وارد کنید. بعد از تأیید، جزئیات کارت شما با این سایت به اشتراک گذاشته می‌شود.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{حداقل ۱ مورد در دستگاه‌های همگام‌سازی‌شده}=1{۱ مورد (و بیشتر در دستگاه‌های همگام‌سازی‌شده)}one{# مورد (و بیشتر در دستگاه‌های همگام‌سازی‌شده)}other{# مورد (و بیشتر در دستگاه‌های همگام‌سازی‌شده)}}</translation>
<translation id="3041612393474885105">اطلاعات گواهی</translation>
<translation id="3063697135517575841">â€Chrome درحال حاضر نمی‌تواند کارت شما را تأیید کند. لطÙاً بعداً دوباره امتحان کنید.</translation>
+<translation id="3064966200440839136">درحال خروج از حالت ناشناس، برای پرداخت ازطریق یک برنامه خارجی. ادامه می‌دهید؟</translation>
<translation id="3093245981617870298">شما Ø¢Ùلاین هستید.</translation>
<translation id="3105172416063519923">شناسه دارایی:</translation>
<translation id="3109728660330352905">شما اجازه مشاهده این صÙحه را ندارید.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />عیب‌یابی اتصال را اجرا کنید<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">رمزگشایی پاسخ انجام نشد</translation>
-<translation id="3149891296864842641">گزینه ارسال</translation>
<translation id="3150653042067488994">خطای موقت سرور</translation>
+<translation id="3154506275960390542">این صÙحه حاوی Ùرمی است Ú©Ù‡ ممکن است به‌طور ایمن ارسال نشود. دیگران می‌توانند داده‌هایی را Ú©Ù‡ ارسال می‌کنید درحین انتقال ببینند یا مهاجمان می‌توانند برای تغییر آنچه سرور دریاÙت می‌کند، آن‌ها را تغییر دهند.</translation>
<translation id="3157931365184549694">بازیابی</translation>
<translation id="3167968892399408617">صÙحه‌هایی Ú©Ù‡ در برگه‌های حالت ناشناس مرور می‌کنید، بعد از بستن همه برگه‌های حالت ناشناس در سابقه مرورگر، Ùضای ذخیره Ú©ÙˆÚ©ÛŒ یا سابقه جستجو باقی نمی‌مانند. Ùایل‌هایی Ú©Ù‡ بارگیری می‌کنید یا نشانک‌هایی Ú©Ù‡ ایجاد می‌کنید Ø­Ùظ می‌شود.</translation>
<translation id="3169472444629675720">کش٠کردن</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">درخواست شما برای دسترسی به این سایت به <ph name="NAME" /> ارسال نشد. لطÙاً دوباره امتحان کنید.</translation>
<translation id="3355823806454867987">تغییر تنظیمات پروکسی...</translation>
<translation id="3369192424181595722">خطای ساعت</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> مورد دیگر...</translation>
<translation id="337363190475750230">لغو مجوز شد</translation>
<translation id="3377188786107721145">خطای تجزیه خط‌مشی</translation>
<translation id="3380365263193509176">خطای ناشناس</translation>
<translation id="3380864720620200369">شناسه سرویس‌گیرنده:</translation>
<translation id="3391030046425686457">نشانی ارسال</translation>
+<translation id="3395827396354264108">روش تحویل گرÙتن</translation>
<translation id="340013220407300675">ممکن است مهاجمان سعی در دزدیدن اطلاعات شما (مثل گذرواژه‌ها، پیام‌ها یا کارت‌های اعتباری) از <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> را داشته باشند.</translation>
<translation id="3422248202833853650">سعی کنید از برنامه‌های دیگر خارج شوید تا حاÙظه آزاد شود.</translation>
<translation id="3422472998109090673">دسترسی به <ph name="HOST_NAME" /> درحال حاضر امکان‌پذیر نیست.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Ùاصله زمانی واکشی:</translation>
<translation id="3462200631372590220">پنهان کردن پیشرÙته</translation>
+<translation id="3467763166455606212">نام صاحب حساب الزامی است</translation>
+<translation id="3478058380795961209">ماه انقضا</translation>
<translation id="3479539252931486093">غیرمنتظره بود؟ <ph name="BEGIN_LINK" />به ما اطلاع دهید<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">اکنون نه</translation>
<translation id="348000606199325318">شناسه خرابی <ph name="CRASH_LOCAL_ID" /> (شناسه سرور: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">در حال حاضر نمی‌توانیم با والدینتان تماس برقرار کنیم. لطÙاً دوباره امتحان کنید.</translation>
<translation id="3528171143076753409">گواهی سرور مطمئن نیست.</translation>
-<translation id="3538531656504267329">سال انقضای نامعتبر</translation>
<translation id="3539171420378717834">یک کپی از این کارت در این دستگاه نگهداری شود</translation>
<translation id="3542684924769048008">استÙاده از گذرواژه برای:</translation>
<translation id="3549644494707163724">رمزگذاری همه داده‌های همگام‌سازی‌شده با رمزعبارتی همگام‌سازی خودتان</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">عدم نمایش جزئیات</translation>
<translation id="3587482841069643663">همه</translation>
<translation id="3600246354004376029"><ph name="TITLE" />، <ph name="DOMAIN" />، <ph name="TIME" /></translation>
+<translation id="3615877443314183785">تاریخ انقضای معتبری وارد کنید</translation>
<translation id="36224234498066874">پاک کردن داده‌های مرور...</translation>
<translation id="362276910939193118">نمایش کل سابقه</translation>
<translation id="3623476034248543066">نشان دادن مقدار</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">گذرواژه:</translation>
<translation id="3696411085566228381">هیچ‌کدام</translation>
<translation id="3704609568417268905"><ph name="TIME" /> â€<ph name="BOOKMARKED" /> â€<ph name="TITLE" /> â€<ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">برای بررسی شرایط لازم و روش‌های تحویل کالا، آدرس تحویل کالا را انتخاب کنید.</translation>
<translation id="370665806235115550">در حال بارکردن…</translation>
<translation id="3712624925041724820">مجوزها دیگر معتبر نیستند</translation>
<translation id="3714780639079136834">â€Ø±ÙˆØ´Ù† کردن داده‌ شبکه تلÙÙ† همراه یا Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">پیوندی که کپی کرده‌اید</translation>
<translation id="375403751935624634">بدلیل خطای سرور ترجمه انجام نشد.</translation>
<translation id="3759461132968374835">شما اخیراً گزارش خرابی ارسال نکرده‌اید. مشکلاتی Ú©Ù‡ در هنگام غیرÙعال بودن ویژگی ارائه گزارش خرابی ایجاد شده است، در اینجا نمایش داده نمی‌شود.</translation>
+<translation id="3787705759683870569">تاریخ انقضا <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">اگر از سرور پراکسی استÙاده می‌کنید...</translation>
<translation id="3828924085048779000">عبارت عبور خالی مجاز نیست.</translation>
<translation id="3845539888601087042">در حال نمایش سابقه از دستگاه‌هایی که در آن‌ها به سیستم وارد شده‌اید. <ph name="BEGIN_LINK" />بیشتر بدانید<ph name="END_LINK" />.</translation>
@@ -344,7 +356,7 @@
<translation id="4072486802667267160">هنگام پردازش سÙارش شما خطایی روی داد. لطÙاً دوباره امتحان کنید.</translation>
<translation id="4075732493274867456">â€Ú©Ù„اینت Ùˆ سرور از مجموعه رمزگذاری یا نسخه پروتکل SSL مشترکی استÙاده نمی‌کنند.</translation>
<translation id="4079302484614802869">â€ØªÙ†Ø¸ÛŒÙ…ات پروکسی، برای استÙاده از آدرس اسکریپت pac. تنظیم شده است Ùˆ از سرورهای ثابت نمی‌تواند استÙاده کند.</translation>
-<translation id="4098354747657067197">سایت پیش‌رو Ùریب‌کار است</translation>
+<translation id="4098354747657067197">احتیاط، سایت گول‌زننده</translation>
<translation id="4103249731201008433">شماره سریال دستگاه نامعتبر است</translation>
<translation id="4103763322291513355">â€Ø¨Ø±Ø§ÛŒ مشاهده Ùهرست نشانی‌های وب ممنوع Ùˆ سایر خط‌مشی‌های اجباری براساس تصمیم سرپرست سیستم خود از &lt;strong&gt;chrome://policy&lt;/strong&gt; بازدید نمایید.</translation>
<translation id="4110615724604346410">این سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن خطاهایی دارد. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">â€Ù…ی‌خواهید Chromium این کارت را ذخیره کند؟</translation>
<translation id="4171400957073367226">امضای تأیید نامناسب</translation>
-<translation id="4176463684765177261">غیرÙعال شد</translation>
<translation id="4196861286325780578">&amp;انجام مجدد انتقال</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />بررسی پیکربندی آنتی‌ویروس و دیوار آتش<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{هیچ‌}=1{۱ برنامه ($1)}=2{۲ برنامه ($1،†$2)}one{# برنامه ($1،†$2،†$3)}other{# برنامه ($1،†$2،†$3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">نتایج جستجو</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> گواهی ورود به سیستمتان را نپذیرÙت یا ممکن است گواهی‌ای ارائه نشده باشد.</translation>
<translation id="443673843213245140">استÙاده از پروکسی غیرÙعال است اما یک پیکربندی خاص برای پروکسی تعیین شده است.</translation>
-<translation id="4446242550670694251">اکنون می‌توانید به‌طور خصوصی مرور کنید Ùˆ سایر اÙرادی Ú©Ù‡ از این دستگاه استÙاده می‌کنند Ùعالیت شما را نخواهند دید.</translation>
<translation id="4492190037599258964">نتایج جستجو برای "<ph name="SEARCH_STRING" />"</translation>
<translation id="4506176782989081258">خطای ارزیابی: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">تماس با سرپرست سیستم</translation>
<translation id="450710068430902550">اشتراک‌گذاری با سرپرست سیستم</translation>
+<translation id="4515275063822566619">â€Ú©Ø§Ø±Øªâ€ŒÙ‡Ø§ Ùˆ نشانی‌ها از Chrome Ùˆ حساب Google شما (<ph name="ACCOUNT_EMAIL" />) هستند. می‌توانید آن‌ها را در <ph name="BEGIN_LINK" />تنظیمات<ph name="END_LINK" /> مدیریت کنید.</translation>
<translation id="4522570452068850558">جزئیات</translation>
<translation id="4558551763791394412">اÙزونه‌ها را غیرÙعال کنید.</translation>
<translation id="457875822857220463">ارسال</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">متناسب با صÙحه</translation>
<translation id="483020001682031208">هیچ صÙحه «وب Ùیزیکی» برای نمایش وجود ندارد</translation>
<translation id="4850886885716139402">نما</translation>
+<translation id="4854362297993841467">این روش تحویل در دسترس نیست. روش دیگری را امتحان کنید.</translation>
<translation id="4858792381671956233">از والدینتان پرسیدید آیا اجازه بازدید از این سایت را دارید</translation>
<translation id="4880827082731008257">سابقه جستجو</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />،†<ph name="TYPE_2" />،†<ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">این صÙحه از یک زبان ناشناس به <ph name="LANGUAGE_LANGUAGE" /> ترجمه شده است.</translation>
<translation id="4923459931733593730">پرداخت</translation>
<translation id="4926049483395192435">باید مشخص شود.</translation>
-<translation id="4941291666397027948">* نشانگر قسمت الزامی است</translation>
<translation id="495170559598752135">عملکردها</translation>
<translation id="4958444002117714549">بزرگ کردن Ùهرست</translation>
<translation id="4962322354953122629">â€Ø§ÛŒÙ† سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن مورداعتماد Chrome نیست. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">گذرواژه نادرست</translation>
<translation id="5056549851600133418">مقالاتی برای شما</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />بررسی آدرس پروکسی<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{بدون Ú©ÙˆÚ©ÛŒ}=1{Û± سایت از Ú©ÙˆÚ©ÛŒ استÙاده می‌کند. }one{# سایت از Ú©ÙˆÚ©ÛŒ استÙاده می‌کنند. }other{# سایت از Ú©ÙˆÚ©ÛŒ استÙاده می‌کنند. }}</translation>
<translation id="5087286274860437796">در حال حاضر گواهی سرور معتبر نیست.</translation>
<translation id="5087580092889165836">اÙزودن کارت</translation>
<translation id="5089810972385038852">ایالت</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">نمایش</translation>
<translation id="5308689395849655368">گزارش خرابی غیر Ùعال است.</translation>
<translation id="5317780077021120954">ذخیره</translation>
-<translation id="5326702247179446998">گیرنده لازم است.</translation>
<translation id="5327248766486351172">نام</translation>
<translation id="5337705430875057403">مهاجمان <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ممکن است شما را Ùریب دهند Ùˆ به انجام کارهای خطرناکی مثل نصب نرم‌اÙزار یا ارائه اطلاعات شخصی‌تان (مثلاً گذرواژه، شماره تلÙÙ† یا کارت‌های اعتباری) ترغیب کنند.</translation>
-<translation id="53553865750799677">نشانی ارسال کالا پشتیبانی نمی‌شود. نشانی دیگری را انتخاب کنید.</translation>
<translation id="5359637492792381994">این سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن درحال‌حاضر معتبر نیست. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">تنظیمات خط‌‌مشی ذخیره نشد</translation>
<translation id="5386426401304769735">â€Ø²Ù†Ø¬ÛŒØ±Ù‡ گواهی این سایت حاوی یک گواهی با امضای SHA-1 است.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">صÙحه جاسازی‌شده‌ای در <ph name="SITE" /> می‌گوید:</translation>
<translation id="5556459405103347317">تازه‌سازی</translation>
<translation id="5565735124758917034">Ùعال</translation>
+<translation id="5571083550517324815">تحویل گرÙتن از این نشانی ممکن نیست. نشانی دیگری را انتخاب کنید.</translation>
<translation id="5572851009514199876">â€Ù„Ø·Ùاً Chrome را باز کنید Ùˆ به سیستم آن وارد شوید تا Chrome بتواند بررسی کند آیا مجاز به دسترسی به این سایت هستید یا خیر.</translation>
-<translation id="5575380383496039204">آدرس ارسال کالا پشتیبانی نمی‌شود. نشانی دیگری انتخاب کنید.</translation>
<translation id="5580958916614886209">ماه انقضا را بررسی و دوباره امتحان کنید</translation>
<translation id="560412284261940334">مدیریت پشتیبانی نمی‌شود</translation>
<translation id="5610142619324316209">بررسی اتصال</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">هویت این وب سایت تأیید نشده است.</translation>
<translation id="5720705177508910913">کاربر کنونی</translation>
<translation id="5732392974455271431">والدینتان می‌توانند این سایت را برای شما بگشایند</translation>
-<translation id="57586589942790530">شماره کارت نامعتبر است</translation>
+<translation id="5763042198335101085">نشانی رایانامه معتبری وارد کنید</translation>
+<translation id="5765072501007116331">برای دیدن روش‌های تحویل و شرایط موردنیاز، یک نشانی انتخاب کنید</translation>
<translation id="5784606427469807560">هنگام تأیید کارت مشکلی پیش آمد. اتصال اینترنتتان را بررسی و دوباره امتحان کنید.</translation>
<translation id="5785756445106461925">علاوه بر این، این صÙحه دارای منابع دیگری است Ú©Ù‡ امن نیستند. دیگران می‌توانند در حین انتقال، این منابع را ببینند Ùˆ این منابع می‌توانند برای تغییر Ù‚ÙÙ„ صÙحه، توسط یک مهاجم تغییر داده شوند.</translation>
<translation id="5786044859038896871">می‌خواهید اطلاعات کارتتان را وارد کنید؟</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">دسترسی به این سایت امکان‌پذیر نیست</translation>
<translation id="5869522115854928033">گذرواژه‌های ذخیره‌شده</translation>
<translation id="5872918882028971132">پیشنهادات والدین</translation>
-<translation id="587760065310675640">نشانی تحویل کالا پشتیبانی نمی‌شود. نشانی دیگری انتخاب کنید.</translation>
<translation id="5901630391730855834">زرد</translation>
-<translation id="59174027418879706">Ùعال شد</translation>
<translation id="5926846154125914413">ممکن است دسترسی به محتوای ممتاز برخی از سایت‌ها را از دست بدهید.</translation>
<translation id="5959728338436674663">â€Ø§Ø±Ø³Ø§Ù„ خودکار برخی از <ph name="BEGIN_WHITEPAPER_LINK" />اطلاعات سیستم Ùˆ محتوای صÙحه<ph name="END_WHITEPAPER_LINK" /> به Google برای Ú©Ù…Ú© به شناسایی برنامه‌ها Ùˆ سایت‌های خطرناک. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Ù‡Ùته</translation>
<translation id="5967867314010545767">حذ٠از سابقه</translation>
<translation id="5975083100439434680">کوچک نمایی</translation>
+<translation id="598637245381783098">برنامه پرداخت باز نشد</translation>
<translation id="5989320800837274978">â€Ø³Ø±ÙˆØ± پروکسی ثابت Ùˆ URL اسکریپت pac. تعیین نشده‌اند.</translation>
<translation id="5990559369517809815">درخواست‌های ارسالی به سرور توسط یک برنامهٔ اÙزودنی مسدود شد.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">â€Ú¯Ø²ÛŒÙ†Ù‡â€ŒÙ‡Ø§ÛŒ کارت Ùˆ نشانی از Chrome هستند. می‌توانید در <ph name="BEGIN_LINK" />تنظیمات<ph name="END_LINK" />ØŒ این گزینه‌ها را مدیریت کنید.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{صÙحه Û±}one{صÙحه #}other{صÙحه #}}</translation>
<translation id="6017514345406065928">سبز</translation>
+<translation id="6027201098523975773">نامی وارد کنید</translation>
<translation id="6040143037577758943">بستن</translation>
-<translation id="604124094241169006">خودکار</translation>
<translation id="6042308850641462728">بیشتر</translation>
<translation id="6060685159320643512">مراقب باشید، این آزمایشات ممکن است خطرناک باشند</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{هیچ‌}=1{۱}one{#}other{#}}</translation>
@@ -543,9 +552,10 @@
 شبکه‌ای را Ú©Ù‡ ممکن است درحال استÙاده از آن‌ها باشید مجدداً راه‌اندازی کنید.</translation>
<translation id="614940544461990577">این موارد را امتحان کنید:</translation>
<translation id="6151417162996330722">دوره اعتبار گواهینامه سرور بسیار طولانی است.</translation>
-<translation id="615643356032862689">Ùایل‌ها Ùˆ نشانک‌های بارگیری‌شده Ø­Ùظ می‌شوند.</translation>
+<translation id="6157877588268064908">برای دیدن روش‌های ارسال و شرایط موردنیاز، یک نشانی انتخاب کنید</translation>
<translation id="6165508094623778733">بیشتر بدانید</translation>
<translation id="6177128806592000436">اتصال شما به این سایت امن نیست</translation>
+<translation id="6184817833369986695">(هم‌گروه: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">اتصال اینترنتتان را بررسی کنید</translation>
<translation id="6218753634732582820">â€Ø¢Ø¯Ø±Ø³ از Chromium پاک شود؟</translation>
<translation id="6251924700383757765">خط‌مشی رازداری</translation>
@@ -554,13 +564,15 @@
<translation id="6259156558325130047">&amp;انجام مجدد ترتیب‌بندی مجدد</translation>
<translation id="6263376278284652872">نشانک‌های <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">بازگشت به ایمنی</translation>
+<translation id="6276112860590028508">صÙحه‌های مربوط به Ùهرست خواندنتان اینجا نشان داده می‌شوند</translation>
+<translation id="6280223929691119688">تحویل به این نشانی ممکن نیست. نشانی دیگری را انتخاب کنید.</translation>
<translation id="6282194474023008486">کد پستی</translation>
<translation id="6290238015253830360">مقاله‌های پیشنهادی شما در اینجا نشان داده می‌شوند</translation>
<translation id="6305205051461490394">دسترسی به <ph name="URL" /> امکان‌پذیر نیست.</translation>
<translation id="6319915415804115995">آخرین استÙاده، بیش از یک سال قبل</translation>
<translation id="6321917430147971392">â€ØªÙ†Ø¸ÛŒÙ…ات DNS خودتان را بررسی کنید</translation>
<translation id="6328639280570009161">غیرÙعال کردن پیش‌بینی شبکه را امتحان کنید</translation>
-<translation id="6328786501058569169">این سایت گمراه‌کننده است</translation>
+<translation id="6328786501058569169">این سایت گول‌زننده است</translation>
<translation id="6337534724793800597">Ùیلتر کردن خط‌مشی‌ها براساس نام</translation>
<translation id="6342069812937806050">Ùقط اکنون</translation>
<translation id="6355080345576803305">لغو جلسه عمومی</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">امکان بررسی اینکه آیا مجوز باطل شده است یا نه وجود ندارد.</translation>
<translation id="6433490469411711332">ویرایش اطلاعات تماس</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> از اتصال خودداری کرد.</translation>
-<translation id="6443118737398455446">تاریخ انقضای نامعتبر</translation>
<translation id="6446608382365791566">اÙزودن اطلاعات بیشتر</translation>
<translation id="6451458296329894277">تأیید ارسال مجدد Ùرم</translation>
<translation id="6456339708790392414">پرداخت شما</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">این سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ شاید گواهینامه امنیتی آن باطل شده باشد. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">خط‌‌مشی‌های دستگاه</translation>
<translation id="6477321094435799029">â€Chrome کد نامعمول در این این صÙحه شناسایی کرده Ùˆ برای محاÙظت از اطلاعات شخصی‌تان (مثلاً گذرواژه‌ها، شماره تلÙن‌‌ها Ùˆ کارت‌های اعتباری) آن را مسدود کرده است.</translation>
-<translation id="6477460825583319731">آدرس رایانامه نامعتبر</translation>
<translation id="6489534406876378309">شروع بارگذاری کردن خرابی‌ها</translation>
<translation id="6508722015517270189">â€Chrome را راه‌اندازی مجدد کنید</translation>
-<translation id="6525462735697194615">ماه انقضای نامعتبر</translation>
<translation id="6529602333819889595">&amp;انجام مجدد حذÙ</translation>
<translation id="6534179046333460208">پیشنهادهای «وب Ùیزیکی»</translation>
<translation id="6550675742724504774">گزینه‌ها</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685">جستجوی <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">این قانون قدیمی شده است.</translation>
<translation id="6652240803263749613">این سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن مورداعتماد سیستم‌عامل رایانه شما نیست. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">این گزینه ارسال دردسترس نیست. گزینه دیگری را امتحان کنید.</translation>
<translation id="6671697161687535275">â€Ù¾ÛŒØ´Ù†Ù‡Ø§Ø¯ Ùرم از Chromium پاک شود؟</translation>
<translation id="6685834062052613830">خروج از سیستم و تکمیل راه‌اندازی</translation>
<translation id="6710213216561001401">قبلی</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">مشکلی در سرور پروکسی وجود دارد یا این آدرس درست نیست.</translation>
<translation id="6727102863431372879">تنظیم</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{هیچ‌}=1{۱ مورد}one{# مورد}other{# مورد}}</translation>
-<translation id="6743044928064272573">گزینه ارسال کالا</translation>
<translation id="674375294223700098">خطای ناشناس گواهی سرور.</translation>
<translation id="6753269504797312559">مقدار خط‌‌مشی</translation>
<translation id="6757797048963528358">دستگاهتان به خواب رÙته است.</translation>
<translation id="6778737459546443941">والدینتان هنوز این سایت را تأیید نکرده‌اند</translation>
<translation id="6810899417690483278">شناسه سÙارشی‌سازی</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">داده‌های منطقه‌ها بارگیری نشد</translation>
<translation id="6831043979455480757">ترجمه</translation>
<translation id="6839929833149231406">منطقه حکومتی</translation>
<translation id="6874604403660855544">&amp;انجام مجدد اÙزودن</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">کارتتان تأیید شد</translation>
<translation id="6897140037006041989">نماینده کاربر</translation>
<translation id="6915804003454593391">کاربر:</translation>
+<translation id="6948701128805548767">برای دیدن روش‌های تحویل گرÙتن Ùˆ شرایط موردنیاز، یک نشانی انتخاب کنید</translation>
<translation id="6957887021205513506">به نظر می‌رسد که گواهی سرور جعلی باشد.</translation>
<translation id="6965382102122355670">قبول</translation>
<translation id="6965978654500191972">دستگاه</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">â€Ù‡Ù… سرورهای پروکسی ثابت Ùˆ هم آدرس اسکریپت pac. مشخص شده‌اند.</translation>
<translation id="6989763994942163495">نمایش تنظیمات پیشرÙته ...</translation>
<translation id="7000990526846637657">هیچ ورودی سابقه‌ای پیدا نشد</translation>
-<translation id="7001663382399377034">اÙزودن گیرنده</translation>
<translation id="7009986207543992532">سعی کردید به <ph name="DOMAIN" /> دسترسی داشته باشید، اما سرور گواهینامه‌ای ارائه کرد که دوره اعتبار بیش از اندازه طولانی آن قابل‌اعتماد نیست. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">â€Ù…Ù…Ú©Ù† است «حساب Google» شما سابقه مروری به Ø´Ú©Ù„ دیگری در <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> داشته باشد</translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">قدیمی تر</translation>
<translation id="7090678807593890770">â€Ø¬Ø³ØªØ¬ÙˆÛŒ <ph name="LINK" /> در Google</translation>
<translation id="7119414471315195487">برگه‌ها یا برنامه‌های دیگر را ببندید</translation>
+<translation id="7129409597930077180">ارسال به این نشانی ممکن نیست. نشانی دیگری را انتخاب کنید.</translation>
+<translation id="7138472120740807366">روش تحویل</translation>
<translation id="7139724024395191329">امارت</translation>
<translation id="7155487117670177674">پرداخت امن نیست</translation>
<translation id="7179921470347911571">اکنون راه‌اندازی مجدد شود</translation>
<translation id="7180611975245234373">بازخوانی</translation>
<translation id="7182878459783632708">هیچ خط‌مشی‌ای تنظیم نشده است</translation>
<translation id="7186367841673660872">این صÙحه از <ph name="ORIGINAL_LANGUAGE" /> به <ph name="LANGUAGE_LANGUAGE" /> ترجمه شده است</translation>
+<translation id="7192203810768312527"><ph name="SIZE" /> از Ùضا را آزاد می‌کند. ممکن است برخی از سایت‌ها در بازدیدهای بعدی کندتر بارگیری شوند.</translation>
<translation id="719464814642662924">ویزا</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> از استانداردهای امنیتی پیروی نمی‌کند.</translation>
<translation id="721197778055552897">دربارهٔ این مشکل <ph name="BEGIN_LINK" />بیشتر بیاموزید<ph name="END_LINK" />.</translation>
@@ -675,7 +686,6 @@
<translation id="7424977062513257142">صÙحه جاسازی‌شده‌ای در این صÙحه وب می‌گوید:</translation>
<translation id="7441627299479586546">موضوع خط‌مشی اشتباه است</translation>
<translation id="7444046173054089907">این سایت مسدود شده است</translation>
-<translation id="7444238235002594607">برای بررسی شرایط لازم Ùˆ روش‌های تحویل کالا، نشانی تحویل گرÙتن کالا را انتخاب کنید.</translation>
<translation id="7445762425076701745">هویت سروری Ú©Ù‡ به آن متصل شده‌اید به‌طور کامل راستی‌آزمایی نمی‌شود. با استÙاده از نامی به سرور متصل شده‌اید Ú©Ù‡ Ùقط در شبکه شما معتبر است Ùˆ ارائه دهنده مجوز خارجی قادر به راستی‌آزمایی مالکیت آن نیست. به دلیل آنکه برخی از ارائه دهندگان مجوز بدون توجه به هر موردی، مجوزهایی را برای این نام‌ها ارائه می‌کنند، روشی برای اطمینان از این امر وجود ندارد Ú©Ù‡ آیا شما به سایت مورد نظر خود متصل شده‌اید یا یک سایت مضر.</translation>
<translation id="7451311239929941790">درباره این مشکل <ph name="BEGIN_LINK" />بیشتر بدانید<ph name="END_LINK" />.</translation>
<translation id="7460163899615895653">برگه‌های اخیر شما از دیگر دستگاه‌ها اینجا نشان داده می‌شوند</translation>
@@ -719,6 +729,7 @@
<translation id="7755287808199759310">والدینتان می‌توانند این سایت را برای شما بگشایند</translation>
<translation id="7758069387465995638">دیوار آتش یا نرم‌اÙزار ضدویروس ممکن است مانع اتصال شده باشد.</translation>
<translation id="7761701407923456692">گواهی سرور با نشانی وب مطابقت ندارد.</translation>
+<translation id="7763386264682878361">تجزیه‌کننده مانیÙست پرداخت</translation>
<translation id="7764225426217299476">اÙزودن آدرس</translation>
<translation id="777702478322588152">حوزه اداری</translation>
<translation id="7791543448312431591">اÙزودن</translation>
@@ -732,6 +743,7 @@
<translation id="785549533363645510">اما، شما نامرئی نیستید. با استÙاده از حالت ناشناس، مرورتان از چشمان کارÙرمای شما، ارائه‌دهنده خدمات اینترنت یا وب‌‌سایت‌هایی Ú©Ù‡ بازدید می‌کنید پنهان نمی‌ماند.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">â€CVC را بررسی کرده Ùˆ دوباره امتحان کنید</translation>
+<translation id="79338296614623784">شماره تلÙÙ† معتبری وارد کنید</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">گواهی سرور هنوز معتبر نیست.</translation>
<translation id="7942349550061667556">قرمز</translation>
@@ -751,6 +763,7 @@
<translation id="8088680233425245692">مشاهده مقاله ناموÙÙ‚ بود.</translation>
<translation id="8089520772729574115">کمتر از ۱ مگابایت</translation>
<translation id="8091372947890762290">Ùعال‌سازی در سرور در حالت تعلیق است</translation>
+<translation id="8118489163946903409">روش پرداخت</translation>
<translation id="8131740175452115882">تأیید</translation>
<translation id="8134994873729925007">â€<ph name="BEGIN_ABBR" />نشانی DNS<ph name="END_ABBR" /> سرور <ph name="HOST_NAME" /> پیدا نشد.</translation>
<translation id="8149426793427495338">رایانه‌تان به خواب رÙته است.</translation>
@@ -776,6 +789,7 @@
<translation id="8349305172487531364">نوار نشانک‌ها</translation>
<translation id="8363502534493474904">خاموش کردن حالت هواپیما</translation>
<translation id="8364627913115013041">تنظیم نشده است.</translation>
+<translation id="8368476060205742148">â€Ø®Ø¯Ù…ات Google Play</translation>
<translation id="8380941800586852976">خطرناک</translation>
<translation id="8382348898565613901">نشانک‌هایی که به‌تازگی از آن‌ها دیدن کرده‌اید، در اینجا نشان داده می‌شوند</translation>
<translation id="8398259832188219207">گزارش خرابی در <ph name="UPLOAD_TIME" /> بارگذاری شد</translation>
@@ -784,31 +798,29 @@
<translation id="8428213095426709021">تنظیمات</translation>
<translation id="8433057134996913067">با این کار از سیستم بیشتر وب‌سایت‌ها خارج می‌شوید.</translation>
<translation id="8437238597147034694">&amp;واگرد انتقال</translation>
-<translation id="8456681095658380701">نام نامعتبر</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{۱ کارت اعتباری}one{# کارت اعتباری}other{# کارت اعتباری}}</translation>
<translation id="8483780878231876732">â€Ø¨Ø±Ø§ÛŒ استÙاده از کارت‌ها از حساب Google خود، به سیستم Chrome وارد شوید</translation>
<translation id="8488350697529856933">اعمال برای</translation>
-<translation id="8492969205326575646">نوع کارت پشتیبانی‌نشده</translation>
<translation id="8498891568109133222">پاسخ <ph name="HOST_NAME" /> بیش از حد طول کشیده است.</translation>
<translation id="852346902619691059">این سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن مورداعتماد سیستم‌عامل دستگاه شما نیست. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">سال انقضا</translation>
<translation id="8543181531796978784">می‌توانید <ph name="BEGIN_ERROR_LINK" />یک مشکل شناسایی‌شده را گزارش کنید<ph name="END_ERROR_LINK" /> یا اگر از خطراتی که امنیت شما را تهدید می‌کنند مطلع شدید، <ph name="BEGIN_LINK" />از این سایت ناامن دیدن کنید<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">ترجمه انجام نشد زیرا زبان صÙحه تعیین نشد.</translation>
<translation id="8559762987265718583">اتصال خصوصی به <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> انجام نمی‌شود، زیرا تاریخ و زمان دستگاه شما (<ph name="DATE_AND_TIME" />) نادرست است.</translation>
-<translation id="8570229484593575558">این اطلاعات |ذخیره نخواهند شد|:#سابقه مرور شما#جستجوهای شما#داده‌های کوکی</translation>
<translation id="8571890674111243710">ترجمه صÙحه به <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">شاید Ùعالیت شما همچنان |برای این موارد قابل‌مشاهده باشد|:#وب‌سایت‌هایی Ú©Ù‡ بازدید می‌کنید#کارÙرمای شما#ارائه‌دهنده خدمات اینترنت شما</translation>
<translation id="858637041960032120">اÙزودن شماره تلÙÙ†</translation>
<translation id="859285277496340001">این مجوز هیچ مکانیزمی را برای بررسی اینکه آیا باطل شده یا نه مشخص نمی‌کند.</translation>
<translation id="8620436878122366504">والدینتان هنوز این سایت را تأیید نکرده‌اند</translation>
<translation id="8647750283161643317">بازنشانی همه به موارد پیش‌Ùرض</translation>
<translation id="8703575177326907206">اتصال شما به <ph name="DOMAIN" /> رمزگذاری نشده است.</translation>
+<translation id="8718314106902482036">پرداخت کامل نشد</translation>
<translation id="8725066075913043281">سعی مجدد</translation>
-<translation id="8728672262656704056">به صورت ناشناس وارد شدید</translation>
+<translation id="8728672262656704056">اکنون در حالت ناشناس هستید</translation>
<translation id="8730621377337864115">تمام</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="8759274551635299824">کارت منقضی شده است</translation>
<translation id="8790007591277257123">&amp;انجام مجدد حذÙ</translation>
-<translation id="8798099450830957504">پیش‌Ùرض</translation>
<translation id="8800988563907321413">پیشنهادات اطرا٠شما در اینجا نشان داده می‌شوند</translation>
<translation id="8820817407110198400">نشانک‌ها</translation>
<translation id="883848425547221593">نشانک‌های دیگر</translation>
@@ -818,6 +830,7 @@
<translation id="8866481888320382733">خطا در تجزیه تنظیمات خط‌مشی</translation>
<translation id="8866959479196209191">این صÙحه می‌گوید:</translation>
<translation id="8870413625673593573">اخیراً بسته‌شده</translation>
+<translation id="8874824191258364635">شماره کارت معتبری وارد کنید</translation>
<translation id="8876793034577346603">پیکربندی شبکه نتوانست تجزیه شود.</translation>
<translation id="8877192140621905067">بعد از تأیید کردن، جزئیات کارتتان با این سایت به اشتراک گذاشته می‌شود</translation>
<translation id="8889402386540077796">رنگ‌مایه</translation>
@@ -827,7 +840,6 @@
<translation id="8931333241327730545">â€Ù…ی‌خواهید این کارت را در حساب Google خود ذخیره کنید؟</translation>
<translation id="8932102934695377596">ساعت شما عقب است</translation>
<translation id="8954894007019320973">(ادامه)</translation>
-<translation id="895548565263634352">خواندن داستان‌های <ph name="ARTICLE_PUBLISHER" /> و <ph name="OTHER_ARTICLE_COUNT" /> مقاله دیگر</translation>
<translation id="8971063699422889582">گواهی سرور منقضی شده است.</translation>
<translation id="8986494364107987395">â€Ø§Ø±Ø³Ø§Ù„ خودکار آمار کاربرد Ùˆ گزارش‌های خرابی به Google</translation>
<translation id="8987927404178983737">ماه</translation>
@@ -845,7 +857,6 @@
<translation id="9068849894565669697">انتخاب رنگ</translation>
<translation id="9076283476770535406">این سایت ممکن است شامل محتوای مخصوص بزرگسالان باشد</translation>
<translation id="9078964945751709336">اطلاعات بیشتری نیاز است</translation>
-<translation id="9094175695478007090">برنامه پرداخت راه‌اندازی نشد.</translation>
<translation id="9103872766612412690">â€<ph name="SITE" /> معمولاً برای محاÙظت از اطلاعات شما از رمزگذاری استÙاده می‌کند. اما این بار Ú©Ù‡ Chromium تلاش کرد به <ph name="SITE" /> متصل شود، وب‌سایت اعتبارنامه‌ای نامعمول Ùˆ نادرست را برگرداند. ممکن است مهاجمی در تلاش باشد خود را به‌جای <ph name="SITE" /> معرÙÛŒ کند یا یک صÙحه ورود به سیستم Wi-Fi در ارتباط اختلال ایجاد کرده باشد. اطلاعات شما همچنان ایمن است، زیرا Chromium قبل از هرگونه تبادل داده، اتصال را متوق٠کرد.</translation>
<translation id="9137013805542155359">نمایش مورد اصلی</translation>
<translation id="9137248913990643158">â€Ù„Ø·Ùاً پیش از استÙاده از این برنامه، Chrome را باز کنید Ùˆ به سیستم آن وارد شوید.</translation>
diff --git a/chromium/components/strings/components_strings_fi.xtb b/chromium/components/strings/components_strings_fi.xtb
index 580f9fcd66b..6ebd0c6f391 100644
--- a/chromium/components/strings/components_strings_fi.xtb
+++ b/chromium/components/strings/components_strings_fi.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="fi">
<translation id="1008557486741366299">Ei nyt</translation>
<translation id="1015730422737071372">Lisätietoja</translation>
+<translation id="1021110881106174305">Hyväksytyt kortit</translation>
<translation id="1032854598605920125">Käännä myötäpäivään</translation>
<translation id="1038842779957582377">tuntematon nimi</translation>
<translation id="1050038467049342496">Sulje muita sovelluksia.</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Piilota arvo</translation>
<translation id="1228893227497259893">Väärä entiteettitunnus</translation>
<translation id="1232569758102978740">Nimetön</translation>
+<translation id="1263231323834454256">Lukulista</translation>
<translation id="1264126396475825575">Kaatumisraportti tallennettu <ph name="CRASH_TIME" /> (ei vielä lähetetty tai ohitettu)</translation>
<translation id="1285320974508926690">Älä käännä tätä sivustoa</translation>
<translation id="129553762522093515">Hiljattain suljetut välilehdet</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromiumin automaattisen täytön asetukset…</translation>
<translation id="1374468813861204354">ehdotuksia</translation>
<translation id="1375198122581997741">Tietoja versiosta</translation>
+<translation id="1377321085342047638">Kortin numero</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> ei lähettänyt tietoja.</translation>
<translation id="1407135791313364759">Avaa kaikki</translation>
<translation id="1413809658975081374">Tietosuojavirhe</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Historia</translation>
<translation id="1645368109819982629">Protokollaa ei tueta</translation>
<translation id="1656489000284462475">Noutoaika</translation>
+<translation id="1663943134801823270">Kortit ja osoitteet ovat peräisin Chromesta. Voit hallinnoida niitä <ph name="BEGIN_LINK" />asetuksissa<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> suojaa tietosi normaalisti salauksen avulla. Kun Chrome yritti tällä kertaa yhdistää sivustoon <ph name="SITE" />, sivusto palautti epätavalliset ja virheelliset kirjautumistiedot. Hyökkääjä saattaa yrittää esiintyä sivustona <ph name="SITE" />, tai Wi-Fi-kirjautumisruutu on keskeyttänyt yhteyden. Tietosi ovat edelleen turvassa, sillä Google Chrome katkaisi yhteyden, ennen kuin mitään tietoja vaihdettiin.</translation>
<translation id="168328519870909584">Sivustolle <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> hyökännyt taho voi yrittää asentaa laitteellesi vaarallisia ohjelmia, jotka varastavat tai poistavat tietojasi, kuten kuviasi, salasanojasi, viestejäsi ja luottokorttiesi tietoja.</translation>
<translation id="168841957122794586">Palvelinvarmenne sisältää heikon salausavaimen.</translation>
<translation id="1710259589646384581">Käyttöjärjestelmä</translation>
<translation id="1721312023322545264">Tarvitset henkilön <ph name="NAME" /> luvan käydä tällä sivustolla</translation>
+<translation id="1721424275792716183">* Kenttä on pakollinen.</translation>
<translation id="1728677426644403582">Tämä on verkkosivun lähdekoodi.</translation>
+<translation id="173080396488393970">Tätä korttityyppiä ei tueta.</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Ota yhteyttä järjestelmänvalvojaan.</translation>
+<translation id="1740951997222943430">Anna kelvollinen viimeinen voimassaolokuukausi.</translation>
<translation id="1745358365027406341">Lataa sivu myöhemmin</translation>
<translation id="17513872634828108">Avoimet välilehdet</translation>
<translation id="1753706481035618306">Sivunumero</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Päivitä synkronoinnin tunnuslause.</translation>
<translation id="1787142507584202372">Avoimet välilehdet näkyvät tässä.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Tarkista toimitusvaihtoehdot ja ‑vaatimukset valitsemalla toimitusosoite.</translation>
+<translation id="1803264062614276815">Kortinhaltijan nimi</translation>
<translation id="1803678881841855883">Googlen selaussuoja <ph name="BEGIN_LINK" />havaitsi äskettäin haittaohjelman<ph name="END_LINK" /> sivustolla <ph name="SITE" />. Myös tavallisesti turvalliset verkkosivustot voivat joskus saada haittaohjelmatartunnan. Haitallisen sisällön lähde on <ph name="SUBRESOURCE_HOST" />, tunnettu haittaohjelmien jakelija. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1806541873155184440">Lisätty: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Pyyntö on virheellinen tai pyynnön parametrit ovat virheelliset</translation>
<translation id="1826516787628120939">Tarkistetaan</translation>
<translation id="1834321415901700177">Tämä sivusto sisältää haitallisia ohjelmia</translation>
<translation id="1842969606798536927">Maksa</translation>
-<translation id="1864455488461349376">Toimitusvaihtoehto</translation>
<translation id="1871208020102129563">Välityspalvelin on asetettu käyttämään kiinteitä välityspalvelimia, ei .pac-URL-osoitetta.</translation>
<translation id="1871284979644508959">Pakollinen tieto</translation>
<translation id="187918866476621466">Avaa aloitussivut</translation>
<translation id="1883255238294161206">Tiivistä luettelo</translation>
<translation id="1898423065542865115">Suodatus</translation>
<translation id="194030505837763158">Siirry osoitteeseen <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Hyväksytyt kortit</translation>
<translation id="1962204205936693436">Verkkotunnuksen <ph name="DOMAIN" /> kirjanmerkit</translation>
<translation id="1973335181906896915">Sarjaesittämisen virhe</translation>
<translation id="1974060860693918893">Lisäasetukset</translation>
<translation id="1978555033938440688">Laiteohjelmiston versio</translation>
+<translation id="1995859865337580572">Vahvista CVC.</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{ja 1 muu}other{ja # muuta}}</translation>
-<translation id="2020194265157481222">Kortissa oleva nimi vaaditaan</translation>
<translation id="2025186561304664664">Välityspalvelimen asetus: automaattisesti määritetty.</translation>
<translation id="2030481566774242610">Tarkoititko: <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Tarkista välityspalvelimen ja palomuurin määritykset.<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Tänään</translation>
<translation id="2154054054215849342">Synkronointi ei ole käytettävissä verkkotunnuksessasi.</translation>
<translation id="2154484045852737596">Muokkaa korttia</translation>
-<translation id="2156993118928861787">Virheellinen osoite</translation>
<translation id="2166049586286450108">Järjestelmänvalvojan täydet käyttöoikeudet</translation>
<translation id="2166378884831602661">Tämä sivusto ei voi tarjota suojattua yhteyttä</translation>
<translation id="2181821976797666341">Käytännöt</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 osoite}other{# osoitetta}}</translation>
+<translation id="2202020181578195191">Anna kelvollinen viimeinen voimassaolovuosi.</translation>
<translation id="2212735316055980242">Käytäntöä ei löydy</translation>
<translation id="2213606439339815911">Noudetaan merkintöjä…</translation>
<translation id="2230458221926704099">Korjaa yhteytesi käyttämällä <ph name="BEGIN_LINK" />diagnostiikkasovellusta<ph name="END_LINK" />.</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Internetyhteytesi on estetty</translation>
<translation id="230155334948463882">Uusi kortti?</translation>
<translation id="2305919008529760154">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />. Sen suojausvarmenne on ehkä myönnetty vilpillisesti. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="230697611605700222">Kortti- ja osoitevaihtoehdot ovat peräisin Google-tililtäsi (<ph name="ACCOUNT_EMAIL" />) ja Chromesta. Voit hallita tietoja <ph name="BEGIN_LINK" />Asetuksissa<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> pyytää käyttäjänimeä ja salasanaa.</translation>
<translation id="2318774815570432836">Et juuri nyt voi siirtyä sivustolle <ph name="SITE" />, sillä se käyttää HSTS:ää. Verkkovirheet ja ‑hyökkäykset ovat yleensä väliaikaisia, joten voit todennäköisesti vierailla sivustolla myöhemmin. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2354001756790975382">Muut kirjanmerkit</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Yrityksen oletus</translation>
<translation id="2386255080630008482">Palvelimen varmenne on kumottu.</translation>
<translation id="2392959068659972793">Näytä käytännöt, joille ei ole asetettu arvoa</translation>
+<translation id="239429038616798445">Lähetystapa ei ole käytettävissä. Kokeile toista tapaa.</translation>
<translation id="2396249848217231973">K&amp;umoa poisto</translation>
<translation id="2460160116472764928">Googlen selaussuoja <ph name="BEGIN_LINK" />havaitsi äskettäin haittaohjelman<ph name="END_LINK" /> sivustolla <ph name="SITE" />. Myös tavallisesti turvalliset verkkosivustot voivat joskus saada haittaohjelmatartunnan. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2463739503403862330">Täytä</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />verkon diagnostiikkaa<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Virheellinen hakukoneen URL-osoite.</translation>
<translation id="2491120439723279231">Palvelimen varmenteessa on virheitä.</translation>
-<translation id="24943777258388405">Virheellinen puhelinnumero</translation>
<translation id="2495083838625180221">JSON-jäsentäjä</translation>
<translation id="2495093607237746763">Jos tämä on valittu, Chromium tallentaa kortin kopion tälle laitteelle nopeuttaakseen lomakkeiden täyttöä.</translation>
<translation id="2498091847651709837">Skannaa uusi kortti</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> lähetti virheellisen vastauksen.</translation>
<translation id="2552545117464357659">Uudempi</translation>
<translation id="2556876185419854533">K&amp;umoa muokkaus</translation>
+<translation id="2587730715158995865">Julkaisijalta <ph name="ARTICLE_PUBLISHER" />. Lue tämä ja <ph name="OTHER_ARTICLE_COUNT" /> muuta tarinaa.</translation>
<translation id="2587841377698384444">Hakemistosovellusliittymän tunnus:</translation>
<translation id="2597378329261239068">Tämä asiakirja on suojattu salasanalla. Anna salasana.</translation>
<translation id="2609632851001447353">Muunnelmat</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />yhteysdiagnostiikkaa<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">Poista valitut kohteet</translation>
+<translation id="277133753123645258">Lähetystapa</translation>
<translation id="277499241957683684">Laitetallenne puuttuu</translation>
<translation id="2784949926578158345">Yhteys katkaistiin.</translation>
<translation id="2794233252405721443">Sivusto estetty</translation>
-<translation id="2812680587231492111">Tämä noutovaihtoehto ei ole käytettävissä. Kokeile toista vaihtoehtoa.</translation>
<translation id="2824775600643448204">Osoite- ja hakupalkki</translation>
<translation id="2826760142808435982">Yhteys on salattu ja todennettu <ph name="CIPHER" />:n avulla ja se käyttää menetelmää <ph name="KX" /> avainvaihtomekanismina.</translation>
<translation id="2835170189407361413">Tyhjennä lomake</translation>
-<translation id="2849041323157393173">Tämä toimitusvaihtoehto ei ole käytettävissä. Kokeile toista vaihtoehtoa.</translation>
<translation id="2889159643044928134">Älä päivitä</translation>
<translation id="2900469785430194048">Google Chromen muisti loppui verkkosivua näytettäessä.</translation>
<translation id="2909946352844186028">Verkossa havaittiin muutos.</translation>
<translation id="2916038427272391327">Sulje muita ohjelmia.</translation>
<translation id="2922350208395188000">Palvelimen varmennetta ei voi tarkistaa.</translation>
+<translation id="2928905813689894207">Laskutusosoite</translation>
<translation id="2948083400971632585">Voit poistaa yhteydelle määritetyt välityspalvelimet käytöstä asetussivulla.</translation>
<translation id="2955913368246107853">Sulje hakupalkki</translation>
<translation id="2958431318199492670">Verkkoasetukset eivät noudata ONC-standardia. Kaikkia asetuksia ei välttämättä tuoda.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">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ä aikoina. Chrome ei voi vahvistaa varmenteita, koska laitteesi kello on väärässä ajassa.</translation>
<translation id="2972581237482394796">&amp;Tee uudelleen</translation>
<translation id="2985306909656435243">Jos tämä on käytössä, Chromium tallentaa kortin kopion tälle laitteelle nopeuttaakseen lomakkeiden täyttöä.</translation>
+<translation id="2985398929374701810">Anna kelvollinen osoite.</translation>
+<translation id="2986368408720340940">Tämä noutotapa ei ole käytettävissä. Kokeile toista tapaa.</translation>
<translation id="2991174974383378012">Jakaminen verkkosivustojen kanssa</translation>
<translation id="3005723025932146533">Näytä tallennettu kopio</translation>
<translation id="3008447029300691911">Anna kortin <ph name="CREDIT_CARD" /> CVC. Vahvistamisen jälkeen korttisi tiedot jaetaan sivuston kanssa.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{vähintään 1 kohde synkronoiduilla laitteilla}=1{1 kohde (ja lisää synkronoiduilla laitteilla)}other{# kohdetta (ja lisää synkronoiduilla laitteilla)}}</translation>
<translation id="3041612393474885105">Varmenteen tiedot</translation>
<translation id="3063697135517575841">Chrome ei voinut vahvistaa korttiasi. Yritä myöhemmin uudelleen.</translation>
+<translation id="3064966200440839136">Incognito-tilasta poistutaan ulkoisessa sovelluksessa maksamisen vuoksi. Haluatko jatkaa?</translation>
<translation id="3093245981617870298">Olet offline-tilassa.</translation>
<translation id="3105172416063519923">Laitteen tunnus:</translation>
<translation id="3109728660330352905">Sinulla ei ole oikeutta tarkastella tätä sivua.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Kokeile yhteysdiagnostiikkaa<ph name="END_LINK" /></translation>
<translation id="3145945101586104090">Vastauksen purkaminen epäonnistui</translation>
-<translation id="3149891296864842641">Toimitustapa</translation>
<translation id="3150653042067488994">Tilapäinen palvelinvirhe</translation>
+<translation id="3154506275960390542">Tällä sivulla on taulukko, jota ei ehkä voi lähettää turvallisesti. Muut voivat nähdä lähettämäsi tiedot siirron aikana tai hyökkääjä voi muuttaa niitä, ennen kuin ne saapuvat palvelimelle.</translation>
<translation id="3157931365184549694">Palauta</translation>
<translation id="3167968892399408617">Incognito-välilehdillä avattujen sivujen tietoja ei säilytetä selaimen historiassa, evästeissä tai hakuhistoriassa, kun kaikki incognito-välilehdet suljetaan. Ladatut tiedostot ja luodut kirjanmerkit säilytetään.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -264,11 +272,13 @@
<translation id="3345135638360864351">Tämän sivuston käyttöpyyntöä ei voitu lähettää henkilölle <ph name="NAME" />. Yritä uudelleen.</translation>
<translation id="3355823806454867987">Muuta välityspalvelimen asetuksia...</translation>
<translation id="3369192424181595722">Väärä kellonaika</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> muuta kohdetta…</translation>
<translation id="337363190475750230">Poistettu käytöstä</translation>
<translation id="3377188786107721145">Virhe jäsennettäessä käytäntöä</translation>
<translation id="3380365263193509176">Tuntematon virhe</translation>
<translation id="3380864720620200369">Asiakastunnus:</translation>
<translation id="3391030046425686457">Toimitusosoite</translation>
+<translation id="3395827396354264108">Noutotapa</translation>
<translation id="340013220407300675">Hyökkääjät saattavat yrittää varastaa tietojasi (esimerkiksi salasanoja, viestejä tai luottokorttitietoja) kohteessa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="3422248202833853650">Yritä vapauttaa muistia sulkemalla muita ohjelmia.</translation>
<translation id="3422472998109090673">Sivustoon <ph name="HOST_NAME" /> ei saada tällä hetkellä yhteyttä.</translation>
@@ -279,12 +289,13 @@
<translation id="3450660100078934250">Mastercard</translation>
<translation id="3452404311384756672">Hakuväli:</translation>
<translation id="3462200631372590220">Piilota lisäasetukset</translation>
+<translation id="3467763166455606212">Kortinhaltijan nimi on pakollinen.</translation>
+<translation id="3478058380795961209">Voimassa (kk)</translation>
<translation id="3479539252931486093">Etkö odottanut tätä? <ph name="BEGIN_LINK" />Kerro siitä meille.<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Ei nyt</translation>
<translation id="348000606199325318">Kaatumistunnus: <ph name="CRASH_LOCAL_ID" /> (palvelintunnus: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Emme tavoittaneet vanhempaasi. Yritä uudelleen.</translation>
<translation id="3528171143076753409">Palvelimen varmenne ei ole luotettava.</translation>
-<translation id="3538531656504267329">Virheellinen vanhentumisvuosi</translation>
<translation id="3539171420378717834">Säilytä tämän kortin kopio laitteella.</translation>
<translation id="3542684924769048008">Käytä salasanaa kohteeseen:</translation>
<translation id="3549644494707163724">Salaa kaikki synkronoidut tiedot oman synkronoinnin tunnuslauseesi avulla</translation>
@@ -297,6 +308,7 @@
<translation id="3586931643579894722">Piilota lisätiedot</translation>
<translation id="3587482841069643663">Kaikki</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Anna kelvollinen viimeinen voimassaolopäivä.</translation>
<translation id="36224234498066874">Poista selaustiedot...</translation>
<translation id="362276910939193118">Näytä koko selaushistoria</translation>
<translation id="3623476034248543066">Näytä arvo</translation>
@@ -313,7 +325,6 @@
<translation id="3693415264595406141">Salasana:</translation>
<translation id="3696411085566228381">ei mitään</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Näet toimitusvaihtoehdot ja ‑vaatimukset valitsemalla toimitusosoitteen.</translation>
<translation id="370665806235115550">Ladataan...</translation>
<translation id="3712624925041724820">Käyttöluvat ovat lopussa</translation>
<translation id="3714780639079136834">Ota mobiilidata tai Wi-Fi käyttöön.</translation>
@@ -322,6 +333,7 @@
<translation id="3739623965217189342">Kopioimasi linkki</translation>
<translation id="375403751935624634">Käännös epäonnistui palvelinvirheen vuoksi.</translation>
<translation id="3759461132968374835">Ei viimeaikaisia kaatumisilmoituksia. Jos selain kaatui kaatumisilmoitusten ollessa pois käytöstä, ilmoituksia ei näytetä täällä.</translation>
+<translation id="3787705759683870569">Vanhenee <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Jos käytät välityspalvelinta…</translation>
<translation id="3828924085048779000">Tunnuslause ei voi olla tyhjä.</translation>
<translation id="3845539888601087042">Näytetään kirjautuneiden laitteiden historia. <ph name="BEGIN_LINK" />Lisätietoja<ph name="END_LINK" /></translation>
@@ -357,7 +369,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Haluatko, että Chromium tallentaa tämän kortin?</translation>
<translation id="4171400957073367226">Virheellinen vahvistusallekirjoitus.</translation>
-<translation id="4176463684765177261">Pois käytöstä</translation>
<translation id="4196861286325780578">&amp;Toista siirto</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Tarkista palomuurin ja virustorjuntaohjelmiston määritykset.<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{ei yhtään}=1{1 sovellus ($1)}=2{2 sovellusta ($1 ja $2)}other{# sovellusta ($1, $2 $3)}}</translation>
@@ -384,11 +395,11 @@
<translation id="4406896451731180161">hakutulokset</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ei hyväksynyt kirjautumisvarmennettasi, tai varmennetta ei annettu.</translation>
<translation id="443673843213245140">Välityspalvelinta ei saa käyttää, mutta erilliset välityspalvelimen asetukset on määritetty.</translation>
-<translation id="4446242550670694251">Nyt voit selata verkkoa yksityisesti. Muut laitteen käyttäjät eivät näe tietoja toiminnastasi.</translation>
<translation id="4492190037599258964">Hakutulokset kyselylle <ph name="SEARCH_STRING" /></translation>
<translation id="4506176782989081258">Todennusvirhe: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Ota yhteyttä järjestelmänvalvojaan.</translation>
<translation id="450710068430902550">Jakaminen järjestelmänvalvojan kanssa</translation>
+<translation id="4515275063822566619">Kortit ja osoitteet ovat peräisin Chromesta ja Google-tililtäsi (<ph name="ACCOUNT_EMAIL" />). Voit hallinnoida niitä <ph name="BEGIN_LINK" />asetuksissa<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Tiedot</translation>
<translation id="4558551763791394412">Poista laajennukset käytöstä.</translation>
<translation id="457875822857220463">Toimitus</translation>
@@ -418,6 +429,7 @@
<translation id="4816492930507672669">Sovita sivulle</translation>
<translation id="483020001682031208">Ei näytettäviä Fyysinen web ‑sivuja</translation>
<translation id="4850886885716139402">Näytä</translation>
+<translation id="4854362297993841467">Tämä toimitustapa ei ole käytettävissä. Kokeile toista tapaa.</translation>
<translation id="4858792381671956233">Pyysit vanhemmiltasi lupaa käydä tällä sivustolla.</translation>
<translation id="4880827082731008257">Haku historiasta</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -425,7 +437,6 @@
<translation id="4923417429809017348">Tämä sivu on käännetty tuntemattomasta kielestä kielelle <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Maksu</translation>
<translation id="4926049483395192435">On määritettävä.</translation>
-<translation id="4941291666397027948">* pakollinen kenttä</translation>
<translation id="495170559598752135">Toiminnot</translation>
<translation id="4958444002117714549">Laajenna luettelo</translation>
<translation id="4962322354953122629">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä Chrome ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -440,6 +451,7 @@
<translation id="5045550434625856497">Väärä salasana</translation>
<translation id="5056549851600133418">Sinulle valitut artikkelit</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Tarkista välityspalvelimen osoite.<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Ei evästeitä}=1{1 sivusto käyttää evästeitä. }other{# sivustoa käyttää evästeitä. }}</translation>
<translation id="5087286274860437796">Palvelimen varmenne ei ole tällä hetkellä kelvollinen.</translation>
<translation id="5087580092889165836">Lisää kortti</translation>
<translation id="5089810972385038852">Osavaltio/alue</translation>
@@ -462,10 +474,8 @@
<translation id="5300589172476337783">Näytä</translation>
<translation id="5308689395849655368">Kaatumisraportit on poistettu käytöstä.</translation>
<translation id="5317780077021120954">Tallenna</translation>
-<translation id="5326702247179446998">Vastaanottaja vaaditaan</translation>
<translation id="5327248766486351172">Nimi</translation>
<translation id="5337705430875057403">Sivustoon <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> hyökännyt taho voi yrittää huijata sinua tekemään jotain vaarallista, kuten asentamaan ohjelmistoja tai paljastamaan henkilötietojasi (esimerkiksi salasanoja, puhelinnumeroita tai luottokorttitietoja).</translation>
-<translation id="53553865750799677">Nouto-osoite ei kelpaa. Valitse toinen osoite.</translation>
<translation id="5359637492792381994">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä sen suojausvarmenne ei ole tällä hetkellä voimassa. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Käytännön asetuksien tallentaminen epäonnistui</translation>
<translation id="5386426401304769735">Tämän sivuston varmenneketju sisältää varmenteen, joka on allekirjoitettu SHA-1:llä.</translation>
@@ -491,8 +501,8 @@
<translation id="5544037170328430102">Viesti upotetulta sivulta osoitteessa <ph name="SITE" />:</translation>
<translation id="5556459405103347317">Lataa uudelleen</translation>
<translation id="5565735124758917034">Aktiivinen</translation>
+<translation id="5571083550517324815">Nouto tästä osoitteesta ei onnistu. Valitse eri osoite.</translation>
<translation id="5572851009514199876">Aloita ja kirjaudu sisään, jotta Chrome voi tarkistaa, onko sinulla oikeus käyttää tätä sivustoa.</translation>
-<translation id="5575380383496039204">Toimitusosoite ei kelpaa. Valitse toinen osoite.</translation>
<translation id="5580958916614886209">Tarkista vanhentumiskuukausi ja yritä uudelleen.</translation>
<translation id="560412284261940334">Hallintaa ei tueta</translation>
<translation id="5610142619324316209">Tarkista yhteys.</translation>
@@ -508,7 +518,8 @@
<translation id="5710435578057952990">Tämän sivuston identiteettiä ei ole vahvistettu.</translation>
<translation id="5720705177508910913">Nykyinen käyttäjä</translation>
<translation id="5732392974455271431">Vanhempasi voivat kumota eston puolestasi.</translation>
-<translation id="57586589942790530">Virheellinen kortin numero</translation>
+<translation id="5763042198335101085">Anna voimassa oleva sähköpostiosoite.</translation>
+<translation id="5765072501007116331">Valitse osoite, niin näet toimitustavat ja vaatimukset.</translation>
<translation id="5784606427469807560">Korttia vahvistettaessa tapahtui virhe. Tarkista internetyhteys ja yritä uudelleen.</translation>
<translation id="5785756445106461925">Tällä sivulla on kuitenkin muita osia, jotka eivät ole suojattuja. Muut voivat tarkastella näitä osia siirron aikana, ja hyökkääjä voi muuttaa sivun ulkoasua muokkaamalla näitä osia.</translation>
<translation id="5786044859038896871">Täytetäänkö kortin tiedot?</translation>
@@ -521,22 +532,20 @@
<translation id="5869405914158311789">Sivustoon ei saada yhteyttä</translation>
<translation id="5869522115854928033">Tallennetut salasanat</translation>
<translation id="5872918882028971132">Ylätason ehdotukset</translation>
-<translation id="587760065310675640">Toimitusosoite ei kelpaa. Valitse toinen osoite.</translation>
<translation id="5901630391730855834">Keltainen</translation>
-<translation id="59174027418879706">Käytössä</translation>
<translation id="5926846154125914413">Saatat menettää joidenkin sivustojen maksullisen sisällön käyttöoikeuden.</translation>
<translation id="5959728338436674663"><ph name="BEGIN_WHITEPAPER_LINK" />Lähetä automaattisesti<ph name="END_WHITEPAPER_LINK" /> joitain järjestelmän tietoja ja sivujen sisältöjä Googlelle auttaaksesi sitä havaitsemaan vaarallisia sovelluksia ja sivustoja. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Viikko</translation>
<translation id="5967867314010545767">Poista historiasta</translation>
<translation id="5975083100439434680">Loitonna</translation>
+<translation id="598637245381783098">Maksusovelluksen avaaminen ei onnistu.</translation>
<translation id="5989320800837274978">Kiinteitä välityspalvelimia tai .pac-URL-osoitetta ei ole määritetty.</translation>
<translation id="5990559369517809815">Laajennus esti palvelinpyynnöt.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Kortti- ja osoitevaihtoehdot ovat peräisin Chromesta. Voit hallita tietoja <ph name="BEGIN_LINK" />Asetuksissa<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Sivu 1}other{Sivu #}}</translation>
<translation id="6017514345406065928">Vihreä</translation>
+<translation id="6027201098523975773">Kirjoita nimi</translation>
<translation id="6040143037577758943">Sulje</translation>
-<translation id="604124094241169006">Automaattinen</translation>
<translation id="6042308850641462728">Lisää</translation>
<translation id="6060685159320643512">Varoitus, nämä kokeilut saattavat puraista</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{ei yhtään}=1{1}other{#}}</translation>
@@ -544,9 +553,10 @@
käytössä olevat verkkolaitteet.</translation>
<translation id="614940544461990577">Kokeile seuraavia toimenpiteitä:</translation>
<translation id="6151417162996330722">Palvelimen varmenteen voimassaoloaika on liian pitkä.</translation>
-<translation id="615643356032862689">Ladatut tiedostot ja kirjanmerkit säilyvät laitteella.</translation>
+<translation id="6157877588268064908">Valitse osoite, niin näet toimitustavat ja vaatimukset.</translation>
<translation id="6165508094623778733">Lisätietoja</translation>
<translation id="6177128806592000436">Sivustoon ei ole muodostettu turvallista yhteyttä.</translation>
+<translation id="6184817833369986695">(kohortti: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Tarkista internetyhteytesi</translation>
<translation id="6218753634732582820">Poistetaanko osoite Chromiumista?</translation>
<translation id="6251924700383757765">Tietosuojakäytäntö</translation>
@@ -555,6 +565,8 @@
<translation id="6259156558325130047">&amp;Toista uudelleenjärjestely</translation>
<translation id="6263376278284652872">Verkkotunnuksen <ph name="DOMAIN" /> kirjanmerkit</translation>
<translation id="6264485186158353794">Takaisin suojaukseen</translation>
+<translation id="6276112860590028508">Lukulistasi sivuja tulee näkyviin tänne.</translation>
+<translation id="6280223929691119688">Toimitus ei onnistu tähän osoitteeseen. Valitse eri osoite.</translation>
<translation id="6282194474023008486">Postinumero</translation>
<translation id="6290238015253830360">Suositellut artikkelit näkyvät tässä.</translation>
<translation id="6305205051461490394">Sivustoon <ph name="URL" /> ei saada yhteyttä.</translation>
@@ -576,7 +588,6 @@
<translation id="6417515091412812850">Ei voida tarkistaa, onko varmenne kumottu.</translation>
<translation id="6433490469411711332">Muokkaa yhteystietoja</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> kieltäytyi muodostamasta yhteyttä.</translation>
-<translation id="6443118737398455446">Virheellinen viimeinen voimassaolopäivä</translation>
<translation id="6446608382365791566">Lisää tietoja</translation>
<translation id="6451458296329894277">Vahvista lomakkeen uudelleenlähetys</translation>
<translation id="6456339708790392414">Maksu</translation>
@@ -584,10 +595,8 @@
<translation id="6462969404041126431">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />. Sen suojausvarmenne on ehkä peruutettu. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">Laitekäytännöt</translation>
<translation id="6477321094435799029">Chrome havaitsi tällä sivulla epätavallista koodia ja esti sen suojellakseen henkilötietojasi (esimerkiksi salasanoja, puhelinnumeroita tai luottokorttitietoja).</translation>
-<translation id="6477460825583319731">Virheellinen sähköpostiosoite</translation>
<translation id="6489534406876378309">Aloita kaatumistietojen lähettäminen</translation>
<translation id="6508722015517270189">Käynnistä Chrome uudelleen.</translation>
-<translation id="6525462735697194615">Virheellinen vanhentumiskuukausi</translation>
<translation id="6529602333819889595">&amp;Toista poisto</translation>
<translation id="6534179046333460208">Fyysisen webin ehdotukset</translation>
<translation id="6550675742724504774">Asetukset</translation>
@@ -602,7 +611,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" />-haku</translation>
<translation id="6644283850729428850">Tämä käytäntö on vanhentunut.</translation>
<translation id="6652240803263749613">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä tietokoneesi käyttöjärjestelmä ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="6665267558048410100">Tämä lähetysvaihtoehto ei ole käytettävissä. Kokeile toista vaihtoehtoa.</translation>
<translation id="6671697161687535275">Poistetaanko lomake-ehdotus Chromiumista?</translation>
<translation id="6685834062052613830">Kirjaudu ulos ja suorita määritys loppuun.</translation>
<translation id="6710213216561001401">Edellinen</translation>
@@ -610,13 +618,13 @@
<translation id="6711464428925977395">Välityspalvelimessa on jotain vikaa tai osoite on virheellinen.</translation>
<translation id="6727102863431372879">Aseta</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{ei yhtään}=1{1 kohde}other{# kohdetta}}</translation>
-<translation id="6743044928064272573">Noutovaihtoehto</translation>
<translation id="674375294223700098">Tuntematon palvelimen varmennevirhe.</translation>
<translation id="6753269504797312559">Käytännön arvo</translation>
<translation id="6757797048963528358">Laitteesi siirtyi virransäästötilaan.</translation>
<translation id="6778737459546443941">Vanhempasi ei ole hyväksynyt sitä vielä.</translation>
<translation id="6810899417690483278">Muokkaustunnus</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Aluetietojen lataus epäonnistui.</translation>
<translation id="6831043979455480757">Käännä</translation>
<translation id="6839929833149231406">Alue</translation>
<translation id="6874604403660855544">&amp;Toista lisäys</translation>
@@ -624,6 +632,7 @@
<translation id="6895330447102777224">Korttisi vahvistettiin.</translation>
<translation id="6897140037006041989">User agent</translation>
<translation id="6915804003454593391">Käyttäjä:</translation>
+<translation id="6948701128805548767">Valitse osoite, niin näet noutotavat ja vaatimukset.</translation>
<translation id="6957887021205513506">Palvelimen varmenne näyttää olevan väärennös.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Laite</translation>
@@ -631,7 +640,6 @@
<translation id="6973656660372572881">Sekä kiinteät välityspalvelimet että .pac-URL-osoite on määritetty.</translation>
<translation id="6989763994942163495">Näytä lisäasetukset...</translation>
<translation id="7000990526846637657">Historiamerkintöjä ei löytynyt</translation>
-<translation id="7001663382399377034">Lisää vastaanottaja</translation>
<translation id="7009986207543992532">Yritit muodostaa yhteyden verkkotunnukseen <ph name="DOMAIN" />, mutta palvelimen esittämän varmenteen voimassaoloaika on epäilyttävän pitkä. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Google-tililläsi voi olla muita selaushistoriatietoja osoitteessa <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
@@ -642,12 +650,15 @@
<translation id="7088615885725309056">Vanhempi</translation>
<translation id="7090678807593890770">Tee Google-haku: <ph name="LINK" /></translation>
<translation id="7119414471315195487">Sulje muita välilehtiä tai ohjelmia.</translation>
+<translation id="7129409597930077180">Lähetys tähän osoitteeseen ei onnistu. Valitse eri osoite.</translation>
+<translation id="7138472120740807366">Toimitustapa</translation>
<translation id="7139724024395191329">Emiirikunta</translation>
<translation id="7155487117670177674">Maksu ei ole turvallinen</translation>
<translation id="7179921470347911571">Käynnistä uudelleen</translation>
<translation id="7180611975245234373">Päivitä</translation>
<translation id="7182878459783632708">Käytäntöjä ei ole asetettu</translation>
<translation id="7186367841673660872">Tämä sivu on käännetty kielestä<ph name="ORIGINAL_LANGUAGE" />kielelle<ph name="LANGUAGE_LANGUAGE" /></translation>
+<translation id="7192203810768312527">Vapauttaa <ph name="SIZE" />. Jotkin sivustot saattavat latautua hitaammin seuraavalla käynnillä.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ei noudata tietoturvastandardeja.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Lisätietoja<ph name="END_LINK" /> ongelmasta.</translation>
@@ -676,7 +687,6 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="7424977062513257142">Viesti tälle verkkosivulle upotetulta sivulta:</translation>
<translation id="7441627299479586546">Väärä käytännön aihe</translation>
<translation id="7444046173054089907">Tämä sivusto on estetty</translation>
-<translation id="7444238235002594607">Tarkista toimitusvaihtoehdot ja ‑vaatimukset valitsemalla nouto-osoite.</translation>
<translation id="7445762425076701745">Palvelimen, johon olet muodostanut yhteyden, identiteettiä ei voi täysin todentaa. Tietokoneesi on yhdistetty palvelimeen sellaisen nimen avulla, joka on kelvollinen vain verkkosi sisällä ja jonka omistajaa ulkopuolinen varmenteen myöntäjä ei pysty todentamaan. Koska jotkin varmenteen myöntäjät kuitenkin myöntävät varmenteita tällaisille nimille, et voi varmistaa, että olet muodostanut yhteyden haluamaasi verkkosivustoon etkä hakkeriin.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />tiedonhakua<ph name="END_LINK" /> ongelmaan liittyen</translation>
<translation id="7460163899615895653">Muiden laitteidesi viimeisimmät välilehdet näkyvät täällä.</translation>
@@ -720,6 +730,7 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="7755287808199759310">Vanhempasi voi kumota eston puolestasi.</translation>
<translation id="7758069387465995638">Palomuuri tai virustorjuntaohjelmisto on saattanut estää yhteyden.</translation>
<translation id="7761701407923456692">Palvelimen varmenne ei vastaa URL-osoitetta.</translation>
+<translation id="7763386264682878361">Maksuluettelon jäsentäjä</translation>
<translation id="7764225426217299476">Lisää osoite</translation>
<translation id="777702478322588152">Prefektuuri</translation>
<translation id="7791543448312431591">Lisää</translation>
@@ -733,6 +744,7 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="785549533363645510">Et ole kuitenkaan näkymätön. Incognito-tilan käyttäminen ei kätke selaamistasi työnantajaltasi, internetpalveluntarjoajaltasi tai käyttämiltäsi sivustoilta.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Tarkista CVC ja yritä uudelleen.</translation>
+<translation id="79338296614623784">Anna kelvollinen puhelinnumero.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Palvelimen varmenne ei ole vielä voimassa.</translation>
<translation id="7942349550061667556">Punainen</translation>
@@ -752,6 +764,7 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="8088680233425245692">Artikkelin näyttäminen epäonnistui.</translation>
<translation id="8089520772729574115">alle 1 Mt</translation>
<translation id="8091372947890762290">Aktivointi odottaa palvelimella</translation>
+<translation id="8118489163946903409">Maksutapa</translation>
<translation id="8131740175452115882">Vahvista</translation>
<translation id="8134994873729925007">Isäntänimen <ph name="HOST_NAME" /> palvelimen <ph name="BEGIN_ABBR" />DNS-osoitetta<ph name="END_ABBR" /> ei löytynyt.</translation>
<translation id="8149426793427495338">Tietokoneesi siirtyi virransäästötilaan.</translation>
@@ -777,6 +790,7 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="8349305172487531364">Kirjanmerkkipalkki</translation>
<translation id="8363502534493474904">Poista lentokonetila käytöstä.</translation>
<translation id="8364627913115013041">Ei määritetty.</translation>
+<translation id="8368476060205742148">Google Play Palvelut</translation>
<translation id="8380941800586852976">Vaarallinen</translation>
<translation id="8382348898565613901">Viimeksi käyttämäsi kirjanmerkit näkyvät tässä.</translation>
<translation id="8398259832188219207">Kaatumisraportti lähetetty <ph name="UPLOAD_TIME" /></translation>
@@ -785,32 +799,30 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="8428213095426709021">Asetukset</translation>
<translation id="8433057134996913067">Sinut kirjataan ulos useimmilta verkkosivustoilta.</translation>
<translation id="8437238597147034694">K&amp;umoa siirto</translation>
-<translation id="8456681095658380701">Nimi ei kelpaa</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 luottokortti}other{# luottokorttia}}</translation>
<translation id="8483780878231876732">Jos haluat käyttää Google-tilillesi tallennettuja kortteja, kirjaudu Chromeen</translation>
<translation id="8488350697529856933">Käyttöalue</translation>
-<translation id="8492969205326575646">Kortin tyyppiä ei tueta</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ei vastannut riittävän nopeasti.</translation>
<translation id="852346902619691059">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä laitteesi käyttöjärjestelmä ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="8532105204136943229">Voimassa (vuosi)</translation>
<translation id="8543181531796978784">Voit <ph name="BEGIN_ERROR_LINK" />ilmoittaa löytyneestä ongelmasta<ph name="END_ERROR_LINK" /> tai <ph name="BEGIN_LINK" />siirtyä mahdollisesti haitalliselle sivustolle<ph name="END_LINK" />, jos ymmärrät tietoturvariskit.</translation>
<translation id="8553075262323480129">Käännös epäonnistui, sillä sivun kieltä ei voitu määrittää.</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="8570229484593575558">Seuraavia tietoja |ei tallenneta|:#selaushistoria#tekemäsi haut#evästeiden tiedot.</translation>
<translation id="8571890674111243710">Käännetään sivua kielelle <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Seuraavat tahot |voivat ehkä nähdä| tietoja toiminnastasi:#käyttämäsi verkkosivustot#työnantajasi#internetpalveluntarjoajasi.</translation>
<translation id="858637041960032120">Lisää puh.nro
</translation>
<translation id="859285277496340001">Varmenne ei määritä mekanismia, jonka avulla voitaisiin tarkistaa, onko varmenne kumottu.</translation>
<translation id="8620436878122366504">Vanhempasi eivät ole hyväksyneet sitä vielä.</translation>
<translation id="8647750283161643317">Palauta kaikki oletusarvoon</translation>
<translation id="8703575177326907206">Yhteyttäsi verkkotunnukseen <ph name="DOMAIN" /> ei ole salattu.</translation>
+<translation id="8718314106902482036">Maksua ei suoritettu loppuun</translation>
<translation id="8725066075913043281">Yritä uudelleen</translation>
<translation id="8728672262656704056">Olet muuttunut näkymättömäksi</translation>
<translation id="8730621377337864115">Valmis</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="8759274551635299824">Tämä kortti on vanhentunut.</translation>
<translation id="8790007591277257123">&amp;Toista poisto</translation>
-<translation id="8798099450830957504">Oletus</translation>
<translation id="8800988563907321413">Nearby-ehdotuksesi näkyvät tässä.</translation>
<translation id="8820817407110198400">Kirjanmerkit</translation>
<translation id="883848425547221593">Muut kirjanmerkit</translation>
@@ -820,6 +832,7 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="8866481888320382733">Virhe jäsennettäessä käytännön asetuksia</translation>
<translation id="8866959479196209191">Viesti tältä sivulta:</translation>
<translation id="8870413625673593573">Hiljattain suljetut</translation>
+<translation id="8874824191258364635">Anna kelvollinen kortin numero.</translation>
<translation id="8876793034577346603">Verkkoasetuksia ei voitu jäsentää.</translation>
<translation id="8877192140621905067">Vahvistamisen jälkeen korttisi tiedot jaetaan sivuston kanssa.</translation>
<translation id="8889402386540077796">Sävy</translation>
@@ -829,7 +842,6 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="8931333241327730545">Haluatko tallentaa tämän kortin Google-tilillesi?</translation>
<translation id="8932102934695377596">Kellosi jätättää</translation>
<translation id="8954894007019320973">(jatkuu)</translation>
-<translation id="895548565263634352">Lue juttuja lähteestä <ph name="ARTICLE_PUBLISHER" /> ja <ph name="OTHER_ARTICLE_COUNT" /> muusta.</translation>
<translation id="8971063699422889582">Palvelimen varmenne on vanhentunut.</translation>
<translation id="8986494364107987395">Lähetä Googlelle käyttötilastoja ja virheraportteja automaattisesti</translation>
<translation id="8987927404178983737">Kuukausi</translation>
@@ -847,7 +859,6 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="9068849894565669697">Valitse väri</translation>
<translation id="9076283476770535406">Se saattaa sisältää vain aikuisille tarkoitettua sisältöä.</translation>
<translation id="9078964945751709336">Lisätietoja tarvitaan</translation>
-<translation id="9094175695478007090">Maksusovelluksen käynnistys epäonnistui.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> suojaa tietosi normaalisti salauksen avulla. Kun Chromium yritti tällä kertaa yhdistää sivustoon <ph name="SITE" />, sivusto palautti epätavalliset ja virheelliset kirjautumistiedot. Hyökkääjä saattaa yrittää esiintyä sivustona <ph name="SITE" />, tai Wi-Fi-kirjautumisruutu on keskeyttänyt yhteyden. Tietosi ovat edelleen turvassa, sillä Chromium katkaisi yhteyden, ennen kuin mitään tietoja vaihdettiin.</translation>
<translation id="9137013805542155359">Näytä alkuperäinen</translation>
<translation id="9137248913990643158">Aloita ja kirjaudu sisään Chromeen ennen tämän sovelluksen käyttämistä.</translation>
diff --git a/chromium/components/strings/components_strings_fil.xtb b/chromium/components/strings/components_strings_fil.xtb
index 56d723d1b28..2e0ac889854 100644
--- a/chromium/components/strings/components_strings_fil.xtb
+++ b/chromium/components/strings/components_strings_fil.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="fil">
<translation id="1008557486741366299">Hindi Ngayon</translation>
<translation id="1015730422737071372">Magbigay ng mga karagdagang detalye</translation>
+<translation id="1021110881106174305">Mga tinatanggap na card</translation>
<translation id="1032854598605920125">I-rotate pakanan</translation>
<translation id="1038842779957582377">Hindi kilalang pangalan</translation>
<translation id="1050038467049342496">Isara ang iba pang app</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Itago ang halaga</translation>
<translation id="1228893227497259893">Maling tagatukoy ng entity</translation>
<translation id="1232569758102978740">Walang pamagat</translation>
+<translation id="1263231323834454256">Listahan ng babasahin</translation>
<translation id="1264126396475825575">Ulat ng pag-crash na nakuha noong <ph name="CRASH_TIME" /> (hindi pa naa-upload o nababalewala)</translation>
<translation id="1285320974508926690">Huwag isalin kailanman ang site na ito</translation>
<translation id="129553762522093515">Kamakailang isinara</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Mga setting ng Autofill ng Chromium...</translation>
<translation id="1374468813861204354">mga suhestiyon</translation>
<translation id="1375198122581997741">Tungkol sa Bersyon</translation>
+<translation id="1377321085342047638">Numero ng Card</translation>
<translation id="139305205187523129">Hindi nagpadala ng anumang data ang <ph name="HOST_NAME" />.</translation>
<translation id="1407135791313364759">Buksan lahat</translation>
<translation id="1413809658975081374">Error sa privacy</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">History</translation>
<translation id="1645368109819982629">Hindi sinusuportahang protocol</translation>
<translation id="1656489000284462475">I-pick up</translation>
+<translation id="1663943134801823270">Ang mga card at address ay mula sa Chrome. Maaari mong pamahalaan ang mga ito sa <ph name="BEGIN_LINK" />Mga Setting<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">Karaniwang gumagamit ang <ph name="SITE" /> ng pag-encrypt upang protektahan ang iyong impormasyon. Noong sinubukang kumonekta ng Chrome sa <ph name="SITE" /> sa pagkakataong ito, nagbalik ang website ng mga hindi pangkaraniwan at maling kredensyal. Maaari itong mangyari kapag sinusubukan ng isang attacker na magpanggap bilang <ph name="SITE" />, o naputol ang koneksyon dahil sa isang screen ng pag-sign in sa Wi-Fi. Secure pa rin ang iyong impormasyon dahil inihinto ng Google Chrome ang koneksyon bago magkaroon ng palitan ng anumang data.</translation>
<translation id="168328519870909584">Ang mga umaatakeng kasalukuyang nasa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ay maaaring magtangkang mag-install ng mapapanganib na app sa iyong device na nagnanakaw o nagde-delete ng iyong impormasyon (halimbawa, mga larawan, password, mensahe at credit card).</translation>
<translation id="168841957122794586">Naglalaman ang server certificate ng isang mahinang cryptographic key.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Kailangan mo ng pahintulot mula kay <ph name="NAME" /> upang mabisita ang site na ito</translation>
+<translation id="1721424275792716183">Kinakailangan ang field na may *</translation>
<translation id="1728677426644403582">Pinagmulan ng isang web page ang tinitingnan mo</translation>
+<translation id="173080396488393970">Hindi sinusuportahan ang uri ng card na ito</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Subukang makipag-ugnayan sa admin ng system.</translation>
+<translation id="1740951997222943430">Maglagay ng wastong buwan ng pag-expire</translation>
<translation id="1745358365027406341">I-download ang page sa ibang pagkakataon</translation>
<translation id="17513872634828108">Mga bukas na tab</translation>
<translation id="1753706481035618306">Numero ng page</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Mangyaring i-update ang iyong passphrase ng pag-sync.</translation>
<translation id="1787142507584202372">Lalabas dito ang iyong mga bukas na tab</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Pumili ng address kung saan maghahatid upang tingnan ang mga paraan at kinakailangan sa paghatid.</translation>
+<translation id="1803264062614276815">Pangalan ng Cardholder</translation>
<translation id="1803678881841855883">Kamakailan lang, <ph name="BEGIN_LINK" />nakakita ng malware<ph name="END_LINK" /> ang Google Safe Browsing sa <ph name="SITE" />. Nagkakaroon ng malware paminsan-minsan ang mga website na karaniwang ligtas. Nanggagaling ang nakakahamak na content sa <ph name="SUBRESOURCE_HOST" />, isang kilalang distributor ng malware. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Idinagdag noong <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Di-wastong kahilingan o mga parameter ng kahilingan</translation>
<translation id="1826516787628120939">Sinusuri</translation>
<translation id="1834321415901700177">Naglalaman ng mga mapanirang program ang site na ito</translation>
<translation id="1842969606798536927">Magbayad</translation>
-<translation id="1864455488461349376">Opsyon sa paghatid</translation>
<translation id="1871208020102129563">Nakatakda ang proxy upang gumamit ng mga hindi nababagong proxy server, hindi ng isang .pac script URL.</translation>
<translation id="1871284979644508959">Kinakailangang field</translation>
<translation id="187918866476621466">Buksan ang mga page sa pagsisimula</translation>
<translation id="1883255238294161206">Tiklupin ang listahan</translation>
<translation id="1898423065542865115">Pagfi-filter</translation>
<translation id="194030505837763158">Pumunta sa <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Mga tinatanggap na card</translation>
<translation id="1962204205936693436">Mga Bookmark ng <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Error sa serialization</translation>
<translation id="1974060860693918893">Advanced</translation>
<translation id="1978555033938440688">Bersyon ng Firmware</translation>
+<translation id="1995859865337580572">Paki-verify ang iyong CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{at 1 pa}one{at # pa}other{at # pa}}</translation>
-<translation id="2020194265157481222">Kinakailangan ang pangalan sa card</translation>
<translation id="2025186561304664664">Nakatakda sa awtomatikong naka-configure ang proxy.</translation>
<translation id="2030481566774242610">Ang ibig mo bang sabihin ay <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Suriin ang proxy at ang firewall<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Ngayon</translation>
<translation id="2154054054215849342">Hindi available ang pag-sync para sa iyong domain</translation>
<translation id="2154484045852737596">I-edit ang card</translation>
-<translation id="2156993118928861787">Di-wastong address</translation>
<translation id="2166049586286450108">Ganap na Access ng Admin</translation>
<translation id="2166378884831602661">Hindi makakapagbigay ng secure na koneksyon ang site na ito</translation>
<translation id="2181821976797666341">Mga Patakaran</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 address}one{# address}other{# na address}}</translation>
+<translation id="2202020181578195191">Maglagay ng wastong taon ng pag-expire</translation>
<translation id="2212735316055980242">Hindi nahanap ang patakaran</translation>
<translation id="2213606439339815911">Kinukuha ang mga entry...</translation>
<translation id="2230458221926704099">Ayusin ang iyong koneksyon gamit ang <ph name="BEGIN_LINK" />diagnostics app<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Naka-block ang iyong access sa Internet</translation>
<translation id="230155334948463882">Bagong card?</translation>
<translation id="2305919008529760154">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; maaaring mapanlokong ibinigay ang certificate na panseguridad. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Ang mga opsyon sa card at address ay mula sa iyong Google Account (<ph name="ACCOUNT_EMAIL" />) at Chrome. Maaari mong pamahalaan ang mga ito sa <ph name="BEGIN_LINK" />Mga Setting<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535">Kailangan ng <ph name="DOMAIN" /> ng username at password.</translation>
<translation id="2318774815570432836">Hindi mo mabibisita ang <ph name="SITE" /> sa ngayon dahil gumagamit ang website ng HSTS. Kadalasang pansamantala lang ang mga error at atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Iba pang mga bookmark</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Default ng enterprise</translation>
<translation id="2386255080630008482">Nabawi ang certificate ng server.</translation>
<translation id="2392959068659972793">Ipakita ang mga patakarang walang nakatakdang halaga</translation>
+<translation id="239429038616798445">Hindi available ang pamamaraan ng pagpapadala na ito. Sumubok ng ibang pamamaraan.</translation>
<translation id="2396249848217231973">&amp;I-undo ang pagtanggal</translation>
<translation id="2460160116472764928">Kamakailan lang, <ph name="BEGIN_LINK" />nakakita ng malware<ph name="END_LINK" /> ang Google Safe Browsing sa <ph name="SITE" />.Nagkakaroon ng malware paminsan-minsan ang mga website na karaniwang ligtas. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Punan</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Magpatakbo ng Network Diagnostics<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Di-wastong URL ng paghahanap.</translation>
<translation id="2491120439723279231">Naglalaman ng mga error ang certificate ng server.</translation>
-<translation id="24943777258388405">Hindi wasto ang numero ng telepono</translation>
<translation id="2495083838625180221">Pang-parse ng JSON</translation>
<translation id="2495093607237746763">Kung may check, mag-iimbak ang Chromium ng kopya ng iyong card sa device na ito para sa mas mabilis na pagsagot sa form.</translation>
<translation id="2498091847651709837">Mag-scan ng bagong card</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027">Nagpadala ng di-wastong tugon ang <ph name="HOST_NAME" />.</translation>
<translation id="2552545117464357659">Mas Bago</translation>
<translation id="2556876185419854533">&amp;I-undo ang Pag-e-edit</translation>
+<translation id="2587730715158995865">Mula sa <ph name="ARTICLE_PUBLISHER" />. Basahin ito at ang <ph name="OTHER_ARTICLE_COUNT" /> (na) iba pang kwento.</translation>
<translation id="2587841377698384444">Directory API ID:</translation>
<translation id="2597378329261239068">Protektado ng password ang dokumentong ito. Mangyaring magpasok ng password.</translation>
<translation id="2609632851001447353">Mga Pagkakaiba-iba</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Magpatakbo ng Connectivity Diagnostics<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">Ok</translation>
<translation id="2742870351467570537">Alisin ang mga napiling item</translation>
+<translation id="277133753123645258">Pamamaraan ng pagpapadala</translation>
<translation id="277499241957683684">Nawawalang tala ng device</translation>
<translation id="2784949926578158345">Na-reset ang koneksyon.</translation>
<translation id="2794233252405721443">Naka-block ang site</translation>
-<translation id="2812680587231492111">Hindi available ang opsyon sa pagkuha na iyon. Sumubok ng ibang opsyon.</translation>
<translation id="2824775600643448204">Address bar at bar sa paghahanap</translation>
<translation id="2826760142808435982">Ine-encrypt at pinapatotoo ang koneksyon gamit ang <ph name="CIPHER" /> at ginagamit ang <ph name="KX" /> bilang key exchange mechanism.</translation>
<translation id="2835170189407361413">I-clear ang form</translation>
-<translation id="2849041323157393173">Hindi available ang opsyon sa paghahatid na iyon. Sumubok ng ibang opsyon.</translation>
<translation id="2889159643044928134">Huwag I-reload</translation>
<translation id="2900469785430194048">Naubusan ng memory ang Google Chrome habang sinusubukang ipakita ang webpage na ito.</translation>
<translation id="2909946352844186028">May nakitang pagbabago sa network.</translation>
<translation id="2916038427272391327">Isara ang iba pang program</translation>
<translation id="2922350208395188000">Hindi masuri ang certificate ng server.</translation>
+<translation id="2928905813689894207">Billing Address</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>
<translation id="2955913368246107853">Isara ang bar sa paghahanap</translation>
<translation id="2958431318199492670">Hindi sumusunod ang configuration ng network sa pamantayan ng ONC. Hindi maaaring i-import ang mga bahagi ng configuration.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">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 Google Chrome ang mga certificate na ito.</translation>
<translation id="2972581237482394796">&amp;I-redo</translation>
<translation id="2985306909656435243">Kung naka-enable, mag-iimbak ang Chromium ng kopya ng iyong card sa device na ito para sa mas mabilis na pagsagot sa form.</translation>
+<translation id="2985398929374701810">Maglagay ng wastong address</translation>
+<translation id="2986368408720340940">Hindi available ang pamamaraan ng pag-pick up na ito. Sumubok ng ibang pamamaraan.</translation>
<translation id="2991174974383378012">Pagbabahagi sa Mga Website</translation>
<translation id="3005723025932146533">Ipakita ang naka-save na kopya</translation>
<translation id="3008447029300691911">Ilagay ang CVC para sa <ph name="CREDIT_CARD" />. Kapag nagkumpirma ka na, ibabahagi ang mga detalye ng iyong card sa site na ito.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{kahit 1 item sa mga naka-sync na device}=1{1 item (at higit pa sa mga naka-sync na device)}one{# item (at higit pa sa mga naka-sync na device)}other{# na item (at higit pa sa mga naka-sync na device)}}</translation>
<translation id="3041612393474885105">Impormasyon sa Certificate</translation>
<translation id="3063697135517575841">Hindi nakumpirma ng Chrome ang iyong card sa pagkakataong ito. Pakisubukang muli sa ibang pagkakataon.</translation>
+<translation id="3064966200440839136">Aalis sa incognito mode upang magbayad sa pamamagitan ng external na application. Magpatuloy?</translation>
<translation id="3093245981617870298">Offline ka.</translation>
<translation id="3105172416063519923">Asset ID:</translation>
<translation id="3109728660330352905">Wala kang pahintulot na tingnan ang page na ito.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Subukang magpatakbo ng Connectivity Diagnostics<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Nabigong i-decode ang tugon</translation>
-<translation id="3149891296864842641">Opsyon sa pagpapadala</translation>
<translation id="3150653042067488994">Pansamantalang error sa server</translation>
+<translation id="3154506275960390542">Naglalaman ang page na ito ng isang form na maaaring hindi secure na maisusumite. Maaaring makita ng iba ang data na iyong ipapadala habang ipinapadala ito o maaaring mabago ng isang nang-aatake upang baguhin kung ano ang matatanggap ng server.</translation>
<translation id="3157931365184549694">Ipanumbalik</translation>
<translation id="3167968892399408617">Ang mga page na titingnan mo sa mga tab na incognito ay hindi mananatili sa history, cookie store o history ng paghahanap ng iyong browser kapag naisara mo na ang lahat ng iyong tab na incognito. Papanatilihin ang anumang mga file na ida-download mo o mga bookmark na gagawin mo.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Hindi maipadala kay <ph name="NAME" /> ang iyong kahilingang i-access ang site na ito. Pakisubukang muli.</translation>
<translation id="3355823806454867987">Baguhin ang mga setting ng proxy...</translation>
<translation id="3369192424181595722">Error sa orasan</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> pang item...</translation>
<translation id="337363190475750230">Naalis sa pagkakaprobisyon</translation>
<translation id="3377188786107721145">Error sa pag-parse ng patakaran</translation>
<translation id="3380365263193509176">Hindi kilalang error</translation>
<translation id="3380864720620200369">Client ID:</translation>
<translation id="3391030046425686457">Address kung saan maghahatid</translation>
+<translation id="3395827396354264108">Pamamaraan sa pag-pick up</translation>
<translation id="340013220407300675">Maaaring sinusubukan ng mga masasamang-loob na nakawin ang iyong impormasyon mula sa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (halimbawa, mga password, mensahe o credit card).</translation>
<translation id="3422248202833853650">Subukang lumabas sa iba pang program upang magbakante ng memory.</translation>
<translation id="3422472998109090673">Hindi makakonekta sa <ph name="HOST_NAME" /> sa kasalukuyan.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Kunin ang agwat:</translation>
<translation id="3462200631372590220">Itago ang advanced</translation>
+<translation id="3467763166455606212">Kinakailangan ang pangalan ng cardholder</translation>
+<translation id="3478058380795961209">Buwan ng Pag-expire</translation>
<translation id="3479539252931486093">Hindi mo ba ito inaasahan? <ph name="BEGIN_LINK" />Ipaalam sa amin<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Hindi ngayon</translation>
<translation id="348000606199325318">Crash ID <ph name="CRASH_LOCAL_ID" /> (Server ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Hindi namin makaugnayan ang iyong magulang sa sandaling ito. Pakisubukang muli.</translation>
<translation id="3528171143076753409">Hindi pinagkakatiwalaan ang certificate ng server.</translation>
-<translation id="3538531656504267329">Di-wastong taon ng pag-expire</translation>
<translation id="3539171420378717834">Magtago ng kopya ng card na ito sa device na ito</translation>
<translation id="3542684924769048008">Gamitin ang password para sa:</translation>
<translation id="3549644494707163724">I-encrypt ang lahat ng naka-sync na data gamit ang sarili mong passphrase sa pag-sync</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Magtago ng mga detalye</translation>
<translation id="3587482841069643663">Lahat</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Maglagay ng wastong petsa ng pag-expire</translation>
<translation id="36224234498066874">Clear Browsing Data...</translation>
<translation id="362276910939193118">Ipakita ang Buong History</translation>
<translation id="3623476034248543066">Ipakita ang halaga</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Password:</translation>
<translation id="3696411085566228381">wala</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Pumili ng address sa pagpapadala upang makita ang mga paraan ng at kinakailangan sa pagpapadala.</translation>
<translation id="370665806235115550">Naglo-load...</translation>
<translation id="3712624925041724820">Naubos na ang mga lisensya</translation>
<translation id="3714780639079136834">I-on ang mobile data o Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Link na kinopya mo</translation>
<translation id="375403751935624634">Nabigo ang translation dahil sa error sa server.</translation>
<translation id="3759461132968374835">Wala kang kamakailang iniulat na mga pag-crash. Hindi lilitaw dito ang mga pag-crash na naganap kapag hindi pinagana ang pag-uulat ng pag-crash.</translation>
+<translation id="3787705759683870569">Mag-e-expire sa <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Kung gumagamit ka ng proxy server...</translation>
<translation id="3828924085048779000">Hindi pinapayagan ang walang laman na passphrase.</translation>
<translation id="3845539888601087042">Ipinapakita ang history mula sa iyong mga naka-sign in na device. <ph name="BEGIN_LINK" />Matuto nang higit pa<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Gusto mo bang i-save ng Chromium ang card na ito?</translation>
<translation id="4171400957073367226">Hindi wasto ang signature sa pag-verify</translation>
-<translation id="4176463684765177261">Hindi Pinagana</translation>
<translation id="4196861286325780578">&amp;Gawing muli ang paglilipat</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Suriin ang mga configuration ng firewall at antivirus<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{wala}=1{1 app ($1)}=2{2 app ($1, $2)}one{# app ($1, $2, $3)}other{# na app ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">mga resulta ng paghahanap</translation>
<translation id="4432688616882109544">Hindi tinanggap ng <ph name="HOST_NAME" /> ang iyong certificate sa pag-log in o maaaring walang ibinigay.</translation>
<translation id="443673843213245140">Hindi pinagana ang paggamit ng isang proxy ngunit tinutukoy ang isang tahasang configuration ng proxy.</translation>
-<translation id="4446242550670694251">Makakapag-browse ka na ngayon nang pribado, at hindi makikita ng iba pang taong gumagamit ng device na ito ang iyong aktibidad.</translation>
<translation id="4492190037599258964">Mga resulta ng paghahanap para sa '<ph name="SEARCH_STRING" />'</translation>
<translation id="4506176782989081258">Error sa pagpapatunay: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Makipag-ugnayan sa admin ng system</translation>
<translation id="450710068430902550">Pagbabahagi sa Administrator</translation>
+<translation id="4515275063822566619">Ang mga card at address ay mula sa Chrome at sa iyong Google Account (<ph name="ACCOUNT_EMAIL" />). Maaari mong pamahalaan ang mga ito sa <ph name="BEGIN_LINK" />Mga Setting<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Mga Detalye</translation>
<translation id="4558551763791394412">Subukang i-disable ang iyong mga extension.</translation>
<translation id="457875822857220463">Paghahatid</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Pagkasyahin sa pahina</translation>
<translation id="483020001682031208">Walang maipakitang page ng Pisikal na Web</translation>
<translation id="4850886885716139402">View</translation>
+<translation id="4854362297993841467">Hindi available ang pamamaraan ng paghahatid na ito. Sumubok ng ibang pamamaraan.</translation>
<translation id="4858792381671956233">Tinanong mo sa iyong mga magulang kung maaari mong bisitahin ang site na ito</translation>
<translation id="4880827082731008257">History ng paghahanap</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Na-translate ang pahinang ito mula sa hindi kilalang wika patungo sa <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Pagbabayad</translation>
<translation id="4926049483395192435">Dapat na tukuyin.</translation>
-<translation id="4941291666397027948">* tumutukoy sa kinakailangang field</translation>
<translation id="495170559598752135">Mga Pagkilos</translation>
<translation id="4958444002117714549">Palawakin ang listahan</translation>
<translation id="4962322354953122629">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; hindi pinagkakatiwalaan ng Chrome ang certificate na panseguridad nito. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Hindi wastong password</translation>
<translation id="5056549851600133418">Mga artikulo para sa iyo</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Suriin ang proxy address<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Walang cookies}=1{1 site ang gumagamit ng cookies. }one{# site ang gumagamit ng cookies. }other{# na site ang gumagamit ng cookies. }}</translation>
<translation id="5087286274860437796">Hindi angkop ang certificate ng server sa oras na ito.</translation>
<translation id="5087580092889165836">Magdagdag ng card</translation>
<translation id="5089810972385038852">Estado</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Ipakita</translation>
<translation id="5308689395849655368">Hindi pinagana ang pag-uulat ng pag-crash.</translation>
<translation id="5317780077021120954">I-save</translation>
-<translation id="5326702247179446998">Kailangan ng tatanggap</translation>
<translation id="5327248766486351172">Pangalan</translation>
<translation id="5337705430875057403">Maaaring subukan ng mga attacker sa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> na linlangin ka sa paggawa ng bagay na mapanganib gaya ng pag-i-install ng software o pagbubunyag ng iyong personal na impormasyon (halimbawa, mga password, numero ng telepono o credit card).</translation>
-<translation id="53553865750799677">Hindi sinusuportahang address sa pag-pick up. Pumili ng ibang address.</translation>
<translation id="5359637492792381994">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; walang bisa ang certificate na panseguridad nito sa ngayon. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Nabigo i-load ang mga setting ng patakaran sa store</translation>
<translation id="5386426401304769735">Naglalaman ang chain ng certificate para sa site na ito ng certificate na naka-sign gamit ang SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">Isinasaad ng isang naka-embed na page sa <ph name="SITE" /> na:</translation>
<translation id="5556459405103347317">I-reload</translation>
<translation id="5565735124758917034">Aktibo</translation>
+<translation id="5571083550517324815">Hindi maaaring mag-pick up mula sa address na ito. Pumili ng ibang address.</translation>
<translation id="5572851009514199876">Magsimula at mag-sign in sa Chrome upang masuri ng Chrome kung pinapayagan kang i-access ang site na ito.</translation>
-<translation id="5575380383496039204">Hindi sinusuportahang address kung saan maghahatid. Pumili ng ibang address.</translation>
<translation id="5580958916614886209">Tingnan ang iyong buwan ng pag-expire at subukang muli</translation>
<translation id="560412284261940334">Hindi sinusuportahan ang pamamahala</translation>
<translation id="5610142619324316209">Suriin ang koneksyon</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">Ang pagkilala ng website na ito ay hindi natukoy.</translation>
<translation id="5720705177508910913">Kasalukuyang user</translation>
<translation id="5732392974455271431">Maaari itong alisin sa pagkaka-block ng iyong mga magulang para sa iyo</translation>
-<translation id="57586589942790530">Di-wasto ang numero ng card</translation>
+<translation id="5763042198335101085">Maglagay ng wastong email address</translation>
+<translation id="5765072501007116331">Upang makita ang mga pamamaraan at kinakailangan sa paghahatid, pumili ng address</translation>
<translation id="5784606427469807560">Nagkaroon ng problema sa pagkumpirma ng iyong card. Suriin ang koneksyon sa internet at subukang muli.</translation>
<translation id="5785756445106461925">Bukod pa rito, ang page na ito ay may iba pang mga mapagkukunang hindi secure. Makikita ng iba ang mga mapagkukunang ito habang ipinadadala, at maaaring baguhin ng isang umaatake upang baguhin ang hitsura ng page.</translation>
<translation id="5786044859038896871">Gusto mo bang ilagay ang impormasyon ng iyong card?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">Hindi makakonekta sa site na ito</translation>
<translation id="5869522115854928033">Mga naka-save na password</translation>
<translation id="5872918882028971132">Mga Suhestyon ng Magulang</translation>
-<translation id="587760065310675640">Hindi sinusuportahan ang address sa pagpapadala. Pumili ng ibang address.</translation>
<translation id="5901630391730855834">Dilaw</translation>
-<translation id="59174027418879706">Naka-enable</translation>
<translation id="5926846154125914413">Maaari kang mawalan ng access sa premium na content mula sa ilang site.</translation>
<translation id="5959728338436674663">Awtomatikong magpadala ng ilang <ph name="BEGIN_WHITEPAPER_LINK" />impormasyon sa system at content ng page<ph name="END_WHITEPAPER_LINK" /> sa Google upang makatulong na tumukoy ng mapapanganib na app at site. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Linggo</translation>
<translation id="5967867314010545767">Alisin sa history</translation>
<translation id="5975083100439434680">Mag-zoom out</translation>
+<translation id="598637245381783098">Hindi mabuksan ang app sa pagbabayad</translation>
<translation id="5989320800837274978">Hindi tunukoy ang alinman sa mga hindi nababagong proxy server o isang .pac script URL.</translation>
<translation id="5990559369517809815">Na-block ng isang extension ang mga kahilingan sa server.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Mula sa Chrome ang mga opsyon sa card at address. Maaari mong pamahalaan ang mga ito sa <ph name="BEGIN_LINK" />Mga Setting<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Page 1}one{Page #}other{Page #}}</translation>
<translation id="6017514345406065928">Berde</translation>
+<translation id="6027201098523975773">Maglagay ng pangalan</translation>
<translation id="6040143037577758943">Isara</translation>
-<translation id="604124094241169006">Awtomatiko</translation>
<translation id="6042308850641462728">Higit pa</translation>
<translation id="6060685159320643512">Mag-ingat, maaaring makahamak ang mga eksperimentong ito</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{wala}=1{1}one{#}other{#}}</translation>
@@ -543,9 +552,10 @@
pang mga network device na maaaring ginagamit mo.</translation>
<translation id="614940544461990577">Subukang:</translation>
<translation id="6151417162996330722">Masyadong mahaba ang panahon ng pagkakaroon ng bisa ng certificate ng server.</translation>
-<translation id="615643356032862689">Itatabi ang mga na-download na file at bookmark.</translation>
+<translation id="6157877588268064908">Upang makita ang mga pamamaraan at kinakailangan sa pagpapadala, pumili ng address</translation>
<translation id="6165508094623778733">Matuto nang higit pa</translation>
<translation id="6177128806592000436">Hindi ligtas ang iyong koneksyon sa site na ito</translation>
+<translation id="6184817833369986695">(cohort: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Suriin ang iyong koneksyon sa Internet</translation>
<translation id="6218753634732582820">Gusto mo bang alisin ang address sa Chromium?</translation>
<translation id="6251924700383757765">Patakaran sa privacy</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Gawing Muli ang Pagbabago sa Ayos</translation>
<translation id="6263376278284652872">Mga bookmark ng <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Bumalik sa safety</translation>
+<translation id="6276112860590028508">Lalabas dito ang mga page mula sa iyong listahan ng babasahin</translation>
+<translation id="6280223929691119688">Hindi maaaring maghatid sa address na ito. Pumili ng ibang address.</translation>
<translation id="6282194474023008486">Postal code</translation>
<translation id="6290238015253830360">Lalabas dito ang iminungkahi mong artikulo</translation>
<translation id="6305205051461490394">Hindi makakonekta sa <ph name="URL" />.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Hindi nagawang masuri kung nabawi na ang certificate.</translation>
<translation id="6433490469411711332">I-edit ang impormasyon sa pakikipag-ugnayan</translation>
<translation id="6433595998831338502">Tumangging kumonekta ang <ph name="HOST_NAME" />.</translation>
-<translation id="6443118737398455446">Di-wastong expiration date</translation>
<translation id="6446608382365791566">Magdagdag ng higit pang impormasyon</translation>
<translation id="6451458296329894277">Muling pagsusumite ng Form sa Pagkumpirma</translation>
<translation id="6456339708790392414">Iyong Pagbabayad</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; maaaring mabawi ang certificate na panseguridad nito. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Mga patakaran sa device</translation>
<translation id="6477321094435799029">May natukoy na kakaibang code ang Chrome sa page na ito at na-block ito upang protektahan ang iyong personal na impormasyon (halimbawa, mga password, numero ng telepono at credit card).</translation>
-<translation id="6477460825583319731">Hindi wasto ang email address</translation>
<translation id="6489534406876378309">Simulang mag-upload ng mga pag-crash</translation>
<translation id="6508722015517270189">I-restart ang Chrome</translation>
-<translation id="6525462735697194615">Di-wastong buwan ng pag-expire</translation>
<translation id="6529602333819889595">&amp;Gawing Muli ang Pagtanggal</translation>
<translation id="6534179046333460208">Mga suhestyon sa Pisikal na Web</translation>
<translation id="6550675742724504774">Mga Pagpipilian</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685">Paghahanap ng <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Hindi na ginagamit ang patakarang ito.</translation>
<translation id="6652240803263749613">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; ang certificate na panseguridad nito ay hindi pinagkakatiwalaan ng operating system ng iyong computer. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Hindi available ang opsyon sa pagpapadala na iyon. Sumubok ng ibang opsyon.</translation>
<translation id="6671697161687535275">Gusto mo bang alisin ang form para sa suhestyon sa Chromium?</translation>
<translation id="6685834062052613830">Mag-sign out at kumpletuhin ang setup</translation>
<translation id="6710213216561001401">Nakaraan</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">May problema sa proxy server, o mali ang address.</translation>
<translation id="6727102863431372879">Itakda</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{wala}=1{1 item}one{# item}other{# na item}}</translation>
-<translation id="6743044928064272573">Opsyon sa pag-pick up</translation>
<translation id="674375294223700098">Hindi alam na error sa certificate ng server</translation>
<translation id="6753269504797312559">Halaga ng patakaran</translation>
<translation id="6757797048963528358">Nag-sleep ang iyong device.</translation>
<translation id="6778737459546443941">Hindi pa ito inaaprubahan ng iyong magulang</translation>
<translation id="6810899417690483278">Customization ID</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Hindi na-load ang data ng mga rehiyon</translation>
<translation id="6831043979455480757">Isalin</translation>
<translation id="6839929833149231406">Lugar</translation>
<translation id="6874604403660855544">&amp;Gawing muli ang pagdagdag</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Nakumpirma na ang iyong card</translation>
<translation id="6897140037006041989">User Agent</translation>
<translation id="6915804003454593391">User:</translation>
+<translation id="6948701128805548767">Upang makita ang mga pamamaraan at kinakailangan sa pag-pick up, pumili ng address</translation>
<translation id="6957887021205513506">Lumilitaw na isang pamamalsipika ang certificate ng server.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Device</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">Tinukoy ang parehong mga hindi nababagong proxy server at isang .pac script URL.</translation>
<translation id="6989763994942163495">Ipakita ang mga advanced na setting...</translation>
<translation id="7000990526846637657">Walang nakitang mga entry sa history</translation>
-<translation id="7001663382399377034">Magdagdag ng tatanggap</translation>
<translation id="7009986207543992532">Tinangka mong makakonekta sa <ph name="DOMAIN" />, ngunit ang server ay nagpakita ng certificate na masyadong matagal ang panahon ng pagkabisa, dahilan upang hindi maging katiwa-katiwala ito. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Ang iyong Google Account ay maaaring may iba pang mga form ng history ng pagba-browse sa <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Mas Nauna</translation>
<translation id="7090678807593890770">Hanapin sa Google ang <ph name="LINK" /></translation>
<translation id="7119414471315195487">Isara ang iba pang tab o program</translation>
+<translation id="7129409597930077180">Hindi maaaring magpadala sa address na ito. Pumili ng ibang address.</translation>
+<translation id="7138472120740807366">Pamamaraan ng paghahatid</translation>
<translation id="7139724024395191329">Emirate</translation>
<translation id="7155487117670177674">Hindi ligtas ang pagbabayad</translation>
<translation id="7179921470347911571">Ilunsad Muli Ngayon</translation>
<translation id="7180611975245234373">I-refresh</translation>
<translation id="7182878459783632708">Walang nakatakdang mga patakaran</translation>
<translation id="7186367841673660872">Naisalin ang pahinang ito mula sa<ph name="ORIGINAL_LANGUAGE" />sa<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423">Hindi sumusunod ang <ph name="HOST_NAME" /> sa mga pamantayan sa seguridad.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Dagdagan ang nalalaman<ph name="END_LINK" /> tungkol sa problemang ito.</translation>
@@ -675,7 +686,6 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="7424977062513257142">Isinasaad ng isang naka-embed na page sa webpage na ito na:</translation>
<translation id="7441627299479586546">Maling paksa ng patakaran</translation>
<translation id="7444046173054089907">Naka-block ang site na ito</translation>
-<translation id="7444238235002594607">Pumili ng address sa pag-pick up upang tingnan ang mga paraan at kinakailangan sa pag-pick up.</translation>
<translation id="7445762425076701745">Hindi ganap na mapatunayan ang pagkakakilanlan ng server na konektado ka. Konektado ka sa server gamit ang pangalan na angkop lamang sa loob ng iyong network, na walang paraan ang panglabas na certificate authority na patunayan ang pagmamay-ari. Dahil magbibigay ang ilang kinauukulan sa certificate para sa mga pangalang ito, walang paraan upang matiyak na konektado ka sa nilayong website at hindi isang umaatake.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Matuto nang higit pa<ph name="END_LINK" /> tungkol sa problemang ito.</translation>
<translation id="7460163899615895653">Lumalabas dito ang mga kamakailan mong tab mula sa iba pang mga device</translation>
@@ -719,6 +729,7 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="7755287808199759310">Maaari itong alisin sa pagkaka-block ng iyong magulang para sa iyo</translation>
<translation id="7758069387465995638">Maaaring na-block ng firewall o antivirus software ang koneksyon.</translation>
<translation id="7761701407923456692">Hindi tumutugma sa URL ang certificate ng server.</translation>
+<translation id="7763386264682878361">Pang-parse ng Manifest ng Pagbabayad</translation>
<translation id="7764225426217299476">Magdagdag ng address</translation>
<translation id="777702478322588152">Prefecture</translation>
<translation id="7791543448312431591">Magdagdag</translation>
@@ -732,6 +743,7 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="785549533363645510">Gayunpaman, hindi ka invisible. Kahit mag-incognito ka, hindi matatago ang iyong pagba-browse mula sa iyong employer, sa iyong internet service provider o sa mga website na binibisita mo.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Tingnan ang iyong CVC at subukang muli</translation>
+<translation id="79338296614623784">Maglagay ng wastong numero ng telepono</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Wala pang bisa ang certificate ng server.</translation>
<translation id="7942349550061667556">Pula</translation>
@@ -751,6 +763,7 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="8088680233425245692">Hindi natingnan ang artikulo.</translation>
<translation id="8089520772729574115">wala pang 1 MB</translation>
<translation id="8091372947890762290">Nakabinbin sa server ang pag-activate</translation>
+<translation id="8118489163946903409">Paraan ng pagbabayad</translation>
<translation id="8131740175452115882">Kumpirmahin</translation>
<translation id="8134994873729925007">Hindi makita ang <ph name="BEGIN_ABBR" />DNS address<ph name="END_ABBR" /> ng server ng <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Nag-sleep ang iyong computer.</translation>
@@ -776,6 +789,7 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="8349305172487531364">Bookmarks bar</translation>
<translation id="8363502534493474904">I-off ang airplane mode</translation>
<translation id="8364627913115013041">Hindi nakatakda.</translation>
+<translation id="8368476060205742148">Mga serbisyo ng Google Play</translation>
<translation id="8380941800586852976">Mapanganib</translation>
<translation id="8382348898565613901">Lalabas dito ang iyong mga kamakailang binisitang bookmark</translation>
<translation id="8398259832188219207">Na-upload ang ulat ng pag-crash noong <ph name="UPLOAD_TIME" /></translation>
@@ -784,31 +798,29 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="8428213095426709021">Mga Setting</translation>
<translation id="8433057134996913067">Masa-sign out ka sa karamihan ng mga website.</translation>
<translation id="8437238597147034694">&amp;I-undo ang paglilipat</translation>
-<translation id="8456681095658380701">Di-wastong pangalan</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 credit card}one{# credit card}other{# na credit card}}</translation>
<translation id="8483780878231876732">Upang gumamit ng mga card mula sa iyong Google Account, mag-sign in sa Chrome</translation>
<translation id="8488350697529856933">Nalalapat sa</translation>
-<translation id="8492969205326575646">Hindi sinusuportahan ang uri ng card</translation>
<translation id="8498891568109133222">Masyadong matagal bago nakatugon ang <ph name="HOST_NAME" />.</translation>
<translation id="852346902619691059">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; ang certificate na panseguridad nito ay hindi pinagkakatiwalaan ng operating system ng iyong device. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Taon ng Pag-expire</translation>
<translation id="8543181531796978784">Maaari kang <ph name="BEGIN_ERROR_LINK" />mag-ulat ng problema sa pagtukoy<ph name="END_ERROR_LINK" /> o, kung nauunawaan mo ang mga panganib sa iyong seguridad, <ph name="BEGIN_LINK" />bisitahin ang hindi ligtas na site na ito<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Nabigo ang pag-translate dahil hindi matukoy ang wika ng pahina.</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="8570229484593575558">|Hindi mase-save| ang impormasyong ito:#Ang iyong history ng pagba-browse#Ang mga paghahanap mo#Date ng cookie</translation>
<translation id="8571890674111243710">Tina-translate ang pahina sa <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Ang iyong aktibidad ay |maaari pa ring makita| ng:#Mga website na binibisita mo#Iyong employer#Provider ng serbisyo mo sa internet</translation>
<translation id="858637041960032120">Magdagdag ng numero ng telepono</translation>
<translation id="859285277496340001">Hindi tumutukoy ang certificate na ito ng mekanismo upang masuri kung nabawi ito.</translation>
<translation id="8620436878122366504">Hindi pa ito inaaprubahan ng iyong mga magulang</translation>
<translation id="8647750283161643317">I-reset ang lahat sa default</translation>
<translation id="8703575177326907206">Ang iyong koneksyon sa <ph name="DOMAIN" /> ay hindi naka-encrypt.</translation>
+<translation id="8718314106902482036">Hindi nakumpleto ang pagbabayad</translation>
<translation id="8725066075913043281">Muling subukan</translation>
<translation id="8728672262656704056">Naging incognito ka</translation>
<translation id="8730621377337864115">Tapos na</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="8759274551635299824">Nag-expire na ang card na ito</translation>
<translation id="8790007591277257123">&amp;Gawing muli ang pagtanggal</translation>
-<translation id="8798099450830957504">Default</translation>
<translation id="8800988563907321413">Lalabas dito ang iyong mga suhestyon na malapit</translation>
<translation id="8820817407110198400">Mga Bookmark</translation>
<translation id="883848425547221593">Iba Pang Mga Bookmark</translation>
@@ -818,6 +830,7 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="8866481888320382733">Error sa pag-parse ng mga setting ng patakaran</translation>
<translation id="8866959479196209191">Isinasaad ng page na ito na:</translation>
<translation id="8870413625673593573">Recently Closed</translation>
+<translation id="8874824191258364635">Maglagay ng wastong numero ng card</translation>
<translation id="8876793034577346603">Nabigong ma-parse ang configuration ng network.</translation>
<translation id="8877192140621905067">Kapag nagkumpirma ka na, ibabahagi ang mga detalye ng iyong card sa site na ito</translation>
<translation id="8889402386540077796">Hue</translation>
@@ -827,7 +840,6 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="8931333241327730545">Gusto mo bang i-save ang card na ito sa iyong Google Account?</translation>
<translation id="8932102934695377596">Nahuhuli ang iyong orasan</translation>
<translation id="8954894007019320973">(Itinuloy)</translation>
-<translation id="895548565263634352">Magbasa ng mga kwento mula sa <ph name="ARTICLE_PUBLISHER" /> at <ph name="OTHER_ARTICLE_COUNT" /> pa</translation>
<translation id="8971063699422889582">Nag-expire na ang certificate ng server.</translation>
<translation id="8986494364107987395">Awtomatikong ipadala ang mga istatistika ng paggamit at mga ulat ng pag-crash sa Google</translation>
<translation id="8987927404178983737">Buwan</translation>
@@ -845,7 +857,6 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="9068849894565669697">Pumili ng kulay</translation>
<translation id="9076283476770535406">Maaaring mayroon itong mature content</translation>
<translation id="9078964945751709336">Nangangailangan ng higit pang impormasyon</translation>
-<translation id="9094175695478007090">Hindi mailunsad ang app sa pagbabayad.</translation>
<translation id="9103872766612412690">Karaniwang gumagamit ang <ph name="SITE" /> ng pag-encrypt upang protektahan ang iyong impormasyon. Noong sinubukang kumonekta ng Chromium sa <ph name="SITE" /> sa pagkakataong ito, nagbalik ang website ng mga hindi pangkaraniwan at maling kredensyal. Maaari itong mangyari kapag sinusubukan ng isang attacker na magpanggap bilang <ph name="SITE" />, o naputol ang koneksyon dahil sa isang screen ng pag-sign in sa Wi-Fi. Secure pa rin ang iyong impormasyon dahil inihinto ng Chromium ang koneksyon bago magkaroon ng palitan ng anumang data.</translation>
<translation id="9137013805542155359">Ipakita ang orihinal</translation>
<translation id="9137248913990643158">Magsimula at mag-sign in sa Chrome bago gamitin ang app na ito.</translation>
diff --git a/chromium/components/strings/components_strings_fr.xtb b/chromium/components/strings/components_strings_fr.xtb
index c8e9a485143..e57c3240f06 100644
--- a/chromium/components/strings/components_strings_fr.xtb
+++ b/chromium/components/strings/components_strings_fr.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="fr">
<translation id="1008557486741366299">Pas maintenant</translation>
<translation id="1015730422737071372">Fournir des informations supplémentaires</translation>
+<translation id="1021110881106174305">Cartes acceptées</translation>
<translation id="1032854598605920125">Faire pivoter vers la droite</translation>
<translation id="1038842779957582377">Nom inconnu</translation>
<translation id="1050038467049342496">Fermez les autres applications</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Masquer la valeur</translation>
<translation id="1228893227497259893">Identifiant d'entité incorrect.</translation>
<translation id="1232569758102978740">Sans titre</translation>
+<translation id="1263231323834454256">Liste de lecture</translation>
<translation id="1264126396475825575">Rapport d'erreur enregistré le <ph name="CRASH_TIME" /> (pas encore importé ou ignoré)</translation>
<translation id="1285320974508926690">Ne jamais traduire ce site</translation>
<translation id="129553762522093515">Récemment fermés</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Paramètres de saisie automatique de Chromium…</translation>
<translation id="1374468813861204354">suggestions</translation>
<translation id="1375198122581997741">À propos de la version</translation>
+<translation id="1377321085342047638">Numéro de carte</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> n'a envoyé aucune donnée.</translation>
<translation id="1407135791313364759">Tout ouvrir</translation>
<translation id="1413809658975081374">Erreur liée à la confidentialité</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Historique</translation>
<translation id="1645368109819982629">Protocole incompatible</translation>
<translation id="1656489000284462475">Enlèvement</translation>
+<translation id="1663943134801823270">Les cartes et les adresses proviennent de Chrome. Vous pouvez les gérer dans les <ph name="BEGIN_LINK" />Paramètres<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">Un chiffrement est normalement utilisé sur le site <ph name="SITE" /> pour protéger vos informations. Lors de la dernière tentative de connexion de Google Chrome au site <ph name="SITE" />, des identifiants inhabituels et incorrects ont été retournés. Il est possible qu'un individu malveillant tente de se faire passer pour <ph name="SITE" /> ou qu'un écran de connexion Wi-Fi ait interrompu la connexion. Vos informations restent sécurisées, car nous avons arrêté la connexion avant l'échange des données.</translation>
<translation id="168328519870909584">Des individus malveillants à l'œuvre sur le site <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> pourraient tenter d'installer des applications dangereuses sur votre appareil afin de récupérer ou de supprimer certaines informations : photos, mots de passe, messages, numéros de carte de paiement, etc.</translation>
<translation id="168841957122794586">Le certificat du serveur contient une clé de chiffrement faible.</translation>
<translation id="1710259589646384581">Système d'exploitation</translation>
<translation id="1721312023322545264">Vous devez disposer de l'autorisation de <ph name="NAME" /> pour consulter ce site</translation>
+<translation id="1721424275792716183">* Champ obligatoire</translation>
<translation id="1728677426644403582">Vous consultez actuellement la source d'une page Web</translation>
+<translation id="173080396488393970">Type de carte non accepté</translation>
<translation id="1734864079702812349">American Express</translation>
<translation id="1734878702283171397">Essayez de contacter l'administrateur système.</translation>
+<translation id="1740951997222943430">Saisissez un mois d'expiration valide</translation>
<translation id="1745358365027406341">Télécharger la page plus tard</translation>
<translation id="17513872634828108">Onglets ouverts</translation>
<translation id="1753706481035618306">Numéro de page</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Mettre à jour votre phrase secrète de synchronisation</translation>
<translation id="1787142507584202372">Les onglets ouverts s'affichent ici</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Sélectionnez une adresse de livraison pour consulter les modes de livraison disponibles et les conditions applicables.</translation>
+<translation id="1803264062614276815">Nom du titulaire de la carte</translation>
<translation id="1803678881841855883">La navigation sécurisée de Google a récemment <ph name="BEGIN_LINK" />détecté des logiciels malveillants<ph name="END_LINK" /> sur le site <ph name="SITE" />. Un site Web qui est normalement sans danger peut parfois être infecté par des logiciels malveillants. Le contenu en cause provient de l'hôte <ph name="SUBRESOURCE_HOST" />, une source de logiciels malveillants connue. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1806541873155184440">Date d'ajout : <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">La demande ou ses paramètres ne sont pas valides.</translation>
<translation id="1826516787628120939">Vérification en cours…</translation>
<translation id="1834321415901700177">Ce site contient des programmes dangereux</translation>
<translation id="1842969606798536927">Paiement</translation>
-<translation id="1864455488461349376">Option de livraison</translation>
<translation id="1871208020102129563">Le proxy est configuré pour utiliser des serveurs proxy déterminés, pas une URL de script .pac.</translation>
<translation id="1871284979644508959">Veuillez compléter ce champ.</translation>
<translation id="187918866476621466">Ouvrir les pages de démarrage</translation>
<translation id="1883255238294161206">Réduire la liste</translation>
<translation id="1898423065542865115">Filtrage</translation>
<translation id="194030505837763158">Accédez à <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Cartes acceptées</translation>
<translation id="1962204205936693436">Favoris du domaine <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Erreur de sérialisation.</translation>
<translation id="1974060860693918893">Paramètres avancés</translation>
<translation id="1978555033938440688">Version du micrologiciel</translation>
+<translation id="1995859865337580572">Veuillez confirmer votre code CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{et 1 autre}one{et # autre}other{et # autres}}</translation>
-<translation id="2020194265157481222">Nom sur la carte obligatoire</translation>
<translation id="2025186561304664664">Le proxy est défini sur la configuration automatique.</translation>
<translation id="2030481566774242610">Essayez avec <ph name="LINK" /></translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Vérifier le proxy et le pare-feu<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Aujourd'hui</translation>
<translation id="2154054054215849342">La synchronisation n'est pas disponible pour votre domaine</translation>
<translation id="2154484045852737596">Modifier la carte</translation>
-<translation id="2156993118928861787">Adresse incorrecte</translation>
<translation id="2166049586286450108">Accès administrateur complet</translation>
<translation id="2166378884831602661">Ce site ne peut pas fournir de connexion sécurisée</translation>
<translation id="2181821976797666341">Règles</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresse}one{# adresse}other{# adresses}}</translation>
+<translation id="2202020181578195191">Saisissez une année d'expiration valide</translation>
<translation id="2212735316055980242">Règle introuvable.</translation>
<translation id="2213606439339815911">Obtention des entrées en cours…</translation>
<translation id="2230458221926704099">Vérifiez la connexion à l'aide de l'<ph name="BEGIN_LINK" />application de diagnostic<ph name="END_LINK" />.</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Votre accès à Internet est bloqué</translation>
<translation id="230155334948463882">Nouvelle carte ?</translation>
<translation id="2305919008529760154">Impossible de vérifier que ce serveur est bien <ph name="DOMAIN" />, car il se peut que son certificat de sécurité ait été émis de manière frauduleuse. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="230697611605700222">Les cartes et les adresses proposées proviennent de votre compte Google (<ph name="ACCOUNT_EMAIL" />) et de Chrome. Vous pouvez les gérer dans les <ph name="BEGIN_LINK" />paramètres<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> nécessite un nom d'utilisateur et un mot de passe.</translation>
<translation id="2318774815570432836">Vous ne pouvez pas consulter le site Web <ph name="SITE" /> pour le moment, car la technologie HSTS y est utilisée. Les attaques et les erreurs réseau sont généralement temporaires. Vous devriez donc pouvoir accéder à cette page ultérieurement. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2354001756790975382">Autres favoris</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Valeur par défaut définie par l'entreprise</translation>
<translation id="2386255080630008482">Le certificat du serveur a été révoqué.</translation>
<translation id="2392959068659972793">Afficher les règles non paramétrées</translation>
+<translation id="239429038616798445">Mode d'expédition non disponible. Choisissez-en un autre.</translation>
<translation id="2396249848217231973">&amp;Annuler la suppression</translation>
<translation id="2460160116472764928">La navigation sécurisée de Google a récemment <ph name="BEGIN_LINK" />détecté des logiciels malveillants<ph name="END_LINK" /> sur le site <ph name="SITE" />. Un site Web qui est normalement sans danger peut parfois être infecté par des logiciels malveillants. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2463739503403862330">Remplir</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Exécuter les diagnostics du réseau<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL de recherche incorrecte</translation>
<translation id="2491120439723279231">Le certificat du serveur contient des erreurs.</translation>
-<translation id="24943777258388405">Numéro de téléphone incorrect</translation>
<translation id="2495083838625180221">Analyse de fichiers JSON</translation>
<translation id="2495093607237746763">Si cette case est cochée, Chromium enregistre une copie de votre carte sur cet appareil pour vous permettre de remplir plus rapidement les formulaires.</translation>
<translation id="2498091847651709837">Lire une nouvelle carte</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> a envoyé une réponse incorrecte.</translation>
<translation id="2552545117464357659">Récent</translation>
<translation id="2556876185419854533">&amp;Annuler la modification</translation>
+<translation id="2587730715158995865">Proposé par <ph name="ARTICLE_PUBLISHER" />. Lisez cet article et <ph name="OTHER_ARTICLE_COUNT" /> autres.</translation>
<translation id="2587841377698384444">ID de l'API d'annuaire :</translation>
<translation id="2597378329261239068">Ce document est protégé par mot de passe. Veuillez saisir ce dernier.</translation>
<translation id="2609632851001447353">Variantes</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Exécuter les diagnostics de connectivité<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">Supprimer les éléments sélectionnés</translation>
+<translation id="277133753123645258">Mode d'expédition</translation>
<translation id="277499241957683684">Enregistrement de l'appareil manquant.</translation>
<translation id="2784949926578158345">La connexion a été réinitialisée.</translation>
<translation id="2794233252405721443">Site bloqué</translation>
-<translation id="2812680587231492111">Cette option d'enlèvement n'est pas disponible. Essayez une autre option.</translation>
<translation id="2824775600643448204">Barre d'adresse et de recherche</translation>
<translation id="2826760142808435982">La connexion est chiffrée et authentifiée avec la clé <ph name="CIPHER" />. La méthode d'échange de clés utilisé est <ph name="KX" />.</translation>
<translation id="2835170189407361413">Effacer le formulaire</translation>
-<translation id="2849041323157393173">Cette option de livraison n'est pas disponible. Essayez une autre option.</translation>
<translation id="2889159643044928134">Ne pas actualiser</translation>
<translation id="2900469785430194048">Google Chrome n'avait pas suffisamment de mémoire pour afficher cette page Web.</translation>
<translation id="2909946352844186028">Un changement de réseau a été détecté.</translation>
<translation id="2916038427272391327">Fermez les autres programmes</translation>
<translation id="2922350208395188000">Impossible de vérifier le certificat du serveur.</translation>
+<translation id="2928905813689894207">Adresse de facturation</translation>
<translation id="2948083400971632585">Vous pouvez désactiver tout proxy configuré pour une connexion à partir de la page des paramètres.</translation>
<translation id="2955913368246107853">Fermer la barre de recherche</translation>
<translation id="2958431318199492670">La configuration du réseau ne respecte pas les normes de l'ONC. Il est possible que des parties de la configuration ne soient pas importées.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">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. Comme l'horloge de votre appareil est incorrecte, Google Chrome n'est pas en mesure de vérifier la validité des certificats.</translation>
<translation id="2972581237482394796">&amp;Rétablir</translation>
<translation id="2985306909656435243">Si cette option est activée, Chromium enregistre une copie de votre carte sur cet appareil pour vous permettre de remplir plus rapidement les formulaires.</translation>
+<translation id="2985398929374701810">Saisissez une adresse valide</translation>
+<translation id="2986368408720340940">Mode d'enlèvement non disponible. Choisissez-en un autre.</translation>
<translation id="2991174974383378012">Partage avec les sites Web</translation>
<translation id="3005723025932146533">Afficher la copie enregistrée</translation>
<translation id="3008447029300691911">Saisissez le code CVC de la carte <ph name="CREDIT_CARD" />. Une fois la validation terminée, les informations relatives à la carte seront partagées avec ce site.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{au moins 1 élément sur les appareils synchronisés}=1{1 élément (et plus sur appareils synchronisés)}one{# élément (et plus sur appareils synchronisés)}other{# éléments (et plus sur appareils synchronisés)}}</translation>
<translation id="3041612393474885105">Informations relatives au certificat</translation>
<translation id="3063697135517575841">Impossible de valider votre carte dans Chrome pour le moment. Veuillez réessayer plus tard.</translation>
+<translation id="3064966200440839136">En payant via une application externe, vous allez quitter le mode navigation privée. Voulez-vous continuer ?</translation>
<translation id="3093245981617870298">Vous êtes actuellement hors connexion</translation>
<translation id="3105172416063519923">ID d'élément :</translation>
<translation id="3109728660330352905">Vous n'êtes pas autorisé à consulter cette page.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Essayez d'exécuter les diagnostics de connectivité<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Échec du décodage de la réponse.</translation>
-<translation id="3149891296864842641">Option d'expédition</translation>
<translation id="3150653042067488994">Erreur temporaire du serveur.</translation>
+<translation id="3154506275960390542">Cette page inclut un formulaire dont la transmission n'est peut-être pas sécurisée. Les données envoyées pourront être vues par d'autres personnes pendant leur transfert ou modifiées par un pirate informatique afin de changer le message reçu par le serveur.</translation>
<translation id="3157931365184549694">Restaurer</translation>
<translation id="3167968892399408617">Les pages consultées dans les onglets de navigation privée ne sont pas enregistrées dans l'historique de votre navigateur, dans les cookies ni dans l'historique des recherches une fois que vous avez fermé tous les onglets de navigation privée. Les fichiers téléchargés et les favoris ajoutés sont conservés.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Impossible d'envoyer votre demande d'accès au site à <ph name="NAME" />. Veuillez réessayer.</translation>
<translation id="3355823806454867987">Modifier les paramètres du proxy...</translation>
<translation id="3369192424181595722">Erreur de l'horloge</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> autres éléments…</translation>
<translation id="337363190475750230">Révoqué</translation>
<translation id="3377188786107721145">Erreur d'analyse de la règle.</translation>
<translation id="3380365263193509176">Erreur inconnue.</translation>
<translation id="3380864720620200369">ID client :</translation>
<translation id="3391030046425686457">Adresse de livraison</translation>
+<translation id="3395827396354264108">Mode d'enlèvement</translation>
<translation id="340013220407300675">Il se peut que des pirates soient en train d'essayer de dérober vos informations sur le site <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (par exemple, des mots de passe, des messages ou des informations sur vos cartes de paiement).</translation>
<translation id="3422248202833853650">Essayez de fermer les autres programmes pour libérer de la mémoire.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> est actuellement inaccessible.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">Mastercard</translation>
<translation id="3452404311384756672">Intervalle de récupération :</translation>
<translation id="3462200631372590220">Masquer les paramètres avancés</translation>
+<translation id="3467763166455606212">Nom du titulaire de la carte obligatoire</translation>
+<translation id="3478058380795961209">Mois d'expiration</translation>
<translation id="3479539252931486093">S'agit-il d'une erreur inattendue ? <ph name="BEGIN_LINK" />Signalez-nous ce problème.<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Pas maintenant</translation>
<translation id="348000606199325318">Identifiant de plantage <ph name="CRASH_LOCAL_ID" /> (identifiant de serveur : <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Impossible de joindre votre parent pour le moment. Veuillez réessayer.</translation>
<translation id="3528171143076753409">Le certificat du serveur n'est pas approuvé.</translation>
-<translation id="3538531656504267329">Année d'expiration non valide</translation>
<translation id="3539171420378717834">Conserver une copie de cette carte sur cet appareil</translation>
<translation id="3542684924769048008">Utiliser un mot de passe pour :</translation>
<translation id="3549644494707163724">Chiffrer toutes les données synchronisées avec votre propre phrase secrète de synchronisation</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Masquer les détails</translation>
<translation id="3587482841069643663">Tous</translation>
<translation id="3600246354004376029">"<ph name="TITLE" />", <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Saisissez une date d'expiration valide</translation>
<translation id="36224234498066874">Effacer les données de navigation...</translation>
<translation id="362276910939193118">Afficher l'historique complet</translation>
<translation id="3623476034248543066">Afficher la valeur</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Mot de passe :</translation>
<translation id="3696411085566228381">aucune</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Sélectionnez une adresse de livraison pour consulter les modes d'expédition disponibles et les conditions applicables.</translation>
<translation id="370665806235115550">Chargement en cours...</translation>
<translation id="3712624925041724820">Licences épuisées.</translation>
<translation id="3714780639079136834">Activer les données mobiles ou le réseau Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Lien copié</translation>
<translation id="375403751935624634">Échec de la traduction en raison d'une erreur de serveur</translation>
<translation id="3759461132968374835">Aucune erreur n'a été signalée récemment. Les erreurs n'apparaissent ici que lorsque l'envoi de rapports d'erreur est activé.</translation>
+<translation id="3787705759683870569">Expire en <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Si vous utilisez un serveur proxy…</translation>
<translation id="3828924085048779000">La phrase secrète est obligatoire.</translation>
<translation id="3845539888601087042">Affichage de l'historique des appareils auxquels vous êtes connecté. <ph name="BEGIN_LINK" />En savoir plus<ph name="END_LINK" /></translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Voulez-vous que cette carte soit enregistrée dans Chromium ?</translation>
<translation id="4171400957073367226">Signature de validation non valide.</translation>
-<translation id="4176463684765177261">Désactivé</translation>
<translation id="4196861286325780578">&amp;Rétablir le déplacement</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Vérifier les configurations du pare-feu et de l'antivirus<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{aucune}=1{1 application ($1)}=2{2 applications ($1, $2)}one{# application ($1, $2 $3)}other{# applications ($1, $2 $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">résultats de recherche</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> n'a pas accepté votre certificat de connexion, ou vous ne l'avez pas fourni.</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="4446242550670694251">Vous pouvez désormais parcourir le Web de manière anonyme, et les autres utilisateurs de cet appareil ne verront pas votre activité.</translation>
<translation id="4492190037599258964">Résultats de recherche pour "<ph name="SEARCH_STRING" />"</translation>
<translation id="4506176782989081258">Erreur de validation : <ph name="VALIDATION_ERROR" />.</translation>
<translation id="4506599922270137252">Contacter l'administrateur système</translation>
<translation id="450710068430902550">Partage avec l'administrateur</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="4522570452068850558">Détails</translation>
<translation id="4558551763791394412">Essayez de désactiver les extensions.</translation>
<translation id="457875822857220463">Livraison</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Ajuster à la page</translation>
<translation id="483020001682031208">Aucune page Web physique à afficher</translation>
<translation id="4850886885716139402">Afficher</translation>
+<translation id="4854362297993841467">Mode de livraison non disponible. Choisissez-en un autre.</translation>
<translation id="4858792381671956233">Une demande d'autorisation a été envoyée à tes parents pour la consultation de ce site</translation>
<translation id="4880827082731008257">Rechercher dans l'historique</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Cette page rédigée dans une langue non identifiée a été traduite en <ph name="LANGUAGE_LANGUAGE" />.</translation>
<translation id="4923459931733593730">Paiement</translation>
<translation id="4926049483395192435">Doit être spécifié.</translation>
-<translation id="4941291666397027948">* indique un champ obligatoire</translation>
<translation id="495170559598752135">Actions</translation>
<translation id="4958444002117714549">Développer la liste</translation>
<translation id="4962322354953122629">Impossible de vérifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sécurité n'est pas considéré comme fiable par Chrome. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -439,12 +450,13 @@
<translation id="5045550434625856497">Mot de passe incorrect</translation>
<translation id="5056549851600133418">Articles pour vous</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Vérifier l'adresse du proxy<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Aucun cookie}=1{Un site utilise des cookies. }one{# site utilise des cookies. }other{# sites utilisent des cookies. }}</translation>
<translation id="5087286274860437796">Le certificat actuel du serveur n'est pas valide.</translation>
<translation id="5087580092889165836">Ajouter une carte</translation>
<translation id="5089810972385038852">État</translation>
<translation id="5095208057601539847">Province</translation>
<translation id="5115563688576182185">(64 bits)</translation>
-<translation id="5141240743006678641">Chiffrer les mots de passe synchronisés avec vos certificats Google</translation>
+<translation id="5141240743006678641">Chiffrer les mots de passe synchronisés avec vos informations de connexion Google</translation>
<translation id="514421653919133810">Ouvrez la page en mode navigation privée (Ctrl+Maj+N)</translation>
<translation id="5145883236150621069">Code d'erreur présent dans la réponse de la règle.</translation>
<translation id="5171045022955879922">Rechercher ou saisir une URL</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Afficher</translation>
<translation id="5308689395849655368">L'envoi de rapports d'erreur est désactivé.</translation>
<translation id="5317780077021120954">Enregistrer</translation>
-<translation id="5326702247179446998">Veuillez indiquer un destinataire</translation>
<translation id="5327248766486351172">Nom</translation>
<translation id="5337705430875057403">Les individus malveillants à l'œuvre sur le site <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> pourraient tenter de vous inciter à effectuer des opérations dangereuses, telles que l'installation d'un logiciel ou la révélation d'informations personnelles (par exemple des mots de passe, des numéros de téléphone ou des numéros de carte de paiement).</translation>
-<translation id="53553865750799677">Adresse d'enlèvement non acceptée. Sélectionnez une autre adresse.</translation>
<translation id="5359637492792381994">Impossible de vérifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sécurité actuel n'est pas valide. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Échec du stockage des paramètres de la règle.</translation>
<translation id="5386426401304769735">La chaîne de certificats de ce site contient un certificat signé avec SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">Une page intégrée à l'adresse <ph name="SITE" /> indique :</translation>
<translation id="5556459405103347317">Actualiser</translation>
<translation id="5565735124758917034">Actif</translation>
+<translation id="5571083550517324815">Enlèvement impossible à cette adresse. Sélectionnez-en une autre.</translation>
<translation id="5572851009514199876">Veuillez démarrer Chrome et vous connecter à votre compte pour que le navigateur puisse vérifier que vous êtes autorisé à accéder à ce site.</translation>
-<translation id="5575380383496039204">Adresse de livraison non acceptée. Sélectionnez une autre adresse.</translation>
<translation id="5580958916614886209">Veuillez vérifier le mois d'expiration, puis réessayer</translation>
<translation id="560412284261940334">Gestion non acceptée.</translation>
<translation id="5610142619324316209">Vérifier la connexion</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">L'identité de ce site Web n'a pas été vérifiée.</translation>
<translation id="5720705177508910913">Utilisateur actuel</translation>
<translation id="5732392974455271431">Tes parents peuvent te le débloquer</translation>
-<translation id="57586589942790530">Numéro de carte incorrect</translation>
+<translation id="5763042198335101085">Saisissez une adresse e-mail valide</translation>
+<translation id="5765072501007116331">Sélectionnez une adresse pour consulter les modes et conditions de livraison disponibles</translation>
<translation id="5784606427469807560">Un problème est survenu lors de la validation de votre carte. Vérifiez votre connexion Internet, puis réessayez.</translation>
<translation id="5785756445106461925">De plus, cette page inclut d'autres ressources qui ne sont pas sécurisées. Ces ressources peuvent être consultées par des tiers pendant leur transfert, et modifiées par un pirate informatique dans le but de changer l'aspect de cette page.</translation>
<translation id="5786044859038896871">Souhaitez-vous indiquer vos informations de carte de paiement ?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">Ce site est inaccessible</translation>
<translation id="5869522115854928033">Mots de passe enregistrés</translation>
<translation id="5872918882028971132">Suggestions des parents</translation>
-<translation id="587760065310675640">Adresse de destination non acceptée. Sélectionnez une autre adresse.</translation>
<translation id="5901630391730855834">Jaune</translation>
-<translation id="59174027418879706">Activée</translation>
<translation id="5926846154125914413">Vous risquez de ne plus avoir accès au contenu premium de certains sites.</translation>
<translation id="5959728338436674663">Envoyer automatiquement <ph name="BEGIN_WHITEPAPER_LINK" />des informations système et du contenu de page<ph name="END_WHITEPAPER_LINK" /> à Google afin de faciliter la détection d'applications et de sites dangereux. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Semaine</translation>
<translation id="5967867314010545767">Supprimer de l'historique</translation>
<translation id="5975083100439434680">Zoom arrière</translation>
+<translation id="598637245381783098">Impossible d'ouvrir l'application de paiement</translation>
<translation id="5989320800837274978">Aucun serveur proxy déterminé ou URL de script .pac n'a été indiqué.</translation>
<translation id="5990559369517809815">Les requêtes vers le serveur ont été bloquées par une extension.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Les cartes et les adresses proposées proviennent de Chrome. Vous pouvez les gérer dans les <ph name="BEGIN_LINK" />paramètres<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Page 1}one{Page #}other{Page #}}</translation>
<translation id="6017514345406065928">Vert</translation>
+<translation id="6027201098523975773">Saisissez un nom</translation>
<translation id="6040143037577758943">Fermer</translation>
-<translation id="604124094241169006">Automatique</translation>
<translation id="6042308850641462728">Plus</translation>
<translation id="6060685159320643512">Attention, ces fonctionnalités expérimentales peuvent mordre.</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{aucun}=1{1}one{#}other{#}}</translation>
@@ -543,9 +552,10 @@
ou tout autre périphérique réseau utilisé.</translation>
<translation id="614940544461990577">Essayez les suggestions ci-dessous :</translation>
<translation id="6151417162996330722">La durée de validité du certificat du serveur est trop longue.</translation>
-<translation id="615643356032862689">Les fichiers téléchargés et les favoris seront conservés.</translation>
+<translation id="6157877588268064908">Sélectionnez une adresse pour consulter les modes et conditions d'expédition disponibles</translation>
<translation id="6165508094623778733">En savoir plus</translation>
<translation id="6177128806592000436">Votre connexion à ce site n'est pas sécurisée.</translation>
+<translation id="6184817833369986695">(cohorte : <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Vérifiez votre connexion Internet</translation>
<translation id="6218753634732582820">Supprimer l'adresse de Chromium ?</translation>
<translation id="6251924700383757765">Règles de confidentialité</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Rétablir la réorganisation</translation>
<translation id="6263376278284652872">Favoris de <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Retour à la sécurité</translation>
+<translation id="6276112860590028508">Les pages de votre liste de lecture s'affichent ici</translation>
+<translation id="6280223929691119688">Impossible de livrer à cette adresse. Sélectionnez-en une autre.</translation>
<translation id="6282194474023008486">Code postal</translation>
<translation id="6290238015253830360">Vos articles suggérés s'affichent ici</translation>
<translation id="6305205051461490394"><ph name="URL" /> est inaccessible.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Impossible de vérifier si le certificat a été révoqué.</translation>
<translation id="6433490469411711332">Modifier les coordonnées</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> n'autorise pas la connexion.</translation>
-<translation id="6443118737398455446">La date d'expiration n'est pas valide</translation>
<translation id="6446608382365791566">Ajouter d'autres informations</translation>
<translation id="6451458296329894277">Confirmer le nouvel envoi du formulaire</translation>
<translation id="6456339708790392414">Votre paiement</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Impossible de vérifier que ce serveur est bien <ph name="DOMAIN" />, car 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. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">Règles relatives aux appareils</translation>
<translation id="6477321094435799029">Chrome a détecté un code inhabituel sur cette page et a bloqué cette dernière pour protéger vos informations personnelles (mots de passe, numéros de téléphone et de cartes de paiement).</translation>
-<translation id="6477460825583319731">Adresse e-mail non valide</translation>
<translation id="6489534406876378309">Lancer l'importation des plantages</translation>
<translation id="6508722015517270189">Relancez Chrome</translation>
-<translation id="6525462735697194615">Mois d'expiration non valide</translation>
<translation id="6529602333819889595">&amp;Rétablir la suppression</translation>
<translation id="6534179046333460208">Suggestions pour le Web physique</translation>
<translation id="6550675742724504774">Options</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685">Recherche <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Cette règle est obsolète.</translation>
<translation id="6652240803263749613">Impossible de vérifier que ce serveur est bien <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. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="6665267558048410100">Cette option d'expédition n'est pas disponible. Choisissez-en une autre.</translation>
<translation id="6671697161687535275">Supprimer la suggestion de saisie de formulaire de Chromium ?</translation>
<translation id="6685834062052613830">Déconnectez-vous et complétez la configuration.</translation>
<translation id="6710213216561001401">Précédent</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Le serveur proxy présente une erreur, ou l'adresse est incorrecte.</translation>
<translation id="6727102863431372879">Définir</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{aucun}=1{1 élément}one{# élément}other{# éléments}}</translation>
-<translation id="6743044928064272573">Option d'enlèvement</translation>
<translation id="674375294223700098">Erreur inconnue liée au certificat du serveur.</translation>
<translation id="6753269504797312559">Valeur de la règle</translation>
<translation id="6757797048963528358">Votre appareil s'est mis en veille.</translation>
<translation id="6778737459546443941">Tes parents ne l'ont pas encore autorisé</translation>
<translation id="6810899417690483278">ID de la personnalisation</translation>
<translation id="6820686453637990663">Cryptogramme</translation>
+<translation id="6824266427216888781">Échec du chargement des données relatives aux régions</translation>
<translation id="6831043979455480757">Traduire</translation>
<translation id="6839929833149231406">Région</translation>
<translation id="6874604403660855544">&amp;Rétablir l'ajout</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Carte validée</translation>
<translation id="6897140037006041989">Agent utilisateur</translation>
<translation id="6915804003454593391">Utilisateur :</translation>
+<translation id="6948701128805548767">Sélectionnez une adresse pour consulter les modes et conditions d'enlèvement disponibles</translation>
<translation id="6957887021205513506">Le certificat du serveur semble être contrefait.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Périphérique</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">Les serveurs proxy déterminés et une URL de script .pac sont spécifiés tous les deux.</translation>
<translation id="6989763994942163495">Afficher les paramètres avancés…</translation>
<translation id="7000990526846637657">Aucune entrée d'historique trouvée</translation>
-<translation id="7001663382399377034">Ajouter un destinataire</translation>
<translation id="7009986207543992532">Vous avez essayé d'accéder à <ph name="DOMAIN" />, mais la durée de validité du certificat du serveur est trop longue pour être fiable. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Votre compte Google conserve peut-être d'autres formes d'historique de navigation sur la page <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Ancien</translation>
<translation id="7090678807593890770">Effectuez une recherche Google sur <ph name="LINK" />.</translation>
<translation id="7119414471315195487">Fermez les autres onglets ou programmes</translation>
+<translation id="7129409597930077180">Impossible d'expédier à cette adresse. Sélectionnez-en une autre.</translation>
+<translation id="7138472120740807366">Mode de livraison</translation>
<translation id="7139724024395191329">Émirat</translation>
<translation id="7155487117670177674">Paiement non sécurisé</translation>
<translation id="7179921470347911571">Relancer maintenant</translation>
<translation id="7180611975245234373">Actualiser</translation>
<translation id="7182878459783632708">Aucune règle n'est définie</translation>
<translation id="7186367841673660872">Cette page en<ph name="ORIGINAL_LANGUAGE" />a été traduite en<ph name="LANGUAGE_LANGUAGE" /></translation>
+<translation id="7192203810768312527">Libère <ph name="SIZE" />. Le chargement de certains sites est susceptible d'être plus lent lors de votre visite suivante.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ne respecte pas les normes de sécurité.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />En savoir plus<ph name="END_LINK" /> sur ce problème.</translation>
@@ -675,7 +686,6 @@ Conseil : Le mode navigation privée (<ph name="SHORTCUT_KEY" />) pourra vous Ã
<translation id="7424977062513257142">Une page intégrée à cette page Web indique :</translation>
<translation id="7441627299479586546">Objet de la règle incorrect.</translation>
<translation id="7444046173054089907">Ce site est bloqué</translation>
-<translation id="7444238235002594607">Sélectionnez une adresse d'enlèvement pour consulter les modes d'enlèvement disponibles et les conditions applicables.</translation>
<translation id="7445762425076701745">Impossible de valider entièrement l'identité du serveur auquel vous êtes connecté. Le nom utilisé pour cette connexion n'est valide que sur votre réseau et aucune autorité de certification externe ne peut en vérifier la propriété. Certaines autorités de certification délivrent tout de même des certificats pour ces types de nom, par conséquent nous ne sommes pas en mesure de vérifier que vous êtes connecté au site voulu et non à un site malveillant.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />En savoir plus<ph name="END_LINK" /> sur ce problème.</translation>
<translation id="7460163899615895653">Les onglets que vous avez utilisés récemment sur d'autres appareils s'affichent ici</translation>
@@ -719,6 +729,7 @@ Conseil : Le mode navigation privée (<ph name="SHORTCUT_KEY" />) pourra vous Ã
<translation id="7755287808199759310">Ton parent peut te le débloquer</translation>
<translation id="7758069387465995638">Il est possible qu'un pare-feu ou un logiciel antivirus ait bloqué la connexion.</translation>
<translation id="7761701407923456692">Le certificat du serveur ne correspond pas à l'URL.</translation>
+<translation id="7763386264682878361">Analyseur du fichier manifeste du paiement</translation>
<translation id="7764225426217299476">Ajouter une adresse</translation>
<translation id="777702478322588152">Préfecture</translation>
<translation id="7791543448312431591">Ajouter</translation>
@@ -732,6 +743,7 @@ Conseil : Le mode navigation privée (<ph name="SHORTCUT_KEY" />) pourra vous Ã
<translation id="785549533363645510">Cependant, cela ne vous rend pas invisible. Si vous passez en mode navigation privée, votre employeur, votre fournisseur d'accès à Internet ou les sites Web que vous consultez pourront toujours avoir accès à votre historique de navigation.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> : <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Veuillez vérifier votre code CVC et réessayer.</translation>
+<translation id="79338296614623784">Saisissez un numéro de téléphone valide</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Le certificat du serveur n'est pas encore valide.</translation>
<translation id="7942349550061667556">Rouge</translation>
@@ -751,6 +763,7 @@ Conseil : Le mode navigation privée (<ph name="SHORTCUT_KEY" />) pourra vous Ã
<translation id="8088680233425245692">Échec de l'affichage de l'article.</translation>
<translation id="8089520772729574115">moins de 1 Mo</translation>
<translation id="8091372947890762290">Activation en attente sur le serveur.</translation>
+<translation id="8118489163946903409">Mode de paiement</translation>
<translation id="8131740175452115882">Confirmer</translation>
<translation id="8134994873729925007">Impossible de trouver l'<ph name="BEGIN_ABBR" />adresse DNS<ph name="END_ABBR" /> du serveur <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Votre ordinateur s'est mis en veille.</translation>
@@ -776,6 +789,7 @@ Conseil : Le mode navigation privée (<ph name="SHORTCUT_KEY" />) pourra vous Ã
<translation id="8349305172487531364">Barre de favoris</translation>
<translation id="8363502534493474904">Désactiver le mode Avion</translation>
<translation id="8364627913115013041">Non définie</translation>
+<translation id="8368476060205742148">Services Google Play</translation>
<translation id="8380941800586852976">Dangereux</translation>
<translation id="8382348898565613901">Vos favoris récemment consultés s'affichent ici</translation>
<translation id="8398259832188219207">Rapport d'erreur importé le <ph name="UPLOAD_TIME" /></translation>
@@ -784,31 +798,29 @@ Conseil : Le mode navigation privée (<ph name="SHORTCUT_KEY" />) pourra vous Ã
<translation id="8428213095426709021">Paramètres</translation>
<translation id="8433057134996913067">Vous serez déconnecté de la plupart des sites.</translation>
<translation id="8437238597147034694">&amp;Annuler le déplacement</translation>
-<translation id="8456681095658380701">Ce nom n'est pas valide.</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 carte de paiement}one{# carte de paiement}other{# cartes de paiement}}</translation>
<translation id="8483780878231876732">Pour utiliser les cartes de votre compte Google, connectez-vous à Chrome.</translation>
<translation id="8488350697529856933">S'applique à</translation>
-<translation id="8492969205326575646">Type de carte non accepté</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> a mis trop de temps à répondre.</translation>
<translation id="852346902619691059">Impossible de vérifier que ce serveur est bien <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. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="8532105204136943229">Année d'expiration</translation>
<translation id="8543181531796978784">Vous pouvez <ph name="BEGIN_ERROR_LINK" />signaler un problème de détection<ph name="END_ERROR_LINK" />. Si vous avez compris les risques auxquels vous vous exposez, vous pouvez <ph name="BEGIN_LINK" />consulter ce site dangereux<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">La traduction a échoué, car nous n'avons pas pu déterminer la langue de la page.</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="8570229484593575558">Les informations suivantes |ne seront pas enregistrées| :#Votre historique de navigation#Vos recherches#Les données des cookies</translation>
<translation id="8571890674111243710">Traduction de la page en <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Votre activité |peut rester visible| pour :#les sites Web que vous consultez ;#votre employeur ;#votre fournisseur d'accès à Internet.</translation>
<translation id="858637041960032120">Saisir num tél</translation>
<translation id="859285277496340001">Le certificat n'indique aucun mécanisme permettant de vérifier s'il a été révoqué.</translation>
<translation id="8620436878122366504">Tes parents ne l'ont pas encore autorisé</translation>
<translation id="8647750283161643317">Rétablir tous les tests par défaut</translation>
<translation id="8703575177326907206">Votre connexion à <ph name="DOMAIN" /> n'est pas chiffrée.</translation>
+<translation id="8718314106902482036">Paiement non finalisé</translation>
<translation id="8725066075913043281">Réessayer</translation>
<translation id="8728672262656704056">Vous êtes passé en mode navigation privée</translation>
<translation id="8730621377337864115">OK</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="8759274551635299824">Carte arrivée à expiration</translation>
<translation id="8790007591277257123">&amp;Rétablir la suppression</translation>
-<translation id="8798099450830957504">Par défaut</translation>
<translation id="8800988563907321413">Vos suggestions à proximité s'affichent ici</translation>
<translation id="8820817407110198400">Favoris</translation>
<translation id="883848425547221593">Autres favoris</translation>
@@ -818,6 +830,7 @@ Conseil : Le mode navigation privée (<ph name="SHORTCUT_KEY" />) pourra vous Ã
<translation id="8866481888320382733">Erreur d'analyse des paramètres de la règle.</translation>
<translation id="8866959479196209191">Cette page indique :</translation>
<translation id="8870413625673593573">Récemment fermés</translation>
+<translation id="8874824191258364635">Saisissez un numéro de carte valide</translation>
<translation id="8876793034577346603">Échec de l'analyse de la configuration du réseau.</translation>
<translation id="8877192140621905067">Une fois la validation terminée, les informations relatives à votre carte seront partagées avec ce site.</translation>
<translation id="8889402386540077796">Teinte</translation>
@@ -827,7 +840,6 @@ Conseil : Le mode navigation privée (<ph name="SHORTCUT_KEY" />) pourra vous Ã
<translation id="8931333241327730545">Voulez-vous enregistrer cette carte dans votre compte Google ?</translation>
<translation id="8932102934695377596">Votre horloge est en retard</translation>
<translation id="8954894007019320973">(suite)</translation>
-<translation id="895548565263634352">Lire les articles de <ph name="ARTICLE_PUBLISHER" /> et <ph name="OTHER_ARTICLE_COUNT" /> autres</translation>
<translation id="8971063699422889582">Le certificat du serveur a expiré.</translation>
<translation id="8986494364107987395">Envoyer automatiquement les statistiques d'utilisation et les rapports d'erreur à Google</translation>
<translation id="8987927404178983737">Mois</translation>
@@ -845,7 +857,6 @@ Conseil : Le mode navigation privée (<ph name="SHORTCUT_KEY" />) pourra vous Ã
<translation id="9068849894565669697">Sélectionner couleur</translation>
<translation id="9076283476770535406">Il est possible qu'il comporte du contenu réservé aux adultes</translation>
<translation id="9078964945751709336">Veuillez fournir d'autres informations</translation>
-<translation id="9094175695478007090">Impossible de lancer l'application de paiement.</translation>
<translation id="9103872766612412690">Un chiffrement est normalement utilisé sur le site <ph name="SITE" /> pour protéger vos informations. Lors de la dernière tentative de connexion de Chromium au site <ph name="SITE" />, des identifiants inhabituels et incorrects ont été retournés. Il est possible qu'un individu malveillant tente de se faire passer pour <ph name="SITE" /> ou qu'un écran de connexion Wi-Fi ait interrompu la connexion. Vos informations restent sécurisées, car nous avons arrêté la connexion avant l'échange des données.</translation>
<translation id="9137013805542155359">Afficher l'original</translation>
<translation id="9137248913990643158">Veuillez démarrer Chrome et vous connecter à votre compte avant d'utiliser cette application</translation>
diff --git a/chromium/components/strings/components_strings_gu.xtb b/chromium/components/strings/components_strings_gu.xtb
index 7ee8aade4f1..c2942fce11b 100644
--- a/chromium/components/strings/components_strings_gu.xtb
+++ b/chromium/components/strings/components_strings_gu.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="gu">
<translation id="1008557486741366299">હમણાં નહીં</translation>
<translation id="1015730422737071372">અતિરિકà«àª¤ વિગતો પà«àª°àª¦àª¾àª¨ કરો</translation>
+<translation id="1021110881106174305">સà«àªµà«€àª•àª¾àª°à«‡àª² કારà«àª¡</translation>
<translation id="1032854598605920125">ઘડિયાળની દિશામાં ફેરવો</translation>
<translation id="1038842779957582377">અજà«àªžàª¾àª¤ નામ</translation>
<translation id="1050038467049342496">અનà«àª¯ àªàªªà«àª²àª¿àª•à«‡àª¶àª¨à«‹ બંધ કરો</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">મૂલà«àª¯ છà«àªªàª¾àªµà«‹</translation>
<translation id="1228893227497259893">ખોટો અસà«àª¤àª¿àª¤à«àªµ ઓળખકરà«àª¤àª¾</translation>
<translation id="1232569758102978740">શીરà«àª·àª• વિનાનà«àª‚</translation>
+<translation id="1263231323834454256">વાચન સૂચિ</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> ઠકà«àª°à«‡àª¶ રિપોરà«àªŸ કૅપà«àªšàª° કરવામાં આવી (હજી સà«àª§à«€ અપલોડ કરવામાં કે અવગણવામાં આવેલ નથી)</translation>
<translation id="1285320974508926690">આ સાઇટનà«àª‚ કà«àª¯àª¾àª°à«‡àª¯ ભાષાંતર કરશો નહીં</translation>
<translation id="129553762522093515">તાજેતરમાં બંધ કરેલા</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromium સà«àªµàª¤àªƒàª­àª°àª£ સેટિંગà«àª¸...</translation>
<translation id="1374468813861204354">સૂચનો</translation>
<translation id="1375198122581997741">વરà«àªàª¨ વિશે</translation>
+<translation id="1377321085342047638">કારà«àª¡ નંબર</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> ઠકોઈપણ ડેટા મોકલà«àª¯à«‹ ન હતો.</translation>
<translation id="1407135791313364759">બધà«àª‚ ખોલો</translation>
<translation id="1413809658975081374">ગોપનીયતા ભૂલ</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">ઇતિહાસ</translation>
<translation id="1645368109819982629">અસમરà«àª¥àª¿àª¤ પà«àª°à«‹àªŸà«‹àª•à«‹àª²</translation>
<translation id="1656489000284462475">પિકઅપ</translation>
+<translation id="1663943134801823270">કારà«àª¡ અને સરનામા Chromeમાંથી છે. તમે તેને <ph name="BEGIN_LINK" />સેટિંગà«àª¸<ph name="END_LINK" />માં સંચાલિત કરી શકો છો.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> સામાનà«àª¯ રીતે તમારી માહિતીને સà«àª°àª•à«àª·àª¿àª¤ રાખવા માટે àªàª¨à«àª•à«àª°àª¿àªªà«àª¶àª¨àª¨à«‹ ઉપયોગ કરે છે. જà«àª¯àª¾àª°à«‡ આ સમયે Google Chrome દà«àªµàª¾àª°àª¾ <ph name="SITE" /> થી કનેકà«àªŸ કરવાનો પà«àª°àª¯àª¾àª¸ થયો, તà«àª¯àª¾àª°à«‡ વેબસાઇટે અસામાનà«àª¯ અને ખોટા ઓળખાણપતà«àª°à«‹àª¨à«‡ પાછા મોકલà«àª¯àª¾àª‚. આવà«àª‚ તà«àª¯àª¾àª°à«‡ થઇ શકે જà«àª¯àª¾àª°à«‡ કોઈ હà«àª®àª²àª¾àª–ોર <ph name="SITE" /> હોવાનો ડોળ કરવાનો પà«àª°àª¯àª¾àª¸ કરી રહà«àª¯à«‹ હોય અથવા કોઈ Wi-Fi સાઇન-ઇન સà«àª•à«àª°à«€àª¨à«‡ કનેકà«àª¶àª¨àª®àª¾àª‚ વિકà«àª·à«‡àªª પાડà«àª¯à«‹ હોય. તમારી માહિતી હજી પણ સà«àª°àª•à«àª·àª¿àª¤ છે કારણ કે Google Chrome ઠકોઈપણ ડેટા વિનિમય થાય તે પહેલાં જ કનેકà«àª¶àª¨ રોકી દીધà«àª‚.</translation>
<translation id="168328519870909584"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> પરનાં હà«àª®àª²àª¾àª–ોરો તમારા ઉપકરણ પર તમારી માહિતી (ઉદાહરણ તરીકે, ફોટા, પાસવરà«àª¡à«àª¸, સંદેશા અને કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡à«àª¸) ચોરી અથવા કાઢી નાખી શકે તેવી જોખમકારક àªàªªà«àª²àª¿àª•à«‡àª¶àª¨à«‹ ઇનà«àª¸à«àªŸà«‹àª² કરવાનો પà«àª°àª¯àª¤à«àª¨ કરી શકે.</translation>
<translation id="168841957122794586">સરà«àªµàª° પà«àª°àª®àª¾àª£àªªàª¤à«àª° àªàª• નબળી કà«àª°àª¿àªªà«àªŸà«‹àª—à«àª°àª¾àª«àª¿àª• કી ધરાવે છે.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">આ સાઇટની મà«àª²àª¾àª•àª¾àª¤ લેવા માટે તમને <ph name="NAME" /> ની પરવાનગીની જરૂર છે</translation>
+<translation id="1721424275792716183">* ફીલà«àª¡ આવશà«àª¯àª• છે</translation>
<translation id="1728677426644403582">તમે વેબ પૃષà«àª àª¨à«‹ સà«àª°à«‹àª¤ જોઈ રહà«àª¯àª¾àª‚ છો</translation>
+<translation id="173080396488393970">આ પà«àª°àª•àª¾àª°àª¨à«àª‚ કારà«àª¡ સમરà«àª¥àª¿àª¤ નથી</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">સિસà«àªŸàª® વà«àª¯àªµàª¸à«àª¥àª¾àªªàª•àª¨à«‹ સંપરà«àª• કરવાનો પà«àª°àª¯àª¾àª¸ કરો.</translation>
+<translation id="1740951997222943430">àªàª• માનà«àª¯ સમાપà«àª¤àª¿ મહિનો દાખલ કરો</translation>
<translation id="1745358365027406341">પૃષà«àª àª¨à«‡ પછીથી ડાઉનલોડ કરો</translation>
<translation id="17513872634828108">ટેબà«àª¸ ખોલો</translation>
<translation id="1753706481035618306">પૃષà«àª  નંબર</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">કૃપા કરી તમારા સમનà«àªµàª¯àª¨ પાસફà«àª°à«‡àªàª¨à«‡ અપડેટ કરો.</translation>
<translation id="1787142507584202372">તમારા ખà«àª²à«àª²àª¾ ટૅબà«àª¸ અહીં દેખાય છે</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">વિતરણ પદà«àª§àª¤àª¿àª“ અને આવશà«àª¯àª•àª¤àª¾àª“ તપાસવા વિતરણ માટેનà«àª‚ સરનામà«àª‚ પસંદ કરો.</translation>
+<translation id="1803264062614276815">કારà«àª¡àª§àª¾àª°àª•àª¨à«àª‚ નામ</translation>
<translation id="1803678881841855883">Google સલામત બà«àª°àª¾àª‰àªàª¿àª‚ગને <ph name="SITE" /> પર <ph name="BEGIN_LINK" />માલવેર મળà«àª¯à«àª‚<ph name="END_LINK" />. વેબસાઇટà«àª¸ કે જે સામાનà«àª¯ રીતે સà«àª°àª•à«àª·àª¿àª¤ હોય છે તે કà«àª¯àª¾àª°à«‡àª• માલવેરથી દૂષિત હોય છે. દà«àª°à«àª­àª¾àªµàª¨àª¾àªªà«‚રà«àª£ સામગà«àª°à«€, <ph name="SUBRESOURCE_HOST" />, àªàª• જાણીતા માલવેર વિકà«àª°à«‡àª¤àª¾àª¥à«€ આવે છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440"><ph name="ADDED_TO_AUTOFILL_MONTH" /> ના રોજ ઉમેરà«àª¯à«àª‚</translation>
<translation id="1821930232296380041">અમાનà«àª¯ વિનંતી અથવા વિનંતી પરિમાણો</translation>
<translation id="1826516787628120939">તપાસી રહà«àª¯àª¾àª‚ છે</translation>
<translation id="1834321415901700177">આ સાઇટમાં હાનિકારક પà«àª°à«‹àª—à«àª°àª¾àª®à«àª¸ છે</translation>
<translation id="1842969606798536927">ચà«àª•àªµàª£à«€ કરો</translation>
-<translation id="1864455488461349376">વિતરણ માટેનો વિકલà«àªª</translation>
<translation id="1871208020102129563">પà«àª°à«‹àª•à«àª¸à«€ નિયત કરેલા પà«àª°à«‹àª•à«àª¸à«€ સરà«àªµàª°àª¨à«‹ ઉપયોગ કરવા માટે સેટ કરેલી છે, .pac સà«àª•à«àª°àª¿àªªà«àªŸ URL નથી.</translation>
<translation id="1871284979644508959">આવશà«àª¯àª• ફીલà«àª¡</translation>
<translation id="187918866476621466">સà«àªŸàª¾àª°à«àªŸàª…પ પૃષà«àª à«‹ ખોલો</translation>
<translation id="1883255238294161206">સૂચિ સંકà«àªšàª¿àª¤ કરો</translation>
<translation id="1898423065542865115">ફિલà«àªŸàª°àª¿àª‚ગ</translation>
<translation id="194030505837763158"><ph name="LINK" /> પર જાઓ</translation>
-<translation id="1946821392246652573">સà«àªµà«€àª•àª¾àª°àªµàª¾àª®àª¾àª‚ આવનાર કારà«àª¡à«àª¸</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> બà«àª•àª®àª¾àª°à«àª•à«àª¸</translation>
<translation id="1973335181906896915">અનà«àª•à«àª°àª®àª¾àª‚કન ભૂલ</translation>
<translation id="1974060860693918893">વિગતવાર</translation>
<translation id="1978555033938440688">ફરà«àª®àªµà«‡àª¯àª° સંસà«àª•àª°àª£</translation>
+<translation id="1995859865337580572">કૃપા કરીને તમારà«àª‚ CVC ચકાસો</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{અને 1 વધà«}one{અને # વધà«}other{અને # વધà«}}</translation>
-<translation id="2020194265157481222">કારà«àª¡ પરનà«àª‚ નામ આવશà«àª¯àª•</translation>
<translation id="2025186561304664664">પà«àª°à«‹àª•à«àª¸à«€ સà«àªµàª¤àªƒ ગોઠવાયેલી પર સેટ છે.</translation>
<translation id="2030481566774242610">શà«àª‚ તમારો અરà«àª¥ <ph name="LINK" /> છે?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />પà«àª°à«‹àª•à«àª¸à«€ અને ફાયરવોલ તપાસીને<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">આજે</translation>
<translation id="2154054054215849342">સમનà«àªµàª¯àª¨ તમારા ડોમેન માટે ઉપલબà«àª§ નથી.</translation>
<translation id="2154484045852737596">કારà«àª¡ સંપાદિત કરો</translation>
-<translation id="2156993118928861787">અમાનà«àª¯ સરનામà«àª‚</translation>
<translation id="2166049586286450108">સંપૂરà«àª£ વà«àª¯àªµàª¸à«àª¥àª¾àªªàª• àªàª•à«àª¸à«‡àª¸</translation>
<translation id="2166378884831602661">આ સાઇટ àªàª• સà«àª°àª•à«àª·àª¿àª¤ કનેકà«àª¶àª¨ આપી શકતી નથી</translation>
<translation id="2181821976797666341">નીતિઓ</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 સરનામà«àª‚}one{# સરનામાં}other{# સરનામાં}}</translation>
+<translation id="2202020181578195191">àªàª• માનà«àª¯ સમાપà«àª¤àª¿ વરà«àª· દાખલ કરો</translation>
<translation id="2212735316055980242">નીતિ મળી નથી</translation>
<translation id="2213606439339815911">પà«àª°àªµàª¿àª·à«àªŸàª¿àª“નà«àª‚ આનયન કરી રહà«àª¯àª¾àª‚ છે...</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />ડાયગà«àª¨à«‹àª¸à«àªŸàª¿àª•à«àª¸ àªàªªà«àª²àª¿àª•à«‡àª¶àª¨<ph name="END_LINK" />નો ઉપયોગ કરીને તમારà«àª‚ કનેકà«àª¶àª¨ ઠીક કરો</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">તમારી ઇનà«àªŸàª°àª¨à«‡àªŸ àªàª•à«àª¸à«‡àª¸ અવરોધિત છે</translation>
<translation id="230155334948463882">નવà«àª‚ કારà«àª¡?</translation>
<translation id="2305919008529760154">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° કપટપૂરà«àª£ રીતે જારી કરવામાં આવà«àª¯à«àª‚ હોઈ શકે છે. આ કદાચ કોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">કારà«àª¡à«àª¸ અને સરનામાં વિકલà«àªªà«‹, તમારા Google àªàª•àª¾àª‰àª¨à«àªŸ (<ph name="ACCOUNT_EMAIL" />) અને Chrome ના છે. તમે આને <ph name="BEGIN_LINK" />સેટિંગà«àª¸<ph name="END_LINK" />માં સંચાલિત કરી શકો છો.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> માટે વપરાશકરà«àª¤àª¾àª¨àª¾àª® અને પાસવરà«àª¡ આવશà«àª¯àª• છે.</translation>
<translation id="2318774815570432836">તમે અતà«àª¯àª¾àª°à«‡ <ph name="SITE" /> ની મà«àª²àª¾àª•àª¾àª¤ લઈ શકતાં નથી કારણ કે વેબસાઇટ HSTS નો ઉપયોગ કરે છે. નેટવરà«àª• ભૂલો અને હà«àª®àª²àª¾ સામાનà«àª¯ રીતે અસà«àª¥àª¾àª¯à«€ છે, તેથી આ પૃષà«àª  સંભવિત રૂપે પછીથી કારà«àª¯ કરશે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2354001756790975382">અનà«àª¯ બà«àª•àª®àª¾àª°à«àª•à«àª¸</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">àªàª¨à«àªŸàª°àªªà«àª°àª¾àª‡àª ડિફોલà«àªŸ</translation>
<translation id="2386255080630008482">સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° રદ કરવામાં આવà«àª¯à«àª‚ છે.</translation>
<translation id="2392959068659972793">કોઈ કિંમત સેટ નહીં સાથે નીતિઓ બતાવો</translation>
+<translation id="239429038616798445">આ વિતરણ પદà«àª§àª¤àª¿ ઉપલબà«àª§ નથી. કોઈ ભિનà«àª¨ પદà«àª§àª¤àª¿ અજમાવો.</translation>
<translation id="2396249848217231973">&amp;કાઢી નાખવà«àª‚ પૂરà«àªµàªµàª¤à«â€Œ કરો</translation>
<translation id="2460160116472764928">Google સલામત બà«àª°àª¾àª‰àªàª¿àª‚ગને તાજેતરમાં <ph name="SITE" /> પર <ph name="BEGIN_LINK" />માલવેર મળà«àª¯à«àª‚<ph name="END_LINK" />. વેબસાઇટà«àª¸ કે જે સામાનà«àª¯ રીતે સà«àª°àª•à«àª·àª¿àª¤ હોય છે તે કà«àª¯àª¾àª°à«‡àª• માલવેરથી દૂષિત હોય છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">ભરો</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />નેટવરà«àª• ડાયગà«àª¨à«‹àª¸à«àªŸàª¿àª•à«àª¸ ચલાવી રહà«àª¯àª¾àª‚ છે<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">અમાનà«àª¯ શોધ URL.</translation>
<translation id="2491120439723279231">સરà«àªµàª°àª¨àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª®àª¾àª‚ ભૂલો છે.</translation>
-<translation id="24943777258388405">અમાનà«àª¯ ફોન નંબર</translation>
<translation id="2495083838625180221">JSON વિશà«àª²à«‡àª¶àª•</translation>
<translation id="2495093607237746763">જો ચેક કરેલà«àª‚ હોય, તો àªàª¡àªªàª¥à«€ ફોરà«àª® ભરવા માટે Chromium આ ઉપકરણ પર તમારા કારà«àª¡àª¨à«€ àªàª• કૉપિ સંગà«àª°àª¹àª¿àª¤ કરશે.</translation>
<translation id="2498091847651709837">નવà«àª‚ કારà«àª¡ સà«àª•à«…ન કરો</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> ઠઅમાનà«àª¯ પà«àª°àª¤àª¿àª¸àª¾àª¦ મોકલà«àª¯à«‹.</translation>
<translation id="2552545117464357659">વધૠનવà«àª‚</translation>
<translation id="2556876185419854533">&amp;સંપાદિત કરવà«àª‚ પૂરà«àªµàªµàª¤à«â€Œ કરો</translation>
+<translation id="2587730715158995865"><ph name="ARTICLE_PUBLISHER" /> તરફથી. આ અને અનà«àª¯ <ph name="OTHER_ARTICLE_COUNT" /> વારà«àª¤àª¾àª“ વાંચો.</translation>
<translation id="2587841377698384444">નિરà«àª¦à«‡àª¶àª¿àª•àª¾ API ID:</translation>
<translation id="2597378329261239068">આ દસà«àª¤àª¾àªµà«‡àªœ પાસવરà«àª¡ સà«àª°àª•à«àª·àª¿àª¤ છે. કૃપા કરીને પાસવરà«àª¡ દાખલ કરો.</translation>
<translation id="2609632851001447353">વૈવિધà«àª¯</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />કનેકà«àªŸàª¿àªµàª¿àªŸà«€ ડાયગà«àª¨à«‹àª¸à«àªŸàª¿àª•à«àª¸ ચલાવી રહà«àª¯àª¾àª‚ છે<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">ઓકે</translation>
<translation id="2742870351467570537">પસંદ કરેલી આઇટમà«àª¸àª¨à«‡ દૂર કરો</translation>
+<translation id="277133753123645258">વિતરણ પદà«àª§àª¤àª¿</translation>
<translation id="277499241957683684">ઉપકરણ રેકોરà«àª¡ ખૂટે છે</translation>
<translation id="2784949926578158345">કનેકà«àª¶àª¨ ફરીથી સેટ થયà«àª‚.</translation>
<translation id="2794233252405721443">સાઇટ અવરોધિત કરી</translation>
-<translation id="2812680587231492111">તે પિકઅપ વિકલà«àªª ઉપલબà«àª§ નથી. àªàª• અલગ વિકલà«àªª અજમાવો.</translation>
<translation id="2824775600643448204">સરનામà«àª‚ અને શોધ બાર</translation>
<translation id="2826760142808435982">કનેકà«àª¶àª¨ <ph name="CIPHER" /> નો ઉપયોગ કરીને àªàª¨à«àª•à«àª°àª¿àªªà«àªŸ અને પà«àª°àª®àª¾àª£àª¿àª¤ કરેલૠછે અને મà«àª–à«àª¯ àªàª•à«àª¸àªšà«‡àª¨à«àªœ મેકેનિàªà«àª® તરીકે <ph name="KX" /> નો ઉપયોગ કરે છે.</translation>
<translation id="2835170189407361413">ફોરà«àª® સાફ કરો</translation>
-<translation id="2849041323157393173">તે વિતરણ વિકલà«àªª ઉપલબà«àª§ નથી. àªàª• અલગ વિકલà«àªª અજમાવો.</translation>
<translation id="2889159643044928134">ફરીથી લોડ કરશો નહીં</translation>
<translation id="2900469785430194048">આ વેબ પૃષà«àª  પà«àª°àª¦àª°à«àª¶àª¿àª¤ કરવાનો પà«àª°àª¯àª¾àª¸ કરતી વખતે Google Chrome ની મેમરી સમાપà«àª¤ થઈ ગઈ.</translation>
<translation id="2909946352844186028">નેટવરà«àª• ફેરફાર મળà«àª¯à«‹ હતો.</translation>
<translation id="2916038427272391327">અનà«àª¯ પà«àª°à«‹àª—à«àª°àª¾àª® બંધ કરો</translation>
<translation id="2922350208395188000">સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° તપાસી શકાતà«àª‚ નથી.</translation>
+<translation id="2928905813689894207">બિલિંગનà«àª‚ સરનામà«àª‚</translation>
<translation id="2948083400971632585">તમે સેટિંગà«àª¸ પૃષà«àª àª®àª¾àª‚થી કનેકà«àª¶àª¨ માટે ગોઠવવામાં આવેલ કોઇપણ પà«àª°à«‹àª•à«àª¸à«€àª“ અકà«àª·àª® કરી શકો છો.</translation>
<translation id="2955913368246107853">શોધ બાર બંધ કરો</translation>
<translation id="2958431318199492670">નેટવરà«àª• ગોઠવણી ONC માનકનà«àª‚ પાલન કરતી નથી. ગોઠવણીના ભાગો આયાત કરી શકાશે નહીં.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">àªàª• સà«àª°àª•à«àª·àª¿àª¤ કનેકà«àª¶àª¨ સà«àª¥àª¾àªªàª¿àª¤ કરવા માટે, તમારી ઘડિયાળ યોગà«àª¯ રીતે સેટ હોવી જરૂરી છે. આનà«àª‚ કારણ ઠકે વેબસાઇટà«àª¸ તેઓને ઓળખવા માટે જે પà«àª°àª®àª¾àª£àªªàª¤à«àª°à«‹àª¨à«‹ ઉપયોગ કરે છે તે ચોકà«àª•àª¸ સમય અવધિ માટે જ માનà«àª¯ હોય છે. તમારા ઉપકરણની ઘડિયાળ ખોટી હોવાને લીધે, Google Chrome આ પà«àª°àª®àª¾àª£àªªàª¤à«àª°à«‹àª¨à«‡ ચકાસી શકતà«àª‚ નથી.</translation>
<translation id="2972581237482394796">&amp;ફરી કરો</translation>
<translation id="2985306909656435243">જો સકà«àª·àª® કરેલà«àª‚ હોય, તો àªàª¡àªªàª¥à«€ ફોરà«àª® ભરવા માટે Chromium આ ઉપકરણ પર તમારા કારà«àª¡àª¨à«€ àªàª• કૉપિ સંગà«àª°àª¹àª¿àª¤ કરશે.</translation>
+<translation id="2985398929374701810">àªàª• માનà«àª¯ સરનામà«àª‚ દાખલ કરો</translation>
+<translation id="2986368408720340940">આ પિકઅપ પદà«àª§àª¤àª¿ ઉપલબà«àª§ નથી. કોઈ ભિનà«àª¨ પદà«àª§àª¤àª¿ અજમાવો.</translation>
<translation id="2991174974383378012">વેબસાઇટà«àª¸ સાથે શેર કરવà«àª‚</translation>
<translation id="3005723025932146533">સાચવેલી કૉપિ બતાવો</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> માટે CVC દાખલ કરો. àªàª•àªµàª¾àª° તમે પà«àª·à«àªŸàª¿ કરી લો, તે પછી આ સાઇટ સાથે તમારા કારà«àª¡àª¨à«€ વિગતો શેર કરવામાં આવશે.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{સમનà«àªµàª¯àª¿àª¤ ઉપકરણો પર ઓછામાં ઓછી 1 આઇટમ}=1{1 આઇટમ (અને સમનà«àªµàª¯àª¿àª¤ ઉપકરણો પર વધà«)}one{# આઇટમ (અને સમનà«àªµàª¯àª¿àª¤ ઉપકરણો પર વધà«)}other{# આઇટમ (અને સમનà«àªµàª¯àª¿àª¤ ઉપકરણો પર વધà«)}}</translation>
<translation id="3041612393474885105">પà«àª°àª®àª¾àª£àªªàª¤à«àª° માહિતી</translation>
<translation id="3063697135517575841">આ સમયે Chrome તમારા કારà«àª¡àª¨à«€ પà«àª·à«àªŸàª¿ કરવામાં અસમરà«àª¥ હતà«àª‚. કૃપા કરીને પછીથી ફરી પà«àª°àª¯àª¾àª¸ કરો.</translation>
+<translation id="3064966200440839136">બાહà«àª¯ àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ મારફતે ચà«àª•àªµàª£à«€ કરવા માટે છà«àªªà«‹ મોડ છોડી રહà«àª¯àª¾àª‚ છીàª. તો ચાલૠરાખીàª?</translation>
<translation id="3093245981617870298">તમે ઑફલાઇન છો</translation>
<translation id="3105172416063519923">સંપતà«àª¤àª¿ ID:</translation>
<translation id="3109728660330352905">તમને આ પૃષà«àª àª¨à«‡ જોવાની અધિકૃતિ નથી.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />કનેકà«àªŸàª¿àªµàª¿àªŸà«€ ડાયગà«àª¨à«‹àª¸à«àªŸàª¿àª•à«àª¸ ચલાવવાનો પà«àª°àª¯àª¾àª¸ કરો<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">પà«àª°àª¤àª¿àª•à«àª°àª¿àª¯àª¾ ડિકોડ કરવી નિષà«àª«àª³ થઇ</translation>
-<translation id="3149891296864842641">રવાના કરવાનો વિકલà«àªª</translation>
<translation id="3150653042067488994">અસà«àª¥àª¾àª¯à«€ સરà«àªµàª° ભૂલ</translation>
+<translation id="3154506275960390542">આ પૃષà«àª àª®àª¾àª‚ àªàª• ફૉરà«àª® છે, જે કદાચ સà«àª°àª•à«àª·àª¿àª¤ રીતે સબમિટ નહીં થાય. જે ડેટા તમે મોકલો તેને પરિવહન દરમિયાન અનà«àª¯ લોકો જોઈ શકશે અથવા સરà«àªµàª° જે મેળવે, તે બદલવા માટે હà«àª®àª²àª¾àª–ોર ફેરફાર કરી શકશે.</translation>
<translation id="3157931365184549694">પà«àª¨àªƒàª¸à«àª¥àª¾àªªàª¿àª¤ કરો</translation>
<translation id="3167968892399408617">તમે છà«àªªàª¾ ટેબà«àª¸àª®àª¾àª‚ જà«àª“ છો તે પૃષà«àª à«‹ તમે તમારા બધા છà«àªªàª¾ ટેબà«àª¸ બંધ કરી દો તે પછી તમારા બà«àª°àª¾àª‰àªàª°àª¨àª¾ ઇતિહાસ, કà«àª•à«€ સà«àªŸà«‹àª° અથવા શોધ ઇતિહાસમાં રહેશે નહીં. તમે ડાઉનલોડ કરો છો તે કોઈપણ ફાઇલો અથવા તમે બનાવો છો તે બà«àª•àª®àª¾àª°à«àª•à«àª¸ રાખવામાં આવશે.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">આ સાઇટને àªàª•à«àª¸à«‡àª¸ કરવાની તમારી વિનંતી <ph name="NAME" /> ને મોકલી શકાઈ નથી. કૃપા કરીને ફરી પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="3355823806454867987">પà«àª°à«‹àª•à«àª¸à«€ સેટિંગà«àª¸ બદલો...</translation>
<translation id="3369192424181595722">ઘડિયાળ ભૂલ</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> વધૠઆઇટમ...</translation>
<translation id="337363190475750230">જોગવાઈ દૂર કરી</translation>
<translation id="3377188786107721145">નીતિ વિશà«àª²à«‡àª·àª£ ભૂલ</translation>
<translation id="3380365263193509176">અજà«àªžàª¾àª¤ ભૂલ</translation>
<translation id="3380864720620200369">કà«àª²àª¾àª‡àª¨à«àªŸ ID:</translation>
<translation id="3391030046425686457">વિતરણ માટેનà«àª‚ સરનામà«àª‚</translation>
+<translation id="3395827396354264108">પિકઅપ પદà«àª§àª¤àª¿</translation>
<translation id="340013220407300675">હà«àª®àª²àª¾àª–ોરો <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> માંથી તમારી માહિતી ચોરી કરવાનો પà«àª°àª¯àª¾àª¸ કરી શકે છે (ઉદાહરણ તરીકે, પાસવરà«àª¡à«àª¸, સંદેશા અથવા કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡à«àª¸).</translation>
<translation id="3422248202833853650">મેમરી ખાલી કરવા માટે અનà«àª¯ પà«àª°à«‹àª—à«àª°àª¾àª®àª¥à«€ બહાર નીકળવાનો પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> હાલમાં પહોંચવા યોગà«àª¯ નથી.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">આનયન અંતરાલ:</translation>
<translation id="3462200631372590220">વિગતવાર છà«àªªàª¾àªµà«‹</translation>
+<translation id="3467763166455606212">કારà«àª¡àª§àª¾àª°àª•àª¨à«àª‚ નામ આવશà«àª¯àª• છે</translation>
+<translation id="3478058380795961209">સમય સમાપà«àª¤àª¿ મહિનો</translation>
<translation id="3479539252931486093">શà«àª‚ આ અનપેકà«àª·àª¿àª¤ હતà«àª‚? <ph name="BEGIN_LINK" />અમને જણાવો<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">હમણાં નહીં</translation>
<translation id="348000606199325318">કà«àª°à«‡àª¶ ID <ph name="CRASH_LOCAL_ID" /> (સરà«àªµàª° ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">અમે આ પળે તમારા વાલી સà«àª§à«€ પહોંચી શકà«àª¯àª¾àª‚ નથી. કૃપા કરીને ફરી પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="3528171143076753409">સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° વિશà«àªµàª¸àª¨à«€àª¯ નથી.</translation>
-<translation id="3538531656504267329">અમાનà«àª¯ સમાપà«àª¤àª¿ વરà«àª·</translation>
<translation id="3539171420378717834">આ ઉપકરણ પર આ કારà«àª¡àª¨à«€ àªàª• કૉપિ રાખો</translation>
<translation id="3542684924769048008">આ માટે પાસવરà«àª¡àª¨à«‹ ઉપયોગ કરો:</translation>
<translation id="3549644494707163724">તમારા પોતાના સમનà«àªµàª¯àª¨ પાસફà«àª°à«‡àª સાથે તમામ સમનà«àªµàª¯àª¿àª¤ ડેટા àªàª¨à«àª•à«àª°àª¿àªªà«àªŸ કરો</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">વિગતો છà«àªªàª¾àªµà«‹</translation>
<translation id="3587482841069643663">બધા</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">àªàª• માનà«àª¯ સમાપà«àª¤àª¿ તારીખ દાખલ કરો</translation>
<translation id="36224234498066874">બà«àª°àª¾àª‰àªàª¿àª‚ગ ડેટા સાફ કરો...</translation>
<translation id="362276910939193118">પૂરà«àª£ ઇતિહાસ બતાવો</translation>
<translation id="3623476034248543066">કિંમત બતાવો</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">પાસવરà«àª¡:</translation>
<translation id="3696411085566228381">કોઈ નહીં</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">શિપિંગ પદà«àª§àª¤àª¿àª“ અને આવશà«àª¯àª•àª¤àª¾àª“ તપાસવા વિતરણ માટેનà«àª‚ સરનામà«àª‚ પસંદ કરો.</translation>
<translation id="370665806235115550">લોડ કરી રહà«àª¯à«àª‚ છે...</translation>
<translation id="3712624925041724820">લાઇસેંસીસ પૂરà«àª£</translation>
<translation id="3714780639079136834">મોબાઇલ ડેટા અથવા Wi-Fi ચાલૠકરીને</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">તમે કૉપિ કરેલ લિંક</translation>
<translation id="375403751935624634">સરà«àªµàª° ભૂલને કારણે ભાષાંતર નિષà«àª«àª³ રહà«àª¯à«àª‚.</translation>
<translation id="3759461132968374835">તમે હાલમાં કà«àª°à«‡àª¶àª¨à«€ જાણ કરી નથી. કà«àª°à«‡àª¶àª¨à«€ જાણ કરવાનà«àª‚ અકà«àª·àª® હતà«àª‚ તà«àª¯àª¾àª°à«‡ થયેલા કà«àª°à«‡àª¶ અહીં દેખાશે નહીં.</translation>
+<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /> માં સમાપà«àª¤ થાય છે</translation>
<translation id="382518646247711829">જો તમે કોઈ પà«àª°à«‹àª•à«àª¸à«€ સરà«àªµàª°àª¨à«‹ ઉપયોગ કરો છો...</translation>
<translation id="3828924085048779000">ખાલી પાસફà«àª°à«‡àªàª¨à«‡ અનà«àª®àª¤àª¿ નથી. </translation>
<translation id="3845539888601087042">તમે સાઇન ઇન થયેલા હોય તેવા ઉપકરણોમાંથી ઇતિહાસ બતાવી રહà«àª¯àª¾àª‚ છે. <ph name="BEGIN_LINK" />વધૠજાણો<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">શà«àª‚ તમે ઇચà«àª›à«‹ છો કે Chromium આ કારà«àª¡ સાચવે?</translation>
<translation id="4171400957073367226">ખોટી ચકાસણી સહી</translation>
-<translation id="4176463684765177261">અકà«àª·àª® કરેલà«àª‚</translation>
<translation id="4196861286325780578">&amp;ખસેડવà«àª‚ ફરી કરો</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ફાયરવોલ અને àªàª¨à«àªŸà«€àªµàª¾àª‡àª°àª¸ ગોઠવણી તપાસીને<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{કોઈ નહીં}=1{1 àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ ($1)}=2{2 àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ ($1, $2)}one{# àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ ($1, $2, $3)}other{# àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">શોધ પરિણામો</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ઠતમારà«àª‚ લોગિન પà«àª°àª®àª¾àª£àªªàª¤à«àª° સà«àªµà«€àª•àª¾àª°à«àª¯à«àª‚ ન હતà«àª‚ અથવા કદાચ કોઈ àªàª• પà«àª°àª¦àª¾àª¨ કરવામાં આવà«àª¯à«àª‚ નથી.</translation>
<translation id="443673843213245140">પà«àª°à«‹àª•à«àª¸à«€àª¨à«‹ ઉપયોગ અકà«àª·àª® કરેલો છે પણ àªàª• સà«àªªàª·à«àªŸ પà«àª°à«‹àª•à«àª¸à«€ ગોઠવણી ઉલà«àª²à«‡àª–િત છે.</translation>
-<translation id="4446242550670694251">હવે તમે ખાનગીપણે બà«àª°àª¾àª‰àª કરી શકો છો અને આ ઉપકરણનો ઉપયોગ કરી રહેલ અનà«àª¯ લોકોને તમારી પà«àª°àªµà«ƒàª¤à«àª¤àª¿ દેખાશે નહીં.</translation>
<translation id="4492190037599258964">'<ph name="SEARCH_STRING" />' માટે શોધ પરિણામ</translation>
<translation id="4506176782989081258">માનà«àª¯àª¤àª¾ ભૂલ: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">સિસà«àªŸàª® વà«àª¯àªµàª¸à«àª¥àª¾àªªàª•àª¨à«‹ સંપરà«àª• કરીને</translation>
<translation id="450710068430902550">વà«àª¯àªµàª¸à«àª¥àª¾àªªàª• સાથે શેર કરવà«àª‚</translation>
+<translation id="4515275063822566619">કારà«àª¡ અને સરનામા Chrome અને Google àªàª•àª¾àª‰àª¨à«àªŸ (<ph name="ACCOUNT_EMAIL" />)માંથી છે. તમે તેને <ph name="BEGIN_LINK" />સેટિંગà«àª¸<ph name="END_LINK" />માં જઈને સંચાલિત કરી શકો છો.</translation>
<translation id="4522570452068850558">વિગતો</translation>
<translation id="4558551763791394412">તમારા àªàª•à«àª¸à«àªŸà«‡àª¨à«àª¶àª¨à«àª¸àª¨à«‡ અકà«àª·àª® કરવાનો પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="457875822857220463">વિતરણ</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">પૃષà«àª  પર ફિટ</translation>
<translation id="483020001682031208">બતાવવા માટે કોઇ ભૌતિક વેબ પૃષà«àª à«‹ નથી</translation>
<translation id="4850886885716139402">જà«àª“</translation>
+<translation id="4854362297993841467">વિતરણની આ પદà«àª§àª¤àª¿ ઉપલબà«àª§ નથી. કોઈ ભિનà«àª¨ પદà«àª§àª¤àª¿ અજમાવો.</translation>
<translation id="4858792381671956233">તમે આ સાઇટની મà«àª²àª¾àª•àª¾àª¤ લો છો તે ઠીક છે કે કેમ તેવà«àª‚ તમે તમારા માતાપિતાને પૂછà«àª¯à«àª‚</translation>
<translation id="4880827082731008257">ઇતિહાસ શોધ</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">આ પૃષà«àª  કોઈ અજà«àªžàª¾àª¤ ભાષામાંથી <ph name="LANGUAGE_LANGUAGE" /> માં અનà«àªµàª¾àª¦àª¿àª¤ કરવામાં આવà«àª¯à«àª‚ છે</translation>
<translation id="4923459931733593730">ચà«àª•àªµàª£à«€</translation>
<translation id="4926049483395192435">ઉલà«àª²à«‡àª–િત હોવà«àª‚ આવશà«àª¯àª• છે.</translation>
-<translation id="4941291666397027948">* આવશà«àª¯àª• ફીલà«àª¡ સૂચવે છે</translation>
<translation id="495170559598752135">કà«àª°àª¿àª¯àª¾àª“</translation>
<translation id="4958444002117714549">સૂચિ વિસà«àª¤à«ƒàª¤ કરો</translation>
<translation id="4962322354953122629">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°, Chrome દà«àªµàª¾àª°àª¾ વિશà«àªµàª¸àª¨à«€àª¯ નથી. આ કદાચ કોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">ખોટો પાસવરà«àª¡</translation>
<translation id="5056549851600133418">તમારા માટે લેખ</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />પà«àª°à«‹àª•à«àª¸à«€ સરનામà«àª‚ તપાસીને<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{કોઈ કà«àª•à«€ નહીં}=1{1 સાઇટ કà«àª•à«€àª¨à«‹ ઉપયોગ કરે છે. }one{# સાઇટ કà«àª•à«€àª¨à«‹ ઉપયોગ કરે છે. }other{# સાઇટ કà«àª•à«€àª¨à«‹ ઉપયોગ કરે છે. }}</translation>
<translation id="5087286274860437796">સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° આ સમયે માનà«àª¯ નથી.</translation>
<translation id="5087580092889165836">કારà«àª¡ ઉમેરો</translation>
<translation id="5089810972385038852">રાજà«àª¯</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">બતાવો</translation>
<translation id="5308689395849655368">કà«àª°à«‡àª¶àª¨à«€ જાણ કરવાનà«àª‚ અકà«àª·àª® કરà«àª¯à«àª‚ છે.</translation>
<translation id="5317780077021120954">સાચવો</translation>
-<translation id="5326702247179446998">પà«àª°àª¾àªªà«àª¤àª•àª°à«àª¤àª¾ જરૂરી છે</translation>
<translation id="5327248766486351172">નામ</translation>
<translation id="5337705430875057403"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> પરના હà«àª®àª²àª¾àª–ોરો તમારી વà«àª¯àª•à«àª¤àª¿àª—ત માહિતી (ઉદાહરણ તરીકે, પાસવરà«àª¡à«àª¸, ફોન નંબરà«àª¸ અથવા કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡à«àª¸) ને દરà«àª¶àª¾àªµàªµàª¾ અથવા સોફà«àªŸàªµà«‡àª° ઇનà«àª¸à«àªŸà«‹àª² કરવા જેવી જોખમી વસà«àª¤à«àª“ને કરવા માટે તમને છેતરવાનો પà«àª°àª¯àª¾àª¸ કરી શકે છે.</translation>
-<translation id="53553865750799677">પિકઅપ માટેનà«àª‚ સરનામà«àª‚ અસમરà«àª¥àª¿àª¤. àªàª• અલગ સરનામà«àª‚ પસંદ કરો.</translation>
<translation id="5359637492792381994">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° આ સમયે માનà«àª¯ નથી. આ કદાચ કોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">નીતિ સેટિંગà«àª¸ સà«àªŸà«‹àª° કરવામાં નિષà«àª«àª³ થયાં</translation>
<translation id="5386426401304769735">આ સાઇટ માટેની પà«àª°àª®àª¾àª£àªªàª¤à«àª° શà«àª°à«ƒàª‚ખલા SHA-1 નો ઉપયોગ કરીને સહી કરેલ પà«àª°àª®àª¾àª£àªªàª¤à«àª° ધરાવે છે.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102"><ph name="SITE" /> પરનà«àª‚ àªàª®à«àª¬à«‡àª¡ કરેલ પૃષà«àª  આ કહે છે:</translation>
<translation id="5556459405103347317">ફરિથી લોડ કરો</translation>
<translation id="5565735124758917034">સકà«àª°àª¿àª¯</translation>
+<translation id="5571083550517324815">આ સરનામેથી પિકઅપ કરી શકતા નથી. કોઈ ભિનà«àª¨ સરનામà«àª‚ પસંદ કરો.</translation>
<translation id="5572851009514199876">કૃપા કરીને Chrome ને પà«àª°àª¾àª°àª‚ભ કરો અને સાઇન ઇન કરો જેથી કરીને Chrome તપાસી શકે કે તમને આ સાઇટની àªàª•à«àª¸à«‡àª¸àª¨à«€ મંજૂરી છે કે કેમ.</translation>
-<translation id="5575380383496039204">વિતરણ માટેનà«àª‚ સરનામà«àª‚ અસમરà«àª¥àª¿àª¤. àªàª• અલગ સરનામà«àª‚ પસંદ કરો.</translation>
<translation id="5580958916614886209">તમારો સમાપà«àª¤àª¿ મહિનો તપાસો અને ફરી પà«àª°àª¯àª¾àª¸ કરો</translation>
<translation id="560412284261940334">સંચાલન સમરà«àª¥àª¿àª¤ નથી</translation>
<translation id="5610142619324316209">કનેકà«àª¶àª¨ તપાસીને</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">આ વેબસાઇટની ઓળખ ચકાસવામાં આવી નથી.</translation>
<translation id="5720705177508910913">વરà«àª¤àª®àª¾àª¨ વપરાશકરà«àª¤àª¾</translation>
<translation id="5732392974455271431">તમારા માટે તમારા માતાપિતા તેને અનાવરોધિત કરી શકે છે</translation>
-<translation id="57586589942790530">અમાનà«àª¯ કારà«àª¡ નંબર</translation>
+<translation id="5763042198335101085">àªàª• માનà«àª¯ ઇમેઇલ àªàª¡à«àª°à«‡àª¸ ઉમેરો</translation>
+<translation id="5765072501007116331">વિતરણ પદà«àª§àª¤àª¿àª“ અને આવશà«àª¯àª•àª¤àª¾àª“ જોવા માટે, àªàª• સરનામà«àª‚ પસંદ કરો</translation>
<translation id="5784606427469807560">તમારા કારà«àª¡àª¨à«€ પà«àª·à«àªŸàª¿ કરવામાં àªàª• સમસà«àª¯àª¾ આવી હતી. તમારà«àª‚ ઇનà«àªŸàª°àª¨à«‡àªŸ કનેકà«àª¶àª¨ તપાસો અને ફરીથી પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="5785756445106461925">વળી, આ પૃષà«àª àª®àª¾àª‚ અનà«àª¯ àªàªµàª¾ સાધનો છે જે સà«àª°àª•à«àª·àª¿àª¤ નથી. ટà«àª°àª¾àª‚àªàª¿àªŸàª®àª¾àª‚ હોવા પર અનà«àª¯ લોકો દà«àªµàª¾àª°àª¾ આ સાધનો જોઈ શકાય છે અને પૃષà«àª àª¨à«‹ દેખાવ બદલવા માટે હà«àª®àª²àª¾àª–ોર દà«àªµàª¾àª°àª¾ સંશોધિત કરવામાં આવી શકે છે.</translation>
<translation id="5786044859038896871">શà«àª‚ તમે તમારી કારà«àª¡ માહિતી ભરવા માગો છો?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">આ સાઇટ પર પહોંચી શકાતà«àª‚ નથી</translation>
<translation id="5869522115854928033">સાચવેલા પાસવરà«àª¡à«àª¸</translation>
<translation id="5872918882028971132">પેરેનà«àªŸ સૂચનો</translation>
-<translation id="587760065310675640">વિતરણ માટેનà«àª‚ સરનામà«àª‚ અસમરà«àª¥àª¿àª¤. àªàª• અલગ સરનામà«àª‚ પસંદ કરો.</translation>
<translation id="5901630391730855834">પીળો</translation>
-<translation id="59174027418879706">સકà«àª·àª®</translation>
<translation id="5926846154125914413">તમે કેટલીક સાઇટà«àª¸àª¨à«€ પà«àª°à«€àª®àª¿àª¯àª® સામગà«àª°à«€àª¨à«€ àªàª•à«àª¸à«‡àª¸ ગà«àª®àª¾àªµà«€ શકો છો.</translation>
<translation id="5959728338436674663">જોખમી અâ€à«…પà«àª²àª¿àª•à«‡àª¶àª¨à«‹ અને સાઇટà«àª¸ શોધવામાં સહાય કરવા માટે Google ને કેટલીક <ph name="BEGIN_WHITEPAPER_LINK" />સિસà«àªŸàª® માહિતી અને પૃષà«àª  સામગà«àª°à«€<ph name="END_WHITEPAPER_LINK" /> આપમેળે મોકલો. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">અઠવાડિયà«àª‚</translation>
<translation id="5967867314010545767">ઇતિહાસમાંથી દૂર કરો</translation>
<translation id="5975083100439434680">àªà«‚મ ઘટાડો</translation>
+<translation id="598637245381783098">ચà«àª•àªµàª£à«€ àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ ખોલી શકાતી નથી</translation>
<translation id="5989320800837274978">નિયત પà«àª°à«‹àª•à«àª¸à«€ સરà«àªµàª°à«àª¸ અથવા .pac સà«àª•à«àª°àª¿àªªà«àªŸàª¨à«‹ URL નો ઉલà«àª²à«‡àª– કરેલો નથી.</translation>
<translation id="5990559369517809815">સરà«àªµàª° પરની વિનંતિઓને àªàª•à«àª¸à«àªŸà«‡àª‚શન દà«àªµàª¾àª°àª¾ અવરોધિત કરવામાં આવી છે.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">કારà«àª¡ અને સરનામાં વિકલà«àªªà«‹, Chrome ના છે. તમે આને <ph name="BEGIN_LINK" />સેટિંગà«àª¸<ph name="END_LINK" />માં સંચાલિત કરી શકો છો.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{પૃષà«àª  1}one{પૃષà«àª  #}other{પૃષà«àª  #}}</translation>
<translation id="6017514345406065928">લીલો</translation>
+<translation id="6027201098523975773">àªàª• નામ દાખલ કરો</translation>
<translation id="6040143037577758943">બંધ કરો</translation>
-<translation id="604124094241169006">સà«àªµàªšàª²àª¿àª¤</translation>
<translation id="6042308850641462728">વધà«</translation>
<translation id="6060685159320643512">સાવચેતી રાખો, આ પà«àª°àª¯à«‹àª—à«‹ નà«àª•àª¸àª¾àª¨àª•àª¾àª°àª• હોઈ શકે છે</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{કોઈ નહીં}=1{1}one{#}other{#}}</translation>
@@ -543,9 +552,10 @@
અથવા અનà«àª¯ નેટવરà«àª• ઉપકરણોને રીબૂટ કરો.</translation>
<translation id="614940544461990577">પà«àª°àª¯àª¾àª¸ કરો:</translation>
<translation id="6151417162996330722">સરà«àªµàª° પà«àª°àª®àª¾àª£àªªàª¤à«àª° પાસે ખૂબ લાંબી હોય àªàªµà«€ માનà«àª¯àª¤àª¾ અવધિ છે.</translation>
-<translation id="615643356032862689">ડાઉનલોડ કરેલ ફાઇલો અને બà«àª•àª®àª¾àª°à«àª• રાખવામાં આવશે.</translation>
+<translation id="6157877588268064908">વિતરણ પદà«àª§àª¤àª¿ અને આવશà«àª¯àª•àª¤àª¾àª“ જોવા માટે, àªàª• સરનામà«àª‚ પસંદ કરો</translation>
<translation id="6165508094623778733">વધૠજાણો</translation>
<translation id="6177128806592000436">આ સાઇટ પરનà«àª‚ તમારà«àª‚ કનેકà«àª¶àª¨ સà«àª°àª•à«àª·àª¿àª¤ નથી</translation>
+<translation id="6184817833369986695">(સાથી: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">તમારà«àª‚ ઇનà«àªŸàª°àª¨à«‡àªŸ કનેકà«àª¶àª¨ તપાસો</translation>
<translation id="6218753634732582820">Chromium માંથી સરનામà«àª‚ દૂર કરીàª?</translation>
<translation id="6251924700383757765">ગોપનીયતા નીતિ</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;પà«àª¨àªƒàª•à«àª°àª®àª¾àª‚કિત કરવà«àª‚ ફરી કરો</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> બà«àª•àª®àª¾àª°à«àª•à«àª¸</translation>
<translation id="6264485186158353794">સà«àª°àª•à«àª·àª¾ પર પાછા</translation>
+<translation id="6276112860590028508">તમારી વાચન સૂચિનાં પૃષà«àª à«‹ અહીં દેખાશે</translation>
+<translation id="6280223929691119688">આ સરનામે વિતરણ કરી શકતા નથી. કોઈ ભિનà«àª¨ સરનામà«àª‚ પસંદ કરો.</translation>
<translation id="6282194474023008486">પોસà«àªŸàª² કોડ</translation>
<translation id="6290238015253830360">તમારા સૂચવેલા લેખ અહીં દેખાય છે</translation>
<translation id="6305205051461490394"><ph name="URL" />, પહોંચવા યોગà«àª¯ નથી.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">પà«àª°àª®àª¾àª£àªªàª¤à«àª° રદ કરવામાં આવà«àª¯à«àª‚ છે કે નહીં તે તપાસવામાં અકà«àª·àª® છે.</translation>
<translation id="6433490469411711332">સંપરà«àª• માહિતી સંપાદિત કરો</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> ઠકનેકà«àªŸ કરવાનો ઇનકાર કરà«àª¯à«‹.</translation>
-<translation id="6443118737398455446">અમાનà«àª¯ સમાપà«àª¤àª¿ તારીખ</translation>
<translation id="6446608382365791566">વધૠમાહિતી ઉમેરો</translation>
<translation id="6451458296329894277">ફોરà«àª®àª¨àª¾àª‚ ફરી સબમિશનની પà«àª·à«àªŸàª¿ કરો</translation>
<translation id="6456339708790392414">તમારી ચà«àª•àªµàª£à«€</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° રદબાતલ કરà«àª¯à«àª‚ હોઈ શકે છે. આ કદાચ કોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">ઉપકરણ નીતિઓ</translation>
<translation id="6477321094435799029">Chrome ને આ પૃષà«àª  પર અસામાનà«àª¯ કોડ મળà«àª¯à«‹ અને તમારી વà«àª¯àª•à«àª¤àª¿àª—ત માહિતી (ઉદાહરણ તરીકે, પાસવરà«àª¡à«àª¸, ફોન નંબરà«àª¸ અને કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡à«àª¸)ની સà«àª°àª•à«àª·àª¾ કરવા માટે તેને અવરોધિત કરેલ છે.</translation>
-<translation id="6477460825583319731">અમાનà«àª¯ ઇમેઇલ સરનામà«àª‚</translation>
<translation id="6489534406876378309">કà«àª°à«‡àª¶ અપલોડ કરવાનà«àª‚ શરૂ કરો</translation>
<translation id="6508722015517270189">Chrome ને પà«àª¨àªƒàªªà«àª°àª¾àª°àª‚ભ કરો</translation>
-<translation id="6525462735697194615">અમાનà«àª¯ સમાપà«àª¤àª¿ મહિનો</translation>
<translation id="6529602333819889595">&amp;કાઢી નાખવà«àª‚ ફરી કરો</translation>
<translation id="6534179046333460208">વાસà«àª¤àªµàª¿àª• વેબ સૂચનો</translation>
<translation id="6550675742724504774">વિકલà«àªªà«‹</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> શોધ</translation>
<translation id="6644283850729428850">આ નીતિ દૂર કરવામાં આવેલી છે.</translation>
<translation id="6652240803263749613">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° તમારા કમà«àªªà«àª¯à«àªŸàª°àª¨à«€ ઓપરેટિંગ સિસà«àªŸàª® દà«àªµàª¾àª°àª¾ વિશà«àªµàª¸àª¨à«€àª¯ નથી. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">તે શિપિંગ વિકલà«àªª ઉપલબà«àª§ નથી. àªàª• અલગ વિકલà«àªª અજમાવો.</translation>
<translation id="6671697161687535275">Chromium માંથી ફોરà«àª® સૂચન દૂર કરીàª?</translation>
<translation id="6685834062052613830">સાઇન આઉટ કરો અને સેટઅપ પૂરà«àª£ કરો</translation>
<translation id="6710213216561001401">પહેલાનà«àª‚</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">પà«àª°à«‹àª•à«àª¸à«€ સરà«àªµàª°àª®àª¾àª‚ કંઈક ખોટà«àª‚ થયà«àª‚ છે અથવા તો સરનામà«àª‚ ખોટà«àª‚ છે.</translation>
<translation id="6727102863431372879">સેટ કરો</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{કોઈ નહીં}=1{1 આઇટમ}one{# આઇટમ}other{# આઇટમ}}</translation>
-<translation id="6743044928064272573">પિકઅપ માટેનો વિકલà«àªª</translation>
<translation id="674375294223700098">અજà«àªžàª¾àª¤ સરà«àªµàª° પà«àª°àª®àª¾àª£àªªàª¤à«àª° ભૂલ.</translation>
<translation id="6753269504797312559">નીતિ મૂલà«àª¯</translation>
<translation id="6757797048963528358">તમારà«àª‚ ઉપકરણ નિષà«àª•à«àª°àª¿àª¯ થઈ ગયà«àª‚ હતà«àª‚.</translation>
<translation id="6778737459546443941">તમારા માતાપિતાઠહજી સà«àª§à«€ તેને મંજૂર કરેલ નથી</translation>
<translation id="6810899417690483278">કસà«àªŸàª®àª¾àª‡àªà«‡àª¶àª¨ ID</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">પà«àª°àª¦à«‡àª¶àª¨à«‹ ડેટા લોડ કરવામાં નિષà«àª«àª³ થયાં</translation>
<translation id="6831043979455480757">અનà«àªµàª¾àª¦ કરો</translation>
<translation id="6839929833149231406">વિસà«àª¤àª¾àª°</translation>
<translation id="6874604403660855544">&amp;ઉમેરવà«àª‚ ફરી કરો</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">તમારા કારà«àª¡àª¨à«€ પà«àª·à«àªŸàª¿ કરવામાં આવી છે</translation>
<translation id="6897140037006041989">વપરાશકરà«àª¤àª¾ àªàªœàª¨à«àªŸ</translation>
<translation id="6915804003454593391">વપરાશકરà«àª¤àª¾: </translation>
+<translation id="6948701128805548767">પિકઅપ પદà«àª§àª¤àª¿ અને આવશà«àª¯àª•àª¤àª¾àª“ જોવા માટે, àªàª• સરનામà«àª‚ પસંદ કરો</translation>
<translation id="6957887021205513506">સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° બનાવટી હોય àªàªµà«àª‚ લાગે છે.</translation>
<translation id="6965382102122355670">ઓકે</translation>
<translation id="6965978654500191972">ઉપકરણ</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">નિયત પà«àª°à«‹àª•à«àª¸à«€ સરà«àªµàª°à«àª¸ અને .pac script URL બનà«àª¨à«‡àª¨à«‹ ઉલà«àª²à«‡àª– કરેલો છે.</translation>
<translation id="6989763994942163495">વિગતવાર સેટિંગà«àª¸ બતાવો...</translation>
<translation id="7000990526846637657">કોઈ ઇતિહાસ પà«àª°àªµàª¿àª·à«àªŸàª¿àª“ મળી નથી</translation>
-<translation id="7001663382399377034">પà«àª°àª¾àªªà«àª¤àª•àª°à«àª¤àª¾àª¨à«‡ ઉમેરો</translation>
<translation id="7009986207543992532">તમે <ph name="DOMAIN" /> પર પહોંચવાનો પà«àª°àª¯àª¤à«àª¨ કરà«àª¯à«‹, પરંતૠસરà«àªµàª°à«‡ àªàªµà«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° પà«àª°àª¸à«àª¤à«àª¤ કરà«àª¯à«àª‚ કે જેની માનà«àª¯àª¤àª¾ અવધિ àªàªŸàª²à«€ લાંબી છે કે તે વિશà«àªµàª¸àª¨à«€àª¯ લાગતી નથી. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª®àª¾àª‚ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> પર બà«àª°àª¾àª‰àªàª¿àª‚ગ ઇતિહાસના અનà«àª¯ સà«àªµàª°à«‚પો હોઇ શકે છે.</translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">વધૠજૂનà«àª‚</translation>
<translation id="7090678807593890770"><ph name="LINK" /> માટે Google પર શોધો</translation>
<translation id="7119414471315195487">અનà«àª¯ ટૅબ અથવા પà«àª°à«‹àª—à«àª°àª¾àª® બંધ કરો</translation>
+<translation id="7129409597930077180">આ સરનામે વિતરણ કરી શકાતà«àª‚ નથી. કોઈ ભિનà«àª¨ સરનામà«àª‚ પસંદ કરો.</translation>
+<translation id="7138472120740807366">વિતરણ પદà«àª§àª¤àª¿</translation>
<translation id="7139724024395191329">àªàª®àª¿àª°àª¾àª¤</translation>
<translation id="7155487117670177674">ચà«àª•àªµàª£à«€ સà«àª°àª•à«àª·àª¿àª¤ નથી</translation>
<translation id="7179921470347911571">હમણાં ફરીથી લોંચ કરો</translation>
<translation id="7180611975245234373">તાજà«àª‚ કરો</translation>
<translation id="7182878459783632708">કોઈ નીતિઓ સેટ નથી</translation>
<translation id="7186367841673660872">આ પૃષà«àª àª¨à«àª‚<ph name="ORIGINAL_LANGUAGE" />માંથી<ph name="LANGUAGE_LANGUAGE" />માં ભાષાંતર કરવામાં આવà«àª¯à«àª‚ છે.</translation>
+<translation id="7192203810768312527"><ph name="SIZE" /> ખાલી કરે છે. તમારી આગલી મà«àª²àª¾àª•àª¾àª¤ સમયે કેટલીક સાઇટો વધૠધીમે લોડ થઈ શકે છે.</translation>
<translation id="719464814642662924">વિàªàª¾</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" />, સà«àª°àª•à«àª·àª¾ માનકોનà«àª‚ પાલન કરતà«àª‚ નથી.</translation>
<translation id="721197778055552897">આ સમસà«àª¯àª¾ વિશે <ph name="BEGIN_LINK" />વધૠજાણો<ph name="END_LINK" />.</translation>
@@ -675,7 +686,6 @@
<translation id="7424977062513257142">આ વેબપૃષà«àª  પરનà«àª‚ àªàª®à«àª¬à«‡àª¡ કરેલ પૃષà«àª  આ કહે છે:</translation>
<translation id="7441627299479586546">ખોટો નીતિ વિષય</translation>
<translation id="7444046173054089907">આ સાઇટ અવરોધિત છે</translation>
-<translation id="7444238235002594607">પિકઅપ પદà«àª§àª¤àª¿àª“ અને આવશà«àª¯àª•àª¤àª¾àª“ તપાસવા પિકઅપ માટેનà«àª‚ સરનામà«àª‚ પસંદ કરો.</translation>
<translation id="7445762425076701745">તમે જે સરà«àªµàª°àª¥à«€ કનેકà«àªŸ છો તેની ઓળખ સંપૂરà«àª£ રૂપે માનà«àª¯ કરી શકાતી નથી. તમે જે નામનો ઉપયોગ કરીને સરà«àªµàª°àª¥à«€ કનેકà«àªŸ છો, તે ફકà«àª¤ તમારા નેટવરà«àª•àª¨à«€ અંતરà«àª—ત જ માનà«àª¯ છે, જેના બાહà«àª¯ પà«àª°àª®àª¾àª£àªªàª¤à«àª° અધિકારીને માલિકીને માનà«àª¯ કરવાની કોઈ રીત નથી. આના પર ધà«àª¯àª¾àª¨ આપà«àª¯àª¾àª‚ વગર કેટલાક પà«àª°àª®àª¾àª£àªªàª¤à«àª° અધિકારીઓ આ નામો માટે પà«àª°àª®àª¾àª£àªªàª¤à«àª° બહાર પાડશે, તેથી તમે ઇચà«àª›àª¿àª¤ વેબસાઇટથી કનેકà«àªŸ છો કોઈ હà«àª®àª²àª¾àª–ોરથી નહીં, તેની ખાતરી કરવાની કોઈ રીત નથી.</translation>
<translation id="7451311239929941790">આ સમસà«àª¯àª¾ વિશે <ph name="BEGIN_LINK" />વધૠજાણો<ph name="END_LINK" />.</translation>
<translation id="7460163899615895653">અનà«àª¯ ઉપકરણોમાંના તમારા તાજેતરના ટૅબà«àª¸ અહીં દેખાય છે</translation>
@@ -719,6 +729,7 @@
<translation id="7755287808199759310">તમારા માટે તમારા માતાપિતા તેને અનાવરોધિત કરી શકે છે</translation>
<translation id="7758069387465995638">ફાયરવોલ અથવા àªàª¨à«àªŸàª¿àªµàª¾àª¯àª°àª¸ સોફà«àªŸàªµà«‡àª° ઠકનેકà«àª¶àª¨ અવરોધિત કરà«àª¯à«àª‚ હોઈ શકે છે.</translation>
<translation id="7761701407923456692">સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° URL સાથે મેળ ખાતà«àª‚ નથી.</translation>
+<translation id="7763386264682878361">ચà«àª•àªµàª£à«€ સà«àªªàª·à«àªŸ વિશà«àª²à«‡àª·àª•</translation>
<translation id="7764225426217299476">સરનામà«àª‚ ઉમેરો</translation>
<translation id="777702478322588152">પà«àª°à«€àª«à«‡àªšàª°</translation>
<translation id="7791543448312431591">ઉમેરો</translation>
@@ -732,6 +743,7 @@
<translation id="785549533363645510">જો કે, તમે અદૃશà«àª¯ નથી. છà«àªªàª¾àª®àª¾àª‚ જવà«àª‚ તમારા નિયોકà«àª¤àª¾, તમારા ઇનà«àªŸàª°àª¨à«‡àªŸ સેવા પà«àª°àª¦àª¾àª¤àª¾ અથવા તમે મà«àª²àª¾àª•àª¾àª¤ લો છો તે વેબસાઇટà«àª¸àª¥à«€ તમારા બà«àª°àª¾àª‰àªàª¿àª‚ગને છà«àªªàª¾àªµàª¤à«àª‚ નથી.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">તમારà«àª‚ CVC તપાસો અને ફરીથી પà«àª°àª¯àª¾àª¸ કરો</translation>
+<translation id="79338296614623784">àªàª• માનà«àª¯ ફોન નંબર દાખલ કરો</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° હજી માનà«àª¯ નથી.</translation>
<translation id="7942349550061667556">લાલ</translation>
@@ -751,6 +763,7 @@
<translation id="8088680233425245692">લેખ જોવામાં નિષà«àª«àª³ થયાં.</translation>
<translation id="8089520772729574115">1 MB કરતાં ઓછà«àª‚</translation>
<translation id="8091372947890762290">સકà«àª°àª¿àª¯àª¤àª¾ સરà«àªµàª° પર બાકી છે</translation>
+<translation id="8118489163946903409">ચà«àª•àªµàª£à«€ પદà«àª§àª¤àª¿</translation>
<translation id="8131740175452115882">પà«àª·à«àªŸàª¿ કરો</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> નà«àª‚ સરà«àªµàª° <ph name="BEGIN_ABBR" />DNS સરનામà«àª‚<ph name="END_ABBR" /> શોધી શકાયà«àª‚ નથી.</translation>
<translation id="8149426793427495338">તમારà«àª‚ કમà«àªªà«àª¯à«àªŸàª° નિષà«àª•à«àª°àª¿àª¯ થઈ ગયà«àª‚ હતà«àª‚.</translation>
@@ -776,6 +789,7 @@
<translation id="8349305172487531364">બà«àª•àª®àª¾àª°à«àª•à«àª¸ બાર</translation>
<translation id="8363502534493474904">àªàª°àªªà«àª²à«‡àª¨ મોડ બંધ કરીને</translation>
<translation id="8364627913115013041">સેટ નથી.</translation>
+<translation id="8368476060205742148">Google Play સેવાઓ</translation>
<translation id="8380941800586852976">જોખમી</translation>
<translation id="8382348898565613901">તમારા તાજેતરમાં મà«àª²àª¾àª•àª¾àª¤ લીધેલ બà«àª•àª®àª¾àª°à«àª•à«àª¸ અહીં દેખાય છે</translation>
<translation id="8398259832188219207"><ph name="UPLOAD_TIME" /> ઠકà«àª°à«‡àª¶ રિપોરà«àªŸ અપલોડ કરà«àª¯à«‹ હતો</translation>
@@ -784,31 +798,29 @@
<translation id="8428213095426709021">સેટિંગà«àª¸</translation>
<translation id="8433057134996913067">આ તમને મોટાભાગની વેબસાઇટà«àª¸àª®àª¾àª‚થી સાઇન આઉટ કરશે.</translation>
<translation id="8437238597147034694">&amp;ખસેડવà«àª‚ પૂરà«àªµàªµàª¤à«â€Œ કરો</translation>
-<translation id="8456681095658380701">અમાનà«àª¯ નામ</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡}one{# કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡}other{# કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡}}</translation>
<translation id="8483780878231876732">તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª®àª¾àª‚થી કારà«àª¡à«àª¸àª¨à«‹ ઉપયોગ કરવા માટે, Chrome માં સાઇન ઇન કરો</translation>
<translation id="8488350697529856933">આમને લાગà«</translation>
-<translation id="8492969205326575646">અસમરà«àª¥àª¿àª¤ કારà«àª¡ પà«àª°àª•àª¾àª°</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ઠપà«àª°àª¤àª¿àª¸àª¾àª¦ આપવા માટે ઘણો સમય લીધો.</translation>
<translation id="852346902619691059">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° તમારા ઉપકરણની ઓપરેટિંગ સિસà«àªŸàª® દà«àªµàª¾àª°àª¾ વિશà«àªµàª¸àª¨à«€àª¯ નથી. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">સમય સમાપà«àª¤àª¿ વરà«àª·</translation>
<translation id="8543181531796978784">તમે <ph name="BEGIN_ERROR_LINK" />શોધ સમસà«àª¯àª¾àª¨à«€ જાણ<ph name="END_ERROR_LINK" /> કરી શકો છો અથવા જો તમે તમારી સà«àª°àª•à«àª·àª¾ અંગેનાં જોખમોને સમજતાં હોવ, તો <ph name="BEGIN_LINK" />આ અસà«àª°àª•à«àª·àª¿àª¤ સાઇટની મà«àª²àª¾àª•àª¾àª¤<ph name="END_LINK" /> લઈ શકો છો.</translation>
<translation id="8553075262323480129">ભાષાંતર નિષà«àª«àª³ રહà«àª¯à«àª‚ કારણ કે પૃષà«àª àª¨à«€ ભાષા નિરà«àª§àª¾àª°àª¿àª¤ થઈ શકી નથી.</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> પર ખાનગી કનેકà«àª¶àª¨ સà«àª¥àª¾àªªàª¿àª¤ કરી શકાતà«àª‚ નથી કારણ કે તમારા ઉપકરણની તારીખ અને સમય (<ph name="DATE_AND_TIME" />) અયોગà«àª¯ છે.</translation>
-<translation id="8570229484593575558">આ માહિતી |સાચવવામાં આવશે નહીં|:#તમારો બà«àª°àª¾àª‰àªàª¿àª‚ગ ઇતિહાસ#તમારી શોધ#કà«àª•à«€ ડેટા</translation>
<translation id="8571890674111243710">પૃષà«àª àª¨à«‡ <ph name="LANGUAGE" /> માં અનà«àªµàª¾àª¦àª¿àª¤ કરી રહà«àª¯à«àª‚ છે...</translation>
-<translation id="8584539743998202583">તમારી પà«àª°àªµà«ƒàª¤à«àª¤àª¿ આમને |હજીપણ દૃશà«àª¯àª•à«àª·àª® હોઈ શકે છે|:#તમે મà«àª²àª¾àª•àª¾àª¤ લો છો તે વેબસાઇટ#તમારા નિયોકà«àª¤àª¾#તમારા ઇનà«àªŸàª°àª¨à«‡àªŸ સેવા પà«àª°àª¦àª¾àª¤àª¾</translation>
<translation id="858637041960032120">ફોન નંબર ઉમેરો</translation>
<translation id="859285277496340001">પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«‡ રદ કરવામાં આવà«àª¯à«àª‚ છે કે નહિ તે તપાસવા માટે કોઈપણ મેકેનિàªàª® નિરà«àª¦àª¿àª·à«àªŸ કરતà«àª‚ નથી.</translation>
<translation id="8620436878122366504">તમારા માતાપિતાઠતેને હજી સà«àª§à«€ મંજૂર કરેલ નથી</translation>
<translation id="8647750283161643317">બધાને ડિફોલà«àªŸ પર ફરીથી સેટ કરો</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> સાથેનà«àª‚ તમારà«àª‚ કનેકà«àª¶àª¨ àªàª¨à«àª•à«àª°àª¿àªªà«àªŸà«‡àª¡ નથી.</translation>
+<translation id="8718314106902482036">ચà«àª•àªµàª£à«€ પૂરà«àª£ થઈ નથી</translation>
<translation id="8725066075913043281">ફરી પà«àª°àª¯àª¾àª¸ કરો</translation>
<translation id="8728672262656704056">તમે છà«àªªàª¾ મોડમાં ગયા છો</translation>
<translation id="8730621377337864115">થઈ ગયà«àª‚</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="8759274551635299824">આ કારà«àª¡àª¨à«€ સમયસીમા સમાપà«àª¤ થઈ ગઈ છે</translation>
<translation id="8790007591277257123">&amp;કાઢી નાખવà«àª‚ ફરી કરો</translation>
-<translation id="8798099450830957504">ડિફૉલà«àªŸ</translation>
<translation id="8800988563907321413">તમારા નજીકના સૂચનો અહીં દેખાય છે</translation>
<translation id="8820817407110198400">બà«àª•àª®àª¾àª°à«àª•à«àª¸</translation>
<translation id="883848425547221593">અનà«àª¯ બà«àª•àª®àª¾àª°à«àª•à«àª¸</translation>
@@ -818,6 +830,7 @@
<translation id="8866481888320382733">ભૂલ વિશà«àª²à«‡àª·àª£ નીતિ સેટિંગà«àª¸</translation>
<translation id="8866959479196209191">આ પૃષà«àª  આ કહે છે:</translation>
<translation id="8870413625673593573">તાજેતરમાં બંધ કરેલા</translation>
+<translation id="8874824191258364635">àªàª• માનà«àª¯ કારà«àª¡ નંબર દાખલ કરો</translation>
<translation id="8876793034577346603">નેટવરà«àª• ગોઠવણી વિશà«àª²à«‡àª·àª¿àª¤ થવામાં નિષà«àª«àª³ થઇ.</translation>
<translation id="8877192140621905067">àªàª•àªµàª¾àª° તમે પà«àª·à«àªŸàª¿ કરી લો તે પછી, આ સાઇટ સાથે તમારા કારà«àª¡àª¨à«€ વિગતો શેર કરવામાં આવશે</translation>
<translation id="8889402386540077796">હà«àª¯à«</translation>
@@ -827,7 +840,6 @@
<translation id="8931333241327730545">શà«àª‚ તમે આ કારà«àª¡àª¨à«‡ તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª®àª¾àª‚ સાચવવા માગો છો?</translation>
<translation id="8932102934695377596">તમારી ઘડિયાળ પાછળ છે</translation>
<translation id="8954894007019320973">(ચાલà«.)</translation>
-<translation id="895548565263634352"><ph name="ARTICLE_PUBLISHER" /> અને <ph name="OTHER_ARTICLE_COUNT" /> વધૠપરથી વારà«àª¤àª¾àª“ વાંચો</translation>
<translation id="8971063699422889582">સરà«àªµàª°àª¨àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«€ સમયસીમા સમાપà«àª¤ થઈ છે.</translation>
<translation id="8986494364107987395">ઉપયોગિતા આંકડાઓ અને કà«àª°à«‡àª¶ રિપોરà«àªŸà«àª¸ Google ને આપમેળે મોકલો</translation>
<translation id="8987927404178983737">મહિનો</translation>
@@ -845,7 +857,6 @@
<translation id="9068849894565669697">રંગ પસંદ કરો</translation>
<translation id="9076283476770535406">તેમાં વયસà«àª• સામગà«àª°à«€ હોઈ શકે છે</translation>
<translation id="9078964945751709336">વધૠમાહિતી આવશà«àª¯àª•</translation>
-<translation id="9094175695478007090">ચà«àª•àªµàª£à«€ àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ લોંચ કરવામાં અસમરà«àª¥.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> સામાનà«àª¯ રીતે તમારી માહિતીને સà«àª°àª•à«àª·àª¿àª¤ રાખવા માટે àªàª¨à«àª•à«àª°àª¿àªªà«àª¶àª¨àª¨à«‹ ઉપયોગ કરે છે. જà«àª¯àª¾àª°à«‡ આ સમયે Chromium દà«àªµàª¾àª°àª¾ <ph name="SITE" /> થી કનેકà«àªŸ કરવાનો પà«àª°àª¯àª¾àª¸ થયો, તà«àª¯àª¾àª°à«‡ વેબસાઇટે અસામાનà«àª¯ અને ખોટા ઓળખાણપતà«àª°à«‹àª¨à«‡ પાછા મોકલà«àª¯àª¾àª‚. આવà«àª‚ તà«àª¯àª¾àª°à«‡ થઇ શકે જà«àª¯àª¾àª°à«‡ કોઈ હà«àª®àª²àª¾àª–ોર <ph name="SITE" /> હોવાનો ડોળ કરવાનો પà«àª°àª¯àª¾àª¸ કરી રહà«àª¯à«‹ હોય અથવા કોઈ Wi-Fi સાઇન-ઇન સà«àª•à«àª°à«€àª¨à«‡ કનેકà«àª¶àª¨àª®àª¾àª‚ વિકà«àª·à«‡àªª પાડà«àª¯à«‹ હોય. તમારી માહિતી હજી પણ સà«àª°àª•à«àª·àª¿àª¤ છે કારણ કે Chromium ઠકોઈપણ ડેટા વિનિમય થાય તે પહેલાં જ કનેકà«àª¶àª¨ રોકી દીધà«àª‚.</translation>
<translation id="9137013805542155359">મૂળ બતાવો</translation>
<translation id="9137248913990643158">આ àªàªªà«àª²àª¿àª•à«‡àª¶àª¨àª¨à«‹ ઉપયોગ કરતાં પહેલાં કૃપા કરીને Chrome ને પà«àª°àª¾àª°àª‚ભ કરો અને સાઇન ઇન કરો.</translation>
diff --git a/chromium/components/strings/components_strings_hi.xtb b/chromium/components/strings/components_strings_hi.xtb
index 7a010440057..6d64e70566d 100644
--- a/chromium/components/strings/components_strings_hi.xtb
+++ b/chromium/components/strings/components_strings_hi.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="hi">
<translation id="1008557486741366299">अभी नहीं</translation>
<translation id="1015730422737071372">अतिरिकà¥à¤¤ विवरण पà¥à¤°à¤¦à¤¾à¤¨ करें</translation>
+<translation id="1021110881106174305">सà¥à¤µà¥€à¤•à¤¾à¤°à¥à¤¯ कारà¥à¤¡</translation>
<translation id="1032854598605920125">घड़ी की दिशा में घà¥à¤®à¤¾à¤à¤‚</translation>
<translation id="1038842779957582377">अजà¥à¤žà¤¾à¤¤ नाम</translation>
<translation id="1050038467049342496">दूूूूसरे à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ बंद करें</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">मान छिपाà¤à¤‚</translation>
<translation id="1228893227497259893">गलत इकाई पहचानकरà¥à¤¤à¤¾</translation>
<translation id="1232569758102978740">शीरà¥à¤·à¤• रहित</translation>
+<translation id="1263231323834454256">पठन सूची</translation>
<translation id="1264126396475825575">ख़राबी रिपोरà¥à¤Ÿ <ph name="CRASH_TIME" /> पर कैपà¥à¤šà¤° की गई (अभी तक अपलोड नहीं की गई या उसे अनदेखा किया गया)</translation>
<translation id="1285320974508926690">कभी भी इस साइट का अनà¥à¤µà¤¾à¤¦ न करें</translation>
<translation id="129553762522093515">हाल ही में बंद किठगà¤</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® ऑटोमैटिक भरने वाली सेटिंग...</translation>
<translation id="1374468813861204354">सà¥à¤à¤¾à¤µ</translation>
<translation id="1375198122581997741">वरà¥à¤¶à¤¨ के बारे में</translation>
+<translation id="1377321085342047638">कारà¥à¤¡ नंबर</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> ने कोई डेटा नहीं भेजा.</translation>
<translation id="1407135791313364759">सभी खोलें</translation>
<translation id="1413809658975081374">निजता गड़बड़ी</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">इतिहास</translation>
<translation id="1645368109819982629">असमरà¥à¤¥à¤¿à¤¤ पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¥‰à¤²</translation>
<translation id="1656489000284462475">पिकअप</translation>
+<translation id="1663943134801823270">कारà¥à¤¡ और पते Chrome से मिलते हैं. आप उनà¥à¤¹à¥‡à¤‚ <ph name="BEGIN_LINK" />सेटिंग<ph name="END_LINK" /> में पà¥à¤°à¤¬à¤‚धित कर सकते हैं.</translation>
<translation id="1676269943528358898">आपकी जानकारी की सà¥à¤°à¤•à¥à¤·à¤¾ करने के लिठ<ph name="SITE" /> आमतौर पर à¤à¤¨à¥à¤•à¥à¤°à¤¿à¤ªà¥à¤¶à¤¨ का उपयोग करती है. जब Google Chrome ने इस बार <ph name="SITE" /> से कनेकà¥à¤Ÿ करने का पà¥à¤°à¤¯à¤¾à¤¸ किया, तो वेबसाइट ने असामानà¥à¤¯ और गलत कà¥à¤°à¥‡à¤¡à¥‡à¤‚शियल वापस भेजे. à¤à¤¸à¤¾ तब हो सकता है जब कोई हमलावर <ph name="SITE" /> होने का दावा करने का पà¥à¤°à¤¯à¤¾à¤¸ कर रहा हो या किसी वाई-फ़ाई पà¥à¤°à¤µà¥‡à¤¶ सà¥à¤•à¥à¤°à¥€à¤¨ ने कनेकà¥à¤¶à¤¨ को बाधित कर दिया हो. आपकी जानकारी अभी भी सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ है कà¥à¤¯à¥‹à¤‚कि किसी भी डेटा के आदान-पà¥à¤°à¤¦à¤¾à¤¨ से पहले ही Google Chrome ने कनेकà¥à¤¶à¤¨ को रोक दिया था.</translation>
<translation id="168328519870909584"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> पर मौजूद हमलावर आपके डिवाइस पर à¤à¤¸à¥‡ खतरनाक पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® इंसà¥à¤Ÿà¥‰à¤² करने की कोशिश कर सकते हैं जो आपकी जानकारी (उदाहरण के लिà¤, फ़ोटो, पासवरà¥à¤¡, संदेश और कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡) को चà¥à¤°à¤¾ लेते हैं या उसे हटा देते हैं.</translation>
<translation id="168841957122794586">सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° में कमज़ोर कà¥à¤°à¤¿à¤ªà¥à¤Ÿà¥‹à¤—à¥à¤°à¤¾à¤«à¤¼à¤¿à¤• कà¥à¤‚जी है.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">आपको <ph name="NAME" /> से इस साइट पर जाने की अनà¥à¤®à¤¤à¤¿ लेनी होगी</translation>
+<translation id="1721424275792716183">* फ़ीलà¥à¤¡ ज़रूरी है</translation>
<translation id="1728677426644403582">आप à¤à¤• वेब पेज का सà¥à¤°à¥‹à¤¤ देख रहे हैं</translation>
+<translation id="173080396488393970">इस तरह का कारà¥à¤¡ काम नहीं करता</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">सिसà¥à¤Ÿà¤® वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤• से संपरà¥à¤• करने का पà¥à¤°à¤¯à¤¾à¤¸ करें.</translation>
+<translation id="1740951997222943430">खतà¥à¤® होने का मानà¥à¤¯ महीना डालें</translation>
<translation id="1745358365027406341">पेज को बाद में डाउनलोड करें</translation>
<translation id="17513872634828108">टैब खोलें</translation>
<translation id="1753706481035618306">पृषà¥â€à¤  संखà¥â€à¤¯à¤¾</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">कृपया अपना समनà¥â€à¤µà¤¯à¤¨ पासफà¥à¤°à¥‡à¤œà¤¼ अपडेट करें.</translation>
<translation id="1787142507584202372">आपके दà¥à¤µà¤¾à¤°à¤¾ खोले गठटैब, यहां दिखाई देंगे</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">वितरण विधियों और आवशà¥à¤¯à¤•à¤¤à¤¾à¤“ं को देखने के लिठकोई वितरण पता चà¥à¤¨à¥‡à¤‚.</translation>
+<translation id="1803264062614276815">कारà¥à¤¡ के मालिक का नाम</translation>
<translation id="1803678881841855883">Google सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग को हाल ही में <ph name="SITE" /> पर <ph name="BEGIN_LINK" />मैलवेयर का पता चला<ph name="END_LINK" /> है. आमतौर पर सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ रहने वाली वेबसाइट कभी-कभी मैलवेयर से संकà¥à¤°à¤®à¤¿à¤¤ हो जाती हैं. दà¥à¤°à¥à¤­à¤¾à¤µà¤¨à¤¾à¤ªà¥‚रà¥à¤£ सामगà¥à¤°à¥€ <ph name="SUBRESOURCE_HOST" /> से आती है, जिसे जà¥à¤žà¤¾à¤¤ मैलवेयर वितरक कहा जाता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440"><ph name="ADDED_TO_AUTOFILL_MONTH" /> को जोड़ा गया</translation>
<translation id="1821930232296380041">अमानà¥à¤¯ अनà¥à¤°à¥‹à¤§ या अनà¥à¤°à¥‹à¤§ पैरामीटर</translation>
<translation id="1826516787628120939">जांच की जा रही है</translation>
<translation id="1834321415901700177">इस साइट में हानिकारक पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® हैं</translation>
<translation id="1842969606798536927">भà¥à¤—तान करें</translation>
-<translation id="1864455488461349376">वितरण विकलà¥à¤ª</translation>
<translation id="1871208020102129563">पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ को फ़िकà¥â€à¤¸à¥â€à¤¡ पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ सरà¥à¤µà¤° का उपयोग करने के लिठसेट किया गया है, .pac सà¥â€à¤•à¥à¤°à¤¿à¤ªà¥â€à¤Ÿ फ़ाइल का उपयोग करने के लिठनहीं.</translation>
<translation id="1871284979644508959">आवशà¥à¤¯à¤• फ़ीलà¥à¤¡</translation>
<translation id="187918866476621466">शà¥à¤°à¥à¤†à¤¤à¥€ पनà¥à¤¨à¤¾ खोलें</translation>
<translation id="1883255238294161206">सूची संकà¥à¤·à¤¿à¤ªà¥à¤¤ करें</translation>
<translation id="1898423065542865115">फ़िलà¥à¤Ÿà¤° किया जा रहा है</translation>
<translation id="194030505837763158"><ph name="LINK" /> पर जाà¤à¤‚</translation>
-<translation id="1946821392246652573">सà¥à¤µà¥€à¤•à¥ƒà¤¤ कारà¥à¤¡</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="1973335181906896915">कà¥à¤°à¤®à¤¬à¤¦à¥à¤§ करने में गड़बड़ी</translation>
<translation id="1974060860693918893">उनà¥à¤¨à¤¤</translation>
<translation id="1978555033938440688">फ़रà¥à¤®à¤µà¥‡à¤¯à¤° वरà¥à¤¶à¤¨</translation>
+<translation id="1995859865337580572">कृपया अपने CVC की पà¥à¤·à¥à¤Ÿà¤¿ करें</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{और 1 अधिक}one{और # अधिक}other{और # अधिक}}</translation>
-<translation id="2020194265157481222">कारà¥à¤¡ पर नाम आवशà¥à¤¯à¤• है</translation>
<translation id="2025186561304664664">पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ सà¥â€à¤µà¤¤: कॉनà¥â€à¤«à¤¼â€à¤¿à¤—र पर सेट है.</translation>
<translation id="2030481566774242610">कà¥à¤¯à¤¾ आप मतलब <ph name="LINK" /> से है?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ और फायरवॉल की जांच करें<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">आज</translation>
<translation id="2154054054215849342">आपके डोमेन के लिठसिंक करने की सà¥à¤µà¤¿à¤§à¤¾ उपलबà¥â€à¤§ नहीं है</translation>
<translation id="2154484045852737596">कारà¥à¤¡ संपादित करें</translation>
-<translation id="2156993118928861787">अमानà¥à¤¯ पता</translation>
<translation id="2166049586286450108">पूरà¥à¤£ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤•à¥€à¤¯ à¤à¤•à¥à¤¸à¥‡à¤¸</translation>
<translation id="2166378884831602661">यह साइट सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ कनेकà¥à¤¶à¤¨ पà¥à¤°à¤¦à¤¾à¤¨ नहीं कर सकती</translation>
<translation id="2181821976797666341">नीतियां</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 पता}one{# पते}other{# पते}}</translation>
+<translation id="2202020181578195191">खतà¥à¤® होने का मानà¥à¤¯ वरà¥à¤· डालें</translation>
<translation id="2212735316055980242">नीति नहीं मिली</translation>
<translation id="2213606439339815911">पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿à¤¯à¤¾à¤‚ फ़ेच की जा रही हैं...</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />निदान à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨<ph name="END_LINK" /> का उपयोग करके अपने कनेकà¥à¤¶à¤¨ को ठीक करें</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">आपका इंटरनेट कनेकà¥à¤¶à¤¨ अवरà¥à¤¦à¥à¤§ है</translation>
<translation id="230155334948463882">नया कारà¥à¤¡?</translation>
<translation id="2305919008529760154">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; हो सकता है कि उसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° कपटपूरà¥à¤µà¤• जारी किया गया हो. à¤à¤¸à¤¾ किसी गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">कारà¥à¤¡ और पता विकलà¥à¤ª आपके Google खाते (<ph name="ACCOUNT_EMAIL" />) और Chrome के हैं. आप <ph name="BEGIN_LINK" />सेटिंग<ph name="END_LINK" /> में इनà¥à¤¹à¥‡à¤‚ पà¥à¤°à¤¬à¤‚धित कर सकते हैं.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> के लिठउपयोगकरà¥à¤¤à¤¾ नाम और पासवरà¥à¤¡ आवशà¥à¤¯à¤• है.</translation>
<translation id="2318774815570432836">आप इस समय <ph name="SITE" /> पर विज़िट नहीं कर सकते कà¥à¤¯à¥‹à¤‚कि वेबसाइट HSTS का उपयोग करती है. नेटवरà¥à¤• की गड़बड़ियां और हमले आमतौर पर असà¥à¤¥à¤¾à¤¯à¥€ होते हैं, इसलिठसंभवत: यह पेज बाद में काम करेगा. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">अनà¥à¤¯ बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">à¤à¤‚टरपà¥à¤°à¤¾à¤‡à¤œà¤¼ डिफ़ॉलà¥à¤Ÿ</translation>
<translation id="2386255080630008482">सरà¥à¤µà¤° का पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निरसà¥à¤¤ कर दिया गया है.</translation>
<translation id="2392959068659972793">कोई भी मान सेट नहीं की गई नीतियां दिखाà¤à¤‚</translation>
+<translation id="239429038616798445">शिपिंग का यह तरीका उपलबà¥à¤§ नहीं है. कोई दूसरा तरीका आज़माà¤à¤‚.</translation>
<translation id="2396249848217231973">&amp;हटाना वापस लाà¤à¤‚</translation>
<translation id="2460160116472764928">Google सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग को हाल ही में <ph name="SITE" /> पर <ph name="BEGIN_LINK" />मैलवेयर का पता चला<ph name="END_LINK" /> है. आमतौर पर सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ रहने वाली वेबसाइट कभी-कभी मैलवेयर से संकà¥à¤°à¤®à¤¿à¤¤ हो जाती हैं. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">भरें</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />नेटवरà¥à¤• निदान चलाकर देखें<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">अमानà¥â€à¤¯ खोज URL.</translation>
<translation id="2491120439723279231">सरà¥à¤µà¤° के पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° में तà¥à¤°à¥à¤Ÿà¤¿à¤¯à¤¾à¤‚ हैं.</translation>
-<translation id="24943777258388405">अमानà¥à¤¯ फ़ोन नंबर</translation>
<translation id="2495083838625180221">JSON पारà¥à¤¸à¤°</translation>
<translation id="2495093607237746763">यदि चेक किया गया हो, तो अधिक तेज़ी से फ़ॉरà¥à¤® भरने के लिठकà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® इस डिवाइस पर आपके कारà¥à¤¡ की कॉपी संगà¥à¤°à¤¹à¤¿à¤¤ करेगा.</translation>
<translation id="2498091847651709837">नया कारà¥à¤¡ सà¥â€à¤•à¥ˆà¤¨ करें</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> ने à¤à¤• अमानà¥à¤¯ पà¥à¤°à¤¤à¤¿à¤¸à¤¾à¤¦ भेजा है.</translation>
<translation id="2552545117464357659">इससे नà¤</translation>
<translation id="2556876185419854533">&amp;संपादन वापस लाà¤à¤‚</translation>
+<translation id="2587730715158995865"><ph name="ARTICLE_PUBLISHER" /> की ओर से. यह और <ph name="OTHER_ARTICLE_COUNT" /> दूसरे समाचार पढ़ें.</translation>
<translation id="2587841377698384444">निरà¥à¤¦à¥‡à¤¶à¤¿à¤•à¤¾ API आईडी:</translation>
<translation id="2597378329261239068">यह दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ पासवरà¥à¤¡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ है. कृपया पासवरà¥à¤¡ डालें.</translation>
<translation id="2609632851001447353">विविधताà¤à¤‚</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />नेटवरà¥à¤• कनेकà¥à¤Ÿà¤¿à¤µà¤¿à¤Ÿà¥€ चलाकर देखें<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">ठीक</translation>
<translation id="2742870351467570537">चयनित आइटम निकालें</translation>
+<translation id="277133753123645258">शिपिंग का तरीका</translation>
<translation id="277499241957683684">डिवाइस का रिकॉरà¥à¤¡ लापता है</translation>
<translation id="2784949926578158345">कनेकà¥â€à¤¶à¤¨ रीसेट किया गया था.</translation>
<translation id="2794233252405721443">साइट अवरोधित है</translation>
-<translation id="2812680587231492111">वह पिकअप विकलà¥à¤ª उपलबà¥à¤§ नहीं है. कोई दूसरा विकलà¥à¤ª आज़माà¤à¤‚.</translation>
<translation id="2824775600643448204">पता और खोज बार</translation>
<translation id="2826760142808435982">कनेकà¥à¤¶à¤¨ को <ph name="CIPHER" /> का उपयोग करके à¤à¤¨à¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ और पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ किया गया है और यह कà¥à¤‚जी विनिमय तकनीक के रूप में <ph name="KX" /> का उपयोग करता है.</translation>
<translation id="2835170189407361413">फ़ॉरà¥à¤® साफ़ करें</translation>
-<translation id="2849041323157393173">वह वितरण विकलà¥à¤ª उपलबà¥à¤§ नहीं है. कोई दूसरा विकलà¥à¤ª आज़माà¤à¤‚.</translation>
<translation id="2889159643044928134">पà¥à¤¨: लोड ना करें</translation>
<translation id="2900469785430194048">यह वेबपेज दिखाते समय Google Chrome में जगह नहीं बची.</translation>
<translation id="2909946352844186028">नेटवरà¥à¤• में बदलाव का पता चला.</translation>
<translation id="2916038427272391327">दूसरे पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® बंद करें</translation>
<translation id="2922350208395188000">सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की जांच नहीं की जा सकती.</translation>
+<translation id="2928905813689894207">बिलिंग पता</translation>
<translation id="2948083400971632585">आप किसी कनेकà¥à¤¶à¤¨ के लिठकॉनà¥à¤«à¤¼à¤¿à¤—र की गई किसी भी पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ को सेटिंग पेज से अकà¥à¤·à¤® कर सकते हैं.</translation>
<translation id="2955913368246107853">खोज बार बंद करें</translation>
<translation id="2958431318199492670">नेटवरà¥à¤• कॉनà¥à¤«à¤¼à¤¿à¤—रेशन ONC मानक का पालन नहीं करता. कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कà¥à¤› भाग आयात नहीं किठजा सकते हैं.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ कनेकà¥â€à¤¶à¤¨ सà¥â€à¤¥à¤¾à¤ªà¤¿à¤¤ करने के लिà¤, आपकी घड़ी को सही तरीके से सेट किठजाने की आवशà¥â€à¤¯à¤•à¤¤à¤¾ है. à¤à¤¸à¤¾ इसलिठकà¥â€à¤¯à¥‹à¤‚कि वेबसाइटों दà¥à¤µà¤¾à¤°à¤¾ सà¥â€à¤µà¤¯à¤‚ की पहचान करने के लिठउपयोग किठजाने वाले पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° केवल विशिषà¥â€à¤Ÿ समयावधियों के लिठही मानà¥â€à¤¯ होते हैं. चूंकि आपके डिवाइस की घड़ी गलत है, इसलिठGoogle Chrome इन पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¥‹à¤‚ का सतà¥â€à¤¯à¤¾à¤ªà¤¨ नहीं कर सकता.</translation>
<translation id="2972581237482394796">&amp;फिर से करें</translation>
<translation id="2985306909656435243">यदि सकà¥à¤·à¤® किया गया हो, तो अधिक तेज़ी से फ़ॉरà¥à¤® भरने के लिठकà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® इस डिवाइस पर आपके कारà¥à¤¡ की à¤à¤• कॉपी संगà¥à¤°à¤¹à¤¿à¤¤ करेगा.</translation>
+<translation id="2985398929374701810">मानà¥à¤¯ पता डालें</translation>
+<translation id="2986368408720340940">पिकअप का यह तरीका उपलबà¥à¤§ नहीं है. कोई दूसरा तरीका आज़माà¤à¤‚.</translation>
<translation id="2991174974383378012">वेबसाइटों के साथ साà¤à¤¾à¤•à¤°à¤£</translation>
<translation id="3005723025932146533">सहेजी गई पà¥à¤°à¤¤à¤¿à¤²à¤¿à¤ªà¤¿ दिखाà¤à¤‚</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> का CVC डालें. आपकी तरफ से पà¥à¤·à¥à¤Ÿà¤¿ हो जाने पर, आपके कारà¥à¤¡ के विवरण इस साइट के साथ साà¤à¤¾ किठजाà¤à¤‚गे.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{समनà¥à¤µà¤¯à¤¿à¤¤ डिवाइस पर कम से कम 1 आइटम}=1{1 आइटम (समनà¥à¤µà¤¯à¤¿à¤¤ डिवाइस पर और भी)}one{# आइटम (समनà¥à¤µà¤¯à¤¿à¤¤ डिवाइस पर और भी)}other{# आइटम (समनà¥à¤µà¤¯à¤¿à¤¤ डिवाइस पर और भी)}}</translation>
<translation id="3041612393474885105">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° जानकारी</translation>
<translation id="3063697135517575841">Chrome इस समय आपके कारà¥à¤¡ की पà¥à¤·à¥à¤Ÿà¤¿ नहीं कर सका. कृपया बाद में पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें.</translation>
+<translation id="3064966200440839136">किसी बाहरी à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ के ज़रिठभà¥à¤—तान करने के लिठगà¥à¤ªà¥à¤¤ मोड छोड़ रहे हैं. जारी रखना चाहते हैं?</translation>
<translation id="3093245981617870298">आप ऑफ़लाइन हैं.</translation>
<translation id="3105172416063519923">à¤à¤¸à¥‡à¤Ÿ आईडी:</translation>
<translation id="3109728660330352905">आपके पास इस पेज को देखने के लिठपà¥à¤°à¤¾à¤§à¤¿à¤•à¤°à¤£ नहीं है.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />कनेकà¥à¤Ÿà¤¿à¤µà¤¿à¤Ÿà¥€ निदान चलाकर देखें<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">उतà¥à¤¤à¤° डीकोड करने में विफल</translation>
-<translation id="3149891296864842641">शिपिंग विकलà¥à¤ª</translation>
<translation id="3150653042067488994">असà¥à¤¥à¤¾à¤¯à¥€ सरà¥à¤µà¤° गड़बड़ी</translation>
+<translation id="3154506275960390542">इस पेज में à¤à¤¸à¤¾ फ़ॉरà¥à¤® शामिल है, जो सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ रूप से सबमिट नहीं किया जा सकता है. टà¥à¤°à¤¾à¤‚ज़िट में होने के दौरान आपके भेजे जाने वाले डेटा को दूसरे लोग देख सकते हैं या सरà¥à¤µà¤° को मिलने वाली सामगà¥à¤°à¥€ में बदलाव करने के लिठकोई आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ उसे संशोधित कर सकता है.</translation>
<translation id="3157931365184549694">पà¥à¤¨à¤°à¥à¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करें</translation>
<translation id="3167968892399408617">आपके दà¥à¤µà¤¾à¤°à¤¾ गà¥à¤ªà¥à¤¤ टैब में देखे जाने वाले पेज, आपके दà¥à¤µà¤¾à¤°à¤¾ अपने सभी गà¥à¤ªà¥à¤¤ टैब बंद कर देने के बाद आपके बà¥à¤°à¤¾à¤‰à¥›à¤° के इतिहास, कà¥à¤•à¥€ संगà¥à¤°à¤¹, या खोज इतिहास में नहीं रहेंगे. आपके दà¥à¤µà¤¾à¤°à¤¾ डाउनलोड की गईं सभी फ़ाइलें या बनाठगठबà¥à¤•à¤®à¤¾à¤°à¥à¤• रख लिठजाà¤à¤‚गे.</translation>
<translation id="3169472444629675720">तलाश करें</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">इस साइट को à¤à¤•à¥â€à¤¸à¥‡à¤¸ करने का आपका अनà¥à¤°à¥‹à¤§ <ph name="NAME" /> को नहीं भेजा जा सका. कृपया पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें.</translation>
<translation id="3355823806454867987">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सेटिंग बदलें...</translation>
<translation id="3369192424181595722">घड़ी गड़बड़ी</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> और आइटम...</translation>
<translation id="337363190475750230">पà¥à¤°à¤¾à¤µà¤§à¤¾à¤¨ रदà¥à¤¦</translation>
<translation id="3377188786107721145">नीति पारà¥à¤¸ गड़बड़ी</translation>
<translation id="3380365263193509176">अजà¥à¤žà¤¾à¤¤ गड़बड़ी</translation>
<translation id="3380864720620200369">कà¥à¤²à¤¾à¤‡à¤‚ट आईडी:</translation>
<translation id="3391030046425686457">वितरण पता</translation>
+<translation id="3395827396354264108">पिकअप का तरीका</translation>
<translation id="340013220407300675">हो सकता है हमलावर <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> से आपकी जानकारी चà¥à¤°à¤¾à¤¨à¥‡ का पà¥à¤°à¤¯à¤¾à¤¸ कर रहे हों (उदाहरण के लिठपासवरà¥à¤¡, संदेश या कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡).</translation>
<translation id="3422248202833853650">जगह खाली करने के लिठदूसरे पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® से बाहर निकलकर देखें.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> वरà¥à¤¤à¤®à¤¾à¤¨ में पहà¥à¤‚च योगà¥à¤¯ नहीं है.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">पà¥à¤°à¤¾à¤ªà¥à¤¤à¤¿ अंतराल:</translation>
<translation id="3462200631372590220">उनà¥à¤¨à¤¤ को छिपाà¤à¤‚</translation>
+<translation id="3467763166455606212">कारà¥à¤¡ मालिक का नाम ज़रूरी है</translation>
+<translation id="3478058380795961209">समापà¥à¤¤à¤¿ माह</translation>
<translation id="3479539252931486093">कà¥à¤¯à¤¾ यह अनपेकà¥à¤·à¤¿à¤¤ था? <ph name="BEGIN_LINK" />हमें बताà¤à¤‚<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">अभी नहीं</translation>
<translation id="348000606199325318">कà¥à¤°à¥ˆà¤¶ आईडी <ph name="CRASH_LOCAL_ID" /> (सरà¥à¤µà¤° आईडी: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">हम इस समय आपके अभिभावक तक नहीं पहà¥à¤‚च पा रहे हैं. कृपया पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें.</translation>
<translation id="3528171143076753409">सरà¥à¤µà¤° का पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं है.</translation>
-<translation id="3538531656504267329">समापà¥à¤¤ होने का वरà¥à¤· मानà¥à¤¯ नहीं है</translation>
<translation id="3539171420378717834">इस डिवाइस पर इस कारà¥à¤¡ की पà¥à¤°à¤¤à¤¿à¤²à¤¿à¤ªà¤¿ रखें</translation>
<translation id="3542684924769048008">इसके लिठपासवरà¥à¤¡ का उपयोग करें:</translation>
<translation id="3549644494707163724">सभी समनà¥à¤µà¤¯à¤¿à¤¤ डेटा को अपने सà¥à¤µà¤¯à¤‚ के समनà¥à¤µà¤¯à¤¨ पासफ़à¥à¤°à¥‡à¤œà¤¼ के साथ à¤à¤¨à¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ करें</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">विवरण छà¥à¤ªà¤¾à¤à¤‚</translation>
<translation id="3587482841069643663">सभी</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">खतà¥à¤® होने की मानà¥à¤¯ तारीख डालें</translation>
<translation id="36224234498066874">बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग डेटा साफ़ करें...</translation>
<translation id="362276910939193118">संपूरà¥à¤£ इतिहास दिखाà¤à¤‚</translation>
<translation id="3623476034248543066">मान दिखाà¤à¤‚</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">पासवरà¥à¤¡:</translation>
<translation id="3696411085566228381">कोई नहीं</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">शिपिंग की विधियां और आवशà¥à¤¯à¤•à¤¤à¤¾à¤à¤‚ देखने के लिठशिपिंग पता चà¥à¤¨à¥‡à¤‚.</translation>
<translation id="370665806235115550">लोड हो रही हैं...</translation>
<translation id="3712624925041724820">लाइसेंस समापà¥à¤¤ हो गà¤</translation>
<translation id="3714780639079136834">मोबाइल डेटा या वाई-फ़ाई चालू करें</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">काॅपी किया गया लिंक</translation>
<translation id="375403751935624634">सरà¥à¤µà¤° गड़बड़ी के कारण अनà¥à¤µà¤¾à¤¦ विफल.</translation>
<translation id="3759461132968374835">आपके पास हाल ही में रिपोरà¥à¤Ÿ किठगठकà¥à¤°à¥ˆà¤¶ नहीं हैं. कà¥à¤°à¥ˆà¤¶ रिपोरà¥à¤Ÿà¤¿à¤‚ग अकà¥à¤·à¤® होने के दौरान होने वाले कà¥à¤°à¥ˆà¤¶ यहां दिखाई नहीं देंगे.</translation>
+<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /> में खतà¥à¤® होगा</translation>
<translation id="382518646247711829">यदि आप पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सरà¥à¤µà¤° का उपयोग करते हैं...</translation>
<translation id="3828924085048779000">खाली पासफ़à¥à¤°à¥‡à¤œà¤¼ की अनà¥à¤®à¤¤à¤¿ नहीं है.</translation>
<translation id="3845539888601087042">आपके पà¥à¤°à¤µà¥‡à¤¶ किठगठडिवाइस का इतिहास दिखाया जा रहा है. <ph name="BEGIN_LINK" />अधिक जानें<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">कà¥à¤¯à¤¾ आप चाहते हैं कि कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® इस कारà¥à¤¡ को सहेजे?</translation>
<translation id="4171400957073367226">गलत सतà¥à¤¯à¤¾à¤ªà¤¨ हसà¥à¤¤à¤¾à¤•à¥à¤·à¤°</translation>
-<translation id="4176463684765177261">अकà¥à¤·à¤®</translation>
<translation id="4196861286325780578">&amp;ले जाना फिर से करें</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />फायरवॉल और à¤à¤‚टीवायरस कॉनà¥à¥žà¤¿à¤—रेशन की जांच करें<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{कोई नहीं}=1{1 à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ ($1)}=2{2 à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ ($1, $2)}one{# à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ ($1, $2, $3)}other{# à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">खोज परिणाम</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ने आपका लॉगिन पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सà¥à¤µà¥€à¤•à¤¾à¤° नहीं किया है या हो सकता है कि पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° उपलबà¥à¤§ नहीं कराया गया हो.</translation>
<translation id="443673843213245140">पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ का उपयोग अकà¥à¤·à¤® है लेकिन कोई सà¥â€à¤ªà¤·à¥à¤Ÿ पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ कॉनà¥à¥žà¤¿à¤—रेशन निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ किया गया है.</translation>
-<translation id="4446242550670694251">अब आप निजी रूप से बà¥à¤°à¤¾à¤‰à¤œà¤¼ कर सकते हैं और इस डिवाइस का उपयोग करने वाले दूसरे लोगों को आपकी गतिविधि दिखाई नहीं देगी.</translation>
<translation id="4492190037599258964">'<ph name="SEARCH_STRING" />' के खोज परिणाम</translation>
<translation id="4506176782989081258">सतà¥â€à¤¯à¤¾à¤ªà¤¨ गड़बड़ी: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">सिसà¥à¤Ÿà¤® वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤• से संपरà¥à¤• करें</translation>
<translation id="450710068430902550">वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤• के साथ साà¤à¤¾ करना</translation>
+<translation id="4515275063822566619">कारà¥à¤¡ और पते Chrome और आपके Google खाते (<ph name="ACCOUNT_EMAIL" />) से मिलते हैं. आप उनà¥à¤¹à¥‡à¤‚ <ph name="BEGIN_LINK" />सेटिंग<ph name="END_LINK" /> में जाकर पà¥à¤°à¤¬à¤‚धित कर सकते हैं.</translation>
<translation id="4522570452068850558">विवरण</translation>
<translation id="4558551763791394412">अपने à¤à¤•à¥à¤¸à¤Ÿà¥‡à¤‚शन अकà¥à¤·à¤® करके देखें.</translation>
<translation id="457875822857220463">वितरण</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">पेज में फ़िट करें</translation>
<translation id="483020001682031208">दिखाने के लिठकोई जीता-जागता वेब पेज नहीं है</translation>
<translation id="4850886885716139402">देखें</translation>
+<translation id="4854362297993841467">वितरण का यह तरीका उपलबà¥à¤§ नहीं है. कोई दूसरा तरीका आज़माà¤à¤‚.</translation>
<translation id="4858792381671956233">आपने अपने अभिभावकों से पूछा था कि इस साइट पर जाना ठीक है या नहीं</translation>
<translation id="4880827082731008257">खोज इतिहास</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">इस पेज का à¤à¤• अजà¥à¤žà¤¾à¤¤ भाषा से <ph name="LANGUAGE_LANGUAGE" /> में अनà¥à¤µà¤¾à¤¦ किया गया है</translation>
<translation id="4923459931733593730">भà¥à¤—तान</translation>
<translation id="4926049483395192435">निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ किया जाना चाहिà¤.</translation>
-<translation id="4941291666397027948">* आवशà¥â€à¤¯à¤• फ़ीलà¥â€à¤¡ इंगित करता है</translation>
<translation id="495170559598752135">कà¥à¤°à¤¿à¤¯à¤¾à¤à¤‚</translation>
<translation id="4958444002117714549">सूची विसà¥à¤¤à¥ƒà¤¤ करें</translation>
<translation id="4962322354953122629">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° Chrome दà¥à¤µà¤¾à¤°à¤¾ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">ग़लत पासवरà¥à¤¡</translation>
<translation id="5056549851600133418">आपके लिठलेख</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ पते की जांच करें<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{कोई कà¥à¤•à¥€ नहीं}=1{1 साइट कà¥à¤•à¥€ का उपयोग करती है. }one{# साइटें कà¥à¤•à¥€ का उपयोग करती हैं. }other{# साइटें कà¥à¤•à¥€ का उपयोग करती हैं. }}</translation>
<translation id="5087286274860437796">सरà¥à¤µà¤° का पà¥à¤°à¤®à¤¾à¤£ पतà¥à¤° इस समय मानà¥à¤¯ नहीं है.</translation>
<translation id="5087580092889165836">कारà¥à¤¡ जोड़ें</translation>
<translation id="5089810972385038852">राजà¥à¤¯</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">दिखाà¤à¤‚</translation>
<translation id="5308689395849655368">कà¥à¤°à¥ˆà¤¶ की रिपोरà¥à¤Ÿ करना अकà¥à¤·à¤® कर दिया गया है.</translation>
<translation id="5317780077021120954">सहेजें</translation>
-<translation id="5326702247179446998">पà¥à¤°à¤¾à¤ªà¥à¤¤à¤•à¤°à¥à¤¤à¤¾ आवशà¥à¤¯à¤• है</translation>
<translation id="5327248766486351172">नाम</translation>
<translation id="5337705430875057403"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> पर मौजूद हमलावर आपको धोखा देकर आपसे कà¥à¤› जोखिम वाला काम करा सकते हैं, जैसे सॉफ़à¥à¤Ÿà¤µà¥‡à¤¯à¤° इंसà¥à¤Ÿà¥‰à¤² करना या आपकी वà¥à¤¯à¤•à¥à¤¤à¤¿à¤—त जानकारी (उदाहरण के लिà¤, पासवरà¥à¤¡, फ़ोन नंबर या कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡) पà¥à¤°à¤•à¤Ÿ करना.</translation>
-<translation id="53553865750799677">असमरà¥à¤¥à¤¿à¤¤ पिकअप पता. कोई दूसरा पता चà¥à¤¨à¥‡à¤‚.</translation>
<translation id="5359637492792381994">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° इस समय मानà¥à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">नीति सेटिंग संगà¥à¤°à¤¹à¤¿à¤¤ करने में विफल</translation>
<translation id="5386426401304769735">इस साइट की पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° शà¥à¤°à¥ƒà¤‚खला में, SHA-1 का उपयोग करके हसà¥à¤¤à¤¾à¤•à¥à¤·à¤° किया गया पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° शामिल है.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102"><ph name="SITE" /> पर à¤à¤®à¥â€à¤¬à¥‡à¤¡ किठगठपृषà¥â€à¤  का कहना है:</translation>
<translation id="5556459405103347317">पà¥à¤¨: लोड करें</translation>
<translation id="5565735124758917034">सकà¥à¤°à¤¿à¤¯</translation>
+<translation id="5571083550517324815">इस पते से पिक अप नहीं किया जा सकता. कोई दूसरा पता चà¥à¤¨à¥‡à¤‚.</translation>
<translation id="5572851009514199876">कृपया Chrome शà¥à¤°à¥‚ करके उसमें पà¥à¤°à¤µà¥‡à¤¶ करें ताकि Chrome देख सके कि कà¥à¤¯à¤¾ आपके पास यह साइट à¤à¤•à¥à¤¸à¥‡à¤¸ करने की अनà¥à¤®à¤¤à¤¿ है.</translation>
-<translation id="5575380383496039204">असमरà¥à¤¥à¤¿à¤¤ वितरण पता. कोई दूसरा पता चà¥à¤¨à¥‡à¤‚.</translation>
<translation id="5580958916614886209">अपना समापà¥à¤¤à¤¿ माह जांचें और फिर से कोशिश करें</translation>
<translation id="560412284261940334">पà¥à¤°à¤¬à¤‚धन समरà¥à¤¥à¤¿à¤¤ नहीं</translation>
<translation id="5610142619324316209">कनेकà¥à¤¶à¤¨ की जांच करें</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">इस वेबसाइट की पहचान सतà¥à¤¯à¤¾à¤ªà¤¿à¤¤ नहीं की गई है.</translation>
<translation id="5720705177508910913">वरà¥à¤¤à¤®à¤¾à¤¨ उपयोगकरà¥à¤¤à¤¾</translation>
<translation id="5732392974455271431">आपके अभिभावक इसे आपके लिठअनवरोधित कर सकते हैं</translation>
-<translation id="57586589942790530">अमानà¥à¤¯ कारà¥à¤¡ संखà¥à¤¯à¤¾</translation>
+<translation id="5763042198335101085">मानà¥à¤¯ ईमेल पता डालें</translation>
+<translation id="5765072501007116331">वितरण के तरीके और ज़रूरतें देखने के लिà¤, कोई पता चà¥à¤¨à¥‡à¤‚</translation>
<translation id="5784606427469807560">आपके कारà¥à¤¡ की पà¥à¤·à¥à¤Ÿà¤¿ करते समय समसà¥â€à¤¯à¤¾ हà¥à¤ˆ. अपना इंटरनेट कनेकà¥â€à¤¶à¤¨ जांचें और पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें.</translation>
<translation id="5785756445106461925">इसके अतिरिकà¥à¤¤, इस पेज में à¤à¤¸à¥‡ अनà¥à¤¯ संसाधन भी शामिल हैं, जो सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहीं हैं. टà¥à¤°à¤¾à¤‚ज़िट में होने के दौरान ये संसाधन अनà¥à¤¯ लोगों दà¥à¤µà¤¾à¤°à¤¾ देखे जा सकते हैं और पेज का सà¥à¤µà¤°à¥‚प बदलने के लिठकिसी हमवलावर दà¥à¤µà¤¾à¤°à¤¾ इनमें बदलाव किठजा सकते हैं.</translation>
<translation id="5786044859038896871">कà¥à¤¯à¤¾ अपनी कारà¥à¤¡ जानकारी भरना चाहते हैं?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">इस साइट तक नहीं पहà¥à¤‚चा जा सकता</translation>
<translation id="5869522115854928033">सहेजे गठपासवरà¥à¤¡</translation>
<translation id="5872918882028971132">अभिभावक सà¥à¤à¤¾à¤µ</translation>
-<translation id="587760065310675640">असमरà¥à¤¥à¤¿à¤¤ शिपिंग पता. कोई दूसरा पता चà¥à¤¨à¥‡à¤‚.</translation>
<translation id="5901630391730855834">पीला</translation>
-<translation id="59174027418879706">सकà¥à¤·à¤® किया गया</translation>
<translation id="5926846154125914413">आप कà¥à¤› साइटों से पà¥à¤°à¥€à¤®à¤¿à¤¯à¤® सामगà¥à¤°à¥€ की à¤à¤•à¥à¤¸à¥‡à¤¸ खो सकते हैं.</translation>
<translation id="5959728338436674663">Google को कà¥à¤› <ph name="BEGIN_WHITEPAPER_LINK" />सिसà¥à¤Ÿà¤® संबंधी जानकारी और पेज सामगà¥à¤°à¥€<ph name="END_WHITEPAPER_LINK" /> अपने आप भेजें ताकि खतरनाक à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ और साइटों का पता लगाने में सहायता मिल सके. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">सपà¥à¤¤à¤¾à¤¹</translation>
<translation id="5967867314010545767">इतिहास से निकालें</translation>
<translation id="5975083100439434680">ज़ूम आउट</translation>
+<translation id="598637245381783098">भà¥à¤—तान à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ नहीं खोला जा सकता</translation>
<translation id="5989320800837274978">न तो कोई फ़िकà¥â€à¤¸à¥â€à¤¡ पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ सरà¥à¤µà¤° और न ही कोई .pac सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ URL निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ किठगठहैं.</translation>
<translation id="5990559369517809815">सरà¥à¤µà¤° से किठगठअनà¥à¤°à¥‹à¤§à¥‹à¤‚ को à¤à¤•à¥â€à¤¸à¤Ÿà¥‡à¤‚शन दà¥à¤µà¤¾à¤°à¤¾ अवरà¥à¤¦à¥à¤§ कर दिया गया है.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">कारà¥à¤¡ और पता विकलà¥à¤ª Chrome के हैं. आप <ph name="BEGIN_LINK" />सेटिंग<ph name="END_LINK" /> में इनà¥à¤¹à¥‡à¤‚ पà¥à¤°à¤¬à¤‚धित कर सकते हैं.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{पेज 1}one{पेज #}other{पेज #}}</translation>
<translation id="6017514345406065928">हरा</translation>
+<translation id="6027201098523975773">नाम डालें</translation>
<translation id="6040143037577758943">बंद करें</translation>
-<translation id="604124094241169006">सà¥à¤µà¤šà¤¾à¤²à¤¿à¤¤</translation>
<translation id="6042308850641462728">अधिक</translation>
<translation id="6060685159320643512">सावधान, ये पà¥à¤°à¤¯à¥‹à¤— नà¥à¤•à¤¸à¤¾à¤¨ पहà¥à¤‚चा सकते हैं</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{कोई नहीं}=1{1}one{#}other{#}}</translation>
@@ -543,9 +552,10 @@
डिवाइस को रीबूट करें.</translation>
<translation id="614940544461990577">यह आज़माकर देखें:</translation>
<translation id="6151417162996330722">सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की मानà¥â€à¤¯à¤¤à¤¾ अवधि बहà¥à¤¤ लंबी है.</translation>
-<translation id="615643356032862689">डाउनलोड की गई फ़ाइलें और बà¥à¤•à¤®à¤¾à¤°à¥à¤• रखे जाà¤à¤‚गे.</translation>
+<translation id="6157877588268064908">शिपिंग के तरीके और ज़रूरतें देखने केे लिà¤, कोई पता चà¥à¤¨à¥‡à¤‚</translation>
<translation id="6165508094623778733">अधिक जानें</translation>
<translation id="6177128806592000436">इस साइट से आपका कनेकà¥â€à¤¶à¤¨ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहीं है</translation>
+<translation id="6184817833369986695">(समानता रखने वाले लोग: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">अपना इंटरनेट कनेकà¥à¤¶à¤¨ जांचें</translation>
<translation id="6218753634732582820">कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® से पता निकालें?</translation>
<translation id="6251924700383757765">निजता नीति</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;पà¥à¤¨: कà¥à¤°à¤®à¤¿à¤¤ करना फिर से करें</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="6264485186158353794">सà¥à¤°à¤•à¥à¤·à¤¾ पर वापस</translation>
+<translation id="6276112860590028508">आपकी पठन सूची के पेज यहां दिखाई देंगे</translation>
+<translation id="6280223929691119688">इस पते पर वितरित नहीं किया जा सकता. कोई दूसरा पता चà¥à¤¨à¥‡à¤‚.</translation>
<translation id="6282194474023008486">डाक कोड</translation>
<translation id="6290238015253830360">आपके सà¥à¤à¤¾à¤ गठलेख यहां दिखाई देते हैं</translation>
<translation id="6305205051461490394"><ph name="URL" /> तक नहीं पहà¥à¤‚चा जा सकता.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° को रदà¥à¤¦ किया गया है या नहीं यह जांच करने में असमररà¥à¤¥.</translation>
<translation id="6433490469411711332">संपरà¥à¤• जानकारी संपादित करें</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> ने कनेकà¥à¤Ÿ करने से मना कर दिया है.</translation>
-<translation id="6443118737398455446">अमानà¥à¤¯ समापà¥à¤¤à¤¿ दिनांक</translation>
<translation id="6446608382365791566">और जानकारी जोड़ें</translation>
<translation id="6451458296329894277">फ़ारà¥à¤® पà¥à¤¨: जमा करने की दà¥à¤¬à¤¾à¤°à¤¾ पूछें</translation>
<translation id="6456339708790392414">आपका भà¥à¤—तान</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; हो सकता है इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निरसà¥à¤¤ कर दिया गया हो. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">डिवाइस नीतियां</translation>
<translation id="6477321094435799029">Chrome को इस पेज पर असामानà¥à¤¯ कोड मिला था और उसने आपकी वà¥à¤¯à¤•à¥à¤¤à¤¿à¤—त जानकारी (उदाहरण के लिà¤, पासवरà¥à¤¡, फ़ोन नंबर और कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡) की सà¥à¤°à¤•à¥à¤·à¤¾ करने के लिठउसे अवरà¥à¤¦à¥à¤§ कर दिया है.</translation>
-<translation id="6477460825583319731">अमानà¥à¤¯ ईमेल पता</translation>
<translation id="6489534406876378309">कà¥à¤°à¥ˆà¤¶ अपलोड करना पà¥à¤°à¤¾à¤°à¤‚भ करें</translation>
<translation id="6508722015517270189">Chrome को फिर से शà¥à¤°à¥‚ करें</translation>
-<translation id="6525462735697194615">समापà¥à¤¤ होने का माह मानà¥à¤¯ नहीं है</translation>
<translation id="6529602333819889595">&amp;हटाना फिर से करें</translation>
<translation id="6534179046333460208">जीता-जागता वेब के सà¥à¤à¤¾à¤µ</translation>
<translation id="6550675742724504774">विकलà¥à¤ª</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> खोज</translation>
<translation id="6644283850729428850">यह नीति हटा दी गई है.</translation>
<translation id="6652240803263749613">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° आपके कंपà¥à¤¯à¥‚टर के ऑपरेटिंग सिसà¥à¤Ÿà¤® दà¥à¤µà¤¾à¤°à¤¾ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">वह शिपिंग विकलà¥à¤ª उपलबà¥à¤§ नहीं है. कोई दूसरा विकलà¥à¤ª आज़माà¤à¤‚.</translation>
<translation id="6671697161687535275">कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® से फ़ॉरà¥à¤® सà¥à¤à¤¾à¤µ निकालें?</translation>
<translation id="6685834062052613830">पà¥à¤°à¤¸à¥à¤¥à¤¾à¤¨ करें और सेटअप पूरा करें</translation>
<translation id="6710213216561001401">पिछला</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सरà¥à¤µà¤° के साथ कà¥à¤› गलत है या पता गलत है.</translation>
<translation id="6727102863431372879">सेट करें</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{कोई नहीं}=1{1 आइटम}one{# आइटम}other{# आइटम}}</translation>
-<translation id="6743044928064272573">पिकअप विकलà¥à¤ª</translation>
<translation id="674375294223700098">अजà¥à¤žà¤¾à¤¤ सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° गड़बड़ी.</translation>
<translation id="6753269504797312559">नीति मान</translation>
<translation id="6757797048963528358">आपका डिवाइस निषà¥à¤•à¥à¤°à¤¿à¤¯ हो गया है.</translation>
<translation id="6778737459546443941">आपके अभिभावक ने अभी तक इसकी सà¥à¤µà¥€à¤•à¥ƒà¤¤à¤¿ नहीं दी है</translation>
<translation id="6810899417690483278">कसà¥à¤Ÿà¤®à¤¾à¤‡à¤œà¤¼à¥‡à¤¶à¤¨ आईडी</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">कà¥à¤·à¥‡à¤¤à¥à¤° डेटा लोड नहीं हो सका</translation>
<translation id="6831043979455480757">अनà¥à¤µà¤¾à¤¦ करें</translation>
<translation id="6839929833149231406">कà¥à¤·à¥‡à¤¤à¥à¤°</translation>
<translation id="6874604403660855544">&amp;जोड़ना फिर से करें</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">आपके कारà¥à¤¡ की पà¥à¤·à¥à¤Ÿà¤¿ हो गई है</translation>
<translation id="6897140037006041989">उपयोगकरà¥à¤¤à¤¾ à¤à¤œà¥‡à¤‚ट</translation>
<translation id="6915804003454593391">उपयोगकरà¥à¤¤à¤¾:</translation>
+<translation id="6948701128805548767">पिकअप के तरीके और ज़रूरतें देखने के लिà¤, कोई पता चà¥à¤¨à¥‡à¤‚</translation>
<translation id="6957887021205513506">सरà¥à¤µà¤° का पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° फरà¥à¤œà¥€ दिखाई देता है.</translation>
<translation id="6965382102122355670">ठीक</translation>
<translation id="6965978654500191972">डिवाइस</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">फ़िकà¥â€à¤¸à¥â€à¤¡ पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ सरà¥à¤µà¤° और .pac सà¥â€à¤•à¥à¤°à¤¿à¤ªà¥â€à¤Ÿ URL दोनों ही निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ हैं.</translation>
<translation id="6989763994942163495">अतिरिकà¥à¤¤ सेटिंग दिखाà¤à¤‚...</translation>
<translation id="7000990526846637657">कोई इतिहास पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿ नहीं मिली</translation>
-<translation id="7001663382399377034">पà¥à¤°à¤¾à¤ªà¥à¤¤à¤•à¤°à¥à¤¤à¤¾ जोड़ें</translation>
<translation id="7009986207543992532">आपने <ph name="DOMAIN" /> पर पहà¥à¤‚चने का पà¥à¤°à¤¯à¤¾à¤¸ किया, लेकिन सरà¥à¤µà¤° ने à¤à¤¸à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ किया जिसकी सतà¥à¤¯à¤¾à¤ªà¤¨ अवधि इतनी लंबी है कि वह विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं लगती है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">आपके Google खाते में <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> पर बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग इतिहास के अनà¥à¤¯ रूप उपलबà¥à¤§ हो सकते हैं</translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">इससे पà¥à¤°à¤¾à¤¨à¥‡</translation>
<translation id="7090678807593890770"><ph name="LINK" /> के लिठGoogle में खोज करें</translation>
<translation id="7119414471315195487">दूसरे टैब या पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® बंद करें</translation>
+<translation id="7129409597930077180">इस पते पर शिप नहीं किया जा सकता. कोई दूसरा पता चà¥à¤¨à¥‡à¤‚.</translation>
+<translation id="7138472120740807366">वितरण का तरीका</translation>
<translation id="7139724024395191329">अमीरात</translation>
<translation id="7155487117670177674">भà¥à¤—तान सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहीं है</translation>
<translation id="7179921470347911571">अभी पà¥à¤¨: लॉनà¥â€à¤š करें</translation>
<translation id="7180611975245234373">रीफà¥à¤°à¥‡à¤¶ करें</translation>
<translation id="7182878459783632708">कोई नीति सेट नहीं की गई है</translation>
<translation id="7186367841673660872">इस पेज का <ph name="ORIGINAL_LANGUAGE" />से<ph name="LANGUAGE_LANGUAGE" /> में अनà¥à¤µà¤¾à¤¦ कर दिया गया है</translation>
+<translation id="7192203810768312527"><ph name="SIZE" /> की जगह बनाता है. कà¥à¤› साइटें आपकी अगली विज़िट पर ज़à¥à¤¯à¤¾à¤¦à¤¾ धीमे लोड हो सकती हैं.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> सà¥à¤°à¤•à¥à¤·à¤¾ मानकों का पालन नहीं करता.</translation>
<translation id="721197778055552897">इस समसà¥à¤¯à¤¾ के बारे में <ph name="BEGIN_LINK" />अधिक जानें<ph name="END_LINK" />.</translation>
@@ -673,7 +684,6 @@
<translation id="7424977062513257142">इस वेबपृषà¥â€à¤  पर à¤à¤®à¥â€à¤¬à¥‡à¤¡ किठगठपृषà¥â€à¤  का कहना है:</translation>
<translation id="7441627299479586546">गलत नीति विषय</translation>
<translation id="7444046173054089907">यह साइट अवरोधित है</translation>
-<translation id="7444238235002594607">पिकअप की विधियां और आवशà¥à¤¯à¤•à¤¤à¤¾à¤à¤‚ देखने के लिठपिकअप पता चà¥à¤¨à¥‡à¤‚.</translation>
<translation id="7445762425076701745">जिस सरà¥à¤µà¤° से आप कनेकà¥â€à¤Ÿ हैं उसकी पहचान पूरà¥à¤£à¤¤: सतà¥â€à¤¯à¤¾à¤ªà¤¿à¤¤ नहीं की जा सकती. आपने केवल आपके नेटवरà¥à¤• में ही मानà¥â€à¤¯ नाम का उपयोग कर किसी सरà¥à¤µà¤° से कनेकà¥â€à¤Ÿ किया है, जिसकी मानà¥â€à¤¯à¤¤à¤¾ का सतà¥â€à¤¯à¤¾à¤ªà¤¨ कोई बाहà¥à¤¯ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¾à¤§à¤¿à¤•à¤°à¤£ नहीं करता है. जैसा कि कà¥à¤› पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¾à¤§à¤¿à¤•à¤°à¤£ इन नामों के लिठपà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° जारी कर देंगे, और इस पर धà¥à¤¯à¤¾à¤¨ नहीं दिया जाà¤à¤—ा कि यह सà¥à¤¨à¤¿à¤¶à¥â€à¤šà¤¿à¤¤ करने का कोई तरीका नहीं है कि आप नियत वेबसाइट से कनेकà¥â€à¤Ÿ हैं, न कि किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ से.</translation>
<translation id="7451311239929941790">इस समसà¥à¤¯à¤¾ के बारे में <ph name="BEGIN_LINK" />अधिक जानें<ph name="END_LINK" />.</translation>
<translation id="7460163899615895653">आपके अनà¥à¤¯ डिवाइस के हाल ही के टैब यहां दिखाई देंगे</translation>
@@ -717,6 +727,7 @@
<translation id="7755287808199759310">आपका अभिभावक इसे आपके लिठअनवरोधित कर सकता है</translation>
<translation id="7758069387465995638">हो सकता है कि फायरवॉल या à¤à¤‚टीवायरस दà¥à¤µà¤¾à¤°à¤¾ कनेकà¥à¤¶à¤¨ अवरà¥à¤¦à¥à¤§ हो.</translation>
<translation id="7761701407923456692">सरà¥à¤µà¤° का पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° URL से मेल नहीं हो रहा है.</translation>
+<translation id="7763386264682878361">भà¥à¤—तान मेनिफ़ेसà¥à¤Ÿ पारà¥à¤¸à¤°</translation>
<translation id="7764225426217299476">पता जोड़ें</translation>
<translation id="777702478322588152">पà¥à¤°à¤¶à¤¾à¤¸à¤• पà¥à¤°à¤¾à¤‚त</translation>
<translation id="7791543448312431591">जोड़ें</translation>
@@ -730,6 +741,7 @@
<translation id="785549533363645510">हालांकि, आप अदृशà¥à¤¯ नहीं हैं. गà¥à¤ªà¥à¤¤ मोड में रहने से आपकी बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग आपके नियोकà¥à¤¤à¤¾, आपके इंटरनेट सेवा पà¥à¤°à¤¦à¤¾à¤¤à¤¾ या आपके दà¥à¤µà¤¾à¤°à¤¾ देखी जाने वाली वेबसाइट से छिपती नहीं है.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">अपना CVC जांचें और पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें</translation>
+<translation id="79338296614623784">मानà¥à¤¯ फ़ोन नंबर डालें</translation>
<translation id="7935318582918952113">DOM डिसà¥à¤Ÿà¤¿à¤²à¤°</translation>
<translation id="7938958445268990899">सरà¥à¤µà¤° का पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° अभी तक मानà¥à¤¯ नहीं है.</translation>
<translation id="7942349550061667556">लाल</translation>
@@ -749,6 +761,7 @@
<translation id="8088680233425245692">लेख देखने में विफल रहा.</translation>
<translation id="8089520772729574115">1 MB से कम</translation>
<translation id="8091372947890762290">सरà¥à¤µà¤° पर सकà¥à¤°à¤¿à¤¯à¤£ लंबित है</translation>
+<translation id="8118489163946903409">भà¥à¤—तान विधि</translation>
<translation id="8131740175452115882">दà¥à¤¬à¤¾à¤°à¤¾ पूछें</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> का सरà¥à¤µà¤° <ph name="BEGIN_ABBR" />DNS पता<ph name="END_ABBR" /> नहीं ढूंà¥à¤¾ जा सका.</translation>
<translation id="8149426793427495338">आपका कंपà¥à¤¯à¥‚टर निषà¥à¤•à¥à¤°à¤¿à¤¯ हो गया है.</translation>
@@ -774,6 +787,7 @@
<translation id="8349305172487531364">बà¥à¤•à¤®à¤¾à¤°à¥à¤• बार</translation>
<translation id="8363502534493474904">हवाई जहाज़ मोड बंद करें</translation>
<translation id="8364627913115013041">सेट नहीं है.</translation>
+<translation id="8368476060205742148">Google Play सेवाà¤à¤‚</translation>
<translation id="8380941800586852976">खतरनाक</translation>
<translation id="8382348898565613901">हाल ही में विज़िट किठगठआपके बà¥à¤•à¤®à¤¾à¤°à¥à¤• यहां दिखाई देते हैं</translation>
<translation id="8398259832188219207">ख़राबी रिपोरà¥à¤Ÿ <ph name="UPLOAD_TIME" /> पर अपलोड की गई</translation>
@@ -782,32 +796,30 @@
<translation id="8428213095426709021">सेटिंगà¥à¤¸</translation>
<translation id="8433057134996913067">इससे आप अधिकांश वेबसाइट से पà¥à¤°à¤¸à¥à¤¥à¤¾à¤¨ कर जाà¤à¤‚गे.</translation>
<translation id="8437238597147034694">&amp;ले जाना वापस लाà¤à¤‚</translation>
-<translation id="8456681095658380701">अमानà¥â€à¤¯ नाम</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡}one{# कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡}other{# कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡}}</translation>
<translation id="8483780878231876732">कारà¥à¤¡ का उपयोग अपने Google खाते से करने के लिà¤, Chrome में पà¥à¤°à¤µà¥‡à¤¶ करें</translation>
<translation id="8488350697529856933">इस पर लागू होती है</translation>
-<translation id="8492969205326575646">असमरà¥à¤¥à¤¿à¤¤ कारà¥à¤¡ पà¥à¤°à¤•à¤¾à¤°</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ने पà¥à¤°à¤¤à¤¿à¤¸à¤¾à¤¦ देने में अतà¥à¤¯à¤§à¤¿à¤• समय लिया.</translation>
<translation id="852346902619691059">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° आपके कंपà¥à¤¯à¥‚टर के ऑपरेटिंग सिसà¥à¤Ÿà¤® दà¥à¤µà¤¾à¤°à¤¾ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">समापà¥â€à¤¤à¤¿ वरà¥à¤·</translation>
<translation id="8543181531796978784">आप <ph name="BEGIN_ERROR_LINK" />पहचान संबंधी समसà¥â€à¤¯à¤¾ की रिपोरà¥à¤Ÿ<ph name="END_ERROR_LINK" /> कर सकते हैं या यदि आप अपनी सà¥à¤°à¤•à¥à¤·à¤¾ से जà¥à¤¡à¤¼à¥‡ जोखिमों को समà¤à¤¤à¥‡ हैं, तो <ph name="BEGIN_LINK" />इस असà¥à¤°à¤•à¥à¤·à¤¿à¤¤ साइट पर जा<ph name="END_LINK" /> सकते हैं.</translation>
<translation id="8553075262323480129">अनà¥à¤µà¤¾à¤¦ विफल हो गया कà¥à¤¯à¥‹à¤‚कि पेज की भाषा निरà¥à¤§à¤¾à¤°à¤¿à¤¤ नहीं की जा सकी.</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> से à¤à¤• निजी कनेकà¥â€à¤¶à¤¨ सà¥â€à¤¥à¤¾à¤ªà¤¿à¤¤ नहीं किया जा सकता कà¥â€à¤¯à¥‹à¤‚कि आपके डिवाइस का दिनांक और समय (<ph name="DATE_AND_TIME" />) गलत है.</translation>
-<translation id="8570229484593575558">यह जानकारी |सहेजी नहीं जाà¤à¤—ी|:#आपका बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग इतिहास#आपकी खोजें#कà¥à¤•à¥€ डेटा</translation>
<translation id="8571890674111243710">पेज का अनà¥à¤µà¤¾à¤¦ <ph name="LANGUAGE" /> में कर रहा है...</translation>
-<translation id="8584539743998202583">आपकी गतिविधि |इनà¥à¤¹à¥‡à¤‚ अभी भी दिखाई दे सकती है|:#जिन वेबसाइटों पर आप जाते हैं#आपका नियोकà¥à¤¤à¤¾#आपका इंटरनेट सेवा पà¥à¤°à¤¦à¤¾à¤¤à¤¾</translation>
<translation id="858637041960032120">फ़ोन नंबर जोड़ें
</translation>
<translation id="859285277496340001">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° यह जांचने के लिठकोई तंतà¥à¤° निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ नहीं करता कि इसे रदà¥à¤¦ कर दिया गया है या नहीं.</translation>
<translation id="8620436878122366504">आपके अभिभावकों ने अभी तक इसकी सà¥à¤µà¥€à¤•à¥ƒà¤¤à¤¿ नहीं दी है</translation>
<translation id="8647750283161643317">सभी को डिफ़ॉलà¥à¤Ÿ पर रीसेट करें</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> से आपके कनेकà¥à¤¶à¤¨ को à¤à¤¨à¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ नहीं किया गया है.</translation>
+<translation id="8718314106902482036">भà¥à¤—तान पूरा नहीं हà¥à¤†</translation>
<translation id="8725066075913043281">पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें</translation>
<translation id="8728672262656704056">आप गà¥à¤ªà¥à¤¤ मोड में चले गठहैं</translation>
<translation id="8730621377337864115">पूरà¥à¤£</translation>
<translation id="8738058698779197622">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ कनेकà¥â€à¤¶à¤¨ सà¥â€à¤¥à¤¾à¤ªà¤¿à¤¤ करने के लिà¤, आपकी घड़ी को ठीक से सेट किठजाने की आवशà¥â€à¤¯à¤•à¤¤à¤¾ है. à¤à¤¸à¤¾ इसलिठकà¥â€à¤¯à¥‹à¤‚कि वेबसाइटों दà¥à¤µà¤¾à¤°à¤¾ सà¥â€à¤µà¤¯à¤‚ की पहचान करने के लिठउपयोग किठजाने वाले पà¥à¤°à¤®à¤¾à¤£ पतà¥à¤° केवल विशिषà¥â€à¤Ÿ समयावधियों के लिठही मानà¥â€à¤¯ होते हैं. चूंकि आपके डिवाइस की घड़ी गलत है, इसलिठकà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® इन पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¥‹à¤‚ को सतà¥â€à¤¯à¤¾à¤ªà¤¿à¤¤ नहीं कर सकता.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> का &lt;abbr id="dnsDefinition"&gt;DNS पता&lt;/abbr&gt; पà¥à¤°à¤¾à¤ªà¥à¤¤ नहीं किया जा सका. समसà¥à¤¯à¤¾ का निदान किया जा रहा है.</translation>
+<translation id="8759274551635299824">इस कारà¥à¤¡ की अवधि खतà¥à¤® हो चà¥à¤•à¥€ है</translation>
<translation id="8790007591277257123">&amp;हटाना फिर से करें</translation>
-<translation id="8798099450830957504">सामानà¥à¤¯</translation>
<translation id="8800988563907321413">आपके आस-पास के सà¥à¤à¤¾à¤µ यहां दिखाई देंगे</translation>
<translation id="8820817407110198400">बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="883848425547221593">अनà¥à¤¯ बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
@@ -817,6 +829,7 @@
<translation id="8866481888320382733">नीति सेटिंग पारà¥à¤¸ करने में गड़बड़ी</translation>
<translation id="8866959479196209191">इस पृषà¥â€à¤  का कहना है:</translation>
<translation id="8870413625673593573">हाल ही में बंद किठगà¤</translation>
+<translation id="8874824191258364635">मानà¥à¤¯ कारà¥à¤¡ संखà¥à¤¯à¤¾ डालें</translation>
<translation id="8876793034577346603">नेटवरà¥à¤• कॉनà¥à¤«à¤¼à¤¿à¤—रेशन पारà¥à¤¸ होने में विफल रहा.</translation>
<translation id="8877192140621905067">आपकी तरफ से पà¥à¤·à¥à¤Ÿà¤¿ हो जाने पर, आपके कारà¥à¤¡ के विवरण इस साइट के साथ साà¤à¤¾ किठजाà¤à¤‚गे</translation>
<translation id="8889402386540077796">रंग</translation>
@@ -826,7 +839,6 @@
<translation id="8931333241327730545">कà¥à¤¯à¤¾ आप इस कारà¥à¤¡ को अपने Google खाते में सहेजना चाहते हैं?</translation>
<translation id="8932102934695377596">आपकी घड़ी पीछे है</translation>
<translation id="8954894007019320973">(जारी.)</translation>
-<translation id="895548565263634352"><ph name="ARTICLE_PUBLISHER" /> और <ph name="OTHER_ARTICLE_COUNT" /> अनà¥à¤¯ की खबरें पढ़ें</translation>
<translation id="8971063699422889582">सरà¥à¤µà¤° के पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की समय-सीमा समापà¥à¤¤ हो चà¥à¤•à¥€ है.</translation>
<translation id="8986494364107987395">उपयोग संबंधी आंकड़े और कà¥à¤°à¥ˆà¤¶ रिपोरà¥à¤Ÿ अपने आप Google को भेजने की अनà¥à¤®à¤¤à¤¿ दें</translation>
<translation id="8987927404178983737">माह</translation>
@@ -844,7 +856,6 @@
<translation id="9068849894565669697">रंग चà¥à¤¨à¥‡à¤‚</translation>
<translation id="9076283476770535406">इसमें वयसà¥à¤• सामगà¥à¤°à¥€ हो सकती है</translation>
<translation id="9078964945751709336">अधिक जानकारी की आवशà¥à¤¯à¤•à¤¤à¤¾ है</translation>
-<translation id="9094175695478007090">भà¥à¤—तान à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ लॉनà¥à¤š नहीं हो पा रहा है.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> आपकी जानकारी की सà¥à¤°à¤•à¥à¤·à¤¾ करने के लिठआमतौर पर à¤à¤¨à¥à¤•à¥à¤°à¤¿à¤ªà¥à¤¶à¤¨ का उपयोग करती है. जब कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® ने इस बार <ph name="SITE" /> से कनेकà¥à¤Ÿ करने का पà¥à¤°à¤¯à¤¾à¤¸ किया, तो वेबसाइट ने असामानà¥à¤¯ और गलत कà¥à¤°à¥‡à¤¡à¥‡à¤‚शियल वापस भेजे. à¤à¤¸à¤¾ तब हो सकता है जब कोई हमलावर <ph name="SITE" /> होने का दावा करने का पà¥à¤°à¤¯à¤¾à¤¸ कर रहा हो या किसी वाई-फ़ाई पà¥à¤°à¤µà¥‡à¤¶ सà¥à¤•à¥à¤°à¥€à¤¨ ने कनेकà¥à¤¶à¤¨ को बाधित कर दिया हो. आपकी जानकारी अभी भी सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ है कà¥à¤¯à¥‹à¤‚कि किसी भी डेटा के आदान-पà¥à¤°à¤¦à¤¾à¤¨ से पहले ही कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® ने कनेकà¥à¤¶à¤¨ को रोक दिया था.</translation>
<translation id="9137013805542155359">मूल दिखाà¤à¤‚</translation>
<translation id="9137248913990643158">इस à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ का उपयोग करने से पहले कृपया Chrome शà¥à¤°à¥‚ करके उसमें पà¥à¤°à¤µà¥‡à¤¶ करें.</translation>
diff --git a/chromium/components/strings/components_strings_hr.xtb b/chromium/components/strings/components_strings_hr.xtb
index 7cf1562d16f..652d3ce159c 100644
--- a/chromium/components/strings/components_strings_hr.xtb
+++ b/chromium/components/strings/components_strings_hr.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="hr">
<translation id="1008557486741366299">Ne sada</translation>
<translation id="1015730422737071372">Navedite dodatne pojedinosti</translation>
+<translation id="1021110881106174305">Prihvaćene kartice</translation>
<translation id="1032854598605920125">Zakretanje u smjeru kazaljke na satu</translation>
<translation id="1038842779957582377">nepoznati naziv</translation>
<translation id="1050038467049342496">Zatvorite ostale aplikacije</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Skrivanje vrijednosti</translation>
<translation id="1228893227497259893">Pogrešan identifikator entiteta</translation>
<translation id="1232569758102978740">Neimenovano</translation>
+<translation id="1263231323834454256">Popis za Äitanje</translation>
<translation id="1264126396475825575">Izvješća o rušenju programa generirana <ph name="CRASH_TIME" /> (još nisu prenesena ili zanemarena)</translation>
<translation id="1285320974508926690">Nikad nemoj prevoditi ovu web-lokaciju</translation>
<translation id="129553762522093515">Nedavno zatvoreno</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Postavke automatskog popunjavanja u Chromiumu...</translation>
<translation id="1374468813861204354">prijedlozi</translation>
<translation id="1375198122581997741">O verziji</translation>
+<translation id="1377321085342047638">Broj kartice</translation>
<translation id="139305205187523129">Host <ph name="HOST_NAME" /> nije poslao nikakve podatke.</translation>
<translation id="1407135791313364759">Otvori sve</translation>
<translation id="1413809658975081374">Pogreška privatnosti</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Povijest</translation>
<translation id="1645368109819982629">Protokol nije podržan</translation>
<translation id="1656489000284462475">Preuzimanje</translation>
+<translation id="1663943134801823270">Kartice i adrese dolaze iz Chromea. Njima možete upravljati u <ph name="BEGIN_LINK" />Postavkama<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> obiÄno upotrebljava enkripciju radi zaÅ¡tite vaÅ¡ih podataka. Prilikom ovog pokuÅ¡aja povezivanja Google Chromea s web-lokacijom <ph name="SITE" /> ta je web-lokacija vratila neuobiÄajene i netoÄne vjerodajnice. To može znaÄiti da se neki napadaÄ pokuÅ¡ava predstaviti kao <ph name="SITE" /> ili je zaslon za prijavu na Wi-Fi prekinuo vezu. VaÅ¡i su podaci joÅ¡ uvijek sigurni jer je Google Chrome zaustavio povezivanje prije razmjene podataka.</translation>
<translation id="168328519870909584">NapadaÄi koji se trenutaÄno nalaze na <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogu pokuÅ¡ati instalirati opasne aplikacije na vaÅ¡ ureÄ‘aj radi kraÄ‘e ili brisanja vaÅ¡ih podataka (na primjer, fotografija, zaporki, poruka i brojeva kreditnih kartica).</translation>
<translation id="168841957122794586">Certifikat poslužitelja sadrži slab kriptografski kljuÄ!</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264"><ph name="NAME" /> mora dopustiti da posjetiš tu web-lokaciju</translation>
+<translation id="1721424275792716183">* Polje je obavezno</translation>
<translation id="1728677426644403582">Gledate izvor web-stranice</translation>
+<translation id="173080396488393970">Ova vrsta kartice nije podržana</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Pokušajte kontaktirati administratora sustava.</translation>
+<translation id="1740951997222943430">Unesite važeći mjesec isteka</translation>
<translation id="1745358365027406341">Preuzmi stranicu kasnije</translation>
<translation id="17513872634828108">Otvorene kartice</translation>
<translation id="1753706481035618306">Broj stranice</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Ažurirajte zaporku za sinkronizaciju.</translation>
<translation id="1787142507584202372">Ovdje se prikazuju vaše otvorene kartice</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Odaberite adresu za dostavu da biste provjerili naÄine i zahtjeve za dostavu.</translation>
+<translation id="1803264062614276815">Ime nositelja kartice</translation>
<translation id="1803678881841855883">Google sigurno pregledavanje nedavno je <ph name="BEGIN_LINK" />otkrilo zlonamjerni softver<ph name="END_LINK" /> na web-lokaciji <ph name="SITE" />. Web-lokacije koje su inaÄe sigurne ponekad mogu biti zaražene zlonamjernim softverom. Zlonamjerni sadržaj potjeÄe s hosta <ph name="SUBRESOURCE_HOST" /> koji je poznati distributer zlonamjernog softvera. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Dodano <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Nevažeći zahtjev ili parametri zahtjeva</translation>
<translation id="1826516787628120939">Provjera</translation>
<translation id="1834321415901700177">Ova web-lokacija sadrži štetne programe</translation>
<translation id="1842969606798536927">Plaćanje</translation>
-<translation id="1864455488461349376">Opcija dostave</translation>
<translation id="1871208020102129563">Proxy poslužitelj postavljen je na upotrebu fiksnih proxy poslužitelja, a ne URL .pac skripte.</translation>
<translation id="1871284979644508959">Obavezno polje</translation>
<translation id="187918866476621466">Otvori polazne stranice</translation>
<translation id="1883255238294161206">Sažmi popis</translation>
<translation id="1898423065542865115">Filtriranje</translation>
<translation id="194030505837763158">Posjetite <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Prihvaćene kartice</translation>
<translation id="1962204205936693436">Oznake s domene <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Pogreška postavljanja u seriju</translation>
<translation id="1974060860693918893">Napredno</translation>
<translation id="1978555033938440688">Verzija opreme</translation>
+<translation id="1995859865337580572">Potvrdite svoj CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{i još 1}one{i još #}few{i još #}other{i još #}}</translation>
-<translation id="2020194265157481222">Potrebno je ime na kartici</translation>
<translation id="2025186561304664664">Proxy je postavljen na automatsko konfiguriranje.</translation>
<translation id="2030481566774242610">Jeste li mislili <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />provjerite proxy i vatrozid<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Danas</translation>
<translation id="2154054054215849342">Sinkronizacija nije dostupna za vašu domenu</translation>
<translation id="2154484045852737596">Uredite karticu</translation>
-<translation id="2156993118928861787">Nevažeća adresa</translation>
<translation id="2166049586286450108">Potpuni administratorski pristup</translation>
<translation id="2166378884831602661">Web-lokacija ne može pružiti sigurnu vezu</translation>
<translation id="2181821976797666341">Pravila</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresa}one{# adresa}few{# adrese}other{# adresa}}</translation>
+<translation id="2202020181578195191">Unesite važeću godinu isteka</translation>
<translation id="2212735316055980242">Pravilo nije pronađeno</translation>
<translation id="2213606439339815911">Dohvaćanje unosa...</translation>
<translation id="2230458221926704099">RijeÅ¡ite problem s povezivanjem pomoću <ph name="BEGIN_LINK" />dijagnostiÄke aplikacije<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Internetski je pristup blokiran</translation>
<translation id="230155334948463882">Nova kartica?</translation>
<translation id="2305919008529760154">Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat možda lažan. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Opcije kartica i adresa preuzete su s vaÅ¡eg Google raÄuna (<ph name="ACCOUNT_EMAIL" />) i Chromea. Tim opcijama možete upravljati u <ph name="BEGIN_LINK" />Postavkama<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> zahtijeva korisniÄko ime i zaporku.</translation>
<translation id="2318774815570432836">TrenutaÄno ne možete otvoriti <ph name="SITE" /> jer web-lokacija upotrebljava HSTS. Mrežne pogreÅ¡ke i napadi uglavnom su privremeni, tako da će ta stranica vjerojatno kasnije funkcionirati. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Druge oznake</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Zadano pravilo organizacije</translation>
<translation id="2386255080630008482">Opozvan je certifikat poslužitelja.</translation>
<translation id="2392959068659972793">Prikaži pravila bez postavljenih vrijednosti</translation>
+<translation id="239429038616798445">Taj naÄin dostave nije dostupan. PokuÅ¡ajte s drugim naÄinom.</translation>
<translation id="2396249848217231973">&amp;Poništi brisanje</translation>
<translation id="2460160116472764928">Google sigurno pregledavanje nedavno je <ph name="BEGIN_LINK" />otkrilo zlonamjerni softver<ph name="END_LINK" /> na web-lokaciji <ph name="SITE" />. Web-lokacije koje su inaÄe sigurne ponekad mogu biti zaražene zlonamjernim softverom. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Ispuni</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />pokrenuti Mrežnu dijagnostiku<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Nevažeći URL pretraživanja.</translation>
<translation id="2491120439723279231">Certifikat poslužitelja sadrži pogreške.</translation>
-<translation id="24943777258388405">Nevažeći telefonski broj</translation>
<translation id="2495083838625180221">RaÅ¡Älanjivanje JSON datoteka</translation>
<translation id="2495093607237746763">Ako je potvrđen taj okvir, Chromium će pohraniti kopiju vaše kartice na uređaj radi bržeg ispunjavanja obrazaca.</translation>
<translation id="2498091847651709837">Skeniraj novu karticu</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027">Host <ph name="HOST_NAME" /> poslao je nevažeći odgovor.</translation>
<translation id="2552545117464357659">Novije</translation>
<translation id="2556876185419854533">&amp;Poništi uređivanje</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>
<translation id="2597378329261239068">Ovaj je dokument zaštićen zaporkom. Unesite zaporku.</translation>
<translation id="2609632851001447353">Varijacije</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />pokrenuti Dijagnostiku povezivosti<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">U redu</translation>
<translation id="2742870351467570537">Ukloni odabrane stavke</translation>
+<translation id="277133753123645258">NaÄin dostave</translation>
<translation id="277499241957683684">Zapis uređaja nije prisutan</translation>
<translation id="2784949926578158345">Veza je ponovo uspostavljena.</translation>
<translation id="2794233252405721443">Web-lokacija blokirana</translation>
-<translation id="2812680587231492111">Ta opcija preuzimanja nije dostupna. Pokušajte s nekom drugom opcijom.</translation>
<translation id="2824775600643448204">Adresna traka i traka za pretraživanje</translation>
<translation id="2826760142808435982">Veza je kriptirana i autentificirana Å¡ifrom <ph name="CIPHER" />, a <ph name="KX" /> služi za mehanizam razmjene kljuÄeva.</translation>
<translation id="2835170189407361413">Obriši obrazac</translation>
-<translation id="2849041323157393173">Ta opcija isporuke nije dostupna. Pokušajte s nekom drugom opcijom.</translation>
<translation id="2889159643044928134">Ne uÄitavaj ponovo</translation>
<translation id="2900469785430194048">Google Chrome ostao je bez memorije dok je pokušavao prikazati ovu web-stranicu.</translation>
<translation id="2909946352844186028">Otkrivena je promjena mreže.</translation>
<translation id="2916038427272391327">Zatvorite ostale programe</translation>
<translation id="2922350208395188000">Certifikat poslužitelja nije moguće provjeriti.</translation>
+<translation id="2928905813689894207">Adresa za naplatu</translation>
<translation id="2948083400971632585">Možete onemogućiti sve proxyje konfigurirane za vezu sa stranice postavki.</translation>
<translation id="2955913368246107853">Zatvori traku za traženje</translation>
<translation id="2958431318199492670">Mrežna konfiguracija nije u skladu sa standardima ONC. Dijelove konfiguracije nije moguće uvesti.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Za uspostavu sigurne veze sat mora biti toÄno postavljen jer certifikati pomoću kojih se web-lokacije meÄ‘usobno identificiraju vrijede samo odreÄ‘eno vrijeme. Budući da vaÅ¡ sat nije toÄan, Chrome ne može potvrditi te certifikate.</translation>
<translation id="2972581237482394796">&amp;Vrati poništeno</translation>
<translation id="2985306909656435243">Ako je to omogućeno, Chromium će pohraniti kopiju vaše kartice na uređaj radi bržeg ispunjavanja obrazaca.</translation>
+<translation id="2985398929374701810">Unesite važeću adresu</translation>
+<translation id="2986368408720340940">Taj naÄin preuzimanja nije dostupan. PokuÅ¡ajte s nekim drugim naÄinom.</translation>
<translation id="2991174974383378012">Dijeljenje s web-lokacijama</translation>
<translation id="3005723025932146533">Prikaži spremljenu kopiju</translation>
<translation id="3008447029300691911">Unesite CVC za karticu <ph name="CREDIT_CARD" />. Nakon što ih potvrdite, podaci o kartici dijelit će se s ovom web-lokacijom.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{najmanje 1 stavka na sinkroniziranim uređajima}=1{1 stavka (i više njih na sinkroniziranim uređajima)}one{# stavka (i više njih na sinkroniziranim uređajima)}few{# stavke (i više njih na sinkroniziranim uređajima)}other{# stavki (i više njih na sinkroniziranim uređajima)}}</translation>
<translation id="3041612393474885105">Podaci o certifikatu</translation>
<translation id="3063697135517575841">Chrome nije uspio potvrditi vašu karticu. Pokušajte ponovo kasnije.</translation>
+<translation id="3064966200440839136">NapuÅ¡tate anonimni naÄin rada da biste platili putem vanjske aplikacije. Želite li nastaviti?</translation>
<translation id="3093245981617870298">Izvan mreže ste.</translation>
<translation id="3105172416063519923">ID uređaja:</translation>
<translation id="3109728660330352905">Nemate ovlaštenje za prikaz te stranice.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Pokušajte pokrenuti Dijagnostiku povezivosti<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Dekodiranje odgovora nije uspjelo</translation>
-<translation id="3149891296864842641">Opcija otpreme</translation>
<translation id="3150653042067488994">Privremena pogreška poslužitelja</translation>
+<translation id="3154506275960390542">Ova stranica sadrži obrazac koji se možda neće poslati na siguran naÄin. Podaci koje Å¡aljete mogu biti vidljivi drugima tijekom prijenosa ili bi ih mogao izmijeniti napadaÄ prije nego Å¡to ih primi poslužitelj.</translation>
<translation id="3157931365184549694">Vrati</translation>
<translation id="3167968892399408617">Stranice koje pregledavate na anonimnim karticama ne zadržavaju se u povijesti preglednika, pohrani kolaÄića ili povijesti pretraživanja nakon Å¡to zatvorite sve anonimne kartice, ali će se zadržati sve datoteke koje preuzmete ili oznake koje napravite.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Slanje zahtjeva za pristup ovoj web-lokaciji korisniku <ph name="NAME" /> nije uspjelo. Pokušaj ponovo.</translation>
<translation id="3355823806454867987">Promijeni proxy postavke...</translation>
<translation id="3369192424181595722">Pogreška sata</translation>
+<translation id="337311366426640088">Još ovoliko stavki: <ph name="ITEM_COUNT" />...</translation>
<translation id="337363190475750230">Dodjela je uklonjena</translation>
<translation id="3377188786107721145">Pogreška pri analizi pravila</translation>
<translation id="3380365263193509176">Nepoznata pogreška</translation>
<translation id="3380864720620200369">ID klijenta:</translation>
<translation id="3391030046425686457">Adresa za dostavu</translation>
+<translation id="3395827396354264108">NaÄin preuzimanja</translation>
<translation id="340013220407300675">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 kreditne kartice).</translation>
<translation id="3422248202833853650">Pokušajte zatvoriti ostale programe da biste oslobodili memoriju.</translation>
<translation id="3422472998109090673">Host <ph name="HOST_NAME" /> trenutaÄno nije dostupan.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Dohvati interval:</translation>
<translation id="3462200631372590220">Sakrij napredno</translation>
+<translation id="3467763166455606212">Potrebno je unijeti ime nositelja kartice</translation>
+<translation id="3478058380795961209">Mjesec isteka</translation>
<translation id="3479539252931486093">Niste to oÄekivali? <ph name="BEGIN_LINK" />Javite nam<ph name="END_LINK" />.</translation>
<translation id="3479552764303398839">Ne sada</translation>
<translation id="348000606199325318">ID rušenja <ph name="CRASH_LOCAL_ID" /> (ID poslužitelja: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Nismo uspjeli stupiti u kontakt s tvojim roditeljem. Pokušaj ponovo.</translation>
<translation id="3528171143076753409">Certifikat poslužitelja nije pouzdan.</translation>
-<translation id="3538531656504267329">Godina isteka nije važeća</translation>
<translation id="3539171420378717834">Zadrži kopiju te kartice na uređaju</translation>
<translation id="3542684924769048008">Upotrijebite zaporku za:</translation>
<translation id="3549644494707163724">Å ifriranje svih sinkroniziranih podataka vlastitom zaporkom za sinkronizaciju</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Sakrij detalje</translation>
<translation id="3587482841069643663">Sve</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Unesite važeći datum isteka</translation>
<translation id="36224234498066874">Obriši podatke o pregledavanju...</translation>
<translation id="362276910939193118">Pokaži cijelu povijest</translation>
<translation id="3623476034248543066">Prikaži vrijednost</translation>
@@ -311,7 +323,6 @@
<translation id="3693415264595406141">Zaporka:</translation>
<translation id="3696411085566228381">ništa</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Odaberite adresu za dostavu da biste provjerili naÄine i zahtjeve za dostavu.</translation>
<translation id="370665806235115550">UÄitavanje...</translation>
<translation id="3712624925041724820">Licence su potrošene</translation>
<translation id="3714780639079136834">ukljuÄite mobilne podatke ili Wi-Fi</translation>
@@ -320,6 +331,7 @@
<translation id="3739623965217189342">Veza koju ste kopirali</translation>
<translation id="375403751935624634">Prijevod nije uspio zbog poslužiteljske pogreške.</translation>
<translation id="3759461132968374835">Nemate nedavnih izvješća o padu. Ovdje se neće prikazati padovi do kojih je došlo kada je izvješćivanje o padovima onemogućeno.</translation>
+<translation id="3787705759683870569">IstjeÄe <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Ako upotrebljavate proxy poslužitelj...</translation>
<translation id="3828924085048779000">Prazne zaporke nisu dopuštene.</translation>
<translation id="3845539888601087042">Prikazuje se povijest s uređaja na kojima ste prijavljeni. <ph name="BEGIN_LINK" />Saznajte više<ph name="END_LINK" />.</translation>
@@ -355,7 +367,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Želite li da Chromium spremi tu karticu?</translation>
<translation id="4171400957073367226">Potpis za potvrdu nije ispravan.</translation>
-<translation id="4176463684765177261">Onemogućeno</translation>
<translation id="4196861286325780578">&amp;Ponovi premještanje</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />provjerite vatrozid i konfiguraciju antivirusnog programa<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{ništa}=1{1 aplikacija ($1)}=2{2 aplikacije ($1, $2)}one{# aplikacija ($1, $2, $3)}few{# aplikacije ($1, $2, $3)}other{# aplikacija ($1, $2, $3)}}</translation>
@@ -382,11 +393,11 @@
<translation id="4406896451731180161">rezultati pretraživanja</translation>
<translation id="4432688616882109544">Host <ph name="HOST_NAME" /> nije prihvatio vaš certifikat za prijavu ili certifikat nije poslan.</translation>
<translation id="443673843213245140">Upotreba proxy poslužitelja onemogućena je, ali odreÄ‘ena je izriÄita konfiguracija proxy poslužitelja.</translation>
-<translation id="4446242550670694251">Sada možete pregledavati privatno i ostali korisnici ovog uređaja neće vidjeti vaše aktivnosti.</translation>
<translation id="4492190037599258964">Rezultati pretraživanja za upit '<ph name="SEARCH_STRING" />'</translation>
<translation id="4506176782989081258">Pogreška pri provjeri valjanosti: <ph name="VALIDATION_ERROR" />.</translation>
<translation id="4506599922270137252">kontaktirajte administratora sustava</translation>
<translation id="450710068430902550">Dijeljenje s administratorom</translation>
+<translation id="4515275063822566619">Kartice i adrese dolaze iz Cromea i vaÅ¡eg Google raÄuna (<ph name="ACCOUNT_EMAIL" />). Njima možete upravljati u <ph name="BEGIN_LINK" />Postavkama<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Detalji</translation>
<translation id="4558551763791394412">Pokušajte onemogućiti proširenja.</translation>
<translation id="457875822857220463">Dostava</translation>
@@ -416,6 +427,7 @@
<translation id="4816492930507672669">Prilagodi stranici</translation>
<translation id="483020001682031208">Nema nijedne stranice FiziÄkog weba za prikazivanje</translation>
<translation id="4850886885716139402">Prikaz</translation>
+<translation id="4854362297993841467">Taj naÄin dostave nije dostupan. PokuÅ¡ajte s nekim drugim naÄinom.</translation>
<translation id="4858792381671956233">Pitao si roditelje smiješ li otvoriti tu web-lokaciju</translation>
<translation id="4880827082731008257">Pretraži povijest</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -423,7 +435,6 @@
<translation id="4923417429809017348">Ova je stranica prevedena s nepoznatog jezika na <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Plaćanje</translation>
<translation id="4926049483395192435">Mora biti određeno.</translation>
-<translation id="4941291666397027948">* oznaÄava obavezno polje</translation>
<translation id="495170559598752135">Radnje</translation>
<translation id="4958444002117714549">Proširi popis</translation>
<translation id="4962322354953122629">Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer Chrome sigurnosni certifikat ne smatra pouzdanim. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -438,6 +449,7 @@
<translation id="5045550434625856497">Pogrešna zaporka</translation>
<translation id="5056549851600133418">PreporuÄeni Älanci</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />provjerite proxy adresu<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Nema kolaÄića}=1{1 web-lokacija upotrebljava kolaÄiće. }one{# web-lokacija upotrebljava kolaÄiće. }few{# web-lokacije upotrebljavaju kolaÄiće. }other{# web-lokacija upotrebljava kolaÄiće. }}</translation>
<translation id="5087286274860437796">Certifikat poslužitelja trenutaÄno nije važeći.</translation>
<translation id="5087580092889165836">Dodaj karticu</translation>
<translation id="5089810972385038852">Država</translation>
@@ -460,10 +472,8 @@
<translation id="5300589172476337783">Prikaži</translation>
<translation id="5308689395849655368">Onemogućeno je izvješćivanje o padu.</translation>
<translation id="5317780077021120954">Spremi</translation>
-<translation id="5326702247179446998">Primatelj je obavezan</translation>
<translation id="5327248766486351172">Naziv</translation>
<translation id="5337705430875057403">NapadaÄi na <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogu vas na prijevaru pokuÅ¡ati navesti da napravite neÅ¡to opasno kao Å¡to je instaliranje softvera ili otkrivanje osobnih podataka (na primjer, zaporki, telefonskih brojeva ili kreditnih kartica).</translation>
-<translation id="53553865750799677">Adresa za preuzimanje nije podržana. Odaberite drugu adresu.</translation>
<translation id="5359637492792381994">Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer sigurnosni certifikat trenutaÄno nije važeći. Razlog može biti pogreÅ¡na konfiguracija ili napad na vaÅ¡u vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Pohrana postavki pravila nije uspjela</translation>
<translation id="5386426401304769735">Lanac certifikata za ovu web-lokaciju sadrži certifikat s SHA-1 potpisom.</translation>
@@ -489,8 +499,8 @@
<translation id="5544037170328430102">Ugrađena stranica na web-lokaciji <ph name="SITE" /> navodi sljedeće:</translation>
<translation id="5556459405103347317">Ponovno uÄitaj</translation>
<translation id="5565735124758917034">Aktivno</translation>
+<translation id="5571083550517324815">Preuzimanje na toj adresi nije moguće. Odaberite drugu adresu.</translation>
<translation id="5572851009514199876">Pokrenite Chrome i prijavite se na njega kako bi mogao provjeriti imate li dopuštenje za pristup toj web-lokaciji.</translation>
-<translation id="5575380383496039204">Adresa za dostavu nije podržana. Odaberite drugu adresu.</translation>
<translation id="5580958916614886209">Provjerite mjesec isteka, pa pokušajte ponovo</translation>
<translation id="560412284261940334">Upravljanje nije podržano</translation>
<translation id="5610142619324316209">provjerite vezu</translation>
@@ -506,7 +516,8 @@
<translation id="5710435578057952990">Identitet ove web lokacije nije ovjeren.</translation>
<translation id="5720705177508910913">TrenutaÄni korisnik:</translation>
<translation id="5732392974455271431">Tvoji je roditelji mogu deblokirati</translation>
-<translation id="57586589942790530">Nevažeći broj kartice</translation>
+<translation id="5763042198335101085">Unesite važeću e-adresu</translation>
+<translation id="5765072501007116331">Odaberite adresu za prikaz naÄina dostave i zahtjeva za dostavu.</translation>
<translation id="5784606427469807560">Pojavio se problem prilikom potvrđivanja kartice. Provjerite internetsku vezu i pokušajte ponovo.</translation>
<translation id="5785756445106461925">Nadalje, ova stranica sadrži druge resurse koji nisu sigurni. Te resurse mogu vidjeti drugi tijekom prijenosa i napadaÄ ih može izmijeniti kako bi promijenio izgled stranice.</translation>
<translation id="5786044859038896871">Želite li ispuniti podatke o kartici?</translation>
@@ -519,22 +530,20 @@
<translation id="5869405914158311789">Web-lokacija ne može se dohvatiti</translation>
<translation id="5869522115854928033">Spremljene zaporke</translation>
<translation id="5872918882028971132">Nadređeni prijedlozi</translation>
-<translation id="587760065310675640">Adresa za dostavu nije podržana. Odaberite drugu adresu.</translation>
<translation id="5901630391730855834">Žuta</translation>
-<translation id="59174027418879706">Omogućeno</translation>
<translation id="5926846154125914413">Možda ćete izgubiti pristup premium sadržaju s nekih web-lokacija.</translation>
<translation id="5959728338436674663">Automatski šalji Googleu neke <ph name="BEGIN_WHITEPAPER_LINK" />podatke o sustavu i sadržaj stranice<ph name="END_WHITEPAPER_LINK" /> radi otkrivanja opasnih aplikacija i web-lokacija. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Tjedan</translation>
<translation id="5967867314010545767">Ukloni iz povijesti</translation>
<translation id="5975083100439434680">Smanji</translation>
+<translation id="598637245381783098">Aplikacija za plaćanje ne može se otvoriti</translation>
<translation id="5989320800837274978">Nisu određeni fiksni proxy poslužitelji ni URL .pac skripte.</translation>
<translation id="5990559369517809815">Zahtjevi poslužitelju blokirani su proširenjem.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Opcije kartica i adresa preuzete su s Chromea. Tim opcijama možete upravljati u <ph name="BEGIN_LINK" />Postavkama<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1. stranica}one{#. stranica}few{#. stranica}other{#. stranica}}</translation>
<translation id="6017514345406065928">Zelena</translation>
+<translation id="6027201098523975773">Unesite ime</translation>
<translation id="6040143037577758943">Zatvori</translation>
-<translation id="604124094241169006">Automatski</translation>
<translation id="6042308850641462728">Više</translation>
<translation id="6060685159320643512">Oprez, ovi eksperimenti mogu ugristi</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{ništa}=1{1}one{#}few{#}other{#}}</translation>
@@ -542,9 +551,10 @@
uređaje koje možda upotrebljavate.</translation>
<translation id="614940544461990577">Pokušajte sljedeće:</translation>
<translation id="6151417162996330722">Certifikat poslužitelja ima predugo razdoblje valjanosti.</translation>
-<translation id="615643356032862689">Preuzete će se datoteke i oznake zadržati.</translation>
+<translation id="6157877588268064908">Odaberite adresu za prikaz naÄina dostave i zahtjeva za dostavu</translation>
<translation id="6165508094623778733">Saznajte više</translation>
<translation id="6177128806592000436">Veza s web-lokacijom nije sigurna</translation>
+<translation id="6184817833369986695">(skupina: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Provjerite internetsku vezu</translation>
<translation id="6218753634732582820">Želite li ukloniti adresu iz Chromiuma?</translation>
<translation id="6251924700383757765">Pravila o privatnosti</translation>
@@ -553,6 +563,8 @@
<translation id="6259156558325130047">&amp;Ponovi promjenu rasporeda</translation>
<translation id="6263376278284652872">Oznake domene <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Natrag u sigurnost</translation>
+<translation id="6276112860590028508">Ovdje se prikazuju stranice s vaÅ¡eg popisa za Äitanje</translation>
+<translation id="6280223929691119688">Dostava na tu adresu nije moguća. Odaberite drugu adresu.</translation>
<translation id="6282194474023008486">Poštanski broj</translation>
<translation id="6290238015253830360">Ovdje će se prikazivati predloženi Älanci</translation>
<translation id="6305205051461490394">Web-lokacija <ph name="URL" /> nije dostupna.</translation>
@@ -574,7 +586,6 @@
<translation id="6417515091412812850">Nije moguće provjeriti je li certifikat opozvan.</translation>
<translation id="6433490469411711332">Uređivanje podataka za kontakt</translation>
<translation id="6433595998831338502">Host <ph name="HOST_NAME" /> odbio je povezivanje.</translation>
-<translation id="6443118737398455446">Datum isteka nije važeći</translation>
<translation id="6446608382365791566">Dodajte još podataka</translation>
<translation id="6451458296329894277">Potvrdi ponovno slanje obrasca</translation>
<translation id="6456339708790392414">Vaše plaćanje</translation>
@@ -582,10 +593,8 @@
<translation id="6462969404041126431">Poslužitelj ne može dokazati da je to <ph name="DOMAIN" /> jer bi sigurnosni certifikat mogao biti opozvan. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Pravila uređaja</translation>
<translation id="6477321094435799029">Chrome je otkrio neuobiÄajeni kôd na toj stranici i blokirao ju je radi zaÅ¡tite vaÅ¡ih osobnih podataka (primjerice zaporki, telefonskih brojeva i kreditnih kartica).</translation>
-<translation id="6477460825583319731">Nevažeća e-adresa</translation>
<translation id="6489534406876378309">Pokreni prijenos rušenja</translation>
<translation id="6508722015517270189">Ponovo pokrenite Chrome</translation>
-<translation id="6525462735697194615">Mjesec isteka nije važeći</translation>
<translation id="6529602333819889595">&amp;Ponovi brisanje</translation>
<translation id="6534179046333460208">Prijedlozi FiziÄkog weba</translation>
<translation id="6550675742724504774">Opcije</translation>
@@ -600,7 +609,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Pretraživanje</translation>
<translation id="6644283850729428850">Ovo je pravilo zastarjelo.</translation>
<translation id="6652240803263749613">Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer operativni sustav raÄunala sigurnosni certifikat ne smatra pouzdanim. Razlog može biti pogreÅ¡na konfiguracija ili napad na vaÅ¡u vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Ta opcija dostave nije dostupna. Pokušajte s nekom drugom opcijom.</translation>
<translation id="6671697161687535275">Želite li ukloniti prijedlog iz Chromiuma?</translation>
<translation id="6685834062052613830">Odjavite se i dovršite postavljanje</translation>
<translation id="6710213216561001401">Prethodno</translation>
@@ -608,13 +616,13 @@
<translation id="6711464428925977395">NeÅ¡to nije u redu s proxy poslužiteljem ili adresa nije toÄna.</translation>
<translation id="6727102863431372879">Postavi</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{ništa}=1{1 stavka}one{# stavka}few{# stavke}other{# stavki}}</translation>
-<translation id="6743044928064272573">Opcija preuzimanja</translation>
<translation id="674375294223700098">Nepoznata pogreška certifikata poslužitelja</translation>
<translation id="6753269504797312559">Vrijednost pravila</translation>
<translation id="6757797048963528358">Uređaj je u stanju mirovanja.</translation>
<translation id="6778737459546443941">Roditelj je još nije odobrio</translation>
<translation id="6810899417690483278">ID prilagođavanja</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">UÄitavanje podataka regija nije uspjelo</translation>
<translation id="6831043979455480757">Prevedi</translation>
<translation id="6839929833149231406">PodruÄje</translation>
<translation id="6874604403660855544">&amp;Ponovi dodavanje</translation>
@@ -622,6 +630,7 @@
<translation id="6895330447102777224">Kartica je potvrđena</translation>
<translation id="6897140037006041989">KorisniÄki agent</translation>
<translation id="6915804003454593391">Korisnik:</translation>
+<translation id="6948701128805548767">Odaberite adresu za prikaz naÄina preuzimanja i zahtjeva za preuzimanje</translation>
<translation id="6957887021205513506">Certifikat poslužitelja izgleda kao falsifikat.</translation>
<translation id="6965382102122355670">U redu</translation>
<translation id="6965978654500191972">Uređaj</translation>
@@ -629,7 +638,6 @@
<translation id="6973656660372572881">Određeni su fiksni proxy poslužitelji i URL .pac skripte.</translation>
<translation id="6989763994942163495">Pokaži napredne postavke...</translation>
<translation id="7000990526846637657">Unosi povijesti nisu pronađeni</translation>
-<translation id="7001663382399377034">Dodaj primatelja</translation>
<translation id="7009986207543992532">PokuÅ¡ali ste otvoriti <ph name="DOMAIN" />, ali poslužitelj je prikazao certifikat Äije je razdoblje valjanosti predugo da bi bilo vjerodostojno. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Na Google raÄunu možda postoje drugi oblici povijesti pregledavanja na stranici <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -640,12 +648,15 @@
<translation id="7088615885725309056">Starije</translation>
<translation id="7090678807593890770">Potražite upit <ph name="LINK" /> na Googleu</translation>
<translation id="7119414471315195487">Zatvorite ostale kartice ili programe</translation>
+<translation id="7129409597930077180">Dostava na tu adresu nije moguća. Odaberite drugu adresu.</translation>
+<translation id="7138472120740807366">NaÄin isporuke</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7155487117670177674">Plaćanje nije sigurno</translation>
<translation id="7179921470347911571">Ponovo pokreni sada</translation>
<translation id="7180611975245234373">Osvježi</translation>
<translation id="7182878459783632708">Nije postavljeno nijedno pravilo</translation>
<translation id="7186367841673660872">Ova je stranica prevedena s jezika<ph name="ORIGINAL_LANGUAGE" />na<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423">Host <ph name="HOST_NAME" /> ne pridržava se sigurnosnih standarda.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Saznajte više<ph name="END_LINK" /> o ovom problemu.</translation>
@@ -674,7 +685,6 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="7424977062513257142">Ugrađena stranica na ovoj web-lokaciji navodi sljedeće:</translation>
<translation id="7441627299479586546">Pogrešan predmet pravila</translation>
<translation id="7444046173054089907">Ova je web-lokacija blokirana</translation>
-<translation id="7444238235002594607">Odaberite adresu za preuzimanje da biste provjerili naÄine i zahtjeve za preuzimanje.</translation>
<translation id="7445762425076701745">Identitet poslužitelja s kojim ste se povezali ne može se u potpunosti potvrditi. Povezali ste se s poslužiteljem upotrebom imena koje je valjano samo unutar vaÅ¡e mreže, a za koje vanjsko tijelo za izdavanje certifikata nikako ne može potvrditi vlasniÅ¡tvo. Budući da postoje tijela za izdavanje certifikata koja će izdati certifikat za ta imena bez obzira na sve, nema naÄina da budete sigurni da ste povezani sa željenom web-lokacijom, a ne s napadaÄem.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Saznajte više<ph name="END_LINK" /> o tom problemu.</translation>
<translation id="7460163899615895653">Ovdje se prikazuju vaše nedavne kartice s drugih uređaja</translation>
@@ -718,6 +728,7 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="7755287808199759310">Roditelj je može deblokirati</translation>
<translation id="7758069387465995638">Vezu možda blokira vatrozid ili antivirusni softver.</translation>
<translation id="7761701407923456692">Certifikat poslužitelja ne podudara se s URL-om.</translation>
+<translation id="7763386264682878361">RaÅ¡ÄlanjivaÄ manifesta za plaćanje</translation>
<translation id="7764225426217299476">Dodaj adresu</translation>
<translation id="777702478322588152">Prefektura</translation>
<translation id="7791543448312431591">Dodaj</translation>
@@ -731,6 +742,7 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="785549533363645510">Niste nevidljivi. Anonimni naÄin ne sakriva vaÅ¡e pregledavanje od poslodavca, davatelja internetskih usluga ili posjećenih web-lokacija.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Provjerite CVC i pokušajte ponovo</translation>
+<translation id="79338296614623784">Unesite važeći telefonski broj</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Certifkat poslužitelja još nije valjan.</translation>
<translation id="7942349550061667556">Crvena</translation>
@@ -750,6 +762,7 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="8088680233425245692">Prikaz Älanka nije uspio.</translation>
<translation id="8089520772729574115">manje od 1 MB</translation>
<translation id="8091372947890762290">Aktivacija je na Äekanju na poslužitelju</translation>
+<translation id="8118489163946903409">NaÄin plaćanja</translation>
<translation id="8131740175452115882">Potvrdi</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />DNS adresa<ph name="END_ABBR" /> poslužitelja hosta <ph name="HOST_NAME" /> nije pronađena.</translation>
<translation id="8149426793427495338">RaÄunalo je u stanju mirovanja.</translation>
@@ -775,6 +788,7 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="8349305172487531364">Traka oznaka</translation>
<translation id="8363502534493474904">iskljuÄite naÄin rada u zrakoplovu</translation>
<translation id="8364627913115013041">Nije postavljeno.</translation>
+<translation id="8368476060205742148">Google Play usluge</translation>
<translation id="8380941800586852976">Opasno</translation>
<translation id="8382348898565613901">Ovdje će se prikazivati oznake koje ste nedavno posjetili</translation>
<translation id="8398259832188219207">Izvješće o rušenju programa preneseno u <ph name="UPLOAD_TIME" /></translation>
@@ -783,32 +797,30 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="8428213095426709021">Postavke</translation>
<translation id="8433057134996913067">Time ćete se odjaviti s većine web-lokacija.</translation>
<translation id="8437238597147034694">&amp;Poništi premještanje</translation>
-<translation id="8456681095658380701">Pogrešno ime</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 kreditna kartica}one{# kreditna kartica}few{# kreditne kartice}other{# kreditnih kartica}}</translation>
<translation id="8483780878231876732">Da biste upotrebljavali kartice sa svojeg Google raÄuna, prijavite se na Chrome</translation>
<translation id="8488350697529856933">Primjenjuje se na</translation>
-<translation id="8492969205326575646">Nepodržana vrsta kartice</translation>
<translation id="8498891568109133222">Hostu <ph name="HOST_NAME" /> bilo je potrebno previše vremena za odgovor.</translation>
<translation id="852346902619691059">Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer operativni sustav uređaja sigurnosni certifikat ne smatra pouzdanim. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Godina isteka</translation>
<translation id="8543181531796978784">Možete <ph name="BEGIN_ERROR_LINK" />prijaviti problem s otkrivanjem<ph name="END_ERROR_LINK" /> ili, ako razumijete na koje je naÄine ugrožena vaÅ¡a sigurnost, <ph name="BEGIN_LINK" />posjetite nesigurnu web-lokaciju<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Prijevod nije uspio jer nije bilo moguće odrediti jezik stranice.</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="8570229484593575558">Ove se informacije |neće spremiti|:#vaÅ¡a povijest pregledavanja#vaÅ¡a pretraživanja#podaci o kolaÄićima</translation>
<translation id="8571890674111243710">Prijevod stranice na <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Vaše aktivnosti |i dalje mogu biti vidljive|:#web-lokacijama koje posjećujete#vašem poslodavcu#vašem davatelju internetskih usluga</translation>
<translation id="858637041960032120">Dodaj tel. broj
</translation>
<translation id="859285277496340001">Certifikat ne navodi mehanizam za provjeru svojeg opoziva.</translation>
<translation id="8620436878122366504">Roditelji je još nisu odobrili</translation>
<translation id="8647750283161643317">Vrati sve na zadano</translation>
<translation id="8703575177326907206">Vaša veza s <ph name="DOMAIN" /> nije šifrirana.</translation>
+<translation id="8718314106902482036">Plaćanje nije dovršeno</translation>
<translation id="8725066075913043281">Pokušajte ponovo</translation>
<translation id="8728672262656704056">Radite u anonimnom naÄinu</translation>
<translation id="8730621377337864115">Gotovo</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="8759274551635299824">Ta je kartica istekla</translation>
<translation id="8790007591277257123">&amp;Ponovi brisanje</translation>
-<translation id="8798099450830957504">Zadano</translation>
<translation id="8800988563907321413">Ovdje se prikazuju prijedlozi u blizini za vas</translation>
<translation id="8820817407110198400">Knjižne oznake</translation>
<translation id="883848425547221593">Druge oznake</translation>
@@ -818,6 +830,7 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="8866481888320382733">Pogreška pri analizi postavki pravila</translation>
<translation id="8866959479196209191">Ova stranica navodi sljedeće:</translation>
<translation id="8870413625673593573">Nedavno zatvoreno</translation>
+<translation id="8874824191258364635">Unesite važeći broj kreditne kartice</translation>
<translation id="8876793034577346603">Mrežna konfiguracija nije uspješno analizirana.</translation>
<translation id="8877192140621905067">Nakon što ih potvrdite, podaci o kartici dijelit će se s ovom web-lokacijom</translation>
<translation id="8889402386540077796">Ton</translation>
@@ -827,7 +840,6 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="8931333241327730545">Želite li spremiti tu karticu na Google raÄun?</translation>
<translation id="8932102934695377596">Sat kasni</translation>
<translation id="8954894007019320973">(Nast.)</translation>
-<translation id="895548565263634352">ÄŒitajte Älanke koje izdaju <ph name="ARTICLE_PUBLISHER" /> i drugi izdavaÄi (njih <ph name="OTHER_ARTICLE_COUNT" />)</translation>
<translation id="8971063699422889582">Istekao je certifikat poslužitelja.</translation>
<translation id="8986494364107987395">Automatski šalji Googleu statistiku o upotrebi i izvješća o padu programa</translation>
<translation id="8987927404178983737">Mjesec</translation>
@@ -845,7 +857,6 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="9068849894565669697">Odaberite boju</translation>
<translation id="9076283476770535406">Možda ima sadržaj za odrasle</translation>
<translation id="9078964945751709336">Potrebno je više podataka</translation>
-<translation id="9094175695478007090">Pokretanje aplikacije za plaćanje nije uspjelo.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> obiÄno upotrebljava enkripciju radi zaÅ¡tite vaÅ¡ih podataka. Prilikom ovog pokuÅ¡aja povezivanja Chromiuma s web-lokacijom <ph name="SITE" /> ta je web-lokacija vratila neuobiÄajene
i netoÄne vjerodajnice. To može znaÄiti da se neki napadaÄ pokuÅ¡ava predstaviti kao <ph name="SITE" /> ili je zaslon za prijavu na Wi-Fi prekinuo vezu. VaÅ¡i su podaci joÅ¡ uvijek sigurni jer je Chromium zaustavio povezivanje prije razmjene podataka.</translation>
<translation id="9137013805542155359">Prikaži original</translation>
diff --git a/chromium/components/strings/components_strings_hu.xtb b/chromium/components/strings/components_strings_hu.xtb
index 2113992e916..338de1073b5 100644
--- a/chromium/components/strings/components_strings_hu.xtb
+++ b/chromium/components/strings/components_strings_hu.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="hu">
<translation id="1008557486741366299">Ne most</translation>
<translation id="1015730422737071372">További részletek megadása</translation>
+<translation id="1021110881106174305">Elfogadott kártyák</translation>
<translation id="1032854598605920125">Forgatás jobbra</translation>
<translation id="1038842779957582377">Ismeretlen név</translation>
<translation id="1050038467049342496">Zárja be a többi alkalmazást</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Érték elrejtése</translation>
<translation id="1228893227497259893">Helytelen entitásazonosító</translation>
<translation id="1232569758102978740">Névtelen</translation>
+<translation id="1263231323834454256">Olvasási lista</translation>
<translation id="1264126396475825575">Hibajelentés készült: <ph name="CRASH_TIME" /> (még nincs feltöltve vagy mellőzték)</translation>
<translation id="1285320974508926690">Ezt a webhelyet soha ne fordítsa le</translation>
<translation id="129553762522093515">Mostanában bezárt</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">A Chromium Automatikus kitöltési beállításai…</translation>
<translation id="1374468813861204354">javaslatok</translation>
<translation id="1375198122581997741">A verzióról</translation>
+<translation id="1377321085342047638">Kártyaszám</translation>
<translation id="139305205187523129">A(z) <ph name="HOST_NAME" /> nem küldött adatokat.</translation>
<translation id="1407135791313364759">Összes megnyitása</translation>
<translation id="1413809658975081374">Adatvédelmi hiba</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Előzmények</translation>
<translation id="1645368109819982629">Nem támogatott protokoll</translation>
<translation id="1656489000284462475">Ãtvétel</translation>
+<translation id="1663943134801823270">A kártyák és a címek a Chrome-ból származnak. A <ph name="BEGIN_LINK" />Beállításokban<ph name="END_LINK" /> kezelheti őket.</translation>
<translation id="1676269943528358898">A(z) <ph name="SITE" /> webhely rendes esetben titkosítást alkalmaz az Ön adatainak védelme érdekében. Amikor a Google Chrome most csatlakozni próbált, a(z) <ph name="SITE" /> webhely szokatlan és helytelen hitelesítési adatokat küldött vissza. Ez olyankor fordulhat elő, amikor egy támadó megpróbálja magát kiadni a(z) <ph name="SITE" /> webhelynek, vagy valamilyen Wi-Fi-bejelentkezési képernyő megszakította a kapcsolatot. Adatai továbbra is biztonságban vannak, mivel a Google Chrome még azt megelőzően megszakította a kapcsolatot, hogy bármiféle adatcserére sor kerülhetett volna.</translation>
<translation id="168328519870909584">Előfordulhat, hogy a(z) <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> webhely támadói veszélyes alkalmazásokat kísérelnek meg telepíteni eszközére, amelyek ellopják vagy törlik adatait (például fotóit, jelszavait, üzeneteit és hitelkártyaadatait).</translation>
<translation id="168841957122794586">A szervertanúsítvány gyenge titkosítási kulcsot tartalmaz.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">A webhely felkereséséhez <ph name="NAME" /> engedélyére van szükség</translation>
+<translation id="1721424275792716183">* A mező kitöltése kötelező</translation>
<translation id="1728677426644403582">Jelenleg weboldal forrását tekinti meg</translation>
+<translation id="173080396488393970">Ez a kártyatípus nem támogatott</translation>
<translation id="1734864079702812349">American Express</translation>
<translation id="1734878702283171397">Próbálja felvenni a kapcsolatot a rendszergazdával.</translation>
+<translation id="1740951997222943430">Érvényes lejárati hónapot kell megadnia</translation>
<translation id="1745358365027406341">Az oldal letöltése később</translation>
<translation id="17513872634828108">Megnyitott lapok</translation>
<translation id="1753706481035618306">Oldalszám</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Kérjük, frissítse szinkronizálási összetett jelszavát.</translation>
<translation id="1787142507584202372">A megnyitott lapok helye</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Válassza ki a szállítási címet a szállítási módok és követelmények megtekintéséhez.</translation>
+<translation id="1803264062614276815">Kártyatulajdonos neve</translation>
<translation id="1803678881841855883">A Google Biztonságos Böngészés funkciója nemrég <ph name="BEGIN_LINK" />rosszindulatú programot észlelt<ph name="END_LINK" /> a(z) <ph name="SITE" /> webhelyen. A normál esetben biztonságos webhelyek néha rosszindulatú programokkal fertőzöttek. A rosszindulatú tartalom az ilyen programok következő ismert terjesztőjétől származik: <ph name="SUBRESOURCE_HOST" />. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Hozzáadva: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Érvénytelen kérés vagy kérésparaméter</translation>
<translation id="1826516787628120939">Ellenőrzés</translation>
<translation id="1834321415901700177">A webhely ártalmas programokat tartalmaz</translation>
<translation id="1842969606798536927">Fizetés</translation>
-<translation id="1864455488461349376">Szállítási beállítás</translation>
<translation id="1871208020102129563">A proxy fix proxyszerverek használatára van beállítva, nem pedig .pac típusú szkript URL címének használatára.</translation>
<translation id="1871284979644508959">Kötelező mező</translation>
<translation id="187918866476621466">Kezdőoldalak megnyitása</translation>
<translation id="1883255238294161206">Lista bezárása</translation>
<translation id="1898423065542865115">Szűrés</translation>
<translation id="194030505837763158">Ugrás ide: <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Elfogadott kártyák</translation>
<translation id="1962204205936693436">A(z) <ph name="DOMAIN" /> könyvjelzői</translation>
<translation id="1973335181906896915">Szerializálási hiba</translation>
<translation id="1974060860693918893">Speciális</translation>
<translation id="1978555033938440688">Firmware verziószáma</translation>
+<translation id="1995859865337580572">Igazolja a CVC-kódot</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{és 1 további}other{és # további}}</translation>
-<translation id="2020194265157481222">A kártyán szereplő név megadása kötelező</translation>
<translation id="2025186561304664664">Automatikusan konfigurálhatóra beállított proxy.</translation>
<translation id="2030481566774242610">Erre gondolt: <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />A proxy és a tűzfal ellenőrzése<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Ma</translation>
<translation id="2154054054215849342">A szinkronizálás az Ön domainjén nem áll rendelkezésre</translation>
<translation id="2154484045852737596">Kártya szerkesztése</translation>
-<translation id="2156993118928861787">Érvénytelen cím</translation>
<translation id="2166049586286450108">Teljes rendszergazdai hozzáférés</translation>
<translation id="2166378884831602661">A webhely nem képes biztonságos kapcsolatot nyújtani</translation>
<translation id="2181821976797666341">Házirendek</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 cím}other{# cím}}</translation>
+<translation id="2202020181578195191">Érvényes lejárati évet kell megadnia</translation>
<translation id="2212735316055980242">Nem találhatók irányelvek</translation>
<translation id="2213606439339815911">Bejegyzések lekérése...</translation>
<translation id="2230458221926704099">Javítsa meg kapcsolatát a <ph name="BEGIN_LINK" />diagnosztikai alkalmazás<ph name="END_LINK" /> segítségével</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Az internethez való hozzáférést a rendszer letiltotta</translation>
<translation id="230155334948463882">Új kártya?</translation>
<translation id="2305919008529760154">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványát csalással állíthatták ki. Ennek oka lehet konfigurációs hiba, vagy hogy támadó térítette el az Ön kapcsolódását. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">A kártya- és címinformációk a Google-fiókjából (<ph name="ACCOUNT_EMAIL" />) és a Chrome-ból származnak. Ezeket a <ph name="BEGIN_LINK" />Beállítások<ph name="END_LINK" /> menüpontban kezelheti.</translation>
<translation id="2317259163369394535">A(z) <ph name="DOMAIN" /> felhasználónevet és jelszót kér.</translation>
<translation id="2318774815570432836">A(z) <ph name="SITE" /> webhelyet pillanatnyilag nem tudja felkeresni, mert a webhely HSTS-t használ. 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. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">További könyvjelzők</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Vállalati alapértelmezett</translation>
<translation id="2386255080630008482">A szerver tanúsítványát visszavonták.</translation>
<translation id="2392959068659972793">Beállított értékkel nem rendelkező házirendek megjelenítése</translation>
+<translation id="239429038616798445">Ez a szállítási mód nem áll rendelkezésre. Próbálkozzon másik móddal.</translation>
<translation id="2396249848217231973">&amp;Törlés visszavonása</translation>
<translation id="2460160116472764928">A Google Biztonságos Böngészés funkciója nemrég <ph name="BEGIN_LINK" />rosszindulatú programot észlelt<ph name="END_LINK" /> a(z) <ph name="SITE" /> webhelyen. A rendes esetben biztonságos webhelyek néha rosszindulatú programokkal fertőzöttek. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Kitöltés</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Hálózati diagnosztika futtatása<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Érvénytelen keresési URL</translation>
<translation id="2491120439723279231">A szervezet tanúsítványa hibákat tartalmaz.</translation>
-<translation id="24943777258388405">Érvénytelen telefonszám</translation>
<translation id="2495083838625180221">JSON Parser</translation>
<translation id="2495093607237746763">Ha be van jelölve, a Chromium megőrzi a kártya másolatát ezen az eszközön a gyorsabb űrlapkitöltés érdekében.</translation>
<translation id="2498091847651709837">Új kártya beolvasása</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027">A(z) <ph name="HOST_NAME" /> érvénytelen választ küldött.</translation>
<translation id="2552545117464357659">Újabb</translation>
<translation id="2556876185419854533">&amp;Szerkesztés visszavonása</translation>
+<translation id="2587730715158995865">Forrás: <ph name="ARTICLE_PUBLISHER" />. Olvassa el ezt és további <ph name="OTHER_ARTICLE_COUNT" /> hírt.</translation>
<translation id="2587841377698384444">Könyvtár API-azonosítója:</translation>
<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>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Kapcsolódási diagnosztika futtatása<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">A kijelölt elemek eltávolítása</translation>
+<translation id="277133753123645258">Szállítási mód</translation>
<translation id="277499241957683684">Hiányzó eszközrekord</translation>
<translation id="2784949926578158345">A kapcsolat alaphelyzetbe állt.</translation>
<translation id="2794233252405721443">A webhely le van tiltva</translation>
-<translation id="2812680587231492111">Ez az átvételi lehetőség nem áll rendelkezésre. Próbálkozzon másik lehetőséggel.</translation>
<translation id="2824775600643448204">Cím- és keresősáv</translation>
<translation id="2826760142808435982">A kapcsolat <ph name="KX" /> algoritmust használ kulcscserélő mechanizmusként, kódolása pedig <ph name="CIPHER" /> használatával történt.</translation>
<translation id="2835170189407361413">Űrlap törlése</translation>
-<translation id="2849041323157393173">Ez a kézbesítési lehetőség nem áll rendelkezésre. Próbálkozzon másik lehetőséggel.</translation>
<translation id="2889159643044928134">Ne töltse újra</translation>
<translation id="2900469785430194048">Elfogyott a memória, miközben a Google Chrome megpróbálta megjeleníteni ezt a weboldalt.</translation>
<translation id="2909946352844186028">Változást érzékeltünk a hálózatban.</translation>
<translation id="2916038427272391327">Zárja be a többi programot</translation>
<translation id="2922350208395188000">A szerver tanúsítványát nem sikerült leellenőrizni.</translation>
+<translation id="2928905813689894207">Számlázási cím</translation>
<translation id="2948083400971632585">Bármelyik kapcsolatlétesítésre használt proxyt letilthatja a beállítások oldalon.</translation>
<translation id="2955913368246107853">Keresősáv bezárása</translation>
<translation id="2958431318199492670">A hálózati konfiguráció nem felel meg az ONC szabványnak. A konfiguráció egyes részeit nem lehet importálni.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">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 Google Chrome nem tudja ellenőrizni ezeket a tanúsítványokat.</translation>
<translation id="2972581237482394796">&amp;Újra</translation>
<translation id="2985306909656435243">Ha engedélyezi, a Chromium megőrzi a kártya másolatát ezen az eszközön a gyorsabb űrlapkitöltés érdekében.</translation>
+<translation id="2985398929374701810">Érvényes címet adjon meg</translation>
+<translation id="2986368408720340940">Ez az átvételi mód nem áll rendelkezésre. Próbálkozzon másik móddal.</translation>
<translation id="2991174974383378012">Megosztás webhelyekkel</translation>
<translation id="3005723025932146533">Mentett másolat megjelenítése</translation>
<translation id="3008447029300691911">Adja meg a(z) <ph name="CREDIT_CARD" /> kártya CVC-kódját. Az ellenőrzést követően a böngésző megosztja kártyaadatait ezzel a webhellyel.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{legalább 1 elem van a szinkronizált eszközökön}=1{1 elem (és még több a szinkronizált eszközökön)}other{# elem (és még több a szinkronizált eszközökön)}}</translation>
<translation id="3041612393474885105">Tanúsítvány adatai</translation>
<translation id="3063697135517575841">A Chrome ez alkalommal nem tudta ellenőrizni az Ön kártyáját. Próbálja újra később.</translation>
+<translation id="3064966200440839136">Inkognitómód elhagyása külső alkalmazással történő fizetéshez. Folytatja?</translation>
<translation id="3093245981617870298">Ön jelenleg offline.</translation>
<translation id="3105172416063519923">Tartalomazonosító:</translation>
<translation id="3109728660330352905">Nincs jogosultsága az oldal megjelenítésére.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Próbálkozzon a kapcsolódási diagnosztika futtatásával<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Nem sikerült dekódolni a választ</translation>
-<translation id="3149891296864842641">Szállítási lehetőség</translation>
<translation id="3150653042067488994">Ãtmeneti szerverhiba</translation>
+<translation id="3154506275960390542">Az oldal olyan űrlapot tartalmaz, amely esetében előfordulhat, hogy küldése nem biztonságosan történik. Az elküldött adatokat továbbítás közben mások is megtekinthetik, illetve támadók módosíthatják, hogy a szerver mást kapjon helyettük.</translation>
<translation id="3157931365184549694">Visszaállítás</translation>
<translation id="3167968892399408617">Az inkognitólapon megtekintett oldalak az összes inkognitólap bezárását követően nem szerepelnek majd böngészési előzményei között, a cookie-k gyűjtőhelyén, illetve a keresési előzményekben. A letöltött fájlok és a könyvjelzők azonban megmaradnak.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -261,11 +269,13 @@
<translation id="3345135638360864351">A webhelyhez való hozzáférésre irányuló kérelme nem jutott el <ph name="NAME" /> felhasználóhoz. Kérjük, próbálkozzon újra.</translation>
<translation id="3355823806454867987">Proxybeállítások módosítása...</translation>
<translation id="3369192424181595722">Órahiba</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> további elem…</translation>
<translation id="337363190475750230">Deaktiválva</translation>
<translation id="3377188786107721145">Irányelv-előfeldolgozási hiba</translation>
<translation id="3380365263193509176">Ismeretlen hiba</translation>
<translation id="3380864720620200369">Ügyfél-azonosító:</translation>
<translation id="3391030046425686457">Szállítási cím</translation>
+<translation id="3395827396354264108">Ãtvételi mód</translation>
<translation id="340013220407300675">A támadók megpróbálhatják ellopni adatait (például jelszavakat, üzeneteket vagy hitelkártyaszámokat) innen: <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="3422248202833853650">Próbáljon meg bezárni más programokat memória felszabadítása céljából.</translation>
<translation id="3422472998109090673">A(z) <ph name="HOST_NAME" /> jelenleg nem érhető el.</translation>
@@ -276,12 +286,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Lekérési intervallum:</translation>
<translation id="3462200631372590220">Speciális beállítások elrejtése</translation>
+<translation id="3467763166455606212">A kártyatulajdonos nevének megadása kötelező</translation>
+<translation id="3478058380795961209">Lejárat hónapja</translation>
<translation id="3479539252931486093">Ez váratlanul érte Önt? <ph name="BEGIN_LINK" />Tudassa velünk.<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Ne most</translation>
<translation id="348000606199325318">Hibaazonosító: <ph name="CRASH_LOCAL_ID" /> (szerverazonosító: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Jelenleg nem tudjuk elérni szüleidet. Próbálkozz újra.</translation>
<translation id="3528171143076753409">A szervezet tanúsítványa nem megbízható.</translation>
-<translation id="3538531656504267329">A kártya lejáratának éve érvénytelen</translation>
<translation id="3539171420378717834">A kártya másolatának megőrzése az eszközön</translation>
<translation id="3542684924769048008">Jelszó használata a következőre:</translation>
<translation id="3549644494707163724">Az összes szinkronizált adat titkosítása saját összetett szinkronizálási jelszóval</translation>
@@ -294,6 +305,7 @@
<translation id="3586931643579894722">Részletek elrejtése</translation>
<translation id="3587482841069643663">Mind</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Érvényes lejárati dátumot kell megadnia</translation>
<translation id="36224234498066874">Böngészési adatok törlése...</translation>
<translation id="362276910939193118">Minden előzmény megjelenítése</translation>
<translation id="3623476034248543066">Érték megjelenítése</translation>
@@ -310,7 +322,6 @@
<translation id="3693415264595406141">Jelszó:</translation>
<translation id="3696411085566228381">nincs</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Válassza ki a szállítási címet a szállítási módok és követelmények megtekintéséhez.</translation>
<translation id="370665806235115550">Betöltés...</translation>
<translation id="3712624925041724820">Az engedélyek elfogytak</translation>
<translation id="3714780639079136834">A mobiladatok vagy a Wi-Fi bekapcsolása</translation>
@@ -319,6 +330,7 @@
<translation id="3739623965217189342">Ãtmásolt link</translation>
<translation id="375403751935624634">A fordítás a szerver hibája miatt nem sikerült.</translation>
<translation id="3759461132968374835">Nincs a közelmúltban bejelentett rendszerösszeomlás. A kikapcsolt jelentésküldés során történt összeomlások nem jelennek meg itt.</translation>
+<translation id="3787705759683870569">Lejárat dátuma: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Ha proxyszervert használ...</translation>
<translation id="3828924085048779000">Az üres összetett jelszó nem engedélyezett.</translation>
<translation id="3845539888601087042">Előzmények megjelenítése bejelentkezett eszközeiről. <ph name="BEGIN_LINK" />További információ<ph name="END_LINK" />.</translation>
@@ -354,7 +366,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Szeretné, hogy a Chromium mentse ezt a kártyát?</translation>
<translation id="4171400957073367226">Hibás igazoló aláírás.</translation>
-<translation id="4176463684765177261">Kikapcsolva</translation>
<translation id="4196861286325780578">&amp;Ãthelyezés újra</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />A tűzfal és a vírusirtó konfigurációjának ellenőrzése<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{nincsen}=1{1 alkalmazás ($1)}=2{2 alkalmazás ($1, $2)}other{# alkalmazás ($1, $2, $3)}}</translation>
@@ -381,11 +392,11 @@
<translation id="4406896451731180161">keresési találat</translation>
<translation id="4432688616882109544">A(z) <ph name="HOST_NAME" /> nem fogadta el az Ön bejelentkezési tanúsítványát, vagy nem talált ilyet.</translation>
<translation id="443673843213245140">A proxy használata le van tiltva, de kifejezett proxykonfiguráció van megadva.</translation>
-<translation id="4446242550670694251">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.</translation>
<translation id="4492190037599258964">Találatok a(z) „<ph name="SEARCH_STRING" />†kifejezésre</translation>
<translation id="4506176782989081258">Érvényesítési hiba: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Kapcsolatfelvétel a rendszergazdával</translation>
<translation id="450710068430902550">Megosztás a rendszergazdával</translation>
+<translation id="4515275063822566619">A kártyák és a címek a Chrome-ból és az Ön Google-fiókjából (<ph name="ACCOUNT_EMAIL" />) származnak. A <ph name="BEGIN_LINK" />Beállításokban<ph name="END_LINK" /> kezelheti őket.</translation>
<translation id="4522570452068850558">Részletek</translation>
<translation id="4558551763791394412">Próbálkozzon a bővítmények letiltásával.</translation>
<translation id="457875822857220463">Szállítás</translation>
@@ -415,6 +426,7 @@
<translation id="4816492930507672669">Igazítás az oldalmérethez</translation>
<translation id="483020001682031208">Nem jeleníthetők meg oldalak a Fizikai webről</translation>
<translation id="4850886885716139402">Nézet</translation>
+<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="4858792381671956233">Megkérdezted a szüleidet, hogy meg szabad-e látogatnod ezt a webhelyet</translation>
<translation id="4880827082731008257">Keresés az előzmények között</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> és <ph name="TYPE_3" /></translation>
@@ -422,7 +434,6 @@
<translation id="4923417429809017348">Ezt az oldalt lefordították egy ismeretlen nyelvről <ph name="LANGUAGE_LANGUAGE" /> nyelvre</translation>
<translation id="4923459931733593730">Fizetés</translation>
<translation id="4926049483395192435">Meg kell határozni.</translation>
-<translation id="4941291666397027948">* kötelező mezőt jelöl</translation>
<translation id="495170559598752135">Műveletek</translation>
<translation id="4958444002117714549">Lista részletes nézete</translation>
<translation id="4962322354953122629">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványa a Chrome szerint nem megbízható. Ennek oka lehet konfigurációs hiba, vagy hogy támadó térítette el az Ön kapcsolódását. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -437,6 +448,7 @@
<translation id="5045550434625856497">Helytelen jelszó</translation>
<translation id="5056549851600133418">Cikkek Önnek</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />A proxy címének ellenőrzése<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Nincs cookie}=1{1 webhely használ cookie-kat. }other{# webhely használ cookie-kat. }}</translation>
<translation id="5087286274860437796">A szerver tanúsítványa jelenleg nem érvényes.</translation>
<translation id="5087580092889165836">Kártya hozzáadása</translation>
<translation id="5089810972385038852">Ãllam</translation>
@@ -459,10 +471,8 @@
<translation id="5300589172476337783">Megjelenítés</translation>
<translation id="5308689395849655368">A hibabejelentés ki van kapcsolva.</translation>
<translation id="5317780077021120954">Mentés</translation>
-<translation id="5326702247179446998">Címzett megadása kötelező</translation>
<translation id="5327248766486351172">Név</translation>
<translation id="5337705430875057403">A(z) <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> webhely támadói megpróbálhatják becsapni Önt, hogy például veszélyes szoftvert telepítsen vagy felfedje személyes adatait (jelszavát, telefonszámát, hitelkártyaszámát stb.).</translation>
-<translation id="53553865750799677">Nem támogatott átvételi cím. Válasszon másik címet.</translation>
<translation id="5359637492792381994">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványa jelenleg nem érvényes. Ennek oka lehet konfigurációs hiba, vagy hogy támadó térítette el az Ön kapcsolatát. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Az irányelv-beállítások tárolása sikertelen</translation>
<translation id="5386426401304769735">A webhely tanúsítványlánca SHA-1 titkosítással aláírt tanúsítványt tartalmaz.</translation>
@@ -488,8 +498,8 @@
<translation id="5544037170328430102">A(z) <ph name="SITE" /> egy beágyazott oldalának közlendője:</translation>
<translation id="5556459405103347317">Újratöltés</translation>
<translation id="5565735124758917034">Aktív</translation>
+<translation id="5571083550517324815">Ezen a címen nem lehetséges az átvétel. Válasszon másik címet.</translation>
<translation id="5572851009514199876">Indítsa el a Chrome böngészőt és jelentkezzen be, hogy a Chrome ellenőrizni tudja, engedélyezték-e a hozzáférést ehhez a webhelyhez.</translation>
-<translation id="5575380383496039204">Nem támogatott szállítási cím. Válasszon másik címet.</translation>
<translation id="5580958916614886209">Ellenőrizze a lejárati hónapot, majd próbálja újra</translation>
<translation id="560412284261940334">A kezelés nem támogatott</translation>
<translation id="5610142619324316209">A kapcsolat ellenőrzése</translation>
@@ -505,7 +515,8 @@
<translation id="5710435578057952990">A webhely valódiságát nem ellenőriztük.</translation>
<translation id="5720705177508910913">Jelenlegi felhasználó</translation>
<translation id="5732392974455271431">A letiltást a szüleid oldhatják fel</translation>
-<translation id="57586589942790530">Érvénytelen kártyaszám</translation>
+<translation id="5763042198335101085">Érvényes e-mail-címet adjon meg</translation>
+<translation id="5765072501007116331">A kézbesítési módok és követelmények megtekintéséhez válassza ki a címet</translation>
<translation id="5784606427469807560">A kártya ellenőrzése során hiba történt. Ellenőrizze az internetkapcsolatot, majd próbálkozzon újra.</translation>
<translation id="5785756445106461925">Emellett az oldal azonban más forrásokat is tartalmaz, amelyek nem biztonságosak. Ezeket a forrásokat mások is megtekinthetik átvitel közben, és megváltoztatásukkal a támadók módosíthatják az oldal viselkedését.</translation>
<translation id="5786044859038896871">Ki szeretné tölteni a kártyaadatait?</translation>
@@ -518,22 +529,20 @@
<translation id="5869405914158311789">A webhely nem érhető el</translation>
<translation id="5869522115854928033">Mentett jelszavak</translation>
<translation id="5872918882028971132">Szülői javaslatok</translation>
-<translation id="587760065310675640">Nem támogatott szállítási cím. Válasszon másik címet.</translation>
<translation id="5901630391730855834">Sárga</translation>
-<translation id="59174027418879706">Engedélyezve</translation>
<translation id="5926846154125914413">Elveszítheti hozzáférését az egyes webhelyek prémium tartalmaihoz.</translation>
<translation id="5959728338436674663">Bizonyos <ph name="BEGIN_WHITEPAPER_LINK" />rendszer-információk és oldaltartalmak<ph name="END_WHITEPAPER_LINK" /> automatikus küldése a Google-nak a veszélyes alkalmazások és webhelyek felderítése érdekében. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Hét</translation>
<translation id="5967867314010545767">Eltávolítás az előzmények közül</translation>
<translation id="5975083100439434680">Kicsinyítés</translation>
+<translation id="598637245381783098">Nem sikerült megnyitni a fizetőalkalmazást</translation>
<translation id="5989320800837274978">Sem fix proxyszerver, sem pedig .pac típusú szkript URL-címe nincs megadva.</translation>
<translation id="5990559369517809815">A szerver felé irányuló kéréseket egy bővítmény blokkolja.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">A kártya- és címlehetőségek a Chrome-ból származnak. Ezeket a <ph name="BEGIN_LINK" />Beállítások<ph name="END_LINK" /> menüpontban kezelheti.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1. oldal}other{#. oldal}}</translation>
<translation id="6017514345406065928">Zöld</translation>
+<translation id="6027201098523975773">Adjon meg nevet</translation>
<translation id="6040143037577758943">Bezárás</translation>
-<translation id="604124094241169006">Automatikus</translation>
<translation id="6042308850641462728">Hosszabban</translation>
<translation id="6060685159320643512">Óvatosan, ezek a kísérletek haraphatnak</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{nincsen}=1{1}other{#}}</translation>
@@ -541,9 +550,10 @@
hálózati eszközt, amelyet használ.</translation>
<translation id="614940544461990577">Próbálja ki a következőket:</translation>
<translation id="6151417162996330722">A szervertanúsítvány érvényességi ideje túl hosszú.</translation>
-<translation id="615643356032862689">A letöltött fájlok és a mentett könyvjelzők megmaradnak.</translation>
+<translation id="6157877588268064908">A szállítási módok és követelmények megtekintéséhez válassza ki a címet</translation>
<translation id="6165508094623778733">További információ</translation>
<translation id="6177128806592000436">Kapcsolata a webhellyel nem biztonságos</translation>
+<translation id="6184817833369986695">(kohorsz: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Ellenőrizze az internetkapcsolatot</translation>
<translation id="6218753634732582820">Eltávolítja a címet a Chromiumból?</translation>
<translation id="6251924700383757765">Adatvédelmi irányelvek</translation>
@@ -552,6 +562,8 @@
<translation id="6259156558325130047">&amp;Ãtrendezés újra</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> könyvjelzők</translation>
<translation id="6264485186158353794">Vissza a biztonsághoz</translation>
+<translation id="6276112860590028508">Az olvasási listájának adatai itt jelennek meg</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="6290238015253830360">A javasolt cikkek helye</translation>
<translation id="6305205051461490394">A(z) <ph name="URL" /> nem érhető el.</translation>
@@ -573,7 +585,6 @@
<translation id="6417515091412812850">Nem lehet ellenőrizni, hogy a tanúsítványt visszavonták-e.</translation>
<translation id="6433490469411711332">Kapcsolattartási adatok szerkesztése</translation>
<translation id="6433595998831338502">A(z) <ph name="HOST_NAME" /> visszautasította a csatlakozást.</translation>
-<translation id="6443118737398455446">Érvénytelen lejárati dátum</translation>
<translation id="6446608382365791566">További adatok hozzáadása</translation>
<translation id="6451458296329894277">Képernyő újraküldésének megerősítése</translation>
<translation id="6456339708790392414">Fizetés</translation>
@@ -581,10 +592,8 @@
<translation id="6462969404041126431">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 támadó térítette el az Ön kapcsolódását. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Eszközházirendek</translation>
<translation id="6477321094435799029">A Chrome szokatlan kódot észlelt az oldalon, ezért letiltotta az Ön személyes adatainak (például jelszavak, telefonszámok és hitelkártyaszámok) védelme érdekében.</translation>
-<translation id="6477460825583319731">Érvénytelen e-mail-cím</translation>
<translation id="6489534406876378309">Feltöltési összeomlások indítása</translation>
<translation id="6508722015517270189">Indítsa újra a Chrome-ot</translation>
-<translation id="6525462735697194615">A kártya lejáratának hónapja érvénytelen</translation>
<translation id="6529602333819889595">&amp;Törlés újra</translation>
<translation id="6534179046333460208">Fizikai web – javaslatok</translation>
<translation id="6550675742724504774">Beállítások</translation>
@@ -599,7 +608,6 @@
<translation id="6628463337424475685">Keresés: <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Ez a házirend már elavult.</translation>
<translation id="6652240803263749613">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványa a számítógép operációs rendszere szerint nem megbízható. Ennek oka lehet konfigurációs hiba, vagy hogy támadó térítette el az Ön kapcsolódását. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Ez a szállítási lehetőség nem áll rendelkezésre. Próbálkozzon másik lehetőséggel.</translation>
<translation id="6671697161687535275">Eltávolítja az űrlapjavaslatot a Chromiumból?</translation>
<translation id="6685834062052613830">Kijelentkezés és a beállítás befejezése</translation>
<translation id="6710213216561001401">Előző</translation>
@@ -607,13 +615,13 @@
<translation id="6711464428925977395">Valami gond van a proxyszerverrel, vagy a cím nem megfelelő.</translation>
<translation id="6727102863431372879">Beállítás</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{nincsen}=1{1 elem}other{# elem}}</translation>
-<translation id="6743044928064272573">Ãtvételi lehetÅ‘ség</translation>
<translation id="674375294223700098">Ismeretlen szervertanúsítvány-hiba.</translation>
<translation id="6753269504797312559">Házirend értéke</translation>
<translation id="6757797048963528358">Eszköze alvó üzemmódba váltott.</translation>
<translation id="6778737459546443941">A szülő még nem hagyta jóvá</translation>
<translation id="6810899417690483278">Testreszabás-azonosító</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Nem sikerült betölteni a régióadatokat</translation>
<translation id="6831043979455480757">Fordítás</translation>
<translation id="6839929833149231406">Körzet</translation>
<translation id="6874604403660855544">&amp;Hozzáadás újra</translation>
@@ -621,6 +629,7 @@
<translation id="6895330447102777224">Kártyáját ellenőriztük</translation>
<translation id="6897140037006041989">User agent</translation>
<translation id="6915804003454593391">Felhasználó:</translation>
+<translation id="6948701128805548767">Az átvételi módok és követelmények megtekintéséhez válassza ki a címet</translation>
<translation id="6957887021205513506">A szerver tanúsítványa hamisítványnak tűnik.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Készülék</translation>
@@ -628,7 +637,6 @@
<translation id="6973656660372572881">Mindkét fix proxyszerver és egy .Pac típusú szkript URL-címe meg van adva.</translation>
<translation id="6989763994942163495">Speciális beállítások megjelenítése...</translation>
<translation id="7000990526846637657">Nincsenek előzménybejegyzések</translation>
-<translation id="7001663382399377034">Címzett hozzáadása</translation>
<translation id="7009986207543992532">Ön megpróbálta elérni a(z) <ph name="DOMAIN" /> domaint, de a szerver olyan tanúsítványt mutatott be, amelynek érvényességi ideje túl hosszú ahhoz, hogy megbízható legyen. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Előfordulhat, hogy a böngészési előzmények más formái megtalálhatók Google-fiókjában a <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> címen</translation>
@@ -639,12 +647,15 @@
<translation id="7088615885725309056">Régebbi</translation>
<translation id="7090678807593890770">Keresés a Google-on a következőre: <ph name="LINK" /></translation>
<translation id="7119414471315195487">Zárja be a többi lapot vagy programot</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="7138472120740807366">Kézbesítési mód</translation>
<translation id="7139724024395191329">Emírség</translation>
<translation id="7155487117670177674">A fizetés nem biztonságos</translation>
<translation id="7179921470347911571">Újraindítás most</translation>
<translation id="7180611975245234373">Frissítés</translation>
<translation id="7182878459783632708">Nincsenek beállított házirendek</translation>
<translation id="7186367841673660872">Ezt az oldalt<ph name="ORIGINAL_LANGUAGE" />nyelvről fordítottuk<ph name="LANGUAGE_LANGUAGE" />nyelvre.</translation>
+<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="7210863904660874423">A(z) <ph name="HOST_NAME" /> nem felel meg a biztonsági szabványoknak.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />További információ<ph name="END_LINK" /> erről a hibáról.</translation>
@@ -673,7 +684,6 @@ Pszt! Az inkognitómód (<ph name="SHORTCUT_KEY" />) hasznos lehet a következő
<translation id="7424977062513257142">A weboldal egy beágyazott oldalának közlendője:</translation>
<translation id="7441627299479586546">Az irányelv tárgya nem megfelelő</translation>
<translation id="7444046173054089907">Ez a webhely le van tiltva</translation>
-<translation id="7444238235002594607">Válassza ki az átvételi címet az átvételi módok és követelmények megtekintéséhez.</translation>
<translation id="7445762425076701745">Nem sikerült teljesen ellenőrizni a szerver azonosságát, amelyhez kapcsolódik. Egy olyan névvel kapcsolódik a szerverhez, amelynek tulajdonjogát egy külső tanúsítványkibocsátó nem ellenőrizheti. Mivel egyes tanúsítványkibocsátók figyelmen kívül hagyják ezeket a neveket, így semmi nem biztosítja, hogy a kívánt webhelyhez kapcsolódik, és nem egy támadó webhelyhez.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />További információk megtekintése<ph name="END_LINK" /> a problémával kapcsolatban.</translation>
<translation id="7460163899615895653">A többi eszközön legutoljára megtekintett lapok láthatók itt</translation>
@@ -717,6 +727,7 @@ Pszt! Az inkognitómód (<ph name="SHORTCUT_KEY" />) hasznos lehet a következő
<translation id="7755287808199759310">A letiltást a szülő oldhatja fel</translation>
<translation id="7758069387465995638">Előfordulhat, hogy a tűzfal vagy a vírusirtó szoftver tiltotta le a kapcsolatot.</translation>
<translation id="7761701407923456692">A szerver tanúsítványa nem egyezik az URL-lel</translation>
+<translation id="7763386264682878361">Fizetésijegyzék-elemző</translation>
<translation id="7764225426217299476">Cím hozzáadása</translation>
<translation id="777702478322588152">Prefektúra</translation>
<translation id="7791543448312431591">Hozzáadás</translation>
@@ -730,6 +741,7 @@ Pszt! Az inkognitómód (<ph name="SHORTCUT_KEY" />) hasznos lehet a következő
<translation id="785549533363645510">Azonban Ön nem teljesen láthatatlan. Az inkognitómód használata nem rejti el böngészési műveleteit munkáltatója, az internetszolgáltatója és a felkeresett webhelyek elől.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" />: <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Ellenőrizze a CVC-t, majd próbálja újra</translation>
+<translation id="79338296614623784">Érvényes telefonszámot adjon meg</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">A szerver tanúsítványa még nem érvényes.</translation>
<translation id="7942349550061667556">Piros</translation>
@@ -749,6 +761,7 @@ Pszt! Az inkognitómód (<ph name="SHORTCUT_KEY" />) hasznos lehet a következő
<translation id="8088680233425245692">Nem sikerült megtekinteni a cikket.</translation>
<translation id="8089520772729574115">kevesebb mint 1 MB</translation>
<translation id="8091372947890762290">Az aktiválás függőben van a szerveren</translation>
+<translation id="8118489163946903409">Fizetési mód</translation>
<translation id="8131740175452115882">Megerősítés</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> szerverének <ph name="BEGIN_ABBR" />DNS-címe<ph name="END_ABBR" /> nem található.</translation>
<translation id="8149426793427495338">Számítógépe alvó üzemmódba váltott.</translation>
@@ -774,6 +787,7 @@ Pszt! Az inkognitómód (<ph name="SHORTCUT_KEY" />) hasznos lehet a következő
<translation id="8349305172487531364">Könyvjelzősáv</translation>
<translation id="8363502534493474904">Repülős üzemmód kikapcsolása</translation>
<translation id="8364627913115013041">Nincs beállítva.</translation>
+<translation id="8368476060205742148">Google Play-szolgáltatások</translation>
<translation id="8380941800586852976">Veszélyes</translation>
<translation id="8382348898565613901">A közelmúltban megnyitott könyvjelzők helye</translation>
<translation id="8398259832188219207">A hibajelentés feltöltésének ideje: <ph name="UPLOAD_TIME" /></translation>
@@ -782,32 +796,30 @@ Pszt! Az inkognitómód (<ph name="SHORTCUT_KEY" />) hasznos lehet a következő
<translation id="8428213095426709021">Beállítások</translation>
<translation id="8433057134996913067">Ezzel kijelentkezik a legtöbb webhelyről.</translation>
<translation id="8437238597147034694">&amp;Ãthelyezés visszavonása</translation>
-<translation id="8456681095658380701">Érvénytelen név</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 hitelkártya}other{# hitelkártya}}</translation>
<translation id="8483780878231876732">Jelentkezzen be a Chrome-ba, hogy használhassa a kártyákat Google-fiókjából.</translation>
<translation id="8488350697529856933">A következőre érvényes</translation>
-<translation id="8492969205326575646">Nem támogatott kártyatípus</translation>
<translation id="8498891568109133222">A(z) <ph name="HOST_NAME" /> túl hosszú ideje nem válaszol.</translation>
<translation id="852346902619691059">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványa az eszköz operációs rendszere szerint nem megbízható. Ennek oka lehet konfigurációs hiba, vagy hogy támadó térítette el az Ön kapcsolódását. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Lejárat éve</translation>
<translation id="8543181531796978784">Lehetősége van arra, hogy <ph name="BEGIN_ERROR_LINK" />jelentse az észlelési problémát<ph name="END_ERROR_LINK" />, ha pedig tisztában van a biztonságát fenyegető kockázatokkal, <ph name="BEGIN_LINK" />felkeresheti a nem biztonságos webhelyet<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">A fordítás nem sikerült, mivel az oldal nyelvét nem lehet megállapítani.</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="8570229484593575558">A következő információk |nem lesznek mentve|:#A böngészési előzmények#A végrehajtott keresések#A cookie-k adatai</translation>
<translation id="8571890674111243710">Oldal fordítása erre a nyelvre: <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Előfordulhat, hogy tevékenységeit |továbbra is láthatják|:#A felkeresett webhelyek#A munkaadója#Az internetszolgáltatója</translation>
<translation id="858637041960032120">Szám hozzáadása
</translation>
<translation id="859285277496340001">Ez a tanúsítvány nem határoz meg olyan mechanizmust, amely ellenőrizné, hogy visszavonták-e.</translation>
<translation id="8620436878122366504">A szüleid még nem hagyták jóvá</translation>
<translation id="8647750283161643317">Minden visszaállítása az alapértékre</translation>
<translation id="8703575177326907206">A kapcsolat (<ph name="DOMAIN" />) nem titkosított.</translation>
+<translation id="8718314106902482036">A fizetés nem fejeződött be</translation>
<translation id="8725066075913043281">Újrapróbálás</translation>
<translation id="8728672262656704056">Ön inkognitómódra váltott</translation>
<translation id="8730621377337864115">Kész</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="8759274551635299824">A kártya lejárt</translation>
<translation id="8790007591277257123">&amp;Törlés újra</translation>
-<translation id="8798099450830957504">Alapértelmezett</translation>
<translation id="8800988563907321413">A közeli javaslatok helye</translation>
<translation id="8820817407110198400">Könyvjelzők</translation>
<translation id="883848425547221593">Egyéb könyvjelzők</translation>
@@ -817,6 +829,7 @@ Pszt! Az inkognitómód (<ph name="SHORTCUT_KEY" />) hasznos lehet a következő
<translation id="8866481888320382733">Irányelv-beállítások előfeldolgozási hibája</translation>
<translation id="8866959479196209191">Az oldal közlendője:</translation>
<translation id="8870413625673593573">Mostanában bezárt</translation>
+<translation id="8874824191258364635">Érvényes kártyaszámot adjon meg</translation>
<translation id="8876793034577346603">A hálózati konfiguráció előfeldolgozása sikertelen.</translation>
<translation id="8877192140621905067">Az igazolást követően a böngésző megosztja kártyaadatait a webhellyel</translation>
<translation id="8889402386540077796">Színárnyalat</translation>
@@ -826,7 +839,6 @@ Pszt! Az inkognitómód (<ph name="SHORTCUT_KEY" />) hasznos lehet a következő
<translation id="8931333241327730545">Menti ezt a kártyát a Google-fiókjába?</translation>
<translation id="8932102934695377596">Késik az órája</translation>
<translation id="8954894007019320973">(Folyt.)</translation>
-<translation id="895548565263634352">A(z) <ph name="ARTICLE_PUBLISHER" /> híreinek olvasása (<ph name="OTHER_ARTICLE_COUNT" /> további cikk van)</translation>
<translation id="8971063699422889582">A szerver tanúsítványa lejárt.</translation>
<translation id="8986494364107987395">Használati statisztikák és hibajelentések automatikus küldése a Google-nak</translation>
<translation id="8987927404178983737">hónap</translation>
@@ -844,7 +856,6 @@ Pszt! Az inkognitómód (<ph name="SHORTCUT_KEY" />) hasznos lehet a következő
<translation id="9068849894565669697">Szín kiválasztása</translation>
<translation id="9076283476770535406">Lehet, hogy felnőtt tartalommal rendelkezik</translation>
<translation id="9078964945751709336">Több információra van szükség</translation>
-<translation id="9094175695478007090">Nem sikerült elindítani a fizetési alkalmazást.</translation>
<translation id="9103872766612412690">A(z) <ph name="SITE" /> webhely rendes esetben titkosítást alkalmaz az Ön adatainak védelme érdekében. Amikor a Chromium most csatlakozni próbált, a(z) <ph name="SITE" /> webhely szokatlan és helytelen hitelesítési adatokat küldött vissza.Ez olyankor fordulhat elő, amikor egy támadó megpróbálja magát kiadni a(z) <ph name="SITE" /> webhelynek, vagy valamilyen Wi-Fi-bejelentkezési képernyő megszakította a kapcsolatot. Adatai továbbra is biztonságban vannak, mivel a Chromium még azt megelőzően megszakította a kapcsolatot, hogy bármiféle adatcserére sor kerülhetett volna.</translation>
<translation id="9137013805542155359">Eredeti megjelenítése</translation>
<translation id="9137248913990643158">Indítsa el a Chrome böngészőt és jelentkezzen be az alkalmazás használata előtt.</translation>
diff --git a/chromium/components/strings/components_strings_id.xtb b/chromium/components/strings/components_strings_id.xtb
index 73e3b873399..468dbe9a02d 100644
--- a/chromium/components/strings/components_strings_id.xtb
+++ b/chromium/components/strings/components_strings_id.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="id">
<translation id="1008557486741366299">Jangan Sekarang</translation>
<translation id="1015730422737071372">Berikan detail tambahan</translation>
+<translation id="1021110881106174305">Kartu yang diterima</translation>
<translation id="1032854598605920125">Putar searah jarum jam</translation>
<translation id="1038842779957582377">nama tidak diketahui</translation>
<translation id="1050038467049342496">Tutup aplikasi lain</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Sembunyikan nilai</translation>
<translation id="1228893227497259893">Pengidentifikasi entitas salah</translation>
<translation id="1232569758102978740">Tanpa Judul</translation>
+<translation id="1263231323834454256">Daftar bacaan</translation>
<translation id="1264126396475825575">Laporan kerusakan diambil pada pukul <ph name="CRASH_TIME" /> (belum diupload atau diabaikan)</translation>
<translation id="1285320974508926690">Jangan pernah terjemahkan situs ini</translation>
<translation id="129553762522093515">Barusan ditutup</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Setelan IsiOtomatis Chromium...</translation>
<translation id="1374468813861204354">saran</translation>
<translation id="1375198122581997741">Tentang Versi</translation>
+<translation id="1377321085342047638">Nomor Kartu</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> tidak mengirimkan data apa pun.</translation>
<translation id="1407135791313364759">Buka semua</translation>
<translation id="1413809658975081374">Kesalahan privasi</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Riwayat</translation>
<translation id="1645368109819982629">Protokol yang tidak didukung</translation>
<translation id="1656489000284462475">Pengambilan</translation>
+<translation id="1663943134801823270">Kartu dan alamat berasal dari Chrome. Anda dapat mengelolanya di <ph name="BEGIN_LINK" />Setelan<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> biasanya menggunakan enkripsi untuk melindungi informasi Anda. Saat Google Chrome mencoba menyambung ke <ph name="SITE" /> kali ini, situs web mengembalikan kredensial yang salah dan tidak biasa. Hal ini dapat terjadi jika ada penyerang yang berpura-pura menjadi <ph name="SITE" />, atau layar masuk Wi-Fi mengganggu sambungan. Informasi Anda masih aman karena Google Chrome menghentikan sambungan sebelum terjadi pertukaran data apa pun.</translation>
<translation id="168328519870909584">Saat ini penyerang yang berada di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mungkin berusaha memasang program berbahaya di perangkat Anda yang dapat mencuri atau menghapus informasi (misalnya, foto, sandi, pesan, dan kartu kredit).</translation>
<translation id="168841957122794586">Sertifikat server berisi kunci kriptografis yang lemah.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Anda memerlukan izin dari <ph name="NAME" /> untuk mengunjungi situs ini</translation>
+<translation id="1721424275792716183">* Kolom wajib diisi</translation>
<translation id="1728677426644403582">Anda melihat sumber halaman web</translation>
+<translation id="173080396488393970">Jenis kartu tidak didukung</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Coba hubungi admin sistem.</translation>
+<translation id="1740951997222943430">Masukkan bulan habis masa berlaku yang valid</translation>
<translation id="1745358365027406341">Download halaman nanti</translation>
<translation id="17513872634828108">Buka tab</translation>
<translation id="1753706481035618306">Nomor laman</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Perbarui frasa sandi sinkronisasi Anda.</translation>
<translation id="1787142507584202372">Tab yang terbuka muncul di sini</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Pilih alamat pengiriman untuk memeriksa metode pengiriman dan persyaratan.</translation>
-<translation id="1803678881841855883">Google Penjelajahan Aman baru-baru ini <ph name="BEGIN_LINK" />mendeteksi perangkat lunak perusak<ph name="END_LINK" /> di <ph name="SITE" />. Situs web yang biasanya aman terkadang dapat terinfeksi perangkat lunak perusak. Konten berbahaya tersebut berasal dari <ph name="SUBRESOURCE_HOST" />, sebuah distributor perangkat lunak perusak ternama. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="1803264062614276815">Nama Pemegang Kartu</translation>
+<translation id="1803678881841855883">Google Penjelajahan Aman baru-baru ini <ph name="BEGIN_LINK" />mendeteksi software perusak<ph name="END_LINK" /> di <ph name="SITE" />. Situs web yang biasanya aman terkadang dapat terinfeksi software perusak. Konten berbahaya tersebut berasal dari <ph name="SUBRESOURCE_HOST" />, sebuah distributor software perusak ternama. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Ditambahkan pada <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Permintaan atau parameter permintaan tidak valid</translation>
<translation id="1826516787628120939">Memeriksa</translation>
<translation id="1834321415901700177">Situs ini berisi program yang berbahaya</translation>
<translation id="1842969606798536927">Bayar</translation>
-<translation id="1864455488461349376">Opsi pengiriman</translation>
<translation id="1871208020102129563">Proxy disetel untuk menggunakan server proxy tetap, bukan URL skrip .pac.</translation>
<translation id="1871284979644508959">Bidang wajib diisi</translation>
<translation id="187918866476621466">Buka halaman awal</translation>
<translation id="1883255238294161206">Ciutkan daftar</translation>
<translation id="1898423065542865115">Pemfilteran</translation>
<translation id="194030505837763158">Buka <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Kartu diterima</translation>
<translation id="1962204205936693436">Bookmark <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Kesalahan serialisasi</translation>
<translation id="1974060860693918893">Lanjutan</translation>
<translation id="1978555033938440688">Versi Firmware</translation>
+<translation id="1995859865337580572">Harap verifikasi CVC Anda</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{dan 1 lainnya}other{dan # lainnya}}</translation>
-<translation id="2020194265157481222">Perlu nama di kartu</translation>
<translation id="2025186561304664664">Proxy disetel ke konfigurasi otomatis.</translation>
<translation id="2030481566774242610">Mungkin maksud Anda <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Memeriksa proxy dan firewall<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Hari ini</translation>
<translation id="2154054054215849342">Sinkronisasi tidak tersedia untuk domain Anda</translation>
<translation id="2154484045852737596">Edit kartu</translation>
-<translation id="2156993118928861787">Alamat tidak valid</translation>
<translation id="2166049586286450108">Akses Penuh Admin</translation>
<translation id="2166378884831602661">Situs ini tidak dapat menyediakan sambungan aman</translation>
<translation id="2181821976797666341">Kebijakan</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 alamat}other{# alamat}}</translation>
+<translation id="2202020181578195191">Masukkan tahun habis masa berlaku yang valid</translation>
<translation id="2212735316055980242">Kebijakan tidak ditemukan</translation>
<translation id="2213606439339815911">Mengambil entri...</translation>
<translation id="2230458221926704099">Perbaiki sambungan menggunakan <ph name="BEGIN_LINK" />aplikasi diagnosis<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Akses Internet Anda diblokir</translation>
<translation id="230155334948463882">Kartu baru?</translation>
<translation id="2305919008529760154">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya mungkin telah dikeluarkan secara tidak sah. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut <ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Opsi kartu dan alamat berasal dari Akun Google (<ph name="ACCOUNT_EMAIL" />) dan Chrome. Anda dapat mengelolanya di <ph name="BEGIN_LINK" />Setelan<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> memerlukan nama pengguna dan sandi.</translation>
<translation id="2318774815570432836">Saat ini, Anda tidak dapat mengunjungi <ph name="SITE" /> karena situs web tersebut menggunakan HSTS. Kesalahan dan serangan jaringan biasanya bersifat sementara, jadi laman ini mungkin akan bekerja nanti. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Bookmark lain</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Default perusahaan</translation>
<translation id="2386255080630008482">Sertifikat server telah dicabut.</translation>
<translation id="2392959068659972793">Tampilkan kebijakan tanpa nilai yang disetel</translation>
+<translation id="239429038616798445">Metode pengiriman tidak tersedia. Coba metode lain.</translation>
<translation id="2396249848217231973">&amp;Urungkan penghapusan</translation>
-<translation id="2460160116472764928">Google Penjelajahan Aman baru-baru ini <ph name="BEGIN_LINK" />mendeteksi perangkat lunak perusak<ph name="END_LINK" /> di <ph name="SITE" />. Situs web yang biasanya aman terkadang dapat terinfeksi perangkat lunak perusak. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="2460160116472764928">Google Penjelajahan Aman baru-baru ini <ph name="BEGIN_LINK" />mendeteksi software perusak<ph name="END_LINK" /> di <ph name="SITE" />. Situs web yang biasanya aman terkadang dapat terinfeksi software perusak. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Isi</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Jalankan Diagnostik Jaringan<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL penelusuran tidak valid.</translation>
<translation id="2491120439723279231">Sertifikat server mengandung kesalahan.</translation>
-<translation id="24943777258388405">Nomor telepon tidak valid</translation>
<translation id="2495083838625180221">Pengurai JSON</translation>
<translation id="2495093607237746763">Jika dicentang, Chromium akan menyimpan salinan kartu Anda di perangkat ini untuk pengisian formulir yang lebih cepat.</translation>
<translation id="2498091847651709837">Pindai kartu baru</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> mengirimkan tanggapan yang tidak valid.</translation>
<translation id="2552545117464357659">Anyar</translation>
<translation id="2556876185419854533">&amp;Urungkan Pengeditan</translation>
+<translation id="2587730715158995865">Dari <ph name="ARTICLE_PUBLISHER" />. Baca artikel ini dan <ph name="OTHER_ARTICLE_COUNT" /> artikel lainnya.</translation>
<translation id="2587841377698384444">ID API Direktori:</translation>
<translation id="2597378329261239068">Dokumen ini dilindungi sandi. Masukkan sandi.</translation>
<translation id="2609632851001447353">Variasi</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Jalankan Diagnostik Konektivitas<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">Oke</translation>
<translation id="2742870351467570537">Hapus item yang dipilih</translation>
+<translation id="277133753123645258">Metode pengiriman</translation>
<translation id="277499241957683684">Catatan perangkat hilang</translation>
<translation id="2784949926578158345">Sambungan disetel ulang.</translation>
<translation id="2794233252405721443">Situs diblokir</translation>
-<translation id="2812680587231492111">Opsi pengambilan tersebut tidak tersedia. Coba opsi lain.</translation>
<translation id="2824775600643448204">Bilah penelusuran dan alamat</translation>
<translation id="2826760142808435982">Sambungan dienkripsi dan diautentikasi menggunakan <ph name="CIPHER" /> dan menggunakan <ph name="KX" /> sebagai mekanisme pertukaran kunci.</translation>
<translation id="2835170189407361413">Hapus formulir</translation>
-<translation id="2849041323157393173">Opsi pengiriman tersebut tidak tersedia. Coba opsi lain.</translation>
<translation id="2889159643044928134">Jangan Muat Ulang</translation>
<translation id="2900469785430194048">Google Chrome kehabisan memori saat mencoba menampilkan laman web ini.</translation>
<translation id="2909946352844186028">Perubahan jaringan terdeteksi.</translation>
<translation id="2916038427272391327">Tutup program lain</translation>
<translation id="2922350208395188000">Sertifikat server tidak dapat diperiksa.</translation>
+<translation id="2928905813689894207">Alamat Penagihan</translation>
<translation id="2948083400971632585">Anda dapat menonaktifkan proxy apa pun yang dikonfigurasi untuk sambungan dari laman setelan.</translation>
<translation id="2955913368246107853">Tutup bilah cari</translation>
<translation id="2958431318199492670">Konfigurasi jaringan tidak mematuhi standar ONC. Bagian dari konfigurasi mungkin tidak diimpor.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Untuk membuat sambungan aman, jam perlu disetel dengan benar. Itu karena sertifikat yang digunakan situs web untuk mengidentifikasi situs web tersebut hanya valid untuk jangka waktu tertentu. Karena jam perangkat tidak benar, Google Chrome tidak dapat memverifikasi sertifikat ini.</translation>
<translation id="2972581237482394796">&amp;Ulang</translation>
<translation id="2985306909656435243">Jika diaktifkan, Chromium akan menyimpan salinan kartu Anda di perangkat ini untuk pengisian formulir yang lebih cepat.</translation>
+<translation id="2985398929374701810">Masukkan alamat yang valid</translation>
+<translation id="2986368408720340940">Metode pengambilan tidak tersedia. Coba metode lain.</translation>
<translation id="2991174974383378012">Berbagi dengan Situs Web</translation>
<translation id="3005723025932146533">Tampilkan salinan yang disimpan</translation>
<translation id="3008447029300691911">Masukkan CVC untuk <ph name="CREDIT_CARD" />. Setelah mengonfirmasi, detail kartu Anda akan dibagikan dengan situs ini.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{minimal 1 item pada perangkat yang disinkronkan}=1{1 item (dan beberapa di perangkat yang disinkronkan)}other{# item (dan beberapa di perangkat yang disinkronkan)}}</translation>
<translation id="3041612393474885105">Informasi Sertifikat</translation>
<translation id="3063697135517575841">Saat ini Chrome tidak dapat mengonfirmasi kartu. Coba lagi nanti.</translation>
+<translation id="3064966200440839136">Keluar dari mode penyamaran untuk membayar melalui aplikasi eksternal. Lanjutkan?</translation>
<translation id="3093245981617870298">Anda sedang offline.</translation>
<translation id="3105172416063519923">ID Aset:</translation>
<translation id="3109728660330352905">Anda tidak memiliki otorisasi untuk melihat laman ini.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Coba jalankan Diagnostik Konektivitas<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Gagal mendekodekan tanggapan</translation>
-<translation id="3149891296864842641">Opsi pengiriman</translation>
<translation id="3150653042067488994">Kesalahan server sementara</translation>
+<translation id="3154506275960390542">Halaman ini berisi formulir yang mungkin tidak dikirim dengan aman. Data yang Anda kirim dapat dilihat oleh orang lain saat dalam proses pengiriman atau dapat diubah oleh penyerang untuk mengubah data yang akan diterima server.</translation>
<translation id="3157931365184549694">Pulihkan</translation>
<translation id="3167968892399408617">Halaman yang Anda lihat di tab penyamaran tidak akan disimpan dalam riwayat browser, penyimpanan cookie, atau riwayat penelusuran setelah Anda menutup semua tab penyamaran. File apa pun yang didownload atau bookmark yang dibuat akan tetap tersimpan.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Permintaan Anda untuk mengakses situs ini tidak dapat dikirimkan ke <ph name="NAME" />. Coba lagi.</translation>
<translation id="3355823806454867987">Ubah setelan proxy...</translation>
<translation id="3369192424181595722">Kesalahan jam</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> item lainnya...</translation>
<translation id="337363190475750230">Tidak ditetapkan</translation>
<translation id="3377188786107721145">Kesalahan penguraian kebijakan</translation>
<translation id="3380365263193509176">Kesalahan tidak dikenal</translation>
<translation id="3380864720620200369">ID Klien:</translation>
<translation id="3391030046425686457">Alamat pengiriman</translation>
+<translation id="3395827396354264108">Metode pengambilan</translation>
<translation id="340013220407300675">Penyerang mungkin mencoba mencuri informasi Anda dari <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (misalnya, sandi, pesan, atau kartu kredit).</translation>
<translation id="3422248202833853650">Coba program lain yang ada untuk mengosongkan memori.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> saat ini tidak dapat dijangkau.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Interval pengambilan:</translation>
<translation id="3462200631372590220">Sembunyikan lanjutan</translation>
+<translation id="3467763166455606212">Diperlukan nama pemegang kartu</translation>
+<translation id="3478058380795961209">Bulan Masa Berlaku Habis</translation>
<translation id="3479539252931486093">Apakah hal ini tidak diharapkan? <ph name="BEGIN_LINK" />Beri tahu kami<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Jangan sekarang</translation>
<translation id="348000606199325318">ID Kerusakan <ph name="CRASH_LOCAL_ID" /> (ID Server: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Orang tua Anda saat ini tidak dapat dihubungi. Coba lagi.</translation>
<translation id="3528171143076753409">Sertifikat server tidak dipercaya.</translation>
-<translation id="3538531656504267329">Tahun habis masa berlaku tidak valid</translation>
<translation id="3539171420378717834">Menyimpan salinan kartu ini di perangkat ini</translation>
<translation id="3542684924769048008">Gunakan sandi untuk:</translation>
<translation id="3549644494707163724">Enkripsikan data yang disinkronkan dengan frasa sandi sinkronisasi Anda</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Sembunyikan detail</translation>
<translation id="3587482841069643663">Semua</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Masukkan tanggal masa berlaku yang valid</translation>
<translation id="36224234498066874">Hapus Data Browsing...</translation>
<translation id="362276910939193118">Tampilkan Riwayat Lengkap</translation>
<translation id="3623476034248543066">Tampilkan nilai</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Sandi:</translation>
<translation id="3696411085566228381">tidak ada</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Pilih alamat pengiriman untuk memeriksa metode dan persyaratan pengiriman.</translation>
<translation id="370665806235115550">Memuat...</translation>
<translation id="3712624925041724820">Lisensi habis</translation>
<translation id="3714780639079136834">Aktifkan data seluler atau Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Tautan yang Anda salin</translation>
<translation id="375403751935624634">Terjemahan gagal karena kesalahan server.</translation>
<translation id="3759461132968374835">Tidak ada laporan kondisi ngadat saat ini. Kondisi ngadat yang terjadi saat pelaporan kondisi ngadat tidak diaktifkan tidak akan tampil di sini.</translation>
+<translation id="3787705759683870569">Masa berlaku <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Jika Anda menggunakan server proxy...</translation>
<translation id="3828924085048779000">Frasa sandi kosong tidak dibolehkan.</translation>
<translation id="3845539888601087042">Menampilkan riwayat dari perangkat yang Anda gunakan untuk masuk. <ph name="BEGIN_LINK" />Pelajari lebih lanjut<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Ingin Chromium menyimpan kartu ini?</translation>
<translation id="4171400957073367226">Tanda tangan verifikasi tidak valid</translation>
-<translation id="4176463684765177261">Dinonaktifkan</translation>
<translation id="4196861286325780578">&amp;Ulangi pemindahan</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Periksa konfigurasi antivirus dan firewall<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{tidak ada}=1{1 aplikasi ($1)}=2{2 aplikasi ($1, $2)}other{# aplikasi ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">hasil penelusuran</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> tidak menerima sertifikat masuk Anda, atau sertifikat masuk mungkin tidak diberikan.</translation>
<translation id="443673843213245140">Penggunaan proxy dinonaktifkan tetapi konfigurasi proxy yang eksplisit ditentukan.</translation>
-<translation id="4446242550670694251">Anda kini dapat mengakses secara pribadi, dan orang lain yang menggunakan perangkat ini tidak akan melihat aktivitas Anda.</translation>
<translation id="4492190037599258964">Telusuri hasil untuk '<ph name="SEARCH_STRING" />'</translation>
<translation id="4506176782989081258">Kesalahan validasi: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Hubungi admin sistem</translation>
<translation id="450710068430902550">Berbagi dengan Administrator</translation>
+<translation id="4515275063822566619">Kartu dan alamat berasal dari Chrome dan Akun Google (<ph name="ACCOUNT_EMAIL" />). Anda dapat mengelolanya di <ph name="BEGIN_LINK" />Setelan<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Detail</translation>
<translation id="4558551763791394412">Coba nonaktifkan ekstensi.</translation>
<translation id="457875822857220463">Pengiriman</translation>
@@ -408,7 +419,7 @@
<translation id="4750917950439032686">Informasi Anda (misalnya, sandi atau nomor kartu kredit) bersifat pribadi saat dikirimkan ke situs ini.</translation>
<translation id="4756388243121344051">&amp;Riwayat</translation>
<translation id="4758311279753947758">Tambahkan info kontak</translation>
-<translation id="4759118997339041434">Isiotomatis pembayaran dinonaktifkan</translation>
+<translation id="4759118997339041434">IsiOtomatis pembayaran dinonaktifkan</translation>
<translation id="4764776831041365478">Laman web di <ph name="URL" /> mungkin sedang tidak aktif untuk sementara atau dipindahkan secara permanen ke alamat web baru.</translation>
<translation id="4771973620359291008">Terjadi kesalahan yang tidak diketahui.</translation>
<translation id="4800132727771399293">Periksa tanggal masa berlaku habis dan CVC, lalu coba lagi</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Paskan dengan halaman</translation>
<translation id="483020001682031208">Tidak ada halaman Web Fisik untuk ditampilkan</translation>
<translation id="4850886885716139402">Lihat</translation>
+<translation id="4854362297993841467">Metode pengiriman tidak tersedia. Coba metode lain.</translation>
<translation id="4858792381671956233">Kamu telah meminta izin kepada orang tua untuk mengunjungi situs ini</translation>
<translation id="4880827082731008257">Telusuri riwayat</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Laman ini telah diterjemahkan dari bahasa yang tidak diketahui ke bahasa <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Pembayaran</translation>
<translation id="4926049483395192435">Harus ditentukan.</translation>
-<translation id="4941291666397027948">* bidang wajib diisi</translation>
<translation id="495170559598752135">Tindakan</translation>
<translation id="4958444002117714549">Luaskan daftar</translation>
<translation id="4962322354953122629">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh Chrome. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Sandi salah</translation>
<translation id="5056549851600133418">Artikel untuk Anda</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Periksa alamat proxy<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Tak ada cookie}=1{1 situs menggunakan cookie. }other{# situs menggunakan cookie. }}</translation>
<translation id="5087286274860437796">Sertifikat server saat ini tidak valid.</translation>
<translation id="5087580092889165836">Tambahkan kartu</translation>
<translation id="5089810972385038852">Negara bagian</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Tampilkan</translation>
<translation id="5308689395849655368">Pelaporan kondisi ngadat dinonaktifkan.</translation>
<translation id="5317780077021120954">Simpan</translation>
-<translation id="5326702247179446998">Perlu penerima</translation>
<translation id="5327248766486351172">Nama</translation>
-<translation id="5337705430875057403">Penyerang di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> dapat mengelabui Anda agar melakukan hal berbahaya seperti memasang perangkat lunak atau mengungkap informasi pribadi Anda (misalnya, sandi, nomor telepon, atau kartu kredit).</translation>
-<translation id="53553865750799677">Alamat pengambilan tidak didukung. Pilih alamat lain.</translation>
+<translation id="5337705430875057403">Penyerang di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> dapat mengelabui Anda agar melakukan hal berbahaya seperti memasang software atau mengungkap informasi pribadi Anda (misalnya, sandi, nomor telepon, atau kartu kredit).</translation>
<translation id="5359637492792381994">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak valid untuk saat ini. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Gagal menyimpan setelan kebijakan</translation>
<translation id="5386426401304769735">Rantai sertifikat untuk situs ini berisi sertifikat yang ditandatangani menggunakan SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">Laman tersemat di <ph name="SITE" /> menyatakan:</translation>
<translation id="5556459405103347317">Muat ulang</translation>
<translation id="5565735124758917034">Aktif</translation>
+<translation id="5571083550517324815">Tidak dapat mengambil dari alamat ini. Pilih alamat lain.</translation>
<translation id="5572851009514199876">Mulai dan login ke Chrome agar Chrome dapat memeriksa apakah Anda diizinkan untuk mengakses situs ini atau tidak.</translation>
-<translation id="5575380383496039204">Alamat pengiriman tidak didukung. Pilih alamat lain.</translation>
<translation id="5580958916614886209">Periksa bulan kedaluwarsa dan coba lagi</translation>
<translation id="560412284261940334">Pengelolaan tidak didukung</translation>
<translation id="5610142619324316209">Periksa sambungan</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">Identitas situs Web ini belum diverifikasi.</translation>
<translation id="5720705177508910913">Pengguna saat ini</translation>
<translation id="5732392974455271431">Orang tua dapat membuka blokirnya untukmu</translation>
-<translation id="57586589942790530">Nomor kartu tidak valid</translation>
+<translation id="5763042198335101085">Masukkan alamat email yang valid</translation>
+<translation id="5765072501007116331">Untuk melihat persyaratan dan metode pengiriman, pilih alamat</translation>
<translation id="5784606427469807560">Terjadi masalah saat mengonfirmasi kartu. Periksa sambungan internet Anda dan coba lagi.</translation>
<translation id="5785756445106461925">Selain itu, laman ini berisi sumber daya lainnya yang tidak aman. Sumber daya ini dapat dilihat oleh orang lain saat transit dan dapat dimodifikasi oleh penyerang untuk mengubah tampilan perangkat.</translation>
<translation id="5786044859038896871">Ingin mengisi informasi kartu?</translation>
@@ -518,24 +529,22 @@
<translation id="5838278095973806738">Jangan masukkan informasi sensitif apa pun di situs ini (misalnya, sandi atau kartu kredit), karena penyerang dapat mencurinya.</translation>
<translation id="5843436854350372569">Anda mencoba menjangkau <ph name="DOMAIN" />, tetapi server menunjukkan sertifikat yang berisi kunci lemah. Penyerang mungkin telah merusak kunci pribadi dan server tersebut mungkin bukan server yang diharapkan (Anda mungkin sedang berkomunikasi dengan penyerang). <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5869405914158311789">Situs ini tidak dapat dijangkau</translation>
-<translation id="5869522115854928033">Sandi yang disimpan</translation>
+<translation id="5869522115854928033">Sandi tersimpan</translation>
<translation id="5872918882028971132">Saran Induk</translation>
-<translation id="587760065310675640">Alamat pengiriman tidak didukung. Pilih alamat lain.</translation>
<translation id="5901630391730855834">Kuning</translation>
-<translation id="59174027418879706">Diaktifkan</translation>
<translation id="5926846154125914413">Anda dapat kehilangan akses ke konten premium dari beberapa situs.</translation>
<translation id="5959728338436674663">Kirim beberapa <ph name="BEGIN_WHITEPAPER_LINK" />informasi sistem dan konten halaman<ph name="END_WHITEPAPER_LINK" /> secara otomatis ke Google untuk membantu mendeteksi aplikasi dan situs berbahaya. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Minggu</translation>
<translation id="5967867314010545767">Hapus dari riwayat</translation>
<translation id="5975083100439434680">Perkecil</translation>
+<translation id="598637245381783098">Tidak dapat membuka aplikasi pembayaran</translation>
<translation id="5989320800837274978">Baik proxy server tetap ataupun URL skrip .pac tidak ditentukan.</translation>
<translation id="5990559369517809815">Permintaan ke server telah dicekal oleh ekstensi.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Opsi kartu dan alamat berasal dari Chrome. Anda dapat mengelolanya di <ph name="BEGIN_LINK" />Setelan<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Halaman 1}other{Halaman #}}</translation>
<translation id="6017514345406065928">Hijau</translation>
+<translation id="6027201098523975773">Masukkan nama</translation>
<translation id="6040143037577758943">Tutup</translation>
-<translation id="604124094241169006">Otomatis</translation>
<translation id="6042308850641462728">Lainnya</translation>
<translation id="6060685159320643512">Hati-hati, eksperimen ini dapat menimbulkan masalah</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{tidak ada}=1{1}other{#}}</translation>
@@ -543,9 +552,10 @@
jaringan lain yang mungkin Anda gunakan.</translation>
<translation id="614940544461990577">Coba:</translation>
<translation id="6151417162996330722">Sertifikat server memiliki masa berlaku yang terlalu panjang.</translation>
-<translation id="615643356032862689">Bookmark dan file yang didownload akan dipertahankan.</translation>
+<translation id="6157877588268064908">Untuk melihat persyaratan dan metode pengiriman, pilih alamat</translation>
<translation id="6165508094623778733">Pelajari lebih lanjut</translation>
<translation id="6177128806592000436">Sambungan Anda ke situs ini tidak aman</translation>
+<translation id="6184817833369986695">(kelompok: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Periksa sambungan internet Anda</translation>
<translation id="6218753634732582820">Hapus alamat dari Chromium?</translation>
<translation id="6251924700383757765">Kebijakan privasi</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Ulangi Pengaturan Ulang</translation>
<translation id="6263376278284652872">Bookmark <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Kembali ke keamanan</translation>
+<translation id="6276112860590028508">Halaman dari daftar bacaan Anda muncul di sini</translation>
+<translation id="6280223929691119688">Tidak dapat mengirim ke alamat ini. Pilih alamat lain.</translation>
<translation id="6282194474023008486">Kode pos</translation>
<translation id="6290238015253830360">Artikel yang disarankan ditampilkan di sini</translation>
<translation id="6305205051461490394"><ph name="URL" /> tidak dapat dijangkau.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Tidak dapat memeriksa apakah sertifikat telah ditarik.</translation>
<translation id="6433490469411711332">Edit info kontak</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> menolak untuk tersambung.</translation>
-<translation id="6443118737398455446">Tanggal habis masa berlaku tidak valid</translation>
<translation id="6446608382365791566">Tambahkan informasi lainnya</translation>
<translation id="6451458296329894277">Konfirmasikan Pengiriman Ulang Formulir</translation>
<translation id="6456339708790392414">Pembayaran Anda</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya mungkin sudah dicabut. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Kebijakan perangkat</translation>
<translation id="6477321094435799029">Chrome mendeteksi kode yang tidak biasa pada halaman ini dan memblokirnya untuk melindungi informasi pribadi Anda (misalnya, sandi, nomor telepon, dan kartu kredit).</translation>
-<translation id="6477460825583319731">Alamat email tidak valid</translation>
<translation id="6489534406876378309">Mulai mengupload kerusakan</translation>
<translation id="6508722015517270189">Buka Ulang Chrome</translation>
-<translation id="6525462735697194615">Bulan habis masa berlaku tidak valid</translation>
<translation id="6529602333819889595">&amp;Ulangi Penghapusan</translation>
<translation id="6534179046333460208">Saran Web Fisik</translation>
<translation id="6550675742724504774">Opsi</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Penelusuran</translation>
<translation id="6644283850729428850">Kebijakan ini telah usang.</translation>
<translation id="6652240803263749613">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh sistem operasi komputer. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Opsi pengiriman tersebut tidak tersedia. Coba opsi lain.</translation>
<translation id="6671697161687535275">Hapus saran formulir dari Chromium?</translation>
<translation id="6685834062052613830">Keluar dan selesaikan penyiapan</translation>
<translation id="6710213216561001401">Sebelumnya</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Ada yang salah dengan server proxy, atau alamat tidak benar.</translation>
<translation id="6727102863431372879">Setel</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{tidak ada}=1{1 item}other{# item}}</translation>
-<translation id="6743044928064272573">Opsi pengambilan</translation>
<translation id="674375294223700098">Kesalahan sertifikat server tidak dikenal.</translation>
<translation id="6753269504797312559">Nilai kebijakan</translation>
<translation id="6757797048963528358">Perangkat Anda sedang dalam mode tidur.</translation>
<translation id="6778737459546443941">Orang tuamu belum menyetujuinya</translation>
<translation id="6810899417690483278">ID Penyesuaian</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Gagal memuat data region</translation>
<translation id="6831043979455480757">Terjemahkan</translation>
<translation id="6839929833149231406">Area</translation>
<translation id="6874604403660855544">&amp;Ulangi penambahan</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Kartu telah dikonfirmasi</translation>
<translation id="6897140037006041989">Agen Pengguna</translation>
<translation id="6915804003454593391">Pengguna:</translation>
+<translation id="6948701128805548767">Untuk melihat persyaratan dan metode pengambilan, pilih alamat</translation>
<translation id="6957887021205513506">Sertifikat server tampaknya palsu.</translation>
<translation id="6965382102122355670">Oke</translation>
<translation id="6965978654500191972">Perangkat</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">Server proxy tetap dan URL skrip .pac telah ditentukan.</translation>
<translation id="6989763994942163495">Tampilkan setelan lanjutan...</translation>
<translation id="7000990526846637657">Entri riwayat tidak ditemukan</translation>
-<translation id="7001663382399377034">Tambahkan penerima</translation>
<translation id="7009986207543992532">Anda berusaha menjangkau <ph name="DOMAIN" />, tetapi server menunjukkan sertifikat yang masa berlakunya terlalu lama untuk dapat dipercaya. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Akun Google Anda mungkin memiliki bentuk riwayat penjelajahan lainnya di <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,18 +649,21 @@
<translation id="7088615885725309056">Lawas</translation>
<translation id="7090678807593890770">Telusuri <ph name="LINK" /> di Google</translation>
<translation id="7119414471315195487">Tutup tab atau program lain</translation>
+<translation id="7129409597930077180">Tidak dapat mengirim ke alamat ini. Pilih alamat lain.</translation>
+<translation id="7138472120740807366">Metode pengiriman</translation>
<translation id="7139724024395191329">Emirate</translation>
<translation id="7155487117670177674">Pembayaran tidak aman</translation>
<translation id="7179921470347911571">Luncurkan Ulang Sekarang</translation>
<translation id="7180611975245234373">Segarkan</translation>
<translation id="7182878459783632708">Tidak ada kebijakan yang disetel</translation>
<translation id="7186367841673660872">Laman ini telah diterjemahkan dari<ph name="ORIGINAL_LANGUAGE" />ke<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> tidak mematuhi standar keamanan.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Selengkapnya<ph name="END_LINK" /> tentang masalah ini.</translation>
<translation id="7219179957768738017">Koneksi menggunakan <ph name="SSL_VERSION" />.</translation>
<translation id="7220786058474068424">Dalam proses</translation>
-<translation id="724691107663265825">Situs yang akan dibuka berisi perangkat lunak perusak</translation>
+<translation id="724691107663265825">Situs yang akan dibuka berisi software perusak</translation>
<translation id="724975217298816891">Masukkan tanggal habis masa berlaku dan CVC untuk <ph name="CREDIT_CARD" /> guna memperbarui detail kartu. Setelah mengonfirmasi, detail kartu Anda akan dibagikan dengan situs ini.</translation>
<translation id="725866823122871198">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" />) komputer Anda tidak benar.</translation>
<translation id="7275334191706090484">Bookmark yang Terkelola</translation>
@@ -675,7 +686,6 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="7424977062513257142">Laman tersemat di laman web ini menyatakan:</translation>
<translation id="7441627299479586546">Subjek kebijakan salah</translation>
<translation id="7444046173054089907">Situs ini diblokir</translation>
-<translation id="7444238235002594607">Pilih alamat pengambilan untuk memeriksa persyaratan dan metode pengambilan.</translation>
<translation id="7445762425076701745">Identitas server yang Anda sambungkan tidak dapat divalidasi sepenuhnya. Anda terhubung ke server menggunakan nama yang hanya valid dalam jaringan Anda, yang mana otoritas sertifikat eksternal sama sekali tidak dapat memvalidasi kepemilikannya. Karena sejumlah otoritas sertifikat akan tetap menerbitkan sertifikat untuk nama tersebut, tidak dapat dipastikan apakah Anda akan tersambung ke situs web yang dimaksudkan dan bahwa tidak akan ada penyerang.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Pelajari lebih lanjut<ph name="END_LINK" /> tentang masalah ini.</translation>
<translation id="7460163899615895653">Tab terbaru dari perangkat lain muncul di sini</translation>
@@ -717,8 +727,9 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="7733391738235763478">(<ph name="NUMBER_VISITS" />)</translation>
<translation id="7752995774971033316">Tidak terkelola</translation>
<translation id="7755287808199759310">Orang tua dapat membuka blokirnya untukmu</translation>
-<translation id="7758069387465995638">Perangkat lunak antivirus atau firewall mungkin memblokir sambungan.</translation>
+<translation id="7758069387465995638">Software antivirus atau firewall mungkin memblokir sambungan.</translation>
<translation id="7761701407923456692">Sertifikat server tidak cocok dengan URL.</translation>
+<translation id="7763386264682878361">Parser Manifes Pembayaran</translation>
<translation id="7764225426217299476">Tambahkan alamat</translation>
<translation id="777702478322588152">Prefektur</translation>
<translation id="7791543448312431591">Tambahkan</translation>
@@ -732,13 +743,14 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="785549533363645510">Namun, Anda masih dapat terlihat. Masuk ke mode penyamaran tidak menyembunyikan penjelajahan Anda dari atasan, penyedia layanan internet, atau situs web yang Anda kunjungi.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Periksa CVC dan coba lagi</translation>
+<translation id="79338296614623784">Masukkan nomor telepon yang valid</translation>
<translation id="7935318582918952113">Penyaring DOM</translation>
<translation id="7938958445268990899">Sertifikat server belum valid.</translation>
<translation id="7942349550061667556">Merah</translation>
<translation id="7947285636476623132">Periksa tahun kedaluwarsa dan coba lagi</translation>
<translation id="7951415247503192394">(32 bit)</translation>
<translation id="7956713633345437162">Bookmark seluler</translation>
-<translation id="7961015016161918242">Tidak pernah</translation>
+<translation id="7961015016161918242">Jangan pernah</translation>
<translation id="7962083544045318153">ID Kerusakan <ph name="CRASH_LOCAL_ID" /></translation>
<translation id="7983301409776629893">Selalu terjemahkan <ph name="ORIGINAL_LANGUAGE" /> ke <ph name="TARGET_LANGUAGE" /></translation>
<translation id="7995512525968007366">Tidak Ditentukan</translation>
@@ -751,6 +763,7 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="8088680233425245692">Gagal melihat artikel.</translation>
<translation id="8089520772729574115">kurang dari 1 MB</translation>
<translation id="8091372947890762290">Aktivasi ditunda di server</translation>
+<translation id="8118489163946903409">Metode pembayaran</translation>
<translation id="8131740175452115882">Konfirmasi</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Alamat DNS<ph name="END_ABBR" /> server <ph name="HOST_NAME" /> tidak dapat ditemukan.</translation>
<translation id="8149426793427495338">Komputer Anda sedang dalam mode tidur.</translation>
@@ -776,6 +789,7 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="8349305172487531364">Bilah bookmark</translation>
<translation id="8363502534493474904">Nonaktifkan mode pesawat</translation>
<translation id="8364627913115013041">Tidak disetel.</translation>
+<translation id="8368476060205742148">Layanan Google Play</translation>
<translation id="8380941800586852976">Berbahaya</translation>
<translation id="8382348898565613901">Bookmark yang baru-baru ini dikunjungi ditampilkan di sini</translation>
<translation id="8398259832188219207">Laporan kerusakan diupload pada <ph name="UPLOAD_TIME" /></translation>
@@ -784,31 +798,29 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="8428213095426709021">Setelan</translation>
<translation id="8433057134996913067">Tindakan ini akan mengeluarkan Anda dari sebagian besar situs web.</translation>
<translation id="8437238597147034694">&amp;Urungkan pemindahan</translation>
-<translation id="8456681095658380701">Nama tidak valid</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 kartu kredit}other{# kartu kredit}}</translation>
<translation id="8483780878231876732">Untuk menggunakan kartu dari Akun Google Anda, masuk ke Chrome</translation>
<translation id="8488350697529856933">Berlaku untuk</translation>
-<translation id="8492969205326575646">Jenis kartu tidak didukung</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> membutuhkan terlalu banyak waktu untuk merespons.</translation>
<translation id="852346902619691059">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh sistem operasi perangkat. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Tahun Masa Berlaku Habis</translation>
<translation id="8543181531796978784">Anda dapat <ph name="BEGIN_ERROR_LINK" />melaporkan masalah pendeteksian<ph name="END_ERROR_LINK" /> atau, jika memahami risiko bagi keamanan, Anda dapat <ph name="BEGIN_LINK" />mengunjungi situs yang tidak aman<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Terjemahan gagal karena bahasa laman tidak dapat ditentukan.</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="8570229484593575558">Informasi ini |tidak akan disimpan|:#Riwayat penjelajahan Anda#Penelusuran Anda#Data cookie</translation>
<translation id="8571890674111243710">Menerjemahkan laman ke <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Aktivitas Anda |mungkin tetap dapat terlihat| ke:#Situs yang Anda buka#Atasan Anda#Penyedia Layanan Internet Anda</translation>
<translation id="858637041960032120">+ nomor telepon</translation>
<translation id="859285277496340001">Sertifikat tidak menetapkan mekanisme untuk memeriksa apakah sertifikat telah ditarik.</translation>
<translation id="8620436878122366504">Orang tuamu belum menyetujuinya</translation>
<translation id="8647750283161643317">Setel ulang semua ke default</translation>
<translation id="8703575177326907206">Sambungan ke <ph name="DOMAIN" /> tidak dienkripsi.</translation>
+<translation id="8718314106902482036">Pembayaran belum selesai</translation>
<translation id="8725066075913043281">Coba lagi</translation>
<translation id="8728672262656704056">Anda masuk mode penyamaran</translation>
<translation id="8730621377337864115">Selesai</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="8759274551635299824">Kartu sudah tidak aktif</translation>
<translation id="8790007591277257123">&amp;Ulangi penghapusan</translation>
-<translation id="8798099450830957504">Default</translation>
<translation id="8800988563907321413">Saran terdekat muncul di sini</translation>
<translation id="8820817407110198400">Bookmark</translation>
<translation id="883848425547221593">Bookmark Lain</translation>
@@ -818,6 +830,7 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="8866481888320382733">Kesalahan saat menguraikan setelan kebijakan</translation>
<translation id="8866959479196209191">Laman ini menyatakan:</translation>
<translation id="8870413625673593573">Barusan Ditutup</translation>
+<translation id="8874824191258364635">Masukkan nomor kartu yang valid</translation>
<translation id="8876793034577346603">Konfigurasi jaringan gagal diuraikan.</translation>
<translation id="8877192140621905067">Setelah mengonfirmasi, detail kartu Anda akan dibagikan dengan situs ini</translation>
<translation id="8889402386540077796">Rona</translation>
@@ -827,7 +840,6 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="8931333241327730545">Ingin menyimpan kartu ini ke Akun Google Anda?</translation>
<translation id="8932102934695377596">Setelan waktu Anda terlalu lambat</translation>
<translation id="8954894007019320973">(Lanjutan.)</translation>
-<translation id="895548565263634352">Baca berita dari <ph name="ARTICLE_PUBLISHER" /> dan <ph name="OTHER_ARTICLE_COUNT" /> lainnya</translation>
<translation id="8971063699422889582">Sertifikat server telah kedaluwarsa.</translation>
<translation id="8986494364107987395">Kirim statistik penggunaan dan laporan kerusakan ke Google secara otomatis</translation>
<translation id="8987927404178983737">Bulan</translation>
@@ -845,7 +857,6 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="9068849894565669697">Pilih warna</translation>
<translation id="9076283476770535406">Situs mungkin berisi konten dewasa</translation>
<translation id="9078964945751709336">Dibutuhkan informasi lebih lanjut</translation>
-<translation id="9094175695478007090">Tidak dapat meluncurkan aplikasi pembayaran.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> biasanya menggunakan enkripsi untuk melindungi informasi Anda. Saat Chromium mencoba menyambung ke <ph name="SITE" /> kali ini, situs web mengembalikan kredensial yang salah dan tidak biasa. Hal ini dapat terjadi jika ada penyerang yang berpura-pura menjadi <ph name="SITE" />, atau layar masuk Wi-Fi mengganggu sambungan. Informasi Anda masih aman karena Chromium menghentikan sambungan sebelum terjadi pertukaran data apa pun.</translation>
<translation id="9137013805542155359">Perlihatkan laman asli</translation>
<translation id="9137248913990643158">Mulai dan login ke Chrome sebelum menggunakan aplikasi ini.</translation>
diff --git a/chromium/components/strings/components_strings_it.xtb b/chromium/components/strings/components_strings_it.xtb
index 35c25f8af79..bde7e1935fd 100644
--- a/chromium/components/strings/components_strings_it.xtb
+++ b/chromium/components/strings/components_strings_it.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="it">
<translation id="1008557486741366299">Non adesso</translation>
<translation id="1015730422737071372">Fornisci ulteriori dettagli</translation>
+<translation id="1021110881106174305">Carte di credito accettate</translation>
<translation id="1032854598605920125">Ruota in senso orario</translation>
<translation id="1038842779957582377">nome sconosciuto</translation>
<translation id="1050038467049342496">Chiudi altre app</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Nascondi valore</translation>
<translation id="1228893227497259893">Identificatore entità errato</translation>
<translation id="1232569758102978740">Senza titolo</translation>
+<translation id="1263231323834454256">Elenco di lettura</translation>
<translation id="1264126396475825575">Rapporto sugli arresti anomali generato il giorno <ph name="CRASH_TIME" /> (non ancora caricato o ignorato)</translation>
<translation id="1285320974508926690">Non tradurre mai questo sito</translation>
<translation id="129553762522093515">Chiuse di recente</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Impostazioni di Compilazione automatica Chromium...</translation>
<translation id="1374468813861204354">suggerimenti</translation>
<translation id="1375198122581997741">Informazioni sulla versione</translation>
+<translation id="1377321085342047638">Numero carta</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> non ha inviato dati.</translation>
<translation id="1407135791313364759">Apri tutte</translation>
<translation id="1413809658975081374">Errore di privacy</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Cronologia</translation>
<translation id="1645368109819982629">Protocollo non supportato</translation>
<translation id="1656489000284462475">Ritiro</translation>
+<translation id="1663943134801823270">Carte di credito e indirizzi provengono da Chrome. Puoi gestirli in <ph name="BEGIN_LINK" />Impostazioni<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> in genere utilizza la crittografia per proteggere le tue informazioni. Questa volta, quando Google Chrome ha provato a connettersi a <ph name="SITE" />, il sito web ha restituito credenziali insolite e sbagliate. È possibile che un malintenzionato stia cercando di spacciarsi per il sito <ph name="SITE" /> oppure che una schermata di accesso alla rete Wi-Fi abbia interrotto la connessione. Le tue informazioni sono ancora al sicuro perché Google Chrome ha interrotto la connessione prima che avvenissero scambi di dati.</translation>
<translation id="168328519870909584">I malintenzionati attualmente sul sito <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> potrebbero tentare di installare sul tuo dispositivo app pericolose che scoprono o eliminano i tuoi dati (ad esempio foto, password, messaggi e carte di credito).</translation>
<translation id="168841957122794586">Il certificato del server contiene una chiave crittografica debole.</translation>
<translation id="1710259589646384581">Sistema operativo</translation>
<translation id="1721312023322545264">Ti occorre l'autorizzazione di <ph name="NAME" /> per poter visitare il sito</translation>
+<translation id="1721424275792716183">* Campo obbligatorio</translation>
<translation id="1728677426644403582">È visualizzata l'origine di una pagina web</translation>
+<translation id="173080396488393970">Questo tipo di carta non è supportato</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Prova a contattare l'amministratore di sistema.</translation>
+<translation id="1740951997222943430">Inserisci un mese di scadenza valido</translation>
<translation id="1745358365027406341">Scarica la pagina più tardi</translation>
<translation id="17513872634828108">Schede aperte</translation>
<translation id="1753706481035618306">Numero di pagina</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Aggiorna la tua passphrase di sincronizzazione.</translation>
<translation id="1787142507584202372">Le tue schede aperte vengono visualizzate qui</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Seleziona un indirizzo di consegna per verificare i metodi di consegna e i requisiti.</translation>
+<translation id="1803264062614276815">Nome del titolare della carta</translation>
<translation id="1803678881841855883">La funzione Navigazione sicura di Google di recente ha <ph name="BEGIN_LINK" />rilevato malware<ph name="END_LINK" /> sul sito <ph name="SITE" />. I siti web che in genere sono sicuri a volte vengono infettati da malware. I contenuti dannosi provengono da <ph name="SUBRESOURCE_HOST" />, un noto distributore di malware. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Data di aggiunta: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Richiesta o parametri della richiesta non validi</translation>
<translation id="1826516787628120939">Verifica in corso...</translation>
<translation id="1834321415901700177">Il sito contiene programmi dannosi.</translation>
<translation id="1842969606798536927">Paga</translation>
-<translation id="1864455488461349376">Opzione consegna</translation>
<translation id="1871208020102129563">L'impostazione del proxy prevede l'utilizzo di server proxy fissi, non di un URL script .pac.</translation>
<translation id="1871284979644508959">Campo obbligatorio</translation>
<translation id="187918866476621466">Apri pagine iniziali</translation>
<translation id="1883255238294161206">Comprimi elenco</translation>
<translation id="1898423065542865115">Filtri</translation>
<translation id="194030505837763158">Vai al link: <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Carte accettate</translation>
<translation id="1962204205936693436">Segnalibri di <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Errore di serializzazione</translation>
<translation id="1974060860693918893">Avanzate</translation>
<translation id="1978555033938440688">Versione firmware</translation>
+<translation id="1995859865337580572">Verifica il tuo CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{e un'altra}other{e altre #}}</translation>
-<translation id="2020194265157481222">Nome indicato sulla carta obbligatorio</translation>
<translation id="2025186561304664664">È stata impostata la configurazione automatica del proxy.</translation>
<translation id="2030481566774242610">Forse cercavi <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Controllare il proxy e firewall<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Oggi</translation>
<translation id="2154054054215849342">Il servizio di sincronizzazione non è disponibile per il tuo dominio</translation>
<translation id="2154484045852737596">Modifica la carta</translation>
-<translation id="2156993118928861787">Indirizzo non valido</translation>
<translation id="2166049586286450108">Accesso amministrativo completo</translation>
<translation id="2166378884831602661">Il sito non può fornire una connessione protetta</translation>
<translation id="2181821976797666341">Criteri</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 indirizzo}other{# indirizzi}}</translation>
+<translation id="2202020181578195191">Inserisci un anno di scadenza valido</translation>
<translation id="2212735316055980242">Criterio non trovato</translation>
<translation id="2213606439339815911">Recupero voci...</translation>
<translation id="2230458221926704099">Correggi la connessione con l'<ph name="BEGIN_LINK" />app diagnostica<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">L'accesso a Internet è bloccato</translation>
<translation id="230155334948463882">Nuova carta?</translation>
<translation id="2305919008529760154">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere stato rilasciato in maniera fraudolenta. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Le opzioni relative alla carta e all'indirizzo derivano dal tuo account Google (<ph name="ACCOUNT_EMAIL" />) e da Chrome. Puoi gestirle nelle <ph name="BEGIN_LINK" />Impostazioni<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> richiede un nome utente e una password.</translation>
<translation id="2318774815570432836">Al momento non puoi visitare il sito <ph name="SITE" /> perché utilizza HSTS. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe funzionare più tardi. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Altri Preferiti</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Valore predefinito aziendale</translation>
<translation id="2386255080630008482">Il certificato del server è stato revocato.</translation>
<translation id="2392959068659972793">Mostra norme senza valori</translation>
+<translation id="239429038616798445">Questo metodo di spedizione non è disponibile. Prova un metodo diverso.</translation>
<translation id="2396249848217231973">&amp;Annulla eliminazione</translation>
<translation id="2460160116472764928">La funzione Navigazione sicura di Google di recente ha <ph name="BEGIN_LINK" />rilevato malware<ph name="END_LINK" /> sul sito <ph name="SITE" />. I siti web che in genere sono sicuri a volte vengono infettati da malware. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Compila</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Eseguire lo strumento Diagnostica di rete<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL ricerca non valido.</translation>
<translation id="2491120439723279231">Il certificato del server contiene degli errori.</translation>
-<translation id="24943777258388405">Numero di telefono non valido</translation>
<translation id="2495083838625180221">JSON Parser</translation>
<translation id="2495093607237746763">Se questa opzione viene selezionata, Chromium memorizza una copia della carta sul dispositivo per velocizzare la compilazione dei moduli.</translation>
<translation id="2498091847651709837">Esegui scansione nuova carta</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> ha inviato una risposta non valida.</translation>
<translation id="2552545117464357659">Più recente</translation>
<translation id="2556876185419854533">&amp;Annulla modifica</translation>
+<translation id="2587730715158995865">Da <ph name="ARTICLE_PUBLISHER" />. Leggi questo e altri <ph name="OTHER_ARTICLE_COUNT" /> articoli.</translation>
<translation id="2587841377698384444">ID API directory:</translation>
<translation id="2597378329261239068">Questo documento è protetto da password. Inserisci una password.</translation>
<translation id="2609632851001447353">Varianti</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Eseguire lo strumento Diagnostica della connettività<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">Rimuovi gli elementi selezionati</translation>
+<translation id="277133753123645258">Metodo di spedizione</translation>
<translation id="277499241957683684">Record del dispositivo mancante</translation>
<translation id="2784949926578158345">La connessione è stata reimpostata.</translation>
<translation id="2794233252405721443">Sito bloccato</translation>
-<translation id="2812680587231492111">Quell'opzione ritiro non è disponibile. Prova un'opzione diversa.</translation>
<translation id="2824775600643448204">Barra degli indirizzi e di ricerca</translation>
<translation id="2826760142808435982">La connessione è stata criptata e autenticata utilizzando <ph name="CIPHER" /> e <ph name="KX" /> come meccanismo di scambio delle chiavi.</translation>
<translation id="2835170189407361413">Cancella modulo</translation>
-<translation id="2849041323157393173">Quell'opzione consegna non è disponibile. Prova con un'altra opzione.</translation>
<translation id="2889159643044928134">Non ricaricare</translation>
<translation id="2900469785430194048">Google Chrome ha esaurito la memoria mentre cercava di visualizzare questa pagina web.</translation>
<translation id="2909946352844186028">È stato rilevato un cambio di rete.</translation>
<translation id="2916038427272391327">Chiudi altri programmi</translation>
<translation id="2922350208395188000">Il certificato del server non può essere verificato.</translation>
+<translation id="2928905813689894207">Indirizzo di fatturazione</translation>
<translation id="2948083400971632585">Puoi disattivare tutti i proxy configurati per una connessione dalla pagina delle impostazioni.</translation>
<translation id="2955913368246107853">Chiudi la barra di ricerca</translation>
<translation id="2958431318199492670">La configurazione di rete non è conforme allo standard ONC. Parti della configurazione potrebbero non essere importate.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">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 non è impostato sull'orario corretto, pertanto Chrome non può verificare i certificati.</translation>
<translation id="2972581237482394796">&amp;Ripeti</translation>
<translation id="2985306909656435243">Se questa opzione viene attivata, Chromium memorizza una copia della carta sul dispositivo per velocizzare la compilazione dei moduli.</translation>
+<translation id="2985398929374701810">Inserisci un indirizzo valido</translation>
+<translation id="2986368408720340940">Questo metodo di ritiro non è disponibile. Prova un metodo diverso.</translation>
<translation id="2991174974383378012">Condivisione con i siti web</translation>
<translation id="3005723025932146533">Mostra copia salvata</translation>
<translation id="3008447029300691911">Inserisci il codice CVC della carta <ph name="CREDIT_CARD" />. Dopo essere stati confermati, i dettagli della carta saranno condivisi con questo sito.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{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="3041612393474885105">Informazioni certificato</translation>
<translation id="3063697135517575841">Al momento non è possibile confermare la carta in Chrome. Riprova più tardi.</translation>
+<translation id="3064966200440839136">Per procedere al pagamento tramite un'applicazione esterna, uscirai dalla modalità di navigazione in incognito. Continuare?</translation>
<translation id="3093245981617870298">Sei offline.</translation>
<translation id="3105172416063519923">ID asset:</translation>
<translation id="3109728660330352905">Non sei autorizzato a visualizzare questa pagina.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Prova a eseguire lo strumento Diagnostica della connettività<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Decodifica della risposta non riuscita</translation>
-<translation id="3149891296864842641">Opzione di spedizione</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>
<translation id="3157931365184549694">Ripristina</translation>
<translation id="3167968892399408617">Le pagine visualizzate nelle schede in incognito non vengono memorizzate nella cronologia del browser, nell'archivio di cookie o nella cronologia delle ricerche dopo avere chiuso tutte le schede in incognito. I file scaricati o i preferiti creati verranno conservati.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -260,11 +268,13 @@
<translation id="3345135638360864351">Impossibile inviare a <ph name="NAME" /> la richiesta di accesso a questo sito. Riprova.</translation>
<translation id="3355823806454867987">Modifica impostazioni proxy...</translation>
<translation id="3369192424181595722">Errore dell'orologio</translation>
+<translation id="337311366426640088">Altri <ph name="ITEM_COUNT" /> elementi...</translation>
<translation id="337363190475750230">Deprovisioning effettuato</translation>
<translation id="3377188786107721145">Errore di analisi del criterio</translation>
<translation id="3380365263193509176">Errore sconosciuto</translation>
<translation id="3380864720620200369">ID client:</translation>
<translation id="3391030046425686457">Indirizzo di consegna</translation>
+<translation id="3395827396354264108">Metodo di ritiro</translation>
<translation id="340013220407300675">Gli autori di un attacco potrebbero cercare di rubare le tue informazioni (ad esempio password, messaggi o dati della carta di credito) da <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="3422248202833853650">Prova a uscire da altri programmi per liberare spazio nella memoria.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> non è attualmente raggiungibile.</translation>
@@ -275,15 +285,16 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Intervallo recupero:</translation>
<translation id="3462200631372590220">Nascondi avanzate</translation>
+<translation id="3467763166455606212">Nome titolare carta obbligatorio</translation>
+<translation id="3478058380795961209">Mese di scadenza</translation>
<translation id="3479539252931486093">Non era previsto? <ph name="BEGIN_LINK" />Contattaci<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Non adesso</translation>
<translation id="348000606199325318">ID arresto anomalo <ph name="CRASH_LOCAL_ID" /> (ID server: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">In questo momento, non è possibile raggiungere il tuo genitore. Riprova.</translation>
<translation id="3528171143076753409">Il certificato del server non è affidabile.</translation>
-<translation id="3538531656504267329">Anno di scadenza non valido</translation>
<translation id="3539171420378717834">Conserva una copia di questa carta sul dispositivo</translation>
<translation id="3542684924769048008">Utilizza password per:</translation>
-<translation id="3549644494707163724">Crittografa tutti i dati sincronizzati con la tua passphrase di sincronizzazione</translation>
+<translation id="3549644494707163724">Cripta tutti i dati sincronizzati con la tua passphrase di sincronizzazione</translation>
<translation id="3549761410225185768">Altre <ph name="NUM_TABS_MORE" />...</translation>
<translation id="3555561725129903880">Questo server non è riuscito a verificare che si tratti 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. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3556433843310711081">Il tuo gestore può sbloccarlo per te</translation>
@@ -293,6 +304,7 @@
<translation id="3586931643579894722">Nascondi dettagli</translation>
<translation id="3587482841069643663">Tutti</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Inserisci una data di scadenza valida</translation>
<translation id="36224234498066874">Cancella dati di navigazione...</translation>
<translation id="362276910939193118">Mostra cronologia completa</translation>
<translation id="3623476034248543066">Mostra valore</translation>
@@ -309,7 +321,6 @@
<translation id="3693415264595406141">Password:</translation>
<translation id="3696411085566228381">nessuno</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Seleziona un indirizzo di spedizione per verificare i metodi di spedizione e i requisiti.</translation>
<translation id="370665806235115550">Caricamento in corso...</translation>
<translation id="3712624925041724820">Licenze esaurite</translation>
<translation id="3714780639079136834">Attivare la rete dati mobile o Wi-Fi</translation>
@@ -318,6 +329,7 @@
<translation id="3739623965217189342">Link che hai copiato</translation>
<translation id="375403751935624634">La traduzione non è riuscita a causa di un errore del server.</translation>
<translation id="3759461132968374835">Non hai segnalato arresti anomali di recente. Quelli che si sono verificati quando la segnalazione degli arresti anomali era disabilitata non verranno visualizzati qui.</translation>
+<translation id="3787705759683870569">Data di scadenza: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Se utilizzi un server proxy...</translation>
<translation id="3828924085048779000">Non è consentita una passphrase vuota.</translation>
<translation id="3845539888601087042">È visualizzata la cronologia dei dispositivi su cui hai eseguito l'accesso. <ph name="BEGIN_LINK" />Ulteriori informazioni<ph name="END_LINK" /></translation>
@@ -353,7 +365,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Vuoi che Chromium salvi questa carta?</translation>
<translation id="4171400957073367226">Firma di verifica non valida</translation>
-<translation id="4176463684765177261">Disabilitato</translation>
<translation id="4196861286325780578">&amp;Ripeti spostamento</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Controllare le configurazioni del firewall e antivirus<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{nessuna}=1{1 app ($ 1)}=2{2 app ($ 1, $ 2)}other{# app ($ 1, $ 2, $ 3)}}</translation>
@@ -380,11 +391,11 @@
<translation id="4406896451731180161">risultati di ricerca</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> non ha accettato il certificato di accesso oppure non ne è stato fornito uno.</translation>
<translation id="443673843213245140">L'utilizzo di un proxy è stato disattivato ma è stata specificata una configurazione proxy esplicita.</translation>
-<translation id="4446242550670694251">Ora puoi navigare in privato. Le altre persone che usano questo dispositivo non vedranno le tue attività.</translation>
<translation id="4492190037599258964">Risultati di ricerca per "<ph name="SEARCH_STRING" />"</translation>
<translation id="4506176782989081258">Errore di convalida. <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Contattare l'amministratore di sistema</translation>
<translation id="450710068430902550">Condivisione con l'amministratore</translation>
+<translation id="4515275063822566619">Carte di credito e indirizzi provengono da Chrome e dall'account Google (<ph name="ACCOUNT_EMAIL" />). Puoi gestirli in <ph name="BEGIN_LINK" />Impostazioni<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Dettagli</translation>
<translation id="4558551763791394412">Prova a disattivare le estensioni.</translation>
<translation id="457875822857220463">Consegna</translation>
@@ -414,6 +425,7 @@
<translation id="4816492930507672669">Adatta alla pagina</translation>
<translation id="483020001682031208">Nessuna pagina di Physical Web da mostrare</translation>
<translation id="4850886885716139402">Visualizza</translation>
+<translation id="4854362297993841467">Questo metodo di consegna non è disponibile. Prova un metodo diverso.</translation>
<translation id="4858792381671956233">Hai chiesto ai tuoi genitori se puoi visitare questo sito</translation>
<translation id="4880827082731008257">Cerca nella cronologia</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -421,7 +433,6 @@
<translation id="4923417429809017348">Questa pagina è stata tradotta da una lingua sconosciuta in <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Pagamento</translation>
<translation id="4926049483395192435">Deve essere specificato.</translation>
-<translation id="4941291666397027948">L'asterisco [*] indica un campo obbligatorio</translation>
<translation id="495170559598752135">Azioni</translation>
<translation id="4958444002117714549">Espandi elenco</translation>
<translation id="4962322354953122629">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato attendibile da Chrome. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -436,12 +447,13 @@
<translation id="5045550434625856497">Password non corretta</translation>
<translation id="5056549851600133418">Articoli per te</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Controllare l'indirizzo proxy<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Nessun cookie}=1{1 sito usa i cookie. }other{# siti usano i cookie. }}</translation>
<translation id="5087286274860437796">Il certificato del server non è valido in questa fase.</translation>
<translation id="5087580092889165836">Aggiungi carta</translation>
<translation id="5089810972385038852">Provincia</translation>
<translation id="5095208057601539847">Provincia</translation>
<translation id="5115563688576182185">(a 64 bit)</translation>
-<translation id="5141240743006678641">Crittografa le password sincronizzate con le tue credenziali Google</translation>
+<translation id="5141240743006678641">Cripta le password sincronizzate con le tue credenziali Google</translation>
<translation id="514421653919133810">Apri la pagina in modalità di navigazione in incognito (CTRL-MAIUSC-N)</translation>
<translation id="5145883236150621069">Codice di errore presente nella risposta del criterio</translation>
<translation id="5171045022955879922">Cerca o digita un URL</translation>
@@ -458,10 +470,8 @@
<translation id="5300589172476337783">Mostra</translation>
<translation id="5308689395849655368">La segnalazione degli arresti anomali è disattivata.</translation>
<translation id="5317780077021120954">Salva</translation>
-<translation id="5326702247179446998">Destinatario obbligatorio</translation>
<translation id="5327248766486351172">Nome</translation>
<translation id="5337705430875057403">I malintenzionati sul sito <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 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="53553865750799677">Indirizzo di ritiro non supportato. Seleziona un indirizzo diverso.</translation>
<translation id="5359637492792381994">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza al momento non è valido. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Archiviazione delle impostazioni criterio non riuscita</translation>
<translation id="5386426401304769735">Il certificato di questo sito contiene un certificato che è stato firmato utilizzando SHA-1.</translation>
@@ -487,8 +497,8 @@
<translation id="5544037170328430102">Una pagina incorporata in <ph name="SITE" /> dice:</translation>
<translation id="5556459405103347317">Ricarica</translation>
<translation id="5565735124758917034">Attivo</translation>
+<translation id="5571083550517324815">Impossibile ritirare dall'indirizzo specificato. Seleziona un indirizzo diverso.</translation>
<translation id="5572851009514199876">Accedi a Chrome per consentire al browser di verificare che tu sia autorizzato ad accedere a questo sito.</translation>
-<translation id="5575380383496039204">Indirizzo di consegna non supportato. Seleziona un indirizzo diverso.</translation>
<translation id="5580958916614886209">Controlla il mese di scadenza e riprova</translation>
<translation id="560412284261940334">Gestione non supportata</translation>
<translation id="5610142619324316209">Verificare la connessione</translation>
@@ -504,7 +514,8 @@
<translation id="5710435578057952990">L'identità di questo sito web non è stata verificata.</translation>
<translation id="5720705177508910913">Utente corrente</translation>
<translation id="5732392974455271431">I tuoi genitori possono sbloccarlo per te</translation>
-<translation id="57586589942790530">Numero di carta non valido</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>
<translation id="5784606427469807560">Si è verificato un problema durante la conferma della carta. Controlla la connessione Internet e riprova.</translation>
<translation id="5785756445106461925">Inoltre, questa pagina include altre risorse che non sono sicure. Tali risorse possono essere visualizzate da altri durante il transito dei dati e possono essere modificate da un utente malintenzionato al fine di modificare l'aspetto della pagina.</translation>
<translation id="5786044859038896871">Vuoi inserire automaticamente i dati della carta?</translation>
@@ -517,31 +528,30 @@
<translation id="5869405914158311789">Impossibile raggiungere il sito</translation>
<translation id="5869522115854928033">Password salvate</translation>
<translation id="5872918882028971132">Suggerimenti per i genitori</translation>
-<translation id="587760065310675640">Indirizzo di spedizione non supportato. Seleziona un indirizzo diverso.</translation>
<translation id="5901630391730855834">Giallo</translation>
-<translation id="59174027418879706">Attiva</translation>
<translation id="5926846154125914413">Potresti perdere l'accesso ai contenuti premium di alcuni siti.</translation>
<translation id="5959728338436674663">Invia automaticamente a Google <ph name="BEGIN_WHITEPAPER_LINK" />alcune informazioni sul sistema e alcuni contenuti delle pagine<ph name="END_WHITEPAPER_LINK" /> per contribuire a rilevare app e siti pericolosi. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Settimana</translation>
<translation id="5967867314010545767">Rimuovi da cronologia</translation>
<translation id="5975083100439434680">Diminuisci lo zoom</translation>
+<translation id="598637245381783098">Impossibile aprire l'app per i pagamenti</translation>
<translation id="5989320800837274978">Non sono stati specificati né server proxy fissi né un URL script .pac.</translation>
<translation id="5990559369517809815">Le richieste al server sono state bloccate da un'estensione.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Le opzioni relative alla carta e all'indirizzo derivano da Chrome. Puoi gestirle nelle <ph name="BEGIN_LINK" />Impostazioni<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Pagina 1}other{Pagina #}}</translation>
<translation id="6017514345406065928">Verde</translation>
+<translation id="6027201098523975773">Inserisci un nome</translation>
<translation id="6040143037577758943">Chiudi</translation>
-<translation id="604124094241169006">Automatica</translation>
<translation id="6042308850641462728">Più</translation>
<translation id="6060685159320643512">Attenzione, prova questi esperimenti a tuo rischio e pericolo</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{nessuna}=1{1}other{#}}</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="6151417162996330722">Il certificato del server ha un periodo di validità troppo lungo.</translation>
-<translation id="615643356032862689">I file e i preferiti scaricati verranno mantenuti.</translation>
+<translation id="6157877588268064908">Seleziona un indirizzo per conoscere i requisiti e i metodi di spedizione</translation>
<translation id="6165508094623778733">Ulteriori informazioni</translation>
<translation id="6177128806592000436">La tua connessione a questo sito non è protetta</translation>
+<translation id="6184817833369986695">(coorte: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Controlla la connessione a Internet</translation>
<translation id="6218753634732582820">Rimuovere l'indirizzo da Chromium?</translation>
<translation id="6251924700383757765">Norme sulla privacy</translation>
@@ -550,6 +560,8 @@
<translation id="6259156558325130047">&amp;Ripeti ridisposizione</translation>
<translation id="6263376278284652872">Segnalibri di <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Torna nell'area protetta</translation>
+<translation id="6276112860590028508">Le pagine del tuo elenco di lettura vengono visualizzate qui</translation>
+<translation id="6280223929691119688">Impossibile consegnare all'indirizzo specificato. Seleziona un indirizzo diverso.</translation>
<translation id="6282194474023008486">Codice postale</translation>
<translation id="6290238015253830360">Gli articoli suggeriti vengono visualizzati qui</translation>
<translation id="6305205051461490394"><ph name="URL" /> non è raggiungibile.</translation>
@@ -571,7 +583,6 @@
<translation id="6417515091412812850">Impossibile controllare se il certificato è stato revocato.</translation>
<translation id="6433490469411711332">Modifica informazioni di contatto</translation>
<translation id="6433595998831338502">Connessione negata da <ph name="HOST_NAME" />.</translation>
-<translation id="6443118737398455446">Data di scadenza non valida</translation>
<translation id="6446608382365791566">Aggiungi altre informazioni</translation>
<translation id="6451458296329894277">Conferma reinvio modulo</translation>
<translation id="6456339708790392414">Il tuo pagamento</translation>
@@ -579,10 +590,8 @@
<translation id="6462969404041126431">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere stato revocato. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Norme dispositivo</translation>
<translation id="6477321094435799029">Chrome ha rilevato un codice insolito su questa pagina e l'ha bloccata per proteggere le tue informazioni personali (ad esempio password, numeri di telefono e carte di credito).</translation>
-<translation id="6477460825583319731">Indirizzo email non valido</translation>
<translation id="6489534406876378309">Avvia caricamento arresti anomali</translation>
<translation id="6508722015517270189">Riavvia Chrome</translation>
-<translation id="6525462735697194615">Mese di scadenza non valido</translation>
<translation id="6529602333819889595">&amp;Ripeti eliminazione</translation>
<translation id="6534179046333460208">Suggerimenti relativi al Physical Web</translation>
<translation id="6550675742724504774">Opzioni</translation>
@@ -597,7 +606,6 @@
<translation id="6628463337424475685">Ricerca <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Questa norma è obsoleta.</translation>
<translation id="6652240803263749613">Questo server non è riuscito a verificare che si tratti 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. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Quell'opzione di spedizione non è disponibile. Prova con un'altra opzione.</translation>
<translation id="6671697161687535275">Rimuovere il suggerimento per i moduli da Chromium?</translation>
<translation id="6685834062052613830">Esci e completa la configurazione</translation>
<translation id="6710213216561001401">Indietro</translation>
@@ -605,13 +613,13 @@
<translation id="6711464428925977395">Si è verificato un problema con il server proxy oppure l'indirizzo non è corretto.</translation>
<translation id="6727102863431372879">Imposta</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{nessuno}=1{1 elemento}other{# elementi}}</translation>
-<translation id="6743044928064272573">Opzione ritiro</translation>
<translation id="674375294223700098">Errore sconosciuto del certificato del server.</translation>
<translation id="6753269504797312559">Valore norma</translation>
<translation id="6757797048963528358">Il dispositivo è entrato in modalità sospensione.</translation>
<translation id="6778737459546443941">Il tuo genitore non ha ancora approvato la richiesta</translation>
<translation id="6810899417690483278">ID personalizzazione</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Impossibile caricare i dati sull'area geografica</translation>
<translation id="6831043979455480757">Traduci</translation>
<translation id="6839929833149231406">Area</translation>
<translation id="6874604403660855544">&amp;Ripeti aggiunta</translation>
@@ -619,6 +627,7 @@
<translation id="6895330447102777224">La carta è stata confermata</translation>
<translation id="6897140037006041989">User-agent</translation>
<translation id="6915804003454593391">Utente:</translation>
+<translation id="6948701128805548767">Seleziona un indirizzo per conoscere i requisiti e i metodi di ritiro</translation>
<translation id="6957887021205513506">Il certificato del server risulta essere un falso.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Dispositivo</translation>
@@ -626,7 +635,6 @@
<translation id="6973656660372572881">Sono stati specificati sia i server proxy fissi che un URL script .pac.</translation>
<translation id="6989763994942163495">Mostra impostazioni avanzate...</translation>
<translation id="7000990526846637657">Nessuna voce della cronologia trovata</translation>
-<translation id="7001663382399377034">Aggiungi destinatario</translation>
<translation id="7009986207543992532">Hai tentato di accedere a <ph name="DOMAIN" />, tuttavia il server ha presentato un certificato il cui periodo di validità è troppo lungo per essere considerato attendibile. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Il tuo account Google potrebbe avere altre forme di cronologia di navigazione all'indirizzo <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -637,12 +645,15 @@
<translation id="7088615885725309056">Meno recente</translation>
<translation id="7090678807593890770">Cerca <ph name="LINK" /> con Google</translation>
<translation id="7119414471315195487">Chiudi altri programmi o schede</translation>
+<translation id="7129409597930077180">Impossibile spedire all'indirizzo specificato. Seleziona un indirizzo diverso.</translation>
+<translation id="7138472120740807366">Metodo di consegna</translation>
<translation id="7139724024395191329">Emirato</translation>
<translation id="7155487117670177674">Pagamento non sicuro</translation>
<translation id="7179921470347911571">Riavvia ora</translation>
<translation id="7180611975245234373">Aggiorna</translation>
<translation id="7182878459783632708">Nessuna norma impostata</translation>
<translation id="7186367841673660872">Questa pagina è stata tradotta da<ph name="ORIGINAL_LANGUAGE" />a<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> non è conforme agli standard di sicurezza.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Ulteriori informazioni<ph name="END_LINK" /> su questo problema.</translation>
@@ -671,7 +682,6 @@ Psst! La prossima volta potrebbe esserti utile la modalità di navigazione in in
<translation id="7424977062513257142">Una pagina incorporata in questa pagina web dice:</translation>
<translation id="7441627299479586546">Oggetto del criterio errato</translation>
<translation id="7444046173054089907">Questo sito è bloccato</translation>
-<translation id="7444238235002594607">Seleziona un indirizzo di ritiro per verificare i metodi di ritiro e i requisiti.</translation>
<translation id="7445762425076701745">Impossibile convalidare completamente l'identità del server a cui sei collegato. Sei collegato a un server con un nome valido soltanto nella tua rete, di cui un'autorità di certificazione esterna non può convalidare in alcun modo la proprietà. Poiché alcune autorità di certificazione emettono comunque certificati per questi nomi, non è in alcun modo possibile garantire che tu sia collegato al sito web desiderato anziché a un sito dannoso.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Leggere ulteriori informazioni<ph name="END_LINK" /> sul problema.</translation>
<translation id="7460163899615895653">Le schede recenti di altri dispositivi sono mostrate qui</translation>
@@ -715,6 +725,7 @@ Psst! La prossima volta potrebbe esserti utile la modalità di navigazione in in
<translation id="7755287808199759310">Il tuo genitore può sbloccarlo per te</translation>
<translation id="7758069387465995638">Il software antivirus o il firewall potrebbe avere bloccato la connessione.</translation>
<translation id="7761701407923456692">Il certificato del server non corrisponde all'URL.</translation>
+<translation id="7763386264682878361">Analizzatore sintattico dei file manifest dei pagamenti</translation>
<translation id="7764225426217299476">Aggiungi indirizzo</translation>
<translation id="777702478322588152">Prefettura</translation>
<translation id="7791543448312431591">Aggiungi</translation>
@@ -728,6 +739,7 @@ Psst! La prossima volta potrebbe esserti utile la modalità di navigazione in in
<translation id="785549533363645510">Non sei completamente invisibile: se navighi in incognito, la tua navigazione non viene nascosta al tuo datore di lavoro, al provider di servizi Internet o ai siti web che visiti.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Controlla il tuo codice CVC e riprova</translation>
+<translation id="79338296614623784">Inserisci un numero di telefono valido</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Il certificato del server non è ancora valido.</translation>
<translation id="7942349550061667556">Rosso</translation>
@@ -747,6 +759,7 @@ Psst! La prossima volta potrebbe esserti utile la modalità di navigazione in in
<translation id="8088680233425245692">Impossibile visualizzare l'articolo.</translation>
<translation id="8089520772729574115">meno di 1 MB</translation>
<translation id="8091372947890762290">Attivazione in attesa sul server</translation>
+<translation id="8118489163946903409">Metodo di pagamento</translation>
<translation id="8131740175452115882">Conferma</translation>
<translation id="8134994873729925007">Impossibile trovare l'<ph name="BEGIN_ABBR" />indirizzo DNS<ph name="END_ABBR" /> del server <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Il computer è entrato in modalità sospensione.</translation>
@@ -772,6 +785,7 @@ Psst! La prossima volta potrebbe esserti utile la modalità di navigazione in in
<translation id="8349305172487531364">Barra dei Preferiti</translation>
<translation id="8363502534493474904">Disattivare la modalità aereo</translation>
<translation id="8364627913115013041">Non impostata.</translation>
+<translation id="8368476060205742148">Google Play Services</translation>
<translation id="8380941800586852976">Pericolosa</translation>
<translation id="8382348898565613901">I preferiti visitati di recente vengono visualizzati qui</translation>
<translation id="8398259832188219207">Rapporto sugli arresti anomali caricato in data <ph name="UPLOAD_TIME" /></translation>
@@ -780,31 +794,29 @@ Psst! La prossima volta potrebbe esserti utile la modalità di navigazione in in
<translation id="8428213095426709021">Impostazioni</translation>
<translation id="8433057134996913067">In questo modo uscirai dalla maggior parte dei siti web.</translation>
<translation id="8437238597147034694">&amp;Annulla spostamento</translation>
-<translation id="8456681095658380701">Nome non valido</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 carta di credito}other{# carte di credito}}</translation>
<translation id="8483780878231876732">Accedi a Chrome per usare le carte memorizzate nel tuo account Google</translation>
<translation id="8488350697529856933">Si applica a</translation>
-<translation id="8492969205326575646">Tipo di carta non supportato</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ha impiegato troppo tempo a rispondere.</translation>
<translation id="852346902619691059">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato attendibile dal sistema operativo del dispositivo. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Anno di scadenza</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="8553075262323480129">La traduzione non è riuscita perché non è stato possibile determinare la lingua della pagina.</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="8570229484593575558">Le seguenti informazioni |non verranno memorizzate|:#Cronologia di navigazione#Ricerche#Dati dei cookie</translation>
<translation id="8571890674111243710">Traduzione della pagina in <ph name="LANGUAGE" /> in corso...</translation>
-<translation id="8584539743998202583">La tua attività |potrebbe rimanere visibile| a:#Siti web visitati#Il tuo datore di lavoro#Il tuo provider di servizi Internet</translation>
<translation id="858637041960032120">Aggiungi telefono</translation>
<translation id="859285277496340001">Il certificato non specifica un meccanismo per il controllo della sua revoca.</translation>
<translation id="8620436878122366504">I tuoi genitori non hanno ancora approvato la richiesta</translation>
<translation id="8647750283161643317">Ripristina i valori predefiniti per tutto</translation>
<translation id="8703575177326907206">La connessione a <ph name="DOMAIN" /> non è criptata.</translation>
+<translation id="8718314106902482036">Pagamento non completato</translation>
<translation id="8725066075913043281">Riprova</translation>
<translation id="8728672262656704056">Sei passato alla navigazione in incognito</translation>
<translation id="8730621377337864115">Fine</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="8759274551635299824">La carta è scaduta</translation>
<translation id="8790007591277257123">&amp;Ripeti eliminazione</translation>
-<translation id="8798099450830957504">Predefinito</translation>
<translation id="8800988563907321413">I suggerimenti Qui vicino vengono visualizzati qui</translation>
<translation id="8820817407110198400">Preferiti</translation>
<translation id="883848425547221593">Altri Preferiti</translation>
@@ -814,6 +826,7 @@ Psst! La prossima volta potrebbe esserti utile la modalità di navigazione in in
<translation id="8866481888320382733">Errore durante l'analisi delle impostazioni criterio</translation>
<translation id="8866959479196209191">Questa pagina dice:</translation>
<translation id="8870413625673593573">Chiusi di recente</translation>
+<translation id="8874824191258364635">Inserisci un numero di carta di credito valido</translation>
<translation id="8876793034577346603">Analisi della configurazione di rete non riuscita.</translation>
<translation id="8877192140621905067">Dopo essere stati confermati, i dettagli della carta saranno condivisi con questo sito</translation>
<translation id="8889402386540077796">Tonalità</translation>
@@ -823,7 +836,6 @@ Psst! La prossima volta potrebbe esserti utile la modalità di navigazione in in
<translation id="8931333241327730545">Vuoi salvare la scheda nel tuo account Google?</translation>
<translation id="8932102934695377596">L'orologio è indietro</translation>
<translation id="8954894007019320973">(Continua)</translation>
-<translation id="895548565263634352">Leggi articoli di <ph name="ARTICLE_PUBLISHER" /> e altri <ph name="OTHER_ARTICLE_COUNT" /></translation>
<translation id="8971063699422889582">Il certificato del server è scaduto.</translation>
<translation id="8986494364107987395">Invia automaticamente a Google statistiche sull'utilizzo e rapporti sugli arresti anomali</translation>
<translation id="8987927404178983737">Mese</translation>
@@ -841,7 +853,6 @@ Psst! La prossima volta potrebbe esserti utile la modalità di navigazione in in
<translation id="9068849894565669697">Seleziona colore</translation>
<translation id="9076283476770535406">Può includere contenuti per adulti</translation>
<translation id="9078964945751709336">Sono necessarie maggiori informazioni</translation>
-<translation id="9094175695478007090">Impossibile avviare l'app di pagamento.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> in genere utilizza la crittografia per proteggere le tue informazioni. Questa volta, quando Chromium ha provato a connettersi a <ph name="SITE" />, il sito web ha restituito credenziali insolite e sbagliate. È possibile che un malintenzionato stia cercando di spacciarsi per il sito <ph name="SITE" /> oppure che una schermata di accesso alla rete Wi-Fi abbia interrotto la connessione. Le tue informazioni sono ancora al sicuro perché Chromium ha interrotto la connessione prima che avvenissero scambi di dati.</translation>
<translation id="9137013805542155359">Mostra originale</translation>
<translation id="9137248913990643158">Accedi a Chrome prima di usare questa app.</translation>
diff --git a/chromium/components/strings/components_strings_iw.xtb b/chromium/components/strings/components_strings_iw.xtb
index fe0216eb4ab..974914f8c34 100644
--- a/chromium/components/strings/components_strings_iw.xtb
+++ b/chromium/components/strings/components_strings_iw.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="iw">
<translation id="1008557486741366299">×œ× ×¢×›×©×™×•</translation>
<translation id="1015730422737071372">ספק ×¤×¨×˜×™× × ×•×¡×¤×™×</translation>
+<translation id="1021110881106174305">×›×¨×˜×™×¡×™× ×ž×ושרי×</translation>
<translation id="1032854598605920125">סובב בכיוון השעון</translation>
<translation id="1038842779957582377">×©× ×œ× ×™×“×•×¢</translation>
<translation id="1050038467049342496">סגירת ×™×™×©×•×ž×™× ×חרי×</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">הסתר ערך</translation>
<translation id="1228893227497259893">מזהה יישות שגוי</translation>
<translation id="1232569758102978740">×œ×œ× ×©×</translation>
+<translation id="1263231323834454256">רשימת קרי××”</translation>
<translation id="1264126396475825575">דוח הקריסה תועד ב-<ph name="CRASH_TIME" /> (עדיין ×œ× ×”×¢×œ×™×ª ×ותו ×ו בחרת ×œ×”×ª×¢×œ× ×ž×ž× ×•)</translation>
<translation id="1285320974508926690">×œ×¢×•×œ× ×ל ×ª×ª×¨×’× ×תר ×–×”</translation>
<translation id="129553762522093515">נסגרו ל×חרונה</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">â€×”גדרות מילוי ×וטומטי של Chromium...</translation>
<translation id="1374468813861204354">הצעות</translation>
<translation id="1375198122581997741">מידע על הגרסה</translation>
+<translation id="1377321085342047638">מספר כרטיס</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> ×œ× ×©×œ×— נתוני×.</translation>
<translation id="1407135791313364759">פתח הכל</translation>
<translation id="1413809658975081374">שגי×ת פרטיות</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">היסטוריה</translation>
<translation id="1645368109819982629">פרוטוקול ×œ× × ×ª×ž×š</translation>
<translation id="1656489000284462475">×יסוף</translation>
+<translation id="1663943134801823270">â€×”×›×¨×˜×™×¡×™× ×•×”×›×ª×•×‘×•×ª × ×œ×§×—×™× ×ž-Chrome. ×פשר לנהל ××•×ª× ×‘<ph name="BEGIN_LINK" />הגדרות<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">â€×”×תר <ph name="SITE" /> משתמש בדרך כלל בהצפנה כדי להגן על המידע שלך. ×›×שר Google Chrome ניסה ×”×¤×¢× ×œ×”×ª×—×‘×¨ ל-<ph name="SITE" />, ×”×תר שלח חזרה ××™×©×•×¨×™× ×—×¨×™×’×™× ×•×©×’×•×™×™×. ייתכן שתוקף מנסה להתחזות ל×תר <ph name="SITE" />, ×ו שמסך כניסה ל-Wi-Fi הפריע לחיבור. המידע שלך עדיין מ×ובטח מכיוון ש-Google Chrome הפסיק ×ת החיבור לפני חילופי הנתוני×.</translation>
<translation id="168328519870909584">×ª×•×§×¤×™× ×”× ×ž×¦××™× ×›×¢×ª ב-<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ×¢×©×•×™×™× ×œ× ×¡×•×ª להתקין במכשיר שלך ×פליקציות מסוכנות שגונבות ×ו מוחקות מידע (לדוגמה, תמונות, סיסמ×ות, הודעות וכרטיסי ×שר××™).</translation>
<translation id="168841957122794586">×ישור השרת מכיל מפתח הצפנה חלש.</translation>
<translation id="1710259589646384581">מערכת הפעלה</translation>
<translation id="1721312023322545264">עליך לפנות ×ל <ph name="NAME" /> לקבלת הרש××” לביקור ב×תר ×”×–×”</translation>
+<translation id="1721424275792716183">* זהו שדה חובה</translation>
<translation id="1728677426644403582">×תה מציג ×ת המקור של דף ×ינטרנט</translation>
+<translation id="173080396488393970">×ין תמיכה בכרטיס מסוג ×–×”</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">נסה לפנות ×ל מנהל המערכת.</translation>
+<translation id="1740951997222943430">עליך להזין חודש תפוגה חוקי</translation>
<translation id="1745358365027406341">הורד ×ת הדף מ×וחר יותר</translation>
<translation id="17513872634828108">כרטיסיות פתוחות</translation>
<translation id="1753706481035618306">מספר דף</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">עדכן ×ת משפט-הסיסמה של הסינכרון.</translation>
<translation id="1787142507584202372">×›×ן מופיעות הכרטיסיות ש×תה פותח</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">בחר כתובת למשלוח כדי לבדוק מהן ×פשרויות ודרישות המשלוח.</translation>
+<translation id="1803264062614276815">×©× ×‘×¢×œ הכרטיס</translation>
<translation id="1803678881841855883">â€×’לישה בטוחה של Google <ph name="BEGIN_LINK" />זיהתה ל×חרונה תוכנה זדונית<ph name="END_LINK" /> ב-<ph name="SITE" />. ×œ×¢×™×ª×™× ×§×•×¨×” ש××ª×¨×™× ×‘×˜×•×—×™× × ×“×‘×§×™× ×‘×ª×•×›× ×” זדונית. מקור התוכן הזדוני ×”×•× <ph name="SUBRESOURCE_HOST" />. זהו מפיץ ידוע של תוכנה זדונית. <ph name="BEGIN_LEARN_MORE_LINK" />למידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">ת×ריך הוספה: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">הבקשה ×ו ×”×¤×¨×ž×˜×¨×™× ×©×œ הבקשה ××™× × ×—×•×§×™×™×</translation>
<translation id="1826516787628120939">מתבצעת בדיקה</translation>
<translation id="1834321415901700177">×”×תר ×”×–×” מכיל תוכניות מזיקות</translation>
<translation id="1842969606798536927">של×</translation>
-<translation id="1864455488461349376">×פשרות משלוח</translation>
<translation id="1871208020102129563">â€×©×¨×ª ×”-Proxy מוגדר להשתמש בשרתי Proxy קבועי×, ×œ× ×‘×›×ª×•×‘×ª ×תר של סקריפט ‎.Pac</translation>
<translation id="1871284979644508959">שדה חובה</translation>
<translation id="187918866476621466">פתח דפי פתיחה</translation>
<translation id="1883255238294161206">כווץ רשימה</translation>
<translation id="1898423065542865115">סינון</translation>
<translation id="194030505837763158">עבור ל-<ph name="LINK" /></translation>
-<translation id="1946821392246652573">×›×¨×˜×™×¡×™× ×ž×•×¨×©×™×</translation>
<translation id="1962204205936693436">סימניות של <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">שגי××” בעריכה בסידרה</translation>
<translation id="1974060860693918893">מתקד×</translation>
<translation id="1978555033938440688">גרסת קושחה</translation>
+<translation id="1995859865337580572">הזן ×ת קוד ×”×ימות</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{ו×פליקציה ×חת נוספת}two{ושתי ×פליקציות נוספות}many{ו-# ×פליקציות נוספות}other{ו-# ×פליקציות נוספות}}</translation>
-<translation id="2020194265157481222">יש לציין ×ת ×”×©× ×”×ž×•×¤×™×¢ בכרטיס</translation>
<translation id="2025186561304664664">â€×©×¨×ª Proxy נקבע למוגדר ×וטומטית.</translation>
<translation id="2030481566774242610">×”×× ×”×ª×›×•×•× ×ª ל-<ph name="LINK" />?</translation>
<translation id="2032962459168915086">â€<ph name="BEGIN_LINK" />לבדוק ×ת שרת ×”-Proxy ו×ת חומת ×”×ש<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">היו×</translation>
<translation id="2154054054215849342">סנכרון ×ינו זמין בדומיין שלך</translation>
<translation id="2154484045852737596">עריכת כרטיס</translation>
-<translation id="2156993118928861787">כתובת ×œ× ×—×•×§×™×ª</translation>
<translation id="2166049586286450108">גישה מל××” של מנהל המערכת</translation>
<translation id="2166378884831602661">×תר ×–×” ×œ× ×™×›×•×œ לספק חיבור מ×ובטח</translation>
<translation id="2181821976797666341">מדיניות</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{כתובת ×חת}two{שתי כתובות}many{# כתובות}other{# כתובות}}</translation>
+<translation id="2202020181578195191">עליך להזין שנת תפוגה חוקית</translation>
<translation id="2212735316055980242">×œ× × ×ž×¦××” מדיניות</translation>
<translation id="2213606439339815911">מ×חזר רשומות...</translation>
<translation id="2230458221926704099">תקן ×ת החיבור ב×מצעות <ph name="BEGIN_LINK" />×פליקציית הבדיקה<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">הגישה ל×ינטרנט חסומה</translation>
<translation id="230155334948463882">כרטיס חדש?</translation>
<translation id="2305919008529760154">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ייתכן ש×ישור ×”×בטחה שלו מזויף. ייתכן שהסיבה לכך ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף מיירט ×ת החיבור שלך. <ph name="BEGIN_LEARN_MORE_LINK" />למידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">â€×”×פשרויות של ×›×¨×˜×™×¡×™× ×•×›×ª×•×‘×•×ª נלקחו מחשבון Google שלך (<ph name="ACCOUNT_EMAIL" />) ומ-Chrome. תוכל לנהל ×ת ×”×פשרויות ×”×לו ב<ph name="BEGIN_LINK" />הגדרות<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> דורש ×©× ×ž×©×ª×ž×© וסיסמה.</translation>
<translation id="2318774815570432836">â€×œ× ניתן לבקר עכשיו ב×תר <ph name="SITE" /> מכיוון ×©×”×•× ×ž×©×ª×ž×© ב-HSTSâ€. שגי×ות רשת ותקיפות מתרחשות בדרך כלל לזמן מוגבל, ולכן סביר להניח שדף ×–×” יחזור לפעול מ×וחר יותר. <ph name="BEGIN_LEARN_MORE_LINK" />למידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">סימניות ×חרות</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">ברירת מחדל של ×רגון</translation>
<translation id="2386255080630008482">×ישור השרת נשלל.</translation>
<translation id="2392959068659972793">הצגת מדיניות ×œ×œ× ×¢×¨×š מוגדר</translation>
+<translation id="239429038616798445">שיטת המשלוח הזו ×œ× ×–×ž×™× ×”. עליך לבחור שיטה ×חרת.</translation>
<translation id="2396249848217231973">&amp;ביטול מחיקה</translation>
<translation id="2460160116472764928">â€×’לישה בטוחה של Google <ph name="BEGIN_LINK" />זיהתה ל×חרונה תוכנה זדונית<ph name="END_LINK" /> ב-<ph name="SITE" />. ×œ×¢×™×ª×™× ×§×•×¨×” ש××ª×¨×™× ×‘×˜×•×—×™× × ×“×‘×§×™× ×‘×ª×•×›× ×” זדונית. <ph name="BEGIN_LEARN_MORE_LINK" />למידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">מל×</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />מפעיל ×ת ×בחון הרשת<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">כתובת ×תר ×œ× ×—×•×§×™×ª של חיפוש</translation>
<translation id="2491120439723279231">×ישור השרת מכיל שגי×ות.</translation>
-<translation id="24943777258388405">מספר טלפון ×œ× ×—×•×§×™</translation>
<translation id="2495083838625180221">â€×ž× ×ª×— JSON</translation>
<translation id="2495093607237746763">â€×× ×”×פשרות תסומן, Chromium ישמור עותק של הכרטיס במכשיר ×”×–×” כדי ×œ×ž×œ× ×˜×¤×¡×™× ×‘×ž×”×™×¨×•×ª רבה יותר.</translation>
<translation id="2498091847651709837">סרוק כרטיס חדש</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> שלח תגובה ×œ× ×—×•×§×™×ª.</translation>
<translation id="2552545117464357659">חדש יותר</translation>
<translation id="2556876185419854533">&amp;ביטול עריכה</translation>
+<translation id="2587730715158995865">מ-<ph name="ARTICLE_PUBLISHER" />. לקרי×ת כתבה זו ו-<ph name="OTHER_ARTICLE_COUNT" /> כתבות נוספות.</translation>
<translation id="2587841377698384444">â€×ž×–×”×” ממשק API של ספרייה:</translation>
<translation id="2597378329261239068">מסמך ×–×” מוגן ב×מצעות סיסמה. הזן סיסמה.</translation>
<translation id="2609632851001447353">ורי×ציות</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />מפעיל ×ת ×בחון הקישוריות<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">×ישור</translation>
<translation id="2742870351467570537">הסר ×¤×¨×™×˜×™× ×©× ×‘×—×¨×•</translation>
+<translation id="277133753123645258">שיטת משלוח</translation>
<translation id="277499241957683684">חסרה רשומת מכשיר</translation>
<translation id="2784949926578158345">החיבור עבר ×יפוס.</translation>
<translation id="2794233252405721443">×תר חסו×</translation>
-<translation id="2812680587231492111">×פשרות ×”×יסוף הזו ×œ× ×–×ž×™× ×”. נסה ×פשרות ×חרת.</translation>
<translation id="2824775600643448204">סרגל חיפוש וכתובות</translation>
<translation id="2826760142808435982">החיבור מוצפן ומ×ומת ב×מצעות <ph name="CIPHER" /> ומשתמש ב-<ph name="KX" /> כמנגנון להחלפת מפתחות.</translation>
<translation id="2835170189407361413">נקה טופס</translation>
-<translation id="2849041323157393173">×פשרות המסירה הזו ×œ× ×–×ž×™× ×”. נסה ×פשרות ×חרת.</translation>
<translation id="2889159643044928134">×ל תטען מחדש</translation>
<translation id="2900469785430194048">â€×זל הזיכרון הזמין ל-Google Chrome בניסיון להציג ×ת דף ×”×ינטרנט ×”×–×”.</translation>
<translation id="2909946352844186028">×ותר שינוי ברשת.</translation>
<translation id="2916038427272391327">סגירת תוכניות ×חרות</translation>
<translation id="2922350208395188000">×œ× × ×™×ª×Ÿ לבדוק ×ת ×ישור השרת.</translation>
+<translation id="2928905813689894207">כתובת לחיוב</translation>
<translation id="2948083400971632585">â€× ×™×ª×Ÿ להשבית כל שרת proxy המוגדר לחיבור מדף ההגדרות.</translation>
<translation id="2955913368246107853">סגור ×ת חלונית החיפוש</translation>
<translation id="2958431318199492670">â€×ª×¦×•×¨×ª הרשת ××™× ×” תו×מת לתקן ONC. ייתכן ×©×—×œ×§×™× ×ž×”×ª×¦×•×¨×” ×œ× ×™×™×›×œ×œ×• בייבו×.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">â€×›×“×™ ליצור חיבור מ×ובטח, השעון צריך להיות מוגדר כהלכה. הסיבה לכך ×”×™× ×©×”××™×©×•×¨×™× ×©×‘××ž×¦×¢×•×ª× ××ª×¨×™× ×ž×–×”×™× ×ת ×¢×¦×ž× ×ª×§×¤×™× ×¨×§ למשך פרקי זמן מסוימי×. מ×חר שהשעון במכשיר שלך שגוי, Google Chrome ×œ× ×™×›×•×œ ל×מת ×ת ×”××™×©×•×¨×™× ×”×לה.</translation>
<translation id="2972581237482394796">&amp;בצע שנית</translation>
<translation id="2985306909656435243">â€×× ×”×פשרות תופעל, Chromium ×™×חסן עותק של הכרטיס שלך במכשיר ×”×–×” למילוי מהיר יותר של טפסי×.</translation>
+<translation id="2985398929374701810">עליך להזין כתובת חוקית</translation>
+<translation id="2986368408720340940">שיטת ×”×יסוף הזו ××™× ×” זמינה. עליך לבחור שיטה ×חרת.</translation>
<translation id="2991174974383378012">שיתוף ×¢× ×תרי×</translation>
<translation id="3005723025932146533">הצג עותק שמור</translation>
<translation id="3008447029300691911">הזן ×ת קוד ×”×ימות של הכרטיס <ph name="CREDIT_CARD" />. ברגע שת×שר, פרטי הכרטיס שלך ישותפו ×¢× ×”×תר ×”×–×”.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{לפחות פריט ×חד ×‘×ž×›×©×™×¨×™× ×ž×¡×•× ×›×¨× ×™×}=1{פריט ×חד (×•×¤×¨×™×˜×™× × ×•×¡×¤×™× ×‘×ž×›×©×™×¨×™× ×ž×¡×•× ×›×¨× ×™×)}two{שני ×¤×¨×™×˜×™× (×•×¤×¨×™×˜×™× × ×•×¡×¤×™× ×‘×ž×›×©×™×¨×™× ×ž×¡×•× ×›×¨× ×™×)}many{# ×¤×¨×™×˜×™× (×•×¤×¨×™×˜×™× × ×•×¡×¤×™× ×‘×ž×›×©×™×¨×™× ×ž×¡×•× ×›×¨× ×™×)}other{# ×¤×¨×™×˜×™× (×•×¤×¨×™×˜×™× × ×•×¡×¤×™× ×‘×ž×›×©×™×¨×™× ×ž×¡×•× ×›×¨× ×™×)}}</translation>
<translation id="3041612393474885105">פרטי ×ישור</translation>
<translation id="3063697135517575841">â€Chrome ×œ× ×”×¦×œ×™×— ל×שר ×ת הכרטיס שלך הפע×. נסה שוב מ×וחר יותר.</translation>
+<translation id="3064966200440839136">בחרת לצ×ת ממצב גלישה בסתר כדי ×œ×©×œ× ×‘×מצעות ×™×™×©×•× ×—×™×¦×•× ×™. להמשיך?</translation>
<translation id="3093245981617870298">×תה במצב ×œ× ×ž×§×•×•×Ÿ.</translation>
<translation id="3105172416063519923">מזהה נכס:</translation>
<translation id="3109728660330352905">×ין לך הרש××” להציג ×ת הדף ×”×–×”.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />נסה להפעיל ×ת ×בחון הקישוריות<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">פענוח התגובה נכשל</translation>
-<translation id="3149891296864842641">×פשרויות משלוח</translation>
<translation id="3150653042067488994">שגי×ת שרת זמנית</translation>
+<translation id="3154506275960390542">דף ×–×” כולל טופס שעשוי להישלח ב×ופן ×œ× ×ž×ובטח. ×”× ×ª×•× ×™× ×©×ª×©×œ×— יהיו ×’×œ×•×™×™× ×‘×ž×”×œ×š ההעברה, וקיימת סכנה שמישהו ישנה ×ת ×”×¤×¨×˜×™× ×©×”×©×¨×ª יקבל.</translation>
<translation id="3157931365184549694">שחזר</translation>
<translation id="3167968892399408617">â€×“×¤×™× ×©×תה מציג בכרטיסיות גלישה בסתר ×œ× ×™×™×©×רו בהיסטוריית הדפדפן, ב×חסון קובצי ×”-Cookie ×ו בהיסטוריית ×”×—×™×¤×•×©×™× ×œ×חר שתסגור ×ת כל כרטיסיות הגלישה בסתר. ×§×‘×¦×™× ×©×”×•×¨×“×ª ×ו סימניות שיצרת יישמרו.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">×œ× × ×™×ª×Ÿ ×”×™×” לשלוח ×ל <ph name="NAME" /> ×ת הבקשה שלך לגשת ל×תר ×”×–×”. נסה שוב.</translation>
<translation id="3355823806454867987">â€×©× ×” הגדרות שרת Proxy...</translation>
<translation id="3369192424181595722">שגי×ת שעון</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> ×¤×¨×™×˜×™× × ×•×¡×¤×™×...</translation>
<translation id="337363190475750230">ניהול התצורה בוטל</translation>
<translation id="3377188786107721145">שגי××” בניתוח המדיניות</translation>
<translation id="3380365263193509176">שגי××” ×œ× ×™×“×•×¢×”</translation>
<translation id="3380864720620200369">מספר לקוח:</translation>
<translation id="3391030046425686457">כתובת למשלוח</translation>
+<translation id="3395827396354264108">שיטת ×יסוף</translation>
<translation id="340013220407300675">ייתכן ×©×ª×•×§×¤×™× ×ž× ×¡×™× ×œ×’× ×•×‘ ×ת המידע שלך מ-<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (לדוגמה: סיסמ×ות, הודעות ×ו כרטיסי ×שר××™).</translation>
<translation id="3422248202833853650">מומלץ לצ×ת מתוכניות ×חרות וכך לפנות ×ž×§×•× ×‘×–×™×›×¨×•×Ÿ.</translation>
<translation id="3422472998109090673">×œ× × ×™×ª×Ÿ לגשת כרגע ×ל <ph name="HOST_NAME" />.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">מרווח ×חזור:</translation>
<translation id="3462200631372590220">הסתר ×¤×¨×˜×™× ×ž×ª×§×“×ž×™×</translation>
+<translation id="3467763166455606212">עליך לציין ×ת ×©× ×‘×¢×œ הכרטיס</translation>
+<translation id="3478058380795961209">חודש פקיעת התוקף</translation>
<translation id="3479539252931486093">×”×× ×–×” קרה ב×ופן בלתי צפוי? <ph name="BEGIN_LINK" />ספר לנו על כך<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">×œ× ×¢×›×©×™×•</translation>
<translation id="348000606199325318">מזהה קריסה <ph name="CRASH_LOCAL_ID" /> (מזהה שרת: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">×œ× ×”×¦×œ×—× ×• ליצור קשר ×¢× ×”×”×•×¨×” שלך. נסה שוב מ×וחר יותר.</translation>
<translation id="3528171143076753409">×ישור השרת ×ינו מהימן.</translation>
-<translation id="3538531656504267329">שנת תפוגה ×œ× ×—×•×§×™×ª</translation>
<translation id="3539171420378717834">שמור עותק של הכרטיס הזה במכשיר הזה</translation>
<translation id="3542684924769048008">השתמש בסיסמה עבור:</translation>
<translation id="3549644494707163724">הצפן ×ת כל ×”× ×ª×•× ×™× ×”×ž×¡×•× ×›×¨× ×™× ×‘×מצעות משפט הסיסמה שלך לסנכרון</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">הסתר פרטי×</translation>
<translation id="3587482841069643663">הכל</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">עליך להזין ת×ריך תפוגה חוקי</translation>
<translation id="36224234498066874">נקה נתוני גלישה...</translation>
<translation id="362276910939193118">הצג ×ת כל ההיסטוריה</translation>
<translation id="3623476034248543066">הצג ערך</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">סיסמה:</translation>
<translation id="3696411085566228381">לל×</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">בחר כתובת למשלוח כדי לבדוק ×ת ×מצעי המשלוח ו×ת הדרישות למשלוח.</translation>
<translation id="370665806235115550">טוען...</translation>
<translation id="3712624925041724820">×ין מספיק רישיונות</translation>
<translation id="3714780639079136834">â€×œ×”פעיל × ×ª×•× ×™× ×œ× ×™×™×“ ×ו ×ת ×”-Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">קישור שהעתקת</translation>
<translation id="375403751935624634">×”×ª×¨×’×•× × ×›×©×œ עקב שגי×ת שרת.</translation>
<translation id="3759461132968374835">×œ× ×”×ª×§×‘×œ×• ×“×™×•×•×—×™× ×¢×œ קריסות ל×חרונה. קריסות שהתרחשו בזמן ש×פשרות הדיווח על קריסות היתה מושבתת ×œ× ×™×•×¤×™×¢×• ×›×ן.</translation>
+<translation id="3787705759683870569">ת×ריך תפוגה: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">â€×× ×תה משתמש בשרת Proxy...</translation>
<translation id="3828924085048779000">×ין ×פשרות להשתמש במשפט-סיסמה ריק.</translation>
<translation id="3845539888601087042">מציג היסטוריה ×ž×”×ž×›×©×™×¨×™× ×©×‘×”× ×תה מחובר לחשבון. <ph name="BEGIN_LINK" />למידע נוסף<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">â€×”×× ×ª×¨×¦×” ש-Chromium ישמור ×ת הכרטיס ×”×–×”?</translation>
<translation id="4171400957073367226">חתימת ×ימות ×œ× ×—×•×§×™×ª</translation>
-<translation id="4176463684765177261">מושבת</translation>
<translation id="4196861286325780578">&amp;ביצוע מחדש של העברה</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />לבדוק ×ת תצורת ×”×נטי-וירוס וחומת ×”×ש<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{לל×}=1{×פליקציה ×חת ($1)}=2{שתי ×פליקציות ($1, $2)}many{# ×פליקציות ($1, $2, $3)}other{# ×פליקציות ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">תוצ×ות חיפוש</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ×œ× ×ישר ×ת ×ישור ההתחברות שלך, ×ו ×©×œ× ×¡×•×¤×§ ×ישור התחברות.</translation>
<translation id="443673843213245140">â€×”שימוש בשרת Proxy הושבת, ×ך צויינה תצורת שרת Proxy מפורשת.</translation>
-<translation id="4446242550670694251">עכשיו ב×פשרותך לגלוש ב×ופן פרטי, ו×× ×©×™× ××—×¨×™× ×©×ž×©×ª×ž×©×™× ×‘×ž×›×©×™×¨ ×”×–×” ×œ× ×™×¨×ו ×ת הפעילות שלך.</translation>
<translation id="4492190037599258964">תוצ×ות החיפוש עבור '<ph name="SEARCH_STRING" />'</translation>
<translation id="4506176782989081258">שגי×ת ×ימות: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">לפנות ×ל מנהל המערכת</translation>
<translation id="450710068430902550">שיתוף ×¢× ×ž× ×”×œ מערכת</translation>
+<translation id="4515275063822566619">â€×”×›×¨×˜×™×¡×™× ×•×”×›×ª×•×‘×•×ª ×œ×§×•×—×™× ×ž-Chrome ומחשבון Google שלך (<ph name="ACCOUNT_EMAIL" />). ×פשר לנהל ××•×ª× ×‘<ph name="BEGIN_LINK" />הגדרות<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">פרטי×</translation>
<translation id="4558551763791394412">נסה להשבית ×ת התוספי×.</translation>
<translation id="457875822857220463">משלוח</translation>
@@ -421,6 +432,7 @@ Del</translation>
<translation id="4816492930507672669">הת×מה לדף</translation>
<translation id="483020001682031208">×ין ×“×¤×™× ×©×œ ×”×ינטרנט הווירטופיזי ×©×–×ž×™× ×™× ×œ×”×¦×’×”</translation>
<translation id="4850886885716139402">הצג</translation>
+<translation id="4854362297993841467">שיטת המסירה הזו ××™× ×” זמינה. עליך לבחור שיטה ×חרת.</translation>
<translation id="4858792381671956233">ש×לת ×ת ×”×”×•×¨×™× ×©×œ×š ×× ×תה יכול לגשת ל×תר ×”×–×”</translation>
<translation id="4880827082731008257">חפש בהיסטוריה</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -428,7 +440,6 @@ Del</translation>
<translation id="4923417429809017348">דף ×–×” ×ª×•×¨×’× ×ž×©×¤×” ×œ× ×™×“×•×¢×” ל<ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">תשלו×</translation>
<translation id="4926049483395192435">יש לציין ערך זה.</translation>
-<translation id="4941291666397027948">* מציין שדה חובה</translation>
<translation id="495170559598752135">פעולות</translation>
<translation id="4958444002117714549">הרחב רשימה</translation>
<translation id="4962322354953122629">â€×”שרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; Chrome ×ינו סומך על ×ישור ×”×בטחה שלו. ייתכן שהסיבה לכך ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף מיירט ×ת החיבור שלך. <ph name="BEGIN_LEARN_MORE_LINK" />למידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -443,6 +454,7 @@ Del</translation>
<translation id="5045550434625856497">סיסמה שגויה</translation>
<translation id="5056549851600133418">מ××ž×¨×™× ×©×¢×©×•×™×™× ×œ×¢× ×™×™×Ÿ ×ותך</translation>
<translation id="5070335125961472645">â€<ph name="BEGIN_LINK" />לבדוק ×ת כתובת שרת ×”-Proxy<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{â€×ין קובצי Cookie}=1{â€×תר ×חד משתמש בקובצי Cookie. }two{â€# ××ª×¨×™× ×ž×©×ª×ž×©×™× ×‘×§×•×‘×¦×™ Cookie. }many{â€# ××ª×¨×™× ×ž×©×ª×ž×©×™× ×‘×§×•×‘×¦×™ Cookie. }other{â€# ××ª×¨×™× ×ž×©×ª×ž×©×™× ×‘×§×•×‘×¦×™ Cookie. }}</translation>
<translation id="5087286274860437796">×”×ישור של השרת ×ינו תקף כעת.</translation>
<translation id="5087580092889165836">הוסף כרטיס</translation>
<translation id="5089810972385038852">מדינה</translation>
@@ -465,10 +477,8 @@ Del</translation>
<translation id="5300589172476337783">הצג</translation>
<translation id="5308689395849655368">דיווח קריסות מושבת.</translation>
<translation id="5317780077021120954">שמור</translation>
-<translation id="5326702247179446998">יש לציין נמען</translation>
<translation id="5327248766486351172">ש×</translation>
<translation id="5337705430875057403">×ª×•×§×¤×™× ×‘-<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ×¢×©×•×™×™× ×œ×’×¨×•× ×œ×š לבצע פעולות מסוכנות, כמו התקנת תוכנה ×ו חשיפה של מידע ×ישי (למשל: סיסמ×ות, מספרי טלפון ×ו כרטיסי ×שר××™).</translation>
-<translation id="53553865750799677">כתובת ×יסוף ×œ× × ×ª×ž×›×ª. בחר כתובת ×חרת.</translation>
<translation id="5359637492792381994">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו ×ינו חוקי כעת. ייתכן שהסיבה לכך ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף מיירט ×ת החיבור שלך. <ph name="BEGIN_LEARN_MORE_LINK" />למידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">×חסון הגדרות המדיניות נכשל</translation>
<translation id="5386426401304769735">â€×©×¨×©×¨×ª ×”××™×©×•×¨×™× ×©×œ ×”×תר ×”×–×” כוללת ×ישור ×©× ×—×ª× ×‘×מצעות SHA-1.</translation>
@@ -495,8 +505,8 @@ Del</translation>
<translation id="5544037170328430102">דף המוטמע ב-<ph name="SITE" /> ×ומר:</translation>
<translation id="5556459405103347317">טען שוב</translation>
<translation id="5565735124758917034">פעיל</translation>
+<translation id="5571083550517324815">×œ× × ×™×ª×Ÿ לבצע ×יסוף מהכתובת הזו. עליך לבחור כתובת ×חרת.</translation>
<translation id="5572851009514199876">â€×ª×—ילה היכנס לחשבונך ב-Chrome כדי ל×פשר ל-Chrome לבדוק ×× ×™×© לך הרש××” לגשת ל×תר ×”×–×”.</translation>
-<translation id="5575380383496039204">כתובת משלוח ×œ× × ×ª×ž×›×ª. בחר כתובת ×חרת.</translation>
<translation id="5580958916614886209">בדוק ×ת חודש התפוגה ונסה שוב</translation>
<translation id="560412284261940334">ניהול ×ינו נתמך</translation>
<translation id="5610142619324316209">לבדוק ×ת החיבור</translation>
@@ -512,7 +522,8 @@ Del</translation>
<translation id="5710435578057952990">הזהות של ×תר ×–×” ×œ× ×ומתה.</translation>
<translation id="5720705177508910913">משתמש נוכחי:</translation>
<translation id="5732392974455271431">×”×”×•×¨×™× ×©×œ×š ×™×›×•×œ×™× ×œ×‘×˜×œ בשבילך ×ת החסימה</translation>
-<translation id="57586589942790530">מספר כרטיס ×œ× ×—×•×§×™</translation>
+<translation id="5763042198335101085">עליך להזין כתובת ×ימייל חוקית</translation>
+<translation id="5765072501007116331">עליך לבחור כתובת כדי לר×ות שיטות מסירה ודרישות</translation>
<translation id="5784606427469807560">הייתה בעיה ב×ישור הכרטיס. בדוק ×ת החיבור ל×ינטרנט ונסה שוב.</translation>
<translation id="5785756445106461925">כמו כן, דף ×–×” כולל מש××‘×™× × ×•×¡×¤×™× ×©××™× × ×ž×ובטחי×. ×’×•×¨×ž×™× ××—×¨×™× ×¢×œ×•×œ×™× ×œ×¨×ות ×ת המש××‘×™× ×”×לה במהלך העברת×, ותוקף עלול לשנות ××•×ª× ×‘×ופן שישנה ×ת מר××” הדף.</translation>
<translation id="5786044859038896871">×”×× ×‘×¨×¦×•× ×š ×œ×ž×œ× ×ת פרטי הכרטיס שלך?</translation>
@@ -525,22 +536,20 @@ Del</translation>
<translation id="5869405914158311789">×œ× × ×™×ª×Ÿ לגשת ל×תר ×”×–×”</translation>
<translation id="5869522115854928033">סיסמ×ות שמורות</translation>
<translation id="5872918882028971132">הצעות להורי×</translation>
-<translation id="587760065310675640">כתובת משלוח ×œ× × ×ª×ž×›×ª. בחר כתובת ×חרת.</translation>
<translation id="5901630391730855834">צהוב</translation>
-<translation id="59174027418879706">מופעל</translation>
<translation id="5926846154125914413">×תה עשוי ל×בד גישה ×ל תוכן ×¤×¨×ž×™×•× ×ž××ª×¨×™× ×ž×¡×•×™×ž×™×.</translation>
<translation id="5959728338436674663">â€×©×œ×— ב×ופן ×וטומטי <ph name="BEGIN_WHITEPAPER_LINK" />חלק מפרטי המערכת ותוכן הדף<ph name="END_WHITEPAPER_LINK" /> ×ל Google כדי לעזור בזיהוי של ×פליקציות ו××ª×¨×™× ×ž×¡×•×›× ×™×. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">שבוע</translation>
<translation id="5967867314010545767">הסר מההיסטוריה</translation>
<translation id="5975083100439434680">התרחק</translation>
+<translation id="598637245381783098">×œ× × ×™×ª×Ÿ לפתוח ×ת ×פליקציית התשלומי×</translation>
<translation id="5989320800837274978">â€×œ× צוינו שרתי Proxy ×§×‘×•×¢×™× ×•×œ× ×›×ª×•×‘×ª ×תר של סקריפט ‎.pac</translation>
<translation id="5990559369517809815">בקשות שנשלחו לשרת נחסמו על ידי תוסף.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">â€×”×פשרויות של ×›×¨×˜×™×¡×™× ×•×›×ª×•×‘×•×ª נלקחו מ-Chrome. תוכל לנהל ×ת ×”×פשרויות ×”×לו ב<ph name="BEGIN_LINK" />הגדרות<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{דף 1}two{דף #}many{דף #}other{דף #}}</translation>
<translation id="6017514345406065928">ירוק</translation>
+<translation id="6027201098523975773">עליך להזין ש×</translation>
<translation id="6040143037577758943">סגור</translation>
-<translation id="604124094241169006">×וטומטי</translation>
<translation id="6042308850641462728">עוד</translation>
<translation id="6060685159320643512">זהירות, × ×™×¡×•×™×™× ×לה ×¢×œ×•×œ×™× ×œ× ×©×•×š</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{לל×}=1{×חת}two{שתיי×}many{#}other{#}}</translation>
@@ -548,9 +557,10 @@ Del</translation>
ש×תה משתמש בה×.</translation>
<translation id="614940544461990577">נסה:</translation>
<translation id="6151417162996330722">תקופת התוקף של ×ישור השרת ×רוכה מדי.</translation>
-<translation id="615643356032862689">×œ× ×ª×ª×‘×¦×¢ מחיקה של ×§×‘×¦×™× ×•×¡×™×ž× ×™×•×ª שהורדת.</translation>
+<translation id="6157877588268064908">עליך לבחור כתובת כדי לר×ות שיטות משלוח ודרישות</translation>
<translation id="6165508094623778733">למידע נוסף</translation>
<translation id="6177128806592000436">החיבור שלך ל×תר ×”×–×” ×œ× ×ž×ובטח</translation>
+<translation id="6184817833369986695">(קבוצה: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">בדוק ×ת חיבור ×”×ינטרנט</translation>
<translation id="6218753634732582820">â€×”×× ×œ×”×¡×™×¨ מ-Chromium ×ת הכתובת?</translation>
<translation id="6251924700383757765">מדיניות פרטיות</translation>
@@ -559,6 +569,8 @@ Del</translation>
<translation id="6259156558325130047">&amp;ביצוע מחדש של שינוי סדר</translation>
<translation id="6263376278284652872">סימניות <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">חזרה לחוף מבטחי×</translation>
+<translation id="6276112860590028508">×“×¤×™× ×ž×¨×©×™×ž×ª הקרי××” שלך ×ž×•×¤×™×¢×™× ×›×ן</translation>
+<translation id="6280223929691119688">×œ× × ×™×ª×Ÿ לבצע מסירה בכתובת זו. עליך לבחור כתובת ×חרת.</translation>
<translation id="6282194474023008486">מיקוד</translation>
<translation id="6290238015253830360">הצעות של מ××ž×¨×™× ×¢×‘×•×¨×š מופיעות ×›×ן</translation>
<translation id="6305205051461490394">×œ× × ×™×ª×Ÿ לגשת ×ל <ph name="URL" />.</translation>
@@ -580,7 +592,6 @@ Del</translation>
<translation id="6417515091412812850">×œ× × ×™×ª×Ÿ לבדוק ×× ×”×ישור נשלל.</translation>
<translation id="6433490469411711332">עריכת ×”×¤×¨×˜×™× ×œ×™×¦×™×¨×ª קשר</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> סירב להתחבר.</translation>
-<translation id="6443118737398455446">ת×ריך התפוגה ×ינו חוקי</translation>
<translation id="6446608382365791566">הוסף מידע</translation>
<translation id="6451458296329894277">×שר שליחה-מחדש של הטופס</translation>
<translation id="6456339708790392414">×”×ª×©×œ×•× ×©×œ×š</translation>
@@ -588,10 +599,8 @@ Del</translation>
<translation id="6462969404041126431">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ייתכן ש×ישור ×”×בטחה שלו בוטל. ייתכן שהסיבה לכך ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף מיירט ×ת החיבור שלך. <ph name="BEGIN_LEARN_MORE_LINK" />למידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">מדיניות המכשיר</translation>
<translation id="6477321094435799029">â€Chrome ×–×™×”×” קוד חריג בדף ×”×–×” ×•×—×¡× ×ותו כדי להגן על המידע הפרטי שלך (כגון סיסמ×ות, מספרי טלפון ומספרי כרטיסי ×שר××™).</translation>
-<translation id="6477460825583319731">כתובת ×ימייל ×œ× ×—×•×§×™×ª</translation>
<translation id="6489534406876378309">התחל להעלות קריסות</translation>
<translation id="6508722015517270189">â€×”פעלה מחדש של Chrome</translation>
-<translation id="6525462735697194615">חודש תפוגה ×œ× ×—×•×§×™</translation>
<translation id="6529602333819889595">&amp;ביצוע מחדש של מחיקה</translation>
<translation id="6534179046333460208">הצעות ל×ינטרנט הווירטופיזי</translation>
<translation id="6550675742724504774">×פשרויות</translation>
@@ -606,7 +615,6 @@ Del</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> חיפוש</translation>
<translation id="6644283850729428850">מדיניות זו ××™× ×” בתוקף.</translation>
<translation id="6652240803263749613">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; מערכת ההפעלה של המחשב ×œ× ×¡×•×ž×›×ª על ×ישור ×”×בטחה שלו. ייתכן שהסיבה לכך ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף מיירט ×ת החיבור שלך. <ph name="BEGIN_LEARN_MORE_LINK" />למידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">×פשרות המשלוח הזו ×œ× ×–×ž×™× ×”. נסה ×פשרות ×חרת.</translation>
<translation id="6671697161687535275">â€×”×× ×œ×”×¡×™×¨ מ-Chromium הצעות לטפסי×?</translation>
<translation id="6685834062052613830">×¦× ×•×”×©×œ× ×ת ההגדרה</translation>
<translation id="6710213216561001401">הקוד×</translation>
@@ -614,13 +622,13 @@ Del</translation>
<translation id="6711464428925977395">â€×ž×©×”ו ×ינו תקין בשרת ×”-proxy, ×ו שהכתובת שגויה.</translation>
<translation id="6727102863431372879">הגדר</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{לל×}=1{פריט ×חד}two{שני פריטי×}many{# פריטי×}other{# פריטי×}}</translation>
-<translation id="6743044928064272573">×פשרות ×יסוף</translation>
<translation id="674375294223700098">שגי×ת ×ישור שרת ×œ× ×™×“×•×¢.</translation>
<translation id="6753269504797312559">ערך מדיניות</translation>
<translation id="6757797048963528358">המכשיר עבר למצב שינה.</translation>
<translation id="6778737459546443941">ההורה שש×לת עדיין ×œ× ×ישר ×–×ת</translation>
<translation id="6810899417690483278">מזהה של הת×מה ×ישית</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">נכשלה הטעינה של נתוני ×”×זורי×</translation>
<translation id="6831043979455480757">תרג×</translation>
<translation id="6839929833149231406">×זור</translation>
<translation id="6874604403660855544">&amp;ביצוע מחדש של הוספה</translation>
@@ -628,6 +636,7 @@ Del</translation>
<translation id="6895330447102777224">הכרטיס שלך מ×ושר</translation>
<translation id="6897140037006041989">User agent</translation>
<translation id="6915804003454593391">משתמש:</translation>
+<translation id="6948701128805548767">עליך לבחור כתובת כדי לר×ות שיטות ×יסוף ודרישות</translation>
<translation id="6957887021205513506">נר××” שה×ישור של השרת מזויף.</translation>
<translation id="6965382102122355670">×ישור</translation>
<translation id="6965978654500191972">התקן</translation>
@@ -635,7 +644,6 @@ Del</translation>
<translation id="6973656660372572881">â€×¦×•×™× ×• שרתי Proxy ×§×‘×•×¢×™× ×•×›×ª×•×‘×ª ×תר של הסקריפט מסוג ‎.Pac</translation>
<translation id="6989763994942163495">הצג הגדרות מתקדמות...</translation>
<translation id="7000990526846637657">×œ× × ×ž×¦×ו רשומות היסטוריה</translation>
-<translation id="7001663382399377034">הוספה של נמען</translation>
<translation id="7009986207543992532">ניסית להגיע ×ל <ph name="DOMAIN" />, ×בל השרת הציג ×ישור ×¢× ×ª×§×•×¤×ª תוקף ×רוכה ב×ופן מחשיד. <ph name="BEGIN_LEARN_MORE_LINK" />למידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">â€×™×™×ª×›×Ÿ שלחשבון Google שלך יש ×¡×•×’×™× ××—×¨×™× ×©×œ היסטוריית גלישה ×©×–×ž×™× ×™× ×‘×›×ª×•×‘×ª <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -646,12 +654,15 @@ Del</translation>
<translation id="7088615885725309056">ישן יותר</translation>
<translation id="7090678807593890770">â€×—פש ב-Google ×ת <ph name="LINK" /></translation>
<translation id="7119414471315195487">סגירת כרטיסיות ×ו תוכניות ×חרות</translation>
+<translation id="7129409597930077180">×œ× × ×™×ª×Ÿ לבצע משלוח לכתובת הזו. עליך לבחור כתובת ×חרת.</translation>
+<translation id="7138472120740807366">שיטת מסירה</translation>
<translation id="7139724024395191329">×מירות</translation>
<translation id="7155487117670177674">×”×ª×©×œ×•× ×ינו מ×ובטח</translation>
<translation id="7179921470347911571">הפעל מחדש עכשיו</translation>
<translation id="7180611975245234373">רענן</translation>
<translation id="7182878459783632708">×œ× ×”×•×’×“×¨×” מדיניות</translation>
<translation id="7186367841673660872">דף ×–×” ×ª×•×¨×’× ×ž<ph name="ORIGINAL_LANGUAGE" />ל<ph name="LANGUAGE_LANGUAGE" /></translation>
+<translation id="7192203810768312527">פינוי של <ph name="SIZE" /> מהשטח. תיתכן טעינה ×יטית יותר של ××ª×¨×™× ×ž×¡×•×™×ž×™× ×‘×‘×™×§×•×¨ ×”×‘× ×©×œ×š.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ×œ× ×¤×•×¢×œ בהת×× ×œ×ª×§× ×™ ×”×בטחה.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />מידע נוסף<ph name="END_LINK" /> ×‘× ×•×©× ×–×”.</translation>
@@ -680,7 +691,6 @@ Del</translation>
<translation id="7424977062513257142">דף המוטמע בדף ×ינטרנט ×–×” ×ומר:</translation>
<translation id="7441627299479586546">× ×•×©× ×”×ž×“×™× ×™×•×ª שגוי</translation>
<translation id="7444046173054089907">×”×תר ×”×–×” חסו×</translation>
-<translation id="7444238235002594607">בחר כתובת ל×יסוף כדי לבדוק מהן ×פשרויות ודרישות ×”×יסוף.</translation>
<translation id="7445762425076701745">×œ× × ×™×ª×Ÿ ל×מת לגמרי ×ת הזהות של השרת ש×ליו ×תה מחובר. ×תה מחובר לשרת ב×מצעות ×©× ×©×§×™×™× ×¨×§ ברשת שלך, ושלרשות ××™×©×•×¨×™× ×—×™×¦×•× ×™×ª ×ין דרך ל×מת ×ת בעלותך עליו. מכיוון שחלק מרשויות ×”××™×©×•×¨×™× ×™× ×¤×™×§×• ××™×©×•×¨×™× ×œ×©×ž×•×ª ×לה ×œ×œ× ×§×©×¨, ×ין דרך להבטיח ש×תה מחובר ל×תר המיועד ו×ינך ×’×•×¨× ×ª×•×§×£.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />למידע נוסף<ph name="END_LINK" /> על בעיה זו.</translation>
<translation id="7460163899615895653">הכרטיסיות ×”×חרונות שפתחת ×‘×ž×›×©×™×¨×™× ××—×¨×™× ×ž×•×¦×’×•×ª ×›×ן</translation>
@@ -724,6 +734,7 @@ Del</translation>
<translation id="7755287808199759310">×חד ×ž×”×”×•×¨×™× ×©×œ×š יכול לבטל בשבילך ×ת החסימה</translation>
<translation id="7758069387465995638">ייתכן שחומת ×ש ×ו תוכנת ×נטי-וירוס חסמו ×ת החיבור.</translation>
<translation id="7761701407923456692">×ישור השרת ×ינו תו×× ×œ×›×ª×•×‘×ª ×”×תר.</translation>
+<translation id="7763386264682878361">מנתח מניפסט התשלו×</translation>
<translation id="7764225426217299476">הוסף כתובת</translation>
<translation id="777702478322588152">משטרת מחוז</translation>
<translation id="7791543448312431591">הוסף</translation>
@@ -737,6 +748,7 @@ Del</translation>
<translation id="785549533363645510">×¢× ×–×ת, ×ינך בלתי נר××”. המעבר למצב גלישה בסתר ×œ× ×ž×¡×ª×™×¨ ×ת הגלישה שלך מהמעסיק, מספק ×”×ינטרנט ×ו מה××ª×¨×™× ×©××œ×™×”× ×תה נכנס.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">â€×‘דוק ×ת ×”-CVC ונסה שוב</translation>
+<translation id="79338296614623784">עליך להזין מספר טלפון חוקי</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">×ישור השרת עדיין ×œ× ×‘×ª×•×§×£.</translation>
<translation id="7942349550061667556">×דו×</translation>
@@ -756,6 +768,7 @@ Del</translation>
<translation id="8088680233425245692">הצגת הפריט נכשלה.</translation>
<translation id="8089520772729574115">â€×¤×—ות מ-‎1 MB</translation>
<translation id="8091372947890762290">ההפעלה ממתינה בשרת</translation>
+<translation id="8118489163946903409">×מצעי תשלו×</translation>
<translation id="8131740175452115882">×ישור</translation>
<translation id="8134994873729925007">â€×œ× ניתן ×”×™×” ×œ×ž×¦×•× ×ת <ph name="BEGIN_ABBR" />כתובת ×”-DNS<ph name="END_ABBR" /> של השרת של <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">המחשב עבר למצב שינה.</translation>
@@ -781,6 +794,7 @@ Del</translation>
<translation id="8349305172487531364">סרגל סימניות</translation>
<translation id="8363502534493474904">לכבות ×ת מצב הטיסה</translation>
<translation id="8364627913115013041">×œ× ×ž×•×’×“×¨.</translation>
+<translation id="8368476060205742148">â€×©×™×¨×•×ª×™ Google Play</translation>
<translation id="8380941800586852976">מסוכן</translation>
<translation id="8382348898565613901">הסימניות ש×ליהן נכנסת ל×חרונה מופיעות ×›×ן</translation>
<translation id="8398259832188219207">דוח קריסה הועלה ב-<ph name="UPLOAD_TIME" /></translation>
@@ -789,32 +803,30 @@ Del</translation>
<translation id="8428213095426709021">הגדרות</translation>
<translation id="8433057134996913067">פעולה זו ×ª×•×¦×™× ×ותך מהחשבון ברוב ×”×תרי×.</translation>
<translation id="8437238597147034694">&amp;ביטול העברה</translation>
-<translation id="8456681095658380701">×©× ×œ× ×—×•×§×™</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{כרטיס ×שר××™ ×חד}two{שני כרטיסי ×שר××™}many{# כרטיסי ×שר××™}other{# כרטיסי ×שר××™}}</translation>
<translation id="8483780878231876732">â€×›×“×™ להשתמש ×‘×›×¨×˜×™×¡×™× ×ž×—×©×‘×•×Ÿ Google, היכנס ×ל Chrome</translation>
<translation id="8488350697529856933">חל על</translation>
-<translation id="8492969205326575646">סוג כרטיס ×œ× × ×ª×ž×š</translation>
<translation id="8498891568109133222">ל-<ph name="HOST_NAME" /> נדרש זמן רב מדי להגיב.</translation>
<translation id="852346902619691059">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; מערכת ההפעלה של המכשיר ×œ× ×¡×•×ž×›×ª על ×ישור ×”×בטחה שלו. ייתכן שהסיבה לכך ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף מיירט ×ת החיבור שלך. <ph name="BEGIN_LEARN_MORE_LINK" />למידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">שנת פקיעת התוקף</translation>
<translation id="8543181531796978784">ב×פשרותך <ph name="BEGIN_ERROR_LINK" />לדווח על בעיית זיהוי<ph name="END_ERROR_LINK" /> ×ו, ×× ×תה מבין ×ת סיכוני ×”×בטחה, <ph name="BEGIN_LINK" />להיכנס ל×תר ×”×–×”, ש×ינו מ×ובטח<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">×”×ª×¨×’×•× × ×›×©×œ כיוון ×©×œ× ×”×™×™×ª×” ×פשרות לקבוע ×ת שפת הדף.</translation>
<translation id="8559762987265718583">×œ× × ×™×ª×Ÿ ליצור חיבור פרטי ×ל <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> מפני שהת×ריך והשעה (<ph name="DATE_AND_TIME" />) במכשיר שלך שגויי×.</translation>
-<translation id="8570229484593575558">â€×œ× תתבצע |שמירה של|:#היסטוריית הגלישה#החיפושי×#× ×ª×•× ×™× ×©×œ קובצי Cookie</translation>
<translation id="8571890674111243710">×ž×ª×¨×’× ×“×£ ל<ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">ייתכן שהפעילות |שלך תוצג| בפני:#××ª×¨×™× ×©×‘×™×§×¨×ª בה×#המעסיק שלך#ספק ×”×ינטרנט שלך</translation>
<translation id="858637041960032120">הוסף מספר טלפון
</translation>
<translation id="859285277496340001">×”×ישור ×ינו מציין מנגנון הבודק ×× ×”×•× × ×©×œ×œ.</translation>
<translation id="8620436878122366504">×”×”×•×¨×™× ×©×œ×š עדיין ×œ× ×ישרו ×–×ת</translation>
<translation id="8647750283161643317">×פס הכל לברירת המחדל</translation>
<translation id="8703575177326907206">ההתחברות שלך ×ל <ph name="DOMAIN" /> ××™× ×” מוצפנת.</translation>
+<translation id="8718314106902482036">×”×ª×©×œ×•× ×œ× ×”×•×©×œ×</translation>
<translation id="8725066075913043281">נסה שוב</translation>
<translation id="8728672262656704056">עברת למצב גלישה בסתר</translation>
<translation id="8730621377337864115">בוצע</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="8759274551635299824">פג תוקפו של הכרטיס</translation>
<translation id="8790007591277257123">&amp;ביצוע מחדש של מחיקה</translation>
-<translation id="8798099450830957504">ברירת מחדל</translation>
<translation id="8800988563907321413">×›×ן מופיעות הצעות עבורך למקומות קרובי×</translation>
<translation id="8820817407110198400">סימניות</translation>
<translation id="883848425547221593">סימניות ×חרות</translation>
@@ -824,6 +836,7 @@ Del</translation>
<translation id="8866481888320382733">שגי××” בניתוח הגדרות המדיניות</translation>
<translation id="8866959479196209191">דף ×–×” ×ומר:</translation>
<translation id="8870413625673593573">נסגרו ל×חרונה</translation>
+<translation id="8874824191258364635">עליך להזין מספר כרטיס חוקי</translation>
<translation id="8876793034577346603">ניתוח תצורת הרשת נכשל.</translation>
<translation id="8877192140621905067">ברגע שת×שר, פרטי הכרטיס שלך ישותפו ×¢× ×”×תר ×”×–×”</translation>
<translation id="8889402386540077796">גוון</translation>
@@ -833,7 +846,6 @@ Del</translation>
<translation id="8931333241327730545">â€×”×× ×‘×¨×¦×•× ×š לשמור ×ת הכרטיס ×”×–×” בחשבון Google שלך?</translation>
<translation id="8932102934695377596">השעון שלך מ×חר</translation>
<translation id="8954894007019320973">(המשך)</translation>
-<translation id="895548565263634352">×§×¨× ×™×“×™×¢×” של <ph name="ARTICLE_PUBLISHER" /> ו-<ph name="OTHER_ARTICLE_COUNT" /> ידיעות ×חרות</translation>
<translation id="8971063699422889582">פג תוקפו של ×ישור השרת.</translation>
<translation id="8986494364107987395">â€×©×œ×— ל-Google דוחות קריסה וסטטיסטיקת שימוש ב×ופן ×וטומטי</translation>
<translation id="8987927404178983737">חודש</translation>
@@ -851,7 +863,6 @@ Del</translation>
<translation id="9068849894565669697">בחירת צבע</translation>
<translation id="9076283476770535406">ייתכן שה×תר מכיל תוכן למבוגרי×</translation>
<translation id="9078964945751709336">נדרש מידע נוסף</translation>
-<translation id="9094175695478007090">×œ× × ×™×ª×Ÿ להפעיל ×ת ×פליקציית התשלו×.</translation>
<translation id="9103872766612412690">â€×”×תר <ph name="SITE" /> משתמש בדרך כלל בהצפנה כדי להגן על המידע שלך. ×›×שר Chromium ניסה ×”×¤×¢× ×œ×”×ª×—×‘×¨ ל-<ph name="SITE" />, ×”×תר שלח חזרה ××™×©×•×¨×™× ×—×¨×™×’×™× ×•×©×’×•×™×™×. ייתכן שתוקף מנסה להתחזות ל×תר <ph name="SITE" />, ×ו שמסך כניסה ל-Wi-Fi הפריע לחיבור. המידע שלך עדיין מ×ובטח מכיוון ש-Chromium הפסיק ×ת החיבור לפני חילופי הנתוני×.</translation>
<translation id="9137013805542155359">הצג מקור</translation>
<translation id="9137248913990643158">â€×”יכנס לחשבונך ב-Chrome לפני שתשתמש ב×פליקציה הזו.</translation>
diff --git a/chromium/components/strings/components_strings_ja.xtb b/chromium/components/strings/components_strings_ja.xtb
index 9bc678f9475..faad5f9d0ff 100644
--- a/chromium/components/strings/components_strings_ja.xtb
+++ b/chromium/components/strings/components_strings_ja.xtb
@@ -3,12 +3,13 @@
<translationbundle lang="ja">
<translation id="1008557486741366299">後ã§</translation>
<translation id="1015730422737071372">詳細を報告ã™ã‚‹</translation>
+<translation id="1021110881106174305">利用å¯èƒ½ãªã‚«ãƒ¼ãƒ‰</translation>
<translation id="1032854598605920125">時計回りã«å›žè»¢</translation>
<translation id="1038842779957582377">ä¸æ˜Žãªåå‰</translation>
<translation id="1050038467049342496">ä»–ã®ã‚¢ãƒ—リを終了ã™ã‚‹</translation>
<translation id="1053591932240354961"><ph name="SITE" /> ã‹ã‚‰ã€Google Chrome ã§å‡¦ç†ã§ããªã„æš—å·åŒ–ã•ã‚ŒãŸèªè¨¼æƒ…å ±ãŒè¿”ã•ã‚ŒãŸãŸã‚ã€ç¾åœ¨ã“ã®ã‚¦ã‚§ãƒ–サイトã«ã¯ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“。通常ã€ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ エラーやä¸æ­£ãªæ“作ã¯ä¸€æ™‚çš„ãªã‚‚ã®ã§ã™ã€‚å°‘ã—時間をãŠãã¨ã€ãƒšãƒ¼ã‚¸ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãるよã†ã«ãªã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1055184225775184556">追加ã®å–り消ã—(&amp;U)</translation>
-<translation id="10614374240317010">未ä¿å­˜</translation>
+<translation id="10614374240317010">常ã«ä¿å­˜ã—ãªã„</translation>
<translation id="106701514854093668">パソコンã®ãƒ–ックマーク</translation>
<translation id="1074497978438210769">ä¿è­·ã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
<translation id="1080116354587839789">ウィンドウ幅ã«åˆã‚ã›ã‚‹</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">値をéžè¡¨ç¤º</translation>
<translation id="1228893227497259893">エンティティ識別å­ãŒæ­£ã—ãã‚ã‚Šã¾ã›ã‚“</translation>
<translation id="1232569758102978740">無題</translation>
+<translation id="1263231323834454256">リーディング リスト</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> ã«ã‚¯ãƒ©ãƒƒã‚·ãƒ¥ レãƒãƒ¼ãƒˆãŒä½œæˆã•ã‚Œã¾ã—ãŸï¼ˆã¾ã ã‚¢ãƒƒãƒ—ロードã•ã‚Œã¦ãŠã‚‰ãšã€ç„¡è¦–ã®æŒ‡å®šã‚‚ã‚ã‚Šã¾ã›ã‚“)</translation>
<translation id="1285320974508926690">ã“ã®ã‚µã‚¤ãƒˆã¯ç¿»è¨³ã—ãªã„</translation>
<translation id="129553762522093515">最近閉ã˜ãŸã‚¿ãƒ–</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromium ã®è‡ªå‹•å…¥åŠ›è¨­å®š...</translation>
<translation id="1374468813861204354">ヒント</translation>
<translation id="1375198122581997741">ãƒãƒ¼ã‚¸ãƒ§ãƒ³æƒ…å ±</translation>
+<translation id="1377321085342047638">カード番å·</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> ã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ãŒé€ä¿¡ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸã€‚</translation>
<translation id="1407135791313364759">ã™ã¹ã¦é–‹ã</translation>
<translation id="1413809658975081374">プライãƒã‚·ãƒ¼ エラー</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">履歴</translation>
<translation id="1645368109819982629">サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„プロトコルã§ã™</translation>
<translation id="1656489000284462475">引å–</translation>
+<translation id="1663943134801823270">Chrome ã«ä¿å­˜ã•ã‚Œã¦ã„るクレジット カードã¨ä½æ‰€ã§ã™ã€‚[<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />] ã§ç®¡ç†ã§ãã¾ã™ã€‚</translation>
<translation id="1676269943528358898"><ph name="SITE" /> ã§ã¯é€šå¸¸ã€æš—å·åŒ–ã—ã¦æƒ…報をä¿è­·ã—ã¦ã„ã¾ã™ã€‚今回ã€Google Chrome ã‹ã‚‰ <ph name="SITE" /> ã¸ã®æŽ¥ç¶šè©¦è¡Œæ™‚ã«ã€ã“ã®ã‚¦ã‚§ãƒ–サイトã‹ã‚‰ã„ã¤ã‚‚ã¨ã¯ç•°ãªã‚‹èª¤ã£ãŸèªè¨¼æƒ…å ±ãŒè¿”ã•ã‚Œã¾ã—ãŸã€‚悪æ„ã®ã‚るユーザー㌠<ph name="SITE" /> ã«ãªã‚Šã™ã¾ãã†ã¨ã—ã¦ã„ã‚‹ã‹ã€Wi-Fi ログイン画é¢ã§æŽ¥ç¶šãŒä¸­æ–­ã•ã‚ŒãŸå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚データã®ã‚„ã‚Šå–ã‚ŠãŒè¡Œã‚れるå‰ã« Google Chrome ã«ã‚ˆã£ã¦æŽ¥ç¶šãŒåœæ­¢ã•ã‚ŒãŸãŸã‚ã€æƒ…å ±ã¯å¼•ã続ãä¿è­·ã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
<translation id="168328519870909584"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ã§ã¯ç¾åœ¨ã€æ‚ªæ„ã®ã‚るユーザーãŒã€ãŠä½¿ã„ã®ãƒ‡ãƒã‚¤ã‚¹ã«å±é™ºãªã‚¢ãƒ—リ(写真ã€ãƒ‘スワードã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã€ã‚¯ãƒ¬ã‚¸ãƒƒãƒˆ カード番å·ãªã©ã‚’ç›—ã¿å–ã‚‹ã‹å‰Šé™¤ã™ã‚‹ã‚¢ãƒ—リ)をインストールã—よã†ã¨ã—ã¦ã„ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="168841957122794586">サーãƒãƒ¼è¨¼æ˜Žæ›¸ã«è„†å¼±ãªæš—å·éµãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">ã“ã®ã‚µã‚¤ãƒˆã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã«ã¯ <ph name="NAME" /> ã•ã‚“ã®è¨±å¯ãŒå¿…è¦ã§ã™</translation>
+<translation id="1721424275792716183">* 必須欄ã§ã™</translation>
<translation id="1728677426644403582">ウェブページã®ã‚½ãƒ¼ã‚¹ã‚’表示ã—ã¦ã„ã¾ã™</translation>
+<translation id="173080396488393970">ã“ã®ç¨®é¡žã®ã‚«ãƒ¼ãƒ‰ã¯ã”利用ã„ãŸã ã‘ã¾ã›ã‚“</translation>
<translation id="1734864079702812349">AMEX</translation>
<translation id="1734878702283171397">システム管ç†è€…ã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。</translation>
+<translation id="1740951997222943430">有効期é™ï¼ˆæœˆï¼‰ã‚’æ­£ã—ã„å½¢å¼ã§å…¥åŠ›ã—ã¦ãã ã•ã„</translation>
<translation id="1745358365027406341">後ã§ãƒšãƒ¼ã‚¸ã‚’ダウンロード</translation>
<translation id="17513872634828108">é–‹ã„ã¦ã„るタブ</translation>
<translation id="1753706481035618306">ページ番å·</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">åŒæœŸãƒ‘スフレーズを更新ã—ã¦ãã ã•ã„。</translation>
<translation id="1787142507584202372">最近開ã„ãŸã‚¿ãƒ–ãŒã“ã“ã«è¡¨ç¤ºã•ã‚Œã¾ã™</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">é…é€æ–¹æ³•ã‚„è¦ä»¶ã‚’確èªã™ã‚‹ã«ã¯ã€é…é€å…ˆä½æ‰€ã‚’é¸æŠžã—ã¾ã™ã€‚</translation>
+<translation id="1803264062614276815">カードå義人</translation>
<translation id="1803678881841855883"><ph name="SITE" /> ã§ã¯æœ€è¿‘ã€Google セーフ ブラウジングã«ã‚ˆã‚Šã€<ph name="BEGIN_LINK" />ä¸æ­£ãªã‚½ãƒ•ãƒˆã‚¦ã‚§ã‚¢ãŒæ¤œå‡º<ph name="END_LINK" />ã•ã‚Œã¾ã—ãŸã€‚通常ã¯å®‰å…¨ãªã‚¦ã‚§ãƒ–サイトã§ã‚ã£ã¦ã‚‚ã€ä¸æ­£ãªã‚½ãƒ•ãƒˆã‚¦ã‚§ã‚¢ã«æ„ŸæŸ“ã—ã¦ã„ã‚‹å ´åˆãŒã‚ã‚Šã¾ã™ã€‚今回ã®æ‚ªæ„ã®ã‚るコンテンツã¯ã€ä¸æ­£ãªã‚½ãƒ•ãƒˆã‚¦ã‚§ã‚¢ã®æ—¢çŸ¥ã®é…布元ã§ã‚る「<ph name="SUBRESOURCE_HOST" />ã€ã‹ã‚‰é€ã‚‰ã‚Œã¦ãã¾ã—ãŸã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1806541873155184440">追加日: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">無効ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆã¾ãŸã¯ãƒªã‚¯ã‚¨ã‚¹ãƒˆ パラメータã§ã™</translation>
<translation id="1826516787628120939">確èªä¸­</translation>
<translation id="1834321415901700177">ã“ã®ã‚µã‚¤ãƒˆã«ã¯æœ‰å®³ãªãƒ—ログラムãŒå«ã¾ã‚Œã¦ã„ã¾ã™</translation>
<translation id="1842969606798536927">ãŠæ”¯æ‰•ã„</translation>
-<translation id="1864455488461349376">é…é€æ–¹æ³•</translation>
<translation id="1871208020102129563">プロキシ㯠.pac スクリプト URL ã§ã¯ãªã固定プロキシ サーãƒãƒ¼ã‚’使用ã™ã‚‹ã‚ˆã†ã«è¨­å®šã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
<translation id="1871284979644508959">必須フィールド</translation>
<translation id="187918866476621466">起動ページを開ã</translation>
<translation id="1883255238294161206">リストを折りãŸãŸã‚€</translation>
<translation id="1898423065542865115">フィルタ</translation>
<translation id="194030505837763158"><ph name="LINK" /> ã«ç§»å‹•ã—ã¾ã™</translation>
-<translation id="1946821392246652573">利用å¯èƒ½ãªã‚«ãƒ¼ãƒ‰</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> ã®ãƒ–ックマーク</translation>
<translation id="1973335181906896915">シリアル化エラーã§ã™</translation>
<translation id="1974060860693918893">詳細設定</translation>
<translation id="1978555033938440688">ファームウェアã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³</translation>
+<translation id="1995859865337580572">CVC を確èªã—ã¦ãã ã•ã„</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{他 1 個}other{他 # 個}}</translation>
-<translation id="2020194265157481222">å義人åãŒå¿…è¦ã§ã™</translation>
<translation id="2025186561304664664">プロキシã¯è‡ªå‹•è¨­å®šã«ãªã£ã¦ã„ã¾ã™ã€‚</translation>
<translation id="2030481566774242610">ã‚‚ã—ã‹ã—ã¦: <ph name="LINK" /></translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />プロキシã¨ãƒ•ã‚¡ã‚¤ã‚¢ã‚¦ã‚©ãƒ¼ãƒ«ã‚’確èªã™ã‚‹<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">今日</translation>
<translation id="2154054054215849342">ãŠä½¿ã„ã®ãƒ‰ãƒ¡ã‚¤ãƒ³ã§ã¯åŒæœŸæ©Ÿèƒ½ã‚’ã”利用ã„ãŸã ã‘ã¾ã›ã‚“</translation>
<translation id="2154484045852737596">カードを編集</translation>
-<translation id="2156993118928861787">ä½æ‰€ãŒç„¡åŠ¹ã§ã™</translation>
<translation id="2166049586286450108">ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã¸ã®ç®¡ç†è€…アクセス</translation>
<translation id="2166378884831602661">ã“ã®ã‚µã‚¤ãƒˆã¯å®‰å…¨ã«æŽ¥ç¶šã§ãã¾ã›ã‚“</translation>
<translation id="2181821976797666341">ãƒãƒªã‚·ãƒ¼</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 件ã®ã‚¢ãƒ‰ãƒ¬ã‚¹}other{# 件ã®ã‚¢ãƒ‰ãƒ¬ã‚¹}}</translation>
+<translation id="2202020181578195191">有効期é™ï¼ˆå¹´ï¼‰ã‚’æ­£ã—ã„å½¢å¼ã§å…¥åŠ›ã—ã¦ãã ã•ã„</translation>
<translation id="2212735316055980242">ãƒãƒªã‚·ãƒ¼ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“</translation>
<translation id="2213606439339815911">エントリをå–å¾—ã—ã¦ã„ã¾ã™...</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />診断アプリ<ph name="END_LINK" />を使用ã—ã¦æŽ¥ç¶šã‚’修正ã—ã¦ãã ã•ã„</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">インターãƒãƒƒãƒˆ アクセスãŒãƒ–ロックã•ã‚Œã¦ã„ã¾ã™</translation>
<translation id="230155334948463882">カード情報を更新</translation>
<translation id="2305919008529760154">ã“ã®ã‚µãƒ¼ãƒãƒ¼ãŒ <ph name="DOMAIN" /> ã§ã‚ã‚‹ã“ã¨ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨¼æ˜Žæ›¸ã¯ä¸æ­£ã«ç™ºè¡Œã•ã‚ŒãŸã‚‚ã®ã§ã‚ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚原因ã¨ã—ã¦ã€è¨­å®šãŒä¸é©åˆ‡ã§ã‚ã‚‹ã‹ã€æ‚ªæ„ã®ã‚るユーザーãŒæŽ¥ç¶šã‚’妨害ã—ã¦ã„ã‚‹ã“ã¨ãŒè€ƒãˆã‚‰ã‚Œã¾ã™ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="230697611605700222">Google アカウント(<ph name="ACCOUNT_EMAIL" />)㨠Chrome ã®ã‚«ãƒ¼ãƒ‰ã¨ä½æ‰€ã®ã‚ªãƒ—ションã§ã™ã€‚ã“れらã®ã‚ªãƒ—ション㯠[<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />] ã§ç®¡ç†ã§ãã¾ã™ã€‚</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> ã«ã¯ãƒ¦ãƒ¼ã‚¶ãƒ¼åã¨ãƒ‘スワードãŒå¿…è¦ã§ã™ã€‚</translation>
<translation id="2318774815570432836"><ph name="SITE" /> ã§ã¯ HSTS ãŒä½¿ç”¨ã•ã‚Œã¦ã„ã‚‹ãŸã‚ã€ç¾åœ¨ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“。通常ã€ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ エラーやä¸æ­£ãªæ“作ã¯ä¸€æ™‚çš„ãªã‚‚ã®ã§ã™ã€‚å°‘ã—時間をãŠãã¨ã€ã¾ãŸãƒšãƒ¼ã‚¸ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãるよã†ã«ãªã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2354001756790975382">ãã®ä»–ã®ãƒ–ックマーク</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">ä¼æ¥­ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆ</translation>
<translation id="2386255080630008482">サーãƒãƒ¼ã®è¨¼æ˜Žæ›¸ã¯å–り消ã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
<translation id="2392959068659972793">値ãŒè¨­å®šã•ã‚Œã¦ã„ãªã„ãƒãƒªã‚·ãƒ¼ã‚’表示ã™ã‚‹</translation>
+<translation id="239429038616798445">ã“ã®é…é€æ–¹æ³•ã¯ã”利用ã„ãŸã ã‘ã¾ã›ã‚“。別ã®æ–¹æ³•ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="2396249848217231973">削除ã®å–り消ã—(&amp;U)</translation>
<translation id="2460160116472764928"><ph name="SITE" /> ã§ã¯æœ€è¿‘ã€Google セーフ ブラウジングã«ã‚ˆã‚Šã€<ph name="BEGIN_LINK" />ä¸æ­£ãªã‚½ãƒ•ãƒˆã‚¦ã‚§ã‚¢ãŒæ¤œå‡º<ph name="END_LINK" />ã•ã‚Œã¾ã—ãŸã€‚通常ã¯å®‰å…¨ãªã‚¦ã‚§ãƒ–サイトã§ã‚ã£ã¦ã‚‚ã€ä¸æ­£ãªã‚½ãƒ•ãƒˆã‚¦ã‚§ã‚¢ã«æ„ŸæŸ“ã—ã¦ã„ã‚‹å ´åˆãŒã‚ã‚Šã¾ã™ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2463739503403862330">入力ã™ã‚‹</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯è¨ºæ–­ãƒ„ールを実行ã™ã‚‹<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">検索 URL ãŒç„¡åŠ¹ã§ã™ã€‚</translation>
<translation id="2491120439723279231">サーãƒãƒ¼ã®è¨¼æ˜Žæ›¸ã«ã‚¨ãƒ©ãƒ¼ãŒã‚ã‚Šã¾ã™ã€‚</translation>
-<translation id="24943777258388405">無効ãªé›»è©±ç•ªå·ã§ã™</translation>
<translation id="2495083838625180221">JSON パーサー</translation>
<translation id="2495093607237746763">ãƒã‚§ãƒƒã‚¯ãƒœãƒƒã‚¯ã‚¹ã‚’オンã«ã™ã‚‹ã¨ã€Chromium ãŒã‚«ãƒ¼ãƒ‰æƒ…報をã“ã®ç«¯æœ«ã«ä¿å­˜ã™ã‚‹ãŸã‚フォームã«ã™ã°ã‚„ã入力ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚</translation>
<translation id="2498091847651709837">æ–°ã—ã„カードをスキャン</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> ã‹ã‚‰ç„¡åŠ¹ãªå¿œç­”ãŒé€ä¿¡ã•ã‚Œã¾ã—ãŸã€‚</translation>
<translation id="2552545117464357659">æ–°ã—ã„</translation>
<translation id="2556876185419854533">編集ã®å–り消ã—(&amp;U)</translation>
+<translation id="2587730715158995865">公開元: <ph name="ARTICLE_PUBLISHER" />。ã“ã®è¨˜äº‹ã¨ä»– <ph name="OTHER_ARTICLE_COUNT" /> 件ã®è¨˜äº‹ã‚’読むã“ã¨ãŒã§ãã¾ã™ã€‚</translation>
<translation id="2587841377698384444">Directory API ID:</translation>
<translation id="2597378329261239068">ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¯ãƒ‘スワードã§ä¿è­·ã•ã‚Œã¦ã„ã¾ã™ã€‚パスワードを入力ã—ã¦ãã ã•ã„。</translation>
<translation id="2609632851001447353">ãƒãƒªã‚¨ãƒ¼ã‚·ãƒ§ãƒ³</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />接続診断ツールを実行ã™ã‚‹<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">é¸æŠžã—ãŸã‚¢ã‚¤ãƒ†ãƒ ã‚’削除</translation>
+<translation id="277133753123645258">é…é€æ–¹æ³•</translation>
<translation id="277499241957683684">デãƒã‚¤ã‚¹ レコードãŒã‚ã‚Šã¾ã›ã‚“</translation>
<translation id="2784949926578158345">接続ãŒãƒªã‚»ãƒƒãƒˆã•ã‚Œã¾ã—ãŸã€‚</translation>
<translation id="2794233252405721443">サイトãŒãƒ–ロックã•ã‚Œã¦ã„ã¾ã™</translation>
-<translation id="2812680587231492111">ãã®å—ã‘å–り方法ã¯ã”利用ã„ãŸã ã‘ã¾ã›ã‚“。別ã®æ–¹æ³•ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="2824775600643448204">アドレス検索ãƒãƒ¼</translation>
<translation id="2826760142808435982">接続㯠<ph name="CIPHER" /> を使用ã—ã¦æš—å·åŒ–ãŠã‚ˆã³èªè¨¼ã•ã‚Œã¦ãŠã‚Šã€<ph name="KX" /> ãŒéµäº¤æ›ãƒ¡ã‚«ãƒ‹ã‚ºãƒ ã¨ã—ã¦ä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
<translation id="2835170189407361413">フォームをクリア</translation>
-<translation id="2849041323157393173">ãã®é…é”方法ã¯ã”利用ã„ãŸã ã‘ã¾ã›ã‚“。別ã®æ–¹æ³•ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="2889159643044928134">å†èª­ã¿è¾¼ã¿ã‚’中止</translation>
<translation id="2900469785430194048">ã“ã®ã‚¦ã‚§ãƒ–ページを表示ã—よã†ã¨ã—ã¾ã—ãŸãŒã€Google Chrome ã®ãƒ¡ãƒ¢ãƒªãŒä¸è¶³ã—ã¦ã„ã¾ã™ã€‚</translation>
<translation id="2909946352844186028">ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®å¤‰æ›´ãŒæ¤œå‡ºã•ã‚Œã¾ã—ãŸã€‚</translation>
<translation id="2916038427272391327">ä»–ã®ãƒ—ログラムを終了ã™ã‚‹</translation>
<translation id="2922350208395188000">サーãƒãƒ¼ã®è¨¼æ˜Žæ›¸ã‚’確èªã§ãã¾ã›ã‚“。</translation>
+<translation id="2928905813689894207">請求先ä½æ‰€</translation>
<translation id="2948083400971632585">接続用ã«è¨­å®šã•ã‚ŒãŸãƒ—ロキシã¯ã€è¨­å®šãƒšãƒ¼ã‚¸ã§ç„¡åŠ¹ã«ã§ãã¾ã™ã€‚</translation>
<translation id="2955913368246107853">検索ãƒãƒ¼ã‚’é–‰ã˜ã‚‹</translation>
<translation id="2958431318199492670">ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯è¨­å®šãŒ ONC 標準ã«æº–æ‹ ã—ã¦ã„ã¾ã›ã‚“。設定ã®ä¸€éƒ¨ãŒã‚¤ãƒ³ãƒãƒ¼ãƒˆã•ã‚Œãªã„å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">安全ãªæŽ¥ç¶šã‚’確立ã™ã‚‹ã«ã¯ã€æ™‚計ãŒæ­£ã—ã設定ã•ã‚Œã¦ã„ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ã“ã‚Œã¯ã€ã‚¦ã‚§ãƒ–サイトãŒè‡ªèº«ã‚’証明ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã™ã‚‹è¨¼æ˜Žæ›¸ã«ã¯æœ‰åŠ¹æœŸé™ãŒã‚ã‚‹ãŸã‚ã§ã™ã€‚デãƒã‚¤ã‚¹ã®æ™‚計ãŒæ­£ã—ããªã„ãŸã‚ã€Google Chrome ã§ã“れらã®è¨¼æ˜Žæ›¸ã‚’確èªã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。</translation>
<translation id="2972581237482394796">ã‚„ã‚Šç›´ã—(&amp;R)</translation>
<translation id="2985306909656435243">有効ã«ã™ã‚‹ã¨ã€Chromium ãŒã‚«ãƒ¼ãƒ‰æƒ…報をã“ã®ç«¯æœ«ã«ä¿å­˜ã™ã‚‹ãŸã‚フォームã«ã™ã°ã‚„ã入力ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚</translation>
+<translation id="2985398929374701810">有効ãªä½æ‰€ã‚’入力ã—ã¦ãã ã•ã„</translation>
+<translation id="2986368408720340940">ã“ã®å—ã‘å–り方法ã¯ã”利用ã„ãŸã ã‘ã¾ã›ã‚“。別ã®æ–¹æ³•ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="2991174974383378012">ウェブサイトã¨ã®å…±æœ‰</translation>
<translation id="3005723025932146533">ä¿å­˜æ¸ˆã¿ã®ã‚³ãƒ”ーを表示</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> ã® CVC を入力ã—ã¾ã™ã€‚確èªã‚’è¡Œã†ã¨ã€ã‚«ãƒ¼ãƒ‰ã®è©³ç´°ãŒã“ã®ã‚µã‚¤ãƒˆã¨å…±æœ‰ã•ã‚Œã¾ã™ã€‚</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{åŒæœŸãƒ‡ãƒã‚¤ã‚¹ã§ 1 件以上ã®ã‚¢ã‚¤ãƒ†ãƒ }=1{1 件ã®ã‚¢ã‚¤ãƒ†ãƒ ï¼ˆåŒæœŸãƒ‡ãƒã‚¤ã‚¹ã§ã¯ãれ以上ã®ã‚¢ã‚¤ãƒ†ãƒ ï¼‰}other{# 件ã®ã‚¢ã‚¤ãƒ†ãƒ ï¼ˆåŒæœŸãƒ‡ãƒã‚¤ã‚¹ã§ã¯ãれ以上ã®ã‚¢ã‚¤ãƒ†ãƒ ï¼‰}}</translation>
<translation id="3041612393474885105">証明書情報</translation>
<translation id="3063697135517575841">Chrome ã§ã‚«ãƒ¼ãƒ‰ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã—ã°ã‚‰ãã—ã¦ã‹ã‚‰ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。</translation>
+<translation id="3064966200440839136">外部アプリケーションを経由ã—ãŸãŠæ”¯æ‰•ã„ã®å‡¦ç†ã«é€²ã‚€ãŸã‚ã€ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ モードを解除ã—ã¾ã™ã€‚続行ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="3093245981617870298">ç¾åœ¨ã‚ªãƒ•ãƒ©ã‚¤ãƒ³ã§ã™ã€‚</translation>
<translation id="3105172416063519923">アセット ID:</translation>
<translation id="3109728660330352905">ã“ã®ãƒšãƒ¼ã‚¸ã‚’表示ã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“。</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />接続診断ツールを実行ã—ã¦ã¿ã¦ãã ã•ã„<ph name="END_LINK" />。</translation>
<translation id="3145945101586104090">応答をデコードã§ãã¾ã›ã‚“ã§ã—ãŸ</translation>
-<translation id="3149891296864842641">é…é€ã‚ªãƒ—ション</translation>
<translation id="3150653042067488994">一時的ãªã‚µãƒ¼ãƒãƒ¼ エラーã§ã™</translation>
+<translation id="3154506275960390542">ã“ã®ãƒšãƒ¼ã‚¸ã®ãƒ•ã‚©ãƒ¼ãƒ ã¯å®‰å…¨ã«é€ä¿¡ã•ã‚Œãªã„å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚é€ä¿¡ä¸­ã«ãƒ‡ãƒ¼ã‚¿ãŒä»–者ã«é–²è¦§ã•ã‚ŒãŸã‚Šã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã‚Šãƒ‡ãƒ¼ã‚¿ãŒå¤‰æ›´ã•ã‚Œã¦ã‚µãƒ¼ãƒãƒ¼ã«åˆ¥ã®å†…容ãŒå±Šã„ãŸã‚Šã™ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="3157931365184549694">復元</translation>
<translation id="3167968892399408617">シークレット タブã§è¡¨ç¤ºã—ãŸãƒšãƒ¼ã‚¸ã®è¨˜éŒ²ã¯ã€ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ タブをã™ã¹ã¦é–‰ã˜ãŸå¾Œã€ãƒ–ラウザã®å±¥æ­´ã€Cookie ã®ä¿å­˜å ´æ‰€ã€æ¤œç´¢å±¥æ­´ã‹ã‚‰æ¶ˆåŽ»ã•ã‚Œã¾ã™ã€‚ãŸã ã—ã€ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚„作æˆã—ãŸãƒ–ックマークã¯ä¿å­˜ã•ã‚Œã¾ã™ã€‚</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">ã“ã®ã‚µã‚¤ãƒˆã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ãŸã‚ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’ <ph name="NAME" /> ã«é€ä¿¡ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。</translation>
<translation id="3355823806454867987">プロキシ設定ã®å¤‰æ›´...</translation>
<translation id="3369192424181595722">時計ã®ã‚¨ãƒ©ãƒ¼</translation>
+<translation id="337311366426640088">ä»– <ph name="ITEM_COUNT" /> 件ã®ã‚¢ã‚¤ãƒ†ãƒ ...</translation>
<translation id="337363190475750230">プロビジョニングãŒè§£é™¤ã•ã‚Œã¾ã—ãŸ</translation>
<translation id="3377188786107721145">ãƒãƒªã‚·ãƒ¼è§£æžã‚¨ãƒ©ãƒ¼ã§ã™</translation>
<translation id="3380365263193509176">ä¸æ˜Žãªã‚¨ãƒ©ãƒ¼</translation>
<translation id="3380864720620200369">クライアント ID:</translation>
<translation id="3391030046425686457">é…é€å…ˆä½æ‰€</translation>
+<translation id="3395827396354264108">å—ã‘å–り方法</translation>
<translation id="340013220407300675">攻撃者ãŒã€<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 上ã®ã‚ãªãŸã®æƒ…報(パスワードã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã€ã‚¯ãƒ¬ã‚¸ãƒƒãƒˆ カード情報ãªã©ï¼‰ã‚’ä¸æ­£ã«å–å¾—ã—よã†ã¨ã—ã¦ã„ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="3422248202833853650">メモリを解放ã™ã‚‹ãŸã‚ã«ã€ä»–ã®ãƒ—ログラムを終了ã—ã¦ã¿ã¦ãã ã•ã„。</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> ã¯ç¾åœ¨ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“。</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">å–å¾—é–“éš”:</translation>
<translation id="3462200631372590220">詳細情報を表示ã—ãªã„</translation>
+<translation id="3467763166455606212">カードå義人ã¯å¿…é ˆã§ã™</translation>
+<translation id="3478058380795961209">有効期é™ï¼ˆæœˆï¼‰</translation>
<translation id="3479539252931486093">想定外ã®å‹•ä½œã§ã‚ã‚‹å ´åˆã¯ã€<ph name="BEGIN_LINK" />å•é¡Œã‚’報告<ph name="END_LINK" />ã—ã¦ãã ã•ã„。</translation>
<translation id="3479552764303398839">後ã§</translation>
<translation id="348000606199325318">クラッシュ ID <ph name="CRASH_LOCAL_ID" />(サーãƒãƒ¼ ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">ç¾åœ¨ã€ä¿è­·è€…ã«ãŸãšã­ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。もã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。</translation>
<translation id="3528171143076753409">サーãƒãƒ¼ã®è¨¼æ˜Žæ›¸ã‚’ä¿¡é ¼ã§ãã¾ã›ã‚“。</translation>
-<translation id="3538531656504267329">有効期é™ï¼ˆå¹´ï¼‰ãŒç„¡åŠ¹ã§ã™</translation>
<translation id="3539171420378717834">ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã«ã“ã®ã‚«ãƒ¼ãƒ‰æƒ…å ±ã®ã‚³ãƒ”ーをä¿å­˜ã™ã‚‹</translation>
<translation id="3542684924769048008">次ã®ãƒ‘スワードを使用:</translation>
<translation id="3549644494707163724">åŒæœŸãƒ‘スフレーズã§åŒæœŸãƒ‡ãƒ¼ã‚¿ã‚’ã™ã¹ã¦æš—å·åŒ–ã™ã‚‹</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">詳細をéžè¡¨ç¤º</translation>
<translation id="3587482841069643663">ã™ã¹ã¦</translation>
<translation id="3600246354004376029"><ph name="TITLE" />ã€<ph name="DOMAIN" />ã€<ph name="TIME" /></translation>
+<translation id="3615877443314183785">有効期é™ï¼ˆæ—¥ï¼‰ã‚’入力ã—ã¦ãã ã•ã„</translation>
<translation id="36224234498066874">閲覧履歴を消去...</translation>
<translation id="362276910939193118">全履歴を表示</translation>
<translation id="3623476034248543066">値を表示</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">パスワード:</translation>
<translation id="3696411085566228381">ãªã—</translation>
<translation id="3704609568417268905"><ph name="TIME" />ã€<ph name="TITLE" />(<ph name="DOMAIN" />)を<ph name="BOOKMARKED" /></translation>
-<translation id="3706658020782046159">é…é€æ–¹æ³•ã‚„è¦ä»¶ã‚’確èªã™ã‚‹ã«ã¯ã€é…é€å…ˆä½æ‰€ã‚’é¸æŠžã—ã¾ã™ã€‚</translation>
<translation id="370665806235115550">読ã¿è¾¼ã‚“ã§ã„ã¾ã™...</translation>
<translation id="3712624925041724820">ライセンスを使ã„切りã¾ã—ãŸ</translation>
<translation id="3714780639079136834">モãƒã‚¤ãƒ«ãƒ‡ãƒ¼ã‚¿ã¾ãŸã¯ Wi-Fi を有効ã«ã™ã‚‹</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">コピーã—ãŸãƒªãƒ³ã‚¯</translation>
<translation id="375403751935624634">サーãƒãƒ¼ エラーã®ãŸã‚翻訳ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚</translation>
<translation id="3759461132968374835">最近発生ã—ãŸéšœå®³ã¯ã‚ã‚Šã¾ã›ã‚“。障害レãƒãƒ¼ãƒˆãŒç„¡åŠ¹ã«ãªã£ã¦ã„ã‚‹ã¨ãã«ç™ºç”Ÿã—ãŸéšœå®³ã¯ã€ã“ã“ã«ã¯è¡¨ç¤ºã•ã‚Œã¾ã›ã‚“。</translation>
+<translation id="3787705759683870569">有効期é™: <ph name="EXPIRATION_MONTH" /> / <ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">プロキシ サーãƒãƒ¼ã‚’使用ã—ã¦ã„ã‚‹å ´åˆ...</translation>
<translation id="3828924085048779000">パスフレーズã¯å¿…ãšæŒ‡å®šã—ã¦ãã ã•ã„。</translation>
<translation id="3845539888601087042">ログインã—ã¦ã„る端末ã®å±¥æ­´ã‚’表示ã—ã¦ã„ã¾ã™ã€‚<ph name="BEGIN_LINK" />詳細<ph name="END_LINK" /></translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chromium ã«ã“ã®ã‚«ãƒ¼ãƒ‰ã‚’ä¿å­˜ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="4171400957073367226">確èªç”¨ã®ç½²åã«å•é¡ŒãŒã‚ã‚Šã¾ã™</translation>
-<translation id="4176463684765177261">無効</translation>
<translation id="4196861286325780578">移動ã®ã‚„ã‚Šç›´ã—(&amp;R)</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ファイアウォールã¨ã‚¦ã‚¤ãƒ«ã‚¹å¯¾ç­–ã®è¨­å®šã‚’確èªã™ã‚‹<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{ãªã—}=1{1 個ã®ã‚¢ãƒ—リ($1)}=2{2 個ã®ã‚¢ãƒ—リ($1ã€$2)}other{# 個ã®ã‚¢ãƒ—リ($1ã€$2ã€$3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">検索çµæžœ</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ã§ãƒ­ã‚°ã‚¤ãƒ³è¨¼æ˜Žæ›¸ãŒæ‰¿èªã•ã‚Œãªã‹ã£ãŸã‹ã€ãƒ­ã‚°ã‚¤ãƒ³è¨¼æ˜Žæ›¸ãŒæ示ã•ã‚Œã¦ã„ãªã„å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="443673843213245140">プロキシã®ä½¿ç”¨ã¯ç„¡åŠ¹ã§ã™ãŒã€ãƒ—ロキシã®è¨­å®šãŒæ˜Žç¤ºçš„ã«æŒ‡å®šã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
-<translation id="4446242550670694251">シークレット モードã§ã™ã€‚ã‚ãªãŸã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティã¯ã€ã“ã®ç«¯æœ«ã‚’使用ã™ã‚‹ä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã¯è¡¨ç¤ºã•ã‚Œã¾ã›ã‚“。</translation>
<translation id="4492190037599258964">「<ph name="SEARCH_STRING" />ã€ã®æ¤œç´¢çµæžœ</translation>
<translation id="4506176782989081258">検証エラー: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">システム管ç†è€…ã«å•ã„åˆã‚ã›ã‚‹</translation>
<translation id="450710068430902550">管ç†è€…ã¨ã®å…±æœ‰</translation>
+<translation id="4515275063822566619">Chrome 㨠Google アカウント(<ph name="ACCOUNT_EMAIL" />)ã«ä¿å­˜ã•ã‚Œã¦ã„るクレジット カードã¨ä½æ‰€ã§ã™ã€‚[<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />] ã§ç®¡ç†ã§ãã¾ã™ã€‚</translation>
<translation id="4522570452068850558">詳細</translation>
<translation id="4558551763791394412">拡張機能を無効ã«ã—ã¦ã¿ã¦ãã ã•ã„。</translation>
<translation id="457875822857220463">é…é€</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">ページサイズã«åˆã‚ã›ã‚‹</translation>
<translation id="483020001682031208">表示ã§ãるフィジカル ウェブã®ãƒšãƒ¼ã‚¸ã¯ã‚ã‚Šã¾ã›ã‚“</translation>
<translation id="4850886885716139402">表示</translation>
+<translation id="4854362297993841467">ã“ã®é…é”方法ã¯ã”利用ã„ãŸã ã‘ã¾ã›ã‚“。別ã®æ–¹æ³•ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="4858792381671956233">ã“ã®ã‚µã‚¤ãƒˆã‚’é–‹ã„ã¦ã‚‚よã„ã‹ã®å•ã„åˆã‚ã›ã‚’ä¿è­·è€…ã«é€ä¿¡ã—ã¾ã—ãŸ</translation>
<translation id="4880827082731008257">履歴を検索</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />ã€<ph name="TYPE_2" />ã€<ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">ã“ã®ãƒšãƒ¼ã‚¸ã¯ã€ä¸æ˜Žãªè¨€èªžã‹ã‚‰<ph name="LANGUAGE_LANGUAGE" />ã«ç¿»è¨³ã•ã‚Œã¾ã—ãŸã€‚</translation>
<translation id="4923459931733593730">ãŠæ”¯æ‰•ã„</translation>
<translation id="4926049483395192435">指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</translation>
-<translation id="4941291666397027948">* ã¯å¿…須項目ã§ã™</translation>
<translation id="495170559598752135">æ“作</translation>
<translation id="4958444002117714549">リストを展開ã™ã‚‹</translation>
<translation id="4962322354953122629">ã“ã®ã‚µãƒ¼ãƒãƒ¼ãŒ <ph name="DOMAIN" /> ã§ã‚ã‚‹ã“ã¨ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨¼æ˜Žæ›¸ã¯ Chrome ã«ã‚ˆã£ã¦ä¿¡é ¼ã•ã‚Œã¦ã„ã‚‹ã‚‚ã®ã§ã¯ã‚ã‚Šã¾ã›ã‚“。原因ã¨ã—ã¦ã€è¨­å®šãŒä¸é©åˆ‡ã§ã‚ã‚‹ã‹ã€æ‚ªæ„ã®ã‚るユーザーãŒæŽ¥ç¶šã‚’妨害ã—ã¦ã„ã‚‹ã“ã¨ãŒè€ƒãˆã‚‰ã‚Œã¾ã™ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">パスワードãŒæ­£ã—ãã‚ã‚Šã¾ã›ã‚“</translation>
<translation id="5056549851600133418">ãŠã™ã™ã‚ã®è¨˜äº‹</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />プロキシ アドレスを確èªã™ã‚‹<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Cookie ã¯ä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã›ã‚“。}=1{1 件ã®ã‚µã‚¤ãƒˆã§ Cookie ãŒä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã™ã€‚}other{# 件ã®ã‚µã‚¤ãƒˆã§ Cookie ãŒä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã™ã€‚}}</translation>
<translation id="5087286274860437796">サーãƒãƒ¼ã®è¨¼æ˜Žæ›¸ãŒç¾åœ¨æœ‰åŠ¹ã§ã¯ã‚ã‚Šã¾ã›ã‚“。</translation>
<translation id="5087580092889165836">カードを追加</translation>
<translation id="5089810972385038852">都é“府県 / å·ž</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">表示</translation>
<translation id="5308689395849655368">障害レãƒãƒ¼ãƒˆãŒç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™ã€‚</translation>
<translation id="5317780077021120954">ä¿å­˜</translation>
-<translation id="5326702247179446998">å—å–人ã¯å¿…é ˆã§ã™</translation>
<translation id="5327248766486351172">åå‰</translation>
<translation id="5337705430875057403"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ã§ã¯ã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã£ã¦ã€ã‚½ãƒ•ãƒˆã‚¦ã‚§ã‚¢ã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã‚„個人情報(パスワードã€é›»è©±ç•ªå·ã€ã‚¯ãƒ¬ã‚¸ãƒƒãƒˆ カードãªã©ï¼‰ã®å…¥åŠ›ã¨ã„ã£ãŸå±é™ºãªæ“作を行ã†ã‚ˆã†èª˜å°Žã•ã‚Œã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
-<translation id="53553865750799677">サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„引å–å…ˆä½æ‰€ã§ã™ã€‚別ã®ä½æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="5359637492792381994">ã“ã®ã‚µãƒ¼ãƒãƒ¼ãŒ <ph name="DOMAIN" /> ã§ã‚ã‚‹ã“ã¨ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨¼æ˜Žæ›¸ã¯ç¾åœ¨æœ‰åŠ¹ã§ã¯ã‚ã‚Šã¾ã›ã‚“。設定ãŒä¸é©åˆ‡ã‹ã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã£ã¦æŽ¥ç¶šãŒå¦¨å®³ã•ã‚Œã¦ã„ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">ãƒãƒªã‚·ãƒ¼è¨­å®šã‚’ä¿å­˜ã§ãã¾ã›ã‚“ã§ã—ãŸ</translation>
<translation id="5386426401304769735">ã“ã®ã‚µã‚¤ãƒˆã®è¨¼æ˜Žæ›¸ãƒã‚§ãƒ¼ãƒ³ã«ã¯ SHA-1 を使ã£ã¦ç½²åã•ã‚ŒãŸè¨¼æ˜Žæ›¸ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102"><ph name="SITE" /> ã«åŸ‹ã‚è¾¼ã¾ã‚Œã¦ã„るページã®å†…容:</translation>
<translation id="5556459405103347317">å†èª­ã¿è¾¼ã¿</translation>
<translation id="5565735124758917034">有効</translation>
+<translation id="5571083550517324815">ã“ã®ä½æ‰€ã§ã®å—ã‘å–ã‚Šã¯ã§ãã¾ã›ã‚“。別ã®ä½æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="5572851009514199876">ã“ã®ã‚µã‚¤ãƒˆã¸ã®ã‚¢ã‚¯ã‚»ã‚¹æ¨©ãŒã‚ã‚‹ã‹ã©ã†ã‹ã‚’ Chrome ã§ç¢ºèªã§ãるよã†ã«ã€Chrome ã‚’èµ·å‹•ã—ã¦ãƒ­ã‚°ã‚¤ãƒ³ã—ã¦ãã ã•ã„。</translation>
-<translation id="5575380383496039204">サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„é…é€å…ˆä½æ‰€ã§ã™ã€‚別ã®ä½æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="5580958916614886209">有効期é™ã®ã€Œæœˆã€ã‚’確èªã—ã¦ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„</translation>
<translation id="560412284261940334">管ç†ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
<translation id="5610142619324316209">接続を確èªã™ã‚‹</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">ã“ã®ã‚¦ã‚§ãƒ–サイト㮠ID ã¯ç¢ºèªã•ã‚Œã¦ã„ã¾ã›ã‚“。</translation>
<translation id="5720705177508910913">ç¾åœ¨ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼</translation>
<translation id="5732392974455271431">ブロックã®è§£é™¤ã¯ä¿è­·è€…ãŒè¡Œã†ã“ã¨ãŒã§ãã¾ã™</translation>
-<translation id="57586589942790530">無効ãªã‚«ãƒ¼ãƒ‰ç•ªå·ã§ã™</translation>
+<translation id="5763042198335101085">有効ãªãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’入力ã—ã¦ãã ã•ã„</translation>
+<translation id="5765072501007116331">é…é”方法ã¨è¦ä»¶ã‚’確èªã™ã‚‹ã«ã¯ã€ä½æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„</translation>
<translation id="5784606427469807560">カードã®ç¢ºèªä¸­ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚インターãƒãƒƒãƒˆæŽ¥ç¶šã‚’確èªã—ã¦ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。</translation>
<translation id="5785756445106461925">加ãˆã¦ã€ã“ã®ãƒšãƒ¼ã‚¸ã«ã¯å®‰å…¨ã§ãªã„ä»–ã®ãƒªã‚½ãƒ¼ã‚¹ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚ã“ã®ãƒªã‚½ãƒ¼ã‚¹ã¯é€ä¿¡ä¸­ã«ä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‹ã‚‰è¦‹ã‚‰ã‚Œã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚ã¾ãŸã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã£ã¦æ”¹å¤‰ã•ã‚Œãƒšãƒ¼ã‚¸ã®è¦‹ãŸç›®ãŒå¤‰ã‚ã‚‹å¯èƒ½æ€§ã‚‚ã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="5786044859038896871">カード情報を入力ã—ã¾ã™ã‹ï¼Ÿ</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">ã“ã®ã‚µã‚¤ãƒˆã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“</translation>
<translation id="5869522115854928033">ä¿å­˜ã—ãŸãƒ‘スワード</translation>
<translation id="5872918882028971132">ä¿è­·è€…ã‹ã‚‰ã®ãŠã™ã™ã‚</translation>
-<translation id="587760065310675640">サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„é…é€å…ˆä½æ‰€ã§ã™ã€‚別ã®ä½æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="5901630391730855834">黄</translation>
-<translation id="59174027418879706">有効</translation>
<translation id="5926846154125914413">一部ã®ã‚µã‚¤ãƒˆã®ãƒ—レミアム コンテンツã«ã‚¢ã‚¯ã‚»ã‚¹ã§ããªããªã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="5959728338436674663">å±é™ºãªã‚¢ãƒ—リやサイトã®æ¤œå‡ºã«å½¹ç«‹ã¦ã‚‹ãŸã‚ã«ä¸€éƒ¨ã®<ph name="BEGIN_WHITEPAPER_LINK" />システム情報やページã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„<ph name="END_WHITEPAPER_LINK" />ã‚’ Google ã«è‡ªå‹•é€ä¿¡ã™ã‚‹ã€‚<ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">週</translation>
<translation id="5967867314010545767">履歴ã‹ã‚‰å‰Šé™¤</translation>
<translation id="5975083100439434680">縮å°ã™ã‚‹</translation>
+<translation id="598637245381783098">ãŠæ”¯æ‰•ã„アプリを開ã‘ã¾ã›ã‚“</translation>
<translation id="5989320800837274978">固定プロキシ サーãƒãƒ¼ã¨ .pac スクリプト URL ã®ã©ã¡ã‚‰ã‚‚指定ã•ã‚Œã¦ã„ã¾ã›ã‚“。</translation>
<translation id="5990559369517809815">サーãƒãƒ¼ã¸ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯æ‹¡å¼µæ©Ÿèƒ½ã«ã‚ˆã£ã¦ãƒ–ロックã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Chrome ã®ã‚«ãƒ¼ãƒ‰ã¨ä½æ‰€ã®ã‚ªãƒ—ションã§ã™ã€‚ã“れらã®ã‚ªãƒ—ション㯠[<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />] ã§ç®¡ç†ã§ãã¾ã™ã€‚</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{ページ 1}other{ページ #}}</translation>
<translation id="6017514345406065928">ç·‘</translation>
+<translation id="6027201098523975773">åå‰ã‚’入力ã—ã¦ãã ã•ã„</translation>
<translation id="6040143037577758943">é–‰ã˜ã‚‹</translation>
-<translation id="604124094241169006">自動設定</translation>
<translation id="6042308850641462728">ã‚‚ã£ã¨è¦‹ã‚‹</translation>
<translation id="6060685159320643512">ã“れらã®è©¦é¨“é‹ç”¨ç‰ˆã¯å•é¡ŒãŒç™ºç”Ÿã™ã‚‹å¯èƒ½æ€§ãŒã‚ã‚‹ãŸã‚ã€ã”利用ã®éš›ã«ã¯å分ã”注æ„ãã ã•ã„</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{ãªã—}=1{1 件}other{# 件}}</translation>
@@ -543,9 +552,10 @@
å†èµ·å‹•ã—ã¦ãã ã•ã„。</translation>
<translation id="614940544461990577">次をãŠè©¦ã—ãã ã•ã„:</translation>
<translation id="6151417162996330722">サーãƒãƒ¼è¨¼æ˜Žæ›¸ã®æœ‰åŠ¹æœŸé™ãŒé•·ã™ãŽã¾ã™ã€‚</translation>
-<translation id="615643356032862689">ダウンロードã—ãŸãƒ•ã‚¡ã‚¤ãƒ«ã¨ãƒ–ックマークã¯ä¿æŒã•ã‚Œã¾ã™ã€‚</translation>
+<translation id="6157877588268064908">é…é€æ–¹æ³•ã¨è¦ä»¶ã‚’確èªã™ã‚‹ã«ã¯ã€ä½æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„</translation>
<translation id="6165508094623778733">詳ã—ã見る</translation>
<translation id="6177128806592000436">ã“ã®ã‚µã‚¤ãƒˆã¸ã®æŽ¥ç¶šã¯ä¿è­·ã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
+<translation id="6184817833369986695">(コホート: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">インターãƒãƒƒãƒˆæŽ¥ç¶šã‚’確èªã—ã¦ãã ã•ã„</translation>
<translation id="6218753634732582820">Chromium ã‹ã‚‰ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’削除ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ</translation>
<translation id="6251924700383757765">プライãƒã‚·ãƒ¼ ãƒãƒªã‚·ãƒ¼</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">é †åºå¤‰æ›´ã®ã‚„ã‚Šç›´ã—(&amp;R)</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> ã®ãƒ–ックマーク</translation>
<translation id="6264485186158353794">セキュリティã§ä¿è­·ã•ã‚ŒãŸãƒšãƒ¼ã‚¸ã«æˆ»ã‚‹</translation>
+<translation id="6276112860590028508">リーディング リストã«ç™»éŒ²ã•ã‚ŒãŸãƒšãƒ¼ã‚¸ãŒã“ã“ã«è¡¨ç¤ºã•ã‚Œã¾ã™</translation>
+<translation id="6280223929691119688">ã“ã®ä½æ‰€ã«ã¯é…é”ã§ãã¾ã›ã‚“。別ã®ä½æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="6282194474023008486">郵便番å·</translation>
<translation id="6290238015253830360">ãŠã™ã™ã‚ã®è¨˜äº‹ãŒã“ã“ã«è¡¨ç¤ºã•ã‚Œã¾ã™</translation>
<translation id="6305205051461490394"><ph name="URL" /> ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“。</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">証明書ãŒå–り消ã•ã‚ŒãŸã‹ã©ã†ã‹ã‚’確èªã§ãã¾ã›ã‚“。</translation>
<translation id="6433490469411711332">連絡先情報ã®ç·¨é›†</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> ã§æŽ¥ç¶šãŒæ‹’å¦ã•ã‚Œã¾ã—ãŸã€‚</translation>
-<translation id="6443118737398455446">有効期é™ãŒç„¡åŠ¹ã§ã™</translation>
<translation id="6446608382365791566">ä»–ã®æƒ…報を追加</translation>
<translation id="6451458296329894277">フォームå†é€ä¿¡ã®ç¢ºèª</translation>
<translation id="6456339708790392414">ãŠæ”¯æ‰•ã„</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">ã“ã®ã‚µãƒ¼ãƒãƒ¼ãŒ <ph name="DOMAIN" /> ã§ã‚ã‚‹ã“ã¨ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨¼æ˜Žæ›¸ã¯å–り消ã•ã‚Œã¦ã„ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚原因ã¨ã—ã¦ã€è¨­å®šãŒä¸é©åˆ‡ã§ã‚ã‚‹ã‹ã€æ‚ªæ„ã®ã‚るユーザーãŒæŽ¥ç¶šã‚’妨害ã—ã¦ã„ã‚‹ã“ã¨ãŒè€ƒãˆã‚‰ã‚Œã¾ã™ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">デãƒã‚¤ã‚¹ ãƒãƒªã‚·ãƒ¼</translation>
<translation id="6477321094435799029">ã“ã®ãƒšãƒ¼ã‚¸ã§é€šå¸¸ã¨ç•°ãªã‚‹ã‚³ãƒ¼ãƒ‰ã‚’検出ã—ãŸãŸã‚ã€å€‹äººæƒ…報(例: パスワードã€é›»è©±ç•ªå·ã€ã‚¯ãƒ¬ã‚¸ãƒƒãƒˆ カード番å·ï¼‰ã‚’ä¿è­·ã™ã‚‹ãŸã‚ã«ã€ãƒšãƒ¼ã‚¸ã‚’ブロックã—ã¾ã—ãŸã€‚</translation>
-<translation id="6477460825583319731">無効ãªãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã§ã™</translation>
<translation id="6489534406876378309">クラッシュã®ã‚¢ãƒƒãƒ—ロードを開始</translation>
<translation id="6508722015517270189">Chrome ã‚’å†èµ·å‹•ã™ã‚‹</translation>
-<translation id="6525462735697194615">有効期é™ï¼ˆæœˆï¼‰ãŒç„¡åŠ¹ã§ã™</translation>
<translation id="6529602333819889595">削除ã®ã‚„ã‚Šç›´ã—(&amp;R)</translation>
<translation id="6534179046333460208">フィジカル ウェブã‹ã‚‰ã® URL</translation>
<translation id="6550675742724504774">オプション</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> 検索</translation>
<translation id="6644283850729428850">ã“ã®ãƒãƒªã‚·ãƒ¼ã¯å»ƒæ­¢ã•ã‚Œã¾ã—ãŸã€‚</translation>
<translation id="6652240803263749613">ã“ã®ã‚µãƒ¼ãƒãƒ¼ãŒ <ph name="DOMAIN" /> ã§ã‚ã‚‹ã“ã¨ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨¼æ˜Žæ›¸ã¯ã€ã”使用ã®ãƒ‘ソコンã®ã‚ªãƒšãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚° システムã«ã‚ˆã£ã¦ä¿¡é ¼ã•ã‚Œã¦ã„ã‚‹ã‚‚ã®ã§ã¯ã‚ã‚Šã¾ã›ã‚“。原因ã¨ã—ã¦ã€è¨­å®šãŒä¸é©åˆ‡ã§ã‚ã‚‹ã‹ã€æ‚ªæ„ã®ã‚るユーザーãŒæŽ¥ç¶šã‚’妨害ã—ã¦ã„ã‚‹ã“ã¨ãŒè€ƒãˆã‚‰ã‚Œã¾ã™ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="6665267558048410100">ãã®é…é€æ–¹æ³•ã¯ã”利用ã„ãŸã ã‘ã¾ã›ã‚“。別ã®æ–¹æ³•ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="6671697161687535275">Chromium ã‹ã‚‰å€™è£œã‚’削除ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ</translation>
<translation id="6685834062052613830">ログアウトã—ã¦è¨­å®šã‚’完了ã—ã¦ãã ã•ã„</translation>
<translation id="6710213216561001401">å‰ã¸</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">プロキシ サーãƒãƒ¼ã«å•é¡ŒãŒã‚ã‚‹ã€ã¾ãŸã¯ã‚¢ãƒ‰ãƒ¬ã‚¹ãŒæ­£ã—ãã‚ã‚Šã¾ã›ã‚“。</translation>
<translation id="6727102863431372879">設定</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{ãªã—}=1{1 件ã®ã‚¢ã‚¤ãƒ†ãƒ }other{# 件ã®ã‚¢ã‚¤ãƒ†ãƒ }}</translation>
-<translation id="6743044928064272573">引å–方法</translation>
<translation id="674375294223700098">ä¸æ˜Žãªã‚µãƒ¼ãƒãƒ¼è¨¼æ˜Žæ›¸ã‚¨ãƒ©ãƒ¼</translation>
<translation id="6753269504797312559">ãƒãƒªã‚·ãƒ¼ã®å€¤</translation>
<translation id="6757797048963528358">デãƒã‚¤ã‚¹ãŒã‚¹ãƒªãƒ¼ãƒ—状態ã§ã™ã€‚</translation>
<translation id="6778737459546443941">ä¿è­·è€…ãŒã¾ã ã‚µã‚¤ãƒˆã‚’é–‹ãã“ã¨ã‚’許å¯ã—ã¦ã„ã¾ã›ã‚“</translation>
<translation id="6810899417690483278">カスタム ID</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">地域データを読ã¿è¾¼ã‚ã¾ã›ã‚“ã§ã—ãŸ</translation>
<translation id="6831043979455480757">翻訳</translation>
<translation id="6839929833149231406">地域</translation>
<translation id="6874604403660855544">追加ã®ã‚„ã‚Šç›´ã—(&amp;R)</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">カードを確èªã—ã¾ã—ãŸ</translation>
<translation id="6897140037006041989">ユーザー エージェント</translation>
<translation id="6915804003454593391">ユーザー:</translation>
+<translation id="6948701128805548767">å—ã‘å–り方法ã¨è¦ä»¶ã‚’確èªã™ã‚‹ã«ã¯ã€ä½æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„</translation>
<translation id="6957887021205513506">サーãƒãƒ¼ã®è¨¼æ˜Žæ›¸ãŒå½é€ ã•ã‚ŒãŸã‚‚ã®ã®ã‚ˆã†ã§ã™ã€‚</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">デãƒã‚¤ã‚¹</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">固定プロキシ サーãƒãƒ¼ã¨ .pac スクリプト URL ã®ä¸¡æ–¹ãŒæŒ‡å®šã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
<translation id="6989763994942163495">詳細設定を表示...</translation>
<translation id="7000990526846637657">履歴項目ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“</translation>
-<translation id="7001663382399377034">å—å–人を追加</translation>
<translation id="7009986207543992532"><ph name="DOMAIN" /> ã«ã‚¢ã‚¯ã‚»ã‚¹ã—よã†ã¨ã—ã¾ã—ãŸãŒã€ã‚µãƒ¼ãƒãƒ¼ã«æ示ã•ã‚ŒãŸè¨¼æ˜Žæ›¸ã®æœ‰åŠ¹æœŸé™ãŒé•·ã™ãŽã¦ä¿¡é ¼æ€§ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">中国銀è¯</translation>
<translation id="7012372675181957985">Google アカウントã§ã®ä»–ã®å½¢å¼ã®é–²è¦§å±¥æ­´ãŒ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ã«æ®‹ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™</translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">å¤ã„</translation>
<translation id="7090678807593890770"><ph name="LINK" /> ã‚’ Google ã§æ¤œç´¢ã—ã¦ãã ã•ã„</translation>
<translation id="7119414471315195487">ä»–ã®ã‚¿ãƒ–やプログラムを閉ã˜ã‚‹</translation>
+<translation id="7129409597930077180">ã“ã®ä½æ‰€ã«ã¯é…é€ã§ãã¾ã›ã‚“。別ã®ä½æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
+<translation id="7138472120740807366">é…é”方法</translation>
<translation id="7139724024395191329">管轄区域</translation>
<translation id="7155487117670177674">ãŠæ”¯æ‰•ã„情報ã¯ä¿è­·ã•ã‚Œã¾ã›ã‚“</translation>
<translation id="7179921470347911571">今ã™ãå†èµ·å‹•</translation>
<translation id="7180611975245234373">æ›´æ–°</translation>
<translation id="7182878459783632708">ãƒãƒªã‚·ãƒ¼ãŒè¨­å®šã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
<translation id="7186367841673660872">ã“ã®ãƒšãƒ¼ã‚¸ã¯<ph name="ORIGINAL_LANGUAGE" />ã‹ã‚‰<ph name="LANGUAGE_LANGUAGE" />ã«ç¿»è¨³ã•ã‚Œã¾ã—ãŸ</translation>
+<translation id="7192203810768312527"><ph name="SIZE" /> を解放ã—ã¾ã™ã€‚サイトã«ã‚ˆã£ã¦ã¯ã€æ¬¡å›žã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹éš›ã«èª­ã¿è¾¼ã¿ãŒã“ã‚Œã¾ã§ã‚ˆã‚Šé…ããªã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ã§ã¯ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¦æ ¼ãŒéµå®ˆã•ã‚Œã¦ã„ã¾ã›ã‚“。</translation>
<translation id="721197778055552897">ã“ã®å•é¡Œã®è©³ç´°ã«ã¤ã„ã¦ã¯ã€<ph name="BEGIN_LINK" />ã“ã¡ã‚‰<ph name="END_LINK" />ã‚’ã”覧ãã ã•ã„。</translation>
@@ -675,7 +686,6 @@
<translation id="7424977062513257142">ã“ã®ã‚¦ã‚§ãƒ–ページã«åŸ‹ã‚è¾¼ã¾ã‚Œã¦ã„るページã®å†…容:</translation>
<translation id="7441627299479586546">ãƒãƒªã‚·ãƒ¼ã®å¯¾è±¡ãŒé–“é•ã£ã¦ã„ã¾ã™</translation>
<translation id="7444046173054089907">ã“ã®ã‚µã‚¤ãƒˆã¯ãƒ–ロックã•ã‚Œã¦ã„ã¾ã™</translation>
-<translation id="7444238235002594607">引å–方法やè¦ä»¶ã‚’確èªã™ã‚‹ã«ã¯ã€å¼•å–å…ˆä½æ‰€ã‚’é¸æŠžã—ã¾ã™ã€‚</translation>
<translation id="7445762425076701745">接続ã—ã¦ã‚‹ã‚µãƒ¼ãƒãƒ¼ã®èº«å…ƒã«ã¤ã„ã¦ã€å分ãªæ¤œè¨¼ãŒã§ãã¾ã›ã‚“。接続ã—ã¦ã„るサーãƒãƒ¼ã¯ã€ãã®ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯å†…ã§ã®ã¿æœ‰åŠ¹ãªåå‰ã‚’使用ã—ã¦ãŠã‚Šã€å¤–部èªè¨¼å±€ãŒãã®æ‰€æœ‰æ¨©ã‚’検証ã™ã‚‹æ–¹æ³•ã¯ã‚ã‚Šã¾ã›ã‚“。ã“ã†ã—ãŸåå‰ã§è¨¼æ˜Žæ›¸ã‚’発行ã™ã‚‹èªè¨¼å±€ã‚‚ã‚ã‚‹ã®ã§ã€æŽ¥ç¶šå…ˆãŒæ„図ã—ãŸã‚¦ã‚§ãƒ–サイトã‹ã€æ‚ªæ„ã®ã‚るユーザーã®ã‚µã‚¤ãƒˆã‹ã¯ç¢ºèªã§ãã¾ã›ã‚“。</translation>
<translation id="7451311239929941790">ã“ã®å•é¡Œã«ã¤ã„ã¦<ph name="BEGIN_LINK" />詳細を確èª<ph name="END_LINK" />ã™ã‚‹</translation>
<translation id="7460163899615895653">ä»–ã®ç«¯æœ«ã§æœ€è¿‘使ã£ãŸã‚¿ãƒ–ãŒã“ã“ã«è¡¨ç¤ºã•ã‚Œã¾ã™</translation>
@@ -719,6 +729,7 @@
<translation id="7755287808199759310">ブロックã®è§£é™¤ã¯ä¿è­·è€…ãŒè¡Œã†ã“ã¨ãŒã§ãã¾ã™</translation>
<translation id="7758069387465995638">ファイアウォールã¾ãŸã¯ã‚¦ã‚¤ãƒ«ã‚¹å¯¾ç­–ソフトウェアã«ã‚ˆã£ã¦æŽ¥ç¶šãŒãƒ–ロックã•ã‚ŒãŸå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="7761701407923456692">サーãƒãƒ¼ã®è¨¼æ˜Žæ›¸ãŒ URL ã¨ä¸€è‡´ã—ã¾ã›ã‚“。</translation>
+<translation id="7763386264682878361">Payment Manifest Parser</translation>
<translation id="7764225426217299476">ä½æ‰€ã‚’追加</translation>
<translation id="777702478322588152">都é“府県</translation>
<translation id="7791543448312431591">追加</translation>
@@ -732,6 +743,7 @@
<translation id="785549533363645510">ã‚らゆる場所ã«è¨˜éŒ²ãŒä¸€åˆ‡æ®‹ã‚‰ãªã„ã‚ã‘ã§ã¯ã‚ã‚Šã¾ã›ã‚“。シークレット モードを使ã£ã¦ã‚‚ã€é›‡ç”¨ä¸»ã€ã‚¤ãƒ³ã‚¿ãƒ¼ãƒãƒƒãƒˆ サービス プロãƒã‚¤ãƒ€ã€è¨ªå•å…ˆã®ã‚¦ã‚§ãƒ–サイトã«é–²è¦§å†…容ãŒçŸ¥ã‚‰ã‚Œã‚‹å¯èƒ½æ€§ã¯ã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">CVC を確èªã—ã¦ã‹ã‚‰ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„</translation>
+<translation id="79338296614623784">有効ãªé›»è©±ç•ªå·ã‚’入力ã—ã¦ãã ã•ã„</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">サーãƒãƒ¼ã®è¨¼æ˜Žæ›¸ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã›ã‚“。</translation>
<translation id="7942349550061667556">赤</translation>
@@ -751,6 +763,7 @@
<translation id="8088680233425245692">記事を表示ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚</translation>
<translation id="8089520772729574115">1 MB 未満</translation>
<translation id="8091372947890762290">サーãƒãƒ¼ã§æœ‰åŠ¹åŒ–ãŒä¿ç•™ã«ãªã£ã¦ã„ã¾ã™</translation>
+<translation id="8118489163946903409">ãŠæ”¯æ‰•ã„方法</translation>
<translation id="8131740175452115882">確èª</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> ã®ã‚µãƒ¼ãƒãƒ¼ã® <ph name="BEGIN_ABBR" />DNS アドレス<ph name="END_ABBR" />ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚</translation>
<translation id="8149426793427495338">パソコンãŒã‚¹ãƒªãƒ¼ãƒ—状態ã§ã™ã€‚</translation>
@@ -776,6 +789,7 @@
<translation id="8349305172487531364">ブックマーク ãƒãƒ¼</translation>
<translation id="8363502534493474904">機内モードをオフã«ã™ã‚‹</translation>
<translation id="8364627913115013041">未設定</translation>
+<translation id="8368476060205742148">Google Play 開発者サービス</translation>
<translation id="8380941800586852976">å±é™º</translation>
<translation id="8382348898565613901">最近アクセスã—ãŸãƒ–ックマークãŒã“ã“ã«è¡¨ç¤ºã•ã‚Œã¾ã™</translation>
<translation id="8398259832188219207">クラッシュ レãƒãƒ¼ãƒˆãŒ <ph name="UPLOAD_TIME" /> ã«ã‚¢ãƒƒãƒ—ロードã•ã‚Œã¾ã—ãŸ</translation>
@@ -784,32 +798,30 @@
<translation id="8428213095426709021">設定</translation>
<translation id="8433057134996913067">ã»ã¨ã‚“ã©ã®ã‚¦ã‚§ãƒ–サイトã‹ã‚‰ãƒ­ã‚°ã‚¢ã‚¦ãƒˆã—ã¾ã™ã€‚</translation>
<translation id="8437238597147034694">移動ã®å–り消ã—(&amp;U)</translation>
-<translation id="8456681095658380701">åå‰ãŒç„¡åŠ¹ã§ã™</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 件ã®ã‚¯ãƒ¬ã‚¸ãƒƒãƒˆ カード}other{# 件ã®ã‚¯ãƒ¬ã‚¸ãƒƒãƒˆ カード}}</translation>
<translation id="8483780878231876732">Google アカウントã«ä¿å­˜ã—ãŸã‚«ãƒ¼ãƒ‰ã‚’使用ã™ã‚‹ã«ã¯ Chrome ã«ãƒ­ã‚°ã‚¤ãƒ³ã—ã¦ãã ã•ã„</translation>
<translation id="8488350697529856933">é©ç”¨å…ˆ</translation>
-<translation id="8492969205326575646">サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„カードã®ç¨®é¡ž</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ã‹ã‚‰ã®å¿œç­”時間ãŒé•·ã™ãŽã¾ã™ã€‚</translation>
<translation id="852346902619691059">ã“ã®ã‚µãƒ¼ãƒãƒ¼ãŒ <ph name="DOMAIN" /> ã§ã‚ã‚‹ã“ã¨ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨¼æ˜Žæ›¸ã¯ã€ã”使用ã®ãƒ‡ãƒã‚¤ã‚¹ã®ã‚ªãƒšãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚° システムã«ã‚ˆã£ã¦ä¿¡é ¼ã•ã‚Œã¦ã„ã‚‹ã‚‚ã®ã§ã¯ã‚ã‚Šã¾ã›ã‚“。原因ã¨ã—ã¦ã€è¨­å®šãŒä¸é©åˆ‡ã§ã‚ã‚‹ã‹ã€æ‚ªæ„ã®ã‚るユーザーãŒæŽ¥ç¶šã‚’妨害ã—ã¦ã„ã‚‹ã“ã¨ãŒè€ƒãˆã‚‰ã‚Œã¾ã™ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="8532105204136943229">有効期é™ï¼ˆå¹´ï¼‰</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />検出ã®å•é¡Œã‚’ã”報告<ph name="END_ERROR_LINK" />ãã ã•ã„。<ph name="BEGIN_LINK" />安全ã§ãªã„ã“ã®ã‚µã‚¤ãƒˆã«ã‚¢ã‚¯ã‚»ã‚¹<ph name="END_LINK" />ã™ã‚‹å ´åˆã¯ã€ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ä¸Šã®ãƒªã‚¹ã‚¯ãŒã‚ã‚‹ã“ã¨ã‚’ã”承知ãŠããã ã•ã„。</translation>
<translation id="8553075262323480129">ページã®è¨€èªžã‚’検出ã§ããªã„ãŸã‚翻訳ã§ãã¾ã›ã‚“。</translation>
<translation id="8559762987265718583">デãƒã‚¤ã‚¹ã®æ—¥æ™‚(<ph name="DATE_AND_TIME" />)ãŒæ­£ã—ããªã„ãŸã‚ã€<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ã¸ã®ãƒ—ライベート接続を確立ã§ãã¾ã›ã‚“。</translation>
-<translation id="8570229484593575558">次ã®æƒ…å ±ã¯|ä¿å­˜ã•ã‚Œã¾ã›ã‚“|。#閲覧履歴#検索内容#Cookie データ</translation>
<translation id="8571890674111243710">ページを<ph name="LANGUAGE" />ã«ç¿»è¨³ã—ã¦ã„ã¾ã™...</translation>
-<translation id="8584539743998202583">ãŸã ã—ã€æ¬¡ã®ä»–者ã«ã‚ˆã£ã¦ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティãŒ|確èªã•ã‚Œã‚‹å¯èƒ½æ€§ã¯ã‚ã‚Šã¾ã™|。#アクセス先ã®ã‚¦ã‚§ãƒ–サイト#雇用主#ã”利用ã®ã‚¤ãƒ³ã‚¿ãƒ¼ãƒãƒƒãƒˆ サービス プロãƒã‚¤ãƒ€</translation>
<translation id="858637041960032120">電話番å·ã‚’追加
</translation>
<translation id="859285277496340001">ã“ã®è¨¼æ˜Žæ›¸ã«ã¯ã€å–り消ã•ã‚ŒãŸã‹ã©ã†ã‹ã‚’確èªã™ã‚‹æ–¹æ³•ãŒæŒ‡å®šã•ã‚Œã¦ã„ã¾ã›ã‚“。</translation>
<translation id="8620436878122366504">ä¿è­·è€…ãŒã¾ã ã‚µã‚¤ãƒˆã‚’é–‹ãã“ã¨ã‚’許å¯ã—ã¦ã„ã¾ã›ã‚“</translation>
<translation id="8647750283161643317">ã™ã¹ã¦ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã«æˆ»ã™</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> ã¸ã®æŽ¥ç¶šã¯æš—å·åŒ–ã•ã‚Œã¦ã„ã¾ã›ã‚“。</translation>
+<translation id="8718314106902482036">支払ã„処ç†ã‚’完了ã§ãã¾ã›ã‚“ã§ã—ãŸ</translation>
<translation id="8725066075913043281">ã‚„ã‚Šç›´ã—</translation>
<translation id="8728672262656704056">シークレット モードã§ã™</translation>
<translation id="8730621377337864115">完了</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="8759274551635299824">ã“ã®ã‚«ãƒ¼ãƒ‰ã¯æœ‰åŠ¹æœŸé™ãŒåˆ‡ã‚Œã¦ã„ã¾ã™</translation>
<translation id="8790007591277257123">削除ã®ã‚„ã‚Šç›´ã—(&amp;R)</translation>
-<translation id="8798099450830957504">既定</translation>
<translation id="8800988563907321413">周辺ã®ãŠã™ã™ã‚ã®å ´æ‰€ãŒã“ã“ã«è¡¨ç¤ºã•ã‚Œã¾ã™</translation>
<translation id="8820817407110198400">ブックマーク</translation>
<translation id="883848425547221593">ãã®ä»–ã®ãƒ–ックマーク</translation>
@@ -819,6 +831,7 @@
<translation id="8866481888320382733">ãƒãƒªã‚·ãƒ¼è¨­å®šã®è§£æžä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ</translation>
<translation id="8866959479196209191">ã“ã®ãƒšãƒ¼ã‚¸ã®å†…容:</translation>
<translation id="8870413625673593573">最近閉ã˜ãŸã‚¿ãƒ–</translation>
+<translation id="8874824191258364635">有効ãªã‚¯ãƒ¬ã‚¸ãƒƒãƒˆ カード番å·ã‚’入力ã—ã¦ãã ã•ã„</translation>
<translation id="8876793034577346603">ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯è¨­å®šã‚’解æžã§ãã¾ã›ã‚“ã§ã—ãŸã€‚</translation>
<translation id="8877192140621905067">確èªã‚’è¡Œã†ã¨ã€ã‚«ãƒ¼ãƒ‰ã®è©³ç´°ãŒã“ã®ã‚µã‚¤ãƒˆã¨å…±æœ‰ã•ã‚Œã¾ã™</translation>
<translation id="8889402386540077796">色調</translation>
@@ -828,7 +841,6 @@
<translation id="8931333241327730545">ã“ã®ã‚«ãƒ¼ãƒ‰ã‚’ Google アカウントã«ä¿å­˜ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="8932102934695377596">時計ãŒé…ã‚Œã¦ã„ã¾ã™</translation>
<translation id="8954894007019320973">(続ã)</translation>
-<translation id="895548565263634352"><ph name="ARTICLE_PUBLISHER" />ã‹ã‚‰ã®è¨˜äº‹ãŒä»–ã« <ph name="OTHER_ARTICLE_COUNT" /> 件ã‚ã‚Šã¾ã™</translation>
<translation id="8971063699422889582">サーãƒãƒ¼ã®è¨¼æ˜Žæ›¸ã®æœ‰åŠ¹æœŸé™ãŒåˆ‡ã‚Œã¦ã„ã¾ã™ã€‚</translation>
<translation id="8986494364107987395">使用統計データã¨éšœå®³ãƒ¬ãƒãƒ¼ãƒˆã‚’ Google ã«è‡ªå‹•é€ä¿¡ã™ã‚‹</translation>
<translation id="8987927404178983737">月</translation>
@@ -846,7 +858,6 @@
<translation id="9068849894565669697">色ã®é¸æŠž</translation>
<translation id="9076283476770535406">æˆäººå‘ã‘コンテンツãŒå«ã¾ã‚Œã¦ã„ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™</translation>
<translation id="9078964945751709336">ãã®ä»–ã®æƒ…å ±ãŒå¿…è¦ã§ã™</translation>
-<translation id="9094175695478007090">ãŠæ”¯æ‰•ã„アプリを起動ã§ãã¾ã›ã‚“。</translation>
<translation id="9103872766612412690"><ph name="SITE" /> ã§ã¯é€šå¸¸ã€æš—å·åŒ–ã—ã¦æƒ…報をä¿è­·ã—ã¦ã„ã¾ã™ã€‚今回ã€Chromium ã‹ã‚‰ <ph name="SITE" /> ã¸ã®æŽ¥ç¶šè©¦è¡Œæ™‚ã«ã€ã“ã®ã‚¦ã‚§ãƒ–サイトã‹ã‚‰ã„ã¤ã‚‚ã¨ã¯ç•°ãªã‚‹èª¤ã£ãŸèªè¨¼æƒ…å ±ãŒè¿”ã•ã‚Œã¾ã—ãŸã€‚悪æ„ã®ã‚るユーザー㌠<ph name="SITE" /> ã«ãªã‚Šã™ã¾ãã†ã¨ã—ã¦ã„ã‚‹ã‹ã€Wi-Fi ログイン画é¢ã§æŽ¥ç¶šãŒä¸­æ–­ã•ã‚ŒãŸå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚データã®ã‚„ã‚Šå–ã‚ŠãŒè¡Œã‚れるå‰ã« Chromium ã«ã‚ˆã£ã¦æŽ¥ç¶šãŒåœæ­¢ã•ã‚ŒãŸãŸã‚ã€æƒ…å ±ã¯å¼•ã続ãä¿è­·ã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
<translation id="9137013805542155359">原文ã®ãƒšãƒ¼ã‚¸ã‚’表示</translation>
<translation id="9137248913990643158">ã“ã®ã‚¢ãƒ—リを使用ã™ã‚‹ã«ã¯ã€Chrome ã‚’èµ·å‹•ã—ã¦ãƒ­ã‚°ã‚¤ãƒ³ã—ã¦ãã ã•ã„。</translation>
diff --git a/chromium/components/strings/components_strings_kn.xtb b/chromium/components/strings/components_strings_kn.xtb
index ff367f30dbb..c7f54c81361 100644
--- a/chromium/components/strings/components_strings_kn.xtb
+++ b/chromium/components/strings/components_strings_kn.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="kn">
<translation id="1008557486741366299">ಈಗಲೇ ಅಲà³à²²</translation>
<translation id="1015730422737071372">ಹೆಚà³à²šà³à²µà²°à²¿ ವಿವರಗಳನà³à²¨à³ ಒದಗಿಸಿ</translation>
+<translation id="1021110881106174305">ಸà³à²µà³€à²•à³ƒà²¤ ಕಾರà³à²¡à³â€Œà²—ಳà³</translation>
<translation id="1032854598605920125">ಪà³à²°à²¦à²•à³à²·à²¿à²£à²¾à²•à²¾à²°à²¦à²²à³à²²à²¿ ತಿರà³à²—ಿಸà³</translation>
<translation id="1038842779957582377">ಆಜà³à²žà²¾à²¤ ಹೆಸರà³</translation>
<translation id="1050038467049342496">ಇತರ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€à²—ಳನà³à²¨à³ ಮà³à²šà³à²šà²¿</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">ಮೌಲà³à²¯à²µà²¨à³à²¨à³ ಮರೆಮಾಡಿ</translation>
<translation id="1228893227497259893">ತಪà³à²ªà²¾à²¦ ಅಸà³à²¤à²¿à²¤à³à²µà²¦ ಗà³à²°à³à²¤à³</translation>
<translation id="1232569758102978740">ಶೀರà³à²·à²¿à²•à³†à²°à²¹à²¿à²¤</translation>
+<translation id="1263231323834454256">ಓದà³à²µ ಪಟà³à²Ÿà²¿</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> ನಲà³à²²à²¿ ಕà³à²°à³à²¯à²¾à²¶à³ ವರದಿಯನà³à²¨à³ ಸೆರೆಹಿಡಿಯಲಾಗಿದೆ (ಇನà³à²¨à³‚ ಅಪà³â€Œà²²à³‹à²¡à³ ಮಾಡಲಾಗಿಲà³à²² ಅಥವಾ ನಿರà³à²²à²•à³à²·à²¿à²¸à²²à²¾à²—ಿಲà³à²²)</translation>
<translation id="1285320974508926690">ಈ ಸೈಟೠಅನà³à²¨à³ ಎಂದಿಗೂ ಭಾಷಾಂತರಿಸದಿರಿ</translation>
<translation id="129553762522093515">ಇತà³à²¤à³€à²šà³†à²—ೆ ಮà³à²šà³à²šà²²à²¾à²—ಿರà³à²µà³à²¦à³</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromium ಸà³à²µà²¯à²‚ತà³à²‚ಬà³à²µà²¿à²•à³† ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳà³...</translation>
<translation id="1374468813861204354">ಸಲಹೆಗಳà³</translation>
<translation id="1375198122581997741">ಆವೃತà³à²¤à²¿à²¯ ಕà³à²°à²¿à²¤à³</translation>
+<translation id="1377321085342047638">ಕಾರà³à²¡à³ ಸಂಖà³à²¯à³†</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> ಯಾವà³à²¦à³‡ ಡೇಟಾ ಕಳà³à²¹à²¿à²¸à²²à²¾à²—ಿಲà³à²².</translation>
<translation id="1407135791313364759">ಎಲà³à²²à²µà²¨à³à²¨à³‚ ತೆರೆಯಿರಿ</translation>
<translation id="1413809658975081374">ಗೌಪà³à²¯à²¤à³† ದೋಷ</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">ಇತಿಹಾಸ</translation>
<translation id="1645368109819982629">ಬೆಂಬಲವಿಲà³à²²à²¦ ಪà³à²°à³†à³‚ಟೋಕಾಲà³</translation>
<translation id="1656489000284462475">ಪಿಕಪà³</translation>
+<translation id="1663943134801823270">ಕಾರà³à²¡à³â€Œà²—ಳೠಮತà³à²¤à³ ವಿಳಾಸಗಳನà³à²¨à³ Chrome ನಿಂದ ಪಡೆಯಲಾಗಿದೆ. ನೀವೠಅವà³à²—ಳನà³à²¨à³ <ph name="BEGIN_LINK" />ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿<ph name="END_LINK" /> ನಿರà³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> ಸಾಮಾನà³à²¯à²µà²¾à²—ಿ ನಿಮà³à²® ಮಾಹಿತಿಯನà³à²¨à³ ಸಂರಕà³à²·à²¿à²¸à²²à³ ಎನà³â€Œà²•à³à²°à²¿à²ªà³à²¶à²¨à³ ಪà³à²°à²¯à³‹à²œà²¨à²µà²¨à³à²¨à³ ಬಳಸಿಕೊಳà³à²³à³à²¤à³à²¤à²¦à³†. ಈ ಸಂದರà³à²­à²¦à²²à³à²²à²¿ Google Chrome <ph name="SITE" /> ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ೆ ಸಂಪರà³à²•à²¿à²¸à²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿à²¦à²¾à²—, ಆ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œâ€Œ ಅಸಹಜ ಮತà³à²¤à³ ತಪà³à²ªà³ ರà³à²œà³à²µà²¾à²¤à³à²—ಳನà³à²¨à³ ಹಿಂತಿರà³à²—ಿಸಿದೆ. ದಾಳಿಕೋರರೠ<ph name="SITE" /> ರೂಪದಲà³à²²à²¿ ಸೋಗೠಹಾಕಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à³à²¤à³à²¤à²¿à²°à³à²µà²¾à²— ಅಥವಾ ವೈ-ಫೈ ಸೈನà³-ಇನೠಪರದೆಯೠಸಂಪರà³à²•à²•à³à²•à³† ಅಡà³à²¡à²¿à²¯à³à²‚ಟೠಮಾಡಿದಾಗ ಇದೠಕಂಡà³à²¬à²°à²¬à²¹à³à²¦à³. ಯಾವà³à²¦à³‡ ಡೇಟಾವನà³à²¨à³ ವಿನಿಮಯ ಮಾಡಿಕೊಳà³à²³à³à²µ ಮೊದಲೇ Google Chrome ಸಂಪರà³à²• ಕಡಿತಗೊಳಿಸಿರà³à²µ ಕಾರಣ, ನಿಮà³à²® ಮಾಹಿತಿ ಈಗಲೂ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿದೆ.</translation>
<translation id="168328519870909584"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ನಲà³à²²à²¿à²°à³à²µ ದಾಳಿಕೋರರೠನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರà³â€Œà²¨à²²à³à²²à²¿à²°à³à²µ ಮಾಹಿತಿ (ಉದಾಹರಣೆಗೆ, ಫೋಟೋಗಳà³, ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳೠಮತà³à²¤à³ ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³ ಮಾಹಿತಿಗಳà³) ಕದಿಯಲೠಇಲà³à²²à²µà³‡ ಅಳಿಸಲೠಅಪಾಯಕಾರಿ ಪà³à²°à³‹à²—à³à²°à²¾à²‚ಗಳನà³à²¨à³ ಸà³à²¥à²¾à²ªà²¿à²¸à²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à³.</translation>
<translation id="168841957122794586">ಸರà³à²µà²°à³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ದà³à²°à³à²¬à²² ಕà³à²°à²¿à²ªà³à²Ÿà³‹à²—à³à²°à²¾à²«à²¿à²•à³ ಕೀಯನà³à²¨à³ ಹೊಂದಿದೆ.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">ಈ ಸೈಟà³â€Œà²—ೆ ಭೇಟಿ ನೀಡಲೠನಿಮಗೆ <ph name="NAME" /> ಅವರ ಅನà³à²®à²¤à²¿à²¯ ಅಗತà³à²¯à²µà²¿à²°à³à²¤à³à²¤à²¦à³†</translation>
+<translation id="1721424275792716183">* ಈ ಫೀಲà³à²¡à³ ಅಗತà³à²¯à²µà²¿à²¦à³†</translation>
<translation id="1728677426644403582">ನೀವೠವೆಬೠಪà³à²Ÿà²¦ ಮೂಲವನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à³à²¤à³à²¤à²¿à²°à³à²µà²¿à²°à²¿</translation>
+<translation id="173080396488393970">ಈ ರೀತಿಯ ಕಾರà³à²¡à³â€Œà²—ೆ ಬೆಂಬಲವಿಲà³à²²</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">ಸಿಸà³à²Ÿà²‚ ನಿರà³à²µà²¾à²¹à²•à²°à²¨à³à²¨à³ ಸಂಪರà³à²•à²¿à²¸à²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
+<translation id="1740951997222943430">ಮಾನà³à²¯à²µà²¾à²¦ ಅವಧಿ-ಮà³à²•à³à²¤à²¾à²¯ ತಿಂಗಳನà³à²¨à³ ನಮೂದಿಸಿ</translation>
<translation id="1745358365027406341">ನಂತರ ಪà³à²Ÿ ಡೌನà³â€Œà²²à³‹à²¡à³ ಮಾಡಿ</translation>
<translation id="17513872634828108">ತೆರೆದ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳà³</translation>
<translation id="1753706481035618306">ಪà³à²Ÿ ಸಂಖà³à²¯à³†</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">ದಯವಿಟà³à²Ÿà³ ನಿಮà³à²® ಸಿಂಕೠಪಾಸà³â€Œà²«à³à²°à³‡à²¸à³ ಅನà³à²¨à³ ನವೀಕರಿಸಿ.</translation>
<translation id="1787142507584202372">ನಿಮà³à²® ತೆರೆಯಲಾದ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳೠಇಲà³à²²à²¿ ಗೋಚರಿಸà³à²¤à³à²¤à²¦à³†</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">ವಿತರಣೆಯ ವಿಧಾನಗಳೠಮತà³à²¤à³ ಅಗತà³à²¯à²¤à³†à²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಲೠವಿತರಣೆಯ ವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³†à²®à²¾à²¡à²¿.</translation>
+<translation id="1803264062614276815">ಕಾರà³à²¡à³â€Œà²¹à³‹à²²à³à²¡à²°à³ ಹೆಸರà³</translation>
<translation id="1803678881841855883">Google ಸà³à²°à²•à³à²·à²¿à²¤ ಬà³à²°à³Œà²¸à³ ಮಾಡà³à²µà²¿à²•à³† ಇತà³à²¤à³€à²šà³†à²—ೆ <ph name="SITE" /> ನಲà³à²²à²¿ <ph name="BEGIN_LINK" />ಮಾಲà³â€Œà²µà³‡à²°à³ ಪತà³à²¤à³†à²¹à²šà³à²šà²¿à²¦à³†<ph name="END_LINK" />. ಸಾಮಾನà³à²¯à²µà²¾à²—ಿ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿರà³à²µ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳೠಕೆಲವೊಮà³à²®à³† ಮಾಲà³â€Œà²µà³‡à²°à³ ದಾಳಿಗೆ ತà³à²¤à³à²¤à²¾à²—ಿರà³à²¤à³à²¤à²µà³†. ದà³à²°à³à²¦à³à²¦à³‡à²¶à²ªà³‚ರಿತ ವಿಷಯವೠಚಿರಪರಿಚಿತ ಮಾಲà³â€Œà²µà³‡à²°à³ <ph name="SUBRESOURCE_HOST" /> ವಿತರಕರಿಂದ ಬರà³à²¤à³à²¤à²µà³†. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1806541873155184440"><ph name="ADDED_TO_AUTOFILL_MONTH" /> ಸೇರಿಸಲಾಗಿದೆ</translation>
<translation id="1821930232296380041">ಅಮಾನà³à²¯à²µà²¾à²¦ ವಿನಂತಿ ಅಥವಾ ವಿನಂತಿ ಪà³à²¯à²¾à²°à²¾à²®à³€à²Ÿà²°à³â€Œà²—ಳà³</translation>
<translation id="1826516787628120939">ಪರಿಶೀಲಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†</translation>
<translation id="1834321415901700177">ಈ ಸೈಟೠಹಾನಿಕಾರಕ ಪà³à²°à³†à³‚ೕಗà³à²°à²¾à²‚ಗಳನà³à²¨à³ ಹೊಂದಿದೆ</translation>
<translation id="1842969606798536927">ಪಾವತಿಸಿ</translation>
-<translation id="1864455488461349376">ವಿತರಣೆಯ ಆಯà³à²•à³†à²—ಳà³</translation>
<translation id="1871208020102129563">.pac ಸà³à²•à³à²°à²¿à²ªà³à²Ÿà³ URL ಅಲà³à²²à²¦à³†, ನಿಗಧಿತ ಪà³à²°à²¾à²•à³à²¸à²¿ ಸರà³à²µà²°à³â€Œà²—ಳನà³à²¨à³ ಬಳಸಲೠಪà³à²°à²¾à²•à³à²¸à²¿à²¯à²¨à³à²¨à³ ಹೊಂದಿಸಲಾಗಿದೆ.</translation>
<translation id="1871284979644508959">ಅಗತà³à²¯ ಕà³à²·à³†à³•à²¤à³à²°</translation>
<translation id="187918866476621466">ಆರಂಭಿಕ ಪà³à²Ÿà²—ಳನà³à²¨à³ ತೆರೆಯಿರಿ</translation>
<translation id="1883255238294161206">ಪಟà³à²Ÿà²¿à²¯à²¨à³à²¨à³ ಸಂಕà³à²šà²¿à²¸à²¿</translation>
<translation id="1898423065542865115">ಫಿಲà³à²Ÿà²°à²¿à²‚ಗà³</translation>
<translation id="194030505837763158"><ph name="LINK" /> ಗೆ ಹೋಗಿ</translation>
-<translation id="1946821392246652573">ಸಮà³à²®à²¤à²¿à²¸à²²à²¾à²¦ ಕಾರà³à²¡à³â€Œà²—ಳà³</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳà³</translation>
<translation id="1973335181906896915">ಅನà³à²•à³à²°à²®à²—ೊಳಿಸà³à²µà²¿à²•à³†à²¯ ದೋಷ</translation>
<translation id="1974060860693918893">ಸà³à²§à²¾à²°à²¿à²¤</translation>
<translation id="1978555033938440688">ಫರà³à²®à³â€Œà²µà³‡à²°à³ ಆವೃತà³à²¤à²¿</translation>
+<translation id="1995859865337580572">ನಿಮà³à²® CVC ಪರಿಶೀಲಿಸಿ</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{ಮತà³à²¤à³ 1 ಇನà³à²¨à²·à³à²Ÿà³}one{ಮತà³à²¤à³ # ಇನà³à²¨à²·à³à²Ÿà³}other{ಮತà³à²¤à³ # ಇನà³à²¨à²·à³à²Ÿà³}}</translation>
-<translation id="2020194265157481222">ಕಾರà³à²¡à³â€Œà²¨à²²à³à²²à²¿à²°à³à²µ ಹೆಸರೠಅಗತà³à²¯à²µà²¿à²¦à³†</translation>
<translation id="2025186561304664664">ಪà³à²°à²¾à²•à³à²¸à²¿à²¯à²¨à³à²¨à³ ಸà³à²µà²¯à²‚ ಕಾನà³à²«à²¿à²—ರೠಆಗಿ ಹೊಂದಿಸಲಾಗಿದೆ.</translation>
<translation id="2030481566774242610">ನಿಮà³à²® ಮಾತಿನ ಅರà³à²¥ <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />ಪà³à²°à²¾à²•à³à²¸à²¿ ಮತà³à²¤à³ ಫೈರà³â€Œà²µà²¾à²²à³ ಅನà³à²¨à³ ಪರಿಶೀಲಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">ಇಂದà³</translation>
<translation id="2154054054215849342">ಸಿಂಕೠಸೇವೆಯೠನಿಮà³à²® ಡೊಮೇನà³â€Œà²—ೆ ಲಭà³à²¯à²µà²¿à²²à³à²²</translation>
<translation id="2154484045852737596">ಕಾರà³à²¡à³ ಎಡಿಟೠಮಾಡಿ</translation>
-<translation id="2156993118928861787">ಅಮಾನà³à²¯ ವಿಳಾಸ</translation>
<translation id="2166049586286450108">ಪೂರà³à²£ ನಿರà³à²µà²¾à²¹à²• ಪà³à²°à²µà³‡à²¶</translation>
<translation id="2166378884831602661">ಈ ಸೈಟà³â€Œà²—ೆ ಸà³à²°à²•à³à²·à²¿à²¤ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಒದಗಿಸಲಾಗà³à²µà³à²¦à²¿à²²à³à²²</translation>
<translation id="2181821976797666341">ನಿಯಮಗಳà³</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 ವಿಳಾಸ}one{# ವಿಳಾಸಗಳà³}other{# ವಿಳಾಸಗಳà³}}</translation>
+<translation id="2202020181578195191">ಮಾನà³à²¯à²µà²¾à²¦ ಅವಧಿ-ಮà³à²•à³à²¤à²¾à²¯ ವರà³à²·à²µà²¨à³à²¨à³ ನಮೂದಿಸಿ</translation>
<translation id="2212735316055980242">ನೀತಿ ಕಂಡೠಬಂದಿಲà³à²²</translation>
<translation id="2213606439339815911">ನಮೂದà³à²—ಳನà³à²¨à³ ಪಡೆಯಲಾಗà³à²¤à³à²¤à²¿à²¦à³†...</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />ಡಯಾಗà³à²¨à²¸à³à²Ÿà²¿à²•à³à²¸à³â€Œâ€Œ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œ<ph name="END_LINK" /> ಬಳಸಿಕೊಂಡೠನಿಮà³à²® ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಸರಿಪಡಿಸಿ</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">ನಿಮà³à²® ಇಂಟರà³à²¨à³†à²Ÿà³ ಪà³à²°à²µà³‡à²¶ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
<translation id="230155334948463882">ಹೊಸ ಕಾರà³à²¡à³?</translation>
<translation id="2305919008529760154">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ನಕಲಿ ಇರಬಹà³à²¦à³. ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">ಕಾರà³à²¡à³ ಮತà³à²¤à³ ವಿಳಾಸ ಆಯà³à²•à³†à²—ಳೠನಿಮà³à²® Google ಖಾತೆ (<ph name="ACCOUNT_EMAIL" />) ಮತà³à²¤à³ Chrome ನಿಂದ ಬಂದಿವೆ. ನೀವೠಇವà³à²—ಳನà³à²¨à³ <ph name="BEGIN_LINK" />ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿<ph name="END_LINK" /> ನಿರà³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> ಗೆ ಬಳಕೆದಾರಹೆಸರೠಮತà³à²¤à³ ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅಗತà³à²¯à²µà²¿à²¦à³†.</translation>
<translation id="2318774815570432836">ವೆಬà³â€Œà²¸à³ˆà²Ÿà³ HSTS ಬಳಸà³à²µ ಕಾರಣ ಇದೀಗ ನೀವೠ<ph name="SITE" /> ಗೆ ಭೇಟಿ ಮಾಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². ನೆಟà³â€Œà²µà²°à³à²•à³ ದೋಷಗಳೠಮತà³à²¤à³ ದಾಳಿಗಳೠಸಾಮಾನà³à²¯à²µà²¾à²—ಿ ತಾತà³à²•à²¾à²²à²¿à²•à²µà²¾à²—ಿರà³à²¤à³à²¤à²µà³†, ಹೀಗಾಗಿ ಈ ಪà³à²Ÿà²µà³ ನಂತರ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">ಇತರ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳà³</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">ಎಂಟರà³â€Œà²ªà³à²°à³ˆà²¸à³ ಡಿಫಾಲà³à²Ÿà³</translation>
<translation id="2386255080630008482">ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಹಿಂಪಡೆಯಲಾಗಿದೆ.</translation>
<translation id="2392959068659972793">ಯಾವà³à²¦à³‡ ಮೌಲà³à²¯ ಹೊಂದಿಸಿಲà³à²²à²¦ ನೀತಿಗಳನà³à²¨à³ ತೋರಿಸಿ</translation>
+<translation id="239429038616798445">ಈ ಶಿಪà³à²ªà²¿à²‚ಗೠವಿಧಾನ ಲಭà³à²¯à²µà²¿à²²à³à²². ಬೇರೊಂದೠವಿಧಾನವನà³à²¨à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="2396249848217231973">&amp;ಅಳಿಸà³à²µà³à²¦à²¨à³à²¨à³ ರದà³à²¦à³à²—ೊಳಿಸà³</translation>
<translation id="2460160116472764928">Google ಸà³à²°à²•à³à²·à²¿à²¤ ಬà³à²°à³Œà²¸à³ ಮಾಡà³à²µà²¿à²•à³† ಇತà³à²¤à³€à²šà³†à²—ೆ <ph name="SITE" /> ನಲà³à²²à²¿ <ph name="BEGIN_LINK" />ಮಾಲà³â€Œà²µà³‡à²°à³ ಪತà³à²¤à³†à²¹à²šà³à²šà²¿à²¦à³†<ph name="END_LINK" />. ಸಾಮಾನà³à²¯à²µà²¾à²—ಿ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿರà³à²µ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳೠಕೆಲವೊಮà³à²®à³† ಮಾಲà³â€Œà²µà³‡à²°à³ ದಾಳಿಗೆ ತà³à²¤à³à²¤à²¾à²—ಿರà³à²¤à³à²¤à²µà³†. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2463739503403862330">ಭರà³à²¤à²¿ ಮಾಡà³</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />ನೆಟà³â€Œà²µà²°à³à²•à³ ಡಯಾಗà³à²¨à²¾à²¸à³à²Ÿà²¿à²•à³à²¸à³â€Œ ರನೠಆಗà³à²¤à³à²¤à²¿à²¦à³†<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">ಅಮಾನà³à²¯à²µà²¾à²¦ ಹà³à²¡à³à²•à²¾à²Ÿ URL.</translation>
<translation id="2491120439723279231">ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ದೋಷಗಳನà³à²¨à³ ಹೊಂದಿದೆ.</translation>
-<translation id="24943777258388405">ಅಮಾನà³à²¯à²µà²¾à²¦ ಫೋನೠಸಂಖà³à²¯à³†</translation>
<translation id="2495083838625180221">JSON ವಿಶà³à²²à³‡à²·à²•</translation>
<translation id="2495093607237746763">ಪರಿಶೀಲಿಸಿದರೆ, ವೇಗವಾಗಿ ಫಾರà³à²®à³ ಭರà³à²¤à²¿ ಮಾಡಲೠChromium ಈ ಸಾಧನದಲà³à²²à²¿ ನಿಮà³à²® ಕಾರà³à²¡à³â€Œà²¨ ಪà³à²°à²¤à²¿à²¯à²¨à³à²¨à³ ಸಂಗà³à²°à²¹à²¿à²¸à³à²¤à³à²¤à²¦à³†.</translation>
<translation id="2498091847651709837">ಹೊಸ ಕಾರà³à²¡à³ ಸà³à²•à³à²¯à²¾à²¨à³ ಮಾಡಿ</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> ಅಮಾನà³à²¯ ಪà³à²°à²¤à²¿à²•à³à²°à²¿à²¯à³† ಕಳà³à²¹à²¿à²¸à²¿à²¦à³†.</translation>
<translation id="2552545117464357659">ನವೀನ</translation>
<translation id="2556876185419854533">&amp;ಸಂಪಾದಿಸà³à²µà³à²¦à²¨à³à²¨à³ ರದà³à²¦à³à²—ೊಳಿಸಿ</translation>
+<translation id="2587730715158995865"><ph name="ARTICLE_PUBLISHER" /> ಅವರಿಂದ. ಇದನà³à²¨à³ ಮತà³à²¤à³ ಇತರ <ph name="OTHER_ARTICLE_COUNT" /> ಸà³à²¦à³à²¦à²¿à²—ಳನà³à²¨à³ ಓದಿ.</translation>
<translation id="2587841377698384444">ಡೈರೆಕà³à²Ÿà²°à²¿ API ID:</translation>
<translation id="2597378329261239068">ಈ ಡಾಕà³à²¯à³à²®à³†à²‚ಟà³â€Œ ಅನà³à²¨à³ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²¨à²¿à²‚ದ ರಕà³à²·à²¿à²¸à²²à²¾à²—ಿದೆ. ದಯವಿಟà³à²Ÿà³ ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅನà³à²¨à³ ನಮೂದಿಸಿ.</translation>
<translation id="2609632851001447353">ಪರಿವರà³à²¤à²¨à³†à²—ಳà³</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />ಸಂಪರà³à²• ಡಯಾಗà³à²¨à²¾à²¸à³à²Ÿà²¿à²•à³à²¸à³â€Œ ರನೠಆಗà³à²¤à³à²¤à²¿à²¦à³†<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">ಸರಿ</translation>
<translation id="2742870351467570537">ಆಯà³à²•à³†à²®à²¾à²¡à²¿à²¦ à²à²Ÿà²‚ಗಳನà³à²¨à³ ತೆಗೆದà³à²¹à²¾à²•à²¿</translation>
+<translation id="277133753123645258">ಶಿಪà³à²ªà²¿à²‚ಗೠವಿಧಾನ</translation>
<translation id="277499241957683684">ಸಾಧನದ ರೆಕಾರà³à²¡à³ ಕಾಣೆಯಾಗಿದೆ</translation>
<translation id="2784949926578158345">ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ರೀಸೆಟೠಮಾಡಲಾಗಿದೆ.</translation>
<translation id="2794233252405721443">ಸೈಟೠನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
-<translation id="2812680587231492111">ಆರಿಸಿಕೊಳà³à²³à³à²µ ಆಯà³à²•à³† ಲಭà³à²¯à²µà²¿à²²à³à²². ಬೇರೆ ಆಯà³à²•à³†à²¯à²¨à³à²¨à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="2824775600643448204">ವಿಳಾಸ ಹಾಗೂ ಹà³à²¡à³à²•à²¾à²Ÿ ಪಟà³à²Ÿà²¿</translation>
<translation id="2826760142808435982"><ph name="CIPHER" /> ಬಳಸಿಕೊಂಡೠಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಎನà³â€Œà²•à³à²°à²¿à²ªà³à²Ÿà³ ಮಾಡಲಾಗಿದೆ ಮತà³à²¤à³ ದೃಢೀಕರಿಸಲಾಗಿದೆ ಮತà³à²¤à³ <ph name="KX" /> ಅನà³à²¨à³ ಕೀ ವಿನಿಮಯ ಯಾಂತà³à²°à²¿à²•à²¤à³†à²¯à²‚ತೆ ಬಳಸà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="2835170189407361413">ಫಾರà³à²®à³ ತೆರವà³à²—ೊಳಿಸà³</translation>
-<translation id="2849041323157393173">ಆ ವಿತರಣೆಯೠಆಯà³à²•à³† ಲಭà³à²¯à²µà²¿à²²à³à²². ಬೇರೆ ಆಯà³à²•à³†à²¯à²¨à³à²¨à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="2889159643044928134">ಮರà³à²²à³‹à²¡à³ ಮಾಡಬೇಡ</translation>
<translation id="2900469785430194048">ಈ ವೆಬà³â€Œà²ªà³à²Ÿ ಪà³à²°à²¦à²°à³à²¶à²¿à²¸à²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à³à²µà²¾à²— Google Chrome ಮೆಮೊರಿ ಖಾಲಿಯಾಗಿದೆ.</translation>
<translation id="2909946352844186028">ನೆಟà³â€Œà²µà²°à³à²•à³ ಬದಲಾವಣೆಯನà³à²¨à³ ಪತà³à²¤à³† ಮಾಡಲಾಗಿದೆ.</translation>
<translation id="2916038427272391327">ಇತರ ಪà³à²°à³‹à²—à³à²°à²¾à²‚ಗಳನà³à²¨à³ ಮà³à²šà³à²šà²¿</translation>
<translation id="2922350208395188000">ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಪರಿಶೀಲಿಸಲಾಗà³à²µà³à²¦à²¿à²²à³à²².</translation>
+<translation id="2928905813689894207">ಬಿಲà³à²²à²¿à²‚ಗೠವಿಳಾಸ</translation>
<translation id="2948083400971632585">ಸಂಪರà³à²•à²•à³à²•à²¾à²—ಿ ಕಾನà³à²«à²¿à²—ರೠಮಾಡಲಾಗಿರà³à²µ ಯಾವà³à²¦à³‡ ಪà³à²°à²¾à²•à³à²¸à²¿à²—ಳನà³à²¨à³ ನೀವೠಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳ ಪà³à²Ÿà²¦à²¿à²‚ದ ನಿಷà³à²•à³à²°à²¿à²¯à²—ೊಳಿಸಬಹà³à²¦à³.</translation>
<translation id="2955913368246107853">ಹà³à²¡à³à²•à²¿ ಬಾರೠಅನà³à²¨à³ ಮà³à²šà³à²šà²¿</translation>
<translation id="2958431318199492670">ONC ಪà³à²°à²®à²¾à²£à²¿à²¤à²•à³à²•à³† ನೆಟà³â€Œà²µà²°à³à²•à³ ಕಾನà³à²«à²¿à²—ರೇಶನೠಅನà³à²¸à²°à²£à³†à²¯à²¾à²—à³à²µà³à²¦à²¿à²²à³à²². ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨ ಭಾಗಗಳನà³à²¨à³ ಆಮದೠಮಾಡಲಾಗದಿರಬಹà³à²¦à³.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">ಸà³à²°à²•à³à²·à²¿à²¤ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಸà³à²¥à²¾à²ªà²¿à²¸à²²à³, ನಿಮà³à²® ಗಡಿಯಾರವನà³à²¨à³ ಸರಿಯಾಗಿ ಹೊಂದಿಸಬೇಕಾದ ಅಗತà³à²¯à²µà²¿à²¦à³†. ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳೠತಮà³à²®à²¨à³à²¨à³ ಗà³à²°à³à²¤à²¿à²¸à²²à³ ಬಳಸà³à²µ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²—ಳೠನಿರà³à²¦à²¿à²·à³à²Ÿ ಅವಧಿಗಳಲà³à²²à²¿ ಮಾತà³à²° ಮಾನà³à²¯à²µà²¾à²—ಿರà³à²µ ಕಾರಣ ಹೀಗಾಗà³à²¤à³à²¤à²¦à³†. ನಿಮà³à²® ಸಾಧನದ ಗಡಿಯಾರವೠತಪà³à²ªà²¾à²—ಿರà³à²µ ಕಾರಣ, Google Chrome ಗೆ ಈ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಲೠಸಾಧà³à²¯à²µà²¾à²—à³à²µà³à²¦à²¿à²²à³à²².</translation>
<translation id="2972581237482394796">&amp;ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
<translation id="2985306909656435243">ಸಕà³à²°à²¿à²¯à²—ೊಳಿಸಿದà³à²¦à²°à³†, ವೇಗವಾಗಿ ಫಾರà³à²®à³ ಭರà³à²¤à²¿ ಮಾಡಲೠChromium ಈ ಸಾಧನದಲà³à²²à²¿ ನಿಮà³à²® ಕಾರà³à²¡à³â€Œà²¨ ಪà³à²°à²¤à²¿à²¯à²¨à³à²¨à³ ಸಂಗà³à²°à²¹à²¿à²¸à³à²¤à³à²¤à²¦à³†.</translation>
+<translation id="2985398929374701810">ಮಾನà³à²¯ ವಿಳಾಸವನà³à²¨à³ ನಮೂದಿಸಿ</translation>
+<translation id="2986368408720340940">ಈ ಪಿಕಪೠವಿಧಾನ ಲಭà³à²¯à²µà²¿à²²à³à²². ಬೇರೊಂದೠವಿಧಾನವನà³à²¨à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="2991174974383378012">ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳ ಜೊತೆಗೆ ಹಂಚಿಕೊಳà³à²³à³à²µà³à²¦à³</translation>
<translation id="3005723025932146533">ಉಳಿಸಲಾದ ನಕಲನà³à²¨à³ ತೋರಿಸà³</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> ಗೆ CVC ಅನà³à²¨à³ ನಮೂದಿಸಿ. ನೀವೠಒಮà³à²®à³† ಖಚಿತಪಡಿಸಿದರೆ, ನಿಮà³à²® ಕಾರà³à²¡à³ ವಿವರಗಳನà³à²¨à³ ಈ ಸೈಟೠಜೊತೆಗೆ ಹಂಚಿಕೊಳà³à²³à²²à²¾à²—à³à²¤à³à²¤à²¦à³†.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{ಸಿಂಕೠಮಾಡಿದ ಸಾಧನಗಳಲà³à²²à²¿ ಕನಿಷà³à²Ÿ 1 à²à²Ÿà²‚}=1{1 à²à²Ÿà²‚ (ಮತà³à²¤à³ ಸಿಂಕೠಮಾಡಿದ ಸಾಧನಗಳಲà³à²²à²¿ ಇನà³à²¨à²·à³à²Ÿà³)}one{# à²à²Ÿà²‚ಗಳೠ(ಮತà³à²¤à³ ಸಿಂಕೠಮಾಡಿದ ಸಾಧನಗಳಲà³à²²à²¿ ಇನà³à²¨à²·à³à²Ÿà³)}other{# à²à²Ÿà²‚ಗಳೠ(ಮತà³à²¤à³ ಸಿಂಕೠಮಾಡಿದ ಸಾಧನಗಳಲà³à²²à²¿ ಇನà³à²¨à²·à³à²Ÿà³)}}</translation>
<translation id="3041612393474885105">ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಮಾಹಿತಿ</translation>
<translation id="3063697135517575841">ಈ ಸಮಯದಲà³à²²à²¿ Chrome ಗೆ ನಿಮà³à²® ಕಾರà³à²¡à³ ಅನà³à²¨à³ ಖಚಿತಪಡಿಸಲೠಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²². ದಯವಿಟà³à²Ÿà³ ನಂತರ ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
+<translation id="3064966200440839136">ಬಾಹà³à²¯ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œâ€Œ ಮೂಲಕರ ಪಾವತಿಸಲೠಅದೃಶà³à²¯ ಮೋಡà³â€Œâ€Œ ತೊರೆಯಲಾಗà³à²¤à³à²¤à²¿à²¦à³†. ಮà³à²‚ದà³à²µà²°à²¿à²¸à³à²µà³à²¦à³‡?</translation>
<translation id="3093245981617870298">ನೀವೠಆಫà³â€Œà²²à³ˆà²¨à³â€Œà²¨à²²à³à²²à²¿à²°à³à²µà²¿à²°à²¿.</translation>
<translation id="3105172416063519923">ಸà³à²µà²¤à³à²¤à³ ID:</translation>
<translation id="3109728660330352905">ಈ ಪà³à²Ÿ ವೀಕà³à²·à²¿à²¸à³à²µ ಅಧಿಕಾರ ನಿಮಗಿಲà³à²²</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />ಸಂಪರà³à²• ಡಯಾಗà³à²¨à²¾à²¸à³à²Ÿà²¿à²•à³à²¸à³ ರನೠಮಾಡಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿â€Œ<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">ಪà³à²°à²¤à²¿à²•à³à²°à²¿à²¯à³†à²¯à²¨à³à²¨à³ ಡೀಕೋಡೠಮಾಡಲೠವಿಫಲವಾಗಿದೆ</translation>
-<translation id="3149891296864842641">ಶಿಪà³à²ªà²¿à²‚ಗೠಆಯà³à²•à³†</translation>
<translation id="3150653042067488994">ತಾತà³à²•à²¾à²²à²¿à²• ಸರà³à²µà²°à³ ದೋಷ</translation>
+<translation id="3154506275960390542">ಈ ಪà³à²Ÿà²¦à²²à³à²²à²¿à²°à³à²µ ಒಂದೠಫಾರà³à²®à³ ಅನà³à²¨à³ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿ ಸಲà³à²²à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ದಿರಬಹà³à²¦à³. ರವಾನಿಸà³à²µ ಸಮಯದಲà³à²²à²¿, ನೀವೠಕಳà³à²¹à²¿à²¸à³à²µ ಡೇಟಾವನà³à²¨à³ ಇತರರೠವೀಕà³à²·à²¿à²¸à²¬à²¹à³à²¦à³ ಅಥವಾ ಸರà³à²µà²°à³ ಪಡೆಯà³à²µ ವಿಷಯವನà³à²¨à³ ದಾಳಿಕೋರರೠಮಾರà³à²ªà²¡à²¿à²¸à²¬à²¹à³à²¦à³.</translation>
<translation id="3157931365184549694">ಮರà³à²¸à³à²¥à²¾à²ªà²¨à³†</translation>
<translation id="3167968892399408617">ನಿಮà³à²® ಎಲà³à²²à²¾ ಅಪರಿಚಿತ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳನà³à²¨à³ ಮà³à²šà³à²šà²¿à²¦ ಬಳಿಕ ನೀವೠಅಪರಿಚಿತ ಮೋಡà³â€Œà²¨à²²à³à²²à²¿ ವೀಕà³à²·à²¿à²¸à²¿à²¦ ಪà³à²Ÿà²—ಳೠಬà³à²°à³Œà²¸à²°à³ ಇತಿಹಾಸದಲà³à²²à²¿, ಕà³à²•à³€ ಸಂಗà³à²°à²¹à²¦à²²à³à²²à²¿ ಅಥವಾ ಹà³à²¡à³à²•à²¾à²Ÿ ಇತಿಹಾಸದಲà³à²²à²¿ ಉಳಿಯà³à²µà³à²¦à²¿à²²à³à²². ನೀವೠಡೌನà³â€Œà²²à³‹à²¡à³ ಮಾಡà³à²µ ಯಾವà³à²¦à³‡ ಫೈಲà³â€Œà²—ಳೠಇಲà³à²²à²µà³‡ ನೀವೠರಚಿಸà³à²µ ಯಾವà³à²¦à³‡ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳನà³à²¨à³ ಹಾಗೆಯೇ ಇರಿಸಲಾಗà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -261,11 +269,13 @@
<translation id="3345135638360864351">ಈ ಸೈಟೠಅನà³à²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à²²à³ ನೀವೠಸಲà³à²²à²¿à²¸à²¿à²¦ ವಿನಂತಿಯನà³à²¨à³ <ph name="NAME" /> ಗೆ ಕಳà³à²¹à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²². ದಯವಿಟà³à²Ÿà³ ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="3355823806454867987">ಪà³à²°à²¾à²•à³à²¸à²¿ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ಬದಲಿಸಿ...</translation>
<translation id="3369192424181595722">ಗಡಿಯಾರ ದೋಷ</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> ಇನà³à²¨à²·à³à²Ÿà³ à²à²Ÿà²‚ಗಳà³...</translation>
<translation id="337363190475750230">ಅನà³à²®à²¤à²¿ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
<translation id="3377188786107721145">ನೀತಿಯ ಪಾರà³à²¸à³ ದೋಷ</translation>
<translation id="3380365263193509176">ಅಪರಿಚಿತ ದೋಷ</translation>
<translation id="3380864720620200369">ಕà³à²²à³ˆà²‚ಟೠID:</translation>
<translation id="3391030046425686457">ವಿತರಣೆಯ ವಿಳಾಸಗಳà³</translation>
+<translation id="3395827396354264108">ಪಿಕಪೠವಿಧಾನ</translation>
<translation id="340013220407300675"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ರಿಂದ ದಾಳಿಕೋರರೠನಿಮà³à²® ಮಾಹಿತಿಯನà³à²¨à³ ಕಳà³à²³à²¤à²¨ ಮಾಡಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à³ (ಉದಾಹರಣೆಗೆ, ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳà³, ಸಂದೇಶಗಳà³, ಅಥವಾ ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³â€Œà²—ಳà³).</translation>
<translation id="3422248202833853650">ಮೆಮೊರಿ ಮà³à²•à³à²¤à²—ೊಳಿಸಲೠಇತರ ಪà³à²°à³‹à²—à³à²°à²¾à²‚ಗಳನà³à²¨à³ ನಿರà³à²—ಮಿಸಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> ಅನà³à²¨à³ ಪà³à²°à²¸à³à²¤à³à²¤ ತಲà³à²ªà²²à²¾à²—à³à²¤à³à²¤à²¿à²²à³à²².</translation>
@@ -276,12 +286,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">ವಿರಾಮವನà³à²¨à³ ಪಡೆಯಿರಿ:</translation>
<translation id="3462200631372590220">ಸà³à²§à²¾à²°à²¿à²¤ ಆಯà³à²•à³†à²®à²¾à²¡à²¿</translation>
+<translation id="3467763166455606212">ಕಾರà³à²¡à³â€Œà²¹à³‹à²²à³à²¡à²°à³ ಹೆಸರೠಅಗತà³à²¯à²µà²¿à²¦à³†</translation>
+<translation id="3478058380795961209">ಮà³à²•à³à²¤à²¾à²¯à²¦ ತಿಂಗಳà³</translation>
<translation id="3479539252931486093">ಇದೠಅನಿರೀಕà³à²·à²¿à²¤à²µà³†à³•? <ph name="BEGIN_LINK" />ನಮಗೆ ತಿಳಿಸಿ<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">ಈಗ ಬೇಡ</translation>
<translation id="348000606199325318">ಕà³à²°à³à²¯à²¾à²¶à³ à²à²¡à²¿ <ph name="CRASH_LOCAL_ID" /> (ಸರà³à²µà²°à³ à²à²¡à²¿: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">ಈ ಕà³à²·à²£à²¦à²²à³à²²à²¿ ನಿಮà³à²® ಪೋಷಕರನà³à²¨à³ ತಲà³à²ªà²²à³ ನಮಗೆ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²². ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="3528171143076753409">ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ನಂಬಲರà³à²¹à²µà²¾à²—ಿಲà³à²².</translation>
-<translation id="3538531656504267329">ಅಮಾನà³à²¯ ಮà³à²•à³à²¤à²¾à²¯ ವರà³à²·</translation>
<translation id="3539171420378717834">ಈ ಸಾಧನದಲà³à²²à²¿ ಈ ಕಾರà³à²¡à³â€Œà²¨ ನಕಲನà³à²¨à³ ಇರಿಸಿಕೊಳà³à²³à²¿</translation>
<translation id="3542684924769048008">ಇದಕà³à²•à³† ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಬಳಸಿ:</translation>
<translation id="3549644494707163724">ನಿಮà³à²® ಸà³à²µà²‚ತ ಸಿಂಕೠಪಾಸà³â€Œà²«à³à²°à³‡à²¸à³â€Œà²¨à³†à³‚ಂದಿಗೆ ಸಿಂಕೠಆದ ಎಲà³à²²à²¾ ಡೇಟಾವನà³à²¨à³ ಎನà³â€Œà²•à³à²°à²¿à²ªà³à²Ÿà³ ಮಾಡಿ</translation>
@@ -294,6 +305,7 @@
<translation id="3586931643579894722">ವಿವರಗಳನà³à²¨à³ ಮರೆಮಾಡಿ</translation>
<translation id="3587482841069643663">ಎಲà³à²²</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">ಮಾನà³à²¯à²µà²¾à²¦ ಅವಧಿ-ಮà³à²•à³à²¤à²¾à²¯ ದಿನಾಂಕವನà³à²¨à³ ನಮೂದಿಸಿ</translation>
<translation id="36224234498066874">ಬà³à²°à³Œà²¸à³ ಆಗà³à²¤à³à²¤à²¿à²°à³à²µ ಡೇಟಾವನà³à²¨à³ ತೆರವà³à²—ೊಳಿಸಿ...</translation>
<translation id="362276910939193118">ಪೂರà³à²£ ಇತಿಹಾಸ ತೋರಿಸಿ</translation>
<translation id="3623476034248543066">ಮೌಲà³à²¯à²µà²¨à³à²¨à³ ತೋರಿಸಿ</translation>
@@ -309,7 +321,6 @@
<translation id="3693415264595406141">ಪಾಸà³â€Œà²µà²°à³à²¡à³:</translation>
<translation id="3696411085566228381">ಯಾವà³à²¦à³‚ ಇಲà³à²²</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">ಶಿಪà³à²ªà²¿à²‚ಗೠವಿಧಾನಗಳನà³à²¨à³ ಮತà³à²¤à³ ಅಗತà³à²¯à²¤à³†à²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಲೠಶಿಪà³à²ªà²¿à²‚ಗೠವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³†à²®à²¾à²¡à²¿.</translation>
<translation id="370665806235115550">ಲೋಡೠಆಗà³à²¤à³à²¤à²¿à²¦à³†...</translation>
<translation id="3712624925041724820">ಪರವಾನಗಿಗಳೠಬರಿದಾಗಿವೆ</translation>
<translation id="3714780639079136834">ಮೊಬೈಲೠಡೇಟಾ ಅಥವಾ ವೈ-ಫೈ ಆನೠಮಾಡಲಾಗà³à²¤à³à²¤à²¿à²¦à³†</translation>
@@ -318,6 +329,7 @@
<translation id="3739623965217189342">ನೀವೠನಕಲಿಸಿದ ಲಿಂಕà³</translation>
<translation id="375403751935624634">ಸರà³à²µà²°à³ ದೋಷದ ಕಾರಣ ಅನà³à²µà²¾à²¦à²µà³ ವಿಫಲವಾಗಿದೆ.</translation>
<translation id="3759461132968374835">ಇತà³à²¤à³€à²šà³†à²—ೆ ನೀವೠಯಾವà³à²¦à³‡ ಕà³à²°â€à³à²¯à²¾à²¶à³â€Œà²—ಳನà³à²¨à³ ವರದಿ ಮಾಡಿಲà³à²². ಕà³à²°â€à³à²¯à²¾à²¶à³â€Œâ€Œ ಅನà³à²¨à³ ವರದಿಮಾಡà³à²µà²¿à²•à³†à²¯à²¨à³à²¨à³ ಉಂಟಾಗಿರà³à²µ ಕà³à²°â€à³à²¯à²¾à²¶à³â€Œà²—ಳೠಇಲà³à²²à²¿ ಗೋಚರಿಸà³à²µà³à²¦à²¿à²²à³à²².</translation>
+<translation id="3787705759683870569">ಅವಧಿ-ಮà³à²•à³à²¤à²¾à²¯ <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">ನೀವೠಪà³à²°à²¾à²•à³à²¸à²¿ ಸರà³à²µà²°à³ ಬಳಸಿದರೆ...</translation>
<translation id="3828924085048779000">ಖಾಲಿ ಪಾಸà³â€Œà²«à³à²°à³‡à²¸à³ ಅನà³à²¨à³ ಅನà³à²®à²¤à²¿à²¸à³à²µà³à²¦à²¿à²²à³à²².</translation>
<translation id="3845539888601087042">ನಿಮà³à²® ಸೈನà³-ಇನೠಮಾಡಿದ ಸಾಧನಗಳಿಂದ ಇತಿಹಾಸವನà³à²¨à³ ತೋರಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†. <ph name="BEGIN_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LINK" />.</translation>
@@ -353,7 +365,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">ಈ ಕಾರà³à²¡à³ ಅನà³à²¨à³ Chromium ಉಳಿಸಬೇಕೆಂದೠನೀವೠಬಯಸà³à²µà²¿à²°à²¾?</translation>
<translation id="4171400957073367226">ತಪà³à²ªà³ ಪರಿಶೀಲನೆ ಸಹಿ</translation>
-<translation id="4176463684765177261">ನಿಷà³à²•à³à²°à²¿à²¯à²—ೊಳಿಸಲಾಗಿದೆ</translation>
<translation id="4196861286325780578">&amp;ಸರಿಸà³à²µà³à²¦à²¨à³à²¨à³ ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ಫೈರà³â€Œà²µà²¾à²²à³ ಮತà³à²¤à³ ಆಂಟಿವೈರಸೠಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œâ€Œà²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{ಯಾವà³à²¦à³‚ ಇಲà³à²²}=1{1 ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œ ($1)}=2{2 ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œà²—ಳೠ($1, $2)}one{# ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œà²—ಳೠ($1, $2, $3)}other{# ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œà²—ಳೠ($1, $2, $3)}}</translation>
@@ -380,11 +391,11 @@
<translation id="4406896451731180161">ಹà³à²¡à³à²•à²¾à²Ÿà²¦ ಫಲಿತಾಂಶಗಳà³</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ನಿಮà³à²® ಲಾಗಿನೠಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸà³à²µà³€à²•à²°à²¿à²¸à²²à²¿à²²à³à²² ಅಥವಾ ಅದನà³à²¨à³ ಒದಗಿಸದೆ ಇರಬಹà³à²¦à³.</translation>
<translation id="443673843213245140">ಪà³à²°à²¾à²•à³à²¸à²¿à²¯ ಬಳಕೆಯನà³à²¨à³ ನಿಷà³à²•à³à²°à²¿à²¯à²—ೊಳಿಸಲಾಗಿದೆ ಆದರೆ ಬಹಿರಂಗ ಪà³à²°à²¾à²•à³à²¸à²¿ ಕಾನà³à²«à²¿à²—ರೇಶನೠಅನà³à²¨à³ ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
-<translation id="4446242550670694251">ಈಗ ನೀವೠಖಾಸಗಿಯಾಗಿ ಬà³à²°à³Œà²¸à³ ಮಾಡಬಹà³à²¦à³ ಮತà³à²¤à³ ಈ ಸಾಧನವನà³à²¨à³ ಬಳಸà³à²µ ಇತರ ಜನರೠನಿಮà³à²® ಚಟà³à²µà²Ÿà²¿à²•à³†à²¯à²¨à³à²¨à³ ವೀಕà³à²·à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¿à²²à³à²².</translation>
<translation id="4492190037599258964"><ph name="SEARCH_STRING" />' ಕà³à²°à²¿à²¤ ಹà³à²¡à³à²•à²¾à²Ÿ ಫಲಿತಾಂಶಗಳà³</translation>
<translation id="4506176782989081258">ಮೌಲà³à²¯à³€à²•à²°à²¿à²¸à³à²µà²¿à²•à³†à²¯ ದೋಷ: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">ಸಿಸà³à²Ÿà²‚ ನಿರà³à²µà²¾à²¹à²•à²°à²¨à³à²¨à³ ಸಂಪರà³à²•à²¿à²¸à²²à²¾à²—à³à²¤à³à²¤à²¿à²¦à³†</translation>
<translation id="450710068430902550">ನಿರà³à²µà²¾à²¹à²•à²°à³Šà²‚ದಿಗೆ ಹಂಚಿಕೊಳà³à²³à³à²µà³à²¦à³</translation>
+<translation id="4515275063822566619">ಕಾರà³à²¡à³â€Œà²—ಳೠಮತà³à²¤à³ ವಿಳಾಸಗಳನà³à²¨à³ ನಿಮà³à²® Chrome ಮತà³à²¤à³ ನಿಮà³à²® Google ಖಾತೆಯಿಂದ (<ph name="ACCOUNT_EMAIL" />) ಪಡೆಯಲಾಗಿದೆ. ನೀವೠಅವà³à²—ಳನà³à²¨à³ <ph name="BEGIN_LINK" />ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿<ph name="END_LINK" /> ನಿರà³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³.</translation>
<translation id="4522570452068850558">ವಿವರಗಳà³</translation>
<translation id="4558551763791394412">ನಿಮà³à²® ವಿಸà³à²¤à²°à²£à³†à²—ಳನà³à²¨à³ ನಿಷà³à²•à³à²°à²¿à²¯à²—ೊಳಿಸಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="457875822857220463">ವಿತರಣೆ</translation>
@@ -414,6 +425,7 @@
<translation id="4816492930507672669">ಪà³à²Ÿà²•à³à²•à³† ಹೊಂದಿಸà³</translation>
<translation id="483020001682031208">ತೋರಿಸಲೠಯಾವà³à²¦à³‡ ಬೌದà³à²§à²¿à²• ವೆಬೠಪà³à²Ÿà²—ಳಿಲà³à²²</translation>
<translation id="4850886885716139402">ವೀಕà³à²·à²£à³†</translation>
+<translation id="4854362297993841467">ಈ ವಿತರಣೆಯ ವಿಧಾನ ಲಭà³à²¯à²µà²¿à²²à³à²². ಬೇರೊಂದೠವಿಧಾನವನà³à²¨à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="4858792381671956233">ಈ ಸೈಟೠಅನà³à²¨à³ ಭೇಟಿ ಮಾಡಬಹà³à²¦à³ ಎಂದೠನಿಮà³à²® ಪೋಷಕರಿಗೆ ನೀವೠಕೇಳಿರà³à²µà²¿à²°à²¿.</translation>
<translation id="4880827082731008257">ಹà³à²¡à³à²•à²¾à²Ÿ ಇತಿಹಾಸ</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -421,7 +433,6 @@
<translation id="4923417429809017348">ಗೊತà³à²¤à²¿à²²à³à²²à²¦ ಭಾಷೆಯಿಂದ <ph name="LANGUAGE_LANGUAGE" /> ಗೆ ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ ಭಾಷಾಂತರಿಸಲಾಗಿದೆ</translation>
<translation id="4923459931733593730">ಪಾವತಿ</translation>
<translation id="4926049483395192435">ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²¬à³‡à²•à²¾à²—ಿದೆ.</translation>
-<translation id="4941291666397027948">* ಅಗತà³à²¯ ಕà³à²·à³‡à²¤à³à²°à²µà²¨à³à²¨à³ ಸೂಚಿಸà³à²¤à³à²¤à²¦à³†</translation>
<translation id="495170559598752135">ಕà³à²°à²¿à²¯à³†à²—ಳà³</translation>
<translation id="4958444002117714549">ಪಟà³à²Ÿà²¿à²¯à²¨à³à²¨à³ ವಿಸà³à²¤à²°à²¿à²¸à²¿</translation>
<translation id="4962322354953122629">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ Chrome ನಿಂದ ವಿಶà³à²µà²¾à²¸à²¹à³Šà²‚ದಿಲà³à²². ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -436,6 +447,7 @@
<translation id="5045550434625856497">ತಪà³à²ªà³ ಪಾಸà³â€Œà²µà²°à³à²¡à³</translation>
<translation id="5056549851600133418">ನಿಮಗಾಗಿ ಲೇಖನಗಳà³</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />ಪà³à²°à²¾à²•à³à²¸à²¿ ವಿಳಾಸವನà³à²¨à³ ಪರಿಶೀಲಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{ಯಾವà³à²¦à³‡ ಕà³à²•à³€à²—ಳಿಲà³à²²}=1{1 ಸೈಟೠಕà³à²•à³€à²—ಳನà³à²¨à³ ಬಳಸà³à²¤à³à²¤à²¦à³†. }one{# ಸೈಟà³â€Œà²—ಳೠಕà³à²•à³€à²—ಳನà³à²¨à³ ಬಳಸà³à²¤à³à²¤à²µà³†. }other{# ಸೈಟà³â€Œà²—ಳೠಕà³à²•à³€à²—ಳನà³à²¨à³ ಬಳಸà³à²¤à³à²¤à²µà³†. }}</translation>
<translation id="5087286274860437796">ಈ ಸಮಯದಲà³à²²à²¿ ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಮಾನà³à²¯à²µà²¾à²—ಿಲà³à²².</translation>
<translation id="5087580092889165836">ಕಾರà³à²¡à³ ಸೇರಿಸಿ</translation>
<translation id="5089810972385038852">ರಾಜà³à²¯</translation>
@@ -458,10 +470,8 @@
<translation id="5300589172476337783">ಪà³à²°à²¦à²°à³à²¶à²¿à²¸à²¿</translation>
<translation id="5308689395849655368">ಕà³à²°â€à³à²¯à²¾à²¶à³â€Œâ€Œ ವರದಿಯನà³à²¨à³ ನಿಷà³à²•à³à²°à²¿à²¯à²—ೊಳಿಸಲಾಗಿದೆ.</translation>
<translation id="5317780077021120954">ಉಳಿಸà³</translation>
-<translation id="5326702247179446998">ಸà³à²µà²¿à³•à²•à²°à²¿à²¸à³à²µà²µà²° ಅಗತà³à²¯à²µà²¿à²¦à³†</translation>
<translation id="5327248766486351172">ಹೆಸರà³</translation>
<translation id="5337705430875057403"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ನಲà³à²²à²¿à²¨ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ಸಾಫà³à²Ÿà³â€Œà²µà³‡à²°à³ ಸà³à²¥à²¾à²ªà²¿à²¸à³à²µà²¿à²•à³† ಅಥವಾ ನಿಮà³à²® ವೈಯಕà³à²¤à²¿à²• ಮಾಹಿತಿಯನà³à²¨à³ ಬಹಿರಂಗ ಪಡಿಸà³à²µà²‚ತಹ ಅಪಾಯಕಾರಿಯಾಗಿ à²à²¨à²¾à²¦à²°à³‚ ಮಾಡà³à²µà²‚ತಹ ಮೋಸವನà³à²¨à³ ಮಾಡಬಹà³à²¦à³ (ಉದಾಹರಣೆಗೆ, ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳà³, ಫೋನà³â€Œ ಸಂಖà³à²¯à³†à²—ಳà³, ಅಥವಾ ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³â€Œà²—ಳà³).</translation>
-<translation id="53553865750799677">ಬೆಂಬಲಿತವಲà³à²²à²¦ ಪಿಕಪೠವಿಳಾಸ. ವಿಭಿನà³à²¨ ವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³†à²®à²¾à²¡à²¿.</translation>
<translation id="5359637492792381994">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ಈ ಸಮಯದಲà³à²²à²¿ ಮಾನà³à²¯à²µà²¾à²—ಿಲà³à²². ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">ನೀತಿಯ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ಸಂಗà³à²°à²¹à²¿à²¸à³à²µà²²à³à²²à²¿ ವಿಫಲವಾಗಿದೆ</translation>
<translation id="5386426401304769735">ಈ ಸೈಟà³â€Œà²—ೆ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಸರಣಿಯೠSHA-1 ಬಳಸಿಕೊಂಡೠಸಹಿ ಮಾಡಲಾದ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಒಳಗೊಂಡಿರà³à²¤à³à²¤à²¦à³†.</translation>
@@ -487,8 +497,8 @@
<translation id="5544037170328430102"><ph name="SITE" /> ನಲà³à²²à²¿ ಎಂಬೆಡೠಮಾಡಲಾದ ಪà³à²Ÿà²µà³ ಹೀಗೆ ಹೇಳà³à²¤à³à²¤à²¦à³†:</translation>
<translation id="5556459405103347317">ಮರà³à²²à³‹à²¡à³â€Œ</translation>
<translation id="5565735124758917034">ಸಕà³à²°à²¿à²¯</translation>
+<translation id="5571083550517324815">ಈ ವಿಳಾಸದಿಂದ ಪಿಕಪೠಮಾಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². ಬೇರೊಂದೠವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³† ಮಾಡಿ.</translation>
<translation id="5572851009514199876">ದಯವಿಟà³à²Ÿà³ Chrome ಪà³à²°à²¾à²°à²‚ಭಿಸಿ ಮತà³à²¤à³ ಸೈನೠಇನೠಮಾಡಿ ಈ ಮೂಲಕ ಈ ಸೈಟà³â€Œà²—ೆ ಪà³à²°à²µà³‡à²¶à²¿à²¸à²²à³ ನಿಮಗೆ ಅನà³à²®à²¤à²¿à²¸à²²à²¾à²—ಿದೆಯೇ ಎಂಬà³à²¦à²¨à³à²¨à³ Chrome ಪರಿಶೀಲಿಸಬಹà³à²¦à³.</translation>
-<translation id="5575380383496039204">ಬೆಂಬಲಿತವಲà³à²²à²¦ ವಿತರಣೆ ವಿಳಾಸ. ವಿಭಿನà³à²¨ ವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³†à²®à²¾à²¡à²¿.</translation>
<translation id="5580958916614886209">ನಿಮà³à²® ಮà³à²•à³à²¤à²¾à²¯ ತಿಂಗಳನà³à²¨à³ ಪರಿಶೀಲಿಸಿ ಹಾಗೂ ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿</translation>
<translation id="560412284261940334">ನಿರà³à²µà²¾à²¹à²• ಬೆಂಬಲಿಸà³à²µà³à²¦à²¿à²²à³à²²</translation>
<translation id="5610142619324316209">ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಪರಿಶೀಲಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†</translation>
@@ -504,7 +514,8 @@
<translation id="5710435578057952990">ಈ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²¨ ಗà³à²°à³à²¤à²¿à²¸à³à²µà²¿à²•à³†à²¯à²¨à³à²¨à³ ಇನà³à²¨à³‚ ಪರಿಶೀಲಿಸಲಾಗಿಲà³à²².</translation>
<translation id="5720705177508910913">ಪà³à²°à²¸à³à²¤à³à²¤ ಬಳಕೆದಾರ</translation>
<translation id="5732392974455271431">ನಿಮà³à²® ಪೋಷಕರೠನಿಮಗಾಗಿ ಅದನà³à²¨à³ ಅನಿರà³à²¬à²‚ಧಿಸಬಹà³à²¦à²¾à²—ಿದೆ</translation>
-<translation id="57586589942790530">ಅಮಾನà³à²¯à²µà²¾à²¦ ಕಾರà³à²¡à³ ಸಂಖà³à²¯à³†</translation>
+<translation id="5763042198335101085">ಮಾನà³à²¯à²µà²¾à²¦ ಇಮೇಲೠವಿಳಾಸವನà³à²¨à³ ನಮೂದಿಸಿ</translation>
+<translation id="5765072501007116331">ವಿತರಣೆಯ ವಿಧಾನಗಳೠಹಾಗೂ ಆವಶà³à²¯à²•à²¤à³†à²—ಳನà³à²¨à³ ನೋಡಲà³, ಒಂದೠವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³† ಮಾಡಿ</translation>
<translation id="5784606427469807560">ನಿಮà³à²® ಕಾರà³à²¡à³ ಅನà³à²¨à³ ದೃಢೀಕರಿಸà³à²µà²²à³à²²à²¿ ಸಮಸà³à²¯à³† ಇದೆ. ನಿಮà³à²® ಇಂಟರà³à²¨à³†à²Ÿà³ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಪರಿಶೀಲಿಸಿ ಹಾಗೂ ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="5785756445106461925">ಅಲà³à²²à²¦à³‡, ಸà³à²°à²•à³à²·à²¿à²¤à²µà²²à³à²²à²¦ ಸಂಪನà³à²®à³‚ಲಗಳನà³à²¨à³ ಈ ಪà³à²Ÿ ಒಳಗೊಂಡಿದೆ. ಪà³à²°à²¯à²¾à²£à²¦ ಸಂದರà³à²­à²¦à²²à³à²²à²¿ ಈ ಸಂಪನà³à²®à³‚ಲಗಳನà³à²¨à³ ಇತರರೂ ವೀಕà³à²·à²¿à²¸à²¬à²¹à³à²¦à²¾à²—ಿದೆ ಮತà³à²¤à³ ಪà³à²Ÿà²¦ ನೋಟವೇ ಬದಲಾಗà³à²µà²‚ತೆ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ಅದನà³à²¨à³ ತಿದà³à²¦à²¬à²¹à³à²¦à²¾à²—ಿದೆ.</translation>
<translation id="5786044859038896871">ನಿಮà³à²® ಕಾರà³à²¡à³ ಮಾಹಿತಿ ಭರà³à²¤à²¿ ಮಾಡಲೠನೀವೠಬಯಸà³à²µà²¿à²°à²¾?</translation>
@@ -517,31 +528,30 @@
<translation id="5869405914158311789">ಈ ಸೈಟೠತಲà³à²ªà²²à²¾à²—à³à²µà³à²¦à²¿à²²à³à²²</translation>
<translation id="5869522115854928033">ಉಳಿಸಲಾದ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳà³</translation>
<translation id="5872918882028971132">ಪೋಷಕ ಸಲಹೆಗಳà³</translation>
-<translation id="587760065310675640">ಬೆಂಬಲಿತವಲà³à²²à²¦ ಶಿಪà³à²ªà²¿à²‚ಗೠವಿಳಾಸ. ವಿಭಿನà³à²¨ ವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³†à²®à²¾à²¡à²¿.</translation>
<translation id="5901630391730855834">ಹಳದಿ</translation>
-<translation id="59174027418879706">ಸಕà³à²°à²¿à²¯à²—ೊಳಿಸಲಾಗಿದೆ</translation>
<translation id="5926846154125914413">ಕೆಲವೠಸೈಟà³â€Œà²—ಳ ಪà³à²°à³€à²®à²¿à²¯à²‚ ವಿಷಯಕà³à²•à³† ಪà³à²°à²µà³‡à²¶à²µà²¨à³à²¨à³ ನೀವೠಕಳೆದà³à²•à³Šà²³à³à²³à²¬à²¹à³à²¦à³.</translation>
<translation id="5959728338436674663">ಅಪಾಯಕಾರಿ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œà²—ಳೠಮತà³à²¤à³ ಸೈಟà³â€Œà²—ಳ ಪತà³à²¤à³†à²—ೆ ಸಹಾಯ ಮಾಡಲೠGoogle ಗೆ ಕೆಲವೠ<ph name="BEGIN_WHITEPAPER_LINK" />ಸಿಸà³à²Ÿà²‚ ಮಾಹಿತಿ ಮತà³à²¤à³ ಪà³à²Ÿ ವಿಷಯ<ph name="END_WHITEPAPER_LINK" />ವನà³à²¨à³ ಸà³à²µà²¯à²‚ಚಾಲಿತವಾಗಿ ಕಳà³à²¹à²¿à²¸à²¿. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">ವಾರ</translation>
<translation id="5967867314010545767">ಇತಿಹಾಸದಿಂದ ತೆಗೆದà³à²¹à²¾à²•à²¿</translation>
<translation id="5975083100439434680">à²à³‚ಮೠಔಟà³</translation>
+<translation id="598637245381783098">ಪಾವತಿ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³ ತೆರೆಯಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²²</translation>
<translation id="5989320800837274978">ಹೊಂದಿಸಿದ ಪà³à²°à²¾à²•à³à²¸à²¿ ಸರà³à²µà²°à³â€Œà²—ಳೠಆಗಲಿ ಅಥವಾ .pac ಸà³à²•à³à²°à²¿à²ªà³à²Ÿà³ URL ಅನà³à²¨à³ ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²¿à²²à³à²².</translation>
<translation id="5990559369517809815">ಸರà³à²µà²°à³â€Œà²—ಳ ವಿನಂತಿಗಳನà³à²¨à³ ವಿಸà³à²¤à²°à²£à³†à²¯à²¿à²‚ದ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">ಕಾರà³à²¡à³ ಮತà³à²¤à³ ವಿಳಾಸ ಆಯà³à²•à³†à²—ಳೠChrome ನಿಂದ ಬಂದಿವೆ. ನೀವೠಇವà³à²—ಳನà³à²¨à³ <ph name="BEGIN_LINK" />ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿<ph name="END_LINK" /> ನಿರà³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{ಪà³à²Ÿ 1}one{ಪà³à²Ÿ #}other{ಪà³à²Ÿ #}}</translation>
<translation id="6017514345406065928">ಹಸಿರà³</translation>
+<translation id="6027201098523975773">ಹೆಸರೠನಮೂದಿಸಿ</translation>
<translation id="6040143037577758943">ಮà³à²šà³à²šà²¿à²°à²¿</translation>
-<translation id="604124094241169006">ಸà³à²µà²¯à²‚ಚಾಲಿತ</translation>
<translation id="6042308850641462728">ಇನà³à²¨à²·à³à²Ÿà³</translation>
<translation id="6060685159320643512">ಜಾಗà³à²°à²¤à³†, ಈ ಪà³à²°à²¯à³‹à²—ಗಳೠವಿಫಲವಾಗಬಹà³à²¦à³</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{ಯಾವà³à²¦à³‚ ಇಲà³à²²}=1{1}one{#}other{#}}</translation>
<translation id="6146055958333702838">ಯಾವà³à²¦à³‡ ಕೇಬಲà³â€Œà²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಿ. ನೀವೠಬಳಸà³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à²¾à²¦ ಯಾವà³à²¦à³‡ ರೂಟರà³â€Œà²—ಳà³, ಮೋಡೆಮà³â€Œà²—ಳೠಅಥವಾ ಇತರ ನೆಟà³â€Œà²µà²°à³à²•à³ ಸಾಧನಗಳನà³à²¨à³ ರೀಬೂಟೠಮಾಡಿ.</translation>
<translation id="614940544461990577">ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿:</translation>
<translation id="6151417162996330722">ಸರà³à²µà²°à³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ತà³à²‚ಬಾ ಉದà³à²¦à²µà²¾à²¦ ವಾಯಿದೆ ಅವಧಿಯನà³à²¨à³ ಹೊಂದಿದೆ.</translation>
-<translation id="615643356032862689">ಡೌನà³â€Œà²²à³‹à²¡à³ ಮಾಡಿದ ಫೈಲà³â€Œà²—ಳನà³à²¨à³ ಮತà³à²¤à³ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳನà³à²¨à³ ಇರಿಸಿಕೊಳà³à²³à²²à²¾à²—à³à²¤à³à²¤à²¦à³†.</translation>
+<translation id="6157877588268064908">ಶಿಪà³à²ªà²¿à²‚ಗೠವಿಧಾನಗಳೠಹಾಗೂ ಆವಶà³à²¯à²•à²¤à³†à²—ಳನà³à²¨à³ ನೋಡಲà³, ಒಂದೠವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³† ಮಾಡಿ</translation>
<translation id="6165508094623778733">ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ</translation>
<translation id="6177128806592000436">ಈ ಸೈಟà³â€Œà²—ೆ ನಿಮà³à²® ಸಂಪರà³à²•à²µà³ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿಲà³à²²</translation>
+<translation id="6184817833369986695">(ಸಂಘ: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">ನಿಮà³à²® ಇಂಟರà³à²¨à³†à²Ÿà³ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಪರಿಶೀಲಿಸಿ</translation>
<translation id="6218753634732582820">Chromium ನಿಂದ ವಿಳಾಸವನà³à²¨à³ ತೆಗೆದà³à²¹à²¾à²•à³à²µà³à²¦à³‡?</translation>
<translation id="6251924700383757765">ಗೌಪà³à²¯à²¤à²¾ ನೀತಿ</translation>
@@ -550,6 +560,8 @@
<translation id="6259156558325130047">&amp;ಮರà³à²•à³à²°à²®à²—ೊಳಿಸà³à²µà³à²¦à²¨à³à²¨à³ ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳà³</translation>
<translation id="6264485186158353794">ಸà³à²°à²•à³à²·à²¤à³†à²—ೆ ಹಿಂದಿರà³à²—ಿ</translation>
+<translation id="6276112860590028508">ನಿಮà³à²® ಓದà³à²µ ಪಟà³à²Ÿà²¿à²¯ ಪà³à²Ÿà²—ಳೠಇಲà³à²²à²¿ ಕಾಣಿಸಿಕೊಳà³à²³à³à²¤à³à²¤à²µà³†</translation>
+<translation id="6280223929691119688">ಈ ವಿಳಾಸಕà³à²•à³† ತಲà³à²ªà²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¿à²²à³à²². ಬೇರೊಂದೠವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³† ಮಾಡಿ.</translation>
<translation id="6282194474023008486">ಪೋಸà³à²Ÿà²²à³ ಕೋಡà³</translation>
<translation id="6290238015253830360">ನೀವೠಸಲಹೆ ನೀಡಿರà³à²µ ಲೇಖನಗಳೠಇಲà³à²²à²¿ ಕಾಣಿಸಿಕೊಳà³à²³à³à²¤à³à²¤à²µà³†</translation>
<translation id="6305205051461490394"><ph name="URL" /> ತಲà³à²ªà²²à²¾à²—à³à²µà³à²¦à²¿à²²à³à²².</translation>
@@ -571,7 +583,6 @@
<translation id="6417515091412812850">ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಹಿಂತೆಗೆದà³à²•à³Šà²³à³à²³à²²à²¾à²—ಿದೆಯೆ ಎಂಬà³à²¦à²¨à³à²¨à³ ಪರಿಶೀಲಿಸಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²².</translation>
<translation id="6433490469411711332">ಸಂಪರà³à²• ಮಾಹಿತಿ ಎಡಿಟೠಮಾಡಿ</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> ಸಂಪರà³à²•à²—ೊಳà³à²³à²²à³ ನಿರಾಕರಿಸಿದೆ.</translation>
-<translation id="6443118737398455446">ಅಮಾನà³à²¯à²µà²¾à²¦ ಮà³à²•à³à²¤à²¾à²¯ ದಿನಾಂಕ</translation>
<translation id="6446608382365791566">ಇನà³à²¨à²·à³à²Ÿà³ ಮಾಹಿತಿಯನà³à²¨à³ ಸೇರಿಸಿ</translation>
<translation id="6451458296329894277">ಮರà³à²¸à²²à³à²²à²¿à²•à³† ಫಾರà³à²®à³ ಅನà³à²¨à³ ಖಚಿತಪಡಿಸಿಕೊಳà³à²³à²¿</translation>
<translation id="6456339708790392414">ನಿಮà³à²® ಪಾವತಿ</translation>
@@ -579,10 +590,8 @@
<translation id="6462969404041126431">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಹಿಂಪಡೆದà³à²•à³Šà²‚ಡಿರಬಹà³à²¦à³. ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">ಸಾಧನ ನೀತಿಗಳà³</translation>
<translation id="6477321094435799029">ಈ ಪà³à²Ÿà²¦à²²à³à²²à²¿ ಅಸಹಜ ಕೋಡೠಅನà³à²¨à³ Chrome ಪತà³à²¤à³†à²¹à²šà³à²šà²¿à²¦à³† ಮತà³à²¤à³ ನಿಮà³à²® ವೈಯಕà³à²¤à²¿à²• ಮಾಹಿತಿಯನà³à²¨à³ (ಉದಾಹರಣೆಗೆ, ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳà³, ಫೋನà³â€Œ ಸಂಖà³à²¯à³†à²—ಳೠಮತà³à²¤à³ ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³â€Œà²—ಳà³) ರಕà³à²·à²¿à²¸à²²à³ ಅದನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಿದೆ.</translation>
-<translation id="6477460825583319731">ಅಮಾನà³à²¯ ಇಮೇಲೠವಿಳಾಸ</translation>
<translation id="6489534406876378309">ವಿಫಲತೆಗಳನà³à²¨à³ ಅಪà³â€Œà²²à³‹à²¡à³â€Œ ಮಾಡà³à²µà³à²¦à²¨à³à²¨à³ ಪà³à²°à²¾à²°à²‚ಭಿಸà³</translation>
<translation id="6508722015517270189">Chrome ಮರà³à²ªà³à²°à²¾à²°à²‚ಭಿಸಿ</translation>
-<translation id="6525462735697194615">ಅಮಾನà³à²¯ ಮà³à²•à³à²¤à²¾à²¯ ತಿಂಗಳà³</translation>
<translation id="6529602333819889595">&amp;ಅಳಿಸà³à²µà³à²¦à²¨à³à²¨à³ ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
<translation id="6534179046333460208">ಭೌತಿಕ ವೆಬೠಸಲಹೆಗಳà³</translation>
<translation id="6550675742724504774">ಆಯà³à²•à³†à²—ಳà³</translation>
@@ -597,7 +606,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> ಹà³à²¡à³à²•à²¾à²Ÿ</translation>
<translation id="6644283850729428850">ಈ ನೀತಿಯನà³à²¨à³ ವಿನಂತಿಸಲಾಗಿದೆ.</translation>
<translation id="6652240803263749613">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರà³â€Œà²¨ ಆಪರೇಟಿಂಗೠಸಿಸà³à²Ÿà²‚ನಿಂದ ವಿಶà³à²µà²¾à²¸à²¹à³Šà²‚ದಿಲà³à²². ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">ಆ ಶಿಪà³à²ªà²¿à²‚ಗೠಆಯà³à²•à³† ಲಭà³à²¯à²µà²¿à²²à³à²². ಬೇರೆ ಆಯà³à²•à³†à²¯à²¨à³à²¨à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="6671697161687535275">Chromium ನಿಂದ ಫಾರà³à²®à³ ಸಲಹೆಯನà³à²¨à³ ತೆಗೆದà³à²¹à²¾à²•à³à²µà³à²¦à³‡?</translation>
<translation id="6685834062052613830">ಸೈನà³â€Œ ಔಟà³â€Œ ಮಾಡಿ ಹಾಗೂ ಸೆಟಪೠಪೂರà³à²£à²—ೊಳಿಸಿ</translation>
<translation id="6710213216561001401">ಹಿಂದೆ</translation>
@@ -605,13 +613,13 @@
<translation id="6711464428925977395">ಪà³à²°à²¾à²•à³à²¸à²¿ ಸರà³à²µà²°à³â€Œâ€Œà²¨à²²à³à²²à²¿ à²à²¨à³‹ ದೋಷವಿದೆ ಅಥವಾ ವಿಳಾಸವೠತಪà³à²ªà²¾à²—ಿದೆ.</translation>
<translation id="6727102863431372879">ಹೊಂದಿಸà³</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{ಯಾವà³à²¦à³‚ ಇಲà³à²²}=1{1 à²à²Ÿà²‚}one{# à²à²Ÿà²‚ಗಳà³}other{# à²à²Ÿà²‚ಗಳà³}}</translation>
-<translation id="6743044928064272573">ಪಿಕಪೠಆಯà³à²•à³†</translation>
<translation id="674375294223700098">ಅಪರಿಚಿತ ಸರà³à²µà²°à³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ದೋಷ.</translation>
<translation id="6753269504797312559">ನೀತಿ ಮೌಲà³à²¯</translation>
<translation id="6757797048963528358">ನಿಮà³à²® ಸಾಧನವೠನಿದà³à²°à²¾à²µà²¸à³à²¥à³†à²—ೆ ಹೋಗಿದೆ.</translation>
<translation id="6778737459546443941">ನಿಮà³à²® ಪೋಷಕರೠಇನà³à²¨à³‚ ಇದನà³à²¨à³ ಅಂಗೀಕರಿಸಿಲà³à²²</translation>
<translation id="6810899417690483278">ಕಸà³à²Ÿà²®à³ˆà²¸à³‡à²¶à²¨à³ à²à²¡à²¿</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">ಪà³à²°à²¦à³†à³•à²¶à²—ಳ ಡೇಟಾವನà³à²¨à³ ಲೋಡೠಮಾಡಲೠವಿಫಲವಾಗಿದೆ</translation>
<translation id="6831043979455480757">ಅನà³à²µà²¾à²¦à²¿à²¸à³</translation>
<translation id="6839929833149231406">ಪà³à²°à²¦à³‡à²¶</translation>
<translation id="6874604403660855544">&amp;ಸೇರಿಸà³à²µà³à²¦à²¨à³à²¨à³ ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
@@ -619,6 +627,7 @@
<translation id="6895330447102777224">ನಿಮà³à²® ಕಾರà³à²¡à³ ಅನà³à²¨à³ ದೃಢೀಕರಿಸಲಾಗಿದೆ</translation>
<translation id="6897140037006041989">ಬಳಕೆದಾರ à²à²œà³†à²‚ಟà³</translation>
<translation id="6915804003454593391">ಬಳಕೆದಾರ:</translation>
+<translation id="6948701128805548767">ಪಿಕಪೠವಿಧಾನಗಳೠಹಾಗೂ ಆವಶà³à²¯à²•à²¤à³†à²—ಳನà³à²¨à³ ನೋಡಲà³, ಒಂದೠವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³† ಮಾಡಿ</translation>
<translation id="6957887021205513506">ಸರà³à²µà²°à³â€Œà²—ಳ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ನಕಲಿಯಾಗಿ ಗೋಚರಿಸà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="6965382102122355670">ಸರಿ</translation>
<translation id="6965978654500191972">ಸಾಧನ</translation>
@@ -626,7 +635,6 @@
<translation id="6973656660372572881">ಹೊಂದಿಸಿದ ಪà³à²°à²¾à²•à³à²¸à²¿ ಸರà³à²µà²°à³â€Œà²—ಳೠಮತà³à²¤à³ .pac ಸà³à²•à³à²°à²¿à²ªà³à²Ÿà³ URL ಎರಡನà³à²¨à³‚ ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
<translation id="6989763994942163495">ಸà³à²§à²¾à²°à²¿à²¤ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ತೋರಿಸà³...</translation>
<translation id="7000990526846637657">ಯಾವà³à²¦à³‡ ಇತಿಹಾಸ ದಾಖಲೆಗಳೠಕಂಡà³à²¬à²‚ದಿಲà³à²²</translation>
-<translation id="7001663382399377034">ಸà³à²µà³€à²•à²°à²¿à²¸à³à²µà²µà²°à²¨à³à²¨à³ ಸೇರಿಸಿ</translation>
<translation id="7009986207543992532">ನೀವೠ<ph name="DOMAIN" /> ತಲà³à²ªà²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿à²°à³à²µà²¿à²°à²¿, ಆದರೆ ವಾಯಿದೆ ಅವಧಿ ದೀರà³à²˜à²µà²¾à²—ಿರà³à²µ ವಿಶà³à²µà²¾à²¸à²¾à²°à³à²¹à²µà²¾à²¦ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸರà³à²µà²°à³ ಪà³à²°à²¸à³à²¤à³à²¤à²ªà²¡à²¿à²¸à²¿à²¦à³†. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">ನಿಮà³à²® Google ಖಾತೆಯೠ<ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ನಲà³à²²à²¿ ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಇತಿಹಾಸದ ಇತರ ಪà³à²°à²•à²¾à²°à²—ಳನà³à²¨à³ ಹೊಂದಿರಬಹà³à²¦à³</translation>
@@ -637,12 +645,15 @@
<translation id="7088615885725309056">ಹಳೆಯದà³</translation>
<translation id="7090678807593890770"><ph name="LINK" /> ಗೆ Google ಹà³à²¡à³à²•à²¾à²Ÿ</translation>
<translation id="7119414471315195487">ಇತರ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳನà³à²¨à³ ಅಥವಾ ಪà³à²°à³‹à²—à³à²°à²¾à²‚ಗಳನà³à²¨à³ ಮà³à²šà³à²šà²¿</translation>
+<translation id="7129409597930077180">ಈ ವಿಳಾಸಕà³à²•à³† ರವಾನಿಸಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². ಬೇರೊಂದೠವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³† ಮಾಡಿ.</translation>
+<translation id="7138472120740807366">ವಿತರಣೆ ವಿಧಾನ</translation>
<translation id="7139724024395191329">ಎಮಿರೇಟà³</translation>
<translation id="7155487117670177674">ಪಾವತಿ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿಲà³à²²</translation>
<translation id="7179921470347911571">ಇದೀಗ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭಿಸà³</translation>
<translation id="7180611975245234373">ರೀಫà³à²°à³†à²¶à³ ಮಾಡಿ</translation>
<translation id="7182878459783632708">ಯಾವà³à²¦à³‡ ನೀತಿಗಳನà³à²¨à³ ಹೊಂದಿಸಿಲà³à²²</translation>
<translation id="7186367841673660872">ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³<ph name="ORIGINAL_LANGUAGE" />ನಿಂದ<ph name="LANGUAGE_LANGUAGE" />ಗೆ ಭಾಷಾಂತರಿಸಲಾಗಿದೆ</translation>
+<translation id="7192203810768312527"><ph name="SIZE" /> ತೆಗೆದà³à²¹à²¾à²•à²¿. ನಿಮà³à²® ನಂತರದ ಭೇಟಿಯ ಸಮಯದಲà³à²²à²¿ ಕೆಲವೠಸೈಟà³â€Œà²—ಳೠನಿಧಾನವಾಗಿ ಲೋಡೠಆಗಬಹà³à²¦à³.</translation>
<translation id="719464814642662924">ವೀಸಾ</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ಭದà³à²°à²¤à³† ಮಾನದಂಡಗಳನà³à²¨à³ ಅನà³à²¸à²°à²¿à²¸à³à²¤à³à²¤à²¿à²²à³à²².</translation>
<translation id="721197778055552897">ಈ ತೊಂದರೆಯ ಬಗà³à²—ೆ <ph name="BEGIN_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LINK" />.</translation>
@@ -671,7 +682,6 @@
<translation id="7424977062513257142">ಈ ವೆಬà³â€Œà²ªà³à²Ÿà²¦à²²à³à²²à²¿ ಎಂಬೆಡೠಮಾಡಲಾದ ಪà³à²Ÿà²µà³ ಹೀಗೆ ಹೇಳà³à²¤à³à²¤à²¦à³†:</translation>
<translation id="7441627299479586546">ತಪà³à²ªà²¾à²¦ ನೀತಿಯ ವಿಷಯ</translation>
<translation id="7444046173054089907">ಈ ಸೈಟೠನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
-<translation id="7444238235002594607">ಪಿಕಪೠವಿಧಾನಗಳೠಮತà³à²¤à³ ಅಗತà³à²¯à²¤à³†à²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಲೠಪಿಕಪೠವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³†à²®à²¾à²¡à²¿.</translation>
<translation id="7445762425076701745">ನೀವೠಸಂಪರà³à²• ಮಾಡಿರà³à²µ ಸರà³à²µà²°à³â€Œà²¨ ಗà³à²°à³à²¤à²¨à³à²¨à³ ಸಂಪೂರà³à²£à²µà²¾à²—ಿ ಮೌಲà³à²¯à³€à²•à²°à²¿à²¸à²²à²¾à²—à³à²µà³à²¦à²¿à²²à³à²². ನೀವೠನಿಮà³à²® ನೆಟà³â€Œà²µà²°à³à²•à³â€Œà²¨à²²à³à²²à²¿à²¯à³‡ ಮಾನà³à²¯à²µà²¿à²°à³à²µ ಹೆಸರನà³à²¨à³ ಮಾತà³à²° ಬಳಸಿಕೊಂಡೠಸಂಪರà³à²• ಹೊಂದಿರà³à²µà²¿à²°à²¿, ಇದರ ಮಾಲಿಕತà³à²µà²µà²¨à³à²¨à³ ಮೌಲà³à²¯à³€à²•à²°à²¿à²¸à³à²µ ಯಾವ ಅವಕಾಶವನà³à²¨à³‚ ಬಾಹà³à²¯ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಪà³à²°à²¾à²§à²¿à²•à²¾à²°à²µà³ ಹೊಂದಿಲà³à²². ಕೆಲವೠಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಪà³à²°à²¾à²§à²¿à²•à²¾à²°à²—ಳà³, ಯಾವà³à²¦à³‡ ಹೆಸರನà³à²¨à³ ಪರಿಗಣಿಸದೇ, ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²—ಳನà³à²¨à³ ಬಿಡà³à²—ಡೆ ಮಾಡà³à²µ ಕಾರಣದಿಂದಾಗಿ, ನೀವೠಉದà³à²¦à³‡à²¶à²¿à²¤ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ೆ ಸಂಪರà³à²•à²¿à²¸à²¿à²°à³à²µà²¿à²°à³‡ ಹೊರತೠದಾಳಿ ಮಾಡಲೠಅಲà³à²² ಎಂದೠಖಚಿತಪಡಿಸಿಕೊಳà³à²³à³à²µ ಯಾವ ಅವಕಾಶವೂ ಇಲà³à²².</translation>
<translation id="7451311239929941790">ಈ ಸಮಸà³à²¯à³†à²¯ ಕà³à²°à²¿à²¤à³ <ph name="BEGIN_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯà³à²µà²¿à²•à³†<ph name="END_LINK" />.</translation>
<translation id="7460163899615895653">ಇತರ ಸಾಧನಗಳಿಂದ ನಿಮà³à²® ಇತà³à²¤à²¿à³•à²šà²¿à²¨ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳೠಇಲà³à²²à²¿ ಗೋಚರಿಸà³à²¤à³à²¤à²µà³†</translation>
@@ -715,6 +725,7 @@
<translation id="7755287808199759310">ನಿಮà³à²® ಪೋಷಕರೠನಿಮಗಾಗಿ ಅದನà³à²¨à³ ಅನಿರà³à²¬à²‚ಧಿಸಬಹà³à²¦à²¾à²—ಿದೆ</translation>
<translation id="7758069387465995638">ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಫೈರà³â€Œà²µà²¾à²²à³ ಅಥವಾ ಆಂಟಿವೈರಸೠಸಾಫà³à²Ÿà³â€Œà²µà³‡à²°à³ ನಿರà³à²¬à²‚ಧಿಸಿರಬಹà³à²¦à³.</translation>
<translation id="7761701407923456692">ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ URL ಗೆ ಸರಿ ಹೊಂದà³à²µà³à²¦à²¿à²²à³à²².</translation>
+<translation id="7763386264682878361">ಪಾವತಿ ಮà³à²¯à²¾à²¨à²¿à²«à³†à²¸à³à²Ÿà³ ವಿಶà³à²²à³‡à²·à²•à²°à³</translation>
<translation id="7764225426217299476">ವಿಳಾಸ ಸೇರಿಸಿ</translation>
<translation id="777702478322588152">Prefecture</translation>
<translation id="7791543448312431591">ಸೇರಿಸà³</translation>
@@ -728,6 +739,7 @@
<translation id="785549533363645510">ಆದರೆ, ನೀವೠಅದೃಶà³à²¯à²°à²¾à²—ಿರà³à²µà³à²¦à²¿à²²à³à²². ಅಜà³à²žà²¾à²¤à²µà²¾à²—ಿ ಹೋಗà³à²µà³à²¦à²°à²¿à²‚ದ ನಿಮà³à²® ಉದà³à²¯à³‹à²—ದಾತರà³, ನಿಮà³à²® ಇಂಟರà³à²¨à³†à²Ÿà³ ಸೇವಾ ಪೂರೈಕೆದಾರರೠಇಲà³à²²à²µà³‡ ನೀವೠಭೇಟಿ ನೀಡà³à²µ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳಿಂದ ನಿಮà³à²® ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಮರೆ ಮಾಡಲಾಗà³à²µà³à²¦à²¿à²²à³à²².</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">ನಿಮà³à²® CVC ಅನà³à²¨à³ ಪರಿಶೀಲಿಸಿ ಹಾಗೂ ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿</translation>
+<translation id="79338296614623784">ಮಾನà³à²¯à²µà²¾à²¦ ಫೋನೠಸಂಖà³à²¯à³†à²¯à²¨à³à²¨à³ ನಮೂದಿಸಿ</translation>
<translation id="7935318582918952113">DOM ಡಿಸà³à²Ÿà²¿à²²à²°à³</translation>
<translation id="7938958445268990899">ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಇನà³à²¨à³‚ ಮಾನà³à²¯à²—ೊಳಿಸಿಲà³à²².</translation>
<translation id="7942349550061667556">ಕೆಂಪà³</translation>
@@ -747,6 +759,7 @@
<translation id="8088680233425245692">ಲೇಖನವನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²²à³ ವಿಫಲವಾಗಿದೆ.</translation>
<translation id="8089520772729574115">1 MB ಗಿಂತ ಕಡಿಮೆ</translation>
<translation id="8091372947890762290">ಸರà³à²µà²°à³â€Œà²¨à²²à³à²²à²¿ ಸಕà³à²°à²¿à²¯à²¤à³† ಬಾಕಿ ಉಳಿದಿದೆ</translation>
+<translation id="8118489163946903409">ಪಾವತಿ ವಿಧಾನ</translation>
<translation id="8131740175452115882">ದೃಢೀಕರಿಸà³</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> ಅವರ ಸರà³à²µà²°à³â€Œ <ph name="BEGIN_ABBR" />DNS ವಿಳಾಸ<ph name="END_ABBR" /> ಕಂಡà³à²¬à²‚ದಿಲà³à²².</translation>
<translation id="8149426793427495338">ನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರೠನಿದà³à²°à²¾à²µà²¸à³à²¥à³†à²—ೆ ಹೋಗಿದೆ.</translation>
@@ -761,7 +774,7 @@
<translation id="8241707690549784388">ನೀವೠಎದà³à²°à³ ನೋಡà³à²¤à³à²¤à²¿à²°à³à²µ ಪà³à²Ÿ ನೀವೠನಮೂದಿಸಿದ ಮಾಹಿತಿಯನà³à²¨à³ ಬಳಸಿದೆ. ಆ ಪà³à²Ÿà²•à³à²•à³† ಹಿಂದಿರà³à²—à³à²µà³à²¦à²°à²¿à²‚ದ ನೀವೠಮಾಡಿದ ಯಾವà³à²¦à³‡ ಕà³à²°à²¿à²¯à³† ಪà³à²¨à²°à²¾à²µà²°à³à²¤à²¿à²¸à³à²µà²‚ತೆ ಮಾಡà³à²¤à³à²¤à²¦à³†. ನೀವೠಮà³à²‚ದà³à²µà²°à²¿à²¸à²²à³ ಬಯಸà³à²¤à³à²¤à³€à²°à²¾?</translation>
<translation id="8249320324621329438">ಕಳೆದ ಬಾರಿ ಪಡೆದಿರà³à²µà³à²¦à³:</translation>
<translation id="8253091569723639551">ಬಿಲà³à²²à²¿à²‚ಗೠವಿಳಾಸ ಅಗತà³à²¯à²µà²¿à²¦à³†</translation>
-<translation id="8261506727792406068">ಅಳಿಸà³</translation>
+<translation id="8261506727792406068">ಅಳಿಸಿ</translation>
<translation id="8289355894181816810">ಇದರ ಅರà³à²¥à²µà³‡à²¨à³†à²‚ದೠನಿಮಗೆ ಖಚಿತವಾಗದಿದà³à²¦à²°à³† ನಿಮà³à²® ನೆಟà³â€Œà²µà²°à³à²•à³ ನಿರà³à²µà²¾à²¹à²•à²°à²¨à³à²¨à³ ಸಂಪರà³à²•à²¿à²¸à²¿.</translation>
<translation id="8293206222192510085">ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³ ಸೇರಿಸà³</translation>
<translation id="8294431847097064396">ಮೂಲ</translation>
@@ -772,6 +785,7 @@
<translation id="8349305172487531364">ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳ ಬಾರà³</translation>
<translation id="8363502534493474904">à²à²°à³â€Œà²ªà³à²²à³‡à²¨à³ ಮೋಡೠಆಫà³â€Œ ಮಾಡಲಾಗà³à²¤à³à²¤à²¿à²¦à³†</translation>
<translation id="8364627913115013041">ಹೊಂದಿಸಿಲà³à²².</translation>
+<translation id="8368476060205742148">Google Play ಸೇವೆಗಳà³</translation>
<translation id="8380941800586852976">ಅಪಾಯಕಾರಿ</translation>
<translation id="8382348898565613901">ನೀವೠಇತà³à²¤à³€à²šà²¿à²—ೆ ಭೇಟಿ ನೀಡಿದ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳೠಇಲà³à²²à²¿ ಕಾಣಿಸಿಕೊಳà³à²³à³à²¤à³à²¤à²µà³†</translation>
<translation id="8398259832188219207"><ph name="UPLOAD_TIME" /> ಸಮಯಕà³à²•à³† ಕà³à²°à³à²¯à²¾à²¶à³ ವರದಿಯನà³à²¨à³ ಅಪà³â€Œà²²à³‹à²¡à³ ಮಾಡಲಾಗಿದೆ</translation>
@@ -780,32 +794,30 @@
<translation id="8428213095426709021">ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳà³</translation>
<translation id="8433057134996913067">ಇದೠನಿಮà³à²®à²¨à³à²¨à³ ಹೆಚà³à²šà²¿à²¨ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳಿಂದ ಸೈನà³â€Œ ಔಟà³â€Œ ಮಾಡà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="8437238597147034694">&amp;ಸರಿಸà³à²µà³à²¦à²¨à³à²¨à³ ರದà³à²¦à³à²—ೊಳಿಸಿ</translation>
-<translation id="8456681095658380701">ಅಮಾನà³à²¯à²µà²¾à²¦ ಹೆಸರà³</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³}one{# ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³â€Œà²—ಳà³}other{# ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³â€Œà²—ಳà³}}</translation>
<translation id="8483780878231876732">ನಿಮà³à²® Google ಖಾತೆಯಿಂದ ಕಾರà³à²¡à³â€Œà²—ಳನà³à²¨à³ ಬಳಸಲà³, Chrome ಗೆ ಸೈನೠಇನೠಮಾಡಿ</translation>
<translation id="8488350697529856933">ಇದಕà³à²•à³† ಅನà³à²µà²¯à²¿à²¸à²²à²¾à²—à³à²¤à³à²¤à²¦à³†</translation>
-<translation id="8492969205326575646">ಬೆಂಬಲವಿಲà³à²²à²¦ ಕಾರà³à²¡à³ ಪà³à²°à²•à²¾à²°</translation>
<translation id="8498891568109133222">ಪà³à²°à²¤à²¿à²•à³à²°à²¿à²¯à²¿à²¸à²²à³ <ph name="HOST_NAME" /> ಹೆಚà³à²šà³ ಸಮಯ ತೆಗೆದà³à²•à³Šà²‚ಡಿದೆ.</translation>
<translation id="852346902619691059">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ನಿಮà³à²® ಸಾಧನದ ಆಪರೇಟಿಂಗೠಸಿಸà³à²Ÿà²‚ನಿಂದ ವಿಶà³à²µà²¾à²¸à²¹à³Šà²‚ದಿಲà³à²². ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">ಮà³à²•à³à²¤à²¾à²¯à²¦ ವರà³à²·</translation>
<translation id="8543181531796978784">ನೀವೠ<ph name="BEGIN_ERROR_LINK" />ಪತà³à²¤à³† ಹಚà³à²šà³à²µà²¿à²•à³† ಸಮಸà³à²¯à³†à²¯à²¨à³à²¨à³ ವರದಿ ಮಾಡಬಹà³à²¦à³<ph name="END_ERROR_LINK" /> ಅಥವಾ ನಿಮà³à²® ಭದà³à²°à²¤à³†à²¯ ಅಪಾಯಗಳ ಕà³à²°à²¿à²¤à³ ನಿಮಗೆ ಅರà³à²¥à²µà²¾à²—ಿದà³à²¦à²°à³†, <ph name="BEGIN_LINK" />ಈ ಅಸà³à²°à²•à³à²·à²¿à²¤ ಸೈಟà³â€Œà²—ೆ ಭೇಟಿ ನೀಡಿ<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">ಪà³à²Ÿà²¦ ಭಾಷೆಯನà³à²¨à³ ಗà³à²°à³à²¤à²¿à²¸à²²à³ ಅಸಾಧà³à²¯à²µà²¾à²¦ ಕಾರಣ ಭಾಷಾಂತರವೠವಿಫಲವಾಗಿದೆ.</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ಗೆ ಖಾಸಗಿ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಸà³à²¥à²¾à²ªà²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¿à²²à³à²² à²à²•à³†à²‚ದರೆ ನಿಮà³à²® ಸಾಧನದ ದಿನಾಂಕ ಮತà³à²¤à³ ಸಮಯ (<ph name="DATE_AND_TIME" />) ತಪà³à²ªà²¾à²—ಿದೆ.</translation>
-<translation id="8570229484593575558">ಈ ಮಾಹಿತಿಯನà³à²¨à³ |ಉಳಿಸಲಾಗà³à²µà³à²¦à²¿à²²à³à²²|:#ನಿಮà³à²® ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಇತಿಹಾಸ#ನಿಮà³à²® ಹà³à²¡à³à²•à²¾à²Ÿà²—ಳà³#ಕà³à²•à³€ ಡೇಟಾ</translation>
<translation id="8571890674111243710"><ph name="LANGUAGE" /> ಗೆ ಪà³à²Ÿà²µà²¨à³à²¨à³ ಭಾಷಾಂತರಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†...</translation>
-<translation id="8584539743998202583">ನಿಮà³à²® ಚಟà³à²µà²Ÿà²¿à²•à³† ಇವರಿಗೆ |ಇನà³à²¨à³‚ ಗೋಚರಿಸà³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à³| :#ನೀವೠಭೇಟಿ ನೀಡà³à²µ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳಿಗೆ#ನಿಮà³à²® ಉದà³à²¯à³‹à²—ದಾತರಿಗೆ#ನಿಮà³à²® ಇಂಟರà³à²¨à³†à²Ÿà³ ಸೇವೆ ಪೂರೈಕೆದಾರರಿಗೆ</translation>
<translation id="858637041960032120">ಫೋನೠಸಂ. ಸೇರಿಸಿ
</translation>
<translation id="859285277496340001">ಇದನà³à²¨à³ ರದà³à²¦à³à²®à²¾à²¡à²²à²¾à²—ಿದೆಯೆ ಎಂದೠಪರಿಶೀಲಿಸಲೠಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ಯಾಂತà³à²°à³€à²•à²°à²£à²µà²¨à³à²¨à³ ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²¿à²²à³à²².</translation>
<translation id="8620436878122366504">ನಿಮà³à²® ಪೋಷಕರೠಇನà³à²¨à³‚ ಇದನà³à²¨à³ ಅಂಗೀಕರಿಸಿಲà³à²²</translation>
<translation id="8647750283161643317">ಎಲà³à²²à²µà²¨à³à²¨à³‚ ಡೀಫಾಲà³à²Ÿà³â€Œà²—ೆ ಮರà³à²¹à³Šà²‚ದಿಸಿ</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> ಗೆ ನಿಮà³à²® ಸಂಪರà³à²•à²µà³ ಎನà³â€Œà²•à³à²°à²¿à²ªà³à²Ÿà³ ಆಗಿಲà³à²².</translation>
+<translation id="8718314106902482036">ಪಾವತಿ ಪೂರà³à²£à²—ೊಂಡಿಲà³à²²</translation>
<translation id="8725066075913043281">ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿</translation>
-<translation id="8728672262656704056">ನೀವೠಈಗ ಅಜà³à²žà²¾à²¤à²°à²¾à²—ಿರà³à²µà²¿à²°à²¿</translation>
+<translation id="8728672262656704056">ನೀವೠಅದೃಶà³à²¯à²°à²¾à²—ಿರà³à²µà²¿à²°à²¿</translation>
<translation id="8730621377337864115">ಮà³à²—ಿದಿದೆ</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="8759274551635299824">ಈ ಕಾರà³à²¡à³â€Œà²¨ ಅವಧಿ ಮà³à²•à³à²¤à²¾à²¯à²µà²¾à²—ಿದೆ</translation>
<translation id="8790007591277257123">&amp;ಅಳಿಸà³à²µà³à²¦à²¨à³à²¨à³ ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
-<translation id="8798099450830957504">ಡಿಫಾಲà³à²Ÿà³</translation>
<translation id="8800988563907321413">ನಿಮà³à²® ಸಮೀಪದ ವೆಬೠಪà³à²Ÿà²¦ ಸಲಹೆಗಳೠಇಲà³à²²à²¿ ಗೋಚರಿಸà³à²¤à³à²¤à²µà³†</translation>
<translation id="8820817407110198400">ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳà³</translation>
<translation id="883848425547221593">ಇತರ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳà³:</translation>
@@ -815,6 +827,7 @@
<translation id="8866481888320382733">ನೀತಿಯ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ಪಾಸೠಮಾಡà³à²µà²²à³à²²à²¿ ದೋಷ</translation>
<translation id="8866959479196209191">ಈ ಪà³à²Ÿà²µà³ ಹೀಗೆ ಹೇಳà³à²¤à³à²¤à²¦à³†:</translation>
<translation id="8870413625673593573">ಇತà³à²¤à³€à²šà³†à²—ೆ ಮà³à²šà³à²šà²¿à²°à³à²µà³à²¦à³</translation>
+<translation id="8874824191258364635">ಮಾನà³à²¯à²µà²¾à²¦ ಕಾರà³à²¡à³ ಸಂಖà³à²¯à³†à²¯à²¨à³à²¨à³ ನಮೂದಿಸಿ</translation>
<translation id="8876793034577346603">ಪಾರà³à²¸à³ ಮಾಡಬೇಕಾಗಿರà³à²µ ನೆಟà³â€Œà²µà²°à³à²•à³ ಕಾನà³à²«à²¿à²—ರೇಶನೠವಿಫಲವಾಗಿದೆ.</translation>
<translation id="8877192140621905067">ನೀವೠಒಮà³à²®à³† ಖಚಿತಪಡಿಸಿದರೆ, ನಿಮà³à²® ಕಾರà³à²¡à³ ವಿವರಗಳನà³à²¨à³ ಈ ಸೈಟೠಜೊತೆಗೆ ಹಂಚಿಕೊಳà³à²³à²²à²¾à²—à³à²¤à³à²¤à²¦à³†</translation>
<translation id="8889402386540077796">ವರà³à²£</translation>
@@ -824,7 +837,6 @@
<translation id="8931333241327730545">ಈ ಕಾರà³à²¡à²¨à³à²¨à³ ನಿಮà³à²® Google ಖಾತೆನಲà³à²²à²¿ ಉಳಿಸಲೠಬಯಸà³à²µà²¿à²°à²¾?</translation>
<translation id="8932102934695377596">ನಿಮà³à²® ಗಡಿಯಾರ ಹಿಂದೆ ಇದೆ</translation>
<translation id="8954894007019320973">(ಮà³à²‚ದà³.)</translation>
-<translation id="895548565263634352"><ph name="ARTICLE_PUBLISHER" /> ನಿಂದ <ph name="OTHER_ARTICLE_COUNT" /> ಕà³à²•à²¿à²‚ತಲೂ ಹೆಚà³à²šà²¿à²¨ ಸà³à²¦à³à²¦à²¿à²—ಳನà³à²¨à³ ಓದಿ</translation>
<translation id="8971063699422889582">ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²•à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಅವಧಿ ಮà³à²•à³à²¤à²¾à²¯à²—ೊಂಡಿದೆ.</translation>
<translation id="8986494364107987395">ಬಳಕೆಯ ಅಂಕಿಅಂಶಗಳನà³à²¨à³ ಮತà³à²¤à³ ಕà³à²°à²¾à²¶à³ ವರದಿಗಳನà³à²¨à³ Google ಗೆ ಸà³à²µà²¯à²‚ಚಾಲಿತವಾಗಿ ರವಾನಿಸà³</translation>
<translation id="8987927404178983737">ತಿಂಗಳà³</translation>
@@ -842,12 +854,11 @@
<translation id="9068849894565669697">ಬಣà³à²£à²µà²¨à³à²¨à³ ಆಯà³à²•à³†à²®à²¾à²¡à²¿</translation>
<translation id="9076283476770535406">ಇದೠಪà³à²°à²¬à³à²¦à³à²§ ವಿಷಯವನà³à²¨à³ ಹೊಂದಿರಬಹà³à²¦à³</translation>
<translation id="9078964945751709336">ಇನà³à²¨à²·à³à²Ÿà³ ಮಾಹಿತಿಯ ಅಗತà³à²¯à²µà²¿à²¦à³†</translation>
-<translation id="9094175695478007090">ಪಾವತಿ ಅಪà³à²²à²¿à²•à³†à³•à²¶à²¨à³ ಆರಂಭಿಸಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²².</translation>
<translation id="9103872766612412690"><ph name="SITE" /> ಸಾಮಾನà³à²¯à²µà²¾à²—ಿ ನಿಮà³à²® ಮಾಹಿತಿಯನà³à²¨à³ ಸಂರಕà³à²·à²¿à²¸à²²à³ ಎನà³â€Œà²•à³à²°à²¿à²ªà³à²¶à²¨à³ ಪà³à²°à²¯à³‹à²œà²¨à²µà²¨à³à²¨à³ ಬಳಸಿಕೊಳà³à²³à³à²¤à³à²¤à²¦à³†. ಈ ಸಂದರà³à²­à²¦à²²à³à²²à²¿ Chromium <ph name="SITE" /> ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ೆ ಸಂಪರà³à²•à²¿à²¸à²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿à²¦à²¾à²—, ಆ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œâ€Œ ಅಸಹಜ ಮತà³à²¤à³ ತಪà³à²ªà³ ರà³à²œà³à²µà²¾à²¤à³à²—ಳನà³à²¨à³ ಹಿಂತಿರà³à²—ಿಸಿದೆ. ದಾಳಿಕೋರರೠ<ph name="SITE" /> ರೂಪದಲà³à²²à²¿ ಸೋಗೠಹಾಕಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à³à²¤à³à²¤à²¿à²°à³à²µà²¾à²— ಅಥವಾ ವೈ-ಫೈ ಸೈನà³-ಇನೠಪರದೆಯೠಸಂಪರà³à²•à²•à³à²•à³† ಅಡà³à²¡à²¿à²¯à³à²‚ಟೠಮಾಡಿದಾಗ ಇದೠಕಂಡà³à²¬à²°à²¬à²¹à³à²¦à³. ಯಾವà³à²¦à³‡ ಡೇಟಾವನà³à²¨à³ ವಿನಿಮಯ ಮಾಡಿಕೊಳà³à²³à³à²µ ಮೊದಲೇ Chromium ಸಂಪರà³à²• ಕಡಿತಗೊಳಿಸಿರà³à²µ ಕಾರಣ, ನಿಮà³à²® ಮಾಹಿತಿ ಈಗಲೂ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿದೆ.</translation>
<translation id="9137013805542155359">ಮೂಲವನà³à²¨à³ ತೋರಿಸಿ</translation>
<translation id="9137248913990643158">ಈ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³ ಬಳಸà³à²µ ಮೊದಲೠChrome ಪà³à²°à²¾à²°à²‚ಭಿಸಿ ಮತà³à²¤à³ ಸೈನೠಇನೠಮಾಡಿ.</translation>
<translation id="9148507642005240123">&amp;ಸಂಪಾದಿಸà³à²µà³à²¦à²¨à³à²¨à³ ರದà³à²¦à³à²—ೊಳಿಸಿ</translation>
-<translation id="9154194610265714752">ನವೀಕರಿಸಲಾಗಿದೆ</translation>
+<translation id="9154194610265714752">ಅಪà³â€Œà²¡à³‡à²Ÿà³â€Œ ಮಾಡಲಾಗಿದೆ</translation>
<translation id="9157595877708044936">ಹೊಂದಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†...</translation>
<translation id="9170848237812810038">&amp;ರದà³à²¦à³à²®à²¾à²¡à³</translation>
<translation id="917450738466192189">ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ಅಮಾನà³à²¯à²µà²¾à²—ಿದೆ.</translation>
diff --git a/chromium/components/strings/components_strings_ko.xtb b/chromium/components/strings/components_strings_ko.xtb
index 49b987cb229..69df7f43047 100644
--- a/chromium/components/strings/components_strings_ko.xtb
+++ b/chromium/components/strings/components_strings_ko.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="ko">
<translation id="1008557486741366299">ë‚˜ì¤‘ì— í•˜ê¸°</translation>
<translation id="1015730422737071372">추가 세부정보 제공</translation>
+<translation id="1021110881106174305">사용할 수 있는 카드</translation>
<translation id="1032854598605920125">시계 방향으로 회전</translation>
<translation id="1038842779957582377">ì•Œ 수 없는 ì´ë¦„</translation>
<translation id="1050038467049342496">다른 앱 닫기</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">값 숨기기</translation>
<translation id="1228893227497259893">ìž˜ëª»ëœ ê°œì²´ ì‹ë³„ìž</translation>
<translation id="1232569758102978740">제목 ì—†ìŒ</translation>
+<translation id="1263231323834454256">ì½ê¸° 목ë¡</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" />ì— ìº¡ì²˜ëœ ë¹„ì •ìƒ ì¢…ë£Œ ë³´ê³ ì„œ(ì•„ì§ ì—…ë¡œë“œ ë˜ëŠ” 무시ë˜ì§€ ì•ŠìŒ)</translation>
<translation id="1285320974508926690">ì´ ì‚¬ì´íŠ¸ 번역 안함</translation>
<translation id="129553762522093515">ìµœê·¼ì— ë‹«ì€ íƒ­</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromium ìžë™ì™„성 설정...</translation>
<translation id="1374468813861204354">제안사항</translation>
<translation id="1375198122581997741">버전 정보</translation>
+<translation id="1377321085342047638">카드 번호</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" />ì—ì„œ 전송한 ë°ì´í„°ê°€ 없습니다.</translation>
<translation id="1407135791313364759">ëª¨ë‘ ì—´ê¸°</translation>
<translation id="1413809658975081374">ê°œì¸ì •ë³´ 보호 오류</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">방문 기ë¡</translation>
<translation id="1645368109819982629">지ì›ë˜ì§€ 않는 프로토콜</translation>
<translation id="1656489000284462475">수령</translation>
+<translation id="1663943134801823270">카드와 주소는 Chromeì—ì„œ 가져왔습니다. ì´ ì •ë³´ëŠ” <ph name="BEGIN_LINK" />설정<ph name="END_LINK" />ì—ì„œ 관리할 수 있습니다.</translation>
<translation id="1676269943528358898"><ph name="SITE" />ì—서는 ì‚¬ìš©ìž ì •ë³´ë¥¼ 보호하기 위해 ì¼ë°˜ì ìœ¼ë¡œ 암호화를 사용합니다. ì´ë²ˆì— Chromeì—ì„œ <ph name="SITE" />ì— ì—°ê²°ì„ ì‹œë„í–ˆì„ ë•Œ 웹사ì´íŠ¸ì—ì„œ 비정ìƒì ì´ê³  ìž˜ëª»ëœ ì‚¬ìš©ìž ì¸ì¦ 정보를 반환했습니다. ì´ëŠ” 공격ìžê°€ <ph name="SITE" />ì¸ ê²ƒì²˜ëŸ¼ 가장하려고 하거나 Wi-Fi ë¡œê·¸ì¸ í™”ë©´ì´ ì—°ê²°ì„ ë°©í•´í–ˆê¸° ë•Œë¬¸ì¼ ìˆ˜ 있습니다. ë°ì´í„° êµí™˜ì´ ë°œìƒí•˜ê¸° ì „ì— Chromeì—ì„œ ì—°ê²°ì„ ì¤‘ë‹¨í–ˆê¸° ë•Œë¬¸ì— ì‚¬ìš©ìž ì •ë³´ëŠ” 안전합니다.</translation>
<translation id="168328519870909584">현재 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />ì˜ ê³µê²©ìžê°€ 사용 ì¤‘ì¸ ê¸°ê¸°ì— ì‚¬ìš©ìž ì •ë³´(예: 사진, 비밀번호, 메시지, ì‹ ìš©ì¹´ë“œ)를 ë„용하거나 삭제하는 위험한 ì•±ì„ ì„¤ì¹˜í•˜ë ¤ê³  ì‹œë„í•  수 있습니다.</translation>
<translation id="168841957122794586">서버 ì¸ì¦ì„œì— ì•ˆì „ì„±ì´ ë‚®ì€ ì•”í˜¸í™” 키가 í¬í•¨ë˜ì–´ 있습니다.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">ì´ ì‚¬ì´íŠ¸ë¥¼ 방문하려면 <ph name="NAME" />님으로부터 ê¶Œí•œì„ ë°›ì•„ì•¼ 합니다.</translation>
+<translation id="1721424275792716183">* 필수 입력란</translation>
<translation id="1728677426644403582">웹페ì´ì§€ 소스를 보는 중</translation>
+<translation id="173080396488393970">ì´ ìœ í˜•ì˜ ì¹´ë“œëŠ” 지ì›ë˜ì§€ 않습니다.</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">시스템 관리ìžì—게 문ì˜í•˜ì„¸ìš”.</translation>
+<translation id="1740951997222943430">올바른 만료 ì›”ì„ ìž…ë ¥í•˜ì„¸ìš”.</translation>
<translation id="1745358365027406341">페ì´ì§€ ë‚˜ì¤‘ì— ë‹¤ìš´ë¡œë“œ</translation>
<translation id="17513872634828108">열린 탭</translation>
<translation id="1753706481035618306">페ì´ì§€ 번호</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">ë™ê¸°í™” 암호를 ì—…ë°ì´íŠ¸í•˜ì„¸ìš”.</translation>
<translation id="1787142507584202372">열린 íƒ­ì´ ì—¬ê¸°ì— í‘œì‹œë©ë‹ˆë‹¤.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">배송 방법과 ìš”ê±´ì„ í™•ì¸í•˜ë ¤ë©´ 배송지 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
+<translation id="1803264062614276815">ì¹´ë“œ ì†Œìœ ìž ì´ë¦„</translation>
<translation id="1803678881841855883">Google 세ì´í”„ 브ë¼ìš°ì§•ì´ 최근 <ph name="SITE" />ì—ì„œ <ph name="BEGIN_LINK" />멀웨어를 ê°ì§€<ph name="END_LINK" />했습니다. ì•ˆì „í•˜ë˜ ì›¹ì‚¬ì´íŠ¸ë„ ë©€ì›¨ì–´ì— ê°ì—¼ë˜ëŠ” 경우가 있습니다. 악성 콘í…ì¸ ì˜ ì¶œì²˜ëŠ” 알려진 멀웨어 ë°°í¬ìžì¸ <ph name="SUBRESOURCE_HOST" />입니다. <ph name="BEGIN_LEARN_MORE_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1806541873155184440">추가ì¼: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">ìž˜ëª»ëœ ìš”ì²­ ë˜ëŠ” 요청 매개변수</translation>
<translation id="1826516787628120939">í™•ì¸ ì¤‘</translation>
<translation id="1834321415901700177">ì´ ì‚¬ì´íŠ¸ì— 유해한 í”„ë¡œê·¸ëž¨ì´ ìžˆìŠµë‹ˆë‹¤.</translation>
<translation id="1842969606798536927">결제하기</translation>
-<translation id="1864455488461349376">배송 옵션</translation>
<translation id="1871208020102129563">프ë¡ì‹œê°€ .pac 스í¬ë¦½íŠ¸ URLì´ ì•„ë‹Œ ê³ ì • 프ë¡ì‹œ 서버를 사용하ë„ë¡ ì„¤ì •ë©ë‹ˆë‹¤.</translation>
<translation id="1871284979644508959">필수 입력란</translation>
<translation id="187918866476621466">시작 페ì´ì§€ 열기</translation>
<translation id="1883255238294161206">접기 목ë¡</translation>
<translation id="1898423065542865115">í•„í„°ë§</translation>
<translation id="194030505837763158"><ph name="LINK" />(으)ë¡œ ì´ë™</translation>
-<translation id="1946821392246652573">카드 사용 가능</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> ë¶ë§ˆí¬</translation>
<translation id="1973335181906896915">ì¼ë ¨í™” 오류</translation>
<translation id="1974060860693918893">고급</translation>
<translation id="1978555033938440688">펌웨어 버전</translation>
+<translation id="1995859865337580572">CVC를 ì¸ì¦í•˜ì„¸ìš”.</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{외 1개}other{외 #개}}</translation>
-<translation id="2020194265157481222">ì¹´ë“œ ëª…ì˜ í•„ìš”</translation>
<translation id="2025186561304664664">프ë¡ì‹œê°€ ìžë™ 설정ë˜ë„ë¡ ì§€ì •ë©ë‹ˆë‹¤.</translation>
<translation id="2030481566774242610"><ph name="LINK" />ì„(를) 찾으셨나요?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />프ë¡ì‹œ ë° ë°©í™”ë²½ 확ì¸<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">오늘</translation>
<translation id="2154054054215849342">ë„ë©”ì¸ì— 대해 ë™ê¸°í™”를 사용할 수 없습니다.</translation>
<translation id="2154484045852737596">카드 수정</translation>
-<translation id="2156993118928861787">ìž˜ëª»ëœ ì£¼ì†Œ</translation>
<translation id="2166049586286450108">ì „ì²´ ê´€ë¦¬ìž ì•¡ì„¸ìŠ¤</translation>
<translation id="2166378884831602661">사ì´íŠ¸ì— 보안 ì—°ê²°í•  수 ì—†ìŒ</translation>
<translation id="2181821976797666341">ì •ì±…</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{주소 1개}other{주소 #개}}</translation>
+<translation id="2202020181578195191">올바른 만료 ì—°ë„를 입력하세요.</translation>
<translation id="2212735316055980242">ì •ì±…ì„ ì°¾ì„ ìˆ˜ ì—†ìŒ</translation>
<translation id="2213606439339815911">í•­ëª©ì„ ê°€ì ¸ì˜¤ëŠ” 중...</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />진단 앱<ph name="END_LINK" />ì„ ì‚¬ìš©í•˜ì—¬ ì—°ê²° 문제를 해결하세요.</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">ì¸í„°ë„· 액세스가 차단ë¨</translation>
<translation id="230155334948463882">새 ì¹´ë“œì¸ê°€ìš”?</translation>
<translation id="2305919008529760154">서버 ë„ë©”ì¸ì´ <ph name="DOMAIN" />ìž„ì„ ì¦ëª…í•  수 없습니다. 보안 ì¸ì¦ì„œê°€ 부정한 ë°©ì‹ìœ¼ë¡œ 발급ë˜ì—ˆì„ 수 있습니다. ì„¤ì •ì´ ìž˜ëª»ë˜ì—ˆê±°ë‚˜ 해커가 ì—°ê²°ì„ ê°€ë¡œì±„ê³  있기 ë•Œë¬¸ì¼ ìˆ˜ 있습니다. <ph name="BEGIN_LEARN_MORE_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="230697611605700222">ì¹´ë“œ ë° ì£¼ì†Œ ì˜µì…˜ì€ Google 계정(<ph name="ACCOUNT_EMAIL" />) ë° Chromeì—ì„œ 가져왔습니다. <ph name="BEGIN_LINK" />설정<ph name="END_LINK" />ì—ì„œ ì¹´ë“œ ë° ì£¼ì†Œ ì˜µì…˜ì„ ê´€ë¦¬í•  수 있습니다.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" />ì— ì‚¬ìš©ìž ì´ë¦„ê³¼ 비밀번호를 입력해야 합니다.</translation>
<translation id="2318774815570432836"><ph name="SITE" />ì—ì„œ HSTS를 사용하고 있기 ë•Œë¬¸ì— ë°©ë¬¸í•  수 없습니다. ë„¤íŠ¸ì›Œí¬ ì˜¤ë¥˜ì™€ ê³µê²©ì€ ëŒ€ë¶€ë¶„ ì¼ì‹œì ì´ë¯€ë¡œ ìž ì‹œ 후 페ì´ì§€ê°€ ì •ìƒí™”ë  ê²ƒìž…ë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2354001756790975382">기타 ë¶ë§ˆí¬</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">엔터프ë¼ì´ì¦ˆ 기본값</translation>
<translation id="2386255080630008482">서버 ì¸ì¦ì„œê°€ í기ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="2392959068659972793">ê°’ì´ ì„¤ì •ë˜ì§€ ì•Šì€ ì •ì±… 표시</translation>
+<translation id="239429038616798445">사용할 수 없는 배송 방법입니다. 다른 ë°©ë²•ì„ ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="2396249848217231973">삭제 실행 취소(&amp;U)</translation>
<translation id="2460160116472764928">Google 세ì´í”„ 브ë¼ìš°ì§•ì´ 최근 <ph name="SITE" />ì—ì„œ <ph name="BEGIN_LINK" />멀웨어를 ê°ì§€<ph name="END_LINK" />했습니다. ì•ˆì „í•˜ë˜ ì›¹ì‚¬ì´íŠ¸ë„ ë©€ì›¨ì–´ì— ê°ì—¼ë˜ëŠ” 경우가 있습니다. <ph name="BEGIN_LEARN_MORE_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2463739503403862330">ìž…ë ¥</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />ë„¤íŠ¸ì›Œí¬ ì§„ë‹¨ 프로그램 실행<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">검색 URLì´ ìž˜ëª»ë¨</translation>
<translation id="2491120439723279231">서버 ì¸ì¦ì„œì— 오류가 있습니다.</translation>
-<translation id="24943777258388405">ìž˜ëª»ëœ ì „í™”ë²ˆí˜¸</translation>
<translation id="2495083838625180221">JSON 파서</translation>
<translation id="2495093607237746763">ì„ íƒí•˜ë©´ ì´ ê¸°ê¸°ì— ì¹´ë“œ ì‚¬ë³¸ì´ ì €ìž¥ë˜ì–´ Chromiumì—ì„œ ì–‘ì‹ì„ ë” ë¹ ë¥´ê²Œ 입력할 수 있습니다.</translation>
<translation id="2498091847651709837">새 카드 스캔</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" />ì—ì„œ ìž˜ëª»ëœ ì‘ë‹µì„ ì „ì†¡í–ˆìŠµë‹ˆë‹¤.</translation>
<translation id="2552545117464357659">ì´ì „</translation>
<translation id="2556876185419854533">수정 실행 취소(&amp;U)</translation>
+<translation id="2587730715158995865"><ph name="ARTICLE_PUBLISHER" />ì—ì„œ 제공한 기사입니다. <ph name="OTHER_ARTICLE_COUNT" />ê°œì˜ ë‹¤ë¥¸ ë‰´ìŠ¤ë„ ì½ì–´ 보세요.</translation>
<translation id="2587841377698384444">Directory API ID:</translation>
<translation id="2597378329261239068">문서가 비밀번호로 보호ë˜ê³  있습니다. 비밀번호를 입력하세요.</translation>
<translation id="2609632851001447353">유사 버전</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />연결 진단 프로그램 실행<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">확ì¸</translation>
<translation id="2742870351467570537">ì„ íƒí•œ 항목 ì‚­ì œ</translation>
+<translation id="277133753123645258">배송 방법</translation>
<translation id="277499241957683684">기기 ê¸°ë¡ ì—†ìŒ</translation>
<translation id="2784949926578158345">ì—°ê²°ì´ ìž¬ì„¤ì •ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="2794233252405721443">ì°¨ë‹¨ëœ ì‚¬ì´íŠ¸</translation>
-<translation id="2812680587231492111">해당 수거 ì˜µì…˜ì€ ì‚¬ìš©í•  수 없습니다. 다른 ì˜µì…˜ì„ ì‚¬ìš©í•´ 보세요.</translation>
<translation id="2824775600643448204">주소창 ë° ê²€ìƒ‰ì°½</translation>
<translation id="2826760142808435982">ì´ ì—°ê²°ì€ <ph name="CIPHER" />ì„(를) 사용하여 암호화ë˜ê³  ì¸ì¦ë˜ë©° <ph name="KX" />ì„(를) 키 êµí™˜ 매커니즘으로 사용합니다.</translation>
<translation id="2835170189407361413">ì„œì‹ ì§€ìš°ê¸°</translation>
-<translation id="2849041323157393173">해당 배달 ì˜µì…˜ì€ ì„ íƒí•  수 없습니다. 다른 ì˜µì…˜ì„ ì‚¬ìš©í•´ 보세요.</translation>
<translation id="2889159643044928134">새로고침 안함</translation>
<translation id="2900469785430194048">ì´ ì›¹íŽ˜ì´ì§€ë¥¼ 표시하려고 했으나 Chrome 메모리가 부족합니다.</translation>
<translation id="2909946352844186028">ë„¤íŠ¸ì›Œí¬ ë³€ê²½ì´ ê°ì§€ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="2916038427272391327">다른 프로그램 닫기</translation>
<translation id="2922350208395188000">서버 ì¸ì¦ì„œë¥¼ 확ì¸í•  수 없습니다.</translation>
+<translation id="2928905813689894207">청구서 수신 주소</translation>
<translation id="2948083400971632585">설정 페ì´ì§€ì˜ ì—°ê²°ì„ êµ¬ì„±í•˜ëŠ” 프ë¡ì‹œë¥¼ 사용 중지할 수 있습니다.</translation>
<translation id="2955913368246107853">검색 바 닫기</translation>
<translation id="2958431318199492670">ë„¤íŠ¸ì›Œí¬ ì„¤ì •ì´ ONC í‘œì¤€ì„ ì¤€ìˆ˜í•˜ì§€ 않습니다. ì¼ë¶€ ì„¤ì •ì„ ê°€ì ¸ì˜¬ 수 없습니다.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">보안 ì—°ê²°ì„ ì„¤ì •í•˜ë ¤ë©´ 시계가 올바로 설정ë˜ì–´ 있어야 합니다. 웹사ì´íŠ¸ê°€ ìžì‹ ì„ ì‹ë³„하는 ë° ì‚¬ìš©í•˜ëŠ” ì¸ì¦ì„œëŠ” 특정 기간ì—만 유효하기 때문입니다. ê¸°ê¸°ì˜ ì‹œê³„ê°€ 잘못 설정ë˜ì–´ Chromeì—ì„œ ì´ ì¸ì¦ì„œë¥¼ 확ì¸í•  수 없습니다.</translation>
<translation id="2972581237482394796">다시 실행(&amp;R)</translation>
<translation id="2985306909656435243">ì„ íƒí•˜ë©´ ì´ ê¸°ê¸°ì— ì¹´ë“œ ì‚¬ë³¸ì´ ì €ìž¥ë˜ì–´ Chromiumì—ì„œ ì–‘ì‹ì„ ë” ë¹ ë¥´ê²Œ 작성할 수 있습니다.</translation>
+<translation id="2985398929374701810">올바른 주소를 입력하세요.</translation>
+<translation id="2986368408720340940">사용할 수 없는 수령 방법입니다. 다른 ë°©ë²•ì„ ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="2991174974383378012">웹사ì´íŠ¸ì™€ 공유</translation>
<translation id="3005723025932146533">ì €ìž¥ëœ ì‚¬ë³¸ 표시</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> ì¹´ë“œì˜ CVC를 입력하세요. 카드를 확ì¸í•˜ë©´ ì¹´ë“œ 세부정보가 ì´ ì‚¬ì´íŠ¸ì™€ 공유ë©ë‹ˆë‹¤.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{ë™ê¸°í™”ëœ ê¸°ê¸°ì— ìµœì†Œ 1ê°œ}=1{1ê°œ(ë™ê¸°í™”ëœ ê¸°ê¸°ì—는 ê·¸ ì´ìƒ)}other{#ê°œ(ë™ê¸°í™”ëœ ê¸°ê¸°ì—는 ê·¸ ì´ìƒ)}}</translation>
<translation id="3041612393474885105">ì¸ì¦ì„œ ì •ë³´</translation>
<translation id="3063697135517575841">현재 Chromeì—ì„œ 카드를 확ì¸í•  수 없습니다. ë‚˜ì¤‘ì— ë‹¤ì‹œ ì‹œë„í•´ 주세요.</translation>
+<translation id="3064966200440839136">ì‹œí¬ë¦¿ 모드를 종료하고 외부 애플리케ì´ì…˜ì—ì„œ 결제합니다. 계ì†í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="3093245981617870298">오프ë¼ì¸ ìƒíƒœìž…니다.</translation>
<translation id="3105172416063519923">ì• ì…‹ ID:</translation>
<translation id="3109728660330352905">ì´ íŽ˜ì´ì§€ë¥¼ ë³¼ 수 있는 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />ì—°ê²° 진단 í”„ë¡œê·¸ëž¨ì„ ì‹¤í–‰<ph name="END_LINK" />í•´ 보세요.</translation>
<translation id="3145945101586104090">ì‘답 디코딩 실패</translation>
-<translation id="3149891296864842641">배송 옵션</translation>
<translation id="3150653042067488994">ì¼ì‹œì ì¸ 서버 오류</translation>
+<translation id="3154506275960390542">ì´ íŽ˜ì´ì§€ì— í¬í•¨ëœ ì–‘ì‹ì€ 안전하게 제출ë˜ì§€ ì•Šì„ ìˆ˜ 있습니다. 전송ë˜ëŠ” ë°ì´í„°ëŠ” 전송 ì¤‘ì— ë‹¤ë¥¸ ì‚¬ëžŒì´ ë³¼ 수 있으며 서버ì—ì„œ 수신하는 ë°ì´í„°ë¥¼ 변경하기 위해 공격ìžê°€ 수정할 수 있습니다.</translation>
<translation id="3157931365184549694">복구</translation>
<translation id="3167968892399408617">ì‹œí¬ë¦¿ íƒ­ì„ ëª¨ë‘ ë‹«ìœ¼ë©´ ì‹œí¬ë¦¿ 탭ì—ì„œ 보는 페ì´ì§€ëŠ” 브ë¼ìš°ì €ì˜ 방문 기ë¡, 쿠키 저장소, 검색 ê¸°ë¡ ì–´ë””ì—ë„ ë‚¨ì§€ 않습니다. 단, 다운로드한 파ì¼ì´ë‚˜ ìƒì„±í•œ ë¶ë§ˆí¬ëŠ” 유지ë©ë‹ˆë‹¤.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">ì´ ì‚¬ì´íŠ¸ì— 대한 액세스 ìš”ì²­ì„ <ph name="NAME" />님ì—게 보내지 못했습니다. ë‚˜ì¤‘ì— ë‹¤ì‹œ ì‹œë„í•´ 주세요.</translation>
<translation id="3355823806454867987">프ë¡ì‹œ 설정 변경...</translation>
<translation id="3369192424181595722">시계 오류</translation>
+<translation id="337311366426640088">항목 <ph name="ITEM_COUNT" />ê°œ ë”보기...</translation>
<translation id="337363190475750230">사용 중단ë¨</translation>
<translation id="3377188786107721145">정책 파싱 오류</translation>
<translation id="3380365263193509176">ì•Œ 수 없는 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤.</translation>
<translation id="3380864720620200369">í´ë¼ì´ì–¸íŠ¸ ID:</translation>
<translation id="3391030046425686457">배송지 주소</translation>
+<translation id="3395827396354264108">수령 방법</translation>
<translation id="340013220407300675">공격ìžê°€ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />ì—ì„œ 사용ìžì˜ 정보를 ë„용하려고 ì‹œë„í•  수 있습니다(예: 비밀번호, 메시지, ì‹ ìš©ì¹´ë“œ ì •ë³´).</translation>
<translation id="3422248202833853650">다른 í”„ë¡œê·¸ëž¨ì„ ì¢…ë£Œí•˜ì—¬ 메모리를 확보하세요.</translation>
<translation id="3422472998109090673">현재 <ph name="HOST_NAME" />ì— ì—°ê²°í•  수 없습니다.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">가져오기 간격:</translation>
<translation id="3462200631372590220">세부정보 숨기기</translation>
+<translation id="3467763166455606212">ì¹´ë“œ ì†Œìœ ìž ì´ë¦„ì„ ìž…ë ¥í•´ì•¼ 합니다.</translation>
+<translation id="3478058380795961209">만료 월</translation>
<translation id="3479539252931486093">예기치 ì•Šì€ ë¬¸ì œê°€ ë°œìƒí–ˆë‚˜ìš”? <ph name="BEGIN_LINK" />Googleì— ì•Œë¦¬ê¸°<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">나중ì—</translation>
<translation id="348000606199325318">ë¹„ì •ìƒ ì¢…ë£Œ ID <ph name="CRASH_LOCAL_ID" />(서버 ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">현재 부모님께 ì—°ë½í•  수 없습니다. ë‚˜ì¤‘ì— ë‹¤ì‹œ ì‹œë„í•´ 주세요.</translation>
<translation id="3528171143076753409">ì„œë²„ì˜ ì¸ì¦ì„œë¥¼ 신뢰할 수 없습니다.</translation>
-<translation id="3538531656504267329">만료 ì—°ë„ê°€ 잘못ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="3539171420378717834">ì¹´ë“œ ì‚¬ë³¸ì„ ì´ ê¸°ê¸°ì— ì €ìž¥</translation>
<translation id="3542684924769048008">비밀번호 사용 항목:</translation>
<translation id="3549644494707163724">ë‚˜ë§Œì˜ ë™ê¸°í™” 암호로 모든 ë™ê¸°í™” ë°ì´í„° 암호화</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">세부정보 숨기기</translation>
<translation id="3587482841069643663">ì „ì²´</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">올바른 만료ì¼ì„ 입력하세요.</translation>
<translation id="36224234498066874">ì¸í„°ë„· 사용정보 ì‚­ì œ...</translation>
<translation id="362276910939193118">방문 ê¸°ë¡ ì „ì²´ 보기</translation>
<translation id="3623476034248543066">값 표시</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">비밀번호:</translation>
<translation id="3696411085566228381">ì—†ìŒ</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">배송 방법과 ìš”ê±´ì„ í™•ì¸í•  수 있ë„ë¡ ë°°ì†¡ì§€ 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="370665806235115550">로드 중...</translation>
<translation id="3712624925041724820">ë¼ì´ì„ ìŠ¤ 만료ë¨</translation>
<translation id="3714780639079136834">ëª¨ë°”ì¼ ë°ì´í„° ë˜ëŠ” Wi-Fi 사용 설정</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">복사한 ë§í¬</translation>
<translation id="375403751935624634">서버 오류가 ë°œìƒí•˜ì—¬ 번역하지 못했습니다.</translation>
<translation id="3759461132968374835">ìµœê·¼ì— ë³´ê³ ëœ ë¹„ì •ìƒ ì¢…ë£Œê°€ 없습니다. ë¹„ì •ìƒ ì¢…ë£Œ 보고를 사용 ì¤‘ì§€í–ˆì„ ë•Œ ë°œìƒí•œ ë¹„ì •ìƒ ì¢…ë£ŒëŠ” ì—¬ê¸°ì— í‘œì‹œë˜ì§€ 않습니다.</translation>
+<translation id="3787705759683870569">만료: <ph name="EXPIRATION_YEAR" />년 <ph name="EXPIRATION_MONTH" />월</translation>
<translation id="382518646247711829">프ë¡ì‹œ 서버를 사용하는 경우</translation>
<translation id="3828924085048779000">암호를 빈 칸으로 ë‘어서는 안 ë©ë‹ˆë‹¤.</translation>
<translation id="3845539888601087042">로그ì¸í•œ ê¸°ê¸°ì˜ ë°©ë¬¸ 기ë¡ì„ 표시합니다. <ph name="BEGIN_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LINK" /></translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chromiumì—ì„œ ì´ ì¹´ë“œë¥¼ 저장하ë„ë¡ í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="4171400957073367226">ìž˜ëª»ëœ ì¸ì¦ 서명입니다.</translation>
-<translation id="4176463684765177261">사용 중지</translation>
<translation id="4196861286325780578">ì´ë™ 다시 실행(&amp;R)</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />방화벽 ë° ë°”ì´ëŸ¬ìŠ¤ 백신 소프트웨어 설정 확ì¸<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{ì—†ìŒ}=1{앱 1ê°œ($1)}=2{앱 2ê°œ($1, $2)}other{앱 #ê°œ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">검색결과</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" />ì—ì„œ ë¡œê·¸ì¸ ì¸ì¦ì„œë¥¼ 승ì¸í•˜ì§€ 않았거나 ë¡œê·¸ì¸ ì¸ì¦ì„œê°€ 제공ë˜ì§€ ì•Šì•˜ì„ ìˆ˜ 있습니다.</translation>
<translation id="443673843213245140">프ë¡ì‹œ ì‚¬ìš©ì€ ì¤‘ì§€ë˜ì—ˆì§€ë§Œ ëª…ì‹œì  í”„ë¡ì‹œ ì„¤ì •ì´ ì§€ì •ë˜ì–´ 있습니다.</translation>
-<translation id="4446242550670694251">ì´ì œ 비공개로 ì¸í„°ë„·ì„ 사용할 수 있으며 ì´ ê¸°ê¸°ë¥¼ 사용하는 다른 사용ìžê°€ ë‚´ 활ë™ì„ 보지 못합니다.</translation>
<translation id="4492190037599258964">'<ph name="SEARCH_STRING" />'ì— ëŒ€í•œ 검색결과</translation>
<translation id="4506176782989081258">유효성 검사 오류 <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">시스템 관리ìžì—게 문ì˜</translation>
<translation id="450710068430902550">관리ìžì™€ 공유</translation>
+<translation id="4515275063822566619">카드와 주소는 Chrome ë° Google 계정(<ph name="ACCOUNT_EMAIL" />)ì—ì„œ 가져왔습니다. ì´ ì •ë³´ëŠ” <ph name="BEGIN_LINK" />설정<ph name="END_LINK" />ì—ì„œ 관리할 수 있습니다.</translation>
<translation id="4522570452068850558">세부정보</translation>
<translation id="4558551763791394412">확장 프로그램 사용 중지해 보기</translation>
<translation id="457875822857220463">배송</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">페ì´ì§€ 맞춤</translation>
<translation id="483020001682031208">표시할 피지컬 웹 페ì´ì§€ê°€ 없습니다.</translation>
<translation id="4850886885716139402">보기</translation>
+<translation id="4854362297993841467">사용할 수 없는 배달 방법입니다. 다른 ë°©ë²•ì„ ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="4858792381671956233">ì´ ì‚¬ì´íŠ¸ë¥¼ ë°©ë¬¸í•´ë„ ê´œì°®ì€ì§€ 부모님께 문ì˜í–ˆìŠµë‹ˆë‹¤.</translation>
<translation id="4880827082731008257">ê¸°ë¡ ê²€ìƒ‰</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">페ì´ì§€ê°€ ì•Œ 수 없는 언어ì—ì„œ <ph name="LANGUAGE_LANGUAGE" />(으)ë¡œ 번역ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="4923459931733593730">결제</translation>
<translation id="4926049483395192435">지정해야 합니다.</translation>
-<translation id="4941291666397027948">* 필수 입력란</translation>
<translation id="495170559598752135">ìž‘ì—…</translation>
<translation id="4958444002117714549">펼치기 목ë¡</translation>
<translation id="4962322354953122629">Chromeì—ì„œ 신뢰하지 않는 기관ì—ì„œ 발행한 ì¸ì¦ì„œë¥¼ 제공하여 서버 ë„ë©”ì¸ì´ <ph name="DOMAIN" />ìž„ì„ ì¦ëª…í•  수 없습니다. ì„¤ì •ì´ ìž˜ëª»ë˜ì—ˆê±°ë‚˜ 해커가 ì—°ê²°ì„ ê°€ë¡œì±„ê³  있기 ë•Œë¬¸ì¼ ìˆ˜ 있습니다. <ph name="BEGIN_LEARN_MORE_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">비밀번호가 잘못ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="5056549851600133418">추천 ë„움ë§</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />프ë¡ì‹œ 주소 확ì¸<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{쿠키를 사용하는 사ì´íŠ¸ ì—†ìŒ}=1{사ì´íŠ¸ 1ê°œì—ì„œ 쿠키를 사용합니다. }other{사ì´íŠ¸ #ê°œì—ì„œ 쿠키를 사용합니다. }}</translation>
<translation id="5087286274860437796">ì„œë²„ì˜ ì¸ì¦ì„œê°€ 현재 유효하지 않습니다.</translation>
<translation id="5087580092889165836">카드 추가</translation>
<translation id="5089810972385038852">주</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">표시</translation>
<translation id="5308689395849655368">ë¹„ì •ìƒ ì¢…ë£Œ ë³´ê³ ê°€ 사용 중지ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="5317780077021120954">저장</translation>
-<translation id="5326702247179446998">ìˆ˜ì‹ ìž í•„ìš”</translation>
<translation id="5327248766486351172">ì´ë¦„</translation>
<translation id="5337705430875057403"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 공격ìžê°€ 소프트웨어를 설치하거나 ê°œì¸ì •ë³´(예: 비밀번호, 전화번호, ì‹ ìš©ì¹´ë“œ ì •ë³´)를 공개하는 ë“±ì˜ ìœ„í—˜í•œ í–‰ë™ì„ 하ë„ë¡ ì‚¬ìš©ìžë¥¼ ì†ì¼ 수 있습니다.</translation>
-<translation id="53553865750799677">지ì›ë˜ì§€ 않는 수령지 주소입니다. 다른 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="5359637492792381994">현재 ì„œë²„ì˜ ë³´ì•ˆ ì¸ì¦ì„œê°€ 유효하지 ì•Šì•„ 서버 ë„ë©”ì¸ì´ <ph name="DOMAIN" />ìž„ì„ ì¦ëª…í•  수 없습니다. ì„¤ì •ì´ ìž˜ëª»ë˜ì—ˆê±°ë‚˜ 해커가 ì—°ê²°ì„ ê°€ë¡œì±„ê³  있기 ë•Œë¬¸ì¼ ìˆ˜ 있습니다. <ph name="BEGIN_LEARN_MORE_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">정책 설정 저장 실패</translation>
<translation id="5386426401304769735">ì´ ì‚¬ì´íŠ¸ì˜ ì¸ì¦ì„œ ì²´ì¸ì€ SHA-1ì„ ì‚¬ìš©í•˜ì—¬ ì„œëª…ëœ ì¸ì¦ì„œë¥¼ í¬í•¨í•©ë‹ˆë‹¤.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102"><ph name="SITE" />ì— ì‚½ìž…ëœ íŽ˜ì´ì§€ ë‚´ìš©:</translation>
<translation id="5556459405103347317">새로고침</translation>
<translation id="5565735124758917034">활성</translation>
+<translation id="5571083550517324815">ì´ ì£¼ì†Œì—ì„œ 수령할 수 없습니다. 다른 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="5572851009514199876">ì´ ì‚¬ì´íŠ¸ì— 액세스할 수 있는지 확ì¸í•  수 있ë„ë¡ Chromeì„ ì‹œìž‘í•˜ê³  로그ì¸í•˜ì„¸ìš”.</translation>
-<translation id="5575380383496039204">지ì›ë˜ì§€ 않는 배송지 주소입니다. 다른 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="5580958916614886209">유효기간 ì›”ì„ í™•ì¸í•œ 후 다시 ì‹œë„í•´ 주세요.</translation>
<translation id="560412284261940334">관리가 지ì›ë˜ì§€ ì•ŠìŒ</translation>
<translation id="5610142619324316209">ì—°ê²° 확ì¸</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">ì´ ì›¹ì‚¬ì´íŠ¸ì˜ 주소가 확ì¸ë˜ì§€ 않았습니다.</translation>
<translation id="5720705177508910913">현재 사용ìž</translation>
<translation id="5732392974455271431">ë¶€ëª¨ë‹˜ì´ ì°¨ë‹¨ 해제할 수 있습니다.</translation>
-<translation id="57586589942790530">ì¹´ë“œ 번호가 잘못ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
+<translation id="5763042198335101085">올바른 ì´ë©”ì¼ ì£¼ì†Œë¥¼ 입력하세요.</translation>
+<translation id="5765072501007116331">배달 방법과 ìš”êµ¬ì‚¬í•­ì„ í™•ì¸í•˜ë ¤ë©´ 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="5784606427469807560">ì¹´ë“œ í™•ì¸ ì¤‘ì— ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì¸í„°ë„· ì—°ê²°ì„ í™•ì¸í•˜ê³  다시 ì‹œë„하세요.</translation>
<translation id="5785756445106461925">ë˜í•œ ì´ íŽ˜ì´ì§€ì—는 안전하지 ì•Šì€ ë‹¤ë¥¸ 리소스가 í¬í•¨ë˜ì–´ 있습니다. ì´ëŸ¬í•œ 리소스는 전송 ì¤‘ì— ë‹¤ë¥¸ ì‚¬ëžŒì´ ë³¼ 수 있으며 페ì´ì§€ì˜ ëª¨ì–‘ì„ ë³€ê²½í•˜ê¸° 위해 공격ìžê°€ 수정할 수 있습니다.</translation>
<translation id="5786044859038896871">카드 정보를 입력하시겠습니까?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">사ì´íŠ¸ì— ì—°ê²°í•  수 ì—†ìŒ</translation>
<translation id="5869522115854928033">ì €ìž¥ëœ ë¹„ë°€ë²ˆí˜¸</translation>
<translation id="5872918882028971132">ìƒìœ„ 추천</translation>
-<translation id="587760065310675640">지ì›ë˜ì§€ 않는 배송지 주소입니다. 다른 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="5901630391730855834">노란색</translation>
-<translation id="59174027418879706">사용 설정ë¨</translation>
<translation id="5926846154125914413">ì¼ë¶€ 사ì´íŠ¸ì˜ 프리미엄 콘í…츠를 액세스하지 못할 수 있습니다.</translation>
<translation id="5959728338436674663">위험한 앱과 사ì´íŠ¸ë¥¼ ê°ì§€í•  수 있ë„ë¡ ì¼ë¶€ <ph name="BEGIN_WHITEPAPER_LINK" />시스템 정보와 페ì´ì§€ 콘í…츠<ph name="END_WHITEPAPER_LINK" />를 Googleë¡œ ìžë™ 전송합니다. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">주</translation>
<translation id="5967867314010545767">기ë¡ì—ì„œ ì‚­ì œ</translation>
<translation id="5975083100439434680">축소</translation>
+<translation id="598637245381783098">ê²°ì œ ì•±ì„ ì—´ 수 없습니다.</translation>
<translation id="5989320800837274978">ê³ ì • 프ë¡ì‹œ 서버와 .pac 스í¬ë¦½íŠ¸ URLì´ ëª¨ë‘ ì§€ì •ë˜ì§€ 않았습니다.</translation>
<translation id="5990559369517809815">ì„œë²„ì— ëŒ€í•œ ìš”ì²­ì´ í™•ìž¥ í”„ë¡œê·¸ëž¨ì— ì˜í•´ 차단ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">ì¹´ë“œ ë° ì£¼ì†Œ ì˜µì…˜ì€ Chromeì—ì„œ 가져왔습니다. <ph name="BEGIN_LINK" />설정<ph name="END_LINK" />ì—ì„œ ì¹´ë“œ ë° ì£¼ì†Œ ì˜µì…˜ì„ ê´€ë¦¬í•  수 있습니다.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1페ì´ì§€}other{#페ì´ì§€}}</translation>
<translation id="6017514345406065928">녹색</translation>
+<translation id="6027201098523975773">ì´ë¦„ì„ ìž…ë ¥í•˜ì„¸ìš”.</translation>
<translation id="6040143037577758943">닫기</translation>
-<translation id="604124094241169006">ìžë™</translation>
<translation id="6042308850641462728">ë”보기</translation>
<translation id="6060685159320643512">ì´ëŸ¬í•œ 실험실 ê¸°ëŠ¥ì€ ë¬¸ì œë¥¼ ì¼ìœ¼í‚¬ 수 있습니다.</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{ì—†ìŒ}=1{1ê°œ}other{#ê°œ}}</translation>
@@ -543,9 +552,10 @@
재부팅하시기 ë°”ëžë‹ˆë‹¤.</translation>
<translation id="614940544461990577">다ìŒì„ ì‹œë„:</translation>
<translation id="6151417162996330722">서버 ì¸ì¦ì„œì˜ 유효 ê¸°ê°„ì´ ë„ˆë¬´ ê¹ë‹ˆë‹¤.</translation>
-<translation id="615643356032862689">ë‹¤ìš´ë¡œë“œëœ íŒŒì¼ ë° ë¶ë§ˆí¬ê°€ ë³´ê´€ë©ë‹ˆë‹¤.</translation>
+<translation id="6157877588268064908">배송 방법과 ìš”êµ¬ì‚¬í•­ì„ í™•ì¸í•˜ë ¤ë©´ 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="6165508094623778733">ìžì„¸ížˆ 알아보기</translation>
<translation id="6177128806592000436">ì´ ì‚¬ì´íŠ¸ì— 대한 ì—°ê²°ì€ ì•ˆì „í•˜ì§€ 않습니다.</translation>
+<translation id="6184817833369986695">(집단: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">ì¸í„°ë„· ì—°ê²°ì„ í™•ì¸í•˜ì„¸ìš”.</translation>
<translation id="6218753634732582820">Chromiumì—ì„œ 주소를 삭제하시겠습니까?</translation>
<translation id="6251924700383757765">ê°œì¸ì •ë³´ì²˜ë¦¬ë°©ì¹¨</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">재정렬 다시 실행(&amp;R)</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> ë¶ë§ˆí¬</translation>
<translation id="6264485186158353794">안전 페ì´ì§€ë¡œ ëŒì•„가기</translation>
+<translation id="6276112860590028508">ì½ê¸° 목ë¡ì˜ 페ì´ì§€ê°€ ì—¬ê¸°ì— í‘œì‹œë©ë‹ˆë‹¤.</translation>
+<translation id="6280223929691119688">ì´ ì£¼ì†Œë¡œ 배달할 수 없습니다. 다른 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="6282194474023008486">우편번호</translation>
<translation id="6290238015253830360">추천 기사가 ì—¬ê¸°ì— í‘œì‹œë©ë‹ˆë‹¤.</translation>
<translation id="6305205051461490394"><ph name="URL" />ì— ì—°ê²°í•  수 없습니다.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">ì¸ì¦ì„œê°€ 취소ë˜ì—ˆëŠ”지 확ì¸í•  수 없습니다.</translation>
<translation id="6433490469411711332">ì—°ë½ì²˜ ì •ë³´ 수정</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" />ì—ì„œ ì—°ê²°ì„ ê±°ë¶€í–ˆìŠµë‹ˆë‹¤.</translation>
-<translation id="6443118737398455446">ìœ íš¨ê¸°ê°„ì´ ìž˜ëª»ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="6446608382365791566">ìžì„¸í•œ ì •ë³´ 추가</translation>
<translation id="6451458296329894277">ì–‘ì‹ ë‹¤ì‹œ 제출 확ì¸</translation>
<translation id="6456339708790392414">결제</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">보안 ì¸ì¦ì„œê°€ 취소ë˜ì—ˆì„ 수 있어서 서버 ë„ë©”ì¸ì´ <ph name="DOMAIN" />ìž„ì„ ì¦ëª…í•  수 없습니다. ì„¤ì •ì´ ìž˜ëª»ë˜ì—ˆê±°ë‚˜ 해커가 ì—°ê²°ì„ ê°€ë¡œì±„ê³  있기 ë•Œë¬¸ì¼ ìˆ˜ 있습니다. <ph name="BEGIN_LEARN_MORE_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">기기 정책</translation>
<translation id="6477321094435799029">Chromeì´ ì´ íŽ˜ì´ì§€ì—ì„œ 비정ìƒì ì¸ 코드를 ê°ì§€í–ˆìœ¼ë©° ê°œì¸ì •ë³´(예: 비밀번호, 전화번호, ì‹ ìš©ì¹´ë“œ) 보호를 위해 차단했습니다.</translation>
-<translation id="6477460825583319731">ìž˜ëª»ëœ ì´ë©”ì¼ ì£¼ì†Œ</translation>
<translation id="6489534406876378309">ë¹„ì •ìƒ ì¢…ë£Œ 업로드 시작하기</translation>
<translation id="6508722015517270189">Chrome 다시 시작하기</translation>
-<translation id="6525462735697194615">만료 ì›”ì´ ìž˜ëª»ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="6529602333819889595">삭제 다시 실행(&amp;R)</translation>
<translation id="6534179046333460208">피지컬 웹 제안</translation>
<translation id="6550675742724504774">옵션</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> 검색</translation>
<translation id="6644283850729428850">ì´ ì •ì±…ì€ ì‚¬ìš©ë˜ì§€ 않습니다.</translation>
<translation id="6652240803263749613">ì»´í“¨í„°ì˜ ìš´ì˜ì²´ì œì—ì„œ 보안 ì¸ì¦ì„œë¥¼ 신뢰하지 ì•Šì•„ì„œ 서버 ë„ë©”ì¸ì´ <ph name="DOMAIN" />ìž„ì„ ì¦ëª…í•  수 없습니다. ì„¤ì •ì´ ìž˜ëª»ë˜ì—ˆê±°ë‚˜ 해커가 ì—°ê²°ì„ ê°€ë¡œì±„ê³  있기 ë•Œë¬¸ì¼ ìˆ˜ 있습니다. <ph name="BEGIN_LEARN_MORE_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="6665267558048410100">해당 배송 ì˜µì…˜ì€ ì„ íƒí•  수 없습니다. 다른 ì˜µì…˜ì„ ì‚¬ìš©í•´ 보세요.</translation>
<translation id="6671697161687535275">Chromiumì—ì„œ ìžë™ì™„성 항목 ì¶”ì²œì„ ì‚­ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="6685834062052613830">로그아웃 후 설정 완료</translation>
<translation id="6710213216561001401">ì´ì „</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">프ë¡ì‹œ ì„œë²„ì— ë¬¸ì œê°€ ë°œìƒí–ˆê±°ë‚˜ 주소가 잘못ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="6727102863431372879">설정</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{ì—†ìŒ}=1{항목 1ê°œ}other{항목 #ê°œ}}</translation>
-<translation id="6743044928064272573">수령 옵션</translation>
<translation id="674375294223700098">ì•Œ 수 없는 서버 ì¸ì¦ì„œ 오류입니다.</translation>
<translation id="6753269504797312559">ì •ì±… ê°’</translation>
<translation id="6757797048963528358">기기가 절전 모드 ìƒíƒœìž…니다.</translation>
<translation id="6778737459546443941">ë¶€ëª¨ë‹˜ì´ ì•„ì§ ìŠ¹ì¸í•˜ì§€ 않았습니다.</translation>
<translation id="6810899417690483278">맞춤설정 ID</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">지역 ë°ì´í„°ë¥¼ 로드하지 못했습니다.</translation>
<translation id="6831043979455480757">번역</translation>
<translation id="6839929833149231406">지역</translation>
<translation id="6874604403660855544">추가 다시 실행(&amp;R)</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">카드가 확ì¸ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="6897140037006041989">ì‚¬ìš©ìž ì—ì´ì „트</translation>
<translation id="6915804003454593391">사용ìž:</translation>
+<translation id="6948701128805548767">수령 방법과 ìš”êµ¬ì‚¬í•­ì„ í™•ì¸í•˜ë ¤ë©´ 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="6957887021205513506">ì„œë²„ì˜ ì¸ì¦ì„œê°€ ìœ„ì¡°ëœ ê²ƒ 같습니다.</translation>
<translation id="6965382102122355670">확ì¸</translation>
<translation id="6965978654500191972">기기</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">ê³ ì • 프ë¡ì‹œ 서버와 .pac 스í¬ë¦½íŠ¸ URLì´ ëª¨ë‘ ì§€ì •ë˜ì–´ 있습니다.</translation>
<translation id="6989763994942163495">고급 설정 표시</translation>
<translation id="7000990526846637657">기ë¡ì´ 없습니다.</translation>
-<translation id="7001663382399377034">ìˆ˜ì‹ ìž ì¶”ê°€</translation>
<translation id="7009986207543992532"><ph name="DOMAIN" />ì— ì ‘ì†í•˜ë ¤ 했으나 서버ì—ì„œ ì¸ì¦ ê¸°ê°„ì´ ë„ˆë¬´ 길어서 신뢰할 수 없는 ì¸ì¦ì„œë¥¼ 제시했습니다. <ph name="BEGIN_LEARN_MORE_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Google ê³„ì •ì— ë‹¤ë¥¸ 형ì‹ì˜ íƒìƒ‰ 기ë¡ì´ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />ì— ë‚¨ì•„ìžˆì„ ìˆ˜ 있습니다.</translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">다ìŒ</translation>
<translation id="7090678807593890770">Googleì—ì„œ <ph name="LINK" /> 검색</translation>
<translation id="7119414471315195487">다른 탭 ë˜ëŠ” 프로그램 닫기</translation>
+<translation id="7129409597930077180">ì´ ì£¼ì†Œë¡œ 배송할 수 없습니다. 다른 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
+<translation id="7138472120740807366">배달 방법</translation>
<translation id="7139724024395191329">ì—미리트</translation>
<translation id="7155487117670177674">결제가 안전하지 ì•ŠìŒ</translation>
<translation id="7179921470347911571">지금 다시 시작</translation>
<translation id="7180611975245234373">새로고침</translation>
<translation id="7182878459783632708">ì„¤ì •ëœ ì •ì±… ì—†ìŒ</translation>
<translation id="7186367841673660872">ì´ íŽ˜ì´ì§€ëŠ”<ph name="ORIGINAL_LANGUAGE" />ì—ì„œ<ph name="LANGUAGE_LANGUAGE" />ë¡œ 번역ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
+<translation id="7192203810768312527"><ph name="SIZE" />ì˜ ì €ìž¥ìš©ëŸ‰ì„ í™•ë³´í•©ë‹ˆë‹¤. ì¼ë¶€ 사ì´íŠ¸ëŠ” 다ìŒì— 방문할 ë•Œ 로드 ì†ë„ê°€ ëŠë ¤ì§ˆ ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" />ì—ì„œ 보안 ê¸°ì¤€ì„ ì¤€ìˆ˜í•˜ì§€ 않습니다.</translation>
<translation id="721197778055552897">ì´ ë¬¸ì œì— ëŒ€í•´ <ph name="BEGIN_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LINK" /></translation>
@@ -675,7 +686,6 @@
<translation id="7424977062513257142">ì´ ì›¹íŽ˜ì´ì§€ì— ì‚½ìž…ëœ íŽ˜ì´ì§€ ë‚´ìš©:</translation>
<translation id="7441627299479586546">ìž˜ëª»ëœ ì •ì±… 주체</translation>
<translation id="7444046173054089907">ì°¨ë‹¨ëœ ì‚¬ì´íŠ¸</translation>
-<translation id="7444238235002594607">배송 방법과 ìš”ê±´ì„ í™•ì¸í•˜ë ¤ë©´ 수령할 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="7445762425076701745">연결하려는 서버 ID를 확ì¸í•  수 없습니다. 외부 ì¸ì¦ 기관ì—ì„œ ì†Œìœ ê¶Œì„ í™•ì¸í•  수 없으므로 네트워í¬ì—ì„œ 유효한 ì´ë¦„ì„ ì‚¬ìš©í•˜ì—¬ ì„œë²„ì— ì—°ê²°ë©ë‹ˆë‹¤. ì¼ë¶€ ì¸ì¦ 기관ì—서는 ì´ëŸ¬í•œ ì´ë¦„ì— ëŒ€í•´ ê´€ê³„ì—†ì´ ì¸ì¦ì„œë¥¼ 발급하기 ë•Œë¬¸ì— ê³µê²©ìžê°€ ì•„ë‹ˆë¼ ì˜ë„í•œ 웹사ì´íŠ¸ì— ì—°ê²°ë˜ì–´ 있는지 확ì¸í•  수 없습니다.</translation>
<translation id="7451311239929941790">ì´ ë¬¸ì œë¥¼ <ph name="BEGIN_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LINK" /></translation>
<translation id="7460163899615895653">다른 기기ì—ì„œ ìµœê·¼ì— ì‚¬ìš©í•œ íƒ­ì´ ì—¬ê¸°ì— í‘œì‹œë©ë‹ˆë‹¤.</translation>
@@ -719,6 +729,7 @@
<translation id="7755287808199759310">ë¶€ëª¨ë‹˜ì´ ì°¨ë‹¨ 해제할 수 있습니다.</translation>
<translation id="7758069387465995638">방화벽ì´ë‚˜ ë°”ì´ëŸ¬ìŠ¤ 백신 소프트웨어가 ì—°ê²°ì„ ì°¨ë‹¨í–ˆì„ ìˆ˜ 있습니다.</translation>
<translation id="7761701407923456692">ì„œë²„ì˜ ì¸ì¦ì„œê°€ URLê³¼ ì¼ì¹˜í•˜ì§€ 않습니다.</translation>
+<translation id="7763386264682878361">결제 매니페스트 파서</translation>
<translation id="7764225426217299476">주소 추가</translation>
<translation id="777702478322588152">ë„</translation>
<translation id="7791543448312431591">추가</translation>
@@ -732,6 +743,7 @@
<translation id="785549533363645510">하지만 í”ì ì´ 아예 남지 않는 ê²ƒì€ ì•„ë‹™ë‹ˆë‹¤. ì‹œí¬ë¦¿ 모드로 íƒìƒ‰í•´ë„ 회사, ì¸í„°ë„· 서비스 제공업체 ë˜ëŠ” 방문한 웹사ì´íŠ¸ì— ì €ìž¥ëœ í”ì ê¹Œì§€ 없앨 수는 없습니다.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">CVC를 확ì¸í•œ 후 다시 ì‹œë„하세요.</translation>
+<translation id="79338296614623784">올바른 전화번호를 입력하세요.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">서버 ì¸ì¦ì„œê°€ 유효하지 않습니다.</translation>
<translation id="7942349550061667556">빨간색</translation>
@@ -751,6 +763,7 @@
<translation id="8088680233425245692">ê¸€ì„ ì¡°íšŒí•˜ì§€ 못했습니다.</translation>
<translation id="8089520772729574115">1MB 미만</translation>
<translation id="8091372947890762290">활성화 ìš”ì²­ì´ ì„œë²„ì—ì„œ 대기 중</translation>
+<translation id="8118489163946903409">결제 수단</translation>
<translation id="8131740175452115882">확ì¸</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" />ì˜ ì„œë²„ <ph name="BEGIN_ABBR" />DNS 주소<ph name="END_ABBR" />를 ì°¾ì„ ìˆ˜ 없습니다.</translation>
<translation id="8149426793427495338">컴퓨터가 절전 모드 ìƒíƒœìž…니다.</translation>
@@ -776,6 +789,7 @@
<translation id="8349305172487531364">ë¶ë§ˆí¬ë°”</translation>
<translation id="8363502534493474904">비행기 모드 사용 중지</translation>
<translation id="8364627913115013041">설정 안ë¨</translation>
+<translation id="8368476060205742148">Google Play 서비스</translation>
<translation id="8380941800586852976">위험</translation>
<translation id="8382348898565613901">ìµœê·¼ì— ë°©ë¬¸í•œ ë¶ë§ˆí¬ê°€ ì—¬ê¸°ì— í‘œì‹œë©ë‹ˆë‹¤.</translation>
<translation id="8398259832188219207">ë¹„ì •ìƒ ì¢…ë£Œ 보고서가 <ph name="UPLOAD_TIME" />ì— ì—…ë¡œë“œë¨</translation>
@@ -784,31 +798,29 @@
<translation id="8428213095426709021">설정</translation>
<translation id="8433057134996913067">ì´ ìž‘ì—…ì„ ìˆ˜í–‰í•˜ë©´ ëŒ€ë¶€ë¶„ì˜ ì›¹ì‚¬ì´íŠ¸ì—ì„œ 로그아웃ë©ë‹ˆë‹¤.</translation>
<translation id="8437238597147034694">ì´ë™ 실행 취소(&amp;U)</translation>
-<translation id="8456681095658380701">ìž˜ëª»ëœ ì´ë¦„입니다.</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{신용카드 1개}other{신용카드 #개}}</translation>
<translation id="8483780878231876732">Google 계정ì—ì„œ 카드를 사용하려면 Chromeì— ë¡œê·¸ì¸í•˜ì„¸ìš”.</translation>
<translation id="8488350697529856933">ì ìš© 대ìƒ</translation>
-<translation id="8492969205326575646">지ì›ë˜ì§€ 않는 ì¹´ë“œ 종류입니다.</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" />ì—ì„œ ì‘답하는 ë° ì‹œê°„ì´ ë„ˆë¬´ 오래 걸립니다.</translation>
<translation id="852346902619691059">ê¸°ê¸°ì˜ ìš´ì˜ì²´ì œì—ì„œ 보안 ì¸ì¦ì„œë¥¼ 신뢰하지 ì•Šì•„ì„œ 서버 ë„ë©”ì¸ì´ <ph name="DOMAIN" />ìž„ì„ ì¦ëª…í•  수 없습니다. ì„¤ì •ì´ ìž˜ëª»ë˜ì—ˆê±°ë‚˜ 해커가 ì—°ê²°ì„ ê°€ë¡œì±„ê³  있기 ë•Œë¬¸ì¼ ìˆ˜ 있습니다. <ph name="BEGIN_LEARN_MORE_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="8532105204136943229">만료 ì—°ë„</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />ê°ì§€ 문제를 ì‹ ê³ <ph name="END_ERROR_LINK" />í•  수 있으며, ë³´ì•ˆì— ë¯¸ì¹˜ëŠ” ìœ„í—˜ì„ ê°ìˆ˜í•œë‹¤ë©´ <ph name="BEGIN_LINK" />ì´ ì•ˆì „í•˜ì§€ ì•Šì€ ì‚¬ì´íŠ¸ë¥¼ 방문<ph name="END_LINK" />í•  수 있습니다.</translation>
<translation id="8553075262323480129">페ì´ì§€ì˜ 언어를 ê²°ì •í•  수 없으므로 번역하지 못했습니다.</translation>
<translation id="8559762987265718583">ê¸°ê¸°ì˜ ë‚ ì§œì™€ 시간(<ph name="DATE_AND_TIME" />)ì´ ìž˜ëª»ë˜ì–´ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />ì— ëŒ€í•œ 비공개 ì—°ê²°ì„ ì„¤ì •í•  수 없습니다.</translation>
-<translation id="8570229484593575558">아래 정보는 |저장ë˜ì§€ 않습니다.|#ì¸í„°ë„· 사용 기ë¡#검색어#쿠키 ë°ì´í„°</translation>
<translation id="8571890674111243710">페ì´ì§€ë¥¼ <ph name="LANGUAGE" />(으)ë¡œ 번역 중...</translation>
-<translation id="8584539743998202583">ì‹œí¬ë¦¿ 모드를 ì‚¬ìš©í•´ë„ ë‹¤ìŒì—ì„œ |ë‚´ 활ë™ì´ 표시|ë  ìˆ˜ 있습니다.#ë‚´ê°€ 방문한 웹사ì´íŠ¸#고용주#ì¸í„°ë„· 서비스 제공업체</translation>
<translation id="858637041960032120">번호 추가</translation>
<translation id="859285277496340001">ì¸ì¦ì„œëŠ” 취소 여부를 확ì¸í•˜ëŠ” ë§¤ì»¤ë‹ˆì¦˜ì„ ì§€ì •í•˜ì§€ 않습니다.</translation>
<translation id="8620436878122366504">ë¶€ëª¨ë‹˜ì´ ì•„ì§ ìŠ¹ì¸í•˜ì§€ 않았습니다.</translation>
<translation id="8647750283161643317">기본값으로 재설정</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" />ë¡œì˜ ì—°ê²°ì€ ì•”í˜¸í™”ë˜ì§€ 않습니다.</translation>
+<translation id="8718314106902482036">결제가 완료ë˜ì§€ ì•ŠìŒ</translation>
<translation id="8725066075913043281">다시 ì‹œë„하세요</translation>
<translation id="8728672262656704056">ì‹œí¬ë¦¿ 모드로 전환ë¨</translation>
<translation id="8730621377337864115">완료</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="8759274551635299824">ë§Œë£Œëœ ì¹´ë“œìž…ë‹ˆë‹¤.</translation>
<translation id="8790007591277257123">삭제 다시 실행(&amp;R)</translation>
-<translation id="8798099450830957504">기본값</translation>
<translation id="8800988563907321413">근처 추천 í•­ëª©ì´ ì—¬ê¸°ì— í‘œì‹œë©ë‹ˆë‹¤.</translation>
<translation id="8820817407110198400">ë¶ë§ˆí¬</translation>
<translation id="883848425547221593">기타 ë¶ë§ˆí¬</translation>
@@ -818,6 +830,7 @@
<translation id="8866481888320382733">ì •ì±… ì„¤ì •ì„ íŒŒì‹±í•˜ëŠ” 중 오류 ë°œìƒ</translation>
<translation id="8866959479196209191">ì´ íŽ˜ì´ì§€ ë‚´ìš©:</translation>
<translation id="8870413625673593573">ìµœê·¼ì— ë‹«ì€ íƒ­</translation>
+<translation id="8874824191258364635">올바른 카드 번호를 입력하세요.</translation>
<translation id="8876793034577346603">ë„¤íŠ¸ì›Œí¬ ì„¤ì •ì„ íŒŒì‹±í•˜ì§€ 못했습니다.</translation>
<translation id="8877192140621905067">카드를 확ì¸í•˜ë©´ ì¹´ë“œ 세부정보가 ì´ ì‚¬ì´íŠ¸ì™€ 공유ë©ë‹ˆë‹¤.</translation>
<translation id="8889402386540077796">색조</translation>
@@ -827,7 +840,6 @@
<translation id="8931333241327730545">ì´ ì¹´ë“œë¥¼ Google ê³„ì •ì— ì €ìž¥í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="8932102934695377596">ì‹œê°„ì´ ë„ˆë¬´ 먼 과거로 설정ë˜ì–´ 있습니다.</translation>
<translation id="8954894007019320973">(계ì†)</translation>
-<translation id="895548565263634352"><ph name="ARTICLE_PUBLISHER" />, <ph name="OTHER_ARTICLE_COUNT" /> 등ì—ì„œ 제공하는 소ì‹ì„ ì½ì–´ë³´ì„¸ìš”.</translation>
<translation id="8971063699422889582">서버 ì¸ì¦ì„œê°€ 만료ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="8986494364107987395">사용 통계 ë° ë¹„ì •ìƒ ì¢…ë£Œ 보고서를 Googleì— ìžë™ìœ¼ë¡œ 보내기</translation>
<translation id="8987927404178983737">ì›”</translation>
@@ -845,7 +857,6 @@
<translation id="9068849894565669697">ìƒ‰ìƒ ì„ íƒ</translation>
<translation id="9076283476770535406">성ì¸ìš© 콘í…츠가 í¬í•¨ë˜ì–´ ìžˆì„ ìˆ˜ 있습니다.</translation>
<translation id="9078964945751709336">ìžì„¸í•œ ì •ë³´ í•„ìš”</translation>
-<translation id="9094175695478007090">ê²°ì œ ì•±ì„ ì‹¤í–‰í•  수 없습니다.</translation>
<translation id="9103872766612412690"><ph name="SITE" />ì—서는 ì‚¬ìš©ìž ì •ë³´ë¥¼ 보호하기 위해 ì¼ë°˜ì ìœ¼ë¡œ 암호화를 사용합니다. ì´ë²ˆì— Chromiumì—ì„œ <ph name="SITE" />ì— ì—°ê²°ì„ ì‹œë„í–ˆì„ ë•Œ 웹사ì´íŠ¸ì—ì„œ 비정ìƒì ì´ê³  ìž˜ëª»ëœ ì‚¬ìš©ìž ì¸ì¦ 정보를 반환했습니다. ì´ëŠ” 공격ìžê°€ <ph name="SITE" />ì¸ ê²ƒì²˜ëŸ¼ 가장하려고 하거나 Wi-Fi ë¡œê·¸ì¸ í™”ë©´ì´ ì—°ê²°ì„ ë°©í•´í–ˆê¸° ë•Œë¬¸ì¼ ìˆ˜ 있습니다. ë°ì´í„° êµí™˜ì´ ë°œìƒí•˜ê¸° ì „ì— Chromiumì—ì„œ ì—°ê²°ì„ ì¤‘ë‹¨í–ˆìœ¼ë¯€ë¡œ ì‚¬ìš©ìž ì •ë³´ëŠ” 안전합니다.</translation>
<translation id="9137013805542155359">ì›ë³¸ 보기</translation>
<translation id="9137248913990643158">ì´ ì•±ì„ ì‚¬ìš©í•˜ê¸° ì „ì— Chromeì„ ì‹œìž‘í•˜ê³  로그ì¸í•˜ì„¸ìš”.</translation>
diff --git a/chromium/components/strings/components_strings_lt.xtb b/chromium/components/strings/components_strings_lt.xtb
index 067043b2ad3..18ca8f6ef11 100644
--- a/chromium/components/strings/components_strings_lt.xtb
+++ b/chromium/components/strings/components_strings_lt.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="lt">
<translation id="1008557486741366299">Ne dabar</translation>
<translation id="1015730422737071372">Pateikti papildomos išsamios informacijos</translation>
+<translation id="1021110881106174305">Tinkamos kortelÄ—s</translation>
<translation id="1032854598605920125">Pasukti pagal laikrodžio rodyklę</translation>
<translation id="1038842779957582377">nežinomas pavadinimas</translation>
<translation id="1050038467049342496">Uždarykite kitas programas</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">SlÄ—pti vertÄ™</translation>
<translation id="1228893227497259893">Netinkamas subjekto identifikatorius</translation>
<translation id="1232569758102978740">Be pavadinimo</translation>
+<translation id="1263231323834454256">Skaitymo sąrašas</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> užfiksuota strigÄių ataskaita (dar neįkelta ar nepaisoma)</translation>
<translation id="1285320974508926690">Niekada neversti Å¡ios svetainÄ—s</translation>
<translation id="129553762522093515">Neseniai uždarytas</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">„Chromium“ automatinio pildymo nustatymai...</translation>
<translation id="1374468813861204354">pasiūlymai</translation>
<translation id="1375198122581997741">Apie versijÄ…</translation>
+<translation id="1377321085342047638">Kort. Nr.</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> neišsiuntė jokių duomenų.</translation>
<translation id="1407135791313364759">Atidaryti viskÄ…</translation>
<translation id="1413809658975081374">Privatumo klaida</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Istorija</translation>
<translation id="1645368109819982629">Nepalaikomas protokolas</translation>
<translation id="1656489000284462475">PaÄ—mimas</translation>
+<translation id="1663943134801823270">Kortelės ir adresai naudojami iš „Chrome“. Juos galite tvarkyti nuėję į <ph name="BEGIN_LINK" />Nustatymus<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">Svetainėje <ph name="SITE" /> įprastai naudojama šifruotė informacijai apsaugoti. Šį kartą „Google Chrome“ bandant prisijungti prie <ph name="SITE" />, ji pateikė neįprastus ir netinkamus prisijungimo duomenis. Gali būti, kad užpuolėjas bando apsimesti svetaine <ph name="SITE" /> arba „Wi-Fi“ prisijungimo ekrane nutrūko ryšys. Jūsų informacija vis tiek liko apsaugota, nes „Google Chrome“ sustabdė prisijungimą prieš apsikeitimą bet kokiais duomenimis.</translation>
<translation id="168328519870909584">Šiuo metu svetainės <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> užpuolėjai gali jūsų įrenginyje bandyti įdiegti pavojingas programas, kurios vagia arba ištrina informaciją (pvz., nuotraukas, slaptažodžius, pranešimus ir kredito kortelių numerius).</translation>
<translation id="168841957122794586">Serverio sertifikate yra nesudÄ—tingas kriptografinis raktas.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Turite gauti <ph name="NAME" /> leidimÄ… apsilankyti Å¡ioje svetainÄ—je</translation>
+<translation id="1721424275792716183">* Būtina užpildyti lauką</translation>
<translation id="1728677426644403582">Peržiūrite tinklalapio šaltinį</translation>
+<translation id="173080396488393970">Å io tipo kortelÄ— nepalaikoma</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Pabandykite susisiekti su sistemos administratoriumi.</translation>
+<translation id="1740951997222943430">Įveskite tinkamą galiojimo laiko pabaigos mėnesį</translation>
<translation id="1745358365027406341">Atsisiųsti puslapį vėliau</translation>
<translation id="17513872634828108">Atidaryti skirtukai</translation>
<translation id="1753706481035618306">Puslapio numeris</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Atnaujinkite sinchronizavimo slaptafrazÄ™.</translation>
<translation id="1787142507584202372">Atidaryti skirtukai bus rodomi Äia</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Pasirinkite pristatymo adresÄ…, kad patikrintumÄ—te pristatymo metodus ir reikalavimus.</translation>
+<translation id="1803264062614276815">KortelÄ—s savininko vardas</translation>
<translation id="1803678881841855883">„Google“ saugaus narÅ¡ymo funkcija <ph name="BEGIN_LINK" />aptiko kenkÄ—jiÅ¡kÄ… programÄ…<ph name="END_LINK" /> svetainÄ—je <ph name="SITE" />. SvetainÄ—s, kurios paprastai yra saugios, kartais užkreÄiamos kenkÄ—jiÅ¡komis programomis. KenkÄ—jiÅ¡kÄ… turinį platina <ph name="SUBRESOURCE_HOST" /> – žinomas kenkÄ—jiÅ¡kų programų platintojas. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">PridÄ—ta <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Netinkama užklausa arba jos parametrai</translation>
<translation id="1826516787628120939">Tikrinama</translation>
<translation id="1834321415901700177">Šioje svetainėje yra kenkėjiškų programų</translation>
<translation id="1842969606798536927">MokÄ—ti</translation>
-<translation id="1864455488461349376">Pristatymo parinktis</translation>
<translation id="1871208020102129563">Įgaliotasis serveris nustatytas naudoti fiksuotų įgaliotųjų serverių, o ne .pac scenarijaus URL.</translation>
<translation id="1871284979644508959">BÅ«tinas laukas</translation>
<translation id="187918866476621466">Atidaryti paleidimo puslapius</translation>
<translation id="1883255238294161206">Sutraukti sąrašą</translation>
<translation id="1898423065542865115">Filtravimas</translation>
<translation id="194030505837763158">Apsilankykite <ph name="LINK" /></translation>
-<translation id="1946821392246652573">KortelÄ—s priimtos</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> žymės</translation>
<translation id="1973335181906896915">Serijinio rengimo klaida</translation>
<translation id="1974060860693918893">IÅ¡plÄ—stiniai</translation>
<translation id="1978555033938440688">Programinės aparatinės įrangos versija</translation>
+<translation id="1995859865337580572">Patvirtinkite kortelÄ—s saugos kodÄ… (CVC)</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{ir dar 1}one{ir dar #}few{ir dar #}many{ir dar #}other{ir dar #}}</translation>
-<translation id="2020194265157481222">BÅ«tina nurodyti ant kortelÄ—s pateiktÄ… vardÄ…</translation>
<translation id="2025186561304664664">Nustatytas automatinis įgaliotojo serverio konfigūravimas.</translation>
<translation id="2030481566774242610">Ar turÄ—jote omenyje <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Patikrinti tarpinį serverį ir užkardą<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Å iandien</translation>
<translation id="2154054054215849342">Sinchronizavimo paslauga nepasiekiama jūsų domenui</translation>
<translation id="2154484045852737596">KortelÄ—s informacijos redagavimas</translation>
-<translation id="2156993118928861787">Netinkamas adresas</translation>
<translation id="2166049586286450108">VisateisÄ— administratoriaus prieiga</translation>
<translation id="2166378884831602661">Ši svetainė negali užtikrinti saugaus ryšio</translation>
<translation id="2181821976797666341">Politika</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresas}one{# adresas}few{# adresai}many{# adreso}other{# adresų}}</translation>
+<translation id="2202020181578195191">Įveskite tinkamus galiojimo laiko pabaigos metus</translation>
<translation id="2212735316055980242">Politika nerasta</translation>
<translation id="2213606439339815911">Gaunami įrašai...</translation>
<translation id="2230458221926704099">Išspręskite ryšio problemas naudodami <ph name="BEGIN_LINK" />diagnostikos programą<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Interneto prieiga užblokuota</translation>
<translation id="230155334948463882">Nauja kortelÄ—?</translation>
<translation id="2305919008529760154">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas galėjo būti išduotas neteisėtai. Taip gali būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Naudojamos kortelės ir adreso parinktys iš jūsų „Google“ paskyros (<ph name="ACCOUNT_EMAIL" />) ir „Chrome“. Jas galite tvarkyti skiltyje <ph name="BEGIN_LINK" />Nustatymai<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> būtina įvesti naudotojo vardą ir slaptažodį.</translation>
<translation id="2318774815570432836">Šiuo metu negalite apsilankyti <ph name="SITE" />, nes svetainėje naudojama HSTS. Tinklo klaidos ir išpuoliai dažniausiai yra laikini, todėl šis puslapis tikriausiai veiks vėliau. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Kitos žymės</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Numatytieji įmonės nustatymai</translation>
<translation id="2386255080630008482">Serverio sertifikatas panaikintas.</translation>
<translation id="2392959068659972793">Rodyti politikÄ… su nenustatyta verte</translation>
+<translation id="239429038616798445">Å is pristatymo metodas nepasiekiamas. IÅ¡bandykite kitÄ… metodÄ….</translation>
<translation id="2396249848217231973">&amp;Anuliuoti ištrynimą</translation>
<translation id="2460160116472764928">„Google“ saugaus narÅ¡ymo funkcija neseniai <ph name="BEGIN_LINK" />aptiko kenkÄ—jiÅ¡kÄ… programÄ…<ph name="END_LINK" /> svetainÄ—je <ph name="SITE" />. Kartais svetainÄ—s, kurios paprastai yra saugios, užkreÄiamos kenkÄ—jiÅ¡komis programomis. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Užpildyti</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Paleistas įrankis „Windows Network Diagnostics“<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Netinkamas paieškos URL.</translation>
<translation id="2491120439723279231">Serverio sertifikate yra klaidų.</translation>
-<translation id="24943777258388405">Netinkamas telefono numeris</translation>
<translation id="2495083838625180221">JSON analizavimo įrankis</translation>
<translation id="2495093607237746763">Jei pažymÄ—ta, „Chromium“ iÅ¡saugos kortelÄ—s kopijÄ… įrenginyje, kad galÄ—tumÄ—te greiÄiau užpildyti formas.</translation>
<translation id="2498091847651709837">Nuskaityti naujÄ… kortelÄ™</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> išsiuntė netinkamą atsaką.</translation>
<translation id="2552545117464357659">Naujesnis</translation>
<translation id="2556876185419854533">&amp;Anuliuoti redagavimÄ…</translation>
+<translation id="2587730715158995865">Nuo „<ph name="ARTICLE_PUBLISHER" />“. Skaitykite šią ir kitas istorijas (<ph name="OTHER_ARTICLE_COUNT" />).</translation>
<translation id="2587841377698384444">Katalogo API ID:</translation>
<translation id="2597378329261239068">Šis dokumentas apsaugotas slaptažodžiu. Įveskite slaptažodį.</translation>
<translation id="2609632851001447353">Variantai</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Paleistas ryšio diagnostikos įrankis<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">Gerai</translation>
<translation id="2742870351467570537">Pašalinti pasirinktus elementus</translation>
+<translation id="277133753123645258">Pristatymo metodas</translation>
<translation id="277499241957683684">Trūksta įrenginio įrašo</translation>
<translation id="2784949926578158345">Ryšys atkurtas.</translation>
<translation id="2794233252405721443">Svetainė užblokuota</translation>
-<translation id="2812680587231492111">Ta paėmimo parinktis nepasiekiama. Išbandykite kitą paėmimo parinktį.</translation>
<translation id="2824775600643448204">Adreso ir paieškos juosta</translation>
<translation id="2826760142808435982">Ryšys užšifruotas ir tapatybė nustatyta naudojant <ph name="CIPHER" />. <ph name="KX" /> naudojamas kaip pagrindinis mainų mechanizmas.</translation>
<translation id="2835170189407361413">Valyti formÄ…</translation>
-<translation id="2849041323157393173">Ta pristatymo parinktis nepasiekiama. Išbandykite kitą paėmimo parinktį.</translation>
<translation id="2889159643044928134">Neįkelti iš naujo</translation>
<translation id="2900469785430194048">„Google Chrome“ trūksta atminties šiam tinklalapiui pateikti.</translation>
<translation id="2909946352844186028">Aptiktas tinklo pasikeitimas.</translation>
<translation id="2916038427272391327">Uždarykite kitas programas</translation>
<translation id="2922350208395188000">Neįmanoma patikrinti serverio sertifikato.</translation>
+<translation id="2928905813689894207">Atsiskaitymo adresas</translation>
<translation id="2948083400971632585">Galite neleisti visų tarpinių serverių, jungimasis prie kurių sukonfigūruotas nustatymų puslapyje.</translation>
<translation id="2955913368246107853">Uždaryti paieškos juostą</translation>
<translation id="2958431318199492670">Tinklo konfigūracija neatitinka ONC standarto. Kai kurių konfigūracijos dalių neįmanoma importuoti.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Kad užmegztumėte saugų ryšį, turėsite tinkamai nustatyti laikrodį. To reikia, nes svetainių tapatybei įrodyti naudojami sertifikatai galioja tik tam tikru laikotarpiu. Įrenginio laikrodis nustatytas netinkamai, todėl „Google Chrome“ negali patvirtinti šių sertifikatų.</translation>
<translation id="2972581237482394796">&amp;Atlikti iš naujo</translation>
<translation id="2985306909656435243">Jei Å¡is nustatymas įgalintas, „Chromium“ iÅ¡saugos kortelÄ—s kopijÄ… įrenginyje, kad galÄ—tumÄ—te greiÄiau užpildyti formas.</translation>
+<translation id="2985398929374701810">Įveskite tinkamą adresą</translation>
+<translation id="2986368408720340940">Å is paÄ—mimo metodas nepasiekiamas. IÅ¡bandykite kitÄ… metodÄ….</translation>
<translation id="2991174974383378012">Bendrinimas su svetainÄ—mis</translation>
<translation id="3005723025932146533">Rodyti išsaugotą kopiją</translation>
<translation id="3008447029300691911">Įveskite „<ph name="CREDIT_CARD" />“ kortelės saugos kodą (CVC). Kai patvirtinsite, išsami kortelės informacija bus bendrinama su šia svetaine.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{mažiausiai 1 elementas sinchronizuotuose įrenginiuose}=1{1 elementas (ir dar daugiau sinchronizuotuose įrenginiuose)}one{# elementas (ir dar daugiau sinchronizuotuose įrenginiuose)}few{# elementai (ir dar daugiau sinchronizuotuose įrenginiuose)}many{# elemento (ir dar daugiau sinchronizuotuose įrenginiuose)}other{# elementų (ir dar daugiau sinchronizuotuose įrenginiuose)}}</translation>
<translation id="3041612393474885105">Sertifikato informacija</translation>
<translation id="3063697135517575841">Šiuo metu „Chrome“ negali patvirtinti jūsų kortelės. Vėliau bandykite dar kartą.</translation>
+<translation id="3064966200440839136">Išjungiate inkognito režimą, kad galėtumėte sumokėti naudodami išorinę programą. Tęsti?</translation>
<translation id="3093245981617870298">Esate neprisijungÄ™.</translation>
<translation id="3105172416063519923">IÅ¡tekliaus ID:</translation>
<translation id="3109728660330352905">Neturite prieigos teisės žiūrėti šį puslapį.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Pabandykite paleisti ryšio diagnostikos įrankį<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Iššifruojant atsakymą įvyko klaida</translation>
-<translation id="3149891296864842641">Pristatymo parinktis</translation>
<translation id="3150653042067488994">Laikina serverio klaida</translation>
+<translation id="3154506275960390542">Å iame puslapyje yra forma, kurios negalima saugiai pateikti. SiunÄiamus duomenis gali peržiÅ«rÄ—ti kiti asmenys juos perduodant arba juos gali modifikuoti atakuojanti programa, siekianti pakeisti serverio gaunamÄ… informacijÄ….</translation>
<translation id="3157931365184549694">Atkurti</translation>
<translation id="3167968892399408617">Puslapiai, kuriuos peržiūrite inkognito skirtukų lapuose, nebus rodomi naršyklės istorijoje, slapukų saugykloje ar paieškos istorijoje, kai uždarysite visus inkognito skirtukų lapus. Visi atsisiųsti failai ar sukurtos žymės išliks.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -264,11 +272,13 @@
<translation id="3345135638360864351">Nepavyko <ph name="NAME" /> išsiųsti jūsų prieigos prie šios svetainės užklausos. Bandykite dar kartą.</translation>
<translation id="3355823806454867987">Pakeisti įgaliotojo serverio nustatymus...</translation>
<translation id="3369192424181595722">Laikrodžio klaida</translation>
+<translation id="337311366426640088">Dar elementų: <ph name="ITEM_COUNT" />...</translation>
<translation id="337363190475750230">Teikimas nutrauktas</translation>
<translation id="3377188786107721145">Politikos analizÄ—s klaida</translation>
<translation id="3380365263193509176">Nežinoma klaida</translation>
<translation id="3380864720620200369">Kliento ID:</translation>
<translation id="3391030046425686457">Pristatymo adresas</translation>
+<translation id="3395827396354264108">PaÄ—mimo metodas</translation>
<translation id="340013220407300675">Atakas vykdanÄios programos gali bandyti pavogti informacijÄ… iÅ¡ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (pavyzdžiui, slaptažodžius, praneÅ¡imus arba kredito kortelių informacijÄ…).</translation>
<translation id="3422248202833853650">Pabandykite išeiti iš kitų programų, kad atlaisvintumėte atminties.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> Å¡iuo metu nepasiekiama.</translation>
@@ -279,12 +289,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Gauti intervalÄ…:</translation>
<translation id="3462200631372590220">Slėpti išsamią informaciją</translation>
+<translation id="3467763166455606212">BÅ«tina nurodyti kortelÄ—s savininko vardÄ… ir pavardÄ™</translation>
+<translation id="3478058380795961209">Gal. pab. mÄ—nuo</translation>
<translation id="3479539252931486093">Ar tai buvo netikėta? <ph name="BEGIN_LINK" />Praneškime mums apie tai<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Ne dabar</translation>
<translation id="348000606199325318">Strigties ID <ph name="CRASH_LOCAL_ID" /> (serverio ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Šiuo metu nepavyko susisiekti su jūsų tėvu. Bandykite dar kartą.</translation>
<translation id="3528171143076753409">Serverio sertifikatas nepatikimas.</translation>
-<translation id="3538531656504267329">Netinkami galiojimo pabaigos metai</translation>
<translation id="3539171420378717834">Išsaugoti kortelės kopiją įrenginyje</translation>
<translation id="3542684924769048008">Slaptažodį naudoti:</translation>
<translation id="3549644494707163724">Å ifruoti visus sinchronizuotus duomenis naudojant sinchronizavimo slaptafrazÄ™</translation>
@@ -297,6 +308,7 @@
<translation id="3586931643579894722">Slėpti išsamią informaciją</translation>
<translation id="3587482841069643663">Visi</translation>
<translation id="3600246354004376029">„<ph name="TITLE" />“, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Įveskite tinkamą galiojimo laiko pabaigos datą</translation>
<translation id="36224234498066874">Išvalyti naršymo duomenis...</translation>
<translation id="362276910939193118">Rodyti visÄ… istorijÄ…</translation>
<translation id="3623476034248543066">Rodyti vertÄ™</translation>
@@ -313,7 +325,6 @@
<translation id="3693415264595406141">Slaptažodis:</translation>
<translation id="3696411085566228381">nÄ—ra</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Norėdami peržiūrėti pristatymo metodus ir reikalavimus, pasirinkite pristatymo adresą.</translation>
<translation id="370665806235115550">Įkeliama...</translation>
<translation id="3712624925041724820">Licencijos baigÄ—si</translation>
<translation id="3714780639079136834">Įjungti mobiliojo ryšio duomenis arba „Wi-Fi“</translation>
@@ -322,6 +333,7 @@
<translation id="3739623965217189342">Nukopijuota nuoroda</translation>
<translation id="375403751935624634">Vertimas nepavyko dÄ—l serverio klaidos.</translation>
<translation id="3759461132968374835">NÄ—ra strigÄių, apie kurias buvo neseniai praneÅ¡ta. Strigtys, įvykusios tuo metu, kai strigÄių ataskaitų teikimas buvo iÅ¡jungtas, Äia rodomos nebus.</translation>
+<translation id="3787705759683870569">Galiojimo laikas baigiasi <ph name="EXPIRATION_MONTH" /> / <ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Jei naudojate tarpinį serverį…</translation>
<translation id="3828924085048779000">Neleidžiama naudoti tuÅ¡Äios slaptafrazÄ—s.</translation>
<translation id="3845539888601087042">Rodoma įrenginių, kuriuose esate prisijungę, istorija. <ph name="BEGIN_LINK" />Sužinokite daugiau<ph name="END_LINK" />.</translation>
@@ -357,7 +369,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Ar norite, kad „Chromium“ išsaugotų šią kortelę?</translation>
<translation id="4171400957073367226">Netinkamas patvirtinimo parašas</translation>
-<translation id="4176463684765177261">Neleista</translation>
<translation id="4196861286325780578">&amp;Perkelti dar kartÄ…</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Patikrinti užkardos ir antivirusinės sistemos konfigūracijas<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{nėra}=1{1 programa („$1“)}=2{2 programos („$1“, „$2“)}one{# programa („$1“, „$2“, „$3“)}few{# programos („$1“, „$2“, „$3“)}many{# programos („$1“, „$2“, „$3“)}other{# programų („$1“, „$2“, „$3“)}}</translation>
@@ -384,11 +395,11 @@
<translation id="4406896451731180161">paieškos rezultatai</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> nepriėmė jūsų prisijungimo sertifikato arba prisijungimo sertifikatas nebuvo pateiktas.</translation>
<translation id="443673843213245140">Įgaliotojo serverio naudojimas neleidžiamas, bet nurodyta aiški įgaliotojo serverio konfigūracija.</translation>
-<translation id="4446242550670694251">Dabar galite narÅ¡yti privaÄiai, o kiti šį įrenginį naudojantys žmonÄ—s nematys jÅ«sų veiklos.</translation>
<translation id="4492190037599258964">„<ph name="SEARCH_STRING" />“ paieškos rezultatai</translation>
<translation id="4506176782989081258">Tikrinimo klaida: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Susisiekti su sistemos administratoriumi</translation>
<translation id="450710068430902550">Bendrinimas su administratoriumi</translation>
+<translation id="4515275063822566619">Kortelės ir adresai naudojami iš „Chrome“ ir jūsų „Google“ paskyros (<ph name="ACCOUNT_EMAIL" />). Galite juos tvarkyti skiltyje <ph name="BEGIN_LINK" />Nustatymai<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">IÅ¡sami informacija</translation>
<translation id="4558551763791394412">Pabandykite išjungti plėtinius.</translation>
<translation id="457875822857220463">Pristatymas</translation>
@@ -418,6 +429,7 @@
<translation id="4816492930507672669">Pritaikyti pagal puslapį</translation>
<translation id="483020001682031208">Nėra rodytinų Fizinio žiniatinklio puslapių</translation>
<translation id="4850886885716139402">Žiūrėti</translation>
+<translation id="4854362297993841467">Å is pristatymo metodas nepasiekiamas. IÅ¡bandykite kitÄ… metodÄ….</translation>
<translation id="4858792381671956233">Paprašėte tėvų leidimo apsilankyti šiame puslapyje</translation>
<translation id="4880827082731008257">Ieškoti istorijoje</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -425,7 +437,6 @@
<translation id="4923417429809017348">Šis puslapis išverstas iš nežinomos kalbos į <ph name="LANGUAGE_LANGUAGE" /> k.</translation>
<translation id="4923459931733593730">MokÄ—jimas</translation>
<translation id="4926049483395192435">Turi būti nurodyta.</translation>
-<translation id="4941291666397027948">* nurodo būtiną lauką</translation>
<translation id="495170559598752135">Veiksmai</translation>
<translation id="4958444002117714549">Išskleisti sąrašą</translation>
<translation id="4962322354953122629">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; „Chrome“ negali pasitikėti jo saugos sertifikatu. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -440,6 +451,7 @@
<translation id="5045550434625856497">Neteisingas slaptažodis</translation>
<translation id="5056549851600133418">Jums skirti straipsniai</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Patikrinti tarpinio serverio adresÄ…<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Nėra jokių slapukų}=1{1 svetainė naudoja slapukus. }one{# svetainė naudoja slapukus. }few{# svetainės naudoja slapukus. }many{# svetainės naudoja slapukus. }other{# svetainių naudoja slapukus. }}</translation>
<translation id="5087286274860437796">Å iuo metu serverio sertifikatas negalioja.</translation>
<translation id="5087580092889165836">PridÄ—ti kortelÄ™</translation>
<translation id="5089810972385038852">Valstija</translation>
@@ -462,10 +474,8 @@
<translation id="5300589172476337783">Rodyti</translation>
<translation id="5308689395849655368">StrigÄių ataskaitų teikimas neleidžiamas.</translation>
<translation id="5317780077021120954">IÅ¡saugoti</translation>
-<translation id="5326702247179446998">Reikia nurodyti gavÄ—jÄ…</translation>
<translation id="5327248766486351172">Pavadinimas</translation>
<translation id="5337705430875057403">Svetainės <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> užpuolėjai gali bandyti apgaulingai priversti atlikti pavojingus veiksmus, pvz., įdiegti programinę įrangą ar atskleisti asmeninę informaciją (pvz., slaptažodžius, telefonų numerius ar kredito kortelių informaciją).</translation>
-<translation id="53553865750799677">Nepalaikomas paÄ—mimo adresas. Pasirinkite kitÄ… adresÄ….</translation>
<translation id="5359637492792381994">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas šiuo metu negalioja. Taip gali būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Išsaugant politikos nustatymus įvyko klaida</translation>
<translation id="5386426401304769735">Šios svetainės sertifikatų grandinėje yra sertifikatas, pasirašytas naudojant SHA-1.</translation>
@@ -491,8 +501,8 @@
<translation id="5544037170328430102"><ph name="SITE" /> įterptame puslapyje sakoma:</translation>
<translation id="5556459405103347317">Įkelti iš naujo</translation>
<translation id="5565735124758917034">Aktyvus</translation>
+<translation id="5571083550517324815">Negalima paimti Å¡iuo adresu. Pasirinkite kitÄ… adresÄ….</translation>
<translation id="5572851009514199876">Pirmiausia prisijunkite prie „Chrome“, kad „Chrome“ galėtų patikrinti, ar jums leidžiama pasiekti šią svetainę.</translation>
-<translation id="5575380383496039204">Nepalaikomas pristatymo adresas. Pasirinkite kitÄ… adresÄ….</translation>
<translation id="5580958916614886209">Patikrinkite galiojimo pabaigos mėnesį ir bandykite dar kartą</translation>
<translation id="560412284261940334">Tvarkymas nepalaikomas</translation>
<translation id="5610142619324316209">Patikrinti ryšį</translation>
@@ -508,7 +518,8 @@
<translation id="5710435578057952990">Å io tinklalapio tapatybÄ— nenustatyta.</translation>
<translation id="5720705177508910913">Dabartinis naudotojas</translation>
<translation id="5732392974455271431">Jūsų tėvai gali atblokuoti ją už jus</translation>
-<translation id="57586589942790530">Netinkamas kortelÄ—s numeris</translation>
+<translation id="5763042198335101085">Įveskite galiojantį el. pašto adresą</translation>
+<translation id="5765072501007116331">Jei norite peržiūrėti pristatymo metodus ir reikalavimus, pasirinkite adresą.</translation>
<translation id="5784606427469807560">Patvirtinant kortelę kilo problema. Patikrinkite interneto ryšį ir bandykite dar kartą.</translation>
<translation id="5785756445106461925">Be to, šiame puslapyje yra kitų nesaugių išteklių. Perduodant duomenis šiuos išteklius gali peržiūrėti kiti asmenys ir keisti atakuojanti programa, siekianti pakeisti puslapio išvaizdą.</translation>
<translation id="5786044859038896871">Ar norite, kad būtų įvesta jūsų kredito kortelės informacija?</translation>
@@ -521,22 +532,20 @@
<translation id="5869405914158311789">Nepavyksta pasiekti Å¡ios svetainÄ—s</translation>
<translation id="5869522115854928033">Išsaugoti slaptažodžiai</translation>
<translation id="5872918882028971132">Pasiūlymai tėvams</translation>
-<translation id="587760065310675640">Nepalaikomas pristatymo adresas. Pasirinkite kitÄ… adresÄ….</translation>
<translation id="5901630391730855834">Geltona</translation>
-<translation id="59174027418879706">Įgalinta</translation>
<translation id="5926846154125914413">Galite prarasti prieigÄ… prie aukÅ¡Äiausios kokybÄ—s turinio iÅ¡ kelių svetainių.</translation>
<translation id="5959728338436674663">Automatiškai siųsti tam tikrą <ph name="BEGIN_WHITEPAPER_LINK" />sistemos informaciją ir puslapio turinį<ph name="END_WHITEPAPER_LINK" /> į sistemą „Google“ siekiant padėti aptikti pavojingas programas ir svetaines. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">SavaitÄ—</translation>
<translation id="5967867314010545767">Pašalinti iš istorijos</translation>
<translation id="5975083100439434680">Tolinti</translation>
+<translation id="598637245381783098">Nepavyksta atidaryti mokÄ—jimo programos</translation>
<translation id="5989320800837274978">Nenurodyti nei fiksuoti įgaliotieji serveriai, nei .pac scenarijaus URL.</translation>
<translation id="5990559369517809815">Plėtinys užblokavo serveriui teikiamas užklausas.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Naudojamos kortelės ir adreso parinktys iš „Chrome“. Jas galite tvarkyti skiltyje <ph name="BEGIN_LINK" />Nustatymai<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1 puslapis}one{# puslapis}few{# puslapiai}many{# puslapio}other{# puslapių}}</translation>
<translation id="6017514345406065928">Žalia</translation>
+<translation id="6027201098523975773">Įveskite pavadinimą</translation>
<translation id="6040143037577758943">Uždaryti</translation>
-<translation id="604124094241169006">Automatinis</translation>
<translation id="6042308850641462728">Daugiau</translation>
<translation id="6060685159320643512">Atsargiai, šie bandymai gali būti pavojingi</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{nÄ—ra}=1{1}one{#}few{#}many{#}other{#}}</translation>
@@ -544,9 +553,10 @@
naudojamus tinklo įrenginius.</translation>
<translation id="614940544461990577">Pabandykite atlikti toliau nurodytus veiksmus.</translation>
<translation id="6151417162996330722">Serverio sertifikato galiojimo laikotarpis per ilgas.</translation>
-<translation id="615643356032862689">Atsiųsti failai ir žymės bus išsaugoti.</translation>
+<translation id="6157877588268064908">Jei norite peržiūrėti pristatymo metodus ir reikalavimus, pasirinkite adresą.</translation>
<translation id="6165508094623778733">Sužinokite daugiau</translation>
<translation id="6177128806592000436">Ryšys su šia svetaine nėra saugus</translation>
+<translation id="6184817833369986695">(grupÄ—: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Patikrinkite interneto ryšį</translation>
<translation id="6218753634732582820">Pašalinti adresą iš „Chromium“?</translation>
<translation id="6251924700383757765">Privatumo politika</translation>
@@ -555,6 +565,8 @@
<translation id="6259156558325130047">&amp;Pertvarkyti dar kartÄ…</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> žymės</translation>
<translation id="6264485186158353794">Grįžti prie saugumo</translation>
+<translation id="6276112860590028508">Čia rodomi puslapiai iš skaitymo sąrašo</translation>
+<translation id="6280223929691119688">Negalima pristatyti Å¡iuo adresu. Pasirinkite kitÄ… adresÄ….</translation>
<translation id="6282194474023008486">Pašto kodas</translation>
<translation id="6290238015253830360">JÅ«sų pasiÅ«lyti straipsniai rodomi Äia</translation>
<translation id="6305205051461490394"><ph name="URL" /> nepasiekiama.</translation>
@@ -576,7 +588,6 @@
<translation id="6417515091412812850">Nepavyksta patikrinti, ar sertifikatas buvo panaikintas.</translation>
<translation id="6433490469411711332">KontaktinÄ—s informacijos redagavimas</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> atsisakÄ— prisijungti.</translation>
-<translation id="6443118737398455446">Netinkama galiojimo pabaigos data</translation>
<translation id="6446608382365791566">Daugiau informacijos pridÄ—jimas</translation>
<translation id="6451458296329894277">Patvirtinkite pakartotinÄ… formos pateikimÄ…</translation>
<translation id="6456339708790392414">Jūsų mokėjimas</translation>
@@ -584,10 +595,8 @@
<translation id="6462969404041126431">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; gali būti, kad jo saugos sertifikatas atšauktas. Taip galėjo nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Įrenginio politika</translation>
<translation id="6477321094435799029">„Chrome“ šiame puslapyje aptiko neįprastą kodą ir jį užblokavo, kad apsaugotų asmens informaciją (pvz., slaptažodžius, telefonų numerius ir kredito korteles).</translation>
-<translation id="6477460825583319731">Netinkamas el. pašto adresas</translation>
<translation id="6489534406876378309">Pradėti įkelti strigtis</translation>
<translation id="6508722015517270189">Iš naujo paleiskite „Chrome“</translation>
-<translation id="6525462735697194615">Netinkamas galiojimo pabaigos mÄ—nuo</translation>
<translation id="6529602333819889595">&amp;IÅ¡trinti dar kartÄ…</translation>
<translation id="6534179046333460208">Fizinio žiniatinklio pasiūlymai</translation>
<translation id="6550675742724504774">Parinktys</translation>
@@ -602,7 +611,6 @@
<translation id="6628463337424475685">„<ph name="ENGINE" />“ paieška</translation>
<translation id="6644283850729428850">Å i politika nepatvirtinta.</translation>
<translation id="6652240803263749613">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; kompiuterio operacinė sistema negali pasitikėti jo saugos sertifikatu. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Ta siuntimo parinktis nepasiekiama. Išbandykite kitą paėmimo parinktį.</translation>
<translation id="6671697161687535275">Pašalinti formos pasiūlymą iš „Chromium“?</translation>
<translation id="6685834062052613830">Atsijunkite ir užbaikite sąranką</translation>
<translation id="6710213216561001401">Ankstesnis</translation>
@@ -610,13 +618,13 @@
<translation id="6711464428925977395">Kažkas negerai su tarpiniu serveriu arba adresas netinkamas.</translation>
<translation id="6727102863431372879">Nustatyti</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{nėra}=1{1 elementas}one{# elementas}few{# elementai}many{# elemento}other{# elementų}}</translation>
-<translation id="6743044928064272573">PaÄ—mimo parinktis</translation>
<translation id="674375294223700098">Nežinoma serverio sertifikato klaida.</translation>
<translation id="6753269504797312559">Politikos vertÄ—</translation>
<translation id="6757797048963528358">Įjungta įrenginio miego būsena.</translation>
<translation id="6778737459546443941">Jūsų tėtis ar mama dar jos nepatvirtino</translation>
<translation id="6810899417690483278">Tinkinimo ID</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Nepavyko įkelti regionų duomenų</translation>
<translation id="6831043979455480757">VertÄ—jas</translation>
<translation id="6839929833149231406">Sritis</translation>
<translation id="6874604403660855544">&amp;PridÄ—ti dar kartÄ…</translation>
@@ -624,6 +632,7 @@
<translation id="6895330447102777224">KortelÄ— patvirtinta</translation>
<translation id="6897140037006041989">Naudotojo atstovas</translation>
<translation id="6915804003454593391">Naudotojas:</translation>
+<translation id="6948701128805548767">Jei norite peržiūrėti paėmimo metodus ir reikalavimus, pasirinkite adresą</translation>
<translation id="6957887021205513506">Panašu, kad serverio sertifikatas yra suklastotas.</translation>
<translation id="6965382102122355670">Gerai</translation>
<translation id="6965978654500191972">Įrenginys</translation>
@@ -631,7 +640,6 @@
<translation id="6973656660372572881">Nurodyti fiksuoti įgaliotieji serveriai ir .pac scenarijaus URL.</translation>
<translation id="6989763994942163495">Rodyti išplėstinius nustatymus...</translation>
<translation id="7000990526846637657">Nerasta jokių istorijos įrašų</translation>
-<translation id="7001663382399377034">GavÄ—jo pridÄ—jimas</translation>
<translation id="7009986207543992532">Bandėte pasiekti <ph name="DOMAIN" />, bet serveris pateikė sertifikatą, kurio galiojimo laikotarpis per ilgas, kad juo būtų galima pasitikėti. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Adresu <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> gali būti pateikta kitų formų jūsų „Google“ paskyros naršymo istorija</translation>
@@ -642,12 +650,15 @@
<translation id="7088615885725309056">AnkstesnÄ—</translation>
<translation id="7090678807593890770">Sistemoje „Google“ atlikite paiešką pagal užklausą „<ph name="LINK" />“</translation>
<translation id="7119414471315195487">Uždarykite kitus skirtukus ir programas</translation>
+<translation id="7129409597930077180">Negalima pristatyti Å¡iuo adresu. Pasirinkite kitÄ… adresÄ….</translation>
+<translation id="7138472120740807366">Pristatymo metodas</translation>
<translation id="7139724024395191329">Emyratas</translation>
<translation id="7155487117670177674">MokÄ—jimas nesaugus</translation>
<translation id="7179921470347911571">Paleisti iš naujo dabar</translation>
<translation id="7180611975245234373">Atnaujinti</translation>
<translation id="7182878459783632708">Nenustatyta jokia politika</translation>
<translation id="7186367841673660872">Šis puslapis išverstas iš<ph name="ORIGINAL_LANGUAGE" />į<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> nesilaikoma saugos standartų.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Sužinokite daugiau<ph name="END_LINK" /> apie šią problemą.</translation>
@@ -676,7 +687,6 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="7424977062513257142">Šiame tinklalapyje įterptame puslapyje sakoma:</translation>
<translation id="7441627299479586546">Netinkamas politikos objektas</translation>
<translation id="7444046173054089907">Ši svetainė užblokuota</translation>
-<translation id="7444238235002594607">Pasirinkite paÄ—mimo adresÄ…, kad patikrintumÄ—te paÄ—mimo metodus ir reikalavimus.</translation>
<translation id="7445762425076701745">Nepavyksta visiÅ¡kai patvirtinti serverio, prie kurio esate prisijungÄ™, tapatybÄ—s. Prie serverio esate prisijungÄ™ naudodami tik tinklui galiojantį vardÄ…, kurio nuosavybÄ—s teisių iÅ¡orinÄ— sertifikatÄ… iÅ¡duodanti institucija negali patvirtinti. Nors kai kurios sertifikatus iÅ¡duodanÄios institucijos vis tiek iÅ¡duos sertifikatus pagal Å¡iuos vardus, niekaip nebus galima užtikrinti, kad bÅ«site prisijungÄ™ prie numatytos svetainÄ—s, o ne prie užpuolÄ—jo.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Sužinokite daugiau<ph name="END_LINK" /> apie šią problemą.</translation>
<translation id="7460163899615895653">Naujausi kitų įrenginių skirtukai rodomi Äia</translation>
@@ -720,6 +730,7 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="7755287808199759310">Jūsų tėtis ar mama gali ją atblokuoti už jus</translation>
<translation id="7758069387465995638">Gali būti, kad užkarda arba antivirusinė programinė įranga užblokavo ryšį.</translation>
<translation id="7761701407923456692">Serverio sertifikatas neatitinka URL.</translation>
+<translation id="7763386264682878361">Mokėjimo aprašo analizavimo įrankis</translation>
<translation id="7764225426217299476">PridÄ—ti adresÄ…</translation>
<translation id="777702478322588152">Prefektūra</translation>
<translation id="7791543448312431591">PridÄ—ti</translation>
@@ -733,6 +744,7 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="785549533363645510">TaÄiau nesate nematomi. Ä®jungus inkognito režimÄ…, narÅ¡ymo veiksmai vis tiek matomi darbdaviui, interneto paslaugų teikÄ—jui ar svetainÄ—ms, kuriose lankotÄ—s.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Patikrinkite kortelÄ—s saugos kodÄ… (CVC) ir bandykite dar kartÄ…</translation>
+<translation id="79338296614623784">Įveskite tinkamą telefono numerį</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Serverio sertifikatas dar negalioja.</translation>
<translation id="7942349550061667556">Raudona</translation>
@@ -752,6 +764,7 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="8088680233425245692">Nepavyko peržiūrėti straipsnio.</translation>
<translation id="8089520772729574115">mažiau nei 1 MB</translation>
<translation id="8091372947890762290">Laukiama aktyvinimo serveryje</translation>
+<translation id="8118489163946903409">MokÄ—jimo metodas</translation>
<translation id="8131740175452115882">Patvirtinti</translation>
<translation id="8134994873729925007">Nepavyko rasti <ph name="HOST_NAME" /> serverio <ph name="BEGIN_ABBR" />DNS adreso<ph name="END_ABBR" />.</translation>
<translation id="8149426793427495338">Įjungta kompiuterio miego būsena.</translation>
@@ -777,6 +790,7 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="8349305172487531364">Žymių juosta</translation>
<translation id="8363502534493474904">Išjungti lėktuvo režimą</translation>
<translation id="8364627913115013041">Nenustatyta.</translation>
+<translation id="8368476060205742148">„Google Play“ paslaugos</translation>
<translation id="8380941800586852976">Pavojingas</translation>
<translation id="8382348898565613901">Čia rodomos žymės, kurias naudojote pastaruoju metu</translation>
<translation id="8398259832188219207">StrigÄių ataskaita įkelta <ph name="UPLOAD_TIME" /></translation>
@@ -785,32 +799,30 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="8428213095426709021">Nustatymai</translation>
<translation id="8433057134996913067">Tai atlikę atsijungsite nuo daugumos svetainių.</translation>
<translation id="8437238597147034694">&amp;Anuliuoti perkÄ—limÄ…</translation>
-<translation id="8456681095658380701">Netinkamas pavadinimas</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 kredito kortelė}one{# kredito kortelė}few{# kredito kortelės}many{# kredito kortelės}other{# kredito kortelių}}</translation>
<translation id="8483780878231876732">Jei norite naudoti korteles iš „Google“ paskyros, prisijunkite prie „Chrome“</translation>
<translation id="8488350697529856933">Taikoma</translation>
-<translation id="8492969205326575646">Nepalaikomas kortelÄ—s tipas</translation>
<translation id="8498891568109133222">Per ilgai laukta <ph name="HOST_NAME" /> atsako.</translation>
<translation id="852346902619691059">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; įrenginio operacinė sistema negali pasitikėti jo saugos sertifikatu. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Gal. pab. metai</translation>
<translation id="8543181531796978784">Galite <ph name="BEGIN_ERROR_LINK" />pranešti apie aptikimo problemą<ph name="END_ERROR_LINK" /> arba, jei suprantate saugos riziką, galite <ph name="BEGIN_LINK" />apsilankyti šioje nesaugioje svetainėje<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">IÅ¡versti negalima, nes nepavyko nustatyti puslapio kalbos.</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="8570229484593575558">Ši informacija |nebus išsaugota|:#Naršymo istorija#Paieškos#Slapukų duomenys</translation>
<translation id="8571890674111243710">Puslapis verÄiamas į <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Veiklą |vis tiek gali peržiūrėti|:#lankomos svetainės;#darbdavys;#interneto paslaugų teikėjas.</translation>
<translation id="858637041960032120">PridÄ—ti tel. nr.
</translation>
<translation id="859285277496340001">Sertifikatas nenurodo mechanizmo, skirto patikrinti, ar jis buvo panaikintas.</translation>
<translation id="8620436878122366504">Jūsų tėvai dar jos nepatvirtino</translation>
<translation id="8647750283161643317">Viską nustatyti į numatytuosius nustatymus</translation>
<translation id="8703575177326907206">Jūsų ryšys su <ph name="DOMAIN" /> nekoduotas.</translation>
+<translation id="8718314106902482036">Mokėjimas neužbaigtas</translation>
<translation id="8725066075913043281">Bandyti dar kartÄ…</translation>
<translation id="8728672262656704056">Veikia inkognito režimas</translation>
<translation id="8730621377337864115">Atlikta</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="8759274551635299824">Å i kortelÄ— nebegalioja</translation>
<translation id="8790007591277257123">&amp;IÅ¡trinti dar kartÄ…</translation>
-<translation id="8798099450830957504">Numatytasis</translation>
<translation id="8800988563907321413">Netoliese esantys pasiÅ«lymai jums rodomi Äia</translation>
<translation id="8820817407110198400">Žymės</translation>
<translation id="883848425547221593">Kitos žymės</translation>
@@ -820,6 +832,7 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="8866481888320382733">Analizuojant politikos nustatymus įvyko klaida</translation>
<translation id="8866959479196209191">Å iame puslapyje sakoma:</translation>
<translation id="8870413625673593573">Neseniai uždaryta</translation>
+<translation id="8874824191258364635">Įveskite tinkamą kortelės numerį</translation>
<translation id="8876793034577346603">Analizuojant tinklo konfigūraciją įvyko klaida.</translation>
<translation id="8877192140621905067">Kai patvirtinsite, išsami kortelės informacija bus bendrinama su šia svetaine</translation>
<translation id="8889402386540077796">Spalva</translation>
@@ -829,7 +842,6 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="8931333241327730545">Ar norite išsaugoti šios kortelės informaciją „Google“ paskyroje?</translation>
<translation id="8932102934695377596">Jūsų laikrodis atsilieka</translation>
<translation id="8954894007019320973">(Tęsinys)</translation>
-<translation id="895548565263634352">Skaitykite „<ph name="ARTICLE_PUBLISHER" />“ istorijas ir dar <ph name="OTHER_ARTICLE_COUNT" /></translation>
<translation id="8971063699422889582">BaigÄ—si serverio sertifikato galiojimo laikas.</translation>
<translation id="8986494364107987395">AutomatiÅ¡kai siųsti naudojimo statistikÄ… ir strigÄių ataskaitas „Google“</translation>
<translation id="8987927404178983737">MÄ—nuo</translation>
@@ -847,7 +859,6 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="9068849894565669697">Pasirinkite spalvÄ…</translation>
<translation id="9076283476770535406">Joje gali būti suaugusiesiems skirto turinio</translation>
<translation id="9078964945751709336">BÅ«tina pateikti daugiau informacijos</translation>
-<translation id="9094175695478007090">Nepavyksta paleisti mokėjimų programos.</translation>
<translation id="9103872766612412690">Svetainėje <ph name="SITE" /> įprastai naudojama šifruotė informacijai apsaugoti. Šį kartą „Chromium“ bandant prisijungti prie <ph name="SITE" />, ji pateikė neįprastus ir netinkamus prisijungimo duomenis. Gali būti, kad užpuolėjas bando apsimesti svetaine <ph name="SITE" /> arba „Wi-Fi“ prisijungimo ekrane nutrūko ryšys. Jūsų informacija vis tiek liko apsaugota, nes „Chromium“ sustabdė prisijungimą prieš apsikeitimą bet kokiais duomenimis.</translation>
<translation id="9137013805542155359">Rodyti originalÄ…</translation>
<translation id="9137248913990643158">Prieš naudodami šią programą prisijunkite prie „Chrome“.</translation>
diff --git a/chromium/components/strings/components_strings_lv.xtb b/chromium/components/strings/components_strings_lv.xtb
index 53398eb24db..a557ff22596 100644
--- a/chromium/components/strings/components_strings_lv.xtb
+++ b/chromium/components/strings/components_strings_lv.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="lv">
<translation id="1008557486741366299">VÄ“lÄk</translation>
<translation id="1015730422737071372">Sniegt papildu informÄciju</translation>
+<translation id="1021110881106174305">PieņemtÄs kartes</translation>
<translation id="1032854598605920125">Pagriezt pulksteņrÄdÄ«tÄju kustÄ«bas virzienÄ</translation>
<translation id="1038842779957582377">nezinÄms nosaukums</translation>
<translation id="1050038467049342496">Aizveriet citas lietotnes</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Slēpt vērtību</translation>
<translation id="1228893227497259893">Nepareizs vienības identifikators</translation>
<translation id="1232569758102978740">Bez nosaukuma</translation>
+<translation id="1263231323834454256">Lasīšanas saraksts</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> notverts ziņojums par avÄriju (vÄ“l nav augÅ¡upielÄdÄ“ts vai ignorÄ“ts)</translation>
<translation id="1285320974508926690">Nekad netulkot Å¡o vietni</translation>
<translation id="129553762522093515">Nesen aizvērtas</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromium automÄtiskÄs aizpildes iestatÄ«jumi...</translation>
<translation id="1374468813861204354">ieteikumus</translation>
<translation id="1375198122581997741">Par versiju</translation>
+<translation id="1377321085342047638">Kartes numurs</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> nenosÅ«tÄ«ja nekÄdus datus.</translation>
<translation id="1407135791313364759">Atvērt visas</translation>
<translation id="1413809658975081374">KonfidencialitÄtes kļūda</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">VÄ“sture</translation>
<translation id="1645368109819982629">Neatbalstīts protokols</translation>
<translation id="1656489000284462475">InformÄcija par saņemÅ¡anu</translation>
+<translation id="1663943134801823270">Kartes un adreses tiek iegÅ«tas no Chrome. Varat pÄrvaldÄ«t tÄs <ph name="BEGIN_LINK" />iestatÄ«jumos<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">VietnÄ“ <ph name="SITE" /> informÄcijas aizsargÄÅ¡anai parasti tiek izmantota Å¡ifrÄ“Å¡ana. Kad pÄrlÅ«kÄ Google Chrome tika mÄ“Ä£inÄts izveidot savienojumu ar vietni <ph name="SITE" />, Å¡oreiz tÄ nosÅ«tÄ«ja neparastus un nepareizus akreditÄcijas datus. IespÄ“jams, tas notika, jo uzbrucÄ“js mÄ“Ä£inÄja uzdoties par vietni <ph name="SITE" />, vai arÄ« Wi-Fi pierakstÄ«Å¡anÄs ekrÄns pÄrtrauc savienojumu. JÅ«su informÄcija joprojÄm ir droÅ¡Ä«bÄ, jo pÄrlÅ«ks Google Chrome pÄrtrauca savienojumu, pirms tika veikta jebkÄdu datu apmaiņa.</translation>
<translation id="168328519870909584">UzbrucÄ“ji, kuri paÅ¡laik atrodas vietnÄ“ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, iespÄ“jams, mÄ“Ä£inÄs jÅ«su ierÄ«cÄ“ instalÄ“t bÄ«stamas lietotnes, kuras zog vai dzÄ“Å¡ jÅ«su informÄciju (piemÄ“ram, fotoattÄ“lus, paroles, ziņojumus un kredÄ«tkarÅ¡u informÄciju).</translation>
<translation id="168841957122794586">Servera sertifikÄts ietver vÄju kriptogrÄfisko atslÄ“gu.</translation>
<translation id="1710259589646384581">OperÄ“tÄjsistÄ“ma</translation>
<translation id="1721312023322545264">Jums ir nepieciešama atļauja no <ph name="NAME" />, lai apmeklētu šo vietni</translation>
+<translation id="1721424275792716183">* ObligÄts lauks</translation>
<translation id="1728677426644403582">JÅ«s skatÄt tÄ«mekļa lapas avotu.</translation>
+<translation id="173080396488393970">Šis kartes veids netiek atbalstīts</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Sazinieties ar sistēmas administratoru.</translation>
+<translation id="1740951997222943430">Ievadiet derīgu mēnesi</translation>
<translation id="1745358365027406341">LejupielÄdÄ“t lapu vÄ“lÄk</translation>
<translation id="17513872634828108">Atvērt cilnes</translation>
<translation id="1753706481035618306">Lapas numurs</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Atjauniniet savu sinhronizÄcijas ieejas frÄzi.</translation>
<translation id="1787142507584202372">Å eit tiks parÄdÄ«tas jÅ«su atvÄ“rtÄs cilnes</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Atlasiet piegÄdes adresi, lai pÄrbaudÄ«tu piegÄdes veidus un prasÄ«bas.</translation>
+<translation id="1803264062614276815">Kartes Ä«paÅ¡nieka vÄrds, uzvÄrds</translation>
<translation id="1803678881841855883">Nesen Google droÅ¡ajÄ pÄrlÅ«koÅ¡anÄ <ph name="BEGIN_LINK" />tika konstatÄ“ta ļaunprÄtÄ«ga programmatÅ«ra<ph name="END_LINK" /> vietnÄ“ <ph name="SITE" />. Vietnes, kas parasti ir droÅ¡as, dažkÄrt var tikt inficÄ“tas ar ļaunprÄtÄ«gu programmatÅ«ru. Ä»aunprÄtÄ«gÄ programmatÅ«ra nÄk no <ph name="SUBRESOURCE_HOST" />, kas ir zinÄms ļaunprÄtÄ«gas programmatÅ«ras izplatÄ«tÄjs. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Pievienota: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">PieprasÄ«jums vai tÄ parametri nebija derÄ«gi.</translation>
<translation id="1826516787628120939">PÄrbaude</translation>
<translation id="1834321415901700177">Å Ä« vietne satur kaitnieciskas programmas</translation>
<translation id="1842969606798536927">MaksÄt</translation>
-<translation id="1864455488461349376">PiegÄdes veids</translation>
<translation id="1871208020102129563">Starpniekserveris ir iestatīts, lai tas lietotu fiksētus starpniekserverus, nevis .pac skripta URL.</translation>
<translation id="1871284979644508959">ObligÄtais lauks</translation>
<translation id="187918866476621466">AtvÄ“rt sÄkumlapas</translation>
<translation id="1883255238294161206">Sakļaut sarakstu</translation>
<translation id="1898423065542865115">Filtrēšana</translation>
<translation id="194030505837763158">Apmeklējiet vietni <ph name="LINK" /></translation>
-<translation id="1946821392246652573">PieņemtÄs kartes</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> grÄmatzÄ«mes</translation>
<translation id="1973335181906896915">RadÄs serializÄ“Å¡anas kļūda.</translation>
<translation id="1974060860693918893">Papildu</translation>
<translation id="1978555033938440688">Pogrammaparatūras versija</translation>
+<translation id="1995859865337580572">LÅ«dzu, apstipriniet savu CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{un vēl 1}zero{un vēl #}one{un vēl #}other{un vēl #}}</translation>
-<translation id="2020194265157481222">JÄnorÄda vÄrds un uzvÄrds uz kartes</translation>
<translation id="2025186561304664664">Starpniekserverim ir iestatÄ«ta autokonfigurÄcija.</translation>
<translation id="2030481566774242610">Vai domÄjÄt <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />PÄrbaudiet starpniekserveri un ugunsmÅ«ri<ph name="END_LINK" />.</translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Å odien</translation>
<translation id="2154054054215849342">SinhronizÄcija jÅ«su domÄ“nam nav pieejama.</translation>
<translation id="2154484045852737596">Kartes informÄcijas rediģēšana</translation>
-<translation id="2156993118928861787">Nederīga adrese</translation>
<translation id="2166049586286450108">Pilna administratora piekļuve</translation>
<translation id="2166378884831602661">Šī vietne nevar garantēt drošu savienojumu</translation>
<translation id="2181821976797666341">Politikas</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adrese}zero{# adreses}one{# adrese}other{# adreses}}</translation>
+<translation id="2202020181578195191">Ievadiet derīgu gadu</translation>
<translation id="2212735316055980242">Politika netika atrasta.</translation>
<translation id="2213606439339815911">Notiek ierakstu ienešana...</translation>
<translation id="2230458221926704099">Labojiet savienojumu, izmantojot <ph name="BEGIN_LINK" />diagnostikas lietotni<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Piekļuve internetam ir bloķēta</translation>
<translation id="230155334948463882">Vai jums ir jauna karte?</translation>
<translation id="2305919008529760154">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts, iespÄ“jams, ir izveidots krÄpnieciski. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Kartes un adreses informÄcija ir no jÅ«su Google konta (<ph name="ACCOUNT_EMAIL" />) un Chrome datiem. Varat tÄs pÄrvaldÄ«t sadaÄ¼Ä <ph name="BEGIN_LINK" />IestatÄ«jumi<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535">VietnÄ“ <ph name="DOMAIN" /> ir jÄievada lietotÄjvÄrds un parole.</translation>
<translation id="2318774815570432836">Å obrÄ«d nevarat apmeklÄ“t vietni <ph name="SITE" />, jo tajÄ tiek izmantota politika HSTS. TÄ«kla kļūdas un uzbrukumi parasti ir Ä«slaicÄ«gi, tÄpÄ“c Å¡Ä« lapa vÄ“lÄk, visticamÄk, darbosies. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Citas grÄmatzÄ«mes</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Uzņēmuma noklusējuma politika</translation>
<translation id="2386255080630008482">Servera sertifikÄts ir atsaukts.</translation>
<translation id="2392959068659972793">RÄdÄ«t politikas, kuru vÄ“rtÄ«ba nav iestatÄ«ta</translation>
+<translation id="239429038616798445">Šis nosūtīšanas veids nav pieejams. Izmēģiniet citu veidu.</translation>
<translation id="2396249848217231973">&amp;Atsaukt dzēšanu</translation>
<translation id="2460160116472764928">Nesen Google droÅ¡ajÄ pÄrlÅ«koÅ¡anÄ <ph name="BEGIN_LINK" />tika konstatÄ“ta ļaunprÄtÄ«ga programmatÅ«ra<ph name="END_LINK" /> vietnÄ“ <ph name="SITE" />. Vietnes, kuras parasti ir droÅ¡as, var tikt inficÄ“tas ar ļaunprÄtÄ«gu programmatÅ«ru. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Aizpildīt</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Palaist tīkla diagnostiku<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Nederīgs meklēšanas URL.</translation>
<translation id="2491120439723279231">Servera sertifikÄtÄ ir kļūdas.</translation>
-<translation id="24943777258388405">Nepareizs tÄlruņa numurs</translation>
<translation id="2495083838625180221">JSON parsÄ“tÄjs</translation>
<translation id="2495093607237746763">Ja Å¡Ä« izvÄ“les rÅ«tiņa ir atzÄ«mÄ“ta, pÄrlÅ«ks Chromium saglabÄs jÅ«su kartes informÄciju Å¡ajÄ ierÄ«cÄ“, lai nodroÅ¡inÄtu ÄtrÄku veidlapu aizpildi.</translation>
<translation id="2498091847651709837">Skenēt jaunu karti</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> nosūtīja nederīgu atbildi.</translation>
<translation id="2552545117464357659">JaunÄka</translation>
<translation id="2556876185419854533">&amp;Labojuma atsaukšana</translation>
+<translation id="2587730715158995865">No: <ph name="ARTICLE_PUBLISHER" />. Lasiet šo un vēl <ph name="OTHER_ARTICLE_COUNT" /> rakstus.</translation>
<translation id="2587841377698384444">Direktorija API ID:</translation>
<translation id="2597378329261239068">Å is dokuments ir aizsargÄts ar paroli. LÅ«dzu, ievadiet paroli.</translation>
<translation id="2609632851001447353">Varianti</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Palaist savienojamības diagnostiku<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">Labi</translation>
<translation id="2742870351467570537">Noņemt atlasītos vienumus</translation>
+<translation id="277133753123645258">Nosūtīšanas veids</translation>
<translation id="277499241957683684">Trūkst ierīces ieraksta.</translation>
<translation id="2784949926578158345">Savienojums tika atiestatīts.</translation>
<translation id="2794233252405721443">Vietne bloÄ·Ä“ta</translation>
-<translation id="2812680587231492111">Šī saņemšanas iespēja nav pieejama. Izvēlieties citu iespēju.</translation>
<translation id="2824775600643448204">Adreses un meklēšanas josla</translation>
<translation id="2826760142808435982">Savienojums ir Å¡ifrÄ“ts un autentificÄ“ts, izmantojot <ph name="CIPHER" />, un tajÄ tiek izmantots <ph name="KX" /> kÄ atslÄ“gu apmaiņas mehÄnisms.</translation>
<translation id="2835170189407361413">Notīrīt veidlapu</translation>
-<translation id="2849041323157393173">Å Ä« piegÄdes iespÄ“ja nav pieejama. IzvÄ“lieties citu iespÄ“ju.</translation>
<translation id="2889159643044928134">NeielÄdÄ“t atkÄrtoti</translation>
<translation id="2900469785430194048">MÄ“Ä£inot parÄdÄ«t Å¡o tÄ«mekļa lapu, pÄrlÅ«ka Google Chrome atmiÅ†Ä nepietika vietas.</translation>
<translation id="2909946352844186028">Konstatētas tīkla izmaiņas.</translation>
<translation id="2916038427272391327">Aizveriet citas programmas</translation>
<translation id="2922350208395188000">Servera sertifikÄtu nevar pÄrbaudÄ«t.</translation>
+<translation id="2928905813689894207">Norēķinu adrese</translation>
<translation id="2948083400971632585">IestatÄ«jumu lapÄ varat atspÄ“jot jebkurus starpniekserverus, kas konfigurÄ“ti savienojuma izveidei.</translation>
<translation id="2955913368246107853">Aizvērt atrašanas joslu</translation>
<translation id="2958431318199492670">TÄ«kla konfigurÄcija neatbilst standartam ONC. IespÄ“jams, konfigurÄcijas daļas netiks importÄ“tas.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">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 pareizs, Google Chrome nevar verificÄ“t Å¡os sertifikÄtus.</translation>
<translation id="2972581237482394796">&amp;PÄratsaukt</translation>
<translation id="2985306909656435243">Ja Å¡Ä« opcija ir iespÄ“jota, Chromium saglabÄs jÅ«su kartes informÄciju Å¡ajÄ ierÄ«cÄ“, lai nodroÅ¡inÄtu ÄtrÄku veidlapu aizpildi.</translation>
+<translation id="2985398929374701810">Ievadiet derīgu adresi</translation>
+<translation id="2986368408720340940">Šis saņemšanas veids nav pieejams. Izmēģiniet citu veidu.</translation>
<translation id="2991174974383378012">Kopīgošana ar vietnēm</translation>
<translation id="3005723025932146533">RÄdÄ«t saglabÄto versiju</translation>
<translation id="3008447029300691911">Ievadiet kredÄ«tkartes <ph name="CREDIT_CARD" /> CVC. PÄ“c apstiprinÄÅ¡anas kartes informÄcija tiks kopÄ«gota ar Å¡o vietni.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{vismaz 1 vienums sinhronizÄ“tÄs ierÄ«cÄ“s}=1{1 vienums (un vÄ“l citi sinhronizÄ“tÄs ierÄ«cÄ“s)}zero{# vienumi (un vÄ“l citi sinhronizÄ“tÄs ierÄ«cÄ“s)}one{# vienums (un vÄ“l citi sinhronizÄ“tÄs ierÄ«cÄ“s)}other{# vienumi (un vÄ“l citi sinhronizÄ“tÄs ierÄ«cÄ“s)}}</translation>
<translation id="3041612393474885105">SertifikÄta informÄcija</translation>
<translation id="3063697135517575841">PÄrlÅ«kÄ Chrome paÅ¡laik nevar apstiprinÄt jÅ«su karti. LÅ«dzu, vÄ“lÄk mÄ“Ä£iniet vÄ“lreiz.</translation>
+<translation id="3064966200440839136">Ja maksÄÅ¡anai tiks izmantota ÄrÄ“ja lietojumprogramma, tiks aizvÄ“rts inkognito režīms. Vai turpinÄt?</translation>
<translation id="3093245981617870298">Esat bezsaistē</translation>
<translation id="3105172416063519923">Līdzekļa ID:</translation>
<translation id="3109728660330352905">Jums nav pilnvaru, lai skatītu šo lapu.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Mēģiniet palaist savienojamības diagnostiku<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">NeizdevÄs atÅ¡ifrÄ“t atbildi.</translation>
-<translation id="3149891296864842641">PiegÄdes iespÄ“ja</translation>
<translation id="3150653042067488994">Īslaicīga servera kļūda</translation>
+<translation id="3154506275960390542">Å ajÄ lapÄ ir veidlapa, ko, iespÄ“jams, nevar droÅ¡i iesniegt. KamÄ“r Å¡ie dati tiek pÄrsÅ«tÄ«ti, tos var aplÅ«kot citi, un uzbrucÄ“js tos varÄ“tu pÄrveidot, lai mainÄ«tu datus, ko saņem serveris.</translation>
<translation id="3157931365184549694">Atjaunot</translation>
<translation id="3167968892399408617">Lapas, ko skatÄt inkognito režīma cilnÄ“s, nebÅ«s redzamas pÄrlÅ«ka vÄ“sturÄ“, sÄ«kfailu krÄtuvÄ“ vai meklÄ“Å¡anas vÄ“sturÄ“, kad aizvÄ“rsiet visas inkognito režīma cilnes. TomÄ“r tiks saglabÄti visi lejupielÄdÄ“tie faili un izveidotÄs grÄmatzÄ«mes.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">LietotÄjam <ph name="NAME" /> nevarÄ“ja nosÅ«tÄ«t jÅ«su pieprasÄ«jumu piekļūt Å¡ai vietnei. LÅ«dzu, mÄ“Ä£iniet vÄ“lreiz.</translation>
<translation id="3355823806454867987">Mainīt starpniekservera iestatījumus...</translation>
<translation id="3369192424181595722">Pulksteņa kļūda</translation>
+<translation id="337311366426640088">Vēl <ph name="ITEM_COUNT" /> vienumi...</translation>
<translation id="337363190475750230">Tika noņemta piekļuve</translation>
<translation id="3377188786107721145">RadÄs politikas parsÄ“Å¡anas kļūda.</translation>
<translation id="3380365263193509176">NezinÄma kļūda</translation>
<translation id="3380864720620200369">Klienta ID:</translation>
<translation id="3391030046425686457">PiegÄdes adrese</translation>
+<translation id="3395827396354264108">Saņemšanas veids</translation>
<translation id="340013220407300675">UzbrucÄ“ji var mÄ“Ä£inÄt 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).</translation>
<translation id="3422248202833853650">Aizveriet citas programmas, lai atbrÄ«votu vietu atmiņÄ.</translation>
<translation id="3422472998109090673">Vietne <ph name="HOST_NAME" /> pašlaik nav sasniedzama.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">PirmsielÄdes intervÄls:</translation>
<translation id="3462200631372590220">SlÄ“pt papildu informÄciju</translation>
+<translation id="3467763166455606212">JÄnorÄda kartes Ä«paÅ¡nieka vÄrds un uzvÄrds</translation>
+<translation id="3478058380795961209">Der. term. mēn.</translation>
<translation id="3479539252931486093">Vai tas bija negaidīti? <ph name="BEGIN_LINK" />Informējiet mūs<ph name="END_LINK" />!</translation>
<translation id="3479552764303398839">VÄ“lÄk</translation>
<translation id="348000606199325318">AvÄrijas ID <ph name="CRASH_LOCAL_ID" /> (servera ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">MÄ“s nevarÄ“jÄm sasniegt jÅ«su mÄti/tÄ“vu. LÅ«dzu, mÄ“Ä£iniet vÄ“lreiz.</translation>
<translation id="3528171143076753409">Servera sertifikÄts nav uzticams.</translation>
-<translation id="3538531656504267329">Derīguma termiņa beigu gads nav derīgs</translation>
<translation id="3539171420378717834">SaglabÄt Å¡Ä«s kartes kopiju Å¡ajÄ ierÄ«cÄ“</translation>
<translation id="3542684924769048008">Izmantot paroli:</translation>
<translation id="3549644494707163724">Å ifrÄ“t visus sinhronizÄ“tos datus, izmantojot sinhronizÄcijas ieejas frÄzi</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Slēpt detaļas</translation>
<translation id="3587482841069643663">Visi</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Ievadiet derīgu datumu</translation>
<translation id="36224234498066874">DzÄ“st pÄrlÅ«koÅ¡anas datus...</translation>
<translation id="362276910939193118">RÄdÄ«t pilnu vÄ“sturi</translation>
<translation id="3623476034248543066">RÄdÄ«t vÄ“rtÄ«bu</translation>
@@ -311,7 +323,6 @@
<translation id="3693415264595406141">Parole:</translation>
<translation id="3696411085566228381">nav</translation>
<translation id="3704609568417268905"><ph name="TIME" />, <ph name="BOOKMARKED" />, <ph name="TITLE" />, <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Atlasiet piegÄdes adresi, lai skatÄ«tu piegÄdes veidus un prasÄ«bas.</translation>
<translation id="370665806235115550">Notiek ielÄde...</translation>
<translation id="3712624925041724820">Nav pietiekami daudz licenÄu.</translation>
<translation id="3714780639079136834">Ieslēdziet mobilo datu savienojumu vai Wi-Fi.</translation>
@@ -320,6 +331,7 @@
<translation id="3739623965217189342">JÅ«su kopÄ“tÄ saite</translation>
<translation id="375403751935624634">Tulkojums neizdevÄs servera kļūdas dēļ.</translation>
<translation id="3759461132968374835">PÄ“dÄ“jÄ laikÄ neesat ziņojis par avÄrijÄm. Å eit nebÅ«s redzamas avÄrijas, kas radÄs laikÄ, kad avÄriju pÄrskatu izveide bija atspÄ“jota.</translation>
+<translation id="3787705759683870569">Derīguma termiņš: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Ja izmantojat starpniekserveri...</translation>
<translation id="3828924085048779000">TukÅ¡a ieejas frÄze nav atļauta.</translation>
<translation id="3845539888601087042">Tiek rÄdÄ«ta vÄ“sture no ierÄ«cÄ“m, kurÄs esat pierakstÄ«jies. <ph name="BEGIN_LINK" />Uzziniet vairÄk<ph name="END_LINK" />.</translation>
@@ -355,7 +367,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Vai vÄ“laties, lai Chromium saglabÄtu Å¡o karti?</translation>
<translation id="4171400957073367226">VerifikÄcijas paraksts nav derÄ«gs.</translation>
-<translation id="4176463684765177261">Atspējots</translation>
<translation id="4196861286325780578">&amp;Atcelt pÄrvietoÅ¡anas atsaukÅ¡anu</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />PÄrbaudiet ugunsmÅ«ri un pretvÄ«rusu programmu konfigurÄcijas<ph name="END_LINK" />.</translation>
<translation id="4206349416402437184">{COUNT,plural, =0{nav}=1{1 lietotne ($1)}=2{2 lietotnes ($1, $2)}zero{# lietotnes ($1, $2, $3)}one{# lietotne ($1, $2, $3)}other{# lietotnes ($1, $2, $3)}}</translation>
@@ -382,11 +393,11 @@
<translation id="4406896451731180161">meklÄ“Å¡anas rezultÄti</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> nepieņēma jÅ«su pieteikÅ¡anÄs sertifikÄtu, vai arÄ« pieteikÅ¡anÄs sertifikÄts netika iesniegts.</translation>
<translation id="443673843213245140">Starpniekservera lietoÅ¡ana ir atspÄ“jota, bet ir norÄdÄ«ta atklÄta starpniekservera konfigurÄcija.</translation>
-<translation id="4446242550670694251">Tagad varat privÄti pÄrlÅ«kot saturu, un citas personas, kas izmanto Å¡o ierÄ«ci, nevarÄ“s redzÄ“t jÅ«su darbÄ«bas.</translation>
<translation id="4492190037599258964">VaicÄjuma “<ph name="SEARCH_STRING" />†meklÄ“Å¡anas rezultÄti</translation>
<translation id="4506176782989081258">ValidÄcijas kļūda: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Sazinieties ar sistēmas administratoru.</translation>
<translation id="450710068430902550">Kopīgošana ar administratoru</translation>
+<translation id="4515275063822566619">Kartes un adreses tiek iegÅ«tas no Chrome un jÅ«su Google konta (<ph name="ACCOUNT_EMAIL" />). Varat tÄs pÄrvaldÄ«t <ph name="BEGIN_LINK" />iestatÄ«jumos<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">InformÄcija</translation>
<translation id="4558551763791394412">AtspÄ“jojiet paplaÅ¡inÄjumus.</translation>
<translation id="457875822857220463">PiegÄde</translation>
@@ -416,6 +427,7 @@
<translation id="4816492930507672669">IetilpinÄt lapÄ</translation>
<translation id="483020001682031208">Nav nevienas fiziskÄ tÄ«mekļa lapas, ko parÄdÄ«t.</translation>
<translation id="4850886885716139402">Skatīt</translation>
+<translation id="4854362297993841467">Å is piegÄdes veids nav pieejams. IzmÄ“Ä£iniet citu veidu.</translation>
<translation id="4858792381671956233">JÅ«s lÅ«dzÄt vecÄkiem atļauju apmeklÄ“t Å¡o lapu</translation>
<translation id="4880827082731008257">Meklēšanas vēsture</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -423,7 +435,6 @@
<translation id="4923417429809017348">Å Ä« lapa ir tulkota no nezinÄmas valodas valodÄ: <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">MaksÄjums</translation>
<translation id="4926049483395192435">JÄbÅ«t norÄdÄ«tai.</translation>
-<translation id="4941291666397027948">* norÄda obligÄtu lauku</translation>
<translation id="495170559598752135">Darbības</translation>
<translation id="4958444002117714549">Izvērst sarakstu</translation>
<translation id="4962322354953122629">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts nav uzticams pÄrlÅ«kÄ Chrome. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -438,6 +449,7 @@
<translation id="5045550434625856497">Nepareiza parole</translation>
<translation id="5056549851600133418">Jums piemeklēti raksti</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />PÄrbaudiet starpniekservera adresi<ph name="END_LINK" />.</translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Nav sīkfailu.}=1{1 vietne izmanto sīkfailus. }zero{# vietnes izmanto sīkfailus. }one{# vietne izmanto sīkfailus. }other{# vietnes izmanto sīkfailus. }}</translation>
<translation id="5087286274860437796">Servera sertifikÄts Å¡obrÄ«d nav derÄ«gs.</translation>
<translation id="5087580092889165836">Pievienot karti</translation>
<translation id="5089810972385038852">Å tats</translation>
@@ -460,10 +472,8 @@
<translation id="5300589172476337783">RÄdÄ«t</translation>
<translation id="5308689395849655368">AvÄriju pÄrskatu izveide ir atspÄ“jota.</translation>
<translation id="5317780077021120954">SaglabÄt</translation>
-<translation id="5326702247179446998">JÄnorÄda adresÄts</translation>
<translation id="5327248766486351172">Nosaukums</translation>
<translation id="5337705430875057403">UzbrucÄ“ji vietnÄ“ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> var pamudinÄt jÅ«s veikt bÄ«stamas darbÄ«bas, piemÄ“ram, instalÄ“t programmatÅ«ru vai atklÄt savu personas informÄciju (t.i., paroles, tÄlruņa numurus vai informÄciju par kredÄ«tkartÄ“m).</translation>
-<translation id="53553865750799677">Neatbalstīta saņemšanas adrese. Atlasiet citu adresi.</translation>
<translation id="5359637492792381994">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts Å¡obrÄ«d nav uzticams. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu.<ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">NeizdevÄs saglabÄt politikas iestatÄ«jumus.</translation>
<translation id="5386426401304769735">Å Ä«s vietnes sertifikÄtu Ä·Ä“dÄ“ ir iekļauts sertifikÄts, kas ir parakstÄ«ts, izmantojot SHA-1.</translation>
@@ -489,8 +499,8 @@
<translation id="5544037170328430102">VietnÄ“ <ph name="SITE" /> iegultÄ lapÄ ir rakstÄ«ts:</translation>
<translation id="5556459405103347317">PÄrlÄdÄ“t</translation>
<translation id="5565735124758917034">Aktīvs</translation>
+<translation id="5571083550517324815">Nevar saņemt sÅ«tÄ«jumu Å¡ajÄ adresÄ“. Atlasiet citu adresi.</translation>
<translation id="5572851009514199876">LÅ«dzu, palaidiet pÄrlÅ«ku Chrome un pierakstieties tajÄ, lai pÄrlÅ«kÄ Chrome varÄ“tu pÄrbaudÄ«t, vai jums ir atļauja piekļūt Å¡ai vietnei.</translation>
-<translation id="5575380383496039204">NeatbalstÄ«ta piegÄdes adrese. Atlasiet citu adresi.</translation>
<translation id="5580958916614886209">PÄrbaudiet derÄ«guma termiņa mÄ“nesi un mÄ“Ä£iniet vÄ“lreiz.</translation>
<translation id="560412284261940334">PÄrvaldÄ«Å¡ana netiek atbalstÄ«ta.</translation>
<translation id="5610142619324316209">PÄrbaudiet savienojumu.</translation>
@@ -506,7 +516,8 @@
<translation id="5710435578057952990">TÄ«mekļa vietnes identitÄte nav apstiprinÄta.</translation>
<translation id="5720705177508910913">PaÅ¡reizÄ“jais lietotÄjs</translation>
<translation id="5732392974455271431">Lai atbloÄ·Ä“tu, vÄ“rsieties pie vecÄkiem</translation>
-<translation id="57586589942790530">Nederīgs kartes numurs</translation>
+<translation id="5763042198335101085">Ievadiet derīgu e-pasta adresi</translation>
+<translation id="5765072501007116331">Lai skatÄ«tu piegÄdes veidus un prasÄ«bas, atlasiet adresi.</translation>
<translation id="5784606427469807560">Apstiprinot karti, radÄs problÄ“ma. PÄrbaudiet interneta savienojumu un mÄ“Ä£iniet vÄ“lreiz.</translation>
<translation id="5785756445106461925">TurklÄt Å¡ajÄ lapÄ ir citi resursi, kas nav droÅ¡i. KamÄ“r Å¡ie resursi tiek pÄrsÅ«tÄ«ti, tos var aplÅ«kot citi, kÄ arÄ« uzbrucÄ“js var tos pÄrveidot, lai mainÄ«tu lapas izskatu.</translation>
<translation id="5786044859038896871">Vai vÄ“laties aizpildÄ«t laukus ar kartes informÄciju?</translation>
@@ -519,22 +530,20 @@
<translation id="5869405914158311789">Å Ä« vietne nav sasniedzama</translation>
<translation id="5869522115854928033">SaglabÄtÄs paroles</translation>
<translation id="5872918882028971132">VecÄku ieteikumi</translation>
-<translation id="587760065310675640">NeatbalstÄ«ta piegÄdes adrese. Atlasiet citu adresi.</translation>
<translation id="5901630391730855834">Dzeltena</translation>
-<translation id="59174027418879706">Iespējots</translation>
<translation id="5926846154125914413">Varat zaudÄ“t piekļuvi maksas saturam no noteiktÄm vietnÄ“m.</translation>
<translation id="5959728338436674663">AutomÄtiski sÅ«tÄ«t Google serveriem noteiktu <ph name="BEGIN_WHITEPAPER_LINK" />sistÄ“mas informÄciju un lapu saturu<ph name="END_WHITEPAPER_LINK" />, lai palÄ«dzÄ“tu noteikt bÄ«stamas lietotnes un vietnes. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Nedēļa</translation>
<translation id="5967867314010545767">Noņemt no vēstures</translation>
<translation id="5975083100439434680">TÄlinÄt</translation>
+<translation id="598637245381783098">Nevar atvÄ“rt maksÄjumu lietotni</translation>
<translation id="5989320800837274978">Nav norÄdÄ«ti nedz fiksÄ“ti starpniekserveri, nedz .pac skripta URL.</translation>
<translation id="5990559369517809815">PaplaÅ¡inÄjums ir bloÄ·Ä“jis pieprasÄ«jumus serverim.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Kartes un adreses informÄcija ir no pÄrlÅ«ka Chrome. Varat pÄrvaldÄ«t Å¡o informÄciju sadaÄ¼Ä <ph name="BEGIN_LINK" />IestatÄ«jumi<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1. lapa}zero{#. lapa}one{#. lapa}other{#. lapa}}</translation>
<translation id="6017514345406065928">Zaļa</translation>
+<translation id="6027201098523975773">Ievadiet vÄrdu</translation>
<translation id="6040143037577758943">Aizvērt</translation>
-<translation id="604124094241169006">AutomÄtiski</translation>
<translation id="6042308850641462728">VairÄk</translation>
<translation id="6060685159320643512">Esiet uzmanīgs! Šie eksperimenti var jums kaitēt</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{nav}=1{1}zero{#}one{#}other{#}}</translation>
@@ -542,9 +551,10 @@
izmantotÄs tÄ«kla ierÄ«ces.</translation>
<translation id="614940544461990577">Veiciet tÄlÄk norÄdÄ«tÄs darbÄ«bas.</translation>
<translation id="6151417162996330722">Å Ä« servera sertifikÄta derÄ«guma periods ir pÄrÄk ilgs.</translation>
-<translation id="615643356032862689">LejupielÄdÄ“tie faili un grÄmatzÄ«mes tiks saglabÄti.</translation>
+<translation id="6157877588268064908">Lai skatītu nosūtīšanas veidus un prasības, atlasiet adresi.</translation>
<translation id="6165508094623778733">Uzziniet vairÄk</translation>
<translation id="6177128806592000436">Savienojums ar šo vietni nav drošs.</translation>
+<translation id="6184817833369986695">(personu grupa: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Interneta savienojuma pÄrbaude</translation>
<translation id="6218753634732582820">Vai noņemt adresi no pÄrlÅ«ka Chromium?</translation>
<translation id="6251924700383757765">KonfidencialitÄtes politika</translation>
@@ -553,6 +563,8 @@
<translation id="6259156558325130047">&amp;PÄrkÄrtoÅ¡anas atsaukuma atcelÅ¡ana</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> grÄmatzÄ«mes</translation>
<translation id="6264485186158353794">Atpakaļ droÅ¡Ä«bÄ</translation>
+<translation id="6276112860590028508">Å eit tiek rÄdÄ«tas lasÄ«Å¡anas sarakstÄ esoÅ¡Äs lapas</translation>
+<translation id="6280223929691119688">Nevar piegÄdÄt uz Å¡o adresi. Atlasiet citu adresi.</translation>
<translation id="6282194474023008486">Pasta indekss</translation>
<translation id="6290238015253830360">Ieteiktie raksti tiek parÄdÄ«ti Å¡eit</translation>
<translation id="6305205051461490394">Vietne <ph name="URL" /> nav sasniedzama.</translation>
@@ -574,7 +586,6 @@
<translation id="6417515091412812850">Nevar pÄrbaudÄ«t, vai sertifikÄts ir atsaukts.</translation>
<translation id="6433490469411711332">KontaktinformÄcijas rediģēšana</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> noraidīja savienojuma izveidi.</translation>
-<translation id="6443118737398455446">Derīguma termiņš nav derīgs.</translation>
<translation id="6446608382365791566">Papildu informÄcijas pievienoÅ¡ana</translation>
<translation id="6451458296329894277">ApstiprinÄt veidlapas atkÄrtotu iesniegÅ¡anu</translation>
<translation id="6456339708790392414">MaksÄjums</translation>
@@ -582,10 +593,8 @@
<translation id="6462969404041126431">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts, iespÄ“jams, ir atsaukts. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Ierīces politikas</translation>
<translation id="6477321094435799029">PÄrlÅ«kÄ Chrome tika noteikts, ka Å¡ajÄ lapÄ ir neparasts kods. Lapa tika bloÄ·Ä“ta, lai aizsargÄtu jÅ«su personas informÄciju (piemÄ“ram, paroles, tÄlruņa numurus un kredÄ«tkarÅ¡u informÄciju).</translation>
-<translation id="6477460825583319731">Nederīga e-pasta adrese</translation>
<translation id="6489534406876378309">SÄkt avÄriju datu augÅ¡upielÄdi</translation>
<translation id="6508722015517270189">RestartÄ“jiet pÄrlÅ«ku Chrome</translation>
-<translation id="6525462735697194615">Derīguma termiņa beigu mēnesis nav derīgs</translation>
<translation id="6529602333819889595">&amp;Dzēšanas atsaukuma atcelšana</translation>
<translation id="6534179046333460208">FiziskÄ tÄ«mekļa ieteikumi</translation>
<translation id="6550675742724504774">Opcijas</translation>
@@ -600,7 +609,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> meklēšana</translation>
<translation id="6644283850729428850">Å Ä« politika ir izbeigta.</translation>
<translation id="6652240803263749613">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts nav uzticams jÅ«su datora operÄ“tÄjsistÄ“mÄ. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Å Ä« pÄrvadÄjuma iespÄ“ja nav pieejama. IzvÄ“lieties citu iespÄ“ju.</translation>
<translation id="6671697161687535275">Vai noņemt veidlapas ieteikumu no pÄrlÅ«ka Chromium?</translation>
<translation id="6685834062052613830">Izrakstieties un pabeidziet iestatīšanu</translation>
<translation id="6710213216561001401">Iepriekšējais</translation>
@@ -608,13 +616,13 @@
<translation id="6711464428925977395">StarpniekserverÄ« radÄs kļūda, vai arÄ« adrese nav pareiza.</translation>
<translation id="6727102863431372879">Iestatīt</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{nav}=1{1 vienums}zero{# vienumi}one{# vienums}other{# vienumi}}</translation>
-<translation id="6743044928064272573">Saņemšanas iespējas</translation>
<translation id="674375294223700098">NezinÄma servera sertifikÄta kļūda.</translation>
<translation id="6753269504797312559">Politikas vērtība</translation>
<translation id="6757797048963528358">IerÄ«ce tika pÄrslÄ“gta miega režīmÄ.</translation>
<translation id="6778737459546443941">Neviens no jÅ«su vecÄkiem vÄ“l nav to apstiprinÄjis</translation>
<translation id="6810899417690483278">PielÄgoÅ¡anas ID</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">NeizdevÄs ielÄdÄ“t reÄ£ionu datus</translation>
<translation id="6831043979455480757">Tulkot</translation>
<translation id="6839929833149231406">Apgabals</translation>
<translation id="6874604403660855544">&amp;Atcelt pievienošanas atsaukšanu</translation>
@@ -622,6 +630,7 @@
<translation id="6895330447102777224">Karte ir apstiprinÄta</translation>
<translation id="6897140037006041989">LietotÄja aÄ£ents</translation>
<translation id="6915804003454593391">LietotÄjs:</translation>
+<translation id="6948701128805548767">Lai skatītu saņemšanas veidus un prasības, atlasiet adresi.</translation>
<translation id="6957887021205513506">Å Ä·iet, ka servera sertifikÄts ir viltojums.</translation>
<translation id="6965382102122355670">Labi</translation>
<translation id="6965978654500191972">Ierīce</translation>
@@ -629,7 +638,6 @@
<translation id="6973656660372572881">Ir norÄdÄ«ti gan fiksÄ“ti starpniekserveri, gan .pac skripta URL.</translation>
<translation id="6989763994942163495">RÄdÄ«t papildu iestatÄ«jumus...</translation>
<translation id="7000990526846637657">Netika atrasts neviens vēstures ieraksts.</translation>
-<translation id="7001663382399377034">AdresÄta pievienoÅ¡ana</translation>
<translation id="7009986207543992532">JÅ«s mÄ“Ä£inÄjÄt sasniegt domÄ“nu <ph name="DOMAIN" />, taÄu serveris uzrÄdÄ«ja sertifikÄtu, kura derÄ«guma periods ir pÄrÄk ilgs, lai bÅ«tu uzticams. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">JÅ«su Google kontam var bÅ«t cita veida pÄrlÅ«koÅ¡anas vÄ“stures dati vietnÄ“ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
@@ -640,12 +648,15 @@
<translation id="7088615885725309056">VecÄka</translation>
<translation id="7090678807593890770">Veiciet Google meklÄ“Å¡anu, izmantojot vaicÄjumu “<ph name="LINK" />â€</translation>
<translation id="7119414471315195487">Aizveriet citas cilnes vai programmas</translation>
+<translation id="7129409597930077180">Nevar nosūtīt uz šo adresi. Atlasiet citu adresi.</translation>
+<translation id="7138472120740807366">PiegÄdes veids</translation>
<translation id="7139724024395191329">EmirÄts</translation>
<translation id="7155487117670177674">MaksÄjums nav droÅ¡s</translation>
<translation id="7179921470347911571">Restartēt tūlīt</translation>
<translation id="7180611975245234373">AtsvaidzinÄt</translation>
<translation id="7182878459783632708">Nav iestatīta neviena politika</translation>
<translation id="7186367841673660872">Å Ä« lapa ir tulkota no<ph name="ORIGINAL_LANGUAGE" />valodas<ph name="LANGUAGE_LANGUAGE" />valodÄ</translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> neatbilst drošības standartiem.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Uzziniet vairÄk<ph name="END_LINK" /> par Å¡o problÄ“mu.</translation>
@@ -674,7 +685,6 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="7424977062513257142">Å ajÄ vietnÄ“ iegultÄ lapÄ ir rakstÄ«ts:</translation>
<translation id="7441627299479586546">Politikas subjekts nav pareizs.</translation>
<translation id="7444046173054089907">Å Ä« vietne ir bloÄ·Ä“ta</translation>
-<translation id="7444238235002594607">Atlasiet saņemÅ¡anas adresi, lai pÄrbaudÄ«tu saņemÅ¡anas veidus un prasÄ«bas.</translation>
<translation id="7445762425076701745">Nevar pilnÄ«bÄ apstiprinÄt servera identifikÄcijas datus, ar kuru esat savienots. Jums ir izveidots savienojums ar serveri, izmantojot nosaukumu, kas ir derÄ«gs tikai jÅ«su tÄ«klÄ, kam ÄrÄ“jÄ sertifikÄta izdevÄ“jiestÄde nekÄdÄ veidÄ nevar apstiprinÄt Ä«paÅ¡umtiesÄ«bas. TÄ kÄ dažas sertifikÄta izdevÄ“jiestÄdes tÄpat izsniegs sertifikÄtus Å¡Ädiem nosaukumiem, nav iespÄ“jams garantÄ“t, ka jÅ«s esat savienots ar vajadzÄ«go vietni, nevis uzbrucÄ“ju.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />UzzinÄt vairÄk<ph name="END_LINK" /> par Å¡o problÄ“mu.</translation>
<translation id="7460163899615895653">JÅ«su nesen izmantotÄs cilnes no citÄm ierÄ«cÄ“m tiek rÄdÄ«tas Å¡eit</translation>
@@ -718,6 +728,7 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="7755287808199759310">Lai atbloÄ·Ä“tu, vÄ“sieties pie vecÄka</translation>
<translation id="7758069387465995638">Iespējams, savienojumu ir bloķējis ugunsmūris vai pretvīrusu programmatūra.</translation>
<translation id="7761701407923456692">Servera sertifikÄts neatbilst URL.</translation>
+<translation id="7763386264682878361">MaksÄjumu manifestu parsÄ“tÄjs</translation>
<translation id="7764225426217299476">Pievienot adresi</translation>
<translation id="777702478322588152">Prefektūra</translation>
<translation id="7791543448312431591">Pievienot</translation>
@@ -731,6 +742,7 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="785549533363645510">TomÄ“r jÅ«s neesat neredzams. PÄrlÅ«kojot inkognito režīmÄ, jÅ«su pÄrlÅ«koÅ¡anas darbÄ«bas netiek slÄ“ptas no jÅ«su darba devÄ“ja, interneta pakalpojumu sniedzÄ“ja vai apmeklÄ“tajÄm vietnÄ“m.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" />: <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">PÄrbaudiet CVC kodu un mÄ“Ä£iniet vÄ“lreiz.</translation>
+<translation id="79338296614623784">Ievadiet derÄ«gu tÄlruņa numuru</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Servera sertifikÄts vÄ“l nav apstiprinÄts.</translation>
<translation id="7942349550061667556">Sarkana</translation>
@@ -750,6 +762,7 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="8088680233425245692">Rakstu neizdevÄs skatÄ«t.</translation>
<translation id="8089520772729574115">mazÄk nekÄ 1 MB</translation>
<translation id="8091372947890762290">AktivizÄcija vÄ“l nav apstiprinÄta serverÄ«.</translation>
+<translation id="8118489163946903409">MaksÄjuma veids</translation>
<translation id="8131740175452115882">ApstiprinÄt</translation>
<translation id="8134994873729925007">Nevarēja atrast <ph name="HOST_NAME" /> servera <ph name="BEGIN_ABBR" />DNS adresi<ph name="END_ABBR" />.</translation>
<translation id="8149426793427495338">Dators tika pÄrslÄ“gts miega režīmÄ.</translation>
@@ -775,6 +788,7 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="8349305172487531364">GrÄmatzÄ«mju josla</translation>
<translation id="8363502534493474904">Izslēdziet lidojuma režīmu.</translation>
<translation id="8364627913115013041">Nav iestatīta.</translation>
+<translation id="8368476060205742148">Google Play pakalpojumi</translation>
<translation id="8380941800586852976">BÄ«stama</translation>
<translation id="8382348898565613901">Nesen izmantotÄs grÄmatzÄ«mes tiek parÄdÄ«tas Å¡eit</translation>
<translation id="8398259832188219207">AvÄriju pÄrskats augÅ¡upielÄdÄ“ts: <ph name="UPLOAD_TIME" /></translation>
@@ -783,32 +797,30 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="8428213095426709021">Iestatījumi</translation>
<translation id="8433057134996913067">Å Ädi tiksiet izrakstÄ«ts no lielÄkÄs daļas vietņu.</translation>
<translation id="8437238597147034694">&amp;Atsaukt pÄrvietoÅ¡anu</translation>
-<translation id="8456681095658380701">Nederīgs nosaukums</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 kredītkarte}zero{# kredītkartes}one{# kredītkarte}other{# kredītkartes}}</translation>
<translation id="8483780878231876732">Lai izmantotu kartes no sava Google konta, pierakstieties pÄrlÅ«kÄ Chrome!</translation>
<translation id="8488350697529856933">Attiecas uz</translation>
-<translation id="8492969205326575646">Neatbalstīts kartes veids</translation>
<translation id="8498891568109133222">Vietne <ph name="HOST_NAME" /> pÄrÄk ilgi nereaģēja.</translation>
<translation id="852346902619691059">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts nav uzticams jÅ«su ierÄ«ces operÄ“tÄjsistÄ“mÄ. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Der. term. gads</translation>
<translation id="8543181531796978784">JÅ«s varat <ph name="BEGIN_ERROR_LINK" />ziņot par noteikÅ¡anas problÄ“mu<ph name="END_ERROR_LINK" /> vai, ja apzinÄties droÅ¡Ä«bas riskus, <ph name="BEGIN_LINK" />apmeklÄ“t Å¡o nedroÅ¡o vietni<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">TulkoÅ¡ana neizdevÄs, jo lapas valoda nav nosakÄma.</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="8570229484593575558">|Netiks saglabÄta| Å¡Äda informÄcija:#jÅ«su pÄrlÅ«koÅ¡anas vÄ“sture;#jÅ«su meklÄ“tie vaicÄjumi;#sÄ«kfailu dati.</translation>
<translation id="8571890674111243710">Notiek lapas tulkošana uz <ph name="LANGUAGE" /> valodu...</translation>
-<translation id="8584539743998202583">IespÄ“jams, jÅ«su darbÄ«bas |joprojÄm bÅ«s redzamas|:#jÅ«su apmeklÄ“tajÄm vietnÄ“m;#jÅ«su darba devÄ“jam;#jÅ«su interneta pakalpojumu sniedzÄ“jam.</translation>
<translation id="858637041960032120">Piev. tÄlr. nr.
</translation>
<translation id="859285277496340001">SertifikÄts nenorÄda mehÄnismu, ar kuru pÄrbaudÄ«t, vai tas nav atsaukts.</translation>
<translation id="8620436878122366504">JÅ«su vecÄki vÄ“l nav to apstiprinÄjuÅ¡i</translation>
<translation id="8647750283161643317">Atiestatīt visiem to noklusējuma iestatījumus</translation>
<translation id="8703575177326907206">Jūsu savienojums ar <ph name="DOMAIN" /> nav kodēts.</translation>
+<translation id="8718314106902482036">MaksÄjums nav pabeigts</translation>
<translation id="8725066075913043281">MÄ“Ä£inÄt vÄ“lreiz</translation>
<translation id="8728672262656704056">Jūs esat atvēris inkognito režīmu</translation>
<translation id="8730621377337864115">Gatavs</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="8759274551635299824">Kartes derīguma termiņš ir beidzies</translation>
<translation id="8790007591277257123">&amp;Atcelt dzēšanas atsaukšanu</translation>
-<translation id="8798099450830957504">Noklusējums</translation>
<translation id="8800988563907321413">Å eit tiks parÄdÄ«ti funkcijas TuvumÄ ieteikumi</translation>
<translation id="8820817407110198400">GrÄmatzÄ«mes</translation>
<translation id="883848425547221593">Citas grÄmatzÄ«mes</translation>
@@ -818,6 +830,7 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="8866481888320382733">ParsÄ“jot politikas iestatÄ«jumus, radÄs kļūda.</translation>
<translation id="8866959479196209191">Å ajÄ lapÄ ir rakstÄ«ts:</translation>
<translation id="8870413625673593573">Nesen aizvērtas</translation>
+<translation id="8874824191258364635">Ievadiet derīgu kartes numuru</translation>
<translation id="8876793034577346603">NeizdevÄs parsÄ“t tÄ«kla konfigurÄciju.</translation>
<translation id="8877192140621905067">PÄ“c apstiprinÄÅ¡anas kartes informÄcija tiks kopÄ«gota ar Å¡o vietni.</translation>
<translation id="8889402386540077796">NokrÄsa</translation>
@@ -827,7 +840,6 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="8931333241327730545">Vai vÄ“laties saglabÄt Å¡o karti savÄ Google kontÄ?</translation>
<translation id="8932102934695377596">NorÄdÄ«tais laiks ir pÄrÄk tÄlu pagÄtnÄ“</translation>
<translation id="8954894007019320973">(turpin.)</translation>
-<translation id="895548565263634352">Lasiet izdevÄ“ja <ph name="ARTICLE_PUBLISHER" /> rakstus, kÄ arÄ« vÄ“l <ph name="OTHER_ARTICLE_COUNT" /> rakstus.</translation>
<translation id="8971063699422889582">Servera sertifikÄtam ir beidzies derÄ«guma termiņš.</translation>
<translation id="8986494364107987395">AutomÄtiski sÅ«tÄ«t lietoÅ¡anas statistiku un avÄriju pÄrskatus uzņēmumam Google</translation>
<translation id="8987927404178983737">MÄ“nesis</translation>
@@ -845,7 +857,6 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="9068849894565669697">KrÄsas izvÄ“le</translation>
<translation id="9076283476770535406">Vietnē var būt pieaugušajiem paredzēts saturs</translation>
<translation id="9078964945751709336">NepiecieÅ¡ama plaÅ¡Äka informÄcija.</translation>
-<translation id="9094175695478007090">Nevar palaist maksÄjumu lietotni.</translation>
<translation id="9103872766612412690">VietnÄ“ <ph name="SITE" /> informÄcijas aizsargÄÅ¡anai parasti tiek izmantota Å¡ifrÄ“Å¡ana. Kad pÄrlÅ«kÄ Chromium tika mÄ“Ä£inÄts izveidot savienojumu ar vietni <ph name="SITE" />, Å¡oreiz tÄ nosÅ«tÄ«ja neparastus un nepareizus akreditÄcijas datus. IespÄ“jams, tas notika, jo uzbrucÄ“js mÄ“Ä£inÄja uzdoties par vietni <ph name="SITE" />, vai arÄ« Wi-Fi pierakstÄ«Å¡anÄs ekrÄns pÄrtrauca savienojumu. JÅ«su informÄcija joprojÄm ir droÅ¡Ä«bÄ, jo pÄrlÅ«ks Chromium pÄrtrauca savienojumu, pirms tika veikta jebkÄdu datu apmaiņa.</translation>
<translation id="9137013805542155359">RÄdÄ«t oriÄ£inÄlo</translation>
<translation id="9137248913990643158">Pirms Å¡Ä«s lietotnes izmantoÅ¡anas, lÅ«dzu, palaidiet pÄrlÅ«ku Chrome un pierakstieties tajÄ.</translation>
diff --git a/chromium/components/strings/components_strings_ml.xtb b/chromium/components/strings/components_strings_ml.xtb
index 00f528c9fd6..d88923ff138 100644
--- a/chromium/components/strings/components_strings_ml.xtb
+++ b/chromium/components/strings/components_strings_ml.xtb
@@ -3,9 +3,10 @@
<translationbundle lang="ml">
<translation id="1008557486741366299">ഇപàµà´ªàµ‹à´´à´²àµà´²</translation>
<translation id="1015730422737071372">കൂടàµà´¤àµ½ വിശദാംശങàµà´™àµ¾ നൽകàµà´•</translation>
+<translation id="1021110881106174305">à´¸àµà´µàµ€à´•à´°à´¿à´šàµà´š കാർഡàµà´•àµ¾</translation>
<translation id="1032854598605920125">ഘടികാരദിശയിൽ‌ തിരികàµà´•àµà´•</translation>
<translation id="1038842779957582377">à´…à´œàµà´žà´¾à´¤ നാമം</translation>
-<translation id="1050038467049342496">മറàµà´±àµ ആപàµâ€Œà´¸àµà´•àµ¾ à´…à´Ÿà´¯àµâ€Œà´•àµà´•àµà´•</translation>
+<translation id="1050038467049342496">മറàµà´±àµ ആപàµà´ªàµà´•àµ¾ à´…à´Ÿà´¯àµâ€Œà´•àµà´•àµà´•</translation>
<translation id="1053591932240354961">Google Chrome-നൠപàµà´°àµ‹à´¸à´¸àµà´¸àµà´šàµ†à´¯àµà´¯à´¾à´¨à´¾à´•à´¾à´¤àµà´¤ രൂപമാറàµà´±à´‚ വരàµà´¤àµà´¤à´¿à´¯ à´•àµà´°àµ†à´¡àµ»à´·àµà´¯à´²àµà´•àµ¾ വെബàµà´¸àµˆà´±àµà´±àµ അയയàµâ€Œà´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½ നിങàµà´™àµ¾à´•àµà´•à´¿à´ªàµà´ªàµ‹àµ¾ <ph name="SITE" /> സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾à´¨à´¾à´•à´¿à´²àµà´².നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ പിശകàµà´•à´³àµà´‚ ആകàµà´°à´®à´£à´™àµà´™à´³àµà´‚ സാധാരണയായി താൽകàµà´•à´¾à´²à´¿à´• à´ªàµà´°à´¶àµâ€Œà´¨à´™àµà´™àµ¾ ആയതിനാൽ, à´ˆ പേജൠമികàµà´•à´µà´¾à´±àµà´‚ പിനàµà´¨àµ€à´Ÿàµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´‚. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;ചേർകàµà´•àµà´¨àµà´¨à´¤àµ പഴയപടിയാകàµà´•àµà´•</translation>
<translation id="10614374240317010">à´’à´°à´¿à´•àµà´•à´²àµà´‚ സംരകàµà´·à´¿à´šàµà´šà´¿à´²àµà´²</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">മൂലàµà´¯à´‚ മറയàµâ€Œà´•àµà´•àµà´•</translation>
<translation id="1228893227497259893">തെറàµà´±à´¾à´¯ à´Žà´¨àµà´±à´¿à´±àµà´±à´¿ à´à´¡à´¨àµà´±à´¿à´«à´¯àµ¼</translation>
<translation id="1232569758102978740">ശീരàµâ€à´·à´•à´®à´¿à´²àµà´²à´¾à´¤àµà´¤</translation>
+<translation id="1263231323834454256">വായനാ ലിസàµà´±àµà´±àµ</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" />-നൠകàµà´¯à´¾à´ªàµâ€Œà´šàµà´šàµ¼ ചെയàµâ€Œà´¤ à´•àµà´°à´¾à´·àµ റിപàµà´ªàµ‹àµ¼à´Ÿàµà´Ÿàµ (ഇതàµà´µà´°àµ† à´…à´ªàµâ€Œà´²àµ‹à´¡àµà´šàµ†à´¯àµâ€Œà´¤à´¿à´Ÿàµà´Ÿàµ‹ അവഗണിചàµà´šà´¿à´Ÿàµà´Ÿàµ‹ ഇലàµà´²)</translation>
<translation id="1285320974508926690">à´ˆ സൈറàµà´±àµ à´’à´°à´¿à´•àµà´•à´²àµà´‚ വിവരàµâ€â€Œà´¤àµà´¤à´¨à´‚ ചെയàµà´¯à´°àµà´¤àµ</translation>
<translation id="129553762522093515">സമീപകാലതàµà´¤àµ à´…à´Ÿà´šàµà´šà´µ</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromium à´“à´Ÿàµà´Ÿàµ‹à´«à´¿àµ½ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾...</translation>
<translation id="1374468813861204354">നിർദàµà´¦àµ‡à´¶à´™àµà´™àµ¾</translation>
<translation id="1375198122581997741">പതിപàµà´ªà´¿à´¨àµ† à´•àµà´±à´¿à´šàµà´šàµ</translation>
+<translation id="1377321085342047638">കാർഡൠനമàµà´ªàµ¼</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> ഡാറàµà´±à´¯àµŠà´¨àµà´¨àµà´‚ അയചàµà´šà´¿à´Ÿàµà´Ÿà´¿à´²àµà´².</translation>
<translation id="1407135791313364759">à´Žà´²àµà´²à´¾à´‚ à´¤àµà´±à´•àµà´•àµà´•</translation>
<translation id="1413809658975081374">à´¸àµà´µà´•à´¾à´°àµà´¯ പിശകàµ</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">à´šà´°à´¿à´¤àµà´°à´‚</translation>
<translation id="1645368109819982629">à´ªàµà´°àµ‡à´¾à´Ÿàµà´Ÿàµ‡à´¾à´•àµà´•àµ‡à´¾àµ¾ പിനàµà´¤àµà´£à´¯àµâ€Œà´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´²</translation>
<translation id="1656489000284462475">പികàµà´•à´ªàµà´ªàµ</translation>
+<translation id="1663943134801823270">കാർഡàµà´•à´³àµà´‚ വിലാസങàµà´™à´³àµà´‚ Chrome-ൽ നിനàµà´¨àµà´³àµà´³à´¤à´¾à´£àµ. നിങàµà´™àµ¾à´•àµà´•àµ à´…à´µ <ph name="BEGIN_LINK" />à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½<ph name="END_LINK" /> മാനേജàµà´šàµ†à´¯àµà´¯à´¾à´‚.</translation>
<translation id="1676269943528358898">നിങàµà´™à´³àµà´Ÿàµ† വിവരങàµà´™àµ¾ പരിരകàµà´·à´¿à´•àµà´•à´¾àµ» സാധാരണയായി <ph name="SITE" />, എൻകàµà´°à´¿à´ªàµâ€Œà´·àµ» ഉപയോഗികàµà´•àµà´¨àµà´¨àµ. ഇപàµà´ªàµ‹àµ¾ <ph name="SITE" /> സൈറàµà´±à´¿à´²àµ‡à´•àµà´•àµ കണകàµâ€Œà´±àµà´±àµà´šàµ†à´¯àµà´¯à´¾àµ» Google Chrome à´¶àµà´°à´®à´¿à´šàµà´šà´ªàµà´ªàµ‹àµ¾, അസാധാരണമായതàµà´‚ തെറàµà´±à´¾à´¯à´¤àµà´®à´¾à´¯ à´•àµà´°àµ†à´¡àµ»à´·àµà´¯à´²àµà´•àµ¾ വെബàµâ€Œà´¸àµˆà´±àµà´±àµ തിരികെ അയചàµà´šàµ. ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿, <ph name="SITE" /> à´Žà´¨àµà´¨à´¤à´¾à´¯à´¿ ഭാവികàµà´•à´¾àµ» à´¶àµà´°à´®à´¿à´•àµà´•àµà´®àµà´ªàµ‹à´´àµ‹ Wi-Fi സൈൻ ഇൻ à´¸àµâ€Œà´•àµà´°àµ€àµ», കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´®àµà´ªàµ‹à´´àµ‹ ആണൠഇങàµà´™à´¨àµ† സംഭവികàµà´•à´¾à´¨à´¿à´Ÿà´¯àµà´³àµà´³à´¤àµ. à´à´¤àµ†à´™àµà´•à´¿à´²àµà´‚ ഡാറàµà´± കൈമാറàµà´¨àµà´¨à´¤à´¿à´¨àµà´®àµà´®àµà´ªàµ Google Chrome കണകàµà´·àµ» അവസാനിപàµà´ªà´¿à´šàµà´šà´¤à´¿à´¨à´¾àµ½, നിങàµà´™à´³àµà´Ÿàµ† വിവരങàµà´™àµ¾ à´¤àµà´Ÿàµ¼à´¨àµà´¨àµà´‚ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´¯à´¿à´°à´¿à´•àµà´•àµà´‚.</translation>
-<translation id="168328519870909584"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµ† ആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† വിവരങàµà´™àµ¾ (ഉദാഹരണതàµà´¤à´¿à´¨àµ, ഫോടàµà´Ÿàµ‹à´•àµ¾, പാസàµâ€Œà´µàµ‡à´¡àµà´•àµ¾, സനàµà´¦àµ‡à´¶à´™àµà´™àµ¾, à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡàµà´•àµ¾ പോലàµà´³àµà´³à´µ) മോഷàµâ€Œà´Ÿà´¿à´•àµà´•à´¾à´¨àµ‹ ഇലàµà´²à´¾à´¤à´¾à´•àµà´•à´¾à´¨àµ‹ ഉപകരണതàµà´¤à´¿àµ½ അപകടകരമായ ആപàµà´ªàµâ€Œà´¸àµ ഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¯à´¾àµ» à´¶àµà´°à´®à´¿à´šàµà´šàµ‡à´•àµà´•à´¾à´‚.</translation>
+<translation id="168328519870909584"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµ† ആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† വിവരങàµà´™àµ¾ (ഉദാഹരണതàµà´¤à´¿à´¨àµ, ഫോടàµà´Ÿàµ‹à´•àµ¾, പാസàµâ€Œà´µàµ‡à´¡àµà´•àµ¾, സനàµà´¦àµ‡à´¶à´™àµà´™àµ¾, à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡàµà´•àµ¾ പോലàµà´³àµà´³à´µ) മോഷàµâ€Œà´Ÿà´¿à´•àµà´•à´¾à´¨àµ‹ ഇലàµà´²à´¾à´¤à´¾à´•àµà´•à´¾à´¨àµ‹ ഉപകരണതàµà´¤à´¿àµ½ അപകടകരമായ ആപàµà´ªàµà´•àµ¾ ഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¯à´¾àµ» à´¶àµà´°à´®à´¿à´šàµà´šàµ‡à´•àµà´•à´¾à´‚.</translation>
<translation id="168841957122794586">സെർവർ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿àµ½ ഒരൠദàµàµ¼à´¬à´²à´®à´¾à´¯ ഗൂഢഭാഷ കീ ഉൾപàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">à´ˆ സൈറàµà´±àµ സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾àµ» നിങàµà´™àµ¾à´•àµà´•àµ <ph name="NAME" /> à´Žà´¨àµà´¨à´¯à´¾à´³à´¿àµ½ നിനàµà´¨àµà´³àµà´³ à´…à´¨àµà´®à´¤à´¿ ആവശàµà´¯à´®à´¾à´£àµ</translation>
+<translation id="1721424275792716183">* ഫീൽഡൠആവശàµà´¯à´®à´¾à´£àµ</translation>
<translation id="1728677426644403582">നിങàµà´™àµ¾ ഒരൠവെബൠപേജിനàµà´±àµ† ഉറവിടമാണൠകാണàµà´¨àµà´¨à´¤àµ</translation>
+<translation id="173080396488393970">ഇതàµà´¤à´°à´¤àµà´¤à´¿à´²àµà´³àµà´³ കാർഡൠഅനàµà´¯àµ‹à´œàµà´¯à´®à´²àµà´²</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">സിസàµà´±àµà´±à´‚ à´…à´¡àµâ€Œà´®à´¿à´¨àµ† ബനàµà´§à´ªàµà´ªàµ†à´Ÿà´¾àµ» à´¶àµà´°à´®à´¿à´•àµà´•àµà´•.</translation>
+<translation id="1740951997222943430">കാലഹരണപàµà´ªàµ†à´Ÿàµà´¨àµà´¨ ശരിയായ മാസം നലàµâ€à´•àµà´•</translation>
<translation id="1745358365027406341">പേജൠപിനàµà´¨àµ€à´Ÿàµ ഡൗൺലോഡàµà´šàµ†à´¯àµà´¯àµà´•</translation>
<translation id="17513872634828108">à´“à´ªàµà´ªàµº ടാബàµà´•àµ¾</translation>
<translation id="1753706481035618306">പേജൠനമàµà´ªàµ¼</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">നിങàµà´™à´³àµà´Ÿàµ† സമനàµà´µà´¯ പാസàµâ€Œà´«àµà´°àµ‡à´¸àµ ദയവായി à´…à´ªàµâ€Œà´¡àµ‡à´±àµà´±àµ ചെയàµà´¯àµà´•.</translation>
<translation id="1787142507584202372">നിങàµà´™àµ¾ നിലവിൽ à´¤àµà´±à´¨àµà´¨à´¿à´Ÿàµà´Ÿàµà´³àµà´³ ടാബàµà´•àµ¾ ഇവിടെ ദൃശàµà´¯à´®à´¾à´•àµà´‚</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">ഡെലിവറി രീതികളàµà´‚ അതിനാവശàµà´¯à´®à´¾à´¯ കാരàµà´¯à´™àµà´™à´³àµà´‚ പരിശോധികàµà´•à´¾àµ», ഡെലിവർ ചെയàµà´¯à´¾à´¨àµà´³àµà´³ വിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
+<translation id="1803264062614276815">കാർഡൠഉടമയàµà´Ÿàµ† പേരàµ</translation>
<translation id="1803678881841855883"><ph name="SITE" /> à´Žà´¨àµà´¨à´¤à´¿àµ½ Google à´¸àµà´°à´•àµà´·à´¿à´¤ à´¬àµà´°àµ—സിംഗൠഈയിടെ <ph name="BEGIN_LINK" />മാൽവേർ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿<ph name="END_LINK" /> . സാധാരണ നിലയിൽ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´¯ വെബàµà´¸àµˆà´±àµà´±àµà´•à´³à´¿àµ½ ചിലപàµà´ªàµ‹àµ¾ മാൽവേർ ഉണàµà´Ÿà´¾à´¯àµ‡à´•àµà´•à´¾à´‚. അറിയപàµà´ªàµ†à´Ÿàµà´¨àµà´¨ മാൽ‌വേർ വിതരണകàµà´•à´¾à´°à´¾à´¯ <ph name="SUBRESOURCE_HOST" /> à´Žà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨à´¾à´£àµ ദോഷകരമായ ഉളàµà´³à´Ÿà´•àµà´•à´‚ വരàµà´¨àµà´¨à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440"><ph name="ADDED_TO_AUTOFILL_MONTH" />-നൠചേർതàµà´¤àµ</translation>
<translation id="1821930232296380041">à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨ à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨ പാരാമീറàµà´±à´±àµà´•àµ¾ അസാധàµà´µà´¾à´£àµ</translation>
<translation id="1826516787628120939">പരിശോധികàµà´•àµà´¨àµà´¨àµ</translation>
<translation id="1834321415901700177">à´ˆ സൈറàµà´±à´¿àµ½ ദോഷകരമായ à´ªàµà´°àµ‹à´—àµà´°à´¾à´®àµà´•àµ¾ à´…à´Ÿà´™àµà´™à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
<translation id="1842969606798536927">പണമടയàµâ€Œà´•àµà´•àµà´•</translation>
-<translation id="1864455488461349376">ഡെലിവറി à´“à´ªàµâ€Œà´·àµ»</translation>
<translation id="1871208020102129563">à´¸àµà´¥à´¿à´°à´®à´¾à´¯ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ സെർവറàµà´•àµ¾ ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´¯à´¿ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ സജàµà´œàµ€à´•à´°à´¿à´šàµà´šà´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ, ഒരൠ.pac à´¸àµâ€Œà´•àµà´°à´¿à´ªàµà´±àµà´±àµ URL ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´²àµà´².</translation>
<translation id="1871284979644508959">നിർബനàµà´§à´®à´¾à´¯àµà´‚ പൂരിപàµà´ªà´¿à´•àµà´•à´£à´‚</translation>
<translation id="187918866476621466">ആരംഭ പേജàµà´•àµ¾ à´¤àµà´±à´•àµà´•àµà´•</translation>
<translation id="1883255238294161206">ലിസàµà´±àµà´±àµ à´šàµà´°àµà´•àµà´•àµà´•</translation>
<translation id="1898423065542865115">ഫിൽടàµà´Ÿàµ¼ ചെയàµà´¯àµà´¨àµà´¨àµ</translation>
<translation id="194030505837763158"><ph name="LINK" />-ലേകàµà´•àµ പോകàµà´•</translation>
-<translation id="1946821392246652573">കാർഡàµà´•àµ¾ à´¸àµà´µàµ€à´•à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¾à´£àµ</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµà´•àµ¾</translation>
<translation id="1973335181906896915">സീരിയലൈസേഷൻ പിശകàµ</translation>
<translation id="1974060860693918893">നൂതനം</translation>
<translation id="1978555033938440688">ഫേംവെയർ പതിപàµà´ªàµ</translation>
+<translation id="1995859865337580572">നിങàµà´™à´³àµà´Ÿàµ† CVC പരിശോധിചàµà´šàµà´±à´ªàµà´ªà´¿à´•àµà´•àµà´•</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{കൂടാതെ 1 കൂടി}other{à´Žà´¨àµà´¨à´¿à´µà´¯àµà´‚ # à´Žà´£àµà´£à´µàµà´‚ കൂടി}}</translation>
-<translation id="2020194265157481222">കാർഡിലെ പേരൠആവശàµà´¯à´®à´¾à´£àµ</translation>
<translation id="2025186561304664664">à´ªàµà´°àµ‹à´•àµà´¸à´¿ à´¸àµà´µà´¯à´®àµ‡à´µ കോൺഫിഗർ ചെയàµà´¯à´¾àµ» സജàµà´œà´®à´¾à´•àµà´•à´¿.</translation>
<translation id="2030481566774242610">നിങàµà´™àµ¾ ഉദàµà´¦àµ‡à´¶à´¿à´šàµà´šà´¤àµ <ph name="LINK" /> ആണോ?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿à´¯àµà´‚ ഫയർവാളàµà´‚ പരിശോധികàµà´•àµà´¨àµà´¨àµ<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">ഇനàµà´¨àµ</translation>
<translation id="2154054054215849342">നിങàµà´™à´³àµà´Ÿàµ† ഡൊമെയàµâ€Œà´¨à´¿à´¨àµ വേണàµà´Ÿà´¿ സമനàµà´µà´¯à´‚ ലഭàµà´¯à´®à´²àµà´²</translation>
<translation id="2154484045852737596">കാർഡൠഎഡിറàµà´±àµà´šàµ†à´¯àµà´¯àµà´•</translation>
-<translation id="2156993118928861787">വിലാസം തെറàµà´±à´¾à´£àµ</translation>
<translation id="2166049586286450108">പൂർണàµà´£à´®à´¾à´¯ à´…à´¡àµâ€Œà´®à´¿àµ» ആകàµâ€Œà´¸à´¸àµà´¸àµ</translation>
<translation id="2166378884831602661">à´ˆ സൈറàµà´±à´¿à´¨àµ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´¯ കണകàµà´·àµ» നൽകാനാകിലàµà´²</translation>
<translation id="2181821976797666341">നയങàµà´™àµ¾</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{ഒരൠവിലാസം}other{# വിലാസങàµà´™àµ¾}}</translation>
+<translation id="2202020181578195191">കാലഹരണപàµà´ªàµ†à´Ÿàµà´¨àµà´¨ ശരിയായ വർഷം നലàµâ€à´•àµà´•</translation>
<translation id="2212735316055980242">നയം à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´²àµà´²</translation>
<translation id="2213606439339815911">എൻടàµà´°à´¿à´•àµ¾ ലഭàµà´¯à´®à´¾à´•àµà´•àµà´¨àµà´¨àµ...</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />ഡയഗണോസàµâ€Œà´±àµà´±à´¿à´•àµâ€Œà´¸àµ ആപàµà´ªàµ<ph name="END_LINK" /> ഉപയോഗിചàµà´šàµ കണകഷൻ à´ªàµà´°à´¶àµâ€Œà´¨à´‚ പരിഹരികàµà´•àµà´•</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">നിങàµà´™à´³àµà´Ÿàµ† ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ ആകàµâ€Œà´¸à´¸àµà´¸àµ à´¬àµà´²àµ‹à´•àµà´•àµà´šàµ†à´¯àµâ€Œà´¤àµ</translation>
<translation id="230155334948463882">à´ªàµà´¤à´¿à´¯ കാർഡാണോ?</translation>
<translation id="2305919008529760154">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> ഡൊമെയàµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ à´µàµà´¯à´¾à´œà´®à´¾à´¯à´¿ നൽകിയതായിരികàµà´•à´¾à´‚. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിചàµà´šà´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">കാർഡàµà´‚ വിലാസ à´“à´ªàµâ€Œà´·à´¨àµà´•à´³àµà´‚ നിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿àµ½ നിനàµà´¨àµà´‚ (<ph name="ACCOUNT_EMAIL" />) Chrome-ൽ നിനàµà´¨àµà´®àµà´³àµà´³à´¤à´¾à´£àµ. നിങàµà´™àµ¾à´•àµà´•àµ ഇവ <ph name="BEGIN_LINK" />à´•àµà´°à´®àµ€à´•à´£à´¤àµà´¤à´¿àµ½<ph name="END_LINK" /> മാനേജàµà´šàµ†à´¯àµà´¯à´¾à´‚.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> ഡൊമെയàµâ€Œà´¨àµ ഒരൠഉപയോകàµà´¤àµƒà´¨à´¾à´®à´µàµà´‚ പാസàµâ€Œà´µàµ‡à´¡àµà´‚ വേണം.</translation>
<translation id="2318774815570432836">വെബàµà´¸àµˆà´±àµà´±àµ HSTS ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½ നിങàµà´™àµ¾à´•àµà´•àµ ഇപàµà´ªàµ‹àµ¾ <ph name="SITE" /> സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾à´¨à´¾à´•à´¿à´²àµà´². നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ പിശകàµà´•à´³àµà´‚ ആകàµà´°à´®à´£à´™àµà´™à´³àµà´‚ സാധാരണയായി താൽകàµà´•à´¾à´²à´¿à´• à´ªàµà´°à´¶àµâ€Œà´¨à´™àµà´™à´³à´¾à´¯à´¤à´¿à´¨à´¾àµ½ à´ˆ പേജൠമികàµà´•à´µà´¾à´±àµà´‚ പിനàµà´¨àµ€à´Ÿàµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´‚. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">മറàµà´±àµ à´¬àµà´•àµâ€Œà´®à´¾à´°àµâ€à´•àµà´•àµà´•à´³àµâ€</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">à´Žà´¨àµà´±à´°àµâ€à´ªàµà´°àµˆà´¸àµ ഡിഫോൾടàµà´Ÿàµ</translation>
<translation id="2386255080630008482">സെരàµâ€à´µà´±à´¿à´¨àµâ€à´±àµ† സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ അസാധàµà´µà´¾à´•àµà´•à´¿.</translation>
<translation id="2392959068659972793">മൂലàµà´¯à´®àµŠà´¨àµà´¨àµà´‚ സജàµà´œà´®à´¾à´•àµà´•à´¾à´¤àµà´¤ നയങàµà´™àµ¾ കാണികàµà´•àµà´•</translation>
+<translation id="239429038616798445">à´ˆ à´·à´¿à´ªàµà´ªà´¿à´‚ഗൠരീതി ലഭàµà´¯à´®à´²àµà´². മറàµà´±àµŠà´°àµ രീതി പരീകàµà´·à´¿à´•àµà´•àµà´•.</translation>
<translation id="2396249848217231973">&amp;ഇലàµà´²à´¾à´¤à´¾à´•àµà´•àµ½ പഴയപടിയാകàµà´•àµà´•</translation>
<translation id="2460160116472764928"><ph name="SITE" /> à´Žà´¨àµà´¨à´¤à´¿àµ½ Google à´¸àµà´°à´•àµà´·à´¿à´¤ à´¬àµà´°àµ—സിംഗൠഈയിടെ <ph name="BEGIN_LINK" />മാൽവേർ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿<ph name="END_LINK" />. സാധാരണ നിലയിൽ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´¯ വെബàµà´¸àµˆà´±àµà´±àµà´•à´³à´¿àµ½ ചിലപàµà´ªàµ‹àµ¾ മാൽവേർ ഉണàµà´Ÿà´¾à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">പൂരിപàµà´ªà´¿à´•àµà´•àµà´•</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ ഡയഗണോസàµâ€Œà´±àµà´±à´¿à´•àµâ€Œà´¸àµ റൺ ചെയàµà´¯àµà´¨àµà´¨àµ<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">തിരയൽ URL അസാധàµà´µà´¾à´£àµ.</translation>
<translation id="2491120439723279231">സെരàµâ€à´µà´±à´¿à´¨àµâ€à´±àµ† സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´²àµâ€ പിശകàµà´•à´³àµâ€ à´…à´Ÿà´™àµà´™à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
-<translation id="24943777258388405">ഫോണàµâ€ നമàµà´ªà´°àµâ€ അസാധàµà´µà´¾à´£àµ</translation>
<translation id="2495083838625180221">JSON പാഴàµâ€Œà´¸àµ¼</translation>
<translation id="2495093607237746763">പരിശോധിചàµà´šàµ†à´™àµà´•à´¿àµ½, വേഗതàµà´¤à´¿àµ½ ഫോം പൂരിപàµà´ªà´¿à´•àµà´•à´¾àµ» Chromium à´ˆ ഉപകരണതàµà´¤à´¿àµ½ നിങàµà´™à´³àµà´Ÿàµ† കാർഡിനàµà´±àµ† ഒരൠപകർപàµà´ªàµ സൂകàµà´·à´¿à´•àµà´•àµà´‚.</translation>
<translation id="2498091847651709837">à´ªàµà´¤à´¿à´¯ കാർഡൠസàµâ€Œà´•à´¾àµ» ചെയàµà´¯àµà´•</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" />, അസാധàµà´µà´¾à´¯ ഒരൠപàµà´°à´¤à´¿à´•à´°à´£à´‚ അയചàµà´šàµ.</translation>
<translation id="2552545117464357659">à´à´±àµà´±à´µàµà´‚ à´ªàµà´¤à´¿à´¯</translation>
<translation id="2556876185419854533">&amp;à´Žà´¡à´¿à´±àµà´±àµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨à´¤àµ പഴയപടിയാകàµà´•àµà´•</translation>
+<translation id="2587730715158995865"><ph name="ARTICLE_PUBLISHER" /> à´Žà´¨àµà´¨à´¯à´¾à´³àµà´Ÿàµ† ലേഖനം. ഇതàµà´‚ മറàµà´±àµ <ph name="OTHER_ARTICLE_COUNT" /> ലേഖനങàµà´™à´³àµà´‚ വായികàµà´•àµà´•.</translation>
<translation id="2587841377698384444">ഡയറകàµâ€Œà´Ÿà´±à´¿ API à´à´¡à´¿:</translation>
<translation id="2597378329261239068">à´ˆ à´ªàµà´°à´®à´¾à´£à´‚ പാസàµâ€Œà´µàµ‡à´¡àµ പരിരകàµà´·à´¿à´¤à´®à´¾à´£àµ. ദയവായി ഒരൠപാസàµâ€Œà´µàµ‡à´¡àµ നലàµâ€â€Œà´•àµà´•.</translation>
<translation id="2609632851001447353">വേരിയേഷനàµà´•àµ¾</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />കണകàµâ€Œà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿ ഡയഗണോസàµâ€Œà´±àµà´±à´¿à´•àµâ€Œà´¸àµ റൺ ചെയàµà´¯àµà´¨àµà´¨àµ<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">ശരി</translation>
<translation id="2742870351467570537">തിരഞàµà´žàµ†à´Ÿàµà´¤àµà´¤ ഇനങàµà´™à´³àµâ€â€Œ നീകàµà´•à´‚ചെയàµà´¯àµà´• </translation>
+<translation id="277133753123645258">à´·à´¿à´ªàµà´ªà´¿à´‚ഗൠരീതി</translation>
<translation id="277499241957683684">ഉപകരണ റെകàµà´•àµ‹àµ¼à´¡àµ കാണàµà´¨àµà´¨à´¿à´²àµà´²</translation>
<translation id="2784949926578158345">കണകàµà´·à´¨àµâ€ à´ªàµà´¨à´ƒà´¸à´œàµà´œà´®à´¾à´•àµà´•à´¿à´¯à´¤à´¾à´£àµ.</translation>
<translation id="2794233252405721443">സൈറàµà´±àµ à´¬àµà´²àµ‹à´•àµà´•àµà´šàµ†à´¯àµâ€Œà´¤àµ</translation>
-<translation id="2812680587231492111">à´† പികàµà´•à´ªàµà´ªàµ à´“à´ªàµâ€Œà´·àµ» ലഭàµà´¯à´®à´²àµà´². മറàµà´±àµŠà´°àµ à´“à´ªàµâ€Œà´·àµ» പരീകàµà´·à´¿à´•àµà´•àµ‚.</translation>
<translation id="2824775600643448204">വിലാസവàµà´‚ തിരയൽ ബാറàµà´‚</translation>
<translation id="2826760142808435982"><ph name="CIPHER" /> ഉപയോഗിചàµà´šàµ കണകàµà´·àµ» എൻകàµà´°à´¿à´ªàµâ€Œà´±àµà´±àµà´šàµ†à´¯àµâ€Œà´¤àµ à´ªàµà´°à´¾à´®à´¾à´£àµ€à´•à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ, à´’à´ªàµà´ªà´‚ à´ªàµà´°à´§à´¾à´¨ à´Žà´•àµâ€Œà´¸àµ‡à´žàµà´šàµ മെകàµà´•à´¾à´¨à´¿à´¸à´®à´¾à´¯à´¿ <ph name="KX" /> ഉപയോഗികàµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="2835170189407361413">ഫോം മായàµâ€Œà´•àµà´•àµà´•</translation>
-<translation id="2849041323157393173">à´† ഡെലിവറി à´“à´ªàµâ€Œà´·àµ» ലഭàµà´¯à´®à´²àµà´². മറàµà´±àµŠà´°àµ à´“à´ªàµâ€Œà´·àµ» പരീകàµà´·à´¿à´•àµà´•àµ‚.</translation>
<translation id="2889159643044928134">റീലോഡàµà´šàµ†à´¯àµà´¯à´°àµà´¤àµ</translation>
<translation id="2900469785430194048">à´ˆ വെബàµâ€Œà´ªàµ‡à´œàµ à´ªàµà´°à´¦àµ¼à´¶à´¿à´ªàµà´ªà´¿à´•àµà´•à´¾àµ» à´¶àµà´°à´®à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¿à´Ÿà´¯à´¿àµ½ Google Chrome-à´¨àµà´±àµ† മെമàµà´®à´±à´¿ നിറഞàµà´žàµ.</translation>
<translation id="2909946352844186028">ഒരൠനെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ മാറàµà´±à´‚ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿.</translation>
<translation id="2916038427272391327">മറàµà´±àµ à´ªàµà´°àµ‹à´—àµà´°à´¾à´®àµà´•àµ¾ à´…à´Ÿà´¯àµâ€Œà´•àµà´•àµà´•</translation>
<translation id="2922350208395188000">സെരàµâ€à´µà´±à´¿à´¨àµâ€à´±àµ† സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ പരിശോധികàµà´•à´¾à´¨àµâ€ കഴിയിലàµà´².</translation>
+<translation id="2928905813689894207">ബിലàµà´²à´¿à´‚ഗൠവിലാസം</translation>
<translation id="2948083400971632585">കണകàµà´·à´¨à´¾à´¯à´¿ കോൺഫിഗർ ചെയàµâ€Œà´¤ à´à´¤àµŠà´°àµ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿à´•à´³àµà´‚ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾ പേജിൽ നിനàµà´¨àµ നിങàµà´™àµ¾à´•àµà´•àµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´°à´¹à´¿à´¤à´®à´¾à´•àµà´•à´¾à´¨à´¾à´•àµà´‚.</translation>
<translation id="2955913368246107853">ഫൈനàµâ€à´¡àµ ബാരàµâ€ à´…à´Ÿà´¯àµà´•àµà´•àµà´•</translation>
<translation id="2958431318199492670">നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ കോൺഫിഗറേഷൻ ONC à´¸àµà´±àµà´±à´¾àµ»à´¡àµ‡àµ¼à´¡à´¿à´¨àµ à´…à´¨àµà´¸àµƒà´¤à´®à´¾à´¯à´¿ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´². കോൺഫിഗറേഷൻ ഭാഗങàµà´™àµ¾ ഇമàµà´ªàµ‹àµ¼à´Ÿàµà´Ÿàµà´šàµ†à´¯àµâ€Œà´¤àµ‡à´•àµà´•à´¿à´²àµà´².</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">ഒരൠസàµà´°à´•àµà´·à´¿à´¤ കണകàµà´·àµ» à´¸àµà´¥à´¾à´ªà´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ, നിങàµà´™à´³àµà´Ÿàµ† à´•àµà´²àµ‹à´•àµà´•àµ ശരിയായി സജàµà´œàµ€à´•à´°à´¿à´•àµà´•àµ‡à´£àµà´Ÿà´¤àµà´£àµà´Ÿàµ. വെബàµâ€Œà´¸àµˆà´±àµà´±àµà´•àµ¾ à´¸àµà´µà´¯à´‚ തിരിചàµà´šà´±à´¿à´¯àµà´¨àµà´¨à´¤à´¿à´¨àµ ഉപയോഗികàµà´•àµà´¨àµà´¨ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµà´•àµ¾, നിർദàµà´¦à´¿à´·àµâ€Œà´Ÿ സമയ പരിധിയിൽ മാതàµà´°à´‚ സാധàµà´¤à´¯àµà´³àµà´³à´¤à´¿à´¨à´¾à´²à´¾à´£à´¿à´¤àµ. നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿à´¨àµà´±àµ† à´•àµà´²àµ‹à´•àµà´•àµ തെറàµà´±à´¾à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½, Google Chrome-നൠഈ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµà´•àµ¾ പരിശോധിചàµà´šàµà´±à´ªàµà´ªà´¿à´•àµà´•à´¾à´¨à´¾à´µà´¿à´²àµà´².</translation>
<translation id="2972581237482394796">&amp;വീണàµà´Ÿàµà´‚ ചെയàµà´¯àµà´•</translation>
<translation id="2985306909656435243">à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´•àµà´·à´®à´®à´¾à´•àµà´•à´¿à´¯àµ†à´™àµà´•à´¿àµ½, വേഗതàµà´¤à´¿àµ½ ഫോം പൂരിപàµà´ªà´¿à´•àµà´•à´¾àµ» Chromium à´ˆ ഉപകരണതàµà´¤à´¿àµ½ നിങàµà´™à´³àµà´Ÿàµ† കാർഡിനàµà´±àµ† ഒരൠപകർപàµà´ªàµ സൂകàµà´·à´¿à´•àµà´•àµà´‚.</translation>
+<translation id="2985398929374701810">ശരിയായ വിലാസം നലàµâ€à´•àµà´•</translation>
+<translation id="2986368408720340940">à´ˆ പികàµà´•à´ªàµà´ªàµ രീതി ലഭàµà´¯à´®à´²àµà´². മറàµà´±àµŠà´°àµ രീതി പരീകàµà´·à´¿à´•àµà´•àµà´•.</translation>
<translation id="2991174974383378012">വെബàµâ€Œà´¸àµˆà´±àµà´±àµà´•à´³àµà´®à´¾à´¯à´¿ പങàµà´•à´¿à´Ÿàµà´¨àµà´¨àµ</translation>
<translation id="3005723025932146533">സംരകàµà´·à´¿à´šàµà´š പകർപàµà´ªàµ കാണികàµà´•àµà´•</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" />-à´¨àµà´±àµ† CVC നൽകàµà´•. à´¸àµà´¥à´¿à´°àµ€à´•à´°à´¿à´šàµà´šàµ à´•à´´à´¿à´žàµà´žà´¾àµ½, നിങàµà´™à´³àµà´Ÿàµ† കാർഡൠവിശദാംശങàµà´™àµ¾ à´ˆ സൈറàµà´±àµà´®à´¾à´¯à´¿ പങàµà´•à´¿à´Ÿàµà´‚.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´šàµà´š ഉപകരണങàµà´™à´³à´¿àµ½ ഒരൠഇനമെങàµà´•à´¿à´²àµà´‚}=1{ഒരൠഇനം (à´’à´ªàµà´ªà´‚ സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´šàµà´š ഉപകരണങàµà´™à´³à´¿àµ½ അതിൽ കൂടàµà´¤à´²àµà´‚)}other{# ഇനങàµà´™àµ¾ (à´’à´ªàµà´ªà´‚ സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´šàµà´š ഉപകരണങàµà´™à´³à´¿àµ½ അതിൽ കൂടàµà´¤à´²àµà´‚)}}</translation>
<translation id="3041612393474885105">സരàµâ€â€Œà´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ വിവരങàµà´™à´³àµâ€â€Œ</translation>
<translation id="3063697135517575841">Chrome-നൠഇപàµà´ªàµ‹àµ¾ നിങàµà´™à´³àµà´Ÿàµ† കാർഡൠസàµà´¥à´¿à´°àµ€à´•à´°à´¿à´•àµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´². പിനàµà´¨àµ€à´Ÿàµ വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•.</translation>
+<translation id="3064966200440839136">ഒരൠഎകàµâ€Œà´¸àµâ€Œà´±àµà´±àµ‡à´£àµ½ à´…à´ªàµà´²à´¿à´•àµà´•àµ‡à´·àµ» വഴി പണമടയàµâ€Œà´•àµà´•à´¾àµ» അദൃശàµà´¯à´¤à´¾ സംവിധാനം ഒഴിവാകàµà´•àµà´¨àµà´¨àµ. à´¤àµà´Ÿà´°à´£àµ‹?</translation>
<translation id="3093245981617870298">നിങàµà´™àµ¾ à´“à´«àµâ€Œà´²àµˆà´¨à´¿à´²à´¾à´£àµ.</translation>
<translation id="3105172416063519923">അസറàµà´±àµ à´à´¡à´¿:</translation>
<translation id="3109728660330352905">നിങàµà´™àµ¾à´•àµà´•àµ à´ˆ പേജൠകാണാനàµà´³àµà´³ അംഗീകാരമിലàµà´².</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />കണകàµâ€Œà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿ ഡയഗണോസàµâ€Œà´±àµà´±à´¿à´•àµâ€Œà´¸àµ റൺ ചെയàµâ€Œà´¤àµà´¨àµ‹à´•àµà´•àµ‚<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">à´ªàµà´°à´¤à´¿à´•à´°à´£à´‚ ഡീകോഡൠചെയàµà´¯àµà´¨àµà´¨à´¤àµ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
-<translation id="3149891296864842641">à´·à´¿à´ªàµà´ªà´¿à´‚ഗൠഓപàµâ€Œà´·àµ»</translation>
<translation id="3150653042067488994">താൽകàµà´•à´¾à´²à´¿à´•à´®à´¾à´¯ സെർവർ പിശകàµ</translation>
+<translation id="3154506275960390542">à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´¯à´¿ സമർപàµà´ªà´¿à´•àµà´•à´¾àµ» സാധികàµà´•à´¾à´¤àµà´¤ ഒരൠഫോം à´ˆ പേജിൽ ഉ‌ണàµà´Ÿàµ. അയയàµà´•àµà´•àµà´¨àµà´¨ സമയതàµà´¤àµ നിങàµà´™à´³àµà´Ÿàµ† ഡാറàµà´± മറàµà´±àµà´³àµà´³à´µà´°àµâ€â€Œà´•àµà´•àµ കാണാനാകàµà´‚, à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ സെർവറിലേകàµà´•àµ à´Žà´¤àµà´¤àµà´‚ ‌മàµà´®àµà´ªàµ ‌ഒരൠഅകàµà´°à´®à´¿à´•àµà´•àµ പരിഷàµâ€Œà´•àµà´•à´°à´¿à´•àµà´•à´¾àµ» à´•à´´à´¿à´¯àµà´‚.</translation>
<translation id="3157931365184549694">à´ªàµà´¨à´ƒà´¸àµà´¥à´¾à´ªà´¿à´•àµà´•àµà´•</translation>
<translation id="3167968892399408617">ആൾമാറാടàµà´Ÿ ടാബàµà´•à´³à´¿àµ½ നിങàµà´™àµ¾ കാണàµà´¨àµà´¨ പേജàµà´•àµ¾, ആൾമാറാടàµà´Ÿ ടാബàµà´•àµ¾ à´Žà´²àµà´²à´¾à´‚ à´…à´Ÿà´šàµà´šà´¤à´¿à´¨àµà´¶àµ‡à´·à´‚ à´¬àµà´°àµ—സർ à´šà´°à´¿à´¤àµà´°à´¤àµà´¤à´¿à´²àµ‹ à´•àµà´•àµà´•à´¿ à´¸àµà´±àµà´±àµ‹à´±à´¿à´²àµ‹ തിരയൽ à´šà´°à´¿à´¤àµà´°à´¤àµà´¤à´¿à´²àµ‹ ഉണàµà´Ÿà´¾à´•à´¿à´²àµà´². നിങàµà´™àµ¾ ഡൗൺലോഡàµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨ ഫയലàµà´•à´³àµ‹ സൃഷàµâ€Œà´Ÿà´¿à´•àµà´•àµà´¨àµà´¨ à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµà´•à´³àµ‹ à´Žà´²àµà´²à´¾à´‚ സൂകàµà´·à´¿à´•àµà´•àµà´‚.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -262,11 +270,13 @@
<translation id="3345135638360864351">à´ˆ സൈറàµà´±àµ ആകàµâ€Œà´¸à´¸àµà´¸àµ ചെയàµà´¯à´¾à´¨àµà´³àµà´³ നിങàµà´™à´³àµà´Ÿàµ† à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨, <ph name="NAME" /> à´Žà´¨àµà´¨à´¯à´¾àµ¾à´•àµà´•àµ അയയàµâ€Œà´•àµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´². വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•.</translation>
<translation id="3355823806454867987">à´ªàµà´°àµ‹à´•àµà´¸à´¿ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™à´³àµâ€ മാറàµà´±àµà´•...</translation>
<translation id="3369192424181595722">à´•àµà´²àµ‹à´•àµà´•à´¿à´²àµ† പിശകàµ</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> ഇനങàµà´™àµ¾ കൂടി...</translation>
<translation id="337363190475750230">à´¡à´¿à´ªàµà´°àµŠà´µà´¿à´·àµ» ചെയàµâ€Œà´¤àµ</translation>
<translation id="3377188786107721145">നയം പാഴàµâ€Œà´¸àµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨à´¤à´¿àµ½ പിശകàµ</translation>
<translation id="3380365263193509176">à´…à´œàµà´žà´¾à´¤à´®à´¾à´¯ പിശകàµ</translation>
<translation id="3380864720620200369">à´•àµà´²à´¯à´¨àµà´±àµ ID:</translation>
<translation id="3391030046425686457">ഡെലിവർ ചെയàµà´¯àµ‡à´£àµà´Ÿ വിലാസം</translation>
+<translation id="3395827396354264108">പികàµà´•à´ªàµà´ªàµ രീതി</translation>
<translation id="340013220407300675">ആകàµà´°à´®à´£à´•à´¾à´°à´¿à´•àµ¾ നിങàµà´™à´³àµà´Ÿàµ† വിവരം <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> à´Žà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµ മോഷàµâ€Œà´Ÿà´¿à´•àµà´•à´¾àµ» à´¶àµà´°à´®à´¿à´•àµà´•à´¾à´‚ (ഉദാഹരണതàµà´¤à´¿à´¨àµ, പാസàµâ€Œà´µàµ‡à´¡àµà´•àµ¾, സനàµà´¦àµ‡à´¶à´™àµà´™àµ¾, à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡàµà´•àµ¾).</translation>
<translation id="3422248202833853650">ഇടം സൃഷàµâ€Œà´Ÿà´¿à´•àµà´•à´¾àµ» മറàµà´±àµ à´ªàµà´°àµ‹à´—àµà´°à´¾à´®àµà´•à´³à´¿àµ½ നിനàµà´¨àµ à´ªàµà´±à´¤àµà´¤àµà´•à´Ÿà´•àµà´•àµà´¨àµà´¨à´¤àµ പരീകàµà´·à´¿à´•àµà´•àµ‚.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> നിലവിൽ ലഭàµà´¯à´®à´²àµà´².</translation>
@@ -277,12 +287,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">ഇടവേള ലഭàµà´¯à´®à´¾à´•àµà´•àµà´•:</translation>
<translation id="3462200631372590220">വിപàµà´²à´®à´¾à´¯à´µ മറയàµà´•àµà´•àµà´•</translation>
+<translation id="3467763166455606212">കാർഡൠഉടമയàµà´Ÿàµ† പേരൠആവശàµà´¯à´®à´¾à´£àµ</translation>
+<translation id="3478058380795961209">കാലഹരണപàµà´ªàµ†à´Ÿàµà´¨àµà´¨ മാസം</translation>
<translation id="3479539252931486093">ഇതൠഅപàµà´°à´¤àµ€à´•àµà´·à´¿à´¤à´®à´¾à´¯à´¿à´°àµà´¨àµà´¨àµ‹? <ph name="BEGIN_LINK" />à´žà´™àµà´™à´³àµ† അറിയികàµà´•àµà´•<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">ഇപàµà´ªàµ‹à´´à´²àµà´²</translation>
<translation id="348000606199325318">à´•àµà´°à´¾à´·àµ à´à´¡à´¿, <ph name="CRASH_LOCAL_ID" /> (സെർവർ à´à´¡à´¿: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">ഇപàµà´ªàµ‹àµ¾ à´žà´™àµà´™àµ¾à´•àµà´•àµ നിങàµà´™à´³àµà´Ÿàµ† à´°à´•àµà´·à´•àµ¼à´¤àµà´¤à´¾à´µà´¿à´¨àµ† ബനàµà´§à´ªàµà´ªàµ†à´Ÿà´¾à´¨à´¾à´¯à´¿à´²àµà´². വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•.</translation>
<translation id="3528171143076753409">സെരàµâ€à´µà´±à´¿à´¨àµâ€à´±àµ† സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ വിശàµà´µà´¾à´¸à´¯àµ‹à´—àµà´¯à´®à´²àµà´².</translation>
-<translation id="3538531656504267329">കാലഹരണപàµà´ªàµ†à´Ÿàµà´¨àµà´¨ വർഷം തെറàµà´±à´¾à´£àµ</translation>
<translation id="3539171420378717834">à´ˆ ഉപകരണതàµà´¤à´¿àµ½ à´ˆ കാർഡിനàµà´±àµ† ഒരൠപകർപàµà´ªàµ സൂകàµà´·à´¿à´•àµà´•àµà´•</translation>
<translation id="3542684924769048008">ഇതിനായി പാസàµâ€Œà´µàµ‡à´¡àµ ഉപയോഗികàµà´•àµà´•:</translation>
<translation id="3549644494707163724">നിങàµà´™à´³àµà´Ÿàµ† à´¸àµà´µà´¨àµà´¤à´‚ പാസàµâ€Œà´«àµà´°àµ†à´¯àµâ€Œà´¸àµ ഉപയോഗിചàµà´šàµ à´Žà´²àµà´²à´¾ സമനàµà´µà´¿à´¤ ഡാറàµà´±à´¯àµà´‚ എൻകàµà´°à´¿à´ªàµà´±àµà´±àµà´šàµ†à´¯àµà´¯àµà´•</translation>
@@ -295,6 +306,7 @@
<translation id="3586931643579894722">വിശദാംശങàµà´™àµ¾ മറയàµâ€Œà´•àµà´•àµà´•â€â€Œ</translation>
<translation id="3587482841069643663">à´Žà´²àµà´²à´¾à´‚</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">കാലഹരണപàµà´ªàµ†à´Ÿàµà´¨àµà´¨ ശരിയായ തീയതി നലàµâ€à´•àµà´•</translation>
<translation id="36224234498066874">à´¬àµà´°àµŒà´¸à´¿à´‚ഗൠഡാറàµà´± മായàµâ€Œà´•àµà´•àµà´•...</translation>
<translation id="362276910939193118">à´®àµà´´àµà´µà´¨àµâ€ à´šà´°à´¿à´¤àµà´°à´µàµà´‚ കാണികàµà´•àµà´•</translation>
<translation id="3623476034248543066">മൂലàµà´¯à´‚ കാണികàµà´•àµà´•</translation>
@@ -311,7 +323,6 @@
<translation id="3693415264595406141">പാസàµâ€Œà´µàµ‡à´¡àµ:</translation>
<translation id="3696411085566228381">à´’à´¨àµà´¨àµà´®à´¿à´²àµà´²</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">à´·à´¿à´ªàµà´ªà´¿à´‚ഗൠരീതികളàµà´‚ അതിനാവശàµà´¯à´®à´¾à´¯ കാരàµà´¯à´™àµà´™à´³àµà´‚ പരിശോധികàµà´•à´¾àµ» ഒരൠഷിപàµà´ªà´¿à´‚ഗൠവിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
<translation id="370665806235115550">ലോഡàµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨àµ...</translation>
<translation id="3712624925041724820">ലൈസൻസàµà´•àµ¾ കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
<translation id="3714780639079136834">മൊബൈൽ ഡാറàµà´± à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ Wi-Fi ഓണാകàµà´•àµà´¨àµà´¨àµ</translation>
@@ -320,6 +331,7 @@
<translation id="3739623965217189342">നിങàµà´™àµ¾ പകർതàµà´¤à´¿à´¯ ലിങàµà´•àµ</translation>
<translation id="375403751935624634">ഒരൠസെരàµâ€à´µà´°àµâ€ പിശകൠകാരണം വിവരàµâ€â€Œà´¤àµà´¤à´¨à´‚ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ.</translation>
<translation id="3759461132968374835">നിങàµà´™à´³àµâ€à´•àµà´•àµ സമീപകാലതàµà´¤àµ റിപàµà´ªàµ‹à´°àµâ€à´Ÿàµà´Ÿàµà´šàµ†à´¯àµà´¤ à´•àµà´°à´¾à´·àµà´•à´³àµŠà´¨àµà´¨àµà´®à´¿à´²àµà´². à´•àµà´°à´¾à´·àµ റിപàµà´ªàµ‹à´°àµâ€à´Ÿàµà´Ÿàµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨ സമയതàµà´¤àµ സംഭവിചàµà´š à´•àµà´°à´¾à´·àµà´•à´³àµ† à´…à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•à´¿, ഇവിടെ ദൃശàµà´¯à´®à´¾à´•à´¿à´²àµà´².</translation>
+<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" />-ൽ അവസാനികàµà´•àµà´¨àµà´¨àµ</translation>
<translation id="382518646247711829">നിങàµà´™àµ¾ ഒരൠപàµà´°àµ‹à´•àµâ€Œà´¸à´¿ സെർവർ ഉപയോഗികàµà´•àµà´¨àµà´¨àµ†à´™àµà´•à´¿àµ½...</translation>
<translation id="3828924085048779000">ശൂനàµà´¯ പാസàµà´«àµà´°àµ†à´¯àµà´¸àµ à´…à´¨àµà´µà´¦à´¨àµ€à´¯à´®à´²àµà´².</translation>
<translation id="3845539888601087042">നിങàµà´™àµ¾ സൈൻ ഇൻ ചെയàµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨ ഉപകരണങàµà´™à´³à´¿àµ½ നിനàµà´¨àµà´³àµà´³ à´šà´°à´¿à´¤àµà´°à´‚ കാണികàµà´•àµà´¨àµà´¨àµ. <ph name="BEGIN_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LINK" />.</translation>
@@ -355,7 +367,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chromium à´ˆ കാർഡൠസംരകàµà´·à´¿à´•àµà´•à´£àµ‹?</translation>
<translation id="4171400957073367226">മോശം പരിശോധിചàµà´šàµà´±à´ªàµà´ªà´¿à´•àµà´•àµ½ സിഗàµâ€Œà´¨àµ‡à´šàµà´šàµ¼</translation>
-<translation id="4176463684765177261">à´…à´ªàµà´°à´¾à´ªàµâ€Œà´¤à´®à´¾à´•àµà´•à´¿</translation>
<translation id="4196861286325780578">&amp;നീകàµà´•àµà´¨àµà´¨à´¤àµ വീണàµà´Ÿàµà´‚ ചെയàµà´¯àµà´•</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ഫയർവാളàµà´‚ ആനàµà´±à´¿à´µàµˆà´±à´¸àµ കോൺഫിഗറേഷനàµà´•à´³àµà´‚ പരിശോധികàµà´•àµà´¨àµà´¨àµ<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{à´’à´¨àµà´¨àµà´®à´¿à´²àµà´²}=1{ഒരൠആപàµà´ªàµ ($1)}=2{2 ആപàµâ€Œà´¸àµ ($1, $2)}other{# ആപàµâ€Œà´¸àµ ($1, $2, $3)}}</translation>
@@ -382,11 +393,11 @@
<translation id="4406896451731180161">തിരയൽ ഫലങàµà´™àµ¾</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" />, നിങàµà´™à´³àµà´Ÿàµ† ലോഗിൻ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ അംഗീകരിചàµà´šà´¿à´Ÿàµà´Ÿà´¿à´²àµà´², à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ à´…à´™àµà´™à´¨àµ†à´¯àµŠà´°àµ†à´£àµà´£à´‚ നൽകിയിടàµà´Ÿà´¿à´²àµà´²à´¾à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚.</translation>
<translation id="443673843213245140">à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ ഉപയോഗം à´…à´ªàµà´°à´¾à´ªàµâ€Œà´¤à´®à´¾à´•àµà´•à´¿ പകàµà´·àµ† ഒരൠവàµà´¯à´•àµà´¤à´®à´¾à´¯ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ കോൺഫിഗറേഷൻ നിർദàµà´¦àµ‡à´¶à´¿à´šàµà´šàµ.</translation>
-<translation id="4446242550670694251">നിങàµà´™àµ¾à´•àµà´•àµ ഇനി à´¸àµà´µà´•à´¾à´°àµà´¯à´®à´¾à´¯à´¿ à´¬àµà´°àµ—à´¸àµà´šàµ†à´¯àµà´¯à´¾à´‚, മാതàµà´°à´®à´²àµà´² à´ˆ ഉപകരണം ഉപയോഗികàµà´•àµà´¨àµà´¨ മറàµà´±àµ ആളàµà´•àµ¾à´•àµà´•àµ നിങàµà´™à´³àµà´Ÿàµ† ആകàµâ€Œà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿ കാണാനàµà´®à´¾à´•à´¿à´²àµà´².</translation>
<translation id="4492190037599258964">'<ph name="SEARCH_STRING" />' à´¨àµà´³àµà´³ തിരയൽ ഫലങàµà´™à´³àµâ€</translation>
<translation id="4506176782989081258">മൂലàµà´¯à´¨à´¿àµ¼à´£àµà´£à´¯ പിശകàµ: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">സിസàµà´±àµà´±à´‚ à´…à´¡àµâ€Œà´®à´¿à´¨àµ† ബനàµà´§à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ</translation>
<translation id="450710068430902550">à´…à´¡àµâ€Œà´®à´¿à´¨à´¿à´¸àµâ€Œà´Ÿàµà´°àµ‡à´±àµà´±à´±àµà´®à´¾à´¯à´¿ പങàµà´•à´¿à´Ÿàµà´¨àµà´¨àµ</translation>
+<translation id="4515275063822566619">കാർഡàµà´•à´³àµà´‚ വിലാസങàµà´™à´³àµà´‚ Chrome-ൽ നിനàµà´¨àµà´‚ നിങàµà´™à´³àµà´Ÿàµ† അ‌കàµà´•àµ—à´£àµà´Ÿà´¿àµ½ (<ph name="ACCOUNT_EMAIL" />) നിനàµà´¨àµà´®àµà´³àµà´³à´¤àµà´®à´¾à´£àµ. നിങàµà´™àµ¾à´•àµà´•àµ ഇവ <ph name="BEGIN_LINK" />à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½<ph name="END_LINK" /> മാനേജàµà´šàµ†à´¯àµà´¯à´¾à´‚.</translation>
<translation id="4522570452068850558">വിശദാംശങàµà´™àµ¾â€Œ</translation>
<translation id="4558551763791394412">നിങàµà´™à´³àµà´Ÿàµ† വിപàµà´²àµ€à´•à´°à´£à´™àµà´™àµ¾ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´°à´¹à´¿à´¤à´®à´¾à´•àµà´•àµà´¨àµà´¨à´¤àµ പരീകàµà´·à´¿à´•àµà´•àµà´•.</translation>
<translation id="457875822857220463">ഡെലിവറി വിവരങàµà´™àµ¾</translation>
@@ -416,6 +427,7 @@
<translation id="4816492930507672669">പേജിനൠയàµà´•àµà´¤à´®à´¾à´•àµà´•àµà´•</translation>
<translation id="483020001682031208">കാണികàµà´•à´¾àµ» à´ªàµà´°à´¤àµà´¯à´•àµà´· വെബൠപേജàµà´•à´³à´¿à´²àµà´²</translation>
<translation id="4850886885716139402">കാണàµà´•</translation>
+<translation id="4854362297993841467">à´ˆ ഡെലിവറി രീതി ലഭàµà´¯à´®à´²àµà´². മറàµà´±àµŠà´°àµ രീതി പരീകàµà´·à´¿à´•àµà´•àµà´•.</translation>
<translation id="4858792381671956233">à´ˆ സൈറàµà´±àµ സനàµà´¦àµ¼à´¶à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ നിങàµà´™àµ¾ à´°à´•àµà´·à´¿à´¤à´¾à´•àµà´•à´³àµ‹à´Ÿàµ à´…à´¨àµà´®à´¤à´¿ ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
<translation id="4880827082731008257">തിരയൽ à´šà´°à´¿à´¤àµà´°à´‚</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -423,7 +435,6 @@
<translation id="4923417429809017348">à´ˆ പേജിനെ അറിയപàµà´ªàµ†à´Ÿà´¾à´¤àµà´¤ ഒരൠഭാഷയിലàµâ€â€Œ നിനàµà´¨àµà´‚ <ph name="LANGUAGE_LANGUAGE" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµ വിവരàµâ€â€Œà´¤àµà´¤à´¨à´‚ ചെയàµà´¤àµ</translation>
<translation id="4923459931733593730">പേയàµâ€Œà´®àµ†à´¨àµà´±àµ രീതി</translation>
<translation id="4926049483395192435">à´µàµà´¯à´•àµà´¤à´®à´¾à´•àµà´•àµ‡à´£àµà´Ÿà´¤à´¾à´£àµ.</translation>
-<translation id="4941291666397027948">* à´šà´¿à´¹àµà´¨à´‚ à´ˆ ഭാഗം പൂരിപàµà´ªà´¿à´•àµà´•àµ‡à´£àµà´Ÿà´¤à´¾à´£àµ à´Žà´¨àµà´¨àµ സൂചിപàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
<translation id="495170559598752135">à´ªàµà´°à´µà´°àµâ€à´¤àµà´¤à´¨à´™àµà´™à´³àµâ€</translation>
<translation id="4958444002117714549">ലിസàµà´±àµà´±àµ വിപàµà´²àµ€à´•à´°à´¿à´•àµà´•àµà´•</translation>
<translation id="4962322354953122629">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> ഡൊമെയàµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ† Chrome വിശàµà´µà´¸à´¿à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിചàµà´šà´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -438,6 +449,7 @@
<translation id="5045550434625856497">ശരിയലàµà´²à´¾à´¤àµà´¤ രഹസàµà´¯à´µà´¾à´•àµà´•àµ</translation>
<translation id="5056549851600133418">നിങàµà´™àµ¾à´•àµà´•àµà´³àµà´³ ലേഖനങàµà´™àµ¾</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ വിലാസം പരിശോധികàµà´•àµà´¨àµà´¨àµ<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{à´•àµà´•àµà´•à´¿à´•à´³à´¿à´²àµà´²}=1{ഒരൠസൈറàµà´±àµ à´•àµà´•àµà´•à´¿à´•àµ¾ ഉപയോഗികàµà´•àµà´¨àµà´¨àµ. }other{# സൈറàµà´±àµà´•àµ¾, à´•àµà´•àµà´•à´¿à´•àµ¾ ഉപയോഗികàµà´•àµà´¨àµà´¨àµ. }}</translation>
<translation id="5087286274860437796">സെർവറിനàµà´±àµ† സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ ഇപàµà´ªàµ‹àµ¾ സാധàµà´¤à´¯à´¿à´²àµà´².</translation>
<translation id="5087580092889165836">കാർഡൠചേർകàµà´•àµà´•</translation>
<translation id="5089810972385038852">à´¸àµà´±àµà´±àµ‡à´±àµà´±àµ</translation>
@@ -460,10 +472,8 @@
<translation id="5300589172476337783">കാണികàµà´•àµà´•</translation>
<translation id="5308689395849655368">à´•àµà´°à´¾à´·àµ റിപàµà´ªàµ‹à´°àµâ€à´Ÿàµà´Ÿàµà´šàµ†à´¯àµà´¯à´²àµâ€ à´…à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•à´¿.</translation>
<translation id="5317780077021120954">സംരകàµà´·à´¿à´•àµà´•àµà´•</translation>
-<translation id="5326702247179446998">à´¸àµà´µàµ€à´•àµ¼à´¤àµà´¤à´¾à´µà´¿à´¨àµ† ചേർകàµà´•àµ‡à´£àµà´Ÿà´¤àµà´£àµà´Ÿàµ</translation>
<translation id="5327248766486351172">പേരàµ</translation>
<translation id="5337705430875057403"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµ† ആകàµà´°à´®à´£à´•à´¾à´°à´¿à´•àµ¾ സോഫàµà´±àµà´±àµâ€Œà´µàµ†à´¯àµ¼ ഇൻസàµà´±àµà´±à´¾à´³àµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨à´¤àµ‹ à´¸àµà´µà´•à´¾à´°àµà´¯ വിവരങàµà´™àµ¾ വെളിപàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ‹ (ഉദാഹരണതàµà´¤à´¿à´¨àµ, പാസàµâ€Œà´µàµ‡à´¡àµà´•àµ¾, ഫോൺ നമàµà´ªà´±àµà´•àµ¾, à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡàµà´•àµ¾ à´¤àµà´Ÿà´™àµà´™à´¿à´¯ വിവരങàµà´™àµ¾) പോലàµà´³àµà´³ അപകടകരമായ കാരàµà´¯à´™àµà´™àµ¾ ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿à´¨àµ നിങàµà´™à´³àµ† കബളിപàµà´ªà´¿à´•àµà´•à´¾à´‚.</translation>
-<translation id="53553865750799677">പികàµà´•à´ªàµà´ªàµ വിലാസം ഉപയോഗികàµà´•à´¾à´¨à´¾à´µà´¿à´²àµà´². മറàµà´±àµŠà´°àµ വിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
<translation id="5359637492792381994">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> ഡൊമെയàµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ ഇപàµà´ªàµ‹àµ¾ സാധàµà´µà´¾à´¯à´¤à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിചàµà´šà´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">നയ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾ സംഭരികàµà´•àµà´¨àµà´¨à´¤à´¿àµ½ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
<translation id="5386426401304769735">à´ˆ സൈറàµà´±à´¿à´¨àµà´±àµ† സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ ചെയിനിൽ SHA-1 ഉപയോഗിചàµà´šàµ സൈൻ ചെയàµâ€Œà´¤ ഒരൠസർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ à´…à´Ÿà´™àµà´™à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
@@ -489,8 +499,8 @@
<translation id="5544037170328430102"><ph name="SITE" /> സൈറàµà´±à´¿à´²àµ† ഒരൠഎംബഡൠചെയàµâ€Œà´¤ പേജൠപറയàµà´¨àµà´¨à´¤àµ:</translation>
<translation id="5556459405103347317">വീണàµà´Ÿàµà´‚ ലോഡàµà´šàµ†à´¯àµà´¯àµà´•</translation>
<translation id="5565735124758917034">സജീവമാണàµ</translation>
+<translation id="5571083550517324815">à´ˆ വിലാസതàµà´¤à´¿àµ½ നിനàµà´¨àµ പികàµà´•àµà´…à´ªàµà´ªàµ ചെയàµà´¯à´¾àµ» കഴിയിലàµà´². മറàµà´±àµŠà´°àµ വിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
<translation id="5572851009514199876">ആരംഭിചàµà´šàµ Chrome-ൽ സൈൻ ഇൻ ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿à´²àµ‚ടെ, നിങàµà´™àµ¾à´•àµà´•àµ à´ˆ സൈറàµà´±àµ ആകàµâ€Œà´¸à´¸àµ ചെയàµà´¯à´¾àµ» à´…à´¨àµà´µà´¾à´¦à´®àµà´£àµà´Ÿàµ‹à´¯àµ†à´¨àµà´¨àµ Chrome-നൠപരിശോധികàµà´•à´¾à´¨à´¾à´µàµà´‚.</translation>
-<translation id="5575380383496039204">à´ˆ ഡെലിവറി വിലാസതàµà´¤à´¿àµ½ അയയàµâ€Œà´•àµà´•à´¾à´¨à´¾à´µà´¿à´²àµà´². മറàµà´±àµŠà´°àµ വിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
<translation id="5580958916614886209">കാലാവധി തീരàµà´¨àµà´¨ മാസം പരിശോധിചàµà´šàµ വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´šàµà´šàµà´¨àµ‹à´•àµà´•àµ‚</translation>
<translation id="560412284261940334">മാനേജàµà´®àµ†à´¨àµà´±àµ പിനàµà´¤àµà´£à´¯àµâ€Œà´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´²</translation>
<translation id="5610142619324316209">കണകàµà´·àµ» പരിശോധികàµà´•àµà´¨àµà´¨àµ</translation>
@@ -506,7 +516,8 @@
<translation id="5710435578057952990">à´ˆ വെബàµà´¸àµˆà´±àµà´±à´¿à´¨àµà´±àµ† à´µàµà´¯à´•àµà´¤à´¿à´¤àµà´µà´‚ പരിശോധിചàµà´šà´¿à´Ÿàµà´Ÿà´¿à´²àµà´².</translation>
<translation id="5720705177508910913">നിലവിലെ ഉപയോകàµà´¤à´¾à´µàµ</translation>
<translation id="5732392974455271431">നിങàµà´™àµ¾à´•àµà´•àµ വേണàµà´Ÿà´¿ ഇതൠഅൺബàµà´²àµ‹à´•àµà´•àµà´šàµ†à´¯àµà´¯à´¾àµ» à´°à´•àµà´·à´¿à´¤à´¾à´•àµà´•àµ¾à´•àµà´•àµ à´•à´´à´¿à´¯àµà´‚</translation>
-<translation id="57586589942790530">അസാധàµà´µà´¾à´¯ കാർഡൠനമàµà´ªàµ¼</translation>
+<translation id="5763042198335101085">ശരിയായ ഇമെയിൽ വിലാസം നൽകàµà´•</translation>
+<translation id="5765072501007116331">ഡെലിവറി രീതികളàµà´‚ ആവശàµà´¯à´•à´¤à´•à´³àµà´‚ കാണാൻ ഒരൠവിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•</translation>
<translation id="5784606427469807560">നിങàµà´™à´³àµà´Ÿàµ† കാർഡൠസàµà´¥à´¿à´°àµ€à´•à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿àµ½ à´ªàµà´°à´¶àµâ€Œà´¨à´®àµà´£àµà´Ÿà´¾à´¯à´¿. ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ കണകàµà´·àµ» പരിശോധിചàµà´šàµ, വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•.</translation>
<translation id="5785756445106461925">കൂടാതെ, à´ˆ പേജിൽ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´²àµà´²à´¾à´¤àµà´¤ മറàµà´±àµ ഉറവിടങàµà´™àµ¾ ഉൾപàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ. à´ˆ ഉറവിടങàµà´™àµ¾ കൈമാറàµà´¨àµà´¨à´¤à´¿à´¨à´¿à´Ÿàµ† മറàµà´±àµà´³àµà´³à´µàµ¼à´•àµà´•àµ കാണാനàµà´‚ പേജിനàµà´±àµ† രൂപം മാറàµà´±àµà´¨àµà´¨ തരതàµà´¤à´¿àµ½ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿à´¯àµâ€Œà´•àµà´•àµ പരിഷàµâ€Œà´•àµà´•à´°à´¿à´•àµà´•à´¾à´¨àµà´®à´¾à´¯àµ‡à´•àµà´•àµà´‚.</translation>
<translation id="5786044859038896871">നിങàµà´™à´³àµà´Ÿàµ† കാർഡൠവിവരം പൂരിപàµà´ªà´¿à´•àµà´•à´£àµ‹?</translation>
@@ -519,22 +530,20 @@
<translation id="5869405914158311789">à´ˆ സൈറàµà´±àµ ലഭàµà´¯à´®à´¾à´•àµà´•à´¾à´¨à´¾à´•àµà´¨àµà´¨à´¿à´²àµà´²</translation>
<translation id="5869522115854928033">സംരകàµà´·à´¿à´šàµà´š പാസàµâ€Œà´µàµ‡à´¡àµà´•à´³àµâ€</translation>
<translation id="5872918882028971132">പാരനàµà´±àµ നിർദàµà´¦àµ‡à´¶à´™àµà´™àµ¾</translation>
-<translation id="587760065310675640">à´ˆ à´·à´¿à´ªàµà´ªà´¿à´‚ഗൠവിലാസതàµà´¤à´¿àµ½ അയയàµâ€Œà´•àµà´•à´¾à´¨à´¾à´µà´¿à´²àµà´². മറàµà´±àµŠà´°àµ വിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
<translation id="5901630391730855834">മഞàµà´ž</translation>
-<translation id="59174027418879706">à´ªàµà´°à´¾à´ªàµâ€Œà´¤à´®à´¾à´•àµà´•à´¿</translation>
<translation id="5926846154125914413">നിങàµà´™àµ¾à´•àµà´•àµ à´šà´¿à´² സൈറàµà´±àµà´•à´³à´¿àµ½ നിനàµà´¨àµà´³àµà´³ à´ªàµà´°àµ€à´®à´¿à´¯à´‚ ഉളàµà´³à´Ÿà´•àµà´•à´¤àµà´¤à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ ആകàµâ€Œà´¸à´¸àµ നഷàµâ€Œà´Ÿà´®à´¾à´¯àµ‡à´•àµà´•à´¾à´‚.</translation>
<translation id="5959728338436674663">അപകടകരമായ ആപàµâ€Œà´¸àµà´•à´³àµà´‚ സൈറàµà´±àµà´•à´³àµà´‚ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¾àµ» സഹായികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµâ€Œ à´šà´¿à´² <ph name="BEGIN_WHITEPAPER_LINK" />സിസàµâ€Œà´±àµà´±à´‚ വിവരങàµà´™à´³àµà´‚ പേജàµâ€Œ ഉളàµà´³à´Ÿà´•àµà´•à´µàµà´‚<ph name="END_WHITEPAPER_LINK" /> Google-à´¨àµâ€Œ à´¸àµà´µà´¯à´®àµ‡à´µ അയയàµâ€Œà´•àµà´•àµà´•. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">ആഴàµâ€Œà´š</translation>
<translation id="5967867314010545767">à´šà´°à´¿à´¤àµà´°à´¤àµà´¤à´¿àµ½ നിനàµà´¨àµà´‚ നീകàµà´•à´‚ചെയàµà´¯àµà´•</translation>
<translation id="5975083100439434680">സൂം ഔടàµà´Ÿàµ</translation>
+<translation id="598637245381783098">പേയàµâ€Œà´®àµ†à´¨àµà´±àµ ആപàµà´ªàµ à´¤àµà´±à´•àµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²</translation>
<translation id="5989320800837274978">ഒരൠസàµà´¥à´¿à´°à´®à´¾à´¯ à´ªàµà´°àµ‹à´•àµà´¸à´¿ സെർവർ à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ ഒരൠ.pac à´¸àµâ€Œà´•àµà´°à´¿à´ªàµà´±àµà´±àµ URL à´µàµà´¯à´•àµà´¤à´®à´¾à´•àµà´•à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´².</translation>
<translation id="5990559369517809815">സെർവറിലേകàµà´•àµà´³àµà´³ à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨à´•àµ¾ ഒരൠവിപàµà´²àµ€à´•à´°à´£à´‚ തടഞàµà´žàµ.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">കാർഡàµà´‚ വിലാസ à´“à´ªàµâ€Œà´·à´¨àµà´•à´³àµà´‚ Chrome-ൽ നിനàµà´¨àµà´³àµà´³à´¤à´¾à´£àµ. നിങàµà´™àµ¾à´•àµà´•àµ ഇവ <ph name="BEGIN_LINK" />à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½<ph name="END_LINK" /> മാനേജàµà´šàµ†à´¯àµà´¯à´¾à´‚.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{പേജൠ1}other{പേജൠ#}}</translation>
<translation id="6017514345406065928">പചàµà´š</translation>
+<translation id="6027201098523975773">ഒരൠപേരൠനൽകàµà´•</translation>
<translation id="6040143037577758943">à´…à´Ÿà´¯àµà´•àµà´•àµà´•</translation>
-<translation id="604124094241169006">à´¸àµà´µà´ªàµà´°àµ‡à´°à´¿à´¤à´‚</translation>
<translation id="6042308850641462728">കൂടàµà´¤àµ½</translation>
<translation id="6060685159320643512">à´¶àµà´°à´¦àµà´§à´¿à´•àµà´•àµ‚, à´ˆ പരീകàµà´·à´£à´™àµà´™à´³àµâ€ പാളിയേകàµà´•à´¾à´‚†</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{à´’à´¨àµà´¨àµà´®à´¿à´²àµà´²}=1{1}other{#}}</translation>
@@ -542,9 +551,10 @@
മറàµà´±àµ നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ ഉപകരണങàµà´™àµ¾ à´Žà´¨àµà´¨à´¿à´µ റീബൂടàµà´Ÿàµà´šàµ†à´¯àµà´¯àµà´•.</translation>
<translation id="614940544461990577">പരീകàµà´·à´¿à´šàµà´šàµà´¨àµ‹à´•àµà´•àµ‚:</translation>
<translation id="6151417162996330722">സെർവർ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ ദൈർഘàµà´¯à´®àµ‡à´±à´¿à´¯ ഒരൠകാലയളവൠഉണàµà´Ÿàµ.</translation>
-<translation id="615643356032862689">ഡൗൺലോഡàµà´šàµ†à´¯àµâ€Œà´¤ ഫയലàµà´•à´³àµà´‚ à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµà´•à´³àµà´‚ സൂകàµà´·à´¿à´•àµà´•àµà´‚.</translation>
+<translation id="6157877588268064908">à´·à´¿à´ªàµà´ªà´¿à´‚ഗൠരീതികളàµà´‚ ആവശàµà´¯à´•à´¤à´•à´³àµà´‚ കാണാൻ ഒരൠവിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•</translation>
<translation id="6165508094623778733">കൂടàµà´¤àµ½â€ മനസിലാകàµà´•àµà´•</translation>
<translation id="6177128806592000436">à´ˆ സൈറàµà´±à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·àµ» à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´²àµà´²</translation>
+<translation id="6184817833369986695">(സമാന വിഭാഗതàµà´¤à´¿àµ½à´ªàµà´ªàµ†à´Ÿàµà´Ÿà´µ: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">നിങàµà´™à´³àµà´Ÿàµ† ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ കണകàµà´·àµ» പരിശോധികàµà´•àµà´•</translation>
<translation id="6218753634732582820">Chromium-à´¤àµà´¤à´¿àµ½ നിനàµà´¨àµ വിലാസം നീകàµà´•à´‚ചെയàµà´¯à´£àµ‹?</translation>
<translation id="6251924700383757765">à´¸àµà´µà´•à´¾à´°àµà´¯à´¤ നയം</translation>
@@ -553,6 +563,8 @@
<translation id="6259156558325130047">&amp;à´ªàµà´¨à´ƒà´•àµà´°à´®àµ€à´•à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ വീണàµà´Ÿàµà´‚ ചെയàµà´¯àµà´•</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµà´•àµ¾</translation>
<translation id="6264485186158353794">à´¸àµà´°à´•àµà´·à´¯à´¿à´²àµ‡à´•àµà´•àµ</translation>
+<translation id="6276112860590028508">നിങàµà´™à´³àµà´Ÿàµ† വായന പടàµà´Ÿà´¿à´•à´¯à´¿àµ½ നിനàµà´¨àµà´³àµà´³ പേജàµà´•àµ¾ ഇവിടെ ദൃശൃമാകàµà´‚</translation>
+<translation id="6280223929691119688">à´ˆ വിലാസതàµà´¤à´¿à´²àµ‡à´•àµà´•àµ ഡെലിവറി ചെയàµà´¯à´¾àµ» കഴിയിലàµà´². മറàµà´±àµŠà´°àµ വിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
<translation id="6282194474023008486">തപാലàµâ€ കോഡàµ</translation>
<translation id="6290238015253830360">നിങàµà´™à´³àµà´Ÿàµ† നിർദàµà´¦àµ‡à´¶à´¿à´šàµà´š ലേഖനങàµà´™àµ¾ ഇവിടെ ദൃശàµà´¯à´®à´¾à´•àµà´‚</translation>
<translation id="6305205051461490394"><ph name="URL" /> ലഭàµà´¯à´®à´²àµà´².</translation>
@@ -574,7 +586,6 @@
<translation id="6417515091412812850">സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ അസാധàµà´µà´¾à´•àµà´•à´¿à´¯àµ‹ à´Žà´¨àµà´¨àµ പരിശോധികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´¯à´¿à´²àµà´².</translation>
<translation id="6433490469411711332">കോൺടാകàµâ€Œà´±àµà´±àµ വിവരം à´Žà´¡à´¿à´±àµà´±àµà´šàµ†à´¯àµà´¯àµà´•</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> കണകàµâ€Œà´±àµà´±àµà´šàµ†à´¯àµà´¯àµ½ നിരസിചàµà´šàµ.</translation>
-<translation id="6443118737398455446">കാലഹരണപàµà´ªàµ†à´Ÿàµà´¨àµà´¨ തീയതി തെറàµà´±à´¾à´£àµ</translation>
<translation id="6446608382365791566">കൂടàµà´¤àµ½ വിവരങàµà´™àµ¾ ചേർകàµà´•àµà´•</translation>
<translation id="6451458296329894277">വീണàµà´Ÿàµà´‚ സമരàµâ€à´ªàµà´ªà´¿à´•àµà´•à´²àµâ€ അപേകàµà´· ഉറപàµà´ªà´¾à´•àµà´•àµà´•</translation>
<translation id="6456339708790392414">നിങàµà´™à´³àµà´Ÿàµ† പേയàµà´®àµ†à´¨àµà´±àµ</translation>
@@ -582,10 +593,8 @@
<translation id="6462969404041126431">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> ഡൊമെയàµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ റദàµà´¦à´¾à´•àµà´•à´¿à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിചàµà´šà´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">ഉപകരണ നയങàµà´™àµ¾</translation>
<translation id="6477321094435799029">Chrome, à´ˆ പേജിൽ അസാധാരണമായ കോഡൠകണàµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¤à´¿à´¨à´¾àµ½ നിങàµà´™à´³àµà´Ÿàµ† à´µàµà´¯à´•àµà´¤à´¿à´—à´¤ വിവരങàµà´™àµ¾ (ഉദാഹരണതàµà´¤à´¿à´¨àµ, പാസàµâ€Œà´µàµ‡à´¡àµà´•à´³àµà´‚ ഫോൺ നമàµà´ªà´±àµà´•à´³àµà´‚ à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡàµà´•à´³àµà´‚ പോലàµà´³àµà´³à´µ) പരിരകàµà´·à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ അതിനെ à´¬àµà´²àµ‹à´•àµà´•àµà´šàµ†à´¯àµâ€Œà´¤àµ.</translation>
-<translation id="6477460825583319731">ഇമെയിൽ വിലാസം അസാധàµà´µà´¾à´£àµ</translation>
<translation id="6489534406876378309">à´•àµà´°à´¾à´·àµà´•àµ¾ à´…à´ªàµâ€Œà´²àµ‹à´¡àµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨à´¤àµ ആരംഭികàµà´•àµà´•</translation>
<translation id="6508722015517270189">Chrome റീസàµâ€Œà´±àµà´±à´¾àµ¼à´Ÿàµà´Ÿàµà´šàµ†à´¯àµà´¯àµà´•</translation>
-<translation id="6525462735697194615">കാലഹരണപàµà´ªàµ†à´Ÿàµà´¨àµà´¨ മാസം തെറàµà´±à´¾à´£àµ</translation>
<translation id="6529602333819889595">&amp;ഇലàµà´²à´¾à´¤à´¾à´•àµà´•àµà´¨àµà´¨à´¤àµ വീണàµà´Ÿàµà´‚ ചെയàµà´¯àµà´•</translation>
<translation id="6534179046333460208">ഫിസികàµà´•àµ½ വെബൠനിർദàµà´¦àµ‡à´¶à´™àµà´™àµ¾</translation>
<translation id="6550675742724504774">à´“à´ªàµà´·à´¨àµà´•àµ¾</translation>
@@ -600,7 +609,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> തിരയൽ</translation>
<translation id="6644283850729428850">à´ˆ നയം ഒഴിവാകàµà´•à´¿.</translation>
<translation id="6652240803263749613">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> ഡൊമെയàµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ† നിങàµà´™à´³àµà´Ÿàµ† à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿà´±à´¿à´¨àµà´±àµ† à´“à´ªàµà´ªà´±àµ‡à´±àµà´±à´¿à´‚ഗൠസിസàµà´±àµà´±à´‚ വിശàµà´µà´¸à´¿à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിചàµà´šà´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">à´† à´·à´¿à´ªàµà´ªà´¿à´‚ഗൠഓപàµâ€Œà´·àµ» ലഭàµà´¯à´®à´²àµà´². മറàµà´±àµŠà´°àµ à´“à´ªàµâ€Œà´·àµ» പരീകàµà´·à´¿à´•àµà´•àµ‚.</translation>
<translation id="6671697161687535275">Chromium-à´¤àµà´¤à´¿àµ½ നിനàµà´¨àµ ഫോം നിർദàµà´¦àµ‡à´¶à´‚ നീകàµà´•à´‚ചെയàµà´¯à´£àµ‹?</translation>
<translation id="6685834062052613830">സൈൻ ഔടàµà´Ÿàµ ചെയàµâ€Œà´¤àµ, സജàµà´œà´®à´¾à´•àµà´•àµ½ പൂർതàµà´¤à´¿à´¯à´¾à´•àµà´•àµà´•</translation>
<translation id="6710213216561001401">à´•à´´à´¿à´žàµà´ž</translation>
@@ -608,13 +616,13 @@
<translation id="6711464428925977395">à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ സെർവറിൽ à´Žà´¨àµà´¤àµ‹ à´ªàµà´°à´¶àµâ€Œà´¨à´®àµà´£àµà´Ÿàµ, à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ വിലാസം തെറàµà´±à´¾à´£àµ.</translation>
<translation id="6727102863431372879">സജàµà´œà´®à´¾à´•àµà´•àµà´•</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{à´’à´¨àµà´¨àµà´®à´¿à´²àµà´²}=1{ഒരൠഇനം}other{# ഇനങàµà´™àµ¾}}</translation>
-<translation id="6743044928064272573">പികàµà´•à´ªàµà´ªàµ à´“à´ªàµâ€Œà´·àµ»</translation>
<translation id="674375294223700098">അറിയപàµà´ªàµ†à´Ÿà´¾à´¤àµà´¤ സെരàµâ€à´µà´°àµâ€ സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ പിശകàµ.</translation>
<translation id="6753269504797312559">നയ മൂലàµà´¯à´‚</translation>
<translation id="6757797048963528358">നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണം à´¸àµà´·àµà´ªàµâ€Œà´¤à´¿à´¯à´¿à´²à´¾à´¯à´¿.</translation>
<translation id="6778737459546443941">നിങàµà´™à´³àµà´Ÿàµ† à´°à´•àµà´·à´¿à´¤à´¾à´µàµ ഇതàµà´µà´°àµ† അംഗീകാരം നൽകിയിടàµà´Ÿà´¿à´²àµà´²</translation>
<translation id="6810899417690483278">ഇഷàµâ€Œà´Ÿà´¾à´¨àµà´¸àµƒà´¤à´®à´¾à´•àµà´•àµ½ à´à´¡à´¿</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">à´ªàµà´°à´¦àµ‡à´¶à´™àµà´™à´³àµà´Ÿàµ† വിവരങàµà´™àµ¾ ലോഡàµà´šàµ†à´¯àµà´¯à´¾à´¨à´¾à´¯à´¿à´²àµà´²</translation>
<translation id="6831043979455480757">വിവർതàµà´¤à´¨à´‚ ചെയàµà´¯àµà´•</translation>
<translation id="6839929833149231406">à´à´°à´¿à´¯</translation>
<translation id="6874604403660855544">&amp;ചേർകàµà´•àµà´¨àµà´¨à´¤àµ വീണàµà´Ÿàµà´‚ ചെയàµà´¯àµà´•</translation>
@@ -622,6 +630,7 @@
<translation id="6895330447102777224">നിങàµà´™à´³àµà´Ÿàµ† കാർഡൠസàµà´¥à´¿à´°àµ€à´•à´°à´¿à´šàµà´šàµ</translation>
<translation id="6897140037006041989">ഉപയോകàµà´¤àµƒ à´à´œà´¨àµâ€à´±àµ</translation>
<translation id="6915804003454593391">ഉപയോകàµà´¤à´¾à´µàµ:</translation>
+<translation id="6948701128805548767">പികàµà´•àµà´…à´ªàµà´ªàµ രീതികളàµà´‚ ആവശàµà´¯à´•à´¤à´•à´³àµà´‚ കാണാൻ ഒരൠവിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•</translation>
<translation id="6957887021205513506">സെർവറിനàµà´±àµ† സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ വിശàµà´µà´¸à´¿à´•àµà´•à´¾àµ» കൊളàµà´³à´¾à´¤àµà´¤ à´’à´¨àµà´¨à´¾à´¯à´¿ തോനàµà´¨àµà´¨àµà´¨àµ.</translation>
<translation id="6965382102122355670">ശരി</translation>
<translation id="6965978654500191972">ഉപാധി</translation>
@@ -629,7 +638,6 @@
<translation id="6973656660372572881">à´¸àµà´¥à´¿à´°à´®à´¾à´¯ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ സെർവറàµà´•à´³àµà´‚ ഒരൠസàµâ€Œà´•àµà´°à´¿à´ªàµà´±àµà´±àµ URL-ഉം à´µàµà´¯à´•àµà´¤à´®à´¾à´•àµà´•à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="6989763994942163495">വിപàµà´²à´®à´¾à´¯ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾ കാണികàµà´•àµà´•...</translation>
<translation id="7000990526846637657">à´šà´°à´¿à´¤àµà´° എൻടàµà´°à´¿à´•à´³àµŠà´¨àµà´¨àµà´‚ à´•à´£àµà´Ÿà´¿à´²àµà´²</translation>
-<translation id="7001663382399377034">à´¸àµà´µàµ€à´•à´°àµâ€à´¤àµà´¤à´¾à´µà´¿à´¨àµ† ചേരàµâ€à´•àµà´•àµ‚</translation>
<translation id="7009986207543992532">നിങàµà´™àµ¾ <ph name="DOMAIN" /> ഡൊമെയàµâ€Œà´¨à´¿àµ½ à´Žà´¤àµà´¤à´¿à´šàµà´šàµ‡à´°à´¾àµ» à´¶àµà´°à´®à´¿à´šàµà´šàµ†à´™àµà´•à´¿à´²àµà´‚, വിശàµà´µà´¾à´¸à´¯àµ‹à´—àµà´¯à´®à´²àµà´²à´¾à´¤àµà´¤ തരതàµà´¤à´¿àµ½ ദൈർഘàµà´¯à´®àµ‡à´±à´¿à´¯ സാധàµà´¤à´¾ കാലയളവàµà´³àµà´³ ഒരൠസർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ സെർവർ നൽകി. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">ചൈന UnionPay</translation>
<translation id="7012372675181957985">നിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿à´¨àµ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> à´Žà´¨àµà´¨à´¤à´¿àµ½ മറàµà´±àµ തരതàµà´¤à´¿à´²àµà´³àµà´³ à´¬àµà´°àµ—സിംഗൠചരിതàµà´°à´®àµà´£àµà´Ÿà´¾à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚</translation>
@@ -640,12 +648,15 @@
<translation id="7088615885725309056">വളരെ പഴയ</translation>
<translation id="7090678807593890770">Google-ൽ <ph name="LINK" /> തിരയàµà´•</translation>
<translation id="7119414471315195487">മറàµà´±àµ ടാബàµà´•à´³àµ‹ à´ªàµà´°àµ‹à´—àµà´°à´¾à´®àµà´•à´³àµ‹ à´…à´Ÿà´¯àµâ€Œà´•àµà´•àµà´•</translation>
+<translation id="7129409597930077180">à´ˆ വിലാസതàµà´¤à´¿à´²àµ‡à´•àµà´•àµ à´·à´¿à´ªàµà´ªàµ ചെയàµà´¯à´¾àµ» കഴിയിലàµà´². മറàµà´±àµŠà´°àµ വിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
+<translation id="7138472120740807366">ഡെലിവറി രീതി</translation>
<translation id="7139724024395191329">എമിറേറàµà´±àµ</translation>
<translation id="7155487117670177674">പേയàµâ€Œà´®àµ†à´¨àµà´±àµ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´²àµà´²</translation>
<translation id="7179921470347911571">ഇപàµà´ªàµ‹à´³àµâ€ വീണàµà´Ÿàµà´‚ സമാരംഭികàµà´•àµà´•</translation>
<translation id="7180611975245234373">à´ªàµà´¤àµà´•àµà´•àµà´•</translation>
<translation id="7182878459783632708">നയങàµà´™à´³àµŠà´¨àµà´¨àµà´‚ സജàµà´œà´®à´¾à´•àµà´•à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´²</translation>
<translation id="7186367841673660872">à´ˆ പേജàµ<ph name="ORIGINAL_LANGUAGE" />à´²àµâ€â€Œ നിനàµà´¨àµà´‚<ph name="LANGUAGE_LANGUAGE" />ലേകàµà´•àµ വിവരàµâ€â€Œà´¤àµà´¤à´¨à´‚ ചെയàµâ€Œà´¤àµ</translation>
+<translation id="7192203810768312527"><ph name="SIZE" /> ലാഭികàµà´•àµà´•. നിങàµà´™à´³àµà´Ÿàµ† à´…à´Ÿàµà´¤àµà´¤ സനàµà´¦àµ¼à´¶à´¨à´¤àµà´¤à´¿àµ½ à´šà´¿à´² സൈറàµà´±àµà´•àµ¾ സാവധാനതàµà´¤à´¿àµ½ ലോഡàµà´šàµ†à´¯àµâ€Œà´¤àµ‡à´•àµà´•à´¾à´‚.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" />, à´¸àµà´°à´•àµà´·à´¾ മാനദണàµà´¡à´™àµà´™àµ¾ പാലികàµà´•àµà´¨àµà´¨à´¿à´²àµà´².</translation>
<translation id="721197778055552897">à´ˆ à´ªàµà´°à´¶àµâ€Œà´¨à´¤àµà´¤àµ†à´•àµà´•àµà´±à´¿à´šàµà´šàµ <ph name="BEGIN_LINK" />കൂടàµà´¤àµ½â€ മനസിലാകàµà´•àµà´•<ph name="END_LINK" />.</translation>
@@ -674,7 +685,6 @@
<translation id="7424977062513257142">à´ˆ വെബàµâ€Œà´¸àµˆà´±àµà´±à´¿à´²àµ† ഒരൠഎംബഡൠചെയàµâ€Œà´¤ പേജൠപറയàµà´¨àµà´¨à´¤àµ:</translation>
<translation id="7441627299479586546">തെറàµà´±à´¾à´¯ നയ വിഷയം</translation>
<translation id="7444046173054089907">à´ˆ സൈറàµà´±àµ à´¬àµà´²àµ‹à´•àµà´•àµà´šàµ†à´¯àµâ€Œà´¤àµ</translation>
-<translation id="7444238235002594607">പികàµà´•à´ªàµà´ªàµ രീതികളàµà´‚ അതിനൠആവശàµà´¯à´®à´¾à´¯ കാരàµà´¯à´™àµà´™à´³àµà´‚ പരിശോധികàµà´•à´¾àµ» ഒരൠപികàµà´•à´ªàµà´ªàµ വിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
<translation id="7445762425076701745">നിങàµà´™à´³àµâ€ ബനàµà´§à´¿à´ªàµà´ªà´¿à´šàµà´š സെരàµâ€à´µà´±à´¿à´¨àµâ€à´±àµ† à´à´¡à´¨àµâ€à´±à´¿à´±àµà´±à´¿ പൂരàµâ€à´£àµà´£à´®à´¾à´¯à´¿ സാധൂകരികàµà´•à´¾à´¨àµâ€ കഴിയിലàµà´². നിങàµà´™à´³àµà´Ÿàµ† നെറàµà´±àµâ€à´µà´°àµâ€à´•àµà´•à´¿à´²àµâ€ മാതàµà´°à´‚ സാധàµà´µà´¾à´¯ ഒരൠനാമം ഉപയോഗികàµà´•àµà´¨àµà´¨ സെരàµâ€à´µà´±à´¿à´²àµ‡à´•àµà´•àµ നിങàµà´™à´³àµâ€ ബനàµà´§à´¿à´ªàµà´ªà´¿à´šàµà´šà´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ, അതിനàµâ€à´±àµ† ഉടമസàµà´¥à´¾à´µà´•à´¾à´¶à´‚ ഒരൠബാഹàµà´¯ അതോറിറàµà´±à´¿à´¯àµà´•àµà´•àµ à´’à´°à´¿à´•àµà´•à´²àµà´‚ സാധൂകരികàµà´•à´¾à´¨àµâ€ കഴിയിലàµà´². à´šà´¿à´² സാകàµâ€à´·àµà´¯à´ªà´¤àµà´° അതോറിറàµà´±à´¿à´•à´³àµâ€ à´ˆ നാമങàµà´™à´³àµ† കണകàµà´•à´¾à´•àµà´•à´¾à´¤àµ† സാകàµâ€à´·àµà´¯à´ªà´¤àµà´°à´™àµà´™à´³àµâ€ നലàµâ€à´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµâ€, ഉദàµà´¦àµ‡à´¶à´¿à´šàµà´š വെബàµà´¸àµˆà´±àµà´±à´¿à´²àµ‡à´•àµà´•à´¾à´£àµ നിങàµà´™à´³àµâ€ ബനàµà´§à´¿à´ªàµà´ªà´¿à´šàµà´šà´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ†à´¨àµà´¨àµà´‚ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿à´¯à´²àµà´²àµ†à´¨àµà´¨àµà´‚ ഉറപàµà´ªà´¾à´•àµà´•à´¾à´¨àµâ€ ഒരൠമാരàµâ€à´—àµà´—à´µàµà´®à´¿à´²àµà´².</translation>
<translation id="7451311239929941790">à´ˆ à´ªàµà´°à´¶àµâ€Œà´¨à´¤àµà´¤àµ†à´•àµà´•àµà´±à´¿à´šàµà´šàµ <ph name="BEGIN_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´¨àµà´¨àµ<ph name="END_LINK" />.</translation>
<translation id="7460163899615895653">മറàµà´±àµ ഉപകരണങàµà´™à´³à´¿àµ½ നിനàµà´¨àµà´³àµà´³ à´…à´Ÿàµà´¤àµà´¤à´¿à´Ÿàµ†à´¯àµà´³àµà´³ നിങàµà´™à´³àµà´Ÿàµ† ടാബàµà´•àµ¾ ഇവിടെ ദൃശàµà´¯à´®à´¾à´•àµà´‚</translation>
@@ -718,6 +728,7 @@
<translation id="7755287808199759310">നിങàµà´™àµ¾à´•àµà´•àµ വേണàµà´Ÿà´¿ ഇതൠഅൺബàµà´²àµ‹à´•àµà´•àµà´šàµ†à´¯àµà´¯à´¾àµ» à´°à´•àµà´·à´¿à´¤à´¾à´µà´¿à´¨àµ à´•à´´à´¿à´¯àµà´‚</translation>
<translation id="7758069387465995638">ഫയർവാളോ ആനàµà´±à´¿ വൈറസൠസോഫàµâ€Œà´±àµà´±àµâ€Œà´µàµ†à´¯à´±àµ‹ കണകàµà´·àµ» à´¬àµà´²àµ‹à´•àµà´•àµà´šàµ†à´¯àµâ€Œà´¤à´¿à´Ÿàµà´Ÿàµà´£àµà´Ÿà´¾à´•à´¾à´‚.</translation>
<translation id="7761701407923456692">സെരàµâ€à´µà´±à´¿à´¨àµâ€à´±àµ† സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ URL മായി പൊരàµà´¤àµà´¤à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨à´¿à´²àµà´².</translation>
+<translation id="7763386264682878361">പേയàµâ€Œà´®àµ†à´¨àµà´±àµ മാനിഫെസàµâ€Œà´±àµà´±àµ പാർസർ</translation>
<translation id="7764225426217299476">വിലാസം ചേർകàµà´•àµà´•</translation>
<translation id="777702478322588152">à´ªàµà´°à´¿à´«àµ†à´•àµâ€Œà´šàµ¼</translation>
<translation id="7791543448312431591">ചേരàµâ€à´•àµà´•àµ‚</translation>
@@ -731,6 +742,7 @@
<translation id="785549533363645510">à´Žà´¨àµà´¨à´¿à´°àµà´¨àµà´¨à´¾à´²àµà´‚ നിങàµà´™àµ¾ അദൃശàµà´¯à´¨à´²àµà´². ആൾമാറാടàµà´Ÿà´¤àµà´¤à´¿à´²àµ‡à´¯àµâ€Œà´•àµà´•àµ പോകàµà´¨àµà´¨à´¤àµ, നിങàµà´™à´³àµà´Ÿàµ† തൊഴിൽ ദാതാവിൽ നിനàµà´¨àµ‹ ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ സേവന ദാതാവിൽ നിനàµà´¨àµ‹ നിങàµà´™àµ¾ സനàµà´¦àµ¼à´¶à´¿à´•àµà´•àµà´¨àµà´¨ വെബàµâ€Œà´¸àµˆà´±àµà´±àµà´•à´³à´¿àµ½ നിനàµà´¨àµ‹ ഉളàµà´³ à´¬àµà´°àµ—സിംഗിനെ മറയàµâ€Œà´•àµà´•à´¿à´²àµà´².</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">നിങàµà´™à´³àµà´Ÿàµ† CVC പരിശോധിചàµà´šàµ വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•</translation>
+<translation id="79338296614623784">ശരിയായ ഒരൠഫോൺ നമàµà´ªàµ¼ നൽകàµà´•</translation>
<translation id="7935318582918952113">DOM à´¡à´¿à´¸àµâ€Œà´±àµà´±à´¿à´²àµ¼</translation>
<translation id="7938958445268990899">സെരàµâ€à´µà´±à´¿à´¨àµâ€à´±àµ† സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ ഇതàµà´µà´°àµ†à´¯àµà´‚ സാധàµà´µà´²àµà´².</translation>
<translation id="7942349550061667556">à´šàµà´µà´ªàµà´ªàµ</translation>
@@ -750,6 +762,7 @@
<translation id="8088680233425245692">ലേഖനം കാണàµà´¨àµà´¨à´¤àµ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ.</translation>
<translation id="8089520772729574115">ഒരൠMB-യിൽ à´•àµà´±à´µà´¾à´£àµ</translation>
<translation id="8091372947890762290">സെർവറിൽ സജീവമാകàµà´•àµ½ തീർപàµà´ªà´¾à´•àµà´•à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´²</translation>
+<translation id="8118489163946903409">പേയàµâ€Œà´®àµ†à´¨àµà´±àµ രീതി</translation>
<translation id="8131740175452115882">à´¸àµà´¥à´¿à´°àµ€à´•à´°à´¿à´•àµà´•àµà´•</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> à´Žà´¨àµà´¨à´¤à´¿à´¨àµà´±àµ† സെർവർ <ph name="BEGIN_ABBR" />DNS വിലാസം<ph name="END_ABBR" /> à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¾à´¨à´¾à´¯à´¿à´²àµà´².</translation>
<translation id="8149426793427495338">നിങàµà´™à´³àµà´Ÿàµ† à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿàµ¼ à´¸àµà´·àµà´ªàµâ€Œà´¤à´¿à´¯à´¿à´²à´¾à´¯à´¿.</translation>
@@ -775,6 +788,7 @@
<translation id="8349305172487531364">à´¬àµà´•àµà´®à´¾à´°àµâ€à´•àµà´•àµ ബാരàµâ€</translation>
<translation id="8363502534493474904">à´«àµà´²àµˆà´±àµà´±àµ മോഡൠഓഫാകàµà´•àµà´¨àµà´¨àµ</translation>
<translation id="8364627913115013041">സജàµà´œà´®à´¾à´•àµà´•à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´².</translation>
+<translation id="8368476060205742148">Google Play സേവനങàµà´™àµ¾</translation>
<translation id="8380941800586852976">അപകടകരമായതàµ</translation>
<translation id="8382348898565613901">നിങàµà´™àµ¾ à´…à´Ÿàµà´¤àµà´¤à´¿à´Ÿàµ† സനàµà´¦àµ¼à´¶à´¿à´šàµà´š à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµà´•àµ¾ ഇവിടെ ദൃശàµà´¯à´®à´¾à´•àµà´‚</translation>
<translation id="8398259832188219207">à´•àµà´°à´¾à´·àµ റിപàµà´ªàµ‹àµ¼à´Ÿàµà´Ÿàµ <ph name="UPLOAD_TIME" />-നൠഅപàµâ€Œà´²àµ‹à´¡àµà´šàµ†à´¯àµâ€Œà´¤àµ</translation>
@@ -783,32 +797,30 @@
<translation id="8428213095426709021">à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™à´³àµâ€</translation>
<translation id="8433057134996913067">ഇതൠനിങàµà´™à´³àµ† മികàµà´• വെബàµâ€Œà´¸àµˆà´±àµà´±àµà´•à´³à´¿àµ½ നിനàµà´¨àµà´‚ സൈൻ ഔടàµà´Ÿàµ ചെയàµà´¯à´¿à´•àµà´•àµà´‚.</translation>
<translation id="8437238597147034694">&amp;നീകàµà´•àµà´¨àµà´¨à´¤àµ പഴയപടിയാകàµà´•àµà´•</translation>
-<translation id="8456681095658380701">അസാധàµà´µà´¾à´¯ പേരàµ</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{ഒരൠകàµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡàµ}other{# à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡàµà´•àµ¾}}</translation>
<translation id="8483780878231876732">നിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿àµ½ നിനàµà´¨àµ കാർഡàµà´•àµ¾ ഉപയോഗികàµà´•à´¾àµ», Chrome-ൽ സൈൻ ഇൻ ചെയàµà´¯àµà´•</translation>
<translation id="8488350697529856933">ഇതിനൠബാധകമാകàµà´•àµà´¨àµà´¨àµ</translation>
-<translation id="8492969205326575646">കാർഡൠതരം ഉപയോഗികàµà´•à´¾à´¨à´¾à´µà´¿à´²àµà´²</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> à´ªàµà´°à´¤à´¿à´•à´°à´¿à´•àµà´•à´¾àµ» കൂടàµà´¤àµ½ സമയമെടàµà´¤àµà´¤àµ.</translation>
<translation id="852346902619691059">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> ഡൊമെയàµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ† നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿à´¨àµà´±àµ† à´“à´ªàµà´ªà´±àµ‡à´±àµà´±à´¿à´‚ഗൠസിസàµà´±àµà´±à´‚ വിശàµà´µà´¸à´¿à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിചàµà´šà´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">കാലഹരണപàµà´ªàµ†à´Ÿàµà´¨àµà´¨ വർഷം</translation>
<translation id="8543181531796978784">നിങàµà´™àµ¾à´•àµà´•àµ <ph name="BEGIN_ERROR_LINK" />à´¸àµà´°à´•àµà´·à´¾à´ªàµà´°à´¶àµâ€Œà´¨à´‚ റിപàµà´ªàµ‹àµ¼à´Ÿàµà´Ÿàµà´šàµ†à´¯àµà´¯à´¾à´‚<ph name="END_ERROR_LINK" /> à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½, à´¸àµà´°à´•àµà´·à´¯àµ† ബാധിചàµà´šàµ‡à´•àµà´•à´¾à´µàµà´¨àµà´¨ അപകട സാധàµà´¯à´¤à´•à´³àµ†à´•àµà´•àµà´±à´¿à´šàµà´šàµ ബോധàµà´¯à´®àµà´£àµà´Ÿàµ†à´™àµà´•à´¿àµ½ <ph name="BEGIN_LINK" />à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´²àµà´²à´¾à´¤àµà´¤ à´ˆ സൈറàµà´±àµ<ph name="END_LINK" />സനàµà´¦àµ¼à´¶à´¿à´•àµà´•àµà´•.</translation>
<translation id="8553075262323480129">പേജിനàµâ€à´±àµ† ഭാഷ നിരàµâ€â€Œà´£àµà´£à´¯à´¿à´•àµà´•à´¾à´¨àµâ€â€Œ കഴിയാതàµà´¤à´¤à´¿à´¨à´¾à´²àµâ€â€Œ വിവരàµâ€â€Œà´¤àµà´¤à´¨à´‚ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ.</translation>
<translation id="8559762987265718583">നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿à´¨àµà´±àµ† തീയതിയàµà´‚ സമയവàµà´‚ (<ph name="DATE_AND_TIME" />) തെറàµà´±à´¾à´¯à´¤à´¿à´¨à´¾àµ½ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ à´¸àµà´µà´•à´¾à´°àµà´¯ കണകàµà´·àµ» à´¸àµà´¥à´¾à´ªà´¿à´•àµà´•à´¾à´¨à´¾à´µà´¿à´²àµà´².</translation>
-<translation id="8570229484593575558">à´ˆ വിവരങàµà´™àµ¾ |സംരകàµà´·à´¿à´•àµà´•à´¿à´²àµà´²|:#നിങàµà´™à´³àµà´Ÿàµ† à´¬àµà´°àµ—സിംഗൠചരിതàµà´°à´‚#നിങàµà´™à´³àµà´Ÿàµ† തിരയലàµà´•àµ¾#à´•àµà´•àµà´•à´¿ ഡാറàµà´±</translation>
<translation id="8571890674111243710"><ph name="LANGUAGE" /> ലേകàµà´•àµ പേജൠവിവരàµâ€â€Œà´¤àµà´¤à´¨à´‚ ചെയàµà´¯àµà´¨àµà´¨àµ...</translation>
-<translation id="8584539743998202583">നിങàµà´™à´³àµà´Ÿàµ† ആകàµâ€Œà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿| à´¤àµà´Ÿàµ¼à´¨àµà´¨àµà´‚ ഇനിപàµà´ªà´±à´¯àµà´¨àµà´¨à´µà´¯àµâ€Œà´•àµà´•àµ| ദൃശàµà´¯à´®à´¾à´¯àµ‡à´•àµà´•àµà´‚:#നിങàµà´™àµ¾ സനàµà´¦àµ¼à´¶à´¿à´•àµà´•àµà´¨àµà´¨ വെബàµâ€Œà´¸àµˆà´±àµà´±àµà´•àµ¾à´•àµà´•àµ#നിങàµà´™à´³àµà´Ÿàµ† തൊഴിൽ ദാതാവിനàµ#നിങàµà´™à´³àµà´Ÿàµ† ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ സേവന ദാതാവിനàµ</translation>
<translation id="858637041960032120">ഫോൺ നം. ചേർകàµà´•àµ‚
</translation>
<translation id="859285277496340001">സാകàµâ€à´·àµà´¯à´ªà´¤àµà´°à´‚ അസാധàµà´µà´¾à´•àµà´•à´¿à´¯àµ‹ à´Žà´¨àµà´¨àµ പരിശോധികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ അതൠഒരൠമെകàµà´•à´¾à´¨à´¿à´¸à´¤àµà´¤àµ†à´¯àµà´‚ സൂചിപàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´².</translation>
<translation id="8620436878122366504">നിങàµà´™à´³àµà´Ÿàµ† à´°à´•àµà´·à´¿à´¤à´¾à´•àµà´•àµ¾ ഇതàµà´µà´°àµ† അംഗീകാരം നൽകിയിടàµà´Ÿà´¿à´²àµà´²</translation>
<translation id="8647750283161643317">à´Žà´²àµà´²à´¾à´‚ à´¸àµà´¥à´¿à´°à´®à´¾à´¯à´¿ à´ªàµà´¨à´ƒà´¸à´œàµà´œà´®à´¾à´•àµà´•àµà´•</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> ലേകàµà´•àµà´³àµà´³ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµâ€ à´Žà´¨àµâ€â€Œà´•àµà´°à´¿à´ªàµà´±àµà´±àµ ചെയàµà´¤à´¿à´Ÿàµà´Ÿà´¿à´²àµà´².</translation>
+<translation id="8718314106902482036">പേയàµâ€Œà´®àµ†à´¨àµà´±àµ പൂർതàµà´¤à´¿à´¯à´¾à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´²</translation>
<translation id="8725066075913043281">വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•</translation>
-<translation id="8728672262656704056">നിങàµà´™àµ¾ ആൾമാറാടàµà´Ÿà´¤àµà´¤à´¿à´²àµ‡à´•àµà´•àµ പോയി</translation>
+<translation id="8728672262656704056">നിങàµà´™àµ¾ അദൃശàµà´¯ വിൻഡോയിലാണàµ</translation>
<translation id="8730621377337864115">പൂർതàµà´¤à´¿à´¯à´¾à´•àµà´•à´¿</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="8759274551635299824">à´ˆ കാർഡൠകാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
<translation id="8790007591277257123">&amp;ഇലàµà´²à´¾à´¤à´¾à´•àµà´•àµà´¨àµà´¨à´¤àµ വീണàµà´Ÿàµà´‚ ചെയàµà´¯àµà´•</translation>
-<translation id="8798099450830957504">à´¸àµà´¥à´¿à´°à´¸àµà´¥à´¿à´¤à´¿</translation>
<translation id="8800988563907321413">നിങàµà´™à´³àµà´Ÿàµ† സമീപതàµà´¤àµà´³àµà´³ നിർദàµà´¦àµ‡à´¶à´™àµà´™àµ¾ ഇവിടെ ദൃശàµà´¯à´®à´¾à´•àµà´‚</translation>
<translation id="8820817407110198400">à´¬àµà´•àµà´•àµâ€Œà´®à´¾à´°àµâ€à´•àµà´•àµà´•à´³àµâ€</translation>
<translation id="883848425547221593">മറàµà´±àµà´³àµà´³ à´¬àµà´•àµà´•àµâ€Œà´®à´¾à´°àµâ€â€Œà´•àµà´•àµà´•à´³àµâ€â€Œ</translation>
@@ -818,6 +830,7 @@
<translation id="8866481888320382733">നയ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾ പാഴàµâ€Œà´¸àµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨à´¤à´¿àµ½ പിശകàµ</translation>
<translation id="8866959479196209191">à´ˆ പേജൠപറയàµà´¨àµà´¨à´¤àµ:</translation>
<translation id="8870413625673593573">സമീപകാലതàµà´¤àµ à´…à´Ÿà´šàµà´šà´µ</translation>
+<translation id="8874824191258364635">ശരിയായ കാർഡൠനമàµà´ªàµ¼ നൽകàµà´•</translation>
<translation id="8876793034577346603">നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ കോൺഫിഗറേഷൻ പാഴàµâ€Œà´¸àµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨à´¤à´¿àµ½ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
<translation id="8877192140621905067">à´¸àµà´¥à´¿à´°àµ€à´•à´°à´¿à´šàµà´šàµ à´•à´´à´¿à´žàµà´žà´¾àµ½, നിങàµà´™à´³àµà´Ÿàµ† കാർഡൠവിശദാംശങàµà´™àµ¾ à´ˆ സൈറàµà´±àµà´®à´¾à´¯à´¿ പങàµà´•à´¿à´Ÿàµà´‚</translation>
<translation id="8889402386540077796">à´¹àµà´¯àµ‚</translation>
@@ -827,7 +840,6 @@
<translation id="8931333241327730545">à´ˆ കാർഡൠനിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿àµ½ സംരകàµà´·à´¿à´•àµà´•à´£àµ‹?</translation>
<translation id="8932102934695377596">നിങàµà´™à´³àµà´Ÿàµ† à´•àµà´²àµ‹à´•àµà´•àµ വളരെ പിനàµà´¨à´¿à´²à´¾à´£àµ</translation>
<translation id="8954894007019320973">(à´¤àµà´Ÿà´°àµâ€.)</translation>
-<translation id="895548565263634352"><ph name="ARTICLE_PUBLISHER" /> à´Žà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµà´‚ മറàµà´±àµ <ph name="OTHER_ARTICLE_COUNT" /> à´ªàµà´°à´¸à´¾à´§à´•à´°à´¿àµ½ നിനàµà´¨àµà´®àµà´³àµà´³ à´¸àµâ€Œà´±àµà´±àµ‹à´±à´¿à´•àµ¾ വായികàµà´•àµà´•</translation>
<translation id="8971063699422889582">സെരàµâ€à´µà´±à´¿à´¨àµâ€à´±àµ† സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿàµ.</translation>
<translation id="8986494364107987395">Google ലേകàµà´•àµ à´¸àµà´µà´ªàµà´°àµ‡à´°à´¿à´¤à´®à´¾à´¯à´¿ ഉപയോഗ à´¸àµà´¥à´¿à´¤à´¿à´µà´¿à´µà´°à´•àµà´•à´£à´•àµà´•àµà´•à´³àµà´‚ à´•àµà´°à´¾à´·àµ റിപàµà´ªàµ‹à´°àµâ€à´Ÿàµà´Ÿàµà´•à´³àµà´‚ അയയàµà´•àµà´•àµà´•</translation>
<translation id="8987927404178983737">മാസം</translation>
@@ -845,7 +857,6 @@
<translation id="9068849894565669697">വർണàµà´£à´‚ തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•</translation>
<translation id="9076283476770535406">ഇതിൽ à´®àµà´¤à´¿àµ¼à´¨àµà´¨à´µàµ¼à´•àµà´•àµà´³àµà´³ ഉളàµà´³à´Ÿà´•àµà´•à´‚ ഉണàµà´Ÿà´¾à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚</translation>
<translation id="9078964945751709336">കൂടàµà´¤àµ½ വിവരങàµà´™àµ¾ ആവശàµà´¯à´®à´¾à´£àµ</translation>
-<translation id="9094175695478007090">പേയàµâ€Œà´®àµ†à´¨àµà´±àµ ആപàµà´ªàµ ആരംഭികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´².</translation>
<translation id="9103872766612412690">നിങàµà´™à´³àµà´Ÿàµ† വിവരങàµà´™àµ¾ പരിരകàµà´·à´¿à´•àµà´•à´¾àµ» സാധാരണയായി <ph name="SITE" />, എൻകàµà´°à´¿à´ªàµâ€Œà´·àµ» ഉപയോഗികàµà´•àµà´¨àµà´¨àµ. ഇപàµà´ªàµ‹àµ¾ <ph name="SITE" /> സൈറàµà´±à´¿à´²àµ‡à´•àµà´•àµ കണകàµâ€Œà´±àµà´±àµà´šàµ†à´¯àµà´¯à´¾àµ» Chromium à´¶àµà´°à´®à´¿à´šàµà´šà´ªàµà´ªàµ‹àµ¾, അസാധാരണമായതàµà´‚ തെറàµà´±à´¾à´¯à´¤àµà´®à´¾à´¯ à´•àµà´°àµ†à´¡àµ»à´·àµà´¯à´²àµà´•àµ¾ വെബàµâ€Œà´¸àµˆà´±àµà´±àµ തിരികെ അയചàµà´šàµ. ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ <ph name="SITE" /> à´Žà´¨àµà´¨à´¤à´¾à´¯à´¿ ഭാവികàµà´•à´¾àµ» à´¶àµà´°à´®à´¿à´•àµà´•àµà´®àµà´ªàµ‹à´´àµ‹ Wi-Fi സൈൻ ഇൻ à´¸àµâ€Œà´•àµà´°àµ€àµ», കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´®àµà´ªàµ‹à´´àµ‹ ആണൠഇങàµà´™à´¨àµ† സംഭവികàµà´•à´¾à´¨à´¿à´Ÿà´¯àµà´³àµà´³à´¤àµ. à´à´¤àµ†à´™àµà´•à´¿à´²àµà´‚ ഡാറàµà´± കൈമാറàµà´¨àµà´¨à´¤à´¿à´¨àµà´®àµà´®àµà´ªàµ Chromium കണകàµà´·àµ» അവസാനിപàµà´ªà´¿à´šàµà´šà´¤à´¿à´¨à´¾àµ½, നിങàµà´™à´³àµà´Ÿàµ† വിവരങàµà´™àµ¾ à´¤àµà´Ÿàµ¼à´¨àµà´¨àµà´‚ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´¯à´¿à´°à´¿à´•àµà´•àµà´‚.</translation>
<translation id="9137013805542155359">യഥാരàµâ€à´¤àµà´¥à´®à´¾à´¯à´¤àµ കാണികàµà´•àµà´•</translation>
<translation id="9137248913990643158">à´ˆ ആപàµà´ªàµ ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ à´®àµà´®àµà´ªàµ ആരംഭിചàµà´šàµ Chrome-ൽ സൈൻ ഇൻ ചെയàµà´¯àµà´•.</translation>
diff --git a/chromium/components/strings/components_strings_mr.xtb b/chromium/components/strings/components_strings_mr.xtb
index 5b836daebc6..ee40a5f4c32 100644
--- a/chromium/components/strings/components_strings_mr.xtb
+++ b/chromium/components/strings/components_strings_mr.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="mr">
<translation id="1008557486741366299">सधà¥à¤¯à¤¾ नाही</translation>
<translation id="1015730422737071372">अतिरिकà¥à¤¤ तपशील पà¥à¤°à¤¦à¤¾à¤¨ करा</translation>
+<translation id="1021110881106174305">सà¥à¤µà¥€à¤•à¤¾à¤°à¤²à¥‡à¤²à¥€ कारà¥à¤¡</translation>
<translation id="1032854598605920125">घडà¥à¤¯à¤¾à¤³à¤¾à¤šà¥à¤¯à¤¾ दिशेने फिरवा</translation>
<translation id="1038842779957582377">अजà¥à¤žà¤¾à¤¤ नाव</translation>
<translation id="1050038467049342496">अनà¥à¤¯ अॅपà¥à¤¸ बंद करा</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">मूलà¥à¤¯ लपवा</translation>
<translation id="1228893227497259893">चà¥à¤•à¥€à¤šà¤¾ असà¥à¤¤à¤¿à¤¤à¥à¤µ ओळखकरà¥à¤¤à¤¾</translation>
<translation id="1232569758102978740">अशीरà¥à¤·à¤•à¤¾à¤‚कित</translation>
+<translation id="1263231323834454256">वाचन सूची</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> वाजता कà¥à¤°à¥…श अहवाल कॅपà¥à¤šà¤° केला (अदà¥à¤¯à¤¾à¤ª अपलोड केलेला नाही किंवा दà¥à¤°à¥à¤²à¤•à¥à¤· केले)</translation>
<translation id="1285320974508926690">या साइटचा कधीही भाषांतर करॠनका</translation>
<translation id="129553762522093515">अलीकडे बंद केलेले</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromium सà¥à¤µà¤¯à¤‚भरण सेटिंगà¥à¤œ...</translation>
<translation id="1374468813861204354">सूचना</translation>
<translation id="1375198122581997741">आवृतà¥à¤¤à¥€à¤¬à¤¦à¥à¤¦à¤²</translation>
+<translation id="1377321085342047638">कारà¥à¤¡ नंबर</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> नी कोणताही डेटा पाठविला नाही.</translation>
<translation id="1407135791313364759">सरà¥à¤µ उघडा</translation>
<translation id="1413809658975081374">गोपनीयता तà¥à¤°à¥à¤Ÿà¥€</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">इतिहास</translation>
<translation id="1645368109819982629">असमरà¥à¤¥à¤¿à¤¤ पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¥‰à¤²</translation>
<translation id="1656489000284462475">घेणे</translation>
+<translation id="1663943134801823270">कारà¥à¤¡ आणि पतà¥à¤¤à¥‡ Chrome कडील आहेत. आपण तà¥à¤¯à¤¾à¤‚ना <ph name="BEGIN_LINK" />सेटिंगà¥â€à¤œ<ph name="END_LINK" /> मधून वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करू शकता.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> आपली माहिती संरकà¥à¤·à¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ सामानà¥à¤¯à¤¤à¤ƒ कूटबदà¥à¤§à¥€à¤•à¤°à¤£ वापरते. Google Chrome ने यावेळी <ph name="SITE" /> शी कनेकà¥â€à¤Ÿ करणà¥â€à¤¯à¤¾à¤šà¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ केला तेवà¥â€à¤¹à¤¾, वेबसाइटने असामानà¥à¤¯ आणि अयोगà¥à¤¯ कà¥à¤°à¥‡à¤¡à¥‡à¤¨à¥à¤¶à¤¿à¤¯à¤² परत पाठविले. à¤à¤•à¤¤à¤° आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ <ph name="SITE" /> असलà¥à¤¯à¤¾à¤šà¥€ बतावणी करणà¥à¤¯à¤¾à¤šà¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करतो तेवà¥â€à¤¹à¤¾ किंवा Wi-Fi साइन इन सà¥à¤•à¥à¤°à¥€à¤¨à¤¨à¥‡ कनेकà¥à¤¶à¤¨à¤®à¤§à¥à¤¯à¥‡ वà¥à¤¯à¤¤à¥à¤¯à¤¯ आणले तेवà¥â€à¤¹à¤¾ हे घडू शकते. कोणतà¥à¤¯à¤¾à¤¹à¥€ डेटाची अदलाबदल करणà¥à¤¯à¤¾à¤ªà¥‚रà¥à¤µà¥€ Google Chrome ने कनेकà¥à¤¶à¤¨ थांबविलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ आपली माहिती अदà¥à¤¯à¤¾à¤ª सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ आहे.</translation>
<translation id="168328519870909584">सधà¥â€à¤¯à¤¾ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> वर असलेले आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥‡ आपली माहिती (उदाहरणारà¥à¤¥, फोटो, संकेतशबà¥à¤¦, संदेश आणि कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡) चोरणारे किंवा हटविणारे धोकादायक अâ€à¥…पà¥â€à¤¸ कदाचित आपलà¥à¤¯à¤¾ डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¤µà¤° सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करणà¥à¤¯à¤¾à¤šà¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करू शकतात.</translation>
<translation id="168841957122794586">सरà¥à¤µà¥à¤¹à¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤¾à¤¤ à¤à¤• कमकà¥à¤µà¤¤ कà¥à¤°à¤¿à¤ªà¥à¤Ÿà¥‹à¤—à¥à¤°à¤¾à¤«à¤¿à¤• की आहे.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">या साइटला भेट देणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ आपलà¥à¤¯à¤¾à¤²à¤¾ <ph name="NAME" /> कडील परवानगी आवशà¥à¤¯à¤• आहे</translation>
+<translation id="1721424275792716183">* फीलà¥à¤¡ आवशà¥à¤¯à¤• आहे</translation>
<translation id="1728677426644403582">आपण वेब पृषà¥à¤ à¤¾à¤šà¤¾ सà¥à¤°à¥‹à¤¤ पाहत आहात</translation>
+<translation id="173080396488393970">या पà¥à¤°à¤•à¤¾à¤°à¤šà¥à¤¯à¤¾ कारà¥à¤¡à¤²à¤¾ सहायà¥à¤¯ नाही</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">सिसà¥à¤Ÿà¥€à¤® पà¥à¤°à¤¶à¤¾à¤¸à¤•à¤¾à¤¶à¥€ संपरà¥à¤• साधणà¥à¤¯à¤¾à¤šà¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.</translation>
+<translation id="1740951997222943430">वैध समापà¥à¤¤à¥€ महिना पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करा</translation>
<translation id="1745358365027406341">पृषà¥à¤  नंतर डाउनलोड करा</translation>
<translation id="17513872634828108">खà¥à¤²à¥‡ टॅब</translation>
<translation id="1753706481035618306">पृषà¥à¤  कà¥à¤°à¤®à¤¾à¤‚क</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">कृपया आपले संंकालित सांकेतिक वाकà¥à¤¯à¤¾à¤‚श अदà¥à¤¯à¤¤à¤¨à¤¿à¤¤ करा.</translation>
<translation id="1787142507584202372">आपले खà¥à¤²à¥‡ टॅब येथे दिसतात</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">पदà¥à¤§à¤¤à¥€ आणि आवशà¥à¤¯à¤•à¤¤à¤¾ वितरण तपासणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ वितरण पतà¥à¤¤à¤¾ निवडा.</translation>
+<translation id="1803264062614276815">कारà¥à¤¡à¤§à¤¾à¤°à¤•à¤¾à¤šà¥‡ नाव</translation>
<translation id="1803678881841855883">Google सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚गला अलीकडे <ph name="SITE" /> वर <ph name="BEGIN_LINK" />मालवेअर आढळले आहे<ph name="END_LINK" />. सामानà¥à¤¯à¤¤à¤ƒ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ असलेलà¥à¤¯à¤¾ वेबसाइट काहीवेळा मालवेअरमà¥à¤³à¥‡ संकà¥à¤°à¤®à¤¿à¤¤ à¤à¤¾à¤²à¥‡à¤²à¥à¤¯à¤¾ असतात. à¤à¤• जà¥à¤žà¤¾à¤¤ मालवेअर वितरक असलेलà¥à¤¯à¤¾, <ph name="SUBRESOURCE_HOST" /> कडून दà¥à¤°à¥à¤­à¤¾à¤µà¤¨à¤¾à¤ªà¥‚रà¥à¤£ सामगà¥à¤°à¥€ येते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">जोडले: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">अवैध विनंती किंवा विनंती मापदंड</translation>
<translation id="1826516787628120939">तपासत आहे</translation>
<translation id="1834321415901700177">या साइटमधà¥à¤¯à¥‡ धोकादायक पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® आहेत</translation>
<translation id="1842969606798536927">देय दà¥à¤¯à¤¾</translation>
-<translation id="1864455488461349376">वितरण परà¥à¤¯à¤¾à¤¯</translation>
<translation id="1871208020102129563">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ निशà¥à¤šà¤¿à¤¤ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सरà¥à¤µà¥à¤¹à¤° वापरणà¥â€à¤¯à¤¾à¤¸ सेट करणà¥â€à¤¯à¤¾à¤¤ आले आहे, .pac सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ URL नवà¥à¤¹à¥‡.</translation>
<translation id="1871284979644508959">आवशà¥à¤¯à¤• फीलà¥à¤¡</translation>
<translation id="187918866476621466">पà¥à¤°à¤¾à¤°à¤‚भ पृषà¥à¤  उघडा</translation>
<translation id="1883255238294161206">सूची संकà¥à¤šà¤¿à¤¤ करा</translation>
<translation id="1898423065542865115">फिलà¥à¤Ÿà¤° करणे</translation>
<translation id="194030505837763158"><ph name="LINK" /> दà¥à¤µà¥à¤¯à¤¾à¤•à¤¡à¥‡ जा</translation>
-<translation id="1946821392246652573">कारà¥à¤¡ सà¥à¤µà¥€à¤•à¤¾à¤°à¤²à¥‡</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="1973335181906896915">कà¥à¤°à¤®à¥€à¤•à¤°à¤£ तà¥à¤°à¥à¤Ÿà¥€</translation>
<translation id="1974060860693918893">पà¥à¤°à¤—त</translation>
<translation id="1978555033938440688">फरà¥à¤®à¤µà¥‡à¤¯à¤° आवृतà¥à¤¤à¥€</translation>
+<translation id="1995859865337580572">कृपया तà¥à¤®à¤šà¥à¤¯à¤¾ CVC ची पडताळणी करा</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{आणि 1 अधिक}one{आणि # अधिक}other{आणि # अधिक}}</translation>
-<translation id="2020194265157481222">कारà¥à¤¡à¤¾à¤µà¤° नाव आवशà¥à¤¯à¤• आहे</translation>
<translation id="2025186561304664664">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सà¥à¤µà¤¯à¤‚चलित â€à¤•à¥‰à¤¨à¥à¤«à¤¿à¤—रेशनवर सेट करणà¥â€à¤¯à¤¾à¤¤ आली.</translation>
<translation id="2030481566774242610">आपलà¥à¤¯à¤¾à¤²à¤¾ असे मà¥à¤¹à¤£à¤¾à¤¯à¤šà¥‡ होते <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ आणि फायरवॉल तपासणे<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">आज</translation>
<translation id="2154054054215849342">आपलà¥à¤¯à¤¾ डोमेनसाठी संकालन उपलबà¥à¤§ नाही</translation>
<translation id="2154484045852737596">कारà¥à¤¡ संपादित करा</translation>
-<translation id="2156993118928861787">अवैध पतà¥à¤¤à¤¾</translation>
<translation id="2166049586286450108">पूरà¥à¤£ पà¥à¤°à¤¶à¤¾à¤¸à¤¨ पà¥à¤°à¤µà¥‡à¤¶</translation>
<translation id="2166378884831602661">ही साइट सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ कनेकà¥à¤¶à¤¨ पà¥à¤°à¤¦à¤¾à¤¨ करू शकत नाही</translation>
<translation id="2181821976797666341">धोरणे</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 पतà¥à¤¤à¤¾}one{# पतà¥à¤¤à¤¾}other{# पतà¥à¤¤à¥‡}}</translation>
+<translation id="2202020181578195191">वैध समापà¥à¤¤à¥€ वरà¥à¤· पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करा</translation>
<translation id="2212735316055980242">धोरण आढळले नाही</translation>
<translation id="2213606439339815911">पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¥à¤¯à¤¾ आणत आहे...</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />निदान अॅप<ph name="END_LINK" /> वापरून आपलà¥à¤¯à¤¾ कनेकà¥à¤¶à¤¨à¤šà¥‡ निराकरण करा</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">आपला इंटरनेट पà¥à¤°à¤µà¥‡à¤¶ अवरोधित केला आहे</translation>
<translation id="230155334948463882">नवीन कारà¥à¤¡?</translation>
<translation id="2305919008529760154">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤šà¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤šà¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° फसवणà¥à¤•à¥€à¤¨à¥‡ जारी केले असावे. हे कदाचित चà¥à¤•à¥€à¤šà¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ आपलà¥à¤¯à¤¾ कनेकà¥à¤¶à¤¨à¤®à¤§à¥à¤¯à¥‡ वà¥à¤¯à¤¤à¥à¤¯à¤¯ आणत असलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असावे. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">कारà¥à¤¡ आणि पतà¥à¤¤à¤¾ परà¥à¤¯à¤¾à¤¯ आपले (<ph name="ACCOUNT_EMAIL" />) Google खाते आणि Chrome मधील आहेत. आपण<ph name="BEGIN_LINK" />सेटिंगà¥à¤œ<ph name="END_LINK" /> मधà¥à¤¯à¥‡ ते वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करू शकता.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> साठी वापरकरà¥à¤¤à¤¾à¤¨à¤¾à¤µ आणि संकेतशबà¥à¤¦ आवशà¥à¤¯à¤• आहेत.</translation>
<translation id="2318774815570432836">आपण <ph name="SITE" /> ला आतà¥à¤¤à¤¾ भेट देऊ शकत नाही कारण वेबसाइट HSTS वापरते. नेटवरà¥à¤• तà¥à¤°à¥à¤Ÿà¥€ आणि आकà¥à¤°à¤®à¤£à¥‡ सामानà¥à¤¯à¤¤à¤ƒ तातà¥à¤ªà¥à¤°à¤¤à¥€ असतात, यामà¥à¤³à¥‡ हे पृषà¥à¤  कदाचित नंतर कारà¥à¤¯ करेल. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">इतर बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">à¤à¤‚टरपà¥à¤°à¤¾à¤‡à¤ डीफॉलà¥à¤Ÿ</translation>
<translation id="2386255080630008482">सरà¥à¤µà¥à¤¹à¤°à¤šà¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निरसà¥à¤¤ केले गेले.</translation>
<translation id="2392959068659972793">कोणतेही मूलà¥à¤¯ सेट केलà¥à¤¯à¤¾à¤¶à¤¿à¤µà¤¾à¤¯ धोरणे दरà¥à¤¶à¤µà¤¾</translation>
+<translation id="239429038616798445">ही शिपिंग पदà¥à¤§à¤¤ उपलबà¥à¤§ नाही. वेगळी पदà¥à¤§à¤¤ वापरून पहा.</translation>
<translation id="2396249848217231973">&amp;हटवा पूरà¥à¤µà¤µà¤¤ करा</translation>
<translation id="2460160116472764928">Google सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚गला अलीकडे <ph name="SITE" /> वर <ph name="BEGIN_LINK" />मालवेअर आढळले आहे<ph name="END_LINK" />. सामानà¥à¤¯à¤¤à¤ƒ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ असलेलà¥à¤¯à¤¾ वेबसाइट काहीवेळा मालवेअरमà¥à¤³à¥‡ संकà¥à¤°à¤®à¤¿à¤¤ à¤à¤¾à¤²à¥‡à¤²à¥à¤¯à¤¾ असतात. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">भरून टाका</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />नेटवरà¥à¤• निदान चालविणे<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">अवैध शोध URL.</translation>
<translation id="2491120439723279231">सरà¥à¤µà¥à¤¹à¤°à¤šà¥à¤¯à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤¾à¤¤ तà¥à¤°à¥à¤Ÿà¥€ आहेत.</translation>
-<translation id="24943777258388405">अवैध फोन नंबर</translation>
<translation id="2495083838625180221">JSON विशà¥à¤²à¥‡à¤·à¤•</translation>
<translation id="2495093607237746763">चेक केलà¥à¤¯à¤¾à¤¸, अधिक जलद फॉरà¥à¤® भरणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° Chromium आपलà¥à¤¯à¤¾ कारà¥à¤¡à¤šà¥€ à¤à¤• पà¥à¤°à¤¤ संचयित करेल.</translation>
<translation id="2498091847651709837">नवीन कारà¥à¤¡ सà¥à¤•à¥…न करा</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> नी à¤à¤• अवैध पà¥à¤°à¤¤à¤¿à¤¸à¤¾à¤¦ पाठविला.</translation>
<translation id="2552545117464357659">थोडे नवीन</translation>
<translation id="2556876185419854533">&amp; संपादित करा पूरà¥à¤µà¤µà¤¤ करा</translation>
+<translation id="2587730715158995865"><ph name="ARTICLE_PUBLISHER" /> कडील. हे आणि अनà¥à¤¯ <ph name="OTHER_ARTICLE_COUNT" /> कथा वाचा.</translation>
<translation id="2587841377698384444">शबà¥à¤¦à¤•à¥‹à¤¶ API आयडी:</translation>
<translation id="2597378329261239068">हा दसà¥à¤¤à¤à¤µà¤œ संकेतशबà¥à¤¦ संरकà¥à¤·à¤¿à¤¤ आहे. कृपया संकेतशबà¥à¤¦ पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करा.</translation>
<translation id="2609632851001447353">तफावत</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />कनेकà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€ निदान चालविणे<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">ओके</translation>
<translation id="2742870351467570537">निवडलेले आयटम काढा</translation>
+<translation id="277133753123645258">शिपिंग पदà¥à¤§à¤¤</translation>
<translation id="277499241957683684">डिवà¥à¤¹à¤¾à¤‡à¤¸ रेकॉरà¥à¤¡ गहाळ</translation>
<translation id="2784949926578158345">कनेकà¥à¤¶à¤¨ रीसेट केले.</translation>
<translation id="2794233252405721443">साइट अवरोधित केली</translation>
-<translation id="2812680587231492111">तो पिकअप परà¥à¤¯à¤¾à¤¯ उपलबà¥à¤§ नाही. à¤à¤• भिनà¥à¤¨ परà¥à¤¯à¤¾à¤¯ वापरून पहा.</translation>
<translation id="2824775600643448204">पतà¥à¤¤à¤¾ आणि शोध बार</translation>
<translation id="2826760142808435982">कनेकà¥à¤¶à¤¨ <ph name="CIPHER" /> वापरून आणि की विनिमय तंतà¥à¤° मà¥à¤¹à¤£à¥‚न <ph name="KX" /> वापर कूटबदà¥à¤§ आणि पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¥ƒà¤¤ केले आहे.</translation>
<translation id="2835170189407361413">फॉरà¥à¤® कà¥à¤²à¤¿à¤…र करा</translation>
-<translation id="2849041323157393173">तो वितरण परà¥à¤¯à¤¾à¤¯ उपलबà¥à¤§ नाही. à¤à¤• भिनà¥à¤¨ परà¥à¤¯à¤¾à¤¯ वापरून पहा.</translation>
<translation id="2889159643044928134">रीलोड करॠनका</translation>
<translation id="2900469785430194048">हे वेबपृषà¥à¤  पà¥à¤°à¤¦à¤°à¥à¤¶à¤¿à¤¤ करणà¥à¤¯à¤¾à¤šà¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करताना Google Chrome ची मेमरी संपली आहे.</translation>
<translation id="2909946352844186028">à¤à¤• नेटवरà¥à¤• बदल आढळला.</translation>
<translation id="2916038427272391327">अनà¥à¤¯ पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® बंद करा</translation>
<translation id="2922350208395188000">सरà¥à¤µà¥à¤¹à¤°à¤šà¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° तपासणे शकà¥à¤¯ नाही.</translation>
+<translation id="2928905813689894207">बिलिंग पतà¥à¤¤à¤¾</translation>
<translation id="2948083400971632585">आपण सेटिंगà¥à¤œ पृषà¥à¤ à¤¾à¤µà¤°à¥‚न à¤à¤•à¤¾ कनेकà¥à¤¶à¤¨à¤¸à¤¾à¤ à¥€ कॉनà¥à¤«à¤¿à¤—र केलेले कोणतेही पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ अकà¥à¤·à¤® करू शकता.</translation>
<translation id="2955913368246107853">शोध बार बंद करा</translation>
<translation id="2958431318199492670">नेटवरà¥à¤• कॉनà¥à¤«à¤¿à¤—रेशन ONC मानकाचे पालन करत नाही. कॉनà¥à¤«à¤¿à¤—रेशनचे भाग आयात केले जाऊ शकत नाहीत.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">à¤à¤• सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ कनेकà¥â€à¤¶à¤¨ सà¥â€à¤¥à¤¾à¤ªà¤¿à¤¤ करणà¥â€à¤¯à¤¾à¤ªà¥‚रà¥à¤µà¥€, आपले घडà¥â€à¤¯à¤¾à¤³ योगà¥à¤¯à¤°à¤¿à¤¤à¥à¤¯à¤¾ सेट केले असणे आवशà¥à¤¯à¤• आहे. वेबसाइट तà¥à¤¯à¤¾à¤‚ना सà¥â€à¤µà¤¤:ला ओळखणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ वापरतात ती पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¥‡ केवळ निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ केलेलà¥â€à¤¯à¤¾ कालावधीसाठी वैध असलà¥à¤¯à¤¾à¤¨à¥‡ हे असू शकते. आपलà¥â€à¤¯à¤¾ डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¤šà¥‡ घडà¥â€à¤¯à¤¾à¤³ चà¥à¤•à¥€à¤šà¥‡ असलà¥â€à¤¯à¤¾à¤®à¥à¤³à¥‡, Google Chrome ही पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¥‡ सतà¥à¤¯à¤¾à¤ªà¤¿à¤¤ करू शकत नाही.</translation>
<translation id="2972581237482394796">&amp;पà¥à¤¨à¥à¤¹à¤¾ करा</translation>
<translation id="2985306909656435243">सकà¥à¤·à¤® केलà¥â€à¤¯à¤¾à¤¸, Chromium जलदपणे फॉरà¥à¤® भरणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ आपलà¥â€à¤¯à¤¾ कारà¥à¤¡à¤šà¥€ à¤à¤• पà¥à¤°à¤¤ या डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¤µà¤° संगà¥à¤°à¤¹à¤¿à¤¤ करेल.</translation>
+<translation id="2985398929374701810">वैध पतà¥à¤¤à¤¾ पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करा</translation>
+<translation id="2986368408720340940">ही पिकअप पदà¥à¤§à¤¤ उपलबà¥à¤§ नाही. वेगळी पदà¥à¤§à¤¤ वापरून पहा.</translation>
<translation id="2991174974383378012">वेबसाइटसह शेअर करीत आहे</translation>
<translation id="3005723025932146533">जतन केलेली पà¥à¤°à¤¤ दरà¥à¤¶à¤µà¤¾</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> साठी CVC पà¥à¤°à¤µà¤¿à¤·à¥â€à¤Ÿ करा. आपण पà¥à¤·à¥à¤Ÿà¥€ केलà¥à¤¯à¤¾à¤µà¤°, आपले कारà¥à¤¡ तपशील या साइटसह सामायिक केले जातील.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{संकालित डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸à¤µà¤° किमान 1 आयटम}=1{1 आयटम (आणि संकालित डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸à¤µà¤° आणखी)}one{# आयटम (आणि संकालित डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸à¤µà¤° आणखी)}other{# आयटम (आणि संकालित डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸à¤µà¤° आणखी)}}</translation>
<translation id="3041612393474885105">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° माहिती...</translation>
<translation id="3063697135517575841">Chrome यावेळी आपलà¥à¤¯à¤¾ कारà¥à¤¡à¤šà¥€ पà¥à¤·à¥à¤Ÿà¥€ करणà¥à¤¯à¤¾à¤¤ अकà¥à¤·à¤® होते. कृपया नंतर पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.</translation>
+<translation id="3064966200440839136">बाहà¥à¤¯ अनà¥à¤ªà¥à¤°à¤¯à¥‹à¤— दà¥à¤µà¤¾à¤°à¥‡ देय देणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ गà¥à¤ªà¥à¤¤ मोड सोडत आहे. सà¥à¤°à¥ ठेवायचे?</translation>
<translation id="3093245981617870298">आपण ऑफलाइन आहात.</translation>
<translation id="3105172416063519923">मालमतà¥à¤¤à¤¾ आयडी:</translation>
<translation id="3109728660330352905">हे पृषà¥à¤  पाहणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ आपण पà¥à¤°à¤¾à¤§à¤¿à¤•à¥ƒà¤¤ नाही.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />कनेकà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€ निदान चालवून पहा<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">पà¥à¤°à¤¤à¤¿à¤¸à¤¾à¤¦ डीकोड करणà¥à¤¯à¤¾à¤¤ अयशसà¥à¤µà¥€</translation>
-<translation id="3149891296864842641">वहनावळ परà¥à¤¯à¤¾à¤¯</translation>
<translation id="3150653042067488994">तातà¥à¤ªà¥à¤°à¤¤à¥€ सरà¥à¤µà¥à¤¹à¤° तà¥à¤°à¥à¤Ÿà¥€</translation>
+<translation id="3154506275960390542">या पृषà¥à¤ à¤¾à¤µà¤° à¤à¤• फॉरà¥à¤® आहे जो कदाचित सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤ªà¤£à¥‡ सबमिट होणार नाही. आपण पाठविलेला डेटा पà¥à¤°à¤µà¤¾à¤¸à¤¾à¤¦à¤°à¤®à¥à¤¯à¤¾à¤¨ इतर पाहू शकतात किंवा सरà¥à¤µà¥à¤¹à¤° पà¥à¤°à¤¾à¤ªà¥à¤¤ करत असलेलà¥à¤¯à¤¾ आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¦à¥à¤µà¤¾à¤°à¥‡ सà¥à¤§à¤¾à¤°à¤¿à¤¤ केले जाऊ शकते.</translation>
<translation id="3157931365184549694">पà¥à¤¨à¤°à¥à¤¸à¤‚चयित करा</translation>
<translation id="3167968892399408617">गà¥à¤ªà¥à¤¤ मोडमधà¥â€à¤¯à¥‡ आपण पाहता ती पृषà¥â€à¤ à¥‡ आपण आपले सरà¥à¤µ गà¥à¤ªà¥à¤¤ टॅब बंद केलà¥â€à¤¯à¤¾à¤¨à¤‚तर आपला बà¥à¤°à¤¾à¤‰à¤à¤° इतिहास, कà¥à¤•à¥€ सà¥à¤Ÿà¥‹à¤…र किंवा शोध इतिहासामधà¥â€à¤¯à¥‡ असणार नाहीत. आपण डाउनलोड करता तà¥à¤¯à¤¾ कोणतà¥à¤¯à¤¾à¤¹à¥€ फायली किंवा आपण केलेले बà¥à¤•à¤®à¤¾à¤°à¥à¤• ठेवले जातील.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">या साइटवर पà¥à¤°à¤µà¥‡à¤¶ करणà¥à¤¯à¤¾à¤šà¥€ आपली विनंती <ph name="NAME" /> कडे पाठविली जाऊ शकली नाही. कृपया पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.</translation>
<translation id="3355823806454867987">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सेटिंगà¥à¤œ बदला...</translation>
<translation id="3369192424181595722">घडà¥à¤¯à¤¾à¤³ तà¥à¤°à¥à¤Ÿà¥€</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> अधिक आयटम...</translation>
<translation id="337363190475750230">तरतूद रदà¥à¤¦ केली</translation>
<translation id="3377188786107721145">धोरण विशà¥à¤²à¥‡à¤·à¤£ तà¥à¤°à¥à¤Ÿà¥€</translation>
<translation id="3380365263193509176">अजà¥à¤žà¤¾à¤¤ तà¥à¤°à¥à¤Ÿà¥€</translation>
<translation id="3380864720620200369">कà¥à¤²à¤¾à¤¯à¤‚ट आयडी:</translation>
<translation id="3391030046425686457">वितरण पतà¥à¤¤à¤¾</translation>
+<translation id="3395827396354264108">पिकअप पदà¥à¤§à¤¤</translation>
<translation id="340013220407300675">आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥‡ कदाचित <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> वरून आपली माहिती चोरणà¥à¤¯à¤¾à¤šà¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करत असू शकतात (उदाहरणारà¥à¤¥, संकेतशबà¥à¤¦, संदेश किंवा कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡).</translation>
<translation id="3422248202833853650">मेमरी मोकळी करणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ अनà¥à¤¯ पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® मधून बाहर पडणà¥à¤¯à¤¾à¤šà¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> सधà¥à¤¯à¤¾ आवाकà¥à¤¯à¤¾à¤¬à¤¾à¤¹à¥‡à¤° आहे.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">मधà¥à¤¯à¤‚तर पà¥à¤°à¤¾à¤ªà¥à¤¤ करा:</translation>
<translation id="3462200631372590220">पà¥à¤°à¤—त लपवा</translation>
+<translation id="3467763166455606212">कारà¥à¤¡à¤§à¤¾à¤°à¤•à¤¾à¤šà¥‡ नाव आवशà¥à¤¯à¤•</translation>
+<translation id="3478058380795961209">कालबाहà¥à¤¯à¤¤à¤¾ महिना:</translation>
<translation id="3479539252931486093">हे अनपेकà¥à¤·à¤¿à¤¤ होते? <ph name="BEGIN_LINK" />आमà¥à¤¹à¤¾à¤²à¤¾ कळवा<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">सधà¥à¤¯à¤¾ नाही</translation>
<translation id="348000606199325318">कà¥à¤°à¥…श आयडी <ph name="CRASH_LOCAL_ID" /> (सरà¥à¤µà¥à¤¹à¤° आयडी: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">याकà¥à¤·à¤£à¥€ आमà¥à¤¹à¥€ आपलà¥à¤¯à¤¾ पालकांपरà¥à¤¯à¤‚त पोहोचू शकलो नाही. कृपया पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.</translation>
<translation id="3528171143076753409">सरà¥à¤µà¥à¤¹à¤°à¤šà¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° विशà¥à¤µà¤¾à¤¸à¤¨à¥€à¤¯ नाही.</translation>
-<translation id="3538531656504267329">अवैध कालबाहà¥à¤¯à¤¤à¤¾ वरà¥à¤·</translation>
<translation id="3539171420378717834">या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° या कारà¥à¤¡à¤šà¥€ à¤à¤• पà¥à¤°à¤¤ ठेवा</translation>
<translation id="3542684924769048008">यासाठी संकेतशबà¥à¤¦ वापरा:</translation>
<translation id="3549644494707163724">आपलà¥à¤¯à¤¾ सà¥à¤µà¤¤à¤ƒà¤šà¥à¤¯à¤¾ वाकà¥à¤¯à¤¾à¤‚शासह सरà¥à¤µ संंकालित केलेला डेटा कूटबदà¥à¤§ करा</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">तपशील लपवा</translation>
<translation id="3587482841069643663">सरà¥à¤µ</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">वैध समापà¥à¤¤à¥€ दिनांक पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करा</translation>
<translation id="36224234498066874">बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग डेटा साफ करा...</translation>
<translation id="362276910939193118">पूरà¥à¤£ इतिहास दरà¥à¤¶à¤µà¤¾</translation>
<translation id="3623476034248543066">मूलà¥à¤¯ दरà¥à¤¶à¤µà¤¾</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">संकेतशबà¥à¤¦:</translation>
<translation id="3696411085566228381">काहीही नाही</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">पाठविणà¥à¤¯à¤¾à¤šà¥à¤¯à¤¾ पदà¥à¤§à¤¤à¥€ आणि आवशà¥à¤¯à¤•à¤¤à¤¾ तपासणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ à¤à¤• पाठविणà¥à¤¯à¤¾à¤šà¤¾ पतà¥à¤¤à¤¾ निवडा.</translation>
<translation id="370665806235115550">लोड करीत आहे...</translation>
<translation id="3712624925041724820">परवाने संपà¥à¤·à¥à¤Ÿà¤¾à¤¤</translation>
<translation id="3714780639079136834">मोबाइल डेटा किंवा Wi-Fi चालू करणे</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">आपण कॉपी केलेलà¥à¤¯à¤¾à¤šà¤¾ दà¥à¤µà¤¾ जोडा</translation>
<translation id="375403751935624634">सरà¥à¤µà¥à¤¹à¤° तà¥à¤°à¥à¤Ÿà¥€à¤®à¥à¤³à¥‡ भाषांतर अयशसà¥à¤µà¥€ à¤à¤¾à¤²à¤¾.</translation>
<translation id="3759461132968374835">आपण अलीकडे कोणतेही कà¥à¤°à¥…श नोंदवले नाहीत. कà¥à¤°à¥…श नोंदवणे अकà¥à¤·à¤® असताना à¤à¤¾à¤²à¥‡à¤²à¥‡ कà¥à¤°à¥…श येथे दिसून येणार नाहीत.</translation>
+<translation id="3787705759683870569">समापà¥à¤¤ होते: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">आपण पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सरà¥à¤µà¥à¤¹à¤° वापरत असलà¥à¤¯à¤¾à¤¸...</translation>
<translation id="3828924085048779000">रिकà¥à¤¤ सांकेतिक वाकà¥à¤¯à¤¾à¤‚शाची परवानगी नाही.</translation>
<translation id="3845539888601087042">आपलà¥à¤¯à¤¾ साइन-इन केलेलà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸ वरील इतिहास दरà¥à¤¶à¤µà¤¿à¤¤ आहे. <ph name="BEGIN_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chromium ने हे कारà¥à¤¡ जतन करावे असे आपण इचà¥à¤›à¤¿à¤¤à¤¾?</translation>
<translation id="4171400957073367226">खराब सतà¥à¤¯à¤¾à¤ªà¤¨ सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€</translation>
-<translation id="4176463684765177261">अकà¥à¤·à¤®</translation>
<translation id="4196861286325780578">&amp;हलवा पà¥à¤¨à¥à¤¹à¤¾ करा</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />फायरवॉल आणि अà¤à¤Ÿà¥€à¤µà¥à¤¹à¤¾à¤¯à¤°à¤¸ कॉनà¥à¤«à¤¿à¤—रेशन तपासणे<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{काहीही नाही}=1{1 अâ€à¥…प ($1)}=2{2 अâ€à¥…पà¥à¤¸ ($1, $2)}one{# अâ€à¥…पà¥à¤¸ ($1, $2, $3)}other{# अâ€à¥…पà¥à¤¸ ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">शोध परिणाम</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ने आपले लॉग इन पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सà¥à¤µà¥€à¤•à¤¾à¤°à¤²à¥‡ नाही किंवा कदाचित पà¥à¤°à¤¦à¤¾à¤¨ केले गेले नसावे.</translation>
<translation id="443673843213245140">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€à¤šà¤¾ वापर अकà¥à¤·à¤® करणà¥â€à¤¯à¤¾à¤¤ आला आहे पण à¤à¤• सà¥à¤¸à¥à¤ªà¤·à¥â€à¤Ÿ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ कॉनà¥â€à¤«à¤¿à¤—रेशन निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ करणà¥â€à¤¯à¤¾à¤¤ आले आहे.</translation>
-<translation id="4446242550670694251">आपण आता खाजगीमधà¥â€à¤¯à¥‡ बà¥à¤°à¤¾à¤‰à¤ करू शकता आणि हे डिवà¥à¤¹à¤¾à¤‡à¤¸ वापरणारे अनà¥à¤¯ लोक आपला कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª पाहणार नाहीत.</translation>
<translation id="4492190037599258964">'<ph name="SEARCH_STRING" />' साठी शोध परिणाम</translation>
<translation id="4506176782989081258">पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¤°à¤£ तà¥à¤°à¥à¤Ÿà¥€: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">सिसà¥à¤Ÿà¥€à¤® पà¥à¤°à¤¶à¤¾à¤¸à¤•à¤¾à¤¶à¥€ संपरà¥à¤• साधणे</translation>
<translation id="450710068430902550">पà¥à¤°à¤¶à¤¾à¤¸à¤•à¤¾à¤¸à¤¹ सामायिक करीत आहे</translation>
+<translation id="4515275063822566619">कारà¥à¤¡ आणि पतà¥à¤¤à¥‡ Chrome आणि आपलà¥à¤¯à¤¾ Google खातà¥à¤¯à¤¾à¤•à¤¡à¥€à¤² (<ph name="ACCOUNT_EMAIL" />) आहेत. आपण तà¥à¤¯à¤¾à¤‚ना <ph name="BEGIN_LINK" />सेटिंगà¥â€à¤œ<ph name="END_LINK" /> मधून वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करू शकता.</translation>
<translation id="4522570452068850558">तपशील</translation>
<translation id="4558551763791394412">आपले विसà¥à¤¤à¤¾à¤° अकà¥à¤·à¤® करून पहा.</translation>
<translation id="457875822857220463">वितरण</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">पृषà¥â€à¤ à¤¾à¤¨à¥à¤°à¥à¤ª करा</translation>
<translation id="483020001682031208">दरà¥à¤¶à¤µà¤¿à¤£à¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ कोणतीही वासà¥à¤¤à¤µà¤¿à¤• वेब पृषà¥à¤ à¥‡ नाहीत</translation>
<translation id="4850886885716139402">पहा</translation>
+<translation id="4854362297993841467">ही वितरण पदà¥à¤§à¤¤ उपलबà¥à¤§ नाही. वेगळी पदà¥à¤§à¤¤ वापरून पहा.</translation>
<translation id="4858792381671956233">या साइटला भेट देणे ठीक आहे का ते आपण आपलà¥â€à¤¯à¤¾ पालकांना विचारले</translation>
<translation id="4880827082731008257">इतिहास शोध</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">हे पृषà¥à¤  अजà¥à¤žà¤¾à¤¤ भाषेतून <ph name="LANGUAGE_LANGUAGE" /> मधà¥à¤¯à¥‡ अनà¥à¤µà¤¾à¤¦à¤¿à¤¤ करणà¥à¤¯à¤¾à¤¤ आले</translation>
<translation id="4923459931733593730">देयक</translation>
<translation id="4926049483395192435">निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ केले जाणे आवशà¥â€à¤¯à¤• आहे.</translation>
-<translation id="4941291666397027948">* आवशà¥à¤¯à¤• फीलà¥à¤¡ सूचित करते</translation>
<translation id="495170559598752135">कà¥à¤°à¤¿à¤¯à¤¾</translation>
<translation id="4958444002117714549">सूची विसà¥à¤¤à¥ƒà¤¤ करा</translation>
<translation id="4962322354953122629">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤šà¥‡ सिदà¥à¤§ करू शकला नाही; याचे सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° Chrome दà¥à¤µà¤¾à¤°à¥‡ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नाही; हे कदाचित à¤à¤•à¤¾ चà¥à¤•à¥€à¤šà¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">अयोगà¥à¤¯ संकेतशबà¥à¤¦</translation>
<translation id="5056549851600133418">आपलà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ लेख</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ पतà¥à¤¤à¤¾ तपासणे<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{कà¥à¤•à¥€à¤œ नाहीत}=1{1 साइट कà¥à¤•à¥€à¤œ वापरते. }one{# साइट कà¥à¤•à¥€à¤œ वापरते. }other{# साइट कà¥à¤•à¥€à¤œ वापरतात. }}</translation>
<translation id="5087286274860437796">यावेळी सरà¥à¤µà¥à¤¹à¤°à¤šà¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° वैध नाही.</translation>
<translation id="5087580092889165836">कारà¥à¤¡ जोडा</translation>
<translation id="5089810972385038852">राजà¥à¤¯</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">दरà¥à¤¶à¤µà¤¾</translation>
<translation id="5308689395849655368">कà¥à¤°à¥…श अहवाल अकà¥à¤·à¤® केला गेला आहे.</translation>
<translation id="5317780077021120954">जतन करा</translation>
-<translation id="5326702247179446998">पà¥à¤°à¤¾à¤ªà¥à¤¤à¤•à¤°à¥à¤¤à¤¾ आवशà¥à¤¯à¤• आहे</translation>
<translation id="5327248766486351172">नाव</translation>
<translation id="5337705430875057403"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> वरील आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥‡ सॉफà¥â€à¤Ÿà¤µà¥‡à¤…र सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करणे किंवा आपली वैवकà¥à¤¤à¤¿à¤• माहिती (उदाहरणारà¥à¤¥, संकेतशबà¥à¤¦, फोन नंबर किंवा कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡) उघड करणे यासारखे काहीतरी धोकादायक करणà¥â€à¤¯à¤¾à¤®à¤§à¥â€à¤¯à¥‡ आपलà¥â€à¤¯à¤¾à¤²à¤¾ यà¥à¤•à¥à¤¤à¥€à¤¨à¥‡ गà¥à¤‚तवू शकतात.</translation>
-<translation id="53553865750799677">असमरà¥à¤¥à¤¿à¤¤ घेणà¥à¤¯à¤¾à¤šà¤¾ पतà¥à¤¤à¤¾. भिनà¥à¤¨ पतà¥à¤¤à¤¾ निवडा.</translation>
<translation id="5359637492792381994">हा सरà¥à¤µà¥à¤¹à¤° <ph name="DOMAIN" /> हे असलà¥à¤¯à¤¾à¤šà¥‡ सिदà¥à¤§ करू शकला नाही; याचे सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° यावेळी वैध नाही हे कदाचित à¤à¤•à¤¾ चà¥à¤•à¥€à¤šà¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">धोरण सेटिंगà¥à¤œ संचयित करणà¥à¤¯à¤¾à¤¤ अयशसà¥à¤µà¥€</translation>
<translation id="5386426401304769735">या साइटसाठी असलेलà¥à¤¯à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° शà¥à¤°à¥ƒà¤‚खलेत SHA-1 वापरून सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€ केलेले पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° असते.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102"><ph name="SITE" /> वरील à¤à¤®à¥à¤¬à¥‡à¤¡ केलेले पृषà¥à¤  मà¥à¤¹à¤£à¤¤à¥‡:</translation>
<translation id="5556459405103347317">रीलोड करा</translation>
<translation id="5565735124758917034">सकà¥à¤°à¤¿à¤¯</translation>
+<translation id="5571083550517324815">या पतà¥à¤¤à¥à¤¯à¤¾à¤µà¤°à¥‚न पिक अप करू शकत नाही. वेगळा पतà¥à¤¤à¤¾ निवडा.</translation>
<translation id="5572851009514199876">कृपया पà¥à¤°à¤¾à¤°à¤‚भ करा आणि Chrome मधà¥â€à¤¯à¥‡ साइन इन करा जेणेकरून आपलà¥à¤¯à¤¾à¤²à¤¾ या साइटमधà¥à¤¯à¥‡ पà¥à¤°à¤µà¥‡à¤¶ करणà¥â€à¤¯à¤¾à¤šà¥€ अनà¥à¤®à¤¤à¥€ आहे किंवा नाही ते Chrome तपासू शकेल.</translation>
-<translation id="5575380383496039204">असमरà¥à¤¥à¤¿à¤¤ वितरण पतà¥à¤¤à¤¾. भिनà¥à¤¨ पतà¥à¤¤à¤¾ निवडा.</translation>
<translation id="5580958916614886209">आपला कालबाहà¥à¤¯à¤¤à¤¾ महिना तपासा आणि पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा</translation>
<translation id="560412284261940334">वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ समरà¥à¤¥à¤¿à¤¤ नाही</translation>
<translation id="5610142619324316209">कनेकà¥à¤¶à¤¨ तपासणे</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">या वेबसाइटची ओळख सतà¥à¤¯à¤¾à¤ªà¤¿à¤¤ केली गेली नाही.</translation>
<translation id="5720705177508910913">वरà¥à¤¤à¤®à¤¾à¤¨ वापरकरà¥à¤¤à¤¾</translation>
<translation id="5732392974455271431">आपले पालक आपलà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ ती अनावरोधित करू शकतात</translation>
-<translation id="57586589942790530">अवैध कारà¥à¤¡ कà¥à¤°à¤®à¤¾à¤‚क</translation>
+<translation id="5763042198335101085">वैध ईमेल पतà¥à¤¤à¤¾ पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करा</translation>
+<translation id="5765072501007116331">वितरण पदà¥à¤§à¤¤à¥€ आणि आवशà¥à¤¯à¤•à¤¤à¤¾ पाहणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, à¤à¤• पतà¥à¤¤à¤¾ निवडा</translation>
<translation id="5784606427469807560">आपलà¥à¤¯à¤¾ कारà¥à¤¡à¤šà¥€ पà¥à¤·à¥à¤Ÿà¥€ करताना समसà¥à¤¯à¤¾ आली. आपले इंटरनेट कनेकà¥à¤¶à¤¨ तपासा आणि पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.</translation>
<translation id="5785756445106461925">पà¥à¤¢à¥‡, या पृषà¥à¤ à¤¾à¤¤ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नसलेली इतर संसाधने समाविषà¥à¤Ÿ आहेत. ही संसाधने संकà¥à¤°à¤®à¤£à¤¾à¤¤ असताना इतरांदà¥à¤µà¤¾à¤°à¥‡ पाहिली जाऊ शकतात आणि पृषà¥à¤ à¤¾à¤šà¥‡ सà¥à¤µà¤°à¥‚प बदलणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¦à¥à¤µà¤¾à¤°à¥‡ सà¥à¤§à¤¾à¤°à¤¿à¤¤ केली जाऊ शकतात.</translation>
<translation id="5786044859038896871">आपण आपली कारà¥à¤¡ माहिती भरू इचà¥à¤›à¤¿à¤¤ आहात?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">या साइटवर पोहचणे शकà¥à¤¯ नाही</translation>
<translation id="5869522115854928033">जतन केलेले संकेतशबà¥à¤¦</translation>
<translation id="5872918882028971132">पालक सूचना</translation>
-<translation id="587760065310675640">असमरà¥à¤¥à¤¿à¤¤ पाठविणà¥â€à¤¯à¤¾à¤šà¤¾ पतà¥à¤¤à¤¾. भिनà¥à¤¨ पतà¥à¤¤à¤¾ निवडा.</translation>
<translation id="5901630391730855834">पिवळा</translation>
-<translation id="59174027418879706">सकà¥à¤·à¤® केलेले</translation>
<translation id="5926846154125914413">आपण काही साइट मधील पà¥à¤°à¥€à¤®à¤¿à¤¯à¤® सामगà¥à¤°à¥€ मधील पà¥à¤°à¤µà¥‡à¤¶ कदाचित गमवाल.</translation>
<translation id="5959728338436674663">धोकादायक अॅपà¥à¤¸ आणि साइट शोधणà¥à¤¯à¤¾à¤¤ मदत करणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ काही <ph name="BEGIN_WHITEPAPER_LINK" />सिसà¥à¤Ÿà¥€à¤® माहिती आणि पृषà¥à¤  सामगà¥à¤°à¥€<ph name="END_WHITEPAPER_LINK" /> सà¥à¤µà¤¯à¤‚चलितपणे Google कडे पाठवा. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">आठवडा</translation>
<translation id="5967867314010545767">इतिहासातून काढा</translation>
<translation id="5975083100439434680">à¤à¥‚म कमी करा</translation>
+<translation id="598637245381783098">पेमेंट अॅप उघडू शकत नाही</translation>
<translation id="5989320800837274978">निशà¥à¤šà¤¿à¤¤ पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ सरà¥à¤µà¥à¤¹à¤° किंवा .pac सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ URL देखील निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ केलेली नाही.</translation>
<translation id="5990559369517809815">सरà¥à¤µà¥à¤¹à¤°à¤²à¤¾ केलà¥à¤¯à¤¾ जाणारà¥â€à¤¯à¤¾ विनंतà¥à¤¯à¤¾ à¤à¤•à¤¾ विसà¥à¤¤à¤¾à¤°à¤¾à¤¨à¥‡ अवरोधित केलà¥à¤¯à¤¾ गेलà¥à¤¯à¤¾ आहेत.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">कारà¥à¤¡ आणि पतà¥à¤¤à¤¾ परà¥à¤¯à¤¾à¤¯ Chrome मधील आहेत. आपण ते <ph name="BEGIN_LINK" />सेटिंगà¥à¤œ<ph name="END_LINK" /> मधà¥à¤¯à¥‡ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करू शकता.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{पृषà¥à¤  1}one{पृषà¥à¤  #}other{पृषà¥à¤ à¥‡ #}}</translation>
<translation id="6017514345406065928">हिरवा</translation>
+<translation id="6027201098523975773">नाव पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करा</translation>
<translation id="6040143037577758943">बंद करा</translation>
-<translation id="604124094241169006">सà¥à¤µà¤¯à¤‚चलित</translation>
<translation id="6042308850641462728">अधिक</translation>
<translation id="6060685159320643512">सावधगिरी बाळगा, या पà¥à¤°à¤¯à¥‹à¤—ांमà¥à¤³à¥‡ हानी होऊ शकते</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{काहीही नाही}=1{1}one{#}other{#}}</translation>
@@ -544,9 +553,10 @@
अनà¥à¤¯ नेटवरà¥à¤• डिवà¥à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸ रीबूट करा.</translation>
<translation id="614940544461990577">हे करून पहा:</translation>
<translation id="6151417162996330722">सरà¥à¤µà¥à¤¹à¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤¾à¤¸ वैधता कालावधी आहे जो खूप मोठा आहे.</translation>
-<translation id="615643356032862689">डाउनलोड केलेलà¥à¤¯à¤¾ फायली आणि बà¥à¤•à¤®à¤¾à¤°à¥à¤• ठेवले जातील.</translation>
+<translation id="6157877588268064908">शिपिंग पदà¥à¤§à¤¤à¥€ आणि आवशà¥à¤¯à¤•à¤¤à¤¾ पाहणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, à¤à¤• पतà¥à¤¤à¤¾ निवडा</translation>
<translation id="6165508094623778733">अधिक जाणून घà¥à¤¯à¤¾</translation>
<translation id="6177128806592000436">या साइटवरील आपले कनेकà¥à¤¶à¤¨ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नाही</translation>
+<translation id="6184817833369986695">(cohort: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">आपले इंटरनेट कनेकà¥à¤¶à¤¨ तपासा</translation>
<translation id="6218753634732582820">Chromium वरून पतà¥à¤¤à¤¾ काढायचा?</translation>
<translation id="6251924700383757765">गोपनीयता धोरण</translation>
@@ -555,6 +565,8 @@
<translation id="6259156558325130047">&amp;पà¥à¤¨à¤°à¥à¤•à¥à¤°à¤®à¤¿à¤¤ करा पà¥à¤¨à¥à¤¹à¤¾ करा</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="6264485186158353794">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¥‡à¤•à¤¡à¥‡ परत</translation>
+<translation id="6276112860590028508">आपलà¥à¤¯à¤¾ वाचन सूचीमधील पृषà¥à¤ à¥‡ येथे दिसतात</translation>
+<translation id="6280223929691119688">या पतà¥à¤¤à¥à¤¯à¤¾à¤µà¤° देऊ शकत नाही. वेगळा पतà¥à¤¤à¤¾ निवडा.</translation>
<translation id="6282194474023008486">पोसà¥à¤Ÿà¤² कोड</translation>
<translation id="6290238015253830360">आपण सà¥à¤šà¤µà¤¿à¤²à¥‡à¤²à¥‡ लेख येथे दिसतील</translation>
<translation id="6305205051461490394"><ph name="URL" /> आवाकà¥à¤¯à¤¾à¤¬à¤¾à¤¹à¥‡à¤° आहे.</translation>
@@ -576,7 +588,6 @@
<translation id="6417515091412812850">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° मागे घेतले की नाही हे तपासणà¥à¤¯à¤¾à¤¤ अकà¥à¤·à¤®.</translation>
<translation id="6433490469411711332">संपरà¥à¤• माहिती संपादित करा</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> नी कनेकà¥à¤Ÿ करणà¥à¤¯à¤¾à¤¸ नकार दिला.</translation>
-<translation id="6443118737398455446">अवैध कालबाहà¥à¤¯à¤¤à¤¾ तारीख</translation>
<translation id="6446608382365791566">अधिक माहिती जोडा</translation>
<translation id="6451458296329894277">फॉरà¥à¤® रीसबमिशनची पà¥à¤·à¥à¤Ÿà¥€ करा</translation>
<translation id="6456339708790392414">आपले देयक</translation>
@@ -584,10 +595,8 @@
<translation id="6462969404041126431">हा सरà¥à¤µà¥à¤¹à¤° <ph name="DOMAIN" /> हे असलà¥à¤¯à¤¾à¤šà¥‡ सिदà¥à¤§ करू शकला नाही; याचे सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निरसà¥à¤¤ केले असावे. हे कदाचित à¤à¤•à¤¾ चà¥à¤•à¥€à¤šà¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">डिवà¥à¤¹à¤¾à¤‡à¤¸ धोरणे</translation>
<translation id="6477321094435799029">Chrome ला या पृषà¥â€à¤ à¤¾à¤µà¤° असमानà¥à¤¯ कोड सापडला आहे आणि आपली वैयकà¥à¤¤à¤¿à¤• माहिती (उदा, संकेतशबà¥à¤¦, फोन नंबर आणि कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡) संरकà¥à¤·à¤¿à¤¤ करणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ अवरोधित केला आहे.</translation>
-<translation id="6477460825583319731">अवैध ईमेल पतà¥à¤¤à¤¾</translation>
<translation id="6489534406876378309">कà¥à¤°à¥…श अपलोड करणे पà¥à¤°à¤¾à¤°à¤‚भ करा</translation>
<translation id="6508722015517270189">Chrome रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ करा</translation>
-<translation id="6525462735697194615">अवैध कालबाहà¥à¤¯à¤¤à¤¾ महिना</translation>
<translation id="6529602333819889595">&amp;पà¥à¤¨à¥à¤¹à¤¾ करा हटवा</translation>
<translation id="6534179046333460208">वासà¥à¤¤à¤µà¤¿à¤• वेब सूचना</translation>
<translation id="6550675742724504774">परà¥à¤¯à¤¾à¤¯</translation>
@@ -602,7 +611,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> शोध</translation>
<translation id="6644283850729428850">हे धोरण नापसंत आहे.</translation>
<translation id="6652240803263749613">हा सरà¥à¤µà¥à¤¹à¤° <ph name="DOMAIN" /> हे असलà¥à¤¯à¤¾à¤šà¥‡ सिदà¥à¤§ करू शकला नाही; याचे सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° आपलà¥à¤¯à¤¾ संगणकाचà¥à¤¯à¤¾ ऑपरेटिंग पà¥à¤°à¤£à¤¾à¤²à¥€à¤¦à¥à¤µà¤¾à¤°à¥‡ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नाही; हे कदाचित à¤à¤•à¤¾ चà¥à¤•à¥€à¤šà¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">तो पाठविणà¥â€à¤¯à¤¾à¤šà¤¾ परà¥à¤¯à¤¾à¤¯ उपलबà¥à¤§ नाही. à¤à¤• भिनà¥à¤¨ परà¥à¤¯à¤¾à¤¯ वापरून पहा.</translation>
<translation id="6671697161687535275">Chromium वरून फॉरà¥à¤® सूचना काढायचà¥à¤¯à¤¾?</translation>
<translation id="6685834062052613830">साइन आउट करा आणि सेटअप पूरà¥à¤£ करा</translation>
<translation id="6710213216561001401">मागील</translation>
@@ -610,13 +618,13 @@
<translation id="6711464428925977395">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सरà¥à¤µà¥à¤¹à¤°à¤®à¤§à¥à¤¯à¥‡ काहीतरी चà¥à¤•à¥€à¤šà¥‡ आहे किंवा पतà¥à¤¤à¤¾ चà¥à¤•à¥€à¤šà¤¾ आहे.</translation>
<translation id="6727102863431372879">सेट करा</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{काहीही नाही}=1{1 आयटम}one{# आयटम}other{# आयटम}}</translation>
-<translation id="6743044928064272573">घेणà¥à¤¯à¤¾à¤šà¥‡ परà¥à¤¯à¤¾à¤¯</translation>
<translation id="674375294223700098">अजà¥à¤žà¤¾à¤¤ सरà¥à¤µà¥à¤¹à¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° तà¥à¤°à¥à¤Ÿà¥€.</translation>
<translation id="6753269504797312559">धोरण मूलà¥à¤¯</translation>
<translation id="6757797048963528358">आपले डिवà¥à¤¹à¤¾à¤‡à¤¸ निषà¥à¤•à¥à¤°à¥€à¤¯ à¤à¤¾à¤²à¥‡.</translation>
<translation id="6778737459546443941">आपलà¥à¤¯à¤¾ पालकाने अदà¥à¤¯à¤¾à¤ª ती मंजूर केली नाही</translation>
<translation id="6810899417690483278">सानà¥à¤•à¥‚लीकरण आयडी</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">पà¥à¤°à¤¦à¥‡à¤¶ डेटा लोड करणà¥à¤¯à¤¾à¤¤ अयशसà¥à¤µà¥€</translation>
<translation id="6831043979455480757">भाषांतर करा</translation>
<translation id="6839929833149231406">कà¥à¤·à¥‡à¤¤à¥à¤°</translation>
<translation id="6874604403660855544">&amp;जोडा पà¥à¤¨à¥à¤¹à¤¾ करा</translation>
@@ -624,6 +632,7 @@
<translation id="6895330447102777224">आपलà¥à¤¯à¤¾ कारà¥à¤¡à¤šà¥€ पà¥à¤·à¥à¤Ÿà¥€ केली</translation>
<translation id="6897140037006041989">वापरकरà¥à¤¤à¤¾ à¤à¤œà¤‚ट</translation>
<translation id="6915804003454593391">वापरकरà¥à¤¤à¤¾:</translation>
+<translation id="6948701128805548767">पिकअप पदà¥à¤§à¤¤à¥€ आणि आवशà¥à¤¯à¤•à¤¤à¤¾ पाहणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, à¤à¤• पतà¥à¤¤à¤¾ निवडा</translation>
<translation id="6957887021205513506">सरà¥à¤µà¥à¤¹à¤°à¤šà¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° खोटे असलà¥à¤¯à¤¾à¤šà¥‡ दिसून येते.</translation>
<translation id="6965382102122355670">ठीक आहे</translation>
<translation id="6965978654500191972">डिवà¥à¤¹à¤¾à¤‡à¤¸</translation>
@@ -631,7 +640,6 @@
<translation id="6973656660372572881">निशà¥à¤šà¤¿à¤¤ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सरà¥à¤µà¥à¤¹à¤° आणि .pac सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ URL निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ करणà¥â€à¤¯à¤¾à¤¤ आले आहेत.</translation>
<translation id="6989763994942163495">पà¥à¤°à¤—त सेटिंगà¥à¤œ दरà¥à¤¶à¤µà¤¾...</translation>
<translation id="7000990526846637657">कोणतà¥à¤¯à¤¾à¤¹à¥€ इतिहास पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¥€ सापडलà¥à¤¯à¤¾ नाहीत</translation>
-<translation id="7001663382399377034">पà¥à¤°à¤¾à¤ªà¥à¤¤à¤•à¤°à¥à¤¤à¤¾ जोडा</translation>
<translation id="7009986207543992532">आपण <ph name="DOMAIN" /> येथे पोहोचणà¥à¤¯à¤¾à¤šà¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ केला, परंतॠसरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ असे पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सादर केले जà¥à¤¯à¤¾à¤šà¤¾ वैधता कालावधी विशà¥à¤µà¤¾à¤¸à¤¾à¤°à¥à¤¹à¤¤à¥‡à¤¸à¤¾à¤ à¥€ खूप मोठा आहे. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">आपलà¥à¤¯à¤¾ Google खातà¥à¤¯à¤¾à¤¤ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> वर बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग इतिहासाची अनà¥à¤¯ सà¥à¤µà¤°à¥‚पे असू शकतात</translation>
@@ -642,12 +650,15 @@
<translation id="7088615885725309056">थोडा जà¥à¤¨à¤¾</translation>
<translation id="7090678807593890770">Google वर <ph name="LINK" /> शोधा</translation>
<translation id="7119414471315195487">अनà¥à¤¯ टॅब आणि पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® बंद करा</translation>
+<translation id="7129409597930077180">या पतà¥à¤¤à¥à¤¯à¤¾à¤µà¤° पाठवू शकत नाही. वेगळा पतà¥à¤¤à¤¾ निवडा.</translation>
+<translation id="7138472120740807366">वितरण पदà¥à¤§à¤¤</translation>
<translation id="7139724024395191329">अमिरात</translation>
<translation id="7155487117670177674">देयक सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नाही</translation>
<translation id="7179921470347911571">आतà¥à¤¤à¤¾ पà¥à¤¨à¥à¤¹à¤¾ लाà¤à¤š करा </translation>
<translation id="7180611975245234373">रीफà¥à¤°à¥‡à¤¶ करा</translation>
<translation id="7182878459783632708">कोणतीही धोरणे सेट नाहीत</translation>
<translation id="7186367841673660872">हे पृषà¥à¤ <ph name="ORIGINAL_LANGUAGE" />मधून<ph name="LANGUAGE_LANGUAGE" />मधà¥à¤¯à¥‡ अनà¥à¤µà¤¾à¤¦à¤¿à¤¤ केले गेले आहे</translation>
+<translation id="7192203810768312527"><ph name="SIZE" /> जागा मोकळी करते. काही साइट तà¥à¤®à¤šà¥à¤¯à¤¾ पà¥à¤¢à¥€à¤² भेटीचà¥à¤¯à¤¾ वेळी आणखी धीमà¥à¤¯à¤¾ गतीने लोड होऊ शकतात.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> नी सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ मानकांचे पालन केले नाही.</translation>
<translation id="721197778055552897">या समसà¥à¤¯à¥‡à¤¬à¤¦à¥à¤¦à¤² <ph name="BEGIN_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LINK" />.</translation>
@@ -676,7 +687,6 @@
<translation id="7424977062513257142">या वेबपृषà¥à¤ à¤¾à¤µà¤°à¥€à¤² à¤à¤®à¥à¤¬à¥‡à¤¡ केलेले पृषà¥à¤  मà¥à¤¹à¤£à¤¤à¥‡:</translation>
<translation id="7441627299479586546">चà¥à¤•à¥€à¤šà¥‡ धोरण विषय</translation>
<translation id="7444046173054089907">ही साइट अवरोधित केली आहे</translation>
-<translation id="7444238235002594607">घेणà¥à¤¯à¤¾à¤šà¥à¤¯à¤¾ पदà¥à¤§à¤¤à¥€ आणि आवशà¥à¤¯à¤•à¤¤à¤¾ तपासणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ घेणà¥à¤¯à¤¾à¤šà¤¾ पतà¥à¤¤à¤¾ निवडा</translation>
<translation id="7445762425076701745">आपण कनेकà¥à¤Ÿ केलेलà¥à¤¯à¤¾ सरà¥à¤µà¥à¤¹à¤°à¤šà¥€ ओळख पूरà¥à¤£à¤ªà¤£à¥‡ सतà¥à¤¯à¤¾à¤ªà¤¿à¤¤ करणे शकà¥à¤¯ नाही. आपण सरà¥à¤µà¥à¤¹à¤°à¤¶à¥€ फकà¥à¤¤ आपलà¥â€à¤¯à¤¾ डोमेनमधà¥à¤¯à¥‡ वैध असलेले नाव वापरून कनेकà¥à¤Ÿ केलेले आहे, जà¥à¤¯à¤¾à¤šà¥€ मालकी सतà¥à¤¯à¤¾à¤ªà¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ बाहà¥à¤¯ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° अधिकृततेला परवानगी नाही. काही पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° अधिकारी तरीही या नावांसाठी पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° जारी करतील, हे सà¥à¤¨à¤¿à¤¶à¥à¤šà¤¿à¤¤ करणà¥à¤¯à¤¾à¤šà¤¾ काहीही मारà¥à¤— नाही की आपण इचà¥à¤›à¤¿à¤¤ वेबसाइटशी कनेकà¥à¤Ÿ केले आहे आणि आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¶à¥€ नाही.</translation>
<translation id="7451311239929941790">या समसà¥à¤¯à¥‡à¤µà¤¿à¤·à¤¯à¥€ <ph name="BEGIN_LINK" />अधिक जाणून घेणे<ph name="END_LINK" />.</translation>
<translation id="7460163899615895653">अनà¥à¤¯ डिवà¥à¤¹à¤¾à¤‡à¤¸ वरील आपले अलीकडील टॅब येथे दिसतात</translation>
@@ -720,6 +730,7 @@
<translation id="7755287808199759310">आपले पालक आपलà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ ती अनावरोधित करू शकतात</translation>
<translation id="7758069387465995638">फायरवॉल किंवा अà¤à¤Ÿà¥€à¤µà¥à¤¹à¤¾à¤¯à¤°à¤¸ सॉफà¥à¤Ÿà¤µà¥‡à¤…रने कदाचित कनेकà¥à¤¶à¤¨ अवरोधित केले असावे.</translation>
<translation id="7761701407923456692">सरà¥à¤µà¥à¤¹à¤°à¤šà¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° URL शी जà¥à¤³à¤¤ नाही.</translation>
+<translation id="7763386264682878361">पेमेंट मॅनिफेसà¥à¤Ÿ विशà¥à¤²à¥‡à¤·à¤•</translation>
<translation id="7764225426217299476">पतà¥à¤¤à¤¾ जोडा</translation>
<translation id="777702478322588152">परफेकà¥à¤šà¥à¤…र</translation>
<translation id="7791543448312431591">जोडा</translation>
@@ -733,6 +744,7 @@
<translation id="785549533363645510">तथापि, आपण अदृशà¥à¤¯ नाही. गà¥à¤ªà¥à¤¤ à¤à¤¾à¤²à¥à¤¯à¤¾à¤¨à¥‡ आपले बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग आपला नियोकà¥à¤¤à¤¾, आपला इंटरनेट सेवा पà¥à¤°à¤¦à¤¾à¤¤à¤¾, किंवा आपण भेट देता तà¥à¤¯à¤¾ वेबसाइटपासून लपत नाही.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">आपले CVC तपासा आणि पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा</translation>
+<translation id="79338296614623784">वैध फोन नंबर पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करा</translation>
<translation id="7935318582918952113">DOM डिसà¥à¤Ÿà¤¿à¤²à¤°</translation>
<translation id="7938958445268990899">सरà¥à¤µà¥à¤¹à¤°à¤šà¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° अदà¥à¤¯à¤¾à¤ª वैध नाही.</translation>
<translation id="7942349550061667556">लाल</translation>
@@ -752,6 +764,7 @@
<translation id="8088680233425245692">लेख पाहणà¥à¤¯à¤¾à¤¤ अयशसà¥à¤µà¥€.</translation>
<translation id="8089520772729574115">1 MB पेकà¥à¤·à¤¾ कमी</translation>
<translation id="8091372947890762290">सकà¥à¤°à¤¿à¤¯à¤•à¤°à¤£ सरà¥à¤µà¥à¤¹à¤°à¤µà¤° पà¥à¤°à¤²à¤‚बित आहे</translation>
+<translation id="8118489163946903409">पेमेंट पदà¥à¤§à¤¤</translation>
<translation id="8131740175452115882">पà¥à¤·à¥à¤Ÿà¥€ करा</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" />चे सरà¥à¤µà¥à¤¹à¤° <ph name="BEGIN_ABBR" />DNS पतà¥à¤¤à¤¾<ph name="END_ABBR" /> शोधणे शकà¥à¤¯ à¤à¤¾à¤²à¥‡ नाही.</translation>
<translation id="8149426793427495338">आपला संगणक निषà¥à¤•à¥à¤°à¥€à¤¯ à¤à¤¾à¤²à¤¾.</translation>
@@ -777,6 +790,7 @@
<translation id="8349305172487531364">बà¥à¤•à¤®à¤¾à¤°à¥à¤• बार</translation>
<translation id="8363502534493474904">विमान मोड बंद करा</translation>
<translation id="8364627913115013041">सेट केलेले नाही.</translation>
+<translation id="8368476060205742148">Google Play सेवा</translation>
<translation id="8380941800586852976">धोकादायक</translation>
<translation id="8382348898565613901">आपण अलिकडेच भेट दिलेले बà¥à¤•à¤®à¤¾à¤°à¥à¤• येथे दिसतील</translation>
<translation id="8398259832188219207">कà¥à¤°à¥…श अहवाल <ph name="UPLOAD_TIME" /> वाजता अपलोड केला</translation>
@@ -785,31 +799,29 @@
<translation id="8428213095426709021">सेटिंगà¥à¤œ</translation>
<translation id="8433057134996913067">हे आपलà¥à¤¯à¤¾à¤²à¤¾ बहà¥à¤¤à¤¾à¤‚श वेबसाइट वरून साइन आउट करेल.</translation>
<translation id="8437238597147034694">&amp;हलवा पूरà¥à¤µà¤µà¤¤ करा</translation>
-<translation id="8456681095658380701">अवैध नाव</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡}one{# कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡}other{# कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡}}</translation>
<translation id="8483780878231876732">आपलà¥à¤¯à¤¾ Google खातà¥à¤¯à¤¾à¤µà¤°à¥‚न कारà¥à¤¡ वापरणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ Chrome मधà¥à¤¯à¥‡ साइन इन करा</translation>
<translation id="8488350697529856933">यावर लागू होते</translation>
-<translation id="8492969205326575646">असमरà¥à¤¥à¤¿à¤¤ कारà¥à¤¡ पà¥à¤°à¤•à¤¾à¤°</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> नी पà¥à¤°à¤¤à¤¿à¤¸à¤¾à¤¦ देणà¥à¤¯à¤¾à¤¤ बराच वेळ घेतला.</translation>
<translation id="852346902619691059">हा सरà¥à¤µà¥à¤¹à¤° <ph name="DOMAIN" /> हे असलà¥à¤¯à¤¾à¤šà¥‡ सिदà¥à¤§ करू शकला नाही; याचे सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° आपलà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤šà¥à¤¯à¤¾ ऑपरेटिंग पà¥à¤°à¤£à¤¾à¤²à¥€à¤¦à¥à¤µà¤¾à¤°à¥‡ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नाही; हे कदाचित à¤à¤•à¤¾ चà¥à¤•à¥€à¤šà¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">कालबाहà¥à¤¯ होणà¥à¤¯à¤¾à¤šà¥‡ वरà¥à¤·</translation>
<translation id="8543181531796978784">आपण <ph name="BEGIN_ERROR_LINK" />ओळखणà¥â€à¤¯à¤¾à¤šà¥à¤¯à¤¾ समसà¥â€à¤¯à¥‡à¤šà¤¾ अहवाल<ph name="END_ERROR_LINK" /> देऊ शकता किंवा आपलà¥â€à¤¯à¤¾ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¥‡à¤¸ असणारà¥â€à¤¯à¤¾ जोखीम आपण समजत असलà¥â€à¤¯à¤¾à¤¸, <ph name="BEGIN_LINK" />या असà¥à¤°à¤•à¥à¤·à¤¿à¤¤ साइटला भेट दà¥à¤¯à¤¾<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">भाषांतर करणà¥à¤¯à¤¾à¤¤ अयशसà¥à¤µà¥€ कारण पृषà¥à¤ à¤¾à¤šà¥€ भाषा निरà¥à¤§à¤¾à¤°à¤¿à¤¤ करणे शकà¥à¤¯ नाही.</translation>
<translation id="8559762987265718583">आपलà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤šà¥€ तारीख आणि वेळ (<ph name="DATE_AND_TIME" />) चà¥à¤•à¥€à¤šà¥€ असलà¥à¤¯à¤¾à¤¨à¥‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> सह खाजगी कनेकà¥à¤¶à¤¨ सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ केले जाऊ शकले नाही.</translation>
-<translation id="8570229484593575558">ही माहिती |जतन केली जाणार नाही|:#आपला बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग इतिहास#आपले शोध#कà¥à¤•à¥€ डेटा</translation>
<translation id="8571890674111243710"><ph name="LANGUAGE" /> मधà¥à¤¯à¥‡ पृषà¥à¤  अनà¥à¤µà¤¾à¤¦à¤¿à¤¤ करत आहे...</translation>
-<translation id="8584539743998202583">यांना आपला कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª |कदाचित अदà¥à¤¯à¤¾à¤ª दृशà¥à¤¯à¤®à¤¾à¤¨| असेल:#आपण भेट देता तà¥à¤¯à¤¾ वेबसाइट#आपला नियोकà¥à¤¤à¤¾#आपला इंटरनेट सेवा पà¥à¤°à¤¦à¤¾à¤¤à¤¾</translation>
<translation id="858637041960032120">फोन नंबर जोडा</translation>
<translation id="859285277496340001">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निरसà¥à¤¤ à¤à¤¾à¤²à¥‡ आहे किंवा नाही हे तपासणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ पà¥à¤°à¤£à¤¾à¤²à¥€ निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ करत नाही.</translation>
<translation id="8620436878122366504">आपलà¥à¤¯à¤¾ पालकांनी अदà¥à¤¯à¤¾à¤ª ती मंजूर केली नाही</translation>
<translation id="8647750283161643317">सरà¥à¤µ डीफॉलà¥à¤Ÿà¤®à¤§à¥à¤¯à¥‡ रीसेट करा</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> चे आपले कनेकà¥à¤¶à¤¨ कूटबदà¥à¤§ केलेले नाही.</translation>
+<translation id="8718314106902482036">पेमेंट पूरà¥à¤£ à¤à¤¾à¤²à¥‡ नाही</translation>
<translation id="8725066075913043281">पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा</translation>
-<translation id="8728672262656704056">आपण गà¥à¤ªà¥à¤¤ à¤à¤¾à¤²à¤¾ आहात</translation>
+<translation id="8728672262656704056">आपण गà¥à¤ªà¥à¤¤ मोडमधà¥à¤¯à¥‡ आहात</translation>
<translation id="8730621377337864115">पूरà¥à¤£ à¤à¤¾à¤²à¥‡</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="8759274551635299824">या कारà¥à¤¡à¤šà¥€ मà¥à¤¦à¤¤ संपली आहे</translation>
<translation id="8790007591277257123">&amp;पà¥à¤¨à¥à¤¹à¤¾ करा हटवा</translation>
-<translation id="8798099450830957504">डीफॉलà¥à¤Ÿ</translation>
<translation id="8800988563907321413">आपलà¥à¤¯à¤¾ जवळपासचà¥à¤¯à¤¾ सूचना येथे दिसतात</translation>
<translation id="8820817407110198400">Bookmarks</translation>
<translation id="883848425547221593">अनà¥à¤¯ बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
@@ -819,6 +831,7 @@
<translation id="8866481888320382733">धोरण सेटिंगà¥à¤œ विशà¥à¤²à¥‡à¤·à¤¿à¤¤ करताना तà¥à¤°à¥à¤Ÿà¥€</translation>
<translation id="8866959479196209191">हे पृषà¥à¤  मà¥à¤¹à¤£à¤¤à¥‡:</translation>
<translation id="8870413625673593573">अलीकडे बंद</translation>
+<translation id="8874824191258364635">वैध कारà¥à¤¡ नंबर पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करा</translation>
<translation id="8876793034577346603">विशà¥à¤²à¥‡à¤·à¤£ करणà¥à¤¯à¤¾à¤¤ नेटवरà¥à¤• कॉनà¥à¤«à¤¿à¤—रेशन अयशसà¥à¤µà¥€.</translation>
<translation id="8877192140621905067">आपण पà¥à¤·à¥à¤Ÿà¥€ केलà¥à¤¯à¤¾à¤µà¤°, आपले कारà¥à¤¡ तपशील या साइटसह सामायिक केले जातील</translation>
<translation id="8889402386540077796">रंगछटा</translation>
@@ -828,7 +841,6 @@
<translation id="8931333241327730545">आपण आपलà¥à¤¯à¤¾ Google खातà¥à¤¯à¤¾à¤¤ हे कारà¥à¤¡ जतन करू इचà¥à¤›à¤¿à¤¤à¤¾?</translation>
<translation id="8932102934695377596">आपले घडà¥à¤¯à¤¾à¤³ मागे आहे</translation>
<translation id="8954894007019320973">(सà¥à¤°à¥‚)</translation>
-<translation id="895548565263634352"><ph name="ARTICLE_PUBLISHER" /> आणि आणखी <ph name="OTHER_ARTICLE_COUNT" /> मधील कथा वाचा</translation>
<translation id="8971063699422889582">सरà¥à¤µà¥à¤¹à¤°à¤šà¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡ आहे.</translation>
<translation id="8986494364107987395">Google ला वापर आकडेवारी आणि कà¥à¤°à¥…श अहवाल सà¥à¤µà¤¯à¤‚चलितपणे पाठवा</translation>
<translation id="8987927404178983737">महिना</translation>
@@ -846,7 +858,6 @@
<translation id="9068849894565669697">रंग निवडा</translation>
<translation id="9076283476770535406">कदाचित तिचà¥à¤¯à¤¾à¤®à¤§à¥à¤¯à¥‡ पà¥à¤°à¥Œà¤¢ सामगà¥à¤°à¥€ असू शकते</translation>
<translation id="9078964945751709336">अधिक माहिती आवशà¥à¤¯à¤• आहे</translation>
-<translation id="9094175695478007090">पेमेंट अॅप लाà¤à¤š करणà¥à¤¯à¤¾à¤¤ अकà¥à¤·à¤®.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> आपली माहिती संरकà¥à¤·à¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ सामानà¥à¤¯à¤¤à¤ƒ कूटबदà¥à¤§à¥€à¤•à¤°à¤£ वापरते. Chromium ने यावेळी <ph name="SITE" /> शी कनेकà¥â€à¤Ÿ करणà¥â€à¤¯à¤¾à¤šà¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ केला तेवà¥â€à¤¹à¤¾, वेबसाइटने असामानà¥à¤¯ आणि अयोगà¥à¤¯ कà¥à¤°à¥‡à¤¡à¥‡à¤¨à¥à¤¶à¤¿à¤¯à¤² परत पाठविले. à¤à¤•à¤¤à¤° आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ <ph name="SITE" /> असलà¥à¤¯à¤¾à¤šà¥€ बतावणी करणà¥à¤¯à¤¾à¤šà¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करतो तेवà¥â€à¤¹à¤¾ किंवा Wi-Fi साइन इन सà¥à¤•à¥à¤°à¥€à¤¨à¤¨à¥‡ कनेकà¥à¤¶à¤¨à¤®à¤§à¥à¤¯à¥‡ वà¥à¤¯à¤¤à¥à¤¯à¤¯ आणले तेवà¥â€à¤¹à¤¾ हे घडू शकते. कोणतà¥à¤¯à¤¾à¤¹à¥€ डेटाची अदलाबदल करणà¥à¤¯à¤¾à¤ªà¥‚रà¥à¤µà¥€ Chromium ने कनेकà¥à¤¶à¤¨ थांबविलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ आपली माहिती अदà¥à¤¯à¤¾à¤ª सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ आहे.</translation>
<translation id="9137013805542155359">मूळ दरà¥à¤¶à¤µà¤¾</translation>
<translation id="9137248913990643158">कृपया हा अॅप वापरणà¥â€à¤¯à¤¾à¤ªà¥‚रà¥à¤µà¥€ पà¥à¤°à¤¾à¤°à¤‚भ करा आणि Chrome मधà¥â€à¤¯à¥‡ साइन इन करा.</translation>
diff --git a/chromium/components/strings/components_strings_ms.xtb b/chromium/components/strings/components_strings_ms.xtb
index 3af496d8a84..f92a55c09e7 100644
--- a/chromium/components/strings/components_strings_ms.xtb
+++ b/chromium/components/strings/components_strings_ms.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="ms">
<translation id="1008557486741366299">Bukan Sekarang</translation>
<translation id="1015730422737071372">Berikan butiran tambahan</translation>
+<translation id="1021110881106174305">Kad diterima</translation>
<translation id="1032854598605920125">Putar ikut arah jam</translation>
<translation id="1038842779957582377">nama tidak diketahui</translation>
<translation id="1050038467049342496">Tutup apl lain</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Sembunyikan nilai</translation>
<translation id="1228893227497259893">Pengecam entiti yang salah</translation>
<translation id="1232569758102978740">Tidak Bertajuk</translation>
+<translation id="1263231323834454256">Senarai bacaan</translation>
<translation id="1264126396475825575">Laporan ranap sistem dirakam pada <ph name="CRASH_TIME" /> (belum dimuat naik atau diabaikan)</translation>
<translation id="1285320974508926690">Jangan sekali-kali menterjemahkan tapak ini</translation>
<translation id="129553762522093515">Ditutup baru-baru ini</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Tetapan Auto Isi Chromium...</translation>
<translation id="1374468813861204354">cadangan</translation>
<translation id="1375198122581997741">Mengenai Versi</translation>
+<translation id="1377321085342047638">Nombor Kad</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> tidak menghantar sebarang data.</translation>
<translation id="1407135791313364759">Buka semua</translation>
<translation id="1413809658975081374">Ralat privasi</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Sejarah</translation>
<translation id="1645368109819982629">Protokol tidak disokong</translation>
<translation id="1656489000284462475">Pengambilan</translation>
+<translation id="1663943134801823270">Kad dan alamat adalah daripada Chrome. Anda boleh mengurus kad dan alamat ini dalam <ph name="BEGIN_LINK" />Tetapan<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> biasanya menggunakan penyulitan untuk melindungi maklumat anda. Apabila Google Chrome cuba menyambung ke <ph name="SITE" /> pada kali ini, tapak web tersebut mengembalikan bukti kelayakan yang luar biasa dan salah. Hal ini boleh berlaku apabila penyerang sedang cuba menyamar sebagai <ph name="SITE" /> atau skrin log masuk Wi-Fi telah memutuskan sambungan. Maklumat anda masih selamat kerana Google Chrome menghentikan sambungan sebelum sebarang pertukaran data berlaku.</translation>
<translation id="168328519870909584">Penyerang yang kini berada di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mungkin cuba memasang apl berbahaya pada peranti anda yang mencuri atau memadamkan maklumat anda (sebagai contoh, foto, kata laluan, mesej dan kad kredit).</translation>
<translation id="168841957122794586">Sijil pelayan mengandungi kunci kriptografi yang lemah.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Anda memerlukan kebenaran daripada <ph name="NAME" /> untuk melawat tapak ini</translation>
+<translation id="1721424275792716183">* Medan perlu diisi</translation>
<translation id="1728677426644403582">Anda sedang melihat sumber halaman web</translation>
+<translation id="173080396488393970">Jenis kad ini tidak disokong</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Cuba hubungi pentadbir sistem.</translation>
+<translation id="1740951997222943430">Masukkan bulan tamat tempoh yang sah</translation>
<translation id="1745358365027406341">Muat turun halaman kemudian</translation>
<translation id="17513872634828108">Buka tab</translation>
<translation id="1753706481035618306">Nombor halaman</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Sila kemas kini frasa laluan segerak anda.</translation>
<translation id="1787142507584202372">Tab yang dibuka dipaparkan di sini</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Pilih alamat penghantaran untuk menyemak kaedah dan keperluan penghantaran.</translation>
+<translation id="1803264062614276815">Nama Pemegang Kad</translation>
<translation id="1803678881841855883">Penyemakan Imbas Selamat Google <ph name="BEGIN_LINK" />mengesan perisian hasad<ph name="END_LINK" /> di <ph name="SITE" /> baru-baru ini. Tapak web yang lazimnya selamat, kadangkala dijangkiti perisian hasad. Kandungan hasad berasal daripada <ph name="SUBRESOURCE_HOST" />, iaitu pengedar perisian hasad yang diketahui. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Ditambahkan <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Permintaan atau parameter permintaan tidak sah</translation>
<translation id="1826516787628120939">Menyemak</translation>
<translation id="1834321415901700177">Tapak ini mengandungi atur cara berbahaya</translation>
<translation id="1842969606798536927">Bayar</translation>
-<translation id="1864455488461349376">Pilihan penghantaran</translation>
<translation id="1871208020102129563">Proksi ditetapkan untuk menggunakan pelayan proksi tetap, bukannya URL skrip .pac.</translation>
<translation id="1871284979644508959">Medan yang diperlukan</translation>
<translation id="187918866476621466">Buka halaman permulaan</translation>
<translation id="1883255238294161206">Runtuhkan senarai</translation>
<translation id="1898423065542865115">Penapisan</translation>
<translation id="194030505837763158">Pergi ke <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Kad diterima</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> Penanda halaman</translation>
<translation id="1973335181906896915">Ralat penyirian</translation>
<translation id="1974060860693918893">Lanjutan</translation>
<translation id="1978555033938440688">Versi Perisian Tegar</translation>
+<translation id="1995859865337580572">Sila sahkan CVC anda</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{dan 1 lagi}other{dan # lagi}}</translation>
-<translation id="2020194265157481222">Nama pada kad diperlukan</translation>
<translation id="2025186561304664664">Proksi ditetapkan kepada auto konfigurasi.</translation>
<translation id="2030481566774242610">Adakah anda maksudkan <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Menyemak proksi dan tembok api<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Hari ini</translation>
<translation id="2154054054215849342">Penyegerakan tidak tersedia untuk domain anda</translation>
<translation id="2154484045852737596">Edit kad</translation>
-<translation id="2156993118928861787">Alamat tidak sah</translation>
<translation id="2166049586286450108">Akses Penuh Pentadbir</translation>
<translation id="2166378884831602661">Tapak ini tidak dapat menyediakan sambungan yang selamat</translation>
<translation id="2181821976797666341">Dasar</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 alamat}other{# alamat}}</translation>
+<translation id="2202020181578195191">Masukkan tahun tamat tempoh yang sah</translation>
<translation id="2212735316055980242">Dasar tidak dijumpai</translation>
<translation id="2213606439339815911">Mengambil entri…</translation>
<translation id="2230458221926704099">Betulkan sambungan anda menggunakan <ph name="BEGIN_LINK" />apl diagnostik<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Akses Internet anda disekat</translation>
<translation id="230155334948463882">Kad baharu?</translation>
<translation id="2305919008529760154">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya mungkin telah dikeluarkan secara penipuan. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Pilihan kad dan alamat adalah daripada Akaun Google anda (<ph name="ACCOUNT_EMAIL" />) dan Chrome. Anda boleh mengurus pilihan ini dalam <ph name="BEGIN_LINK" />Tetapan<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> memerlukan nama pengguna dan kata laluan.</translation>
<translation id="2318774815570432836">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana tapak web ini menggunakan HSTS. Ralat rangkaian dan serangan biasanya bersifat sementara, oleh itu halaman ini mungkin akan berfungsi sebentar lagi. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Penanda halaman lain</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Lalai perusahaan</translation>
<translation id="2386255080630008482">Sijil pelayan telah dibatalkan.</translation>
<translation id="2392959068659972793">Paparkan dasar tanpa nilai yang ditetapkan</translation>
+<translation id="239429038616798445">Kaedah penghantaran ini tidak tersedia. Cuba kaedah lain.</translation>
<translation id="2396249848217231973">&amp;Buat asal pemadaman</translation>
<translation id="2460160116472764928">Penyemakan Imbas Selamat <ph name="BEGIN_LINK" />mengesan perisian hasad <ph name="END_LINK" /> di <ph name="SITE" /> baru-baru ini. Tapak web yang biasanya selamat, kadangkala dijangkiti perisian hasad. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Isi</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Jalankan Diagnostik Rangkaian<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL carian tidak sah.</translation>
<translation id="2491120439723279231">Sijil pelayan mengandungi ralat.</translation>
-<translation id="24943777258388405">Nombor telefon tidak sah</translation>
<translation id="2495083838625180221">Penghurai JSON</translation>
<translation id="2495093607237746763">Jika ditandai, Chromium akan menyimpan salinan kad anda pada peranti ini untuk pengisian borang yang lebih cepat.</translation>
<translation id="2498091847651709837">Imbas kad baharu</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> menghantar balasan yang tidak sah.</translation>
<translation id="2552545117464357659">Lebih baharu</translation>
<translation id="2556876185419854533">&amp;Buat Asal Edit</translation>
+<translation id="2587730715158995865">Daripada <ph name="ARTICLE_PUBLISHER" />. Baca artikel ini dan <ph name="OTHER_ARTICLE_COUNT" /> cerita lain.</translation>
<translation id="2587841377698384444">ID API Direktori:</translation>
<translation id="2597378329261239068">Dokumen ini dilindungi kata laluan. Sila masukkan kata laluan.</translation>
<translation id="2609632851001447353">Variasi</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Jalankan Diagnostik Sambungan<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">Ok</translation>
<translation id="2742870351467570537">Buang item yang dipilih</translation>
+<translation id="277133753123645258">Kaedah penghantaran</translation>
<translation id="277499241957683684">Tiada rekod peranti</translation>
<translation id="2784949926578158345">Sambungan ditetapkan semula.</translation>
<translation id="2794233252405721443">Tapak disekat</translation>
-<translation id="2812680587231492111">Pilihan pengambilan itu tidak tersedia. Cuba pilihan lain.</translation>
<translation id="2824775600643448204">Bar alamat dan carian</translation>
<translation id="2826760142808435982">Sambungan disulitkan dan disahkan menggunakan <ph name="CIPHER" /> dan menggunakan <ph name="KX" /> sebagai mekanisme pertukaran kunci.</translation>
<translation id="2835170189407361413">Kosongkan borang</translation>
-<translation id="2849041323157393173">Pilihan penghantaran itu tidak tersedia. Cuba pilihan lain.</translation>
<translation id="2889159643044928134">Jangan Muat Semula</translation>
<translation id="2900469785430194048">Google Chrome kehabisan memori semasa cuba memaparkan halaman web ini.</translation>
<translation id="2909946352844186028">Perubahan rangkaian dikesan.</translation>
<translation id="2916038427272391327">Tutup atur cara lain</translation>
<translation id="2922350208395188000">Sijil pelayan tidak boleh diperiksa.</translation>
+<translation id="2928905813689894207">Alamat Pengebilan</translation>
<translation id="2948083400971632585">Anda boleh melumpuhkan sebarang proksi yang dikonfigurasi untuk sambungan dari halaman tetapan.</translation>
<translation id="2955913368246107853">Tutup bar cari</translation>
<translation id="2958431318199492670">Konfigurasi rangkaian tidak mematuhi piawaian ONC. Sebahagian konfigurasi tidak boleh diimport.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Untuk mewujudkan sambungan yang selamat, jam anda perlu ditetapkan dengan betul. Perkara ini perlu dilakukan kerana sijil yang digunakan laman web untuk mengenal pastinya hanya sah untuk tempoh masa yang tertentu. Memandangkan jam peranti anda tidak betul, Google Chrome tidak boleh mengesahkan sijil ini.</translation>
<translation id="2972581237482394796">&amp;Buat Semula</translation>
<translation id="2985306909656435243">Jika didayakan, Chromium akan menyimpan salinan kad anda pada peranti ini untuk pengisian borang yang lebih cepat.</translation>
+<translation id="2985398929374701810">Masukkan alamat yang sah</translation>
+<translation id="2986368408720340940">Kaedah pengambilan ini tidak tersedia. Cuba kaedah lain.</translation>
<translation id="2991174974383378012">Berkongsi dengan Tapak Web</translation>
<translation id="3005723025932146533">Paparkan salinan disimpan</translation>
<translation id="3008447029300691911">Masukkan CVC untuk <ph name="CREDIT_CARD" />. Setelah anda mengesahkan, butiran kad anda akan dikongsi dengan tapak ini.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{sekurang-kurangnya 1 item pada peranti yang disegerakkan}=1{1 item (dan beberapa lagi pada peranti yang disegerakkan)}other{# item (dan beberapa lagi pada peranti yang disegerakkan)}}</translation>
<translation id="3041612393474885105">Maklumat Sijil</translation>
<translation id="3063697135517575841">Chrome tidak dapat mengesahkan kad anda pada masa ini. Sila cuba sebentar lagi.</translation>
+<translation id="3064966200440839136">Meninggalkan mod inkognito untuk membayar melalui aplikasi luar. Teruskan?</translation>
<translation id="3093245981617870298">Anda di luar talian.</translation>
<translation id="3105172416063519923">ID Aset:</translation>
<translation id="3109728660330352905">Anda tidak mempunyai kebenaran untuk melihat halaman ini.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Cuba jalankan Diagnostik Sambungan<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Gagal menyahkod balasan</translation>
-<translation id="3149891296864842641">Pilihan penghantaran</translation>
<translation id="3150653042067488994">Ralat pelayan sementara</translation>
+<translation id="3154506275960390542">Halaman ini mengandungi borang yang mungkin tidak diserahkan secara selamat. Data yang dihantar boleh dilihat oleh orang lain semasa dihantar atau boleh diubah suai oleh penyerang untuk mengubah data yang diterima oleh pelayan.</translation>
<translation id="3157931365184549694">Pulihkan</translation>
<translation id="3167968892399408617">Halaman yang anda lihat dalam tab inkognito tidak akan kekal dalam sejarah, simpanan kuki atau sejarah carian penyemak imbas anda selepas anda menutup semua tab inkognito anda. Sebarang fail yang anda muat turun atau penanda halaman yang anda buat akan disimpan.</translation>
<translation id="3169472444629675720">Temui</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Permintaan anda untuk mengakses tapak web ini tidak boleh dihantar kepada <ph name="NAME" />. Sila cuba lagi.</translation>
<translation id="3355823806454867987">Tukar tetapan proksi...</translation>
<translation id="3369192424181595722">Ralat Jam</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> item lagi...</translation>
<translation id="337363190475750230">Nyahperuntukkan</translation>
<translation id="3377188786107721145">Ralat menghuraikan dasar</translation>
<translation id="3380365263193509176">Ralat tidak diketahui</translation>
<translation id="3380864720620200369">ID Pelanggan:</translation>
<translation id="3391030046425686457">Alamat penghantaran</translation>
+<translation id="3395827396354264108">Kaedah pengambilan</translation>
<translation id="340013220407300675">Penyerang mungkin akan cuba mencuri maklumat anda daripada <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (sebagai contoh, kata laluan, mesej atau kad kredit).</translation>
<translation id="3422248202833853650">Cuba keluar daripada atur cara lain untuk mengosongkan memori.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> tidak dapat dicapai pada masa ini.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Selang masa ambil:</translation>
<translation id="3462200631372590220">Menyembunyikan butiran</translation>
+<translation id="3467763166455606212">Nama pemegang kad diperlukan</translation>
+<translation id="3478058380795961209">Bulan Tamat Tempoh</translation>
<translation id="3479539252931486093">Adakah hal ini tidak dijangka? <ph name="BEGIN_LINK" />Beritahu kami<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Bukan sekarang</translation>
<translation id="348000606199325318">ID Ranap Sistem <ph name="CRASH_LOCAL_ID" /> (ID Pelayan: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Kami tidak dapat menghubungi ibu bapa anda pada masa ini. Sila cuba lagi.</translation>
<translation id="3528171143076753409">Sijil pelayan tidak dipercayai.</translation>
-<translation id="3538531656504267329">Tahun tamat tempoh tidak sah</translation>
<translation id="3539171420378717834">Simpan salinan kad ini pada peranti ini</translation>
<translation id="3542684924769048008">Gunakan kata laluan untuk:</translation>
<translation id="3549644494707163724">Sulitkan semua data yang disegerakkan dengan ungkapan laluan segerak anda sendiri</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Sembunyikan butiran</translation>
<translation id="3587482841069643663">Semua</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Masukkan tarikh tamat tempoh yang sah</translation>
<translation id="36224234498066874">Kosongkan Data Penyemakan Imbas...</translation>
<translation id="362276910939193118">Paparkan Sejarah Penuh</translation>
<translation id="3623476034248543066">Tunjukkan nilai</translation>
@@ -313,7 +325,6 @@
<translation id="3693415264595406141">Kata laluan:</translation>
<translation id="3696411085566228381">tiada</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Pilih alamat penghantaran untuk menyemak kaedah penghantaran dan keperluan.</translation>
<translation id="370665806235115550">Memuatkan...</translation>
<translation id="3712624925041724820">Kehabisan lesen</translation>
<translation id="3714780639079136834">Menghidupkan data mudah alih atau Wi-Fi</translation>
@@ -322,6 +333,7 @@
<translation id="3739623965217189342">Pautan yang anda salin</translation>
<translation id="375403751935624634">Gagal menterjemah disebabkan ralat pelayan.</translation>
<translation id="3759461132968374835">Tiada laporan nahas yang dibuat baru-baru ini. Nahas yang berlaku apabila laporan nahas dilumpuhkan tidak akan kelihatan di sini.</translation>
+<translation id="3787705759683870569">Tamat tempoh pada <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Jika anda menggunakan pelayan proksi...</translation>
<translation id="3828924085048779000">Kosongkan frasa laluan adalah tidak dibenarkan.</translation>
<translation id="3845539888601087042">Menunjukkan sejarah daripada peranti anda yang dilog masuk. <ph name="BEGIN_LINK" />Ketahui lebih lanjut<ph name="END_LINK" />.</translation>
@@ -357,7 +369,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Adakah anda mahu Chromium menyimpan kad ini?</translation>
<translation id="4171400957073367226">Tandatangan pengesahan tidak sah</translation>
-<translation id="4176463684765177261">Dilumpuhkan</translation>
<translation id="4196861286325780578">&amp;Buat semula pindahkan</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Menyemak konfigurasi tembok api dan antivirus<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{tiada}=1{1 apl ($1)}=2{2 apl ($1, $2)}other{# apl ($1, $2, $3)}}</translation>
@@ -384,11 +395,11 @@
<translation id="4406896451731180161">hasil carian</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> tidak menerima sijil log masuk anda atau sijil log masuk mungkin tidak diberikan.</translation>
<translation id="443673843213245140">Penggunaan proksi dilumpuhkan tetapi konfigurasi proksi yang jelas dinyatakan.</translation>
-<translation id="4446242550670694251">Kini, anda boleh menyemak imbas secara sulit dan orang lain yang menggunakan peranti ini tidak akan melihat aktiviti anda.</translation>
<translation id="4492190037599258964">Hasil carian untuk '<ph name="SEARCH_STRING" />'</translation>
<translation id="4506176782989081258">Ralat pengesahan: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Menghubungi pentadbir sistem</translation>
<translation id="450710068430902550">Berkongsi dengan Pentadbir</translation>
+<translation id="4515275063822566619">Kad dan alamat adalah daripada Chrome dan Akaun Google anda (<ph name="ACCOUNT_EMAIL" />). Anda boleh mengurus kad dan alamat ini dalam <ph name="BEGIN_LINK" />Tetapan<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Butiran</translation>
<translation id="4558551763791394412">Cuba lumpuhkan sambungan anda.</translation>
<translation id="457875822857220463">Penghantaran</translation>
@@ -418,6 +429,7 @@
<translation id="4816492930507672669">Muat halaman</translation>
<translation id="483020001682031208">Tiada halaman Web Fizikal yang hendak dipaparkan</translation>
<translation id="4850886885716139402">Lihat</translation>
+<translation id="4854362297993841467">Kaedah penghantaran ini tidak tersedia. Cuba kaedah lain.</translation>
<translation id="4858792381671956233">Anda telah bertanya kepada ibu bapa anda sama ada OK untuk melawat tapak ini</translation>
<translation id="4880827082731008257">Sejarah carian</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -425,7 +437,6 @@
<translation id="4923417429809017348">Halaman ini diterjemahkan dari bahasa yang tidak diketahui ke <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Pembayaran</translation>
<translation id="4926049483395192435">Mesti ditentukan.</translation>
-<translation id="4941291666397027948">* menandakan medan yang diperlukan</translation>
<translation id="495170559598752135">Tindakan</translation>
<translation id="4958444002117714549">Kembangkan senarai</translation>
<translation id="4962322354953122629">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh Chrome. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -440,6 +451,7 @@
<translation id="5045550434625856497">Kata laluan tidak sah</translation>
<translation id="5056549851600133418">Artikel untuk anda</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Menyemak alamat proksi<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Tiada kuki}=1{1 tapak menggunakan kuki. }other{# tapak menggunakan kuki. }}</translation>
<translation id="5087286274860437796">Sijil pelayan tidak sah pada masa ini.</translation>
<translation id="5087580092889165836">Tambah kad</translation>
<translation id="5089810972385038852">Negeri</translation>
@@ -462,10 +474,8 @@
<translation id="5300589172476337783">Paparkan</translation>
<translation id="5308689395849655368">Pelaporan nahas dilumpuhkan.</translation>
<translation id="5317780077021120954">Simpan</translation>
-<translation id="5326702247179446998">Penerima diperlukan</translation>
<translation id="5327248766486351172">Nama</translation>
<translation id="5337705430875057403">Penyerang di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mungkin menipu anda supaya melakukan sesuatu yang berbahaya seperti memasang perisian atau mendedahkan maklumat peribadi anda (contohnya, kata laluan, nombor telefon atau kad kredit).</translation>
-<translation id="53553865750799677">Alamat pengambilan tidak disokong. Pilih alamat lain.</translation>
<translation id="5359637492792381994">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya tidak sah pada masa ini. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Gagal menyimpan tetapan dasar</translation>
<translation id="5386426401304769735">Rantaian sijil untuk tapak ini mengandungi sijil yang ditandatangani menggunakan SHA-1.</translation>
@@ -491,8 +501,8 @@
<translation id="5544037170328430102">Halaman terbenam di <ph name="SITE" /> menyatakan:</translation>
<translation id="5556459405103347317">Muat Semula</translation>
<translation id="5565735124758917034">Aktif</translation>
+<translation id="5571083550517324815">Tidak boleh mengambil dari alamat ini. Pilih alamat lain.</translation>
<translation id="5572851009514199876">Sila mulakan dan log masuk ke Chrome supaya Chrome boleh menyemak sama ada anda dibenarkan mengakses tapak ini.</translation>
-<translation id="5575380383496039204">Alamat penghantaran tidak disokong. Pilih alamat lain.</translation>
<translation id="5580958916614886209">Semak bulan tamat tempoh anda dan cuba lagi</translation>
<translation id="560412284261940334">Pengurusan tidak disokong</translation>
<translation id="5610142619324316209">Menyemak sambungan</translation>
@@ -508,7 +518,8 @@
<translation id="5710435578057952990">Identiti tapak web ini belum disahkan.</translation>
<translation id="5720705177508910913">Pengguna semasa</translation>
<translation id="5732392974455271431">Ibu bapa anda boleh menyahsekatnya untuk anda</translation>
-<translation id="57586589942790530">Nombor kad tidak sah</translation>
+<translation id="5763042198335101085">Masukkan alamat e-mel yang sah</translation>
+<translation id="5765072501007116331">Pilih alamat untuk melihat kaedah dan syarat penghantaran</translation>
<translation id="5784606427469807560">Terdapat masalah mengesahkan kad anda. Semak sambungan Internet anda dan cuba lagi.</translation>
<translation id="5785756445106461925">Selain itu, halaman ini mengandungi sumber lain yang tidak selamat. Sumber ini boleh dilihat oleh orang lain semasa dalam transit dan boleh diubah oleh penyerang untuk menukar penampilan halaman.</translation>
<translation id="5786044859038896871">Adakah anda ingin mengisi maklumat kad anda?</translation>
@@ -521,22 +532,20 @@
<translation id="5869405914158311789">Tapak ini tidak dapat dicapai</translation>
<translation id="5869522115854928033">Kata laluan disimpan</translation>
<translation id="5872918882028971132">Cadangan Ibu Bapa</translation>
-<translation id="587760065310675640">Alamat penghantaran tidak disokong. Pilih alamat lain.</translation>
<translation id="5901630391730855834">Kuning</translation>
-<translation id="59174027418879706">Didayakan</translation>
<translation id="5926846154125914413">Anda mungkin kehilangan akses kepada kandungan premium daripada sesetengah tapak web.</translation>
<translation id="5959728338436674663">Hantar secara automatik beberapa <ph name="BEGIN_WHITEPAPER_LINK" />maklumat sistem dan kandungan halaman<ph name="END_WHITEPAPER_LINK" /> kepada Google untuk membantu anda mengesan apl dan tapak yang berbahaya. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Minggu</translation>
<translation id="5967867314010545767">Buang daripada sejarah</translation>
<translation id="5975083100439434680">Zum keluar</translation>
+<translation id="598637245381783098">Tidak dapat membuka apl pembayaran</translation>
<translation id="5989320800837274978">Pelayan proksi tetap begitu juga URL skrip .pac, kedua-duanya tidak ditetapkan.</translation>
<translation id="5990559369517809815">Permintaan pada pelayan telah disekat oleh sambungan.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Pilihan kad dan alamat adalah daripada Chrome. Anda boleh mengurus pilihan ini dalam <ph name="BEGIN_LINK" />Tetapan<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Halaman 1}other{Halaman #}}</translation>
<translation id="6017514345406065928">Hijau</translation>
+<translation id="6027201098523975773">Masukkan nama</translation>
<translation id="6040143037577758943">Tutup</translation>
-<translation id="604124094241169006">Automatik</translation>
<translation id="6042308850641462728">Lagi</translation>
<translation id="6060685159320643512">Berhati-hati, percubaan ini mungkin memudaratkan</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{tiada}=1{1}other{#}}</translation>
@@ -544,9 +553,10 @@
rangkaian lain yang mungkin anda gunakan.</translation>
<translation id="614940544461990577">Cuba:</translation>
<translation id="6151417162996330722">Sijil pelayan mempunyai tempoh sah yang terlalu panjang.</translation>
-<translation id="615643356032862689">Fail yang dimuat turun dan penanda halaman akan disimpan.</translation>
+<translation id="6157877588268064908">Pilih alamat untuk melihat kaedah dan syarat penghantaran</translation>
<translation id="6165508094623778733">Ketahui lebih lanjut</translation>
<translation id="6177128806592000436">Sambungan anda ke tapak ini tidak selamat</translation>
+<translation id="6184817833369986695">(kohort: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Semak sambungan Internet anda</translation>
<translation id="6218753634732582820">Alih keluar alamat daripada Chromium?</translation>
<translation id="6251924700383757765">Dasar privasi</translation>
@@ -555,6 +565,8 @@
<translation id="6259156558325130047">&amp;Buat Asal Susun Semula</translation>
<translation id="6263376278284652872">Penanda halaman <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Kembali ke keselamatan</translation>
+<translation id="6276112860590028508">Halaman daripada senarai bacaan anda dipaparkan di sini</translation>
+<translation id="6280223929691119688">Tidak dapat menghantar ke alamat ini. Pilih alamat lain.</translation>
<translation id="6282194474023008486">Poskod</translation>
<translation id="6290238015253830360">Artikel cadangan anda dipaparkan di sini</translation>
<translation id="6305205051461490394"><ph name="URL" /> tidak dapat dicapai.</translation>
@@ -576,7 +588,6 @@
<translation id="6417515091412812850">Tidak dapat memeriksa sama ada sijil telah dibatalkan.</translation>
<translation id="6433490469411711332">Edit maklumat hubungan</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> enggan menyambung.</translation>
-<translation id="6443118737398455446">Tarikh tamat tempoh tidak sah</translation>
<translation id="6446608382365791566">Tambahkan maklumat lanjut</translation>
<translation id="6451458296329894277">Sahkan Penyerahan Semula Borang</translation>
<translation id="6456339708790392414">Pembayaran Anda</translation>
@@ -584,10 +595,8 @@
<translation id="6462969404041126431">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya telah dibatalkan. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Dasar peranti</translation>
<translation id="6477321094435799029">Chrome mengesan kod luar biasa pada halaman ini dan menyekatnya untuk melindungi maklumat peribadi anda (contohnya, kata laluan, nombor telefon dan maklumat kad kredit).</translation>
-<translation id="6477460825583319731">Alamat e-mel tidak sah</translation>
<translation id="6489534406876378309">Mulakan muat naik ranap sistem</translation>
<translation id="6508722015517270189">Mulakan semula Chrome</translation>
-<translation id="6525462735697194615">Bulan tamat tempoh tidak sah</translation>
<translation id="6529602333819889595">&amp;Buat Semula Pemadaman</translation>
<translation id="6534179046333460208">Cadangan Web Fizikal</translation>
<translation id="6550675742724504774">Pilihan</translation>
@@ -602,7 +611,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Carian</translation>
<translation id="6644283850729428850">Dasar ini telah dikecam.</translation>
<translation id="6652240803263749613">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh sistem pengendalian komputer anda. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Pilihan pengiriman itu tidak tersedia. Cuba pilihan lain.</translation>
<translation id="6671697161687535275">Alih keluar cadangan borang daripada Chromium?</translation>
<translation id="6685834062052613830">Log keluar dan selesaikan persediaan</translation>
<translation id="6710213216561001401">Sebelumnya</translation>
@@ -610,13 +618,13 @@
<translation id="6711464428925977395">Ada sesuatu yang tidak kena dengan pelayan proksi atau alamat tidak betul.</translation>
<translation id="6727102863431372879">Tetapkan</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{tiada}=1{1 item}other{# item}}</translation>
-<translation id="6743044928064272573">Pilihan pengambilan</translation>
<translation id="674375294223700098">Ralat sijil pelayan tidak diketahui.</translation>
<translation id="6753269504797312559">Nilai dasar</translation>
<translation id="6757797048963528358">Peranti anda tidak aktif.</translation>
<translation id="6778737459546443941">Ibu bapa anda belum meluluskannya</translation>
<translation id="6810899417690483278">ID Penyesuaian</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Gagal memuatkan data rantau</translation>
<translation id="6831043979455480757">Terjemah</translation>
<translation id="6839929833149231406">Kawasan</translation>
<translation id="6874604403660855544">&amp;Buat semula tambahkan</translation>
@@ -624,6 +632,7 @@
<translation id="6895330447102777224">Kad anda telah disahkan</translation>
<translation id="6897140037006041989">Ejen Pengguna</translation>
<translation id="6915804003454593391">Pengguna:</translation>
+<translation id="6948701128805548767">Pilih alamat untuk melihat kaedah dan syarat pengambilan</translation>
<translation id="6957887021205513506">Sijil pelayan rupanya adalah pemalsuan.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Peranti</translation>
@@ -631,7 +640,6 @@
<translation id="6973656660372572881">Pelayan proksi tetap dan juga URL skrip .pac tidak ditetapkan.</translation>
<translation id="6989763994942163495">Paparkan tetapan lanjutan...</translation>
<translation id="7000990526846637657">Tiada masukan sejarah ditemui</translation>
-<translation id="7001663382399377034">Tambahkan penerima</translation>
<translation id="7009986207543992532">Anda cuba mencapai <ph name="DOMAIN" />, tetapi pelayan memberikan sijil yang tempoh sahnya terlalu panjang untuk dipercayai. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Akaun Google anda mungkin mempunyai sejarah penyemakan imbas dalam bentuk lain di <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -642,12 +650,15 @@
<translation id="7088615885725309056">Lebih lama</translation>
<translation id="7090678807593890770">Cari <ph name="LINK" /> di Google</translation>
<translation id="7119414471315195487">Tutup tab atau atur cara lain</translation>
+<translation id="7129409597930077180">Tidak dapat menghantar ke alamat ini. Pilih alamat lain.</translation>
+<translation id="7138472120740807366">Kaedah penghantaran</translation>
<translation id="7139724024395191329">Emiriah</translation>
<translation id="7155487117670177674">Pembayaran tidak selamat</translation>
<translation id="7179921470347911571">Lancarkan Semula Sekarang</translation>
<translation id="7180611975245234373">Muat semula</translation>
<translation id="7182878459783632708">Tiada dasar ditetapkan</translation>
<translation id="7186367841673660872">Halaman ini telah diterjemahkan dari<ph name="ORIGINAL_LANGUAGE" />ke<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> tidak mematuhi piawaian keselamatan.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Ketahui lebih lanjut<ph name="END_LINK" /> mengenai masalah ini.</translation>
@@ -676,7 +687,6 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="7424977062513257142">Halaman terbenam pada halaman web ini menyatakan:</translation>
<translation id="7441627299479586546">Subjek dasar salah</translation>
<translation id="7444046173054089907">Tapak ini disekat</translation>
-<translation id="7444238235002594607">Pilih alamat pengambilan untuk menyemak kaedah dan keperluan pengambilan.</translation>
<translation id="7445762425076701745">Identiti pelayan yang disambungkan kepada anda tidak dapat disahkan sepenuhnya. Anda disambungkan ke pelayan menggunakan nama yang sah dalam rangkaian anda sahaja, apabila pihak berkuasa sijil luaran tiada cara untuk mengesahkan pemilikan. Oleh kerana beberapa pihak berkuasa sijil juga akan terus mengeluarkan sijil untuk nama ini, tiada cara untuk memastikan anda disambungkan ke tapak web yang diingini dan bukannya penyerang.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Ketahui lebih lanjut<ph name="END_LINK" /> tentang masalah ini.</translation>
<translation id="7460163899615895653">Tab terbaharu anda daripada peranti lain dipaparkan di sini</translation>
@@ -720,6 +730,7 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="7755287808199759310">Ibu bapa anda boleh menyahsekatnya untuk anda</translation>
<translation id="7758069387465995638">Tembok api atau perisian antivirus mungkin telah menyekat sambungan.</translation>
<translation id="7761701407923456692">Sijil pelayan tidak sepadan dengan URL.</translation>
+<translation id="7763386264682878361">Penghurai Manifes Bayaran</translation>
<translation id="7764225426217299476">Tambahkan alamat</translation>
<translation id="777702478322588152">Wilayah</translation>
<translation id="7791543448312431591">Tambah</translation>
@@ -733,6 +744,7 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="785549533363645510">Walau bagaimanapun, anda tidak halimunan. Apabila anda menggunakan mod inkognito, penyemakan imbas anda tidak akan disembunyikan daripada majikan anda, penyedia perkhidmatan Internet anda atau tapak web yang anda lawati.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Semak CVC anda dan cuba lagi</translation>
+<translation id="79338296614623784">Masukkan nombor telefon yang sah</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Sijil pelayan masih belum sah.</translation>
<translation id="7942349550061667556">Merah</translation>
@@ -752,6 +764,7 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="8088680233425245692">Gagal melihat artikel.</translation>
<translation id="8089520772729574115">kurang daripada 1 MB</translation>
<translation id="8091372947890762290">Pengaktifan belum selesai pada pelayan</translation>
+<translation id="8118489163946903409">Kaedah pembayaran</translation>
<translation id="8131740175452115882">Sahkan</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Alamat DNS<ph name="END_ABBR" /> pelayan <ph name="HOST_NAME" /> tidak ditemui.</translation>
<translation id="8149426793427495338">Komputer anda dalam mod tidur.</translation>
@@ -777,6 +790,7 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="8349305172487531364">Bar penanda halaman</translation>
<translation id="8363502534493474904">Matikan mod pesawat</translation>
<translation id="8364627913115013041">Tidak ditetapkan.</translation>
+<translation id="8368476060205742148">Perkhidmatan Google Play</translation>
<translation id="8380941800586852976">Berbahaya</translation>
<translation id="8382348898565613901">Penanda halaman anda yang terbaharu dilawati dipaparkan di sini</translation>
<translation id="8398259832188219207">Laporan ranap sistem dimuat naik pada <ph name="UPLOAD_TIME" /></translation>
@@ -785,32 +799,30 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="8428213095426709021">Tetapan</translation>
<translation id="8433057134996913067">Pemadaman ini akan membuatkan anda dilog keluar daripada kebanyakan tapak web.</translation>
<translation id="8437238597147034694">&amp;Buat asal pindahkan</translation>
-<translation id="8456681095658380701">Nama tidak sah</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 kad kredit}other{# kad kredit}}</translation>
<translation id="8483780878231876732">Log masuk ke Chrome untuk menggunakan kad daripada Akaun Google anda</translation>
<translation id="8488350697529856933">Diguna pakai untuk</translation>
-<translation id="8492969205326575646">Jenis kad tidak disokong</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> mengambil masa terlalu lama untuk bertindak balas.</translation>
<translation id="852346902619691059">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh sistem pengendalian peranti anda. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Tahun Tamat Tempoh</translation>
<translation id="8543181531796978784">Anda boleh <ph name="BEGIN_ERROR_LINK" />laporkan masalah pengesanan<ph name="END_ERROR_LINK" /> atau jika anda memahami risikonya kepada keselamatan anda, <ph name="BEGIN_LINK" />lawati tapak yang tidak selamat ini<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Gagal terjemahan kerana bahasa halaman tidak dapat ditentukan.</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="8570229484593575558">Maklumat ini |tidak akan disimpan|:#Sejarah penyemakan imbas anda#Carian anda#Data kuki</translation>
<translation id="8571890674111243710">Menterjemah halaman ke <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Aktiviti anda |mungkin masih dapat dilihat| kepada:#Tapak web yang anda lawati#Majikan anda#Penyedia perkhidmatan Internet anda</translation>
<translation id="858637041960032120">Tambah no. tel.
</translation>
<translation id="859285277496340001">Sijil tidak menyatakan mekanisme untuk memeriksa sama ada ia telah dibatalkan.</translation>
<translation id="8620436878122366504">Ibu bapa anda belum meluluskannya</translation>
<translation id="8647750283161643317">Tetapkan semula semua kepada lalai</translation>
<translation id="8703575177326907206">Sambungan anda ke <ph name="DOMAIN" /> tidak disulitkan.</translation>
+<translation id="8718314106902482036">Pembayaran belum selesai</translation>
<translation id="8725066075913043281">Cuba lagi</translation>
<translation id="8728672262656704056">Anda menggunakan mod inkognito</translation>
<translation id="8730621377337864115">Selesai</translation>
<translation id="8738058698779197622">Untuk mewujudkan sambungan yang selamat, jam anda perlu ditetapkan dengan betul. Ini kerana sijil yang digunakan oleh tapak 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="8759274551635299824">Kad ini telah tamat tempoh</translation>
<translation id="8790007591277257123">&amp;Buat semula pemadaman</translation>
-<translation id="8798099450830957504">Lalai</translation>
<translation id="8800988563907321413">Cadangan berdekatan anda dipaparkan di sini</translation>
<translation id="8820817407110198400">Penanda buku</translation>
<translation id="883848425547221593">Penanda Halaman Lain</translation>
@@ -820,6 +832,7 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="8866481888320382733">Ralat semasa menghuraikan tetapan dasar</translation>
<translation id="8866959479196209191">Halaman ini menyatakan:</translation>
<translation id="8870413625673593573">Ditutup Baru-baru Ini</translation>
+<translation id="8874824191258364635">Masukkan nombor kad yang sah</translation>
<translation id="8876793034577346603">Konfigurasi rangkaian gagal dihuraikan.</translation>
<translation id="8877192140621905067">Setelah anda mengesahkan, butiran kad anda akan dikongsi dengan tapak ini</translation>
<translation id="8889402386540077796">Rona</translation>
@@ -829,7 +842,6 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="8931333241327730545">Adakah anda mahu menyimpan kad ini ke Akaun Google anda?</translation>
<translation id="8932102934695377596">Jam anda di belakang</translation>
<translation id="8954894007019320973">(Samb.)</translation>
-<translation id="895548565263634352">Baca cerita daripada <ph name="ARTICLE_PUBLISHER" /> dan <ph name="OTHER_ARTICLE_COUNT" /> lagi</translation>
<translation id="8971063699422889582">Sijil pelayan telah tamat tempoh.</translation>
<translation id="8986494364107987395">Hantar statistik penggunaan dan laporan nahas kepada Google secara automatik</translation>
<translation id="8987927404178983737">Bulan</translation>
@@ -847,7 +859,6 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="9068849894565669697">Pilih warna</translation>
<translation id="9076283476770535406">Tapak mungkin mengandungi kandungan dewasa</translation>
<translation id="9078964945751709336">Maklumat lanjut diperlukan</translation>
-<translation id="9094175695478007090">Tidak dapat melancarkan apl pembayaran.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> biasanya menggunakan penyulitan untuk melindungi maklumat anda. Apabila Chromium cuba menyambung ke <ph name="SITE" /> pada kali ini, tapak web tersebut mengembalikan bukti kelayakan yang luar biasa dan salah. Hal ini boleh berlaku apabila penyerang sedang cuba menyamar sebagai <ph name="SITE" /> atau skrin log masuk Wi-Fi telah memutuskan sambungan. Maklumat anda masih selamat kerana Chromium menghentikan sambungan sebelum sebarang pertukaran data berlaku.</translation>
<translation id="9137013805542155359">Paparkan asal</translation>
<translation id="9137248913990643158">Sila mulakan dan log masuk ke Chrome sebelum menggunakan apl ini.</translation>
diff --git a/chromium/components/strings/components_strings_nl.xtb b/chromium/components/strings/components_strings_nl.xtb
index fa969e7e0a5..72e888f266c 100644
--- a/chromium/components/strings/components_strings_nl.xtb
+++ b/chromium/components/strings/components_strings_nl.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="nl">
<translation id="1008557486741366299">Niet nu</translation>
<translation id="1015730422737071372">Aanvullende gegevens verzenden</translation>
+<translation id="1021110881106174305">Geaccepteerde kaarten</translation>
<translation id="1032854598605920125">Rechtsom draaien</translation>
<translation id="1038842779957582377">onbekende naam</translation>
<translation id="1050038467049342496">Andere apps sluiten</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Waarde verbergen</translation>
<translation id="1228893227497259893">Onjuiste entiteits-ID</translation>
<translation id="1232569758102978740">Naamloos</translation>
+<translation id="1263231323834454256">Leeslijst</translation>
<translation id="1264126396475825575">Crashrapport vastgelegd op <ph name="CRASH_TIME" /> (nog niet geüpload of genegeerd)</translation>
<translation id="1285320974508926690">Deze site nooit vertalen</translation>
<translation id="129553762522093515">Recent gesloten</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Instellingen voor automatisch aanvullen in Chromium...</translation>
<translation id="1374468813861204354">suggesties</translation>
<translation id="1375198122581997741">Over deze versie</translation>
+<translation id="1377321085342047638">Kaartnummer</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> heeft geen gegevens verzonden.</translation>
<translation id="1407135791313364759">Alles openen</translation>
<translation id="1413809658975081374">Privacyfout</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Geschiedenis</translation>
<translation id="1645368109819982629">Niet-ondersteund protocol</translation>
<translation id="1656489000284462475">Ophaaltijd</translation>
+<translation id="1663943134801823270">Kaarten en adressen zijn afkomstig uit Chrome. Je kunt ze beheren in <ph name="BEGIN_LINK" />Instellingen<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> gebruikt gewoonlijk versleuteling om je gegevens te beschermen. Toen Google Chrome deze keer probeerde verbinding te maken met <ph name="SITE" />, retourneerde de website ongewone en onjuiste inloggegevens. Dit kan gebeuren als een aanvaller probeert zich als <ph name="SITE" /> voor te doen of als een wifi-inlogscherm de verbinding heeft verbroken. Je gegevens zijn nog steeds veilig omdat Google Chrome de verbinding heeft beëindigd voordat er gegevens konden worden uitgewisseld.</translation>
<translation id="168328519870909584">Cybercriminelen op <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> proberen mogelijk gevaarlijke apps op je apparaat te installeren waarmee je gegevens kunnen worden gestolen of verwijderd (bijvoorbeeld foto's, wachtwoorden, berichten en creditcardgegevens).</translation>
<translation id="168841957122794586">Het servercertificaat bevat een zwakke cryptografische sleutel.</translation>
<translation id="1710259589646384581">Besturingssysteem</translation>
<translation id="1721312023322545264">Je hebt toestemming van <ph name="NAME" /> nodig om deze site te bezoeken</translation>
+<translation id="1721424275792716183">* Verplicht veld</translation>
<translation id="1728677426644403582">Je bekijkt de bron van een webpagina</translation>
+<translation id="173080396488393970">Dit type kaart wordt niet ondersteund</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Probeer contact op te nemen met de systeembeheerder.</translation>
+<translation id="1740951997222943430">Geef een geldige vervalmaand op</translation>
<translation id="1745358365027406341">Pagina later downloaden</translation>
<translation id="17513872634828108">Geopende tabbladen</translation>
<translation id="1753706481035618306">Paginanummer</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Update je wachtwoordzin voor synchronisatie.</translation>
<translation id="1787142507584202372">Je geopende tabbladen worden hier weergegeven</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Selecteer een afleveradres om de aflevermethoden en -vereisten te controleren.</translation>
+<translation id="1803264062614276815">Naam kaarthouder</translation>
<translation id="1803678881841855883">Google Safe Browsing heeft onlangs <ph name="BEGIN_LINK" />malware gedetecteerd<ph name="END_LINK" /> op <ph name="SITE" />. Websites die normaal gesproken veilig zijn, worden soms besmet met malware. De schadelijke content is afkomstig van <ph name="SUBRESOURCE_HOST" />, een bekende distributeur van malware. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Toegevoegd: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Ongeldige aanvraag of aanvraagparameters</translation>
<translation id="1826516787628120939">Controleren</translation>
<translation id="1834321415901700177">Deze site bevat schadelijke programma's</translation>
<translation id="1842969606798536927">Betalen</translation>
-<translation id="1864455488461349376">Afleveroptie</translation>
<translation id="1871208020102129563">Proxy is ingesteld op het gebruik van vaste proxyservers, niet op een script-URL van het PAC-type.</translation>
<translation id="1871284979644508959">Verplicht veld</translation>
<translation id="187918866476621466">Startpagina's openen</translation>
<translation id="1883255238294161206">Lijst samenvouwen</translation>
<translation id="1898423065542865115">Filteren</translation>
<translation id="194030505837763158">Ga naar <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Geaccepteerde creditcards</translation>
<translation id="1962204205936693436">Bladwijzers voor <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Serialisatiefout</translation>
<translation id="1974060860693918893">Geavanceerd</translation>
<translation id="1978555033938440688">Firmwareversie</translation>
+<translation id="1995859865337580572">Verifieer je CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{en 1 andere}other{en # andere}}</translation>
-<translation id="2020194265157481222">Naam op kaart vereist</translation>
<translation id="2025186561304664664">Proxy is ingesteld op automatische configuratie.</translation>
<translation id="2030481566774242610">Bedoelde je <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Controleer de proxy en firewall<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Vandaag</translation>
<translation id="2154054054215849342">De synchronisatieservice is niet beschikbaar voor je domein</translation>
<translation id="2154484045852737596">Kaart bewerken</translation>
-<translation id="2156993118928861787">Ongeldig adres</translation>
<translation id="2166049586286450108">Volledige beheerderstoegang</translation>
<translation id="2166378884831602661">Deze site kan geen beveiligde verbinding leveren</translation>
<translation id="2181821976797666341">Beleid</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adres}other{# adressen}}</translation>
+<translation id="2202020181578195191">Geef een geldig vervaljaar op</translation>
<translation id="2212735316055980242">Beleid niet gevonden</translation>
<translation id="2213606439339815911">Items ophalen…</translation>
<translation id="2230458221926704099">Los problemen met je verbinding op met de <ph name="BEGIN_LINK" />diagnose-app<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Je toegang tot internet wordt geblokkeerd</translation>
<translation id="230155334948463882">Nieuwe kaart?</translation>
<translation id="2305919008529760154">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server is mogelijk frauduleus verstrekt. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Kaart- en adresopties komen uit je Google-account (<ph name="ACCOUNT_EMAIL" />) en Chrome. Je kunt ze beheren in <ph name="BEGIN_LINK" />Instellingen<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535">Voor <ph name="DOMAIN" /> zijn een gebruikersnaam en een wachtwoord vereist.</translation>
<translation id="2318774815570432836">Je kunt <ph name="SITE" /> op dit moment niet bezoeken, omdat de website gebruikmaakt van HSTS. Aangezien netwerkfouten en aanvallen meestal van tijdelijke aard zijn, zal deze pagina later waarschijnlijk weer correct werken. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Andere bladwijzers</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Standaardinstelling van bedrijf</translation>
<translation id="2386255080630008482">Het servercertificaat is ingetrokken.</translation>
<translation id="2392959068659972793">Beleid weergeven zonder waarde ingesteld</translation>
+<translation id="239429038616798445">Deze verzendmethode is niet beschikbaar. Kies een andere methode.</translation>
<translation id="2396249848217231973">&amp;Verwijderen ongedaan maken</translation>
<translation id="2460160116472764928">Google Safe Browsing heeft onlangs <ph name="BEGIN_LINK" />malware gedetecteerd<ph name="END_LINK" /> op <ph name="SITE" />. Websites die normaal gesproken veilig zijn, worden soms besmet met malware. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Invullen</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Netwerkcontrole uitvoeren<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Ongeldige zoek-URL.</translation>
<translation id="2491120439723279231">Het servercertificaat bevat fouten.</translation>
-<translation id="24943777258388405">Ongeldig telefoonnummer</translation>
<translation id="2495083838625180221">JSON Parser</translation>
<translation id="2495093607237746763">Als deze optie is aangevinkt, bewaart Chromium een exemplaar van je kaart op dit apparaat om formulieren sneller te kunnen invullen.</translation>
<translation id="2498091847651709837">Nieuwe kaart scannen</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> heeft een ongeldige reactie verzonden.</translation>
<translation id="2552545117464357659">Nieuwer</translation>
<translation id="2556876185419854533">&amp;Bewerken ongedaan maken</translation>
+<translation id="2587730715158995865">Van <ph name="ARTICLE_PUBLISHER" />. Lees dit en <ph name="OTHER_ARTICLE_COUNT" /> andere artikelen.</translation>
<translation id="2587841377698384444">Directory API-ID:</translation>
<translation id="2597378329261239068">Dit document is beveiligd met een wachtwoord. Geef een wachtwoord op.</translation>
<translation id="2609632851001447353">Varianten</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Verbindingsdiagnose uitvoeren<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">Geselecteerde items verwijderen</translation>
+<translation id="277133753123645258">Verzendmethode</translation>
<translation id="277499241957683684">Apparaatrecord ontbreekt</translation>
<translation id="2784949926578158345">De verbinding is opnieuw ingesteld.</translation>
<translation id="2794233252405721443">Site geblokkeerd</translation>
-<translation id="2812680587231492111">Die optie voor ophalen is niet beschikbaar. Kies een andere optie.</translation>
<translation id="2824775600643448204">Adres- en zoekbalk</translation>
<translation id="2826760142808435982">De verbinding is gecodeerd en geverifieerd met <ph name="CIPHER" /> en gebruikt <ph name="KX" /> als mechanisme voor sleuteluitwisseling.</translation>
<translation id="2835170189407361413">Formulier leegmaken</translation>
-<translation id="2849041323157393173">Die optie voor bezorging is niet beschikbaar. Kies een andere optie.</translation>
<translation id="2889159643044928134">Niet opnieuw laden</translation>
<translation id="2900469785430194048">Google Chrome beschikt over onvoldoende geheugen om deze webpagina weer te geven.</translation>
<translation id="2909946352844186028">Er is een netwerkwijziging gedetecteerd.</translation>
<translation id="2916038427272391327">Andere programma's sluiten</translation>
<translation id="2922350208395188000">Het servercertificaat kan niet worden gecontroleerd.</translation>
+<translation id="2928905813689894207">Factuuradres</translation>
<translation id="2948083400971632585">Via de instellingenpagina kun je proxyservers uitschakelen die voor een verbinding zijn geconfigureerd.</translation>
<translation id="2955913368246107853">Zoekbalk sluiten</translation>
<translation id="2958431318199492670">De netwerkconfiguratie voldoet niet aan de ONC-standaard. Delen van de configuratie worden mogelijk niet geïmporteerd.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Als je een beveiligde verbinding tot stand wilt brengen, moet je klok correct 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 Chrome deze certificaten niet verifiëren.</translation>
<translation id="2972581237482394796">&amp;Opnieuw</translation>
<translation id="2985306909656435243">Als deze instelling is ingeschakeld, slaat Chromium een kopie van je kaart op dit apparaat op zodat formulieren sneller kunnen worden ingevuld.</translation>
+<translation id="2985398929374701810">Geef een geldig adres op</translation>
+<translation id="2986368408720340940">Deze ophaalmethode is niet beschikbaar. Kies een andere methode.</translation>
<translation id="2991174974383378012">Delen met websites</translation>
<translation id="3005723025932146533">Opgeslagen kopie weergeven</translation>
<translation id="3008447029300691911">Geef de CVC-code voor <ph name="CREDIT_CARD" /> op. Zodra je bevestigt, worden je creditcardgegevens gedeeld met deze site.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{ten minste 1 item op gesynchroniseerde apparaten}=1{1 item (en meer op gesynchroniseerde apparaten)}other{# items (en meer op gesynchroniseerde apparaten)}}</translation>
<translation id="3041612393474885105">Certificaatgegevens</translation>
<translation id="3063697135517575841">Chrome kan je creditcard momenteel niet bevestigen. Probeer het later opnieuw.</translation>
+<translation id="3064966200440839136">Je verlaat de incognitomodus om te betalen via een externe app. Doorgaan?</translation>
<translation id="3093245981617870298">Je bent offline.</translation>
<translation id="3105172416063519923">Item-ID:</translation>
<translation id="3109728660330352905">Je hebt geen toestemming om deze pagina te bekijken.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Voer Verbindingsdiagnose uit<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Kan reactie niet decoderen</translation>
-<translation id="3149891296864842641">Verzendoptie</translation>
<translation id="3150653042067488994">Tijdelijke serverfout</translation>
+<translation id="3154506275960390542">Deze pagina bevat een formulier dat mogelijk niet beveiligd wordt verzonden. Gegevens die je verzendt, kunnen tijdens de overdracht worden bekeken door anderen of kunnen worden aangepast door een aanvaller om te wijzigen wat de server ontvangt.</translation>
<translation id="3157931365184549694">Herstellen</translation>
<translation id="3167968892399408617">De pagina's die je op incognitotabbladen weergeeft, worden niet bewaard in je browsergeschiedenis, cookie-opslag of zoekgeschiedenis nadat je al je incognitotabbladen hebt gesloten. Alle bestanden die je hebt gedownload of bladwijzers die je hebt gemaakt, blijven behouden.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -260,11 +268,13 @@
<translation id="3345135638360864351">Je verzoek om toegang tot deze site kan niet worden verzonden naar <ph name="NAME" />. Probeer het opnieuw.</translation>
<translation id="3355823806454867987">Proxyinstellingen wijzigen...</translation>
<translation id="3369192424181595722">Klokfout</translation>
+<translation id="337311366426640088">Nog <ph name="ITEM_COUNT" /> items...</translation>
<translation id="337363190475750230">Uitgeschreven</translation>
<translation id="3377188786107721145">Fout bij het parseren van beleid</translation>
<translation id="3380365263193509176">Onbekende fout</translation>
<translation id="3380864720620200369">Klant-ID:</translation>
<translation id="3391030046425686457">Afleveradres</translation>
+<translation id="3395827396354264108">Ophaalmethode</translation>
<translation id="340013220407300675">Aanvallers proberen mogelijk je gegevens van <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> te stelen (bijvoorbeeld wachtwoorden, berichten of creditcarddetails).</translation>
<translation id="3422248202833853650">Probeer andere programma's af te sluiten om geheugen vrij te maken.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> is momenteel niet bereikbaar.</translation>
@@ -275,12 +285,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Ophaalinterval:</translation>
<translation id="3462200631372590220">Gedetailleerde informatie verbergen</translation>
+<translation id="3467763166455606212">Naam kaarthouder vereist</translation>
+<translation id="3478058380795961209">Vervalmaand</translation>
<translation id="3479539252931486093">Wat dit onverwacht? <ph name="BEGIN_LINK" />Laat het ons weten<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Niet nu</translation>
<translation id="348000606199325318">Crash-ID <ph name="CRASH_LOCAL_ID" /> (Server-ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">We kunnen je ouder momenteel niet bereiken. Probeer het opnieuw.</translation>
<translation id="3528171143076753409">Het servercertificaat is niet betrouwbaar.</translation>
-<translation id="3538531656504267329">Ongeldig vervaljaar</translation>
<translation id="3539171420378717834">Een exemplaar van deze kaart op dit apparaat bewaren</translation>
<translation id="3542684924769048008">Wachtwoord gebruiken voor:</translation>
<translation id="3549644494707163724">Alle gesynchroniseerde gegevens versleutelen met je eigen wachtwoordzin voor synchronisatie</translation>
@@ -293,6 +304,7 @@
<translation id="3586931643579894722">Details verbergen</translation>
<translation id="3587482841069643663">Alles</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Geef een geldige vervaldatum op</translation>
<translation id="36224234498066874">Wis browsegegevens...</translation>
<translation id="362276910939193118">Volledige geschiedenis weergeven</translation>
<translation id="3623476034248543066">Waarde weergeven</translation>
@@ -308,7 +320,6 @@
<translation id="3693415264595406141">Wachtwoord:</translation>
<translation id="3696411085566228381">geen</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Selecteer een verzendadres om verzendmethoden en vereisten te bekijken.</translation>
<translation id="370665806235115550">Bezig met laden...</translation>
<translation id="3712624925041724820">Licenties zijn verbruikt</translation>
<translation id="3714780639079136834">Schakel mobiele data of wifi in</translation>
@@ -317,6 +328,7 @@
<translation id="3739623965217189342">Link die je hebt gekopieerd</translation>
<translation id="375403751935624634">Het vertalen is mislukt wegens een serverfout.</translation>
<translation id="3759461132968374835">Je hebt geen onlangs gemelde crashes. Crashes die zich voordeden toen de crashrapportage was uitgeschakeld, worden hier niet weergegeven.</translation>
+<translation id="3787705759683870569">Verloopt: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Als je een proxyserver gebruikt...</translation>
<translation id="3828924085048779000">Een lege wachtwoordzin is niet toegestaan.</translation>
<translation id="3845539888601087042">Geschiedenis van je ingelogde apparaten wordt weergegeven. <ph name="BEGIN_LINK" />Meer informatie<ph name="END_LINK" />.</translation>
@@ -352,7 +364,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Wil je dat Chromium deze kaart opslaat?</translation>
<translation id="4171400957073367226">Onjuiste verificatiehandtekening</translation>
-<translation id="4176463684765177261">Uitgeschakeld</translation>
<translation id="4196861286325780578">&amp;Opnieuw verplaatsen</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Controleer firewall- en antivirusconfiguraties<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{geen}=1{1 app ($1)}=2{2 apps ($1, $2)}other{# apps ($1, $2, $3)}}</translation>
@@ -379,11 +390,11 @@
<translation id="4406896451731180161">zoekresultaten</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> heeft je inlogcertificaat niet geaccepteerd of er is geen inlogcertificaat geleverd.</translation>
<translation id="443673843213245140">Het gebruik van een proxy is uitgeschakeld, maar er is wel een expliciete proxyconfiguratie opgegeven.</translation>
-<translation id="4446242550670694251">Je kunt nu privé browsen, zodat andere mensen die dit apparaat gebruiken, jouw activiteiten niet kunnen zien.</translation>
<translation id="4492190037599258964">Zoekresultaten voor '<ph name="SEARCH_STRING" />'</translation>
<translation id="4506176782989081258">Validatiefout: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Neem contact op met de systeembeheerder</translation>
<translation id="450710068430902550">Delen met beheerder</translation>
+<translation id="4515275063822566619">Kaarten en adressen zijn afkomstig uit Chrome en je Google-account (<ph name="ACCOUNT_EMAIL" />). Je kunt ze beheren in <ph name="BEGIN_LINK" />Instellingen<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Details</translation>
<translation id="4558551763791394412">Probeer je extensies uit te schakelen.</translation>
<translation id="457875822857220463">Bezorging</translation>
@@ -413,6 +424,7 @@
<translation id="4816492930507672669">Aanpassen aan pagina</translation>
<translation id="483020001682031208">Geen Fysieke webpagina's om weer te geven</translation>
<translation id="4850886885716139402">Weergave</translation>
+<translation id="4854362297993841467">Deze bezorgingsmethode is niet beschikbaar. Kies een andere methode.</translation>
<translation id="4858792381671956233">Je hebt je ouders gevraagd of je deze site mag bezoeken</translation>
<translation id="4880827082731008257">Geschiedenis doorzoeken</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -420,7 +432,6 @@
<translation id="4923417429809017348">Deze pagina is vertaald uit een onbekende taal naar het <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Betaling</translation>
<translation id="4926049483395192435">Moet worden opgegeven.</translation>
-<translation id="4941291666397027948">* geeft een verplicht veld aan</translation>
<translation id="495170559598752135">Acties</translation>
<translation id="4958444002117714549">Lijst uitvouwen</translation>
<translation id="4962322354953122629">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server wordt niet vertrouwd door Chrome. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -435,6 +446,7 @@
<translation id="5045550434625856497">Onjuist wachtwoord</translation>
<translation id="5056549851600133418">Artikelen voor jou</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Het proxy-adres controleren<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Geen cookies}=1{1 site gebruikt cookies. }other{# sites gebruiken cookies. }}</translation>
<translation id="5087286274860437796">Het servercertificaat is momenteel niet geldig.</translation>
<translation id="5087580092889165836">Kaart toevoegen</translation>
<translation id="5089810972385038852">Staat</translation>
@@ -457,10 +469,8 @@
<translation id="5300589172476337783">Weergeven</translation>
<translation id="5308689395849655368">Crashrapportage is uitgeschakeld.</translation>
<translation id="5317780077021120954">Opslaan</translation>
-<translation id="5326702247179446998">Ontvanger vereist</translation>
<translation id="5327248766486351172">Naam</translation>
<translation id="5337705430875057403">Cybercriminelen op <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> proberen je mogelijk te misleiden om iets gevaarlijks te doen, zoals software installeren of je persoonlijke gegevens bekendmaken (bijvoorbeeld wachtwoorden, telefoonnummers of creditcards).</translation>
-<translation id="53553865750799677">Niet-ondersteund ophaaladres. Selecteer een ander adres.</translation>
<translation id="5359637492792381994">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat is momenteel niet geldig. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Opslaan van beleidsinstellingen is mislukt</translation>
<translation id="5386426401304769735">De certificaatketen voor deze site bevat een certificaat dat is ondertekend met SHA-1.</translation>
@@ -486,8 +496,8 @@
<translation id="5544037170328430102">Een ingesloten pagina op <ph name="SITE" /> meldt het volgende:</translation>
<translation id="5556459405103347317">Opnieuw laden</translation>
<translation id="5565735124758917034">Actief</translation>
+<translation id="5571083550517324815">Kan niet ophalen van dit adres. Selecteer een ander adres.</translation>
<translation id="5572851009514199876">Start Chrome en log in zodat Chrome kan controleren of je deze site mag openen.</translation>
-<translation id="5575380383496039204">Niet-ondersteund afleveradres. Selecteer een ander adres.</translation>
<translation id="5580958916614886209">Controleer de vervalmaand en probeer het opnieuw</translation>
<translation id="560412284261940334">Beheer wordt niet ondersteund</translation>
<translation id="5610142619324316209">Controleer de verbinding</translation>
@@ -503,7 +513,8 @@
<translation id="5710435578057952990">De identiteit van deze website is niet geverifieerd.</translation>
<translation id="5720705177508910913">Huidige gebruiker</translation>
<translation id="5732392974455271431">Je ouders kunnen de blokkering van deze site opheffen</translation>
-<translation id="57586589942790530">Ongeldig creditcardnummer</translation>
+<translation id="5763042198335101085">Geef een geldig e-mailadres op</translation>
+<translation id="5765072501007116331">Selecteer een adres om bezorgingsmethoden en vereisten te bekijken</translation>
<translation id="5784606427469807560">Er is een probleem opgetreden bij het bevestigen van je creditcard. Controleer je internetverbinding en probeer het opnieuw.</translation>
<translation id="5785756445106461925">Bovendien bevat deze pagina bronnen die niet beveiligd zijn. Deze bronnen kunnen tijdens verzending door anderen worden bekeken en kunnen door een aanvaller worden gewijzigd om het uiterlijk van de pagina aan te passen.</translation>
<translation id="5786044859038896871">Wil je de gegevens van je creditcard laten invullen?</translation>
@@ -516,31 +527,30 @@
<translation id="5869405914158311789">Deze site is niet bereikbaar</translation>
<translation id="5869522115854928033">Opgeslagen wachtwoorden</translation>
<translation id="5872918882028971132">Bovenliggende suggesties</translation>
-<translation id="587760065310675640">Niet-ondersteund verzendadres. Selecteer een ander adres.</translation>
<translation id="5901630391730855834">Geel</translation>
-<translation id="59174027418879706">Ingeschakeld</translation>
<translation id="5926846154125914413">Mogelijk heb je geen toegang meer tot premium content van bepaalde sites.</translation>
<translation id="5959728338436674663">Bepaalde <ph name="BEGIN_WHITEPAPER_LINK" />systeeminformatie en paginacontent<ph name="END_WHITEPAPER_LINK" /> automatisch verzenden naar Google om te helpen bij de detectie van gevaarlijke apps en sites. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Week</translation>
<translation id="5967867314010545767">Verwijderen uit geschiedenis</translation>
<translation id="5975083100439434680">Uitzoomen</translation>
+<translation id="598637245381783098">Kan betaal-app niet openen</translation>
<translation id="5989320800837274978">Er worden geen vaste proxyservers en geen pac-script-URL gespecificeerd.</translation>
<translation id="5990559369517809815">Verzoeken aan de server zijn door een extensie geblokkeerd.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Kaart- en adresopties komen uit Chrome. Je kunt ze beheren in <ph name="BEGIN_LINK" />Instellingen<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Pagina 1}other{Pagina #}}</translation>
<translation id="6017514345406065928">Groen</translation>
+<translation id="6027201098523975773">Geef een naam op</translation>
<translation id="6040143037577758943">Sluiten</translation>
-<translation id="604124094241169006">Automatisch</translation>
<translation id="6042308850641462728">Meer</translation>
<translation id="6060685159320643512">Pas op, dit zijn geen experimenten om zonder handschoenen aan te pakken</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{geen}=1{1}other{#}}</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 het volgende:</translation>
<translation id="6151417162996330722">Het servercertificaat heeft een te lange geldigheidsperiode.</translation>
-<translation id="615643356032862689">Gedownloade bestanden en bladwijzers worden bewaard.</translation>
+<translation id="6157877588268064908">Selecteer een adres om verzendmethoden en vereisten te bekijken</translation>
<translation id="6165508094623778733">Meer informatie</translation>
<translation id="6177128806592000436">Je verbinding met deze site is niet veilig</translation>
+<translation id="6184817833369986695">(cohort: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Controleer je internetverbinding</translation>
<translation id="6218753634732582820">Adres verwijderen uit Chromium?</translation>
<translation id="6251924700383757765">Privacybeleid</translation>
@@ -549,6 +559,8 @@
<translation id="6259156558325130047">&amp;Opnieuw volgorde wijzigen</translation>
<translation id="6263376278284652872">Bladwijzers voor <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Terug naar veilige website</translation>
+<translation id="6276112860590028508">Pagina's uit je leeslijst worden hier weergegeven</translation>
+<translation id="6280223929691119688">Kan niet bezorgen op dit adres. Selecteer een ander adres.</translation>
<translation id="6282194474023008486">Postcode</translation>
<translation id="6290238015253830360">Je voorgestelde artikelen worden hier weergegeven</translation>
<translation id="6305205051461490394"><ph name="URL" /> is niet bereikbaar.</translation>
@@ -570,7 +582,6 @@
<translation id="6417515091412812850">Kan niet controleren of het certificaat is ingetrokken.</translation>
<translation id="6433490469411711332">Contactgegevens bewerken</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> heeft de verbinding geweigerd.</translation>
-<translation id="6443118737398455446">Ongeldige vervaldatum</translation>
<translation id="6446608382365791566">Meer informatie toevoegen</translation>
<translation id="6451458296329894277">Opnieuw indienen bevestigen</translation>
<translation id="6456339708790392414">Je betaling</translation>
@@ -578,10 +589,8 @@
<translation id="6462969404041126431">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. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Apparaatbeleid</translation>
<translation id="6477321094435799029">Chrome heeft ongebruikelijke code op deze pagina gedetecteerd en heeft de code geblokkeerd om je persoonlijke gegevens (zoals wachtwoorden, telefoonnummers en creditcards) te beschermen.</translation>
-<translation id="6477460825583319731">Ongeldig e-mailadres</translation>
<translation id="6489534406876378309">Uploaden van crashes starten</translation>
<translation id="6508722015517270189">Chrome opnieuw starten</translation>
-<translation id="6525462735697194615">Ongeldige vervalmaand</translation>
<translation id="6529602333819889595">&amp;Opnieuw verwijderen</translation>
<translation id="6534179046333460208">Fysieke web-suggesties</translation>
<translation id="6550675742724504774">Opties</translation>
@@ -596,7 +605,6 @@
<translation id="6628463337424475685">Zoeken via <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Dit beleid is verouderd.</translation>
<translation id="6652240803263749613">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. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Die optie voor levering is niet beschikbaar. Kies een andere optie.</translation>
<translation id="6671697161687535275">Formuliersuggestie verwijderen uit Chromium?</translation>
<translation id="6685834062052613830">Uitloggen en configuratie voltooien</translation>
<translation id="6710213216561001401">Vorige</translation>
@@ -604,13 +612,13 @@
<translation id="6711464428925977395">Er is iets mis met de proxyserver of het adres is onjuist.</translation>
<translation id="6727102863431372879">Instellen</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{geen}=1{1 item}other{# items}}</translation>
-<translation id="6743044928064272573">Ophaaloptie</translation>
<translation id="674375294223700098">Onbekende fout met servercertificaat.</translation>
<translation id="6753269504797312559">Beleidswaarde</translation>
<translation id="6757797048963528358">De slaapstand van je apparaat is geactiveerd.</translation>
<translation id="6778737459546443941">Je ouder of voogd heeft dit nog niet goedgekeurd</translation>
<translation id="6810899417690483278">Aanpassings-ID</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Kan regiogegevens niet laden</translation>
<translation id="6831043979455480757">Vertalen</translation>
<translation id="6839929833149231406">Gebied</translation>
<translation id="6874604403660855544">&amp;Opnieuw toevoegen</translation>
@@ -618,6 +626,7 @@
<translation id="6895330447102777224">Je creditcard is bevestigd</translation>
<translation id="6897140037006041989">User-agent</translation>
<translation id="6915804003454593391">Gebruiker:</translation>
+<translation id="6948701128805548767">Selecteer een adres om ophaalmethoden en vereisten te bekijken</translation>
<translation id="6957887021205513506">Het certificaat van de server lijkt vals te zijn.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Apparaat</translation>
@@ -625,7 +634,6 @@
<translation id="6973656660372572881">Zowel vaste proxyservers als een pac-script-URL worden gespecificeerd.</translation>
<translation id="6989763994942163495">Geavanceerde instellingen weergeven...</translation>
<translation id="7000990526846637657">Geen geschiedenisitems gevonden</translation>
-<translation id="7001663382399377034">Ontvanger toevoegen</translation>
<translation id="7009986207543992532">Je probeert <ph name="DOMAIN" /> te bereiken, maar de server heeft een certificaat geretourneerd waarvan de geldigheidsperiode te lang is om betrouwbaar te zijn. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Voor je Google-account kunnen andere vormen van browsegeschiedenis beschikbaar zijn via <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -636,12 +644,15 @@
<translation id="7088615885725309056">Ouder</translation>
<translation id="7090678807593890770">Zoek op Google naar <ph name="LINK" /></translation>
<translation id="7119414471315195487">Andere tabbladen of programma's sluiten</translation>
+<translation id="7129409597930077180">Kan niet verzenden naar dit adres. Selecteer een ander adres.</translation>
+<translation id="7138472120740807366">Bezorgingsmethode</translation>
<translation id="7139724024395191329">Emiraat</translation>
<translation id="7155487117670177674">Betalen niet veilig</translation>
<translation id="7179921470347911571">Nu opnieuw starten</translation>
<translation id="7180611975245234373">Vernieuwen</translation>
<translation id="7182878459783632708">Geen beleid ingesteld</translation>
<translation id="7186367841673660872">Deze pagina is vertaald van het<ph name="ORIGINAL_LANGUAGE" />in het<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> voldoet niet aan de beveiligingsnormen.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Meer informatie<ph name="END_LINK" /> over dit probleem.</translation>
@@ -670,7 +681,6 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="7424977062513257142">Een ingesloten pagina op deze webpagina meldt het volgende:</translation>
<translation id="7441627299479586546">Onjuist beleidsonderwerp</translation>
<translation id="7444046173054089907">Deze site is geblokkeerd</translation>
-<translation id="7444238235002594607">Selecteer een ophaaladres om de ophaalmethoden en -vereisten te controleren.</translation>
<translation id="7445762425076701745">De identiteit van de server waarmee je verbinding maakt, kan niet volledig worden geverifieerd. Je hebt verbinding gemaakt met een server die een naam gebruikt die alleen binnen je netwerk geldig is. Een externe certificeringsinstantie kan hiervoor nooit het eigendom verifiëren. Aangezien sommige certificeringsinstanties toch certificaten voor deze namen verlenen, kun je nooit zeker weten of je verbinding hebt met de bedoelde website en niet met een aanvaller.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Meer informatie<ph name="END_LINK" /> over dit probleem.</translation>
<translation id="7460163899615895653">Je recente tabbladen van andere apparaten worden hier weergegeven</translation>
@@ -714,6 +724,7 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="7755287808199759310">Je ouder of voogd kan de blokkering van deze site opheffen</translation>
<translation id="7758069387465995638">De verbinding is mogelijk geblokkeerd door de firewall of antivirussoftware.</translation>
<translation id="7761701407923456692">Het servercertificaat komt niet overeen met de URL.</translation>
+<translation id="7763386264682878361">Payment Manifest Parser</translation>
<translation id="7764225426217299476">Adres toevoegen</translation>
<translation id="777702478322588152">Prefectuur</translation>
<translation id="7791543448312431591">Toevoegen</translation>
@@ -727,6 +738,7 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="785549533363645510">Je bent echter niet onzichtbaar. Als je incognito bent, wordt je browsegeschiedenis niet verborgen voor je werkgever, je internetprovider of de websites die je bezoekt.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Controleer je CVC-code en probeer het opnieuw</translation>
+<translation id="79338296614623784">Geef een geldig telefoonnummer op</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Het servercertificaat is nog niet geldig.</translation>
<translation id="7942349550061667556">Rood</translation>
@@ -746,6 +758,7 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="8088680233425245692">Kan artikel niet bekijken.</translation>
<translation id="8089520772729574115">minder dan 1 MB</translation>
<translation id="8091372947890762290">Activering is in behandeling op de server</translation>
+<translation id="8118489163946903409">Betaalmethode</translation>
<translation id="8131740175452115882">Bevestigen</translation>
<translation id="8134994873729925007">Het <ph name="BEGIN_ABBR" />DNS-adres<ph name="END_ABBR" /> van de server van <ph name="HOST_NAME" /> kan niet worden gevonden.</translation>
<translation id="8149426793427495338">De slaapstand van je computer is geactiveerd.</translation>
@@ -771,6 +784,7 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="8349305172487531364">Bladwijzerbalk</translation>
<translation id="8363502534493474904">Schakel de vliegtuigmodus uit</translation>
<translation id="8364627913115013041">Niet ingesteld.</translation>
+<translation id="8368476060205742148">Google Play-services</translation>
<translation id="8380941800586852976">Gevaarlijk</translation>
<translation id="8382348898565613901">Je onlangs bezochte bladwijzers worden hier weergegeven</translation>
<translation id="8398259832188219207">Crashrapport geüpload op <ph name="UPLOAD_TIME" /></translation>
@@ -779,31 +793,29 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="8428213095426709021">Instellingen</translation>
<translation id="8433057134996913067">Hiermee word je uitgelogd van de meeste websites.</translation>
<translation id="8437238597147034694">&amp;Verplaatsen ongedaan maken</translation>
-<translation id="8456681095658380701">Ongeldige naam</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 creditcard}other{# creditcards}}</translation>
<translation id="8483780878231876732">Log in bij Chrome om kaarten uit je Google-account te gebruiken</translation>
<translation id="8488350697529856933">Van toepassing op</translation>
-<translation id="8492969205326575646">Niet-ondersteund kaarttype</translation>
<translation id="8498891568109133222">Het duurt te lang voordat <ph name="HOST_NAME" /> reageert.</translation>
<translation id="852346902619691059">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server wordt niet vertrouwd door het besturingssysteem van je apparaat. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Vervaljaar</translation>
<translation id="8543181531796978784">Je kunt <ph name="BEGIN_ERROR_LINK" />een detectieprobleem melden<ph name="END_ERROR_LINK" />. Als je de veiligheidsrisico's begrijpt, kun je ook <ph name="BEGIN_LINK" />deze onveilige site bezoeken<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">De vertaling is mislukt omdat de taal van de pagina niet kan worden bepaald.</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="8570229484593575558">Deze informatie |wordt niet opgeslagen|:#Je browsegeschiedenis#Je zoekopdrachten#Cookiegegevens</translation>
<translation id="8571890674111243710">Pagina wordt vertaald in het <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Je activiteit is mogelijk |nog wel zichtbaar| voor:#Websites die je bezoekt#Je werkgever#Je internetprovider</translation>
<translation id="858637041960032120">Telnr. toevoegen</translation>
<translation id="859285277496340001">Er wordt in het certificaat geen methode gespecificeerd waarmee kan worden gecontroleerd of het certificaat is ingetrokken.</translation>
<translation id="8620436878122366504">Je ouders hebben dit nog niet goedgekeurd</translation>
<translation id="8647750283161643317">Alle standaardinstellingen herstellen</translation>
<translation id="8703575177326907206">Je verbinding met <ph name="DOMAIN" /> is niet gecodeerd.</translation>
+<translation id="8718314106902482036">Betaling niet voltooid</translation>
<translation id="8725066075913043281">Opnieuw proberen</translation>
<translation id="8728672262656704056">Je bent incognito</translation>
<translation id="8730621377337864115">Gereed</translation>
<translation id="8738058698779197622">Als je een veilige 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="8759274551635299824">Deze kaart is verlopen</translation>
<translation id="8790007591277257123">&amp;Opnieuw verwijderen</translation>
-<translation id="8798099450830957504">Standaard</translation>
<translation id="8800988563907321413">Je suggesties voor in de buurt worden hier weergegeven</translation>
<translation id="8820817407110198400">Bladwijzers</translation>
<translation id="883848425547221593">Andere bladwijzers</translation>
@@ -813,6 +825,7 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="8866481888320382733">Fout bij het parseren van beleidsinstellingen</translation>
<translation id="8866959479196209191">Deze pagina meldt het volgende:</translation>
<translation id="8870413625673593573">Recent gesloten</translation>
+<translation id="8874824191258364635">Geef een geldig kaartnummer op</translation>
<translation id="8876793034577346603">Netwerkconfiguratie kan niet worden geparseerd.</translation>
<translation id="8877192140621905067">Zodra je bevestigt, worden je creditcardgegevens gedeeld met deze site</translation>
<translation id="8889402386540077796">Kleurtoon</translation>
@@ -822,7 +835,6 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="8931333241327730545">Wil je deze kaart opslaan in je Google-account?</translation>
<translation id="8932102934695377596">Je klok loopt achter</translation>
<translation id="8954894007019320973">(Vervolg)</translation>
-<translation id="895548565263634352">Lees verhalen van <ph name="ARTICLE_PUBLISHER" /> en nog <ph name="OTHER_ARTICLE_COUNT" /> anderen</translation>
<translation id="8971063699422889582">Het servercertificaat is verlopen.</translation>
<translation id="8986494364107987395">Automatisch gebruiksstatistieken en crashrapporten naar Google verzenden</translation>
<translation id="8987927404178983737">Maand</translation>
@@ -840,7 +852,6 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="9068849894565669697">Kleur selecteren</translation>
<translation id="9076283476770535406">De site kan content voor volwassenen bevatten</translation>
<translation id="9078964945751709336">Meer informatie vereist</translation>
-<translation id="9094175695478007090">Kan betalings-app niet starten.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> gebruikt gewoonlijk versleuteling om je gegevens te beschermen. Toen Chromium deze keer probeerde verbinding te maken met <ph name="SITE" />, retourneerde de website ongewone en onjuiste inloggegevens. Dit gebeurt wanneer een aanvaller probeert zich als <ph name="SITE" /> voor te doen of wanneer een wifi-inlogscherm de verbinding heeft verbroken. Je gegevens zijn nog steeds veilig omdat Chromium de verbinding heeft beëindigd voordat er gegevens konden worden uitgewisseld.</translation>
<translation id="9137013805542155359">Origineel weergeven</translation>
<translation id="9137248913990643158">Start Chrome en log in voordat je deze app gebruikt.</translation>
diff --git a/chromium/components/strings/components_strings_no.xtb b/chromium/components/strings/components_strings_no.xtb
index b2903a9e56d..8b556a7a504 100644
--- a/chromium/components/strings/components_strings_no.xtb
+++ b/chromium/components/strings/components_strings_no.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="no">
<translation id="1008557486741366299">Ikke nå</translation>
<translation id="1015730422737071372">Oppgi flere detaljer</translation>
+<translation id="1021110881106174305">Godkjente kort</translation>
<translation id="1032854598605920125">Rotér med klokken</translation>
<translation id="1038842779957582377">ukjent navn</translation>
<translation id="1050038467049342496">Lukk andre apper</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Skjul verdien</translation>
<translation id="1228893227497259893">Feil enhetsidentifikator</translation>
<translation id="1232569758102978740">Uten tittel</translation>
+<translation id="1263231323834454256">Leseliste</translation>
<translation id="1264126396475825575">Programstopprapport fra <ph name="CRASH_TIME" /> (ignorert eller ikke lastet opp ennå)</translation>
<translation id="1285320974508926690">Oversett aldri dette nettstedet</translation>
<translation id="129553762522093515">Nylig lukket</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Innstillinger for autofyll i Chromium</translation>
<translation id="1374468813861204354">forslagene</translation>
<translation id="1375198122581997741">Om versjon</translation>
+<translation id="1377321085342047638">Kortnummer</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> sendte ingen data.</translation>
<translation id="1407135791313364759">Ã…pne alle</translation>
<translation id="1413809658975081374">Personvernfeil</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Logg</translation>
<translation id="1645368109819982629">Protokollen støttes ikke</translation>
<translation id="1656489000284462475">Henting</translation>
+<translation id="1663943134801823270">Kortene og adressene er fra Chrome. Du kan administrere dem i <ph name="BEGIN_LINK" />Innstillinger<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> bruker vanligvis kryptering for å beskytte informasjonen din. Da Chrome prøvde å koble til <ph name="SITE" /> denne gangen, sendte nettstedet tilbake uvanlig og feil legitimasjon. Dette kan skje hvis en angriper prøver å utgi seg for å være <ph name="SITE" />, eller hvis en Wi-Fi-påloggingsskjerm har avbrutt tilkoblingen. Informasjonen din er likevel sikker fordi Chrome stoppet tilkoblingen før det ble utvekslet noen data.</translation>
<translation id="168328519870909584">Hackere som for øyeblikket er på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, prøver kanskje å installere farlige apper på enheten din. Disse appene kan stjele eller slette informasjonen din (for eksempel bilder, passord, meldinger og kredittkortinformasjon).</translation>
<translation id="168841957122794586">Tjenersertifikatet inneholder en svak kryptografisk nøkkel.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Du trenger tillatelse fra <ph name="NAME" /> for å besøke dette nettstedet</translation>
+<translation id="1721424275792716183">* Feltet er obligatorisk</translation>
<translation id="1728677426644403582">Du ser på kildekoden for en nettside</translation>
+<translation id="173080396488393970">Denne korttypen støttes ikke</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Prøv å kontakte systemadministratoren.</translation>
+<translation id="1740951997222943430">Angi en gyldig utløpsmåned</translation>
<translation id="1745358365027406341">Last ned siden senere</translation>
<translation id="17513872634828108">Ã…pne faner</translation>
<translation id="1753706481035618306">Sidenummer</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Oppdater passordfrasen for synkronisering.</translation>
<translation id="1787142507584202372">De åpne fanene dine vises her</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Velg en leveringsadresse for å sjekke leveringsmetoder og -krav.</translation>
+<translation id="1803264062614276815">Kortinnehaverens navn</translation>
<translation id="1803678881841855883">Google Safe Browsing oppdaget nylig <ph name="BEGIN_LINK" />skadelig programvare<ph name="END_LINK" /> på <ph name="SITE" />. Nettsteder som vanligvis er pålitelige, kan av og til bli infisert med skadelig programvare. Det skadelige innholdet kommer fra <ph name="SUBRESOURCE_HOST" />, som er en kjent distributør av skadelig programvare. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Lagt til: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Ugyldig forespørsel eller forespørselsparametere</translation>
<translation id="1826516787628120939">Kontrollerer</translation>
<translation id="1834321415901700177">Dette nettstedet inneholder skadelige programmer</translation>
<translation id="1842969606798536927">Betal</translation>
-<translation id="1864455488461349376">Leveringsalternativer</translation>
<translation id="1871208020102129563">Mellomtjeneren er angitt til å bruke statiske proxytjenere, ikke en nettadresse med .pac-skript.</translation>
<translation id="1871284979644508959">Obligatorisk felt</translation>
<translation id="187918866476621466">Ã…pne oppstartssidene</translation>
<translation id="1883255238294161206">Skjul liste</translation>
<translation id="1898423065542865115">Filtrering</translation>
<translation id="194030505837763158">GÃ¥ til <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Kort som godtas</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" />-bokmerker</translation>
<translation id="1973335181906896915">Serialiseringsfeil</translation>
<translation id="1974060860693918893">Avansert</translation>
<translation id="1978555033938440688">Fastvareversjon</translation>
+<translation id="1995859865337580572">Bekreft CVC-koden din</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{og 1 til}other{og # til}}</translation>
-<translation id="2020194265157481222">Navnet som er oppført på kortet, er obligatorisk</translation>
<translation id="2025186561304664664">Mellomtjeneren er innstilt på automatisk konfigurasjon.</translation>
<translation id="2030481566774242610">Mener du <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Sjekk proxy-tjeneren og brannmuren<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">I dag</translation>
<translation id="2154054054215849342">Synkronisering er ikke tilgjengelig for domenet ditt</translation>
<translation id="2154484045852737596">Endre kortet</translation>
-<translation id="2156993118928861787">Ugyldig adresse</translation>
<translation id="2166049586286450108">Full administratortilgang</translation>
<translation id="2166378884831602661">Dette nettstedet tilbyr ikke sikre tilkoblinger</translation>
<translation id="2181821976797666341">Retningslinjer</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresse}other{# adresser}}</translation>
+<translation id="2202020181578195191">Angi et gyldig utløpsår</translation>
<translation id="2212735316055980242">Innstillingene ble ikke funnet</translation>
<translation id="2213606439339815911">Henter oppføringer …</translation>
<translation id="2230458221926704099">Løs tilkoblingsproblemene med <ph name="BEGIN_LINK" />diagnostikkappen<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Internett-tilgangen din er blokkert</translation>
<translation id="230155334948463882">Nytt kort?</translation>
<translation id="2305919008529760154">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet kan ha blitt utstedt på uredelig vis. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Alternativene for kort og adresser kommer fra Google-kontoen din (<ph name="ACCOUNT_EMAIL" />) og Chrome. Du kan administrere disse i <ph name="BEGIN_LINK" />Innstillinger<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> krever brukernavn og passord.</translation>
<translation id="2318774815570432836">Du kan ikke gå til <ph name="SITE" /> akkurat nå, fordi nettstedet bruker HSTS. Nettverksfeil og -angrep er som regel kortvarige, så denne siden fungerer nok igjen senere. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Andre bokmerker</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Bedriftsstandard</translation>
<translation id="2386255080630008482">Tjenerens sertifikat er tilbakekalt.</translation>
<translation id="2392959068659972793">Vis innstillinger uten verdi</translation>
+<translation id="239429038616798445">Denne leveringsmetoden er ikke tilgjengelig. Prøv en annen metode.</translation>
<translation id="2396249848217231973">&amp;Angre slettingen</translation>
<translation id="2460160116472764928">Google Safe Browsing oppdaget nylig <ph name="BEGIN_LINK" />skadelig programvare<ph name="END_LINK" /> på <ph name="SITE" />. Nettsteder som vanligvis er pålitelige, kan av og til bli infisert med skadelig programvare. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Fyll ut</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Kjør Nettverksdiagnose<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Ugyldig nettadresse for søk.</translation>
<translation id="2491120439723279231">Tjenerens sertifikat inneholder feil.</translation>
-<translation id="24943777258388405">Ugyldig telefonnummer</translation>
<translation id="2495083838625180221">JSON Parser</translation>
<translation id="2495093607237746763">Hvis det er merket av for dette alternativet, lagrer Chromium en kopi av kortet ditt på denne enheten, slik at det går raskere å fylle ut skjemaer.</translation>
<translation id="2498091847651709837">Skann nytt kort</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> sendte et ugyldig svar.</translation>
<translation id="2552545117464357659">Nyere</translation>
<translation id="2556876185419854533">&amp;Angre endringen</translation>
+<translation id="2587730715158995865">Fra <ph name="ARTICLE_PUBLISHER" />. Les denne og <ph name="OTHER_ARTICLE_COUNT" /> andre nyhetssaker.</translation>
<translation id="2587841377698384444">ID for katalog-API:</translation>
<translation id="2597378329261239068">Dette dokumentet er passordbeskyttet. Skriv inn et passord.</translation>
<translation id="2609632851001447353">Varianter</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Kjør Tilkoblingsdiagnostikk<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">Fjern valgte elementer</translation>
+<translation id="277133753123645258">Leveringsmetode</translation>
<translation id="277499241957683684">Manglende enhetsoppføring</translation>
<translation id="2784949926578158345">Tilkoblingen ble tilbakestilt.</translation>
<translation id="2794233252405721443">Nettstedet er blokkert</translation>
-<translation id="2812680587231492111">Det hentealternativet er ikke tilgjengelig. Prøv et annet alternativ.</translation>
<translation id="2824775600643448204">Adresse- og søkefelt</translation>
<translation id="2826760142808435982">Tilkoblingen er kryptert ved hjelp av <ph name="CIPHER" />, og bruker <ph name="KX" /> som mekanisme for nøkkelutveksling.</translation>
<translation id="2835170189407361413">Slett skjemaet</translation>
-<translation id="2849041323157393173">Det leveringsalternativet er ikke tilgjengelig. Prøv et annet alternativ.</translation>
<translation id="2889159643044928134">Ikke last inn på nytt</translation>
<translation id="2900469785430194048">Google Chrome gikk tom for minne under forsøket på å vise denne nettsiden.</translation>
<translation id="2909946352844186028">En nettverksendring ble oppdaget.</translation>
<translation id="2916038427272391327">Lukk andre programmer</translation>
<translation id="2922350208395188000">Tjenerens sertifikat kan ikke kontrolleres.</translation>
+<translation id="2928905813689894207">Faktureringsadresse</translation>
<translation id="2948083400971632585">PÃ¥ innstillingssiden kan du deaktivere eventuelle mellomtjenere for tilkoblinger.</translation>
<translation id="2955913368246107853">Lukk søkefelt</translation>
<translation id="2958431318199492670">Nettverkskonfigurasjonen overholder ikke ONC-standarden. Deler av konfigurasjonen kan muligens ikke importeres.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Klokken må være riktig stilt før du kan opprette sikre tilkoblinger. Grunnen til dette er at sertifikatene nettsteder identifiserer seg med, bare er gyldige i visse tidsperioder. Ettersom klokken på enheten din er feil, kan ikke Google Chrome bekrefte disse sertifikatene.</translation>
<translation id="2972581237482394796">Gjø&amp;r om</translation>
<translation id="2985306909656435243">Hvis du slår på dette alternativet, lagrer Chromium en kopi av kortet ditt på denne enheten, slik at det går raskere å fylle ut skjemaer.</translation>
+<translation id="2985398929374701810">Angi en gyldig adresse</translation>
+<translation id="2986368408720340940">Denne hentemetoden er ikke tilgjengelig. Prøv en annen metode.</translation>
<translation id="2991174974383378012">Deling med nettsteder</translation>
<translation id="3005723025932146533">Vis lagret kopi</translation>
<translation id="3008447029300691911">Skriv inn verifiseringskoden for <ph name="CREDIT_CARD" />. NÃ¥r du bekrefter, deles kortinformasjonen din med dette nettstedet.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{minst 1 element på synkroniserte enheter}=1{1 element (og flere på synkroniserte enheter)}other{# elementer (og flere på synkroniserte enheter)}}</translation>
<translation id="3041612393474885105">Sertifikatinformasjon</translation>
<translation id="3063697135517575841">Chrome kunne ikke bekrefte kortet ditt akkurat nå. Prøv igjen senere.</translation>
+<translation id="3064966200440839136">Går ut av inkognitomodus for å betale via en ekstern app. Vil du fortsette?</translation>
<translation id="3093245981617870298">Du er ikke tilkoblet Internett.</translation>
<translation id="3105172416063519923">Ressurs-ID:</translation>
<translation id="3109728660330352905">Du har ikke autorisasjon til å se denne siden.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Prøv å kjøre Tilkoblingsdiagnostikk<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Kunne ikke avkode responsen</translation>
-<translation id="3149891296864842641">Fraktalternativ</translation>
<translation id="3150653042067488994">Midlertidig tjenerfeil</translation>
+<translation id="3154506275960390542">Denne siden inneholder et skjema som kanskje ikke sendes på en sikker måte. Data du sender, kan bli sett av andre mens de overføres, eller de kan endres av en angriper slik at tjeneren mottar noe annet enn det du sender.</translation>
<translation id="3157931365184549694">Gjenopprett</translation>
<translation id="3167968892399408617">Sider du går til i inkognitofaner, blir ikke værende i nettleserloggen, lageret for informasjonskapsler eller søkeloggen etter at du har lukket alle inkognitofanene. Filer du laster ned eller bokmerker du oppretter, blir lagret.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Forespørselen om tilgang til dette nettstedet kunne ikke sendes til <ph name="NAME" />. Prøv igjen.</translation>
<translation id="3355823806454867987">Endre innstillinger for mellomtjener</translation>
<translation id="3369192424181595722">Klokkefeil</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> varer til …</translation>
<translation id="337363190475750230">Godkjenningen er opphevet</translation>
<translation id="3377188786107721145">Feil under analysen av enhetsinnstillinger</translation>
<translation id="3380365263193509176">Ukjent feil</translation>
<translation id="3380864720620200369">Klient-ID:</translation>
<translation id="3391030046425686457">Leveringsadresse</translation>
+<translation id="3395827396354264108">Hentemetode</translation>
<translation id="340013220407300675">Angripere prøver kanskje å stjele informasjonen din fra <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (for eksempel passord, e-post eller kredittkort).</translation>
<translation id="3422248202833853650">Prøv å lukke andre programmer for å frigjøre minne.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> er ikke tilgjengelig for øyeblikket.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">Mastercard</translation>
<translation id="3452404311384756672">Hentingsintervall:</translation>
<translation id="3462200631372590220">Skjul detaljer</translation>
+<translation id="3467763166455606212">Kortinnhaverens navn er obligatorisk</translation>
+<translation id="3478058380795961209">Utløpsmåned</translation>
<translation id="3479539252931486093">Var dette uventet? <ph name="BEGIN_LINK" />Si fra til oss<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Ikke nå</translation>
<translation id="348000606199325318">Kræsj-ID <ph name="CRASH_LOCAL_ID" /> (Tjener-ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Vi kunne ikke nå foreldrene dine akkurat nå. Prøv igjen.</translation>
<translation id="3528171143076753409">Tjenerens sertifikat er ikke pålitelig.</translation>
-<translation id="3538531656504267329">Ugyldig utløpsår</translation>
<translation id="3539171420378717834">Lagre en kopi av dette kortet på denne enheten</translation>
<translation id="3542684924769048008">Bruk passord for:</translation>
<translation id="3549644494707163724">Kryptér alle synkroniserte data med din egen passordfrase for synkronisering</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Skjul detaljer</translation>
<translation id="3587482841069643663">Alle</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Angi en gyldig utløpsdato</translation>
<translation id="36224234498066874">Slett nettlesingsdata...</translation>
<translation id="362276910939193118">Vis fullstendig logg</translation>
<translation id="3623476034248543066">Vis verdien</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Passord:</translation>
<translation id="3696411085566228381">ingen</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Velg en leveringsadresse for å se leveringsmåter og krav.</translation>
<translation id="370665806235115550">Laster inn ...</translation>
<translation id="3712624925041724820">Lisensene er oppbrukt</translation>
<translation id="3714780639079136834">Slå på mobildata eller Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">En link du kopierte</translation>
<translation id="375403751935624634">Oversettelsen mislyktes på grunn av en tjenerfeil.</translation>
<translation id="3759461132968374835">Du har ingen nylig rapportert programstopp. Programstopp som inntraff når rapportering om programstopp var deaktivert, blir ikke vist her.</translation>
+<translation id="3787705759683870569">Utløper <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Hvis du bruker en mellomtjener...</translation>
<translation id="3828924085048779000">Tom passordfrase er ikke tillatt.</translation>
<translation id="3845539888601087042">Viser loggen fra enhetene du er logget på. <ph name="BEGIN_LINK" />Finn ut mer<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Vil du at Chromium skal lagre dette kortet?</translation>
<translation id="4171400957073367226">Ugyldig bekreftelsessignatur</translation>
-<translation id="4176463684765177261">Deaktivert</translation>
<translation id="4196861286325780578">&amp;Flytt likevel</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Sjekk brannmur- og antiviruskonfigurasjonen<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{ingen}=1{1 app ($1)}=2{2 apper ($1, $2)}other{# apper ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">søkeresultater</translation>
<translation id="4432688616882109544">Enten godtok ikke <ph name="HOST_NAME" /> påloggingssertifikatet ditt, eller så ble det ikke oppgitt.</translation>
<translation id="443673843213245140">Bruk av mellomtjener er deaktivert, men det er angitt en uttrykkelig mellomtjenerkonfigurasjon.</translation>
-<translation id="4446242550670694251">NÃ¥ kan du surfe privat, og andre som bruker denne enheten, ser ikke aktiviteten din.</translation>
<translation id="4492190037599258964">Søkeresultater for «<ph name="SEARCH_STRING" />»</translation>
<translation id="4506176782989081258">Valideringsfeil: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Kontakt systemadministratoren</translation>
<translation id="450710068430902550">Deling med administratoren</translation>
+<translation id="4515275063822566619">Kortene og adressene er fra Chrome og Google-kontoen din (<ph name="ACCOUNT_EMAIL" />). Du kan administrere dem i <ph name="BEGIN_LINK" />Innstillinger<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Detaljer</translation>
<translation id="4558551763791394412">Prøv å slå av utvidelsene dine.</translation>
<translation id="457875822857220463">Levering</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Tilpass til siden</translation>
<translation id="483020001682031208">Det finnes ingen sider på det fysiske nettet å vise</translation>
<translation id="4850886885716139402">Visning</translation>
+<translation id="4854362297993841467">Denne leveringsmetoden er ikke tilgjengelig. Prøv en annen metode.</translation>
<translation id="4858792381671956233">Du har spurt foreldrene dine om det er greit å besøke dette nettstedet</translation>
<translation id="4880827082731008257">Søk i loggen</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Denne siden er oversatt til <ph name="LANGUAGE_LANGUAGE" /> fra et ukjent språk</translation>
<translation id="4923459931733593730">Betaling</translation>
<translation id="4926049483395192435">MÃ¥ angis.</translation>
-<translation id="4941291666397027948">* indikerer obligatoriske felt</translation>
<translation id="495170559598752135">Handlinger</translation>
<translation id="4958444002117714549">Utvid liste</translation>
<translation id="4962322354953122629">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom skkerhetssertifikatet ikke er regnet som pålitelig av Chrome. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Feil passord</translation>
<translation id="5056549851600133418">Artikler for deg</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Sjekk proxy-tjeneradressen<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Ingen informasjonskapsler}=1{1 nettsted bruker informasjonskapsler }other{# nettsteder bruker informasjonskapsler }}</translation>
<translation id="5087286274860437796">Sertifikatet til tjeneren er ikke gyldig for øyeblikket.</translation>
<translation id="5087580092889165836">Legg til et kort</translation>
<translation id="5089810972385038852">Fylke / delstat</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Vis</translation>
<translation id="5308689395849655368">Rapportering av programstopp er deaktivert.</translation>
<translation id="5317780077021120954">Lagre</translation>
-<translation id="5326702247179446998">Du må angi en mottaker</translation>
<translation id="5327248766486351172">Navn</translation>
<translation id="5337705430875057403">Angripere på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> prøver kanskje å lure deg til å gjøre farlige ting som å installere programvare eller avsløre personopplysningene dine (for eksempel passord, telefonnumre eller kredittkortinformasjon).</translation>
-<translation id="53553865750799677">Henteadressen støttes ikke. Velg en annen adresse.</translation>
<translation id="5359637492792381994">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet ikke er gyldig for øyeblikket. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Kunne ikke lagre angivelsen for enhetsinnstillinger</translation>
<translation id="5386426401304769735">Sertifikatkjeden for dette nettstedet inneholder et sertifikat som er signert med SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">En innebygd side på <ph name="SITE" /> sier:</translation>
<translation id="5556459405103347317">Last inn på nytt</translation>
<translation id="5565735124758917034">Aktiv</translation>
+<translation id="5571083550517324815">Kan ikke hente på denne adressen. Velg en annen adresse.</translation>
<translation id="5572851009514199876">Start og logg på Chrome, så Chrome kan sjekke om du har tillatelse til å gå til dette nettstedet.</translation>
-<translation id="5575380383496039204">Leveringsadressen støttes ikke. Velg en annen adresse.</translation>
<translation id="5580958916614886209">Kontrollér utløpsmåneden, og prøv igjen</translation>
<translation id="560412284261940334">Administrering støttes ikke</translation>
<translation id="5610142619324316209">Sjekk tilkoblingen</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">Identiteten til dette nettstedet er ikke verifisert.</translation>
<translation id="5720705177508910913">Gjeldende bruker</translation>
<translation id="5732392974455271431">Foreldrene dine kan oppheve blokkeringen for deg</translation>
-<translation id="57586589942790530">Ugyldig kortnummer</translation>
+<translation id="5763042198335101085">Angi en gyldig e-postadresse</translation>
+<translation id="5765072501007116331">For å se leveringsmetoder og -krav, velg en adresse</translation>
<translation id="5784606427469807560">Det oppsto et problem under forsøket på å bekrefte kortet ditt. Kontrollér Internett-tilkoblingen din, og prøv igjen.</translation>
<translation id="5785756445106461925">Denne siden inneholder i tillegg andre ressurser som ikke er sikre. Disse ressursene er synlige for andre mens de sendes frem og tilbake, og eventuelle angripere kan modifisere dem for å endre på utseendet til siden.</translation>
<translation id="5786044859038896871">Vil du fylle ut kortinformasjonen?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">Dette nettstedet er ikke tilgjengelig</translation>
<translation id="5869522115854928033">Lagrede passord</translation>
<translation id="5872918882028971132">Overordnede forslag</translation>
-<translation id="587760065310675640">Fraktadressen støttes ikke. Velg en annen adresse.</translation>
<translation id="5901630391730855834">Gul</translation>
-<translation id="59174027418879706">Aktivert</translation>
<translation id="5926846154125914413">Det kan hende du mister tilgang til premium-innhold fra enkelte nettsteder.</translation>
<translation id="5959728338436674663">Send automatisk noe <ph name="BEGIN_WHITEPAPER_LINK" />systeminformasjon og sideinnhold<ph name="END_WHITEPAPER_LINK" /> til Google for å bidra til å oppdage farlige apper og nettsteder. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Uke</translation>
<translation id="5967867314010545767">Fjern fra loggen</translation>
<translation id="5975083100439434680">Zoom ut</translation>
+<translation id="598637245381783098">Kan ikke åpne betalingsappen</translation>
<translation id="5989320800837274978">Verken statiske proxytjenere eller en nettadresse med .pac-skript er angitt.</translation>
<translation id="5990559369517809815">Forespørsler til tjeneren har blitt blokkert av en utvidelse.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Alternativene for kort og adresser kommer fra Chrome. Du kan administrere disse i <ph name="BEGIN_LINK" />Innstillinger<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Side 1}other{Side #}}</translation>
<translation id="6017514345406065928">Grønn</translation>
+<translation id="6027201098523975773">Skriv inn et navn</translation>
<translation id="6040143037577758943">Lukk</translation>
-<translation id="604124094241169006">Automatisk</translation>
<translation id="6042308850641462728">Mer</translation>
<translation id="6060685159320643512">Vær forsiktig. Disse eksperimentene kan bite</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{ingen}=1{1}other{#}}</translation>
@@ -543,9 +552,10 @@
du bruker, på nytt.</translation>
<translation id="614940544461990577">Prøv dette:</translation>
<translation id="6151417162996330722">Tjenersertifikatet har en gyldighetsperiode som er for lang.</translation>
-<translation id="615643356032862689">Nedlastede filer og bokmerker beholdes.</translation>
+<translation id="6157877588268064908">For å se fraktmetoder og -krav, velg en adresse</translation>
<translation id="6165508094623778733">Les mer</translation>
<translation id="6177128806592000436">Tilkoblingen til dette nettstedet er ikke sikker</translation>
+<translation id="6184817833369986695">(kohort: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Kontrollér Internett-tilkoblingen</translation>
<translation id="6218753634732582820">Vil du fjerne adressen fra Chromium?</translation>
<translation id="6251924700383757765">Personvern</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Omorganiser likevel</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" />-bokmerker</translation>
<translation id="6264485186158353794">Tilbake til trygg grunn</translation>
+<translation id="6276112860590028508">Sider fra leselisten din vises her</translation>
+<translation id="6280223929691119688">Kan ikke levere til denne adressen. Velg en annen adresse.</translation>
<translation id="6282194474023008486">Postnummer</translation>
<translation id="6290238015253830360">De foreslåtte artiklene dine vises her</translation>
<translation id="6305205051461490394"><ph name="URL" /> er ikke tilgjengelig.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Kan ikke kontrollere hvorvidt sertifikatet har blitt tilbakekalt.</translation>
<translation id="6433490469411711332">Endre kontaktinformasjonen</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> avviste tilkoblingsforsøket.</translation>
-<translation id="6443118737398455446">Ugyldig utløpsdato</translation>
<translation id="6446608382365791566">Legg til mer informasjon</translation>
<translation id="6451458296329894277">Bekreft ny innsending av skjema</translation>
<translation id="6456339708790392414">Betalingen din</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet kan ha blitt trukket tilbake. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Enhetsinnstillinger</translation>
<translation id="6477321094435799029">Chrome har oppdaget uvanlig kode på denne siden og blokkert den for å beskytte personopplysningene dine (for eksempel passord, telefonnumre og kredittkortinformasjon).</translation>
-<translation id="6477460825583319731">Ugyldig e-postadresse</translation>
<translation id="6489534406876378309">Start opplastingen av krasj</translation>
<translation id="6508722015517270189">Start Chrome på nytt</translation>
-<translation id="6525462735697194615">Ugyldig utløpsmåned</translation>
<translation id="6529602333819889595">&amp;Slett likevel</translation>
<translation id="6534179046333460208">Fysisk nett-forslag</translation>
<translation id="6550675742724504774">Alternativer</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Søk</translation>
<translation id="6644283850729428850">Denne retningslinjen er foreldet.</translation>
<translation id="6652240803263749613">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet ikke er regnet som pålitelig av operativsystemet på datamaskinen din. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Det fraktalternativet er ikke tilgjengelig. Prøv et annet alternativ.</translation>
<translation id="6671697161687535275">Vil du fjerne forslaget fra Chromium?</translation>
<translation id="6685834062052613830">Logg av og fullfør konfigurasjonen</translation>
<translation id="6710213216561001401">Forrige</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Det er noe galt med proxy-tjeneren, eller adressen er feil.</translation>
<translation id="6727102863431372879">Angi</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{ingen}=1{1 element}other{# elementer}}</translation>
-<translation id="6743044928064272573">Hentealtivernativ</translation>
<translation id="674375294223700098">Ukjent feil med tjenersertifikat.</translation>
<translation id="6753269504797312559">Retningslinjeverdi</translation>
<translation id="6757797048963528358">Enheten din gikk inn i hvilemodus.</translation>
<translation id="6778737459546443941">Forelderen din har ikke godkjent det ennå</translation>
<translation id="6810899417690483278">Tilpasnings-ID</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Kunne ikke laste inn områdedataene</translation>
<translation id="6831043979455480757">Oversett</translation>
<translation id="6839929833149231406">Område</translation>
<translation id="6874604403660855544">&amp;Legg til likevel</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Kortet ditt er bekreftet</translation>
<translation id="6897140037006041989">Brukeragent</translation>
<translation id="6915804003454593391">Bruker:</translation>
+<translation id="6948701128805548767">For å se hentemetoder og -krav, velg en adresse</translation>
<translation id="6957887021205513506">Tjenersertifikatet ser ut til å være forfalsket.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Enhet</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">BÃ¥de statiske proxytjenere og en .pac-skriptnettadresse er angitt.</translation>
<translation id="6989763994942163495">Vis avanserte innstillinger</translation>
<translation id="7000990526846637657">Fant ingen loggoppføringer</translation>
-<translation id="7001663382399377034">Legg til mottaker</translation>
<translation id="7009986207543992532">Du prøvde å gå til <ph name="DOMAIN" />, men tjeneren presenterte et sertifikat hvor gyldighetsperioden er oppgitt som for lang til å være pålitelig. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Google-kontoen din kan ha andre typer nettlesingslogger på <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Eldre</translation>
<translation id="7090678807593890770">Søk på Google etter <ph name="LINK" /></translation>
<translation id="7119414471315195487">Lukk andre faner eller programmer</translation>
+<translation id="7129409597930077180">Kan ikke sende til denne adressen. Velg en annen adresse.</translation>
+<translation id="7138472120740807366">Leveringsmetode</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7155487117670177674">Betalingen er ikke trygg</translation>
<translation id="7179921470347911571">Start på nytt nå</translation>
<translation id="7180611975245234373">Last inn på nytt</translation>
<translation id="7182878459783632708">Ingen retningslinjer er angitt</translation>
<translation id="7186367841673660872">Denne siden har blitt oversatt fra<ph name="ORIGINAL_LANGUAGE" />til<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> retter seg ikke etter sikkerhetsstandardene.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Mer informasjon<ph name="END_LINK" /> om dette problemet.</translation>
@@ -675,7 +686,6 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="7424977062513257142">En innebygd side på denne nettsiden sier:</translation>
<translation id="7441627299479586546">Feil emne for innstillinger</translation>
<translation id="7444046173054089907">Dette nettstedet er blokkert</translation>
-<translation id="7444238235002594607">Velg en henteadresse for å sjekke hentemetoder og -krav.</translation>
<translation id="7445762425076701745">Identiteten til tjernen du er tilkoblet kan ikke valideres. Du er tilkoblet en tjener som bruker et navn som kun er gyldig i ditt nettverk, som en ekstern sertifiseringsinstans ikke har noen mulighet til å validere eierskap for. Siden enkelte sertifiseringsinstanser likevel utsteder sertifikater for disse navnene, er det umulig å sikre at du er tilkoblet ønsket nettsted og ikke en angriper.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Finn ut mer<ph name="END_LINK" /> om dette problemet.</translation>
<translation id="7460163899615895653">De nylige fanene dine fra andre enheter vises her</translation>
@@ -719,6 +729,7 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="7755287808199759310">Forelderen din kan oppheve blokkeringen for deg</translation>
<translation id="7758069387465995638">Brannmur- eller antivirusprogramvare kan ha blokkert tilkoblingen.</translation>
<translation id="7761701407923456692">Tjenerens sertifikat samsvarer ikke med nettadressen.</translation>
+<translation id="7763386264682878361">Parser for betalingsmanifest</translation>
<translation id="7764225426217299476">Legg til adresse</translation>
<translation id="777702478322588152">Prefektur</translation>
<translation id="7791543448312431591">Legg til</translation>
@@ -732,6 +743,7 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="785549533363645510">Du er imidlertid ikke usynlig. Inkognitomodus skjuler ikke surfingen din for arbeidsgiveren din, Internett-leverandøren eller nettstedene du besøker.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Kontrollér CVC-koden din, og prøv igjen.</translation>
+<translation id="79338296614623784">Angi et gyldig telefonnummer</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Tjenerens sertifikat er ikke gyldig ennå.</translation>
<translation id="7942349550061667556">Rød</translation>
@@ -751,6 +763,7 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="8088680233425245692">Kunne ikke åpne artikkelen.</translation>
<translation id="8089520772729574115">under 1 MB</translation>
<translation id="8091372947890762290">Aktivering venter på tjeneren</translation>
+<translation id="8118489163946903409">Betalingsmåte</translation>
<translation id="8131740175452115882">Bekreft</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" />-tjenerens <ph name="BEGIN_ABBR" />DNS-adresse<ph name="END_ABBR" /> ble ikke funnet.</translation>
<translation id="8149426793427495338">Datamaskinen din gikk inn i hvilemodus.</translation>
@@ -776,6 +789,7 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="8349305172487531364">Bokmerkerad</translation>
<translation id="8363502534493474904">Slå av flymodus</translation>
<translation id="8364627913115013041">Ikke angitt.</translation>
+<translation id="8368476060205742148">Google Play Tjenester</translation>
<translation id="8380941800586852976">Farlig</translation>
<translation id="8382348898565613901">Bokmerkene du nylig har besøkt, vises her</translation>
<translation id="8398259832188219207">Programstopprapport lastet opp <ph name="UPLOAD_TIME" /></translation>
@@ -784,31 +798,29 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="8428213095426709021">Innstillinger</translation>
<translation id="8433057134996913067">Dette logger deg av de fleste nettsteder.</translation>
<translation id="8437238597147034694">&amp;Angre flyttingen</translation>
-<translation id="8456681095658380701">Ugyldig navn</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 kredittkort}other{# kredittkort}}</translation>
<translation id="8483780878231876732">For å bruke kredittkort du har lagret i Google-kontoen din, logg på Chrome</translation>
<translation id="8488350697529856933">Gjelder for</translation>
-<translation id="8492969205326575646">Korttypen støttes ikke</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> brukte for lang tid på å svare.</translation>
<translation id="852346902619691059">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet ikke er regnet som pålitelig av operativsystemet på enheten din. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Utløpsår</translation>
<translation id="8543181531796978784">Du kan <ph name="BEGIN_ERROR_LINK" />rapportere et påvisningsproblem<ph name="END_ERROR_LINK" /> eller, hvis du forstår sikkerhetsrisikoen, <ph name="BEGIN_LINK" />gå til dette usikre nettstedet<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Oversettelsen mislyktes fordi sidens språk ikke kunne fastslås.</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="8570229484593575558">Denne informasjonen |lagres ikke|:#nettleserloggen din#søkene dine#data fra informasjonskapsler</translation>
<translation id="8571890674111243710">Oversett siden til <ph name="LANGUAGE" /></translation>
-<translation id="8584539743998202583">Aktiviteten din |kan fortsatt være synlig| for#nettsteder du besøker#arbeidsgiveren din#Internett-leverandøren din</translation>
<translation id="858637041960032120">Legg til telefonnummer</translation>
<translation id="859285277496340001">Sertifikatet spesifiserer ikke en mekanisme for å kontrollere hvorvidt det har blitt tilbakekalt.</translation>
<translation id="8620436878122366504">Foreldrene dine har ikke godkjent det ennå</translation>
<translation id="8647750283161643317">Tilbakestill alle til standard</translation>
<translation id="8703575177326907206">Tilkoblingen til <ph name="DOMAIN" /> er ikke kryptert.</translation>
+<translation id="8718314106902482036">Betalingen er ikke fullført</translation>
<translation id="8725066075913043281">Prøv igjen</translation>
<translation id="8728672262656704056">Du er nå i inkognitomodus</translation>
<translation id="8730621377337864115">Ferdig</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="8759274551635299824">Dette kortet er utløpt</translation>
<translation id="8790007591277257123">&amp;Slett likevel</translation>
-<translation id="8798099450830957504">Standard</translation>
<translation id="8800988563907321413">Forslagene dine om ting like ved vises her</translation>
<translation id="8820817407110198400">Bokmerker</translation>
<translation id="883848425547221593">Andre bokmerker</translation>
@@ -818,6 +830,7 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="8866481888320382733">Analysefeil i angivelsen av enhetrsinnstillinger</translation>
<translation id="8866959479196209191">Denne siden sier:</translation>
<translation id="8870413625673593573">Nylig lukket</translation>
+<translation id="8874824191258364635">Angi et gyldig kortnummer</translation>
<translation id="8876793034577346603">Nettverkskonfigurasjon kunne ikke analyseres.</translation>
<translation id="8877192140621905067">NÃ¥r du bekrefter, deles kortinformasjonen din med dette nettstedet</translation>
<translation id="8889402386540077796">Fargetone</translation>
@@ -827,7 +840,6 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="8931333241327730545">Vil du lagre dette kortet i Google-kontoen din?</translation>
<translation id="8932102934695377596">Klokken går for sent</translation>
<translation id="8954894007019320973">(Forts.)</translation>
-<translation id="895548565263634352">Les nyhetssaker fra <ph name="ARTICLE_PUBLISHER" /> og <ph name="OTHER_ARTICLE_COUNT" /> til</translation>
<translation id="8971063699422889582">Tjenerens sertifikat er utløpt.</translation>
<translation id="8986494364107987395">Send bruksstatistikk og programstopprapporter automatisk til Google</translation>
<translation id="8987927404178983737">MÃ¥ned</translation>
@@ -845,7 +857,6 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="9068849894565669697">Velg farge</translation>
<translation id="9076283476770535406">Det kan ha voksent innhold</translation>
<translation id="9078964945751709336">Mer informasjon er nødvendig</translation>
-<translation id="9094175695478007090">Kan ikke starte betalingsappen.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> bruker vanligvis kryptering for å beskytte informasjonen din. Da Chromium prøvde å koble til <ph name="SITE" /> denne gangen, sendte nettstedet tilbake uvanlig og feil legitimasjon. Dette kan skje hvis en angriper prøver å utgi seg for å være <ph name="SITE" />, eller hvis en Wi-Fi-påloggingsskjerm har avbrutt tilkoblingen. Informasjonen din er likevel sikker fordi Chromium stoppet tilkoblingen før det ble utvekslet noen data.</translation>
<translation id="9137013805542155359">Vis original</translation>
<translation id="9137248913990643158">Du må starte og logge på Chrome før du bruker denne appen.</translation>
diff --git a/chromium/components/strings/components_strings_pl.xtb b/chromium/components/strings/components_strings_pl.xtb
index cd121980582..123d96be668 100644
--- a/chromium/components/strings/components_strings_pl.xtb
+++ b/chromium/components/strings/components_strings_pl.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="pl">
<translation id="1008557486741366299">Nie teraz</translation>
<translation id="1015730422737071372">Podaj dodatkowe informacje</translation>
+<translation id="1021110881106174305">Akceptowane karty</translation>
<translation id="1032854598605920125">Obróć w prawo</translation>
<translation id="1038842779957582377">nieznana nazwa</translation>
<translation id="1050038467049342496">Zamknij inne aplikacje</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Ukryj wartość</translation>
<translation id="1228893227497259893">Błędny identyfikator elementu</translation>
<translation id="1232569758102978740">Bez tytułu</translation>
+<translation id="1263231323834454256">Do przeczytania</translation>
<translation id="1264126396475825575">Utworzono raport o awarii w dniu: <ph name="CRASH_TIME" /> (nie został jeszcze przesłany ani zignorowany)</translation>
<translation id="1285320974508926690">Nigdy nie tłumacz tej witryny</translation>
<translation id="129553762522093515">Ostatnio zamknięte</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Ustawienia autouzupełniania Chromium...</translation>
<translation id="1374468813861204354">sugestie</translation>
<translation id="1375198122581997741">Informacje o wersji</translation>
+<translation id="1377321085342047638">Numer karty</translation>
<translation id="139305205187523129">Serwer <ph name="HOST_NAME" /> nie wysłał żadnych danych.</translation>
<translation id="1407135791313364759">Otwórz wszystkie</translation>
<translation id="1413809658975081374">Błąd dotyczący prywatności</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Historia</translation>
<translation id="1645368109819982629">Nieobsługiwany protokół</translation>
<translation id="1656489000284462475">Odbiór</translation>
+<translation id="1663943134801823270">Karty i adresy pochodzą z Chrome. Możesz nimi zarządzać w <ph name="BEGIN_LINK" />Ustawieniach<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> zazwyczaj używa szyfrowania do ochrony Twoich informacji. Gdy tym razem Google Chrome próbował połączyć się ze stroną <ph name="SITE" />, odesłała ona nietypowe i nieprawidłowe dane logowania. Może się tak zdarzyć, gdy pod stronę <ph name="SITE" /> podszywa się atakująca osoba albo gdy ekran logowania do sieci Wi-Fi przerwie połączenie. Twoje informacje są nadal bezpieczne, bo połączenie w Google Chrome zakończyło się przed wymianą jakichkolwiek danych.</translation>
<translation id="168328519870909584">Hakerzy mogliby wykorzystać stronę <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, by zainstalować na Twoim urządzeniu niebezpieczne aplikacje, które mogłyby wykraść lub skasować Twoje dane (takie jak zdjęcia, hasła, wiadomości czy numery kart kredytowych).</translation>
<translation id="168841957122794586">Certyfikat serwera ma słaby klucz kryptograficzny.</translation>
<translation id="1710259589646384581">System operacyjny</translation>
<translation id="1721312023322545264">Aby wejść na tę stronę, musisz uzyskać pozwolenie od użytkownika <ph name="NAME" /></translation>
+<translation id="1721424275792716183">* Pole jest wymagane</translation>
<translation id="1728677426644403582">Przeglądasz źródło strony internetowej</translation>
+<translation id="173080396488393970">Ten typ karty nie jest obsługiwany</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Skontaktuj siÄ™ z administratorem systemu.</translation>
+<translation id="1740951997222943430">Wpisz miesiąc w prawidłowym formacie</translation>
<translation id="1745358365027406341">Pobierz stronę później</translation>
<translation id="17513872634828108">Otwarte karty</translation>
<translation id="1753706481035618306">Numer strony</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Zaktualizuj swoje hasło synchronizacji.</translation>
<translation id="1787142507584202372">Tutaj pojawiajÄ… siÄ™ otwarte karty</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Wybierz adres dostawy, by sprawdzić sposoby dostawy i związane z nimi wymagania.</translation>
+<translation id="1803264062614276815">ImiÄ™ i nazwisko posiadacza karty</translation>
<translation id="1803678881841855883">Bezpieczne przeglądanie Google ostatnio <ph name="BEGIN_LINK" />wykryło złośliwe oprogramowanie<ph name="END_LINK" /> na <ph name="SITE" />. Strony, które normalnie są bezpieczne, czasem zostają zainfekowane złośliwym oprogramowaniem. Złośliwa zawartość pochodzi z <ph name="SUBRESOURCE_HOST" /> – znanego dystrybutora złośliwego oprogramowania. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz się więcej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Dodano: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Nieprawidłowe żądanie lub jego parametry</translation>
<translation id="1826516787628120939">Sprawdzam</translation>
<translation id="1834321415901700177">Ta strona zawiera szkodliwe programy</translation>
<translation id="1842969606798536927">Zapłać</translation>
-<translation id="1864455488461349376">Opcja dostawy</translation>
<translation id="1871208020102129563">Proxy skonfigurowano do używania stałych serwerów proxy, a nie URL-a skryptu PAC.</translation>
<translation id="1871284979644508959">Pole wymagane</translation>
<translation id="187918866476621466">Otwórz strony początkowe</translation>
<translation id="1883255238294161206">Zwiń listę</translation>
<translation id="1898423065542865115">Filtrowanie</translation>
<translation id="194030505837763158">Wejdź na <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Akceptowane karty</translation>
<translation id="1962204205936693436">Zakładki z <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Podczas przekształcania do postaci szeregowej wystąpił błąd</translation>
<translation id="1974060860693918893">Zaawansowane</translation>
<translation id="1978555033938440688">Wersja oprogramowania</translation>
+<translation id="1995859865337580572">Sprawdź kod CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{i jeszcze 1}few{i jeszcze #}many{i jeszcze #}other{i jeszcze #}}</translation>
-<translation id="2020194265157481222">Na karcie musi być imię i nazwisko</translation>
<translation id="2025186561304664664">Ustawiono automatyczne konfigurowanie proxy.</translation>
<translation id="2030481566774242610">Czy chodziło Ci o <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Sprawdź serwer proxy i zaporę sieciową<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Dzisiaj</translation>
<translation id="2154054054215849342">Synchronizacja nie jest dostępna w Twojej domenie.</translation>
<translation id="2154484045852737596">Edytowanie karty</translation>
-<translation id="2156993118928861787">Nieprawidłowy adres</translation>
<translation id="2166049586286450108">Pełny dostęp administratora</translation>
<translation id="2166378884831602661">Ta witryna nie umożliwia bezpiecznego połączenia</translation>
<translation id="2181821976797666341">Zasady</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adres}few{# adresy}many{# adresów}other{# adresu}}</translation>
+<translation id="2202020181578195191">Wpisz rok w prawidłowym formacie</translation>
<translation id="2212735316055980242">Nie znaleziono zasady</translation>
<translation id="2213606439339815911">Pobieram wpisy...</translation>
<translation id="2230458221926704099">Napraw połączenie, używając <ph name="BEGIN_LINK" />aplikacji diagnostycznej<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Masz zablokowany dostęp do internetu</translation>
<translation id="230155334948463882">Nowa karta?</translation>
<translation id="2305919008529760154">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat mógł zostać wydany w celu dokonania oszustwa. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz się więcej<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Opcje karty i adresu pochodzą z Twojego konta Google (<ph name="ACCOUNT_EMAIL" />) i Chrome. Możesz nimi zarządzać w <ph name="BEGIN_LINK" />Ustawieniach<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> wymaga nazwy użytkownika i hasła.</translation>
<translation id="2318774815570432836">Nie możesz teraz wejść na stronę <ph name="SITE" />, bo używa ona HSTS. Błędy sieci i ataki są zazwyczaj przejściowe, więc prawdopodobnie później strona będzie działać. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz się więcej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Inne zakładki</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Domyślne zasady przedsiębiorstwa</translation>
<translation id="2386255080630008482">Certyfikat serwera został unieważniony.</translation>
<translation id="2392959068659972793">Pokaż zasady bez ustawionej wartości</translation>
+<translation id="239429038616798445">Ta metoda wysyłki jest niedostępna. Wybierz inną.</translation>
<translation id="2396249848217231973">&amp;Cofnij usunięcie</translation>
<translation id="2460160116472764928">Bezpieczne przeglądanie Google ostatnio <ph name="BEGIN_LINK" />wykryło złośliwe oprogramowanie<ph name="END_LINK" /> na <ph name="SITE" />. Strony, które normalnie są bezpieczne, czasem zostają zainfekowane złośliwym oprogramowaniem. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz się więcej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Wpisz</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Uruchom diagnostykÄ™ sieci<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Nieprawidłowy URL wyszukiwania</translation>
<translation id="2491120439723279231">Certyfikat serwera zawiera błędy.</translation>
-<translation id="24943777258388405">Nieprawidłowy numer telefonu</translation>
<translation id="2495083838625180221">Parser JSON</translation>
<translation id="2495093607237746763">Jeśli zaznaczysz tę opcję, Chromium zapisze kopię Twojej karty na tym urządzeniu, by umożliwić Ci szybsze wypełnianie formularzy.</translation>
<translation id="2498091847651709837">Zeskanuj nowÄ… kartÄ™</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027">Serwer <ph name="HOST_NAME" /> wysłał nieprawidłową odpowiedź.</translation>
<translation id="2552545117464357659">Nowsze</translation>
<translation id="2556876185419854533">&amp;Cofnij edycjÄ™</translation>
+<translation id="2587730715158995865">Wydawca: <ph name="ARTICLE_PUBLISHER" />. Przeczytaj ten artykuł i inne (<ph name="OTHER_ARTICLE_COUNT" />).</translation>
<translation id="2587841377698384444">Identyfikator interfejsu API katalogu:</translation>
<translation id="2597378329261239068">Ten dokument jest chroniony hasłem. Wprowadź hasło.</translation>
<translation id="2609632851001447353">Odmiany</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Uruchomienie diagnostyki połączeń<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">Usuń wybrane elementy</translation>
+<translation id="277133753123645258">Metoda wysyłki</translation>
<translation id="277499241957683684">Brak rekordu urzÄ…dzenia</translation>
<translation id="2784949926578158345">Połączenie zostało zresetowane.</translation>
<translation id="2794233252405721443">Strona zablokowana</translation>
-<translation id="2812680587231492111">Ta opcja odbioru jest niedostępna .Wybierz inną.</translation>
<translation id="2824775600643448204">Pasek adresu i wyszukiwania</translation>
<translation id="2826760142808435982">Połączenie jest szyfrowane i uwierzytelniane algorytmem <ph name="CIPHER" />, a mechanizm wymiany kluczy to <ph name="KX" />.</translation>
<translation id="2835170189407361413">Wyczyść formularz</translation>
-<translation id="2849041323157393173">Ta opcja dostawy jest niedostępna. Wybierz inną.</translation>
<translation id="2889159643044928134">Nie Å‚aduj ponownie</translation>
<translation id="2900469785430194048">Podczas próby wyświetlenia tej strony w Google Chrome zabrakło pamięci.</translation>
<translation id="2909946352844186028">Wykryto zmianÄ™ sieci.</translation>
<translation id="2916038427272391327">Zamknij inne programy</translation>
<translation id="2922350208395188000">Nie można sprawdzić certyfikatu serwera.</translation>
+<translation id="2928905813689894207">Adres rozliczeniowy</translation>
<translation id="2948083400971632585">Możesz wyłączyć dowolne serwery proxy skonfigurowane dla połączenia na stronie ustawień.</translation>
<translation id="2955913368246107853">Zamknij pasek wyszukiwania</translation>
<translation id="2958431318199492670">Konfiguracja sieci jest niezgodna ze standardem ONC. Jej fragmenty mogły nie zostać zaimportowane.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Aby urządzenie nawiązało bezpieczne połączenie, jego zegar musi wskazywać prawidłową godzinę. Jest to wymagane, bo certyfikaty używane do identyfikacji stron internetowych są ważne tylko przez określony czas. Zegar urządzenia jest ustawiony nieprawidłowo, więc Google Chrome nie może zweryfikować tych certyfikatów.</translation>
<translation id="2972581237482394796">&amp;Ponów</translation>
<translation id="2985306909656435243">Jeśli włączysz tę opcję, Chromium zapisze kopię Twojej karty na tym urządzeniu, by umożliwić Ci szybsze wypełnianie formularzy.</translation>
+<translation id="2985398929374701810">Wpisz prawidłowy adres</translation>
+<translation id="2986368408720340940">Ta metoda odbioru jest niedostępna. Wybierz inną.</translation>
<translation id="2991174974383378012">Udostępnianie stronom internetowym</translation>
<translation id="3005723025932146533">Pokaż zapisaną kopię</translation>
<translation id="3008447029300691911">Wpisz kod CVC karty <ph name="CREDIT_CARD" />. Po potwierdzeniu szczegółowe dane karty zostaną udostępnione tej stronie.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{co najmniej 1 element na synchronizowanych urządzeniach}=1{1 element (i więcej na synchronizowanych urządzeniach)}few{# elementy (i więcej na synchronizowanych urządzeniach)}many{# elementów (i więcej na synchronizowanych urządzeniach)}other{# elementu (i więcej na synchronizowanych urządzeniach)}}</translation>
<translation id="3041612393474885105">Informacje o certyfikacie</translation>
<translation id="3063697135517575841">Chrome nie może obecnie potwierdzić karty. Spróbuj ponownie później.</translation>
+<translation id="3064966200440839136">Opuszczasz tryb incognito, by zapłacić w aplikacji zewnętrznej. Kontynuować?</translation>
<translation id="3093245981617870298">JesteÅ› offline.</translation>
<translation id="3105172416063519923">Identyfikator zasobu:</translation>
<translation id="3109728660330352905">Nie masz uprawnień do wyświetlania tej strony.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Uruchom diagnostykę połączeń<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Dekodowanie odpowiedzi nie powiodło się</translation>
-<translation id="3149891296864842641">Sposób dostawy</translation>
<translation id="3150653042067488994">Tymczasowy błąd serwera</translation>
+<translation id="3154506275960390542">Strona zawiera formularz, którego nie można przesłać bezpiecznie. Podczas przesyłania dane mogą zobaczyć inni użytkownicy, a hakerzy mogą je zmodyfikować, by na serwer dotarły zmienione dane.</translation>
<translation id="3157931365184549694">Przywróć</translation>
<translation id="3167968892399408617">Po zamknięciu wszystkich kart incognito wyświetlane na nich strony nie pozostawią żadnych śladów w historii przeglądarki, magazynie plików cookie ani historii wyszukiwania. Pobrane pliki i utworzone zakładki zostaną jednak zachowane.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Nie udało się wysłać żądania dostępu do strony do <ph name="NAME" />. Spróbuj ponownie.</translation>
<translation id="3355823806454867987">Zmień ustawienia serwera proxy...</translation>
<translation id="3369192424181595722">BÅ‚Ä…d zegara</translation>
+<translation id="337311366426640088">I jeszcze <ph name="ITEM_COUNT" />…</translation>
<translation id="337363190475750230">Anulowano obsługę</translation>
<translation id="3377188786107721145">Podczas przetwarzania zasady wystąpił błąd</translation>
<translation id="3380365263193509176">Nieznany błąd</translation>
<translation id="3380864720620200369">Identyfikator klienta:</translation>
<translation id="3391030046425686457">Adres dostawy</translation>
+<translation id="3395827396354264108">Metoda odbioru</translation>
<translation id="340013220407300675">Hakerzy mogą próbować wykraść Twoje dane z <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (np. hasła, wiadomości lub informacje o karcie kredytowej).</translation>
<translation id="3422248202833853650">Zamknij inne programy, by zwolnić pamięć.</translation>
<translation id="3422472998109090673">Strona <ph name="HOST_NAME" /> jest obecnie nieosiÄ…galna.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">Mastercard</translation>
<translation id="3452404311384756672">Okres pobierania:</translation>
<translation id="3462200631372590220">Ukryj zaawansowane</translation>
+<translation id="3467763166455606212">Wymagane jest imiÄ™ i nazwisko posiadacza karty</translation>
+<translation id="3478058380795961209">Miesiąc utraty ważności</translation>
<translation id="3479539252931486093">Zaskoczyło Cię to? <ph name="BEGIN_LINK" />Daj nam znać<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Nie teraz</translation>
<translation id="348000606199325318">Identyfikator awarii: <ph name="CRASH_LOCAL_ID" /> (identyfikator serwera: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Obecnie nie możemy się skontaktować z Twoim rodzicem. Spróbuj ponownie.</translation>
<translation id="3528171143076753409">Certyfikat serwera nie jest zaufany.</translation>
-<translation id="3538531656504267329">Rok utraty ważności jest nieprawidłowy</translation>
<translation id="3539171420378717834">Zachowaj kopiÄ™ tej karty na urzÄ…dzeniu</translation>
<translation id="3542684924769048008">Używaj hasła dla:</translation>
<translation id="3549644494707163724">Szyfruj wszystkie synchronizowane dane za pomocą hasła synchronizacji</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Ukryj szczegóły</translation>
<translation id="3587482841069643663">Wszystkie</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Wpisz prawidłową datę ważności</translation>
<translation id="36224234498066874">Wyczyść dane przeglądania...</translation>
<translation id="362276910939193118">Wyświetl całą historię</translation>
<translation id="3623476034248543066">Pokaż wartość</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Hasło:</translation>
<translation id="3696411085566228381">brak</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Wybierz adres dostawy, by sprawdzić sposoby wysyłki i związane z nimi wymagania.</translation>
<translation id="370665806235115550">ÅadujÄ™...</translation>
<translation id="3712624925041724820">Brak wolnych licencji</translation>
<translation id="3714780639079136834">Włącz komórkową transmisję danych lub Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Skopiowany link</translation>
<translation id="375403751935624634">Tłumaczenie nie powiodło się z powodu błędu serwera.</translation>
<translation id="3759461132968374835">Brak ostatnio zgłoszonych awarii. Awarie, które nastąpiły wówczas, gdy funkcja zgłaszania awarii była wyłączona, nie są tutaj wymienione.</translation>
+<translation id="3787705759683870569">Wygasa: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Jeśli używasz serwera proxy...</translation>
<translation id="3828924085048779000">Puste hasło jest niedozwolone.</translation>
<translation id="3845539888601087042">Wyświetlam historię z urządzeń, na których jesteś zalogowany. <ph name="BEGIN_LINK" />Więcej informacji<ph name="END_LINK" /></translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Czy Chromium ma zapisać tę kartę?</translation>
<translation id="4171400957073367226">Nieprawidłowy podpis weryfikujący</translation>
-<translation id="4176463684765177261">Wyłączone</translation>
<translation id="4196861286325780578">&amp;Ponów przeniesienie</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Sprawdź konfigurację zapory sieciowej i oprogramowania antywirusowego<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{brak}=1{1 aplikacja ($1)}=2{2 aplikacje ($1, $2)}few{# aplikacje ($1, $2, $3)}many{# aplikacji ($1, $2, $3)}other{# aplikacji ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">wyniki wyszukiwania</translation>
<translation id="4432688616882109544">Serwer <ph name="HOST_NAME" /> nie zaakceptował lub nie otrzymał Twojego certyfikatu logowania.</translation>
<translation id="443673843213245140">Korzystanie z serwera proxy jest wyłączone, ale podano konfigurację proxy.</translation>
-<translation id="4446242550670694251">Możesz teraz przeglądać w trybie prywatnym. Inne osoby korzystające z tego urządzenia nie zobaczą Twojej aktywności.</translation>
<translation id="4492190037599258964">Wyniki wyszukiwania dla „<ph name="SEARCH_STRING" />â€</translation>
<translation id="4506176782989081258">Błąd sprawdzania poprawności: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Skontaktuj siÄ™ z administratorem systemu</translation>
<translation id="450710068430902550">Udostępnianie administratorowi</translation>
+<translation id="4515275063822566619">Karty i adresy pochodzą z Chrome i Twojego konta Google (<ph name="ACCOUNT_EMAIL" />). Możesz nimi zarządzać w <ph name="BEGIN_LINK" />Ustawieniach<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Szczegóły</translation>
<translation id="4558551763791394412">Spróbuj wyłączyć rozszerzenia.</translation>
<translation id="457875822857220463">Dostawa</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Dopasuj do strony</translation>
<translation id="483020001682031208">Brak stron internetu rzeczy do pokazania</translation>
<translation id="4850886885716139402">Widok</translation>
+<translation id="4854362297993841467">Ta metoda dostawy jest niedostępna. Wybierz inną.</translation>
<translation id="4858792381671956233">Zapytałeś rodziców, czy możesz wejść na tę stronę</translation>
<translation id="4880827082731008257">Przeszukaj historiÄ™</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Ta strona została przetłumaczona z nieznanego języka na język <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Płatność</translation>
<translation id="4926049483395192435">Musi być określona.</translation>
-<translation id="4941291666397027948">* oznacza pole wymagane</translation>
<translation id="495170559598752135">Czynności</translation>
<translation id="4958444002117714549">Rozwiń listę</translation>
<translation id="4962322354953122629">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat nie jest zaufany w Chrome. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz się więcej<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Nieprawidłowe hasło</translation>
<translation id="5056549851600133418">Artykuły dla Ciebie</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Sprawdź adres serwera proxy<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Bez plików cookie}=1{1 strona używa plików cookie. }few{# strony używają plików cookie. }many{# stron używa plików cookie. }other{# strony używa plików cookie. }}</translation>
<translation id="5087286274860437796">Certyfikat serwera nie jest obecnie ważny.</translation>
<translation id="5087580092889165836">Dodaj kartÄ™</translation>
<translation id="5089810972385038852">Stan</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Pokaż</translation>
<translation id="5308689395849655368">Funkcja zgłaszania awarii jest wyłączona.</translation>
<translation id="5317780077021120954">Zapisz</translation>
-<translation id="5326702247179446998">Wymagane podanie adresata</translation>
<translation id="5327248766486351172">Nazwa</translation>
<translation id="5337705430875057403">Osoby atakujące stronę <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogą podstępem nakłonić Cię do zrobienia czegoś niebezpiecznego, np. zainstalowania oprogramowania lub ujawnienia danych osobowych (takich jak hasła, numery telefonów i dane kart kredytowych).</translation>
-<translation id="53553865750799677">Nieobsługiwany adres odbioru. Wybierz inny.</translation>
<translation id="5359637492792381994">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa nie jest obecnie ważny. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz się więcej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Zapisanie ustawień zasady nie powiodło się</translation>
<translation id="5386426401304769735">ÅaÅ„cuch certyfikatów tej witryny zawiera certyfikat podpisany za pomocÄ… SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">Komunikat z elementu umieszczonego na stronie <ph name="SITE" />:</translation>
<translation id="5556459405103347317">Odśwież</translation>
<translation id="5565735124758917034">Aktywny</translation>
+<translation id="5571083550517324815">Odbiór spod tego adresu jest niemożliwy. Wybierz inny adres.</translation>
<translation id="5572851009514199876">Uruchom Chrome i zaloguj się w nim, by mógł sprawdzić, czy masz uprawnienia dostępu do tej strony.</translation>
-<translation id="5575380383496039204">Nieobsługiwany adres dostawy. Wybierz inny.</translation>
<translation id="5580958916614886209">Sprawdź miesiąc ważności i spróbuj ponownie</translation>
<translation id="560412284261940334">Zarządzanie jest nieobsługiwane</translation>
<translation id="5610142619324316209">Sprawdź połączenie</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">Tożsamość witryny nie została zweryfikowana.</translation>
<translation id="5720705177508910913">Bieżący użytkownik</translation>
<translation id="5732392974455271431">Mogą ją dla Ciebie odblokować Twoi rodzice</translation>
-<translation id="57586589942790530">Nieprawidłowy numer karty</translation>
+<translation id="5763042198335101085">Wpisz prawidłowy adres e-mail</translation>
+<translation id="5765072501007116331">Aby zobaczyć metody dostawy oraz wymagania, wybierz adres</translation>
<translation id="5784606427469807560">Podczas potwierdzania karty wystąpił problem. Sprawdź połączenie internetowe i spróbuj ponownie.</translation>
<translation id="5785756445106461925">Ta strona zawiera także niezabezpieczone zasoby. Podczas przesyłania mogą je wyświetlić inni użytkownicy, a osoby atakujące mogą je zmodyfikować, by zmienić wygląd strony.</translation>
<translation id="5786044859038896871">Chcesz wpisać dane swojej karty?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">Ta witryna jest nieosiÄ…galna</translation>
<translation id="5869522115854928033">Zapisane hasła</translation>
<translation id="5872918882028971132">Propozycje rodziców</translation>
-<translation id="587760065310675640">Nieobsługiwany adres wysyłki. Wybierz inny.</translation>
<translation id="5901630391730855834">Żółty</translation>
-<translation id="59174027418879706">WÅ‚Ä…czone</translation>
<translation id="5926846154125914413">Możesz stracić dostęp do płatnych treści na niektórych stronach.</translation>
<translation id="5959728338436674663">Automatycznie wysyłaj do Google niektóre <ph name="BEGIN_WHITEPAPER_LINK" />informacje o systemie i część zawartości stron<ph name="END_WHITEPAPER_LINK" />, by pomóc w wykrywaniu niebezpiecznych aplikacji i witryn. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Tydzień</translation>
<translation id="5967867314010545767">Usuń z historii</translation>
<translation id="5975083100439434680">Pomniejsz</translation>
+<translation id="598637245381783098">Nie można otworzyć aplikacji do płatności</translation>
<translation id="5989320800837274978">Nie określono ani stałych serwerów proxy, ani adresu URL skryptu PAC.</translation>
<translation id="5990559369517809815">Żądania do serwera zostały zablokowane przez rozszerzenie.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Opcje karty i adresu pochodzą z Chrome. Możesz nimi zarządzać w <ph name="BEGIN_LINK" />Ustawieniach<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Strona 1}few{Strona #}many{Strona #}other{Strona #}}</translation>
<translation id="6017514345406065928">Zielony</translation>
+<translation id="6027201098523975773">Wpisz imiÄ™ i nazwisko</translation>
<translation id="6040143037577758943">Zamknij</translation>
-<translation id="604124094241169006">Automatyczne</translation>
<translation id="6042308850641462728">Więcej</translation>
<translation id="6060685159320643512">Ostrożnie, na tych eksperymentach można się sparzyć</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{brak}=1{1}few{#}many{#}other{#}}</translation>
@@ -543,9 +552,10 @@
i inne urzÄ…dzenia sieciowe.</translation>
<translation id="614940544461990577">Wypróbuj te rozwiązania:</translation>
<translation id="6151417162996330722">Certyfikat serwera ma za długi okres ważności.</translation>
-<translation id="615643356032862689">Pobrane pliki i zakładki zostaną zachowane.</translation>
+<translation id="6157877588268064908">Aby zobaczyć metody wysyłki oraz wymagania, wybierz adres</translation>
<translation id="6165508094623778733">Więcej informacji</translation>
<translation id="6177128806592000436">Twoje połączenie z tą witryną nie jest bezpieczne</translation>
+<translation id="6184817833369986695">(kohorta: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Sprawdź połączenie z internetem</translation>
<translation id="6218753634732582820">Usunąć ten adres z Chromium?</translation>
<translation id="6251924700383757765">Polityka prywatności</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Ponów zmianę kolejności</translation>
<translation id="6263376278284652872">Zakładki <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Powrót do bezpieczeństwa</translation>
+<translation id="6276112860590028508">Tu pojawiÄ… siÄ™ strony z Twojej listy Do przeczytania</translation>
+<translation id="6280223929691119688">Nie można dostarczyć pod ten adres. Wybierz inny.</translation>
<translation id="6282194474023008486">Kod pocztowy</translation>
<translation id="6290238015253830360">Tutaj wyświetlają się sugerowane artykuły</translation>
<translation id="6305205051461490394">Strona <ph name="URL" /> jest nieosiÄ…galna.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Nie można sprawdzić, czy certyfikat został unieważniony.</translation>
<translation id="6433490469411711332">Edytuj dane kontaktowe</translation>
<translation id="6433595998831338502">Serwer <ph name="HOST_NAME" /> odrzucił połączenie.</translation>
-<translation id="6443118737398455446">Data ważności jest nieprawidłowa</translation>
<translation id="6446608382365791566">Dodaj więcej informacji</translation>
<translation id="6451458296329894277">Potwierdź ponowne przesłanie formularza</translation>
<translation id="6456339708790392414">Twoja płatność</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat mógł zostać unieważniony. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz się więcej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Zasady dotyczące urządzeń</translation>
<translation id="6477321094435799029">Chrome wykrył nietypowy kod na tej stronie i zablokował ją, by chronić Twoje dane osobowe (np. hasła, numery telefonu czy dane kart kredytowych).</translation>
-<translation id="6477460825583319731">Nieprawidłowy adres e-mail</translation>
<translation id="6489534406876378309">Rozpocznij przesyłanie informacji o awariach</translation>
<translation id="6508722015517270189">Uruchom ponownie Chrome</translation>
-<translation id="6525462735697194615">Miesiąc utraty ważności jest nieprawidłowy</translation>
<translation id="6529602333819889595">&amp;Ponów usunięcie</translation>
<translation id="6534179046333460208">Sugestie dotyczÄ…ce internetu rzeczy</translation>
<translation id="6550675742724504774">Opcje</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685">Wyszukiwarka <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Zasada jest przestarzała.</translation>
<translation id="6652240803263749613">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat nie jest zaufany w systemie operacyjnym Twojego komputera. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz się więcej<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Ta opcja zakupu jest niedostępna. Wybierz inną.</translation>
<translation id="6671697161687535275">Usunąć tę podpowiedź do formularza z Chromium?</translation>
<translation id="6685834062052613830">Wyloguj się i dokończ konfigurację</translation>
<translation id="6710213216561001401">Wstecz</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Serwer proxy działa nieprawidłowo albo adres jest błędny.</translation>
<translation id="6727102863431372879">Ustaw</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{brak}=1{1 element}few{# elementy}many{# elementów}other{# elementu}}</translation>
-<translation id="6743044928064272573">Opcja odbioru</translation>
<translation id="674375294223700098">Nieznany błąd certyfikatu serwera.</translation>
<translation id="6753269504797312559">Wartość zasady</translation>
<translation id="6757797048963528358">Twoje urządzenie przeszło w tryb uśpienia.</translation>
<translation id="6778737459546443941">Twój rodzic jeszcze na to nie zezwolił</translation>
<translation id="6810899417690483278">Identyfikator dostosowania</translation>
<translation id="6820686453637990663">Kod CVC</translation>
+<translation id="6824266427216888781">Nie udało się załadować danych dotyczących regionów</translation>
<translation id="6831043979455480757">TÅ‚umacz</translation>
<translation id="6839929833149231406">Dzielnica</translation>
<translation id="6874604403660855544">&amp;Ponów dodanie</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Karta została potwierdzona</translation>
<translation id="6897140037006041989">Klient</translation>
<translation id="6915804003454593391">Użytkownik:</translation>
+<translation id="6948701128805548767">Aby zobaczyć metody odbioru oraz wymagania, wybierz adres</translation>
<translation id="6957887021205513506">Certyfikat serwera wydaje się sfałszowany.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">UrzÄ…dzenie</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">Określono zarówno stałe serwery proxy, jak i URL skryptu PAC.</translation>
<translation id="6989763994942163495">Pokaż ustawienia zaawansowane...</translation>
<translation id="7000990526846637657">Brak wpisów historii</translation>
-<translation id="7001663382399377034">Dodaj adresata</translation>
<translation id="7009986207543992532">Próbujesz połączyć się z <ph name="DOMAIN" />, ale serwer przedstawił certyfikat, którego okres ważności jest za długi, by był wiarygodny. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz się więcej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Inne rodzaje historii przeglądania mogą być nadal dostępne na Twoim koncie Google na <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Starsze</translation>
<translation id="7090678807593890770">Wyszukaj w Google: <ph name="LINK" /></translation>
<translation id="7119414471315195487">Zamknij inne karty lub programy</translation>
+<translation id="7129409597930077180">Nie można wysłać pod ten adres. Wybierz inny.</translation>
+<translation id="7138472120740807366">Metoda dostawy</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7155487117670177674">Płatność nie jest bezpieczna</translation>
<translation id="7179921470347911571">Uruchom ponownie teraz</translation>
<translation id="7180611975245234373">Odśwież</translation>
<translation id="7182878459783632708">Brak ustawionych zasad</translation>
<translation id="7186367841673660872">Ta strona została przetłumaczona z języka<ph name="ORIGINAL_LANGUAGE" />na język<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423">Serwer <ph name="HOST_NAME" /> nie spełnia norm bezpieczeństwa.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Więcej informacji<ph name="END_LINK" /> na temat tego problemu.</translation>
@@ -675,7 +686,6 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="7424977062513257142">Komunikat z elementu umieszczonego na bieżącej stronie internetowej:</translation>
<translation id="7441627299479586546">Nieprawidłowy podmiot zasady</translation>
<translation id="7444046173054089907">Ta strona jest zablokowana</translation>
-<translation id="7444238235002594607">Wybierz adres odbioru, by sprawdzić sposoby odbioru i związane z nimi wymagania.</translation>
<translation id="7445762425076701745">Nie można w pełni zweryfikować tożsamości serwera, z którym nawiązano połączenie. Nawiązano połączenie z serwerem przy użyciu nazwy obowiązującej jedynie w Twojej sieci i której własności zewnętrzny urząd certyfikacji nie jest w stanie zweryfikować. Niektóre urzędy certyfikacji wydają certyfikaty dla takich nazw bez względu na to, że nie można upewnić się, iż nawiązano połączenie z witryną, z którą zamierzano, a nie z intruzem.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Dowiedz się więcej<ph name="END_LINK" /> o tym problemie.</translation>
<translation id="7460163899615895653">W tym miejscu pojawią się Twoje ostatnie karty z innych urządzeń</translation>
@@ -719,6 +729,7 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="7755287808199759310">Może ją dla Ciebie odblokować Twój rodzic</translation>
<translation id="7758069387465995638">Połączenie mogło zostać zablokowane przez zaporę sieciową lub program antywirusowy.</translation>
<translation id="7761701407923456692">Certyfikat serwera jest niezgodny z adresem URL.</translation>
+<translation id="7763386264682878361">Parser pliku manifestu dla płatności</translation>
<translation id="7764225426217299476">Dodaj adres</translation>
<translation id="777702478322588152">Prefektura</translation>
<translation id="7791543448312431591">Dodaj</translation>
@@ -732,6 +743,7 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="785549533363645510">To jednak nie znaczy, że Cię nie widać. Nawet gdy przejdziesz w tryb incognito, Twój pracodawca, dostawca usług internetowych czy webmasterzy stron, na które wchodzisz, mogą dowiedzieć się, co przeglądasz.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" />: <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Sprawdź kod CVC i spróbuj ponownie</translation>
+<translation id="79338296614623784">Wpisz prawidłowy numer telefonu</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Certyfikat serwera nie jest jeszcze ważny.</translation>
<translation id="7942349550061667556">Czerwony</translation>
@@ -751,6 +763,7 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="8088680233425245692">Nie udało się wyświetlić artykułu.</translation>
<translation id="8089520772729574115">mniej niż 1 MB</translation>
<translation id="8091372947890762290">Aktywacja oczekuje na serwerze</translation>
+<translation id="8118489163946903409">Forma płatności</translation>
<translation id="8131740175452115882">Potwierdź</translation>
<translation id="8134994873729925007">Nie udało się znaleźć <ph name="BEGIN_ABBR" />adresu DNS<ph name="END_ABBR" /> serwera <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Twój komputer przeszedł w tryb uśpienia.</translation>
@@ -776,6 +789,7 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="8349305172487531364">Pasek zakładek</translation>
<translation id="8363502534493474904">Wyłącz tryb samolotowy</translation>
<translation id="8364627913115013041">Nie ustawiono.</translation>
+<translation id="8368476060205742148">Usługi Google Play</translation>
<translation id="8380941800586852976">Niebezpieczna</translation>
<translation id="8382348898565613901">Tutaj wyświetlają się ostatnio otwierane zakładki</translation>
<translation id="8398259832188219207">Raport o awarii przesłano: <ph name="UPLOAD_TIME" /></translation>
@@ -784,31 +798,29 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="8428213095426709021">Ustawienia</translation>
<translation id="8433057134996913067">Zostaniesz wylogowany z większości stron internetowych.</translation>
<translation id="8437238597147034694">&amp;Cofnij przeniesienie</translation>
-<translation id="8456681095658380701">Nieprawidłowa nazwa</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 karta kredytowa}few{# karty kredytowe}many{# kart kredytowych}other{# karty kredytowej}}</translation>
<translation id="8483780878231876732">Aby użyć kart z konta Google, zaloguj się w Chrome</translation>
<translation id="8488350697529856933">Dotyczy</translation>
-<translation id="8492969205326575646">Nieobsługiwany typ karty</translation>
<translation id="8498891568109133222">Serwer <ph name="HOST_NAME" /> potrzebował zbyt wiele czasu na odpowiedź.</translation>
<translation id="852346902619691059">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat nie jest zaufany w systemie operacyjnym Twojego urządzenia. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz się więcej<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Rok utraty ważności</translation>
<translation id="8543181531796978784">Możesz <ph name="BEGIN_ERROR_LINK" />zgłosić problem z wykrywaniem<ph name="END_ERROR_LINK" /> lub – jeśli rozumiesz zagrożenie – <ph name="BEGIN_LINK" />wejść na tę niebezpieczną stronę<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Tłumaczenie nie powiodło się, ponieważ nie można określić języka strony.</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="8570229484593575558">Te informacje |nie zostaną zapisane|:#historia przeglądania#wyszukiwania#dane w plikach cookie</translation>
<translation id="8571890674111243710">Trwa tłumaczenie strony na język: <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Twoja aktywność |może być nadal widoczna| dla:#stron internetowych, które odwiedzasz#Twojego pracodawcy#dostawcy usług internetowych</translation>
<translation id="858637041960032120">Dodaj numer telefonu</translation>
<translation id="859285277496340001">Certyfikat nie określa mechanizmu do sprawdzania, czy został on unieważniony.</translation>
<translation id="8620436878122366504">Twoi rodzice jeszcze na to nie zezwolili</translation>
<translation id="8647750283161643317">Przywróć wszystkie ustawienia domyślne</translation>
<translation id="8703575177326907206">Połączenie z witryną <ph name="DOMAIN" /> nie jest szyfrowane.</translation>
+<translation id="8718314106902482036">Płatność nie została zrealizowana</translation>
<translation id="8725066075913043281">Spróbuj ponownie</translation>
<translation id="8728672262656704056">JesteÅ› w trybie incognito</translation>
<translation id="8730621377337864115">Gotowe</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="8759274551635299824">Ta karta straciła ważność</translation>
<translation id="8790007591277257123">&amp;Ponów usunięcie</translation>
-<translation id="8798099450830957504">Domyślny</translation>
<translation id="8800988563907321413">Tutaj wyświetlają się sugestie witryn w pobliżu</translation>
<translation id="8820817407110198400">Zakładki</translation>
<translation id="883848425547221593">Inne zakładki</translation>
@@ -818,6 +830,7 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="8866481888320382733">Podczas przetwarzania ustawień zasady wystąpił błąd</translation>
<translation id="8866959479196209191">Komunikat z bieżącej strony:</translation>
<translation id="8870413625673593573">Ostatnio zamknięte</translation>
+<translation id="8874824191258364635">Wpisz prawidłowy numer karty</translation>
<translation id="8876793034577346603">Przetwarzanie konfiguracji sieci nie powiodło się.</translation>
<translation id="8877192140621905067">Po potwierdzeniu szczegółowe dane karty zostaną udostępnione tej stronie</translation>
<translation id="8889402386540077796">Odcień</translation>
@@ -827,7 +840,6 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="8931333241327730545">Chcesz zapisać tę kartę na swoim koncie Google?</translation>
<translation id="8932102934695377596">Twój zegar się spóźnia</translation>
<translation id="8954894007019320973">(cd.)</translation>
-<translation id="895548565263634352">Przeczytaj artykuły wydawcy <ph name="ARTICLE_PUBLISHER" /> i jeszcze <ph name="OTHER_ARTICLE_COUNT" /></translation>
<translation id="8971063699422889582">Ważność certyfikatu serwera wygasła.</translation>
<translation id="8986494364107987395">Automatycznie przesyłaj do Google statystyki użytkowania i raporty o awariach</translation>
<translation id="8987927404178983737">MiesiÄ…c</translation>
@@ -845,7 +857,6 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="9068849894565669697">Wybierz kolor</translation>
<translation id="9076283476770535406">Może zawierać treści dla dorosłych</translation>
<translation id="9078964945751709336">Potrzebujemy więcej informacji</translation>
-<translation id="9094175695478007090">Nie można uruchomić aplikacji do płatności.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> zazwyczaj używa szyfrowania do ochrony Twoich informacji. Gdy tym razem przeglądarka Chromium próbowała połączyć się ze stroną <ph name="SITE" />, odesłała ona nietypowe i nieprawidłowe dane logowania. Może się tak zdarzyć, gdy pod stronę <ph name="SITE" /> podszywa się osoba atakująca albo gdy ekran logowania do sieci Wi-Fi przerwie połączenie. Twoje informacje są nadal bezpieczne, bo połączenie w Chromium zakończyło się przed wymianą jakichkolwiek danych.</translation>
<translation id="9137013805542155359">Pokaż tekst oryginalny</translation>
<translation id="9137248913990643158">Aby użyć tej aplikacji, najpierw uruchom Chrome i zaloguj się w nim.</translation>
diff --git a/chromium/components/strings/components_strings_pt-BR.xtb b/chromium/components/strings/components_strings_pt-BR.xtb
index bf31be2d0fc..45ae90872d1 100644
--- a/chromium/components/strings/components_strings_pt-BR.xtb
+++ b/chromium/components/strings/components_strings_pt-BR.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="pt-BR">
<translation id="1008557486741366299">Não agora</translation>
<translation id="1015730422737071372">Forneça detalhes adicionais</translation>
+<translation id="1021110881106174305">Cartões aceitos</translation>
<translation id="1032854598605920125">Girar no sentido horário</translation>
<translation id="1038842779957582377">nome desconhecido</translation>
<translation id="1050038467049342496">Fechar outros apps</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Ocultar valor</translation>
<translation id="1228893227497259893">Identificador de entidade incorreto</translation>
<translation id="1232569758102978740">Sem título</translation>
+<translation id="1263231323834454256">Lista de leitura</translation>
<translation id="1264126396475825575">Relatório de erros registrado em <ph name="CRASH_TIME" /> (ainda não enviado ou ignorado)</translation>
<translation id="1285320974508926690">Nunca traduzir este site</translation>
<translation id="129553762522093515">Recentemente fechadas</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Configurações de preenchimento automático do Chromium...</translation>
<translation id="1374468813861204354">sugestões</translation>
<translation id="1375198122581997741">Sobre a versão</translation>
+<translation id="1377321085342047638">Número do cartão</translation>
<translation id="139305205187523129">Nenhum dado foi enviado por <ph name="HOST_NAME" /></translation>
<translation id="1407135791313364759">Abrir todas</translation>
<translation id="1413809658975081374">Erro de privacidade</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Histórico</translation>
<translation id="1645368109819982629">Protocolo não compatível</translation>
<translation id="1656489000284462475">Retirada</translation>
+<translation id="1663943134801823270">Os cartões e os endereços vieram do Chrome. É possível gerenciar essas opções em <ph name="BEGIN_LINK" />Configurações<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">O site <ph name="SITE" /> geralmente usa criptografia para proteger suas informações. Quando o Google Chrome tentou se conectar a <ph name="SITE" /> dessa vez, o website retornou credenciais incomuns e incorretas. Isso pode acontecer quando um invasor está fingindo ser <ph name="SITE" /> ou quando uma tela de login por Wi-Fi interrompeu a conexão. Suas informações ainda estão protegidas, porque o Google Chrome interrompeu a conexão antes que os dados fossem trocados.</translation>
<translation id="168328519870909584">Os invasores que estão atualmente em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podem tentar instalar apps perigosos no seu dispositivo para roubar ou excluir suas informações (por exemplo, fotos, senhas, mensagens e cartões de crédito).</translation>
<translation id="168841957122794586">O certificado do servidor contém uma chave de criptografia fraca.</translation>
<translation id="1710259589646384581">SO</translation>
<translation id="1721312023322545264">É necessário pedir a permissão de <ph name="NAME" /> para visitar este site</translation>
+<translation id="1721424275792716183">* Campo obrigatório</translation>
<translation id="1728677426644403582">Você está vendo o código-fonte de uma página da Web.</translation>
+<translation id="173080396488393970">Esse tipo de cartão não é aceito</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Tente entrar em contato com o administrador do sistema.</translation>
+<translation id="1740951997222943430">Informe um mês de validade válido</translation>
<translation id="1745358365027406341">Fazer o download da página mais tarde</translation>
<translation id="17513872634828108">Guias abertas</translation>
<translation id="1753706481035618306">Numero da página</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Favor atualizar sua senha de sincronização.</translation>
<translation id="1787142507584202372">Suas guias abertas são exibidas aqui</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Selecione um endereço de entrega para verificar os requisitos e métodos de entrega.</translation>
+<translation id="1803264062614276815">Nome do titular do cartão</translation>
<translation id="1803678881841855883">Recentemente, a Navegação segura do Google <ph name="BEGIN_LINK" />detectou malware<ph name="END_LINK" /> em <ph name="SITE" />. Websites que costumam ser seguros às vezes são infectados por malware. O conteúdo malicioso vem de <ph name="SUBRESOURCE_HOST" />, um conhecido distribuidor de malware. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Adicionado em: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Solicitação ou parâmetros de solicitação inválidos</translation>
<translation id="1826516787628120939">Em verificação</translation>
<translation id="1834321415901700177">Este site contém programas perigosos</translation>
<translation id="1842969606798536927">Pagar</translation>
-<translation id="1864455488461349376">Opção de entrega</translation>
<translation id="1871208020102129563">O proxy foi configurado para utilizar servidores de proxy fixo e não um URL de script .pac.</translation>
<translation id="1871284979644508959">Campo obrigatório</translation>
<translation id="187918866476621466">Abrir páginas de inicialização</translation>
<translation id="1883255238294161206">Recolher lista</translation>
<translation id="1898423065542865115">Filtragem</translation>
<translation id="194030505837763158">Ir para <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Cartões aceitos</translation>
<translation id="1962204205936693436">Favoritos de <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Erro de serialização</translation>
<translation id="1974060860693918893">Avançado</translation>
<translation id="1978555033938440688">Versão do firmware</translation>
+<translation id="1995859865337580572">Verifique seu CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{e mais um}one{e mais #}other{e mais #}}</translation>
-<translation id="2020194265157481222">Nome (como consta no cartão) necessário</translation>
<translation id="2025186561304664664">O proxy está configurado em configuração automática.</translation>
<translation id="2030481566774242610">Você quis dizer <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Verificar o proxy e o firewall<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Hoje</translation>
<translation id="2154054054215849342">O serviço de sincronização não está disponível para seu domínio</translation>
<translation id="2154484045852737596">Editar cartão</translation>
-<translation id="2156993118928861787">Endereço inválido</translation>
<translation id="2166049586286450108">Acesso completo de administrador</translation>
<translation id="2166378884831602661">Não foi possível estabelecer uma conexão segura com este site</translation>
<translation id="2181821976797666341">Políticas</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 endereço}one{# endereço}other{# endereços}}</translation>
+<translation id="2202020181578195191">Informe um ano de validade válido</translation>
<translation id="2212735316055980242">Política não encontrada</translation>
<translation id="2213606439339815911">Buscando entradas...</translation>
<translation id="2230458221926704099">Corrija sua conexão usando o <ph name="BEGIN_LINK" />app de diagnóstico<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">O seu acesso à Internet está bloqueado</translation>
<translation id="230155334948463882">Novo cartão?</translation>
<translation id="2305919008529760154">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. É possível que o certificado de segurança dele tenha sido emitido de forma fraudulenta. Isso pode ser causado por uma configuração incorreta ou por um invasor que interceptou sua conexão. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">As opções de endereço e cartão vieram da sua Conta do Google (<ph name="ACCOUNT_EMAIL" />) e do Chrome. É possível gerenciar essas opções em <ph name="BEGIN_LINK" />Configurações<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> exige um nome de usuário e uma senha.</translation>
<translation id="2318774815570432836">Não é possível visitar <ph name="SITE" /> no momento, porque o website usa HSTS. Ataques e erros de rede costumam ser temporários. Portanto, essa página deve voltar a funcionar mais tarde. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Outros favoritos</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Padrão da empresa</translation>
<translation id="2386255080630008482">O certificado do servidor foi revogado.</translation>
<translation id="2392959068659972793">Mostrar políticas sem valor definido</translation>
+<translation id="239429038616798445">Esse método de envio não está disponível. Tente um método diferente.</translation>
<translation id="2396249848217231973">&amp;Desfazer exclusão</translation>
<translation id="2460160116472764928">Recentemente, a Navegação segura do Google <ph name="BEGIN_LINK" />detectou malware<ph name="END_LINK" /> em <ph name="SITE" />. Websites que costumam ser seguros às vezes são infectados por malware. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Preencher</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Executar o Diagnóstico de Rede<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL de pesquisa inválido.</translation>
<translation id="2491120439723279231">O certificado do servidor contém erros.</translation>
-<translation id="24943777258388405">Número de telefone inválido</translation>
<translation id="2495083838625180221">Analisador JSON</translation>
<translation id="2495093607237746763">Se esta opção for selecionada, o Chromium armazenará uma cópia do seu cartão neste dispositivo para preencher de formulários mais rapidamente.</translation>
<translation id="2498091847651709837">Digitalizar novo cartão</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> enviou uma resposta inválida.</translation>
<translation id="2552545117464357659">Recente</translation>
<translation id="2556876185419854533">&amp;Desfazer editar</translation>
+<translation id="2587730715158995865">De <ph name="ARTICLE_PUBLISHER" />. Leia essa matéria e <ph name="OTHER_ARTICLE_COUNT" /> outras.</translation>
<translation id="2587841377698384444">Código da API do diretório:</translation>
<translation id="2597378329261239068">Este documento está protegido por senha. Digite a senha.</translation>
<translation id="2609632851001447353">Variações</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Executar o Diagnóstico de Conectividade<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">Ok</translation>
<translation id="2742870351467570537">Remover itens selecionados</translation>
+<translation id="277133753123645258">Método de envio</translation>
<translation id="277499241957683684">Registro de dispositivo não encontrado</translation>
<translation id="2784949926578158345">A conexão foi redefinida.</translation>
<translation id="2794233252405721443">Site bloqueado</translation>
-<translation id="2812680587231492111">Essa opção de retirada não está disponível. Tente uma opção diferente.</translation>
<translation id="2824775600643448204">Barra de endereço e de pesquisa</translation>
<translation id="2826760142808435982">A conexão foi criptografada e autenticada utilizando <ph name="CIPHER" /> e usa <ph name="KX" /> como o mecanismo de troca de chave.</translation>
<translation id="2835170189407361413">Limpar formulário</translation>
-<translation id="2849041323157393173">Essa opção de entrega não está disponível. Tente uma opção diferente.</translation>
<translation id="2889159643044928134">Não atualizar</translation>
<translation id="2900469785430194048">O Google Chrome ficou sem memória ao tentar exibir essa página da Web.</translation>
<translation id="2909946352844186028">Foi detectada uma alteração na rede.</translation>
<translation id="2916038427272391327">Fechar outros programas</translation>
<translation id="2922350208395188000">O certificado do servidor não pode ser verificado.</translation>
+<translation id="2928905813689894207">Endereço de cobrança</translation>
<translation id="2948083400971632585">Na página "Configurações", você pode desativar quaisquer proxies configurados para uma conexão.</translation>
<translation id="2955913368246107853">Fechar barra de localização</translation>
<translation id="2958431318199492670">A configuração de rede não está de acordo com o padrão ONC. Partes da configuração podem não ser importadas.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Para estabelecer uma conexão segura, o relógio precisa estar configurado 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 Google Chrome não consegue verificar esses certificados.</translation>
<translation id="2972581237482394796">&amp;Refazer</translation>
<translation id="2985306909656435243">Se esta opção for ativada, o Chromium armazenará uma cópia do seu cartão neste dispositivo para preencher formulários mais rapidamente.</translation>
+<translation id="2985398929374701810">Informe um endereço válido</translation>
+<translation id="2986368408720340940">Esse método de retirada não está disponível. Tente um método diferente.</translation>
<translation id="2991174974383378012">Compartilhar com websites</translation>
<translation id="3005723025932146533">Mostrar cópia salva</translation>
<translation id="3008447029300691911">Digite o CVC do <ph name="CREDIT_CARD" />. Depois da confirmação, os detalhes do seu cartão serão compartilhados com esse site.</translation>
@@ -225,16 +232,17 @@
<translation id="3024663005179499861">Tipo de política incorreto</translation>
<translation id="3032412215588512954">Deseja atualizar este site?</translation>
<translation id="3037605927509011580">Ah, não!</translation>
-<translation id="3040955737384246924">{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="3040955737384246924">{COUNT,plural, =0{pelo menos 1 item em dispositivos sincronizados}=1{1 item (e mais em dispositivos sincronizados)}one{# items (and more on synced devices)}other{# itens (e mais em dispositivos sincronizados)}}</translation>
<translation id="3041612393474885105">Informações do certificado</translation>
<translation id="3063697135517575841">Não foi possível confirmar seu cartão com o Chrome no momento. Tente novamente mais tarde.</translation>
+<translation id="3064966200440839136">Saindo do modo de navegação anônima para pagar usando um aplicativo externo. Continuar?</translation>
<translation id="3093245981617870298">Você está off-line.</translation>
<translation id="3105172416063519923">Código do recurso:</translation>
<translation id="3109728660330352905">Você não tem autorização para ver esta página.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Tente executar o Diagnóstico de Conectividade<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Falha ao decodificar resposta</translation>
-<translation id="3149891296864842641">Opção de envio</translation>
<translation id="3150653042067488994">Erro temporário do servidor</translation>
+<translation id="3154506275960390542">Essa página inclui um formulário que pode não ser enviado de forma segura. Os dados que você envia podem ser vistos por outras pessoas enquanto elas navegam ou ser modificados por um invasor para alterar o que o servidor recebe.</translation>
<translation id="3157931365184549694">Restaurar</translation>
<translation id="3167968892399408617">Quando você está no modo invisível, as páginas que você visita não aparecem no seu histórico de navegação e de pesquisa, nem armazenam arquivos "cookies". Mas os downloads e os favoritos continuam funcionando normalmente.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Não foi possível enviar sua solicitação a <ph name="NAME" /> para acessar este site. Tente novamente.</translation>
<translation id="3355823806454867987">Alterar configurações de proxy...</translation>
<translation id="3369192424181595722">Erro do relógio</translation>
+<translation id="337311366426640088">Mais <ph name="ITEM_COUNT" /> itens…</translation>
<translation id="337363190475750230">Desprovisionado</translation>
<translation id="3377188786107721145">Erro de análise da política</translation>
<translation id="3380365263193509176">Erro desconhecido</translation>
<translation id="3380864720620200369">ID do cliente:</translation>
<translation id="3391030046425686457">Endereço de entrega</translation>
+<translation id="3395827396354264108">Método de retirada</translation>
<translation id="340013220407300675">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).</translation>
<translation id="3422248202833853650">Tente sair de outros programas para liberar memória.</translation>
<translation id="3422472998109090673">No momento, não é possível acessar <ph name="HOST_NAME" />.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Buscar intervalo:</translation>
<translation id="3462200631372590220">Ocultar detalhes</translation>
+<translation id="3467763166455606212">O nome do titular do cartão é obrigatório</translation>
+<translation id="3478058380795961209">Mês de vencimento</translation>
<translation id="3479539252931486093">Isso foi inesperado? <ph name="BEGIN_LINK" />Informe-nos<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Não agora</translation>
<translation id="348000606199325318">Código de falha <ph name="CRASH_LOCAL_ID" /> (código do servidor: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Não foi possível contatar seu pai/mãe no momento. Tente novamente.</translation>
<translation id="3528171143076753409">O certificado do servidor não é confiável.</translation>
-<translation id="3538531656504267329">Ano de validade inválido</translation>
<translation id="3539171420378717834">Manter uma cópia deste cartão neste dispositivo</translation>
<translation id="3542684924769048008">Usar senha para:</translation>
<translation id="3549644494707163724">Criptografar todos os dados sincronizados com sua senha de sincronização</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Ocultar detalhes</translation>
<translation id="3587482841069643663">Tudo</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Informe uma data de validade válida</translation>
<translation id="36224234498066874">Limpar dados de navegação...</translation>
<translation id="362276910939193118">Mostrar histórico completo</translation>
<translation id="3623476034248543066">Mostrar valor</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Senha:</translation>
<translation id="3696411085566228381">nenhum</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Selecione um endereço de envio para verificar os métodos e requisitos de entrega.</translation>
<translation id="370665806235115550">Carregando...</translation>
<translation id="3712624925041724820">Licenças esgotadas</translation>
<translation id="3714780639079136834">Ativar os dados da rede celular ou o Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Link que você copiou</translation>
<translation id="375403751935624634">A tradução falhou devido a um erro no servidor.</translation>
<translation id="3759461132968374835">Você não relatou falhas recentemente. As falhas que ocorreram quando o relatório de erros estava desativado não aparecerão aqui.</translation>
+<translation id="3787705759683870569">Validade: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Se você usa um servidor proxy...</translation>
<translation id="3828924085048779000">Uma senha vazia não é permitida.</translation>
<translation id="3845539888601087042">Exibindo histórico dos seus dispositivos conectados. <ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" />.</translation>
@@ -356,10 +368,9 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Deseja que o Chromium salve este cartão?</translation>
<translation id="4171400957073367226">Assinatura de verificação inválida</translation>
-<translation id="4176463684765177261">Desativado</translation>
<translation id="4196861286325780578">&amp;Refazer mover</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Verificar as configurações do antivírus e firewall<ph name="END_LINK" /></translation>
-<translation id="4206349416402437184">{COUNT,plural, =0{nenhum}=1{1 app ($1)}=2{2 apps ($1, $2)}other{# apps ($1, $2, $3)}}</translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{nenhum}=1{1 app ($1)}=2{2 apps ($1, $2)}one{# apps ($1, $2, $3)}other{# apps ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Falhas</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Tente executar o Diagnóstico de Rede<ph name="END_LINK" />.</translation>
<translation id="4250431568374086873">Sua conexão com esse site não é completamente segura</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">resultados da pesquisa</translation>
<translation id="4432688616882109544">O certificado de login não foi aceito por <ph name="HOST_NAME" /> ou não foi fornecido.</translation>
<translation id="443673843213245140">O uso de um proxy está desativado, mas uma configuração explícita de proxy é especificada.</translation>
-<translation id="4446242550670694251">Agora você pode navegar com privacidade, e outras pessoas que usarem este dispositivo não verão sua atividade.</translation>
<translation id="4492190037599258964">Resultados de pesquisa para "<ph name="SEARCH_STRING" />"</translation>
<translation id="4506176782989081258">Erro de validação: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Entrar em contato com o administrador do sistema</translation>
<translation id="450710068430902550">Compartilhar com o administrador</translation>
+<translation id="4515275063822566619">Os cartões e os endereços vieram do Chrome e da sua Conta do Google (<ph name="ACCOUNT_EMAIL" />). É possível gerenciar essas opções em <ph name="BEGIN_LINK" />Configurações<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Detalhes</translation>
<translation id="4558551763791394412">Tente desativar suas extensões.</translation>
<translation id="457875822857220463">Entrega</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Ajustar à página</translation>
<translation id="483020001682031208">Nenhuma página da Web física para exibição</translation>
<translation id="4850886885716139402">Visualizar</translation>
+<translation id="4854362297993841467">Esse método de entrega não está disponível. Tente um método diferente.</translation>
<translation id="4858792381671956233">Você perguntou aos seus responsáveis se pode visitar este site</translation>
<translation id="4880827082731008257">Histórico de pesquisa</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Esta página foi traduzida de um idioma desconhecido para o <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Pagamento</translation>
<translation id="4926049483395192435">Deve ser especificado.</translation>
-<translation id="4941291666397027948">* indica campo obrigatório</translation>
<translation id="495170559598752135">Ações</translation>
<translation id="4958444002117714549">Expandir lista</translation>
<translation id="4962322354953122629">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança dele não é confiável para o Chrome. Isso pode ser causado por uma configuração incorreta ou por um invasor que interceptou sua conexão. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Senha incorreta</translation>
<translation id="5056549851600133418">Artigos para você</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Verificar o endereço do proxy<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Sem cookies}=1{1 site usa cookies. }one{# sites use cookies. }other{# sites usam cookies. }}</translation>
<translation id="5087286274860437796">O certificado do servidor não é válido no momento.</translation>
<translation id="5087580092889165836">Adicionar cartão</translation>
<translation id="5089810972385038852">Estado</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Mostrar</translation>
<translation id="5308689395849655368">O relatório de erros está desativado.</translation>
<translation id="5317780077021120954">Salvar</translation>
-<translation id="5326702247179446998">O destinatário é obrigatório</translation>
<translation id="5327248766486351172">Nome</translation>
<translation id="5337705430875057403">Os invasores em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 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="53553865750799677">Endereço de retirada não aceito. Selecione um endereço diferente.</translation>
<translation id="5359637492792381994">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 por um invasor que interceptou sua conexão. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Falha ao armazenar as configurações da política</translation>
<translation id="5386426401304769735">A cadeia de certificados desse site contém um certificado assinado usando SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">Uma página incorporada em <ph name="SITE" /> diz:</translation>
<translation id="5556459405103347317">Recarregar</translation>
<translation id="5565735124758917034">Ativo</translation>
+<translation id="5571083550517324815">Não é possível fazer a retirada nesse endereço. Tente um endereço diferente.</translation>
<translation id="5572851009514199876">Inicie e faça login no Chrome para que ele possa verificar se você tem permissão para acessar este site.</translation>
-<translation id="5575380383496039204">Endereço de entrega não aceito. Selecione um endereço diferente.</translation>
<translation id="5580958916614886209">Verifique o mês de validade e tente novamente</translation>
<translation id="560412284261940334">Gerenciamento não suportado</translation>
<translation id="5610142619324316209">Verificar a conexão</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">A identidade deste site não foi confirmada.</translation>
<translation id="5720705177508910913">Usuário atual</translation>
<translation id="5732392974455271431">Seus responsáveis podem desbloqueá-lo para você</translation>
-<translation id="57586589942790530">Número de cartão inválido</translation>
+<translation id="5763042198335101085">Informe um endereço de e-mail válido.</translation>
+<translation id="5765072501007116331">Para ver métodos e requisitos de entrega, selecione um endereço</translation>
<translation id="5784606427469807560">Ocorreu um problema ao confirmar seu cartão. Verifique a conexão com a Internet e tente novamente.</translation>
<translation id="5785756445106461925">Além disso, esta página inclui outros recursos que não são seguros. Esses recursos podem ser visualizados por outros usuários enquanto eles navegam e podem ser modificados por um invasor para alterar o comportamento da página.</translation>
<translation id="5786044859038896871">Deseja preencher as informações do cartão?</translation>
@@ -520,32 +531,31 @@
<translation id="5869405914158311789">Não é possível acessar esse site</translation>
<translation id="5869522115854928033">Senhas salvas</translation>
<translation id="5872918882028971132">Sugestões para pais</translation>
-<translation id="587760065310675640">Endereço de entrega não aceito. Selecione um endereço diferente.</translation>
<translation id="5901630391730855834">Amarelo</translation>
-<translation id="59174027418879706">Ativada</translation>
<translation id="5926846154125914413">É possível que você perca o acesso a conteúdos premier de alguns sites.</translation>
<translation id="5959728338436674663">Enviar automaticamente <ph name="BEGIN_WHITEPAPER_LINK" />algumas informações do sistema e conteúdos de página<ph name="END_WHITEPAPER_LINK" /> ao Google para ajudar a detectar sites e apps perigosos. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Semana</translation>
<translation id="5967867314010545767">Remover do histórico</translation>
<translation id="5975083100439434680">Diminuir zoom</translation>
+<translation id="598637245381783098">Não foi possível abrir app de pagamento</translation>
<translation id="5989320800837274978">Nem os servidores proxy fixos nem o URL de script .pac foram especificados.</translation>
<translation id="5990559369517809815">Solicitações ao servidor foram bloqueadas por uma extensão.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">As opções de endereço e cartão vieram do Chrome. É possível gerenciar essas opções em <ph name="BEGIN_LINK" />Configurações<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Página 1}one{Página #}other{Página #}}</translation>
<translation id="6017514345406065928">Verde</translation>
+<translation id="6027201098523975773">Insira um nome</translation>
<translation id="6040143037577758943">Fechar</translation>
-<translation id="604124094241169006">Automático</translation>
<translation id="6042308850641462728">Mais</translation>
<translation id="6060685159320643512">Tome cuidado, esses experimentos podem morder</translation>
-<translation id="6108835911243775197">{COUNT,plural, =0{nenhum}=1{1}other{#}}</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{nenhum}=1{1}one{#}other{#}}</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>
<translation id="6151417162996330722">O certificado do servidor tem um período de validade excessivamente longo.</translation>
-<translation id="615643356032862689">Os arquivos e favoritos transferidos por download serão mantidos.</translation>
+<translation id="6157877588268064908">Para ver métodos e requisitos de envio, selecione um endereço</translation>
<translation id="6165508094623778733">Saiba mais</translation>
<translation id="6177128806592000436">Sua conexão com esse site não é segura</translation>
+<translation id="6184817833369986695">(coorte: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Verifique sua conexão com a Internet</translation>
<translation id="6218753634732582820">Remover endereço do Chromium?</translation>
<translation id="6251924700383757765">Política de Privacidade</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Refazer reordenar</translation>
<translation id="6263376278284652872">Favoritos de <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Voltar à segurança</translation>
+<translation id="6276112860590028508">As páginas da sua lista de leitura são exibidas aqui</translation>
+<translation id="6280223929691119688">Não é possível entregar nesse endereço. Selecione um endereço diferente.</translation>
<translation id="6282194474023008486">Código postal</translation>
<translation id="6290238015253830360">Os artigos sugeridos aparecerão aqui</translation>
<translation id="6305205051461490394">Não é possível acessar <ph name="URL" />.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Não foi possível verificar se o certificado foi revogado</translation>
<translation id="6433490469411711332">Editar informações de contato</translation>
<translation id="6433595998831338502">A conexão com <ph name="HOST_NAME" /> foi recusada.</translation>
-<translation id="6443118737398455446">Data de vencimento inválida</translation>
<translation id="6446608382365791566">Adicionar mais informações</translation>
<translation id="6451458296329894277">Confirmar reenvio do formulário</translation>
<translation id="6456339708790392414">Seu pagamento</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança dele pode ter sido revogado. Isso pode ser causado por uma configuração incorreta ou por um invasor que interceptou sua conexão. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Políticas de dispositivos</translation>
<translation id="6477321094435799029">O Chrome detectou um código incomum nesta página e a bloqueou para proteger suas informações pessoais (por exemplo, senhas, números de telefone e cartões de crédito).</translation>
-<translation id="6477460825583319731">Endereço de e-mail inválido</translation>
<translation id="6489534406876378309">Iniciar upload de falhas</translation>
<translation id="6508722015517270189">Reiniciar o Chrome</translation>
-<translation id="6525462735697194615">Mês de validade inválido</translation>
<translation id="6529602333819889595">&amp;Refazer excluir</translation>
<translation id="6534179046333460208">Sugestões da Web física</translation>
<translation id="6550675742724504774">Opções</translation>
@@ -601,21 +610,20 @@
<translation id="6628463337424475685">Pesquisa do <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Esta política foi encerrada.</translation>
<translation id="6652240803263749613">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança dele não é confiável para o sistema operacional do seu computador. Isso pode ser causado por uma configuração incorreta ou por um invasor que interceptou sua conexão. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Essa opção de envio não está disponível. Tente uma opção diferente.</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="6710213216561001401">Anterior</translation>
<translation id="6710594484020273272">&lt;Digitar termo de pesquisa&gt;</translation>
<translation id="6711464428925977395">Há algo errado com o servidor proxy, ou o endereço está incorreto.</translation>
<translation id="6727102863431372879">Definir</translation>
-<translation id="6731320287533051140">{COUNT,plural, =0{nenhum}=1{1 item}other{# itens}}</translation>
-<translation id="6743044928064272573">Opção de retirada</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{nenhum}=1{1 item}one{# items}other{# itens}}</translation>
<translation id="674375294223700098">Erro, certificado de servidor desconhecido.</translation>
<translation id="6753269504797312559">Valor da política</translation>
<translation id="6757797048963528358">O dispositivo entrou em modo de suspensão.</translation>
<translation id="6778737459546443941">Seu responsável ainda não o aprovou</translation>
<translation id="6810899417690483278">Código de personalização</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Falha ao carregar dados de regiões</translation>
<translation id="6831043979455480757">Traduzir</translation>
<translation id="6839929833149231406">Ãrea</translation>
<translation id="6874604403660855544">&amp;Refazer adicionar</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Seu cartão foi confirmado</translation>
<translation id="6897140037006041989">Agente do usuário</translation>
<translation id="6915804003454593391">Usuário:</translation>
+<translation id="6948701128805548767">Para ver métodos e requisitos de retirada, selecione um endereço</translation>
<translation id="6957887021205513506">O certificado do servidor parece ser falsificado.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Dispositivo</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">Ambos os servidores proxy fixo e um URL de script .pac foram especificados.</translation>
<translation id="6989763994942163495">Mostrar configurações avançadas...</translation>
<translation id="7000990526846637657">Nenhum entrada de histórico encontrada</translation>
-<translation id="7001663382399377034">Adicionar destinatário</translation>
<translation id="7009986207543992532">Você tentou acessar <ph name="DOMAIN" />, mas o servidor apresentou um certificado cujo período de validade é longo demais para ser confiável. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Sua Conta do Google pode ter outras formas de histórico de navegação em <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Mais antigo</translation>
<translation id="7090678807593890770">Pesquise <ph name="LINK" /> no Google</translation>
<translation id="7119414471315195487">Fechar outras guias ou programas</translation>
+<translation id="7129409597930077180">Não é possível enviar para esse endereço. Selecione um endereço diferente.</translation>
+<translation id="7138472120740807366">Método de entrega</translation>
<translation id="7139724024395191329">Emirado</translation>
<translation id="7155487117670177674">Pagamento não seguro</translation>
<translation id="7179921470347911571">Reiniciar agora</translation>
<translation id="7180611975245234373">Atualizar</translation>
<translation id="7182878459783632708">Não há políticas definidas</translation>
<translation id="7186367841673660872">Esta página foi traduzida de<ph name="ORIGINAL_LANGUAGE" />para<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> não adere aos padrões de segurança.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" /> sobre este problema.</translation>
@@ -675,7 +686,6 @@ Dica: o modo de navegação anônimo <ph name="SHORTCUT_KEY" /> pode ser útil d
<translation id="7424977062513257142">Uma página incorporada nessa página da Web diz:</translation>
<translation id="7441627299479586546">Assunto da política incorreto</translation>
<translation id="7444046173054089907">Este site está bloqueado</translation>
-<translation id="7444238235002594607">Selecione um endereço de retirada para verificar os requisitos e métodos de retirada.</translation>
<translation id="7445762425076701745">A identidade do servidor ao qual você está conectado não pode ser validada completamente. Você está conectado ao servidor com um nome válido somente na sua rede e que, portanto, uma autoridade de certificação externa não consegue validar a propriedade. Como algumas autoridades de certificação emitem certificados para esses nomes mesmo assim, não é possível garantir que você esteja conectado ao site que gostaria e não a um invasor.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Saber mais<ph name="END_LINK" /> sobre esse problema.</translation>
<translation id="7460163899615895653">Suas guias recentes de outros dispositivos são exibidas aqui</translation>
@@ -719,6 +729,7 @@ Dica: o modo de navegação anônimo <ph name="SHORTCUT_KEY" /> pode ser útil d
<translation id="7755287808199759310">Seu responsável pode desbloqueá-lo para você</translation>
<translation id="7758069387465995638">É possível que o software antivírus ou o firewall tenha bloqueado a conexão.</translation>
<translation id="7761701407923456692">O certificado do servidor não é compatível com o URL.</translation>
+<translation id="7763386264682878361">Analisador de manifesto de pagamento</translation>
<translation id="7764225426217299476">Adicionar endereço</translation>
<translation id="777702478322588152">Prefeitura</translation>
<translation id="7791543448312431591">Adicionar</translation>
@@ -732,6 +743,7 @@ Dica: o modo de navegação anônimo <ph name="SHORTCUT_KEY" /> pode ser útil d
<translation id="785549533363645510">O modo invisível NÃO oculta seus dados de navegação. Seu empregador, seu provedor de Internet e os websites visitados continuam tendo acesso a essas informações.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Verifique seu CVC e tente novamente</translation>
+<translation id="79338296614623784">Informe um número de telefone válido</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">O certificado do servidor ainda não é válido.</translation>
<translation id="7942349550061667556">Vermelho</translation>
@@ -751,6 +763,7 @@ Dica: o modo de navegação anônimo <ph name="SHORTCUT_KEY" /> pode ser útil d
<translation id="8088680233425245692">Falha ao exibir artigo.</translation>
<translation id="8089520772729574115">menos de 1 MB</translation>
<translation id="8091372947890762290">A ativação está pendente no servidor</translation>
+<translation id="8118489163946903409">Método de pagamento</translation>
<translation id="8131740175452115882">Confirmar</translation>
<translation id="8134994873729925007">Não foi possível encontrar o <ph name="BEGIN_ABBR" />endereço DNS<ph name="END_ABBR" /> do servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Seu computador entrou em modo de suspensão.</translation>
@@ -776,6 +789,7 @@ Dica: o modo de navegação anônimo <ph name="SHORTCUT_KEY" /> pode ser útil d
<translation id="8349305172487531364">Barra de favoritos</translation>
<translation id="8363502534493474904">Desativar modo avião</translation>
<translation id="8364627913115013041">Não definida.</translation>
+<translation id="8368476060205742148">Serviços do Google Play</translation>
<translation id="8380941800586852976">Perigoso</translation>
<translation id="8382348898565613901">Os favoritos visitados recentemente aparecerão aqui</translation>
<translation id="8398259832188219207">Relatório de erros enviado em <ph name="UPLOAD_TIME" /></translation>
@@ -784,32 +798,30 @@ Dica: o modo de navegação anônimo <ph name="SHORTCUT_KEY" /> pode ser útil d
<translation id="8428213095426709021">Configurações</translation>
<translation id="8433057134996913067">Essa opção desconecta você da maioria dos websites.</translation>
<translation id="8437238597147034694">&amp;Desfazer mover</translation>
-<translation id="8456681095658380701">Nome inválido</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 cartão de crédito}one{# cartão de crédito}other{# cartões de crédito}}</translation>
<translation id="8483780878231876732">Para usar os cards da sua Conta do Google, faça login no Google Chrome</translation>
<translation id="8488350697529856933">Aplicável a</translation>
-<translation id="8492969205326575646">Tipo de cartão não compatível</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> demorou muito para responder.</translation>
<translation id="852346902619691059">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança dele não é confiável para o sistema operacional do seu dispositivo. Isso pode ser causado por uma configuração incorreta ou por um invasor que interceptou sua conexão. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Ano de vencimento</translation>
<translation id="8543181531796978784">Você pode <ph name="BEGIN_ERROR_LINK" />denunciar um problema de detecção<ph name="END_ERROR_LINK" /> ou, se entende os riscos à sua segurança, <ph name="BEGIN_LINK" />acessar este site não seguro<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">A tradução falhou porque não foi possível determinar o idioma da página.</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="8570229484593575558">Estas informações |não serão salvas|:#Seu histórico de navegação#Suas pesquisas#Dados de cookies</translation>
<translation id="8571890674111243710">Traduzindo página para <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Sua atividade |ainda pode ficar visível| para:#Websites acessados#Seu empregador#Seu provedor de acesso à Internet</translation>
<translation id="858637041960032120">Ad. nº. telefone
</translation>
<translation id="859285277496340001">O certificado não especifica um mecanismo para verificar se ele foi revogado.</translation>
<translation id="8620436878122366504">Seus responsáveis ainda não o aprovaram</translation>
<translation id="8647750283161643317">Redefinir tudo para o padrão</translation>
<translation id="8703575177326907206">Sua conexão com <ph name="DOMAIN" /> não está criptografada.</translation>
+<translation id="8718314106902482036">Pagamento não concluído</translation>
<translation id="8725066075913043281">Tentar novamente</translation>
-<translation id="8728672262656704056">Você entrou no modo de navegação anônima</translation>
+<translation id="8728672262656704056">Você está navegando sem deixar rastros</translation>
<translation id="8730621377337864115">Concluído</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="8759274551635299824">Este cartão expirou</translation>
<translation id="8790007591277257123">&amp;Refazer excluir</translation>
-<translation id="8798099450830957504">Padrão</translation>
<translation id="8800988563907321413">As sugestões de itens nas proximidades são exibidas aqui</translation>
<translation id="8820817407110198400">Favoritos</translation>
<translation id="883848425547221593">Outros favoritos</translation>
@@ -819,6 +831,7 @@ Dica: o modo de navegação anônimo <ph name="SHORTCUT_KEY" /> pode ser útil d
<translation id="8866481888320382733">Configurações da política de análise de erros</translation>
<translation id="8866959479196209191">Essa página diz:</translation>
<translation id="8870413625673593573">Recentemente fechadas</translation>
+<translation id="8874824191258364635">Informe um número de cartão válido</translation>
<translation id="8876793034577346603">Falha ao analisar a configuração de rede.</translation>
<translation id="8877192140621905067">Depois da confirmação, os detalhes do cartão serão compartilhados com esse site</translation>
<translation id="8889402386540077796">Matiz</translation>
@@ -828,7 +841,6 @@ Dica: o modo de navegação anônimo <ph name="SHORTCUT_KEY" /> pode ser útil d
<translation id="8931333241327730545">Deseja salvar este cartão na sua Conta do Google?</translation>
<translation id="8932102934695377596">Seu relógio está atrasado</translation>
<translation id="8954894007019320973">(Continuação)</translation>
-<translation id="895548565263634352">Leia matérias de <ph name="ARTICLE_PUBLISHER" /> e mais <ph name="OTHER_ARTICLE_COUNT" /> artigo(s)</translation>
<translation id="8971063699422889582">O certificado do servidor expirou.</translation>
<translation id="8986494364107987395">Enviar estatísticas de uso e relatórios de erros ao Google automaticamente</translation>
<translation id="8987927404178983737">Mês</translation>
@@ -846,7 +858,6 @@ Dica: o modo de navegação anônimo <ph name="SHORTCUT_KEY" /> pode ser útil d
<translation id="9068849894565669697">Selecionar cor</translation>
<translation id="9076283476770535406">Pode apresentar conteúdo adulto</translation>
<translation id="9078964945751709336">São necessárias mais informações</translation>
-<translation id="9094175695478007090">Não foi possível abrir o app de pagamento</translation>
<translation id="9103872766612412690">O site <ph name="SITE" /> geralmente usa criptografia para proteger suas informações. Quando o Chromium tentou se conectar a <ph name="SITE" /> dessa vez, o website retornou credenciais
incomuns e incorretas. Isso pode acontecer quando um invasor está fingindo ser <ph name="SITE" /> ou quando uma tela de login por Wi-Fi interrompeu a conexão. Suas informações ainda estão protegidas, porque o Chromium interrompeu a conexão antes que os dados fossem trocados.</translation>
<translation id="9137013805542155359">Mostrar original</translation>
diff --git a/chromium/components/strings/components_strings_pt-PT.xtb b/chromium/components/strings/components_strings_pt-PT.xtb
index 50788b2d65a..0719e2480fa 100644
--- a/chromium/components/strings/components_strings_pt-PT.xtb
+++ b/chromium/components/strings/components_strings_pt-PT.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="pt-PT">
<translation id="1008557486741366299">Agora não</translation>
<translation id="1015730422737071372">Forneça mais detalhes</translation>
+<translation id="1021110881106174305">Cartões admitidos</translation>
<translation id="1032854598605920125">Rodar para a direita</translation>
<translation id="1038842779957582377">nome desconhecido</translation>
<translation id="1050038467049342496">Fechar outras aplicações</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Esconder o valor</translation>
<translation id="1228893227497259893">Identificador de entidade errado</translation>
<translation id="1232569758102978740">Sem nome</translation>
+<translation id="1263231323834454256">Lista de leitura</translation>
<translation id="1264126396475825575">Relatório de falhas capturado <ph name="CRASH_TIME" /> (ainda não carregado ou ignorado)</translation>
<translation id="1285320974508926690">Nunca traduzir este site</translation>
<translation id="129553762522093515">Fechados recentemente</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Definições de preenchimento automático do Chromium…</translation>
<translation id="1374468813861204354">sugestões</translation>
<translation id="1375198122581997741">Acerca da versão</translation>
+<translation id="1377321085342047638">N.º cartão</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> não enviou quaisquer dados.</translation>
<translation id="1407135791313364759">Abrir tudo</translation>
<translation id="1413809658975081374">Erro de privacidade</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Histórico</translation>
<translation id="1645368109819982629">Protocolo não suportado</translation>
<translation id="1656489000284462475">Recolha</translation>
+<translation id="1663943134801823270">Os cartões e os endereços são provenientes do Chrome. Pode geri-los nas <ph name="BEGIN_LINK" />Definições<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">Normalmente, o site <ph name="SITE" /> utiliza a encriptação para proteger as suas informações. Quando o Google Chrome tentou estabelecer ligação a <ph name="SITE" /> desta vez, o Website devolveu credenciais invulgares e incorretas. Isto pode acontecer quando um utilizador mal intencionado tenta simular ser <ph name="SITE" /> ou quando um ecrã de início de sessão Wi-Fi interrompe a ligação. As suas informações continuam seguras porque o Google Chrome interrompeu a ligação antes de qualquer troca de dados.</translation>
<translation id="168328519870909584">Os utilizadores mal intencionados que se encontram em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podem tentar instalar aplicações perigosas no seu dispositivo que roubem ou eliminem as suas informações (por exemplo, fotos, palavras-passe, mensagens e cartões de crédito).</translation>
<translation id="168841957122794586">O certificado do servidor contém uma chave criptográfica fraca.</translation>
<translation id="1710259589646384581">SO</translation>
<translation id="1721312023322545264">Precisa da autorização de <ph name="NAME" /> para visitar este site</translation>
+<translation id="1721424275792716183">* Campo de preenchimento obrigatório</translation>
<translation id="1728677426644403582">Está a ver a fonte de uma página Web</translation>
+<translation id="173080396488393970">Este tipo de cartão não é suportado</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Experimente contactar o administrador do sistema.</translation>
+<translation id="1740951997222943430">Introduza um mês de expiração válido</translation>
<translation id="1745358365027406341">Transferir página mais tarde</translation>
<translation id="17513872634828108">Separadores abertos</translation>
<translation id="1753706481035618306">Número de página</translation>
@@ -88,32 +95,30 @@
<translation id="1783075131180517613">Atualize a frase de acesso de sincronização.</translation>
<translation id="1787142507584202372">Os separadores abertos aparecem aqui</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Selecione um endereço de entrega para ver os métodos e os requisitos de entrega.</translation>
-<translation id="1803678881841855883">Recentemente, a Navegação segura do Google <ph name="BEGIN_LINK" />detetou programas maliciosos<ph name="END_LINK" /> em <ph name="SITE" />. Os Websites que normalmente são seguros estão, por vezes, infetados com programas maliciosos. O conteúdo malicioso é proveniente de <ph name="SUBRESOURCE_HOST" />, um distribuidor de programas maliciosos conhecido. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="1803264062614276815">Nome do titular do cartão</translation>
+<translation id="1803678881841855883">Recentemente, a Navegação segura do Google <ph name="BEGIN_LINK" />detetou programas maliciosos<ph name="END_LINK" /> em <ph name="SITE" />. Os Sites que normalmente são seguros estão, por vezes, infetados com programas maliciosos. O conteúdo malicioso é proveniente de <ph name="SUBRESOURCE_HOST" />, um distribuidor de programas maliciosos conhecido. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Adicionado a <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Pedido ou parâmetros do pedido inválidos</translation>
<translation id="1826516787628120939">A verificar</translation>
<translation id="1834321415901700177">Este site contém programas prejudiciais</translation>
<translation id="1842969606798536927">Pagar</translation>
-<translation id="1864455488461349376">Opção de entrega</translation>
<translation id="1871208020102129563">O proxy está definido para utilizar servidores proxy fixos e não um URL de script .pac.</translation>
<translation id="1871284979644508959">Campo obrigatório</translation>
<translation id="187918866476621466">Abrir páginas iniciais</translation>
<translation id="1883255238294161206">Fechar lista</translation>
<translation id="1898423065542865115">Filtragem</translation>
<translation id="194030505837763158">Aceder a <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Cartões aceites</translation>
<translation id="1962204205936693436">Marcadores de <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Erro de serialização</translation>
<translation id="1974060860693918893">Avançadas</translation>
<translation id="1978555033938440688">Versão do firmware</translation>
-<translation id="2001146170449793414">{COUNT,plural, =1{e mais 1}other{e mais #}}</translation>
-<translation id="2020194265157481222">É necessário o nome no cartão</translation>
+<translation id="1995859865337580572">Valide o seu CVC</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{e mais 1}one{and # more}other{e mais #}}</translation>
<translation id="2025186561304664664">O proxy está definido para configuração automática.</translation>
<translation id="2030481566774242610">Será que quis dizer <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Verificar o proxy e a firewall<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Código postal</translation>
-<translation id="2064691555167957331">{COUNT,plural, =1{1 sugestão}other{# sugestões}}</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 sugestão}one{# suggestions}other{# sugestões}}</translation>
<translation id="2065985942032347596">Autenticação necessária</translation>
<translation id="2079545284768500474">Anular</translation>
<translation id="20817612488360358">As definições de proxy do sistema estão definidas para serem utilizadas, mas também está especificada uma configuração de proxy explícita.</translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Hoje</translation>
<translation id="2154054054215849342">A sincronização não está disponível para o domínio</translation>
<translation id="2154484045852737596">Editar cartão</translation>
-<translation id="2156993118928861787">Endereço inválido</translation>
<translation id="2166049586286450108">Acesso de administrador total</translation>
<translation id="2166378884831602661">Este site não consegue fornecer uma ligação segura</translation>
<translation id="2181821976797666341">Políticas</translation>
-<translation id="2184405333245229118">{COUNT,plural, =1{1 endereço}other{# endereços}}</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 endereço}one{# addresses}other{# endereços}}</translation>
+<translation id="2202020181578195191">Introduza um ano de expiração válido</translation>
<translation id="2212735316055980242">Política não encontrada</translation>
<translation id="2213606439339815911">A obter entradas...</translation>
<translation id="2230458221926704099">Utilize a <ph name="BEGIN_LINK" />aplicação de diagnóstico<ph name="END_LINK" /> para corrigir a ligação</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">O acesso à Internet está bloqueado</translation>
<translation id="230155334948463882">Tem um cartão novo?</translation>
<translation id="2305919008529760154">Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o respetivo certificado de segurança pode ter sido emitido de forma fraudulenta. Isto pode ser o resultado de uma configuração incorreta ou de um utilizador mal-intencionado que intercetou a sua ligação. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">As opções de cartão e endereço são provenientes da sua Conta Google (<ph name="ACCOUNT_EMAIL" />) e do Chrome. Pode geri-las nas <ph name="BEGIN_LINK" />Definições<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535">O domínio <ph name="DOMAIN" /> requer um nome de utilizador e uma palavra-passe.</translation>
<translation id="2318774815570432836">De momento, não é possível aceder a <ph name="SITE" /> porque o Website utiliza HSTS. Geralmente, os erros de rede e os ataques são temporários, pelo que é provável que esta página funcione mais tarde. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Outros marcadores</translation>
@@ -151,18 +155,18 @@
<translation id="2359808026110333948">Continuar</translation>
<translation id="2365563543831475020">O relatório de falhas capturado <ph name="CRASH_TIME" /> não foi carregado</translation>
<translation id="2367567093518048410">Nível</translation>
-<translation id="2371153335857947666">{1,plural, =1{Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o respetivo certificado de segurança expirou ontem. 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 definição parece-lhe correta? Caso contrário, deve corrigir o relógio do seu sistema e, em seguida, atualizar esta página. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}other{Este servidor não conseguiu provar que é <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 definição parece-lhe correta? Caso contrário, deve corrigir o relógio do seu sistema e, em seguida, atualizar esta página. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}}</translation>
+<translation id="2371153335857947666">{1,plural, =1{Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o respetivo certificado de segurança expirou ontem. 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 definição parece-lhe correta? Caso contrário, deve corrigir o relógio do seu sistema e, em seguida, atualizar esta página. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}one{This server could not prove that it is <ph name="DOMAIN" />; its security certificate expired # days ago. This may be caused by a misconfiguration or an attacker intercepting your connection. Your computer's clock is currently set to <ph name="CURRENT_DATE" />. Does that look right? If not, you should correct your system's clock and then refresh this page. <ph name="BEGIN_LEARN_MORE_LINK" />Learn more<ph name="END_LEARN_MORE_LINK" />.}other{Este servidor não conseguiu provar que é <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 definição parece-lhe correta? Caso contrário, deve corrigir o relógio do seu sistema e, em seguida, atualizar esta página. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Nenhuma alternativa da interface disponível</translation>
<translation id="2384307209577226199">Predefinição empresarial</translation>
<translation id="2386255080630008482">O certificado do servidor foi revogado.</translation>
<translation id="2392959068659972793">Apresentar políticas sem valor definido</translation>
+<translation id="239429038616798445">Este método de envio não está disponível. Experimente um método diferente.</translation>
<translation id="2396249848217231973">&amp;Anular eliminação</translation>
-<translation id="2460160116472764928">Recentemente, a Navegação segura do Google <ph name="BEGIN_LINK" />detetou programas maliciosos<ph name="END_LINK" /> em <ph name="SITE" />. Os Websites que normalmente são seguros estão, por vezes, infetados com programas maliciosos. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="2460160116472764928">Recentemente, a Navegação segura do Google <ph name="BEGIN_LINK" />detetou programas maliciosos<ph name="END_LINK" /> em <ph name="SITE" />. Os Sites que normalmente são seguros estão, por vezes, infetados com programas maliciosos. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Preencher</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Executar o Diagnóstico de rede<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL de pesquisa inválido.</translation>
<translation id="2491120439723279231">O certificado do servidor contém erros.</translation>
-<translation id="24943777258388405">Número de telefone inválido</translation>
<translation id="2495083838625180221">Analisador JSON</translation>
<translation id="2495093607237746763">Se marcada, o Chromium armazena uma cópia do seu cartão neste dispositivo para preencher formulários mais rapidamente.</translation>
<translation id="2498091847651709837">Digitalizar novo cartão</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> enviou uma resposta inválida.</translation>
<translation id="2552545117464357659">Mais recente</translation>
<translation id="2556876185419854533">&amp;Anular edição</translation>
+<translation id="2587730715158995865">De <ph name="ARTICLE_PUBLISHER" />. Leia esta e mais <ph name="OTHER_ARTICLE_COUNT" /> notícias.</translation>
<translation id="2587841377698384444">ID da API de diretório:</translation>
<translation id="2597378329261239068">Este documento está protegido por palavra-passe. Introduza uma palavra-passe.</translation>
<translation id="2609632851001447353">Variações</translation>
@@ -197,44 +202,47 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Executar o Diagnóstico de conetividade<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">Remover itens seleccionados</translation>
+<translation id="277133753123645258">Método de envio</translation>
<translation id="277499241957683684">Registo do dispositivo em falta</translation>
<translation id="2784949926578158345">A ligação foi reposta.</translation>
<translation id="2794233252405721443">Site bloqueado</translation>
-<translation id="2812680587231492111">A opção de recolha não está disponível. Experimente uma opção diferente.</translation>
<translation id="2824775600643448204">Barra de pesquisa e endereço</translation>
<translation id="2826760142808435982">A ligação é encriptada e autenticada com <ph name="CIPHER" /> e utiliza <ph name="KX" /> como mecanismo de troca de chaves.</translation>
<translation id="2835170189407361413">Limpar formulário</translation>
-<translation id="2849041323157393173">A opção de fornecimento não está disponível. Experimente uma opção diferente.</translation>
<translation id="2889159643044928134">Não atualizar</translation>
<translation id="2900469785430194048">O Google Chrome ficou sem memória ao tentar apresentar esta página Web.</translation>
<translation id="2909946352844186028">Foi detetada uma alteração de rede.</translation>
<translation id="2916038427272391327">Fechar outros programas</translation>
<translation id="2922350208395188000">Não é possível verificar o certificado do servidor.</translation>
+<translation id="2928905813689894207">Endereço de faturação</translation>
<translation id="2948083400971632585">Pode desativar qualquer proxy configurado para uma ligação a partir da página de definições.</translation>
<translation id="2955913368246107853">Fechar barra de localização</translation>
<translation id="2958431318199492670">A configuração de rede não cumpre a norma ONC. Partes da configuração podem não ser importadas.</translation>
<translation id="29611076221683977">Os hackers que atualmente se encontram em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podem tentar instalar programas perigosos no seu Mac que roubam ou eliminam as suas informações (por exemplo, fotografias, palavras-passe, mensagens e cartões de crédito).</translation>
<translation id="2966678944701946121">Exp.: <ph name="EXPIRATION_DATE_ABBR" />, adicionado a <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
-<translation id="2969319727213777354">Para estabelecer uma ligação segura, o relógio tem de ser definido corretamente. Isto deve-se ao facto de os certificados que os Websites 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 Google Chrome não consegue validar estes certificados.</translation>
+<translation id="2969319727213777354">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 Google Chrome não consegue validar estes certificados.</translation>
<translation id="2972581237482394796">&amp;Repetir</translation>
<translation id="2985306909656435243">Se ativada, o Chromium armazena uma cópia do seu cartão neste dispositivo para preencher formulários mais rapidamente.</translation>
-<translation id="2991174974383378012">Partilha com Websites</translation>
+<translation id="2985398929374701810">Introduza um endereço válido</translation>
+<translation id="2986368408720340940">Este método de recolha não está disponível. Experimente um método diferente.</translation>
+<translation id="2991174974383378012">Partilha com Sites</translation>
<translation id="3005723025932146533">Mostrar cópia guardada</translation>
<translation id="3008447029300691911">Introduza o Código de Segurança/CVC de <ph name="CREDIT_CARD" />. Ao confirmar, os detalhes do cartão são partilhados com este site.</translation>
<translation id="3010559122411665027">Entrada da lista "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="3024663005179499861">Tipo de política incorreto</translation>
<translation id="3032412215588512954">Pretende atualizar este site?</translation>
<translation id="3037605927509011580">Ah, bolas!!</translation>
-<translation id="3040955737384246924">{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="3040955737384246924">{COUNT,plural, =0{pelo menos 1 item em dispositivos sincronizados}=1{1 item (e mais em dispositivos sincronizados)}one{# items (and more on synced devices)}other{# itens (e mais em dispositivos sincronizados)}}</translation>
<translation id="3041612393474885105">Informações do certificado</translation>
<translation id="3063697135517575841">O Chrome não conseguiu confirmar o seu cartão neste momento. Tente novamente mais tarde.</translation>
+<translation id="3064966200440839136">Está a sair do modo de navegação anónima para pagar através de uma aplicação externa. Pretende continuar?</translation>
<translation id="3093245981617870298">O utilizador está em modo offline.</translation>
<translation id="3105172416063519923">ID de recurso:</translation>
<translation id="3109728660330352905">Não tem autorização para ver esta página.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Experimente executar o Diagnóstico de conetividade<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Falha ao descodificar resposta</translation>
-<translation id="3149891296864842641">Opção de envio</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>
<translation id="3157931365184549694">Restaurar</translation>
<translation id="3167968892399408617">As páginas que visualizar em separadores de navegação anónima não são memorizadas no histórico do navegador, no armazenamento de cookies ou no histórico de pesquisas depois de fechar todos os separadores de navegação anónima. Todos os ficheiros transferidos ou os marcadores criados são guardados.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Não é possível enviar o seu pedido de acesso a este site a <ph name="NAME" />. Tente novamente.</translation>
<translation id="3355823806454867987">Alterar definições de proxy...</translation>
<translation id="3369192424181595722">Erro de relógio</translation>
+<translation id="337311366426640088">Mais <ph name="ITEM_COUNT" /> itens...</translation>
<translation id="337363190475750230">Desaprovisionado</translation>
<translation id="3377188786107721145">Erro de análise da política</translation>
<translation id="3380365263193509176">Erro desconhecido</translation>
<translation id="3380864720620200369">ID do Cliente:</translation>
<translation id="3391030046425686457">Endereço de entrega</translation>
+<translation id="3395827396354264108">Método de recolha</translation>
<translation id="340013220407300675">Os atacantes podem 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).</translation>
<translation id="3422248202833853650">Experimente fechar outros programas para libertar memória.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> está inacessível de momento.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Intervalo de obtenção:</translation>
<translation id="3462200631372590220">Ocultar avançadas</translation>
+<translation id="3467763166455606212">Nome do titular do cartão obrigatório</translation>
+<translation id="3478058380795961209">Mês de validade</translation>
<translation id="3479539252931486093">Esta ação foi inesperada? <ph name="BEGIN_LINK" />Informe-nos<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Agora não</translation>
<translation id="348000606199325318">ID de falha <ph name="CRASH_LOCAL_ID" /> (ID do servidor: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Não conseguimos falar com o(a) seu (sua) pai/mãe de momento. Tente novamente.</translation>
<translation id="3528171143076753409">O certificado do servidor não é fidedigno.</translation>
-<translation id="3538531656504267329">Ano de validade inválido</translation>
<translation id="3539171420378717834">Guardar uma cópia deste cartão neste dispositivo</translation>
<translation id="3542684924769048008">Utilizar palavra-passe para:</translation>
<translation id="3549644494707163724">Encriptar todos os dados sincronizados com a sua própria frase de acesso de sincronização</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Ocultar detalhes</translation>
<translation id="3587482841069643663">Tudo</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Introduza uma data de expiração válida</translation>
<translation id="36224234498066874">Limpar dados de navegação...</translation>
<translation id="362276910939193118">Mostrar histórico completo</translation>
<translation id="3623476034248543066">Apresentar o valor</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Palavra-passe:</translation>
<translation id="3696411085566228381">nenhuns</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Selecione uma morada para envio para verificar os métodos e os requisitos de envio.</translation>
<translation id="370665806235115550">A carregar...</translation>
<translation id="3712624925041724820">Licenças esgotadas</translation>
<translation id="3714780639079136834">Ativar os dados móveis ou o Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Link copiado por si</translation>
<translation id="375403751935624634">A tradução falhou devido a um erro do servidor.</translation>
<translation id="3759461132968374835">Não tem comunicado falhas recentemente. As falhas que tenham ocorrido enquanto a criação de relatórios de falha esteve desativada não surgem aqui.</translation>
+<translation id="3787705759683870569">Expira a <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Se utilizar um servidor de proxy...</translation>
<translation id="3828924085048779000">Não é permitida uma frase de acesso vazia.</translation>
<translation id="3845539888601087042">A mostrar o histórico do seus dispositivos com sessão iniciada. <ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" />.</translation>
@@ -331,12 +343,12 @@
<translation id="3886446263141354045">O seu pedido para aceder a este site foi enviado para <ph name="NAME" />.</translation>
<translation id="3890664840433101773">Adicionar email</translation>
<translation id="3901925938762663762">O cartão expirou</translation>
-<translation id="3933571093587347751">{1,plural, =1{Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o respetivo certificado de segurança é supostamente de amanhã. Isto pode ser o resultado de uma configuração incorreta ou de um utilizador mal-intencionado que intercetou a sua ligação. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}other{Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o respetivo certificado de segurança é supostamente de daqui a # dias. Isto pode ser o resultado de uma configuração incorreta ou de um utilizador mal-intencionado que intercetou a sua ligação. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}}</translation>
+<translation id="3933571093587347751">{1,plural, =1{Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o respetivo certificado de segurança é supostamente de amanhã. Isto pode ser o resultado de uma configuração incorreta ou de um utilizador mal-intencionado que intercetou a sua ligação. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}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. <ph name="BEGIN_LEARN_MORE_LINK" />Learn more<ph name="END_LEARN_MORE_LINK" />.}other{Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o respetivo certificado de segurança é supostamente de daqui a # dias. Isto pode ser o resultado de uma configuração incorreta ou de um utilizador mal-intencionado que intercetou a sua ligação. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Falha ao carregar o documento em PDF</translation>
<translation id="3963721102035795474">Modo de leitor</translation>
<translation id="397105322502079400">A calcular...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> está bloqueado</translation>
-<translation id="40103911065039147">{URL_count,plural, =1{1 página Web próxima}other{# páginas Web próximas}}</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 página Web próxima}one{# web pages nearby}other{# páginas Web próximas}}</translation>
<translation id="4021036232240155012">O DNS é o serviço de rede que converte o nome de um Website no respetivo endereço de Internet.</translation>
<translation id="4030383055268325496">&amp;Anular adição</translation>
<translation id="404928562651467259">AVISO</translation>
@@ -351,15 +363,14 @@
<translation id="4115378294792113321">Magenta</translation>
<translation id="4117700440116928470">O âmbito da política não é suportado.</translation>
<translation id="4118212371799607889">Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o Chromium não confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuração incorreta ou de um utilizador mal-intencionado que intercetou a sua ligação. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="4129401438321186435">{COUNT,plural, =1{1 outro}other{# outros}}</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 outro}one{# others}other{# outros}}</translation>
<translation id="4130226655945681476">Verificar os cabos de rede, o modem e o router</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Pretende que o Chromium guarde este cartão?</translation>
<translation id="4171400957073367226">Assinatura de verificação incorreta</translation>
-<translation id="4176463684765177261">Desativado</translation>
<translation id="4196861286325780578">&amp;Refazer movimentação</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Verificar as configurações da firewall e de antivírus<ph name="END_LINK" /></translation>
-<translation id="4206349416402437184">{COUNT,plural, =0{nenhuma}=1{1 aplicação ($1)}=2{2 aplicações ($1, $2)}other{# aplicações ($1, $2, $3)}}</translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{nenhuma}=1{1 aplicação ($1)}=2{2 aplicações ($1, $2)}one{# apps ($1, $2, $3)}other{# aplicações ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Erros</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Experimente executar o Diagnóstico de rede<ph name="END_LINK" />.</translation>
<translation id="4250431568374086873">A ligação a este site não é totalmente segura</translation>
@@ -372,7 +383,7 @@
<translation id="4295944351946828969">Recentemente, a Navegação segura do Google <ph name="BEGIN_LINK" />encontrou programas prejudiciais<ph name="END_LINK" /> em <ph name="SITE" />. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4300246636397505754">Sugestões superiores</translation>
<translation id="4304224509867189079">Iniciar sessão</translation>
-<translation id="432290197980158659">O servidor apresentou um certificado que não corresponde às expetativas existentes. Estas expetativas estão incluídas em determinados Websites de alta segurança para o proteger. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="432290197980158659">O servidor apresentou um certificado que não corresponde às expetativas existentes. Estas expetativas estão incluídas em determinados Sites de alta segurança para o proteger. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Falha ao encontrar o artigo</translation>
<translation id="4326324639298822553">Verifique a data de validade e tente novamente</translation>
<translation id="4331708818696583467">Inseguro</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">resultados da pesquisa</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> não aceitou o seu certificado de início de sessão ou este pode não ter sido fornecido.</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="4446242550670694251">Agora, pode navegar no modo privado e as outras pessoas que utilizarem este dispositivo não veem a sua atividade.</translation>
<translation id="4492190037599258964">Resultados da pesquisa para "<ph name="SEARCH_STRING" />"</translation>
<translation id="4506176782989081258">Erro de validação: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Contactar o administrador do sistema</translation>
<translation id="450710068430902550">Partilha com o administrador</translation>
+<translation id="4515275063822566619">Os cartões e os endereços são provenientes do Chrome e da sua Conta Google (<ph name="ACCOUNT_EMAIL" />). Pode geri-los nas <ph name="BEGIN_LINK" />Definições<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Detalhes</translation>
<translation id="4558551763791394412">Experimente desativar as extensões.</translation>
<translation id="457875822857220463">Entrega</translation>
@@ -417,14 +428,14 @@
<translation id="4816492930507672669">Ajustar à página</translation>
<translation id="483020001682031208">Sem páginas da Web física a apresentar</translation>
<translation id="4850886885716139402">Ver</translation>
+<translation id="4854362297993841467">Este método de fornecimento não está disponível. Experimente um método diferente.</translation>
<translation id="4858792381671956233">Perguntaste aos teus pais se podes aceder a este site.</translation>
<translation id="4880827082731008257">Pesquisar histórico</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
-<translation id="4914479371620770914">{URL_count,plural, =1{e mais 1 página Web}other{e mais # páginas Web}}</translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{e mais 1 página Web}one{and # more web pages}other{e mais # páginas Web}}</translation>
<translation id="4923417429809017348">Esta página foi traduzida de um idioma desconhecido para <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Pagamento</translation>
<translation id="4926049483395192435">Tem de ser especificado.</translation>
-<translation id="4941291666397027948">* indica um campo obrigatório</translation>
<translation id="495170559598752135">Ações</translation>
<translation id="4958444002117714549">Expandir lista</translation>
<translation id="4962322354953122629">Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o Chrome não confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuração incorreta ou de um utilizador mal-intencionado que intercetou a sua ligação. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Palavra-passe incorrecta</translation>
<translation id="5056549851600133418">Artigos para si</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Verificar o endereço proxy<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Sem cookies}=1{1 site utiliza cookies. }one{# sites use cookies. }other{# sites utilizam cookies. }}</translation>
<translation id="5087286274860437796">De momento, o certificado do servidor não é válido.</translation>
<translation id="5087580092889165836">Adicionar cartão</translation>
<translation id="5089810972385038852">Estado</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Mostrar</translation>
<translation id="5308689395849655368">O relatório de falha está desativado.</translation>
<translation id="5317780077021120954">Guardar</translation>
-<translation id="5326702247179446998">Destinatário obrigatório</translation>
<translation id="5327248766486351172">Nome</translation>
<translation id="5337705430875057403">Utilizadores mal intencionados em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 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="53553865750799677">Endereço de recolha não suportado. Selecione um endereço diferente.</translation>
<translation id="5359637492792381994">Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o respetivo certificado de segurança não é válido neste momento. Isto pode ser o resultado de uma configuração incorreta ou de um utilizador mal-intencionado que intercetou a sua ligação. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Falha ao armazenar as definições da política</translation>
<translation id="5386426401304769735">A cadeia de certificados inclui um certificado assinado através de SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">Uma página incorporada em <ph name="SITE" /> diz:</translation>
<translation id="5556459405103347317">Recarregar</translation>
<translation id="5565735124758917034">Ativo</translation>
+<translation id="5571083550517324815">Não é possível recolher a partir deste endereço. Selecione um diferente.</translation>
<translation id="5572851009514199876">Comece e inicie sessão no Chrome para que este possa verificar se tem autorização para aceder a este site.</translation>
-<translation id="5575380383496039204">Endereço de entrega não suportado. Selecione um endereço diferente.</translation>
<translation id="5580958916614886209">Verifique o mês de validade e tente novamente</translation>
<translation id="560412284261940334">Gestão não suportada</translation>
<translation id="5610142619324316209">Verificar a ligação</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">A identidade deste Web site não foi verificada.</translation>
<translation id="5720705177508910913">Utilizador atual</translation>
<translation id="5732392974455271431">Os teus pais podem desbloquear-te</translation>
-<translation id="57586589942790530">Número de cartão inválido</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>
<translation id="5784606427469807560">Ocorreu um erro ao confirmar o cartão. Verifique a sua ligação à Internet e tente novamente.</translation>
<translation id="5785756445106461925">Além disso, esta página inclui outros recursos que não são seguros. Estes recursos podem ser vistos por outros utilizadores em trânsito e modificados por um utilizador mal intencionado com o intuito de alterar o aspeto da página.</translation>
<translation id="5786044859038896871">Pretende preencher as informações do cartão?</translation>
@@ -520,32 +531,31 @@
<translation id="5869405914158311789">Não é possível aceder a este site</translation>
<translation id="5869522115854928033">Palavras-passe guardadas</translation>
<translation id="5872918882028971132">Sugestões superiores</translation>
-<translation id="587760065310675640">Morada para envio não suportada. Selecione uma morada diferente.</translation>
<translation id="5901630391730855834">Amarelo</translation>
-<translation id="59174027418879706">Ativada</translation>
<translation id="5926846154125914413">Pode perder o acesso ao conteúdo premium de alguns sites.</translation>
<translation id="5959728338436674663">Enviar automaticamente algumas <ph name="BEGIN_WHITEPAPER_LINK" />informações do sistema e conteúdos de páginas<ph name="END_WHITEPAPER_LINK" /> para a Google de modo a ajudar a detetar aplicações e sites perigosos. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Semana</translation>
<translation id="5967867314010545767">Remover do histórico</translation>
<translation id="5975083100439434680">Reduzir</translation>
+<translation id="598637245381783098">Não é possível abrir a aplicação de pagamento</translation>
<translation id="5989320800837274978">Não foram especificados servidores proxy fixos nem um URL de script .pac.</translation>
<translation id="5990559369517809815">Os pedidos para o servidor foram bloqueados por uma extensão.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">As opções de cartão e endereço são provenientes do Chrome. Pode geri-las nas <ph name="BEGIN_LINK" />Definições<ph name="END_LINK" />.</translation>
-<translation id="6016158022840135739">{COUNT,plural, =1{Página 1}other{Página #}}</translation>
+<translation id="6016158022840135739">{COUNT,plural, =1{Página 1}one{Page #}other{Página #}}</translation>
<translation id="6017514345406065928">Verde</translation>
+<translation id="6027201098523975773">Introduza um nome</translation>
<translation id="6040143037577758943">Fechar</translation>
-<translation id="604124094241169006">Automático</translation>
<translation id="6042308850641462728">Mais</translation>
<translation id="6060685159320643512">Tenha cuidado, estas experiências podem morder</translation>
-<translation id="6108835911243775197">{COUNT,plural, =0{nenhuma}=1{1}other{#}}</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{nenhuma}=1{1}one{#}other{#}}</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>
<translation id="6151417162996330722">O certificado do servidor tem um período de validade demasiado longo.</translation>
-<translation id="615643356032862689">Os ficheiros transferidos e os marcadores serão mantidos.</translation>
+<translation id="6157877588268064908">Para ver os métodos de envio e os requisitos, selecione um endereço</translation>
<translation id="6165508094623778733">Saiba mais</translation>
<translation id="6177128806592000436">A sua ligação a este site não é segura</translation>
+<translation id="6184817833369986695">(grupo com caraterísticas em comum: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Verificar a ligação à Internet</translation>
<translation id="6218753634732582820">Pretende remover o endereço do Chromium?</translation>
<translation id="6251924700383757765">Política de privacidade</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Refazer reordenação</translation>
<translation id="6263376278284652872">Marcadores do <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Retroceder para segurança</translation>
+<translation id="6276112860590028508">As páginas da sua lista de leitura aparecem aqui</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="6290238015253830360">Os seus artigos sugeridos são apresentados aqui</translation>
<translation id="6305205051461490394"><ph name="URL" /> está inacessível.</translation>
@@ -565,7 +577,7 @@
<translation id="6342069812937806050">Mesmo agora</translation>
<translation id="6355080345576803305">Substituição da sessão pública</translation>
<translation id="6358450015545214790">O que significam?</translation>
-<translation id="6386120369904791316">{COUNT,plural, =1{1 outra sugestão}other{# outras sugestões}}</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 outra sugestão}one{# other suggestions}other{# outras sugestões}}</translation>
<translation id="6387478394221739770">Está interessado nas novas e fantásticas funcionalidades do Chrome? Experimente o nosso canal beta em chrome.com/beta.</translation>
<translation id="6389758589412724634">O Chromium ficou sem memória ao tentar apresentar esta página Web.</translation>
<translation id="6404511346730675251">Editar marcador</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Não é possível verificar se o certificado foi revogado.</translation>
<translation id="6433490469411711332">Editar informações de contacto</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> recusou estabelecer ligação.</translation>
-<translation id="6443118737398455446">Data de validade inválida</translation>
<translation id="6446608382365791566">Adicionar mais informações</translation>
<translation id="6451458296329894277">Confirmar nova submissão de formulário</translation>
<translation id="6456339708790392414">O seu pagamento</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o respetivo certificado de segurança pode ser revogado. Isto pode ser o resultado de uma configuração incorreta ou de um utilizador mal-intencionado que intercetou a sua ligação. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Políticas do dispositivo</translation>
<translation id="6477321094435799029">O Chrome detetou código estranho nesta página e bloqueou-a para proteger as suas informações pessoais (por exemplo, palavras-passe, números de telefone e números de cartões de crédito).</translation>
-<translation id="6477460825583319731">Endereço de email inválido</translation>
<translation id="6489534406876378309">Começar a carregar falhas</translation>
<translation id="6508722015517270189">Reiniciar o Chrome</translation>
-<translation id="6525462735697194615">Mês de validade inválido</translation>
<translation id="6529602333819889595">&amp;Refazer eliminação</translation>
<translation id="6534179046333460208">Sugestões da Web física</translation>
<translation id="6550675742724504774">Opções</translation>
@@ -601,21 +610,20 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Pesquisar</translation>
<translation id="6644283850729428850">Esta política está obsoleta.</translation>
<translation id="6652240803263749613">Este servidor não conseguiu provar que é <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 utilizador mal-intencionado que intercetou a sua ligação. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">A opção de envio não está disponível. Experimente uma opção diferente.</translation>
<translation id="6671697161687535275">Pretende remover a sugestão do formulário do Chromium?</translation>
<translation id="6685834062052613830">Termine sessão e conclua a configuração</translation>
<translation id="6710213216561001401">Anterior</translation>
<translation id="6710594484020273272">&lt;Introduzir termo de pesquisa&gt;</translation>
<translation id="6711464428925977395">Existe um problema com o servidor proxy ou o endereço está incorreto.</translation>
<translation id="6727102863431372879">Definir</translation>
-<translation id="6731320287533051140">{COUNT,plural, =0{nenhuma}=1{1 item}other{# itens}}</translation>
-<translation id="6743044928064272573">Opção de recolha</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{nenhuma}=1{1 item}one{# items}other{# itens}}</translation>
<translation id="674375294223700098">Erro de certificado de servidor desconhecido.</translation>
<translation id="6753269504797312559">Valor da política</translation>
<translation id="6757797048963528358">O dispositivo entrou em suspensão.</translation>
<translation id="6778737459546443941">O teu pai/a tua mãe ainda não o aprovou</translation>
<translation id="6810899417690483278">ID de personalização</translation>
<translation id="6820686453637990663">Código de segurança</translation>
+<translation id="6824266427216888781">Falha ao carregar os dados das regiões</translation>
<translation id="6831043979455480757">Traduzir</translation>
<translation id="6839929833149231406">Ãrea</translation>
<translation id="6874604403660855544">&amp;Refazer adição</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">O seu cartão foi confirmado</translation>
<translation id="6897140037006041989">Agente do utilizador</translation>
<translation id="6915804003454593391">Utilizador:</translation>
+<translation id="6948701128805548767">Para ver os métodos de recolha e os requisitos, selecione um endereço</translation>
<translation id="6957887021205513506">O certificado do servidor parece ser uma falsificação.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Dispositivo</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">Foram especificados servidores proxy fixos e um URL de script .pac.</translation>
<translation id="6989763994942163495">Mostrar definições avançadas...</translation>
<translation id="7000990526846637657">Não foram encontradas entradas no histórico</translation>
-<translation id="7001663382399377034">Adicionar destinatário</translation>
<translation id="7009986207543992532">Tentou aceder a <ph name="DOMAIN" />, mas o servidor apresentou um certificado cujo período de validade é demasiado longo para ser fidedigno. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">A sua Conta Google pode ter outras formas do histórico de navegação em <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Mais antigo</translation>
<translation id="7090678807593890770">Pesquisar <ph name="LINK" /> no Google</translation>
<translation id="7119414471315195487">Fechar outros separadores ou programas</translation>
+<translation id="7129409597930077180">Não é possível enviar para este endereço. Selecione um diferente.</translation>
+<translation id="7138472120740807366">Método de fornecimento</translation>
<translation id="7139724024395191329">Emirado</translation>
<translation id="7155487117670177674">Pagamento não seguro</translation>
<translation id="7179921470347911571">Reiniciar agora</translation>
<translation id="7180611975245234373">Atualizar</translation>
<translation id="7182878459783632708">Não estão definidas políticas</translation>
<translation id="7186367841673660872">Esta página foi traduzida de<ph name="ORIGINAL_LANGUAGE" />para<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> não respeita os padrões de segurança.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" /> sobre este problema.</translation>
@@ -675,7 +686,6 @@ O modo de navegação anónima <ph name="SHORTCUT_KEY" /> pode ser útil da pró
<translation id="7424977062513257142">Uma página incorporada nesta página Web diz:</translation>
<translation id="7441627299479586546">Assunto da política incorreto</translation>
<translation id="7444046173054089907">Este site está bloqueado</translation>
-<translation id="7444238235002594607">Selecione um endereço de recolha para ver os métodos e os requisitos de recolha.</translation>
<translation id="7445762425076701745">Não é possível validar totalmente a identidade do servidor ao qual está ligado. Está ligado a um servidor com um nome que apenas é válido na sua rede, que não permite que uma autoridade de certificação externa valide a respectiva propriedade. Ainda assim, algumas autoridades emitem certificados para esses nomes, pelo que não há forma de garantir que está ligado ao Web site que pretende e não a um site pirata.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Saber mais<ph name="END_LINK" /> sobre este problema.</translation>
<translation id="7460163899615895653">Os seus separadores recentes de outros dispositivos aparecem aqui</translation>
@@ -719,6 +729,7 @@ O modo de navegação anónima <ph name="SHORTCUT_KEY" /> pode ser útil da pró
<translation id="7755287808199759310">O teu pai/a tua mãe pode desbloquear-te</translation>
<translation id="7758069387465995638">O software de firewall ou antivírus pode ter bloqueado a ligação.</translation>
<translation id="7761701407923456692">O certificado do servidor não corresponde ao URL.</translation>
+<translation id="7763386264682878361">Analisador de manifestos de pagamento</translation>
<translation id="7764225426217299476">Adicionar endereço</translation>
<translation id="777702478322588152">Prefeitura</translation>
<translation id="7791543448312431591">Adicionar</translation>
@@ -729,9 +740,10 @@ O modo de navegação anónima <ph name="SHORTCUT_KEY" /> pode ser útil da pró
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Pretende remover a sugestão do formulário do Chrome?</translation>
<translation id="7815407501681723534">Encontrados <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para "<ph name="SEARCH_STRING" />"</translation>
-<translation id="785549533363645510">No entanto, a navegação não é invisível. Passar para o modo de navegação anónima não oculta a navegação do empregador ou do fornecedor de serviços de Internet, nem dos Websites que visitar.</translation>
+<translation id="785549533363645510">No entanto, a navegação não é invisível. Passar para o modo de navegação anónima não oculta a navegação do empregador ou do fornecedor de serviços de Internet, nem dos Sites que visitar.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Verifique o Código de Segurança/CVC e tente novamente</translation>
+<translation id="79338296614623784">Introduza um número de telefone válido</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">O certificado do servidor ainda não é válido.</translation>
<translation id="7942349550061667556">Vermelho</translation>
@@ -745,12 +757,13 @@ O modo de navegação anónima <ph name="SHORTCUT_KEY" /> pode ser útil da pró
<translation id="800218591365569300">Experimente fechar outros separadores ou programas para libertar memória.</translation>
<translation id="8012647001091218357">Não conseguimos falar com os seus pais de momento. Tente novamente.</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="803030522067524905">Recentemente, a Navegação segura do Google detetou atividade de phishing em <ph name="SITE" />. Os sites de phishing fazem-se passar por outros Websites para o enganar. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="803030522067524905">Recentemente, a Navegação segura do Google detetou atividade de phishing em <ph name="SITE" />. Os sites de phishing fazem-se passar por outros Sites para o enganar. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8034522405403831421">Esta página está em <ph name="SOURCE_LANGUAGE" />. Pretende traduzi-la para <ph name="TARGET_LANGUAGE" />?</translation>
<translation id="8041089156583427627">Enviar comentários</translation>
<translation id="8088680233425245692">Falha ao ver o artigo.</translation>
<translation id="8089520772729574115">menos de 1 MB</translation>
<translation id="8091372947890762290">Ativação pendente no servidor</translation>
+<translation id="8118489163946903409">Método de pagamento</translation>
<translation id="8131740175452115882">Confirmar</translation>
<translation id="8134994873729925007">Não foi possível encontrar o <ph name="BEGIN_ABBR" />endereço DNS<ph name="END_ABBR" /> do servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">O computador entrou em suspensão.</translation>
@@ -776,40 +789,39 @@ O modo de navegação anónima <ph name="SHORTCUT_KEY" /> pode ser útil da pró
<translation id="8349305172487531364">Barra de marcadores</translation>
<translation id="8363502534493474904">Desativar o modo de avião</translation>
<translation id="8364627913115013041">Não definida.</translation>
+<translation id="8368476060205742148">Serviços do Google Play</translation>
<translation id="8380941800586852976">Perigosa</translation>
<translation id="8382348898565613901">Os seus marcadores visitados recentemente são apresentados aqui.</translation>
<translation id="8398259832188219207">Relatório de falhas carregado no(a) <ph name="UPLOAD_TIME" /></translation>
<translation id="8412145213513410671">Falhas (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Tem de introduzir a mesma frase de acesso duas vezes.</translation>
<translation id="8428213095426709021">Definições</translation>
-<translation id="8433057134996913067">Esta opção termina a sessão na maioria dos Websites.</translation>
+<translation id="8433057134996913067">Esta opção termina a sessão na maioria dos Sites.</translation>
<translation id="8437238597147034694">&amp;Anular movimentação</translation>
-<translation id="8456681095658380701">Nome inválido</translation>
-<translation id="8466379296835108687">{COUNT,plural, =1{1 cartão de crédito}other{# cartões de crédito}}</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="8483780878231876732">Para utilizar cartões da sua Conta Google, inicie sessão no Chrome.</translation>
<translation id="8488350697529856933">Aplica-se a</translation>
-<translation id="8492969205326575646">Tipo de cartão incompatível</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> demorou demasiado tempo a responder.</translation>
<translation id="852346902619691059">Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o sistema operativo do seu dispositivo não confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuração incorreta ou de um utilizador mal-intencionado que intercetou a sua ligação. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Ano de validade</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="8553075262323480129">A tradução falhou porque não foi possível determinar o idioma da página.</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="8570229484593575558">Estas informações |não serão guardadas|:#O histórico de navegação#As pesquisas#Dados de cookies</translation>
<translation id="8571890674111243710">A traduzir a página para <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">A sua atividade |poderá continuar visível| para:#Os Websites que visita#A sua entidade empregadora#O seu fornecedor de serviços de Internet</translation>
<translation id="858637041960032120">Adic. n.º telef.
</translation>
<translation id="859285277496340001">O certificado não indica um mecanismo para verificar se foi ou não revogado.</translation>
<translation id="8620436878122366504">Os teus pais ainda não o aprovaram</translation>
<translation id="8647750283161643317">Repor todas as predefinições</translation>
<translation id="8703575177326907206">A sua ligação a <ph name="DOMAIN" /> não está encriptada.</translation>
+<translation id="8718314106902482036">Pagamento não concluído</translation>
<translation id="8725066075913043281">Tentar novamente</translation>
<translation id="8728672262656704056">Está anónimo</translation>
<translation id="8730621377337864115">Concluído</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 Websites 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="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="8759274551635299824">Este cartão expirou</translation>
<translation id="8790007591277257123">&amp;Refazer eliminação</translation>
-<translation id="8798099450830957504">Predefinição</translation>
<translation id="8800988563907321413">As sugestões próximas aparecem aqui</translation>
<translation id="8820817407110198400">Marcadores</translation>
<translation id="883848425547221593">Outros marcadores</translation>
@@ -819,6 +831,7 @@ O modo de navegação anónima <ph name="SHORTCUT_KEY" /> pode ser útil da pró
<translation id="8866481888320382733">Erro ao analisar as definições da política</translation>
<translation id="8866959479196209191">Esta página diz:</translation>
<translation id="8870413625673593573">Fechadas recentemente</translation>
+<translation id="8874824191258364635">Introduza um número de cartão válido</translation>
<translation id="8876793034577346603">Falha ao analisar a configuração de rede.</translation>
<translation id="8877192140621905067">Ao confirmar, os detalhes do cartão são partilhados com este site.</translation>
<translation id="8889402386540077796">Tonalidade</translation>
@@ -828,7 +841,6 @@ O modo de navegação anónima <ph name="SHORTCUT_KEY" /> pode ser útil da pró
<translation id="8931333241327730545">Pretende guardar este cartão na sua Conta Google?</translation>
<translation id="8932102934695377596">O seu relógio está atrasado</translation>
<translation id="8954894007019320973">(Cont.)</translation>
-<translation id="895548565263634352">Ler notícias do(a) <ph name="ARTICLE_PUBLISHER" /> e mais <ph name="OTHER_ARTICLE_COUNT" /></translation>
<translation id="8971063699422889582">O certificado do servidor expirou.</translation>
<translation id="8986494364107987395">Enviar automaticamente estatísticas de utilização e relatórios de falhas para a Google</translation>
<translation id="8987927404178983737">Mês</translation>
@@ -846,7 +858,6 @@ O modo de navegação anónima <ph name="SHORTCUT_KEY" /> pode ser útil da pró
<translation id="9068849894565669697">Selecionar cor</translation>
<translation id="9076283476770535406">Pode ter conteúdo para adultos</translation>
<translation id="9078964945751709336">São necessárias mais informações</translation>
-<translation id="9094175695478007090">Não é possível iniciar a aplicação de pagamento.</translation>
<translation id="9103872766612412690">Normalmente, o site <ph name="SITE" /> utiliza a encriptação para proteger as suas informações. Quando o Chromium tentou estabelecer ligação a <ph name="SITE" /> desta vez, o Website devolveu credenciais invulgares e incorretas. Isto pode acontecer quando um utilizador mal intencionado tenta simular ser <ph name="SITE" /> ou quando um ecrã de início de sessão Wi-Fi interrompe a ligação. As suas informações continuam seguras porque o Chromium interrompeu a ligação antes de qualquer troca de dados.</translation>
<translation id="9137013805542155359">Mostrar original</translation>
<translation id="9137248913990643158">Comece e inicie sessão no Chrome antes de utilizar esta aplicação.</translation>
diff --git a/chromium/components/strings/components_strings_ro.xtb b/chromium/components/strings/components_strings_ro.xtb
index 59448dd3daf..f0843816bc1 100644
--- a/chromium/components/strings/components_strings_ro.xtb
+++ b/chromium/components/strings/components_strings_ro.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="ro">
<translation id="1008557486741366299">Nu acum</translation>
<translation id="1015730422737071372">Specifică detalii suplimentare</translation>
+<translation id="1021110881106174305">Carduri acceptate</translation>
<translation id="1032854598605920125">Rotește în sensul acelor de ceasornic</translation>
<translation id="1038842779957582377">nume necunoscut</translation>
<translation id="1050038467049342496">închide celelalte aplicații;</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Ascundeți valoarea</translation>
<translation id="1228893227497259893">Identificator greșit pentru entitate</translation>
<translation id="1232569758102978740">Fără titlu</translation>
+<translation id="1263231323834454256">Lista de lectură</translation>
<translation id="1264126396475825575">Raport de blocare creat <ph name="CRASH_TIME" /> (nu a fost încă încărcat sau ignorat)</translation>
<translation id="1285320974508926690">Nu traduce niciodată acest site</translation>
<translation id="129553762522093515">ÃŽnchise recent</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Setări de completare automată în Chromium...</translation>
<translation id="1374468813861204354">sugestii</translation>
<translation id="1375198122581997741">Despre versiune</translation>
+<translation id="1377321085342047638">Număr card</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> nu a trimis date.</translation>
<translation id="1407135791313364759">Deschideți-le pe toate</translation>
<translation id="1413809658975081374">Eroare legată de confidențialitate</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Istoric</translation>
<translation id="1645368109819982629">Protocol neacceptat</translation>
<translation id="1656489000284462475">Preluare</translation>
+<translation id="1663943134801823270">Cardurile și adresele sunt din Chrome. Le poți gestiona în <ph name="BEGIN_LINK" />Setări<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">Site-ul <ph name="SITE" /> folosește în mod obișnuit criptarea pentru a-ți proteja informațiile. Când Google Chrome a încercat să se conecteze la <ph name="SITE" /> de această dată, site-ul a returnat date de conectare neobișnuite și incorecte. Acest lucru s-a întâmplat fie pentru că un atacator încearcă să falsifice site-ul <ph name="SITE" />, fie pentru că un ecran de conectare Wi-Fi a întrerupt conexiunea. Securitatea informațiilor tale nu a fost afectată, deoarece Google Chrome a oprit conexiunea înainte ca datele să fie transferate.</translation>
<translation id="168328519870909584">Atacatorii de pe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> pot încerca să instaleze aplicații periculoase pe dispozitiv, care să îți fure sau să îți șteargă informațiile (de exemplu, fotografii, parole, mesaje și carduri de credit).</translation>
<translation id="168841957122794586">Certificatul de server conține o cheie criptografică slabă.</translation>
<translation id="1710259589646384581">Sistem de operare</translation>
<translation id="1721312023322545264">Ai nevoie de permisiunea utilizatorului <ph name="NAME" /> ca să accesezi acest site</translation>
+<translation id="1721424275792716183">* Câmp obligatoriu</translation>
<translation id="1728677426644403582">Se afișează sursa unei pagini web</translation>
+<translation id="173080396488393970">Acest tip de card nu este acceptat</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Încearcă să contactezi administratorul sistemului.</translation>
+<translation id="1740951997222943430">Introdu o lună de expirare validă</translation>
<translation id="1745358365027406341">Descarcă pagina mai târziu</translation>
<translation id="17513872634828108">File deschise</translation>
<translation id="1753706481035618306">Numărul paginii</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Actualizează expresia de acces pentru sincronizare.</translation>
<translation id="1787142507584202372">Filele deschise sunt afișate aici</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Selectează o adresă pentru livrare pentru a vedea care sunt metodele și cerințele privind livrarea.</translation>
+<translation id="1803264062614276815">Numele titularului cardului</translation>
<translation id="1803678881841855883">Recent, Navigarea sigură Google <ph name="BEGIN_LINK" />a detectat programe malware<ph name="END_LINK" /> pe <ph name="SITE" />. Site-urile care sunt de obicei sigure sunt uneori infectate cu programe malware. Conținutul rău-intenționat provine de la <ph name="SUBRESOURCE_HOST" />, un distribuitor cunoscut de programe malware. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Adăugat pe <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Solicitarea sau parametrii săi sunt greșiți</translation>
<translation id="1826516787628120939">Se verifică</translation>
<translation id="1834321415901700177">Acest site conține programe dăunătoare</translation>
<translation id="1842969606798536927">Plătiți</translation>
-<translation id="1864455488461349376">Opțiune pentru livrare</translation>
<translation id="1871208020102129563">Configurația proxy este setată să utilizeze servere proxy fixe, și nu o adresă URL pentru scripturi .pac.</translation>
<translation id="1871284979644508959">Câmp obligatoriu</translation>
<translation id="187918866476621466">Deschide paginile de pornire</translation>
<translation id="1883255238294161206">Restrângeți lista</translation>
<translation id="1898423065542865115">Filtrarea</translation>
<translation id="194030505837763158">Accesați <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Carduri acceptate</translation>
<translation id="1962204205936693436">Marcaje <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Eroare de serializare</translation>
<translation id="1974060860693918893">Avansate</translation>
<translation id="1978555033938440688">Versiune de firmware</translation>
+<translation id="1995859865337580572">Confirmă codul CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{și încă una}few{și încă #}other{și încă #}}</translation>
-<translation id="2020194265157481222">Numele de pe card este obligatoriu</translation>
<translation id="2025186561304664664">Proxy-ul este setat la Configurat automat.</translation>
<translation id="2030481566774242610">Ați dorit să scrieți <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />să verifici proxy-ul și firewallul;<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Astăzi</translation>
<translation id="2154054054215849342">Sincronizarea nu este disponibilă pentru domeniul tău</translation>
<translation id="2154484045852737596">Editează cardul</translation>
-<translation id="2156993118928861787">Adresa nu este validă</translation>
<translation id="2166049586286450108">Acces complet de administrare</translation>
<translation id="2166378884831602661">Acest site nu poate oferi o conexiune sigură</translation>
<translation id="2181821976797666341">Politici</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresă}few{# adrese}other{# de adrese}}</translation>
+<translation id="2202020181578195191">Introdu un an de expirare valid</translation>
<translation id="2212735316055980242">Politica nu a fost găsită</translation>
<translation id="2213606439339815911">Se preiau intrările...</translation>
<translation id="2230458221926704099">Remediază conexiunea folosind <ph name="BEGIN_LINK" />aplicația de diagnosticare<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Accesul la internet este blocat</translation>
<translation id="230155334948463882">Card nou?</translation>
<translation id="2305919008529760154">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Este posibil ca certificatul său de securitate să fi fost emis fraudulos. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Opțiunile privind cardul și adresa provin din Contul Google (<ph name="ACCOUNT_EMAIL" />) și din Chrome. Le poți gestiona în <ph name="BEGIN_LINK" />Setări<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> necesită un nume de utilizator și o parolă.</translation>
<translation id="2318774815570432836">Momentan, nu poți accesa site-ul <ph name="SITE" />, deoarece acesta folosește HSTS. Erorile de rețea și atacurile sunt de obicei temporare și probabil că această pagină va funcționa mai târziu. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Alte marcaje</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Setare prestabilită la nivel de companie</translation>
<translation id="2386255080630008482">Certificatul serverului a fost revocat.</translation>
<translation id="2392959068659972793">Afișați politicile care nu au valori setate</translation>
+<translation id="239429038616798445">Această metodă de expediere nu este disponibilă. Încearcă altă metodă.</translation>
<translation id="2396249848217231973">&amp;Anulați ștergerea</translation>
<translation id="2460160116472764928">Recent, Navigarea sigură Google <ph name="BEGIN_LINK" />a detectat programe malware<ph name="END_LINK" /> pe <ph name="SITE" />. Site-urile care sunt de obicei sigure sunt uneori infectate cu programe malware. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Completează</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />să rulezi Diagnostice rețea<ph name="END_LINK" />;</translation>
<translation id="2479410451996844060">Adresă URL de căutare nevalidă.</translation>
<translation id="2491120439723279231">Certificatul serverului conține erori.</translation>
-<translation id="24943777258388405">Număr de telefon nevalid</translation>
<translation id="2495083838625180221">Analizor JSON</translation>
<translation id="2495093607237746763">Dacă opțiunea este bifată, Chromium va stoca o copie a cardului pe dispozitiv pentru a completa formularul mai rapid.</translation>
<translation id="2498091847651709837">Scanează un card nou</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> a trimis un răspuns nevalid.</translation>
<translation id="2552545117464357659">Mai noi</translation>
<translation id="2556876185419854533">&amp;Anulați editarea</translation>
+<translation id="2587730715158995865">De la <ph name="ARTICLE_PUBLISHER" />. Citește acest articol și încă <ph name="OTHER_ARTICLE_COUNT" />.</translation>
<translation id="2587841377698384444">ID-ul API-ului Directory:</translation>
<translation id="2597378329261239068">Acest document este protejat cu parolă. Introdu o parolă.</translation>
<translation id="2609632851001447353">Modificări</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />să rulezi Diagnostice conectivitate<ph name="END_LINK" />;</translation>
<translation id="2740531572673183784">Ok</translation>
<translation id="2742870351467570537">Elimină elementele selectate</translation>
+<translation id="277133753123645258">Metodă de expediere</translation>
<translation id="277499241957683684">Lipsește o înregistrare pentru gadget</translation>
<translation id="2784949926578158345">Conexiunea a fost resetată.</translation>
<translation id="2794233252405721443">Site blocat</translation>
-<translation id="2812680587231492111">Opțiunea respectivă de preluare nu este disponibilă. Încearcă altă opțiune.</translation>
<translation id="2824775600643448204">Bara de adrese și de căutare</translation>
<translation id="2826760142808435982">Conexiunea este criptată și autentificată utilizând <ph name="CIPHER" /> și folosește <ph name="KX" /> ca mecanism de schimb al cheii.</translation>
<translation id="2835170189407361413">Golește formularul</translation>
-<translation id="2849041323157393173">Opțiunea respectivă de livrare nu este disponibilă. Încearcă altă opțiune.</translation>
<translation id="2889159643044928134">Nu reîncărca</translation>
<translation id="2900469785430194048">Google Chrome nu a avut suficientă memorie la afișarea paginii web.</translation>
<translation id="2909946352844186028">A fost detectată o schimbare a rețelei.</translation>
<translation id="2916038427272391327">închide celelalte programe;</translation>
<translation id="2922350208395188000">Certificatul serverului nu poate fi verificat.</translation>
+<translation id="2928905813689894207">Adresă de facturare</translation>
<translation id="2948083400971632585">Puteți să dezactivați serverele proxy configurate pentru o conexiune din pagina de setări.</translation>
<translation id="2955913368246107853">Închide Bara de căutare</translation>
<translation id="2958431318199492670">Configurația rețelei nu respectă standardul ONC. Este posibil ca anumite părți ale configurației să nu fie importate.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Pentru a stabili o conexiune securizată, ceasul trebuie să fie setat corect, 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ă, Google Chrome nu poate verifica aceste certificate.</translation>
<translation id="2972581237482394796">&amp;Repetă</translation>
<translation id="2985306909656435243">Dacă opțiunea este activată, Chromium va stoca o copie a cardului pe dispozitiv pentru a completa formularul mai rapid.</translation>
+<translation id="2985398929374701810">Introdu o adresă validă</translation>
+<translation id="2986368408720340940">Această metodă de preluare nu este disponibilă. Încearcă altă metodă.</translation>
<translation id="2991174974383378012">Permiterea accesului pentru site-uri</translation>
<translation id="3005723025932146533">Afișați o copie salvată</translation>
<translation id="3008447029300691911">Introdu codul CVC pentru <ph name="CREDIT_CARD" />. După ce confirmi, acest site va avea acces la detaliile cardului tău.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{cel puțin un element pe dispozitivele sincronizate}=1{un element (și mai multe pe dispozitivele sincronizate)}few{# elemente (și mai multe pe dispozitivele sincronizate)}other{# de elemente (și mai multe pe dispozitivele sincronizate)}}</translation>
<translation id="3041612393474885105">Informații despre certificat</translation>
<translation id="3063697135517575841">Momentan, Chrome nu a putut confirma cardul. Încearcă din nou mai târziu.</translation>
+<translation id="3064966200440839136">Vei părăsi modul incognito pentru a plăti folosind o aplicație externă. Continui?</translation>
<translation id="3093245981617870298">Ești offline.</translation>
<translation id="3105172416063519923">ID articol:</translation>
<translation id="3109728660330352905">Nu ești autorizat(ă) să vezi această pagină.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Rulează Diagnostice conectivitate<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Răspunsul nu a putut fi decodificat</translation>
-<translation id="3149891296864842641">Opțiune de expediere</translation>
<translation id="3150653042067488994">Eroare temporară de server</translation>
+<translation id="3154506275960390542">Pagina include un formular care este posibil să nu fie trimis în siguranță. Alți utilizatori pot vedea datele trimise în timpul transferului sau acestea ar putea fi modificate de un atacator pentru a schimba conținutul primit de server.</translation>
<translation id="3157931365184549694">Restabilește</translation>
<translation id="3167968892399408617">Paginile pe care le accesezi în filele incognito nu vor fi înregistrate în istoricul browserului, nu vor stoca cookie-uri și nu vor rămâne în istoricul de căutare după ce închizi toate filele incognito. Fișierele descărcate și marcajele create vor fi păstrate.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Solicitarea de a accesa acest site nu a putut fi trimisă la <ph name="NAME" />. Încearcă din nou.</translation>
<translation id="3355823806454867987">Modifica setările proxy...</translation>
<translation id="3369192424181595722">Eroare de ceas</translation>
+<translation id="337311366426640088">Încă <ph name="ITEM_COUNT" /> articole…</translation>
<translation id="337363190475750230">Scos din uz</translation>
<translation id="3377188786107721145">Eroare la analizarea politicii</translation>
<translation id="3380365263193509176">Eroare necunoscută</translation>
<translation id="3380864720620200369">Cod de client:</translation>
<translation id="3391030046425686457">Adresă de livrare</translation>
+<translation id="3395827396354264108">Metodă de preluare</translation>
<translation id="340013220407300675">Atacatorii pot încerca să vă fure informațiile de pe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (de exemplu, parolele, mesajele sau informațiile despre cardurile de credit).</translation>
<translation id="3422248202833853650">Încearcă să ieși din celelalte programe pentru a elibera memoria.</translation>
<translation id="3422472998109090673">Momentan, <ph name="HOST_NAME" /> nu poate fi accesat.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Interval de preluare:</translation>
<translation id="3462200631372590220">Ascundeți detaliile avansate</translation>
+<translation id="3467763166455606212">Este necesar numele titularului cardului</translation>
+<translation id="3478058380795961209">Lună expirare</translation>
<translation id="3479539252931486093">A fost o situație neașteptată? <ph name="BEGIN_LINK" />Anunță-ne<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Nu acum</translation>
<translation id="348000606199325318">ID blocare <ph name="CRASH_LOCAL_ID" /> (ID server: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Momentan, nu ți-am putut contacta părintele. Încearcă din nou.</translation>
<translation id="3528171143076753409">Certificatul serverului nu este de încredere.</translation>
-<translation id="3538531656504267329">Anul de expirare nu este valid</translation>
<translation id="3539171420378717834">Păstrează o copie a cardului pe dispozitiv</translation>
<translation id="3542684924769048008">Folosește parola pentru:</translation>
<translation id="3549644494707163724">Criptați toate datele sincronizate cu parola dvs. de acces pentru sincronizare</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Ascunde detaliile</translation>
<translation id="3587482841069643663">Toate</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Introdu o dată de expirare validă</translation>
<translation id="36224234498066874">Ștergeți datele de navigare...</translation>
<translation id="362276910939193118">Afișează întregul istoric</translation>
<translation id="3623476034248543066">Afișați valoarea</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Parolă:</translation>
<translation id="3696411085566228381">niciuna</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Pentru a vedea care sunt metodele și cerințele privind expedierea, selectează o adresă de expediere.</translation>
<translation id="370665806235115550">Se încarcă…</translation>
<translation id="3712624925041724820">Licențe epuizate</translation>
<translation id="3714780639079136834">să activezi datele mobile sau conexiunea Wi-Fi;</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Linkul copiat de tine</translation>
<translation id="375403751935624634">Traducerea nu a reușit din cauza unei erori de server.</translation>
<translation id="3759461132968374835">Nu există blocări raportate recent. Blocările care au avut loc când raportarea blocărilor era dezactivată nu vor apărea aici.</translation>
+<translation id="3787705759683870569">Expiră în <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Dacă utilizați un server proxy...</translation>
<translation id="3828924085048779000">Trebuie să fie introdusă expresia de acces.</translation>
<translation id="3845539888601087042">Se afișează istoricul de pe dispozitivele pe care te-ai conectat. <ph name="BEGIN_LINK" />Află mai multe<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Dorești ca acest card să fie salvat în Chromium?</translation>
<translation id="4171400957073367226">Semnătură de verificare nevalidă</translation>
-<translation id="4176463684765177261">Dezactivat</translation>
<translation id="4196861286325780578">&amp;Repetați mutarea</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />să verifici configurarea pentru firewall și antivirus;<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{niciuna}=1{1 aplicație ($1)}=2{2 aplicații ($1, $2)}few{# aplicații ($1, $2, $3)}other{# de aplicații ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">rezultate ale căutării</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> nu a acceptat certificatul de conectare sau un astfel de certificat nu a fost oferit.</translation>
<translation id="443673843213245140">Utilizarea unui proxy este dezactivată, dar o configurare proxy este specificată în mod explicit.</translation>
-<translation id="4446242550670694251">Acum poți naviga în mod privat, iar celelalte persoane care folosesc acest dispozitiv nu îți vor vedea activitatea.</translation>
<translation id="4492190037599258964">Rezultatele căutării pentru „<ph name="SEARCH_STRING" />â€</translation>
<translation id="4506176782989081258">Eroare de validare: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">să contactezi administratorul sistemului;</translation>
<translation id="450710068430902550">Permiterea accesului pentru administrator</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="4522570452068850558">Detalii</translation>
<translation id="4558551763791394412">Dezactivează extensiile.</translation>
<translation id="457875822857220463">Livrare</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Încadrați în pagină</translation>
<translation id="483020001682031208">Nu există pagini din Webul material de afișat</translation>
<translation id="4850886885716139402">Afișează</translation>
+<translation id="4854362297993841467">Această metodă de livrare nu este disponibilă. Încearcă altă metodă.</translation>
<translation id="4858792381671956233">Ți-ai întrebat părinții dacă poți accesa acest site</translation>
<translation id="4880827082731008257">Caută în istoric</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Această pagină a fost tradusă dintr-o limbă necunoscută în <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Plată</translation>
<translation id="4926049483395192435">Valoarea trebuie specificată.</translation>
-<translation id="4941291666397027948">* indică un câmp obligatoriu</translation>
<translation id="495170559598752135">Acțiuni</translation>
<translation id="4958444002117714549">Extindeți lista</translation>
<translation id="4962322354953122629">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Chrome nu consideră că certificatul său de securitate este de încredere. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Parolă incorectă</translation>
<translation id="5056549851600133418">Articole pentru tine</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />să verifici adresa proxy-ului;<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Niciun cookie}=1{1 site folosește cookie-uri. }few{# site-uri folosesc cookie-uri. }other{# de site-uri folosesc cookie-uri. }}</translation>
<translation id="5087286274860437796">Momentan, certificatul serverului este nevalid.</translation>
<translation id="5087580092889165836">Adaugă un card</translation>
<translation id="5089810972385038852">Stat</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Afișează</translation>
<translation id="5308689395849655368">Raportarea blocărilor este dezactivată.</translation>
<translation id="5317780077021120954">Salvează</translation>
-<translation id="5326702247179446998">Destinatarul este obligatoriu</translation>
<translation id="5327248766486351172">Nume</translation>
<translation id="5337705430875057403">Atacatorii de pe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> te pot înșela, determinându-te să faci ceva periculos, cum ar fi să instalezi software sau să îți dezvălui informațiile personale (de exemplu, parole, numere de telefon sau carduri de credit).</translation>
-<translation id="53553865750799677">Adresa de preluare nu este acceptată. Selectează o altă adresă.</translation>
<translation id="5359637492792381994">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Momentan, certificatul său de securitate nu este valid. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Setările pentru politică nu au putut fi stocate</translation>
<translation id="5386426401304769735">Lanțul de certificate pentru acest site conține un certificat semnat folosind SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">O pagină încorporată de pe <ph name="SITE" /> afișează mesajul:</translation>
<translation id="5556459405103347317">Reîncarcă</translation>
<translation id="5565735124758917034">Activ</translation>
+<translation id="5571083550517324815">Nu se poate prelua de la această adresă. Selectează altă adresă.</translation>
<translation id="5572851009514199876">Pornește și conectează-te la Chrome, ca acesta să verifice dacă ai permisiunea să accesezi site-ul.</translation>
-<translation id="5575380383496039204">Adresa de livrare nu este acceptată. Selectează o altă adresă.</translation>
<translation id="5580958916614886209">Verifică luna în care expiră și încearcă din nou</translation>
<translation id="560412284261940334">Gestionarea nu este acceptată</translation>
<translation id="5610142619324316209">să verifici conexiunea;</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">Identitatea acestui site nu a fost confirmată.</translation>
<translation id="5720705177508910913">Utilizator curent</translation>
<translation id="5732392974455271431">Părinții tăi îl pot debloca pentru tine</translation>
-<translation id="57586589942790530">Numărul cardului nu este valid</translation>
+<translation id="5763042198335101085">Introdu o adresă de e-mail validă</translation>
+<translation id="5765072501007116331">Pentru a vedea metodele de livrare și cerințele, selectează o adresă</translation>
<translation id="5784606427469807560">A apărut o eroare la confirmarea cardului. Verifică conexiunea la internet și încearcă din nou.</translation>
<translation id="5785756445106461925">În plus, această pagină include alte resurse care nu sunt securizate. Aceste resurse sunt vizibile pentru alți utilizatori în cursul transferului și pot fi modificate de un atacator pentru a schimba aspectul paginii.</translation>
<translation id="5786044859038896871">Dorești să completezi datele cardului de credit?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">Acest site nu poate fi accesat</translation>
<translation id="5869522115854928033">Parole salvate</translation>
<translation id="5872918882028971132">Sugestii parentale</translation>
-<translation id="587760065310675640">Adresa de expediere nu este acceptată. Selectează o altă adresă.</translation>
<translation id="5901630391730855834">Galben</translation>
-<translation id="59174027418879706">Activat</translation>
<translation id="5926846154125914413">Este posibil să pierzi accesul la conținutul premium de pe anumite site-uri.</translation>
<translation id="5959728338436674663">Trimite automat anumite <ph name="BEGIN_WHITEPAPER_LINK" />informații despre sistem și conținutul paginii<ph name="END_WHITEPAPER_LINK" /> la Google pentru a detecta aplicațiile și site-urile periculoase. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Săptămână</translation>
<translation id="5967867314010545767">Eliminați din istoric</translation>
<translation id="5975083100439434680">Micșorează</translation>
+<translation id="598637245381783098">Nu se poate deschide aplicația de plată</translation>
<translation id="5989320800837274978">Nu sunt specificate nici servere proxy fixe și nici o adresă URL pentru scripturi .pac.</translation>
<translation id="5990559369517809815">Solicitările trimise la server au fost blocate de o extensie.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Opțiunile privind cardul și adresa provin din Chrome. Le poți gestiona în <ph name="BEGIN_LINK" />Setări<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Pagina 1}few{Pagina #}other{Pagina #}}</translation>
<translation id="6017514345406065928">Verde</translation>
+<translation id="6027201098523975773">Introdu un nume</translation>
<translation id="6040143037577758943">ÃŽnchide</translation>
-<translation id="604124094241169006">Automat</translation>
<translation id="6042308850641462728">Mai multe</translation>
<translation id="6060685159320643512">Atenție, aceste experimente pot produce daune</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{niciuna}=1{1}few{#}other{#}}</translation>
@@ -543,9 +552,10 @@
dispozitive de rețea pe care le folosești.</translation>
<translation id="614940544461990577">Încearcă:</translation>
<translation id="6151417162996330722">Certificatul de server are o perioadă de validitate prea lungă.</translation>
-<translation id="615643356032862689">Se vor păstra fișierele descărcate și marcajele.</translation>
+<translation id="6157877588268064908">Pentru a vedea metodele de expediere și cerințele, selectează o adresă</translation>
<translation id="6165508094623778733">Află mai multe</translation>
<translation id="6177128806592000436">Conexiunea la acest site nu este sigură</translation>
+<translation id="6184817833369986695">(grup: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Verificați conexiunea la internet</translation>
<translation id="6218753634732582820">Elimini adresa din Chromium?</translation>
<translation id="6251924700383757765">Politica de confidențialitate</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Repetați reordonarea</translation>
<translation id="6263376278284652872">Marcaje <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Înapoi la zona sigură</translation>
+<translation id="6276112860590028508">Paginile din lista de lectură sunt afișate aici</translation>
+<translation id="6280223929691119688">Nu se poate livra la această adresă. Selectează altă adresă.</translation>
<translation id="6282194474023008486">Cod poștal</translation>
<translation id="6290238015253830360">Articolele sugerate apar aici</translation>
<translation id="6305205051461490394">Adresa URL <ph name="URL" /> nu poate fi accesată.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Nu se poate verifica dacă certificatul a fost revocat.</translation>
<translation id="6433490469411711332">Editează informațiile de contact</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> a refuzat conexiunea.</translation>
-<translation id="6443118737398455446">Dată de expirare nevalidă</translation>
<translation id="6446608382365791566">Adaugă mai multe informații</translation>
<translation id="6451458296329894277">Confirmă retrimiterea formularului</translation>
<translation id="6456339708790392414">Plata</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Este posibil ca certificatul său de securitate să fi fost revocat. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Politici privind dispozitivele</translation>
<translation id="6477321094435799029">Chrome a detectat un cod neobișnuit pe această pagină și l-a blocat pentru a-ți proteja informațiile cu caracter personal (de exemplu, parole, numere de telefon sau carduri de credit).</translation>
-<translation id="6477460825583319731">Adresă de e-mail nevalidă</translation>
<translation id="6489534406876378309">Începeți încărcarea rapoartelor de blocare</translation>
<translation id="6508722015517270189">repornește Chrome;</translation>
-<translation id="6525462735697194615">Luna de expirare nu este validă</translation>
<translation id="6529602333819889595">&amp;Repetați ștergerea</translation>
<translation id="6534179046333460208">Sugestii pentru Webul material</translation>
<translation id="6550675742724504774">Opțiuni</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685">Căutare <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Această politică este învechită.</translation>
<translation id="6652240803263749613">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 eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Opțiunea respectivă de expediere nu este disponibilă. Încearcă altă opțiune.</translation>
<translation id="6671697161687535275">Elimini sugestia pentru formular din Chromium?</translation>
<translation id="6685834062052613830">Deconectează-te și finalizează configurarea</translation>
<translation id="6710213216561001401">ÃŽnapoi</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">A apărut o problemă la serverul proxy sau adresa nu este corectă.</translation>
<translation id="6727102863431372879">Setează</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{niciuna}=1{1 element}few{# elemente}other{# de elemente}}</translation>
-<translation id="6743044928064272573">Opțiune de preluare</translation>
<translation id="674375294223700098">Eroare de certificat de server necunoscută.</translation>
<translation id="6753269504797312559">Valoarea politicii</translation>
<translation id="6757797048963528358">Dispozitivul este inactiv.</translation>
<translation id="6778737459546443941">Părintele tău nu l-a aprobat încă</translation>
<translation id="6810899417690483278">ID-ul de personalizare</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Datele regiunii nu au fost încărcate</translation>
<translation id="6831043979455480757">Tradu</translation>
<translation id="6839929833149231406">Zonă</translation>
<translation id="6874604403660855544">&amp;Repetați adăugarea</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Cardul tău este confirmat</translation>
<translation id="6897140037006041989">User Agent</translation>
<translation id="6915804003454593391">Utilizator:</translation>
+<translation id="6948701128805548767">Pentru a vedea metodele de preluare și cerințele, selectează o adresă</translation>
<translation id="6957887021205513506">Certificatul serverului pare a fi un fals.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Dispozitiv</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">Sunt specificate atât servere proxy fixe, cât și o adresă URL pentru scripturi .pac.</translation>
<translation id="6989763994942163495">Afișează setările avansate...</translation>
<translation id="7000990526846637657">Nu s-au găsit intrări în istoric</translation>
-<translation id="7001663382399377034">Adaugă un destinatar</translation>
<translation id="7009986207543992532">Ai încercat să accesezi <ph name="DOMAIN" />, dar serverul a prezentat un certificat a cărui perioadă de valabilitate este prea mare pentru a fi de încredere. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Contul Google poate să ofere alte forme ale istoricului de navigare la <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Mai vechi</translation>
<translation id="7090678807593890770">Caută <ph name="LINK" /> pe Google</translation>
<translation id="7119414471315195487">închide celelalte file sau programe;</translation>
+<translation id="7129409597930077180">Nu se poate expedia la această adresă. Selectează altă adresă.</translation>
+<translation id="7138472120740807366">Metodă de livrare</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7155487117670177674">Plata nu este securizată</translation>
<translation id="7179921470347911571">Relansează acum</translation>
<translation id="7180611975245234373">Actualizați</translation>
<translation id="7182878459783632708">Nu au fost setate politici</translation>
<translation id="7186367841673660872">Această pagină a fost tradusă din <ph name="ORIGINAL_LANGUAGE" /> în <ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> nu respectă standardele de securitate.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Află mai multe<ph name="END_LINK" /> despre această problemă.</translation>
@@ -675,7 +686,6 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="7424977062513257142">O pagină încorporată de pe această pagină web afișează mesajul:</translation>
<translation id="7441627299479586546">Subiectul politicii este greșit</translation>
<translation id="7444046173054089907">Acest site este blocat</translation>
-<translation id="7444238235002594607">Pentru a vedea care sunt metodele și cerințele privind preluarea, selectează o adresă de preluare.</translation>
<translation id="7445762425076701745">Identitatea serverului la care te-ai conectat nu poate fi validată complet. Ești conectat(ă) la un server folosind un nume valid numai în rețeaua ta, pentru care o autoritate de certificare externă nu are nici o modalitate de a-l valida. Deoarece unele autorități de certificare vor emite certificate pentru aceste nume oricum, nu există nicio modalitate de a te asigura că ești conectat(ă) la site-ul corect și nu la un atacator.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />să afli mai multe<ph name="END_LINK" /> despre această problemă.</translation>
<translation id="7460163899615895653">Filele recente de pe alte dispozitive sunt afișate aici</translation>
@@ -719,6 +729,7 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="7755287808199759310">Părintele tău îl poate debloca pentru tine</translation>
<translation id="7758069387465995638">Este posibil ca firewallul sau software-ul antivirus să fi blocat conexiunea.</translation>
<translation id="7761701407923456692">Certificatul serverului nu se potrivește cu adresa URL.</translation>
+<translation id="7763386264682878361">Parser pentru manifestul plății</translation>
<translation id="7764225426217299476">Adaugă o adresă</translation>
<translation id="777702478322588152">Prefectură</translation>
<translation id="7791543448312431591">Adaugă</translation>
@@ -732,6 +743,7 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="785549533363645510">Cu toate acestea, nu ești invizibil(ă). Trecerea în modul incognito nu ascunde activitatea de navigare față de angajator, față de furnizorul de servicii de internet sau față de site-urile pe care le accesezi.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Verifică codul CVC și încearcă din nou</translation>
+<translation id="79338296614623784">Introdu un număr de telefon valid</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Certificatul serverului nu este încă valid.</translation>
<translation id="7942349550061667556">Roșu</translation>
@@ -751,6 +763,7 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="8088680233425245692">Articolul nu a fost vizualizat.</translation>
<translation id="8089520772729574115">mai puțin de 1 MB</translation>
<translation id="8091372947890762290">Se așteaptă activarea pe server</translation>
+<translation id="8118489163946903409">Metodă de plată</translation>
<translation id="8131740175452115882">Confirmați</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Adresa DNS<ph name="END_ABBR" /> pentru serverul <ph name="HOST_NAME" /> nu a putut fi găsită.</translation>
<translation id="8149426793427495338">Computerul este inactiv.</translation>
@@ -776,6 +789,7 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="8349305172487531364">Bara de marcaje</translation>
<translation id="8363502534493474904">să dezactivezi modul Avion.</translation>
<translation id="8364627913115013041">Nesetată.</translation>
+<translation id="8368476060205742148">Servicii Google Play</translation>
<translation id="8380941800586852976">Periculos</translation>
<translation id="8382348898565613901">Marcajele accesate recent apar aici</translation>
<translation id="8398259832188219207">Raport de blocare încărcat <ph name="UPLOAD_TIME" /></translation>
@@ -784,32 +798,30 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="8428213095426709021">Setări</translation>
<translation id="8433057134996913067">Astfel, te vei deconecta de pe majoritatea site-urilor.</translation>
<translation id="8437238597147034694">&amp;Anulați mutarea</translation>
-<translation id="8456681095658380701">Nume nevalid</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 card de credit}few{# carduri de credit}other{# de carduri de credit}}</translation>
<translation id="8483780878231876732">Pentru a folosi cardurile din Contul Google, conectează-te la Chrome</translation>
<translation id="8488350697529856933">Se aplică pentru</translation>
-<translation id="8492969205326575646">Tip de card neacceptat</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> a răspuns prea târziu.</translation>
<translation id="852346902619691059">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Sistemul de operare al dispozitivului nu consideră că certificatul său de securitate este de încredere. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">An expirare</translation>
<translation id="8543181531796978784">Poți să <ph name="BEGIN_ERROR_LINK" />raportezi o problemă privind detectarea<ph name="END_ERROR_LINK" /> sau, dacă îți asumi riscurile de securitate, poți să <ph name="BEGIN_LINK" />accesezi acest site nesigur<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Traducerea nu a reușit, deoarece nu a putut fi stabilită limba paginii.</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="8570229484593575558">Aceste informații |nu vor fi salvate|:#istoricul de navigare;#căutările;#datele asociate cookie-urilor.</translation>
<translation id="8571890674111243710">Se traduce pagina în <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">|Este posibil ca activitatea ta| să fie vizibilă pentru:#site-urile pe care le accesezi;#angajator;#furnizorul de servicii de internet.</translation>
<translation id="858637041960032120">Adăugați telefon
</translation>
<translation id="859285277496340001">Certificatul nu specifică un mecanism pentru a verifica dacă acesta a fost revocat.</translation>
<translation id="8620436878122366504">Părinții tăi nu l-au aprobat încă</translation>
<translation id="8647750283161643317">Resetați-le pe toate la valorile prestabilite</translation>
<translation id="8703575177326907206">Conexiunea la <ph name="DOMAIN" /> nu este criptată.</translation>
+<translation id="8718314106902482036">Plata nu a fost finalizată</translation>
<translation id="8725066075913043281">Încearcă din nou</translation>
<translation id="8728672262656704056">Ați trecut în modul incognito</translation>
<translation id="8730621377337864115">Terminat</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="8759274551635299824">Acest card este expirat</translation>
<translation id="8790007591277257123">&amp;Repetați ștergerea</translation>
-<translation id="8798099450830957504">Prestabilit</translation>
<translation id="8800988563907321413">Sugestiile pentru În apropiere sunt afișate aici</translation>
<translation id="8820817407110198400">Marcaje</translation>
<translation id="883848425547221593">Alte marcaje</translation>
@@ -819,6 +831,7 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="8866481888320382733">Eroare la analizarea setărilor pentru politică</translation>
<translation id="8866959479196209191">Această pagină afișează mesajul:</translation>
<translation id="8870413625673593573">ÃŽnchise recent</translation>
+<translation id="8874824191258364635">Introdu un număr de card valid</translation>
<translation id="8876793034577346603">Configurația rețelei nu a putut fi analizată.</translation>
<translation id="8877192140621905067">După ce confirmi, acest site va avea acces la detaliile cardului tău</translation>
<translation id="8889402386540077796">Nuanță</translation>
@@ -828,7 +841,6 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="8931333241327730545">Dorești să salvezi acest card în Contul Google?</translation>
<translation id="8932102934695377596">Ora este setată în trecut</translation>
<translation id="8954894007019320973">(Continuare)</translation>
-<translation id="895548565263634352">Citește articole de la <ph name="ARTICLE_PUBLISHER" /> și încă <ph name="OTHER_ARTICLE_COUNT" /></translation>
<translation id="8971063699422889582">Certificatul serverului a expirat.</translation>
<translation id="8986494364107987395">Trimite automat la Google statistici de utilizare și rapoarte de blocare</translation>
<translation id="8987927404178983737">Lună</translation>
@@ -846,7 +858,6 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="9068849894565669697">Selectați culoarea</translation>
<translation id="9076283476770535406">Poate include conținut destinat adulților</translation>
<translation id="9078964945751709336">Sunt necesare mai multe informații</translation>
-<translation id="9094175695478007090">Nu se poate lansa aplicația de plată.</translation>
<translation id="9103872766612412690">Site-ul <ph name="SITE" /> folosește în mod obișnuit criptarea pentru a-ți proteja informațiile. Când Chromium a încercat să se conecteze la <ph name="SITE" /> de această dată, site-ul a returnat date de conectare neobișnuite și incorecte. Acest lucru s-a întâmplat fie pentru că un atacator încearcă să falsifice site-ul <ph name="SITE" />, fie pentru că un ecran de conectare Wi-Fi a întrerupt conexiunea. Securitatea informațiilor tale nu a fost afectată, deoarece Chromium a oprit conexiunea înainte ca datele să fie transferate.</translation>
<translation id="9137013805542155359">Afișează originalul</translation>
<translation id="9137248913990643158">Pornește și conectează-te la Chrome înainte de a folosi această aplicație.</translation>
diff --git a/chromium/components/strings/components_strings_ru.xtb b/chromium/components/strings/components_strings_ru.xtb
index 33ef469a628..8afc29de8fb 100644
--- a/chromium/components/strings/components_strings_ru.xtb
+++ b/chromium/components/strings/components_strings_ru.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="ru">
<translation id="1008557486741366299">Ðе ÑейчаÑ</translation>
<translation id="1015730422737071372">Сообщить дополнительную информацию</translation>
+<translation id="1021110881106174305">Карты, которые принимаютÑÑ Ðº оплате</translation>
<translation id="1032854598605920125">Повернуть по чаÑовой Ñтрелке</translation>
<translation id="1038842779957582377">неизвеÑтное имÑ</translation>
<translation id="1050038467049342496">Закройте другие приложениÑ.</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Скрыть значение</translation>
<translation id="1228893227497259893">Ðеверный идентификатор объекта</translation>
<translation id="1232569758102978740">Без имени</translation>
+<translation id="1263231323834454256">СпиÑок Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" />: получен отчет о Ñбое (ещё не загружен или не отклонен)</translation>
<translation id="1285320974508926690">Ðикогда не переводить Ñтот Ñайт</translation>
<translation id="129553762522093515">Ðедавно закрытые</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">ÐаÑтройки Ð°Ð²Ñ‚Ð¾Ð·Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð² Chromium...</translation>
<translation id="1374468813861204354">подÑказки</translation>
<translation id="1375198122581997741">Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ верÑии</translation>
+<translation id="1377321085342047638">Ðомер карты</translation>
<translation id="139305205187523129">Сайт <ph name="HOST_NAME" /> не отправил данных.</translation>
<translation id="1407135791313364759">Открыть вÑе</translation>
<translation id="1413809658975081374">Ошибка Ð½Ð°Ñ€ÑƒÑˆÐµÐ½Ð¸Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð´ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ð¾Ñти</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">ИÑториÑ</translation>
<translation id="1645368109819982629">Ðеподдерживаемый протокол</translation>
<translation id="1656489000284462475">Получение</translation>
+<translation id="1663943134801823270">Карты и адреÑа, указанные в Chrome. Ð’Ñ‹ можете изменить их на Ñтранице <ph name="BEGIN_LINK" />ÐаÑтройки<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">Ðа Ñайте <ph name="SITE" /> Ð´Ð»Ñ Ð·Ð°Ñ‰Ð¸Ñ‚Ñ‹ ваших данных обычно иÑпользуетÑÑ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ðµ. Однако учетные данные, которые мы получили от Ñайта <ph name="SITE" /> ÑейчаÑ, отличаютÑÑ Ð¾Ñ‚ тех, которые он отправлÑет обычно. ВероÑтно, вредоноÑный Ñайт пытаетÑÑ Ð²Ñ‹Ð´Ð°Ñ‚ÑŒ ÑÐµÐ±Ñ Ð·Ð° <ph name="SITE" />, либо Ñтраница Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº Ñети Wi-Fi прервала Ñоединение. Ваша Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ð¾-прежнему в безопаÑноÑти, так как браузер Google Chrome разорвал Ñоединение до того, как произошел обмен данными.</translation>
<translation id="168328519870909584">Через Ñайт <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> на ваш компьютер могут уÑтановить вредоноÑное ПО Ð´Ð»Ñ ÐºÑ€Ð°Ð¶Ð¸ или ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð»Ð¸Ñ‡Ð½Ð¾Ð¹ информации (например, фотографий, паролей, Ñообщений и реквизитов банковÑких карт).</translation>
<translation id="168841957122794586">Сертификат Ñервера Ñодержит ненадежный криптографичеÑкий ключ.</translation>
<translation id="1710259589646384581">ОС</translation>
<translation id="1721312023322545264">Ð”Ð»Ñ Ð´Ð¾Ñтупа к Ñтой Ñтранице требуетÑÑ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ðµ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ <ph name="NAME" /></translation>
+<translation id="1721424275792716183">*ОбÑзательное поле</translation>
<translation id="1728677426644403582">Ð’Ñ‹ проÑматриваете код Ñтраницы</translation>
+<translation id="173080396488393970">Этот тип карты не поддерживаетÑÑ.</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">ОбратитеÑÑŒ за помощью к ÑиÑтемному админиÑтратору.</translation>
+<translation id="1740951997222943430">ÐедопуÑтимый формат меÑÑца.</translation>
<translation id="1745358365027406341">Скачать позже</translation>
<translation id="17513872634828108">Открытые вкладки</translation>
<translation id="1753706481035618306">Ðомер Ñтраницы</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Обновите кодовую фразу Ð´Ð»Ñ Ñинхронизации.</translation>
<translation id="1787142507584202372">ЗдеÑÑŒ поÑвÑÑ‚ÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ðµ вкладки.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Чтобы узнать ÑпоÑобы доÑтавки и требованиÑ, выберите Ð°Ð´Ñ€ÐµÑ Ð´Ð¾Ñтавки.</translation>
+<translation id="1803264062614276815">Владелец карты</translation>
<translation id="1803678881841855883">СиÑтема Google по проверке безопаÑноÑти недавно обнаружила на Ñайте <ph name="SITE" /> <ph name="BEGIN_LINK" />вредоноÑное ПО<ph name="END_LINK" />. Его иÑточник, <ph name="SUBRESOURCE_HOST" />, не раз замечен в раÑпроÑтранении вируÑов. Будьте внимательны: иногда даже на надежных Ñайтах поÑвлÑÑŽÑ‚ÑÑ Ð²Ð¸Ñ€ÑƒÑÑ‹. <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1806541873155184440">Добавлена <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">ÐедопуÑтимый Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð¸Ð»Ð¸ неверные параметры запроÑа</translation>
<translation id="1826516787628120939">Проверка</translation>
<translation id="1834321415901700177">Сайт Ñодержит вредоноÑное ПО</translation>
<translation id="1842969606798536927">Оплатить</translation>
-<translation id="1864455488461349376">СпоÑоб доÑтавки</translation>
<translation id="1871208020102129563">Выбрано иÑпользование фикÑированных прокÑи-Ñерверов, а не URL PAC-Ñкрипта.</translation>
<translation id="1871284979644508959">Поле, обÑзательное Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ</translation>
<translation id="187918866476621466">Открыть Ñтартовые Ñтраницы</translation>
<translation id="1883255238294161206">Свернуть ÑпиÑок</translation>
<translation id="1898423065542865115">Фильтры</translation>
<translation id="194030505837763158">Перейдите по ÑÑылке: <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Поддерживаемые типы карт</translation>
<translation id="1962204205936693436">Закладки <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Ðе удалоÑÑŒ выполнить Ñериализацию</translation>
<translation id="1974060860693918893">Дополнительные</translation>
<translation id="1978555033938440688">ВерÑÐ¸Ñ ÐŸÐž</translation>
+<translation id="1995859865337580572">Подтвердите CVC-код</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{и ещё 1}one{и ещё #}few{и ещё #}many{и ещё #}other{и ещё #}}</translation>
-<translation id="2020194265157481222">Ðеобходимо указать Ð¸Ð¼Ñ Ð²Ð»Ð°Ð´ÐµÐ»ÑŒÑ†Ð° карты</translation>
<translation id="2025186561304664664">ПрокÑи-Ñервер наÑтраиваетÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑки.</translation>
<translation id="2030481566774242610">Возможно, вы имели в виду <ph name="LINK" />.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Проверьте наÑтройки прокÑи-Ñервера и брандмауÑра<ph name="END_LINK" />.</translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">СегоднÑ</translation>
<translation id="2154054054215849342">Ð’ вашем домене ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½ÐµÐ´Ð¾Ñтупна</translation>
<translation id="2154484045852737596">Изменение данных карты</translation>
-<translation id="2156993118928861787">ÐедопуÑтимый адреÑ</translation>
<translation id="2166049586286450108">ДоÑтуп админиÑтратора ко вÑем данным</translation>
<translation id="2166378884831602661">Этот Ñайт не может обеÑпечить безопаÑное Ñоединение</translation>
<translation id="2181821976797666341">Правила</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 адреÑ}one{# адреÑ}few{# адреÑа}many{# адреÑов}other{# адреÑа}}</translation>
+<translation id="2202020181578195191">ÐедопуÑтимый формат года.</translation>
<translation id="2212735316055980242">Политика Ð´Ð»Ñ ÑƒÑтройÑтва не найдена</translation>
<translation id="2213606439339815911">Извлечение запиÑей…</translation>
<translation id="2230458221926704099">Чтобы уÑтранить неполадки, проведите <ph name="BEGIN_LINK" />диагноÑтику<ph name="END_LINK" /> подключениÑ.</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">ДоÑтуп в Интернет закрыт</translation>
<translation id="230155334948463882">Добавить карту?</translation>
<translation id="2305919008529760154">Сервер не может подтвердить ÑвÑзь Ñ Ð´Ð¾Ð¼ÐµÐ½Ð¾Ð¼Â <ph name="DOMAIN" />. Его Ñертификат безопаÑноÑти мог быть выпущен мошенниками. Проблема также может быть ÑвÑзана Ñ Ð½Ð°Ñтройками Ñервера или дейÑтвиÑми злоумышленников, которые пытаютÑÑ Ð¿ÐµÑ€ÐµÑ…Ð²Ð°Ñ‚Ð¸Ñ‚ÑŒ Ñоединение. <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="230697611605700222">Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ карте и адреÑе получены из вашего аккаунта Google (<ph name="ACCOUNT_EMAIL" />) и браузера Chrome. Их можно изменить в <ph name="BEGIN_LINK" />наÑтройках<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535">Ð”Ð»Ñ Ð´Ð¾Ñтупа к домену <ph name="DOMAIN" /> необходимо указать Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ пароль.</translation>
<translation id="2318774815570432836">Соединение Ñ Ð²ÐµÐ±-Ñайтом <ph name="SITE" />, иÑпользующим механизм HSTS, могло быть Ñкомпрометировано, поÑтому его Ð½ÐµÐ»ÑŒÐ·Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ в наÑтоÑщий момент. Проблема также может быть ÑвÑзана Ñ Ð½Ð°Ñтройками Ñервера или дейÑтвиÑми злоумышленников. Скорее вÑего, Ñайт заработает через некоторое времÑ. <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2354001756790975382">Другие закладки</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Ð”Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¿Ñ€Ð¸Ñтий (по умолчанию)</translation>
<translation id="2386255080630008482">Сертификат Ñервера отозван.</translation>
<translation id="2392959068659972793">Показывать правила, Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ñ… не заданы</translation>
+<translation id="239429038616798445">Этот ÑпоÑоб доÑтавки недоÑтупен. Выберите другой.</translation>
<translation id="2396249848217231973">&amp;Отменить удаление</translation>
<translation id="2460160116472764928">СиÑтема Google по проверке безопаÑноÑти недавно обнаружила на Ñайте <ph name="SITE" /> <ph name="BEGIN_LINK" />вредоноÑное ПО<ph name="END_LINK" />. Будьте внимательны: иногда даже на надежных Ñайтах поÑвлÑÑŽÑ‚ÑÑ Ð²Ð¸Ñ€ÑƒÑÑ‹. <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2463739503403862330">Заполнить</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Выполните диагноÑтику Ñети<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">ÐедейÑтвительный URL поиÑковой ÑиÑтемы.</translation>
<translation id="2491120439723279231">Сертификат Ñервера Ñодержит ошибки.</translation>
-<translation id="24943777258388405">Ðеверный номер телефона</translation>
<translation id="2495083838625180221">СинтакÑичеÑкий анализатор JSON</translation>
<translation id="2495093607237746763">ЕÑли флажок уÑтановлен, Chromium будет хранить на Ñтом уÑтройÑтве данные карты Ð´Ð»Ñ Ð±Ñ‹Ñтрого Ð·Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ñ„Ð¾Ñ€Ð¼.</translation>
<translation id="2498091847651709837">Сканировать новую карту</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027">Сайт <ph name="HOST_NAME" /> отправил недейÑтвительный ответ.</translation>
<translation id="2552545117464357659">Позже</translation>
<translation id="2556876185419854533">&amp;Отменить изменениÑ</translation>
+<translation id="2587730715158995865">ИÑточник: <ph name="ARTICLE_PUBLISHER" />. ДоÑтупно ещё неÑколько Ñтатей (<ph name="OTHER_ARTICLE_COUNT" />).</translation>
<translation id="2587841377698384444">Идентификатор Directory API:</translation>
<translation id="2597378329261239068">Документ защищен паролем. Введите пароль.</translation>
<translation id="2609632851001447353">Варианты</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Выполните диагноÑтику подключениÑ<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">ОК</translation>
<translation id="2742870351467570537">Удалить выбранные Ñлементы</translation>
+<translation id="277133753123645258">СпоÑоб доÑтавки</translation>
<translation id="277499241957683684">УÑтройÑтво не зарегиÑтрировано</translation>
<translation id="2784949926578158345">Соединение Ñброшено.</translation>
<translation id="2794233252405721443">Сайт заблокирован</translation>
-<translation id="2812680587231492111">Этот ÑпоÑоб выдачи недоÑтупен. Выберите другой.</translation>
<translation id="2824775600643448204">ÐдреÑÐ½Ð°Ñ Ñтрока и Ñтрока поиÑка</translation>
<translation id="2826760142808435982">Соединение зашифровано и проверено Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ <ph name="CIPHER" />. Ð’ качеÑтве механизма обмена ключами иÑпользуетÑÑ <ph name="KX" />.</translation>
<translation id="2835170189407361413">ОчиÑтить форму</translation>
-<translation id="2849041323157393173">Этот ÑпоÑоб доÑтавки недоÑтупен. Выберите другой.</translation>
<translation id="2889159643044928134">Ðе обновлÑÑ‚ÑŒ</translation>
<translation id="2900469785430194048">Chrome не хватает памÑти Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ð° Ñтой Ñтраницы.</translation>
<translation id="2909946352844186028">Похоже, вы подключилиÑÑŒ к другой Ñети.</translation>
<translation id="2916038427272391327">Закройте другие программы.</translation>
<translation id="2922350208395188000">Ðе удаетÑÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€Ð¸Ñ‚ÑŒ Ñертификат Ñервера.</translation>
+<translation id="2928905813689894207">Платежный адреÑ</translation>
<translation id="2948083400971632585">ПрокÑи-Ñерверы, иÑпользуемые Ð´Ð»Ñ ÑоединениÑ, можно отключить на Ñтранице наÑтроек.</translation>
<translation id="2955913368246107853">Закрыть панель поиÑка</translation>
<translation id="2958431318199492670">Ðекоторые Ñлементы Ñетевой конфигурации невозможно импортировать, поÑкольку она не ÑоответÑтвует Ñтандарту ONC.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Ð”Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð±ÐµÐ·Ð¾Ð¿Ð°Ñного Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð½ÐµÐ¾Ð±Ñ…Ð¾Ð´Ð¸Ð¼Ð¾, чтобы Ð¿Ð¾ÐºÐ°Ð·Ð°Ð½Ð¸Ñ ÑиÑтемных чаÑов были верны. Причина в том, что Ñертификаты Ð´Ð»Ñ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ð¸ Ñайтов имеют ограниченный Ñрок дейÑтвиÑ. ЕÑли чаÑÑ‹ на уÑтройÑтве неточны, Chrome не может проверить актуальноÑÑ‚ÑŒ Ñтих Ñертификатов.</translation>
<translation id="2972581237482394796">&amp;Повторить</translation>
<translation id="2985306909656435243">ЕÑли Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð°, Chromium будет хранить на Ñтом уÑтройÑтве данные карты Ð´Ð»Ñ Ð±Ñ‹Ñтрого Ð·Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ñ„Ð¾Ñ€Ð¼.</translation>
+<translation id="2985398929374701810">Укажите дейÑтвительный адреÑ.</translation>
+<translation id="2986368408720340940">Этот ÑпоÑоб выдачи недоÑтупен. Выберите другой.</translation>
<translation id="2991174974383378012">ДоÑтуп веб-Ñайтов</translation>
<translation id="3005723025932146533">Открыть Ñохраненную копию</translation>
<translation id="3008447029300691911">Введите CVC-код карты <ph name="CREDIT_CARD" />. ПоÑле Ñтого ее данные будут переданы Ñайту.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{по меньшей мере 1 запиÑÑŒ на Ñинхронизируемых уÑтройÑтвах}=1{1 запиÑÑŒ (не ÑÑ‡Ð¸Ñ‚Ð°Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… на Ñинхронизируемых уÑтройÑтвах)}one{# запиÑÑŒ (не ÑÑ‡Ð¸Ñ‚Ð°Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… на Ñинхронизируемых уÑтройÑтвах)}few{# запиÑи (не ÑÑ‡Ð¸Ñ‚Ð°Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… на Ñинхронизируемых уÑтройÑтвах)}many{# запиÑей (не ÑÑ‡Ð¸Ñ‚Ð°Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… на Ñинхронизируемых уÑтройÑтвах)}other{# запиÑей (не ÑÑ‡Ð¸Ñ‚Ð°Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… на Ñинхронизируемых уÑтройÑтвах)}}</translation>
<translation id="3041612393474885105">Данные Ñертификата</translation>
<translation id="3063697135517575841">Ðе удалоÑÑŒ подтвердить данные карты. Повторите попытку позже.</translation>
+<translation id="3064966200440839136">Ð’Ñ‹ выйдете из режима инкогнито, чтобы произвеÑти оплату во внешнем приложении. Продолжить?</translation>
<translation id="3093245981617870298">Ðет Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº Ñети</translation>
<translation id="3105172416063519923">Идентификатор объекта:</translation>
<translation id="3109728660330352905">У Ð²Ð°Ñ Ð½ÐµÑ‚ прав Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра Ñтой Ñтраницы.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Выполните диагноÑтику подключениÑ<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Ðе удалоÑÑŒ декодировать ответ</translation>
-<translation id="3149891296864842641">Выберите вариант отправки</translation>
<translation id="3150653042067488994">Временные неполадки на Ñервере</translation>
+<translation id="3154506275960390542">Эта Ñтраница Ñодержит форму, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¼Ð¾Ð¶ÐµÑ‚ быть не защищена. Отправленные вами данные могут быть проÑмотрены третьими лицами во Ð²Ñ€ÐµÐ¼Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‡Ð¸, а также могут быть изменены злоумышленником до Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ñервером.</translation>
<translation id="3157931365184549694">ВоÑÑтановить</translation>
<translation id="3167968892399408617">Страницы, открытые в Ñтом окне, не оÑтанутÑÑ Ð² иÑтории браузера или поиÑка. Они не оÑтавÑÑ‚ на компьютере Ñледов, таких как файлы cookie, поÑле того как вы закроете вÑе вкладки инкогнито. Скачанные вами файлы и добавленные закладки будут Ñохранены.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -262,11 +270,13 @@
<translation id="3345135638360864351">Ðе удалоÑÑŒ отправить пользователю <ph name="NAME" /> Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° доÑтуп к Ñтому Ñайту. Повторите попытку.</translation>
<translation id="3355823806454867987">Изменить наÑтройки прокÑи-Ñервера...</translation>
<translation id="3369192424181595722">Ошибка чаÑов</translation>
+<translation id="337311366426640088">Ещё <ph name="ITEM_COUNT" /></translation>
<translation id="337363190475750230">Отключен</translation>
<translation id="3377188786107721145">Ðе удалоÑÑŒ выполнить анализ политики</translation>
<translation id="3380365263193509176">ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°</translation>
<translation id="3380864720620200369">Идентификатор клиента:</translation>
<translation id="3391030046425686457">ÐÐ´Ñ€ÐµÑ Ð´Ð¾Ñтавки</translation>
+<translation id="3395827396354264108">СпоÑоб выдачи</translation>
<translation id="340013220407300675">Злоумышленники могут пытатьÑÑ Ð¿Ð¾Ñ…Ð¸Ñ‚Ð¸Ñ‚ÑŒ ваши данные Ñ Ñайта <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (например, пароли, ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ номера банковÑких карт).</translation>
<translation id="3422248202833853650">Закройте другие программы, чтобы оÑвободить памÑÑ‚ÑŒ.</translation>
<translation id="3422472998109090673">Сайт <ph name="HOST_NAME" /> недоÑтупен.</translation>
@@ -277,12 +287,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Выберите интервал:</translation>
<translation id="3462200631372590220">Скрыть подробноÑти</translation>
+<translation id="3467763166455606212">Укажите Ð¸Ð¼Ñ Ð²Ð»Ð°Ð´ÐµÐ»ÑŒÑ†Ð° карты.</translation>
+<translation id="3478058380795961209">МеÑÑц</translation>
<translation id="3479539252931486093">Этот Ñайт не должен быть заблокирован? <ph name="BEGIN_LINK" />Сообщите нам об Ñтом<ph name="END_LINK" />.</translation>
<translation id="3479552764303398839">Ðе ÑейчаÑ</translation>
<translation id="348000606199325318">Идентификатор ÑбоÑ: <ph name="CRASH_LOCAL_ID" /> (идентификатор Ñервера: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Ðе удалоÑÑŒ ÑвÑзатьÑÑ Ñ Ð²Ð°ÑˆÐ¸Ð¼Ð¸ родителÑми. Повторите попытку.</translation>
<translation id="3528171143076753409">Сертификат Ñервера не ÑвлÑетÑÑ Ð´Ð¾Ð²ÐµÑ€ÐµÐ½Ð½Ñ‹Ð¼.</translation>
-<translation id="3538531656504267329">ÐедопуÑтимый год Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ñрока дейÑтвиÑ</translation>
<translation id="3539171420378717834">Хранить данные карты на Ñтом уÑтройÑтве</translation>
<translation id="3542684924769048008">ИÑпользовать пароль длÑ:</translation>
<translation id="3549644494707163724">Шифровать вÑе Ñинхронизированные данные Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ кодовой фразы</translation>
@@ -295,6 +306,7 @@
<translation id="3586931643579894722">Скрыть подробноÑти</translation>
<translation id="3587482841069643663">Ð’Ñе</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Укажите правильный Ñрок дейÑтвиÑ.</translation>
<translation id="36224234498066874">ОчиÑтить иÑторию...</translation>
<translation id="362276910939193118">Показать вÑÑŽ иÑторию</translation>
<translation id="3623476034248543066">Показать значение</translation>
@@ -311,7 +323,6 @@
<translation id="3693415264595406141">Пароль:</translation>
<translation id="3696411085566228381">нет</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Чтобы узнать ÑпоÑобы доÑтавки и требованиÑ, выберите Ð°Ð´Ñ€ÐµÑ Ð´Ð¾Ñтавки.</translation>
<translation id="370665806235115550">Загрузка...</translation>
<translation id="3712624925041724820">ÐедоÑтаточно лицензий</translation>
<translation id="3714780639079136834">Включите Wi-Fi или передачу данных по мобильной Ñети.</translation>
@@ -320,6 +331,7 @@
<translation id="3739623965217189342">Ð¡ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ ÑÑылка</translation>
<translation id="375403751935624634">Сбой при переводе вÑледÑтвие ошибки Ñервера.</translation>
<translation id="3759461132968374835">Ðет запиÑей о недавних ÑбоÑÑ…. Сбои, которые произошли при отключенной функции запиÑи Ñбоев, здеÑÑŒ не отображаютÑÑ.</translation>
+<translation id="3787705759683870569">Срок дейÑтвиÑ: до <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">ЕÑли вы иÑпользуете прокÑи-Ñервер...</translation>
<translation id="3828924085048779000">ПуÑтые кодовые фразы запрещены.</translation>
<translation id="3845539888601087042">Показана иÑÑ‚Ð¾Ñ€Ð¸Ñ Ñо вÑех уÑтройÑтв, на которых иÑпользуетÑÑ Ñтот аккаунт. <ph name="BEGIN_LINK" />Подробнее…<ph name="END_LINK" /></translation>
@@ -355,7 +367,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Сохранить Ñту карту в Chromium?</translation>
<translation id="4171400957073367226">ÐŸÐ¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´Ð°ÑŽÑ‰Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ недейÑтвительна</translation>
-<translation id="4176463684765177261">Отключено</translation>
<translation id="4196861286325780578">&amp;Повторить перемещение</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Проверьте наÑтройки брандмауÑра и антивируÑного ПО<ph name="END_LINK" />.</translation>
<translation id="4206349416402437184">{COUNT,plural, =0{нет}=1{1 приложение ($1)}=2{2Â Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ($1 и $2)}one{# приложение ($1, $2, $3)}few{#Â Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ($1, $2, $3)}many{# приложений ($1, $2, $3)}other{#Â Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ($1, $2, $3)}}</translation>
@@ -382,11 +393,11 @@
<translation id="4406896451731180161">Результаты поиÑка</translation>
<translation id="4432688616882109544">Ваш Ñертификат отклонен Ñайтом <ph name="HOST_NAME" /> или не был выдан.</translation>
<translation id="443673843213245140">ПрокÑи-Ñервер отключен, но при Ñтом его ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð·Ð°Ð´Ð°Ð½Ð° Ñвным образом.</translation>
-<translation id="4446242550670694251">Ваши дейÑÑ‚Ð²Ð¸Ñ Ð² режиме инкогнито будут недоÑтупны другим пользователÑм Ñтого уÑтройÑтва.</translation>
<translation id="4492190037599258964">Результаты поиÑка по запроÑу "<ph name="SEARCH_STRING" />"</translation>
<translation id="4506176782989081258">Ошибка проверки: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">ОбратитеÑÑŒ за помощью к ÑиÑтемному админиÑтратору.</translation>
<translation id="450710068430902550">ДоÑтуп админиÑтратора</translation>
+<translation id="4515275063822566619">Карты и адреÑа, указанные в Chrome и в вашем аккаунте Google (<ph name="ACCOUNT_EMAIL" />). Ð’Ñ‹ можете изменить их на Ñтранице <ph name="BEGIN_LINK" />ÐаÑтройки<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Подробнее</translation>
<translation id="4558551763791394412">Отключите раÑширениÑ.</translation>
<translation id="457875822857220463">ДоÑтавка</translation>
@@ -416,6 +427,7 @@
<translation id="4816492930507672669">По размеру Ñтраницы</translation>
<translation id="483020001682031208">Ðет веб-Ñтраниц Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ð°</translation>
<translation id="4850886885716139402">ПоÑмотреть</translation>
+<translation id="4854362297993841467">Этот ÑпоÑоб доÑтавки недоÑтупен. Выберите другой.</translation>
<translation id="4858792381671956233">Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° проÑмотр Ñайта отправлен вашим родителÑм</translation>
<translation id="4880827082731008257">ИÑкать в иÑтории</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> и <ph name="TYPE_3" /></translation>
@@ -423,7 +435,6 @@
<translation id="4923417429809017348">Эта Ñтраница была автоматичеÑки переведена Ñ Ð½ÐµÐ¸Ð·Ð²ÐµÑтного Ñзыка на <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Платеж</translation>
<translation id="4926049483395192435">Укажите значение.</translation>
-<translation id="4941291666397027948">Звездочкой (*) отмечены полÑ, обÑзательные Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ</translation>
<translation id="495170559598752135">ДейÑтвиÑ</translation>
<translation id="4958444002117714549">Развернуть ÑпиÑок</translation>
<translation id="4962322354953122629">Сервер не может подтвердить ÑвÑзь Ñ Ð´Ð¾Ð¼ÐµÐ½Ð¾Ð¼Â <ph name="DOMAIN" />. Chrome не Ñчитает его Ñертификат безопаÑноÑти надежным. Возможно, проблема ÑвÑзана Ñ Ð½Ð°Ñтройками Ñервера или дейÑтвиÑми злоумышленников, которые пытаютÑÑ Ð¿ÐµÑ€ÐµÑ…Ð²Ð°Ñ‚Ð¸Ñ‚ÑŒ Ñоединение. <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -438,6 +449,7 @@
<translation id="5045550434625856497">Ðеправильный пароль</translation>
<translation id="5056549851600133418">Статьи Ð´Ð»Ñ Ð²Ð°Ñ</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Проверьте Ð°Ð´Ñ€ÐµÑ Ð¿Ñ€Ð¾ÐºÑи-Ñервера<ph name="END_LINK" />.</translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Ðет файлов cookie.}=1{1 Ñайт иÑпользует файлы cookie. }one{# Ñайт иÑпользует файлы cookie. }few{# Ñайта иÑпользуют файлы cookie. }many{# Ñайтов иÑпользуют файлы cookie. }other{# Ñайта иÑпользуют файлы cookie. }}</translation>
<translation id="5087286274860437796">Сертификат Ñервера не дейÑтвителен в наÑтоÑщее времÑ.</translation>
<translation id="5087580092889165836">Добавить карту</translation>
<translation id="5089810972385038852">Штат</translation>
@@ -460,10 +472,8 @@
<translation id="5300589172476337783">Показать</translation>
<translation id="5308689395849655368">Отчеты о ÑбоÑÑ… отключены.</translation>
<translation id="5317780077021120954">Сохранить</translation>
-<translation id="5326702247179446998">Ðеобходимо указать получателÑ</translation>
<translation id="5327248766486351172">Ðазвание</translation>
<translation id="5337705430875057403">ПоÑещение Ñайта <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> может привеÑти к уÑтановке вредоноÑного ПО или хищению вашей личной информации (например, паролей, телефонных номеров и данных кредитных карт).</translation>
-<translation id="53553865750799677">ÐÐ´Ñ€ÐµÑ Ð²Ñ‹Ð´Ð°Ñ‡Ð¸ не поддерживаетÑÑ. Выберите другой вариант.</translation>
<translation id="5359637492792381994">Сервер не может подтвердить ÑвÑзь Ñ Ð´Ð¾Ð¼ÐµÐ½Ð¾Ð¼Â <ph name="DOMAIN" />, его Ñертификат в наÑтоÑщий момент недейÑтвителен. Возможно, проблема ÑвÑзана Ñ Ð½Ð°Ñтройками Ñервера или дейÑтвиÑми злоумышленников, которые пытаютÑÑ Ð¿ÐµÑ€ÐµÑ…Ð²Ð°Ñ‚Ð¸Ñ‚ÑŒ Ñоединение. <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Ðе удалоÑÑŒ Ñохранить наÑтройки политики</translation>
<translation id="5386426401304769735">Ð’ цепочке Ñертификатов Ñтого Ñайта еÑÑ‚ÑŒ Ñертификат, подпиÑанный Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ алгоритма SHA-1.</translation>
@@ -489,8 +499,8 @@
<translation id="5544037170328430102">Подтвердите дейÑтвие на <ph name="SITE" />:</translation>
<translation id="5556459405103347317">Перезагрузить</translation>
<translation id="5565735124758917034">Ðктивен</translation>
+<translation id="5571083550517324815">Этот Ð°Ð´Ñ€ÐµÑ Ð½Ðµ поддерживаетÑÑ. Выберите другой.</translation>
<translation id="5572851009514199876">Выполните вход, чтобы Chrome определил, разрешен ли вам доÑтуп к Ñтому Ñайту.</translation>
-<translation id="5575380383496039204">ÐÐ´Ñ€ÐµÑ Ð´Ð¾Ñтавки не поддерживаетÑÑ. Выберите другой вариант.</translation>
<translation id="5580958916614886209">Проверьте меÑÑц в Ñроке дейÑÑ‚Ð²Ð¸Ñ ÐºÐ°Ñ€Ñ‚Ñ‹ и повторите попытку</translation>
<translation id="560412284261940334">Управление уÑтройÑтвами не поддерживаетÑÑ</translation>
<translation id="5610142619324316209">Проверьте подключение к Интернету.</translation>
@@ -506,7 +516,8 @@
<translation id="5710435578057952990">Идентификационные данные Ñтого Ñайта не проверены.</translation>
<translation id="5720705177508910913">Текущий пользователь</translation>
<translation id="5732392974455271431">Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ обратитеÑÑŒ к родителÑм.</translation>
-<translation id="57586589942790530">Ðеверный номер карты</translation>
+<translation id="5763042198335101085">Укажите дейÑтвительный Ð°Ð´Ñ€ÐµÑ Ñлектронной почты.</translation>
+<translation id="5765072501007116331">Выберите адреÑ, чтобы поÑмотреть ÑпоÑобы и уÑÐ»Ð¾Ð²Ð¸Ñ Ð´Ð¾Ñтавки.</translation>
<translation id="5784606427469807560">Ðе удалоÑÑŒ подтвердить данные карты. Проверьте подключение к Интернету и повторите попытку.</translation>
<translation id="5785756445106461925">Обратите внимание, что на Ñтранице обнаружен небезопаÑный контент. Возможно, при передаче реÑурÑÑ‹ проÑматриваютÑÑ Ñ‚Ñ€ÐµÑ‚ÑŒÐ¸Ð¼Ð¸ лицами, а злоумышленники могут получить доÑтуп к Ñтранице и изменить ее поведение или внешний вид.</translation>
<translation id="5786044859038896871">Заполнить данные банковÑкой карты?</translation>
@@ -519,22 +530,20 @@
<translation id="5869405914158311789">Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ доÑтуп к Ñайту</translation>
<translation id="5869522115854928033">Сайты Ñ Ñохраненными паролÑми</translation>
<translation id="5872918882028971132">ПодÑказки Ð´Ð»Ñ Ñ€Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÑких Ñлементов</translation>
-<translation id="587760065310675640">ÐÐ´Ñ€ÐµÑ Ð´Ð¾Ñтавки не поддерживаетÑÑ. Выберите другой вариант.</translation>
<translation id="5901630391730855834">Желтый</translation>
-<translation id="59174027418879706">Включено</translation>
<translation id="5926846154125914413">Ð’Ñ‹ можете потерÑÑ‚ÑŒ доÑтуп к премиум-контенту на некоторых Ñайтах.</translation>
<translation id="5959728338436674663">ÐвтоматичеÑки отправлÑÑ‚ÑŒ <ph name="BEGIN_WHITEPAPER_LINK" />ÑиÑтемную информацию и контент Ñтраниц<ph name="END_WHITEPAPER_LINK" /> в Google, чтобы улучшить раÑпознавание опаÑных приложений и Ñайтов. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">ÐеделÑ</translation>
<translation id="5967867314010545767">Удалить из иÑтории</translation>
<translation id="5975083100439434680">Уменьшить</translation>
+<translation id="598637245381783098">Ðе удалоÑÑŒ открыть Payments</translation>
<translation id="5989320800837274978">Ðи фикÑированные прокÑи-Ñерверы, ни URL PAC-Ñкриптов не указаны.</translation>
<translation id="5990559369517809815">РаÑширение заблокировало отправку запроÑа на Ñервер.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ карте и адреÑе получены из браузера Chrome. Их можно изменить в <ph name="BEGIN_LINK" />наÑтройках<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Страница 1}one{Страница #}few{Страница #}many{Страница #}other{Страница #}}</translation>
<translation id="6017514345406065928">Зеленый</translation>
+<translation id="6027201098523975773">Введите имÑ.</translation>
<translation id="6040143037577758943">Закрыть</translation>
-<translation id="604124094241169006">ÐвтоматичеÑки</translation>
<translation id="6042308850641462728">Подробнее...</translation>
<translation id="6060685159320643512">Будьте оÑторожны при работе Ñ ÑкÑпериментальной верÑией</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{нет}=1{1}one{#}few{#}many{#}other{#}}</translation>
@@ -542,9 +551,10 @@
Ñетевые уÑтройÑтва.</translation>
<translation id="614940544461990577">Попробуйте Ñделать Ñледующее:</translation>
<translation id="6151417162996330722">Слишком долгий Ñрок дейÑÑ‚Ð²Ð¸Ñ Ñертификата, предоÑтавленного Ñервером.</translation>
-<translation id="615643356032862689">Скачанные файлы и закладки ÑохранÑÑ‚ÑÑ.</translation>
+<translation id="6157877588268064908">Выберите адреÑ, чтобы поÑмотреть ÑпоÑобы и уÑÐ»Ð¾Ð²Ð¸Ñ Ð´Ð¾Ñтавки.</translation>
<translation id="6165508094623778733">Подробнее...</translation>
<translation id="6177128806592000436">Подключение к Ñайту не защищено</translation>
+<translation id="6184817833369986695">(когорта: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Проверьте подключение к Интернету</translation>
<translation id="6218753634732582820">Удалить Ð°Ð´Ñ€ÐµÑ Ð¸Ð· Chromium?</translation>
<translation id="6251924700383757765">Политика конфиденциальноÑти</translation>
@@ -553,6 +563,8 @@
<translation id="6259156558325130047">&amp;Повторить изменение порÑдка</translation>
<translation id="6263376278284652872">Закладки <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Ðазад к безопаÑноÑти</translation>
+<translation id="6276112860590028508">ЗдеÑÑŒ будут Ñтраницы из ÑпиÑка Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ.</translation>
+<translation id="6280223929691119688">Ðевозможно доÑтавить заказ по Ñтому адреÑу. Выберите другой вариант.</translation>
<translation id="6282194474023008486">Почтовый индекÑ</translation>
<translation id="6290238015253830360">ЗдеÑÑŒ поÑвÑÑ‚ÑÑ Ñ€ÐµÐºÐ¾Ð¼ÐµÐ½Ð´ÑƒÐµÐ¼Ñ‹Ðµ Ñтатьи.</translation>
<translation id="6305205051461490394">Сайт <ph name="URL" /> недоÑтупен.</translation>
@@ -574,7 +586,6 @@
<translation id="6417515091412812850">Ðе удаетÑÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€Ð¸Ñ‚ÑŒ, был ли отозван Ñертификат.</translation>
<translation id="6433490469411711332">Изменить контактную информацию</translation>
<translation id="6433595998831338502">Сайт <ph name="HOST_NAME" /> не позволÑет уÑтановить Ñоединение.</translation>
-<translation id="6443118737398455446">ÐедопуÑтимый Ñрок дейÑтвиÑ</translation>
<translation id="6446608382365791566">Укажите дополнительную информацию</translation>
<translation id="6451458296329894277">Подтвердите повторную отправку формы</translation>
<translation id="6456339708790392414">Оплата</translation>
@@ -582,10 +593,8 @@
<translation id="6462969404041126431">Сервер не может подтвердить ÑвÑзь Ñ Ð´Ð¾Ð¼ÐµÐ½Ð¾Ð¼Â <ph name="DOMAIN" />. ВероÑтно, его Ñертификат был отозван. Проблема также может быть ÑвÑзана Ñ Ð½Ð°Ñтройками Ñервера или дейÑтвиÑми злоумышленников, которые пытаютÑÑ Ð¿ÐµÑ€ÐµÑ…Ð²Ð°Ñ‚Ð¸Ñ‚ÑŒ Ñоединение. <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">Правила уÑтройÑтва</translation>
<translation id="6477321094435799029">Браузер Chrome обнаружил на Ñтой Ñтранице необычный код и заблокировал его, чтобы защитить ваши данные (например, пароли, а также номера телефонов и банковÑких карт).</translation>
-<translation id="6477460825583319731">Ðеверный Ð°Ð´Ñ€ÐµÑ Ñлектронной почты</translation>
<translation id="6489534406876378309">Ðачать загрузку Ñведений об ошибках</translation>
<translation id="6508722015517270189">ПерезапуÑтите Google Chrome.</translation>
-<translation id="6525462735697194615">ÐедопуÑтимый меÑÑц Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ñрока дейÑтвиÑ</translation>
<translation id="6529602333819889595">&amp;Повторить удаление</translation>
<translation id="6534179046333460208">Интернет вокруг наÑ: рекомендации</translation>
<translation id="6550675742724504774">Параметры</translation>
@@ -600,7 +609,6 @@
<translation id="6628463337424475685">ПоиÑк <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Правило уÑтарело.</translation>
<translation id="6652240803263749613">Сервер не может подтвердить ÑвÑзь Ñ Ð´Ð¾Ð¼ÐµÐ½Ð¾Ð¼Â <ph name="DOMAIN" />. Его Ñертификат безопаÑноÑти не принимаетÑÑ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð¾Ð¹ ÑиÑтемой вашего компьютера. Возможно, проблема ÑвÑзана Ñ Ð½Ð°Ñтройками Ñервера или дейÑтвиÑми злоумышленников, которые пытаютÑÑ Ð¿ÐµÑ€ÐµÑ…Ð²Ð°Ñ‚Ð¸Ñ‚ÑŒ Ñоединение. <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="6665267558048410100">Этот ÑпоÑоб отправки недоÑтупен. Выберите другой.</translation>
<translation id="6671697161687535275">Удалить подÑказку из Chromium?</translation>
<translation id="6685834062052613830">Выйдите из аккаунта и завершите наÑтройку</translation>
<translation id="6710213216561001401">Ðазад</translation>
@@ -608,13 +616,13 @@
<translation id="6711464428925977395">Ðа прокÑи-Ñервере возникла проблема или Ð°Ð´Ñ€ÐµÑ ÑƒÐºÐ°Ð·Ð°Ð½ неверно.</translation>
<translation id="6727102863431372879">УÑтановить</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{нет}=1{1 запиÑÑŒ}one{# запиÑÑŒ}few{# запиÑи}many{# запиÑей}other{# запиÑи}}</translation>
-<translation id="6743044928064272573">СпоÑоб выдачи</translation>
<translation id="674375294223700098">ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° Ñертификата Ñервера.</translation>
<translation id="6753269504797312559">Значение правила</translation>
<translation id="6757797048963528358">УÑтройÑтво находитÑÑ Ð² ÑпÑщем режиме.</translation>
<translation id="6778737459546443941">Ещё не одобрено родителем</translation>
<translation id="6810899417690483278">Идентификатор перÑонализации</translation>
<translation id="6820686453637990663">Код CVC</translation>
+<translation id="6824266427216888781">Ðе удалоÑÑŒ загрузить данные регионов</translation>
<translation id="6831043979455480757">ПеревеÑти</translation>
<translation id="6839929833149231406">ÐдминиÑтративный район</translation>
<translation id="6874604403660855544">&amp;Повторить добавление</translation>
@@ -622,6 +630,7 @@
<translation id="6895330447102777224">Ваша карта подтверждена</translation>
<translation id="6897140037006041989">User Agent</translation>
<translation id="6915804003454593391">Пользователь:</translation>
+<translation id="6948701128805548767">Выберите адреÑ, чтобы поÑмотреть ÑпоÑобы и уÑÐ»Ð¾Ð²Ð¸Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ.</translation>
<translation id="6957887021205513506">Возможно, Ñертификат Ñервера фальÑифицирован.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">УÑтройÑтво</translation>
@@ -629,7 +638,6 @@
<translation id="6973656660372572881">Указаны как фикÑированные прокÑи-Ñерверы, так и URL PAC-Ñкриптов.</translation>
<translation id="6989763994942163495">Показать дополнительные наÑтройки</translation>
<translation id="7000990526846637657">Данные из иÑтории не найдены</translation>
-<translation id="7001663382399377034">Добавьте получателÑ</translation>
<translation id="7009986207543992532">Ð’Ñ‹ пытаетеÑÑŒ обратитьÑÑ Ðº Ñерверу в домене <ph name="DOMAIN" />, но он предоÑтавил Ñертификат Ñ Ð¿Ð¾Ð´Ð¾Ð·Ñ€Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾ долгим Ñроком дейÑтвиÑ. <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">ИÑÑ‚Ð¾Ñ€Ð¸Ñ Ð¿Ñ€Ð¾Ñмотра также может хранитьÑÑ Ð² вашем аккаунте Google: <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
@@ -640,12 +648,15 @@
<translation id="7088615885725309056">Раньше</translation>
<translation id="7090678807593890770">Выполните поиÑк по запроÑу <ph name="LINK" /> в Google</translation>
<translation id="7119414471315195487">Закройте другие вкладки и программы.</translation>
+<translation id="7129409597930077180">Ðевозможно отправить заказ по Ñтому адреÑу. Выберите другой вариант.</translation>
+<translation id="7138472120740807366">СпоÑоб доÑтавки</translation>
<translation id="7139724024395191329">Эмират</translation>
<translation id="7155487117670177674">ÐебезопаÑÐ½Ð°Ñ Ð¾Ð¿Ð»Ð°Ñ‚Ð°</translation>
<translation id="7179921470347911571">ПерезапуÑтить</translation>
<translation id="7180611975245234373">Обновить</translation>
<translation id="7182878459783632708">Правила не заданы</translation>
<translation id="7186367841673660872">Эта Ñтраница была переведена автоматичеÑки<ph name="ORIGINAL_LANGUAGE" />&gt;<ph name="LANGUAGE_LANGUAGE" /></translation>
+<translation id="7192203810768312527">ОÑвободитÑÑ <ph name="SIZE" /> проÑтранÑтва. ПоÑле Ñтого некоторые веб-Ñтраницы могут загружатьÑÑ Ð´Ð¾Ð»ÑŒÑˆÐµ обычного.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423">Сайт <ph name="HOST_NAME" /> не ÑоответÑтвует Ñтандартам безопаÑноÑти.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Подробнее <ph name="END_LINK" /> об Ñтой неполадке.</translation>
@@ -674,7 +685,6 @@
<translation id="7424977062513257142">Подтвердите дейÑтвие:</translation>
<translation id="7441627299479586546">Ðеверный Ñубъект политики</translation>
<translation id="7444046173054089907">Сайт заблокирован</translation>
-<translation id="7444238235002594607">Чтобы узнать ÑпоÑобы выдачи и требованиÑ, выберите Ð°Ð´Ñ€ÐµÑ Ð²Ñ‹Ð´Ð°Ñ‡Ð¸.</translation>
<translation id="7445762425076701745">Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ñервера, к которому вы подключилиÑÑŒ, не может быть полноÑтью подтверждена. Ð’Ñ‹ подключилиÑÑŒ к Ñерверу, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ðµ, которое дейÑтвительно только в вашей Ñети; владелец Ñтого Ñервера не может быть проверен или подтвержден внешним центром Ñертификации. Так как некоторые центры Ñертификации могут выдавать Ñертификаты Ð´Ð»Ñ Ð¿Ð¾Ð´Ð¾Ð±Ð½Ñ‹Ñ… названий, отÑутÑтвуют гарантии в том, что Ñто дейÑтвительно нужный вам Ñайт, а не Ñайт злоумышленника.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Узнайте больше<ph name="END_LINK" /> об Ñтой проблеме.</translation>
<translation id="7460163899615895653">ЗдеÑÑŒ поÑвÑÑ‚ÑÑ Ð½ÐµÐ´Ð°Ð²Ð½Ð¸Ðµ вкладки Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… уÑтройÑтв</translation>
@@ -718,6 +728,7 @@
<translation id="7755287808199759310">Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ обратитеÑÑŒ к родителю.</translation>
<translation id="7758069387465995638">Возможно, подключение заблокировано брандмауÑром или антивируÑным ПО.</translation>
<translation id="7761701407923456692">Сертификат Ñервера не ÑоответÑтвует URL.</translation>
+<translation id="7763386264682878361">СинтакÑичеÑкий анализатор манифеÑтов</translation>
<translation id="7764225426217299476">Добавить адреÑ</translation>
<translation id="777702478322588152">Префектура</translation>
<translation id="7791543448312431591">Добавить</translation>
@@ -731,6 +742,7 @@
<translation id="785549533363645510">Тем не менее ваши дейÑÑ‚Ð²Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ видны ÑиÑтемному админиÑтратору и интернет-провайдеру, а также доÑтупны веб-Ñайтам, которые вы поÑещаете.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Проверьте CVC-код и повторите попытку</translation>
+<translation id="79338296614623784">Укажите дейÑтвительный номер телефона.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Сертификат Ñервера еще не дейÑтвителен.</translation>
<translation id="7942349550061667556">КраÑный</translation>
@@ -750,6 +762,7 @@
<translation id="8088680233425245692">Ðе удалоÑÑŒ показать Ñтатью</translation>
<translation id="8089520772729574115">менее 1 МБ</translation>
<translation id="8091372947890762290">ÐÐºÑ‚Ð¸Ð²Ð°Ñ†Ð¸Ñ ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÑƒÑтройÑтвами не завершена</translation>
+<translation id="8118489163946903409">СпоÑоб оплаты</translation>
<translation id="8131740175452115882">Подтвердить</translation>
<translation id="8134994873729925007">Ðе удаетÑÑ Ð½Ð°Ð¹Ñ‚Ð¸ <ph name="BEGIN_ABBR" />DNS-адреÑ<ph name="END_ABBR" /> Ñервера <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Ваш компьютер перешел в ÑпÑщий режим.</translation>
@@ -775,6 +788,7 @@
<translation id="8349305172487531364">Панель закладок</translation>
<translation id="8363502534493474904">Отключите режим полета.</translation>
<translation id="8364627913115013041">Ðе задано</translation>
+<translation id="8368476060205742148">СервиÑÑ‹ Google Play</translation>
<translation id="8380941800586852976">ОпаÑно</translation>
<translation id="8382348898565613901">ЗдеÑÑŒ поÑвÑÑ‚ÑÑ Ð·Ð°ÐºÐ»Ð°Ð´ÐºÐ¸, которые вы недавно открывали.</translation>
<translation id="8398259832188219207"><ph name="UPLOAD_TIME" />: отчет о ÑбоÑÑ… загружен.</translation>
@@ -783,31 +797,29 @@
<translation id="8428213095426709021">ÐаÑтройки</translation>
<translation id="8433057134996913067">Ðа большинÑтве Ñайтов будет выполнен выход из аккаунта.</translation>
<translation id="8437238597147034694">&amp;Отменить перемещение</translation>
-<translation id="8456681095658380701">ÐедопуÑтимое название</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 банковÑÐºÐ°Ñ ÐºÐ°Ñ€Ñ‚Ð°}one{# банковÑÐºÐ°Ñ ÐºÐ°Ñ€Ñ‚Ð°}few{# банковÑкие карты}many{# банковÑких карт}other{# банковÑкой карты}}</translation>
<translation id="8483780878231876732">Чтобы иÑпользовать карты, привÑзанные к аккаунту Google Account, войдите в Chrome</translation>
<translation id="8488350697529856933">Объект применениÑ</translation>
-<translation id="8492969205326575646">Ðеподдерживаемый тип карты</translation>
<translation id="8498891568109133222">Превышено Ð²Ñ€ÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð¾Ñ‚Ð²ÐµÑ‚Ð° от Ñайта <ph name="HOST_NAME" />.</translation>
<translation id="852346902619691059">Сервер не может подтвердить ÑвÑзь Ñ Ð´Ð¾Ð¼ÐµÐ½Ð¾Ð¼Â <ph name="DOMAIN" />. Его Ñертификат безопаÑноÑти не принимаетÑÑ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð¾Ð¹ ÑиÑтемой вашего уÑтройÑтва. Возможно, проблема ÑвÑзана Ñ Ð½Ð°Ñтройками Ñервера или дейÑтвиÑми злоумышленников, которые пытаютÑÑ Ð¿ÐµÑ€ÐµÑ…Ð²Ð°Ñ‚Ð¸Ñ‚ÑŒ Ñоединение. <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="8532105204136943229">Год</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />Сообщите о зараженном Ñайте<ph name="END_ERROR_LINK" />. ЕÑли вы готовы подвергнуть риÑку личные данные, то можете <ph name="BEGIN_LINK" />перейти на Ñтраницу<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Перевод не удалÑÑ, так как не удаетÑÑ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»Ð¸Ñ‚ÑŒ Ñзык Ñтраницы.</translation>
<translation id="8559762987265718583">Ðе удалоÑÑŒ уÑтановить защищенное Ñоединение Ñ Ð´Ð¾Ð¼ÐµÐ½Ð¾Ð¼ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> из-за неверных наÑтроек ÑиÑтемных чаÑов и ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ (<ph name="DATE_AND_TIME" />).</translation>
-<translation id="8570229484593575558">|Ðе ÑохранÑÑŽÑ‚ÑÑ|:#иÑÑ‚Ð¾Ñ€Ð¸Ñ Ð¿Ñ€Ð¾Ñмотров;#поиÑковые запроÑÑ‹;#файлы cookie.</translation>
<translation id="8571890674111243710">Перевод Ñтраницы на <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Ваши дейÑÑ‚Ð²Ð¸Ñ |будут видны|:#Ñайтам, которые вы поÑещаете;#ÑиÑтемному админиÑтратору;#интернет-провайдеру.</translation>
<translation id="858637041960032120">Добавьте номер</translation>
<translation id="859285277496340001">Этот Ñертификат не определÑет механизм проверки отзыва.</translation>
<translation id="8620436878122366504">Ещё не одобрено родителÑми</translation>
<translation id="8647750283161643317">ВоÑÑтановить наÑтройки по умолчанию</translation>
<translation id="8703575177326907206">Соединение Ñ <ph name="DOMAIN" /> не зашифровано.</translation>
+<translation id="8718314106902482036">Ðе удалоÑÑŒ обработать платеж</translation>
<translation id="8725066075913043281">Повторить попытку</translation>
<translation id="8728672262656704056">Вы перешли в режим инкогнито</translation>
<translation id="8730621377337864115">Готово</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="8759274551635299824">Срок дейÑÑ‚Ð²Ð¸Ñ ÐºÐ°Ñ€Ñ‚Ñ‹ иÑтек.</translation>
<translation id="8790007591277257123">&amp;Повторить удаление</translation>
-<translation id="8798099450830957504">По умолчанию</translation>
<translation id="8800988563907321413">ЗдеÑÑŒ поÑвÑÑ‚ÑÑ Ñ€ÐµÐºÐ¾Ð¼ÐµÐ½Ð´Ð°Ñ†Ð¸Ð¸.</translation>
<translation id="8820817407110198400">Закладки</translation>
<translation id="883848425547221593">Другие закладки</translation>
@@ -817,6 +829,7 @@
<translation id="8866481888320382733">Ðе удалоÑÑŒ выполнить анализ наÑтроек политики</translation>
<translation id="8866959479196209191">Подтвердите дейÑтвие:</translation>
<translation id="8870413625673593573">Ðедавно закрытые</translation>
+<translation id="8874824191258364635">Введите дейÑтвительный номер карты.</translation>
<translation id="8876793034577346603">Ðе удалоÑÑŒ выполнить анализ конфигурации Ñети.</translation>
<translation id="8877192140621905067">ПоÑле Ñтого данные вашей карты будут переданы Ñайту.</translation>
<translation id="8889402386540077796">Тон</translation>
@@ -826,7 +839,6 @@
<translation id="8931333241327730545">Сохранить Ñту карту в аккаунте Google?</translation>
<translation id="8932102934695377596">ЧаÑÑ‹ отÑтают</translation>
<translation id="8954894007019320973">(Продолж.)</translation>
-<translation id="895548565263634352">Читайте Ñту и <ph name="OTHER_ARTICLE_COUNT" /> других Ñтатей от Ð¸Ð·Ð´Ð°Ñ‚ÐµÐ»Ñ "<ph name="ARTICLE_PUBLISHER" />"</translation>
<translation id="8971063699422889582">Сертификат Ñервера уÑтарел.</translation>
<translation id="8986494364107987395">ÐвтоматичеÑки отправлÑÑ‚ÑŒ в Google ÑтатиÑтику иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸ отчеты о ÑбоÑÑ…</translation>
<translation id="8987927404178983737">МеÑÑц</translation>
@@ -844,7 +856,6 @@
<translation id="9068849894565669697">Выберите цвет</translation>
<translation id="9076283476770535406">Может Ñодержать контент Ð´Ð»Ñ Ð²Ð·Ñ€Ð¾Ñлых</translation>
<translation id="9078964945751709336">Информации недоÑтаточно</translation>
-<translation id="9094175695478007090">Ðе удалоÑÑŒ запуÑтить платежное приложение.</translation>
<translation id="9103872766612412690">Ðа Ñайте <ph name="SITE" /> Ð´Ð»Ñ Ð·Ð°Ñ‰Ð¸Ñ‚Ñ‹ ваших данных обычно иÑпользуетÑÑ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ðµ. Однако учетные данные, которые мы получили от Ñайта <ph name="SITE" /> ÑейчаÑ, отличаютÑÑ Ð¾Ñ‚ тех, которые он отправлÑет обычно. ВероÑтно, вредоноÑный Ñайт пытаетÑÑ Ð²Ñ‹Ð´Ð°Ñ‚ÑŒ ÑÐµÐ±Ñ Ð·Ð° <ph name="SITE" />, либо Ñтраница Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº Ñети Wi-Fi прервала Ñоединение. Ваша Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ð¾-прежнему в безопаÑноÑти, так как браузер Chromium разорвал Ñоединение до того, как произошел обмен данными.</translation>
<translation id="9137013805542155359">Показать оригинал</translation>
<translation id="9137248913990643158">Войдите в Chrome, прежде чем иÑпользовать Ñто приложение.</translation>
diff --git a/chromium/components/strings/components_strings_sk.xtb b/chromium/components/strings/components_strings_sk.xtb
index 939d93b895c..f2dc2971e9f 100644
--- a/chromium/components/strings/components_strings_sk.xtb
+++ b/chromium/components/strings/components_strings_sk.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="sk">
<translation id="1008557486741366299">Teraz nie</translation>
<translation id="1015730422737071372">Poskytnite ÄalÅ¡ie podrobnosti</translation>
+<translation id="1021110881106174305">Prijímané karty</translation>
<translation id="1032854598605920125">OtoÄiÅ¥ v smere hodinových ruÄiÄiek</translation>
<translation id="1038842779957582377">neznámy názov</translation>
<translation id="1050038467049342496">Zavrite ostatné aplikácie</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Skryť hodnotu</translation>
<translation id="1228893227497259893">Nesprávny identifikátor entity</translation>
<translation id="1232569758102978740">Bez názvu</translation>
+<translation id="1263231323834454256">Čitateľský zoznam</translation>
<translation id="1264126396475825575">Správa o zlyhaní bola zaznamenaná v Äase <ph name="CRASH_TIME" /> (eÅ¡te nebola nahraná ani ignorovaná)</translation>
<translation id="1285320974508926690">Nikdy neprekladať tieto webové stránky</translation>
<translation id="129553762522093515">Naposledy zatvorené</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Nastavenia Automatického dopĺňania prehliadaÄa Chromium...</translation>
<translation id="1374468813861204354">návrhy</translation>
<translation id="1375198122581997741">Informácie o verzii</translation>
+<translation id="1377321085342047638">Číslo karty</translation>
<translation id="139305205187523129">Web <ph name="HOST_NAME" /> neodoslal žiadne údaje.</translation>
<translation id="1407135791313364759">Otvoriť všetko</translation>
<translation id="1413809658975081374">Chyba v ochrane osobných údajov</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">História</translation>
<translation id="1645368109819982629">Nepodporovaný protokol</translation>
<translation id="1656489000284462475">Vyzdvihnutie</translation>
+<translation id="1663943134801823270">Karty a adresy pochádzajú z Chromu. Môžete ich spravovať v <ph name="BEGIN_LINK" />Nastaveniach<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">Web <ph name="SITE" /> zvyÄajne chráni vaÅ¡e informácie pomocou Å¡ifrovania. KeÄ sa Chrome tentokrát pokúsil pripojiÅ¥ k webu <ph name="SITE" />, odoslal späť nezvyÄajné a nesprávne poverenia. Môže sa to staÅ¥ vtedy, keÄ sa za web <ph name="SITE" /> snaží vydávaÅ¥ útoÄník alebo keÄ pripojenie preruší prihlasovacia obrazovka siete Wi-Fi. VaÅ¡e informácie sú stále zabezpeÄené, pretože Chrome zastavil pripojenie eÅ¡te pred výmenou dát.</translation>
<translation id="168328519870909584">ÚtoÄníci, ktorí sú práve na webe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, sa možno pokúsia nainÅ¡talovaÅ¥ na vaÅ¡e zariadenie nebezpeÄné programy, ktoré ukradnú alebo odstránia vaÅ¡e informácie, napríklad fotky, heslá, správy alebo kreditné karty.</translation>
<translation id="168841957122794586">Certifikát servera obsahuje slabý kryptografický kľúÄ.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Ak chcete navštíviť tento web, potrebujete povolenie od správcu <ph name="NAME" /></translation>
+<translation id="1721424275792716183">* Toto pole je povinné</translation>
<translation id="1728677426644403582">Prezeráte si zdrojový kód webovej stránky</translation>
+<translation id="173080396488393970">Tento typ karty nie je podporovaný</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Skúste kontaktovať správcu systému.</translation>
+<translation id="1740951997222943430">Zadajte platný mesiac vypršania platnosti</translation>
<translation id="1745358365027406341">Stiahnuť stránku neskôr</translation>
<translation id="17513872634828108">Otvorené karty</translation>
<translation id="1753706481035618306">Číslo stránky</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Aktualizujte prístupovú frázu na synchronizáciu.</translation>
<translation id="1787142507584202372">Tu sa zobrazia otvorené karty</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Ak chcete skontrolovaÅ¥ spôsoby doruÄenia a požiadavky, vyberte adresu doruÄenia.</translation>
+<translation id="1803264062614276815">Meno majiteľa karty</translation>
<translation id="1803678881841855883">Funkcia BezpeÄné prehliadanie Google nedávno <ph name="BEGIN_LINK" />zistila malvér<ph name="END_LINK" /> na webe <ph name="SITE" />. Weby, ktoré sú zvyÄajne bezpeÄné, môžu byÅ¥ niekedy nakazené malvérom. Å kodlivý obsah pochádza od hostiteľa <ph name="SUBRESOURCE_HOST" />, ktorý je známym distribútorom malvéru. <ph name="BEGIN_LEARN_MORE_LINK" />ÄŽalÅ¡ie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1806541873155184440">Pridané <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Neplatná žiadosť alebo parametre žiadosti</translation>
<translation id="1826516787628120939">Kontroluje sa</translation>
<translation id="1834321415901700177">Tento web obsahuje škodlivé programy</translation>
<translation id="1842969606798536927">Zaplatiť</translation>
-<translation id="1864455488461349376">MožnosÅ¥ doruÄenia</translation>
<translation id="1871208020102129563">Proxy je nastavené na použitie pevne daných serverov proxy, nie skriptov PAC webovej adresy.</translation>
<translation id="1871284979644508959">Povinné pole</translation>
<translation id="187918866476621466">Otvoriť stránky pri spustení</translation>
<translation id="1883255238294161206">Zbaliť zoznam</translation>
<translation id="1898423065542865115">Filtrovanie</translation>
<translation id="194030505837763158">Prejdite na stránku <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Prijímame karty</translation>
<translation id="1962204205936693436">Záložky (<ph name="DOMAIN" />)</translation>
<translation id="1973335181906896915">Chyba serializácie</translation>
<translation id="1974060860693918893">Rozšírené</translation>
<translation id="1978555033938440688">Verzia firmvéru</translation>
+<translation id="1995859865337580572">Overte svoje Äíslo CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{a 1 ÄalÅ¡ia}few{a # ÄalÅ¡ie}many{a # ÄalÅ¡ej}other{a # Äalších}}</translation>
-<translation id="2020194265157481222">Meno na karte je povinné</translation>
<translation id="2025186561304664664">Proxy je nastavené na automatickú konfiguráciu.</translation>
<translation id="2030481566774242610">Mysleli ste stránku <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Skontrolovať proxy server a bránu firewall<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Dnes</translation>
<translation id="2154054054215849342">Synchronizácia nie je pre vašu doménu k dispozícii</translation>
<translation id="2154484045852737596">Úprava karty</translation>
-<translation id="2156993118928861787">Neplatná adresa</translation>
<translation id="2166049586286450108">Úplný prístup správcu</translation>
<translation id="2166378884831602661">Tento web nedokáže poskytnúť zabezpeÄené pripojenie</translation>
<translation id="2181821976797666341">Pravidlá</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresa}few{# adresy}many{# adresy}other{# adries}}</translation>
+<translation id="2202020181578195191">Zadajte platný rok vypršania platnosti</translation>
<translation id="2212735316055980242">Pravidlo sa nenašlo</translation>
<translation id="2213606439339815911">NaÄítavanie záznamov...</translation>
<translation id="2230458221926704099">Opravte svoje pripojenie pomocou <ph name="BEGIN_LINK" />diagnostickej aplikácie<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Váš prístup k internetu je blokovaný</translation>
<translation id="230155334948463882">Nová karta?</translation>
<translation id="2305919008529760154">Tomuto serveru sa nepodarilo dokázaÅ¥, že ide o doménu <ph name="DOMAIN" />; bezpeÄnostný certifikát mohol byÅ¥ vydaný podvodným spôsobom. Môže to byÅ¥ následok nesprávnej konfigurácie alebo napadnutia vášho pripojenia útoÄníkom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄŽalÅ¡ie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="230697611605700222">Možnosti karty a adresy sú z úÄtu Google (<ph name="ACCOUNT_EMAIL" />) a Chromu. Môžete ich spravovaÅ¥ v Äasti <ph name="BEGIN_LINK" />Nastavenia<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535">Doména <ph name="DOMAIN" /> vyžaduje používateľské meno a heslo.</translation>
<translation id="2318774815570432836">Web <ph name="SITE" /> momentálne nemôžete navÅ¡tíviÅ¥, pretože používa pravidlo HSTS. Chyby siete a útoky sú zvyÄajne doÄasné, takže by táto stránka mala neskôr pravdepodobne fungovaÅ¥. <ph name="BEGIN_LEARN_MORE_LINK" />ÄŽalÅ¡ie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2354001756790975382">Iné záložky</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Predvolené nastavenie na podnikovej úrovni</translation>
<translation id="2386255080630008482">Certifikát servera bol zrušený.</translation>
<translation id="2392959068659972793">Zobraziť pravidlá bez nastavenej hodnoty</translation>
+<translation id="239429038616798445">Tento spôsob dodania nie je k dispozícii. Skúste inú možnosť.</translation>
<translation id="2396249848217231973">&amp;Vrátiť späť odstránenie</translation>
<translation id="2460160116472764928">Funkcia BezpeÄné prehliadanie Google nedávno <ph name="BEGIN_LINK" />zistila malvér<ph name="END_LINK" /> na webe <ph name="SITE" />. Weby, ktoré sú zvyÄajne bezpeÄné, môžu byÅ¥ niekedy nakazené malvérom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄŽalÅ¡ie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2463739503403862330">Vyplniť</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Spustiť nástroj Diagnostika siete<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Neplatná webová adresa vyhľadávania.</translation>
<translation id="2491120439723279231">Certifikát servera obsahuje chyby.</translation>
-<translation id="24943777258388405">Neplatné telefónne Äíslo</translation>
<translation id="2495083838625180221">JSON Parser</translation>
<translation id="2495093607237746763">Ak je toto nastavenie zaÄiarknuté, Chromium uloží na tomto zariadení kópiu karty, aby ste mohli rýchlejÅ¡ie vypĺňaÅ¥ formuláre.</translation>
<translation id="2498091847651709837">Naskenovať novú kartu</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027">Web <ph name="HOST_NAME" /> odoslal neplatnú odpoveÄ.</translation>
<translation id="2552545117464357659">Novšie</translation>
<translation id="2556876185419854533">&amp;Vrátiť späť úpravu</translation>
+<translation id="2587730715158995865">Od vydavateľa <ph name="ARTICLE_PUBLISHER" />. PreÄítajte si tento príbeh a ÄalÅ¡ie (<ph name="OTHER_ARTICLE_COUNT" />).</translation>
<translation id="2587841377698384444">Identifikátor prieÄinka API:</translation>
<translation id="2597378329261239068">Tento dokument je chránený heslom. Zadajte heslo.</translation>
<translation id="2609632851001447353">Variácie</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Spustiť nástroj Diagnostika konektivity<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">Odstrániť vybraté položky</translation>
+<translation id="277133753123645258">Spôsob dodania</translation>
<translation id="277499241957683684">Chýbajúci záznam zariadenia</translation>
<translation id="2784949926578158345">Spojenie bolo obnovené.</translation>
<translation id="2794233252405721443">Web je blokovaný</translation>
-<translation id="2812680587231492111">Táto možnosť vyzdvihnutia nie je k dispozícii. Skúste inú možnosť.</translation>
<translation id="2824775600643448204">Panel s adresou a vyhľadávací panel</translation>
<translation id="2826760142808435982">Pripojenie je Å¡ifrované pomocou Å¡tandardu <ph name="CIPHER" /> a používa mechanizmus výmeny kľúÄov <ph name="KX" />.</translation>
<translation id="2835170189407361413">Vymazať formulár</translation>
-<translation id="2849041323157393173">Táto možnosÅ¥ doruÄenia nie je k dispozícii. Skúste inú možnosÅ¥.</translation>
<translation id="2889159643044928134">NenaÄítaÅ¥ znova</translation>
<translation id="2900469785430194048">Pri pokuse o zobrazenie tejto webovej stránky doÅ¡lo miesto v pamäti prehliadaÄa Google Chrome.</translation>
<translation id="2909946352844186028">Zistila sa zmena siete.</translation>
<translation id="2916038427272391327">Zavrite ostatné programy</translation>
<translation id="2922350208395188000">Certifikát servera sa nedá overiť.</translation>
+<translation id="2928905813689894207">FakturaÄná adresa</translation>
<translation id="2948083400971632585">Môžete zakázať ktorékoľvek servery proxy nakonfigurované na pripojenie na stránke nastavení.</translation>
<translation id="2955913368246107853">Zatvoriť panel pre vyhľadávanie</translation>
<translation id="2958431318199492670">Konfigurácia siete nie je v súlade so Å¡tandardom ONC. Niektoré Äasti konfigurácie sa nemusia importovaÅ¥.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">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, Chrome nemôže tieto certifikáty overiÅ¥.</translation>
<translation id="2972581237482394796">&amp;Dopredu</translation>
<translation id="2985306909656435243">Ak túto možnosť povolíte, Chromium uloží na tomto zariadení kópiu karty, aby ste mohli rýchlejšie vypĺňať formuláre.</translation>
+<translation id="2985398929374701810">Zadajte platnú adresu</translation>
+<translation id="2986368408720340940">Tento spôsob vyzdvihnutia nie je k dispozícii. Skúste iný spôsob.</translation>
<translation id="2991174974383378012">Zdieľanie s webmi</translation>
<translation id="3005723025932146533">Zobraziť uloženú kópiu</translation>
<translation id="3008447029300691911">Zadajte kód CVC karty <ph name="CREDIT_CARD" />. Po potvrdení budú podrobnosti o karte zdieľané s týmto webom.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{aspoň jedna položka v synchronizovaných zariadeniach}=1{1 položka (a ÄalÅ¡ie v synchronizovaných zariadeniach)}few{# položky (a ÄalÅ¡ie v synchronizovaných zariadeniach)}many{# položky (a ÄalÅ¡ie v synchronizovaných zariadeniach)}other{# položiek (a ÄalÅ¡ie v synchronizovaných zariadeniach)}}</translation>
<translation id="3041612393474885105">Informácie o certifikáte</translation>
<translation id="3063697135517575841">Chromu sa nepodarilo overiť vašu kartu. Skúste to znova neskôr.</translation>
+<translation id="3064966200440839136">Ak zaplatíte pomocou externej aplikácie, opustíte režim inkognito. Chcete pokraÄovaÅ¥?</translation>
<translation id="3093245981617870298">Ste v režime offline.</translation>
<translation id="3105172416063519923">Identifikátor obsahu:</translation>
<translation id="3109728660330352905">Nemáte povolenie na zobrazenie tejto stránky.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Skúste spustiť nástroj Diagnostika konektivity<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">OdpoveÄ sa nepodarilo dekódovaÅ¥</translation>
-<translation id="3149891296864842641">Možnosť dodania</translation>
<translation id="3150653042067488994">DoÄasná chyba servera</translation>
+<translation id="3154506275960390542">Táto stránka obsahuje formulár, ktorý zrejme nebude možné bezpeÄne odoslaÅ¥. Odoslané dáta si môžu pri prenose zobraziÅ¥ iní používatelia a prípadný útoÄník ich môže zmeniÅ¥. Server preto môže prijaÅ¥ nieÄo iné, než ste odoslali.</translation>
<translation id="3157931365184549694">Obnoviť</translation>
<translation id="3167968892399408617">KeÄ zavriete vÅ¡etky karty inkognito, po stránkach, ktoré ste na nich zobrazili, nezostane v histórii prehliadania, úložisku súborov cookie a histórii vyhľadávania ani stopa. VÅ¡etky stiahnuté súbory a vytvorené záložky zostanú zachované.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -260,11 +268,13 @@
<translation id="3345135638360864351">Vašu žiadosť o prístup k týmto webovým stránkam sa používateľovi <ph name="NAME" /> neporadilo odoslať. Skúste to znova neskôr.</translation>
<translation id="3355823806454867987">Zmeniť nastavenia proxy...</translation>
<translation id="3369192424181595722">Chyba hodín</translation>
+<translation id="337311366426640088">Ďalšie položky (<ph name="ITEM_COUNT" />)…</translation>
<translation id="337363190475750230">Odstránené</translation>
<translation id="3377188786107721145">Chyba analýzy pravidla</translation>
<translation id="3380365263193509176">Neznáma chyba</translation>
<translation id="3380864720620200369">ID klienta:</translation>
<translation id="3391030046425686457">DoruÄovacia adresa</translation>
+<translation id="3395827396354264108">Spôsob vyzdvihnutia</translation>
<translation id="340013220407300675">ÚtoÄníci sa možno pokúšajú ukradnúť vaÅ¡e informácie zo stránok <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (napríklad heslá, správy alebo informácie o kreditných kartách).</translation>
<translation id="3422248202833853650">Skúste ukonÄiÅ¥ ostatné programy a uvoľniÅ¥ tak miesto v pamäti.</translation>
<translation id="3422472998109090673">Web <ph name="HOST_NAME" /> nie je momentálne k dispozícii.</translation>
@@ -275,12 +285,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Interval naÄítania:</translation>
<translation id="3462200631372590220">Skryť rozšírené podrobnosti</translation>
+<translation id="3467763166455606212">Meno majiteľa karty je povinný údaj</translation>
+<translation id="3478058380795961209">Mesiac vypršania platnosti</translation>
<translation id="3479539252931486093">NeoÄakávali ste to? <ph name="BEGIN_LINK" />Dajte nám vedieÅ¥<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Teraz nie</translation>
<translation id="348000606199325318">ID zlyhania <ph name="CRASH_LOCAL_ID" /> (ID servera: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">V tejto chvíli sa nám nepodarilo spojiÅ¥ s vaším rodiÄom. Skúste to znova neskôr.</translation>
<translation id="3528171143076753409">Certifikát servera nie je dôveryhodný.</translation>
-<translation id="3538531656504267329">Neplatný rok ukonÄenia platnosti</translation>
<translation id="3539171420378717834">Ponechať kópiu tejto karty na tomto zariadení</translation>
<translation id="3542684924769048008">Použiť heslo pre:</translation>
<translation id="3549644494707163724">Šifrovať všetky synchronizované údaje pomocou vlastnej prístupovej frázy pre synchronizáciu</translation>
@@ -293,6 +304,7 @@
<translation id="3586931643579894722">Skryť podrobnosti</translation>
<translation id="3587482841069643663">VÅ¡etko</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Zadajte správny dátum vypršania platnosti</translation>
<translation id="36224234498066874">Vymazať údaje prehliadania...</translation>
<translation id="362276910939193118">Zobraziť celú históriu</translation>
<translation id="3623476034248543066">Zobraziť hodnotu</translation>
@@ -308,7 +320,6 @@
<translation id="3693415264595406141">Heslo:</translation>
<translation id="3696411085566228381">žiadne</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Vyberte dodaciu adresu a prezrite si spôsoby dodania a požiadavky.</translation>
<translation id="370665806235115550">NaÄítava sa...</translation>
<translation id="3712624925041724820">VyÄerpané licencie</translation>
<translation id="3714780639079136834">Zapnúť mobilné dáta alebo Wi-Fi</translation>
@@ -317,6 +328,7 @@
<translation id="3739623965217189342">Skopírovaný odkaz</translation>
<translation id="375403751935624634">Preklad zlyhal v dôsledku chyby servera.</translation>
<translation id="3759461132968374835">Nemáte žiadne nedávno nahlásené zlyhania. Na tejto stránke sa nezobrazujú zlyhania, ktoré nastali pri zakázanej možnosti hlásení zlyhaní.</translation>
+<translation id="3787705759683870569">Platnosť vyprší <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Ak používate server proxy...</translation>
<translation id="3828924085048779000">Prístupová fráza nemôže byť prázdna.</translation>
<translation id="3845539888601087042">Zobrazuje sa história zo zariadení, na ktorých ste prihlásený/-á. <ph name="BEGIN_LINK" />Ďalšie informácie<ph name="END_LINK" /></translation>
@@ -352,7 +364,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chcete, aby Chromium uložil túto kartu?</translation>
<translation id="4171400957073367226">Nesprávny overovací podpis</translation>
-<translation id="4176463684765177261">Zakázané</translation>
<translation id="4196861286325780578">&amp;Znova presunúť</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Skontrolovať konfiguráciu brány firewall a antivírusového softvéru<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{žiadne}=1{1 aplikácia ($1)}=2{2 aplikácie ($1, $2)}few{# aplikácie ($1, $2, $3)}many{# aplikácie ($1, $2, $3)}other{# aplikácií ($1, $2, $3)}}</translation>
@@ -379,11 +390,11 @@
<translation id="4406896451731180161">výsledky vyhľadávania</translation>
<translation id="4432688616882109544">Web <ph name="HOST_NAME" /> neakceptoval váš prihlasovací certifikát alebo nebol žiadny poskytnutý.</translation>
<translation id="443673843213245140">Použitie servera proxy je zakázané, ale je urÄená explicitná konfigurácia servera proxy.</translation>
-<translation id="4446242550670694251">Teraz môžete súkromne prehliadaÅ¥ a vaÅ¡a aktivita sa nezobrazí Äalším ľuÄom používajúcim toto zariadenie.</translation>
<translation id="4492190037599258964">Výsledky vyhľadávania pre dopyt „<ph name="SEARCH_STRING" />“</translation>
<translation id="4506176782989081258">Chyba overenia: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Kontaktovať správcu systému</translation>
<translation id="450710068430902550">Zdieľanie so správcom</translation>
+<translation id="4515275063822566619">Karty a adresy pochádzajú z Chromu a úÄtu Google (<ph name="ACCOUNT_EMAIL" />). Môžete ich spravovaÅ¥ v <ph name="BEGIN_LINK" />Nastaveniach<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Podrobnosti</translation>
<translation id="4558551763791394412">Skúste deaktivovať rozšírenia.</translation>
<translation id="457875822857220463">DoruÄenie</translation>
@@ -413,6 +424,7 @@
<translation id="4816492930507672669">Prispôsobiť stránke</translation>
<translation id="483020001682031208">K dispozícii nie sú žiadne stránky Fyzického webu</translation>
<translation id="4850886885716139402">Zobraziť</translation>
+<translation id="4854362297993841467">Tento spôsob doruÄenia nie je k dispozícii. Skúste inú adresu.</translation>
<translation id="4858792381671956233">Požiadali ste rodiÄov o povolenie návÅ¡tevy tohto webu.</translation>
<translation id="4880827082731008257">Hľadať v histórii</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -420,7 +432,6 @@
<translation id="4923417429809017348">Táto stránka bola preložená z neznámeho jazyka do jazyka <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Platba</translation>
<translation id="4926049483395192435">Musí byÅ¥ urÄená.</translation>
-<translation id="4941291666397027948">* oznaÄuje povinné pole</translation>
<translation id="495170559598752135">Akcie</translation>
<translation id="4958444002117714549">Rozbaliť zoznam</translation>
<translation id="4962322354953122629">Tomuto serveru sa nepodarilo dokázaÅ¥, že ide o doménu <ph name="DOMAIN" />; Chrome jej bezpeÄnostnému certifikátu nedôveruje. Môže to byÅ¥ následok nesprávnej konfigurácie alebo napadnutia vášho pripojenia útoÄníkom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄŽalÅ¡ie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -435,6 +446,7 @@
<translation id="5045550434625856497">Nesprávne heslo</translation>
<translation id="5056549851600133418">Články pre vás</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Skontrolovať adresu proxy servera<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Žiadne súbory cookie}=1{1 web používa súbory cookie. }few{# weby používajú súbory cookie. }many{# webu používa súbory cookie. }other{# webov používa súbory cookie. }}</translation>
<translation id="5087286274860437796">Certifikát servera je momentálne neplatný</translation>
<translation id="5087580092889165836">Pridať kartu</translation>
<translation id="5089810972385038852">Štát</translation>
@@ -457,10 +469,8 @@
<translation id="5300589172476337783">Zobraziť</translation>
<translation id="5308689395849655368">Hlásenie zlyhaní je zakázané.</translation>
<translation id="5317780077021120954">Uložiť</translation>
-<translation id="5326702247179446998">Vyžaduje sa príjemca</translation>
<translation id="5327248766486351172">Názov</translation>
<translation id="5337705430875057403">ÚtoÄníci na webe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> sa vás môžu pokúsiÅ¥ naviesÅ¥ vykonaÅ¥ nieÄo nebezpeÄné, ako je inÅ¡talovanie softvéru alebo odhalenie osobných informácií (napr. heslá, telefónne Äísla alebo kreditné karty).</translation>
-<translation id="53553865750799677">Nepodporovaná adresa vyzdvihnutia. Vyberte inú adresu.</translation>
<translation id="5359637492792381994">Tomuto serveru sa nepodarilo dokázaÅ¥, že ide o doménu <ph name="DOMAIN" />; jej bezpeÄnostný certifikát je momentálne neplatný. Môže to byÅ¥ následok nesprávnej konfigurácie alebo napadnutia vášho pripojenia útoÄníkom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄŽalÅ¡ie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Nastavenia pravidla sa nepodarilo uložiť</translation>
<translation id="5386426401304769735">Reťazec certifikátu pre tento web obsahuje certifikát podpísaný pomocou funkcie SHA-1.</translation>
@@ -486,8 +496,8 @@
<translation id="5544037170328430102">Vložená stránka na webe <ph name="SITE" /> hovorí:</translation>
<translation id="5556459405103347317">Obnoviť</translation>
<translation id="5565735124758917034">Aktívne</translation>
+<translation id="5571083550517324815">Vyzdvihnutie na tejto adrese nie je možné. Vyberte inú adresu.</translation>
<translation id="5572851009514199876">ZaÄnite a prihláste sa do Chromu, aby skontroloval, Äi môžete navÅ¡tíviÅ¥ tento web.</translation>
-<translation id="5575380383496039204">Nepodporovaná doruÄovacia adresa. Vyberte inú adresu.</translation>
<translation id="5580958916614886209">Skontrolujte mesiac vypršania platnosti a skúste to znova</translation>
<translation id="560412284261940334">Správa nie je podporovaná</translation>
<translation id="5610142619324316209">Skontrolovať pripojenie</translation>
@@ -503,7 +513,8 @@
<translation id="5710435578057952990">Identita tejto webovej stránky nebola overená.</translation>
<translation id="5720705177508910913">Aktuálny používateľ</translation>
<translation id="5732392974455271431">VaÅ¡i rodiÄia ho môžu pre vás odblokovaÅ¥</translation>
-<translation id="57586589942790530">Neplatné Äíslo karty</translation>
+<translation id="5763042198335101085">Zadajte platnú e-mailovú adresu</translation>
+<translation id="5765072501007116331">Ak chcete zobraziÅ¥ spôsoby a požiadavky doruÄenia, vyberte adresu</translation>
<translation id="5784606427469807560">Pri overovaní karty sa vyskytol problém. Skontrolujte pripojenie k internetu a skúste to znova.</translation>
<translation id="5785756445106461925">Táto stránka obsahuje aj iné zdroje, ktoré nie sú zabezpeÄené. Tieto zdroje môžu pri prenose vidieÅ¥ ostatní používatelia a útoÄník ich môže upraviÅ¥ tak, aby zmenil vzhľad stránky.</translation>
<translation id="5786044859038896871">Chcete vyplniť informácie o karte?</translation>
@@ -516,31 +527,30 @@
<translation id="5869405914158311789">K tomuto webu sa nedá pripojiť</translation>
<translation id="5869522115854928033">Uložené heslá</translation>
<translation id="5872918882028971132">Návrhy rodiÄa</translation>
-<translation id="587760065310675640">Nepodporovaná dodacia adresa. Vyberte inú adresu.</translation>
<translation id="5901630391730855834">Žltá</translation>
-<translation id="59174027418879706">Povolené</translation>
<translation id="5926846154125914413">Môžete stratiť prístup k prémiovému obsahu z niektorých webov.</translation>
<translation id="5959728338436674663">Automaticky odosielaÅ¥ <ph name="BEGIN_WHITEPAPER_LINK" />niektoré informácie o systéme a obsah stránok<ph name="END_WHITEPAPER_LINK" /> do Googlu s cieľom pomôcÅ¥ rozpoznávaÅ¥ nebezpeÄné aplikácie a weby. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Týždeň</translation>
<translation id="5967867314010545767">Odstrániť z histórie</translation>
<translation id="5975083100439434680">Oddialiť</translation>
+<translation id="598637245381783098">Nie je možné otvoriť platobnú aplikáciu</translation>
<translation id="5989320800837274978">Nie sú urÄené pevne dané servery proxy ani skript PAC webovej adresy.</translation>
<translation id="5990559369517809815">Žiadosti odoslané serveru boli zablokované rozšírením.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Možnosti karty a adresy pochádzajú z Chromu. Môžete ich spravovaÅ¥ v Äasti <ph name="BEGIN_LINK" />Nastavenia<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Strana 1}few{Strana #}many{Strana #}other{Strana #}}</translation>
<translation id="6017514345406065928">Zelená</translation>
+<translation id="6027201098523975773">Zadajte meno</translation>
<translation id="6040143037577758943">Zavrieť</translation>
-<translation id="604124094241169006">Automatické</translation>
<translation id="6042308850641462728">Viac</translation>
<translation id="6060685159320643512">Opatrne, tieto experimenty môžu spôsobiť problémy</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{žiadne}=1{1}few{#}many{#}other{#}}</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="6151417162996330722">Obdobie platnosti certifikátu servera je príliš dlhé</translation>
-<translation id="615643356032862689">Stiahnuté súbory a záložky sa zachovajú.</translation>
+<translation id="6157877588268064908">Ak chcete zobraziť spôsoby a požiadavky dodania, vyberte adresu</translation>
<translation id="6165508094623778733">Viac informácií</translation>
<translation id="6177128806592000436">VaÅ¡e pripojenie k tomuto webu nie je zabezpeÄené</translation>
+<translation id="6184817833369986695">(kohorta: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Skontrolujte internetové pripojenie</translation>
<translation id="6218753634732582820">Chcete adresu odstrániÅ¥ z prehliadaÄa Chromium?</translation>
<translation id="6251924700383757765">Pravidlá ochrany súkromia</translation>
@@ -549,7 +559,9 @@
<translation id="6259156558325130047">&amp;Znova zmeniť poradie</translation>
<translation id="6263376278284652872">Záložky domény <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Naspäť do bezpeÄného režimu</translation>
-<translation id="6282194474023008486">Poštový kód</translation>
+<translation id="6276112860590028508">Tu nájdete stránky z Äitateľského zoznamu</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="6290238015253830360">Tu sa zobrazia vaÅ¡e navrhované Älánky</translation>
<translation id="6305205051461490394">Web <ph name="URL" /> je nedostupný.</translation>
<translation id="6319915415804115995">Naposledy použitá pred viac ako rokom.</translation>
@@ -570,7 +582,6 @@
<translation id="6417515091412812850">Nie je možné skontrolovaÅ¥, Äi bol certifikát odmietnutý.</translation>
<translation id="6433490469411711332">Úprava kontaktných informácií</translation>
<translation id="6433595998831338502">Web <ph name="HOST_NAME" /> zamietol pripojenie.</translation>
-<translation id="6443118737398455446">Neplatný dátum ukonÄenia platnosti</translation>
<translation id="6446608382365791566">Pridanie Äalších informácií</translation>
<translation id="6451458296329894277">Potvrdiť opakované odoslanie formulára</translation>
<translation id="6456339708790392414">Vaša platba</translation>
@@ -578,10 +589,8 @@
<translation id="6462969404041126431">Tomuto serveru sa nepodarilo dokázaÅ¥, že ide o doménu <ph name="DOMAIN" />; jej bezpeÄnostný certifikát bol zrejme odvolaný. Môže to byÅ¥ následok nesprávnej konfigurácie alebo napadnutia vášho pripojenia útoÄníkom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄŽalÅ¡ie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">Pravidlá zariadenia</translation>
<translation id="6477321094435799029">Chrome na tejto stránke zaznamenal nezvyÄajný kód a v záujme ochrany vaÅ¡ich osobných informácií (napr. hesiel, telefónnych Äísel a kreditných kariet) ho zablokoval.</translation>
-<translation id="6477460825583319731">Neplatná e-mailová adresa</translation>
<translation id="6489534406876378309">Spustiť nahrávanie správ o zlyhaní</translation>
<translation id="6508722015517270189">Reštartujte Chrome</translation>
-<translation id="6525462735697194615">Neplatný mesiac ukonÄenia platnosti</translation>
<translation id="6529602333819889595">&amp;Znova odstrániť</translation>
<translation id="6534179046333460208">Návrhy Fyzického webu</translation>
<translation id="6550675742724504774">Možnosti</translation>
@@ -596,7 +605,6 @@
<translation id="6628463337424475685">Vyhľadávanie <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Toto pravidlo bolo oznaÄené ako zastarané.</translation>
<translation id="6652240803263749613">Tomuto serveru sa nepodarilo dokázaÅ¥, že 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Å¥ následok nesprávnej konfigurácie alebo napadnutia vášho pripojenia útoÄníkom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄŽalÅ¡ie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="6665267558048410100">Táto možnosť dodania nie je k dispozícii. Skúste inú možnosť.</translation>
<translation id="6671697161687535275">Chcete návrh položky formulára odstrániÅ¥ z prehliadaÄa Chromium?</translation>
<translation id="6685834062052613830">Odhláste sa a dokonÄite nastavenie</translation>
<translation id="6710213216561001401">Dozadu</translation>
@@ -604,13 +612,13 @@
<translation id="6711464428925977395">Vyskytol sa problém s proxy serverom alebo je adresa nesprávna.</translation>
<translation id="6727102863431372879">Nastaviť</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{žiadne}=1{1 položka}few{# položky}many{# položky}other{# položiek}}</translation>
-<translation id="6743044928064272573">Možnosť vyzdvihnutia</translation>
<translation id="674375294223700098">Neznáma chyba spôsobená certifikátom servera.</translation>
<translation id="6753269504797312559">Hodnota pravidla</translation>
<translation id="6757797048963528358">Vaše zariadenie prešlo do režimu spánku.</translation>
<translation id="6778737459546443941">Váš rodiÄ to zatiaľ neschválil</translation>
<translation id="6810899417690483278">Identifikátor prispôsobenia</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">NaÄítanie údajov o regiónoch zlyhalo</translation>
<translation id="6831043979455480757">Preložiť</translation>
<translation id="6839929833149231406">Oblasť</translation>
<translation id="6874604403660855544">&amp;Znova pridať</translation>
@@ -618,6 +626,7 @@
<translation id="6895330447102777224">Vaša karta je overená</translation>
<translation id="6897140037006041989">Používateľský agent</translation>
<translation id="6915804003454593391">Používateľ:</translation>
+<translation id="6948701128805548767">Ak chcete zobraziť spôsoby a požiadavky vyzdvihnutia, vyberte adresu</translation>
<translation id="6957887021205513506">Zdá sa, že certifikát servera je falošný.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Zariadenie</translation>
@@ -625,7 +634,6 @@
<translation id="6973656660372572881">UrÄené sú pevne dané servery proxy aj skript PAC webovej adresy.</translation>
<translation id="6989763994942163495">Zobraziť rozšírené nastavenia...</translation>
<translation id="7000990526846637657">V histórii sa nenašli žiadne záznamy</translation>
-<translation id="7001663382399377034">Pridanie príjemcu</translation>
<translation id="7009986207543992532">Pokúsili ste sa prejsť do domény <ph name="DOMAIN" />, ale server poskytol certifikát, ktorého obdobie platnosti je príliš dlhé a preto nedôveryhodné.<ph name="BEGIN_LEARN_MORE_LINK" />Ďalšie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Váš úÄet Google môže maÅ¥ ÄalÅ¡ie formy histórie prehliadania na adrese <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -636,12 +644,15 @@
<translation id="7088615885725309056">Staršie</translation>
<translation id="7090678807593890770">Vyhľadajte na Googli výraz <ph name="LINK" /></translation>
<translation id="7119414471315195487">Zavrite ostatné karty alebo programy</translation>
+<translation id="7129409597930077180">Dodanie na túto adresu nie je možné. Vyberte inú adresu.</translation>
+<translation id="7138472120740807366">Spôsob doruÄenia</translation>
<translation id="7139724024395191329">Emirát</translation>
<translation id="7155487117670177674">Platba nie je zabezpeÄená</translation>
<translation id="7179921470347911571">Reštartovať teraz</translation>
<translation id="7180611975245234373">Obnoviť</translation>
<translation id="7182878459783632708">Nie sú nastavené žiadne pravidlá</translation>
<translation id="7186367841673660872">Táto stránka bola preložená z jazyka<ph name="ORIGINAL_LANGUAGE" />do jazyka<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423">Web <ph name="HOST_NAME" /> nespĺňa bezpeÄnostné Å¡tandardy.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Viac informácií<ph name="END_LINK" /> o tomto probléme.</translation>
@@ -670,7 +681,6 @@ Nabudúce by sa vám mohol hodiť režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="7424977062513257142">Vložená stránka na tejto webstránke hovorí:</translation>
<translation id="7441627299479586546">Chybný predmet pravidla</translation>
<translation id="7444046173054089907">Tento web je blokovaný</translation>
-<translation id="7444238235002594607">Ak chcete skontrolovať spôsoby vyzdvihnutia a požiadavky, vyberte adresu vyzdvihnutia.</translation>
<translation id="7445762425076701745">Identita servera, ku ktorému ste pripojení, sa nedá úplne overiÅ¥. Ste pripojení k serveru, ktorý používa názov platný iba v rámci vaÅ¡ej siete. Externá certifikaÄná autorita nemôže vlastníctvo názvu nijakým spôsobom overiÅ¥. Niektoré certifikaÄné autority vÅ¡ak vydajú certifikát aj pre takéto názvy, a preto sa nedá zaruÄiÅ¥, že ste pripojení k požadovaným webovým stránkam a nie k stránkam útoÄníka.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Ďalšie informácie o tomto probléme<ph name="END_LINK" /></translation>
<translation id="7460163899615895653">Vaše nedávne karty z iných zariadení sa zobrazia na tomto mieste</translation>
@@ -714,6 +724,7 @@ Nabudúce by sa vám mohol hodiť režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="7755287808199759310">Váš rodiÄ ho môže pre vás odblokovaÅ¥</translation>
<translation id="7758069387465995638">Pripojenie mohla zablokovať brána firewall alebo antivírusový softvér.</translation>
<translation id="7761701407923456692">Certifikát servera sa nezhoduje s webovou adresou.</translation>
+<translation id="7763386264682878361">Analyzátor manifestov platieb</translation>
<translation id="7764225426217299476">Pridať adresu</translation>
<translation id="777702478322588152">Prefektúra</translation>
<translation id="7791543448312431591">Pridať</translation>
@@ -727,6 +738,7 @@ Nabudúce by sa vám mohol hodiť režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="785549533363645510">Nie ste však neviditeľný/-á. Prejdením do režimu inkognito neskryjete svoje prehliadanie pred zamestnávateľom, poskytovateľom internetových služieb ani pred navštívenými webmi.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Skontrolujte svoj kód CVC a skúste to znova</translation>
+<translation id="79338296614623784">Zadajte platné telefónne Äíslo</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Certifikát servera ešte nie je platný.</translation>
<translation id="7942349550061667556">Červená</translation>
@@ -746,6 +758,7 @@ Nabudúce by sa vám mohol hodiť režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="8088680233425245692">Článok sa nepodarilo zobraziť.</translation>
<translation id="8089520772729574115">menej ako 1 MB</translation>
<translation id="8091372947890762290">Aktivácia Äaká na server</translation>
+<translation id="8118489163946903409">Spôsob platby</translation>
<translation id="8131740175452115882">Potvrdiť</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Adresu DNS<ph name="END_ABBR" /> servera <ph name="HOST_NAME" /> sa nepodarilo nájsť.</translation>
<translation id="8149426793427495338">Váš poÄítaÄ preÅ¡iel do režimu spánku.</translation>
@@ -771,6 +784,7 @@ Nabudúce by sa vám mohol hodiť režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="8349305172487531364">Panel so záložkami</translation>
<translation id="8363502534493474904">Vypnúť režim v lietadle</translation>
<translation id="8364627913115013041">Nenastavené.</translation>
+<translation id="8368476060205742148">Služby Google Play</translation>
<translation id="8380941800586852976">NebezpeÄná</translation>
<translation id="8382348898565613901">Tu sa zobrazia vaše nedávno navštívené záložky</translation>
<translation id="8398259832188219207">Správa o zlyhaní bola nahraná o <ph name="UPLOAD_TIME" /></translation>
@@ -779,32 +793,30 @@ Nabudúce by sa vám mohol hodiť režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="8428213095426709021">Nastavenia</translation>
<translation id="8433057134996913067">Táto možnosÅ¥ vás odhlási z väÄÅ¡iny webov.</translation>
<translation id="8437238597147034694">&amp;Vrátiť späť presunutie</translation>
-<translation id="8456681095658380701">Neplatný názov</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 kreditná karta}few{# kreditné karty}many{# kreditnej karty}other{# kreditných kariet}}</translation>
<translation id="8483780878231876732">Ak chcete používaÅ¥ karty z úÄtu Google, prihláste sa do Chromu</translation>
<translation id="8488350697529856933">Platí pre</translation>
-<translation id="8492969205326575646">Nepodporovaný typ karty</translation>
<translation id="8498891568109133222">Web <ph name="HOST_NAME" /> príliš dlho neodpovedal.</translation>
<translation id="852346902619691059">Tomuto serveru sa nepodarilo dokázaÅ¥, že 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Å¥ následok nesprávnej konfigurácie alebo napadnutia vášho pripojenia útoÄníkom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄŽalÅ¡ie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="8532105204136943229">Rok vypršania platnosti</translation>
<translation id="8543181531796978784">Môžete buÄ <ph name="BEGIN_ERROR_LINK" />nahlásiÅ¥ problém s zisÅ¥ovaním<ph name="END_ERROR_LINK" />, alebo <ph name="BEGIN_LINK" />tieto nebezpeÄné stránky navÅ¡tíviÅ¥<ph name="END_LINK" /> (ak si uvedomujete bezpeÄnostné riziko).</translation>
<translation id="8553075262323480129">Prekladanie zlyhalo, pretože sa nepodarilo urÄiÅ¥ jazyk stránky.</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="8570229484593575558">Tieto informácie |sa neuložia|:#história prehliadania,#vyhľadávania,#údaje súborov cookie.</translation>
<translation id="8571890674111243710">Prebieha preklad stránky do jazyka: <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Vaša aktivita |sa môžu stále zobrazovať|:#navštíveným webom,#vášmu zamestnávateľovi,#poskytovateľovi internetových služieb.</translation>
<translation id="858637041960032120">Pridať telefón
</translation>
<translation id="859285277496340001">V certifikáte nie je uvedené, akým spôsobom sa má skontrolovaÅ¥, Äi certifikát nebol odmietnutý.</translation>
<translation id="8620436878122366504">VaÅ¡i rodiÄia to zatiaľ neschválili</translation>
<translation id="8647750283161643317">Obnoviť predvolené nastavenia všetkých experimentov</translation>
<translation id="8703575177326907206">Vaše pripojenie k doméne <ph name="DOMAIN" /> sa nešifruje.</translation>
+<translation id="8718314106902482036">Platba nebola dokonÄená</translation>
<translation id="8725066075913043281">Skúsiť znova</translation>
<translation id="8728672262656704056">Ste v režime inkognito</translation>
<translation id="8730621377337864115">Hotovo</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="8759274551635299824">Platnosť tejto karty vypršala</translation>
<translation id="8790007591277257123">&amp;Znova vymazať</translation>
-<translation id="8798099450830957504">Predvolené</translation>
<translation id="8800988563907321413">Tu sa zobrazia návrhy funkcie Nablízku</translation>
<translation id="8820817407110198400">Záložky</translation>
<translation id="883848425547221593">Iné záložky</translation>
@@ -814,6 +826,7 @@ Nabudúce by sa vám mohol hodiť režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="8866481888320382733">Pri analýze nastavení pravidla sa vyskytla chyba</translation>
<translation id="8866959479196209191">Táto stránka hovorí:</translation>
<translation id="8870413625673593573">Naposledy zatvorené</translation>
+<translation id="8874824191258364635">Zadajte platné Äíslo karty</translation>
<translation id="8876793034577346603">Konfiguráciu siete sa nepodarilo analyzovať.</translation>
<translation id="8877192140621905067">Po potvrdení budú podrobnosti o karte zdieľané s týmto webom</translation>
<translation id="8889402386540077796">Odtieň</translation>
@@ -823,7 +836,6 @@ Nabudúce by sa vám mohol hodiť režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="8931333241327730545">Chcete túto kartu uložiÅ¥ do svojho úÄtu Google?</translation>
<translation id="8932102934695377596">Vaše hodiny idú pozadu</translation>
<translation id="8954894007019320973">(PokraÄ.)</translation>
-<translation id="895548565263634352">Čítajte Älánky od vydavateľa <ph name="ARTICLE_PUBLISHER" /> a <ph name="OTHER_ARTICLE_COUNT" /> Äalších</translation>
<translation id="8971063699422889582">Platnosť certifikátu servera vypršala.</translation>
<translation id="8986494364107987395">Automaticky odosielať Googlu štatistiky používania a správy o zlyhaní</translation>
<translation id="8987927404178983737">Mesiac</translation>
@@ -841,7 +853,6 @@ Nabudúce by sa vám mohol hodiť režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="9068849894565669697">Výber farby</translation>
<translation id="9076283476770535406">Môže zahŕňať obsah pre dospelých</translation>
<translation id="9078964945751709336">Treba zadaÅ¥ ÄalÅ¡ie informácie</translation>
-<translation id="9094175695478007090">Platobnú aplikáciu sa nepodarilo spustiť.</translation>
<translation id="9103872766612412690">Web <ph name="SITE" /> zvyÄajne chráni vaÅ¡e informácie pomocou Å¡ifrovania. KeÄ sa prehliadaÄ Chromium tentokrát pokúsil pripojiÅ¥ k webu <ph name="SITE" />, odoslal späť nezvyÄajné a nesprávne poverenia. Môže sa to staÅ¥ vtedy, keÄ sa za web <ph name="SITE" /> snaží vydávaÅ¥ útoÄník alebo keÄ pripojenie preruší prihlasovacia obrazovka siete Wi-Fi. VaÅ¡e informácie sú stále zabezpeÄené, pretože prehliadaÄ Chromium zastavil pripojenie eÅ¡te pred výmenou dát.</translation>
<translation id="9137013805542155359">Zobraziť originál</translation>
<translation id="9137248913990643158">ZaÄnite a prihláste sa do Chromu eÅ¡te predtým, ako použijete túto aplikáciu.</translation>
diff --git a/chromium/components/strings/components_strings_sl.xtb b/chromium/components/strings/components_strings_sl.xtb
index 930a4a83c3e..25bdb040cef 100644
--- a/chromium/components/strings/components_strings_sl.xtb
+++ b/chromium/components/strings/components_strings_sl.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="sl">
<translation id="1008557486741366299">Ne zdaj</translation>
<translation id="1015730422737071372">Navedite dodatne podrobnosti</translation>
+<translation id="1021110881106174305">Sprejete kartice</translation>
<translation id="1032854598605920125">Sukanje v smeri urnega kazalca</translation>
<translation id="1038842779957582377">neznano ime</translation>
<translation id="1050038467049342496">Zaprite druge aplikacije</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Skrij vrednost</translation>
<translation id="1228893227497259893">NapaÄni identifikator subjekta</translation>
<translation id="1232569758102978740">Brez naslova</translation>
+<translation id="1263231323834454256">Bralni seznam</translation>
<translation id="1264126396475825575">PoroÄilo o zruÅ¡itvi je bilo zajeto takrat: <ph name="CRASH_TIME" /> (ni Å¡e naloženo ali je prezrto)</translation>
<translation id="1285320974508926690">Nikoli ne prevedi tega spletnega mesta</translation>
<translation id="129553762522093515">Nedavno zaprto</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Nastavitve samodejnega izpolnjevanja v Chromiumu …</translation>
<translation id="1374468813861204354">predlogi</translation>
<translation id="1375198122581997741">O razliÄici</translation>
+<translation id="1377321085342047638">Card Number</translation>
<translation id="139305205187523129">Spletno mesto <ph name="HOST_NAME" /> ni poslalo nobenih podatkov.</translation>
<translation id="1407135791313364759">Odpri vse</translation>
<translation id="1413809658975081374">Napaka zasebnosti</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Zgodovina</translation>
<translation id="1645368109819982629">Nepodprt protokol</translation>
<translation id="1656489000284462475">Prevzem</translation>
+<translation id="1663943134801823270">Kartice in naslovi so iz Chroma. Upravljate jih lahko v <ph name="BEGIN_LINK" />nastavitvah<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">Spletno mesto <ph name="SITE" /> za zaÅ¡Äito vaÅ¡ih podatkov obiÄajno uporablja Å¡ifriranje. Ko se je Google Chrome tokrat poskusil povezati s spletnim mestom <ph name="SITE" />, je to vrnilo nenavadne in nepravilne poverilnice. Do tega lahko pride, Äe se napadalec lažno predstavlja za spletno mesto <ph name="SITE" /> ali Äe je povezavo prekinil zaslon za prijavo v omrežje Wi-Fi. VaÅ¡i podatki so Å¡e vedno varni, saj je Google Chrome pred izmenjavo podatkov prekinil povezavo.</translation>
<translation id="168328519870909584">Napadalci, ki so trenutno na spletnem mestu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, lahko poskusijo v vaÅ¡i napravi namestiti nevarne programe, ki kradejo ali briÅ¡ejo podatke (na primer fotografije, gesla, sporoÄila in podatke kreditnih kartic).</translation>
<translation id="168841957122794586">Potrdilo strežnika vsebuje Å¡ibek Å¡ifrirni kljuÄ.</translation>
<translation id="1710259589646384581">Operacijski sistem</translation>
<translation id="1721312023322545264"><ph name="NAME" /> vam mora odobriti obisk tega spletnega mesta</translation>
+<translation id="1721424275792716183">*Polje je obvezno</translation>
<translation id="1728677426644403582">Ogledujete si izvorno kodo spletne strani</translation>
+<translation id="173080396488393970">Ta vrsta kartice ni podprta</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Poskusite se obrniti na skrbnika sistema.</translation>
+<translation id="1740951997222943430">Vnesite veljaven mesec poteka veljavnosti</translation>
<translation id="1745358365027406341">Prenesi stran pozneje</translation>
<translation id="17513872634828108">Odpri zavihke</translation>
<translation id="1753706481035618306">Å tevilka strani</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Posodobite geslo za sinhronizacijo.</translation>
<translation id="1787142507584202372">Tu so prikazani odprti zavihki</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Izberite naslov za dostavo, Äe želite preveriti naÄine dostave in zahteve za dostavo.</translation>
+<translation id="1803264062614276815">Ime imetnika kartice</translation>
<translation id="1803678881841855883">Googlova funkcija varnega brskanja je na spletnem mestu <ph name="SITE" /> nedavno <ph name="BEGIN_LINK" />zaznala zlonamerno programsko opremo<ph name="END_LINK" />. Spletna mesta, ki so obiÄajno varna, so vÄasih okužena z zlonamerno programsko opremo. Zlonamerno vsebino razÅ¡irja znani distributer zlonamerne programske opreme, <ph name="SUBRESOURCE_HOST" />. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Dodano: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Neveljavna zahteva ali parametri zahteve</translation>
<translation id="1826516787628120939">Preverjanje</translation>
<translation id="1834321415901700177">Na tem spletnem mestu so Å¡kodljivi programi</translation>
<translation id="1842969606798536927">PlaÄilo</translation>
-<translation id="1864455488461349376">Možnost dostave</translation>
<translation id="1871208020102129563">Proxy je nastavljen na uporabo stalnih strežnikov proxy, ne na URL skripta .pac.</translation>
<translation id="1871284979644508959">Obvezno polje</translation>
<translation id="187918866476621466">Odpiranje strani ob zagonu</translation>
<translation id="1883255238294161206">Strni seznam</translation>
<translation id="1898423065542865115">Filtriranje</translation>
<translation id="194030505837763158">Pojdite na <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Dovoljene kartice</translation>
<translation id="1962204205936693436">Zaznamki domene <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Napaka pri serializaciji</translation>
<translation id="1974060860693918893">Dodatno</translation>
<translation id="1978555033938440688">RazliÄica vdelane programske opreme</translation>
+<translation id="1995859865337580572">Preverite kodo CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{in Å¡e 1}one{in Å¡e #}two{in Å¡e #}few{in Å¡e #}other{in Å¡e #}}</translation>
-<translation id="2020194265157481222">Ime na kartici je obvezno</translation>
<translation id="2025186561304664664">Strežnik proxy je nastavljen na samodejno konfiguriranje.</translation>
<translation id="2030481566774242610">Ali ste mislili <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />preveriti strežnik proxy in požarni zid<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Danes</translation>
<translation id="2154054054215849342">Sinhronizacija ni na voljo za vašo domeno</translation>
<translation id="2154484045852737596">Urejanje kartice</translation>
-<translation id="2156993118928861787">Neveljavni naslov</translation>
<translation id="2166049586286450108">Polni skrbniški dostop</translation>
<translation id="2166378884831602661">To spletno mesto ne more zagotoviti varne povezave</translation>
<translation id="2181821976797666341">Pravilniki</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 naslov}one{# naslov}two{# naslova}few{# naslovi}other{# naslovov}}</translation>
+<translation id="2202020181578195191">Vnesite veljavno leto poteka veljavnosti</translation>
<translation id="2212735316055980242">Pravilnika ni mogoÄe najti</translation>
<translation id="2213606439339815911">Prenos vnosov ...</translation>
<translation id="2230458221926704099">Odpravite težave s povezavo z <ph name="BEGIN_LINK" />aplikacijo za diagnostiko<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Internetni dostop je blokiran</translation>
<translation id="230155334948463882">Nova kartica?</translation>
<translation id="2305919008529760154">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je bilo morda izdano z goljufijo. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Možnosti kartic in naslovov so iz Google RaÄuna (<ph name="ACCOUNT_EMAIL" />) in Chroma. To je mogoÄe upravljati v <ph name="BEGIN_LINK" />nastavitvah<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535">Domena <ph name="DOMAIN" /> zahteva uporabniško ime in geslo.</translation>
<translation id="2318774815570432836">Spletnega mesta <ph name="SITE" /> trenutno ni mogoÄe obiskati, saj uporablja protokol HSTS. Napake omrežja in napadi na omrežje so obiÄajno zaÄasni, zato bo ta stran verjetno delovala pozneje. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2354001756790975382">Drugi zaznamki</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Privzeto za podjetja</translation>
<translation id="2386255080630008482">Potrdilo strežnika je bilo preklicano.</translation>
<translation id="2392959068659972793">Pokaži pravilnike brez nastavljene vrednosti</translation>
+<translation id="239429038616798445">Ta naÄin poÅ¡iljanja ni na voljo. Poskusite uporabiti drugega.</translation>
<translation id="2396249848217231973">&amp;Razveljavi izbris</translation>
<translation id="2460160116472764928">Googlova funkcija varnega brskanja je na spletnem mestu <ph name="SITE" /> nedavno <ph name="BEGIN_LINK" />zaznala zlonamerno programsko opremo<ph name="END_LINK" />.Spletna mesta, ki so obiÄajno varna, so vÄasih okužena z zlonamerno programsko opremo. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Izpolni</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Izvajanje orodja za omrežno diagnostiko<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Neveljaven URL iskanja.</translation>
<translation id="2491120439723279231">V potrdilu strežnika so napake.</translation>
-<translation id="24943777258388405">Neveljavna telefonska Å¡tevilka</translation>
<translation id="2495083838625180221">RazÄlenjevalnik za JSON</translation>
<translation id="2495093607237746763">Če je izbrana ta možnost, bo Chromium shranil kopijo kartice v tej napravi za hitrejše izpolnjevanje obrazcev.</translation>
<translation id="2498091847651709837">OptiÄno branje nove kartice</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027">Spletno mesto <ph name="HOST_NAME" /> je poslalo neveljaven odgovor.</translation>
<translation id="2552545117464357659">Novejša</translation>
<translation id="2556876185419854533">&amp;Razveljavi urejanje</translation>
+<translation id="2587730715158995865">Izdajatelj: <ph name="ARTICLE_PUBLISHER" />. Preberite to in Å¡e toliko drugih Älankov: <ph name="OTHER_ARTICLE_COUNT" />.</translation>
<translation id="2587841377698384444">ID API-ja imenika:</translation>
<translation id="2597378329261239068">Dokument je zaÅ¡Äiten z geslom. Vnesite geslo.</translation>
<translation id="2609632851001447353">RazliÄice</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Izvajanje orodja Diagnostika povezljivosti<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">V redu</translation>
<translation id="2742870351467570537">Odstrani izbrane elemente</translation>
+<translation id="277133753123645258">NaÄin poÅ¡iljanja</translation>
<translation id="277499241957683684">Manjka zapis o napravi</translation>
<translation id="2784949926578158345">Povezava je bila obnovljena.</translation>
<translation id="2794233252405721443">Spletno mesto blokirano</translation>
-<translation id="2812680587231492111">Ta možnost prevzema ni na voljo. Poskusite drugo.</translation>
<translation id="2824775600643448204">Naslovna in iskalna vrstica</translation>
<translation id="2826760142808435982">Za Å¡ifriranje in preverjanje pristnosti povezave se uporablja <ph name="CIPHER" />, kot mehanizem za izmenjavo kljuÄev pa <ph name="KX" />.</translation>
<translation id="2835170189407361413">PoÄisti obrazec</translation>
-<translation id="2849041323157393173">Ta možnost dostave ni na voljo. Poskusite drugo.</translation>
<translation id="2889159643044928134">Ne naloži znova</translation>
<translation id="2900469785430194048">Google Chromu je med poskusom prikazovanja te spletne strani zmanjkalo pomnilnika.</translation>
<translation id="2909946352844186028">Zaznana je bila sprememba omrežja.</translation>
<translation id="2916038427272391327">Zaprite druge programe</translation>
<translation id="2922350208395188000">Potrdila strežnika ni mogoÄe preveriti.</translation>
+<translation id="2928905813689894207">Naslov za izstavitev raÄuna</translation>
<translation id="2948083400971632585">NamestniÅ¡ke strežnike, konfigurirane za povezavo, lahko onemogoÄite na strani z nastavitvami.</translation>
<translation id="2955913368246107853">Zapri vrstico za iskanje</translation>
<translation id="2958431318199492670">Omrežna konfiguracija ne ustreza standardu ONC. Deli konfiguracije morda niso bili uvoženi.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">ÄŒ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 naprave nepravilna, Google Chrome teh potrdil ne more preveriti.</translation>
<translation id="2972581237482394796">&amp;Uveljavi</translation>
<translation id="2985306909656435243">ÄŒe je to omogoÄeno, Chromium shrani kopijo kartice v tej napravi zaradi hitrejÅ¡ega izpolnjevanja obrazcev.</translation>
+<translation id="2985398929374701810">Vnesite veljaven naslov</translation>
+<translation id="2986368408720340940">Ta naÄin prevzema ni na voljo. Poskusite uporabiti drugega.</translation>
<translation id="2991174974383378012">Deljenje s spletnimi mesti</translation>
<translation id="3005723025932146533">Pokaži shranjeno kopijo</translation>
<translation id="3008447029300691911">Vnesite CVC za <ph name="CREDIT_CARD" />. Ko potrdite, bodo temu spletnemu mestu razkriti podatki o vaši kartici.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{vsaj en element v sinhroniziranih napravah}=1{1 element (in veÄ v sinhroniziranih napravah)}one{# element (in veÄ v sinhroniziranih napravah)}two{# elementa (in veÄ v sinhroniziranih napravah)}few{# elementi (in veÄ v sinhroniziranih napravah)}other{# elementov (in veÄ v sinhroniziranih napravah)}}</translation>
<translation id="3041612393474885105">Informacije o potrdilu</translation>
<translation id="3063697135517575841">Chrome trenutno ni mogel potrditi vaše kartice. Poskusite znova pozneje.</translation>
+<translation id="3064966200440839136">Zaradi plaÄila v zunanji aplikaciji boste zapustili naÄin brez beleženja zgodovine. Želite nadaljevati?</translation>
<translation id="3093245981617870298">Povezava ni vzpostavljena.</translation>
<translation id="3105172416063519923">ID sredstva:</translation>
<translation id="3109728660330352905">Nimate dovoljenja za ogled te strani.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Poskušajte zagnati orodje Diagnostika povezljivosti<ph name="END_LINK" /></translation>
<translation id="3145945101586104090">Dekodiranje odziva ni uspelo</translation>
-<translation id="3149891296864842641">Možnost pošiljanja</translation>
<translation id="3150653042067488994">ZaÄasna napaka strežnika</translation>
+<translation id="3154506275960390542">Na tej strani je tudi obrazec, ki morda ne bo poslan varno. Podatke, ki jih pošljete, si lahko med prenosom ogledujejo drugi, ali pa jih lahko spremeni morebitni napadalec, tako da strežnik prejme spremenjene podatke.</translation>
<translation id="3157931365184549694">Obnovi</translation>
<translation id="3167968892399408617">Strani, ki si jih ogledujete na zavihkih brez beleženja zgodovine, se ne bodo ohranile v zgodovini brskalnika, hrambi piškotkov ali zgodovini iskanja, ko boste zaprli vse zavihke brez beleženja zgodovine. Datoteke, ki jih prenesete, ali zaznamki, ki jih ustvarite, se bodo ohranili.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Zahteve za dostop do tega spletnega mesta ni bilo mogoÄe poslati osebi <ph name="NAME" />. Poskusite znova.</translation>
<translation id="3355823806454867987">Spremeni nastavitve proxyja ...</translation>
<translation id="3369192424181595722">Napaka ure</translation>
+<translation id="337311366426640088">Å e toliko elementov: <ph name="ITEM_COUNT" /> ...</translation>
<translation id="337363190475750230">Nepripravljen</translation>
<translation id="3377188786107721145">Napaka pri razÄlenjevanju pravilnika</translation>
<translation id="3380365263193509176">Neznana napaka</translation>
<translation id="3380864720620200369">ID odjemalca:</translation>
<translation id="3391030046425686457">Naslov za dostavo</translation>
+<translation id="3395827396354264108">NaÄin prevzema</translation>
<translation id="340013220407300675">Napadalci morda poskuÅ¡ajo ukrasti vaÅ¡e podatke s spletnega mesta <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (na primer gesla, sporoÄila ali kreditne kartice).</translation>
<translation id="3422248202833853650">Poskusite zapreti druge programe, da boste tako sprostili pomnilnik.</translation>
<translation id="3422472998109090673">Spletno mesto <ph name="HOST_NAME" /> trenutno ni dosegljivo.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">Mastercard</translation>
<translation id="3452404311384756672">Interval prejemanja:</translation>
<translation id="3462200631372590220">Skrij podrobnosti</translation>
+<translation id="3467763166455606212">Ime imetnika kartice je obvezno</translation>
+<translation id="3478058380795961209">Expiration Month</translation>
<translation id="3479539252931486093">Ali tega niste priÄakovali? <ph name="BEGIN_LINK" />SporoÄite nam<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Ne zdaj</translation>
<translation id="348000606199325318">ID zrušitve <ph name="CRASH_LOCAL_ID" /> (ID strežnika: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Trenutno ni mogoÄe vzpostaviti stika s starÅ¡em. Poskusi znova pozneje.</translation>
<translation id="3528171143076753409">Potrdilo strežnika ni zaupanja vredno.</translation>
-<translation id="3538531656504267329">Neveljavno leto poteka</translation>
<translation id="3539171420378717834">Ohrani kopijo te kartice v tej napravi</translation>
<translation id="3542684924769048008">Uporaba gesla za:</translation>
<translation id="3549644494707163724">Å ifrirajte vse sinhronizirane podatke s svojim geslom</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Skrij podrobnosti</translation>
<translation id="3587482841069643663">Vse</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Vnesite veljaven datum poteka veljavnosti</translation>
<translation id="36224234498066874">Izbriši podatke brskanja ...</translation>
<translation id="362276910939193118">Prikaži celotno zgodovino</translation>
<translation id="3623476034248543066">Pokaži vrednost</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Geslo:</translation>
<translation id="3696411085566228381">brez</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Izberite naslov za poÅ¡iljanje, Äe želite preveriti naÄine poÅ¡iljanja in zahteve za poÅ¡iljanje.</translation>
<translation id="370665806235115550">Nalaganje ...</translation>
<translation id="3712624925041724820">Ni dovolj licenc</translation>
<translation id="3714780639079136834">vklopiti prenos podatkov v mobilnih omrežjih ali Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Povezava, ki ste jo kopirali</translation>
<translation id="375403751935624634">Prevajanje ni uspelo zaradi napake strežnika.</translation>
<translation id="3759461132968374835">Nimate nedavnih poroÄil o zruÅ¡itvah. ZruÅ¡itve, do katerih je priÅ¡lo, ko je bilo poroÄanje onemogoÄeno, ne bodo prikazane zukaj.</translation>
+<translation id="3787705759683870569">PoteÄe: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Če uporabite namestniški strežnik ...</translation>
<translation id="3828924085048779000">Prazno geslo ni dovoljeno.</translation>
<translation id="3845539888601087042">Prikazana je zgodovina iz naprav, v katere ste prijavljeni. <ph name="BEGIN_LINK" />VeÄ o tem<ph name="END_LINK" /></translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Ali želite, da Chromium shrani to kartico?</translation>
<translation id="4171400957073367226">Neveljavni podpis za preverjanje</translation>
-<translation id="4176463684765177261">OnemogoÄeno</translation>
<translation id="4196861286325780578">&amp;Uveljavi premik</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />preveriti požarni zid in konfiguracije protivirusnega programa<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{niÄ}=1{1 aplikacija ($1)}=2{2 aplikaciji ($1, $2)}one{# aplikacija ($1, $2, $3)}two{# aplikaciji ($1, $2, $3)}few{# aplikacije ($1, $2, $3)}other{# aplikacij ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">rezultati iskanja</translation>
<translation id="4432688616882109544">Spletno mesto <ph name="HOST_NAME" /> ni sprejelo potrdila za prijavo ali pa to ni bilo posredovano.</translation>
<translation id="443673843213245140">Uporaba strežnika proxy je onemogoÄena, vendar je njegova konfiguracija izrecno doloÄena.</translation>
-<translation id="4446242550670694251">Zdaj je mogoÄe brskati zasebno in drugi, ki uporabljajo to napravo, ne bodo videli vaÅ¡e dejavnosti.</translation>
<translation id="4492190037599258964">Rezultati iskanja za »<ph name="SEARCH_STRING" />«</translation>
<translation id="4506176782989081258">Napaka pri preverjanju veljavnosti: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">se obrniti na skrbnika sistema</translation>
<translation id="450710068430902550">Deljenje s skrbnikom</translation>
+<translation id="4515275063822566619">Kartice in naslovi so iz Chroma in Google RaÄuna (<ph name="ACCOUNT_EMAIL" />). Upravljate jih lahko v <ph name="BEGIN_LINK" />nastavitvah<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Podrobnosti</translation>
<translation id="4558551763791394412">Poskusite onemogoÄiti razÅ¡iritve.</translation>
<translation id="457875822857220463">Dostava</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Prilagodi strani</translation>
<translation id="483020001682031208">Ni strani za FiziÄni splet za prikaz</translation>
<translation id="4850886885716139402">Pogled</translation>
+<translation id="4854362297993841467">Ta naÄin poÅ¡iljanja ni na voljo. Poskusite uporabiti drugega.</translation>
<translation id="4858792381671956233">Starše si vprašal(-a), ali smeš obiskati to spletno mesto</translation>
<translation id="4880827082731008257">Zgodovina iskanja</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Stran je bila iz neznanega jezika prevedena v jezik »<ph name="LANGUAGE_LANGUAGE" />«</translation>
<translation id="4923459931733593730">PlaÄilo</translation>
<translation id="4926049483395192435">Vrednost mora biti doloÄena.</translation>
-<translation id="4941291666397027948">* oznaÄuje obvezno polje</translation>
<translation id="495170559598752135">Dejanja</translation>
<translation id="4958444002117714549">Razširi seznam</translation>
<translation id="4962322354953122629">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; Chrome ne zaupa njegovemu varnostnemu potrdilu. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Nepravilno geslo</translation>
<translation id="5056549851600133418">ÄŒlanki za vas</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />preveriti naslov strežnika proxy<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Brez piškotkov}=1{1 spletno mesto uporablja piškotke. }one{# spletno mesto uporablja piškotke. }two{# spletni mesti uporabljata piškotke. }few{# spletna mesta uporabljajo piškotke. }other{# spletnih mest uporablja piškotke. }}</translation>
<translation id="5087286274860437796">Potrdilo strežnika trenutno ni veljavno.</translation>
<translation id="5087580092889165836">Dodaj kartico</translation>
<translation id="5089810972385038852">Zvezna država</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Pokaži</translation>
<translation id="5308689395849655368">PoroÄanje o zruÅ¡itvah je onemogoÄeno.</translation>
<translation id="5317780077021120954">Shrani</translation>
-<translation id="5326702247179446998">Vnos prejemnika je obvezen</translation>
<translation id="5327248766486351172">Ime</translation>
<translation id="5337705430875057403">Napadalci na spletnem mestu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> vas lahko z zavajanjem pripravijo do tega, da storite kaj nevarnega – denimo, da namestite programsko opremo ali razkrijete osebne podatke (na primer gesla, telefonske številke ali podatke kreditnih kartic).</translation>
-<translation id="53553865750799677">Nepodprt naslov za dostavo. Izberite drug naslov.</translation>
<translation id="5359637492792381994">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo trenutno ni veljavno. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Nastavitev pravilnika ni bilo mogoÄe shraniti</translation>
<translation id="5386426401304769735">Veriga potrdil za to spletno mesto vsebuje potrdilo, podpisano z algoritmom SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">Vdelana stran na spletnem mestu <ph name="SITE" /> sporoÄa:</translation>
<translation id="5556459405103347317">Ponovno naloži</translation>
<translation id="5565735124758917034">Aktivno</translation>
+<translation id="5571083550517324815">Prevzem na tem naslovu ni mogoÄ. Izberite drugega.</translation>
<translation id="5572851009514199876">ZaÄnite s prijavo v Chrome, da lahko Chrome preveri, ali vam je dovoljeno dostopati do tega spletnega mesta.</translation>
-<translation id="5575380383496039204">Nepodprt naslov za dostavo. Izberite drug naslov.</translation>
<translation id="5580958916614886209">Preverite mesec poteka veljavnosti in poskusite znova</translation>
<translation id="560412284261940334">Upravljanje ni podprto</translation>
<translation id="5610142619324316209">preveriti povezavo</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">Identiteta tega spletnega mesta ni bila potrjena.</translation>
<translation id="5720705177508910913">Trenutni uporabnik</translation>
<translation id="5732392974455271431">Starši ga lahko odblokirajo</translation>
-<translation id="57586589942790530">Neveljavna Å¡tevilka kartice</translation>
+<translation id="5763042198335101085">Vnesite veljaven e-poštni naslov</translation>
+<translation id="5765072501007116331">ÄŒe si želite ogledati naÄine dostave in zahteve, izberite naslov</translation>
<translation id="5784606427469807560">Težava pri potrditvi kartice. Preverite internetno povezavo in poskusite znova.</translation>
<translation id="5785756445106461925">Poleg tega so na tej strani druga sredstva, ki niso varna. Ta sredstva lahko med prenosom pregledujejo drugi, morebitni napadalec pa jih lahko spremeni, tako da se spremeni videz strani.</translation>
<translation id="5786044859038896871">Ali želite izpolniti podatke kreditne kartice?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">Tega spletnega mesta ni mogoÄe doseÄi</translation>
<translation id="5869522115854928033">Shranjena gesla</translation>
<translation id="5872918882028971132">Predlogi staršev</translation>
-<translation id="587760065310675640">Nepodprt naslov za pošiljanje. Izberite drug naslov.</translation>
<translation id="5901630391730855834">Rumena</translation>
-<translation id="59174027418879706">OmogoÄena</translation>
<translation id="5926846154125914413">Morda boste izgubili dostop do plaÄljive vsebine na nekaterih spletnih mestih.</translation>
<translation id="5959728338436674663">Samodejno pošlji Googlu nekatere <ph name="BEGIN_WHITEPAPER_LINK" />sistemske podatke in vsebino strani<ph name="END_WHITEPAPER_LINK" /> zaradi zaznavanja nevarnih aplikacij in spletnih mest. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Teden</translation>
<translation id="5967867314010545767">Odstrani iz zgodovine</translation>
<translation id="5975083100439434680">Pomanjšaj</translation>
+<translation id="598637245381783098">PlaÄilne aplikacije ni mogoÄe odpreti</translation>
<translation id="5989320800837274978">DoloÄeni niso ne stalni strežniki proxy ne URL skripta .pac.</translation>
<translation id="5990559369517809815">Zahteve za strežnik je blokirala razširitev.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Možnosti kartic in naslovov so iz Chroma. Upravljati jih je mogoÄe v <ph name="BEGIN_LINK" />nastavitvah<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Stran 1}one{Stran #}two{Stran #}few{Stran #}other{Stran #}}</translation>
<translation id="6017514345406065928">Zelena</translation>
+<translation id="6027201098523975773">Vnesite ime</translation>
<translation id="6040143037577758943">Zapri</translation>
-<translation id="604124094241169006">Samodejno</translation>
<translation id="6042308850641462728">VeÄ</translation>
<translation id="6060685159320643512">Previdno, ti poskusi lahko Å¡kodujejo</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{niÄ}=1{1}one{#}two{#}few{#}other{#}}</translation>
@@ -543,9 +552,10 @@
naprave, ki jih uporabljate.</translation>
<translation id="614940544461990577">Poskusite:</translation>
<translation id="6151417162996330722">Potrdilo strežnika ima predolgo obdobje veljavnosti.</translation>
-<translation id="615643356032862689">Prenesene datoteke in zaznamki bodo ohranjeni.</translation>
+<translation id="6157877588268064908">ÄŒe si želite ogledati naÄine poÅ¡iljanja in zahteve, izberite naslov</translation>
<translation id="6165508094623778733">VeÄ o tem</translation>
<translation id="6177128806592000436">Povezava s tem spletnim mestom ni zasebna</translation>
+<translation id="6184817833369986695">(kohorta: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Preverite internetno povezavo</translation>
<translation id="6218753634732582820">Želite naslov odstraniti iz Chromiuma?</translation>
<translation id="6251924700383757765">Pravilnik o zasebnosti</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Uveljavi razvrstitev</translation>
<translation id="6263376278284652872">Zaznamki <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Nazaj na varnost</translation>
+<translation id="6276112860590028508">Strani z bralnega seznama so prikazane tukaj</translation>
+<translation id="6280223929691119688">Dostava na ta naslov ni mogoÄa. Izberite drugega.</translation>
<translation id="6282194474023008486">Poštna številka</translation>
<translation id="6290238015253830360">Tu so prikazani predlagani Älanki</translation>
<translation id="6305205051461490394">Naslov <ph name="URL" /> je nedosegljiv.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Ni mogoÄe preveriti, ali je bilo potrdilo preklicano.</translation>
<translation id="6433490469411711332">Uredi informacije o stiku</translation>
<translation id="6433595998831338502">Spletno mesto <ph name="HOST_NAME" /> ni dovolilo povezave.</translation>
-<translation id="6443118737398455446">Datum poteka ni veljaven</translation>
<translation id="6446608382365791566">Dodajanje veÄ podatkov</translation>
<translation id="6451458296329894277">Potrdite ponovno pošiljanje obrazca</translation>
<translation id="6456339708790392414">PlaÄilo</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je bilo morda preklicano. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Pravilniki za naprave</translation>
<translation id="6477321094435799029">Chrome je zaznal nenavadno kodo na tej strani in jo zaradi zaÅ¡Äite vaÅ¡ih osebnih podatkov (na primer gesel, telefonskih Å¡tevilk in kreditnih kartic) blokiral.</translation>
-<translation id="6477460825583319731">Neveljaven e-poštni naslov</translation>
<translation id="6489534406876378309">ZaÄetek prenaÅ¡anja zruÅ¡itev v storitev</translation>
<translation id="6508722015517270189">Znova zaženite Chrome</translation>
-<translation id="6525462735697194615">Neveljaven mesec poteka</translation>
<translation id="6529602333819889595">&amp;Uveljavi izbris</translation>
<translation id="6534179046333460208">Predlogi za FiziÄni splet</translation>
<translation id="6550675742724504774">Možnosti</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Iskanje</translation>
<translation id="6644283850729428850">Ta pravilnik je zastarel.</translation>
<translation id="6652240803263749613">Temu strežniku ni uspelo dokazati, da je domena <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. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Ta možnost pošiljanja ni na voljo. Poskusite drugo.</translation>
<translation id="6671697161687535275">Želite predlog obrazca odstraniti iz Chromiuma?</translation>
<translation id="6685834062052613830">Odjavite se in dokonÄajte nastavitev</translation>
<translation id="6710213216561001401">Nazaj</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Nekaj je narobe s strežnikom proxy ali pa naslov ni pravilen.</translation>
<translation id="6727102863431372879">Nastavi</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{niÄ}=1{1 element}one{# element}two{# elementa}few{# elementi}other{# elementov}}</translation>
-<translation id="6743044928064272573">Možnosti prevzema</translation>
<translation id="674375294223700098">Neznana napaka potrdila strežnika.</translation>
<translation id="6753269504797312559">Vrednost pravilnika</translation>
<translation id="6757797048963528358">Naprava je preklopila v stanje pripravljenosti.</translation>
<translation id="6778737459546443941">Starši še niso odobrili</translation>
<translation id="6810899417690483278">ID za prilagajanje</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Podatkov o obmoÄjih ni bilo mogoÄe naložiti</translation>
<translation id="6831043979455480757">Prevedi</translation>
<translation id="6839929833149231406">ObmoÄje</translation>
<translation id="6874604403660855544">&amp;Uveljavi dodajanje</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Kartica je potrjena.</translation>
<translation id="6897140037006041989">Uporabnikov posrednik</translation>
<translation id="6915804003454593391">Uporabnik:</translation>
+<translation id="6948701128805548767">ÄŒe si želite ogledati naÄine prevzema in zahteve, izberite naslov</translation>
<translation id="6957887021205513506">Potrdilo strežnika je oÄitno ponaredek.</translation>
<translation id="6965382102122355670">V redu</translation>
<translation id="6965978654500191972">Naprava</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">DoloÄeni so stalni strežniki proxy in URL skripta .pac.</translation>
<translation id="6989763994942163495">Prikaži dodatne nastavitve ...</translation>
<translation id="7000990526846637657">Ni vnosov v zgodovino</translation>
-<translation id="7001663382399377034">Dodajanje prejemnika</translation>
<translation id="7009986207543992532">Poskusili ste dostopati do domene <ph name="DOMAIN" />, vendar je strežnik uporabil potrdilo, ki ima predolgo obdobje veljavnosti, da bi bilo verodostojno. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">V Google RaÄunu so morda druge vrste zgodovine brskanja na <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Starejše</translation>
<translation id="7090678807593890770">IÅ¡Äite v Googlu s poizvedbo <ph name="LINK" /></translation>
<translation id="7119414471315195487">Zaprite druge zavihke ali programe</translation>
+<translation id="7129409597930077180">PoÅ¡iljanje na ta naslov ni mogoÄe. Izberite drugega.</translation>
+<translation id="7138472120740807366">NaÄin dostave</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7155487117670177674">PlaÄilo ni varno</translation>
<translation id="7179921470347911571">Znova zaženi</translation>
<translation id="7180611975245234373">Osveži</translation>
<translation id="7182878459783632708">Ni nastavljenih pravilnikov</translation>
<translation id="7186367841673660872">Ta stran je bila prevedena iz jezika<ph name="ORIGINAL_LANGUAGE" />v jezik<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423">Spletno mesto <ph name="HOST_NAME" /> ne upošteva varnostnih standardov.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />VeÄ o<ph name="END_LINK" /> tej težavi.</translation>
@@ -675,7 +686,6 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="7424977062513257142">Vdelana stran na tej spletni strani sporoÄa:</translation>
<translation id="7441627299479586546">NapaÄen subjekt pravilnika</translation>
<translation id="7444046173054089907">To spletno mesto je blokirano</translation>
-<translation id="7444238235002594607">Izberite naslov za prevzem, Äe želite preveriti naÄine prevzema in zahteve za prevzem.</translation>
<translation id="7445762425076701745">Identitete strežnika, s katerim ste povezani, ni mogoÄe v celoti preveriti. S strežnikom ste povezani z uporabo imena, ki je veljavno samo v vaÅ¡em omrežju, zato zunanji overitelj potrdil ne more preveriti njegovega lastniÅ¡tva. Ker nekateri overitelji potrdil kljub temu izdajajo potrdila za takÅ¡na imena, ni mogoÄe zagotoviti, da ste povezani z želenim spletnim mestom in ne z napadalcem.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Preberite veÄ<ph name="END_LINK" /> o tej težavi.</translation>
<translation id="7460163899615895653">Tu so prikazani nedavni zavihki iz drugih naprav</translation>
@@ -719,6 +729,7 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="7755287808199759310">Starš ga lahko odblokira</translation>
<translation id="7758069387465995638">Povezavo je morda blokiral požarni zid ali protivirusni program.</translation>
<translation id="7761701407923456692">Potrdilo strežnika se ne ujema z URL-jem.</translation>
+<translation id="7763386264682878361">RazÄlenjevalnik manifesta plaÄil</translation>
<translation id="7764225426217299476">Dodaj naslov</translation>
<translation id="777702478322588152">Prefektura</translation>
<translation id="7791543448312431591">Dodaj</translation>
@@ -732,6 +743,7 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="785549533363645510">Kljub temu pa niste nevidni. Z uporabo naÄina brez beleženja zgodovine brskanja ne skrijete pred delodajalcem, ponudnikom internetnih storitev ali spletnimi mesti, ki jih obiÅ¡Äete.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" />: <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Preverite CVC in poskusite znova</translation>
+<translation id="79338296614623784">Vnesite veljavno telefonsko Å¡tevilko</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Potrdilo strežnika še ni veljavno.</translation>
<translation id="7942349550061667556">RdeÄa</translation>
@@ -751,6 +763,7 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="8088680233425245692">ÄŒlanka si ni bilo mogoÄe ogledati.</translation>
<translation id="8089520772729574115">manj kot 1 MB</translation>
<translation id="8091372947890762290">Čakanje na aktivacijo v strežniku</translation>
+<translation id="8118489163946903409">PlaÄilno sredstvo</translation>
<translation id="8131740175452115882">Potrdi</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Naslova DNS<ph name="END_ABBR" /> strežnika spletnega mesta <ph name="HOST_NAME" /> ni bilo mogoÄe najti.</translation>
<translation id="8149426793427495338">RaÄunalnik je preklopil v stanje pripravljenosti.</translation>
@@ -776,6 +789,7 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="8349305172487531364">Vrstica z zaznamki</translation>
<translation id="8363502534493474904">izklopiti naÄin za letalo</translation>
<translation id="8364627913115013041">Ni nastavljen.</translation>
+<translation id="8368476060205742148">Storitve Google Play</translation>
<translation id="8380941800586852976">Nevarno</translation>
<translation id="8382348898565613901">Tu so prikazani nedavno obiskani zaznamki</translation>
<translation id="8398259832188219207">PoroÄilo o zruÅ¡itvi je bilo naloženo takrat: <ph name="UPLOAD_TIME" /></translation>
@@ -784,31 +798,29 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="8428213095426709021">Nastavitve</translation>
<translation id="8433057134996913067">S tem boste odjavljeni z veÄine spletnih mest.</translation>
<translation id="8437238597147034694">&amp;Razveljavi premik</translation>
-<translation id="8456681095658380701">Neveljavno ime</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 kreditna kartica}one{# kreditna kartica}two{# kreditni kartici}few{# kreditne kartice}other{# kreditnih kartic}}</translation>
<translation id="8483780878231876732">ÄŒe želite uporabljati kartice iz Google RaÄuna, se prijavite v Chrome</translation>
<translation id="8488350697529856933">Velja za</translation>
-<translation id="8492969205326575646">Nepodprta vrsta kartice</translation>
<translation id="8498891568109133222">Spletno mesto <ph name="HOST_NAME" /> se ni odzvalo v ustreznem Äasu.</translation>
<translation id="852346902619691059">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; operacijski sistem vaÅ¡e naprave ne zaupa njegovemu varnostnemu potrdilu. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Expiration Year</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />Prijavite lahko težavo z zaznavanjem<ph name="END_ERROR_LINK" />, Äe razumete varnostna tveganja, pa lahko <ph name="BEGIN_LINK" />obiÅ¡Äete to spletno mesto, ki ni varno<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Prevod ni uspel, ker ni mogoÄe doloÄiti jezika strani.</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="8570229484593575558">Ti podatki |ne bodo shranjeni|:#zgodovina brskanja#iskanja#podatki piškotkov</translation>
<translation id="8571890674111243710">Prevajanje strani v jezik <ph name="LANGUAGE" /> ...</translation>
-<translation id="8584539743998202583">VaÅ¡a dejavnost |bo morda Å¡e vedno vidna|:#spletnim mestom, ki jih obiÅ¡Äete#delodajalcu#ponudniku internetnih storitev</translation>
<translation id="858637041960032120">Dodajte tel. Å¡t. </translation>
<translation id="859285277496340001">Potrdilo ne navaja mehanizma za preverjanje tega, ali je bilo preklicano.</translation>
<translation id="8620436878122366504">Starši še niso odobrili</translation>
<translation id="8647750283161643317">Ponastavi vse na privzete</translation>
<translation id="8703575177326907206">Vaša povezava z <ph name="DOMAIN" /> ni kodirana.</translation>
+<translation id="8718314106902482036">PlaÄilo ni konÄano</translation>
<translation id="8725066075913043281">Poskusite znova</translation>
<translation id="8728672262656704056">Uporabljate naÄin brez beleženja zgodovine</translation>
<translation id="8730621377337864115">KonÄano</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="8759274551635299824">Ta kartica je potekla</translation>
<translation id="8790007591277257123">&amp;Uveljavi izbris</translation>
-<translation id="8798099450830957504">Privzeto</translation>
<translation id="8800988563907321413">Tu so prikazani predlogi v bližini</translation>
<translation id="8820817407110198400">Zaznamki</translation>
<translation id="883848425547221593">Drugi zaznamki</translation>
@@ -818,6 +830,7 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="8866481888320382733">Napaka pri razÄlenjevanju nastavitev pravilnika</translation>
<translation id="8866959479196209191">Ta stran sporoÄa:</translation>
<translation id="8870413625673593573">Nedavno zaprto</translation>
+<translation id="8874824191258364635">Vnesite veljavno Å¡tevilko kartice</translation>
<translation id="8876793034577346603">Omrežne konfiguracije ni bilo mogoÄe razÄleniti.</translation>
<translation id="8877192140621905067">Ko potrdite, bodo temu spletnemu mestu razkriti podatki o kartici.</translation>
<translation id="8889402386540077796">Odtenek</translation>
@@ -827,7 +840,6 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="8931333241327730545">Ali želite to kartico shraniti v Google RaÄun?</translation>
<translation id="8932102934695377596">Ura zaostaja</translation>
<translation id="8954894007019320973">(Nadalj.)</translation>
-<translation id="895548565263634352">Branje novic izdajatelja <ph name="ARTICLE_PUBLISHER" /> in Å¡e toliko drugih: <ph name="OTHER_ARTICLE_COUNT" /></translation>
<translation id="8971063699422889582">Potrdilo strežnika je poteklo.</translation>
<translation id="8986494364107987395">Samodejno poÅ¡lji statistiÄne podatke o uporabi in poroÄila o zruÅ¡itvah Googlu</translation>
<translation id="8987927404178983737">Mesec</translation>
@@ -845,7 +857,6 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="9068849894565669697">Izbira barve</translation>
<translation id="9076283476770535406">Morda vsebuje vsebino za odrasle</translation>
<translation id="9078964945751709336">Vnesti morate veÄ podatkov</translation>
-<translation id="9094175695478007090">Aplikacije za plaÄevanje ni mogoÄe zagnati.</translation>
<translation id="9103872766612412690">Spletno mesto <ph name="SITE" /> za zaÅ¡Äito vaÅ¡ih podatkov obiÄajno uporablja Å¡ifriranje. Ko se je Chromium tokrat poskusil povezati s spletnim mestom <ph name="SITE" />, je to vrnilo nenavadne in nepravilne poverilnice. Do tega lahko pride, Äe se napadalec lažno predstavlja za spletno mesto <ph name="SITE" /> ali Äe je povezavo prekinil zaslon za prijavo v omrežje Wi-Fi. VaÅ¡i podatki so Å¡e vedno varni, saj je Chromium pred izmenjavo podatkov prekinil povezavo.</translation>
<translation id="9137013805542155359">Pokaži izvirno besedilo</translation>
<translation id="9137248913990643158">ZaÄnite s prijavo v Chrome, preden zaÄnete uporabljati to aplikacijo.</translation>
diff --git a/chromium/components/strings/components_strings_sr.xtb b/chromium/components/strings/components_strings_sr.xtb
index 5023b8444a8..674c02c696a 100644
--- a/chromium/components/strings/components_strings_sr.xtb
+++ b/chromium/components/strings/components_strings_sr.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="sr">
<translation id="1008557486741366299">Ðе Ñада</translation>
<translation id="1015730422737071372">Ðаведите додатне детаље</translation>
+<translation id="1021110881106174305">Прихваћене картице</translation>
<translation id="1032854598605920125">Окрените у Ñмеру казаљке на Ñату</translation>
<translation id="1038842779957582377">непознато име</translation>
<translation id="1050038467049342496">Затворите друге апликације</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Сакриј вредноÑÑ‚</translation>
<translation id="1228893227497259893">Погрешан идентификатор ентитета</translation>
<translation id="1232569758102978740">ÐенаÑловљено</translation>
+<translation id="1263231323834454256">ЛиÑта за читање</translation>
<translation id="1264126396475825575">Извештај о отказивању је Ñнимљен <ph name="CRASH_TIME" /> (још увек није отпремљен или игнориÑан)</translation>
<translation id="1285320974508926690">Ðикад не преводи овај Ñајт</translation>
<translation id="129553762522093515">Ðедавно затворено</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Подешавања Chromium аутоматÑког попуњавања...</translation>
<translation id="1374468813861204354">предлози</translation>
<translation id="1375198122581997741">О верзији</translation>
+<translation id="1377321085342047638">Број картице</translation>
<translation id="139305205187523129">ХоÑÑ‚ <ph name="HOST_NAME" /> није поÑлао никакве податке.</translation>
<translation id="1407135791313364759">Отвори Ñве</translation>
<translation id="1413809658975081374">Грешка у вези Ñа приватношћу</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">ИÑторија</translation>
<translation id="1645368109819982629">Ðеподржани протокол</translation>
<translation id="1656489000284462475">Преузимање</translation>
+<translation id="1663943134801823270">Картице и адреÑе Ñу из Chrome-а. Њима можете да управљате у <ph name="BEGIN_LINK" />подешавањима<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> обично кориÑти шифровање да би заштитио информације. Када је Google Chrome овог пута покушао да Ñе повеже Ñа <ph name="SITE" />, веб-Ñајт је вратио необичне и нетачне акредитиве. Или нападач покушава да Ñе предÑтави као <ph name="SITE" /> или је екран за Wi-Fi пријављивање прекинуо везу. Информације Ñу и даље безбедне зато што је Google Chrome прекинуо везу пре него што Ñу размењени било какви подаци.</translation>
<translation id="168328519870909584">Ðападачи који Ñу тренутно на <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ће можда покушати да инÑталирају опаÑне апликације на уређај које краду или бришу податке (на пример, Ñлике, лозинке, поруке и бројеве кредитних картица).</translation>
<translation id="168841957122794586">Сертификат Ñервера Ñадржи Ñлаб криптографÑки кључ.</translation>
<translation id="1710259589646384581">ОС</translation>
<translation id="1721312023322545264">Потребна вам је дозвола кориÑника <ph name="NAME" /> да биÑте поÑетили овај Ñајт</translation>
+<translation id="1721424275792716183">* Поље је обавезно</translation>
<translation id="1728677426644403582">Прегледате извор веб-Ñтранице.</translation>
+<translation id="173080396488393970">Овај тип картице није подржан</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Покушајте да контактирате админиÑтратора ÑиÑтема.</translation>
+<translation id="1740951997222943430">УнеÑите важећи меÑец иÑтека</translation>
<translation id="1745358365027406341">Преузми Ñтраницу каÑније</translation>
<translation id="17513872634828108">Отворене картице</translation>
<translation id="1753706481035618306">Број Ñтранице</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Ðжурирај приÑтупну фразу за Ñинхронизацију</translation>
<translation id="1787142507584202372">Отворене картице Ñе појављују овде</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Изаберите адреÑу за иÑпоруку да биÑте проверили начине и уÑлове иÑпоруке.</translation>
+<translation id="1803264062614276815">Име влаÑника картице</translation>
<translation id="1803678881841855883">Google безбедно прегледање је недавно <ph name="BEGIN_LINK" />открило малвер<ph name="END_LINK" /> на <ph name="SITE" />. Веб-Ñајтови који Ñу обично безбедни Ñе понекад заразе малвером. Злонамеран Ñадржај потиче Ñа <ph name="SUBRESOURCE_HOST" />, који је познати диÑтрибутер малвера. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Додато је: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Ðеважећи захтев или параметри захтева</translation>
<translation id="1826516787628120939">Провера</translation>
<translation id="1834321415901700177">Овај Ñајт Ñадржи штетне програме</translation>
<translation id="1842969606798536927">Плаћање</translation>
-<translation id="1864455488461349376">Опција иÑпоруке</translation>
<translation id="1871208020102129563">ПрокÑи је подешен да кориÑти фикÑне прокÑи Ñервере, а не URL адреÑу .pac Ñкрипте.</translation>
<translation id="1871284979644508959">Обавезно поље</translation>
<translation id="187918866476621466">Отвори почетне Ñтранице</translation>
<translation id="1883255238294161206">Скупи лиÑту</translation>
<translation id="1898423065542865115">Филтрирање</translation>
<translation id="194030505837763158">Идите на <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Прихваћене картице</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> – обележивачи</translation>
<translation id="1973335181906896915">Грешка при Ñеријализацији</translation>
<translation id="1974060860693918893">Ðапредне опције</translation>
<translation id="1978555033938440688">Верзија фирмвера</translation>
+<translation id="1995859865337580572">Верификујте CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{ и још 1}one{и још #}few{и још #}other{и још #}}</translation>
-<translation id="2020194265157481222">Име на картици је обавезно</translation>
<translation id="2025186561304664664">ПрокÑи је подешен да буде аутоматÑки конфигуриÑан.</translation>
<translation id="2030481566774242610">Да ли Ñте миÑлили <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />да проверите прокÑи и заштитни зид<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">ДанаÑ</translation>
<translation id="2154054054215849342">Синхронизација није доÑтупна за домен</translation>
<translation id="2154484045852737596">Измените картицу</translation>
-<translation id="2156993118928861787">Ðеважећа адреÑа</translation>
<translation id="2166049586286450108">Потпуни админиÑтраторÑки приÑтуп</translation>
<translation id="2166378884831602661">Овај Ñајт не може да пружи безбедну везу</translation>
<translation id="2181821976797666341">Смернице</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 адреÑа}one{# адреÑа}few{# адреÑе}other{# адреÑа}}</translation>
+<translation id="2202020181578195191">УнеÑите важећу годину иÑтека</translation>
<translation id="2212735316055980242">Смернице ниÑу пронађене</translation>
<translation id="2213606439339815911">Преузимање уноÑа...</translation>
<translation id="2230458221926704099">Поправите везу помоћу <ph name="BEGIN_LINK" />апликације за дијагноÑтику<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">ПриÑтуп интернету је блокиран</translation>
<translation id="230155334948463882">Ðова картица?</translation>
<translation id="2305919008529760154">Овај Ñервер не може да докаже да је <ph name="DOMAIN" />; могуће је да је његов безбедноÑни Ñертификат лажно издат. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Опције за картицу и адреÑу Ñу Ñа Google налога (<ph name="ACCOUNT_EMAIL" />) и из Chrome-а. Њима можете да управљате у <ph name="BEGIN_LINK" />Подешавањима<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> захтева кориÑничко име и лозинку.</translation>
<translation id="2318774815570432836">Тренутно не можете да поÑетите <ph name="SITE" /> зато што веб-Ñајт кориÑти HSTS. Грешке и напади на мрежи Ñу обично привремени, па ће ова Ñтраница вероватно функциониÑати каÑније. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">ОÑтали обележивачи</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Подразумеване Ñмернице за предузеће</translation>
<translation id="2386255080630008482">Сертификат Ñервера је опозван.</translation>
<translation id="2392959068659972793">Прикажи Ñмернице без подешених вредноÑти</translation>
+<translation id="239429038616798445">Овај начин Ñлања није доÑтупан. ИÑпробајте неки други начин.</translation>
<translation id="2396249848217231973">&amp;Опозови бриÑање</translation>
<translation id="2460160116472764928">Google безбедно прегледање је недавно <ph name="BEGIN_LINK" />открило малвер<ph name="END_LINK" /> на <ph name="SITE" />. Веб-Ñајтови који Ñу обично безбедни Ñе понекад заразе малвером. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Попуни</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />да покренете дијагноÑтику мреже<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Ðеважећа URL адреÑа претраге.</translation>
<translation id="2491120439723279231">Сертификат Ñервера Ñадржи грешке.</translation>
-<translation id="24943777258388405">Ðеважећи број телефона</translation>
<translation id="2495083838625180221">Рашчлањивач JSON датотека</translation>
<translation id="2495093607237746763">Ðко означите ову опцију, Chromium ће Ñкладиштити копију картице на овом уређају ради бржег попуњавања образаца.</translation>
<translation id="2498091847651709837">Скенирајте нову картицу</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027">ХоÑÑ‚ <ph name="HOST_NAME" /> је поÑлао неважећи одговор.</translation>
<translation id="2552545117464357659">Ðовије</translation>
<translation id="2556876185419854533">&amp;Опозови измену</translation>
+<translation id="2587730715158995865">Од издавача <ph name="ARTICLE_PUBLISHER" />. Прочитајте овај чланак веÑти и још <ph name="OTHER_ARTICLE_COUNT" /> чланака.</translation>
<translation id="2587841377698384444">ИД API-ја за директоријуме:</translation>
<translation id="2597378329261239068">Овај документ је заштићен лозинком. УнеÑите лозинку.</translation>
<translation id="2609632851001447353">Варијације</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />да покренете дијагноÑтику везе<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">Потврди</translation>
<translation id="2742870351467570537">Уклони изабране Ñтавке</translation>
+<translation id="277133753123645258">Ðачин Ñлања</translation>
<translation id="277499241957683684">ÐедоÑтаје евиденција уређаја</translation>
<translation id="2784949926578158345">Веза је враћена на почетне вредноÑти.</translation>
<translation id="2794233252405721443">Сајт је блокиран</translation>
-<translation id="2812680587231492111">Та опција преузимања није доÑтупна. ИÑпробајте неку другу опцију.</translation>
<translation id="2824775600643448204">Трака за адреÑу и претрагу</translation>
<translation id="2826760142808435982">Веза је шифрована и њена аутентичноÑÑ‚ је потврђена помоћу <ph name="CIPHER" /> и кориÑти <ph name="KX" /> као механизам за размену шифара.</translation>
<translation id="2835170189407361413">Обриши образац</translation>
-<translation id="2849041323157393173">Та опција иÑпоруке није доÑтупна. ИÑпробајте неку другу опцију.</translation>
<translation id="2889159643044928134">Ðе учитавај поново</translation>
<translation id="2900469785430194048">Google Chrome-у је понеÑтало меморије док је покушавао да прикаже ову веб-Ñтраницу.</translation>
<translation id="2909946352844186028">Откривена је промена на мрежи.</translation>
<translation id="2916038427272391327">Затворите друге програме</translation>
<translation id="2922350208395188000">Ðије могуће проверити Ñертификат Ñервера.</translation>
+<translation id="2928905813689894207">ÐдреÑа за обрачун</translation>
<translation id="2948083400971632585">Ðа Ñтраници Подешавања можете да онемогућите Ñве прокÑије конфигуриÑане за везу.</translation>
<translation id="2955913368246107853">Затворите траку за проналажење</translation>
<translation id="2958431318199492670">Конфигурација мреже није у Ñкладу Ñа ONC Ñтандардом. Делови конфигурације не могу да Ñе увезу.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Да биÑте уÑпоÑтавили безбедну везу, Ñат на уређају мора да буде тачан. То је зато што Ñертификати које веб-Ñајтови кориÑте за идентификацију важе Ñамо за одређене временÑке периоде. Пошто Ñат на вашем уређају није тачан, Google Chrome не може да верификује те Ñертификате.</translation>
<translation id="2972581237482394796">&amp;Понови радњу</translation>
<translation id="2985306909656435243">Ðко омогућите ову опцију, Chromium ће Ñкладиштити копију картице на овом уређају ради бржег попуњавања образаца.</translation>
+<translation id="2985398929374701810">УнеÑите важећу адреÑу</translation>
+<translation id="2986368408720340940">Овај начин преузимања није доÑтупан. ИÑпробајте неки други начин.</translation>
<translation id="2991174974383378012">Дељење Ñа веб-Ñајтовима</translation>
<translation id="3005723025932146533">Прикажи Ñачувану копију</translation>
<translation id="3008447029300691911">УнеÑите CVC за картицу <ph name="CREDIT_CARD" />. Када будете потврдили, подаци о картици ће бити поÑлати овом Ñајту.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{најмање 1 Ñтавка на Ñинхронизованим уређајима}=1{1 Ñтавка (и још Ñтавки на Ñинхронизованим уређајима)}one{# Ñтавка (и још Ñтавки на Ñинхронизованим уређајима)}few{# Ñтавке (и још Ñтавки на Ñинхронизованим уређајима)}other{# Ñтавки (и још Ñтавки на Ñинхронизованим уређајима)}}</translation>
<translation id="3041612393474885105">Информације о Ñертификату</translation>
<translation id="3063697135517575841">Chrome није уÑпео да потврди картицу. Пробајте поново каÑније.</translation>
+<translation id="3064966200440839136">ÐапуÑтићете режим без архивирања да биÑте платили у Ñпољној апликацији. Желите ли да наÑтавите?</translation>
<translation id="3093245981617870298">Офлајн Ñте.</translation>
<translation id="3105172416063519923">ИД елемента:</translation>
<translation id="3109728660330352905">Ðемате овлашћење да прегледате ову Ñтраницу.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Покушајте да покренете дијагноÑтику везе<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Декодирање одговора није уÑпело</translation>
-<translation id="3149891296864842641">Опције иÑпоруке</translation>
<translation id="3150653042067488994">Привремена грешка на Ñерверу</translation>
+<translation id="3154506275960390542">Ова Ñтраница Ñадржи образац чије Ñлање може да буде небезбедно. Податке које пошаљете могу да виде и други док Ñу у пролазу и нападач може да их измени да би променио Ñадржај који Ñервер прима.</translation>
<translation id="3157931365184549694">Поново отвори</translation>
<translation id="3167968892399408617">Странице које прегледате на картицама без архивирања Ñе неће задржавати у иÑторији прегледача, Ñкладишту колачића или иÑторији претраге када затворите Ñве картице без архивирања. Сачуваћемо Ñве преузете датотеке или направљене обележиваче.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Слање захтева за приÑтуп овом Ñајту кориÑнику <ph name="NAME" /> није уÑпело. Пробајте поново.</translation>
<translation id="3355823806454867987">Промени подешавања прокÑија...</translation>
<translation id="3369192424181595722">Грешка на Ñату</translation>
+<translation id="337311366426640088">Још Ñтавки (<ph name="ITEM_COUNT" />)...</translation>
<translation id="337363190475750230">Онемогућен је</translation>
<translation id="3377188786107721145">Грешка при рашчлањивању Ñмерница</translation>
<translation id="3380365263193509176">Ðепозната грешка</translation>
<translation id="3380864720620200369">ИД клијента:</translation>
<translation id="3391030046425686457">ÐдреÑа иÑпоруке</translation>
+<translation id="3395827396354264108">Ðачин преузимања</translation>
<translation id="340013220407300675">Хакери можда покушавају да украду ваше информације из <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (на пример, лозинке, поруке или информације о кредитним картицама).</translation>
<translation id="3422248202833853650">Пробајте да изађете из других програма да биÑте оÑлободили меморију.</translation>
<translation id="3422472998109090673">ХоÑÑ‚ <ph name="HOST_NAME" /> тренутно није доÑтупан.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">Mastercard</translation>
<translation id="3452404311384756672">Интервал учитавања:</translation>
<translation id="3462200631372590220">Сакриј напредно</translation>
+<translation id="3467763166455606212">Име влаÑника картице је обавезно</translation>
+<translation id="3478058380795961209">МеÑец иÑтека</translation>
<translation id="3479539252931486093">Да ли је ово било неочекивано? <ph name="BEGIN_LINK" />ОбавеÑтите наÑ<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Ðе Ñада</translation>
<translation id="348000606199325318">ИД отказивања <ph name="CRASH_LOCAL_ID" /> (ИД Ñервера: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Тренутно не можемо да контактирамо родитеља. Пробај поново.</translation>
<translation id="3528171143076753409">Сертификат Ñервера није поуздан.</translation>
-<translation id="3538531656504267329">Ðеважећа година иÑтека</translation>
<translation id="3539171420378717834">Задржи копију ове картице на овом уређају</translation>
<translation id="3542684924769048008">КориÑти лозинку за:</translation>
<translation id="3549644494707163724">Шифруј Ñве Ñинхронизоване податке помоћу моје приÑтупне фразе за Ñинхронизацију</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Сакриј детаље</translation>
<translation id="3587482841069643663">Све</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">УнеÑите важећи датум иÑтека</translation>
<translation id="36224234498066874">Обриши податке прегледања...</translation>
<translation id="362276910939193118">Прикажи комплетну иÑторију</translation>
<translation id="3623476034248543066">Прикажи вредноÑÑ‚</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Лозинка:</translation>
<translation id="3696411085566228381">ништа</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Изаберите адреÑу за иÑпоруку да биÑте проверили начине иÑпоруке и уÑлове.</translation>
<translation id="370665806235115550">Учитава Ñе...</translation>
<translation id="3712624925041724820">Ðема више лиценци</translation>
<translation id="3714780639079136834">да укључите податке за мобилне уређаје или Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Линк који Ñте копирали</translation>
<translation id="375403751935624634">Превођење није уÑпело због грешке Ñервера.</translation>
<translation id="3759461132968374835">Ðемате ниједно недавно пријављено отказивање. Отказивања која Ñу Ñе деÑила док је пријављивање отказивања било онемогућено неће Ñе овде приказати.</translation>
+<translation id="3787705759683870569">ИÑтиче <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Ðко кориÑтите прокÑи Ñервер...</translation>
<translation id="3828924085048779000">Ðије дозвољено да поље за приÑтупну фразу буде празно.</translation>
<translation id="3845539888601087042">Приказујемо иÑторију Ñа уређаја на које Ñте пријављени. <ph name="BEGIN_LINK" />Сазнајте више<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Желите ли да Chromium Ñачува ову картицу?</translation>
<translation id="4171400957073367226">ÐеиÑправан Ð¿Ð¾Ñ‚Ð¿Ð¸Ñ Ð·Ð° верификацију</translation>
-<translation id="4176463684765177261">Онемогућено</translation>
<translation id="4196861286325780578">&amp;Понови премештање</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />да проверите конфигурацију заштитног зида и антивируÑа<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{ниједна}=1{1 апликација ($1)}=2{2 апликације ($1, $2)}one{# апликација ($1, $2, $3)}few{# апликације ($1, $2, $3)}other{# апликација ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">резултати претраге</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> није прихватио Ñертификат за пријављивање или Ñертификат за пријављивање није приложен.</translation>
<translation id="443673843213245140">Коришћење прокÑија је онемогућено, али је наведена екÑплицитна конфигурација прокÑија.</translation>
-<translation id="4446242550670694251">Сада можете да прегледате приватно и други људи који кориÑте овај уређај неће видети ваше активноÑти.</translation>
<translation id="4492190037599258964">Резултати претраге за „<ph name="SEARCH_STRING" />“</translation>
<translation id="4506176782989081258">Грешка при потврди ваљаноÑти: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">да контактирате админиÑтратора ÑиÑтема</translation>
<translation id="450710068430902550">Дељење Ñа админиÑтратором</translation>
+<translation id="4515275063822566619">Картице и адреÑе Ñу из Chrome-а и Ñа вашег Google налога (<ph name="ACCOUNT_EMAIL" />). Њима можете да управљате у <ph name="BEGIN_LINK" />подешавњима<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Детаљи</translation>
<translation id="4558551763791394412">Покушајте да онемогућите додатке.</translation>
<translation id="457875822857220463">ИÑпорука</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Уклопи у Ñтраницу</translation>
<translation id="483020001682031208">Ðе поÑтоје Ñтранице Интернета око Ð½Ð°Ñ Ð·Ð° приказивање</translation>
<translation id="4850886885716139402">Приказ</translation>
+<translation id="4854362297993841467">Овај начин иÑпоруке није доÑтупан. ИÑпробајте неки други начин.</translation>
<translation id="4858792381671956233">Питао/ла Ñи родитеље да ли Ñмеш да поÑетиш овај Ñајт</translation>
<translation id="4880827082731008257">Претражи иÑторију</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Ова Ñтраница је преведена Ñа непознатог језика на <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Плаћање</translation>
<translation id="4926049483395192435">Мора да буде наведено.</translation>
-<translation id="4941291666397027948">* означава обавезно поље</translation>
<translation id="495170559598752135">Радње</translation>
<translation id="4958444002117714549">Прошири лиÑту</translation>
<translation id="4962322354953122629">Овај Ñервер не може да докаже да је <ph name="DOMAIN" />; Chrome нема поверења у његов безбедноÑни Ñертификат. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">ÐеиÑправна лозинка</translation>
<translation id="5056549851600133418">Чланци за ваÑ</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />да проверите адреÑу прокÑија<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Ðема колачића}=1{1 Ñајт кориÑти колачиће. }one{# Ñајт кориÑти колачиће. }few{# Ñајта кориÑте колачиће. }other{# Ñајтова кориÑти колачиће. }}</translation>
<translation id="5087286274860437796">Сертификат Ñервера тренутно није важећи.</translation>
<translation id="5087580092889165836">Додај картицу</translation>
<translation id="5089810972385038852">Држава</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Прикажи</translation>
<translation id="5308689395849655368">Извештавање о отказивању је онемогућено.</translation>
<translation id="5317780077021120954">Сачувај</translation>
-<translation id="5326702247179446998">Прималац је обавезан</translation>
<translation id="5327248766486351172">Ðазив</translation>
<translation id="5337705430875057403">Ðападачи на <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> могу да Ð²Ð°Ñ Ð¿Ñ€ÐµÐ²Ð°Ñ€Ðµ како биÑте урадили нешто опаÑно, на пример, да инÑталирате Ñофтвер или откријете личне податке (попут лозинки, бројева телефона или бројева кредитних картица).</translation>
-<translation id="53553865750799677">ÐдреÑа за преузимање није подржана. Изаберите другу адреÑу.</translation>
<translation id="5359637492792381994">Овај Ñервер не може да докаже да је <ph name="DOMAIN" />; његов безбедноÑни Ñертификат тренутно није важећи. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Складиштење подешавања Ñмерница није уÑпело</translation>
<translation id="5386426401304769735">Ланац Ñертификата за овај Ñајт Ñадржи Ñертификат потпиÑан помоћу алгоритма SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">Уграђена Ñтраница на <ph name="SITE" /> каже:</translation>
<translation id="5556459405103347317">Учитај поново</translation>
<translation id="5565735124758917034">Ðктивно</translation>
+<translation id="5571083550517324815">Преузимање Ñа ове адреÑе није могуће. Изаберите другу адреÑу.</translation>
<translation id="5572851009514199876">Отворите и пријавите Ñе у Chrome да би Chrome могао да провери да ли имате дозволу за приÑтуп овом Ñајту.</translation>
-<translation id="5575380383496039204">ÐдреÑа за иÑпоруку није подржана. Изаберите другу адреÑу.</translation>
<translation id="5580958916614886209">Проверите меÑец иÑтека и пробајте поново</translation>
<translation id="560412284261940334">Управљање није подржано</translation>
<translation id="5610142619324316209">да проверите везу</translation>
@@ -504,10 +514,11 @@
<translation id="5675650730144413517">Ова Ñтраница не функционише</translation>
<translation id="5677928146339483299">Блокирано</translation>
<translation id="5694783966845939798">Покушали Ñте да поÑетите <ph name="DOMAIN" />, али је Ñервер поÑлао Ñертификат потпиÑан Ñлабим алгоритмом (као што је SHA-1). То значи да Ñу безбедноÑни акредитиви које је Ñервер поÑлао можда кривотворени и Ñервер можда није онај који миÑлите да јеÑте (можда комуницирате Ñа нападачем). <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="5710435578057952990">Идентитет овог веб Ñајта није верификован.</translation>
+<translation id="5710435578057952990">Идентитет овог веб-Ñајта није верификован.</translation>
<translation id="5720705177508910913">Тренутни кориÑник</translation>
<translation id="5732392974455271431">Родитељи могу да га деблокирају за тебе</translation>
-<translation id="57586589942790530">ÐеиÑправан број кредитне картице</translation>
+<translation id="5763042198335101085">УнеÑите важећу имејл адреÑу</translation>
+<translation id="5765072501007116331">Да биÑте видели начине и захтеве за иÑпоруку, изаберите адреÑу</translation>
<translation id="5784606427469807560">Дошло је до проблема при потврди картице. Проверите интернет везу и покушајте поново.</translation>
<translation id="5785756445106461925">Поред тога, ова Ñтраница Ñадржи и друге реÑурÑе који ниÑу безбедни. Ове реÑурÑе могу да виде и други док Ñу у пролазу и нападач може да их измени како би променио изглед Ñтранице.</translation>
<translation id="5786044859038896871">Желите ли да попуните информације о картици?</translation>
@@ -520,31 +531,30 @@
<translation id="5869405914158311789">Овај Ñајт није доÑтупан</translation>
<translation id="5869522115854928033">Сачуване лозинке</translation>
<translation id="5872918882028971132">Предлози родитеља</translation>
-<translation id="587760065310675640">ÐдреÑа за иÑпоруку није подржана. Изаберите другу адреÑу.</translation>
<translation id="5901630391730855834">Жута</translation>
-<translation id="59174027418879706">Омогућено</translation>
<translation id="5926846154125914413">Можете да изгубите приÑтуп премијум Ñадржају Ñа неких Ñајтова.</translation>
<translation id="5959728338436674663">ÐутоматÑки шаљите одређене <ph name="BEGIN_WHITEPAPER_LINK" />информације о ÑиÑтему и Ñадржај Ñтраница<ph name="END_WHITEPAPER_LINK" /> Google-у да биÑте нам помогли да откријемо опаÑне апликације и Ñајтове. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Ðедеља</translation>
<translation id="5967867314010545767">Уклони из иÑторије</translation>
<translation id="5975083100439434680">Умањивање</translation>
+<translation id="598637245381783098">Отварање апликације за плаћање није уÑпело</translation>
<translation id="5989320800837274978">ÐиÑу наведени ни фикÑни прокÑи Ñервери нити URL адреÑа .pac Ñкрипте.</translation>
<translation id="5990559369517809815">Додатак је блокирао захтеве упућене Ñерверу.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Опције за картицу и адреÑу Ñу из Chrome-а. Њима можете да управљате у <ph name="BEGIN_LINK" />Подешавањима<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1. Ñтраница}one{#. Ñтраница}few{#. Ñтраница}other{#. Ñтраница}}</translation>
<translation id="6017514345406065928">Зелена</translation>
+<translation id="6027201098523975773">УнеÑите назив</translation>
<translation id="6040143037577758943">Затвори</translation>
-<translation id="604124094241169006">ÐутоматÑки</translation>
<translation id="6042308850641462728">Више</translation>
<translation id="6060685159320643512">Пазите, ови екÑперименти могу бити опаÑни</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{ниједна}=1{1}one{#}few{#}other{#}}</translation>
<translation id="6146055958333702838">Проверите Ñве каблове и реÑтартујте Ñве рутере, модеме или друге мрежне уређаје које можда кориÑтите.</translation>
<translation id="614940544461990577">Покушајте:</translation>
<translation id="6151417162996330722">Сертификат Ñервера има предугачак период важења.</translation>
-<translation id="615643356032862689">Преузете датотеке и обележивачи ће бити Ñачувани.</translation>
+<translation id="6157877588268064908">Да биÑте видели начине и захтеве за Ñлање, изаберите адреÑу</translation>
<translation id="6165508094623778733">Сазнајте више</translation>
<translation id="6177128806592000436">Веза Ñа овим Ñајтом није безбедна</translation>
+<translation id="6184817833369986695">(кохорта: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Проверите интернет везу</translation>
<translation id="6218753634732582820">Желите ли да уклоните адреÑу из Chromium-а?</translation>
<translation id="6251924700383757765">Политика приватноÑти</translation>
@@ -553,6 +563,8 @@
<translation id="6259156558325130047">&amp;Понови промену редоÑледа</translation>
<translation id="6263376278284652872">Обележивачи домена <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Ðазад на безбедно</translation>
+<translation id="6276112860590028508">Странице Ñа лиÑте за читање ће Ñе појавити овде</translation>
+<translation id="6280223929691119688">ИÑпорука на ову адреÑу није могућа. Изаберите другу адреÑу.</translation>
<translation id="6282194474023008486">ПоштанÑки број</translation>
<translation id="6290238015253830360">Предложени чланци Ñе приказују овде</translation>
<translation id="6305205051461490394">URL <ph name="URL" /> није доÑтупан.</translation>
@@ -574,7 +586,6 @@
<translation id="6417515091412812850">Ðије могуће проверити да ли је Ñертификат опозван.</translation>
<translation id="6433490469411711332">Измените контакт информације</translation>
<translation id="6433595998831338502">ХоÑÑ‚ <ph name="HOST_NAME" /> је одбио повезивање.</translation>
-<translation id="6443118737398455446">Ðеважећи датум иÑтека</translation>
<translation id="6446608382365791566">Додајте још информација</translation>
<translation id="6451458296329894277">Потврђивање поновног Ñлања обраÑца</translation>
<translation id="6456339708790392414">Плаћање</translation>
@@ -582,10 +593,8 @@
<translation id="6462969404041126431">Овај Ñервер не може да докаже да је <ph name="DOMAIN" />; његов безбедноÑни Ñертификат је можда опозван. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Смернице за уређај</translation>
<translation id="6477321094435799029">Chrome је открио неуобичајени кôд на овој Ñтраници и блокирао је ради заштите ваших личних података (попут лозинки, бројева телефона или бројева кредитних картица).</translation>
-<translation id="6477460825583319731">Ðеважећа имејл адреÑа</translation>
<translation id="6489534406876378309">Покрени отпремање отказивања</translation>
<translation id="6508722015517270189">Поново покрените Chrome</translation>
-<translation id="6525462735697194615">Ðеважећи меÑец иÑтека</translation>
<translation id="6529602333819889595">&amp;Понови бриÑање</translation>
<translation id="6534179046333460208">Предлози Интернета око наÑ</translation>
<translation id="6550675742724504774">Опције</translation>
@@ -600,7 +609,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> претрага</translation>
<translation id="6644283850729428850">Ове Ñмернице Ñу заÑтареле.</translation>
<translation id="6652240803263749613">Овај Ñервер не може да докаже да је <ph name="DOMAIN" />; оперативни ÑиÑтем вашег рачунара нема поверења у његов безбедноÑни Ñертификат. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Та опција Ñлања није доÑтупна. ИÑпробајте неку другу опцију.</translation>
<translation id="6671697161687535275">Желите ли да уклоните предлог из Chromium-а?</translation>
<translation id="6685834062052613830">Одјавите Ñе и довршите подешавање</translation>
<translation id="6710213216561001401">Претходно</translation>
@@ -608,13 +616,13 @@
<translation id="6711464428925977395">Ðешто није у реду Ñа прокÑи Ñервером или је адреÑа нетачна.</translation>
<translation id="6727102863431372879">ПоÑтави</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{ниједна}=1{1 Ñтавка}one{# Ñтавка}few{# Ñтавке}other{# Ñтавки}}</translation>
-<translation id="6743044928064272573">Опција преузимања</translation>
<translation id="674375294223700098">Ðепозната грешка Ñертификата Ñервера.</translation>
<translation id="6753269504797312559">ВредноÑÑ‚ Ñмерница</translation>
<translation id="6757797048963528358">Уређај је прешао у режим Ñпавања.</translation>
<translation id="6778737459546443941">Родитељ га још увек није одобрио</translation>
<translation id="6810899417690483278">ИД за прилагођавање</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Учитавање података према регионима није уÑпело</translation>
<translation id="6831043979455480757">Преведи</translation>
<translation id="6839929833149231406">ОблаÑÑ‚</translation>
<translation id="6874604403660855544">&amp;Понови додавање</translation>
@@ -622,6 +630,7 @@
<translation id="6895330447102777224">Картица је потврђена</translation>
<translation id="6897140037006041989">КориÑнички агент</translation>
<translation id="6915804003454593391">КориÑник:</translation>
+<translation id="6948701128805548767">Да биÑте видели начине и захтеве за преузимање, изаберите адреÑу</translation>
<translation id="6957887021205513506">Изгледа да је Ñертификат Ñервера фалÑификован.</translation>
<translation id="6965382102122355670">Потврди</translation>
<translation id="6965978654500191972">Уређај</translation>
@@ -629,7 +638,6 @@
<translation id="6973656660372572881">Ðаведени Ñу и фикÑни прокÑи Ñервери и URL адреÑа .pac Ñкрипте.</translation>
<translation id="6989763994942163495">Прикажи напредна подешавања...</translation>
<translation id="7000990526846637657">Ðије пронађен ниједан ÑƒÐ½Ð¾Ñ Ñƒ иÑторији</translation>
-<translation id="7001663382399377034">Додајте кориÑника</translation>
<translation id="7009986207543992532">Покушали Ñте да поÑетите <ph name="DOMAIN" />, али је Ñервер поÑлао Ñертификат Ñа периодом важења који је предугачак да би био поуздан. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Google налог има друге облике иÑторије прегледања на <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -640,12 +648,15 @@
<translation id="7088615885725309056">Старије</translation>
<translation id="7090678807593890770">Потражите <ph name="LINK" /> на Google-у</translation>
<translation id="7119414471315195487">Затворите друге картице или програме</translation>
+<translation id="7129409597930077180">Слање на ову адреÑу није могуће. Изаберите другу адреÑу.</translation>
+<translation id="7138472120740807366">Ðачин иÑпоруке</translation>
<translation id="7139724024395191329">Емират</translation>
<translation id="7155487117670177674">Плаћање није безбедно</translation>
<translation id="7179921470347911571">Поново покрени</translation>
<translation id="7180611975245234373">ОÑвежи</translation>
<translation id="7182878459783632708">ÐиÑу подешене никакве Ñмернице</translation>
<translation id="7186367841673660872">Ова Ñтраница је преведена Ñа језика:<ph name="ORIGINAL_LANGUAGE" />на<ph name="LANGUAGE_LANGUAGE" /></translation>
+<translation id="7192203810768312527">ОÑлободиће Ñе <ph name="SIZE" />. Ðеки Ñајтови ће Ñе Ñпорије учитавати при Ñледећој поÑети.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423">ХоÑÑ‚ <ph name="HOST_NAME" /> не поштује безбедноÑне Ñтандарде.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Сазнајте више<ph name="END_LINK" /> о овом проблему.</translation>
@@ -674,8 +685,7 @@
<translation id="7424977062513257142">Уграђена Ñтраница на овој веб-Ñтраници каже:</translation>
<translation id="7441627299479586546">Погрешан Ñубјекат Ñмерница</translation>
<translation id="7444046173054089907">Овај Ñајт је блокиран</translation>
-<translation id="7444238235002594607">Изаберите адреÑу за преузимање да биÑте проверили начине и уÑлове преузимања.</translation>
-<translation id="7445762425076701745">Ðије могуће у потпуноÑти потврдити идентитет Ñервера Ñа којим Ñте повезани. Повезани Ñте Ñа Ñервером који кориÑти назив који је важећи Ñамо у вашој мрежи, а којем Ñпољни ауторитет за издавање Ñертификата не може да провери влаÑништво. Будући да неки ауторитети за издавање Ñертификата ÑƒÐ¿Ñ€ÐºÐ¾Ñ Ñ‚Ð¾Ð¼Ðµ издају Ñертификате за ове називе, ни на који начин не можете да будете Ñигурни да Ñте повезани Ñа жељеним веб Ñајтом, а не Ñа нападачем.</translation>
+<translation id="7445762425076701745">Ðије могуће у потпуноÑти потврдити идентитет Ñервера Ñа којим Ñте повезани. Повезани Ñте Ñа Ñервером који кориÑти назив који је важећи Ñамо у вашој мрежи, а којем Ñпољни ауторитет за издавање Ñертификата не може да провери влаÑништво. Будући да неки ауторитети за издавање Ñертификата ÑƒÐ¿Ñ€ÐºÐ¾Ñ Ñ‚Ð¾Ð¼Ðµ издају Ñертификате за ове називе, ни на који начин не можете да будете Ñигурни да Ñте повезани Ñа жељеним веб-Ñајтом, а не Ñа нападачем.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />да Ñазнате више<ph name="END_LINK" /> о овом проблему.</translation>
<translation id="7460163899615895653">Ðедавне картице Ñа других уређаја Ñе приказују овде</translation>
<translation id="7469372306589899959">Потврђивање картице</translation>
@@ -718,6 +728,7 @@
<translation id="7755287808199759310">Родитељ може да га деблокира за тебе</translation>
<translation id="7758069387465995638">Можда је заштитни зид или антивируÑни Ñофтвер блокирао везу.</translation>
<translation id="7761701407923456692">Сертификат Ñервера Ñе не подудара Ñа URL адреÑом.</translation>
+<translation id="7763386264682878361">Рашчлањивач манифеÑта за плаћање</translation>
<translation id="7764225426217299476">Додајте адреÑу</translation>
<translation id="777702478322588152">Префектура</translation>
<translation id="7791543448312431591">Додај</translation>
@@ -731,6 +742,7 @@
<translation id="785549533363645510">Ðли, ниÑте невидљиви. ПрелаÑком у режим без архивирања нећете Ñакрити прегледање од поÑлодавца, интернет провајдера или веб-Ñајтова које поÑећујете.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" />: <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Проверите CVC и покушајте поново</translation>
+<translation id="79338296614623784">УнеÑите важећи број телефона</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Сертификат Ñервера још увек није важећи.</translation>
<translation id="7942349550061667556">Црвена</translation>
@@ -750,6 +762,7 @@
<translation id="8088680233425245692">Прегледање чланка није уÑпело.</translation>
<translation id="8089520772729574115">мање од 1 MB</translation>
<translation id="8091372947890762290">Ðктивација је на чекању на Ñерверу</translation>
+<translation id="8118489163946903409">Ðачин плаћања</translation>
<translation id="8131740175452115882">Потврди</translation>
<translation id="8134994873729925007">ÐиÑмо уÑпели да пронађемо <ph name="BEGIN_ABBR" />DNS адреÑу<ph name="END_ABBR" /> Ñервера хоÑта <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Рачунар је прешао у режим Ñпавања.</translation>
@@ -775,6 +788,7 @@
<translation id="8349305172487531364">Трака Ñа обележивачима</translation>
<translation id="8363502534493474904">да иÑкључите режим рада у авиону</translation>
<translation id="8364627913115013041">Ðије подешено.</translation>
+<translation id="8368476060205742148">Google Play уÑлуге</translation>
<translation id="8380941800586852976">ОпаÑно</translation>
<translation id="8382348898565613901">Ðедавно поÑећени обележивачи Ñе приказују овде</translation>
<translation id="8398259832188219207">Извештај о отказивању је отпремљен у: <ph name="UPLOAD_TIME" /></translation>
@@ -783,32 +797,30 @@
<translation id="8428213095426709021">Подешавања</translation>
<translation id="8433057134996913067">Овако ћете Ñе одјавити Ñа већине веб-Ñајтова.</translation>
<translation id="8437238597147034694">&amp;Опозови премештање</translation>
-<translation id="8456681095658380701">Ðеважеће име</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 кредитна картица}one{# кредитна картица}few{# кредитне картице}other{# кредитних картица}}</translation>
<translation id="8483780878231876732">Да биÑте кориÑтили картице Ñа Google налога, пријавите Ñе у Chrome</translation>
<translation id="8488350697529856933">ОдноÑе Ñе на</translation>
-<translation id="8492969205326575646">Тип картице није подржан</translation>
<translation id="8498891568109133222">Одговор хоÑта <ph name="HOST_NAME" /> је трајао предуго.</translation>
<translation id="852346902619691059">Овај Ñервер не може да докаже да је <ph name="DOMAIN" />; оперативни ÑиÑтем вашег уређаја нема поверења у његов безбедноÑни Ñертификат. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Година иÑтека</translation>
<translation id="8543181531796978784">Можете да <ph name="BEGIN_ERROR_LINK" />пријавите проблем Ñа откривањем<ph name="END_ERROR_LINK" /> или, ако Ñхватате безбедноÑне ризике, <ph name="BEGIN_LINK" />поÑетите овај небезбедан Ñајт<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Превод није уÑпео јер језик Ñтранице није могао да буде утврђен.</translation>
<translation id="8559762987265718583">Ðије могуће уÑпоÑтавити приватну везу Ñа доменом <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> јер датум и време на уређају (<ph name="DATE_AND_TIME" />) ниÑу тачни.</translation>
-<translation id="8570229484593575558">Следеће информације |неће бити Ñачуване|:#иÑторија прегледања#претраге#подаци колачића</translation>
<translation id="8571890674111243710">Превођење Ñтранице на <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">ÐктивноÑти |ће можда ипак бити видљиве| за:#веб-Ñајтове које поÑећујете#поÑлодавца#интернет провајдера</translation>
<translation id="858637041960032120">Додај тел. број
</translation>
<translation id="859285277496340001">Сертификат не наводи механизам којим Ñе проверава да ли је опозван.</translation>
<translation id="8620436878122366504">Родитељи га још увек ниÑу одобрили</translation>
<translation id="8647750283161643317">Врати Ñве на подразумевано</translation>
<translation id="8703575177326907206">Ваша веза Ñа доменом <ph name="DOMAIN" /> није шифрована.</translation>
+<translation id="8718314106902482036">Плаћање није довршено</translation>
<translation id="8725066075913043281">Пробајте поново</translation>
<translation id="8728672262656704056">Прешли Ñте у режим Без архивирања</translation>
<translation id="8730621377337864115">Готово</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="8759274551635299824">Ова картица је иÑтекла</translation>
<translation id="8790007591277257123">&amp;Понови бриÑање</translation>
-<translation id="8798099450830957504">Подразумевано</translation>
<translation id="8800988563907321413">Предлози у близини ће Ñе приказивати овде</translation>
<translation id="8820817407110198400">Обележивачи</translation>
<translation id="883848425547221593">ОÑтали обележивачи</translation>
@@ -818,6 +830,7 @@
<translation id="8866481888320382733">Грешка при рашчлањивању подешавања Ñмерница</translation>
<translation id="8866959479196209191">Ова Ñтраница каже:</translation>
<translation id="8870413625673593573">Ðедавно затворено</translation>
+<translation id="8874824191258364635">УнеÑите важећи број картице</translation>
<translation id="8876793034577346603">Рашчлањивање конфигурације мреже није уÑпело.</translation>
<translation id="8877192140621905067">Када будете потврдили, подаци о картици ће бити поÑлати овом Ñајту</translation>
<translation id="8889402386540077796">ÐијанÑа</translation>
@@ -827,7 +840,6 @@
<translation id="8931333241327730545">Да ли желите да Ñачувате ову картицу на Google налог?</translation>
<translation id="8932102934695377596">Сат вам каÑни</translation>
<translation id="8954894007019320973">(наÑтавак)</translation>
-<translation id="895548565263634352">Читајте чланак веÑти издавача <ph name="ARTICLE_PUBLISHER" /> и још <ph name="OTHER_ARTICLE_COUNT" /> чланака</translation>
<translation id="8971063699422889582">Сертификат Ñервера је иÑтекао.</translation>
<translation id="8986494364107987395">ÐутоматÑки шаљи Google-у ÑтатиÑтичке податке о коришћењу и извештаје о отказивању</translation>
<translation id="8987927404178983737">МеÑец</translation>
@@ -845,7 +857,6 @@
<translation id="9068849894565669697">Изаберите боју</translation>
<translation id="9076283476770535406">Можда обухвата Ñадржај за одраÑле</translation>
<translation id="9078964945751709336">Потребно је више информација</translation>
-<translation id="9094175695478007090">Покретање апликације за плаћање није уÑпело.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> обично кориÑти шифровање да би заштитио информације. Када је Chromium овог пута покушао да Ñе повеже Ñа <ph name="SITE" />, веб-Ñајт је вратио необичне и нетачне акредитиве. Или нападач покушава да Ñе предÑтави као <ph name="SITE" /> или је екран за Wi-Fi пријављивање прекинуо везу. Информације Ñу и даље безбедне зато што је Chromium прекинуо везу пре него што Ñу размењени било какви подаци.</translation>
<translation id="9137013805542155359">Прикажи оригинал</translation>
<translation id="9137248913990643158">Пријавите Ñе у Chrome пре коришћења ове апликације.</translation>
diff --git a/chromium/components/strings/components_strings_sv.xtb b/chromium/components/strings/components_strings_sv.xtb
index a7dc922d2f7..23cfb64cb04 100644
--- a/chromium/components/strings/components_strings_sv.xtb
+++ b/chromium/components/strings/components_strings_sv.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="sv">
<translation id="1008557486741366299">Inte nu</translation>
<translation id="1015730422737071372">Ange ytterligare information</translation>
+<translation id="1021110881106174305">Godkända kort</translation>
<translation id="1032854598605920125">Rotera medurs</translation>
<translation id="1038842779957582377">okänt namn</translation>
<translation id="1050038467049342496">Stäng andra appar</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Dölj värde</translation>
<translation id="1228893227497259893">Fel enhetsidentifierare</translation>
<translation id="1232569758102978740">Namnlös</translation>
+<translation id="1263231323834454256">Läslista</translation>
<translation id="1264126396475825575">Felrapport skapades <ph name="CRASH_TIME" /> (har ännu inte laddats upp eller ignorerats)</translation>
<translation id="1285320974508926690">Översätt aldrig den här webbplatsen</translation>
<translation id="129553762522093515">Nyligen stängda</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Inställningar för Autofyll i Chromium …</translation>
<translation id="1374468813861204354">förslag</translation>
<translation id="1375198122581997741">Om version</translation>
+<translation id="1377321085342047638">Kortnummer</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> skickade ingen data.</translation>
<translation id="1407135791313364759">Öppna alla</translation>
<translation id="1413809658975081374">Sekretessfel</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Historik</translation>
<translation id="1645368109819982629">Det finns inget stöd för protokollet</translation>
<translation id="1656489000284462475">Upphämtning</translation>
+<translation id="1663943134801823270">Kort och adresser har hämtats från Chrome. Du hanterar dessa under <ph name="BEGIN_LINK" />Inställningar<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">På <ph name="SITE" /> används vanligtvis kryptering (SSL) för att skydda din information. När Chrome försökte ansluta till <ph name="SITE" /> den här gången skickade webbplatsen tillbaka ovanliga och felaktiga uppgifter. Sådant kan hända när en angripare utger sig för att vara <ph name="SITE" /> eller när anslutningen har avbrutits av en Wi-Fi-inloggningsskärm. Din information är fortfarande säker eftersom Chrome avbröt anslutningen innan någon data utbyttes.</translation>
<translation id="168328519870909584">Det kan hända att angripare som för närvarande finns på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> försöker installera skadliga appar på enheten som stjäl eller raderar dina uppgifter (t.ex. foton, lösenord, meddelanden och kreditkort).</translation>
<translation id="168841957122794586">Servercertifikatet innehåller en svag kryptografisk nyckel.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Du behöver tillstånd från <ph name="NAME" /> om du vill besöka den här webbplatsen</translation>
+<translation id="1721424275792716183">* Fältet är obligatoriskt</translation>
<translation id="1728677426644403582">Du visar källkoden till en webbsida</translation>
+<translation id="173080396488393970">Denna korttyp stöds inte</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Kontakta systemadministratören.</translation>
+<translation id="1740951997222943430">Ange en giltig utgångsmånad</translation>
<translation id="1745358365027406341">Ladda ned sidan senare</translation>
<translation id="17513872634828108">Öppna flikar</translation>
<translation id="1753706481035618306">Sidnummer</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Uppdatera lösenfrasen för synkroniseringen.</translation>
<translation id="1787142507584202372">Öppna flikar visas här</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Välj en leveransadress om du vill se vilka leveranssätt och villkor som finns.</translation>
+<translation id="1803264062614276815">Namn på kortinnehavare</translation>
<translation id="1803678881841855883">Googles tjänst Säker webbsökning <ph name="BEGIN_LINK" />hittade skadliga program<ph name="END_LINK" /> på <ph name="SITE" /> nyligen. Ibland förekommer det skadlig programvara på webbplatser som vanligtvis är säkra. Det skadliga innehållet kommer från <ph name="SUBRESOURCE_HOST" />, som är en känd distributör av skadlig programvara. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Lades till den <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Begäran eller parametrar i begäran var ogiltiga</translation>
<translation id="1826516787628120939">Kontrollerar</translation>
<translation id="1834321415901700177">Den här webbplatsen innehåller skadliga program</translation>
<translation id="1842969606798536927">Betala</translation>
-<translation id="1864455488461349376">Leveransalternativ</translation>
<translation id="1871208020102129563">Proxyn är inställd på att använda fasta proxyservrar, inte en webbadress med PAC-skript.</translation>
<translation id="1871284979644508959">Obligatoriskt fält</translation>
<translation id="187918866476621466">Öppna startsidorna</translation>
<translation id="1883255238294161206">Komprimera lista</translation>
<translation id="1898423065542865115">Filtrering</translation>
<translation id="194030505837763158">Öppna <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Godkända kort</translation>
<translation id="1962204205936693436">Bokmärken på <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Serieproduktionsfel</translation>
<translation id="1974060860693918893">Avancerat</translation>
<translation id="1978555033938440688">Firmwareversion</translation>
+<translation id="1995859865337580572">Verifiera CVC-koden</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{och 1 till}other{och # till}}</translation>
-<translation id="2020194265157481222">Namnet på kortet måste anges</translation>
<translation id="2025186561304664664">Proxyn är inställd på automatisk konfiguration.</translation>
<translation id="2030481566774242610">Menade du <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />kontrollera proxyn och brandväggen<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Idag</translation>
<translation id="2154054054215849342">Synkronisering är inte tillgänglig för din domän</translation>
<translation id="2154484045852737596">Redigera kortet</translation>
-<translation id="2156993118928861787">Ogiltig adress</translation>
<translation id="2166049586286450108">Fullständig administrativ åtkomst</translation>
<translation id="2166378884831602661">Webbplatsen kan inte tillhandahålla en säker anslutning</translation>
<translation id="2181821976797666341">Policyer</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adress}other{# adresser}}</translation>
+<translation id="2202020181578195191">Ange ett giltigt utgångsår</translation>
<translation id="2212735316055980242">Policyn hittades inte</translation>
<translation id="2213606439339815911">Hämtar poster …</translation>
<translation id="2230458221926704099">Åtgärda anslutningsproblemet med hjälp av <ph name="BEGIN_LINK" />diagnostiseringsappen<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Internetanslutningen har blockerats</translation>
<translation id="230155334948463882">Har du ett nytt kort?</translation>
<translation id="2305919008529760154">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat kan ha utfärdats utan behörighet. Detta kan orsakas av en felaktig konfigurering eller att någon spärrar anslutningen.. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Kort- och adressalternativen kommer från Google-kontot (<ph name="ACCOUNT_EMAIL" />) och Chrome. Du hanterar dessa under <ph name="BEGIN_LINK" />Inställningar<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> kräver användarnamn och lösenord.</translation>
<translation id="2318774815570432836">Det går inte att besöka <ph name="SITE" /> just nu på grund av att HSTS används på webbplatsen. Nätverksfel och attacker är vanligtvis tillfälliga, så den här sidan fungerar troligen senare. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Övriga bokmärken</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Standardinställning i företaget</translation>
<translation id="2386255080630008482">Servercertifikatet har återkallats.</translation>
<translation id="2392959068659972793">Visa policyer utan inställt värde</translation>
+<translation id="239429038616798445">Det här fraktalternativet är inte tillgängligt. Testa ett annat alternativ.</translation>
<translation id="2396249848217231973">&amp;Ã…ngra Ta bort</translation>
<translation id="2460160116472764928">Googles tjänst Säker webbsökning <ph name="BEGIN_LINK" />hittade skadliga program<ph name="END_LINK" /> på <ph name="SITE" /> nyligen. Ibland förekommer det skadlig programvara på webbplatser som vanligtvis är säkra. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Fyll i</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />att köra nätverksdiagnostik<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Ogiltig sökadress.</translation>
<translation id="2491120439723279231">Servercertifikatet innehåller fel.</translation>
-<translation id="24943777258388405">Ogiltigt telefonnummer</translation>
<translation id="2495083838625180221">JSON-analysator</translation>
<translation id="2495093607237746763">Om alternativet är markerat sparar Chromium en kopia av kortet på enheten så att det går snabbare att fylla i formulär.</translation>
<translation id="2498091847651709837">Läs in ett nytt kort</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> skickade ett ogiltigt svar.</translation>
<translation id="2552545117464357659">Nyare</translation>
<translation id="2556876185419854533">&amp;Ã…nga Redigera</translation>
+<translation id="2587730715158995865">Från <ph name="ARTICLE_PUBLISHER" />. Läs denna och <ph name="OTHER_ARTICLE_COUNT" /> andra artiklar.</translation>
<translation id="2587841377698384444">Id för katalog-API:</translation>
<translation id="2597378329261239068">Dokumentet är lösenordsskyddat. Ange ett lösenord.</translation>
<translation id="2609632851001447353">Varianter</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />att köra anslutningsdiagnostik<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">OK</translation>
<translation id="2742870351467570537">Ta bort valda objekt</translation>
+<translation id="277133753123645258">Fraktalternativ</translation>
<translation id="277499241957683684">Enhetsregister saknas</translation>
<translation id="2784949926578158345">Anslutningen återställdes.</translation>
<translation id="2794233252405721443">Webbplatsen har blockerats</translation>
-<translation id="2812680587231492111">Hämtningsalternativet är inte tillgängligt. Testa ett annat alternativ.</translation>
<translation id="2824775600643448204">Adress- och sökfält</translation>
<translation id="2826760142808435982">Anslutningen är krypterad och verifieras med <ph name="CIPHER" /> och använder <ph name="KX" /> som nyckelutbytesmekanism.</translation>
<translation id="2835170189407361413">Rensa formuläret</translation>
-<translation id="2849041323157393173">Leveransalternativet är inte tillgängligt. Testa ett annat alternativ.</translation>
<translation id="2889159643044928134">Läs inte in sidan igen</translation>
<translation id="2900469785430194048">Minnet tog slut när den här webbsidan skulle visas i Google Chrome.</translation>
<translation id="2909946352844186028">En nätverksförändring upptäcktes.</translation>
<translation id="2916038427272391327">Stäng andra program</translation>
<translation id="2922350208395188000">Servercertifikatet kan inte kontrolleras.</translation>
+<translation id="2928905813689894207">Faktureringsadress</translation>
<translation id="2948083400971632585">Du kan inaktivera alla proxyservrar som har konfigurerats för en anslutning från sidan Inställningar.</translation>
<translation id="2955913368246107853">Stäng sökfältet</translation>
<translation id="2958431318199492670">Nätverkskonfigurationen uppfyller inte ONC-standarden. Det kan hända att delar av konfigurationen inte kan importeras.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">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 har en bestämd giltighetstid. Google Chrome kan inte verifiera certifikaten eftersom klockan på enheten inte går rätt.</translation>
<translation id="2972581237482394796">&amp;Upprepa</translation>
<translation id="2985306909656435243">Om alternativet är aktiverat sparar Chromium en kopia av kortet på enheten så att det går snabbare att fylla i formulär.</translation>
+<translation id="2985398929374701810">Ange en giltig adress</translation>
+<translation id="2986368408720340940">Det här alternativet för utlämning är inte tillgängligt. Testa ett annat alternativ.</translation>
<translation id="2991174974383378012">Dela med webbplatsen</translation>
<translation id="3005723025932146533">Visa sparad kopia</translation>
<translation id="3008447029300691911">Ange CVC-koden för <ph name="CREDIT_CARD" />. När du bekräftar delas kortinformationen med den här webbplatsen.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{minst 1 objekt på synkroniserade enheter}=1{1 objekt (och fler på synkroniserade enheter)}other{# objekt (och fler på synkroniserade enheter)}}</translation>
<translation id="3041612393474885105">Certifikatinformation</translation>
<translation id="3063697135517575841">Det gick inte att bekräfta kortet. Försök igen senare.</translation>
+<translation id="3064966200440839136">Om du betalar i ett externt program sker inte det i inkognitoläge. Vill du fortsätta?</translation>
<translation id="3093245981617870298">Du är offline.</translation>
<translation id="3105172416063519923">Tillgångs-id:</translation>
<translation id="3109728660330352905">Du är inte behörig att se den här sidan.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Testa att köra anslutningsdiagnostik<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Det gick inte att avkoda svaret</translation>
-<translation id="3149891296864842641">Fraktalternativ</translation>
<translation id="3150653042067488994">Tillfälligt serverfel</translation>
+<translation id="3154506275960390542">Den här sidan innehåller ett formulär som kanske inte kan skickas säkert. Data som skickas kan visas av andra vid överföringen eller modifieras av en obehörig innan den tas emot av servern.</translation>
<translation id="3157931365184549694">Återställ</translation>
<translation id="3167968892399408617">Sidor som visas på flikar i inkognitoläget försvinner från webbhistoriken, från dina cookies och från sökhistoriken när alla inkognitoflikar har stängts. Alla filer som du laddar ned eller bokmärken som du skapar sparas.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Det gick inte att skicka begäran om åtkomst till den här webbplatsen till <ph name="NAME" />. Försök igen.</translation>
<translation id="3355823806454867987">Ändra proxyinställningar...</translation>
<translation id="3369192424181595722">Fel på klockan</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> objekt till …</translation>
<translation id="337363190475750230">Tagen ur bruk</translation>
<translation id="3377188786107721145">Fel vid analys av policyn</translation>
<translation id="3380365263193509176">Okänt fel</translation>
<translation id="3380864720620200369">Klient-ID:</translation>
<translation id="3391030046425686457">Leveransadress</translation>
+<translation id="3395827396354264108">Alternativ för utlämning</translation>
<translation id="340013220407300675">Det är möjligt att hackare försöker stjäla dina uppgifter från <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (till exempel lösenord, meddelanden eller kreditkort).</translation>
<translation id="3422248202833853650">Testa att stänga andra program för att frigöra minne.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> kan inte nås för tillfället.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Hämta intervall:</translation>
<translation id="3462200631372590220">Dölja avancerade uppgifter</translation>
+<translation id="3467763166455606212">Kortinnehavarens namn måste anges</translation>
+<translation id="3478058380795961209">Sista giltighetsmånad</translation>
<translation id="3479539252931486093">Var det här oväntat? <ph name="BEGIN_LINK" />Meddela oss<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Inte nu</translation>
<translation id="348000606199325318">Krasch-id <ph name="CRASH_LOCAL_ID" /> (server-id: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Vi kunde inte nå din förälder just nu. Försök igen.</translation>
<translation id="3528171143076753409">Servercertifikatet är inte tillförlitligt.</translation>
-<translation id="3538531656504267329">Ogiltigt sista giltighetsår</translation>
<translation id="3539171420378717834">Spara en kopia av kortet på enheten</translation>
<translation id="3542684924769048008">Använd lösenord för:</translation>
<translation id="3549644494707163724">Kryptera alla synkroniserade data med en egen lösenfras</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Dölj detaljerad information</translation>
<translation id="3587482841069643663">Alla</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Ange ett giltigt utgångsdatum</translation>
<translation id="36224234498066874">Rensa webbinformation...</translation>
<translation id="362276910939193118">Visa fullständig historik</translation>
<translation id="3623476034248543066">Visa värde</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Lösenord:</translation>
<translation id="3696411085566228381">ingen</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Välj en leveransadress om du vill visa leveranssätt och krav.</translation>
<translation id="370665806235115550">Läser in...</translation>
<translation id="3712624925041724820">Licenserna har tagit slut</translation>
<translation id="3714780639079136834">aktivera mobildata eller Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Länk som du har kopierat</translation>
<translation id="375403751935624634">Det gick inte att översätta på grund av ett serverfel.</translation>
<translation id="3759461132968374835">Inga krascher har rapporterats nyligen. Krascher som uppstod när kraschrapporteringen var inaktiverad visas inte här.</translation>
+<translation id="3787705759683870569">Utgångsdatum: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Om du använder en proxyserver ...</translation>
<translation id="3828924085048779000">Lösenfrasen får inte vara tom.</translation>
<translation id="3845539888601087042">Historik från enheter som du är inloggad på visas. <ph name="BEGIN_LINK" />Läs mer<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Vill du att Chromium sparar det här kortet?</translation>
<translation id="4171400957073367226">Felaktig verifieringssignatur</translation>
-<translation id="4176463684765177261">Inaktiverad</translation>
<translation id="4196861286325780578">&amp;Gör om Flytta</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />kontrollera konfigureringarna för brandväggen och antivirusprogram<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{inga}=1{1 app ($1)}=2{2 appar ($1, $2)}other{# appar ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">sökresultat</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> godkände inte inloggningscertifikatet eller så har inget inloggningscertifikat angetts.</translation>
<translation id="443673843213245140">Användning av proxy är inaktiverad men en explicit proxykonfiguration har angetts.</translation>
-<translation id="4446242550670694251">Nu kan du surfa privat. Din aktivitet visas inte för andra som använder enheten.</translation>
<translation id="4492190037599258964">Sökresultat för "<ph name="SEARCH_STRING" />"</translation>
<translation id="4506176782989081258">Valideringsfel: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">kontakta systemadministratören</translation>
<translation id="450710068430902550">Delad med en administratör</translation>
+<translation id="4515275063822566619">Kort och adresser har hämtats från Chrome och ditt Google-konto (<ph name="ACCOUNT_EMAIL" />). Du hanterar dessa under <ph name="BEGIN_LINK" />Inställningar<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Info</translation>
<translation id="4558551763791394412">Testa att inaktivera tilläggen.</translation>
<translation id="457875822857220463">Leverans</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Anpassa till sida</translation>
<translation id="483020001682031208">Det finns inga Physical Web-sidor att visa</translation>
<translation id="4850886885716139402">Visa</translation>
+<translation id="4854362297993841467">Det här leveranssättet är inte tillgängligt. Testa ett annat alternativ.</translation>
<translation id="4858792381671956233">Du har frågat dina föräldrar om lov att besöka den här webbplatsen.</translation>
<translation id="4880827082731008257">Sök i historiken</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Sidan har översatts från ett okänt språk till <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Betalning</translation>
<translation id="4926049483395192435">Värdet måste anges.</translation>
-<translation id="4941291666397027948">* anger att fältet är obligatoriskt</translation>
<translation id="495170559598752135">Åtgärder</translation>
<translation id="4958444002117714549">Expandera lista</translation>
<translation id="4962322354953122629">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom Chrome inte litar på dess säkerhetscertifikat. Det kan bero på att servern är felkonfigurerad eller att anslutningen har blivit kapad. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Felaktigt lösenord</translation>
<translation id="5056549851600133418">Artiklar för dig</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />kontrollera proxyadressen<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Inga cookies}=1{Cookies används på 1 webbplats. }other{Cookies används på # webbplatser. }}</translation>
<translation id="5087286274860437796">Servercertifikatet är inte giltigt för närvarande.</translation>
<translation id="5087580092889165836">Lägg till kort</translation>
<translation id="5089810972385038852">Delstat</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Visa</translation>
<translation id="5308689395849655368">Krashrapportering har inaktiverats.</translation>
<translation id="5317780077021120954">Spara</translation>
-<translation id="5326702247179446998">Mottagare krävs</translation>
<translation id="5327248766486351172">Namn</translation>
<translation id="5337705430875057403">Angripare på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> kan lura dig att göra något farligt, till exempel installera program eller lämna ut din personliga information (som lösenord, telefonnummer eller kreditkortsuppgifter).</translation>
-<translation id="53553865750799677">Hämtningsadressen stöds inte. Välj en annan adress.</translation>
<translation id="5359637492792381994">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" />. Dess säkerhetscertifikat är inte giltigt för närvarande. Det kan bero på att servern är felkonfigurerad eller att anslutningen har blivit kapad. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Det gick inte att spara policyinställningarna</translation>
<translation id="5386426401304769735">Certifikatkedjan för den här webbplatsen innehåller ett certifikat som signerades med SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">På en inbäddad sida på <ph name="SITE" /> står det:</translation>
<translation id="5556459405103347317">Hämta igen</translation>
<translation id="5565735124758917034">Aktiv</translation>
+<translation id="5571083550517324815">Utlämning erbjuds inte på den här adressen. Välj en annan adress.</translation>
<translation id="5572851009514199876">Logga in på Chrome så att Chrome kan kontrollera om du har tillgång till den här webbplatsen.</translation>
-<translation id="5575380383496039204">Leveransadressen stöds inte. Välj en annan adress.</translation>
<translation id="5580958916614886209">Kontrollera utgångsmånad och försök igen</translation>
<translation id="560412284261940334">Hantering stöds inte</translation>
<translation id="5610142619324316209">kontrollera anslutningen</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">Webbplatsens identitet har inte verifierats.</translation>
<translation id="5720705177508910913">Aktuell användare</translation>
<translation id="5732392974455271431">Dina föräldrar kan ta bort blockeringen</translation>
-<translation id="57586589942790530">Ogiltigt kortnummer</translation>
+<translation id="5763042198335101085">Ange en giltig e-postadress</translation>
+<translation id="5765072501007116331">Välj en adress för att visa leveranssätt och krav</translation>
<translation id="5784606427469807560">Det gick inte att bekräfta kortet. Kontrollera internetanslutningen och försök igen.</translation>
<translation id="5785756445106461925">Den här sidan innehåller emellertid andra resurser som inte är säkra. Andra kan se resurserna när de överförs och hackare kan ändra resurserna så att sidan får ett annat utseende.</translation>
<translation id="5786044859038896871">Vill du att kortuppgifterna ska fyllas i?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">Webbplatsen kan inte nås</translation>
<translation id="5869522115854928033">Sparade lösenord</translation>
<translation id="5872918882028971132">Föräldratips</translation>
-<translation id="587760065310675640">Leveransadressen stöds inte. Välj en annan adress.</translation>
<translation id="5901630391730855834">Gul</translation>
-<translation id="59174027418879706">Aktiverat</translation>
<translation id="5926846154125914413">Du kan förlora tillgång till premiuminnehåll från vissa webbplatser.</translation>
<translation id="5959728338436674663">Skicka automatiskt viss <ph name="BEGIN_WHITEPAPER_LINK" />information om systemet och innehåll på sidan<ph name="END_WHITEPAPER_LINK" /> för att hjälpa Google att identifiera skadliga appar och webbplatser. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Vecka</translation>
<translation id="5967867314010545767">Ta bort från historiken</translation>
<translation id="5975083100439434680">Zooma ut</translation>
+<translation id="598637245381783098">Det gick inte att öppna betalningsappen</translation>
<translation id="5989320800837274978">Varken fasta proxyservrar eller en webbadress med PAC-skript har angetts.</translation>
<translation id="5990559369517809815">Förfrågningar till servern har blockerats av ett tillägg.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Kort- och adressalternativen kommer från Chrome. Du hanterar dessa under <ph name="BEGIN_LINK" />Inställningar<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Sida 1}other{Sida #}}</translation>
<translation id="6017514345406065928">Grön</translation>
+<translation id="6027201098523975773">Ange ett namn</translation>
<translation id="6040143037577758943">Stäng</translation>
-<translation id="604124094241169006">Automatisk</translation>
<translation id="6042308850641462728">Mer</translation>
<translation id="6060685159320643512">Försiktigt, experimenten kan vara skadliga</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{inga}=1{1}other{#}}</translation>
@@ -543,9 +552,10 @@
som används.</translation>
<translation id="614940544461990577">Testa att</translation>
<translation id="6151417162996330722">Servercertifikatet har för lång giltighetstid.</translation>
-<translation id="615643356032862689">Nedladdade filer och bokmärken sparas.</translation>
+<translation id="6157877588268064908">Välj en adress för att visa fraktalternativ och krav</translation>
<translation id="6165508094623778733">Läs mer</translation>
<translation id="6177128806592000436">Anslutningen till webbplatsen är inte säker</translation>
+<translation id="6184817833369986695">(kohort: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Kontrollera internetanslutningen</translation>
<translation id="6218753634732582820">Vill du ta bort adressen från Chromium?</translation>
<translation id="6251924700383757765">Sekretesspolicy</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Gör om Ändra ordning</translation>
<translation id="6263376278284652872">Bokmärken för <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Tillbaka till säker webbplats</translation>
+<translation id="6276112860590028508">Sidor från läslistan visas här</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="6290238015253830360">Rekommenderade artiklar visas här</translation>
<translation id="6305205051461490394"><ph name="URL" /> kan inte nås.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Det gick inte att kontrollera om certifikatet har återkallats.</translation>
<translation id="6433490469411711332">Redigera kontaktuppgifter</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> avvisade anslutningen.</translation>
-<translation id="6443118737398455446">Ogiltigt förfallodatum</translation>
<translation id="6446608382365791566">Lägg till mer information</translation>
<translation id="6451458296329894277">Bekräfta återsändning av formulär</translation>
<translation id="6456339708790392414">Din betalning</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Det gick inte att bevisa att serverns identitet ä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. <ph name="BEGIN_LEARN_MORE_LINK" />Lär mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Enhetspolicyer</translation>
<translation id="6477321094435799029">Chrome har identifierat ovanlig kod på sidan och blockerat den för att skydda dina personliga uppgifter (som lösenord, telefonnummer och kreditkortsuppgifter).</translation>
-<translation id="6477460825583319731">Ogiltig e-postadress</translation>
<translation id="6489534406876378309">Börja överföra information om krascher</translation>
<translation id="6508722015517270189">Starta om Chrome</translation>
-<translation id="6525462735697194615">Ogiltig sista giltighetsmånad</translation>
<translation id="6529602333819889595">&amp;Gör om Ta bort</translation>
<translation id="6534179046333460208">Förslag från Physical Web</translation>
<translation id="6550675742724504774">Alternativ</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Sök</translation>
<translation id="6644283850729428850">Policyn är föråldrad.</translation>
<translation id="6652240803263749613">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom datorns operativsystem inte litar på dess säkerhetscertifikat. Det kan bero på att servern är felkonfigurerad eller att anslutningen har blivit kapad. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Fraktalternativet är inte tillgängligt. Testa ett annat alternativ.</translation>
<translation id="6671697161687535275">Vill du ta bort formulärförslaget från Chromium?</translation>
<translation id="6685834062052613830">Logga ut och slutför konfigureringen</translation>
<translation id="6710213216561001401">Föregående</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Något är fel med proxyservern eller så är adressen felaktig.</translation>
<translation id="6727102863431372879">Ange</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{inga}=1{1 objekt}other{# objekt}}</translation>
-<translation id="6743044928064272573">Hämtningsalternativ</translation>
<translation id="674375294223700098">Fel - okänt servercertifikat.</translation>
<translation id="6753269504797312559">Policyvärde</translation>
<translation id="6757797048963528358">Enheten gick i viloläge.</translation>
<translation id="6778737459546443941">Din förälder har inte godkänt den ännu</translation>
<translation id="6810899417690483278">Anpassnings-id</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Det gick inte att läsa in regionsuppgifter</translation>
<translation id="6831043979455480757">Översätt</translation>
<translation id="6839929833149231406">Huvudområde</translation>
<translation id="6874604403660855544">&amp;Gör om Lägg till</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Kortet har bekräftats</translation>
<translation id="6897140037006041989">Användaragent</translation>
<translation id="6915804003454593391">Användare:</translation>
+<translation id="6948701128805548767">Välj en adress för att visa alternativ för utlämning och krav</translation>
<translation id="6957887021205513506">Serverns certifikat verkar vara falskt.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Enhet</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">Både fasta proxyservrar och en webbadress för PAC-skript anges.</translation>
<translation id="6989763994942163495">Visa avancerade inställningar ...</translation>
<translation id="7000990526846637657">Inga historikposter hittades</translation>
-<translation id="7001663382399377034">Lägg till mottagare</translation>
<translation id="7009986207543992532">Du försökte öppna <ph name="DOMAIN" />, men servern angav ett certifikat vars giltighetstid är för lång för att det ska vara trovärdigt. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Andra former av webbhistorik för Google-kontot kan finnas på <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Äldre</translation>
<translation id="7090678807593890770">Sök efter <ph name="LINK" /> på Google</translation>
<translation id="7119414471315195487">Stäng andra flikar eller program</translation>
+<translation id="7129409597930077180">Det går inte att skicka till den här adressen. Välj en annan adress.</translation>
+<translation id="7138472120740807366">Leveranssätt</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7155487117670177674">Osäker betalning</translation>
<translation id="7179921470347911571">Starta om nu</translation>
<translation id="7180611975245234373">Uppdatera</translation>
<translation id="7182878459783632708">Inga policyer har ställts in</translation>
<translation id="7186367841673660872">Sidan har översatts från<ph name="ORIGINAL_LANGUAGE" />till<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> följer inte säkerhetsstandarderna.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Läs mer<ph name="END_LINK" /> om problemet.</translation>
@@ -675,7 +686,6 @@ Psst! Nästa gÃ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nÃ
<translation id="7424977062513257142">På en inbäddad sida på den här webbplatsen står det:</translation>
<translation id="7441627299479586546">Felaktigt policyämne</translation>
<translation id="7444046173054089907">Webbplatsen är blockerad</translation>
-<translation id="7444238235002594607">Välj en hämtningsadress om du vill se vilka hämtningssätt och villkor som finns.</translation>
<translation id="7445762425076701745">Det går inte att fastställa identiteten hos servern som du är ansluten till. Servernamnet som du angav vid anslutningen är bara giltigt inom ditt nätverk och externa certifikatutfärdare kan inte fastställa dess ägarskap. Vissa certifikatutfärdare utfärdar certifikat oavsett namn och därför går det inte att säkerställa att du är ansluten till den avsedda webbplatsen och inte till en skadlig server.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />att läsa mer<ph name="END_LINK" /> om det här problemet.</translation>
<translation id="7460163899615895653">De senaste flikarna från andra enheter visas här</translation>
@@ -719,6 +729,7 @@ Psst! Nästa gÃ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nÃ
<translation id="7755287808199759310">En förälder kan ta bort blockeringen</translation>
<translation id="7758069387465995638">Anslutningen kan ha blockerats av en brandvägg eller antivirusprogram.</translation>
<translation id="7761701407923456692">Servercertifikatet överensstämmer inte med webbadressen.</translation>
+<translation id="7763386264682878361">Textanalysator för manifest för betalning</translation>
<translation id="7764225426217299476">Lägg till adress</translation>
<translation id="777702478322588152">Prefektur</translation>
<translation id="7791543448312431591">Lägg till</translation>
@@ -732,6 +743,7 @@ Psst! Nästa gÃ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nÃ
<translation id="785549533363645510">Men du är inte osynlig. Inkognitoläget döljer inte webbhistoriken för din arbetsgivare, internetleverantören eller webbplatserna du besöker.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Kontrollera CVC-koden och försök igen</translation>
+<translation id="79338296614623784">Ange ett giltigt telefonnummer</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Servercertifikatet är inte giltigt ännu.</translation>
<translation id="7942349550061667556">Röd</translation>
@@ -751,6 +763,7 @@ Psst! Nästa gÃ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nÃ
<translation id="8088680233425245692">Det gick inte att visa artikeln.</translation>
<translation id="8089520772729574115">mindre än 1 MB</translation>
<translation id="8091372947890762290">Aktiveringen väntar på servern</translation>
+<translation id="8118489163946903409">Betalningsmetod</translation>
<translation id="8131740175452115882">Bekräfta</translation>
<translation id="8134994873729925007">Det gick inte att hitta <ph name="BEGIN_ABBR" />DNS-adressen<ph name="END_ABBR" /> till servern för <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Datorn gick i viloläge.</translation>
@@ -776,6 +789,7 @@ Psst! Nästa gÃ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nÃ
<translation id="8349305172487531364">Bokmärkesfältet</translation>
<translation id="8363502534493474904">inaktivera flygplansläget</translation>
<translation id="8364627913115013041">Inte angiven.</translation>
+<translation id="8368476060205742148">Google Play-tjänster</translation>
<translation id="8380941800586852976">Farlig</translation>
<translation id="8382348898565613901">Dina senast besökta bokmärken visas här</translation>
<translation id="8398259832188219207">Kraschrapporten laddades upp den <ph name="UPLOAD_TIME" /></translation>
@@ -784,32 +798,30 @@ Psst! Nästa gÃ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nÃ
<translation id="8428213095426709021">Inställningar</translation>
<translation id="8433057134996913067">Alternativet innebär att du loggas ut från de flesta webbplatser.</translation>
<translation id="8437238597147034694">&amp;Ã…ngra Flytta</translation>
-<translation id="8456681095658380701">Ogiltigt namn</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 kreditkort}other{# kreditkort}}</translation>
<translation id="8483780878231876732">Logga in i Chrome om du vill använda kort i Google-kontot</translation>
<translation id="8488350697529856933">Gäller för</translation>
-<translation id="8492969205326575646">Korttypen stöds inte</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> tog för lång tid på sig att svara.</translation>
<translation id="852346902619691059">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom datorns operativsystem inte litar på dess säkerhetscertifikat. Det kan bero på att servern är felkonfigurerad eller att anslutningen har blivit kapad. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Sista giltighetsår</translation>
<translation id="8543181531796978784">Du kan <ph name="BEGIN_ERROR_LINK" />rapportera ett identifieringsproblem<ph name="END_ERROR_LINK" /> eller <ph name="BEGIN_LINK" />besöka den här osäkra webbplatsen<ph name="END_LINK" /> om du är medveten om säkerhetsriskerna.</translation>
<translation id="8553075262323480129">Det gick inte att översätta eftersom det inte gick att avgöra vilket språk som användes på sidan.</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="8570229484593575558">Den här informationen sparas inte|:#din webbhistorik#dina sökningar#cookiedata.</translation>
<translation id="8571890674111243710">Översätter sidan till <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Din aktivitet |kanske fortfarande är synlig| för#webbplatser som du besöker#din arbetsgivare#din internetleverantör.</translation>
<translation id="858637041960032120">Ange telefonnr
</translation>
<translation id="859285277496340001">Certifikatet har inte någon specificerad mekanism för att kontrollera om det har återkallats.</translation>
<translation id="8620436878122366504">Dina föräldrar har inte godkänt den ännu</translation>
<translation id="8647750283161643317">Återställ alla till standardvärden</translation>
<translation id="8703575177326907206">Din anslutning till <ph name="DOMAIN" /> är inte krypterad.</translation>
+<translation id="8718314106902482036">Betalningen slutfördes inte</translation>
<translation id="8725066075913043281">Försök igen</translation>
-<translation id="8728672262656704056">Du surfar inkognito.</translation>
+<translation id="8728672262656704056">Du surfar inkognito</translation>
<translation id="8730621377337864115">Klart</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="8759274551635299824">Kortets giltighetstid har löpt ut</translation>
<translation id="8790007591277257123">&amp;Gör om Ta bort</translation>
-<translation id="8798099450830957504">Standard</translation>
<translation id="8800988563907321413">Förslag på webbsidor i närheten visas här</translation>
<translation id="8820817407110198400">Bokmärken</translation>
<translation id="883848425547221593">Övriga bokmärken</translation>
@@ -819,6 +831,7 @@ Psst! Nästa gÃ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nÃ
<translation id="8866481888320382733">Det uppstod ett fel när policyinställningarna analyserades</translation>
<translation id="8866959479196209191">På den här sidan står det:</translation>
<translation id="8870413625673593573">Nyligen stängda</translation>
+<translation id="8874824191258364635">Ange ett giltigt kortnummer</translation>
<translation id="8876793034577346603">Det gick inte att tolka nätverkskonfigurationen.</translation>
<translation id="8877192140621905067">När du bekräftar delas kortinformationen med den här webbplatsen</translation>
<translation id="8889402386540077796">Nyans</translation>
@@ -828,7 +841,6 @@ Psst! Nästa gÃ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nÃ
<translation id="8931333241327730545">Vill du spara det här kortet i ditt Google-konto?</translation>
<translation id="8932102934695377596">Klockan går efter</translation>
<translation id="8954894007019320973">(forts)</translation>
-<translation id="895548565263634352">Läs artiklar av <ph name="ARTICLE_PUBLISHER" /> och <ph name="OTHER_ARTICLE_COUNT" /> andra</translation>
<translation id="8971063699422889582">Servercertifikatet har gått ut.</translation>
<translation id="8986494364107987395">Skicka användningsstatistik och kraschrapporter till Google automatiskt</translation>
<translation id="8987927404178983737">MÃ¥nad</translation>
@@ -846,7 +858,6 @@ Psst! Nästa gÃ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nÃ
<translation id="9068849894565669697">Välj färg</translation>
<translation id="9076283476770535406">Den kan innehålla barnförbjudet innehåll</translation>
<translation id="9078964945751709336">Mer information krävs</translation>
-<translation id="9094175695478007090">Det gick inte att starta betalningsappen.</translation>
<translation id="9103872766612412690">På <ph name="SITE" /> används normalt kryptering (SSL) för att skydda din information. När Chromium försökte ansluta till <ph name="SITE" /> den här gången skickade webbplatsen tillbaka ovanliga och felaktiga uppgifter. Sådant kan hända när en angripare utger sig för att vara <ph name="SITE" /> eller när anslutningen har avbrutits av en Wi-Fi-inloggningsskärm. Din information är fortfarande säker eftersom Chromium avbröt anslutningen innan någon data utbyttes.</translation>
<translation id="9137013805542155359">Visa original</translation>
<translation id="9137248913990643158">Logga in på Chrome innan du använder den här appen.</translation>
diff --git a/chromium/components/strings/components_strings_sw.xtb b/chromium/components/strings/components_strings_sw.xtb
index 91d673d80d1..f0b4fcc16a4 100644
--- a/chromium/components/strings/components_strings_sw.xtb
+++ b/chromium/components/strings/components_strings_sw.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="sw">
<translation id="1008557486741366299">Sio Sasa</translation>
<translation id="1015730422737071372">Toa maelezo ya ziada</translation>
+<translation id="1021110881106174305">Kadi zinazokubaliwa</translation>
<translation id="1032854598605920125">Zungusha kwenye mwendo wa saa</translation>
<translation id="1038842779957582377">jina lisilojulikana</translation>
<translation id="1050038467049342496">Funga programu nyingine</translation>
@@ -19,7 +20,7 @@
<translation id="1126551341858583091">Ukubwa kwenye nafasi ya hifadhi ya ndani ya kifaa ni <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Akiba ya sera ni SAWA</translation>
<translation id="113188000913989374"><ph name="SITE" /> unasema:</translation>
-<translation id="1132774398110320017">Mipangilio ya Kujaza otomatiki ya Chrome...</translation>
+<translation id="1132774398110320017">Mipangilio ya Chrome ya kujaza kiotomatiki...</translation>
<translation id="1152921474424827756">Fikia <ph name="BEGIN_LINK" />nakala iliyowekwa kwenye akiba<ph name="END_LINK" /> ya <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> ilifunga muunganisho bila kutarajia.</translation>
<translation id="1161325031994447685">Kuunganisha tena kwenye Wi-Fi</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Ficha thamani</translation>
<translation id="1228893227497259893">Kitambulisho cha huluki kisicho halali</translation>
<translation id="1232569758102978740">Hakina Jina</translation>
+<translation id="1263231323834454256">Orodha ya kusoma</translation>
<translation id="1264126396475825575">Ripoti ya kuacha kufanya kazi iliyochukuliwa <ph name="CRASH_TIME" /> (haijapakiwa au imepuuzwa)</translation>
<translation id="1285320974508926690">Kamwe usitafsiri tovuti hii</translation>
<translation id="129553762522093515">Vilivyofungwa hivi karibuni</translation>
@@ -42,9 +44,10 @@
<translation id="1339601241726513588">Kikoa cha kujiandikisha:</translation>
<translation id="1340482604681802745">Anwani ya eneo la kuchukulia</translation>
<translation id="1344211575059133124">Inaonekana unahitaji ruhusa ili uweze kutembelea tovuti hii</translation>
-<translation id="1344588688991793829">Mipangilio ya Kujaza otomatiki ya Chromium...</translation>
+<translation id="1344588688991793829">Mipangilio ya Chromium ya kujaza kiotomatiki...</translation>
<translation id="1374468813861204354">mapendekezo</translation>
<translation id="1375198122581997741">Kuhusu Toleo</translation>
+<translation id="1377321085342047638">Nambari ya Kadi</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> haikutuma data yoyote.</translation>
<translation id="1407135791313364759">Fungua zote</translation>
<translation id="1413809658975081374">Hitilafu ya faragha</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Historia</translation>
<translation id="1645368109819982629">Itifaki haitumiki</translation>
<translation id="1656489000284462475">Muda wa kuabiri gari</translation>
+<translation id="1663943134801823270">Kadi na anwani zinatoka Chrome. Unaweza kuzidhibiti kwenye <ph name="BEGIN_LINK" />Mipangilio<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">Kwa kawaida <ph name="SITE" /> hutumia usimbaji fiche ili kulinda maelezo yako. Google Chrome ilipojaribu kuunganisha kwenye <ph name="SITE" /> wakati huu, tovuti ilituma kitambulisho kisicho cha kawaida na kisicho sahihi. Hili linaweza kutokea mvamizi anapojaribu kujifanya kuwa <ph name="SITE" />, au uchanganuzi wa kuingia katika Wi-Fi umeingilia muunganisho. Maelezo yako yangali salama kwa sababu Google Chrome ilisimamisha muunganisho kabla data yoyote itumwe.</translation>
<translation id="168328519870909584">Huenda wavamizi walio kwenye <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> kwa sasa wakajaribu kusakinisha programu hatari ambazo zinaiba au kufuta maelezo kwenye kifaa chako (kwa mfano, picha, manenosiri, ujumbe na kadi za mkopo).</translation>
<translation id="168841957122794586">Cheti cha seva kina kitufe dhaifu cha kifichua msimbo.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Unahitaji ruhusa kutoka kwa <ph name="NAME" /> ili utembelee tovuti hii</translation>
+<translation id="1721424275792716183">* Unahitaji kujaza sehemu hii</translation>
<translation id="1728677426644403582">Unaangalia chanzo cha ukurasa wa wavuti</translation>
+<translation id="173080396488393970">Aina hii ya kadi haitumiki</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Kuwasiliana na msimamizi wa mfumo.</translation>
+<translation id="1740951997222943430">Andika mwezi sahihi wa kuisha kwa muda wa matumizi</translation>
<translation id="1745358365027406341">Pakua ukurasa baadaye</translation>
<translation id="17513872634828108">Vichupo vilivyo wazi</translation>
<translation id="1753706481035618306">Nambari ya ukurasa</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Tafadhali sasisha kaulisiri yako iliyolandanishwa.</translation>
<translation id="1787142507584202372">Vichupo vyako vilivyo wazi huonekana hapa</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Chagua anwani ya uwasilishaji ili uangalie mbinu na mahitaji ya uwasilishaji.</translation>
+<translation id="1803264062614276815">Jina la mwenye kadi</translation>
<translation id="1803678881841855883">Mfumo wa Google wa Kuvinjari Salama <ph name="BEGIN_LINK" />uligundua programu hasidi<ph name="END_LINK" /> kwenye <ph name="SITE" /> hivi majuzi. Tovuti ambazo kwa kawaida huwa salama wakati mwingine huathiriwa na programu hasidi. Maudhui hasidi hutoka kwa <ph name="SUBRESOURCE_HOST" />, msambazaji wa programu hasidi anayejulikana. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Iliongezwa <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Ombi au vigezo vya ombi batili</translation>
<translation id="1826516787628120939">Inakagua</translation>
<translation id="1834321415901700177">Tovuti hii ina programu hatari</translation>
<translation id="1842969606798536927">Lipa</translation>
-<translation id="1864455488461349376">Chaguo za uwasilishaji</translation>
<translation id="1871208020102129563">Proksi imewekwa ili kutumia seva za proksi thabiti, siyo URL ya hati .pac.</translation>
<translation id="1871284979644508959">Lazima sehemu hii ijazwe</translation>
<translation id="187918866476621466">Fungua kurasa zinazoanza</translation>
<translation id="1883255238294161206">Kunja orodha</translation>
<translation id="1898423065542865115">Kuchuja</translation>
<translation id="194030505837763158">Nenda kwenye <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Kadi zinazokubaliwa</translation>
<translation id="1962204205936693436">Alamisho za <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Hitilafu ya namba tambulishi</translation>
<translation id="1974060860693918893">Mipangilio ya kina</translation>
<translation id="1978555033938440688">Toleo la Programu dhibiti</translation>
+<translation id="1995859865337580572">Tafadhali thibitisha CVC yako</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{na nyingine 1}other{na nyingine #}}</translation>
-<translation id="2020194265157481222">Inahitaji jina kwenye kadi</translation>
<translation id="2025186561304664664">Proksi imewekwa katika usanidi otomatiki.</translation>
<translation id="2030481566774242610">Je, ulimaanisha <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Kuangalia seva mbadala na kinga-mtandao<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Leo</translation>
<translation id="2154054054215849342">Huduma ya usawazishaji haipatikani kwa ajili ya kikoa chako</translation>
<translation id="2154484045852737596">Badilisha kadi</translation>
-<translation id="2156993118928861787">Anwani si sahihi</translation>
<translation id="2166049586286450108">Idhini Kamili ya Kufikia ya Msimamizi</translation>
<translation id="2166378884831602661">Tovuti hii haiwezi kutoa muunganisho salama</translation>
<translation id="2181821976797666341">Sera</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{Anwani 1}other{Anwani #}}</translation>
+<translation id="2202020181578195191">Andika mwaka sahihi wa kuisha kwa muda wa matumizi</translation>
<translation id="2212735316055980242">Sera haikupatikana</translation>
<translation id="2213606439339815911">Inachukua viingizo...</translation>
<translation id="2230458221926704099">Weka muunganisho wako kwa kutumia <ph name="BEGIN_LINK" />programu ya kuchunguza<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Ufikiaji wako wa intaneti umezuiwa</translation>
<translation id="230155334948463882">Je, ni kadi mpya?</translation>
<translation id="2305919008529760154">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; huenda cheti chake cha usalama kilitolewa kwa ulaghai. Huenda hali hii ilitokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako.<ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Chaguo za kadi na anwani zinatoka kwenye Akaunti yako ya Google (<ph name="ACCOUNT_EMAIL" />) na Chrome. Unaweza kudhibiti chaguo hizi katika <ph name="BEGIN_LINK" />Mipangilio<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> inahitaji jina la mtumiaji na nenosiri.</translation>
<translation id="2318774815570432836">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu tovuti hii hutumia HSTS. Hitilafu na uvamizi wa mtandao kwa kawaida huwa wa muda tu, kwa hivyo ukurasa huu huenda utafanya kazi baadaye.<ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Alamisho zingine</translation>
@@ -152,26 +156,27 @@
<translation id="2365563543831475020">Ripoti ya kuacha kufanya kazi iliyochukuliwa <ph name="CRASH_TIME" /> haikupakiwa</translation>
<translation id="2367567093518048410">Kiwango</translation>
<translation id="2371153335857947666">{1,plural, =1{Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kilikwisha muda jana. Huenda hali hii ilitokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. Saa ya kompyuta kwa sasa imewekwa kuwa <ph name="CURRENT_DATE" />. Je, hiyo ni sahihi? Ikiwa si sahihi, rekebisha saa ya mfumo wako kisha uonyeshe upya ukurasa huu. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.}other{Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kilikwisha muda siku # zilizopita. Huenda hali hii ilitokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako Saa ya kompyuta kwa sasa imewekwa kuwa <ph name="CURRENT_DATE" />. Je, hiyo ni sahihi? Ikiwa si sahihi, rekebisha saa ya mfumo wako kisha uonyeshe upya ukurasa huu. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.}}</translation>
-<translation id="237718015863234333">Hakuna UI mbadala zinazopatikana</translation>
+<translation id="237718015863234333">Hakuna chaguo mbadala za kiolesura zinazopatikana</translation>
<translation id="2384307209577226199">Biashara chaguo-msingi</translation>
<translation id="2386255080630008482">Cheti cha seva kimebatilishwa.</translation>
<translation id="2392959068659972793">Onyesha sera zisizowekwa thamani</translation>
+<translation id="239429038616798445">Mbinu hii ya usafirishaji haipatikani. Jaribu mbinu tofauti.</translation>
<translation id="2396249848217231973">Tendua kufuta</translation>
<translation id="2460160116472764928">Mfumo wa Google wa Kuvinjari Salama <ph name="BEGIN_LINK" />umegundua programu hasidi<ph name="END_LINK" /> kwenye <ph name="SITE" /> hivi majuzi. Tovuti ambazo kwa kawaida huwa salama wakati mwingine huathiriwa na programu hasidi. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Jaza</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Inaendesha Zana ya Kuchunguza Mtandao<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL batili ya utafutaji.</translation>
<translation id="2491120439723279231">Cheti cha seva kina hitilafu.</translation>
-<translation id="24943777258388405">Nambari ya simu si sahihi</translation>
<translation id="2495083838625180221">Kichanganuzi cha JSON</translation>
<translation id="2495093607237746763">Ikitiwa tiki, Chromium itahifadhi nakala ya kadi yako kwenye kifaa hiki kwa ajili ya kujaza fomu haraka zaidi.</translation>
<translation id="2498091847651709837">Changanua kadi mpya</translation>
<translation id="2501278716633472235">Rudi nyuma</translation>
<translation id="2515629240566999685">Kuangalia uthabiti wa mawimbi katika eneo lako</translation>
-<translation id="2516305470678292029">UI Mbadala</translation>
+<translation id="2516305470678292029">Chaguo mbadala za kiolesura</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> imetuma jibu ambalo si sahihi.</translation>
<translation id="2552545117464357659">Mpya zaidi</translation>
<translation id="2556876185419854533">Tendua Kuhariri</translation>
+<translation id="2587730715158995865">Kutoka <ph name="ARTICLE_PUBLISHER" />. Soma makala haya na mengine <ph name="OTHER_ARTICLE_COUNT" />.</translation>
<translation id="2587841377698384444">Kitambulisho cha API ya Saraka:</translation>
<translation id="2597378329261239068">Hati hii imelindwa kwa nenosiri. Tafadhali weka nenosiri linalotumika.</translation>
<translation id="2609632851001447353">Vipera</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Inaendesha Zana ya Kuchunguza Muunganisho<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">Sawa</translation>
<translation id="2742870351467570537">Ondoa vipengee vilivyochaguliwa</translation>
+<translation id="277133753123645258">Mbinu ya usafirishaji</translation>
<translation id="277499241957683684">Rekodi ya kifaa inayokosekana</translation>
<translation id="2784949926578158345">Muunganisho uliwekwa upya.</translation>
<translation id="2794233252405721443">Tovuti imezuiwa</translation>
-<translation id="2812680587231492111">Chaguo hilo la kuchukua halipatikani. Jaribu chaguo tofauti.</translation>
<translation id="2824775600643448204">Upau wa anwani na utafutaji</translation>
<translation id="2826760142808435982">Muunganisho umesimbwa kwa njia fiche na kuthibitishwa kupitia <ph name="CIPHER" /> na unatumia <ph name="KX" /> kama utaratibu msingi wa ubadilishaji.</translation>
<translation id="2835170189407361413">Futa fomu</translation>
-<translation id="2849041323157393173">Chaguo hilo la kuwasilisha halipatikani. Jaribu chaguo tofauti.</translation>
<translation id="2889159643044928134">Usipakie Upya</translation>
<translation id="2900469785430194048">Nafasi ya kuhifadhi kwenye Google Chrome iliisha ilipokuwa ikijaribu kuonyesha ukurasa huu wa wavuti.</translation>
<translation id="2909946352844186028">Mabadiliko ya mtandao yamegunduliwa.</translation>
<translation id="2916038427272391327">Funga programu nyingine</translation>
<translation id="2922350208395188000">Cheti cha seva hakiwezi kukaguliwa.</translation>
+<translation id="2928905813689894207">Anwani ya kutuma Bili</translation>
<translation id="2948083400971632585">Unaweza kuzima proksi zozote zilizosanidiwa kwa muunganisho kutoka kwenye ukurasa wa mipangilio.</translation>
<translation id="2955913368246107853">Funga upau wa kupata</translation>
<translation id="2958431318199492670">Usanidi wa mtandao hautii kiwango cha ONC. Sehemu za usanidi haziwezi kuingizwa.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Ili kutambua muunganisho salama, saa yako inahitaji kusahihishwa. Hii ni kwa sababu vyeti ambavyo tovuti hutumia kujitambua ni sahihi kwa vipindi mahususi pekee. Kwa kuwa saa ya kifaa chako si sahihi, Google Chrome haiwezi kuthibitisha vyeti hivi.</translation>
<translation id="2972581237482394796">&amp;Rudia</translation>
<translation id="2985306909656435243">Ikiwashwa, Chromium itahifadhi nakala ya kadi yako kwenye kifaa hiki kwa ajili ya kujaza fomu haraka zaidi.</translation>
+<translation id="2985398929374701810">Andika anwani sahihi</translation>
+<translation id="2986368408720340940">Mbinu hii ya kuchukua haipatikani. Jaribu mbinu tofauti.</translation>
<translation id="2991174974383378012">Kushiriki kwenye Tovuti</translation>
<translation id="3005723025932146533">Onyesha nakala iliyohifadhiwa</translation>
<translation id="3008447029300691911">Weka CVC ya <ph name="CREDIT_CARD" />. Baada ya kuthibitisha, maelezo ya kadi yako yatashirikiwa na tovuti hii.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{angalau kipengee 1 kwenye vifaa vilivyosawazishwa}=1{Kipengee 1 (na zaidi kwenye vifaa vilivyosawazishwa)}other{Vipengee # (na zaidi kwenye vifaa vilivyosawazishwa)}}</translation>
<translation id="3041612393474885105">Maelezo ya Cheti</translation>
<translation id="3063697135517575841">Chrome haikuweza kuthibitisha kadi yako wakati huu. Tafadhali jaribu tena baadaye.</translation>
+<translation id="3064966200440839136">Inaacha hali fiche ili kulipa kupitia programu ya nje. Je, ungependa kuendelea?</translation>
<translation id="3093245981617870298">Uko nje ya mtandao.</translation>
<translation id="3105172416063519923">Kitambulisho cha Kipengee:</translation>
<translation id="3109728660330352905">Huna idhini ya kuona ukurasa huu.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Jaribu kutumia zana ya Kuchunguza Muunganisho<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Imeshindwa kusimbua jibu</translation>
-<translation id="3149891296864842641">Chaguo la usafirishaji</translation>
<translation id="3150653042067488994">Hitilfau ya muda ya seva</translation>
+<translation id="3154506275960390542">Ukurasa huu una fomu ambayo haiwezi kuwasilishwa kwa njia salama. Data unayotuma inaweza kusomwa na watu wengine inapotumwa au inaweza kurekebishwa na mvamizi ili kubadilisha data ambayo seva inapokea.</translation>
<translation id="3157931365184549694">Rejesha</translation>
<translation id="3167968892399408617">Kurasa unazoziangalia katika vichupo fiche hazitaendelea kuwepo katika historia ya kivinjari, hifadhi ya vidakuzi, au historia yako ya utafutaji ukishafunga vichupo vyako vyote fiche. Faili zozote unazopakua au alamisho unazounda hazitafutwa.</translation>
<translation id="3169472444629675720">Gundua</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Ombi lako la kufikia tovuti hii halikutumwa kwa <ph name="NAME" />. Tafadhali jaribu tena.</translation>
<translation id="3355823806454867987">Badilisha mipangilio ya seva mbadala...</translation>
<translation id="3369192424181595722">Hitilafu ya saa</translation>
+<translation id="337311366426640088">Vipengee <ph name="ITEM_COUNT" /> zaidi...</translation>
<translation id="337363190475750230">Imewekwa katika hali ya kutotumika</translation>
<translation id="3377188786107721145">Hitilafu ya kuchanganua sera</translation>
<translation id="3380365263193509176">Hitilafu isiyojulikana</translation>
<translation id="3380864720620200369">Kitambulisho cha Mteja:</translation>
-<translation id="3391030046425686457">Anwani ya uwasilishaji</translation>
+<translation id="3391030046425686457">Mahali pa kupeleka</translation>
+<translation id="3395827396354264108">Mbinu ya kuchukua</translation>
<translation id="340013220407300675">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 malipo).</translation>
<translation id="3422248202833853650">Jaribu kuondoka kwenye programu nyingine ili upate nafasi zaidi.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> haiwezi kufikiwa kwa sasa.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Muda unaotumika kuleta:</translation>
<translation id="3462200631372590220">Ficha mahiri</translation>
+<translation id="3467763166455606212">Jina la mwenye kadi linahitajika</translation>
+<translation id="3478058380795961209">Mwezi wa Muda wa Matumizi Kuisha</translation>
<translation id="3479539252931486093">Je, hukutarajia tukio hili? <ph name="BEGIN_LINK" />Tujulishe<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Sio sasa</translation>
<translation id="348000606199325318">Kitambulisho cha kuacha kufanya kazi <ph name="CRASH_LOCAL_ID" /> (Kitambulisho cha Seva: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Hatukuweza kufikia mzazi wako wakati huu. Tafadhali jaribu tena.</translation>
<translation id="3528171143076753409">Cheti cha seva hakiaminiki.</translation>
-<translation id="3538531656504267329">Mwaka wa kuisha kwa muda wa matumizi si sahihi</translation>
<translation id="3539171420378717834">Weka nakala ya kadi hii kwenye kifaa hiki</translation>
<translation id="3542684924769048008">Tumia nenosiri kwa:</translation>
<translation id="3549644494707163724">Simba kwa njia fiche data yote iliyosawazishwa kwa kaulisiri yako binafsi ya usawazishaji</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Ficha maelezo</translation>
<translation id="3587482841069643663">Zote</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Andika tarehe sahihi ya kuisha kwa muda wa matumizi</translation>
<translation id="36224234498066874">Futa Data ya Kuvinjari...</translation>
<translation id="362276910939193118">Onyesha Historia Kamili</translation>
<translation id="3623476034248543066">Onyesha thamani</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Nenosiri:</translation>
<translation id="3696411085566228381">hamna</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Chagua anwani ya mahali bidhaa zitakapopelekwa ili uangalie masharti na mbinu za kusafirisha.</translation>
<translation id="370665806235115550">Inapakia...</translation>
<translation id="3712624925041724820">Leseni zimekwisha</translation>
<translation id="3714780639079136834">Kuwasha data ya simu au Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Kiungo ulichonakili</translation>
<translation id="375403751935624634">Utafsiri haukufanikiwa kwa sababu ya hitilafu ya seva.</translation>
<translation id="3759461132968374835">Huna uharibifu ulioripotiwa hivi karibuni. Uharibifu uliotokea wakati kuripoti kwa uharibifu kulipolemazwa hakutaonekana hapa.</translation>
+<translation id="3787705759683870569">Muda wa matumizi utakwisha <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Ukitumia seva mbadala...</translation>
<translation id="3828924085048779000">Kaulisiri tupu hairuhusiwi.</translation>
<translation id="3845539888601087042">Inaonyesha historia kutoka vifaa vyako ulivyotumia kuingia katika akaunti. <ph name="BEGIN_LINK" />Pata maelezo zaidi<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Je, unataka Chromium ihifadhi kadi hii?</translation>
<translation id="4171400957073367226">Sahihi mbaya ya uthibitishaji</translation>
-<translation id="4176463684765177261">Kimelemazwa</translation>
<translation id="4196861286325780578">Rudia hatua</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Kuangalia mipangilio ya kinga-mtandao na kinga-virusi<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{hamna}=1{Programu 1 ($1)}=2{Programu 2 ($1, $2)}other{Programu # ($1, $2, $3)}}</translation>
@@ -383,14 +394,14 @@
<translation id="4406896451731180161">matokeo ya utafutaji</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> haikukubali cheti chako cha kuingia katika akaunti, au huenda hukutoa cheti.</translation>
<translation id="443673843213245140">Matumizi ya proksi yamelemazwa lakini usanidi wa proksi wazi umebainishwa.</translation>
-<translation id="4446242550670694251">Sasa unaweza kuvinjari kwa faragha, na watu wengine wanaotumia kifaa hiki hawataona shughuli zako.</translation>
<translation id="4492190037599258964">Matokeo ya utafutaji wa '<ph name="SEARCH_STRING" />'</translation>
<translation id="4506176782989081258">Hitilafu ya uthibitishaji: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Kuwasiliana na msimamizi wa mfumo</translation>
<translation id="450710068430902550">Kushiriki na Msimamizi</translation>
+<translation id="4515275063822566619">Kadi na anwani zinatoka Chrome na Akaunti yako ya Google (<ph name="ACCOUNT_EMAIL" />). Unaweza kuzidhibiti katika <ph name="BEGIN_LINK" />Mipangilio<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Maelezo</translation>
<translation id="4558551763791394412">Jaribu kuzima viendelezi vyako.</translation>
-<translation id="457875822857220463">Uwasilishaji</translation>
+<translation id="457875822857220463">Usafirishaji</translation>
<translation id="4587425331216688090">Ungependa kuondoa anwani kutoka kwenye Chrome?</translation>
<translation id="4589078953350245614">Umejaribu kufikia <ph name="DOMAIN" />, lakini seva imewasilisha cheti kisicho sahihi. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Muunganisho wako kwenye <ph name="DOMAIN" /> umesimbwa kwa njia fiche kwa kutumia mipangilio ya kriptografia ya kisasa.</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Sawazisha kwenye ukurasa</translation>
<translation id="483020001682031208">Hakuna Kurasa za Wavuti kila Mahali za kuonyesha</translation>
<translation id="4850886885716139402">Mwonekano</translation>
+<translation id="4854362297993841467">Njia hii ya kusafirisha haitumiki. Jaribu njia tofauti.</translation>
<translation id="4858792381671956233">Umewaomba wazazi wako ruhusa ya kuutembelea ukurasa huu.</translation>
<translation id="4880827082731008257">Tafuta katika historia</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Ukurasa huu umetafsiriwa kutoka katika lugha ambayo haijulikani hadi <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Malipo</translation>
<translation id="4926049483395192435">Sharti ibainishwe.</translation>
-<translation id="4941291666397027948">* inaonyesha sehemu ambayo sharti ijazwe</translation>
<translation id="495170559598752135">Vitendo</translation>
<translation id="4958444002117714549">Panua orodha</translation>
<translation id="4962322354953122629">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na Chrome. Hii inatokana na uwekaji mipangilio usiofaa, au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Nenosiri lisilo sahihi</translation>
<translation id="5056549851600133418">Makala kwa ajili yako</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Kuangalia anwani mbadala<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Hamna vidakuzi}=1{Tovuti 1 inatumia vidakuzi. }other{Tovuti # zinatumia vidakuzi. }}</translation>
<translation id="5087286274860437796">Cheti cha seva si sahihi kwa sasa.</translation>
<translation id="5087580092889165836">Ongeza kadi</translation>
<translation id="5089810972385038852">Jimbo</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Onyesha</translation>
<translation id="5308689395849655368">Kuripoti uharibifu kumelemazwa.</translation>
<translation id="5317780077021120954">Hifadhi</translation>
-<translation id="5326702247179446998">Lazima mpokeaji awekwe</translation>
<translation id="5327248766486351172">Jina</translation>
<translation id="5337705430875057403">Huenda wavamizi kwenye <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> wakakulaghai ili ufanye kitu hatari kama vile kusakinisha programu au kuonyesha maelezo yako ya kibinafsi (kwa mfano, manenosiri, nambari za simu, au kadi za mikopo).</translation>
-<translation id="53553865750799677">Anwani ya eneo la kuchukulia haitumiki. Chagua anwani tofauti.</translation>
<translation id="5359637492792381994">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama si sahihi. Hii inatokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Imeshindwa kuhifadhi mipangilio ya sera</translation>
<translation id="5386426401304769735">Msururu wa cheti wa tovuti hii una cheti kilichotiwa sahihi kwa kutumia SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">Ukurasa uliopachikwa kwenye <ph name="SITE" /> unasema:</translation>
<translation id="5556459405103347317">Pakia upya</translation>
<translation id="5565735124758917034">Inatumika</translation>
+<translation id="5571083550517324815">Haiwezi kuchukua kutoka kwenye anwani hii. Chagua anwani tofauti.</translation>
<translation id="5572851009514199876">Tafadhali anza na uingie katika Chrome ili Chrome iangalie ikiwa unaruhusiwa kufikia tovuti hii.</translation>
-<translation id="5575380383496039204">Anwani ya uwasilishaji haitumiki. Chagua anwani tofauti.</translation>
<translation id="5580958916614886209">Angalia mwezi kuisha kwa muda wa matumizi halafu ujajibu tena</translation>
<translation id="560412284261940334">Usimamizi hautumiki</translation>
<translation id="5610142619324316209">Kuangalia muunganisho</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">Utambulisho wa tovuti hii haujathibitishwa.</translation>
<translation id="5720705177508910913">Mtumiaji wa sasa</translation>
<translation id="5732392974455271431">Wazazi wako wanaweza kukuondolea kizuizi</translation>
-<translation id="57586589942790530">Nambari ya kadi si sahihi</translation>
+<translation id="5763042198335101085">Andika anwani sahihi ya barua pepe</translation>
+<translation id="5765072501007116331">Chagua mahali ili uone njia za kusafirisha na mahitaji</translation>
<translation id="5784606427469807560">Kulikuwa na tatizo wakati wa kuthibitisha kadi yako. Angalia muunganisho wako wa intaneti kisha ujaribu tena.</translation>
<translation id="5785756445106461925">Mbali na hayo, ukurasa huu una rasilimali nyingine zisizo salama. Rasilimali hizi zinaweza kuangaliwa na watu wengine wanaosafiri, na zinaweza kurekebishwa na mvamizi kubadilisha mwonekano wa ukurasa.</translation>
<translation id="5786044859038896871">Ungependa kujaza maelezo ya kadi yako?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">Tovuti hii haiwezi kufikiwa</translation>
<translation id="5869522115854928033">Manenosiri yaliyohifadhiwa</translation>
<translation id="5872918882028971132">Mapendekezo ya Wazazi</translation>
-<translation id="587760065310675640">Anwani ya mahali bidhaa zitakapopelekwa haitumiki. Chagua anwani tofauti.</translation>
<translation id="5901630391730855834">Manjano</translation>
-<translation id="59174027418879706">Imewashwa</translation>
<translation id="5926846154125914413">Utapoteza idhini ya kufikia maudhui ya kulipiwa kutoka kwenye tovuti nyingine.</translation>
<translation id="5959728338436674663">Tuma kiotomatiki <ph name="BEGIN_WHITEPAPER_LINK" />maelezo ya mfumo na maudhui kadha ya ukurasa<ph name="END_WHITEPAPER_LINK" /> kwa Google ili kusaidia kugundua programu na tovuti hatari. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Juma</translation>
<translation id="5967867314010545767">Ondoa kwenye historia</translation>
<translation id="5975083100439434680">Fifiza</translation>
+<translation id="598637245381783098">Imeshindwa kufungua programu ya kulipa</translation>
<translation id="5989320800837274978">Siyo seva proksi za kudumu wala URL ya hati ya .pac zimebainishwa.</translation>
<translation id="5990559369517809815">Maombi katika seva yamezuiwa kwa kiendelezi.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Chaguo za maelezo ya kadi na anwani zinatoka kwenye Chrome. Unaweza kudhibiti chaguo hizi katika <ph name="BEGIN_LINK" />Mipangilio<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Ukurasa wa 1}other{Ukurasa wa #}}</translation>
<translation id="6017514345406065928">Kijani</translation>
+<translation id="6027201098523975773">Andika jina</translation>
<translation id="6040143037577758943">Funga</translation>
-<translation id="604124094241169006">Otomatiki</translation>
<translation id="6042308850641462728">Zaidi</translation>
<translation id="6060685159320643512">Tahadhari, majaribio haya yanaweza kusumbua</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{hamna}=1{1}other{#}}</translation>
@@ -543,9 +552,10 @@
mtandao ambavyo huenda unavitumia.</translation>
<translation id="614940544461990577">Jaribu:</translation>
<translation id="6151417162996330722">Cheti cha seva kina muda sahihi ambao ni mrefu sana.</translation>
-<translation id="615643356032862689">Faili na alamisho ulizopakua zitahifadhiwa.</translation>
+<translation id="6157877588268064908">Chagua anwani ili uone mbinu za kusafirisha na mahitaji</translation>
<translation id="6165508094623778733">Pata maelezo zaidi</translation>
<translation id="6177128806592000436">Muunganisho wako kwenye tovuti hii si salama</translation>
+<translation id="6184817833369986695">(kundi: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Angalia muunganisho wako wa Intaneti</translation>
<translation id="6218753634732582820">Je, ungependa kuondoa anwani kwenye Chromium?</translation>
<translation id="6251924700383757765">Sera ya faragha</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">Rudia Kupanga Upya</translation>
<translation id="6263376278284652872">Alamisho za <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Rejea kwenye usalama</translation>
+<translation id="6276112860590028508">Kurasa kutoka orodha yako ya usomaji huonekana hapa</translation>
+<translation id="6280223929691119688">Haiwezi kuwasilisha kwenye anwani hii. Chagua anwani tofauti.</translation>
<translation id="6282194474023008486">Msimbo wa posta</translation>
<translation id="6290238015253830360">Makala uliyopendekeza yataonekana hapa</translation>
<translation id="6305205051461490394"><ph name="URL" /> haiwezi kufikiwa.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Haiwezi kukagua ikiwa cheti kimebatilishwa.</translation>
<translation id="6433490469411711332">Badilisha maelezo ya mawasiliano</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> imekataa kuunganisha.</translation>
-<translation id="6443118737398455446">Tarehe ya kumalizika muda si sahihi</translation>
<translation id="6446608382365791566">Ongeza maelezo zaidi</translation>
<translation id="6451458296329894277">Thibitisha kuwa Fomu Iwasilishwe Tena</translation>
<translation id="6456339708790392414">Malipo Yako</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama huenda kimebatilishwa. Huenda hali hii inatokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Sera za kifaa</translation>
<translation id="6477321094435799029">Chrome imegundua nambari ya kuthibitisha isiyo ya kawaida kwenye ukurasa huu na ikaizuia ili kulinda maelezo ya binafsi (kwa mfano, manenosiri, nambari za simu na kadi za mikopo).</translation>
-<translation id="6477460825583319731">Anwani ya barua pepe si sahihi</translation>
<translation id="6489534406876378309">Anza kupakia matukio ya kuacha kufanya kazi</translation>
<translation id="6508722015517270189">Zima na uwashe Chrome</translation>
-<translation id="6525462735697194615">Mwezi wa kuisha kwa muda wa matumizi si sahihi</translation>
<translation id="6529602333819889595">Rudia Kufuta</translation>
<translation id="6534179046333460208">Mapendekezo ya Wavuti kila Mahali</translation>
<translation id="6550675742724504774">Chaguo</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685">Utafutaji wa <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Sera hii imepingwa.</translation>
<translation id="6652240803263749613">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na mfumo wa uendeshaji wa kompyuta yako. Hali hii inatokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Chaguo hilo la kusafirisha halipatikani. Jaribu chaguo tofauti.</translation>
<translation id="6671697161687535275">Je, ungependa kuondoa pendekezo la fomu kwenye Chromium?</translation>
<translation id="6685834062052613830">Ondoka na ukamilishe kuweka mipangilio</translation>
<translation id="6710213216561001401">Iliyotangulia</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Kuna hitilafu katika seva mbadala, au anwani siyo sahihi.</translation>
<translation id="6727102863431372879">Weka</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{hamna}=1{Kipengee 1}other{Vipengee #}}</translation>
-<translation id="6743044928064272573">Chaguo za eneo la kuchukulia</translation>
<translation id="674375294223700098">Hitilafu isiyojulikana ya cheti cha seva.</translation>
<translation id="6753269504797312559">Thamani ya sera</translation>
<translation id="6757797048963528358">Kifaa chako kiko katika hali tuli.</translation>
<translation id="6778737459546443941">Mzazi wako bado hajaiidhinisha</translation>
<translation id="6810899417690483278">Kitambulisho cha kubadilisha ili kukufaa</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Imeshindwa kupakia maeneo ya data</translation>
<translation id="6831043979455480757">Tafsiri</translation>
<translation id="6839929833149231406">Eneo</translation>
<translation id="6874604403660855544">Rudia kuongeza</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Kadi yako imethibitishwa</translation>
<translation id="6897140037006041989">Programu ya Mtumiaji</translation>
<translation id="6915804003454593391">Mtumiaji:</translation>
+<translation id="6948701128805548767">Chagua anwani ili uone mbinu za kuchukua na mahitaji</translation>
<translation id="6957887021205513506">Cheti cha seva kinaonekana kuwa ghushi.</translation>
<translation id="6965382102122355670">Sawa</translation>
<translation id="6965978654500191972">Kifaa</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">Seva zote za proksi thabiti na URL ya hati ya .pac zimebainishwa.</translation>
<translation id="6989763994942163495">Onyesha mipangilio ya kina...</translation>
<translation id="7000990526846637657">Hakuna historia ya mambo uliyovinjari inayopatikana</translation>
-<translation id="7001663382399377034">Ongeza mpokeaji</translation>
<translation id="7009986207543992532">Umejaribu kufikia <ph name="DOMAIN" />, lakini seva iliwasilisha cheti ambacho muda wake wa kutumika ni mrefu sana hivi kwamba hauaminiki. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Huenda Akaunti yako ya Google ina aina nyingine za historia ya kuvinjari kwenye <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Za awali</translation>
<translation id="7090678807593890770">Tafuta <ph name="LINK" /> kwenye Google</translation>
<translation id="7119414471315195487">Funga vichupo au programu nyingine</translation>
+<translation id="7129409597930077180">Haiwezi kusafirisha kwenda kwenye anwani hii. Chagua anwani tofauti.</translation>
+<translation id="7138472120740807366">Njia ya kusafirisha</translation>
<translation id="7139724024395191329">Emirate</translation>
<translation id="7155487117670177674">Malipo si salama</translation>
<translation id="7179921470347911571">Zindua upya Sasa</translation>
<translation id="7180611975245234373">Onyesha upya</translation>
<translation id="7182878459783632708">Hakuna sera zilizowekwa</translation>
<translation id="7186367841673660872">Ukurasa huu umetafsiriwa kutoka<ph name="ORIGINAL_LANGUAGE" />hadi<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> haizingatii viwango vya usalama.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Pata maelezo zaidi<ph name="END_LINK" /> kuhusu tatizo hili.</translation>
@@ -675,7 +686,6 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="7424977062513257142">Ukurasa uliopachikwa kwenye ukurasa huu wa wavuti unasema:</translation>
<translation id="7441627299479586546">Kichwa cha sera kisichofaa</translation>
<translation id="7444046173054089907">Tovuti hii imezuiwa</translation>
-<translation id="7444238235002594607">Chagua anwani ya eneo la kuchukulia ili uangalie mbinu na mahitaji ya kuchukulia.</translation>
<translation id="7445762425076701745">Utambulisho wa seva ambayo umejiunga kwayo hauwezi kuhalalishwa kikamilifu. Umeunganishwa kwenye seva kwa kutumia jina ambalo ni halali tu katika mtandao wako, ambalo mamlaka ya cheti cha nje hayana njia ya kuhalalisha umiliki wake. Kama baadhi ya mamlaka ya cheti yatatoa vyeti vya majina haya bila kujali, hakuna njia ya kuhakikisha umeunganishwa kwenye tovuti inayohitajika na sio mshambulizi.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Pata maelezo zaidi<ph name="END_LINK" /> kuhusu hitilafu hii.</translation>
<translation id="7460163899615895653">Vichupo vyako vya hivi majuzi kutoka kwenye vifaa vingine vitaonekana hapa</translation>
@@ -719,6 +729,7 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="7755287808199759310">Mzazi wako anaweza kukuondolea kizuizi</translation>
<translation id="7758069387465995638">Huenda programu ya kinga-mtandao au kinga-virusi zimezuia muunganisho huu.</translation>
<translation id="7761701407923456692">Cheti cha seva hakilingani na URL.</translation>
+<translation id="7763386264682878361">Kichanganuzi cha Faili za Maelezo ya Malipo</translation>
<translation id="7764225426217299476">Ongeza anwani</translation>
<translation id="777702478322588152">Wilaya</translation>
<translation id="7791543448312431591">Ongeza</translation>
@@ -732,6 +743,7 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="785549533363645510">Hata hivyo, huonekani. Kuvinjari katika hali fiche hakufichi kuvinjari kwako kusionekane na mwajiri, mtoaji huduma wako wa intaneti, au tovuti unazotembelea.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Angalia CVC yako na ujaribu tena</translation>
+<translation id="79338296614623784">Andika nambari sahihi ya simu</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Cheti cha seva bado sio halali.</translation>
<translation id="7942349550061667556">Nyekundu</translation>
@@ -751,6 +763,7 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="8088680233425245692">Haikufaulu kuangalia makala.</translation>
<translation id="8089520772729574115">chini ya MB 1</translation>
<translation id="8091372947890762290">Uwashaji unasubiri kwenye seva</translation>
+<translation id="8118489163946903409">Njia ya kulipa</translation>
<translation id="8131740175452115882">Thibitisha</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Anwani ya DNS <ph name="END_ABBR" /> ya seva ya <ph name="HOST_NAME" /> haikupatikana.</translation>
<translation id="8149426793427495338">Kompyuta yako iko katika hali tuli.</translation>
@@ -776,6 +789,7 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="8349305172487531364">Sehemu ya Alamisho</translation>
<translation id="8363502534493474904">Kuzima hali ya ndegeni</translation>
<translation id="8364627913115013041">Haijawekwa.</translation>
+<translation id="8368476060205742148">Huduma za Google Play</translation>
<translation id="8380941800586852976">Hatari</translation>
<translation id="8382348898565613901">Alamisho ulizotembelea hivi majuzi zitaonekana hapa</translation>
<translation id="8398259832188219207">Ripoti ya kuacha kufanya kazi ilipakiwa <ph name="UPLOAD_TIME" /></translation>
@@ -784,32 +798,30 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="8428213095426709021">Mipangilio</translation>
<translation id="8433057134996913067">Kufanya hivyo kutakuondoa kwenye tovuti nyingi.</translation>
<translation id="8437238597147034694">Tendua hatua</translation>
-<translation id="8456681095658380701">Jina batili</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{Kadi 1 ya mikopo}other{Kadi # za mikopo}}</translation>
<translation id="8483780878231876732">Ili utumie kadi kutoka kwenye Akaunti yako ya Google, ingia katika Chrome</translation>
<translation id="8488350697529856933">Inatumika kwenye</translation>
-<translation id="8492969205326575646">Aina ya kadi haitumiki</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> imechukua muda mrefu kupakia.</translation>
<translation id="852346902619691059">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na mfumo wa uendeshaji wa kifaa chako. Hii inatokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Mwaka wa Muda wa Matumizi Kuisha</translation>
<translation id="8543181531796978784">Unaweza <ph name="BEGIN_ERROR_LINK" />kuripoti tatizo la ugunduzi<ph name="END_ERROR_LINK" /> au, ikiwa unaelewa kiwango cha hatari kinachoweza kutokea, <ph name="BEGIN_LINK" />tembelea tovuti hii isiyo salama<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Tafsiri imeshindwa kwa sababu lugha ya ukurasa isingeweza kuthibitishwa.</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="8570229484593575558">Maelezo haya |hayatahifadhiwa|:#Historia yako ya kuvinjari#Mambo uliyotafuta#Data ya vidakuzi</translation>
<translation id="8571890674111243710">Inatafsiri ukurasa katika <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Shughuli zako |huenda bado zinaonekana| na:#Tovuti unazotembelea#Mwajiri wako#Mtoa huduma wako wa intaneti</translation>
<translation id="858637041960032120">Ongeza simu
</translation>
<translation id="859285277496340001">Cheti hakibainishi utaratibu wa kuangalia iwapo kimekataliwa.</translation>
<translation id="8620436878122366504">Wazazi wako bado hawajaiidhinisha</translation>
<translation id="8647750283161643317">Weka upya zote kwa chaguo-msingi</translation>
<translation id="8703575177326907206">Muunganisho wako kwa <ph name="DOMAIN" /> haujasimbwa.</translation>
+<translation id="8718314106902482036">Malipo hayajakamilishwa</translation>
<translation id="8725066075913043281">Jaribu tena</translation>
-<translation id="8728672262656704056">Unavinjari katika hali fiche.</translation>
+<translation id="8728672262656704056">Unavinjari katika hali fiche</translation>
<translation id="8730621377337864115">Nimemaliza</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="8759274551635299824">Muda wa matumizi wa kadi hii umekwisha</translation>
<translation id="8790007591277257123">Rudia kufuta</translation>
-<translation id="8798099450830957504">Chaguo Msingi</translation>
<translation id="8800988563907321413">Mapendekezo ya maudhui ya uhamishaji wa karibu yataonekana hapa</translation>
<translation id="8820817407110198400">Alamisho</translation>
<translation id="883848425547221593">Alamisho Zingine</translation>
@@ -819,6 +831,7 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="8866481888320382733">Hitilafu wakati wa kuchanganua mipangilio ya sera</translation>
<translation id="8866959479196209191">Ukurasa huu unasema:</translation>
<translation id="8870413625673593573">Zilizofungwa Hivi Karibuni</translation>
+<translation id="8874824191258364635">Andika nambari sahihi ya kadi</translation>
<translation id="8876793034577346603">Usanidi wa mtandao umekosa kuchanganuliwa.</translation>
<translation id="8877192140621905067">Baada ya kuthibitisha, maelezo ya kadi yako yatashirikiwa na tovuti hii</translation>
<translation id="8889402386540077796">Rangi</translation>
@@ -828,7 +841,6 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="8931333241327730545">Je, ungependa kuhifadhi kadi hii katika Akaunti yako ya Google?</translation>
<translation id="8932102934695377596">Saa yako iko nyuma</translation>
<translation id="8954894007019320973">(Inaendelea)</translation>
-<translation id="895548565263634352">Soma hadithi zilizoandikwa na <ph name="ARTICLE_PUBLISHER" /> na <ph name="OTHER_ARTICLE_COUNT" /> zaidi</translation>
<translation id="8971063699422889582">Cheti cha seva kimechina.</translation>
<translation id="8986494364107987395">Tumia Google takwimu za matumizi na ripoti za mara ambazo kivinjari kinaacha kufanya kazi, moja kwa moja</translation>
<translation id="8987927404178983737">Mwezi</translation>
@@ -846,7 +858,6 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="9068849894565669697">Chagua rangi</translation>
<translation id="9076283476770535406">Huenda ina maudhui ya ngono</translation>
<translation id="9078964945751709336">Maelezo zaidi yanahitajika</translation>
-<translation id="9094175695478007090">Imeshindwa kuanzisha programu ya malipo.</translation>
<translation id="9103872766612412690">Kwa kawaida <ph name="SITE" /> hutumia usimbaji fiche ili kulinda maelezo yako. Chromium ilipojaribu kuunganisha kwenye <ph name="SITE" /> wakati huu, tovuti ilituma kitambulisho kisicho cha kawaida na kisicho sahihi. Hili linaweza kutokea mvamizi anapojaribu kujifanya kuwa <ph name="SITE" />, au uchanganuzi wa kuingia katika Wi-Fi umeingilia muunganisho. Maelezo yako yangali salama kwa sababu Chromium ilisimamisha muunganisho kabla data yoyote itumwe.</translation>
<translation id="9137013805542155359">Onyesha asili</translation>
<translation id="9137248913990643158">Tafadhali anza na uingie katika Chrome kabla ya kutumia programu hii.</translation>
diff --git a/chromium/components/strings/components_strings_ta.xtb b/chromium/components/strings/components_strings_ta.xtb
index c5035dd83c7..ddabd30035c 100644
--- a/chromium/components/strings/components_strings_ta.xtb
+++ b/chromium/components/strings/components_strings_ta.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="ta">
<translation id="1008557486741366299">இபà¯à®ªà¯‹à®¤à¯ இலà¯à®²à¯ˆ </translation>
<translation id="1015730422737071372">கூடà¯à®¤à®²à¯ விவரஙà¯à®•à®³à¯ˆ வழஙà¯à®•à®µà¯à®®à¯</translation>
+<translation id="1021110881106174305">à®à®±à¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯ காரà¯à®Ÿà¯à®•à®³à¯</translation>
<translation id="1032854598605920125">கடிகாரதà¯à®¤à®¿à®šà¯ˆà®¯à®¿à®²à¯ சà¯à®´à®±à¯à®±à¯</translation>
<translation id="1038842779957582377">அறியபà¯à®ªà®Ÿà®¾à®¤ பெயரà¯</translation>
<translation id="1050038467049342496">பிற பயனà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ˆ மூடவà¯à®®à¯</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">மதிபà¯à®ªà¯ˆ மறை</translation>
<translation id="1228893227497259893">தவறான உடà¯à®ªà¯Šà®°à¯à®³à¯ அடையாளஙà¯à®•à®¾à®Ÿà¯à®Ÿà®¿</translation>
<translation id="1232569758102978740">தலைபà¯à®ªà®¿à®Ÿà®¾à®¤à®¤à¯</translation>
+<translation id="1263231323834454256">வாசிபà¯à®ªà¯à®ªà¯ படà¯à®Ÿà®¿à®¯à®²à¯</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> அனà¯à®±à¯ சிதைவ௠அறிகà¯à®•à¯ˆ பெறபà¯à®ªà®Ÿà¯à®Ÿà®¤à¯ (இனà¯à®©à¯à®®à¯ பதிவேறà¯à®±à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ அலà¯à®²à®¤à¯ பà¯à®±à®•à¯à®•à®£à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ)</translation>
<translation id="1285320974508926690">இநà¯à®¤ தளதà¯à®¤à¯ˆ எபà¯à®ªà¯‹à®¤à¯à®®à¯ மொழிபெயரà¯à®•à¯à®• வேணà¯à®Ÿà®¾à®®à¯</translation>
<translation id="129553762522093515">சமீபதà¯à®¤à®¿à®²à¯ மூடியவை</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromium தனà¯à®©à®¿à®°à®ªà¯à®ªà®¿ அமைபà¯à®ªà¯à®•à®³à¯...</translation>
<translation id="1374468813861204354">பரிநà¯à®¤à¯à®°à¯ˆà®•à®³à¯</translation>
<translation id="1375198122581997741">பதிபà¯à®ªà¯ˆà®ªà¯ பறà¯à®±à®¿</translation>
+<translation id="1377321085342047638">காரà¯à®Ÿà¯ எணà¯</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> எநà¯à®¤à®¤à¯ தரவையà¯à®®à¯ அனà¯à®ªà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="1407135791313364759">எலà¯à®²à®¾à®µà®±à¯à®±à¯ˆà®¯à¯à®®à¯ திற</translation>
<translation id="1413809658975081374">தனியà¯à®°à®¿à®®à¯ˆà®ªà¯ பிழை</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">வரலாறà¯</translation>
<translation id="1645368109819982629">ஆதரிகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤ நெறிமà¯à®±à¯ˆ</translation>
<translation id="1656489000284462475">பிகà¯à®•à®ªà¯</translation>
+<translation id="1663943134801823270">காரà¯à®Ÿà¯à®•à®³à¯à®®à¯ à®®à¯à®•à®µà®°à®¿à®•à®³à¯à®®à¯ Chrome இலிரà¯à®¨à¯à®¤à¯ பெறபà¯à®ªà®Ÿà¯à®Ÿà®µà¯ˆà®¯à®¾à®•à¯à®®à¯. <ph name="BEGIN_LINK" />அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯<ph name="END_LINK" /> அவறà¯à®±à¯ˆ நிரà¯à®µà®•à®¿à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="1676269943528358898">வழகà¯à®•à®®à®¾à®•, <ph name="SITE" /> உஙà¯à®•à®³à¯ தகவலைப௠பாதà¯à®•à®¾à®ªà¯à®ªà®¤à®±à¯à®•à®¾à®• à®®à¯à®±à¯ˆà®®à¯ˆà®¯à®¾à®•à¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à®¤à¯. இநà¯à®¤ à®®à¯à®±à¯ˆ <ph name="SITE" /> உடன௠இணைவதறà¯à®•à¯ Google Chrome à®®à¯à®¯à®±à¯à®šà®¿à®¤à¯à®¤à®ªà¯‹à®¤à¯ வழகà¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯ மாறான மறà¯à®±à¯à®®à¯ தவறான நறà¯à®šà®¾à®©à¯à®±à®¿à®¤à®´à¯à®•à®³à¯ˆ இணையதளம௠வழஙà¯à®•à®¿à®¯à®¤à¯. தாகà¯à®•à¯à®ªà®µà®°à¯ தனà¯à®©à¯ˆ <ph name="SITE" /> ஆகக௠காடà¯à®Ÿ à®®à¯à®¯à®±à¯à®šà®¿à®•à¯à®•à¯à®®à¯ போத௠அலà¯à®²à®¤à¯ இணைபà¯à®ªà¯ˆ வைஃபை உளà¯à®¨à¯à®´à¯ˆà®µà¯à®¤à¯ திரை கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®®à¯ போத௠இத௠à®à®±à¯à®ªà®Ÿà®²à®¾à®®à¯. இரà¯à®ªà¯à®ªà®¿à®©à¯à®®à¯, தரவ௠எதà¯à®µà¯à®®à¯ பரிமாறà¯à®±à®ªà¯à®ªà®Ÿà¯à®µà®¤à®±à¯à®•à¯ à®®à¯à®©à¯ Google Chrome இணைபà¯à®ªà¯ˆ நிறà¯à®¤à¯à®¤à®¿à®¯à®¤à®¾à®²à¯ உஙà¯à®•à®³à¯ தகவல௠பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®•à®µà¯‡ இரà¯à®•à¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="168328519870909584"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> தளதà¯à®¤à®¿à®²à®¿à®°à¯à®•à¯à®•à¯à®®à¯ தாகà¯à®•à¯à®ªà®µà®°à¯à®•à®³à¯, உஙà¯à®•à®³à¯ தகவலைத௠(எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà®¾à®•, படஙà¯à®•à®³à¯, கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯, செயà¯à®¤à®¿à®•à®³à¯ மறà¯à®±à¯à®®à¯ கிரெடிட௠காரà¯à®Ÿà¯à®•à®³à¯) திரà¯à®Ÿà®•à¯à®•à¯‚டிய அலà¯à®²à®¤à¯ நீகà¯à®•à®•à¯à®•à¯‚டிய தீஙà¯à®•à®¿à®´à¯ˆà®•à¯à®•à¯à®®à¯ பயனà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ˆ உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®²à¯ நிறà¯à®µ à®®à¯à®¯à®±à¯à®šà®¿à®¤à¯à®¤à®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="168841957122794586">சேவையக சானà¯à®±à®¿à®¤à®´à®¿à®²à¯ வலà¯à®µà®±à¯à®± கà¯à®±à®¿à®¯à¯€à®Ÿà¯à®Ÿà®¾à®•à¯à®• விசை இரà¯à®•à¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®±à¯à®•à¯à®šà¯ செலà¯à®², <ph name="NAME" /> இன௠அனà¯à®®à®¤à®¿ வேணà¯à®Ÿà¯à®®à¯</translation>
+<translation id="1721424275792716183">* அவசியமான பà¯à®²à®®à¯</translation>
<translation id="1728677426644403582">இணையப௠பகà¯à®•à®¤à¯à®¤à®¿à®©à¯ மூலதà¯à®¤à¯ˆà®ªà¯ பாரà¯à®•à¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯</translation>
+<translation id="173080396488393970">இநà¯à®¤à®•à¯ காரà¯à®Ÿà¯ வகை ஆதரிகà¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">கணினி நிரà¯à®µà®¾à®•à®¿à®¯à¯ˆà®¤à¯ தொடரà¯à®ªà¯à®•à¯Šà®³à¯à®³à®µà¯à®®à¯</translation>
+<translation id="1740951997222943430">சரியான காலாவதி மாததà¯à®¤à¯ˆ உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯</translation>
<translation id="1745358365027406341">பகà¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பினà¯à®©à®°à¯ பதிவிறகà¯à®•à¯</translation>
<translation id="17513872634828108">தாவலà¯à®•à®³à¯ˆà®¤à¯ திற</translation>
<translation id="1753706481035618306">பகà¯à®• எணà¯</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">உஙà¯à®•à®³à®¿à®©à¯ ஒதà¯à®¤à®¿à®šà¯ˆ சொறà¯à®±à¯Šà®Ÿà®°à¯ˆà®ªà¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="1787142507584202372">உஙà¯à®•à®³à¯ தாவலà¯à®•à®³à¯ இஙà¯à®•à¯‡ தோனà¯à®±à¯à®®à¯</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">டெலிவரி à®®à¯à®±à¯ˆà®•à®³à¯ˆà®¯à¯à®®à¯ தேவைகளையà¯à®®à¯ சரிபாரà¯à®•à¯à®•, டெலிவரி à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
+<translation id="1803264062614276815">காரà¯à®Ÿà¯ உரிமையாளரின௠பெயரà¯</translation>
<translation id="1803678881841855883">சமீபதà¯à®¤à®¿à®²à¯ Google இன௠பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®© உலாவலானத௠<ph name="SITE" /> இல௠<ph name="BEGIN_LINK" />தீமà¯à®ªà¯Šà®°à¯à®³à¯ˆà®•à¯ கணà¯à®Ÿà®±à®¿à®¨à¯à®¤à¯à®³à¯à®³à®¤à¯<ph name="END_LINK" />. பொதà¯à®µà®¾à®•à®ªà¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®• இரà¯à®•à¯à®•à¯à®®à¯ இணையதளஙà¯à®•à®³à¯ சில நேரஙà¯à®•à®³à®¿à®²à¯ தீமà¯à®ªà¯Šà®°à¯à®³à®¾à®²à¯ பாதிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®µà®¤à¯à®£à¯à®Ÿà¯. தீஙà¯à®•à®¿à®´à¯ˆà®•à¯à®•à¯à®®à¯ உளà¯à®³à®Ÿà®•à¯à®•à®®à®¾à®©à®¤à¯ பிரபலமான <ph name="SUBRESOURCE_HOST" /> எனà¯à®®à¯ தீமà¯à®ªà¯Šà®°à¯à®³à¯ வழஙà¯à®•à¯à®¨à®°à®¿à®Ÿà®®à®¿à®°à¯à®¨à¯à®¤à¯ வரà¯à®•à®¿à®±à®¤à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">சேரà¯à®¤à¯à®¤à®¤à¯: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">தவறான கோரிகà¯à®•à¯ˆ அலà¯à®²à®¤à¯ கோரிகà¯à®•à¯ˆ அளவà¯à®°à¯à®•à¯à®•à®³à¯</translation>
<translation id="1826516787628120939">சரிபாரà¯à®•à¯à®•à®¿à®±à®¤à¯</translation>
<translation id="1834321415901700177">இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®•à¯à®•à¯à®®à¯ நிரலà¯à®•à®³à¯ உளà¯à®³à®©</translation>
<translation id="1842969606798536927">பணம௠செலà¯à®¤à¯à®¤à¯à®•</translation>
-<translation id="1864455488461349376">டெலிவரி விரà¯à®ªà¯à®ªà®®à¯</translation>
<translation id="1871208020102129563">நிலையான பà¯à®°à®¾à®•à¯à®¸à®¿ சேவையகஙà¯à®•à®³à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ பà¯à®°à®¾à®•à¯à®¸à®¿ அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯, .pac ஸà¯à®•à®¿à®°à®¿à®ªà¯à®Ÿà¯ URL அலà¯à®².</translation>
<translation id="1871284979644508959">அவசியமà¯</translation>
<translation id="187918866476621466">தà¯à®µà®•à¯à®•à®ªà¯ பகà¯à®•à®™à¯à®•à®³à¯ˆà®¤à¯ திற</translation>
<translation id="1883255238294161206">படà¯à®Ÿà®¿à®¯à®²à¯ˆà®šà¯ சà¯à®°à¯à®•à¯à®•à¯</translation>
<translation id="1898423065542865115">வடிகடà¯à®Ÿà¯à®¤à®²à¯</translation>
<translation id="194030505837763158"><ph name="LINK" /> கà¯à®•à¯à®šà¯ செலà¯à®•</translation>
-<translation id="1946821392246652573">à®à®±à¯à®±à¯à®•à¯à®•à¯Šà®³à¯à®³à®ªà¯à®ªà®Ÿà¯à®®à¯ காரà¯à®Ÿà¯à®•à®³à¯</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> பà¯à®¤à¯à®¤à®•à®•à¯à®•à¯à®±à®¿à®•à®³à¯</translation>
<translation id="1973335181906896915">தொடராகà¯à®• பிழை</translation>
<translation id="1974060860693918893">மேமà¯à®ªà®Ÿà¯à®Ÿà®µà¯ˆ</translation>
<translation id="1978555033938440688">நிலைபà¯à®ªà¯Šà®°à¯à®³à®¿à®©à¯ பதிபà¯à®ªà¯</translation>
+<translation id="1995859865337580572">CVC எணà¯à®£à¯ˆà®šà¯ சரிபாரà¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{மேலà¯à®®à¯ 1}other{மேலà¯à®®à¯ #}}</translation>
-<translation id="2020194265157481222">காரà¯à®Ÿà®¿à®²à¯ உளà¯à®³ பெயர௠தேவை</translation>
<translation id="2025186561304664664">பà¯à®°à®¾à®•à¯à®¸à®¿, தானியஙà¯à®•à®¿ உளà¯à®³à®®à¯ˆà®µà¯à®•à¯à®•à¯ அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯</translation>
<translation id="2030481566774242610"><ph name="LINK" /> à®à®•à¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à®¾?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />பà¯à®°à®¾à®•à¯à®¸à®¿ மறà¯à®±à¯à®®à¯ ஃபயரà¯à®µà®¾à®²à¯ˆà®šà¯ சரிபாரà¯à®¤à¯à®¤à®²à¯<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">இனà¯à®±à¯</translation>
<translation id="2154054054215849342">உஙà¯à®•à®³à¯ டொமைனà¯à®•à¯à®•à¯ ஒதà¯à®¤à®¿à®šà¯ˆà®¤à¯à®¤à®²à¯ சேவை à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯</translation>
<translation id="2154484045852737596">காரà¯à®Ÿà¯ˆà®¤à¯ திரà¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
-<translation id="2156993118928861787">தவறான à®®à¯à®•à®µà®°à®¿</translation>
<translation id="2166049586286450108">à®®à¯à®´à¯ நிரà¯à®µà®¾à®•à®¿ அணà¯à®•à®²à¯</translation>
<translation id="2166378884831602661">இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¾à®²à¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®© இணைபà¯à®ªà¯ˆ வழஙà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="2181821976797666341">கொளà¯à®•à¯ˆà®•à®³à¯</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 à®®à¯à®•à®µà®°à®¿}other{# à®®à¯à®•à®µà®°à®¿à®•à®³à¯}}</translation>
+<translation id="2202020181578195191">சரியான காலாவதி ஆணà¯à®Ÿà¯ˆ உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯</translation>
<translation id="2212735316055980242">கொளà¯à®•à¯ˆ காணபà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="2213606439339815911">உளà¯à®³à¯€à®Ÿà¯à®•à®³à¯ˆà®ªà¯ பெறà¯à®•à®¿à®±à®¤à¯...</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />கணà¯à®Ÿà®±à®¿à®¯à¯à®®à¯ பயனà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ˆà®ªà¯<ph name="END_LINK" /> பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ இணைபà¯à®ªà¯ˆà®šà¯ சரிசெயà¯à®¯à®µà¯à®®à¯</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">உஙà¯à®•à®³à¯ இணைய அணà¯à®•à®²à¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="230155334948463882">பà¯à®¤à®¿à®¯ அடà¯à®Ÿà¯ˆà®¯à®¾?</translation>
<translation id="2305919008529760154"><ph name="DOMAIN" /> என இநà¯à®¤à®šà¯ சேவையகதà¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. அதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®šà¯ சானà¯à®±à®¿à®¤à®´à¯ தவறான à®®à¯à®±à¯ˆà®¯à®¿à®²à¯ வழஙà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®•à¯à®•à¯‚டà¯à®®à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">காரà¯à®Ÿà¯à®®à¯ à®®à¯à®•à®µà®°à®¿ விவரஙà¯à®•à®³à¯à®®à¯ உஙà¯à®•à®³à¯ Google கணகà¯à®•à¯ (<ph name="ACCOUNT_EMAIL" />) மறà¯à®±à¯à®®à¯ Chrome இலிரà¯à®¨à¯à®¤à¯ பெறபà¯à®ªà®Ÿà¯à®Ÿà®¤à®¾à®•à¯à®®à¯. அவறà¯à®±à¯ˆ <ph name="BEGIN_LINK" />அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯<ph name="END_LINK" /> நிரà¯à®µà®•à®¿à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" />கà¯à®•à¯à®ªà¯ பயனரà¯à®ªà¯†à®¯à®°à¯à®®à¯ கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯à®®à¯ தேவை.</translation>
<translation id="2318774815570432836"><ph name="SITE" /> இணையதளம௠HSTSà®à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®µà®¤à®¾à®²à¯, இபà¯à®ªà¯‹à®¤à¯ அதà¯à®¤à®³à®¤à¯à®¤à®¿à®±à¯à®•à¯à®šà¯ செலà¯à®² à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. நெடà¯à®µà¯Šà®°à¯à®•à¯ பிழைகளà¯à®®à¯ பாதிபà¯à®ªà¯à®•à®³à¯à®®à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®©à®µà¯ˆà®¯à¯‡. இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ சிறித௠நேரம௠கழிதà¯à®¤à¯à®šà¯ செயலà¯à®ªà®Ÿà¯à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">பிற பà¯à®•à¯à®®à®¾à®°à¯à®•à¯à®¸à¯</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">நிறà¯à®µà®© இயலà¯à®ªà¯à®¨à®¿à®²à¯ˆ</translation>
<translation id="2386255080630008482">சேவையகச௠சானà¯à®±à®¿à®¤à®´à¯ திரà¯à®®à¯à®ªà®ªà¯ பெறபà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="2392959068659972793">மதிபà¯à®ªà¯à®®à¯ எதà¯à®µà¯à®®à¯ அமைகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤ கொளà¯à®•à¯ˆà®•à®³à¯ˆà®•à¯ காடà¯à®Ÿà¯</translation>
+<translation id="239429038616798445">இநà¯à®¤ ஷிபà¯à®ªà®¿à®™à¯ à®®à¯à®±à¯ˆ இலà¯à®²à¯ˆ. வேற௠மà¯à®±à¯ˆà®¯à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®ªà¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="2396249848217231973">&amp;நீகà¯à®•à¯à®¤à®²à¯ˆà®šà¯ செயலà¯à®¤à®µà®¿à®°à¯</translation>
<translation id="2460160116472764928">சமீபதà¯à®¤à®¿à®²à¯ Google இன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯ உலாவலானத௠<ph name="SITE" /> இல௠<ph name="BEGIN_LINK" />தீமà¯à®ªà¯Šà®°à¯à®³à¯ˆà®•à¯ கணà¯à®Ÿà®±à®¿à®¨à¯à®¤à¯à®³à¯à®³à®¤à¯<ph name="END_LINK" />. பொதà¯à®µà®¾à®•à®ªà¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®• இரà¯à®•à¯à®•à¯à®®à¯ இணையதளஙà¯à®•à®³à¯ சில நேரஙà¯à®•à®³à®¿à®²à¯ தீமà¯à®ªà¯Šà®°à¯à®³à®¾à®²à¯ பாதிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®µà®¤à¯à®£à¯à®Ÿà¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">நிரபà¯à®ªà¯</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />நெடà¯à®µà¯Šà®°à¯à®•à¯ டயகà¯à®©à®¸à¯à®Ÿà®¿à®•à¯à®¸à¯ கரà¯à®µà®¿à®¯à¯ˆ இயகà¯à®•à®µà¯à®®à¯<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">தவறான தேடல௠URL.</translation>
<translation id="2491120439723279231">சேவையகச௠சானà¯à®±à®¿à®¤à®´à®¿à®²à¯ பிழைகள௠உளà¯à®³à®©.</translation>
-<translation id="24943777258388405">தவறான ஃபோன௠எணà¯</translation>
<translation id="2495083838625180221">JSON பாரà¯à®šà®°à¯</translation>
<translation id="2495093607237746763">இத௠தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¾à®²à¯, விரைவாகப௠படிவதà¯à®¤à¯ˆ நிரபà¯à®ª, உஙà¯à®•à®³à¯ காரà¯à®Ÿà®¿à®©à¯ நகலை Chromium இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ சேமிகà¯à®•à¯à®®à¯.</translation>
<translation id="2498091847651709837">பà¯à®¤à®¿à®¯ காரà¯à®Ÿà¯ˆ ஸà¯à®•à¯‡à®©à¯à®šà¯†à®¯à¯</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> தவறான பதிலை அனà¯à®ªà¯à®ªà®¿à®¯à®¤à¯.</translation>
<translation id="2552545117464357659">பà¯à®¤à®¿à®¯à®¤à¯</translation>
<translation id="2556876185419854533">&amp;திரà¯à®¤à¯à®¤à®²à¯ˆà®šà¯ செயலà¯à®¤à®µà®¿à®°à¯</translation>
+<translation id="2587730715158995865">வெளியீடà¯à®Ÿà®¾à®³à®°à¯: <ph name="ARTICLE_PUBLISHER" />. இதையà¯à®®à¯ பிற வெளியீடà¯à®Ÿà®¾à®³à®°à¯à®•à®³à¯ வழஙà¯à®•à¯à®®à¯ <ph name="OTHER_ARTICLE_COUNT" /> கடà¯à®Ÿà¯à®°à¯ˆà®•à®³à¯ˆà®¯à¯à®®à¯ படிகà¯à®•à®µà¯à®®à¯.</translation>
<translation id="2587841377698384444">கோபà¯à®ªà®• API à®à®Ÿà®¿:</translation>
<translation id="2597378329261239068">இநà¯à®¤ ஆவணம௠கடவà¯à®šà¯à®šà¯Šà®²à¯ பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ ஒனà¯à®±à¯. தயவà¯à®šà¯†à®¯à¯à®¤à¯ ஒர௠கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ உளà¯à®³à®¿à®Ÿà¯à®•.</translation>
<translation id="2609632851001447353">வேறà¯à®ªà®¾à®Ÿà¯à®•à®³à¯</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />கனெகà¯à®Ÿà®¿à®µà®¿à®Ÿà¯à®Ÿà®¿ டயகà¯à®©à®¸à¯à®Ÿà®¿à®•à¯à®¸à¯ கரà¯à®µà®¿à®¯à¯ˆ இயகà¯à®•à®µà¯à®®à¯<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">சரி</translation>
<translation id="2742870351467570537">தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®¤à¯à®¤ உரà¯à®ªà¯à®ªà®Ÿà®¿à®•à®³à¯ˆ அகறà¯à®±à¯à®•</translation>
+<translation id="277133753123645258">ஷிபà¯à®ªà®¿à®™à¯ à®®à¯à®±à¯ˆ</translation>
<translation id="277499241957683684">சாதனப௠பதிவ௠இலà¯à®²à¯ˆ</translation>
<translation id="2784949926578158345">இணைபà¯à®ªà¯ மீடà¯à®Ÿà®®à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="2794233252405721443">தளம௠தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
-<translation id="2812680587231492111">தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®¤à¯à®¤ பிகà¯à®…ப௠மà¯à®±à¯ˆ இலà¯à®²à¯ˆ. வேற௠மà¯à®±à¯ˆà®¯à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®ªà¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="2824775600643448204">à®®à¯à®•à®µà®°à®¿ மறà¯à®±à¯à®®à¯ தேடல௠படà¯à®Ÿà®¿</translation>
<translation id="2826760142808435982">இநà¯à®¤ இணைபà¯à®ªà¯ <ph name="CIPHER" /> à®à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ கà¯à®±à®¿à®¯à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯, à®…à®™à¯à®•à¯€à®•à®°à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯, ஒர௠மà¯à®•à¯à®•à®¿à®¯ பரிமாறà¯à®± செயலà¯à®®à¯à®±à¯ˆà®¯à®¾à®• <ph name="KX" /> à®à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="2835170189407361413">படிவதà¯à®¤à¯ˆ அழி</translation>
-<translation id="2849041323157393173">தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®¤à¯à®¤ டெலிவரி à®®à¯à®±à¯ˆ இலà¯à®²à¯ˆ. வேற௠மà¯à®±à¯ˆà®¯à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®ªà¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="2889159643044928134">மீணà¯à®Ÿà¯à®®à¯ à®à®±à¯à®± வேணà¯à®Ÿà®¾à®®à¯</translation>
<translation id="2900469785430194048">நினைவகப௠பறà¯à®±à®¾à®•à¯à®•à¯à®±à¯ˆà®¯à®¿à®©à®¾à®²à¯, Google Chrome இநà¯à®¤ இணையபà¯à®ªà®•à¯à®•à®¤à¯à®¤à¯ˆà®•à¯ காடà¯à®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="2909946352844186028">பிணைய மாறà¯à®±à®®à¯ கணà¯à®Ÿà®±à®¿à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="2916038427272391327">பிற நிரலà¯à®•à®³à¯ˆ மூடவà¯à®®à¯</translation>
<translation id="2922350208395188000">சேவையகச௠சானà¯à®±à®¿à®¤à®´à¯ˆ சோதிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
+<translation id="2928905813689894207">பிலà¯à®²à®¿à®™à¯ à®®à¯à®•à®µà®°à®¿</translation>
<translation id="2948083400971632585">இணைபà¯à®ªà®¿à®±à¯à®•à®¾à®• உளà¯à®³à®®à¯ˆà®¤à¯à®¤ எநà¯à®¤ பிராகà¯à®šà®¿à®•à®³à¯ˆà®¯à¯à®®à¯ நீஙà¯à®•à®³à¯ அமைபà¯à®ªà¯à®•à®³à¯ பகà¯à®•à®¤à¯à®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ à®®à¯à®Ÿà®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="2955913368246107853">தேடல௠பெடà¯à®Ÿà®¿à®¯à¯ˆ மூடà¯à®•</translation>
<translation id="2958431318199492670">பிணைய உளà¯à®³à®®à¯ˆà®ªà¯à®ªà®¾à®©à®¤à¯ ONC தரதà¯à®¤à¯à®Ÿà®©à¯ இணஙà¯à®•à®µà®¿à®²à¯à®²à¯ˆ. உளà¯à®³à®®à¯ˆà®µà®¿à®©à¯ பகà¯à®¤à®¿à®•à®³à¯ இறகà¯à®•à¯à®®à®¤à®¿à®¯à®¾à®•à®¾à®®à®²à¯ போககà¯à®•à¯‚டà¯à®®à¯.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®© இணைபà¯à®ªà¯ˆ à®à®±à¯à®ªà®Ÿà¯à®¤à¯à®¤, கடிகாரம௠சரியாக அமைகà¯à®•à®ªà¯à®ªà®Ÿ வேணà¯à®Ÿà¯à®®à¯. இணையதளஙà¯à®•à®³à¯ தஙà¯à®•à®³à¯ˆà®¤à¯ தாமே அடையாளபà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®®à¯ சானà¯à®±à®¿à®¤à®´à¯à®•à®³à¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®Ÿ காலதà¯à®¤à®¿à®±à¯à®•à¯ மடà¯à®Ÿà¯à®®à¯ செலà¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®µà®¤à®¾à®²à¯, இத௠செயà¯à®¯à®ªà¯à®ªà®Ÿ வேணà¯à®Ÿà¯à®®à¯. உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®©à¯ கடிகாரம௠தவறாக இரà¯à®ªà¯à®ªà®¤à®¾à®²à¯, இநà¯à®¤à®šà¯ சானà¯à®±à®¿à®¤à®´à¯à®•à®³à¯ˆ Google Chrome ஆல௠சரிபாரà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="2972581237482394796">&amp;மீணà¯à®Ÿà¯à®®à¯ செயà¯</translation>
<translation id="2985306909656435243">இத௠இயகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¾à®²à¯, விரைவாகப௠படிவதà¯à®¤à¯ˆ நிரபà¯à®ª, உஙà¯à®•à®³à¯ காரà¯à®Ÿà®¿à®©à¯ நகலை Chromium இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ சேமிகà¯à®•à¯à®®à¯.</translation>
+<translation id="2985398929374701810">சரியான à®®à¯à®•à®µà®°à®¿à®¯à¯ˆ உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯</translation>
+<translation id="2986368408720340940">இநà¯à®¤à®ªà¯ பிகà¯à®…ப௠மà¯à®±à¯ˆ இலà¯à®²à¯ˆ. வேற௠மà¯à®±à¯ˆà®¯à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®ªà¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="2991174974383378012">இணையதளஙà¯à®•à®³à¯à®Ÿà®©à¯ பகிரà¯à®ªà®µà¯ˆ</translation>
<translation id="3005723025932146533">சேமிதà¯à®¤ நகலைக௠காடà¯à®Ÿà¯</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> இன௠CVC எணà¯à®£à¯ˆ உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯. உறà¯à®¤à®¿à®šà¯†à®¯à¯à®¤ பினà¯à®©à®°à¯, உஙà¯à®•à®³à¯ காரà¯à®Ÿà¯ விவரஙà¯à®•à®³à¯ இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®±à¯à®•à¯à®ªà¯ பகிரபà¯à®ªà®Ÿà¯à®®à¯.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{ஒதà¯à®¤à®¿à®šà¯ˆà®¤à¯à®¤ சாதனஙà¯à®•à®³à®¿à®²à¯ கà¯à®±à¯ˆà®¨à¯à®¤à®¤à¯ 1 உரà¯à®ªà¯à®ªà®Ÿà®¿ உளà¯à®³à®¤à¯}=1{1 உரà¯à®ªà¯à®ªà®Ÿà®¿ (ஒதà¯à®¤à®¿à®šà¯ˆà®¤à¯à®¤ சாதனஙà¯à®•à®³à®¿à®²à¯ இதறà¯à®•à¯ மேல௠உளà¯à®³à®©)}other{# உரà¯à®ªà¯à®ªà®Ÿà®¿à®•à®³à¯ (ஒதà¯à®¤à®¿à®šà¯ˆà®¤à¯à®¤ சாதனஙà¯à®•à®³à®¿à®²à¯ இதறà¯à®•à¯ மேல௠உளà¯à®³à®©)}}</translation>
<translation id="3041612393474885105">சானà¯à®±à®¿à®¤à®´à¯ தகவலà¯</translation>
<translation id="3063697135517575841">இபà¯à®ªà¯‹à®¤à¯ உஙà¯à®•à®³à¯ காரà¯à®Ÿà¯ˆ உறà¯à®¤à®¿à®šà¯†à®¯à¯à®¯ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. பிறக௠மà¯à®¯à®²à®µà¯à®®à¯.</translation>
+<translation id="3064966200440839136">வெளிபà¯à®ªà¯à®±à®ªà¯ பயனà¯à®ªà®¾à®Ÿà¯à®Ÿà®¿à®©à¯ மூலம௠பணதà¯à®¤à¯ˆ செலà¯à®¤à¯à®¤, மறைநிலையிலிரà¯à®¨à¯à®¤à¯ வெளியேறà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯. தொடரவா?</translation>
<translation id="3093245981617870298">ஆஃபà¯à®²à¯ˆà®©à®¿à®²à¯ உளà¯à®³à¯€à®°à¯à®•à®³à¯.</translation>
<translation id="3105172416063519923">பணà¯à®ªà¯ à®à®Ÿà®¿:</translation>
<translation id="3109728660330352905">இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆà®•à¯ காண உஙà¯à®•à®³à¯à®•à¯à®•à¯ à®…à®™à¯à®•à¯€à®•à®¾à®°à®®à¯ அளிகà¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />கனெகà¯à®Ÿà®¿à®µà®¿à®Ÿà¯à®Ÿà®¿ டயகà¯à®©à®¸à¯à®Ÿà®¿à®•à¯à®¸à¯ கரà¯à®µà®¿à®¯à¯ˆ இயகà¯à®•à®µà¯à®®à¯<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">பதிலைக௠கà¯à®±à®¿à®¨à¯€à®•à¯à®•à®®à¯ செயà¯à®µà®¤à®¿à®²à¯ தோலà¯à®µà®¿</translation>
-<translation id="3149891296864842641">ஷிபà¯à®ªà®¿à®™à¯ விரà¯à®ªà¯à®ªà®®à¯</translation>
<translation id="3150653042067488994">தறà¯à®•à®¾à®²à®¿à®• சேவையகப௠பிழை</translation>
+<translation id="3154506275960390542">பாதà¯à®•à®¾à®ªà¯à®ªà®±à¯à®± à®®à¯à®±à¯ˆà®¯à®¿à®²à¯ சமரà¯à®ªà¯à®ªà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà®•à¯à®•à¯‚டிய படிவம௠இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à®¿à®²à¯ உளà¯à®³à®¤à¯. நீஙà¯à®•à®³à¯ அனà¯à®ªà¯à®ªà¯à®®à¯ தரவ௠சேவையகதà¯à®¤à¯ˆ அடையà¯à®®à¯ à®®à¯à®©à¯à®ªà¯ பிறர௠அதைப௠பாரà¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ சேவையகம௠பெறà¯à®®à¯ தரவை தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ மாறà¯à®±à®¿à®¯à®®à¯ˆà®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="3157931365184549694">மீடà¯à®Ÿà®®à¯ˆ</translation>
<translation id="3167968892399408617">உஙà¯à®•à®³à¯ மறைநிலை தாவலà¯à®•à®³à¯ அனைதà¯à®¤à¯ˆà®¯à¯à®®à¯ மூடிய பினà¯, அவறà¯à®±à®¿à®²à¯ நீஙà¯à®•à®³à¯ பாரà¯à®¤à¯à®¤ பகà¯à®•à®™à¯à®•à®³à¯ உலாவியின௠வரலாறà¯, கà¯à®•à¯à®•à¯€ சேமிபà¯à®ªà®•à®®à¯ அலà¯à®²à®¤à¯ தேடல௠வரலாறà¯à®±à®¿à®²à¯ இரà¯à®•à¯à®•à®¾à®¤à¯. நீஙà¯à®•à®³à¯ இறகà¯à®•à®¿à®¯ எலà¯à®²à®¾ கோபà¯à®ªà¯à®•à®³à¯ அலà¯à®²à®¤à¯ உரà¯à®µà®¾à®•à¯à®•à®¿à®¯ பà¯à®¤à¯à®¤à®•à®•à¯à®•à¯à®±à®¿à®•à®³à¯ அபà¯à®ªà®Ÿà®¿à®¯à¯‡ இரà¯à®•à¯à®•à¯à®®à¯.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -260,11 +268,13 @@
<translation id="3345135638360864351">இநà¯à®¤à®¤à¯ தளதà¯à®¤à¯ˆ அணà¯à®•à¯à®µà®¤à®±à¯à®•à®¾à®© கோரிகà¯à®•à¯ˆà®¯à¯ˆ <ph name="NAME" />கà¯à®•à¯ அனà¯à®ªà¯à®ª à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®±à¯à®šà®¿à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="3355823806454867987">பà¯à®°à®¾à®•à¯à®¸à®¿ அமைபà¯à®ªà¯à®•à®³à¯ˆ மாறà¯à®±à¯à®•...</translation>
<translation id="3369192424181595722">கடிகாரப௠பிழை</translation>
+<translation id="337311366426640088">மேலà¯à®®à¯ <ph name="ITEM_COUNT" /> உரà¯à®ªà¯à®ªà®Ÿà®¿à®•à®³à¯...</translation>
<translation id="337363190475750230">விடà¯à®µà®¿à®¤à¯à®¤à®¤à¯</translation>
<translation id="3377188786107721145">கொளà¯à®•à¯ˆà®¯à¯ˆ அலசà¯à®µà®¤à®¿à®²à¯ பிழை</translation>
<translation id="3380365263193509176">அறியபà¯à®ªà®Ÿà®¾à®¤ பிழை</translation>
<translation id="3380864720620200369">கிளையனà¯à®Ÿà¯ à®à®Ÿà®¿:</translation>
<translation id="3391030046425686457">டெலிவரி à®®à¯à®•à®µà®°à®¿</translation>
+<translation id="3395827396354264108">பிகà¯à®…ப௠மà¯à®±à¯ˆ</translation>
<translation id="340013220407300675">தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯à®•à®³à¯ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> இலிரà¯à®¨à¯à®¤à¯ உஙà¯à®•à®³à¯ தகவலைத௠திரà¯à®Ÿ à®®à¯à®¯à®±à¯à®šà®¿à®•à¯à®•à®²à®¾à®®à¯ (எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà®¾à®•, கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯, செயà¯à®¤à®¿à®•à®³à¯ அலà¯à®²à®¤à¯ கிரெடிட௠காரà¯à®Ÿà¯à®•à®³à¯).</translation>
<translation id="3422248202833853650">பிற நிரலà¯à®•à®³à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ வெளியேறி, நினைவகதà¯à®¤à¯ˆà®•à¯ காலியாகà¯à®•à®µà¯à®®à¯.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" />à®à®¤à¯ தறà¯à®ªà¯‹à®¤à¯ அணà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
@@ -275,12 +285,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">எடà¯à®ªà¯à®ªà®¤à®±à¯à®•à®¾à®© இடைவேளை:</translation>
<translation id="3462200631372590220">மேமà¯à®ªà®Ÿà¯à®Ÿà®µà¯ˆà®¯à¯ˆ மறை</translation>
+<translation id="3467763166455606212">காரà¯à®Ÿà¯ உரிமையாளரின௠பெயர௠தேவை</translation>
+<translation id="3478058380795961209">காலாவதியாகà¯à®®à¯ மாதமà¯</translation>
<translation id="3479539252931486093">இதை எதிரà¯à®ªà®¾à®°à¯à®•à¯à®•à®µà®¿à®²à¯à®²à¯ˆà®¯à®¾? <ph name="BEGIN_LINK" />எஙà¯à®•à®³à¯à®•à¯à®•à¯à®¤à¯ தெரியபà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà¯à®®à¯<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">இபà¯à®ªà¯Šà®´à¯à®¤à¯ இலà¯à®²à¯ˆ</translation>
<translation id="348000606199325318">சிதைவ௠à®à®Ÿà®¿ <ph name="CRASH_LOCAL_ID" /> (சேவையக à®à®Ÿà®¿: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">தறà¯à®ªà¯‹à®¤à¯ உஙà¯à®•à®³à¯ பெறà¯à®±à¯‹à®°à¯ˆà®¤à¯ தொடரà¯à®ªà¯à®•à¯Šà®³à¯à®³ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®±à¯à®šà®¿à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="3528171143076753409">சேவையகச௠சானà¯à®±à®¿à®¤à®´à¯ நமà¯à®ªà®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
-<translation id="3538531656504267329">தவறான காலாவதி ஆணà¯à®Ÿà¯</translation>
<translation id="3539171420378717834">இநà¯à®¤à®•à¯ காரà¯à®Ÿà®¿à®©à¯ பிரதியை சாதனதà¯à®¤à®¿à®²à¯ சேமி</translation>
<translation id="3542684924769048008">இதறà¯à®•à®¾à®• கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà¯à®®à¯:</translation>
<translation id="3549644494707163724">உஙà¯à®•à®³à¯ சொநà¯à®¤ ஒதà¯à®¤à®¿à®šà¯ˆà®µà¯ கடவà¯à®šà¯à®šà¯Šà®±à¯à®±à¯Šà®Ÿà®°à¯ மூலம௠எலà¯à®²à®¾ தரவையà¯à®®à¯ எனà¯à®•à¯à®°à®¿à®ªà¯à®Ÿà¯ செயà¯à®¯à®µà¯à®®à¯</translation>
@@ -293,6 +304,7 @@
<translation id="3586931643579894722">விவரஙà¯à®•à®³à¯ˆ மறை</translation>
<translation id="3587482841069643663">அனைதà¯à®¤à¯à®®à¯</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">சரியான காலாவதித௠தேதியை உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯</translation>
<translation id="36224234498066874">உலாவல௠தரவை அழி...</translation>
<translation id="362276910939193118">à®®à¯à®´à¯ வரலாறà¯à®±à¯ˆà®¯à¯à®®à¯ காணà¯à®ªà®¿</translation>
<translation id="3623476034248543066">மதிபà¯à®ªà¯ˆà®•à¯ காடà¯à®Ÿà¯</translation>
@@ -309,7 +321,6 @@
<translation id="3693415264595406141">கடவà¯à®šà¯à®šà¯Šà®²à¯:</translation>
<translation id="3696411085566228381">எதà¯à®µà¯à®®à®¿à®²à¯à®²à¯ˆ</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">ஷிபà¯à®ªà®¿à®™à¯ à®®à¯à®±à¯ˆà®•à®³à¯ˆà®¯à¯à®®à¯ தேவைகளையà¯à®®à¯ பாரà¯à®•à¯à®•, ஷிபà¯à®ªà®¿à®™à¯ à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="370665806235115550">à®à®±à¯à®±à¯à®•à®¿à®±à®¤à¯â€¦</translation>
<translation id="3712624925041724820">உரிமம௠மà¯à®Ÿà®¿à®¨à¯à®¤à®¤à¯</translation>
<translation id="3714780639079136834">மொபைல௠தரவ௠அலà¯à®²à®¤à¯ வைஃபையை இயகà¯à®•à¯à®¤à®²à¯</translation>
@@ -318,6 +329,7 @@
<translation id="3739623965217189342">நீஙà¯à®•à®³à¯ நகலெடà¯à®¤à¯à®¤ இணைபà¯à®ªà¯</translation>
<translation id="375403751935624634">ஒர௠சேவையகப௠பிழையின௠காரணமாக மொழிபெயரà¯à®ªà¯à®ªà¯à®¤à¯ தோலà¯à®µà®¿à®¯à®Ÿà¯ˆà®¨à¯à®¤à®¤à¯.</translation>
<translation id="3759461132968374835">உஙà¯à®•à®³à®¿à®Ÿà®®à¯ சமீபதà¯à®¤à®¿à®²à¯ செயலிழபà¯à®ªà¯à®•à®³à¯ எதà¯à®µà¯à®®à¯ பà¯à®•à®¾à®°à®³à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ. செயலிழபà¯à®ªà¯ பà¯à®•à®¾à®°à®³à®¿à®¤à¯à®¤à®²à¯ à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®¨à¯à®¤à®ªà¯‹à®¤à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿ செயலிழபà¯à®ªà¯à®•à®³à¯ இஙà¯à®•à¯ காணà¯à®ªà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤à¯.</translation>
+<translation id="3787705759683870569">காலாவதி: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">நீஙà¯à®•à®³à¯ பிராகà¯à®šà®¿ சரà¯à®µà®°à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®©à®¾à®²à¯....</translation>
<translation id="3828924085048779000">வெறà¯à®±à¯ கடவà¯à®šà¯à®šà¯Šà®±à¯à®±à¯Šà®Ÿà®°à¯à®•à¯à®•à¯ அனà¯à®®à®¤à®¿à®¯à®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="3845539888601087042">நீஙà¯à®•à®³à¯ உளà¯à®¨à¯à®´à¯ˆà®¨à¯à®¤à®¿à®°à¯à®•à¯à®•à¯à®®à¯ சாதனஙà¯à®•à®³à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ வரலாறà¯à®±à¯ˆà®•à¯ காடà¯à®Ÿà¯à®•à®¿à®±à®¤à¯. <ph name="BEGIN_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LINK" />.</translation>
@@ -353,7 +365,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">இநà¯à®¤à®•à¯ காரà¯à®Ÿà¯ˆ Chromium சேமிகà¯à®• வேணà¯à®Ÿà¯à®®à®¾?</translation>
<translation id="4171400957073367226">தவறான சரிபாரà¯à®ªà¯à®ªà¯ கையொபà¯à®ªà®®à¯</translation>
-<translation id="4176463684765177261">à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="4196861286325780578">&amp;நகரà¯à®¤à¯à®¤à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ செயà¯</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ஃபயரà¯à®µà®¾à®²à¯ மறà¯à®±à¯à®®à¯ ஆணà¯à®Ÿà®¿à®µà¯ˆà®°à®¸à¯ உளà¯à®³à®®à¯ˆà®µà¯ˆà®šà¯ சரிபாரà¯à®¤à¯à®¤à®²à¯<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{பயனà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ இலà¯à®²à¯ˆ}=1{1 பயனà¯à®ªà®¾à®Ÿà¯ ($1)}=2{2 பயனà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ ($1, $2)}other{# பயனà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ ($1, $2, $3)}}</translation>
@@ -380,11 +391,11 @@
<translation id="4406896451731180161">தேடல௠மà¯à®Ÿà®¿à®µà¯à®•à®³à¯</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> உஙà¯à®•à®³à¯ உளà¯à®¨à¯à®´à¯ˆà®µà¯à®šà¯ சானà¯à®±à®¿à®¤à®´à¯ˆ à®à®±à¯à®•à®µà®¿à®²à¯à®²à¯ˆ அலà¯à®²à®¤à¯ சானà¯à®±à®¿à®¤à®´à¯ வழஙà¯à®•à®ªà¯à®ªà®Ÿà®¾à®®à®²à¯ இரà¯à®•à¯à®•à®•à¯à®•à¯‚டà¯à®®à¯.</translation>
<translation id="443673843213245140">பà¯à®°à®¾à®•à¯à®¸à®¿ பயனà¯à®ªà®¾à®Ÿà¯ à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. ஆனால௠வெளிபà¯à®ªà®Ÿà¯ˆà®¯à®¾à®© பà¯à®°à®¾à®•à¯à®¸à®¿ உளà¯à®³à®®à¯ˆà®µà¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
-<translation id="4446242550670694251">இபà¯à®ªà¯‹à®¤à¯ தனிபà¯à®ªà®Ÿà¯à®Ÿ à®®à¯à®±à¯ˆà®¯à®¿à®²à¯ உலாவலாமà¯. இநà¯à®¤à®šà¯ சாதனதà¯à®¤à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯ பிறரால௠உஙà¯à®•à®³à¯ செயலà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ˆà®ªà¯ பாரà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯.</translation>
<translation id="4492190037599258964"><ph name="SEARCH_STRING" />' கà¯à®•à®¾à®©à®¤à¯ தேடல௠மà¯à®Ÿà®¿à®µà¯à®•à®³à¯</translation>
<translation id="4506176782989081258">சரிபாரà¯à®ªà¯à®ªà¯à®ªà¯ பிழை: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">கணினி நிரà¯à®µà®¾à®•à®¿à®¯à¯ˆà®¤à¯ தொடரà¯à®ªà¯à®•à¯Šà®³à¯à®³à¯à®¤à®²à¯</translation>
<translation id="450710068430902550">நிரà¯à®µà®¾à®•à®¿à®¯à¯à®Ÿà®©à¯ பகிரà¯à®ªà®µà¯ˆ</translation>
+<translation id="4515275063822566619">காரà¯à®Ÿà¯à®•à®³à¯à®®à¯ à®®à¯à®•à®µà®°à®¿à®•à®³à¯à®®à¯ Chrome இலிரà¯à®¨à¯à®¤à¯à®®à¯ <ph name="ACCOUNT_EMAIL" /> எனà¯à®®à¯ உஙà¯à®•à®³à¯ Google கணகà¯à®•à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯à®®à¯ பெறபà¯à®ªà®Ÿà¯à®Ÿà®µà¯ˆà®¯à®¾à®•à¯à®®à¯. <ph name="BEGIN_LINK" />அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯<ph name="END_LINK" /> அவறà¯à®±à¯ˆ நிரà¯à®µà®•à®¿à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="4522570452068850558">விவரஙà¯à®•à®³à¯</translation>
<translation id="4558551763791394412">நீடà¯à®Ÿà®¿à®ªà¯à®ªà¯à®•à®³à¯ˆ à®®à¯à®Ÿà®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="457875822857220463">டெலிவரி</translation>
@@ -414,6 +425,7 @@
<translation id="4816492930507672669">பகà¯à®•à®¤à¯à®¤à®¿à®²à¯ பொரà¯à®¤à¯à®¤à¯</translation>
<translation id="483020001682031208">காடà¯à®Ÿà¯à®µà®¤à®±à¯à®•à¯ இயலà¯à®¨à®¿à®²à¯ˆ இணையப௠பகà¯à®•à®™à¯à®•à®³à¯ எதà¯à®µà¯à®®à®¿à®²à¯à®²à¯ˆ</translation>
<translation id="4850886885716139402">காடà¯à®šà®¿</translation>
+<translation id="4854362297993841467">இநà¯à®¤ டெலிவரி à®®à¯à®±à¯ˆ இலà¯à®²à¯ˆ. வேற௠மà¯à®±à¯ˆà®¯à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®ªà¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="4858792381671956233">இநà¯à®¤à®¤à¯ தளதà¯à®¤à¯ˆà®ªà¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà®²à®¾à®®à®¾ என, நீஙà¯à®•à®³à¯ பெறà¯à®±à¯‹à®°à®¿à®Ÿà®®à¯ கேடà¯à®Ÿà¯à®³à¯à®³à¯€à®°à¯à®•à®³à¯</translation>
<translation id="4880827082731008257">வரலாறà¯à®±à®¿à®²à¯ தேடà¯</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -421,7 +433,6 @@
<translation id="4923417429809017348">ஒர௠அறியபà¯à®ªà®Ÿà®¾à®¤ மொழியிலிரà¯à®¨à¯à®¤à¯ <ph name="LANGUAGE_LANGUAGE" /> -கà¯à®•à¯ இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ மொழிபெயரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯</translation>
<translation id="4923459931733593730">கடà¯à®Ÿà®£ à®®à¯à®±à¯ˆ</translation>
<translation id="4926049483395192435">கடà¯à®Ÿà®¾à®¯à®®à¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿ வேணà¯à®Ÿà¯à®®à¯.</translation>
-<translation id="4941291666397027948">* அவசியமானதைக௠கà¯à®±à®¿à®•à¯à®•à®¿à®±à®¤à¯</translation>
<translation id="495170559598752135">செயலà¯à®•à®³à¯</translation>
<translation id="4958444002117714549">படà¯à®Ÿà®¿à®¯à®²à¯ˆ விரி</translation>
<translation id="4962322354953122629"><ph name="DOMAIN" /> என இநà¯à®¤à®šà¯ சேவையகதà¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®šà¯ சானà¯à®±à®¿à®¤à®´à¯ˆ Chrome நமà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -436,6 +447,7 @@
<translation id="5045550434625856497">தவறான கடவà¯à®šà¯à®šà¯Šà®²à¯</translation>
<translation id="5056549851600133418">உஙà¯à®•à®³à¯à®•à¯à®•à®¾à®© கடà¯à®Ÿà¯à®°à¯ˆà®•à®³à¯</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />பà¯à®°à®¾à®•à¯à®¸à®¿ à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®šà¯ சரிபாரà¯à®¤à¯à®¤à®²à¯<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{கà¯à®•à¯à®•à¯€à®•à®³à¯ எதà¯à®µà¯à®®à®¿à®²à¯à®²à¯ˆ}=1{கà¯à®•à¯à®•à¯€à®•à®³à¯ˆ ஒர௠தளம௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à®¤à¯. }other{கà¯à®•à¯à®•à¯€à®•à®³à¯ˆ # தளஙà¯à®•à®³à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®©à¯à®±à®©. }}</translation>
<translation id="5087286274860437796">தறà¯à®ªà¯‹à®¤à¯ சேவையகதà¯à®¤à®¿à®©à¯ சானà¯à®±à®¿à®¤à®´à¯ செலà¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®•à®¾à®¤à¯.</translation>
<translation id="5087580092889165836">காரà¯à®Ÿà¯ˆà®šà¯ சேரà¯</translation>
<translation id="5089810972385038852">மாநிலமà¯</translation>
@@ -458,10 +470,8 @@
<translation id="5300589172476337783">காணà¯à®ªà®¿</translation>
<translation id="5308689395849655368">செயலிழபà¯à®ªà¯ பà¯à®•à®¾à®°à®³à®¿à®¤à¯à®¤à®²à¯ à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
<translation id="5317780077021120954">சேமி</translation>
-<translation id="5326702247179446998">பெறà¯à®¨à®°à¯ தேவை</translation>
<translation id="5327248766486351172">பெயரà¯</translation>
<translation id="5337705430875057403"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> இல௠உளà¯à®³ தாகà¯à®•à¯à®ªà®µà®°à¯à®•à®³à¯, மெனà¯à®ªà¯Šà®°à¯à®³à¯ˆ நிறà¯à®µà¯à®¤à®²à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ தனிபà¯à®ªà®Ÿà¯à®Ÿ தகவலை (எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà®¾à®•, கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯, ஃபோன௠எணà¯à®•à®³à¯ அலà¯à®²à®¤à¯ கிரெடிட௠காரà¯à®Ÿà¯à®•à®³à¯) வெளியிடச௠செயà¯à®¤à®²à¯ போனà¯à®± ஆபதà¯à®¤à®¾à®© செயலà¯à®•à®³à¯ˆà®šà¯ செயà¯à®¯à¯à®®à¯à®ªà®Ÿà®¿ à®à®®à®¾à®±à¯à®± à®®à¯à®¯à®±à¯à®šà®¿à®•à¯à®•à®²à®¾à®®à¯.</translation>
-<translation id="53553865750799677">ஆதரிகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤ பிகà¯à®•à®ªà¯ à®®à¯à®•à®µà®°à®¿. வேற௠மà¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="5359637492792381994"><ph name="DOMAIN" /> என இநà¯à®¤à®šà¯ சேவையகதà¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®šà¯ சானà¯à®±à®¿à®¤à®´à¯ இபà¯à®ªà¯‹à®¤à¯ செலà¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®•à®µà®¿à®²à¯à®²à¯ˆ. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">கொளà¯à®•à¯ˆ அமைபà¯à®ªà¯à®•à®³à¯ˆà®šà¯ சேமிபà¯à®ªà®¤à®¿à®²à¯ தோலà¯à®µà®¿</translation>
<translation id="5386426401304769735">இநà¯à®¤à®šà¯ சானà¯à®±à®¿à®¤à®´à¯ சஙà¯à®•à®¿à®²à®¿à®¯à®¿à®²à¯, SHA-1à®à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ கையொபà¯à®ªà®®à®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿ சானà¯à®±à®¿à®¤à®´à¯ உளà¯à®³à®¤à¯.</translation>
@@ -487,8 +497,8 @@
<translation id="5544037170328430102"><ph name="SITE" /> இல௠உளà¯à®³ உடà¯à®ªà¯Šà®¤à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ பகà¯à®•à®®à¯ தெரிவிபà¯à®ªà®¤à¯:</translation>
<translation id="5556459405103347317">மீணà¯à®Ÿà¯à®®à¯ à®à®±à¯à®±à¯</translation>
<translation id="5565735124758917034">செயலில௠உளà¯à®³à®¤à¯</translation>
+<translation id="5571083550517324815">இநà¯à®¤ à®®à¯à®•à®µà®°à®¿à®¯à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ பிகà¯à®…ப௠செயà¯à®¯ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. வேற௠மà¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="5572851009514199876">Chromeà®à®¤à¯ தொடஙà¯à®•à®¿ உளà¯à®¨à¯à®´à¯ˆà®¯à®µà¯à®®à¯. அபà¯à®ªà¯‹à®¤à¯à®¤à®¾à®©à¯ இநà¯à®¤à®¤à¯ தளதà¯à®¤à¯ˆ அணà¯à®•à¯à®µà®¤à®±à¯à®•à¯ உஙà¯à®•à®³à¯à®•à¯à®•à¯ அனà¯à®®à®¤à®¿ உளà¯à®³à®¤à®¾ எனà¯à®ªà®¤à¯ˆ Chrome ஆல௠சரிபாரà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯.</translation>
-<translation id="5575380383496039204">ஆதரிகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤ டெலிவரி à®®à¯à®•à®µà®°à®¿. வேற௠மà¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="5580958916614886209">காலாவதி மாததà¯à®¤à¯ˆà®šà¯ சரிபாரà¯à®¤à¯à®¤à¯, மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®²à®µà¯à®®à¯</translation>
<translation id="560412284261940334">நிரà¯à®µà®¾à®•à®®à¯ ஆதரிகà¯à®•à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="5610142619324316209">இணைபà¯à®ªà¯ˆà®šà¯ சரிபாரà¯à®¤à¯à®¤à®²à¯</translation>
@@ -504,7 +514,8 @@
<translation id="5710435578057952990">இநà¯à®¤ தளதà¯à®¤à®¿à®©à¯ அடையாளம௠சரிபாரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="5720705177508910913">நடபà¯à®ªà¯à®ªà¯ பயனரà¯</translation>
<translation id="5732392974455271431">உஙà¯à®•à®³à¯à®•à¯à®•à®¾à®•, தளதà¯à®¤à®¿à®©à¯ தடà¯à®ªà¯à®ªà¯ˆ உஙà¯à®•à®³à¯ பெறà¯à®±à¯‹à®°à¯ நீகà¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯</translation>
-<translation id="57586589942790530">தவறான காரà¯à®Ÿà¯ எணà¯</translation>
+<translation id="5763042198335101085">சரியான மினà¯à®©à®žà¯à®šà®²à¯ à®®à¯à®•à®µà®°à®¿à®¯à¯ˆ உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯</translation>
+<translation id="5765072501007116331">டெலிவரி à®®à¯à®±à¯ˆà®•à®³à¯ˆà®¯à¯à®®à¯ தேவைகளையà¯à®®à¯ பாரà¯à®•à¯à®•, à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="5784606427469807560">காரà¯à®Ÿà¯ˆ உறà¯à®¤à®¿à®šà¯†à®¯à¯à®µà®¤à®¿à®²à¯ சிகà¯à®•à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¤à¯. இணைய இணைபà¯à®ªà¯ˆà®šà¯ சரிபாரà¯à®¤à¯à®¤à¯, மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®²à®µà¯à®®à¯.</translation>
<translation id="5785756445106461925">மேலà¯à®®à¯, பாதà¯à®•à®¾à®ªà¯à®ªà®±à¯à®± பிற ஆதாரஙà¯à®•à®³à¯ இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à®¿à®²à¯ உளà¯à®³à®©. இநà¯à®¤ ஆதாரஙà¯à®•à®³à¯ˆ டà¯à®°à®¾à®©à¯à®¸à®¿à®Ÿà¯à®Ÿà®¿à®²à¯ இரà¯à®•à¯à®•à¯à®®à¯à®ªà¯‹à®¤à¯à®®à¯ பிறர௠பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà®²à®¾à®®à¯, மேலà¯à®®à¯ பகà¯à®•à®¤à¯à®¤à®¿à®©à¯ தோறà¯à®±à®¤à¯à®¤à¯ˆ மாறà¯à®±, தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ அதை மாறà¯à®±à®¿à®¯à®®à¯ˆà®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="5786044859038896871">காரà¯à®Ÿà¯ தகவலை நிரபà¯à®ª விரà¯à®®à¯à®ªà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à®¾?</translation>
@@ -517,31 +528,30 @@
<translation id="5869405914158311789">இநà¯à®¤à®¤à¯ தளதà¯à®¤à¯ˆ அணà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="5869522115854928033">சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯</translation>
<translation id="5872918882028971132">மூலப௠பரிநà¯à®¤à¯à®°à¯ˆà®•à®³à¯</translation>
-<translation id="587760065310675640">ஆதரிகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤ ஷிபà¯à®ªà®¿à®™à¯ à®®à¯à®•à®µà®°à®¿. வேற௠மà¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="5901630391730855834">மஞà¯à®šà®³à¯</translation>
-<translation id="59174027418879706">செயலாகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="5926846154125914413">சில தளஙà¯à®•à®³à®¿à®©à¯ பிரீமிய உளà¯à®³à®Ÿà®•à¯à®• அணà¯à®•à®²à¯ˆ நீஙà¯à®•à®³à¯ இழகà¯à®•à®•à¯à®•à¯‚டà¯à®®à¯.</translation>
<translation id="5959728338436674663">ஆபதà¯à®¤à®¾à®© பயனà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ˆà®¯à¯à®®à¯ தளஙà¯à®•à®³à¯ˆà®¯à¯à®®à¯ கணà¯à®Ÿà®±à®¿à®µà®¤à®±à¯à®•à¯ உதவியாக, சில <ph name="BEGIN_WHITEPAPER_LINK" />சாதனத௠தகவலையà¯à®®à¯ பகà¯à®• உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®¯à¯à®®à¯<ph name="END_WHITEPAPER_LINK" /> Googleகà¯à®•à¯à®¤à¯ தானாக அனà¯à®ªà¯à®ªà¯. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">வாரமà¯</translation>
<translation id="5967867314010545767">வரலாறà¯à®±à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ அகறà¯à®±à¯</translation>
<translation id="5975083100439434680">சிறிதாகà¯à®•à¯</translation>
+<translation id="598637245381783098">பேமணà¯à®Ÿà¯ பயனà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ˆà®¤à¯ திறகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="5989320800837274978">பà¯à®°à®¾à®•à¯à®¸à®¿ சேவையகம௠சரிசெயà¯à®¯à®ªà¯à®ªà®Ÿà®µà¯à®®à¯ இலà¯à®²à¯ˆ .pac ஸà¯à®•à®¿à®°à®¿à®ªà¯à®Ÿà¯ URL கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®ªà¯à®ªà®Ÿà®µà¯à®®à®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="5990559369517809815">சேவையகதà¯à®¤à®¿à®±à¯à®•à®¾à®© கோரிகà¯à®•à¯ˆà®•à®³à¯ நீடà¯à®Ÿà®¿à®ªà¯à®ªà®¿à®©à®¾à®²à¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">காரà¯à®Ÿà¯à®®à¯ à®®à¯à®•à®µà®°à®¿ விரà¯à®ªà¯à®ªà®™à¯à®•à®³à¯à®®à¯ Chrome இலிரà¯à®¨à¯à®¤à¯ பெறபà¯à®ªà®Ÿà¯à®Ÿà®¤à®¾à®•à¯à®®à¯. அவறà¯à®±à¯ˆ <ph name="BEGIN_LINK" />அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯<ph name="END_LINK" /> நிரà¯à®µà®•à®¿à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{பகà¯à®•à®®à¯ 1}other{பகà¯à®•à®®à¯ #}}</translation>
<translation id="6017514345406065928">பசà¯à®šà¯ˆ</translation>
+<translation id="6027201098523975773">பெயரை உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯</translation>
<translation id="6040143037577758943">மூடà¯</translation>
-<translation id="604124094241169006">தானியஙà¯à®•à¯</translation>
<translation id="6042308850641462728">மேலà¯à®®à¯</translation>
<translation id="6060685159320643512">கவனமà¯, இநà¯à®¤ சோதனைகள௠பாதிபà¯à®ªà¯ˆ à®à®±à¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à®¾à®®à¯</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ இலà¯à®²à¯ˆ}=1{1}other{#}}</translation>
<translation id="6146055958333702838">கேபிளà¯à®•à®³à¯ˆà®šà¯ சரிபாரà¯à®¤à¯à®¤à¯, நீஙà¯à®•à®³à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®•à¯à®•à¯‚டிய ரூடà¯à®Ÿà®°à¯à®•à®³à¯, மோடமà¯à®•à®³à¯ அலà¯à®²à®¤à¯ பிற நெடà¯à®µà¯Šà®°à¯à®•à¯ சாதனஙà¯à®•à®³à¯ˆ மறà¯à®¤à¯Šà®Ÿà®•à¯à®•à®®à¯ செயà¯à®¯à®µà¯à®®à¯.</translation>
<translation id="614940544461990577">இவறà¯à®±à¯ˆà®šà¯ செயà¯à®¤à¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯:</translation>
<translation id="6151417162996330722">சேவை சானà¯à®±à®¿à®¤à®´à¯ நீணà¯à®Ÿ செலà¯à®²à¯à®ªà®Ÿà®¿à®•à¯ காலதà¯à®¤à¯ˆà®•à¯ கொணà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
-<translation id="615643356032862689">பதிவிறகà¯à®•à®¿à®¯ கோபà¯à®ªà¯à®•à®³à¯à®®à¯ பà¯à®¤à¯à®¤à®•à®•à¯à®•à¯à®±à®¿à®•à®³à¯à®®à¯ அபà¯à®ªà®Ÿà®¿à®¯à¯‡ இரà¯à®•à¯à®•à¯à®®à¯.</translation>
+<translation id="6157877588268064908">ஷிபà¯à®ªà®¿à®™à¯ à®®à¯à®±à¯ˆà®•à®³à¯ˆà®¯à¯à®®à¯ தேவைகளையà¯à®®à¯ பாரà¯à®•à¯à®•, à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="6165508094623778733">மேலà¯à®®à¯ அறிக</translation>
<translation id="6177128806592000436">இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®±à¯à®•à®¾à®© உஙà¯à®•à®³à¯ இணைபà¯à®ªà¯, பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®• இலà¯à®²à¯ˆ</translation>
+<translation id="6184817833369986695">(கà¯à®´à¯: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">உஙà¯à®•à®³à¯ இணைய இணைபà¯à®ªà¯ˆà®šà¯ சரிபாரà¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="6218753634732582820">Chromium இலிரà¯à®¨à¯à®¤à¯ à®®à¯à®•à®µà®°à®¿à®¯à¯ˆ அகறà¯à®±à®µà®¾?</translation>
<translation id="6251924700383757765">தனியà¯à®°à®¿à®®à¯ˆà®•à¯ கொளà¯à®•à¯ˆ</translation>
@@ -550,6 +560,8 @@
<translation id="6259156558325130047">&amp;மறà¯à®µà®°à®¿à®šà¯ˆà®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ செயà¯</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> பà¯à®•à¯à®®à®¾à®°à¯à®•à¯à®•à¯à®•à®³à¯</translation>
<translation id="6264485186158353794">பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®© நிலைகà¯à®•à¯à®¤à¯ திரà¯à®®à¯à®ªà¯</translation>
+<translation id="6276112860590028508">வாசிபà¯à®ªà¯à®ªà¯ படà¯à®Ÿà®¿à®¯à®²à®¿à®²à¯ இரà¯à®•à¯à®•à¯à®®à¯ பகà¯à®•à®™à¯à®•à®³à¯ இஙà¯à®•à¯‡ தோனà¯à®±à¯à®®à¯</translation>
+<translation id="6280223929691119688">இநà¯à®¤ à®®à¯à®•à®µà®°à®¿à®•à¯à®•à¯ டெலிவரி செயà¯à®¯ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. வேற௠மà¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="6282194474023008486">அஞà¯à®šà®²à¯ கà¯à®±à®¿à®¯à¯€à®Ÿà¯</translation>
<translation id="6290238015253830360">நீஙà¯à®•à®³à¯ பரிநà¯à®¤à¯à®°à¯ˆà®¤à¯à®¤ கடà¯à®Ÿà¯à®°à¯ˆà®•à®³à¯ இஙà¯à®•à¯‡ தோனà¯à®±à¯à®®à¯</translation>
<translation id="6305205051461490394"><ph name="URL" />஠அடையமà¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
@@ -571,7 +583,6 @@
<translation id="6417515091412812850">சானà¯à®±à®¿à®¤à®´à¯ திரà¯à®®à¯à®ªà®ªà¯à®ªà¯†à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à®¾ எனà¯à®±à¯ சோதிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="6433490469411711332">தொடரà¯à®ªà¯à®¤à¯ தகவலை மாறà¯à®±à¯</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> இணைகà¯à®• மறà¯à®¤à¯à®¤à®¤à¯.</translation>
-<translation id="6443118737398455446">தவறான காலாவதித௠தேதி</translation>
<translation id="6446608382365791566">மேலà¯à®®à¯ தகவலைச௠சேரà¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="6451458296329894277">படிவ மறà¯à®šà®®à®°à¯à®ªà¯à®ªà®¿à®ªà¯à®ªà¯ˆ உறà¯à®¤à®¿à®šà¯†à®¯à¯à®•</translation>
<translation id="6456339708790392414">உஙà¯à®•à®³à¯ கடà¯à®Ÿà®£à®®à¯</translation>
@@ -579,10 +590,8 @@
<translation id="6462969404041126431"><ph name="DOMAIN" /> என இநà¯à®¤à®šà¯ சேவையகதà¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®šà¯ சானà¯à®±à®¿à®¤à®´à¯ ரதà¯à®¤à¯à®šà¯†à®¯à¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">சாதனக௠கொளà¯à®•à¯ˆà®•à®³à¯</translation>
<translation id="6477321094435799029">இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à®¿à®²à¯ வழகà¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯ மாறான கà¯à®±à®¿à®¯à¯€à®Ÿà¯ இரà¯à®ªà¯à®ªà®¤à¯ˆ Chrome கணà¯à®Ÿà®±à®¿à®¨à¯à®¤à¯à®³à¯à®³à®¤à¯, மேலà¯à®®à¯ உஙà¯à®•à®³à¯ தனிபà¯à®ªà®Ÿà¯à®Ÿ தகவலை (எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà¯: கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯, ஃபோன௠எணà¯à®•à®³à¯ மறà¯à®±à¯à®®à¯ கிரெடிட௠காரà¯à®Ÿà¯à®•à®³à¯) பாதà¯à®•à®¾à®•à¯à®• அதைத௠தடà¯à®¤à¯à®¤à¯à®³à¯à®³à®¤à¯.</translation>
-<translation id="6477460825583319731">தவறான மினà¯à®©à®žà¯à®šà®²à¯ à®®à¯à®•à®µà®°à®¿</translation>
<translation id="6489534406876378309">சிதைவà¯à®•à®³à¯ˆà®ªà¯ பதிவேறà¯à®±à¯à®µà®¤à¯ˆà®¤à¯ தொடஙà¯à®•à¯</translation>
<translation id="6508722015517270189">Chrome஠மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à®µà¯à®®à¯</translation>
-<translation id="6525462735697194615">தவறான காலாவதி மாதமà¯</translation>
<translation id="6529602333819889595">&amp;நீகà¯à®•à¯à®¤à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ செயà¯</translation>
<translation id="6534179046333460208">இயலà¯à®¨à®¿à®²à¯ˆ இணையப௠பரிநà¯à®¤à¯à®°à¯ˆà®•à®³à¯</translation>
<translation id="6550675742724504774">விரà¯à®ªà¯à®ªà®¤à¯à®¤à¯‡à®°à¯à®µà¯à®•à®³à¯</translation>
@@ -597,7 +606,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> தேடலà¯</translation>
<translation id="6644283850729428850">இநà¯à®¤à®•à¯ கொளà¯à®•à¯ˆ தவிரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="6652240803263749613"><ph name="DOMAIN" /> என இநà¯à®¤à®šà¯ சேவையகதà¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®šà¯ சானà¯à®±à®¿à®¤à®´à¯ˆ உஙà¯à®•à®³à¯ கணினியின௠இயகà¯à®• à®®à¯à®±à¯ˆà®®à¯ˆ நமà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®¤à¯à®¤ ஷிபà¯à®ªà®¿à®™à¯ à®®à¯à®±à¯ˆ இலà¯à®²à¯ˆ. வேற௠மà¯à®±à¯ˆà®¯à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®ªà¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="6671697161687535275">Chromium இலிரà¯à®¨à¯à®¤à¯ படிவப௠பரிநà¯à®¤à¯à®°à¯ˆà®¯à¯ˆ அகறà¯à®±à®µà®¾?</translation>
<translation id="6685834062052613830">வெளியேறி, அமைபà¯à®ªà¯ˆ à®®à¯à®Ÿà®¿à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="6710213216561001401">à®®à¯à®¨à¯à®¤à¯ˆà®¯à®¤à¯</translation>
@@ -605,13 +613,13 @@
<translation id="6711464428925977395">பà¯à®°à®¾à®•à¯à®¸à®¿ சரà¯à®µà®°à®¿à®²à¯ à®à®¤à¯‹ தவற௠உளà¯à®³à®¤à¯ அலà¯à®²à®¤à¯ à®®à¯à®•à®µà®°à®¿ தவறாக உளà¯à®³à®¤à¯.</translation>
<translation id="6727102863431372879">அமை</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{உரà¯à®ªà¯à®ªà®Ÿà®¿à®•à®³à¯ இலà¯à®²à¯ˆ}=1{1 உரà¯à®ªà¯à®ªà®Ÿà®¿}other{# உரà¯à®ªà¯à®ªà®Ÿà®¿à®•à®³à¯}}</translation>
-<translation id="6743044928064272573">பிகà¯à®•à®ªà¯ விரà¯à®ªà¯à®ªà®®à¯</translation>
<translation id="674375294223700098">தெரியாத சேவையகச௠சானà¯à®±à®¿à®¤à®´à¯ பிழை.</translation>
<translation id="6753269504797312559">கொளà¯à®•à¯ˆ மதிபà¯à®ªà¯</translation>
<translation id="6757797048963528358">உஙà¯à®•à®³à¯ சாதனம௠உறகà¯à®•à®¨à®¿à®²à¯ˆà®•à¯à®•à¯à®šà¯ செனà¯à®±à®¤à¯.</translation>
<translation id="6778737459546443941">இனà¯à®©à¯à®®à¯ உஙà¯à®•à®³à¯ பெறà¯à®±à¯‹à®°à¯ அனà¯à®®à®¤à®¿à®•à¯à®•à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="6810899417690483278">தனிபà¯à®ªà®¯à®©à®¾à®•à¯à®•à®²à¯ à®à®Ÿà®¿</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">மணà¯à®Ÿà®²à®™à¯à®•à®³à®¿à®©à¯ தரவை à®à®±à¯à®± à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="6831043979455480757">மொழிபெயரà¯</translation>
<translation id="6839929833149231406">பகà¯à®¤à®¿</translation>
<translation id="6874604403660855544">&amp;சேரà¯à®¤à¯à®¤à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ செயà¯</translation>
@@ -619,6 +627,7 @@
<translation id="6895330447102777224">காரà¯à®Ÿà¯ உறà¯à®¤à®¿à®šà¯†à®¯à¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="6897140037006041989">பயனர௠மà¯à®•à®µà®°à¯</translation>
<translation id="6915804003454593391">பயனரà¯:</translation>
+<translation id="6948701128805548767">பிகà¯à®…ப௠மà¯à®±à¯ˆà®•à®³à¯ˆà®¯à¯à®®à¯ தேவைகளையà¯à®®à¯ பாரà¯à®•à¯à®•, à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="6957887021205513506">சேவையகதà¯à®¤à®¿à®©à¯ சானà¯à®±à®¿à®¤à®´à¯ போலியானத௠போல௠தெரிகிறதà¯.</translation>
<translation id="6965382102122355670">சரி</translation>
<translation id="6965978654500191972">சாதனமà¯</translation>
@@ -626,7 +635,6 @@
<translation id="6973656660372572881">நிலையான பà¯à®°à®¾à®•à¯à®¸à®¿ சேவையகஙà¯à®•à®³à¯à®®à¯ .pac ஸà¯à®•à®¿à®°à®¿à®ªà¯à®Ÿà¯ URL ஆகிய இரணà¯à®Ÿà¯à®®à¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
<translation id="6989763994942163495">மேமà¯à®ªà®Ÿà¯à®Ÿ அமைபà¯à®ªà¯à®•à®³à¯ˆà®•à¯ காணà¯à®ªà®¿...</translation>
<translation id="7000990526846637657">வரலாற௠உளà¯à®³à¯€à®Ÿà¯à®•à®³à¯ எதà¯à®µà¯à®®à®¿à®²à¯à®²à¯ˆ</translation>
-<translation id="7001663382399377034">பெறà¯à®¨à®°à¯ˆà®šà¯ சேரà¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="7009986207543992532"><ph name="DOMAIN" />கà¯à®•à¯à®šà¯ செலà¯à®² à®®à¯à®¯à®©à¯à®±à¯€à®°à¯à®•à®³à¯, ஆனால௠நீணà¯à®Ÿ செலà¯à®²à¯à®ªà®Ÿà®¿à®•à¯ காலதà¯à®¤à¯ˆà®•à¯ கொணà¯à®Ÿ சானà¯à®±à®¿à®¤à®´à¯ˆ சேவையகம௠வழஙà¯à®•à®¿à®¯à¯à®³à¯à®³à®¤à¯, இதà¯à®ªà¯‹à®©à¯à®± சானà¯à®±à®¿à®¤à®´à¯à®•à®³à¯ நமà¯à®ªà®¤à¯à®¤à®•à¯à®•à®µà¯ˆà®¯à®²à¯à®². <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">சீனா UnionPay</translation>
<translation id="7012372675181957985">உஙà¯à®•à®³à¯ Google கணகà¯à®•à¯ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> எனà¯à®± தளதà¯à®¤à®¿à®²à¯ உலாவல௠வரலாற௠தொடரà¯à®ªà®¾à®© பிற தகவலà¯à®•à®³à¯ˆà®•à¯ கொணà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®•à¯à®•à¯‚டà¯à®®à¯</translation>
@@ -637,12 +645,15 @@
<translation id="7088615885725309056">பழையவை</translation>
<translation id="7090678807593890770">Google இல௠<ph name="LINK" />à®à®¤à¯ தேடவà¯à®®à¯</translation>
<translation id="7119414471315195487">பிற தாவலà¯à®•à®³à¯ அலà¯à®²à®¤à¯ நிரலà¯à®•à®³à¯ˆ மூடவà¯à®®à¯</translation>
+<translation id="7129409597930077180">இநà¯à®¤ à®®à¯à®•à®µà®°à®¿à®•à¯à®•à¯ அனà¯à®ªà¯à®ª à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. வேற௠மà¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
+<translation id="7138472120740807366">டெலிவரி à®®à¯à®±à¯ˆ</translation>
<translation id="7139724024395191329">எமிரேடà¯</translation>
<translation id="7155487117670177674">கடà¯à®Ÿà®£à®®à¯ செலà¯à®¤à¯à®¤à¯à®µà®¤à¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®©à®¤à¯ அலà¯à®²</translation>
<translation id="7179921470347911571">இபà¯à®ªà¯‹à®¤à¯ மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à¯</translation>
<translation id="7180611975245234373">பà¯à®¤à¯à®ªà¯à®ªà®¿</translation>
<translation id="7182878459783632708">கொளà¯à®•à¯ˆà®•à®³à¯ அமைகà¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="7186367841673660872">இநà¯à®¤à®ªà¯ பகà¯à®•à®®à®¾à®©à®¤à¯<ph name="ORIGINAL_LANGUAGE" />இலிரà¯à®¨à¯à®¤à¯<ph name="LANGUAGE_LANGUAGE" />கà¯à®•à¯ மொழிபெயரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
+<translation id="7192203810768312527"><ph name="SIZE" /> அளவைக௠காலியாகà¯à®•à¯à®®à¯. நீஙà¯à®•à®³à¯ அடà¯à®¤à¯à®¤ à®®à¯à®±à¯ˆ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà¯à®®à¯ போதà¯, சில தளஙà¯à®•à®³à¯ மிகவà¯à®®à¯ மெதà¯à®µà®¾à®• à®à®±à¯à®±à®ªà¯à®ªà®Ÿà®²à®¾à®®à¯.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> பாதà¯à®•à®¾à®ªà¯à®ªà¯à®¤à¯ தரநிலைகளà¯à®•à¯à®•à¯ உடà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="721197778055552897">இநà¯à®¤ சிகà¯à®•à®²à¯ கà¯à®±à®¿à®¤à¯à®¤à¯ <ph name="BEGIN_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LINK" />.</translation>
@@ -671,7 +682,6 @@
<translation id="7424977062513257142">இநà¯à®¤ இணையபà¯à®ªà®•à¯à®•à®¤à¯à®¤à®¿à®²à¯à®³à¯à®³ உடà¯à®ªà¯Šà®¤à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ பகà¯à®•à®®à¯ தெரிவிபà¯à®ªà®¤à¯:</translation>
<translation id="7441627299479586546">தவறான கொளà¯à®•à¯ˆà®¤à¯ தலைபà¯à®ªà¯</translation>
<translation id="7444046173054089907">இநà¯à®¤à®¤à¯ தளம௠தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
-<translation id="7444238235002594607">பிகà¯à®•à®ªà¯ à®®à¯à®±à¯ˆà®•à®³à¯ˆà®¯à¯à®®à¯ தேவைகளையà¯à®®à¯ சரிபாரà¯à®•à¯à®•, பிகà¯à®•à®ªà¯ à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="7445762425076701745">நீஙà¯à®•à®³à¯ இணைநà¯à®¤à¯à®³à¯à®³ சேவையகதà¯à®¤à®¿à®©à¯ அடையாளதà¯à®¤à¯ˆ à®®à¯à®´à¯à®®à¯ˆà®¯à®¾à®• சரிபாரà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. பெயர௠மடà¯à®Ÿà¯à®®à¯‡ செலà¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®•à¯à®®à¯ எனà¯à®± à®®à¯à®±à¯ˆà®¯à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ உஙà¯à®•à®³à¯ பிணையதà¯à®¤à®¿à®±à¯à®•à¯à®³à¯ சேவையகதà¯à®¤à¯à®Ÿà®©à¯ இணைநà¯à®¤à¯à®³à¯à®³à¯€à®°à¯à®•à®³à¯, இதன௠உரிமையை ஒர௠வெளிபà¯à®ªà¯à®± சானà¯à®±à®¿à®¤à®´à¯ மையம௠எபà¯à®ªà¯‹à®¤à¯à®®à¯ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. சில சானà¯à®±à®¿à®¤à®´à¯ மையஙà¯à®•à®³à¯, இநà¯à®¤à®ªà¯ பெயரà¯à®•à®³à¯à®•à¯à®•à¯à®®à¯ சானà¯à®±à®¿à®¤à®´à¯à®•à®³à¯ˆ வழஙà¯à®•à¯à®µà®¾à®°à¯à®•à®³à¯ எனà¯à®ªà®¤à®¾à®²à¯, நீஙà¯à®•à®³à¯ நினைதà¯à®¤ வலைபà¯à®ªà®•à¯à®•à®¤à¯à®¤à¯à®Ÿà®©à¯‡ இணைநà¯à®¤à¯à®³à¯à®³à¯€à®°à¯à®•à®³à¯, à®à®¤à¯‡à®©à¯à®®à¯ மோசடி தளதà¯à®¤à¯à®Ÿà®©à¯ இணையவிலà¯à®²à¯ˆ எனà¯à®ªà®¤à¯ˆ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤ எநà¯à®¤ வழியà¯à®®à¯ இலà¯à®²à¯ˆ.</translation>
<translation id="7451311239929941790">இநà¯à®¤à®šà¯ சிகà¯à®•à®²à¯ கà¯à®±à®¿à®¤à¯à®¤à¯ <ph name="BEGIN_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LINK" />.</translation>
<translation id="7460163899615895653">பிற சாதனஙà¯à®•à®³à®¿à®²à®¿à®°à¯à®•à¯à®•à¯à®®à¯ உஙà¯à®•à®³à¯ சமீபதà¯à®¤à®¿à®¯ தாவலà¯à®•à®³à¯ இஙà¯à®•à¯‡ தோனà¯à®±à¯à®®à¯</translation>
@@ -715,6 +725,7 @@
<translation id="7755287808199759310">உஙà¯à®•à®³à¯à®•à¯à®•à®¾à®•, தளதà¯à®¤à®¿à®©à¯ தடà¯à®ªà¯à®ªà¯ˆ உஙà¯à®•à®³à¯ பெறà¯à®±à¯‹à®°à¯ நீகà¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯</translation>
<translation id="7758069387465995638">தீசà¯à®šà¯à®µà®°à¯ அலà¯à®²à®¤à¯ வைரஸà¯à®¤à®Ÿà¯à®ªà¯à®ªà¯ மெனà¯à®ªà¯Šà®°à¯à®³à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà¯ˆà®¤à¯ தடà¯à®¤à¯à®¤à®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="7761701407923456692">சேவையகச௠சானà¯à®±à®¿à®¤à®´à¯ URL உடன௠பொரà¯à®¨à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ.</translation>
+<translation id="7763386264682878361">பேமணà¯à®Ÿà¯ மேனிஃபெஸà¯à®Ÿà¯ பாகà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿</translation>
<translation id="7764225426217299476">à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®šà¯ சேரà¯</translation>
<translation id="777702478322588152">பà¯à®°à¯€à®ƒà®ªà¯†à®•à¯à®šà®°à¯</translation>
<translation id="7791543448312431591">சேரà¯</translation>
@@ -728,6 +739,7 @@
<translation id="785549533363645510">இரà¯à®ªà¯à®ªà®¿à®©à¯à®®à¯, நீஙà¯à®•à®³à¯ மறைநà¯à®¤à®¿à®°à¯à®•à¯à®•à®®à®¾à®Ÿà¯à®Ÿà¯€à®°à¯à®•à®³à¯. மறைநிலைகà¯à®•à¯à®šà¯ செலà¯à®µà®¤à¯ பணிகà¯à®•à®®à®°à¯à®¤à¯à®¤à¯à®®à¯ நிறà¯à®µà®©à®®à¯, இணையச௠சேவை வழஙà¯à®•à¯à®¨à®°à¯ அலà¯à®²à®¤à¯ நீஙà¯à®•à®³à¯ செலà¯à®²à¯à®®à¯ இணையதளஙà¯à®•à®³à®¿à®Ÿà®®à¯ உஙà¯à®•à®³à¯ உலாவலை மறைகà¯à®•à®¾à®¤à¯.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">CVCà®à®šà¯ சோதிதà¯à®¤à¯, மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®±à¯à®šà®¿à®•à¯à®•à®µà¯à®®à¯</translation>
+<translation id="79338296614623784">சரியான ஃபோன௠எணà¯à®£à¯ˆ உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯</translation>
<translation id="7935318582918952113">DOM டிஸà¯à®Ÿà®¿à®²à¯à®²à®°à¯</translation>
<translation id="7938958445268990899">சேவையகச௠சானà¯à®±à®¿à®¤à®´à¯ இனà¯à®©à¯à®®à¯ செலà¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®•à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="7942349550061667556">சிவபà¯à®ªà¯</translation>
@@ -747,6 +759,7 @@
<translation id="8088680233425245692">கடà¯à®Ÿà¯à®°à¯ˆà®¯à¯ˆà®•à¯ காடà¯à®Ÿà¯à®µà®¤à®¿à®²à¯ தோலà¯à®µà®¿.</translation>
<translation id="8089520772729574115">1 மெ.பை. கà¯à®•à¯à®®à¯ கà¯à®±à¯ˆà®µà®¾à®• உளà¯à®³à®¤à¯</translation>
<translation id="8091372947890762290">சேவையகதà¯à®¤à®¿à®²à¯ செயலாகà¯à®•à®®à¯ நிலà¯à®µà¯ˆà®¯à®¿à®²à¯à®³à¯à®³à®¤à¯</translation>
+<translation id="8118489163946903409">கடà¯à®Ÿà®£ à®®à¯à®±à¯ˆ</translation>
<translation id="8131740175452115882">உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> இன௠சேவையக <ph name="BEGIN_ABBR" />DNS à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®•à¯<ph name="END_ABBR" /> கணà¯à®Ÿà¯à®ªà®¿à®Ÿà®¿à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="8149426793427495338">உஙà¯à®•à®³à¯ கணினி உறகà¯à®•à®¨à®¿à®²à¯ˆà®•à¯à®•à¯à®šà¯ செனà¯à®±à®¤à¯.</translation>
@@ -772,6 +785,7 @@
<translation id="8349305172487531364">பà¯à®•à¯à®®à®¾à®°à¯à®•à¯ படà¯à®Ÿà®¿</translation>
<translation id="8363502534493474904">விமானப௠பயனà¯à®®à¯à®±à¯ˆà®¯à¯ˆ à®®à¯à®Ÿà®•à¯à®•à¯à®¤à®²à¯</translation>
<translation id="8364627913115013041">அமைகà¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
+<translation id="8368476060205742148">Google Play சேவைகளà¯</translation>
<translation id="8380941800586852976">ஆபதà¯à®¤à®¾à®©à®¤à¯</translation>
<translation id="8382348898565613901">நீஙà¯à®•à®³à¯ சமீபதà¯à®¤à®¿à®²à¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà¯à®Ÿ பà¯à®¤à¯à®¤à®•à®•à¯à®•à¯à®±à®¿à®•à®³à¯ இஙà¯à®•à¯‡ தோனà¯à®±à¯à®®à¯</translation>
<translation id="8398259832188219207">சிதைவ௠அறிகà¯à®•à¯ˆ பதிவேறà¯à®±à®ªà¯à®ªà®Ÿà¯à®Ÿ தேதி: <ph name="UPLOAD_TIME" /></translation>
@@ -780,31 +794,29 @@
<translation id="8428213095426709021">அமைபà¯à®ªà¯à®•à®³à¯</translation>
<translation id="8433057134996913067">இதனால௠பெரà¯à®®à¯à®ªà®¾à®²à®¾à®© வலைதà¯à®¤à®³à®™à¯à®•à®³à®¿à®²à¯ இரà¯à®¨à¯à®¤à¯ வெளியேறà¯à®±à®ªà¯à®ªà®Ÿà¯à®µà¯€à®°à¯à®•à®³à¯.</translation>
<translation id="8437238597147034694">&amp;நகரà¯à®¤à¯à®¤à®²à¯ˆà®šà¯ செயலà¯à®¤à®µà®¿à®°à¯</translation>
-<translation id="8456681095658380701">தவறான பெயரà¯</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 கிரெடிட௠காரà¯à®Ÿà¯}other{# கிரெடிட௠காரà¯à®Ÿà¯à®•à®³à¯}}</translation>
<translation id="8483780878231876732">Google கணகà¯à®•à®¿à®²à¯ உளà¯à®³ காரà¯à®Ÿà¯à®•à®³à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤, Chrome இல௠உளà¯à®¨à¯à®´à¯ˆà®¯à®µà¯à®®à¯</translation>
<translation id="8488350697529856933">இதறà¯à®•à¯à®ªà¯ பொரà¯à®¨à¯à®¤à¯à®®à¯</translation>
-<translation id="8492969205326575646">ஆதரிகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤ காரà¯à®Ÿà¯ வகை</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> பதிலளிகà¯à®• நீணà¯à®Ÿ நேரம௠எடà¯à®¤à¯à®¤à¯à®•à¯à®•à¯Šà®£à¯à®Ÿà®¤à¯.</translation>
<translation id="852346902619691059"><ph name="DOMAIN" /> என இநà¯à®¤à®šà¯ சேவையகதà¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®šà¯ சானà¯à®±à®¿à®¤à®´à¯ˆ உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®©à¯ இயகà¯à®• à®®à¯à®±à¯ˆà®®à¯ˆ நமà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">காலாவதியாகà¯à®®à¯ ஆணà¯à®Ÿà¯</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />கணà¯à®Ÿà®±à®¿à®µà®¤à®¿à®²à¯ சிகà¯à®•à®²à¯ இரà¯à®ªà¯à®ªà®¤à¯ˆà®ªà¯ பà¯à®•à®¾à®°à®³à®¿à®•à¯à®•à®²à®¾à®®à¯<ph name="END_ERROR_LINK" /> அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¿à®±à¯à®•à¯ à®à®±à¯à®ªà®Ÿà®•à¯à®•à¯‚டிய ஆபதà¯à®¤à¯à®•à®³à¯ˆà®ªà¯ பà¯à®°à®¿à®¨à¯à®¤à¯à®•à¯Šà®£à¯à®Ÿà®¿à®°à¯à®¨à¯à®¤à®¾à®²à¯, <ph name="BEGIN_LINK" />இநà¯à®¤à®ªà¯ பாதà¯à®•à®¾à®ªà¯à®ªà®±à¯à®± தளதà¯à®¤à®¿à®±à¯à®•à¯à®šà¯ செலà¯à®²à®²à®¾à®®à¯<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">பகà¯à®•à®¤à¯à®¤à®¿à®©à¯ மொழியைத௠தீரà¯à®®à®¾à®©à®¿à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®¾à®¤à®¤à®¾à®²à¯ மொழிபெயரà¯à®ªà¯à®ªà¯ தோலà¯à®µà®¿à®¯à®Ÿà¯ˆà®¨à¯à®¤à®¤à¯.</translation>
<translation id="8559762987265718583">உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®©à¯ தேதி மறà¯à®±à¯à®®à¯ நேரம௠(<ph name="DATE_AND_TIME" />) தவறாக உளà¯à®³à®¤à®¾à®²à¯ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> கà¯à®•à®¾à®© தனிபà¯à®ªà®Ÿà¯à®Ÿ இணைபà¯à®ªà¯ˆ à®à®±à¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
-<translation id="8570229484593575558">பினà¯à®µà®°à¯à®®à¯ தகவல௠|சேமிகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤à¯|:#உஙà¯à®•à®³à¯ உலாவல௠வரலாறà¯#உஙà¯à®•à®³à¯ தேடலà¯à®•à®³à¯#கà¯à®•à¯à®•à¯€à®¤à¯ தரவà¯</translation>
<translation id="8571890674111243710"><ph name="LANGUAGE" /> கà¯à®•à¯ பகà¯à®•à®¤à¯à®¤à¯ˆ மொழிபெயரà¯à®•à¯à®•à®¿à®±à®¤à¯...</translation>
-<translation id="8584539743998202583">உஙà¯à®•à®³à¯ செயலà¯à®ªà®¾à®Ÿà¯ பினà¯à®µà®°à¯à®ªà®µà®°à¯à®•à®³à¯à®•à¯à®•à¯à®¤à¯ |தொடரà¯à®¨à¯à®¤à¯ தெரியà¯à®®à¯|:#நீஙà¯à®•à®³à¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà¯à®®à¯ இணையதளஙà¯à®•à®³à¯#உஙà¯à®•à®³à¯ நிறà¯à®µà®©à®®à¯#உஙà¯à®•à®³à¯ இணையச௠சேவை வழஙà¯à®•à¯à®¨à®°à¯</translation>
<translation id="858637041960032120">தொலைபேசி எணà¯</translation>
<translation id="859285277496340001">இநà¯à®¤ சானà¯à®±à®¿à®¤à®´à¯ திரà¯à®®à¯à®ªà®ªà¯à®ªà¯†à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à®¾ எனà¯à®ªà®¤à¯ˆà®šà¯ சரிபாரà¯à®ªà¯à®ªà®¤à®±à¯à®•à®¾à®© செயலà¯à®®à¯à®±à¯ˆ இதில௠இலà¯à®²à¯ˆ.</translation>
<translation id="8620436878122366504">இனà¯à®©à¯à®®à¯ உஙà¯à®•à®³à¯ பெறà¯à®±à¯‹à®°à¯ அனà¯à®®à®¤à®¿à®•à¯à®•à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="8647750283161643317">எலà¯à®²à®¾à®µà®±à¯à®±à¯ˆà®¯à¯à®®à¯ இயலà¯à®ªà¯à®¨à®¿à®²à¯ˆà®•à¯à®•à¯ மீடà¯à®Ÿà®®à¯ˆ</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> கà¯à®•à®¾à®© உஙà¯à®•à®³à¯ இணைபà¯à®ªà¯ கà¯à®±à®¿à®¯à®¾à®•à¯à®•à®®à¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
+<translation id="8718314106902482036">பேமணà¯à®Ÿà¯ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="8725066075913043281">மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®±à¯à®šà®¿à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="8728672262656704056">மறைநிலைகà¯à®•à¯à®šà¯ செனà¯à®±à¯à®µà®¿à®Ÿà¯à®Ÿà¯€à®°à¯à®•à®³à¯</translation>
<translation id="8730621377337864115">à®®à¯à®Ÿà®¿à®¨à¯à®¤à®¤à¯</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="8759274551635299824">காரà¯à®Ÿà¯ காலாவதியாகிவிடà¯à®Ÿà®¤à¯</translation>
<translation id="8790007591277257123">&amp;நீகà¯à®•à¯à®¤à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ செயà¯</translation>
-<translation id="8798099450830957504">இயலà¯à®ªà¯à®¨à®¿à®²à¯ˆ</translation>
<translation id="8800988563907321413">உஙà¯à®•à®³à¯ à®…à®°à¯à®•à®¿à®²à¯à®³à¯à®³à®µà®±à¯à®±à¯à®•à¯à®•à®¾à®© பரிநà¯à®¤à¯à®°à¯ˆà®•à®³à¯ இஙà¯à®•à¯‡ தோனà¯à®±à¯à®®à¯</translation>
<translation id="8820817407110198400">பà¯à®¤à¯à®¤à®•à®•à¯à®•à¯à®±à®¿à®•à®³à¯</translation>
<translation id="883848425547221593">மறà¯à®± பà¯à®•à¯à®®à®¾à®°à¯à®•à¯à®•à¯à®•à®³à¯</translation>
@@ -814,6 +826,7 @@
<translation id="8866481888320382733">கொளà¯à®•à¯ˆ அமைபà¯à®ªà¯à®•à®³à¯ˆ அலசà¯à®µà®¤à®¿à®²à¯ பிழை</translation>
<translation id="8866959479196209191">இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ தெரிவிபà¯à®ªà®¤à¯:</translation>
<translation id="8870413625673593573">சமீபதà¯à®¤à®¿à®²à¯ மூடியவை</translation>
+<translation id="8874824191258364635">சரியான காரà¯à®Ÿà¯ எணà¯à®£à¯ˆ உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯</translation>
<translation id="8876793034577346603">அலசà¯à®µà®¤à®¿à®²à¯ பிணைய உளà¯à®³à®®à¯ˆà®µà¯ தோலà¯à®µà®¿.</translation>
<translation id="8877192140621905067">உறà¯à®¤à®¿à®šà¯†à®¯à¯à®¤ பினà¯à®©à®°à¯, உஙà¯à®•à®³à¯ காரà¯à®Ÿà¯ விவரஙà¯à®•à®³à¯ இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®±à¯à®•à¯à®ªà¯ பகிரபà¯à®ªà®Ÿà¯à®®à¯</translation>
<translation id="8889402386540077796">நிறசà¯à®šà®¾à®¯à®²à¯</translation>
@@ -823,7 +836,6 @@
<translation id="8931333241327730545">இநà¯à®¤à®•à¯ காரà¯à®Ÿà¯ˆ உஙà¯à®•à®³à¯ Google கணகà¯à®•à®¿à®²à¯ சேமிகà¯à®• வேணà¯à®Ÿà¯à®®à®¾?</translation>
<translation id="8932102934695377596">உஙà¯à®•à®³à¯ கடிகாரம௠மிகவà¯à®®à¯ பினà¯à®¤à®™à¯à®•à®¿ இரà¯à®•à¯à®•à®¿à®±à®¤à¯</translation>
<translation id="8954894007019320973">(தொடரà¯à®•à®¿à®±à®¤à¯)</translation>
-<translation id="895548565263634352"><ph name="ARTICLE_PUBLISHER" /> மறà¯à®±à¯à®®à¯ <ph name="OTHER_ARTICLE_COUNT" /> வெளியீடà¯à®Ÿà®¾à®³à®°à¯à®•à®³à®¿à®©à¯ செயà¯à®¤à®¿à®•à¯ கடà¯à®Ÿà¯à®°à¯ˆà®•à®³à¯ˆà®ªà¯ படிகà¯à®•à®²à®¾à®®à¯</translation>
<translation id="8971063699422889582">சேவையகச௠சானà¯à®±à®¿à®¤à®´à¯ காலாவதியானதà¯.</translation>
<translation id="8986494364107987395">பயனà¯à®ªà®¾à®Ÿà¯à®Ÿà¯à®ªà¯ பà¯à®³à¯à®³à®¿à®µà®¿à®µà®°à®™à¯à®•à®³à¯ˆà®¯à¯à®®à¯ சிதைவ௠அறிகà¯à®•à¯ˆà®•à®³à¯ˆà®¯à¯à®®à¯ தானாகவே Google கà¯à®•à¯ அனà¯à®ªà¯à®ªà¯</translation>
<translation id="8987927404178983737">மாதமà¯</translation>
@@ -841,7 +853,6 @@
<translation id="9068849894565669697">வணà¯à®£à®¤à¯à®¤à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯</translation>
<translation id="9076283476770535406">இதில௠பெரியவரà¯à®•à®³à¯à®•à¯à®•à®¾à®© உளà¯à®³à®Ÿà®•à¯à®•à®®à¯ இரà¯à®•à¯à®•à®•à¯à®•à¯‚டà¯à®®à¯</translation>
<translation id="9078964945751709336">கூடà¯à®¤à®²à¯ தகவல௠தேவை</translation>
-<translation id="9094175695478007090">கடà¯à®Ÿà®£à®ªà¯ பயனà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ˆà®¤à¯ தொடஙà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="9103872766612412690">வழகà¯à®•à®®à®¾à®•, <ph name="SITE" /> உஙà¯à®•à®³à¯ தகவலைப௠பாதà¯à®•à®¾à®ªà¯à®ªà®¤à®±à¯à®•à®¾à®• à®®à¯à®±à¯ˆà®®à¯ˆà®¯à®¾à®•à¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à®¤à¯.
இநà¯à®¤ à®®à¯à®±à¯ˆ <ph name="SITE" /> உடன௠இணைவதறà¯à®•à¯ Chromium à®®à¯à®¯à®±à¯à®šà®¿à®¤à¯à®¤à®ªà¯‹à®¤à¯ வழகà¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯ மாறான, தவறான நறà¯à®šà®¾à®©à¯à®±à®¿à®¤à®´à¯à®•à®³à¯ˆ இணையதளம௠வழஙà¯à®•à®¿à®¯à®¤à¯. தாகà¯à®•à¯à®ªà®µà®°à¯ தனà¯à®©à¯ˆ <ph name="SITE" /> ஆகக௠காடà¯à®Ÿ à®®à¯à®¯à®±à¯à®šà®¿à®•à¯à®•à¯à®®à¯ போத௠அலà¯à®²à®¤à¯ இணைபà¯à®ªà¯ˆ வைஃபை உளà¯à®¨à¯à®´à¯ˆà®µà¯à®¤à¯ திரை கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®®à¯ போத௠இத௠à®à®±à¯à®ªà®Ÿà®²à®¾à®®à¯. இரà¯à®ªà¯à®ªà®¿à®©à¯à®®à¯, தரவ௠எதà¯à®µà¯à®®à¯ பரிமாறà¯à®±à®ªà¯à®ªà®Ÿà¯à®µà®¤à®±à¯à®•à¯ à®®à¯à®©à¯ Chromium இணைபà¯à®ªà¯ˆ நிறà¯à®¤à¯à®¤à®¿à®¯à®¤à®¾à®²à¯ உஙà¯à®•à®³à¯ தகவல௠பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®•à®µà¯‡ இரà¯à®•à¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="9137013805542155359">அசலைக௠காணà¯à®ªà®¿</translation>
diff --git a/chromium/components/strings/components_strings_te.xtb b/chromium/components/strings/components_strings_te.xtb
index dd0fa625b49..fa3023c1407 100644
--- a/chromium/components/strings/components_strings_te.xtb
+++ b/chromium/components/strings/components_strings_te.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="te">
<translation id="1008557486741366299">ఇపà±à°ªà±à°¡à± కాదà±</translation>
<translation id="1015730422737071372">అదనపౠవివరాలనౠఅందించండి</translation>
+<translation id="1021110881106174305">ఆమోదించబడే కారà±à°¡à±â€Œà°²à±</translation>
<translation id="1032854598605920125">సవà±à°¯à°¦à°¿à°¶à°²à±‹ తిపà±à°ªà±</translation>
<translation id="1038842779957582377">తెలియని పేరà±</translation>
<translation id="1050038467049342496">ఇతర à°…à°¨à±à°µà°°à±à°¤à°¨à°¾à°²à°¨à± మూసివేయండి</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">విలà±à°µà°¨à± దాచండి</translation>
<translation id="1228893227497259893">à°Žà°‚à°Ÿà°¿à°Ÿà±€ à°à°¡à±†à°‚టిఫైయరౠచెలà±à°²à°¦à±</translation>
<translation id="1232569758102978740">శీరà±à°·à°¿à°•à°²à±‡à°¨à°¿à°¦à°¿</translation>
+<translation id="1263231323834454256">పఠన జాబితా</translation>
<translation id="1264126396475825575">à°•à±à°°à°¾à°·à± నివేదిక <ph name="CRASH_TIME" />à°•à°¿ సంగà±à°°à°¹à°¿à°‚చబడింది (ఇంకా à°…à°ªà±â€Œà°²à±‹à°¡à± చేయలేదౠలేదా విసà±à°®à°°à°¿à°‚చబడింది)</translation>
<translation id="1285320974508926690">à°ˆ సైటà±â€Œà°¨à± à°…à°¨à±à°µà°¦à°¿à°‚చవదà±à°¦à±</translation>
<translation id="129553762522093515">ఇటీవల మూసివెయà±à°¯à°¬à°¡à°¿à°¨à°µà°¿</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromium à°¸à±à°µà°¯à°‚పూరà±à°¤à°¿ సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à±...</translation>
<translation id="1374468813861204354">సూచనలà±</translation>
<translation id="1375198122581997741">వెరà±à°·à°¨à± à°—à±à°°à°¿à°‚à°šà°¿</translation>
+<translation id="1377321085342047638">కారà±à°¡à± సంఖà±à°¯</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> డేటా à°à°¦à±€ పంపలేదà±.</translation>
<translation id="1407135791313364759">à°…à°¨à±à°¨à±€ తెరà±à°µà±</translation>
<translation id="1413809658975081374">గోపà±à°¯à°¤à°¾ లోపం</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">à°šà°°à°¿à°¤à±à°°</translation>
<translation id="1645368109819982629">à°ªà±à°°à±‹à°Ÿà±‹à°•à°¾à°²à±â€Œà°•à± మదà±à°¦à°¤à± లేదà±</translation>
<translation id="1656489000284462475">పికపà±</translation>
+<translation id="1663943134801823270">కారà±à°¡à±â€Œà°²à± మరియౠచిరà±à°¨à°¾à°®à°¾à°²à± Chrome à°¨à±à°‚à°¡à°¿ పొందినవి. మీరౠ<ph name="BEGIN_LINK" />సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à±<ph name="END_LINK" />లో వాటిని నిరà±à°µà°¹à°¿à°‚చవచà±à°šà±.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> సాధారణంగా మీ సమాచారానà±à°¨à°¿ à°°à°•à±à°·à°¿à°‚చడానికి à°—à±à°ªà±à°¤à±€à°•à°°à°£à°¨à± ఉపయోగిసà±à°¤à±à°‚ది. Google Chrome ఈసారి <ph name="SITE" />à°•à°¿ కనెకà±à°Ÿà± చేయడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚చినపà±à°ªà±à°¡à±, వెబà±â€Œà°¸à±ˆà°Ÿà± అసాధారణ మరియౠతపà±à°ªà± ఆధారాలౠఅని à°ªà±à°°à°¤à°¿à°¸à±à°ªà°‚దించింది. దాడి చేసే à°µà±à°¯à°•à±à°¤à°¿ <ph name="SITE" />à°—à°¾ à°µà±à°¯à°µà°¹à°°à°¿à°‚à°šà°¿ మోసగించడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°¸à±à°¤à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± లేదా Wi-Fi సైనà±-ఇనౠసà±à°•à±à°°à±€à°¨à± కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగించినపà±à°ªà±à°¡à± ఇలా జరగవచà±à°šà±. Google Chrome డేటా వినిమయం సంభవించక à°®à±à°‚దే కనెకà±à°·à°¨à±â€Œà°¨à± ఆపివేసినందà±à°¨ మీ సమాచారం ఇపà±à°ªà°Ÿà°¿à°•à±€ à°¸à±à°°à°•à±à°·à°¿à°¤à°‚గానే ఉంది.</translation>
<translation id="168328519870909584">à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />పై దాడి చేసేవారౠమీ పరికరంలో మీ సమాచారానà±à°¨à°¿ (ఉదాహరణకà±, ఫోటోలà±, పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à±, సందేశాలౠమరియౠకà±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à±â€Œà°²à±) దొంగిలించగలిగే లేదా తొలగించగలిగే à°ªà±à°°à°®à°¾à°¦à°•à°°à°®à±ˆà°¨ à°…à°¨à±à°µà°°à±à°¤à°¨à°¾à°²à°¨à± ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేయడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚చవచà±à°šà±.</translation>
<translation id="168841957122794586">సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ బలహీన à°•à±à°°à°¿à°ªà±à°Ÿà±‹à°—à±à°°à°¾à°«à°¿à°•à± కీని కలిగి ఉంది.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">à°ˆ సైటà±â€Œà°¨à°¿ సందరà±à°¶à°¿à°‚చడానికి మీకౠ<ph name="NAME" /> à°¨à±à°‚à°¡à°¿ à°…à°¨à±à°®à°¤à°¿ అవసరం</translation>
+<translation id="1721424275792716183">* అవసరమైన ఫీలà±à°¡à±</translation>
<translation id="1728677426644403582">మీరౠవెబౠపేజీ యొకà±à°• మూలాధారానà±à°¨à°¿ వీకà±à°·à°¿à°¸à±à°¤à±à°¨à±à°¨à°¾à°°à±</translation>
+<translation id="173080396488393970">à°ˆ రకమైన కారà±à°¡à±â€Œà°•à°¿ మదà±à°¦à°¤à± లేదà±</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">సిసà±à°Ÿà°®à± నిరà±à°µà°¾à°¹à°•à±à°¡à°¿à°¨à°¿ సంపà±à°°à°¦à°¿à°‚à°šà°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
+<translation id="1740951997222943430">చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°¯à±à°¯à±‡ à°—à°¡à±à°µà± à°®à±à°—ింపౠనెలనౠనమోదౠచేయండి</translation>
<translation id="1745358365027406341">పేజీని తరà±à°µà°¾à°¤ డౌనà±â€Œà°²à±‹à°¡à± చేయి</translation>
<translation id="17513872634828108">తెరిచిన à°Ÿà±à°¯à°¾à°¬à±â€à°²à±</translation>
<translation id="1753706481035618306">పేజీ సంఖà±à°¯</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">దయచేసి మీ సమకాలీకరణ పాసà±â€Œà°«à±à°°à±‡à°œà±â€Œà°¨à± నవీకరించండి.</translation>
<translation id="1787142507584202372">మీ తెరవబడిన à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à± ఇకà±à°•à°¡ కనిపిసà±à°¤à°¾à°¯à°¿</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">బటà±à°µà°¾à°¡à°¾ పదà±à°§à°¤à±à°²à± మరియౠఆవశà±à°¯à°•à°¾à°²à°¨à± చూడటానికి బటà±à°µà°¾à°¡à°¾ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
+<translation id="1803264062614276815">కారà±à°¡à±à°¦à°¾à°°à±à°¨à°¿ పేరà±</translation>
<translation id="1803678881841855883">Google à°¸à±à°°à°•à±à°·à°¿à°¤ à°¬à±à°°à±Œà°œà°¿à°‚గౠఇటీవల <ph name="SITE" />లో <ph name="BEGIN_LINK" />మాలà±à°µà±‡à°°à±â€Œà°¨à°¿ à°—à±à°°à±à°¤à°¿à°‚చింది<ph name="END_LINK" />. సాధారణంగా à°¸à±à°°à°•à±à°·à°¿à°¤à°®à±ˆà°¨ వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œâ€Œà°²à± కూడా కొనà±à°¨à°¿à°¸à°¾à°°à±à°²à± మాలà±à°µà±‡à°°à± బారినపడతాయి. మాలà±à°µà±‡à°°à±â€Œ పంపిణీదారà±à°—à°¾ పేరà±à°—ాంచిన <ph name="SUBRESOURCE_HOST" /> à°¨à±à°‚à°¡à°¿ ఇతరà±à°²à°•à± హాని తలపటà±à°Ÿà±‡ లాంటి కంటెంటౠసంకà±à°°à°®à°¿à°¸à±à°¤à±à°‚ది. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">జోడించినది <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">చెలà±à°²à°¨à°¿ à°…à°­à±à°¯à°°à±à°¥à°¨ లేదా à°…à°­à±à°¯à°°à±à°¥à°¨ పరామితà±à°²à±</translation>
<translation id="1826516787628120939">తనిఖీ చేసà±à°¤à±‹à°‚ది</translation>
<translation id="1834321415901700177">à°ˆ సైటౠహానికరమైన à°ªà±à°°à±‹à°—à±à°°à°¾à°®à±â€Œà°²à°¨à± కలిగి ఉంది</translation>
<translation id="1842969606798536927">చెలà±à°²à°¿à°‚à°ªà±</translation>
-<translation id="1864455488461349376">బటà±à°µà°¾à°¡à°¾ ఎంపిక</translation>
<translation id="1871208020102129563">à°ªà±à°°à°¾à°•à±à°¸à±€ à°¸à±à°¥à°¿à°°à°®à±ˆà°¨ à°ªà±à°°à°¾à°•à±à°¸à±€ సరà±à°µà°°à±â€Œà°²à°¨à± ఉపయోగించడానికి సెటౠచేయబడింది, .pac à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà± URLనౠకాదà±.</translation>
<translation id="1871284979644508959">అవసరమైన ఫీలà±à°¡à±</translation>
<translation id="187918866476621466">à°ªà±à°°à°¾à°°à°‚à°­ పేజీలనౠతెరà±à°µà±</translation>
<translation id="1883255238294161206">జాబితానౠకà±à°¦à°¿à°‚à°šà±</translation>
<translation id="1898423065542865115">à°«à°¿à°²à±à°Ÿà°°à°¿à°‚à°—à±</translation>
<translation id="194030505837763158"><ph name="LINK" />à°•à°¿ వెళà±à°²à°‚à°¡à°¿</translation>
-<translation id="1946821392246652573">ఆమోదించబడే కారà±à°¡à±â€Œà°²à±</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à±</translation>
<translation id="1973335181906896915">à°¶à±à°°à±‡à°£à°¿à°—à°¾ రూపొందించడంలో లోపం</translation>
<translation id="1974060860693918893">ఆధà±à°¨à°¿à°•</translation>
<translation id="1978555033938440688">à°«à°°à±à°®à±â€Œà°µà±‡à°°à± సంసà±à°•à°°à°£</translation>
+<translation id="1995859865337580572">దయచేసి మీ CVCని ధృవీకరించండి</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{మరియౠమరొకటి}other{మరియౠమరో #}}</translation>
-<translation id="2020194265157481222">కారà±à°¡à±â€Œà°²à±‹ పేరౠఆవశà±à°¯à°•à°‚</translation>
<translation id="2025186561304664664">à°ªà±à°°à°¾à°•à±à°¸à±€ à°¸à±à°µà°¯à°‚చాలకంగా కానà±à°«à°¿à°—రౠచేయబడేలా సెటౠచేయబడింది.</translation>
<translation id="2030481566774242610">మీ ఉదà±à°¦à±‡à°¶à±à°¯à°‚ <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />à°ªà±à°°à°¾à°•à±à°¸à±€ మరియౠఫైరà±â€Œà°µà°¾à°²à±â€Œà°¨à± తనిఖీ చేయడం<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">à°ˆ రోజà±</translation>
<translation id="2154054054215849342">సమకాలీకరణ మీ డొమైనà±â€Œà°•à± à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±</translation>
<translation id="2154484045852737596">కారà±à°¡à±â€Œà°¨à± సవరించండి</translation>
-<translation id="2156993118928861787">à°šà°¿à°°à±à°¨à°¾à°®à°¾ చెలà±à°²à°¦à±</translation>
<translation id="2166049586286450108">పూరà±à°¤à°¿ నిరà±à°µà°¾à°¹à°• à°ªà±à°°à°¾à°ªà±à°¯à°¤</translation>
<translation id="2166378884831602661">à°ˆ సైటౠసà±à°°à°•à±à°·à°¿à°¤à°®à±ˆà°¨ కనెకà±à°·à°¨à±â€Œà°¨à± అందించలేదà±</translation>
<translation id="2181821976797666341">విధానాలà±</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 à°šà°¿à°°à±à°¨à°¾à°®à°¾}other{# à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à±}}</translation>
+<translation id="2202020181578195191">చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°¯à±à°¯à±‡ à°—à°¡à±à°µà± à°®à±à°—ింపౠసంవతà±à°¸à°°à°¾à°¨à±à°¨à°¿ నమోదౠచేయండి</translation>
<translation id="2212735316055980242">విధానం à°•à°¨à±à°—ొనబడలేదà±</translation>
<translation id="2213606439339815911">నమోదà±à°²à°¨à± పొందà±à°¤à±‹à°‚ది...</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />విశà±à°²à±‡à°·à°£à°² à°…à°¨à±à°µà°°à±à°¤à°¨à°¾à°¨à±à°¨à°¿<ph name="END_LINK" /> ఉపయోగించి మీ కనెకà±à°·à°¨à±â€Œà°¨à± సరి చేయండి</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">మీ ఇంటరà±à°¨à±†à°Ÿà± à°ªà±à°°à°¾à°ªà±à°¯à°¤ à°¬à±à°²à°¾à°•à± చేయబడింది</translation>
<translation id="230155334948463882">కొతà±à°¤ కారà±à°¡à°¾?</translation>
<translation id="2305919008529760154">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపించà±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ మోసపూరితంగా జారీ అయి ఉండవచà±à°šà±. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—రౠచేయడం వలన లేదా దాడి చేసే à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగించడం వలన జరిగి ఉండవచà±à°šà±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">కారà±à°¡à± మరియౠచిరà±à°¨à°¾à°®à°¾ ఎంపికలౠమీ Google ఖాతా (<ph name="ACCOUNT_EMAIL" />) మరియౠChrome à°¨à±à°‚à°¡à°¿ ఉనà±à°¨à°¾à°¯à°¿. మీరౠవీటిని <ph name="BEGIN_LINK" />సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²<ph name="END_LINK" />లో నిరà±à°µà°¹à°¿à°‚చగలరà±.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" />à°•à°¿ వినియోగదారౠపేరౠమరియౠపాసà±â€Œà°µà°°à±à°¡à± అవసరం.</translation>
<translation id="2318774815570432836">వెబà±â€Œà°¸à±ˆà°Ÿà± HSTSని ఉపయోగిసà±à°¤à±à°¨à±à°¨à°‚à°¦à±à°¨ మీరౠపà±à°°à°¸à±à°¤à±à°¤à°‚ <ph name="SITE" />ని సందరà±à°¶à°¿à°‚చలేరà±. నెటà±â€Œà°µà°°à±à°•à± లోపాలౠమరియౠదాడà±à°²à± సాధారణంగా తాతà±à°•à°¾à°²à°¿à°•à°‚గానే ఉంటాయి, కావà±à°¨ à°ˆ పేజీ కాసేపటి తరà±à°µà°¾à°¤ పని చేసే అవకాశం ఉంది. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">ఇతర à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à±</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">à°Žà°‚à°Ÿà°°à±â€Œà°ªà±à°°à±ˆà°œà± డిఫాలà±à°Ÿà±</translation>
<translation id="2386255080630008482">సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°°à°¦à±à°¦à± చెయà±à°¯à°¬à°¡à°¿à°‚ది.</translation>
<translation id="2392959068659972793">విలà±à°µ సెటౠచేయని విధానాలనౠచూపà±</translation>
+<translation id="239429038616798445">à°ˆ రవాణా పదà±à°§à°¤à°¿ à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±. వేరే పదà±à°§à°¤à°¿à°¨à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="2396249848217231973">&amp;తొలగించడానà±à°¨à°¿ à°°à°¦à±à°¦à± చేయి</translation>
<translation id="2460160116472764928">Google à°¸à±à°°à°•à±à°·à°¿à°¤ à°¬à±à°°à±Œà°œà°¿à°‚గౠఇటీవల <ph name="SITE" />లో <ph name="BEGIN_LINK" />మాలà±à°µà±‡à°°à±â€Œà°¨à°¿ à°—à±à°°à±à°¤à°¿à°‚చింది<ph name="END_LINK" />. సాధారణంగా à°¸à±à°°à°•à±à°·à°¿à°¤à°®à±ˆà°¨ వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œâ€Œà°²à± కూడా కొనà±à°¨à°¿à°¸à°¾à°°à±à°²à± మాలà±à°µà±‡à°°à±â€Œ బారినపడతాయి. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">పూరించà±</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />నెటà±â€Œà°µà°°à±à°•à± సమసà±à°¯ విశà±à°²à±‡à°·à°£à°²à°¨à± అమలౠచేయడం<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">చెలà±à°²à°¨à°¿ శోధన URL.</translation>
<translation id="2491120439723279231">సరà±à°µà°°à± యొకà±à°• à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚లో లోపాలౠఉనà±à°¨à°¾à°¯à°¿.</translation>
-<translation id="24943777258388405">ఫోనౠనంబరౠచెలà±à°²à°¦à±</translation>
<translation id="2495083838625180221">JSON పారà±à°¸à°°à±</translation>
<translation id="2495093607237746763">à°Žà°‚à°šà±à°•à±à°‚టే, Chromium వేగవంతమైన ఫారమౠపూరింపౠకోసం à°ˆ పరికరంలో మీ కారà±à°¡à± కాపీని నిలà±à°µ చేసà±à°¤à±à°‚ది.</translation>
<translation id="2498091847651709837">కొతà±à°¤ కారà±à°¡à±â€Œà°¨à± à°¸à±à°•à°¾à°¨à± చేయండి</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> చెలà±à°²à°¨à°¿ à°ªà±à°°à°¤à°¿à°¸à±à°ªà°‚దననౠపంపింది.</translation>
<translation id="2552545117464357659">à°•à±à°°à±Šà°¤à±à°¤à°µà°¿</translation>
<translation id="2556876185419854533">&amp;సవరించడానà±à°¨à°¿ à°°à°¦à±à°¦à± చేయి</translation>
+<translation id="2587730715158995865">à°ªà±à°°à°šà±à°°à°£à°•à°°à±à°¤ <ph name="ARTICLE_PUBLISHER" />. దీనà±à°¨à°¿ మరియౠమరో <ph name="OTHER_ARTICLE_COUNT" /> ఇతర కథనాలనౠచదవండి.</translation>
<translation id="2587841377698384444">డైరెకà±à°Ÿà°°à±€ API ID:</translation>
<translation id="2597378329261239068">à°ˆ పతà±à°°à°‚ à°…à°¨à±à°®à°¤à°¿ పదంచే à°°à°•à±à°·à°¿à°‚చబడింది. దయచేసి à°…à°¨à±à°®à°¤à°¿ పదానà±à°¨à°¿ నమోదౠచేయండి.</translation>
<translation id="2609632851001447353">à°µà±à°¯à°¤à±à°¯à°¾à°¸à°¾à°²à±</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />కనెకà±à°Ÿà°¿à°µà°¿à°Ÿà±€ సమసà±à°¯ విశà±à°²à±‡à°·à°£à°²à°¨à± అమలౠచేయడం<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">సరే</translation>
<translation id="2742870351467570537">à°Žà°‚à°šà±à°•à±à°¨à±à°¨ అంశాలనౠతీసివేయండి</translation>
+<translation id="277133753123645258">రవాణా పదà±à°§à°¤à°¿</translation>
<translation id="277499241957683684">పరికరం రికారà±à°¡à± లేదà±</translation>
<translation id="2784949926578158345">కనెకà±à°·à°¨à± మళà±à°³à±€ సెటౠచెయà±à°¯à°¬à°¡à°¿à°‚ది.</translation>
<translation id="2794233252405721443">సైటౠబà±à°²à°¾à°•à± చేయబడింది</translation>
-<translation id="2812680587231492111">à°† తీసà±à°•à±†à°³à±à°²à±‡ ఎంపిక à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±. వేరొక ఎంపికనౠపà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="2824775600643448204">à°šà°¿à°°à±à°¨à°¾à°®à°¾ మరియౠశోధన బారà±</translation>
<translation id="2826760142808435982"><ph name="CIPHER" />నౠఉపయోగించి కనెకà±à°·à°¨à± à°—à±à°ªà±à°¤à±€à°•à°°à°¿à°‚చబడింది మరియౠపà±à°°à°¾à°®à°¾à°£à±€à°•à°°à°¿à°‚చబడింది మరియౠ<ph name="KX" />నౠకీలకమైన పరివరà±à°¤à°¨ విధానంగా ఉపయోగిసà±à°¤à±à°‚ది.</translation>
<translation id="2835170189407361413">ఫారమà±â€Œà°¨à± à°¤à±à°¡à°¿à°šà°¿à°µà±‡à°¯à°¿</translation>
-<translation id="2849041323157393173">à°† బటà±à°µà°¾à°¡à°¾ ఎంపిక à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±. వేరొక ఎంపికనౠపà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="2889159643044928134">మళà±à°²à±€ లోడౠచేయవదà±à°¦à±</translation>
<translation id="2900469785430194048">Google Chrome à°ˆ వెబà±â€Œà°ªà±‡à°œà±€à°¨à°¿ à°ªà±à°°à°¦à°°à±à°¶à°¿à°‚చడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°¸à±à°¤à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± మెమరీ అయిపోయింది.</translation>
<translation id="2909946352844186028">నెటà±â€Œà°µà°°à±à°•à± మారà±à°ªà± à°—à±à°°à±à°¤à°¿à°‚చబడింది.</translation>
<translation id="2916038427272391327">ఇతర à°ªà±à°°à±‹à°—à±à°°à°¾à°®à±â€Œà°²à°¨à± మూసివేయండి</translation>
<translation id="2922350208395188000">సరà±à°µà°°à± యొకà±à°• à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ తనిఖీ చెయà±à°¯à°¬à°¡à°¦à±.</translation>
+<translation id="2928905813689894207">బిలà±à°²à°¿à°‚à°—à± à°šà°¿à°°à±à°¨à°¾à°®à°¾</translation>
<translation id="2948083400971632585">మీరౠసెటà±à°Ÿà°¿à°‚à°—à±â€Œà°² పేజీ à°¨à±à°‚à°¡à°¿ కనెకà±à°·à°¨à± కోసం కానà±à°«à°¿à°—రౠచేయబడిన à° à°ªà±à°°à°¾à°•à±à°¸à±€à°²à°¨à± అయినా నిలిపివేయవచà±à°šà±.</translation>
<translation id="2955913368246107853">à°•à°¨à±à°—ొనౠపటà±à°Ÿà±€à°¨à°¿ మూసివేయి</translation>
<translation id="2958431318199492670">నెటà±â€Œà°µà°°à±à°•à± కానà±à°«à°¿à°—రేషనౠONC à°ªà±à°°à°®à°¾à°£à°¾à°¨à°¿à°•à°¿ à°…à°¨à±à°•à±‚లంగా లేదà±. కానà±à°«à°¿à°—రేషనà±â€Œà°²à±‹à°¨à°¿ భాగాలౠదిగà±à°®à°¤à°¿ కాకపోయి ఉండకపోవచà±à°šà±.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">à°¸à±à°°à°•à±à°·à°¿à°¤ కనెకà±à°·à°¨à±â€Œà°¨à± à°à°°à±à°ªà°¾à°Ÿà± చేయడానికి, మీ గడియారానà±à°¨à°¿ సరైన సమయానికి సెటౠచేయాలి. à°Žà°‚à°¦à±à°•à°‚టే వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°²à± వాటిని à°—à±à°°à±à°¤à°¿à°‚చడానికి ఉపయోగించే à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°²à± నిరà±à°¦à°¿à°·à±à°Ÿ కాలవà±à°¯à°µà°§à±à°²à±à°²à±‹ మాతà±à°°à°®à±‡ చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°µà±à°¤à°¾à°¯à°¿. మీ పరికరం గడియారం సమయం తపà±à°ªà±à°—à°¾ ఉనà±à°¨à°‚à°¦à±à°¨, Google Chrome à°ˆ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°²à°¨à± ధృవీకరించలేదà±.</translation>
<translation id="2972581237482394796">&amp;à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚</translation>
<translation id="2985306909656435243">à°ªà±à°°à°¾à°°à°‚à°­à°¿à°¸à±à°¤à±‡, Chromium వేగవంతమైన ఫారమౠపూరింపౠకోసం à°ˆ పరికరంలో మీ కారà±à°¡à± కాపీని నిలà±à°µ చేసà±à°¤à±à°‚ది.</translation>
+<translation id="2985398929374701810">చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°¯à±à°¯à±‡ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à°¿ నమోదౠచేయండి</translation>
+<translation id="2986368408720340940">à°ˆ పికపౠపదà±à°§à°¤à°¿ à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±. వేరే పదà±à°§à°¤à°¿à°¨à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="2991174974383378012">వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°²à°¤à±‹ భాగసà±à°µà°¾à°®à±à°¯à°‚</translation>
<translation id="3005723025932146533">సేవౠచేయబడిన కాపీని చూపà±</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> కారà±à°¡à± CVCని నమోదౠచేయండి. మీరౠనిరà±à°§à°¾à°°à°¿à°‚à°šà°¿à°¨ తరà±à°µà°¾à°¤, మీ కారà±à°¡à± వివరాలౠఈ సైటà±â€Œà°¤à±‹ భాగసà±à°µà°¾à°®à±à°¯à°‚ చేయబడతాయి.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{సమకాలీకరించిన పరికరాలà±à°²à±‹ కనీసం 1 అంశం}=1{1 అంశం (మరియౠసమకాలీకరించిన పరికరాలà±à°²à±‹ మరినà±à°¨à°¿)}other{# అంశాలౠ(మరియౠసమకాలీకరించిన పరికరాలà±à°²à±‹ మరినà±à°¨à°¿)}}</translation>
<translation id="3041612393474885105">సరà±à°Ÿà°¿à°«à°¿à°•à±†à°Ÿà± సమాచారం</translation>
<translation id="3063697135517575841">Chrome à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ మీ కారà±à°¡à±â€Œà°¨à± నిరà±à°§à°¾à°°à°¿à°‚చలేకపోయింది. దయచేసి తరà±à°µà°¾à°¤ మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
+<translation id="3064966200440839136">బాహà±à°¯ à°…à°¨à±à°µà°°à±à°¤à°¨à°‚ à°¦à±à°µà°¾à°°à°¾ చెలà±à°²à°¿à°‚చడానికి à°…à°œà±à°žà°¾à°¤ మోడౠనà±à°‚à°¡à°¿ నిషà±à°•à±à°°à°®à°¿à°¸à±à°¤à±‹à°‚ది. కొనసాగించాలా?</translation>
<translation id="3093245981617870298">మీరౠఆఫà±â€Œà°²à±ˆà°¨à±â€Œà°²à±‹ ఉనà±à°¨à°¾à°°à±.</translation>
<translation id="3105172416063519923">అసెటౠID:</translation>
<translation id="3109728660330352905">మీకౠఈ పేజీని వీకà±à°·à°¿à°‚చడానికి అధికారం లేదà±.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />కనెకà±à°Ÿà°¿à°µà°¿à°Ÿà±€ సమసà±à°¯ విశà±à°²à±‡à°·à°£à°²à°¨à± అమలౠచేయడం à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">à°ªà±à°°à°¤à°¿à°¸à±à°ªà°‚దననౠడీకోడౠచేయడంలో విఫలమైంది</translation>
-<translation id="3149891296864842641">à°·à°¿à°ªà±à°ªà°¿à°‚గౠఎంపిక</translation>
<translation id="3150653042067488994">తాతà±à°•à°¾à°²à°¿à°• సరà±à°µà°°à± లోపం</translation>
+<translation id="3154506275960390542">à°ˆ పేజీలో ఉనà±à°¨ ఫారమà±â€Œà°¨à°¿ à°¸à±à°°à°•à±à°·à°¿à°¤à°‚à°—à°¾ సమరà±à°ªà°¿à°‚చలేకపోవచà±à°šà±. బదిలీ చేయబడే సమయంలో మీరౠపంపే డేటాని ఇతరà±à°²à± వీకà±à°·à°¿à°‚చవచà±à°šà± లేదా సరà±à°µà°°à± à°¸à±à°µà±€à°•à°°à°¿à°‚చే డేటాని మారà±à°šà°¡à°‚ కోసం à°¹à±à°¯à°¾à°•à°°à±â€Œà°²à± దీనిని సవరించవచà±à°šà±.</translation>
<translation id="3157931365184549694">à°ªà±à°¨à°°à±à°¦à±à°§à°°à°¿à°‚à°šà±</translation>
<translation id="3167968892399408617">మీరౠఅజà±à°žà°¾à°¤ à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à±à°²à±‹ వీకà±à°·à°¿à°‚à°šà°¿à°¨ పేజీలౠమీ à°…à°¨à±à°¨à°¿ à°…à°œà±à°žà°¾à°¤ à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à°¨à± మూసివేసిన అనంతరం మీ à°¬à±à°°à±Œà°œà°°à± à°šà°°à°¿à°¤à±à°°, à°•à±à°•à±à°•à±€ à°¸à±à°Ÿà±‹à°°à± లేదా శోధన à°šà°°à°¿à°¤à±à°°à°²à±‹ ఉంచబడవà±. మీరౠడౌనà±â€Œà°²à±‹à°¡à± చేసే à°à°µà±ˆà°¨à°¾ ఫైలà±â€Œà°²à± లేదా మీరౠసృషà±à°Ÿà°¿à°‚చే à°à°µà±ˆà°¨à°¾ à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à± అలాగే ఉంచబడతాయి.</translation>
<translation id="3169472444629675720">à°•à°¨à±à°—ొనà±</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">à°ˆ సైటà±â€Œà°¨à°¿ à°ªà±à°°à°¾à°ªà±à°¯à°¤ చేయడానికి మీరౠచేసిన à°…à°­à±à°¯à°°à±à°¥à°¨ <ph name="NAME" />à°•à°¿ పంపబడలేదà±. దయచేసి మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="3355823806454867987">à°ªà±à°°à°¾à°•à±à°¸à±€ సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± మారà±à°šà±...</translation>
<translation id="3369192424181595722">గడియారం లోపం</translation>
+<translation id="337311366426640088">మరో <ph name="ITEM_COUNT" /> వసà±à°¤à±à°µà±à°²à±...</translation>
<translation id="337363190475750230">కేటాయింపౠతీసివేయబడింది</translation>
<translation id="3377188786107721145">విధాన à°…à°¨à±à°µà°¯ లోపం</translation>
<translation id="3380365263193509176">తెలియని లోపం</translation>
<translation id="3380864720620200369">à°•à±à°²à°¯à°¿à°‚à°Ÿà± ID:</translation>
<translation id="3391030046425686457">బటà±à°µà°¾à°¡à°¾ à°šà°¿à°°à±à°¨à°¾à°®à°¾</translation>
+<translation id="3395827396354264108">పికపౠపదà±à°§à°¤à°¿</translation>
<translation id="340013220407300675">దాడి చేసేవారౠ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> à°¨à±à°‚à°¡à°¿ మీ సమాచారానà±à°¨à°¿ దొంగిలించడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°¸à±à°¤à±à°‚డవచà±à°šà± (ఉదాహరణకà±, పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à±, సందేశాలౠలేదా à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à±â€Œà°²à±).</translation>
<translation id="3422248202833853650">మెమరీని ఖాళీ చేయడానికి ఇతర à°ªà±à°°à±‹à°—à±à°°à°¾à°®à±â€Œà°² à°¨à±à°‚à°¡à°¿ నిషà±à°•à±à°°à°®à°¿à°‚చడానà±à°¨à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" />ని à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ చేరà±à°•à±‹à°µà°¡à°‚ సాధà±à°¯à°ªà°¡à°¦à±.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">మాసà±à°Ÿà°°à±â€Œà°•à°¾à°°à±à°¡à±</translation>
<translation id="3452404311384756672">విరామానà±à°¨à°¿ పొందండి:</translation>
<translation id="3462200631372590220">à°…à°§à±à°¨à°¾à°¤à°¨à°‚ దాచà±</translation>
+<translation id="3467763166455606212">కారà±à°¡à±à°¦à°¾à°°à±à°¨à°¿ పేరౠఅవసరం</translation>
+<translation id="3478058380795961209">à°—à°¡à±à°µà± à°®à±à°—ింపౠనెల</translation>
<translation id="3479539252931486093">ఊహించని విధంగా ఇది సంభవించిందా? <ph name="BEGIN_LINK" />మాకౠతెలియజేయండి<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">ఇపà±à°ªà±à°¡à± కాదà±</translation>
<translation id="348000606199325318">à°•à±à°°à°¾à°·à± ID <ph name="CRASH_LOCAL_ID" /> (సరà±à°µà°°à± ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">మేమౠపà±à°°à°¸à±à°¤à±à°¤à°‚ మీ తలà±à°²à°¿/తండà±à°°à°¿à°¨à°¿ సంపà±à°°à°¦à°¿à°‚చలేకపోయామà±. దయచేసి మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="3528171143076753409">సరà±à°µà°°à± యొకà±à°• à°ªà±à°°à°®à°¾à°£ పతà±à°°à°‚ నమà±à°®à°¦à°—ినది కాదà±.</translation>
-<translation id="3538531656504267329">à°—à°¡à±à°µà± à°®à±à°—ింపౠసంవతà±à°¸à°°à°‚ చెలà±à°²à°¦à±</translation>
<translation id="3539171420378717834">à°ˆ పరికరంలో à°ˆ కారà±à°¡à± కాపీని ఉంచà±</translation>
<translation id="3542684924769048008">దీని కోసం పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± ఉపయోగించండి:</translation>
<translation id="3549644494707163724">మీ à°¸à±à°µà°‚à°¤ సమకాలీకరణ రహసà±à°¯ పదబంధంతో సమకాలీకరించబడిన డేటా మొతà±à°¤à°¾à°¨à±à°¨à°¿ à°—à±à°ªà±à°¤à±€à°•à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">వివరాలనౠదాచిపెటà±à°Ÿà±</translation>
<translation id="3587482841069643663">మొతà±à°¤à°‚</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°¯à±à°¯à±‡ à°—à°¡à±à°µà± à°®à±à°—ింపౠతేదీని నమోదౠచేయండి</translation>
<translation id="36224234498066874">à°¬à±à°°à±Œà°œà°¿à°‚గౠడేటానౠకà±à°²à°¿à°¯à°°à± చెయà±à°¯à°¿...</translation>
<translation id="362276910939193118">పూరà±à°¤à°¿ à°šà°°à°¿à°¤à±à°°à°¨à± చూపించà±</translation>
<translation id="3623476034248543066">విలà±à°µà°¨à± చూపండి</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">పాసà±â€Œà°µà°°à±à°¡à±:</translation>
<translation id="3696411085566228381">à°à°¦à±€ కాదà±</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">à°·à°¿à°ªà±à°ªà°¿à°‚గౠపదà±à°§à°¤à±à°²à± మరియౠఆవశà±à°¯à°•à°¾à°²à°¨à± చూడటానికి à°·à°¿à°ªà±à°ªà°¿à°‚à°—à± à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
<translation id="370665806235115550">లోడౠఅవà±à°¤à±‹à°‚ది...</translation>
<translation id="3712624925041724820">లైసెనà±à°¸à±â€Œà°²à± అయిపోయాయి</translation>
<translation id="3714780639079136834">మొబైలౠడేటా లేదా Wi-Fiని ఆనౠచేయడం</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">మీరౠకాపీ చేసిన లింకà±</translation>
<translation id="375403751935624634">సరà±à°µà°°à± లోపం వలà±à°² à°…à°¨à±à°µà°¾à°¦à°‚ విఫలమైంది.</translation>
<translation id="3759461132968374835">మీకౠఇటీవల నివేదించిన à°•à±à°°à°¾à°·à±â€Œà°²à± లేవà±. à°•à±à°°à°¾à°·à±â€Œ నివేదన నిలిపివేసినపà±à°¡à± à°à°°à±à°ªà°¡à±‡ à°•à±à°°à°¾à°·à±â€Œà°²à± ఇకà±à°•à°¡ కనిపించవà±.</translation>
+<translation id="3787705759683870569">à°—à°¡à±à°µà± à°®à±à°—ింపౠ<ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">మీరౠపà±à°°à°¾à°•à±à°¸à±€ సరà±à°µà°°à±â€Œà°¨à± ఉపయోగిసà±à°¤à±‡...</translation>
<translation id="3828924085048779000">ఖాళీ పాసà±â€Œà°«à±à°°à±‡à°œà± à°…à°¨à±à°®à°¤à°¿à°‚చబడదà±.</translation>
<translation id="3845539888601087042">మీరౠసైనà±-ఇనౠచేసిన పరికరాల à°¨à±à°‚à°¡à°¿ à°šà°°à°¿à°¤à±à°°à°¨à± చూపà±à°¤à±‹à°‚ది. <ph name="BEGIN_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">అమెరికనౠఎకà±à°¸à±â€Œà°ªà±à°°à±†à°¸à±</translation>
<translation id="4169947484918424451">Chromium à°ˆ కారà±à°¡à±â€Œà°¨à± సేవౠచేయాలని మీరౠకోరà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
<translation id="4171400957073367226">ధృవీకరణ సంతకం చెలà±à°²à°¦à±</translation>
-<translation id="4176463684765177261">ఆపివేయబడింది</translation>
<translation id="4196861286325780578">&amp;తరలించడానà±à°¨à°¿ à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ చేయి</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ఫైరà±â€Œà°µà°¾à°²à± మరియౠయాంటీవైరసౠకానà±à°«à°¿à°—రేషనà±â€Œà°²à°¨à± తనిఖీ చేయడం<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{à°à°¦à±€ లేదà±}=1{1 à°…à°¨à±à°µà°°à±à°¤à°¨à°‚ ($1)}=2{2 à°…à°¨à±à°µà°°à±à°¤à°¨à°¾à°²à± ($1, $2)}other{# à°…à°¨à±à°µà°°à±à°¤à°¨à°¾à°²à± ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">శోధన ఫలితాలà±</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> మీ లాగినౠపà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ ఆమోదించలేదౠలేదా à°à°¦à±€ అందించి ఉండకపోవచà±à°šà±.</translation>
<translation id="443673843213245140">à°ªà±à°°à°¾à°•à±à°¸à±€à°¨à°¿ ఉపయోగించడం ఆపివేయబడింది కానీ à°¸à±à°ªà°·à±à°Ÿà°®à±ˆà°¨ à°ªà±à°°à°¾à°•à±à°¸à±€ కానà±à°«à°¿à°—రేషనౠపేరà±à°•à±Šà°¨à°¬à°¡à°¿à°‚ది.</translation>
-<translation id="4446242550670694251">ఇపà±à°ªà±à°¡à± మీరౠపà±à°°à±ˆà°µà±‡à°Ÿà±â€Œà°—à°¾ à°¬à±à°°à±Œà°œà± చేయవచà±à°šà±, à°…à°ªà±à°ªà±à°¡à± à°ˆ పరికరానà±à°¨à°¿ ఉపయోగించే ఇతర à°µà±à°¯à°•à±à°¤à±à°²à°•à± మీ కారà±à°¯à°¾à°šà°°à°£ కనిపించదà±.</translation>
<translation id="4492190037599258964"><ph name="SEARCH_STRING" />' కోసం శోధన ఫలితాలà±</translation>
<translation id="4506176782989081258">ధృవీకరణ లోపం: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">సిసà±à°Ÿà°®à± నిరà±à°µà°¾à°¹à°•à±à°¡à°¿à°¨à°¿ సంపà±à°°à°¦à°¿à°‚à°šà°¡à°‚</translation>
<translation id="450710068430902550">నిరà±à°µà°¾à°¹à°•à±à°¡à°¿à°¤à±‹ భాగసà±à°µà°¾à°®à±à°¯à°‚</translation>
+<translation id="4515275063822566619">కారà±à°¡à±â€Œà°²à± మరియౠచిరà±à°¨à°¾à°®à°¾à°²à± Chrome మరియౠమీ Google ఖాతా (<ph name="ACCOUNT_EMAIL" />) à°¨à±à°‚à°¡à°¿ పొందినవి. మీరౠ<ph name="BEGIN_LINK" />సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à±<ph name="END_LINK" />లో వాటిని నిరà±à°µà°¹à°¿à°‚చవచà±à°šà±.</translation>
<translation id="4522570452068850558">వివరాలà±</translation>
<translation id="4558551763791394412">మీ పొడిగింపà±à°²à°¨à± నిలిపివేయడం à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="457875822857220463">బటà±à°µà°¾à°¡à°¾</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">పేజీకి తగినటà±à°²à± అమరà±à°šà±</translation>
<translation id="483020001682031208">చూపడానికి సహజసిదà±à°§ వెబౠపేజీలేవీ లేవà±</translation>
<translation id="4850886885716139402">వీకà±à°·à°£</translation>
+<translation id="4854362297993841467">à°ˆ బటà±à°µà°¾à°¡à°¾ పదà±à°§à°¤à°¿ à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±. వేరే పదà±à°§à°¤à°¿à°¨à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="4858792381671956233">à°ˆ సైటà±â€Œà°¨à± సందరà±à°¶à°¿à°‚చడానికి à°…à°¨à±à°®à°¤à°¿à°‚చమని కోరà±à°¤à±‚ మీ తలà±à°²à°¿à°¦à°‚à°¡à±à°°à±à°²à°•à± à°…à°­à±à°¯à°°à±à°¥à°¨ పంపారà±</translation>
<translation id="4880827082731008257">శోధన à°šà°°à°¿à°¤à±à°°</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">à°ˆ పేజీ తెలియని భాష à°¨à±à°‚à°¡à°¿ <ph name="LANGUAGE_LANGUAGE" />à°•à± à°…à°¨à±à°µà°¦à°¿à°‚చబడింది</translation>
<translation id="4923459931733593730">చెలà±à°²à°¿à°‚à°ªà±</translation>
<translation id="4926049483395192435">à°–à°šà±à°šà°¿à°¤à°‚à°—à°¾ పేరà±à°•à±Šà°¨à°¾à°²à°¿.</translation>
-<translation id="4941291666397027948">* ఆవశà±à°¯à°• ఫీలà±à°¡à±â€Œà°¨à± సూచిసà±à°¤à±à°‚ది</translation>
<translation id="495170559598752135">à°šà°°à±à°¯à°²à±</translation>
<translation id="4958444002117714549">జాబితానౠవిసà±à°¤à°°à°¿à°‚à°šà±</translation>
<translation id="4962322354953122629">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపించà±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ Chrome విశà±à°µà°¸à°¿à°‚చలేదà±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—రౠచేయడం వలన లేదా దాడిచేసే à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగించడం వలన ఇలా జరిగి ఉండవచà±à°šà±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">సరికాని పాసà±â€Œà°µà°°à±à°¡à±</translation>
<translation id="5056549851600133418">మీ కోసం కథనాలà±</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />à°ªà±à°°à°¾à°•à±à°¸à±€ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± తనిఖీ చేయడం<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{à°•à±à°•à±à°•à±€à°²à± లేవà±}=1{1 సైటౠకà±à°•à±à°•à±€à°²à°¨à± ఉపయోగిసà±à°¤à±‹à°‚ది. }other{# సైటà±â€Œà°²à± à°•à±à°•à±à°•à±€à°²à°¨à± ఉపయోగిసà±à°¤à±à°¨à±à°¨à°¾à°¯à°¿. }}</translation>
<translation id="5087286274860437796">à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ చెలà±à°²à°¦à±.</translation>
<translation id="5087580092889165836">కారà±à°¡à±â€Œà°¨à± జోడించà±</translation>
<translation id="5089810972385038852">రాషà±à°Ÿà±à°°à°‚</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">చూపించà±</translation>
<translation id="5308689395849655368">à°•à±à°°à°¾à°·à± నివేదిక నిలిపివెయà±à°¯à°¬à°¡à°¿à°‚ది.</translation>
<translation id="5317780077021120954">సేవౠచేయి</translation>
-<translation id="5326702247179446998">à°¸à±à°µà±€à°•à°°à±à°¤ అవసరం</translation>
<translation id="5327248766486351172">పేరà±</translation>
<translation id="5337705430875057403"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />పై దాడి చేసే à°µà±à°¯à°•à±à°¤à±à°²à± సాఫà±à°Ÿà±â€Œà°µà±‡à°°à±â€Œà°¨à± ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేసà±à°•à±‹à°®à°¨à°¡à°‚ లేదా మీ à°µà±à°¯à°•à±à°¤à°¿à°—à°¤ సమాచారానà±à°¨à°¿ (ఉదాహరణకà±, పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à±, ఫోనౠనంబరà±â€Œà°²à± లేదా à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à±â€Œà°²à±) వెలà±à°²à°¡à°¿à°‚చమనడం వంటి à°ªà±à°°à°®à°¾à°¦à°•à°°à°®à±ˆà°¨ పనà±à°²à± చేయమని à°ªà±à°°à°¿à°•à±Šà°²à±à°ªà±‡à°²à°¾ మిమà±à°®à°²à±à°¨à°¿ మాయ చేయవచà±à°šà±.</translation>
-<translation id="53553865750799677">పికపౠచిరà±à°¨à°¾à°®à°¾à°•à± మదà±à°¦à°¤à± లేదà±. మరొక à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
<translation id="5359637492792381994">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపించà±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; à°ˆ సమయంలో దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ చెలà±à°²à°¦à±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—రౠచేయడం వలన లేదా దాడిచేసే à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగించడం వలన ఇలా జరిగి ఉండవచà±à°šà±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">విధాన సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± నిలà±à°µ చేయడంలో విఫలమైంది</translation>
<translation id="5386426401304769735">à°ˆ సైటౠపà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ గొలà±à°¸à±à°²à±‹ SHA-1 ఉపయోగించి సంతకం చేసిన à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ ఉంది.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102"><ph name="SITE" />లో పొందà±à°ªà°°à°¿à°šà°¿à°¨ పేజీ ఇలా చెబà±à°¤à±‹à°‚ది:</translation>
<translation id="5556459405103347317">రీలోడà±</translation>
<translation id="5565735124758917034">సకà±à°°à°¿à°¯à°‚</translation>
+<translation id="5571083550517324815">à°ˆ à°šà°¿à°°à±à°¨à°¾à°®à°¾ à°¨à±à°‚à°¡à°¿ పికపౠచేసà±à°•à±‹à°µà°¡à°‚ సాధà±à°¯à°‚ కాదà±. వేరే à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
<translation id="5572851009514199876">దయచేసి Chromeని à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°¿, దానికి సైనౠఇనౠచేయండి, à°…à°ªà±à°ªà±à°¡à± మీకౠఈ సైటà±â€Œà°¨à± à°ªà±à°°à°¾à°ªà±à°¯à°¤ చేయడానికి à°…à°¨à±à°®à°¤à°¿ ఉందో లేదో Chrome తనిఖీ చేయగలదà±.</translation>
-<translation id="5575380383496039204">బటà±à°µà°¾à°¡à°¾ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°•à± మదà±à°¦à°¤à± లేదà±. మరొక à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
<translation id="5580958916614886209">మీ à°—à°¡à±à°µà± à°®à±à°—ింపౠనెలనౠతనిఖీ చేసి, ఆపై మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿</translation>
<translation id="560412284261940334">నిరà±à°µà°¹à°£à°•à± మదà±à°¦à°¤à± లేదà±</translation>
<translation id="5610142619324316209">కనెకà±à°·à°¨à±â€Œà°¨à± తనిఖీ చేయడం</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">à°ˆ వెబà±â€â€Œà°¸à±ˆà°Ÿà± యొకà±à°• à°—à±à°°à±à°¤à°¿à°‚పౠనిరà±à°¥à°¾à°°à°¿à°‚చబడలేదà±.</translation>
<translation id="5720705177508910913">à°ªà±à°°à°¸à±à°¤à±à°¤ వినియోగదారà±</translation>
<translation id="5732392974455271431">మీ తలà±à°²à°¿à°¦à°‚à°¡à±à°°à±à°²à± దీనà±à°¨à°¿ మీ కోసం à°…à°¨à±â€Œà°¬à±à°²à°¾à°•à± చేయగలరà±</translation>
-<translation id="57586589942790530">చెలà±à°²à°¨à°¿ కారà±à°¡à± నంబరà±</translation>
+<translation id="5763042198335101085">చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°¯à±à°¯à±‡ ఇమెయిలౠచిరà±à°¨à°¾à°®à°¾à°¨à°¿ నమోదౠచేయండి</translation>
+<translation id="5765072501007116331">బటà±à°µà°¾à°¡à°¾ పదà±à°§à°¤à±à°²à± మరియౠఅవసరాలనౠచూడాలంటే, à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="5784606427469807560">మీ కారà±à°¡à±â€Œà°¨à± నిరà±à°§à°¾à°°à°¿à°‚చడంలో సమసà±à°¯ à°à°°à±à°ªà°¡à°¿à°‚ది. మీ ఇంటరà±à°¨à±†à°Ÿà± కనెకà±à°·à°¨à±â€Œà°¨à°¿ తనిఖీ చేసి, ఆపై మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="5785756445106461925">అలాగే, à°ˆ పేజీలో à°¸à±à°°à°•à±à°·à°¿à°¤à°‚ కాని ఇతర వనరà±à°²à± ఉనà±à°¨à°¾à°¯à°¿. à°ˆ వనరà±à°²à°¨à± బదిలీ చేసà±à°¤à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± ఇతరà±à°²à± చూడగలరౠమరియౠదాడికి పాలà±à°ªà°¡à±‡à°µà°¾à°°à± పేజీ రూపానà±à°¨à°¿ మారà±à°šà±‡à°²à°¾ వీటిని సవరించగలరà±.</translation>
<translation id="5786044859038896871">మీరౠమీ కారà±à°¡à± సమాచారం పూరించాలనà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">à°ˆ సైటà±â€Œà°¨à± చేరà±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¾à°®à±</translation>
<translation id="5869522115854928033">సేవౠచేసిన పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à±</translation>
<translation id="5872918882028971132">తలà±à°²à°¿/తండà±à°°à°¿ సూచనలà±</translation>
-<translation id="587760065310675640">à°·à°¿à°ªà±à°ªà°¿à°‚à°—à± à°šà°¿à°°à±à°¨à°¾à°®à°¾à°•à± మదà±à°¦à°¤à± లేదà±. మరొక à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
<translation id="5901630391730855834">పసà±à°ªà±</translation>
-<translation id="59174027418879706">à°ªà±à°°à°¾à°°à°‚భించబడింది</translation>
<translation id="5926846154125914413">మీరౠకొనà±à°¨à°¿ సైటà±â€Œà°² à°¨à±à°‚à°¡à°¿ à°ªà±à°°à±€à°®à°¿à°¯à°‚ కంటెంటà±â€Œà°•à°¿ à°ªà±à°°à°¾à°ªà±à°¯à°¤à°¨à± కోలà±à°ªà±‹à°µà°šà±à°šà±.</translation>
<translation id="5959728338436674663">హానికరమైన à°…à°¨à±à°µà°°à±à°¤à°¨à°¾à°²à± మరియౠసైటà±â€Œà°²à°¨à± à°—à±à°°à±à°¤à°¿à°‚చడంలో సహాయపడటానికి కొంత <ph name="BEGIN_WHITEPAPER_LINK" />సిసà±à°Ÿà°®à± సమాచారానà±à°¨à°¿ మరియౠపేజీ కంటెంటà±<ph name="END_WHITEPAPER_LINK" />నౠGoogleà°•à± à°¸à±à°µà°¯à°‚చాలకంగా పంపà±à°¤à±à°‚ది. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">వారం</translation>
<translation id="5967867314010545767">à°šà°°à°¿à°¤à±à°° à°¨à±à°‚à°¡à°¿ తీసివేయి</translation>
<translation id="5975083100439434680">దూరంగా జూమౠచెయà±à°¯à°¿</translation>
+<translation id="598637245381783098">చెలà±à°²à°¿à°‚పౠఆపà±â€Œà°¨à°¿ తెరవడం సాధà±à°¯à°‚ కాదà±</translation>
<translation id="5989320800837274978">à°¸à±à°¥à°¿à°° à°ªà±à°°à°¾à°•à±à°¸à±€ సరà±à°µà°°à±â€Œà°²à± లేదా à°’à°• .pac à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà± URL పేరà±à°•à±Šà°¨à°¬à°¡à°²à±‡à°¦à±.</translation>
<translation id="5990559369517809815">సరà±à°µà°°à±â€Œà°•à± à°…à°­à±à°¯à°°à±à°¥à°¨à°²à°¨à± à°’à°• పొడిగింపౠబà±à°²à°¾à°•à± చేయబడà±à°¡à°¾à°¯à°¿.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Chrome à°¨à±à°‚à°¡à°¿ కారà±à°¡à± మరియౠచిరà±à°¨à°¾à°®à°¾ ఎంపికలౠఉనà±à°¨à°¾à°¯à°¿. మీరౠవీటిని <ph name="BEGIN_LINK" />సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²<ph name="END_LINK" />లో నిరà±à°µà°¹à°¿à°‚చగలరà±.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{పేజీ 1}other{పేజీ #}}</translation>
<translation id="6017514345406065928">ఆకà±à°ªà°šà±à°š</translation>
+<translation id="6027201098523975773">పేరà±à°¨à°¿ నమోదౠచేయండి</translation>
<translation id="6040143037577758943">మూసివేయి</translation>
-<translation id="604124094241169006">à°¸à±à°µà°¯à°‚చాలకంగా</translation>
<translation id="6042308850641462728">మరింత</translation>
<translation id="6060685159320643512">జాగà±à°°à°¤à±à°¤, à°ˆ à°ªà±à°°à°¯à±‹à°—ాలౠవిఫలం కావచà±à°šà±</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{à°à°¦à±€ లేదà±}=1{1}other{#}}</translation>
@@ -543,9 +552,10 @@
లేదా ఇతర నెటà±â€Œà°µà°°à±à°•à± పరికరాలనౠరీబూటౠచేయండి.</translation>
<translation id="614940544461990577">ఇలా చేసి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿:</translation>
<translation id="6151417162996330722">సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ చెలà±à°²à±à°¬à°¾à°Ÿà± à°µà±à°¯à°µà°§à°¿ చాలా à°Žà°•à±à°•à±à°µ కాలం ఉంది.</translation>
-<translation id="615643356032862689">డౌనà±â€Œà°²à±‹à°¡à± చేయబడిన ఫైలà±â€Œà°²à± మరియౠబà±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à± అలాగే ఉంచబడతాయి.</translation>
+<translation id="6157877588268064908">రవాణా పదà±à°§à°¤à±à°²à± మరియౠఅవసరాలనౠచూడాలంటే, à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="6165508094623778733">మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="6177128806592000436">à°ˆ సైటà±â€Œà°•à°¿ మీ కనెకà±à°·à°¨à± à°¸à±à°°à°•à±à°·à°¿à°¤à°‚à°—à°¾ లేదà±</translation>
+<translation id="6184817833369986695">(బృందం: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">మీ ఇంటరà±à°¨à±†à°Ÿà± కనెకà±à°·à°¨à±â€Œà°¨à± తనిఖీ చేయండి</translation>
<translation id="6218753634732582820">Chromium à°¨à±à°‚à°¡à°¿ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± తీసివేయాలా?</translation>
<translation id="6251924700383757765">గోపà±à°¯à°¤à°¾ విధానం</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;మళà±à°²à±€ à°•à±à°°à°®à°‚ చేయడానà±à°¨à°¿ à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ చేయి</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à±</translation>
<translation id="6264485186158353794">à°­à°¦à±à°°à°¤à°•à± తిరిగి వెళà±à°³à±</translation>
+<translation id="6276112860590028508">మీ పఠన జాబితాలో ఉనà±à°¨ పేజీలౠఇకà±à°•à°¡ కనిపిసà±à°¤à°¾à°¯à°¿</translation>
+<translation id="6280223929691119688">à°ˆ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°•à± బటà±à°µà°¾à°¡à°¾ చేయడం సాధà±à°¯à°‚ కాదà±. వేరే à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
<translation id="6282194474023008486">పోసà±à°Ÿà°²à± కోడà±</translation>
<translation id="6290238015253830360">మీకౠసూచించిన కథనాలౠఇకà±à°•à°¡ కనిపిసà±à°¤à°¾à°¯à°¿</translation>
<translation id="6305205051461490394"><ph name="URL" />ని చేరà±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¾à°®à±.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°°à°¦à±à°¦à± చెయà±à°¯à°¬à°¡à°¿à°‚దా అని తనిఖీ చెయà±à°¯à°¡à°‚ సాధà±à°¯à°‚ కాలేదà±.</translation>
<translation id="6433490469411711332">సంపà±à°°à°¦à°¿à°‚పౠసమాచారానà±à°¨à°¿ సవరించండి</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> కనెకà±à°Ÿà± కావడానికి నిరాకరించింది.</translation>
-<translation id="6443118737398455446">à°—à°¡à±à°µà± à°®à±à°—ింపౠతేదీ చెలà±à°²à°¦à±</translation>
<translation id="6446608382365791566">మరింత సమాచారానà±à°¨à°¿ జోడించండి</translation>
<translation id="6451458296329894277">ఫారమౠపà±à°¨à°ƒà°¸à°®à°°à±à°ªà°£à°¨à± నిరà±à°¥à°¾à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
<translation id="6456339708790392414">మీ చెలà±à°²à°¿à°‚à°ªà±</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపించà±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ ఉపసంహరించబడింది. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—రౠచేయడం వలన లేదా దాడిచేసే à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగించడం వలన ఇలా జరిగి ఉండవచà±à°šà±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">పరికర విధానాలà±</translation>
<translation id="6477321094435799029">Chrome à°ˆ పేజీలో అసాధారణ కోడà±â€Œà°¨à± à°—à±à°°à±à°¤à°¿à°‚చింది మరియౠమీ à°µà±à°¯à°•à±à°¤à°¿à°—à°¤ సమాచారం (ఉదాహరణకà±, పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à±, ఫోనౠనంబరà±â€Œà°²à± మరియౠకà±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à±â€Œà°²à±) à°°à°•à±à°·à°¿à°‚చడానికి దానà±à°¨à°¿ à°¬à±à°²à°¾à°•à± చేసింది.</translation>
-<translation id="6477460825583319731">ఇమెయిలౠచిరà±à°¨à°¾à°®à°¾ చెలà±à°²à°¦à±</translation>
<translation id="6489534406876378309">à°•à±à°°à°¾à°·à±â€Œà°²à°¨à± à°…à°ªà±â€Œà°²à±‹à°¡à± చేయడానà±à°¨à°¿ à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°‚à°¡à°¿</translation>
<translation id="6508722015517270189">Chromeనౠపà±à°¨à°ƒà°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°‚à°¡à°¿</translation>
-<translation id="6525462735697194615">à°—à°¡à±à°µà± à°®à±à°—ింపౠనెల చెలà±à°²à°¦à±</translation>
<translation id="6529602333819889595">&amp;తొలగించడానà±à°¨à°¿ à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ చేయి</translation>
<translation id="6534179046333460208">à°ªà±à°°à°¤à±à°¯à°•à±à°· వెబౠసూచనలà±</translation>
<translation id="6550675742724504774">ఎంపికలà±</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> శోధన</translation>
<translation id="6644283850729428850">à°ˆ విధానం విలà±à°µ తగà±à°—ించబడింది.</translation>
<translation id="6652240803263749613">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపించà±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ మీ à°•à°‚à°ªà±à°¯à±‚టరౠఆపరేటింగౠసిసà±à°Ÿà°®à± విశà±à°µà°¸à°¿à°‚చలేదà±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—రౠచేయడం వలన లేదా దాడిచేసే à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగించడం వలన ఇలా జరిగి ఉండవచà±à°šà±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">à°† à°·à°¿à°ªà±à°ªà°¿à°‚గౠఎంపిక à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±. వేరొక ఎంపికనౠపà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="6671697161687535275">Chromium à°¨à±à°‚à°¡à°¿ ఫారమౠసూచననౠతీసివేయాలా?</translation>
<translation id="6685834062052613830">సైనౠఅవà±à°Ÿà± చేసి, సెటపà±â€Œà°¨à± పూరà±à°¤à°¿ చేయండి</translation>
<translation id="6710213216561001401">à°®à±à°¨à±à°ªà°Ÿà°¿</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">à°ªà±à°°à°¾à°•à±à°¸à±€ సరà±à°µà°°à±â€Œà°²à±‹ à°à°¦à±‹ తపà±à°ªà± ఉంది లేదా à°šà°¿à°°à±à°¨à°¾à°®à°¾ సరైనది కాదà±.</translation>
<translation id="6727102863431372879">సెటౠచెయà±à°¯à°¿</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{à°à°¦à±€ లేదà±}=1{1 అంశం}other{# అంశాలà±}}</translation>
-<translation id="6743044928064272573">పికపౠఎంపిక</translation>
<translation id="674375294223700098">తెలియని సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ లోపం.</translation>
<translation id="6753269504797312559">విధానం విలà±à°µ</translation>
<translation id="6757797048963528358">మీ పరికరం నిదà±à°°à°¾à°µà°¸à±à°¥à°•à°¿ వెళà±à°²à°¿à°‚ది.</translation>
<translation id="6778737459546443941">మీ తలà±à°²à°¿/తండà±à°°à°¿ దీనà±à°¨à°¿ ఇంకా ఆమోదించలేదà±</translation>
<translation id="6810899417690483278">à°…à°¨à±à°•à±‚లీకరణ ID</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">à°ªà±à°°à°¾à°‚తాల డేటానౠలోడౠచేయడం విఫలమైంది</translation>
<translation id="6831043979455480757">à°…à°¨à±à°µà°¦à°¿à°‚à°šà±</translation>
<translation id="6839929833149231406">à°ªà±à°°à°¾à°‚తం</translation>
<translation id="6874604403660855544">&amp;జోడించడానà±à°¨à°¿ à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ చేయి</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">మీ కారà±à°¡à± నిరà±à°§à°¾à°°à°¿à°‚చబడింది</translation>
<translation id="6897140037006041989">వినియోగదారౠపà±à°°à°¤à°¿à°¨à°¿à°§à°¿</translation>
<translation id="6915804003454593391">వినియోగదారà±:</translation>
+<translation id="6948701128805548767">పికపౠపదà±à°§à°¤à±à°²à± మరియౠఅవసరాలనౠచూడాలంటే, à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="6957887021205513506">సరà±à°µà°°à± ధృవీకరణ పతà±à°°à°‚ చెలà±à°²à°¦à±.</translation>
<translation id="6965382102122355670">సరే</translation>
<translation id="6965978654500191972">పరికరం</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">రెండౠసà±à°¥à°¿à°° à°ªà±à°°à°¾à°•à±à°¸à±€ సరà±à°µà°°à±à°²à± మరియౠఒక .pac à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà± URL పేరà±à°•à±Šà°¨à°¬à°¡à±à°¡à°¾à°¯à°¿.</translation>
<translation id="6989763994942163495">à°…à°§à±à°¨à°¾à°¤à°¨ సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± చూపించà±...</translation>
<translation id="7000990526846637657">à°šà°°à°¿à°¤à±à°° నమోదà±à°²à± à°à°µà±€ à°•à°¨à±à°—ొనబడలేదà±</translation>
-<translation id="7001663382399377034">à°¸à±à°µà±€à°•à°°à±à°¤à°¨à± జోడించండి</translation>
<translation id="7009986207543992532">మీరౠ<ph name="DOMAIN" />à°•à°¿ కనెకà±à°Ÿà± కావడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚చారà±, కానీ సరà±à°µà°°à± అందించిన à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°—à°¡à±à°µà± కాలం విశà±à°µà°¸à°¿à°‚చలేనంత à°Žà°•à±à°•à±à°µ à°µà±à°¯à°µà°§à°¿ ఉంది. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">చైనా యూనియనౠపే</translation>
<translation id="7012372675181957985">మీ Google ఖాతా <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />లో ఇతర à°¬à±à°°à±Œà°œà°¿à°‚à°—à± à°šà°°à°¿à°¤à±à°° రూపాలౠఉండవచà±à°šà±.</translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">పాతవి</translation>
<translation id="7090678807593890770"><ph name="LINK" /> కోసం Googleలో శోధించండి</translation>
<translation id="7119414471315195487">ఇతర à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à± లేదా à°ªà±à°°à±‹à°—à±à°°à°¾à°®à±â€Œà°²à°¨à± మూసివేయండి</translation>
+<translation id="7129409597930077180">à°ˆ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°•à± రవాణా చేయడం సాధà±à°¯à°‚ కాదà±. వేరే à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
+<translation id="7138472120740807366">బటà±à°µà°¾à°¡à°¾ పదà±à°§à°¤à°¿</translation>
<translation id="7139724024395191329">ఎమిరేటà±</translation>
<translation id="7155487117670177674">చెలà±à°²à°¿à°‚పౠసà±à°°à°•à±à°·à°¿à°¤à°‚ కాదà±</translation>
<translation id="7179921470347911571">ఇపà±à°ªà±à°¡à±‡ à°ªà±à°¨à°ƒà°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà±</translation>
<translation id="7180611975245234373">రీఫà±à°°à±†à°·à± చేయి</translation>
<translation id="7182878459783632708">విధానాలనౠసెటౠచేయలేదà±</translation>
<translation id="7186367841673660872">à°ˆ పేజీ<ph name="ORIGINAL_LANGUAGE" />à°¨à±à°‚à°¡à°¿<ph name="LANGUAGE_LANGUAGE" />à°•à± à°…à°¨à±à°µà°¦à°¿à°‚చబడింది</translation>
+<translation id="7192203810768312527"><ph name="SIZE" />ని ఖాళీ చేసà±à°¤à±à°‚ది. మీ తదà±à°ªà°°à°¿ సందరà±à°¶à°¨à°²à±‹ కొనà±à°¨à°¿ సైటà±â€Œà°²à± మరింత నెమà±à°®à°¦à°¿à°—à°¾ లోడౠకావచà±à°šà±.</translation>
<translation id="719464814642662924">వీసా</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°¾à°²à°•à± à°•à°Ÿà±à°Ÿà±à°¬à°¡à°¿ లేదà±.</translation>
<translation id="721197778055552897">à°ˆ సమసà±à°¯ à°—à±à°°à°¿à°‚à°šà°¿ <ph name="BEGIN_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿ <ph name="END_LINK" />.</translation>
@@ -675,7 +686,6 @@
<translation id="7424977062513257142">à°ˆ వెబà±â€Œà°ªà±‡à°œà±€à°²à±‹à°¨à°¿ పొందà±à°ªà°°à°¿à°šà°¿à°¨ పేజీ ఇలా చెబà±à°¤à±‹à°‚ది:</translation>
<translation id="7441627299479586546">చెలà±à°²à°¨à°¿ విధాన విషయం</translation>
<translation id="7444046173054089907">à°ˆ సైటౠబà±à°²à°¾à°•à± చేయబడింది</translation>
-<translation id="7444238235002594607">పికపౠపదà±à°§à°¤à±à°²à± మరియౠఆవశà±à°¯à°•à°¾à°²à°¨à± చూడటానికి పికపౠచిరà±à°¨à°¾à°®à°¾à°¨à± à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
<translation id="7445762425076701745">మీరౠకనెకà±à°Ÿà± చేసిన సరà±à°µà°°à± యొకà±à°• à°—à±à°°à±à°¤à°¿à°‚పౠపూరà±à°¤à°¿à°—à°¾ ధృవీకరించబడలేదà±. మీరౠదీని యొకà±à°• యాజమానà±à°¯à°¾à°¨à±à°¨à°¿ ధృవీకరించడానికి అంతరà±à°—à°¤ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ అధికారికి మరొక దాని లేని మీ నెటà±â€Œà°µà°°à±à°•à±â€Œà°²à±‹ మాతà±à°°à°®à±‡ చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°¯à±à°¯à±‡ పేరà±à°¨à± ఉపయోగించి సరà±à°µà°°à±â€Œà°•à°¿ కనెకà±à°Ÿà± చేసారà±. కొనà±à°¨à°¿ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ అధికారà±à°²à± సంబంధంలేని à°ˆ పేరà±à°²à°•à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ జారీ చేసà±à°¤à°¾à°°à±, మీరౠసరైన వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°•à°¿ మరియౠఅటాకరà±â€Œà°•à°¿ కనెకà±à°Ÿà± చేసారా అని నిరà±à°§à°¾à°°à°¿à°‚చడానికి వేరే మారà±à°—à°‚ లేదà±.</translation>
<translation id="7451311239929941790">à°ˆ సమసà±à°¯ à°—à±à°°à°¿à°‚à°šà°¿ <ph name="BEGIN_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LINK" />.</translation>
<translation id="7460163899615895653">ఇతర పరికరాలà±à°²à±‹ మీ ఇటీవలి à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à± ఇకà±à°•à°¡ కనిపిసà±à°¤à°¾à°¯à°¿</translation>
@@ -719,6 +729,7 @@
<translation id="7755287808199759310">మీ తలà±à°²à°¿/తండà±à°°à°¿ దీనà±à°¨à°¿ మీ కోసం à°…à°¨à±â€Œà°¬à±à°²à°¾à°•à± చేయగలరà±</translation>
<translation id="7758069387465995638">ఫైరà±â€Œà°µà°¾à°²à± లేదా యాంటీవైరసౠసాఫà±à°Ÿà±â€Œà°µà±‡à°°à± కనెకà±à°·à°¨à±â€Œà°¨à± à°¬à±à°²à°¾à°•à± చేసి ఉండవచà±à°šà±.</translation>
<translation id="7761701407923456692">URLతో సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ సరిపోలడం లేదà±.</translation>
+<translation id="7763386264682878361">చెలà±à°²à°¿à°‚పౠమానిఫెసà±à°Ÿà± à°…à°¨à±à°µà°¯ నియమం</translation>
<translation id="7764225426217299476">à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± జోడించà±</translation>
<translation id="777702478322588152">అధికారిక నివాసం</translation>
<translation id="7791543448312431591">జోడించà±</translation>
@@ -732,6 +743,7 @@
<translation id="785549533363645510">అయితే, మీరౠఅదృశà±à°¯à°‚à°—à°¾ ఉండరà±. à°…à°œà±à°žà°¾à°¤à°‚లోకి వెళà±à°²à°¡à°‚ వలన మీ à°¬à±à°°à±Œà°œà°¿à°‚గౠమీ యజమానికి, మీ ఇంటరà±à°¨à±†à°Ÿà± సేవా à°ªà±à°°à°¦à°¾à°¤à°•à± లేదా మీరౠసందరà±à°¶à°¿à°‚చే వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°²à°•à± కనిపించకà±à°‚à°¡à°¾ దాచబడదà±.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">మీ CVCని తనిఖీ చేసి, మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿</translation>
+<translation id="79338296614623784">చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°¯à±à°¯à±‡ ఫోనౠనంబరà±â€Œà°¨à°¿ నమోదౠచేయండి</translation>
<translation id="7935318582918952113">DOM à°¡à°¿à°¸à±à°Ÿà°¿à°²à±à°²à°°à±</translation>
<translation id="7938958445268990899">సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ ఇంకా చెలà±à°²à±à°¬à°¾à°Ÿà± కాదà±.</translation>
<translation id="7942349550061667556">à°Žà°°à±à°ªà±</translation>
@@ -751,6 +763,7 @@
<translation id="8088680233425245692">కథనానà±à°¨à°¿ వీకà±à°·à°¿à°‚చడంలో విఫలమైంది.</translation>
<translation id="8089520772729574115">1 MB కంటే తకà±à°•à±à°µ</translation>
<translation id="8091372947890762290">సకà±à°°à°¿à°¯à°‚ సరà±à°µà°°à±â€Œà°²à±‹ పెండింగà±â€Œà°²à±‹ ఉంది</translation>
+<translation id="8118489163946903409">చెలà±à°²à°¿à°‚పౠపదà±à°§à°¤à°¿</translation>
<translation id="8131740175452115882">నిరà±à°§à°¾à°°à°¿à°‚à°šà±</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> సరà±à°µà°°à± <ph name="BEGIN_ABBR" />DNS à°šà°¿à°°à±à°¨à°¾à°®à°¾<ph name="END_ABBR" />నౠకనà±à°—ొనడం సాధà±à°¯à°ªà°¡à°²à±‡à°¦à±.</translation>
<translation id="8149426793427495338">మీ à°•à°‚à°ªà±à°¯à±‚టరౠనిదà±à°°à°¾à°µà°¸à±à°¥à°•à°¿ వెళà±à°²à°¿à°‚ది.</translation>
@@ -776,6 +789,7 @@
<translation id="8349305172487531364">à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°² పటà±à°Ÿà±€</translation>
<translation id="8363502534493474904">ఎయిరà±â€Œà°ªà±à°²à±ˆà°¨à± మోడà±â€Œà°¨à± ఆఫౠచేయడం</translation>
<translation id="8364627913115013041">సెటౠచేయలేదà±.</translation>
+<translation id="8368476060205742148">Google Play సేవలà±</translation>
<translation id="8380941800586852976">అపాయకరమైనది</translation>
<translation id="8382348898565613901">మీరౠఇటీవల సందరà±à°¶à°¿à°‚à°šà°¿à°¨ à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à± ఇకà±à°•à°¡ కనిపిసà±à°¤à°¾à°¯à°¿</translation>
<translation id="8398259832188219207">à°•à±à°°à°¾à°·à± నివేదిక <ph name="UPLOAD_TIME" />à°•à°¿ à°…à°ªà±â€Œà°²à±‹à°¡à± చేయబడింది</translation>
@@ -784,32 +798,30 @@
<translation id="8428213095426709021">సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à±</translation>
<translation id="8433057134996913067">దీని వలన మీరౠచాలా వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°² à°¨à±à°‚à°¡à°¿ సైనౠఅవà±à°Ÿà± చేయబడతారà±.</translation>
<translation id="8437238597147034694">&amp;తరలించడానà±à°¨à°¿ à°°à°¦à±à°¦à± చేయి</translation>
-<translation id="8456681095658380701">చెలà±à°²à°¨à°¿ పేరà±</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à±}other{# à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à±â€Œà°²à±}}</translation>
<translation id="8483780878231876732">మీ Google ఖాతా à°¨à±à°‚à°¡à°¿ కారà±à°¡à±â€Œà°²à°¨à± ఉపయోగించేందà±à°•à±, Chromeà°•à°¿ సైనౠఇనౠచేయండి</translation>
<translation id="8488350697529856933">వీటికి వరà±à°¤à°¿à°¸à±à°¤à±à°‚ది</translation>
-<translation id="8492969205326575646">మదà±à°¦à°¤à±à°²à±‡à°¨à°¿ కారà±à°¡à± à°°à°•à°‚</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> à°ªà±à°°à°¤à°¿à°¸à±à°ªà°‚దించడానికి చాలా à°Žà°•à±à°•à±à°µ సమయం పటà±à°Ÿà°¿à°‚ది.</translation>
<translation id="852346902619691059">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపించలేకపోయింది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ మీ పరికరం ఆపరేటింగౠసిసà±à°Ÿà°®à± విశà±à°µà°¸à°¿à°‚చలేదà±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—రౠచేయడం వలన లేదా దాడిచేసే à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగించడం వలన ఇలా జరిగి ఉండవచà±à°šà±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">à°—à°¡à±à°µà± à°®à±à°—ింపౠసంవతà±à°¸à°°à°‚</translation>
<translation id="8543181531796978784">మీరౠ<ph name="BEGIN_ERROR_LINK" />à°—à±à°°à±à°¤à°¿à°‚పౠసమసà±à°¯à°¨à± నివేదించవచà±à°šà±<ph name="END_ERROR_LINK" /> లేదా మీకౠమీ à°­à°¦à±à°°à°¤à°•à± పొంచి ఉనà±à°¨ à°ªà±à°°à°®à°¾à°¦à°¾à°²à± à°…à°°à±à°¥à°‚ à°…à°¯à±à°¯à°¿ ఉంటే, <ph name="BEGIN_LINK" />à°ˆ à°…à°¸à±à°°à°•à±à°·à°¿à°¤ సైటà±â€Œà°¨à± సందరà±à°¶à°¿à°‚à°šà°‚à°¡à°¿<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">పేజీ భాష నిరà±à°¥à°¾à°°à°¿à°‚చలేకపోయినందà±à°¨ à°…à°¨à±à°µà°¾à°¦à°‚ విఫలమైంది.</translation>
<translation id="8559762987265718583">మీ పరికరం తేదీ మరియౠసమయం (<ph name="DATE_AND_TIME" />) తపà±à°ªà±à°—à°¾ ఉనà±à°¨à°‚à°¦à±à°¨ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />à°•à°¿ à°ªà±à°°à±ˆà°µà±‡à°Ÿà± కనెకà±à°·à°¨à± à°à°°à±à°ªà°¾à°Ÿà± చేయబడదà±.</translation>
-<translation id="8570229484593575558">à°ˆ సమాచారం |సేవౠచేయబడదà±|:#మీ à°¬à±à°°à±Œà°œà°¿à°‚à°—à± à°šà°°à°¿à°¤à±à°°#మీ శోధనలà±#à°•à±à°•à±à°•à±€ డేటా</translation>
<translation id="8571890674111243710">పేజీని <ph name="LANGUAGE" />à°•à± à°…à°¨à±à°µà°¦à°¿à°¸à±à°¤à±‹à°‚ది...</translation>
-<translation id="8584539743998202583">మీ కారà±à°¯à°¾à°šà°°à°£ |ఇపà±à°ªà°Ÿà°¿à°•à±€ వీటికి కనిపించవచà±à°šà±|:#మీరౠసందరà±à°¶à°¿à°‚చే వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°²à±#మీ యజమాని#మీ ఇంటరà±à°¨à±†à°Ÿà± సేవా à°ªà±à°°à°¦à°¾à°¤</translation>
<translation id="858637041960032120">ఫోనౠనం. జోడిం.
</translation>
<translation id="859285277496340001">ఇది à°°à°¦à±à°¦à± చెయà±à°¯à°¬à°¡à°¿à°‚దా అని తనిఖీ చెయà±à°¯à°¡à°¾à°¨à°¿à°•à°¿ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ విధానానà±à°¨à°¿ పేరà±à°•à±Šà°¨à°²à±‡à°¦à±.</translation>
<translation id="8620436878122366504">మీ తలà±à°²à°¿à°¦à°‚à°¡à±à°°à±à°²à± దీనà±à°¨à°¿ ఇంకా ఆమోదించలేదà±</translation>
<translation id="8647750283161643317">à°…à°¨à±à°¨à°¿à°‚టినీ డిఫాలà±à°Ÿà±â€Œà°•à± రీసెటౠచేయి</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" />కౠమీ కనెకà±à°·à°¨à± à°—à±à°ªà±à°¤à±€à°•à°°à°¿à°‚చబడలేదà±.</translation>
+<translation id="8718314106902482036">చెలà±à°²à°¿à°‚పౠపూరà±à°¤à°¿ కాలేదà±</translation>
<translation id="8725066075913043281">మళà±à°³à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿</translation>
-<translation id="8728672262656704056">మీరౠఅజà±à°žà°¾à°¤à°‚à°—à°¾ ఉనà±à°¨à°¾à°°à±</translation>
+<translation id="8728672262656704056">మీరౠఇపà±à°ªà±à°¡à± à°…à°œà±à°žà°¾à°¤ మోడà±â€Œà°²à±‹ ఉనà±à°¨à°¾à°°à±</translation>
<translation id="8730621377337864115">పూరà±à°¤à°¯à°¿à°‚ది</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="8759274551635299824">à°ˆ కారà±à°¡à± à°—à°¡à±à°µà± à°®à±à°—ిసింది</translation>
<translation id="8790007591277257123">&amp;తొలగించడానà±à°¨à°¿ à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ చేయి</translation>
-<translation id="8798099450830957504">డిఫాలà±à°Ÿà±</translation>
<translation id="8800988563907321413">మీ సమీపంలోని సూచనలౠఇకà±à°•à°¡ కనిపిసà±à°¤à°¾à°¯à°¿</translation>
<translation id="8820817407110198400">à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à±</translation>
<translation id="883848425547221593">ఇతర à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à±:</translation>
@@ -819,6 +831,7 @@
<translation id="8866481888320382733">విధాన సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± à°…à°¨à±à°µà°¯à°¿à°‚చడంలో లోపం</translation>
<translation id="8866959479196209191">à°ˆ పేజీ ఇలా చెబà±à°¤à±‹à°‚ది:</translation>
<translation id="8870413625673593573">ఇటీవల మూసివేసినవి</translation>
+<translation id="8874824191258364635">చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°¯à±à°¯à±‡ కారà±à°¡à± నంబరà±â€Œà°¨à± నమోదౠచేయండి</translation>
<translation id="8876793034577346603">నెటà±â€Œà°µà°°à±à°•à± కానà±à°«à°¿à°—రేషనౠఅనà±à°µà°¯à°¿à°‚చబడటంలో విఫలమైంది.</translation>
<translation id="8877192140621905067">మీరౠనిరà±à°§à°¾à°°à°¿à°‚à°šà°¿à°¨ తరà±à°µà°¾à°¤, మీ కారà±à°¡à± వివరాలౠఈ సైటà±â€Œà°¤à±‹ భాగసà±à°µà°¾à°®à±à°¯à°‚ చేయబడతాయి</translation>
<translation id="8889402386540077796">వరà±à°£à°‚</translation>
@@ -828,7 +841,6 @@
<translation id="8931333241327730545">మీరౠఈ కారà±à°¡à±â€Œà°¨à± మీ Google ఖాతాకి సేవౠచేయాలనà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
<translation id="8932102934695377596">మీ గడియారం సమయం గతంలో ఉంది</translation>
<translation id="8954894007019320973">(కొనసాగౠ.)</translation>
-<translation id="895548565263634352"><ph name="ARTICLE_PUBLISHER" /> మరియౠమరో <ph name="OTHER_ARTICLE_COUNT" /> à°¨à±à°‚à°¡à°¿ కథనాలనౠచదవండి</translation>
<translation id="8971063699422889582">సరà±à°µà°°à± యొకà±à°• à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°—à°¡à±à°µà± à°®à±à°—ిసింది.</translation>
<translation id="8986494364107987395">Googleà°•à± à°¸à±à°µà°¯à°‚చాలకంగా ఉపయోగ గణాంకాలనౠమరియౠకà±à°°à°¾à°·à± నివేదికలనౠపంపà±</translation>
<translation id="8987927404178983737">నెల</translation>
@@ -846,7 +858,6 @@
<translation id="9068849894565669697">à°°à°‚à°—à±à°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="9076283476770535406">ఇందà±à°²à±‹ పెదà±à°¦à°²à°•à± మాతà±à°°à°®à±‡ à°…à°¨à±à°®à°¤à°¿à°‚à°šà°¿à°¨ కంటెంటౠఉండవచà±à°šà±</translation>
<translation id="9078964945751709336">మరింత సమాచారం ఆవశà±à°¯à°•à°‚</translation>
-<translation id="9094175695478007090">చెలà±à°²à°¿à°‚పౠఅనà±à°µà°°à±à°¤à°¨à°¾à°¨à±à°¨à°¿ à°ªà±à°°à°¾à°°à°‚భించలేకపోయింది.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> సాధారణంగా మీ సమాచారానà±à°¨à°¿ à°°à°•à±à°·à°¿à°‚చడానికి à°—à±à°ªà±à°¤à±€à°•à°°à°£à°¨à± ఉపయోగిసà±à°¤à±à°‚ది. Chromium ఈసారి <ph name="SITE" />à°•à°¿ కనెకà±à°Ÿà± చేయడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚చినపà±à°ªà±à°¡à±, వెబà±â€Œà°¸à±ˆà°Ÿà± అసాధారణ మరియౠతపà±à°ªà± ఆధారాలౠఅని à°ªà±à°°à°¤à°¿à°¸à±à°ªà°‚దించింది. దాడి చేసే à°µà±à°¯à°•à±à°¤à°¿ <ph name="SITE" />à°—à°¾ à°µà±à°¯à°µà°¹à°°à°¿à°‚à°šà°¿ మోసగించడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°¸à±à°¤à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± లేదా Wi-Fi సైనà±-ఇనౠసà±à°•à±à°°à±€à°¨à± కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగించినపà±à°ªà±à°¡à± ఇలా జరగవచà±à°šà±. Chromium ఎలాంటి డేటా వినిమయం సంభవించక à°®à±à°‚దే కనెకà±à°·à°¨à±â€Œà°¨à± ఆపివేసినందà±à°¨ మీ సమాచారం ఇపà±à°ªà°Ÿà°¿à°•à±€ à°¸à±à°°à°•à±à°·à°¿à°¤à°‚గానే ఉంది.</translation>
<translation id="9137013805542155359">అసలà±à°¨à± చూపించà±</translation>
<translation id="9137248913990643158">దయచేసి à°ˆ à°…à°¨à±à°µà°°à±à°¤à°¨à°¾à°¨à±à°¨à°¿ ఉపయోగించే à°®à±à°‚దౠChromeని à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°¿, దానికి సైనౠఇనౠచేయండి.</translation>
diff --git a/chromium/components/strings/components_strings_th.xtb b/chromium/components/strings/components_strings_th.xtb
index 4d0d1994258..d3f6b466d12 100644
--- a/chromium/components/strings/components_strings_th.xtb
+++ b/chromium/components/strings/components_strings_th.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="th">
<translation id="1008557486741366299">ไม่ใช่ตอนนี้</translation>
<translation id="1015730422737071372">ให้รายละเอียดเพิ่มเติม</translation>
+<translation id="1021110881106174305">บัตรที่ยอมรับ</translation>
<translation id="1032854598605920125">หมุนตามเข็มนาฬิà¸à¸²</translation>
<translation id="1038842779957582377">ไม่ทราบชื่อ</translation>
<translation id="1050038467049342496">ปิดà¹à¸­à¸›à¸­à¸·à¹ˆà¸™à¹†</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">ซ่อนค่า</translation>
<translation id="1228893227497259893">ตัวระบุเอนทิตีไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="1232569758102978740">ไม่ระบุชื่อ</translation>
+<translation id="1263231323834454256">เรื่องรออ่าน</translation>
<translation id="1264126396475825575">รายงานข้อขัดข้องเมื่อ <ph name="CRASH_TIME" /> (ยังไม่ได้อัปโหลดหรือละเว้น)</translation>
<translation id="1285320974508926690">ไม่ต้องà¹à¸›à¸¥à¹„ซต์นี้</translation>
<translation id="129553762522093515">เพิ่งปิด</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าป้อนข้อความอัตโนมัติของ Chromium...</translation>
<translation id="1374468813861204354">คำà¹à¸™à¸°à¸™à¸³</translation>
<translation id="1375198122581997741">เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸£à¸¸à¹ˆà¸™</translation>
+<translation id="1377321085342047638">หมายเลขบัตร</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> ไม่ส่งข้อมูลใดๆ</translation>
<translation id="1407135791313364759">เปิดทั้งหมด</translation>
<translation id="1413809658975081374">ข้อผิดพลาดเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸„วามเป็นส่วนตัว</translation>
@@ -56,7 +59,7 @@
<translation id="1517433312004943670">ต้องระบุหมายเลขโทรศัพท์</translation>
<translation id="1519264250979466059">วันที่สร้าง</translation>
<translation id="153384715582417236">เสร็จเรียบร้อย</translation>
-<translation id="1549470594296187301">ต้องเปิดใช้ JavaScript เพื่อใช้คุณลัà¸à¸©à¸“ะนี้</translation>
+<translation id="1549470594296187301">ต้องเปิดใช้ JavaScript เพื่อใช้ฟีเจอร์นี้</translation>
<translation id="1555130319947370107">สีน้ำเงิน</translation>
<translation id="1559528461873125649">ไม่มีไฟล์หรือไดเรà¸à¸—อรีดังà¸à¸¥à¹ˆà¸²à¸§</translation>
<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;
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">ประวัติà¸à¸²à¸£à¹€à¸‚้าชม</translation>
<translation id="1645368109819982629">ไม่รองรับโปรโตคอล</translation>
<translation id="1656489000284462475">à¸à¸²à¸£à¸£à¸±à¸š</translation>
+<translation id="1663943134801823270">ข้อมูลบัตรà¹à¸¥à¸°à¸—ี่อยู่มาจาภChrome คุณสามารถจัดà¸à¸²à¸£à¸‚้อมูลเหล่านี้ใน<ph name="BEGIN_LINK" />à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า<ph name="END_LINK" /></translation>
<translation id="1676269943528358898">โดยทั่วไป <ph name="SITE" /> จะใช้à¸à¸²à¸£à¹€à¸‚้ารหัสเพื่อปà¸à¸›à¹‰à¸­à¸‡à¸‚้อมูลของคุณ เมื่อ Google Chrome พยายามเชื่อมต่อà¸à¸±à¸š <ph name="SITE" /> ในครั้งนี้ เว็บไซต์ดังà¸à¸¥à¹ˆà¸²à¸§à¸ªà¹ˆà¸‡à¸‚้อมูลรับรองที่ผิดปà¸à¸•à¸´à¹à¸¥à¸°à¹„ม่ถูà¸à¸•à¹‰à¸­à¸‡à¸à¸¥à¸±à¸šà¸¡à¸² เหตุà¸à¸²à¸£à¸“์นี้อาจเà¸à¸´à¸”ขึ้นเมื่อผู้บุà¸à¸£à¸¸à¸à¸žà¸¢à¸²à¸¢à¸²à¸¡à¸›à¸¥à¸­à¸¡à¹€à¸›à¹‡à¸™ <ph name="SITE" /> หรือหน้าจอà¸à¸²à¸£à¸¥à¸‡à¸Šà¸·à¹ˆà¸­à¹€à¸‚้าใช้ Wi-Fi รบà¸à¸§à¸™à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­ ข้อมูลของคุณยังปลอดภัยอยู่เนื่องจาภGoogle Chrome หยุดà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸à¹ˆà¸­à¸™à¸¡à¸µà¸à¸²à¸£à¹à¸¥à¸à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸‚้อมูล</translation>
<translation id="168328519870909584">ผู้บุà¸à¸£à¸¸à¸à¸—ี่à¸à¸³à¸¥à¸±à¸‡à¸­à¸¢à¸¹à¹ˆà¹ƒà¸™ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> อาจพยายามติดตั้งโปรà¹à¸à¸£à¸¡à¸­à¸±à¸™à¸•à¸£à¸²à¸¢à¸šà¸™à¸­à¸¸à¸›à¸à¸£à¸“์ของคุณ ซึ่งจะขโมยหรือลบข้อมูล (ตัวอย่างเช่น รูปภาพ รหัสผ่าน ข้อความ à¹à¸¥à¸°à¸šà¸±à¸•à¸£à¹€à¸„รดิต)</translation>
<translation id="168841957122794586">ใบรับรองของเซิร์ฟเวอร์มีคีย์à¸à¸²à¸£à¹€à¸‚้ารหัสที่ไม่รัดà¸à¸¸à¸¡</translation>
<translation id="1710259589646384581">ระบบปà¸à¸´à¸šà¸±à¸•à¸´à¸à¸²à¸£</translation>
<translation id="1721312023322545264">คุณต้องได้รับสิทธิ์จาภ<ph name="NAME" /> เพื่อเข้าชมเว็บไซต์นี้</translation>
+<translation id="1721424275792716183">* ช่องที่ต้องà¸à¸£à¸­à¸</translation>
<translation id="1728677426644403582">คุณà¸à¸³à¸¥à¸±à¸‡à¸”ูซอร์สโค้ดของหน้าเว็บ</translation>
+<translation id="173080396488393970">ไม่รองรับบัตรประเภทนี้</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">ลองติดต่อผู้ดูà¹à¸¥à¸£à¸°à¸šà¸š</translation>
+<translation id="1740951997222943430">ป้อนเดือนที่หมดอายุที่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="1745358365027406341">ดาวน์โหลดหน้าเว็บในภายหลัง</translation>
<translation id="17513872634828108">à¹à¸—็บที่เปิดอยู่</translation>
<translation id="1753706481035618306">เลขหน้า</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">โปรดอัปเดตข้อความรหัสผ่านที่ซิงค์ของคุณ</translation>
<translation id="1787142507584202372">à¹à¸—็บที่คุณเปิดไว้จะปราà¸à¸à¸—ี่นี่</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">เลือà¸à¸—ี่อยู่ในà¸à¸²à¸£à¸ˆà¸±à¸”ส่งเพื่อตรวจสอบวิธีà¹à¸¥à¸°à¸‚้อà¸à¸³à¸«à¸™à¸”ในà¸à¸²à¸£à¸ˆà¸±à¸”ส่ง</translation>
+<translation id="1803264062614276815">ชื่อผู้ถือบัตร</translation>
<translation id="1803678881841855883">เมื่อเร็วๆ นี้ Google Safe Browsing <ph name="BEGIN_LINK" />ตรวจพบมัลà¹à¸§à¸£à¹Œ<ph name="END_LINK" />บน <ph name="SITE" /> บางครั้งเว็บไซต์ที่โดยปà¸à¸•à¸´à¹à¸¥à¹‰à¸§à¸ˆà¸°à¸›à¸¥à¸­à¸”ภัยอาจติดมัลà¹à¸§à¸£à¹Œà¹„ด้ เนื้อหาที่เป็นอันตรายมาจาภ<ph name="SUBRESOURCE_HOST" /> ซึ่งเป็นผู้เผยà¹à¸žà¸£à¹ˆà¸¡à¸±à¸¥à¹à¸§à¸£à¹Œà¸—ี่เป็นที่รู้จัภ<ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1806541873155184440">วันที่เพิ่ม <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">คำขอหรือพารามิเตอร์คำขอไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="1826516787628120939">à¸à¸³à¸¥à¸±à¸‡à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸š</translation>
<translation id="1834321415901700177">เว็บไซต์นี้มีโปรà¹à¸à¸£à¸¡à¸­à¸±à¸™à¸•à¸£à¸²à¸¢</translation>
<translation id="1842969606798536927">จ่าย</translation>
-<translation id="1864455488461349376">ตัวเลือà¸à¸à¸²à¸£à¸ˆà¸±à¸”ส่ง</translation>
<translation id="1871208020102129563">พร็อà¸à¸‹à¸µà¸–ูà¸à¸•à¸±à¹‰à¸‡à¸„่าให้ใช้พร็อà¸à¸‹à¸µà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹à¸šà¸šà¸„งที่ ไม่ใช่ URL สคริปต์ .pac</translation>
<translation id="1871284979644508959">ช่องที่ต้องà¸à¸£à¸­à¸</translation>
<translation id="187918866476621466">เปิดหน้าเริ่มต้นใช้งาน</translation>
<translation id="1883255238294161206">ยุบรายà¸à¸²à¸£</translation>
<translation id="1898423065542865115">à¸à¸²à¸£à¸à¸£à¸­à¸‡</translation>
<translation id="194030505837763158">ไปที่ <ph name="LINK" /></translation>
-<translation id="1946821392246652573">บัตรที่รับ</translation>
<translation id="1962204205936693436">บุ๊à¸à¸¡à¸²à¸£à¹Œà¸à¸‚อง <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">ข้อผิดพลาดในà¸à¸²à¸£à¸ˆà¸±à¸”เรียง</translation>
<translation id="1974060860693918893">ขั้นสูง</translation>
<translation id="1978555033938440688">เวอร์ชันของเฟิร์มà¹à¸§à¸£à¹Œ</translation>
+<translation id="1995859865337580572">โปรดยืนยัน CVC ของคุณ</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{à¹à¸¥à¸°à¸­à¸µà¸ 1 à¹à¸­à¸›}other{à¹à¸¥à¸°à¸­à¸µà¸ # à¹à¸­à¸›}}</translation>
-<translation id="2020194265157481222">ต้องใส่ชื่อบนบัตร</translation>
<translation id="2025186561304664664">พร็อà¸à¸‹à¸µà¸–ูà¸à¸•à¸±à¹‰à¸‡à¸„่าให้ทำà¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าโดยอัตโนมัติ</translation>
<translation id="2030481566774242610">หรือคุณหมายถึง <ph name="LINK" /></translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />ตรวจสอบพร็อà¸à¸‹à¸µà¹à¸¥à¸°à¹„ฟร์วอลล์<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">วันนี้</translation>
<translation id="2154054054215849342">ไม่มีà¸à¸²à¸£à¸‹à¸´à¸‡à¸„์สำหรับโดเมนของคุณ</translation>
<translation id="2154484045852737596">à¹à¸à¹‰à¹„ขบัตร</translation>
-<translation id="2156993118928861787">ที่อยู่ไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="2166049586286450108">à¸à¸²à¸£à¹€à¸‚้าถึงระดับผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¹‚ดยสมบูรณ์</translation>
<translation id="2166378884831602661">เว็บไซต์นี้ไม่สามารถให้à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸—ี่ปลอดภัย</translation>
<translation id="2181821976797666341">นโยบาย</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{ที่อยู่ 1 รายà¸à¸²à¸£}other{ที่อยู่ # รายà¸à¸²à¸£}}</translation>
+<translation id="2202020181578195191">ป้อนปีที่หมดอายุที่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="2212735316055980242">ไม่พบนโยบาย</translation>
<translation id="2213606439339815911">à¸à¸³à¸¥à¸±à¸‡à¸”ึงรายà¸à¸²à¸£...</translation>
<translation id="2230458221926704099">à¹à¸à¹‰à¹„ขà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณด้วย<ph name="BEGIN_LINK" />à¹à¸­à¸›à¸à¸²à¸£à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">à¸à¸²à¸£à¹€à¸‚้าถึงอินเทอร์เน็ตของคุณถูà¸à¸šà¸¥à¹‡à¸­à¸</translation>
<translation id="230155334948463882">บัตรใหม่ใช่ไหม</translation>
<translation id="2305919008529760154">เซิร์ฟเวอร์นี้พิสูจน์ไม่ได้ว่าเป็น <ph name="DOMAIN" /> เพราะอาจมีà¸à¸²à¸£à¸­à¸­à¸à¹ƒà¸šà¸£à¸±à¸šà¸£à¸­à¸‡à¸„วามปลอดภัยปลอม สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="230697611605700222">ตัวเลือà¸à¸šà¸±à¸•à¸£à¹à¸¥à¸°à¸—ี่อยู่มาจาà¸à¹ƒà¸™à¸šà¸±à¸à¸Šà¸µ Google (<ph name="ACCOUNT_EMAIL" />) à¹à¸¥à¸° Chrome โดยคุณสามารถจัดà¸à¸²à¸£à¸•à¸±à¸§à¹€à¸¥à¸·à¸­à¸à¹€à¸«à¸¥à¹ˆà¸²à¸™à¸µà¹‰à¹ƒà¸™<ph name="BEGIN_LINK" />à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า<ph name="END_LINK" /></translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> ต้องใช้ชื่อผู้ใช้à¹à¸¥à¸°à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™</translation>
<translation id="2318774815570432836">คุณไม่สามารถเข้าชม <ph name="SITE" /> ได้ในขณะนี้ เนื่องจาà¸à¹€à¸§à¹‡à¸šà¹„ซต์ดังà¸à¸¥à¹ˆà¸²à¸§à¹ƒà¸Šà¹‰ HSTS โดยปà¸à¸•à¸´à¸‚้อผิดพลาดของเครือข่ายà¹à¸¥à¸°à¸à¸²à¸£à¹‚จมตีจะเà¸à¸´à¸”ขึ้นเพียงชั่วคราว หน้านี้จึงอาจจะใช้งานได้ในภายหลัง <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2354001756790975382">บุ๊à¸à¸¡à¸²à¸£à¹Œà¸à¸­à¸·à¹ˆà¸™à¹†</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">ค่าเริ่มต้นขององค์à¸à¸£</translation>
<translation id="2386255080630008482">ใบรับรองของเซิร์ฟเวอร์ถูà¸à¹€à¸žà¸´à¸à¸–อนà¹à¸¥à¹‰à¸§</translation>
<translation id="2392959068659972793">à¹à¸ªà¸”งนโยบายโดยที่ไม่ได้ตั้งค่า</translation>
+<translation id="239429038616798445">วิธีà¸à¸²à¸£à¸ˆà¸±à¸”ส่งสินค้านี้ไม่พร้อมให้บริà¸à¸²à¸£ โปรดลองใช้วิธีà¸à¸²à¸£à¸­à¸·à¹ˆà¸™</translation>
<translation id="2396249848217231973">&amp;เลิà¸à¸—ำà¸à¸²à¸£à¸™à¸³à¸­à¸­à¸</translation>
<translation id="2460160116472764928">เมื่อเร็วๆ นี้ Google Safe Browsing <ph name="BEGIN_LINK" />ตรวจพบมัลà¹à¸§à¸£à¹Œ<ph name="END_LINK" />บน <ph name="SITE" /> บางครั้งเว็บไซต์ที่โดยปà¸à¸•à¸´à¹à¸¥à¹‰à¸§à¸ˆà¸°à¸›à¸¥à¸­à¸”ภัยอาจติดมัลà¹à¸§à¸£à¹Œà¹„ด้ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2463739503403862330">à¸à¸£à¸­à¸à¸‚้อมูล</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />เรียà¸à¹ƒà¸Šà¹‰à¸à¸²à¸£à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢à¹€à¸„รือข่าย<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL ค้นหาไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="2491120439723279231">ใบรับรองของเซิร์ฟเวอร์มีข้อผิดพลาด</translation>
-<translation id="24943777258388405">หมายเลขโทรศัพท์ไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="2495083838625180221">โปรà¹à¸à¸£à¸¡à¹à¸¢à¸à¸§à¸´à¹€à¸„ราะห์ JSON</translation>
<translation id="2495093607237746763">หาà¸à¹€à¸¥à¸·à¸­à¸à¹„ว้ Chromium จะจัดเà¸à¹‡à¸šà¸ªà¸³à¹€à¸™à¸²à¸šà¸±à¸•à¸£à¸‚องคุณบนอุปà¸à¸£à¸“์นี้เพื่อà¸à¸²à¸£à¸à¸£à¸­à¸à¹à¸šà¸šà¸Ÿà¸­à¸£à¹Œà¸¡à¸—ี่รวดเร็วขึ้น</translation>
<translation id="2498091847651709837">สà¹à¸à¸™à¸šà¸±à¸•à¸£à¹ƒà¸«à¸¡à¹ˆ</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> ส่งà¸à¸²à¸£à¸•à¸­à¸šà¸à¸¥à¸±à¸šà¸—ี่ไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="2552545117464357659">ใหม่à¸à¸§à¹ˆà¸²</translation>
<translation id="2556876185419854533">&amp;เลิà¸à¸—ำà¸à¸²à¸£à¹à¸à¹‰à¹„ข</translation>
+<translation id="2587730715158995865">จาภ<ph name="ARTICLE_PUBLISHER" /> อ่านเรื่องราวนี้à¹à¸¥à¸°à¸­à¸·à¹ˆà¸™à¹† อีภ<ph name="OTHER_ARTICLE_COUNT" /> เรื่อง</translation>
<translation id="2587841377698384444">รหัส API ไดเรà¸à¸—อรี:</translation>
<translation id="2597378329261239068">เอà¸à¸ªà¸²à¸£à¸™à¸µà¹‰à¹„ด้รับà¸à¸²à¸£à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¸”้วยรหัสผ่าน โปรดป้อนรหัสผ่าน</translation>
<translation id="2609632851001447353">รูปà¹à¸šà¸šà¸•à¹ˆà¸²à¸‡à¹†</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />เรียà¸à¹ƒà¸Šà¹‰à¸à¸²à¸£à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">ตà¸à¸¥à¸‡</translation>
<translation id="2742870351467570537">นำรายà¸à¸²à¸£à¸—ี่เลือà¸à¸­à¸­à¸ </translation>
+<translation id="277133753123645258">วิธีà¸à¸²à¸£à¸ˆà¸±à¸”ส่งสินค้า</translation>
<translation id="277499241957683684">ไม่มีอุปà¸à¸£à¸“์บันทึà¸</translation>
<translation id="2784949926578158345">à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¹„ด้รับà¸à¸²à¸£à¸£à¸µà¹€à¸‹à¹‡à¸•à¹à¸¥à¹‰à¸§</translation>
<translation id="2794233252405721443">เว็บไซต์ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸</translation>
-<translation id="2812680587231492111">ตัวเลือà¸à¸à¸²à¸£à¸¡à¸²à¸£à¸±à¸šà¸”ังà¸à¸¥à¹ˆà¸²à¸§à¹„ม่พร้อมใช้งาน โปรดลองใช้ตัวเลือà¸à¸­à¸·à¹ˆà¸™</translation>
<translation id="2824775600643448204">ที่อยู่à¹à¸¥à¸°à¹à¸–บค้นหา</translation>
<translation id="2826760142808435982">à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸–ูà¸à¹€à¸‚้ารหัสà¹à¸¥à¸°à¸£à¸±à¸šà¸£à¸­à¸‡à¸„วามถูà¸à¸•à¹‰à¸­à¸‡à¹‚ดยใช้ <ph name="CIPHER" /> à¹à¸¥à¸°à¹ƒà¸Šà¹‰ <ph name="KX" /> เป็นà¸à¸¥à¹„à¸à¸à¸²à¸£à¹à¸¥à¸à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸„ีย์</translation>
<translation id="2835170189407361413">ล้างฟอร์ม</translation>
-<translation id="2849041323157393173">ตัวเลือà¸à¸à¸²à¸£à¸ˆà¸±à¸”ส่งดังà¸à¸¥à¹ˆà¸²à¸§à¹„ม่พร้อมใช้งาน โปรดลองใช้ตัวเลือà¸à¸­à¸·à¹ˆà¸™</translation>
<translation id="2889159643044928134">อย่าโหลดซ้ำ</translation>
<translation id="2900469785430194048">Google Chrome หน่วยความจำเต็มเมื่อพยายามà¹à¸ªà¸”งหน้าเว็บนี้</translation>
<translation id="2909946352844186028">ตรวจพบà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¹€à¸„รือข่าย</translation>
<translation id="2916038427272391327">ปิดโปรà¹à¸à¸£à¸¡à¸­à¸·à¹ˆà¸™à¹†</translation>
<translation id="2922350208395188000">ไม่สามารถตรวจสอบใบรับรองของเซิร์ฟเวอร์</translation>
+<translation id="2928905813689894207">ที่อยู่สำหรับà¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸à¹€à¸à¹‡à¸šà¹€à¸‡à¸´à¸™</translation>
<translation id="2948083400971632585">คุณสามารถปิดใช้งานพร็อà¸à¸‹à¸µà¸—ี่à¸à¸³à¸«à¸™à¸”ค่าสำหรับà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸ˆà¸²à¸à¸«à¸™à¹‰à¸²à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าได้</translation>
<translation id="2955913368246107853">ปิดà¹à¸–บค้นหา</translation>
<translation id="2958431318199492670">à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าเครือข่ายไม่เป็นไปตามมาตรà¸à¸²à¸™ ONC à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าบางส่วนอาจไม่ได้รับà¸à¸²à¸£à¸™à¸³à¹€à¸‚้า</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">หาà¸à¸•à¹‰à¸­à¸‡à¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸—ี่ปลอดภัย คุณต้องตั้งค่านาฬิà¸à¸²à¹ƒà¸«à¹‰à¸–ูà¸à¸•à¹‰à¸­à¸‡à¹€à¸™à¸·à¹ˆà¸­à¸‡à¸ˆà¸²à¸à¹ƒà¸šà¸£à¸±à¸šà¸£à¸­à¸‡à¸—ี่เว็บไซต์ใช้เพื่อระบุตัวตนจะใช้ได้ในช่วงเวลาที่เจาะจงเท่านั้น à¹à¸•à¹ˆà¹€à¸™à¸·à¹ˆà¸­à¸‡à¸ˆà¸²à¸à¸™à¸²à¸¬à¸´à¸à¸²à¸‚องอุปà¸à¸£à¸“์ไม่ถูà¸à¸•à¹‰à¸­à¸‡ Google Chrome จึงไม่สามารถยืนยันใบรับรองเหล่านี้</translation>
<translation id="2972581237482394796">&amp;ทำซ้ำ</translation>
<translation id="2985306909656435243">หาà¸à¹€à¸›à¸´à¸”ใช้ไว้ Chromium จะจัดเà¸à¹‡à¸šà¸ªà¸³à¹€à¸™à¸²à¸šà¸±à¸•à¸£à¸‚องคุณในอุปà¸à¸£à¸“์นี้เพื่อà¸à¸²à¸£à¸à¸£à¸­à¸à¹à¸šà¸šà¸Ÿà¸­à¸£à¹Œà¸¡à¸—ี่รวดเร็วขึ้น</translation>
+<translation id="2985398929374701810">ป้อนที่อยู่ที่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
+<translation id="2986368408720340940">วิธีà¸à¸²à¸£à¸£à¸±à¸šà¸ªà¸´à¸™à¸„้านี้ไม่พร้อมให้บริà¸à¸²à¸£ โปรดลองใช้วิธีà¸à¸²à¸£à¸­à¸·à¹ˆà¸™</translation>
<translation id="2991174974383378012">à¸à¸²à¸£à¹à¸Šà¸£à¹Œà¸à¸±à¸šà¹€à¸§à¹‡à¸šà¹„ซต์</translation>
<translation id="3005723025932146533">à¹à¸ªà¸”งสำเนาที่บันทึà¸à¹„ว้</translation>
<translation id="3008447029300691911">ป้อน CVC สำหรับ <ph name="CREDIT_CARD" /> เมื่อยืนยันà¹à¸¥à¹‰à¸§ รายละเอียดบัตรของคุณจะà¹à¸Šà¸£à¹Œà¸à¸±à¸šà¹€à¸§à¹‡à¸šà¹„ซต์นี้</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{อย่างน้อย 1 รายà¸à¸²à¸£à¸šà¸™à¸­à¸¸à¸›à¸à¸£à¸“์ที่ซิงค์}=1{1 รายà¸à¸²à¸£ (à¹à¸¥à¸°à¸¡à¸²à¸à¸à¸§à¹ˆà¸²à¸šà¸™à¸­à¸¸à¸›à¸à¸£à¸“์ที่ซิงค์)}other{# รายà¸à¸²à¸£ (à¹à¸¥à¸°à¸¡à¸²à¸à¸à¸§à¹ˆà¸²à¸šà¸™à¸­à¸¸à¸›à¸à¸£à¸“์ที่ซิงค์)}}</translation>
<translation id="3041612393474885105">ข้อมูลในใบรับรอง</translation>
<translation id="3063697135517575841">Chrome ไม่สามารถยืนยันบัตรของคุณได้ในขณะนี้ โปรดลองอีà¸à¸„รั้งในภายหลัง</translation>
+<translation id="3064966200440839136">ออà¸à¸ˆà¸²à¸à¹‚หมดไม่ระบุตัวตนเพื่อชำระเงินผ่านà¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชันภายนอภดำเนินà¸à¸²à¸£à¸•à¹ˆà¸­à¹„หม</translation>
<translation id="3093245981617870298">คุณออฟไลน์อยู่</translation>
<translation id="3105172416063519923">รหัสสินทรัพย์:</translation>
<translation id="3109728660330352905">คุณไม่มีสิทธิ์ดูหน้านี้</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />ลองเรียà¸à¹ƒà¸Šà¹‰à¸à¸²à¸£à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­<ph name="END_LINK" /></translation>
<translation id="3145945101586104090">à¸à¸²à¸£à¸–อดรหัสà¸à¸²à¸£à¸•à¸­à¸šà¸à¸¥à¸±à¸šà¸¥à¹‰à¸¡à¹€à¸«à¸¥à¸§</translation>
-<translation id="3149891296864842641">ตัวเลือà¸à¸à¸²à¸£à¸ˆà¸±à¸”ส่ง</translation>
<translation id="3150653042067488994">ข้อผิดพลาดชั่วคราวของเซิร์ฟเวอร์</translation>
+<translation id="3154506275960390542">หน้านี้มีฟอร์มที่อาจส่งอย่างไม่ปลอดภัย บุคคลอื่นสามารถดูข้อมูลที่คุณส่งได้ระหว่างทางหรือข้อมูลอาจถูà¸à¹à¸à¹‰à¹„ขโดยผู้โจมตีเพื่อเปลี่ยนà¹à¸›à¸¥à¸‡à¸ªà¸´à¹ˆà¸‡à¸—ี่เซิร์ฟเวอร์จะได้รับ</translation>
<translation id="3157931365184549694">คืนค่า</translation>
<translation id="3167968892399408617">หน้าที่คุณดูในà¹à¸—็บไม่ระบุตัวตนจะไม่เà¸à¹‡à¸šà¸­à¸¢à¸¹à¹ˆà¹ƒà¸™à¸›à¸£à¸°à¸§à¸±à¸•à¸´à¸à¸²à¸£à¹€à¸‚้าชมของเบราว์เซอร์ à¸à¸²à¸£à¸ˆà¸±à¸”เà¸à¹‡à¸šà¸„ุà¸à¸à¸µà¹‰ หรือประวัติà¸à¸²à¸£à¸„้นหาหลังจาà¸à¸—ี่คุณปิดà¹à¸—็บไม่ระบุตัวตนทั้งหมด à¹à¸•à¹ˆà¸ˆà¸°à¸¡à¸µà¸à¸²à¸£à¹€à¸à¹‡à¸šà¹„ฟล์ที่คุณดาวน์โหลดหรือบุ๊à¸à¸¡à¸²à¸£à¹Œà¸à¸—ี่คุณสร้างขึ้น</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">ไม่สามารถส่งคำขอเข้าถึงไซต์นี้ไปยัง <ph name="NAME" /> ได้ โปรดลองอีà¸à¸„รั้ง</translation>
<translation id="3355823806454867987">เปลี่ยนà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าพร็อà¸à¸‹à¸µ...</translation>
<translation id="3369192424181595722">ข้อผิดพลาดของนาฬิà¸à¸²</translation>
+<translation id="337311366426640088">à¹à¸¥à¸°à¸­à¸µà¸ <ph name="ITEM_COUNT" /> รายà¸à¸²à¸£...</translation>
<translation id="337363190475750230">ยà¸à¹€à¸¥à¸´à¸à¸à¸²à¸£à¸ˆà¸±à¸”เตรียมà¹à¸¥à¹‰à¸§</translation>
<translation id="3377188786107721145">ข้อผิดพลาดในà¸à¸²à¸£à¹à¸¢à¸à¸§à¸´à¹€à¸„ราะห์นโยบาย</translation>
<translation id="3380365263193509176">ข้อผิดพลาดที่ไม่รู้จัà¸</translation>
<translation id="3380864720620200369">รหัสลูà¸à¸„้า:</translation>
<translation id="3391030046425686457">ที่อยู่สำหรับจัดส่ง</translation>
+<translation id="3395827396354264108">วิธีà¸à¸²à¸£à¸£à¸±à¸šà¸ªà¸´à¸™à¸„้า</translation>
<translation id="340013220407300675">ผู้บุà¸à¸£à¸¸à¸à¸­à¸²à¸ˆà¸žà¸¢à¸²à¸¢à¸²à¸¡à¸‚โมยข้อมูลของคุณจาภ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (ตัวอย่างเช่น รหัสผ่าน ข้อความ หรือบัตรเครดิต)</translation>
<translation id="3422248202833853650">ลองออà¸à¸ˆà¸²à¸à¹‚ปรà¹à¸à¸£à¸¡à¸­à¸·à¹ˆà¸™à¹† เพื่อเพิ่มหน่วยความจำ</translation>
<translation id="3422472998109090673">ไม่สามารถเข้าถึง <ph name="HOST_NAME" /> ได้ในขณะนี้</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">ช่วงà¸à¸²à¸£à¸”ึงข้อมูล:</translation>
<translation id="3462200631372590220">ซ่อนข้อมูลขั้นสูง</translation>
+<translation id="3467763166455606212">ต้องระบุชื่อผู้ถือบัตร</translation>
+<translation id="3478058380795961209">เดือนที่หมดอายุ</translation>
<translation id="3479539252931486093">หาà¸à¹€à¸«à¸•à¸¸à¸à¸²à¸£à¸“์นี้ผิดปà¸à¸•à¸´ <ph name="BEGIN_LINK" />โปรดà¹à¸ˆà¹‰à¸‡à¹ƒà¸«à¹‰à¹€à¸£à¸²à¸—ราบ<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">ไม่ใช่ตอนนี้</translation>
<translation id="348000606199325318">รหัสข้อขัดข้อง <ph name="CRASH_LOCAL_ID" /> (รหัสเซิร์ฟเวอร์: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">เราไม่สามารถติดต่อผู้ปà¸à¸„รองของคุณได้ในขณะนี้ โปรดลองอีà¸à¸„รั้ง</translation>
<translation id="3528171143076753409">ใบรับรองของเซิร์ฟเวอร์ไม่น่าเชื่อถือ</translation>
-<translation id="3538531656504267329">ปีที่หมดอายุไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="3539171420378717834">เà¸à¹‡à¸šà¸ªà¸³à¹€à¸™à¸²à¸šà¸±à¸•à¸£à¸™à¸µà¹‰à¹„ว้บนอุปà¸à¸£à¸“์นี้</translation>
<translation id="3542684924769048008">ใช้รหัสผ่านสำหรับ:</translation>
<translation id="3549644494707163724">เข้ารหัสข้อมูลที่ซิงค์ทั้งหมดด้วยข้อความรหัสผ่านà¸à¸²à¸£à¸‹à¸´à¸‡à¸„์ของคุณเอง</translation>
@@ -296,12 +307,13 @@
<translation id="3586931643579894722">ซ่อนรายละเอียด</translation>
<translation id="3587482841069643663">ทั้งหมด</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">ป้อนวันที่หมดอายุที่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="36224234498066874">ล้างข้อมูลà¸à¸²à¸£à¸—่องเว็บ</translation>
<translation id="362276910939193118">à¹à¸ªà¸”งประวัติà¸à¸²à¸£à¹€à¸‚้าชมทั้งหมด</translation>
<translation id="3623476034248543066">à¹à¸ªà¸”งค่า</translation>
<translation id="3630155396527302611">หาà¸à¹‚ปรà¹à¸à¸£à¸¡à¸­à¸¢à¸¹à¹ˆà¹ƒà¸™à¸£à¸²à¸¢à¸à¸²à¸£à¸—ี่ได้รับอนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸‚้าถึงเครือข่ายอยู่à¹à¸¥à¹‰à¸§
ลองนำโปรà¹à¸à¸£à¸¡à¸­à¸­à¸à¸ˆà¸²à¸à¸£à¸²à¸¢à¸à¸²à¸£à¹à¸¥à¸°à¹€à¸žà¸´à¹ˆà¸¡à¸à¸¥à¸±à¸šà¹€à¸‚้าไปใหม่</translation>
-<translation id="3648607100222897006">คุณลัà¸à¸©à¸“ะทดลองเหล่านี้อาจมีà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡ เสียหาย หรือยà¸à¹€à¸¥à¸´à¸à¹„ปได้ตลอดเวลา เราไม่รับประà¸à¸±à¸™à¹ƒà¸”ๆ เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸ªà¸´à¹ˆà¸‡à¸—ี่อาจเà¸à¸´à¸”ขึ้นทั้งสิ้นหาà¸à¸„ุณเปิดใช้à¸à¸²à¸£à¸—ดลองรายà¸à¸²à¸£à¹ƒà¸”รายà¸à¸²à¸£à¸«à¸™à¸¶à¹ˆà¸‡à¸™à¸µà¹‰ เบราว์เซอร์ของคุณอาจพังโดยไม่มีสัà¸à¸à¸²à¸“เตือน ยิ่งไปà¸à¸§à¹ˆà¸²à¸™à¸±à¹‰à¸™ เบราว์เซอร์อาจลบข้อมูลทั้งหมดของคุณได้ หรือà¸à¸²à¸£à¸£à¸±à¸à¸©à¸²à¸„วามปลอดภัยà¹à¸¥à¸°à¸„วามเป็นส่วนตัวของคุณอาจโดนคุà¸à¸„ามโดยไม่คาดคิด à¸à¸²à¸£à¸—ดลองใดๆ ที่คุณเปิดใช้งานจะเปิดใช้สำหรับผู้ใช้ทุà¸à¸„นที่ใช้เบราว์เซอร์นี้ด้วย โปรดดำเนินà¸à¸²à¸£à¸”้วยความระมัดระวัง</translation>
+<translation id="3648607100222897006">ฟีเจอร์ทดลองเหล่านี้อาจมีà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡ เสียหาย หรือยà¸à¹€à¸¥à¸´à¸à¹„ปได้ตลอดเวลา เราไม่รับประà¸à¸±à¸™à¹ƒà¸”ๆ เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸ªà¸´à¹ˆà¸‡à¸—ี่อาจเà¸à¸´à¸”ขึ้นทั้งสิ้นหาà¸à¸„ุณเปิดใช้à¸à¸²à¸£à¸—ดลองรายà¸à¸²à¸£à¹ƒà¸”รายà¸à¸²à¸£à¸«à¸™à¸¶à¹ˆà¸‡à¸™à¸µà¹‰ เบราว์เซอร์ของคุณอาจพังโดยไม่มีสัà¸à¸à¸²à¸“เตือน ยิ่งไปà¸à¸§à¹ˆà¸²à¸™à¸±à¹‰à¸™ เบราว์เซอร์อาจลบข้อมูลทั้งหมดของคุณได้ หรือà¸à¸²à¸£à¸£à¸±à¸à¸©à¸²à¸„วามปลอดภัยà¹à¸¥à¸°à¸„วามเป็นส่วนตัวของคุณอาจโดนคุà¸à¸„ามโดยไม่คาดคิด à¸à¸²à¸£à¸—ดลองใดๆ ที่คุณเปิดใช้งานจะเปิดใช้สำหรับผู้ใช้ทุà¸à¸„นที่ใช้เบราว์เซอร์นี้ด้วย โปรดดำเนินà¸à¸²à¸£à¸”้วยความระมัดระวัง</translation>
<translation id="3650584904733503804">à¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸ªà¸³à¹€à¸£à¹‡à¸ˆ</translation>
<translation id="3655670868607891010">หาà¸à¸„ุณเห็นข้อความนี้บ่อยๆ ให้ลองไปที่ <ph name="HELP_LINK" /></translation>
<translation id="3658742229777143148">à¸à¸²à¸£à¹à¸à¹‰à¹„ข</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">รหัสผ่าน:</translation>
<translation id="3696411085566228381">ไม่มี</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">เลือà¸à¸—ี่อยู่สำหรับจัดส่งเพื่อตรวจสอบวิธีจัดส่งà¹à¸¥à¸°à¸‚้อà¸à¸³à¸«à¸™à¸”</translation>
<translation id="370665806235115550">à¸à¸³à¸¥à¸±à¸‡à¹‚หลด ...</translation>
<translation id="3712624925041724820">ใบอนุà¸à¸²à¸•à¸«à¸¡à¸”</translation>
<translation id="3714780639079136834">เปิดข้อมูลเครือข่ายมือถือหรือ Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">ลิงà¸à¹Œà¸—ี่คุณคัดลอà¸à¸¡à¸²</translation>
<translation id="375403751935624634">à¸à¸²à¸£à¹à¸›à¸¥à¸¥à¹‰à¸¡à¹€à¸«à¸¥à¸§à¹€à¸™à¸·à¹ˆà¸­à¸‡à¸ˆà¸²à¸à¸‚้อผิดพลาดของเซิร์ฟเวอร์</translation>
<translation id="3759461132968374835">คุณไม่ได้รายงานข้อขัดข้องเมื่อเร็วๆ นี้ ข้อขัดข้องที่เà¸à¸´à¸”ขึ้นเมื่อปิดใช้งานà¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™à¸‚้อขัดข้อง จะไม่ปราà¸à¸à¸—ี่นี่</translation>
+<translation id="3787705759683870569">หมดอายุ <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">หาà¸à¸„ุณใช้พร็อà¸à¸‹à¸µà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œ...</translation>
<translation id="3828924085048779000">ข้อความรหัสผ่านต้องไม่เว้นว่างไว้</translation>
<translation id="3845539888601087042">à¸à¸³à¸¥à¸±à¸‡à¹à¸ªà¸”งประวัติà¸à¸²à¸£à¹€à¸‚้าชมจาà¸à¸­à¸¸à¸›à¸à¸£à¸“์ที่คุณลงชื่อเข้าใช้ <ph name="BEGIN_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LINK" /></translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">คุณต้องà¸à¸²à¸£à¹ƒà¸«à¹‰ Chromium บันทึà¸à¸šà¸±à¸•à¸£à¸™à¸µà¹‰à¹„หม</translation>
<translation id="4171400957073367226">ลายเซ็นยืนยันไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
-<translation id="4176463684765177261">ปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¹à¸¥à¹‰à¸§</translation>
<translation id="4196861286325780578">&amp;ทำซ้ำà¸à¸²à¸£à¸¢à¹‰à¸²à¸¢</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ตรวจสอบไฟร์วอลล์à¹à¸¥à¸°à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าà¸à¸²à¸£à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¹„วรัส<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{ไม่มี}=1{1 à¹à¸­à¸› ($1)}=2{2 à¹à¸­à¸› ($1, $2)}other{# à¹à¸­à¸› ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">ผลà¸à¸²à¸£à¸„้นหา</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ไม่ยอมรับใบรับรองà¸à¸²à¸£à¹€à¸‚้าสู่ระบบหรือไม่ได้ให้ใบรับรองไว้</translation>
<translation id="443673843213245140">à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸žà¸£à¹‡à¸­à¸à¸‹à¸µà¸–ูà¸à¸›à¸´à¸”ใช้งาน à¹à¸•à¹ˆà¸¡à¸µà¸à¸²à¸£à¸£à¸°à¸šà¸¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าพร็อà¸à¸‹à¸µà¸­à¸¢à¹ˆà¸²à¸‡à¸Šà¸±à¸”เจน</translation>
-<translation id="4446242550670694251">ขณะนี้คุณสามารถท่องเว็บà¹à¸šà¸šà¹€à¸›à¹‡à¸™à¸ªà¹ˆà¸§à¸™à¸•à¸±à¸§à¹à¸¥à¸°à¸œà¸¹à¹‰à¸­à¸·à¹ˆà¸™à¸—ี่ใช้อุปà¸à¸£à¸“์เครื่องนี้จะไม่เห็นà¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸‚องคุณ</translation>
<translation id="4492190037599258964">ผลà¸à¸²à¸£à¸„้นหาคำว่า "<ph name="SEARCH_STRING" />"</translation>
<translation id="4506176782989081258">ข้อผิดพลาดในà¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸š: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">ติดต่อผู้ดูà¹à¸¥à¸£à¸°à¸šà¸š</translation>
<translation id="450710068430902550">à¸à¸²à¸£à¹à¸Šà¸£à¹Œà¸à¸±à¸šà¸œà¸¹à¹‰à¸”ูà¹à¸¥à¸£à¸°à¸šà¸š</translation>
+<translation id="4515275063822566619">ข้อมูลบัตรà¹à¸¥à¸°à¸—ี่อยู่มาจาภChrome à¹à¸¥à¸°à¸šà¸±à¸à¸Šà¸µ Google (<ph name="ACCOUNT_EMAIL" />) คุณสามารถจัดà¸à¸²à¸£à¸‚้อมูลเหล่านี้ใน<ph name="BEGIN_LINK" />à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า<ph name="END_LINK" /></translation>
<translation id="4522570452068850558">รายละเอียด</translation>
<translation id="4558551763791394412">ลองปิดใช้ส่วนขยาย</translation>
<translation id="457875822857220463">à¸à¸²à¸£à¸ˆà¸±à¸”ส่ง</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">พอดีà¸à¸±à¸šà¸«à¸™à¹‰à¸²</translation>
<translation id="483020001682031208">ไม่มีหน้า Physical Web ที่จะà¹à¸ªà¸”ง</translation>
<translation id="4850886885716139402">มุมมอง</translation>
+<translation id="4854362297993841467">วิธีà¸à¸²à¸£à¸™à¸³à¸ªà¹ˆà¸‡à¸ªà¸´à¸™à¸„้านี้ไม่พร้อมให้บริà¸à¸²à¸£ โปรดลองใช้วิธีà¸à¸²à¸£à¸­à¸·à¹ˆà¸™</translation>
<translation id="4858792381671956233">คุณถามผู้ปà¸à¸„รองà¹à¸¥à¹‰à¸§à¸§à¹ˆà¸²à¸ªà¸²à¸¡à¸²à¸£à¸–เข้าชมเว็บไซต์นี้ได้ไหม</translation>
<translation id="4880827082731008257">ค้นประวัติà¸à¸²à¸£à¹€à¸‚้าชม</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> à¹à¸¥à¸° <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">หน้านี้à¹à¸›à¸¥à¸ˆà¸²à¸à¸ à¸²à¸©à¸²à¸—ี่ไม่รู้จัà¸à¹€à¸›à¹‡à¸™à¸ à¸²à¸©à¸² <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">à¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™</translation>
<translation id="4926049483395192435">ต้องระบุ</translation>
-<translation id="4941291666397027948">* เป็นช่องที่ต้องà¸à¸£à¸­à¸</translation>
<translation id="495170559598752135">à¸à¸²à¸£à¸—ำงาน</translation>
<translation id="4958444002117714549">ขยายรายà¸à¸²à¸£</translation>
<translation id="4962322354953122629">เซิร์ฟเวอร์นี้พิสูจน์ไม่ได้ว่าเป็น <ph name="DOMAIN" /> เพราะ Chrome ไม่เชื่อถือใบรับรองความปลอดภัยของเซิร์ฟเวอร์นี้ สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">รหัสผ่านไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="5056549851600133418">บทความสำหรับคุณ</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />ตรวจสอบที่อยู่พร็อà¸à¸‹à¸µ<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{ไม่มีคุà¸à¸à¸µà¹‰}=1{1 เว็บไซต์ใช้คุà¸à¸à¸µà¹‰ }other{# เว็บไซต์ใช้คุà¸à¸à¸µà¹‰ }}</translation>
<translation id="5087286274860437796">ใบรับรองของเซิร์ฟเวอร์ไม่สามารถใช้ได้ในขณะนี้</translation>
<translation id="5087580092889165836">เพิ่มบัตร</translation>
<translation id="5089810972385038852">รัà¸</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">à¹à¸ªà¸”ง</translation>
<translation id="5308689395849655368">à¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™à¸‚้อขัดข้องถูà¸à¸›à¸´à¸”ใช้งาน</translation>
<translation id="5317780077021120954">บันทึà¸</translation>
-<translation id="5326702247179446998">ต้องระบุผู้รับ</translation>
<translation id="5327248766486351172">ชื่อ</translation>
<translation id="5337705430875057403">ผู้บุà¸à¸£à¸¸à¸à¸—ี่อยู่ใน <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> อาจหลอà¸à¸¥à¹ˆà¸­à¸„ุณเพื่อทำบางสิ่งที่อันตราย เช่น à¸à¸²à¸£à¸•à¸´à¸”ตั้งซอฟต์à¹à¸§à¸£à¹Œà¸«à¸£à¸·à¸­à¹€à¸›à¸´à¸”เผยข้อมูลส่วนบุคคล (ตัวอย่างเช่น รหัสผ่าน หมายเลขโทรศัพท์ หรือบัตรเครดิต)</translation>
-<translation id="53553865750799677">ที่อยู่ในà¸à¸²à¸£à¸£à¸±à¸šà¹ƒà¸Šà¹‰à¹„ม่ได้ โปรดเลือà¸à¸—ี่อยู่อื่น</translation>
<translation id="5359637492792381994">เซิร์ฟเวอร์นี้พิสูจน์ไม่ได้ว่าเป็น <ph name="DOMAIN" /> เพราะใบรับรองความปลอดภัยของเซิร์ฟเวอร์ใช้ไม่ได้ในขณะนี้ สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">ไม่สามารถจัดเà¸à¹‡à¸šà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่านโยบาย</translation>
<translation id="5386426401304769735">à¸à¸¥à¸¸à¹ˆà¸¡à¹ƒà¸šà¸£à¸±à¸šà¸£à¸­à¸‡à¸ªà¸³à¸«à¸£à¸±à¸šà¹€à¸§à¹‡à¸šà¹„ซต์นี้มีใบรับรองที่ลงนามโดยใช้ SHA-1</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">หน้าที่à¸à¸±à¸‡à¹„ว้ใน <ph name="SITE" /> บอà¸à¸§à¹ˆà¸²:</translation>
<translation id="5556459405103347317">โหลดใหม่</translation>
<translation id="5565735124758917034">ใช้งานอยู่</translation>
+<translation id="5571083550517324815">ไม่สามารถรับสินค้าจาà¸à¸—ี่อยู่นี้ โปรดเลือà¸à¸—ี่อยู่อื่น</translation>
<translation id="5572851009514199876">โปรดเปิดà¹à¸¥à¸°à¸¥à¸‡à¸Šà¸·à¹ˆà¸­à¹€à¸‚้าใช้ Chrome เพื่อให้ Chrome ตรวจสอบได้ว่าคุณได้รับอนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸‚้าถึงไซต์นี้หรือไม่</translation>
-<translation id="5575380383496039204">ที่อยู่สำหรับจัดส่งใช้ไม่ได้ โปรดเลือà¸à¸—ี่อยู่อื่น</translation>
<translation id="5580958916614886209">ตรวจสอบเดือนหมดอายุà¹à¸¥à¹‰à¸§à¸¥à¸­à¸‡à¸­à¸µà¸à¸„รั้ง</translation>
<translation id="560412284261940334">ไม่สนับสนุนà¸à¸²à¸£à¸ˆà¸±à¸”à¸à¸²à¸£</translation>
<translation id="5610142619324316209">ตรวจสอบà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">ข้อมูลประจำตัวของเว็บไซต์นี้ยังไม่ได้รับà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™</translation>
<translation id="5720705177508910913">ผู้ใช้ปัจจุบัน</translation>
<translation id="5732392974455271431">ผู้ปà¸à¸„รองสามารถเลิà¸à¸šà¸¥à¹‡à¸­à¸à¹€à¸§à¹‡à¸šà¹„ซต์ให้คุณ</translation>
-<translation id="57586589942790530">หมายเลขบัตรไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
+<translation id="5763042198335101085">ป้อนที่อยู่อีเมลที่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
+<translation id="5765072501007116331">หาà¸à¸•à¹‰à¸­à¸‡à¸à¸²à¸£à¸”ูวิธีà¸à¸²à¸£à¸™à¸³à¸ªà¹ˆà¸‡à¸ªà¸´à¸™à¸„้าà¹à¸¥à¸°à¸‚้อà¸à¸³à¸«à¸™à¸” โปรดเลือà¸à¸—ี่อยู่</translation>
<translation id="5784606427469807560">เà¸à¸´à¸”ปัà¸à¸«à¸²à¹ƒà¸™à¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¸šà¸±à¸•à¸£à¸‚องคุณ โปรดตรวจสอบà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸­à¸´à¸™à¹€à¸—อร์เน็ตà¹à¸¥à¸°à¸¥à¸­à¸‡à¸­à¸µà¸à¸„รั้ง</translation>
<translation id="5785756445106461925">นอà¸à¸ˆà¸²à¸à¸™à¸µà¹‰ หน้านี้ประà¸à¸­à¸šà¸”้วยทรัพยาà¸à¸£à¸­à¸·à¹ˆà¸™à¹† ซึ่งไม่ปลอดภัย ผู้อื่นสามารถดูทรัพยาà¸à¸£à¹€à¸«à¸¥à¹ˆà¸²à¸™à¸µà¹‰à¸‚ณะถ่ายโอน à¹à¸¥à¸°à¸œà¸¹à¹‰à¸šà¸¸à¸à¸£à¸¸à¸à¸ªà¸²à¸¡à¸²à¸£à¸–à¹à¸à¹‰à¹„ขเพื่อเปลี่ยนรูปลัà¸à¸©à¸“์ของหน้าได้</translation>
<translation id="5786044859038896871">คุณต้องà¸à¸²à¸£à¸à¸£à¸­à¸à¸‚้อมูลบัตรไหม</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">ไม่สามารถเข้าถึงเว็บไซต์นี้</translation>
<translation id="5869522115854928033">รหัสผ่านที่บันทึà¸à¹„ว้</translation>
<translation id="5872918882028971132">คำà¹à¸™à¸°à¸™à¸³à¸£à¸°à¸”ับบนสุด</translation>
-<translation id="587760065310675640">ที่อยู่สำหรับจัดส่งใช้ไม่ได้ โปรดเลือà¸à¸—ี่อยู่อื่น</translation>
<translation id="5901630391730855834">สีเหลือง</translation>
-<translation id="59174027418879706">เปิดใช้งานà¹à¸¥à¹‰à¸§</translation>
<translation id="5926846154125914413">คุณอาจสูà¸à¹€à¸ªà¸µà¸¢à¸ªà¸´à¸—ธิ์à¸à¸²à¸£à¹€à¸‚้าถึงเนื้อหาระดับพรีเมียมจาà¸à¹€à¸§à¹‡à¸šà¹„ซต์บางà¹à¸«à¹ˆà¸‡</translation>
<translation id="5959728338436674663">ส่ง<ph name="BEGIN_WHITEPAPER_LINK" />ข้อมูลบางอย่างของระบบà¹à¸¥à¸°à¹€à¸™à¸·à¹‰à¸­à¸«à¸²à¸‚องหน้าเว็บ<ph name="END_WHITEPAPER_LINK" />ไปยัง Google เพื่อช่วยตรวจหาà¹à¸­à¸›à¹à¸¥à¸°à¹€à¸§à¹‡à¸šà¹„ซต์ที่เป็นอันตรายโดยอัตโนมัติ<ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">สัปดาห์</translation>
<translation id="5967867314010545767">ลบจาà¸à¸›à¸£à¸°à¸§à¸±à¸•à¸´à¸à¸²à¸£à¹€à¸‚้าชม</translation>
<translation id="5975083100439434680">ย่อ</translation>
+<translation id="598637245381783098">ไม่สามารถเปิดà¹à¸­à¸›à¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™</translation>
<translation id="5989320800837274978">ไม่มีà¸à¸²à¸£à¸£à¸°à¸šà¸¸à¸—ั้งพร็อà¸à¸‹à¸µà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹à¸šà¸šà¸„งที่หรือ URL สคริปต์ .pac</translation>
<translation id="5990559369517809815">คำขอไปยังเซิร์ฟเวอร์ถูà¸à¸šà¸¥à¹‡à¸­à¸à¹‚ดยส่วนขยาย</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">ตัวเลือà¸à¸šà¸±à¸•à¸£à¹à¸¥à¸°à¸—ี่อยู่มาจาภChrome โดยคุณสามารถจัดà¸à¸²à¸£à¸•à¸±à¸§à¹€à¸¥à¸·à¸­à¸à¹€à¸«à¸¥à¹ˆà¸²à¸™à¸µà¹‰à¹ƒà¸™<ph name="BEGIN_LINK" />à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า<ph name="END_LINK" /></translation>
<translation id="6016158022840135739">{COUNT,plural, =1{หน้า 1}other{หน้า #}}</translation>
<translation id="6017514345406065928">สีเขียว</translation>
+<translation id="6027201098523975773">ป้อนชื่อ</translation>
<translation id="6040143037577758943">ปิด</translation>
-<translation id="604124094241169006">อัตโนมัติ</translation>
<translation id="6042308850641462728">เพิ่มเติม</translation>
<translation id="6060685159320643512">ระวัง à¸à¸²à¸£à¸—ดลองนี้อาจเป็นอันตราย</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{ไม่มี}=1{1}other{#}}</translation>
@@ -543,9 +552,10 @@
ที่คุณอาจใช้งานอยู่</translation>
<translation id="614940544461990577">ลอง:</translation>
<translation id="6151417162996330722">ใบรับรองเซิร์ฟเวอร์มีระยะเวลาที่สามารถใช้ได้นานเà¸à¸´à¸™à¹„ป</translation>
-<translation id="615643356032862689">ระบบจะเà¸à¹‡à¸šà¹„ฟล์ที่ดาวน์โหลดà¹à¸¥à¸°à¸šà¸¸à¹Šà¸à¸¡à¸²à¸£à¹Œà¸à¹„ว้</translation>
+<translation id="6157877588268064908">หาà¸à¸•à¹‰à¸­à¸‡à¸à¸²à¸£à¸”ูวิธีà¸à¸²à¸£à¸ˆà¸±à¸”ส่งสินค้าà¹à¸¥à¸°à¸‚้อà¸à¸³à¸«à¸™à¸” โปรดเลือà¸à¸—ี่อยู่</translation>
<translation id="6165508094623778733">เรียนรู้เพิ่มเติม</translation>
<translation id="6177128806592000436">à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸à¸±à¸šà¹€à¸§à¹‡à¸šà¹„ซต์นี้ไม่ปลอดภัย</translation>
+<translation id="6184817833369986695">(รุ่น: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">ตรวจสอบà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸­à¸´à¸™à¹€à¸—อร์เน็ต</translation>
<translation id="6218753634732582820">ต้องà¸à¸²à¸£à¸™à¸³à¸—ี่อยู่ออà¸à¸ˆà¸²à¸ Chromium ใช่ไหม</translation>
<translation id="6251924700383757765">นโยบายความเป็นส่วนตัว</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;ทำซ้ำà¸à¸²à¸£à¸ˆà¸±à¸”ลำดับใหม่</translation>
<translation id="6263376278284652872">บุ๊à¸à¸¡à¸²à¸£à¹Œà¸ <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">à¸à¸¥à¸±à¸šà¸ªà¸¹à¹ˆà¸„วามปลอดภัย</translation>
+<translation id="6276112860590028508">หน้าเว็บจาà¸à¹€à¸£à¸·à¹ˆà¸­à¸‡à¸£à¸­à¸­à¹ˆà¸²à¸™à¸‚องคุณจะปราà¸à¸à¸—ี่นี่</translation>
+<translation id="6280223929691119688">ไม่สามารถนำส่งสินค้าไปยังที่อยู่นี้ โปรดเลือà¸à¸—ี่อยู่อื่น</translation>
<translation id="6282194474023008486">รหัสไปรษณีย์</translation>
<translation id="6290238015253830360">บทความที่à¹à¸™à¸°à¸™à¸³à¸ˆà¸°à¸›à¸£à¸²à¸à¸à¸—ี่นี่</translation>
<translation id="6305205051461490394">ไม่สามารถเข้าถึง <ph name="URL" /></translation>
@@ -566,7 +578,7 @@
<translation id="6355080345576803305">à¸à¸²à¸£à¸¥à¸šà¸¥à¹‰à¸²à¸‡à¹€à¸‹à¸ªà¸Šà¸±à¸™à¸ªà¸²à¸˜à¸²à¸£à¸“ะ</translation>
<translation id="6358450015545214790">นี่หมายถึงอะไร</translation>
<translation id="6386120369904791316">{COUNT,plural, =1{อีภ1 คำà¹à¸™à¸°à¸™à¸³}other{อีภ# คำà¹à¸™à¸°à¸™à¸³}}</translation>
-<translation id="6387478394221739770">หาà¸à¸ªà¸™à¹ƒà¸ˆà¹ƒà¸™à¸„ุณลัà¸à¸©à¸“ะสุดเจ๋งของ Chrome ใหม่ ลองใช้เวอร์ชันเบต้าของเราที่ chrome.com/beta</translation>
+<translation id="6387478394221739770">หาà¸à¸ªà¸™à¹ƒà¸ˆà¹ƒà¸™à¸Ÿà¸µà¹€à¸ˆà¸­à¸£à¹Œà¸ªà¸¸à¸”เจ๋งของ Chrome ใหม่ ลองใช้เวอร์ชันเบต้าของเราที่ chrome.com/beta</translation>
<translation id="6389758589412724634">Chromium หน่วยความจำเต็มเมื่อพยายามà¹à¸ªà¸”งหน้าเว็บนี้</translation>
<translation id="6404511346730675251">à¹à¸à¹‰à¹„ขบุ๊à¸à¸¡à¸²à¸£à¹Œà¸</translation>
<translation id="6410264514553301377">ป้อนวันหมดอายุà¹à¸¥à¸° CVC ของ <ph name="CREDIT_CARD" /></translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">ไม่สามารถตรวจสอบว่าใบรับรองถูà¸à¹€à¸žà¸´à¸à¸–อนหรือไม่</translation>
<translation id="6433490469411711332">à¹à¸à¹‰à¹„ขข้อมูลติดต่อ</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> ปà¸à¸´à¹€à¸ªà¸˜à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­</translation>
-<translation id="6443118737398455446">วันหมดอายุไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="6446608382365791566">เพิ่มข้อมูลเพิ่มเติม</translation>
<translation id="6451458296329894277">ยืนยันà¸à¸²à¸£à¸ªà¹ˆà¸‡à¹à¸šà¸šà¸Ÿà¸­à¸£à¹Œà¸¡à¸­à¸µà¸à¸„รั้ง</translation>
<translation id="6456339708790392414">à¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™à¸‚องคุณ</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">เซิร์ฟเวอร์นี้พิสูจน์ไม่ได้ว่าเป็น <ph name="DOMAIN" /> เพราะใบรับรองความปลอดภัยของเซิร์ฟเวอร์อาจถูà¸à¹€à¸žà¸´à¸à¸–อนไปà¹à¸¥à¹‰à¸§ สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">นโยบายอุปà¸à¸£à¸“์</translation>
<translation id="6477321094435799029">Chrome ได้ตรวจพบรหัสที่ผิดปà¸à¸•à¸´à¸šà¸™à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰à¹à¸¥à¸°à¹„ด้บล็อà¸à¸£à¸«à¸±à¸ªà¸”ังà¸à¸¥à¹ˆà¸²à¸§à¹€à¸žà¸·à¹ˆà¸­à¸›à¸à¸›à¹‰à¸­à¸‡à¸‚้อมูลส่วนบุคคลของคุณ (เช่น รหัสผ่าน หมายเลขโทรศัพท์ à¹à¸¥à¸°à¸šà¸±à¸•à¸£à¹€à¸„รดิต)</translation>
-<translation id="6477460825583319731">ที่อยู่อีเมลไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="6489534406876378309">เริ่มอัปโหลดข้อขัดข้อง</translation>
<translation id="6508722015517270189">รีสตาร์ท Chrome</translation>
-<translation id="6525462735697194615">เดือนที่หมดอายุไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="6529602333819889595">&amp;ทำซ้ำà¸à¸²à¸£à¸™à¸³à¸­à¸­à¸</translation>
<translation id="6534179046333460208">คำà¹à¸™à¸°à¸™à¸³ Physical Web</translation>
<translation id="6550675742724504774">ตัวเลือà¸</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> ค้นหา</translation>
<translation id="6644283850729428850">นโยบายนี้ถูà¸à¸¢à¸à¹€à¸¥à¸´à¸à¹à¸¥à¹‰à¸§</translation>
<translation id="6652240803263749613">เซิร์ฟเวอร์นี้พิสูจน์ไม่ได้ว่าเป็น <ph name="DOMAIN" /> เพราะระบบปà¸à¸´à¸šà¸±à¸•à¸´à¸à¸²à¸£à¸‚องคอมพิวเตอร์ไม่เชื่อถือใบรับรองความปลอดภัยของเซิร์ฟเวอร์นี้ สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="6665267558048410100">ตัวเลือà¸à¸à¸²à¸£à¸ˆà¸±à¸”ส่งดังà¸à¸¥à¹ˆà¸²à¸§à¹„ม่พร้อมใช้งาน โปรดลองใช้ตัวเลือà¸à¸­à¸·à¹ˆà¸™</translation>
<translation id="6671697161687535275">ต้องà¸à¸²à¸£à¸™à¸³à¸„ำà¹à¸™à¸°à¸™à¸³à¸ªà¸³à¸«à¸£à¸±à¸šà¹à¸šà¸šà¸Ÿà¸­à¸£à¹Œà¸¡à¸­à¸­à¸à¸ˆà¸²à¸ Chromium ใช่ไหม</translation>
<translation id="6685834062052613830">ออà¸à¸ˆà¸²à¸à¸£à¸°à¸šà¸šà¹à¸¥à¸°à¸•à¸±à¹‰à¸‡à¸„่าให้เสร็จสมบูรณ์</translation>
<translation id="6710213216561001401">à¸à¹ˆà¸­à¸™à¸«à¸™à¹‰à¸²</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">พร็อà¸à¸‹à¸µà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸œà¸´à¸”ปà¸à¸•à¸´à¸«à¸£à¸·à¸­à¸—ี่อยู่ไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="6727102863431372879">ตั้งค่า</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{ไม่มี}=1{1 รายà¸à¸²à¸£}other{# รายà¸à¸²à¸£}}</translation>
-<translation id="6743044928064272573">ตัวเลือà¸à¹ƒà¸™à¸à¸²à¸£à¸£à¸±à¸š</translation>
<translation id="674375294223700098">ข้อผิดพลาดใบรับรองของเซิร์ฟเวอร์ที่ไม่รู้จัà¸</translation>
<translation id="6753269504797312559">ค่านโยบาย</translation>
<translation id="6757797048963528358">อุปà¸à¸£à¸“์ของคุณเข้าสู่โหมดสลีปà¹à¸¥à¹‰à¸§</translation>
<translation id="6778737459546443941">ผู้ปà¸à¸„รองยังไม่ได้อนุมัติเว็บไซต์นี้</translation>
<translation id="6810899417690483278">รหัสà¸à¸²à¸£à¸›à¸£à¸±à¸šà¹à¸•à¹ˆà¸‡</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">ไม่สามารถโหลดข้อมูลภูมิภาค</translation>
<translation id="6831043979455480757">à¹à¸›à¸¥à¸ à¸²à¸©à¸²</translation>
<translation id="6839929833149231406">พื้นที่</translation>
<translation id="6874604403660855544">&amp;ทำซ้ำà¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">บัตรของคุณได้รับà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¹à¸¥à¹‰à¸§</translation>
<translation id="6897140037006041989">User agent</translation>
<translation id="6915804003454593391">ผู้ใช้:</translation>
+<translation id="6948701128805548767">หาà¸à¸•à¹‰à¸­à¸‡à¸à¸²à¸£à¸”ูวิธีà¸à¸²à¸£à¸£à¸±à¸šà¸ªà¸´à¸™à¸„้าà¹à¸¥à¸°à¸‚้อà¸à¸³à¸«à¸™à¸” โปรดเลือà¸à¸—ี่อยู่</translation>
<translation id="6957887021205513506">ใบรับรองของเซิร์ฟเวอร์น่าจะเป็นของปลอม</translation>
<translation id="6965382102122355670">ตà¸à¸¥à¸‡</translation>
<translation id="6965978654500191972">อุปà¸à¸£à¸“์</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">มีà¸à¸²à¸£à¸£à¸°à¸šà¸¸à¸—ั้งพร็อà¸à¸‹à¸µà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹à¸šà¸šà¸„งที่à¹à¸¥à¸° URL สคริปต์ .pac ไว้</translation>
<translation id="6989763994942163495">à¹à¸ªà¸”งà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าขั้นสูง...</translation>
<translation id="7000990526846637657">ไม่พบข้อมูลประวัติà¸à¸²à¸£à¹€à¸‚้าชม</translation>
-<translation id="7001663382399377034">เพิ่มผู้รับ</translation>
<translation id="7009986207543992532">คุณพยายามเข้าถึง <ph name="DOMAIN" /> à¹à¸•à¹ˆà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹à¸ªà¸”งใบรับรองที่มีระยะเวลาà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¹„ด้นานเà¸à¸´à¸™à¸à¸§à¹ˆà¸²à¸ˆà¸°à¹€à¸Šà¸·à¹ˆà¸­à¸–ือได้ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">บัà¸à¸Šà¸µ Google ของคุณอาจมีประวัติà¸à¸²à¸£à¸—่องเว็บในรูปà¹à¸šà¸šà¸­à¸·à¹ˆà¸™à¹† ที่ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">เà¸à¹ˆà¸²à¸à¸§à¹ˆà¸²</translation>
<translation id="7090678807593890770">ค้นหา <ph name="LINK" /> จาภGoogle</translation>
<translation id="7119414471315195487">ปิดà¹à¸—็บหรือโปรà¹à¸à¸£à¸¡à¸­à¸·à¹ˆà¸™à¹†</translation>
+<translation id="7129409597930077180">ไม่สามารถจัดส่งสินค้าไปยังที่อยู่นี้ โปรดเลือà¸à¸—ี่อยู่อื่น</translation>
+<translation id="7138472120740807366">วิธีà¸à¸²à¸£à¸™à¸³à¸ªà¹ˆà¸‡à¸ªà¸´à¸™à¸„้า</translation>
<translation id="7139724024395191329">เอมิเรต</translation>
<translation id="7155487117670177674">à¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™à¹„ม่ปลอดภัย</translation>
<translation id="7179921470347911571">เปิดใช้งานใหม่เดี๋ยวนี้</translation>
<translation id="7180611975245234373">รีเฟรช</translation>
<translation id="7182878459783632708">ไม่ได้à¸à¸³à¸«à¸™à¸”นโยบายไว้</translation>
<translation id="7186367841673660872">à¹à¸›à¸¥à¸«à¸™à¹‰à¸²à¹€à¸§à¹‡à¸šà¸™à¸µà¹‰à¸ˆà¸²à¸<ph name="ORIGINAL_LANGUAGE" />เป็น<ph name="LANGUAGE_LANGUAGE" />à¹à¸¥à¹‰à¸§</translation>
+<translation id="7192203810768312527">เพิ่มพื้นที่ว่าง <ph name="SIZE" /> เว็บไซต์บางà¹à¸«à¹ˆà¸‡à¸­à¸²à¸ˆà¹‚หลดช้าลงเมื่อคุณเข้าชมครั้งถัดไป</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ไม่เป็นไปตามมาตรà¸à¸²à¸™à¸„วามปลอดภัย</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LINK" /> เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸›à¸±à¸à¸«à¸²à¸™à¸µà¹‰</translation>
@@ -675,7 +686,6 @@
<translation id="7424977062513257142">หน้าที่à¸à¸±à¸‡à¹„ว้ในหน้าเว็บนี้บอà¸à¸§à¹ˆà¸²:</translation>
<translation id="7441627299479586546">หัวเรื่องนโยบายไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="7444046173054089907">เว็บไซต์นี้ถูà¸à¸šà¸¥à¹‡à¸­à¸</translation>
-<translation id="7444238235002594607">เลือà¸à¸—ี่อยู่ในà¸à¸²à¸£à¸£à¸±à¸šà¹€à¸žà¸·à¹ˆà¸­à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸§à¸´à¸˜à¸µà¹à¸¥à¸°à¸‚้อà¸à¸³à¸«à¸™à¸”ในà¸à¸²à¸£à¸£à¸±à¸š</translation>
<translation id="7445762425076701745">ไม่สามารถตรวจสอบความถูà¸à¸•à¹‰à¸­à¸‡à¸‚องข้อมูลประจำตัวของเซิร์ฟเวอร์ที่คุณเชื่อมต่ออยู่ได้ทั้งหมด คุณà¸à¸³à¸¥à¸±à¸‡à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸à¸±à¸šà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸—ี่ใช้ชื่อที่ใช้ได้เฉพาะในเครือข่ายของคุณ ซึ่งผู้ออà¸à¹ƒà¸šà¸£à¸±à¸šà¸£à¸­à¸‡à¸ à¸²à¸¢à¸™à¸­à¸à¹„ม่สามารถตรวจสอบà¸à¸²à¸£à¹€à¸›à¹‡à¸™à¹€à¸ˆà¹‰à¸²à¸‚องได้ เนื่องจาà¸à¸œà¸¹à¹‰à¸­à¸­à¸à¹ƒà¸šà¸£à¸±à¸šà¸£à¸­à¸‡à¸šà¸²à¸‡à¸£à¸²à¸¢à¸ˆà¸°à¸¢à¸±à¸‡à¸„งออà¸à¹ƒà¸šà¸£à¸±à¸šà¸£à¸­à¸‡à¹ƒà¸«à¹‰à¸à¸±à¸šà¸Šà¸·à¹ˆà¸­à¹€à¸«à¸¥à¹ˆà¸²à¸™à¸µà¹‰à¸­à¸¢à¸¹à¹ˆ คุณจึงไม่มีทางมั่นใจได้ว่าà¸à¸³à¸¥à¸±à¸‡à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸à¸±à¸šà¹€à¸§à¹‡à¸šà¹„ซต์ที่คุณต้องà¸à¸²à¸£à¸”ูโดยไม่ใช่ผู้โจมตี</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LINK" />เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸›à¸±à¸à¸«à¸²à¸™à¸µà¹‰</translation>
<translation id="7460163899615895653">à¹à¸—็บล่าสุดจาà¸à¸­à¸¸à¸›à¸à¸£à¸“์อื่นๆ จะปราà¸à¸à¸—ี่นี่</translation>
@@ -710,7 +720,7 @@
<translation id="7667346355482952095">โทเค็นนโยบายที่ส่งà¸à¸¥à¸±à¸šà¸§à¹ˆà¸²à¸‡à¹€à¸›à¸¥à¹ˆà¸²à¸«à¸£à¸·à¸­à¹„ม่ตรงà¸à¸±à¸šà¹‚ทเค็นปัจจุบัน</translation>
<translation id="7668654391829183341">อุปà¸à¸£à¸“์ที่ไม่รู้จัà¸</translation>
<translation id="7669271284792375604">ผู้โจมตีเว็บไซต์นี้อาจพยายามหลอà¸à¸¥à¹ˆà¸­à¹ƒà¸«à¹‰à¸„ุณติดตั้งโปรà¹à¸à¸£à¸¡à¸—ี่เป็นอันตรายต่อประสบà¸à¸²à¸£à¸“์à¸à¸²à¸£à¸—่องเว็บของคุณ (ตัวอย่างเช่น โดยà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸«à¸™à¹‰à¸²à¹à¸£à¸à¸«à¸£à¸·à¸­à¹à¸ªà¸”งโฆษณาเพิ่มเติมในเว็บไซต์ที่คุณเข้าชม)</translation>
-<translation id="7674629440242451245">หาà¸à¸ªà¸™à¹ƒà¸ˆà¹ƒà¸™à¸„ุณลัà¸à¸©à¸“ะใหม่ๆ สุดเจ๋งของ Chrome ลองใช้เวอร์ชันที่à¸à¸³à¸¥à¸±à¸‡à¸žà¸±à¸’นาของเราที่ chrome.com/dev</translation>
+<translation id="7674629440242451245">หาà¸à¸ªà¸™à¹ƒà¸ˆà¹ƒà¸™à¸Ÿà¸µà¹€à¸ˆà¸­à¸£à¹Œà¹ƒà¸«à¸¡à¹ˆà¹† สุดเจ๋งของ Chrome ลองใช้เวอร์ชันที่à¸à¸³à¸¥à¸±à¸‡à¸žà¸±à¸’นาของเราที่ chrome.com/dev</translation>
<translation id="7682287625158474539">จัดส่ง</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />ไปยัง <ph name="SITE" /> (ไม่ปลอดภัย)<ph name="END_LINK" /></translation>
<translation id="7716424297397655342">ไม่สามารถโหลดเว็บไซต์นี้จาà¸à¹à¸„ช</translation>
@@ -719,6 +729,7 @@
<translation id="7755287808199759310">ผู้ปà¸à¸„รองสามารถเลิà¸à¸šà¸¥à¹‡à¸­à¸à¹€à¸§à¹‡à¸šà¹„ซต์ให้คุณ</translation>
<translation id="7758069387465995638">ไฟร์วอลล์หรือซอฟต์à¹à¸§à¸£à¹Œà¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¹„วรัสอาจบล็อà¸à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸™à¸µà¹‰</translation>
<translation id="7761701407923456692">ใบรับรองของเซิร์ฟเวอร์ไม่ตรงà¸à¸±à¸š URL</translation>
+<translation id="7763386264682878361">โปรà¹à¸à¸£à¸¡à¹à¸¢à¸à¸§à¸´à¹€à¸„ราะห์ไฟล์ Manifest ของà¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™</translation>
<translation id="7764225426217299476">เพิ่มที่อยู่</translation>
<translation id="777702478322588152">เขตปà¸à¸„รอง</translation>
<translation id="7791543448312431591">เพิ่ม</translation>
@@ -732,6 +743,7 @@
<translation id="785549533363645510">อย่างไรà¸à¹‡à¸•à¸²à¸¡ ระบบยังมองเห็นคุณ à¸à¸²à¸£à¹€à¸‚้าสู่โหมดไม่ระบุตัวตนไม่ได้เป็นà¸à¸²à¸£à¸‹à¹ˆà¸­à¸™à¸à¸²à¸£à¸—่องเว็บจาà¸à¸™à¸²à¸¢à¸ˆà¹‰à¸²à¸‡à¸‚องคุณ ผู้ให้บริà¸à¸²à¸£à¸­à¸´à¸™à¹€à¸—อร์เน็ต หรือเว็บไซต์ที่คุณเข้าชม</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">ตรวจสอบ CVC à¹à¸¥à¸°à¸¥à¸­à¸‡à¸­à¸µà¸à¸„รั้ง</translation>
+<translation id="79338296614623784">ป้อนหมายเลขโทรศัพท์ที่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">ใบรับรองของเซิร์ฟเวอร์ยังไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="7942349550061667556">สีà¹à¸”ง</translation>
@@ -751,6 +763,7 @@
<translation id="8088680233425245692">à¸à¸²à¸£à¸”ูบทความล้มเหลว</translation>
<translation id="8089520772729574115">ไม่ถึง 1 MB</translation>
<translation id="8091372947890762290">à¸à¸³à¸¥à¸±à¸‡à¸£à¸­à¸à¸²à¸£à¹€à¸›à¸´à¸”ใช้งานบนเซิร์ฟเวอร์</translation>
+<translation id="8118489163946903409">วิธีà¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™</translation>
<translation id="8131740175452115882">ยืนยัน</translation>
<translation id="8134994873729925007">ไม่พบ<ph name="BEGIN_ABBR" />ที่อยู่ DNS<ph name="END_ABBR" /> ของเซิร์ฟเวอร์ของ <ph name="HOST_NAME" /></translation>
<translation id="8149426793427495338">คอมพิวเตอร์ของคุณเข้าสู่โหมดสลีปà¹à¸¥à¹‰à¸§</translation>
@@ -776,6 +789,7 @@
<translation id="8349305172487531364">à¹à¸–บบุ๊à¸à¸¡à¸²à¸£à¹Œà¸</translation>
<translation id="8363502534493474904">ปิดโหมดบนเครื่องบิน</translation>
<translation id="8364627913115013041">ไม่ได้ตั้งค่า</translation>
+<translation id="8368476060205742148">บริà¸à¸²à¸£ Google Play</translation>
<translation id="8380941800586852976">อันตราย</translation>
<translation id="8382348898565613901">บุ๊à¸à¸¡à¸²à¸£à¹Œà¸à¸—ี่คุณเข้าชมล่าสุดจะปราà¸à¸à¸—ี่นี่</translation>
<translation id="8398259832188219207">อัปโหลดรายงานข้อขัดข้องเมื่อ <ph name="UPLOAD_TIME" /></translation>
@@ -784,32 +798,30 @@
<translation id="8428213095426709021">à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า</translation>
<translation id="8433057134996913067">วิธีนี้จะทำให้คุณออà¸à¸ˆà¸²à¸à¸£à¸°à¸šà¸šà¸‚องเว็บไซต์ส่วนใหà¸à¹ˆ</translation>
<translation id="8437238597147034694">&amp;เลิà¸à¸—ำà¸à¸²à¸£à¸¢à¹‰à¸²à¸¢</translation>
-<translation id="8456681095658380701">ชื่อไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{บัตรเครดิต 1 ใบ}other{บัตรเครดิต # ใบ}}</translation>
<translation id="8483780878231876732">หาà¸à¸•à¹‰à¸­à¸‡à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸à¸²à¸£à¹Œà¸”จาà¸à¸šà¸±à¸à¸Šà¸µ Google ให้ลงชื่อเข้าใช้ Chrome</translation>
<translation id="8488350697529856933">ใช้à¸à¸±à¸š</translation>
-<translation id="8492969205326575646">ประเภทบัตรที่ไม่รองรับธุรà¸à¸£à¸£à¸¡à¸™à¸µà¹‰</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ใช้เวลาตอบà¸à¸¥à¸±à¸šà¸™à¸²à¸™à¹€à¸à¸´à¸™à¹„ป</translation>
<translation id="852346902619691059">เซิร์ฟเวอร์นี้พิสูจน์ไม่ได้ว่าเป็น <ph name="DOMAIN" /> เพราะระบบปà¸à¸´à¸šà¸±à¸•à¸´à¸à¸²à¸£à¸‚องอุปà¸à¸£à¸“์ไม่เชื่อถือใบรับรองความปลอดภัยของเซิร์ฟเวอร์นี้ สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="8532105204136943229">ปีที่หมดอายุ</translation>
<translation id="8543181531796978784">คุณสามารถ<ph name="BEGIN_ERROR_LINK" />รายงานปัà¸à¸«à¸²à¹ƒà¸™à¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸«à¸²<ph name="END_ERROR_LINK" />ได้ หรือหาà¸à¸„ุณเข้าใจถึงความเสี่ยงต่อความปลอดภัยของคุณ คุณสามารถ<ph name="BEGIN_LINK" />เข้าชมเว็บไซต์ที่ไม่ปลอดภัย<ph name="END_LINK" />ได้</translation>
<translation id="8553075262323480129">à¸à¸²à¸£à¹à¸›à¸¥à¸¥à¹‰à¸¡à¹€à¸«à¸¥à¸§à¹€à¸™à¸·à¹ˆà¸­à¸‡à¸ˆà¸²à¸à¹„ม่สามารถระบุภาษาของหน้าเว็บนี้ได้</translation>
<translation id="8559762987265718583">ไม่สามารถเริ่มà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸ªà¹ˆà¸§à¸™à¸•à¸±à¸§à¸à¸±à¸š <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ได้เนื่องจาà¸à¸§à¸±à¸™à¸—ี่à¹à¸¥à¸°à¹€à¸§à¸¥à¸²à¸‚องอุปà¸à¸£à¸“์ (<ph name="DATE_AND_TIME" />) ไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
-<translation id="8570229484593575558">ระบบ|จะไม่บันทึà¸|ข้อมูลนี้:#ประวัติà¸à¸²à¸£à¸—่องเว็บ#à¸à¸²à¸£à¸„้นหา#ข้อมูลคุà¸à¸à¸µà¹‰</translation>
<translation id="8571890674111243710">à¸à¸³à¸¥à¸±à¸‡à¹à¸›à¸¥à¸«à¸™à¹‰à¸²à¹€à¸§à¹‡à¸šà¸™à¸µà¹‰à¹€à¸›à¹‡à¸™à¸ à¸²à¸©à¸²<ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">ผู้อื่น|อาจยังมองเห็น|à¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸‚องคุณ:#เว็บไซต์ที่คุณเข้าชม#นายจ้าง#ผู้ให้บริà¸à¸²à¸£à¸­à¸´à¸™à¹€à¸—อร์เน็ต</translation>
<translation id="858637041960032120">เพิ่มเบอร์โทร
</translation>
<translation id="859285277496340001">ใบรับรองไม่ระบุวิธีà¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸§à¹ˆà¸²à¸¡à¸µà¸à¸²à¸£à¹€à¸žà¸´à¸à¸–อนไปà¹à¸¥à¹‰à¸§à¸«à¸£à¸·à¸­à¹„ม่</translation>
<translation id="8620436878122366504">ผู้ปà¸à¸„รองยังไม่ได้อนุมัติเว็บไซต์นี้</translation>
<translation id="8647750283161643317">รีเซ็ตทั้งหมดเป็นค่าเริ่มต้น</translation>
<translation id="8703575177326907206">à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณไปยัง <ph name="DOMAIN" /> ไม่ได้รับà¸à¸²à¸£à¹€à¸‚้ารหัส</translation>
+<translation id="8718314106902482036">à¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™à¹„ม่เสร็จสมบูรณ์</translation>
<translation id="8725066075913043281">ลองอีà¸à¸„รั้ง</translation>
<translation id="8728672262656704056">คุณได้เข้าสู่โหมดไม่ระบุตัวตนà¹à¸¥à¹‰à¸§</translation>
<translation id="8730621377337864115">เสร็จสิ้น</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="8759274551635299824">บัตรนี้หมดอายุà¹à¸¥à¹‰à¸§</translation>
<translation id="8790007591277257123">&amp;ทำซ้ำà¸à¸²à¸£à¸™à¸³à¸­à¸­à¸</translation>
-<translation id="8798099450830957504">ค่าเริ่มต้น</translation>
<translation id="8800988563907321413">คำà¹à¸™à¸°à¸™à¸³à¹ƒà¸™à¸šà¸£à¸´à¹€à¸§à¸“ใà¸à¸¥à¹‰à¹€à¸„ียงจะปราà¸à¸à¸—ี่นี่</translation>
<translation id="8820817407110198400">บุ๊à¸à¸¡à¸²à¸£à¹Œà¸</translation>
<translation id="883848425547221593">บุ๊à¸à¸¡à¸²à¸£à¹Œà¸à¸­à¸·à¹ˆà¸™à¹†</translation>
@@ -819,6 +831,7 @@
<translation id="8866481888320382733">ข้อผิดพลาดในà¸à¸²à¸£à¹à¸¢à¸à¸§à¸´à¹€à¸„ราะห์à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่านโยบาย</translation>
<translation id="8866959479196209191">หน้านี้บอà¸à¸§à¹ˆà¸²:</translation>
<translation id="8870413625673593573">เพิ่งปิด</translation>
+<translation id="8874824191258364635">ป้อนหมายเลขบัตรที่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="8876793034577346603">ไม่สามารถà¹à¸¢à¸à¸§à¸´à¹€à¸„ราะห์à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าเครือข่าย</translation>
<translation id="8877192140621905067">เมื่อคุณยืนยันà¹à¸¥à¹‰à¸§ รายละเอียดบัตรของคุณจะà¹à¸Šà¸£à¹Œà¸à¸±à¸šà¹€à¸§à¹‡à¸šà¹„ซต์นี้</translation>
<translation id="8889402386540077796">โทนสี</translation>
@@ -828,7 +841,6 @@
<translation id="8931333241327730545">คุณต้องà¸à¸²à¸£à¸šà¸±à¸™à¸—ึà¸à¸šà¸±à¸•à¸£à¸™à¸µà¹‰à¹ƒà¸™à¸šà¸±à¸à¸Šà¸µ Google ไหม</translation>
<translation id="8932102934695377596">นาฬิà¸à¸²à¸Šà¹‰à¸²à¹€à¸à¸´à¸™à¹„ป</translation>
<translation id="8954894007019320973">(ต่อ)</translation>
-<translation id="895548565263634352">อ่านเรื่องราวจาภ<ph name="ARTICLE_PUBLISHER" /> à¹à¸¥à¸°à¸­à¸µà¸à¸à¸§à¹ˆà¸² <ph name="OTHER_ARTICLE_COUNT" /> บทความ</translation>
<translation id="8971063699422889582">ใบรับรองของเซิร์ฟเวอร์หมดอายุà¹à¸¥à¹‰à¸§</translation>
<translation id="8986494364107987395">ส่งสถิติà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¹à¸¥à¸°à¸£à¸²à¸¢à¸‡à¸²à¸™à¸‚้อขัดข้องไปยัง Google โดยอัตโนมัติ</translation>
<translation id="8987927404178983737">เดือน</translation>
@@ -846,7 +858,6 @@
<translation id="9068849894565669697">เลือà¸à¸ªà¸µ</translation>
<translation id="9076283476770535406">เว็บไซต์นี้อาจมีเนื้อหาสำหรับผู้ใหà¸à¹ˆ</translation>
<translation id="9078964945751709336">ต้องระบุข้อมูลเพิ่มเติม</translation>
-<translation id="9094175695478007090">ไม่สามารถเปิดà¹à¸­à¸›à¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™</translation>
<translation id="9103872766612412690">โดยทั่วไป <ph name="SITE" /> จะใช้à¸à¸²à¸£à¹€à¸‚้ารหัสเพื่อปà¸à¸›à¹‰à¸­à¸‡à¸‚้อมูลของคุณ เมื่อ Chromium พยายามเชื่อมต่อà¸à¸±à¸š <ph name="SITE" /> ในครั้งนี้ เว็บไซต์ดังà¸à¸¥à¹ˆà¸²à¸§à¸ªà¹ˆà¸‡à¸‚้อมูลรับรองที่ผิดปà¸à¸•à¸´à¹à¸¥à¸°à¹„ม่ถูà¸à¸•à¹‰à¸­à¸‡à¸à¸¥à¸±à¸šà¸¡à¸² เหตุà¸à¸²à¸£à¸“์นี้อาจเà¸à¸´à¸”ขึ้นเมื่อผู้บุà¸à¸£à¸¸à¸à¸žà¸¢à¸²à¸¢à¸²à¸¡à¸›à¸¥à¸­à¸¡à¹€à¸›à¹‡à¸™ <ph name="SITE" /> หรือหน้าจอà¸à¸²à¸£à¸¥à¸‡à¸Šà¸·à¹ˆà¸­à¹€à¸‚้าใช้ Wi-Fi รบà¸à¸§à¸™à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­ ข้อมูลของคุณยังปลอดภัยอยู่เนื่องจาภChromium หยุดà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸à¹ˆà¸­à¸™à¸¡à¸µà¸à¸²à¸£à¹à¸¥à¸à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸‚้อมูล</translation>
<translation id="9137013805542155359">à¹à¸ªà¸”งหน้าเว็บเดิม</translation>
<translation id="9137248913990643158">โปรดเปิดà¹à¸¥à¸°à¸¥à¸‡à¸Šà¸·à¹ˆà¸­à¹€à¸‚้าใช้ Chrome à¸à¹ˆà¸­à¸™à¹ƒà¸Šà¹‰à¹à¸­à¸›à¸™à¸µà¹‰</translation>
diff --git a/chromium/components/strings/components_strings_tr.xtb b/chromium/components/strings/components_strings_tr.xtb
index 9c7faae99c0..75426a1332a 100644
--- a/chromium/components/strings/components_strings_tr.xtb
+++ b/chromium/components/strings/components_strings_tr.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="tr">
<translation id="1008557486741366299">Åžimdi DeÄŸil</translation>
<translation id="1015730422737071372">Diğer ayrıntıları sağlayın</translation>
+<translation id="1021110881106174305">Kabul edilen kartlar</translation>
<translation id="1032854598605920125">Saat yönünde döndür</translation>
<translation id="1038842779957582377">bilinmeyen ad</translation>
<translation id="1050038467049342496">Diğer uygulamaları kapatın</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">DeÄŸeri gizle</translation>
<translation id="1228893227497259893">Yanlış varlık tanımlayıcı</translation>
<translation id="1232569758102978740">Adsız</translation>
+<translation id="1263231323834454256">Okuma listesi</translation>
<translation id="1264126396475825575">Kilitlenme raporu yakalanma zamanı: <ph name="CRASH_TIME" /> (henüz yüklenmedi veya yoksayıldı)</translation>
<translation id="1285320974508926690">Bu siteyi hiçbir zaman çevirme</translation>
<translation id="129553762522093515">Son kapatılan</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromium Otomatik Doldurma ayarları...</translation>
<translation id="1374468813861204354">öneriler</translation>
<translation id="1375198122581997741">Sürüm Hakkında</translation>
+<translation id="1377321085342047638">Kart Numarası</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> hiç veri göndermedi.</translation>
<translation id="1407135791313364759">Tümünü aç</translation>
<translation id="1413809658975081374">Gizlilik hatası</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Geçmiş</translation>
<translation id="1645368109819982629">Desteklenmeyen protokol</translation>
<translation id="1656489000284462475">Alma</translation>
+<translation id="1663943134801823270">Kartlar ve adresler Chrome'dan alınmaktadır. Bu bilgileri <ph name="BEGIN_LINK" />Ayarlar<ph name="END_LINK" />'dan yönetebilirsiniz.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> normalde bilgilerinizi korumak için şifreleme kullanmaktadır. Google Chrome bu sefer <ph name="SITE" /> sitesine bağlanmayı denediğinde, web sitesi sıra dışı ve yanlış kimlik bilgileri döndürdü. Bir saldırgan <ph name="SITE" /> gibi davranmaya çalışıyor olabilir ya da bir Kablosuz oturum açma ekranı bağlantıyı kesmiştir. Google Chrome herhangi bir veri alışverişinden önce bağlantıyı durdurduğu için bilgileriniz hâlâ güvendedir.</translation>
<translation id="168328519870909584">Şu anda <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> sitesinde bulunan saldırganlar, cihazınıza bilgilerinizi (örneğin fotoğraflar, şifreler, mesajlar ve kredi kartları) çalacak veya silecek tehlikeli uygulamalar yüklemeyi deneyebilir.</translation>
<translation id="168841957122794586">Sunucu sertifikasında zayıf bir şifreleme anahtarı var.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Bu siteyi ziyaret etmek için <ph name="NAME" /> size izin vermelidir</translation>
+<translation id="1721424275792716183">* Zorunlu alan</translation>
<translation id="1728677426644403582">Bir web sayfasının kaynak kodunu görüntülüyorsunuz</translation>
+<translation id="173080396488393970">Bu kart türü desteklenmiyor</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Sistem yöneticisiyle iletişime geçmeyi deneyin.</translation>
+<translation id="1740951997222943430">Geçerli bir son kullanma ayı girin</translation>
<translation id="1745358365027406341">Sayfayı daha sonra indir</translation>
<translation id="17513872634828108">Açık sekmeler</translation>
<translation id="1753706481035618306">Sayfa numarası</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Lütfen senkronizasyon parolanızı güncelleyin.</translation>
<translation id="1787142507584202372">Açık sekmeleriniz burada görünür</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Teslimat yöntemlerini ve gereksinimlerini kontrol etmek için teslimat adresi seçin.</translation>
+<translation id="1803264062614276815">Kart Sahibinin Adı</translation>
<translation id="1803678881841855883">Google Güvenli Tarama, yakın bir zamanda <ph name="SITE" /> web sitesinde <ph name="BEGIN_LINK" />kötü amaçlı yazılım tespit etti<ph name="END_LINK" />. Normalde güvenli olan web sitelerine bazen kötü amaçlı yazılımlar bulaşır. Kötü amaçlı içerik, kötü amaçlı yazılım dağıtımcısı olduğu bilinen <ph name="SUBRESOURCE_HOST" /> kaynağından gelmektedir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Eklenme tarihi: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Geçersiz istek veya istek parametreleri</translation>
<translation id="1826516787628120939">Kontrol ediliyor</translation>
<translation id="1834321415901700177">Bu site zararlı programlar içeriyor</translation>
<translation id="1842969606798536927">Ödeme</translation>
-<translation id="1864455488461349376">Teslimat seçeneği</translation>
<translation id="1871208020102129563">Proxy, bir .pac komut dosyası URL'sini değil, sabit proxy sunucuları kullanacak şekilde ayarlanır.</translation>
<translation id="1871284979644508959">Zorunlu alan</translation>
<translation id="187918866476621466">Başlangıç sayfalarını aç</translation>
<translation id="1883255238294161206">Listeyi daralt</translation>
<translation id="1898423065542865115">Filtreleme</translation>
<translation id="194030505837763158"><ph name="LINK" /> adresine git</translation>
-<translation id="1946821392246652573">Kabul edilen kartlar</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> Yer Ä°ÅŸaretleri</translation>
<translation id="1973335181906896915">Serileştirme hatası</translation>
<translation id="1974060860693918893">GeliÅŸmiÅŸ</translation>
<translation id="1978555033938440688">Donanım Yazılımı Sürümü</translation>
+<translation id="1995859865337580572">Lütfen CVC'nizi doğrulayın</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{ve 1 uygulama daha}other{ve # uygulama daha}}</translation>
-<translation id="2020194265157481222">Kart üzerindeki isim gerekli</translation>
<translation id="2025186561304664664">Proxy, otomatik yapılandırıldı değerine ayarlandı.</translation>
<translation id="2030481566774242610">Åžunu mu demek istediniz?: <ph name="LINK" /></translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Proxy'yi ve güvenlik duvarını kontrol etme<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Bugün</translation>
<translation id="2154054054215849342">Senkronizasyon alan adınızda kullanılamıyor</translation>
<translation id="2154484045852737596">Kartı düzenle</translation>
-<translation id="2156993118928861787">Geçersiz adres</translation>
<translation id="2166049586286450108">Tam Yönetici Erişimi</translation>
<translation id="2166378884831602661">Bu site güvenli bağlantı sağlayamıyor</translation>
<translation id="2181821976797666341">Politikalar</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adres}other{# adres}}</translation>
+<translation id="2202020181578195191">Geçerli bir son kullanma yılı girin</translation>
<translation id="2212735316055980242">Politika bulunamadı</translation>
<translation id="2213606439339815911">GiriÅŸler getiriliyor...</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />Tanılama uygulamasını<ph name="END_LINK" /> kullanarak bağlantınızı düzeltin</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Ä°nternet eriÅŸiminiz engellendi</translation>
<translation id="230155334948463882">Yeni bir kart mı?</translation>
<translation id="2305919008529760154">Bu sunucu, <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Güvenlik sertifikası hileli bir şekilde yayınlanmış olabilir. Bu durum, yanlış yapılandırmadan veya bağlantınıza müdahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Kart ve adres seçenekleri Google Hesabınızdan (<ph name="ACCOUNT_EMAIL" />) ve Chrome'dan alınmıştır. Bunları <ph name="BEGIN_LINK" />Ayarlar<ph name="END_LINK" />'da yönetebilirsiniz.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> için kullanıcı adı ve şifre gerekiyor.</translation>
<translation id="2318774815570432836"><ph name="SITE" /> web sitesi HSTS kullandığı için bu 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. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">DiÄŸer yer iÅŸaretleri</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Kuruluşun varsayılan ayarı</translation>
<translation id="2386255080630008482">Sunucunun sertifikası iptal edildi.</translation>
<translation id="2392959068659972793">Hiçbir değer ayarlanmamış politikaları göster</translation>
+<translation id="239429038616798445">Bu gönderim yöntemi kullanılamıyor. Farklı bir yöntem deneyin.</translation>
<translation id="2396249848217231973">Silmeyi &amp;geri al</translation>
<translation id="2460160116472764928">Google Güvenli Tarama, yakın bir zamanda <ph name="SITE" /> web sitesinde <ph name="BEGIN_LINK" />kötü amaçlı yazılım tespit etti<ph name="END_LINK" />. Normalde güvenli olan web sitelerine bazen kötü amaçlı yazılımlar bulaşır. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Doldur</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Ağ Teşhislerini Çalıştırma<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Geçersiz arama URL'si.</translation>
<translation id="2491120439723279231">Sunucu sertifikası hatalar içeriyor.</translation>
-<translation id="24943777258388405">Geçersiz telefon numarası</translation>
<translation id="2495083838625180221">JSON Ayrıştırıcı</translation>
<translation id="2495093607237746763">İşaretlenirse Chromium, formları daha hızlı doldurma amacıyla kartınızın bir kopyasını bu cihazda depolar.</translation>
<translation id="2498091847651709837">Yeni kart tara</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> geçersiz bir yanıt gönderdi.</translation>
<translation id="2552545117464357659">Daha yeni</translation>
<translation id="2556876185419854533">Düzenlemeyi &amp;Geri Al</translation>
+<translation id="2587730715158995865"><ph name="ARTICLE_PUBLISHER" /> adlı yayıncıdan. Bunu ve diğer <ph name="OTHER_ARTICLE_COUNT" /> haberi okuyun.</translation>
<translation id="2587841377698384444">Dizin API'sı Kimliği:</translation>
<translation id="2597378329261239068">Doküman şifre korumalı. Lütfen şifreyi girin.</translation>
<translation id="2609632851001447353">Varyasyonlar</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Bağlantı Teşhislerini Çalıştırma<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">Tamam</translation>
<translation id="2742870351467570537">Seçilen öğeleri kaldır</translation>
+<translation id="277133753123645258">Gönderim yöntemi</translation>
<translation id="277499241957683684">Eksik cihaz kaydı</translation>
<translation id="2784949926578158345">Bağlantı sıfırlandı.</translation>
<translation id="2794233252405721443">Site engellenmiÅŸ</translation>
-<translation id="2812680587231492111">Belirtilen alım seçeneği kullanılamıyor. Farklı bir seçenek deneyin.</translation>
<translation id="2824775600643448204">Adres ve arama çubuğu</translation>
<translation id="2826760142808435982">Bağlantı <ph name="CIPHER" /> kullanılarak şifrelenmiş ve kimliği doğrulanmıştır. Anahtar değişim mekanizması olarak <ph name="KX" /> kullanılır.</translation>
<translation id="2835170189407361413">Formu temizle</translation>
-<translation id="2849041323157393173">Belirtilen teslimat seçeneği kullanılamıyor. Farklı bir seçenek deneyin.</translation>
<translation id="2889159643044928134">Yeniden Yükleme</translation>
<translation id="2900469785430194048">Bu web sayfası görüntülenmeye çalışılırken Google Chrome'da bellek kalmadı.</translation>
<translation id="2909946352844186028">Bir ağ değişikliği algılandı.</translation>
<translation id="2916038427272391327">Diğer programları kapatın</translation>
<translation id="2922350208395188000">Sunucunun sertifikası kontrol edilemiyor.</translation>
+<translation id="2928905813689894207">Fatura Adresi</translation>
<translation id="2948083400971632585">Ayarlar sayfasından, bir bağlantı için yapılandırılmış proxy'leri devre dışı bırakabilirsiniz.</translation>
<translation id="2955913368246107853">Bulma çubuğunu kapat</translation>
<translation id="2958431318199492670">Ağ yapılandırması ONC standardıyla uyumlu değil. Yapılandırmanın bazı bölümleri içe aktarılamaz.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">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, Google Chrome bu sertifikaları doğrulayamıyor.</translation>
<translation id="2972581237482394796">&amp;Yinele</translation>
<translation id="2985306909656435243">Bu seçenek etkinleştirildiğinde Chromium, formları daha hızlı doldurmak için kartınızın bir kopyasını bu cihazda saklar.</translation>
+<translation id="2985398929374701810">Geçerli bir adres girin</translation>
+<translation id="2986368408720340940">Bu alım yöntemi kullanılamıyor. Farklı bir yöntem deneyin.</translation>
<translation id="2991174974383378012">Web Siteleriyle PaylaÅŸma</translation>
<translation id="3005723025932146533">Kaydedilen kopyayı göster</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> numaralı kartın CVC kodunu girin. Onayladığınızda kart ayrıntılarınız bu siteyle paylaşılacaktır.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{senkronize edilmiş cihazlarda en az 1 öğe}=1{1 öğe (ve senkronize edilmiş cihazlarda daha fazlası)}other{# öğe (ve senkronize edilmiş cihazlarda daha fazlası)}}</translation>
<translation id="3041612393474885105">Sertifika Bilgileri</translation>
<translation id="3063697135517575841">Chrome şu anda kartınızı onaylayamıyor. Lütfen daha sonra tekrar deneyin.</translation>
+<translation id="3064966200440839136">Harici bir uygulama üzerinden ödeme gerçekleştirmek için gizli moddan çıkılacak. Devam edilsin mi?</translation>
<translation id="3093245981617870298">Çevrimdışısınız.</translation>
<translation id="3105172416063519923">Öğe Kimliği:</translation>
<translation id="3109728660330352905">Bu sayfayı görüntüleme yetkiniz yok.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Bağlantı Teşhislerini çalıştırmayı deneyin<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Yanıtın kodu çözülemedi</translation>
-<translation id="3149891296864842641">Gönderim seçeneği</translation>
<translation id="3150653042067488994">Geçici sunucu hatası</translation>
+<translation id="3154506275960390542">Bu sayfada güvenli şekilde gönderilemeyecek bir form bulunmaktadır. Gönderdiğiniz veriler, aktarım sırasında başkaları tarafından görüntülenebilir veya bir saldırgan tarafından sunucunun alacağı verileri değiştirmek amacıyla kullanılabilir.</translation>
<translation id="3157931365184549694">Geri yükle</translation>
<translation id="3167968892399408617">Gizli sekmelerde görüntülediğiniz sayfalar, açık olan tüm gizli sekmeler kapatıldıktan sonra tarayıcınızın geçmişinden, çerez deposundan veya arama geçmişinden silinecektir. İndirdiğiniz dosyalar veya oluşturduğunuz yer işaretleri kalacaktır.</translation>
<translation id="3169472444629675720">Bul</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Bu siteye erişim isteğiniz <ph name="NAME" /> adlı kullanıcıya gönderilemedi. Lütfen tekrar deneyin.</translation>
<translation id="3355823806454867987">Proxy ayarlarını değiştir...</translation>
<translation id="3369192424181595722">Saat hatası</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> öğe daha...</translation>
<translation id="337363190475750230">Temel hazırlık iptal edildi</translation>
<translation id="3377188786107721145">Politika ayrıştırma hatası</translation>
<translation id="3380365263193509176">Bilinmeyen hata</translation>
<translation id="3380864720620200369">Ä°stemci KimliÄŸi:</translation>
<translation id="3391030046425686457">Teslimat adresi</translation>
+<translation id="3395827396354264108">Alım yöntemi</translation>
<translation id="340013220407300675">Saldırganlar <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> sitesinden bilgilerinizi çalmaya çalışıyor olabilir (örneğin, şifreler, mesajlar veya kredi kartı bilgileri).</translation>
<translation id="3422248202833853650">Bellekte yer açmak için diğer programlardan çıkmayı deneyin.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> ana makinesine şu anda ulaşılamıyor.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Getirme aralığı:</translation>
<translation id="3462200631372590220">GeliÅŸmiÅŸ bilgileri gizle</translation>
+<translation id="3467763166455606212">Kart sahibinin adı zorunludur</translation>
+<translation id="3478058380795961209">Son Kullanım Ayı</translation>
<translation id="3479539252931486093">Bu beklenmedik bir durum mu? <ph name="BEGIN_LINK" />Bize bildirin<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Åžimdi deÄŸil</translation>
<translation id="348000606199325318">Kilitlenme KimliÄŸi: <ph name="CRASH_LOCAL_ID" /> (Sunucu KimliÄŸi: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Şu anda ebeveyninize erişemedik. Lütfen tekrar deneyin.</translation>
<translation id="3528171143076753409">Sunucunun sertifikasına güvenilmiyor.</translation>
-<translation id="3538531656504267329">Geçersiz son kullanım yılı</translation>
<translation id="3539171420378717834">Bu kartın bir kopyasını bu cihazda tut</translation>
<translation id="3542684924769048008">Şunun için şifre kullan:</translation>
<translation id="3549644494707163724">Senkronize edilen tüm verileri kendi senkronizasyon parolanızla şifreleyin</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Ayrıntıları gizle</translation>
<translation id="3587482841069643663">Tümü</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Geçerli bir son kullanma tarihi girin</translation>
<translation id="36224234498066874">Göz Atma Verilerini Temizle...</translation>
<translation id="362276910939193118">Tam Geçmişi Göster</translation>
<translation id="3623476034248543066">Değeri göster</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Åžifre:</translation>
<translation id="3696411085566228381">yok</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Gönderim yöntemlerini ve gereksinimleri kontrol etmek için bir gönderim adresi seçin.</translation>
<translation id="370665806235115550">Yükleniyor...</translation>
<translation id="3712624925041724820">Lisanslar bitti</translation>
<translation id="3714780639079136834">Mobil veriyi veya kablosuz bağlantıyı açma</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Kopyaladığınız bağlantı</translation>
<translation id="375403751935624634">Çeviri, bir sunucu hatası nedeniyle başarısız oldu.</translation>
<translation id="3759461132968374835">Son zamanda herhangi bir kilitlenme bildirmediniz. Kilitlenme bildirme özelliği devre dışıyken oluşan kilitlenmeler burada görünmez.</translation>
+<translation id="3787705759683870569">Son kullanma tarihi: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Proxy sunucu kullanıyorsanız...</translation>
<translation id="3828924085048779000">BoÅŸ parolaya izin verilmez.</translation>
<translation id="3845539888601087042">Oturum açtığınız cihazlardan geçmiş bilgileri gösteriliyor. <ph name="BEGIN_LINK" />Daha fazla bilgi edinin<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chromium'un bu kartı kaydetmesini istiyor musunuz?</translation>
<translation id="4171400957073367226">Geçersiz doğrulama imzası</translation>
-<translation id="4176463684765177261">Devre dışı</translation>
<translation id="4196861286325780578">Taşımayı &amp;yeniden yap</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Güvenlik duvarı ve virüsten korunma yapılandırmalarını kontrol etme<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{yok}=1{1 uygulama ($1)}=2{2 uygulama ($1, $2)}other{# uygulama ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">arama sonuçları</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> giriş sertifikanızı kabul etmedi veya giriş sertifikası sağlanmamış olabilir.</translation>
<translation id="443673843213245140">Proxy kullanımı devre dışı, ancak açık bir proxy yapılandırması belirtildi.</translation>
-<translation id="4446242550670694251">Artık gizli göz atabilirsiniz ve bu cihazı kullanan diğer kişiler etkinliğinizi görmez.</translation>
<translation id="4492190037599258964">'<ph name="SEARCH_STRING" />' için arama sonuçları</translation>
<translation id="4506176782989081258">Doğrulama hatası: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">Sistem yöneticisiyle iletişime geçme</translation>
<translation id="450710068430902550">Yöneticiyle Paylaşma</translation>
+<translation id="4515275063822566619">Kart ve adres bilgileri Chrome'dan ve Google Hesabınızdan (<ph name="ACCOUNT_EMAIL" />) alınmaktadır. Bunları <ph name="BEGIN_LINK" />Ayarlar<ph name="END_LINK" />'dan yönetebilirsiniz.</translation>
<translation id="4522570452068850558">Ayrıntılar</translation>
<translation id="4558551763791394412">Uzantılarınızı devre dışı bırakmayı deneyin</translation>
<translation id="457875822857220463">Teslimat</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Sayfaya sığdır</translation>
<translation id="483020001682031208">Gösterilecek Fiziksel Web sayfası yok</translation>
<translation id="4850886885716139402">Görüntüle</translation>
+<translation id="4854362297993841467">Bu teslimat yöntemi kullanılamıyor. Farklı bir yöntem deneyin.</translation>
<translation id="4858792381671956233">Ebeveynlerinize bu siteyi ziyaret etmenizin uygun olup olmadığını sordunuz</translation>
<translation id="4880827082731008257">Geçmişte ara</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Bu sayfa, bilinmeyen bir dilden <ph name="LANGUAGE_LANGUAGE" /> diline çevrildi</translation>
<translation id="4923459931733593730">Ödeme</translation>
<translation id="4926049483395192435">Belirtilmelidir.</translation>
-<translation id="4941291666397027948">* zorunlu alanı belirtir</translation>
<translation id="495170559598752135">Ä°ÅŸlemler</translation>
<translation id="4958444002117714549">Listeyi geniÅŸlet</translation>
<translation id="4962322354953122629">Bu sunucu <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Chrome, sunucunun güvenlik sertifikasına güvenmiyor. Bu durum, yanlış yapılandırmadan veya bağlantınıza müdahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Hatalı parola</translation>
<translation id="5056549851600133418">Size uygun makaleler</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Proxy adresini kontrol etme<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Çerez yok}=1{1 site çerez kullanıyor. }other{# site çerez kullanıyor. }}</translation>
<translation id="5087286274860437796">Sunucu sertifikası şu anda geçerli değil.</translation>
<translation id="5087580092889165836">Kart ekle</translation>
<translation id="5089810972385038852">Eyalet</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Göster</translation>
<translation id="5308689395849655368">Kilitlenme bildirme devre dışı.</translation>
<translation id="5317780077021120954">Kaydet</translation>
-<translation id="5326702247179446998">Alıcı gerekli</translation>
<translation id="5327248766486351172">Ad</translation>
<translation id="5337705430875057403"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> sitesindeki saldırganlar, yazılım yükleme veya kişisel bilgilerinizi (örneğin, şifreler, telefon numaraları veya kredi kartları) ortaya çıkarma gibi tehlikeli şeyler yapmak için sizi kandırabilir.</translation>
-<translation id="53553865750799677">Alma adresi desteklenmiyor. Farklı bir adres seçin.</translation>
<translation id="5359637492792381994">Bu sunucu <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Güvenlik sertifikası şu anda geçerli değil. Bu durum, yanlış yapılandırmadan veya bağlantınıza müdahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Politika ayarları saklanamadı</translation>
<translation id="5386426401304769735">Bu sitenin sertifika zinciri, SHA-1 kullanılarak imzalanmış bir sertifika içeriyor.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102"><ph name="SITE" /> web sitesindeki yerleşik bir sayfanın mesajı:</translation>
<translation id="5556459405103347317">Yeniden Yükle</translation>
<translation id="5565735124758917034">Etkin</translation>
+<translation id="5571083550517324815">Bu adresten alım yapılamıyor. Farklı bir adres seçin.</translation>
<translation id="5572851009514199876">Chrome'un bu siteye erişmenize izin verilip verilmediğini kontrol edebilmesi için lütfen Chrome'u başlatıp oturum açın.</translation>
-<translation id="5575380383496039204">Teslimat adresi desteklenmiyor. Farklı bir adres seçin.</translation>
<translation id="5580958916614886209">Son kullanma tarihinin ayını kontrol edip tekrar deneyin</translation>
<translation id="560412284261940334">Yönetim desteklenmiyor</translation>
<translation id="5610142619324316209">Bağlantınızı kontrol etme</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">Bu web sitesinin kimliği doğrulanmadı.</translation>
<translation id="5720705177508910913">Geçerli kullanıcı</translation>
<translation id="5732392974455271431">Ebeveynleriniz engellemeyi kaldırabilir</translation>
-<translation id="57586589942790530">Geçersiz kart numarası</translation>
+<translation id="5763042198335101085">Geçerli bir e-posta adresi girin</translation>
+<translation id="5765072501007116331">Teslimat yöntemlerini ve gereksinimleri görmek için bir adres seçin</translation>
<translation id="5784606427469807560">Kartınız onaylanırken bir sorun oluştu. İnternet bağlantınızı kontrol edip tekrar deneyin.</translation>
<translation id="5785756445106461925">Ayrıca, bu sayfa güvenli olmayan başka kaynaklar içeriyor. Bu kaynaklar, aktarım sırasında başkaları tarafından görülebilir ve bir saldırgan tarafından sayfanın görünüşünü değiştirmek üzere kullanılabilir.</translation>
<translation id="5786044859038896871">Kart bilgilerinizin doldurulmasını istiyor musunuz?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">Bu siteye ulaşılamıyor</translation>
<translation id="5869522115854928033">Kayıtlı şifreler</translation>
<translation id="5872918882028971132">Ebeveyn Önerileri</translation>
-<translation id="587760065310675640">Gönderim adresi desteklenmiyor. Farklı bir adres seçin.</translation>
<translation id="5901630391730855834">Sarı</translation>
-<translation id="59174027418879706">Etkin</translation>
<translation id="5926846154125914413">Bazı sitelerden alınan premium içeriğe erişiminizi kaybedebilirsiniz.</translation>
<translation id="5959728338436674663">Tehlikeli uygulamaların ve sitelerin tespit edilmesine yardımcı olmak için Google'a bazı <ph name="BEGIN_WHITEPAPER_LINK" />sistem bilgilerini ve sayfa içeriklerini<ph name="END_WHITEPAPER_LINK" /> otomatik olarak gönder.<ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Hafta</translation>
<translation id="5967867314010545767">Geçmişten kaldır.</translation>
<translation id="5975083100439434680">Uzaklaştır</translation>
+<translation id="598637245381783098">Ödeme uygulaması açılamıyor</translation>
<translation id="5989320800837274978">Sabit proxy sunucular veya bir .pac komut dosyası URL'si belirtilmedi.</translation>
<translation id="5990559369517809815">Sunucuya gönderilen istekler bir uzantı tarafından engellendi.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Kart ve adres seçenekleri Chrome'dan alınmıştır. Bunları <ph name="BEGIN_LINK" />Ayarlar<ph name="END_LINK" />'da yönetebilirsiniz.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1. sayfa}other{#. sayfa}}</translation>
<translation id="6017514345406065928">YeÅŸil</translation>
+<translation id="6027201098523975773">Bir ad girin</translation>
<translation id="6040143037577758943">Kapat</translation>
-<translation id="604124094241169006">Otomatik</translation>
<translation id="6042308850641462728">Daha fazla</translation>
<translation id="6060685159320643512">Dikkatli olun, bu deneyler canınızı yakabilir</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{yok}=1{1}other{#}}</translation>
@@ -543,9 +552,10 @@
veya diğer ağ cihazlarını yeniden başlatın.</translation>
<translation id="614940544461990577">Aşağıdakileri deneyin:</translation>
<translation id="6151417162996330722">Sunucu sertifikasının geçerlilik dönemi çok uzun.</translation>
-<translation id="615643356032862689">Ä°ndirilen dosyalar ve yer iÅŸaretleri saklanacak.</translation>
+<translation id="6157877588268064908">Gönderim yöntemlerini ve gereksinimlerini görmek için bir adres seçin</translation>
<translation id="6165508094623778733">Daha fazla bilgi edinin</translation>
<translation id="6177128806592000436">Bu siteye bağlantınız güvenli değil</translation>
+<translation id="6184817833369986695">(kohort: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">İnternet bağlantınızı kontrol edin</translation>
<translation id="6218753634732582820">Adres Chromium'dan kaldırılsın mı?</translation>
<translation id="6251924700383757765">Gizlilik politikası</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">Sıralama Değişikliğini &amp;Yeniden Yap</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> yer iÅŸaretleri</translation>
<translation id="6264485186158353794">Güvenliğe geri dön</translation>
+<translation id="6276112860590028508">Okuma listenize ait sayfalar burada görünür</translation>
+<translation id="6280223929691119688">Bu adrese teslimat yapılamıyor. Farklı bir adres seçin.</translation>
<translation id="6282194474023008486">Posta kodu</translation>
<translation id="6290238015253830360">Önerilen makaleler burada görünür</translation>
<translation id="6305205051461490394"><ph name="URL" /> adresine ulaşılamıyor.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Sertifikanın iptal edilip edilmediği kontrol edilemiyor.</translation>
<translation id="6433490469411711332">İletişim bilgilerini düzenle</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> bağlanmayı reddetti.</translation>
-<translation id="6443118737398455446">Son kullanma tarihi geçersiz</translation>
<translation id="6446608382365791566">Daha fazla bilgi ekleyin</translation>
<translation id="6451458296329894277">Yeniden Form Gönderme İşlemini Onayla</translation>
<translation id="6456339708790392414">Ödemeniz</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Bu sunucu, <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Güvenlik sertifikası iptal edilmiş olabilir. Bu durum, yanlış yapılandırmadan veya bağlantınıza müdahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Cihaz politikaları</translation>
<translation id="6477321094435799029">Chrome, bu sayfada olağan dışı kod tespit etti ve kişisel bilgilerinizi (örneğin, şifreler, telefon numaraları ve kredi kartları) korumak için sayfayı engelledi.</translation>
-<translation id="6477460825583319731">Geçersiz e-posta adresi</translation>
<translation id="6489534406876378309">Kilitlenmeleri yüklemeye başla</translation>
<translation id="6508722015517270189">Chrome'u yeniden başlatın</translation>
-<translation id="6525462735697194615">Geçersiz son kullanım ayı</translation>
<translation id="6529602333819889595">Silmeyi &amp;Yeniden Yap</translation>
<translation id="6534179046333460208">Fiziksel Web önerileri</translation>
<translation id="6550675742724504774">Seçenekler</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Arama</translation>
<translation id="6644283850729428850">Bu politika uygun bulunmadı.</translation>
<translation id="6652240803263749613">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, yanlış yapılandırmadan veya bağlantınıza müdahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Belirtilen gönderim seçeneği kullanılamıyor. Farklı bir seçenek deneyin.</translation>
<translation id="6671697161687535275">Form önerisi Chromium'dan kaldırılsın mı?</translation>
<translation id="6685834062052613830">Çıkış yapın ve kurulumu tamamlayın</translation>
<translation id="6710213216561001401">Önceki</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Proxy sunucusunda bir sorun var veya adres yanlış.</translation>
<translation id="6727102863431372879">Ayarla</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{yok}=1{1 öğe}other{# öğe}}</translation>
-<translation id="6743044928064272573">Alma seçeneği</translation>
<translation id="674375294223700098">Bilinmeyen sunucu sertifikası hatası.</translation>
<translation id="6753269504797312559">Politika deÄŸeri</translation>
<translation id="6757797048963528358">Cihazınız uyku moduna geçti.</translation>
<translation id="6778737459546443941">Ebeveyniniz henüz onaylamadı</translation>
<translation id="6810899417690483278">Özelleştirme Kimliği</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Bölge verileri yüklenemedi</translation>
<translation id="6831043979455480757">Çevir</translation>
<translation id="6839929833149231406">Bölge</translation>
<translation id="6874604403660855544">Eklemeyi &amp;yeniden yap</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Kartınız onaylandı</translation>
<translation id="6897140037006041989">Kullanıcı Aracısı</translation>
<translation id="6915804003454593391">Kullanıcı:</translation>
+<translation id="6948701128805548767">Alım yöntemlerini ve gereksinimlerini görmek için bir adres seçin</translation>
<translation id="6957887021205513506">Sunucunun sertifikası sahte görünüyor.</translation>
<translation id="6965382102122355670">Tamam</translation>
<translation id="6965978654500191972">Cihaz</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">Hem sabit proxy sunucular hem de bir .pac komut dosyası URL'si belirtildi.</translation>
<translation id="6989763994942163495">Gelişmiş ayarları göster...</translation>
<translation id="7000990526846637657">Geçmiş girişi bulunamadı</translation>
-<translation id="7001663382399377034">Alıcı ekleyin</translation>
<translation id="7009986207543992532"><ph name="DOMAIN" /> alan adına erişmeyi denediniz ancak sunucu, geçerlilik dönemi güvenilir olmayacak kadar uzun olan bir sertifika sundu. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985"><ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> adresinde Google Hesabınıza ilişkin başka biçimlerde tarama geçmişi olabilir.</translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Daha eski</translation>
<translation id="7090678807593890770">Google'da <ph name="LINK" /> araması yapın</translation>
<translation id="7119414471315195487">Diğer sekmeleri veya programları kapatın</translation>
+<translation id="7129409597930077180">Bu adrese gönderim yapılamıyor. Farklı bir adres seçin.</translation>
+<translation id="7138472120740807366">Teslimat yöntemi</translation>
<translation id="7139724024395191329">Emirlik</translation>
<translation id="7155487117670177674">Ödeme işlemi güvenli değil</translation>
<translation id="7179921470347911571">Åžimdi Yeniden BaÅŸlat</translation>
<translation id="7180611975245234373">Yenile</translation>
<translation id="7182878459783632708">Hiçbir politika ayarlanmamış</translation>
<translation id="7186367841673660872">Bu sayfa,<ph name="ORIGINAL_LANGUAGE" />dilinden<ph name="LANGUAGE_LANGUAGE" />diline çevrilmiştir</translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> güvenlik standartlarına uymuyor.</translation>
<translation id="721197778055552897">Bu sorun hakkında <ph name="BEGIN_LINK" />daha fazla<ph name="END_LINK" /> bilgi edinin.</translation>
@@ -675,7 +686,6 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="7424977062513257142">Bu web sayfasındaki yerleşik bir sayfanın mesajı:</translation>
<translation id="7441627299479586546">Politika konusu yanlış</translation>
<translation id="7444046173054089907">Bu site engellenmiÅŸ</translation>
-<translation id="7444238235002594607">Alma yöntemlerini ve şartlarını kontrol etmek için alma adresi seçin.</translation>
<translation id="7445762425076701745">Bağlı olduğunuz sunucunun kimliği tam olarak doğrulanamıyor. Sunucuya yalnızca ağınızın içinde geçerli olan ve dış sertifika yetkilisi tarafından hiçbir şekilde sahipliği doğrulanamayacak bir ad kullanarak bağlandınız. Bazı sertifika yetkilileri bu adlar için sertifikalar yayınlasa da, bir saldırgana değil, hedeflenen web sitesine bağlandığınızdan emin olmanın herhangi bir yolu yoktur.</translation>
<translation id="7451311239929941790">Bu sorun hakkında <ph name="BEGIN_LINK" />daha fazla<ph name="END_LINK" /> bilgi edinme.</translation>
<translation id="7460163899615895653">Diğer cihazlardan yeni tarihli sekmeleriniz burada görünür</translation>
@@ -719,6 +729,7 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="7755287808199759310">Ebeveyniniz engellemeyi sizin için kaldırabilir</translation>
<translation id="7758069387465995638">Bağlantıyı güvenlik duvarı veya virüsten korunma yazılımı engellemiş olabilir.</translation>
<translation id="7761701407923456692">Sunucu sertifikası URL ile eşleşmiyor.</translation>
+<translation id="7763386264682878361">Ödeme Bildirimi Ayrıştırıcısı</translation>
<translation id="7764225426217299476">Adres ekle</translation>
<translation id="777702478322588152">İdari bölge</translation>
<translation id="7791543448312431591">Ekle</translation>
@@ -732,6 +743,7 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="785549533363645510">Ancak görünmez olmazsınız. Gizli moda geçmek göz atma etkinliğinizi işvereninizden, İnternet servis sağlayıcınızdan veya ziyaret ettiğiniz web sitelerinden gizlemez.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">CVC'nizi kontrol edin ve tekrar deneyin</translation>
+<translation id="79338296614623784">Geçerli bir telefon numarası girin</translation>
<translation id="7935318582918952113">DOM Ayrıştırıcı</translation>
<translation id="7938958445268990899">Sunucunun sertifikası henüz geçerli değil.</translation>
<translation id="7942349550061667556">Kırmızı</translation>
@@ -751,6 +763,7 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="8088680233425245692">Makale görüntülenemedi.</translation>
<translation id="8089520772729574115">1 MB'tan az</translation>
<translation id="8091372947890762290">EtkinleÅŸtirme sunucuda bekliyor</translation>
+<translation id="8118489163946903409">Ödeme yöntemi</translation>
<translation id="8131740175452115882">Onayla</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> ana makinesinin sunucu <ph name="BEGIN_ABBR" />DNS adresi<ph name="END_ABBR" /> bulunamadı.</translation>
<translation id="8149426793427495338">Bilgisayarınız uyku moduna geçti.</translation>
@@ -776,6 +789,7 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="8349305172487531364">Yer işaretleri çubuğu</translation>
<translation id="8363502534493474904">Uçak modunu kapatma</translation>
<translation id="8364627913115013041">Henüz ayarlanmadı.</translation>
+<translation id="8368476060205742148">Google Play hizmetleri</translation>
<translation id="8380941800586852976">Tehlikeli</translation>
<translation id="8382348898565613901">Son ziyaret ettiğiniz yer işaretleri burada görünür</translation>
<translation id="8398259832188219207">Kilitlenme raporunun yüklenme zamanı: <ph name="UPLOAD_TIME" /></translation>
@@ -784,32 +798,30 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="8428213095426709021">Ayarlar</translation>
<translation id="8433057134996913067">Bu işlem, çoğu web sitesinden çıkış yapmanıza neden olacak.</translation>
<translation id="8437238597147034694">Taşımayı &amp;geri al</translation>
-<translation id="8456681095658380701">Geçersiz ad</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 kredi kartı}other{# kredi kartı}}</translation>
<translation id="8483780878231876732">Google Hesabınızda kayıtlı kartları kullanmak için Chrome'da oturum açın</translation>
<translation id="8488350697529856933">Uygulandığı yer</translation>
-<translation id="8492969205326575646">Desteklenmeyen kart türü</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ana makinesinin yanıt vermesi çok uzun sürdü.</translation>
<translation id="852346902619691059">Bu sunucu <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Cihazınızın işletim sistemi, sunucunun güvenlik sertifikasına güvenmiyor. Bu durum, yanlış yapılandırmadan veya bağlantınıza müdahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Son Kullanım Yılı</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />Bir tespit sorununu bildirebilir<ph name="END_ERROR_LINK" /> veya güvenliğiniz açısından riskleri anlıyorsanız <ph name="BEGIN_LINK" />güvenli olmayan bu siteyi ziyaret edebilirsiniz<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Sayfanın dili belirlenemediğinden çeviri başarısız oldu.</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="8570229484593575558">Şu bilgiler |kaydedilmeyecek|:#Tarama geçmişiniz#Aramalarınız#Çerez verileri</translation>
<translation id="8571890674111243710">Sayfa <ph name="LANGUAGE" /> diline çevriliyor...</translation>
-<translation id="8584539743998202583">Etkinlikleriniz şunlar tarafından |hâlâ görülebilir|:#Ziyaret ettiğiniz web siteleri#İşvereniniz#İnternet servis sağlayıcınız</translation>
<translation id="858637041960032120">Telefon no ekle
</translation>
<translation id="859285277496340001">Sertifika, iptal edilip edilmediÄŸinin denetlenebileceÄŸi bir mekanizma belirtmiyor.</translation>
<translation id="8620436878122366504">Ebeveynleriniz henüz onaylamadı</translation>
<translation id="8647750283161643317">Tümünü varsayılan değerlere sıfırla</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> bağlantınız şifrelenmedi.</translation>
+<translation id="8718314106902482036">Ödeme işlemi tamamlanmadı</translation>
<translation id="8725066075913043281">Yeniden dene</translation>
<translation id="8728672262656704056">Gizli moda geçtiniz</translation>
<translation id="8730621377337864115">Bitti</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="8759274551635299824">Bu kartın kullanım süresi doldu</translation>
<translation id="8790007591277257123">Silmeyi &amp;yeniden yap</translation>
-<translation id="8798099450830957504">Varsayılan</translation>
<translation id="8800988563907321413">Yakın çevrenizle ilgili öneriler burada görünür</translation>
<translation id="8820817407110198400">Favoriler</translation>
<translation id="883848425547221593">DiÄŸer Yer Ä°ÅŸaretleri</translation>
@@ -819,6 +831,7 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="8866481888320382733">Politika ayarlarını ayrıştırma hatası</translation>
<translation id="8866959479196209191">Bu sayfanın mesajı:</translation>
<translation id="8870413625673593573">Son Kapatılan</translation>
+<translation id="8874824191258364635">Geçerli bir kart numarası girin</translation>
<translation id="8876793034577346603">Ağ yapılandırması ayrıştırılamadı.</translation>
<translation id="8877192140621905067">Onayladığınızda kart ayrıntılarınız bu siteyle paylaşılacaktır</translation>
<translation id="8889402386540077796">Ton</translation>
@@ -828,7 +841,6 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="8931333241327730545">Bu kartı Google Hesabınıza kaydetmek istiyor musunuz?</translation>
<translation id="8932102934695377596">Saatiniz geri</translation>
<translation id="8954894007019320973">(Dev.)</translation>
-<translation id="895548565263634352"><ph name="ARTICLE_PUBLISHER" /> adlı yayıncıdan haberleri ve diğer <ph name="OTHER_ARTICLE_COUNT" /> makaleyi okuyun</translation>
<translation id="8971063699422889582">Sunucu sertifikasının süresi doldu.</translation>
<translation id="8986494364107987395">Kullanım istatistiklerini ve çökme raporlarını otomatik olarak Google'a gönder</translation>
<translation id="8987927404178983737">Ay</translation>
@@ -846,7 +858,6 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="9068849894565669697">Renk seçin</translation>
<translation id="9076283476770535406">Yetişkin içeriği bulunabilir</translation>
<translation id="9078964945751709336">Daha fazla bilgi gerekli</translation>
-<translation id="9094175695478007090">Ödeme uygulaması başlatılamıyor.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> normalde bilgilerinizi korumak için şifreleme kullanmaktadır. Chromium bu sefer <ph name="SITE" /> sitesine bağlanmayı denediğinde, web sitesi sıra dışı ve yanlış kimlik bilgileri döndürdü. Bir saldırgan <ph name="SITE" /> gibi davranmaya çalışıyor olabilir ya da bir Kablosuz oturum açma ekranı bağlantıyı kesmiştir. Chromium herhangi bir veri alışverişinden önce bağlantıyı durdurduğu için bilgileriniz hâlâ güvendedir.</translation>
<translation id="9137013805542155359">Orijinali göster</translation>
<translation id="9137248913990643158">Lütfen bu uygulamayı kullanmadan önce Chrome'u başlatıp oturum açın.</translation>
diff --git a/chromium/components/strings/components_strings_uk.xtb b/chromium/components/strings/components_strings_uk.xtb
index 0b38eaf7468..8f2b5a497e4 100644
--- a/chromium/components/strings/components_strings_uk.xtb
+++ b/chromium/components/strings/components_strings_uk.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="uk">
<translation id="1008557486741366299">Ðе зараз</translation>
<translation id="1015730422737071372">Ðадати додаткову інформацію</translation>
+<translation id="1021110881106174305">ПрийнÑÑ‚Ñ– картки</translation>
<translation id="1032854598605920125">Обернути за годинниковою Ñтрілкою</translation>
<translation id="1038842779957582377">Ðевідоме ім’Ñ</translation>
<translation id="1050038467049342496">Закрийте інші додатки</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Сховати значеннÑ</translation>
<translation id="1228893227497259893">Ðеправильний ідентифікатор організації</translation>
<translation id="1232569758102978740">Без імені</translation>
+<translation id="1263231323834454256">СпиÑок читаннÑ</translation>
<translation id="1264126396475825575">Звіт про аварійне Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ о <ph name="CRASH_TIME" /> (ще не завантажено або пропущено)</translation>
<translation id="1285320974508926690">Ðіколи не перекладати цей Ñайт</translation>
<translation id="129553762522093515">Ðещодавно закриті</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð°Ð²Ñ‚Ð¾Ð·Ð°Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Chromium…</translation>
<translation id="1374468813861204354">пропозиції</translation>
<translation id="1375198122581997741">Про верÑÑ–ÑŽ</translation>
+<translation id="1377321085342047638">Ðомер картки</translation>
<translation id="139305205187523129">ХоÑÑ‚ <ph name="HOST_NAME" /> не надіÑлав дані.</translation>
<translation id="1407135791313364759">Відкрити вÑе</translation>
<translation id="1413809658975081374">Помилка через Ð¿Ð¾Ñ€ÑƒÑˆÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ñ„Ñ–Ð´ÐµÐ½Ñ†Ñ–Ð¹Ð½Ð¾ÑÑ‚Ñ–</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">ІÑторіÑ</translation>
<translation id="1645368109819982629">Протокол не підтримуєтьÑÑ</translation>
<translation id="1656489000284462475">ОтриманнÑ</translation>
+<translation id="1663943134801823270">Дані картки та ÑпиÑок Ð°Ð´Ñ€ÐµÑ Ð¼Ñ–ÑÑ‚ÑÑ‚ÑŒÑÑ Ð² Chrome. Ðими можна керувати в <ph name="BEGIN_LINK" />ÐалаштуваннÑÑ…<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898">Веб-Ñайт <ph name="SITE" /> зазвичай викориÑтовує ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð·Ð°Ñ…Ð¸Ñту вашої інформації. Під Ñ‡Ð°Ñ Ñ†Ñ–Ñ”Ñ— Ñпроби Chrome під’єднатиÑÑ Ð´Ð¾ Ñторінки <ph name="SITE" /> з неї отримано незвичні й неправильні облікові дані. Це може ÑтатиÑÑ, коли зловмиÑник намагаєтьÑÑ Ð²Ð¸Ð´Ð°Ð²Ð°Ñ‚Ð¸ Ñебе за веб-Ñайт <ph name="SITE" /> або Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÑ€Ð²Ð°Ð½Ð¾ екраном входу Wi-Fi. Ваша Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð·Ð°Ð»Ð¸ÑˆÐ°Ñ”Ñ‚ÑŒÑÑ Ð·Ð°Ñ…Ð¸Ñ‰ÐµÐ½Ð¾ÑŽ, оÑкільки Chrome припинив Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð´Ð¾ того, Ñк почавÑÑ Ð¾Ð±Ð¼Ñ–Ð½ будь-Ñкими даними.</translation>
<translation id="168328519870909584">ЗловмиÑники, Ñкі зараз перебувають на Ñайті <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, можуть намагатиÑÑ Ð²Ñтановити на ваш приÑтрій небезпечні додатки, що викрадають або видалÑÑŽÑ‚ÑŒ інформацію (Ñк-от фотографії, паролі, Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñ‡Ð¸ дані кредитних карток).</translation>
<translation id="168841957122794586">Сертифікат Ñервера міÑтить Ñлабкий криптографічний ключ.</translation>
<translation id="1710259589646384581">ОС</translation>
<translation id="1721312023322545264">Вам потрібен дозвіл адмініÑтратора <ph name="NAME" />, щоб перейти на цей Ñайт</translation>
+<translation id="1721424275792716183">* Обов’Ñзкове поле</translation>
<translation id="1728677426644403582">Ви переглÑдаєте джерело веб-Ñторінки</translation>
+<translation id="173080396488393970">Цей тип картки не підтримуєтьÑÑ</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Зв’ÑжітьÑÑ Ñ–Ð· ÑиÑтемним адмініÑтратором.</translation>
+<translation id="1740951997222943430">Введіть дійÑний міÑÑць Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії</translation>
<translation id="1745358365027406341">Завантажити Ñторінку пізніше</translation>
<translation id="17513872634828108">Відкриті вкладки</translation>
<translation id="1753706481035618306">Ðомер Ñторінки</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Оновіть парольну фразу Ð´Ð»Ñ Ñинхронізації.</translation>
<translation id="1787142507584202372">Тут відображатимутьÑÑ Ð²Ð°ÑˆÑ– відкриті вкладки</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Укажіть адреÑу доÑтавки, щоб переглÑнути ÑпоÑоби доÑтавки та вимоги.</translation>
+<translation id="1803264062614276815">Ð†Ð¼â€™Ñ Ñ‚Ð° прізвище влаÑника картки</translation>
<translation id="1803678881841855883">Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ Ð±ÐµÐ·Ð¿ÐµÑ‡Ð½Ð¾Ð³Ð¾ переглÑду від Google нещодавно <ph name="BEGIN_LINK" />виÑвила зловмиÑне програмне забезпеченнÑ<ph name="END_LINK" /> на Ñайті <ph name="SITE" />. Іноді зловмиÑне програмне Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ Ð·Ð°Ñ€Ð°Ð¶Ð°Ñ” зазвичай безпечні веб-Ñайти. Шкідливий вміÑÑ‚ походить із хоÑту <ph name="SUBRESOURCE_HOST" /> – відомого розповÑюджувача зловмиÑного програмного забезпеченнÑ. <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Додано <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">ÐедійÑний запит або параметри запиту</translation>
<translation id="1826516787628120939">Перевірка</translation>
<translation id="1834321415901700177">Цей Ñайт міÑтить шкідливі програми</translation>
<translation id="1842969606798536927">Оплатити</translation>
-<translation id="1864455488461349376">Параметри доÑтавки</translation>
<translation id="1871208020102129563">ПрокÑÑ–-Ñервер налаштовано на викориÑÑ‚Ð°Ð½Ð½Ñ Ñ„Ñ–ÐºÑованих прокÑÑ–-Ñерверів, а не URL-адреÑи Ñценарію .pac.</translation>
<translation id="1871284979644508959">Обов’Ñзкове поле</translation>
<translation id="187918866476621466">Відкрити Ñтартові Ñторінки</translation>
<translation id="1883255238294161206">Згорнути ÑпиÑок</translation>
<translation id="1898423065542865115">ФільтруваннÑ</translation>
<translation id="194030505837763158">Перейдіть за адреÑою <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Підтримувані типи карток</translation>
<translation id="1962204205936693436">Закладки <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Помилка Ñеріалізації</translation>
<translation id="1974060860693918893">Розширені</translation>
<translation id="1978555033938440688">ВерÑÑ–Ñ Ð¼Ñ–ÐºÑ€Ð¾Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¸</translation>
+<translation id="1995859865337580572">Підтвердьте CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{і ще 1}one{і ще #}few{і ще #}many{і ще #}other{і ще #}}</translation>
-<translation id="2020194265157481222">Потрібно вказати Ñ–Ð¼â€™Ñ Ð½Ð° кредитній картці</translation>
<translation id="2025186561304664664">ПрокÑÑ–-Ñервер уÑтановлено на автоматичне налаштуваннÑ.</translation>
<translation id="2030481566774242610">Можливо, ви мали на увазі <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />перевірити прокÑÑ–-Ñервер Ñ– брандмауер<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Сьогодні</translation>
<translation id="2154054054215849342">Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð½ÐµÐ´Ð¾Ñтупна Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ домену</translation>
<translation id="2154484045852737596">Редагувати картку</translation>
-<translation id="2156993118928861787">ÐедійÑна адреÑа</translation>
<translation id="2166049586286450108">Повний адмініÑтративний доÑтуп</translation>
<translation id="2166378884831602661">Цей Ñайт не може забезпечити захищене з’єднаннÑ</translation>
<translation id="2181821976797666341">Правила</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 адреÑа}one{# адреÑа}few{# адреÑи}many{# адреÑ}other{# адреÑи}}</translation>
+<translation id="2202020181578195191">Введіть дійÑний рік Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії</translation>
<translation id="2212735316055980242">Правило не знайдено</translation>
<translation id="2213606439339815911">ÐžÑ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñів…</translation>
<translation id="2230458221926704099">Відновіть Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð·Ð° допомогою <ph name="BEGIN_LINK" />додатка Ð´Ð»Ñ Ð´Ñ–Ð°Ð³Ð½Ð¾Ñтики<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Ваш доÑтуп до Інтернету заблоковано</translation>
<translation id="230155334948463882">Ðова картка?</translation>
<translation id="2305919008529760154">Ðе вдалоÑÑ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¸Ñ‚Ð¸, що це Ñервер <ph name="DOMAIN" />. Можливо, його Ñертифікат безпеки видали шахраї. Імовірні причини: Ñервер налаштовано неправильно або хтоÑÑŒ намагаєтьÑÑ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð¿Ð¸Ñ‚Ð¸ ваше з’єднаннÑ. <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="230697611605700222">Дані картки й ÑпиÑок Ð°Ð´Ñ€ÐµÑ Ð¼Ñ–ÑÑ‚ÑÑ‚ÑŒÑÑ Ñƒ вашому обліковому запиÑÑ– Google (<ph name="ACCOUNT_EMAIL" />) Ñ– Chrome. Ðими можна керувати в <ph name="BEGIN_LINK" />ÐалаштуваннÑÑ…<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535">Ð”Ð»Ñ Ñайту <ph name="DOMAIN" /> потрібно ввеÑти Ñ–Ð¼â€™Ñ ÐºÐ¾Ñ€Ð¸Ñтувача та пароль.</translation>
<translation id="2318774815570432836">Зараз не можна перейти на Ñторінку <ph name="SITE" />, оÑкільки веб-Ñайт викориÑтовує протокол HSTS. Помилки мережі й атаки зазвичай тимчаÑові, тому Ñ†Ñ Ñторінка, Ñкоріш за вÑе, запрацює пізніше. <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Інші закладки</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Стандартне корпоративне правило</translation>
<translation id="2386255080630008482">Сертифікат Ñервера відкликано.</translation>
<translation id="2392959068659972793">Показувати правила, Ð´Ð»Ñ Ñких не вÑтановлено значеннÑ</translation>
+<translation id="239429038616798445">Цей ÑпоÑіб Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ð½ÐµÐ´Ð¾Ñтупний. Виберіть інший ÑпоÑіб.</translation>
<translation id="2396249848217231973">&amp;Відмінити видаленнÑ</translation>
<translation id="2460160116472764928">Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ Ð±ÐµÐ·Ð¿ÐµÑ‡Ð½Ð¾Ð³Ð¾ переглÑду від Google нещодавно <ph name="BEGIN_LINK" />виÑвила зловмиÑне програмне забезпеченнÑ<ph name="END_LINK" /> на Ñайті <ph name="SITE" />. Іноді зловмиÑне програмне Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ Ð·Ð°Ñ€Ð°Ð¶Ð°Ñ” зазвичай безпечні веб-Ñайти. <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Заповнити</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />провеÑти діагноÑтику мережі<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">ÐедійÑна URL-адреÑа Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ.</translation>
<translation id="2491120439723279231">Сертифікат Ñервера міÑтить помилки.</translation>
-<translation id="24943777258388405">Ðеправильний номер телефону</translation>
<translation id="2495083838625180221">СинтакÑичний аналізатор файлів JSON</translation>
<translation id="2495093607237746763">Якщо вибрати цю опцію, Chromium зберігатиме копію даних вашої картки на цьому приÑтрої, щоб ви могли швидше заповнювати форми.</translation>
<translation id="2498091847651709837">Сканувати нову картку</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027">ХоÑÑ‚ <ph name="HOST_NAME" /> надіÑлав недійÑну відповідь.</translation>
<translation id="2552545117464357659">Ðовіша</translation>
<translation id="2556876185419854533">&amp;Відмінити редагуваннÑ</translation>
+<translation id="2587730715158995865">Видавець: <ph name="ARTICLE_PUBLISHER" />. Читайте цю та ще <ph name="OTHER_ARTICLE_COUNT" /> Ñтатей.</translation>
<translation id="2587841377698384444">Ідентифікатор API каталогу:</translation>
<translation id="2597378329261239068">Цей документ захищено паролем. Введіть пароль.</translation>
<translation id="2609632851001447353">Різновиди</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />провеÑти діагноÑтику з’єднаннÑ<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">Ok</translation>
<translation id="2742870351467570537">Видалити вибрані елементи</translation>
+<translation id="277133753123645258">СпоÑіб відправленнÑ</translation>
<translation id="277499241957683684">ВідÑутній Ð·Ð°Ð¿Ð¸Ñ Ð¿Ñ€Ð¸Ñтрою</translation>
<translation id="2784949926578158345">Ð—â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð±ÑƒÐ»Ð¾ Ñкинуто.</translation>
<translation id="2794233252405721443">Сайт заблоковано</translation>
-<translation id="2812680587231492111">Цей ÑпоÑіб Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð½ÐµÐ´Ð¾Ñтупний. Виберіть інший ÑпоÑіб.</translation>
<translation id="2824775600643448204">ÐдреÑний Ñ– пошуковий Ñ€Ñдок</translation>
<translation id="2826760142808435982">Ð—â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð·Ð°ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¾ й автентифіковано з викориÑтаннÑм шифру <ph name="CIPHER" /> Ñ– викориÑтовує механізм обміну ключами <ph name="KX" />.</translation>
<translation id="2835170189407361413">ОчиÑтити форму</translation>
-<translation id="2849041323157393173">Цей ÑпоÑіб доÑтавки недоÑтупний. Виберіть інший ÑпоÑіб.</translation>
<translation id="2889159643044928134">Ðе оновлювати</translation>
<translation id="2900469785430194048">ÐедоÑтатньо пам’ÑÑ‚Ñ– Google Chrome, щоб показати цю веб-Ñторінку.</translation>
<translation id="2909946352844186028">ВиÑвлено зміну в мережі.</translation>
<translation id="2916038427272391327">Закрийте інші програми</translation>
<translation id="2922350208395188000">Сертифікат Ñервера неможливо перевірити.</translation>
+<translation id="2928905813689894207">Платіжна адреÑа</translation>
<translation id="2948083400971632585">УÑÑ– прокÑÑ–-Ñервери, налаштовані Ð´Ð»Ñ Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ, можна вимкнути на Ñторінці налаштувань.</translation>
<translation id="2955913368246107853">Закрити панель пошуку</translation>
<translation id="2958431318199492670">ÐšÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ Ð¼ÐµÑ€ÐµÐ¶Ñ– не відповідає Ñтандарту ONC. Вона може імпортуватиÑÑ Ñ‡Ð°Ñтково.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Щоб уÑтановити безпечне з’єднаннÑ, потрібно правильно налаштувати чаÑ, оÑкільки Ñертифікати, Ñкі підтверджують ÑправжніÑÑ‚ÑŒ веб-Ñайтів, дійÑні лише протÑгом певного періоду. Ðа вашому приÑтрої неправильно налаштовано чаÑ, тому Chrome не може перевірити Ñертифікати.</translation>
<translation id="2972581237482394796">&amp;Повторити</translation>
<translation id="2985306909656435243">Якщо цю функцію ввімкнено, Chromium зберігає копію даних вашої картки на приÑтрої, щоб ви могли швидше заповнювати форми.</translation>
+<translation id="2985398929374701810">Введіть дійÑну адреÑу</translation>
+<translation id="2986368408720340940">Цей ÑпоÑіб Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð½ÐµÐ´Ð¾Ñтупний. Виберіть інший ÑпоÑіб.</translation>
<translation id="2991174974383378012">ÐÐ°Ð´Ð°Ð½Ð½Ñ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ— веб-Ñайтам</translation>
<translation id="3005723025932146533">Показати збережену копію</translation>
<translation id="3008447029300691911">Введіть код CVC картки <ph name="CREDIT_CARD" />. Щойно ви підтвердите дані картки, цей Ñайт отримає доÑтуп до них.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{щонайменше 1 Ð·Ð°Ð¿Ð¸Ñ Ð½Ð° Ñинхронізованих приÑтроÑÑ…}=1{1 Ð·Ð°Ð¿Ð¸Ñ (Ñ– більше на Ñинхронізованих приÑтроÑÑ…)}one{# Ð·Ð°Ð¿Ð¸Ñ (Ñ– більше на Ñинхронізованих приÑтроÑÑ…)}few{# запиÑи (Ñ– більше на Ñинхронізованих приÑтроÑÑ…)}many{# запиÑів (Ñ– більше на Ñинхронізованих приÑтроÑÑ…)}other{# запиÑу (Ñ– більше на Ñинхронізованих приÑтроÑÑ…)}}</translation>
<translation id="3041612393474885105">Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ Ñертифікат</translation>
<translation id="3063697135517575841">Chrome не вдалоÑÑ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¸Ñ‚Ð¸ дані вашої картки. Спробуйте пізніше.</translation>
+<translation id="3064966200440839136">Щоб оплатити в зовнішньому додатку, ви вийдете з режиму анонімного переглÑду. Продовжити?</translation>
<translation id="3093245981617870298">Ви в режимі офлайн</translation>
<translation id="3105172416063519923">Ідентифікатор об’єкта:</translation>
<translation id="3109728660330352905">У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” дозволу переглÑдати цю Ñторінку.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Проведіть діагноÑтику з’єднаннÑ<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Помилка Ð´ÐµÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ñ–</translation>
-<translation id="3149891296864842641">Варіант доÑтавки</translation>
<translation id="3150653042067488994">ТимчаÑова помилка Ñервера</translation>
+<translation id="3154506275960390542">Ð¦Ñ Ñторінка міÑтить незахищену форму. Інші люди можуть бачити дані під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ð²Ð°Ð½Ð½Ñ, а зловмиÑники можуть змінювати Ñ—Ñ….</translation>
<translation id="3157931365184549694">Відновити</translation>
<translation id="3167968892399408617">Сторінки, Ñкі ви переглÑдаєте на анонімних вкладках, не реєÑтруютьÑÑ Ð² Ñ–Ñторії веб-переглÑдача чи Ñ–Ñторії пошуку та не залишають файлів cookie, коли ви закриваєте вÑÑ– анонімні вкладки. УÑÑ– завантажені файли чи Ñтворені закладки зберігаютьÑÑ.</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Ðе вдалоÑÑ Ð½Ð°Ð´Ñ–Ñлати запит на доÑтуп до цього Ñайту кориÑтувачеві <ph name="NAME" />. Повторіть Ñпробу.</translation>
<translation id="3355823806454867987">Змінити Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾ÐºÑÑ–...</translation>
<translation id="3369192424181595722">Помилка годинника</translation>
+<translation id="337311366426640088">Ще <ph name="ITEM_COUNT" />…</translation>
<translation id="337363190475750230">Деініціалізовано</translation>
<translation id="3377188786107721145">Помилка аналізу правила</translation>
<translation id="3380365263193509176">Ðевідома помилка</translation>
<translation id="3380864720620200369">Ідентифікатор клієнта:</translation>
<translation id="3391030046425686457">ÐдреÑа доÑтавки</translation>
+<translation id="3395827396354264108">СпоÑіб отриманнÑ</translation>
<translation id="340013220407300675">ЗловмиÑники можуть намагатиÑÑ Ð²Ð¸ÐºÑ€Ð°Ñти вашу інформацію з <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (наприклад, паролі, Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñ‡Ð¸ кредитні картки).</translation>
<translation id="3422248202833853650">Щоб звільнити пам’ÑÑ‚ÑŒ, закрийте інші програми.</translation>
<translation id="3422472998109090673">ХоÑÑ‚ <ph name="HOST_NAME" /> зараз недоÑтупний.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Інтервал отриманнÑ:</translation>
<translation id="3462200631372590220">Сховати додаткову інформацію</translation>
+<translation id="3467763166455606212">Потрібно вказати Ñ–Ð¼â€™Ñ Ð²Ð»Ð°Ñника картки</translation>
+<translation id="3478058380795961209">МіÑÑць Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії</translation>
<translation id="3479539252931486093">Ðе очікували? <ph name="BEGIN_LINK" />Повідомте наÑ<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Ðе зараз</translation>
<translation id="348000606199325318">Ідентифікатор аварійного Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ <ph name="CRASH_LOCAL_ID" /> (ідентифікатор Ñервера: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Ðе вдалоÑÑ Ð·Ð²â€™ÑзатиÑÑ Ð· одним із ваших батьків. Повторіть Ñпробу.</translation>
<translation id="3528171143076753409">Сертифікат Ñервера ненадійний.</translation>
-<translation id="3538531656504267329">ÐедійÑний рік Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії</translation>
<translation id="3539171420378717834">Зберігати копію даних цієї картки на цьому приÑтрої</translation>
<translation id="3542684924769048008">ВикориÑтовувати пароль длÑ:</translation>
<translation id="3549644494707163724">Шифрувати вÑÑ– Ñинхронізовані дані за допомогою влаÑної парольної фрази Ð´Ð»Ñ Ñинхронізації</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Сховати докладні дані</translation>
<translation id="3587482841069643663">Ð’Ñе</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Введіть дійÑний термін дії</translation>
<translation id="36224234498066874">ОчиÑтити дані веб-переглÑду...</translation>
<translation id="362276910939193118">Показати повну Ñ–Ñторію</translation>
<translation id="3623476034248543066">Показати значеннÑ</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Пароль:</translation>
<translation id="3696411085566228381">немає</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Виберіть адреÑу доÑтавки, щоб переглÑнути ÑпоÑоби доÑтавки та вимоги.</translation>
<translation id="370665806235115550">ЗавантаженнÑ...</translation>
<translation id="3712624925041724820">Ліцензії вичерпано</translation>
<translation id="3714780639079136834">увімкнути мобільний Інтернет або Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Скопійоване поÑиланнÑ</translation>
<translation id="375403751935624634">Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ переклад через помилку Ñервера.</translation>
<translation id="3759461132968374835">У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” оÑтанніх повідомлень про аварійне Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸. Тут не відображатимутьÑÑ Ð²Ð¸Ð¿Ð°Ð´ÐºÐ¸ аварійного Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸, Ñкі ÑталиÑÑ, коли Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ аварійне Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ було вимкнено.</translation>
+<translation id="3787705759683870569">Діє до <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Якщо ви викориÑтовуєте прокÑÑ–-Ñервер…</translation>
<translation id="3828924085048779000">ÐŸÐ¾Ñ€Ð¾Ð¶Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»ÑŒÐ½Ð° фраза заборонена.</translation>
<translation id="3845539888601087042">Показано Ñ–Ñторію з приÑтроїв, на Ñких ви ввійшли в обліковий запиÑ. <ph name="BEGIN_LINK" />Докладніше<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Зберегти цю картку в Chromium?</translation>
<translation id="4171400957073367226">ÐедійÑний Ð¿Ñ–Ð´Ð¿Ð¸Ñ Ð´Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ</translation>
-<translation id="4176463684765177261">Вимкнено</translation>
<translation id="4196861286325780578">&amp;Повторити переміщеннÑ</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />перевірити конфігурацію брандмауера й антивіруÑної програми<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{немає}=1{1 додаток ($1)}=2{2 додатки ($1, $2)}one{# додаток ($1, $2, $3)}few{# додатки ($1, $2, $3)}many{# додатків ($1, $2, $3)}other{# додатка ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">результати пошуку</translation>
<translation id="4432688616882109544">ХоÑÑ‚ <ph name="HOST_NAME" /> не прийнÑв ваш Ñертифікат входу або ви не надали цей Ñертифікат.</translation>
<translation id="443673843213245140">ВикориÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾ÐºÑÑ–-Ñервера вимкнено, але чітко вказано Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾ÐºÑÑ–-Ñервера.</translation>
-<translation id="4446242550670694251">Тепер ви можете переглÑдати вміÑÑ‚ анонімно. Інші кориÑтувачі вашого приÑтрою не бачитимуть даних про вашу активніÑÑ‚ÑŒ.</translation>
<translation id="4492190037599258964">Результати пошуку Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ "<ph name="SEARCH_STRING" />"</translation>
<translation id="4506176782989081258">Помилка перевірки: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">зв’ÑзатиÑÑ Ñ–Ð· ÑиÑтемним адмініÑтратором</translation>
<translation id="450710068430902550">ÐÐ°Ð´Ð°Ð½Ð½Ñ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ— адмініÑтратору</translation>
+<translation id="4515275063822566619">Дані картки та ÑпиÑок Ð°Ð´Ñ€ÐµÑ Ð¼Ñ–ÑÑ‚ÑÑ‚ÑŒÑÑ Ð² Chrome Ñ– вашому обліковому запиÑÑ– Google (<ph name="ACCOUNT_EMAIL" />). Ðими можна керувати в <ph name="BEGIN_LINK" />ÐалаштуваннÑÑ…<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Деталі</translation>
<translation id="4558551763791394412">Спробуйте вимкнути розширеннÑ.</translation>
<translation id="457875822857220463">ДоÑтавка</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">За розміром Ñторінки</translation>
<translation id="483020001682031208">Ðемає Ñторінок ÑервіÑу "Інтернет навколо наÑ" Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ</translation>
<translation id="4850886885716139402">ПереглÑд</translation>
+<translation id="4854362297993841467">Цей ÑпоÑіб доÑтавки недоÑтупний. Виберіть інший ÑпоÑіб.</translation>
<translation id="4858792381671956233">Ви надіÑлали батькам запит на переглÑд цього Ñайту</translation>
<translation id="4880827082731008257">Пошук в Ñ–Ñторії</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Цю Ñторінку перекладено з невідомої мови оригіналу такою мовою: <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Оплата</translation>
<translation id="4926049483395192435">Потрібно вказати.</translation>
-<translation id="4941291666397027948">* позначає обов’Ñзкове поле</translation>
<translation id="495170559598752135">Дії</translation>
<translation id="4958444002117714549">Розгорнути ÑпиÑок</translation>
<translation id="4962322354953122629">Ðе вдалоÑÑ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¸Ñ‚Ð¸, що це Ñервер <ph name="DOMAIN" />. Chrome вважає його Ñертифікат безпеки ненадійним. Імовірні причини: Ñервер налаштовано неправильно або хтоÑÑŒ намагаєтьÑÑ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð¿Ð¸Ñ‚Ð¸ ваше з’єднаннÑ. <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Ðеправильний пароль</translation>
<translation id="5056549851600133418">Статті Ð´Ð»Ñ Ð²Ð°Ñ</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />перевірити адреÑу прокÑÑ–-Ñервера<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Ðемає файлів cookie}=1{1 Ñайт викориÑтовує файли cookie. }one{# Ñайт викориÑтовує файли cookie. }few{# Ñайти викориÑтовують файли cookie. }many{# Ñайтів викориÑтовують файли cookie. }other{# Ñайту викориÑтовує файли cookie. }}</translation>
<translation id="5087286274860437796">Сертифікат Ñервера зараз недійÑний.</translation>
<translation id="5087580092889165836">Додати картку</translation>
<translation id="5089810972385038852">Штат</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Показати</translation>
<translation id="5308689395849655368">ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ аварійне Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ вимкнено.</translation>
<translation id="5317780077021120954">Зберегти</translation>
-<translation id="5326702247179446998">Потрібно вказати отримувача</translation>
<translation id="5327248766486351172">Ðазва</translation>
<translation id="5337705430875057403">ЗловмиÑники на Ñайті <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> можуть обманом змуÑити Ð²Ð°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ небезпечну дію, Ñк-от уÑтановити шкідливе програмне Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ Ð°Ð±Ð¾ повідомити оÑобиÑту інформацію (наприклад, паролі, номери телефонів або кредитних карток).</translation>
-<translation id="53553865750799677">ÐдреÑа Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð½Ðµ підтримуєтьÑÑ. Укажіть іншу адреÑу.</translation>
<translation id="5359637492792381994">Ðе вдалоÑÑ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¸Ñ‚Ð¸, що це Ñервер <ph name="DOMAIN" />. Його Ñертифікат безпеки зараз недійÑний. Імовірні причини: Ñервер налаштовано неправильно або хтоÑÑŒ намагаєтьÑÑ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð¿Ð¸Ñ‚Ð¸ ваше з’єднаннÑ. <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Помилка Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½ÑŒ правила</translation>
<translation id="5386426401304769735">Ланцюжок Ñертифіката цього Ñайту міÑтить Ñертифікат, підпиÑаний за допомогою SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð· вбудованої Ñторінки Ñайту <ph name="SITE" />:</translation>
<translation id="5556459405103347317">Перезавантажити</translation>
<translation id="5565735124758917034">Ðктивний клієнт</translation>
+<translation id="5571083550517324815">ÐдреÑа Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð½Ðµ підтримуєтьÑÑ. Укажіть іншу адреÑу.</translation>
<translation id="5572851009514199876">Увійдіть в обліковий Ð·Ð°Ð¿Ð¸Ñ Chrome, щоб веб-переглÑдач міг перевірити, чи ви маєте дозвіл відвідувати цей Ñайт.</translation>
-<translation id="5575380383496039204">ÐдреÑа доÑтавки не підтримуєтьÑÑ. Укажіть іншу адреÑу.</translation>
<translation id="5580958916614886209">Перевірте міÑÑць Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії та повторіть Ñпробу</translation>
<translation id="560412284261940334">ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ðµ підтримуєтьÑÑ</translation>
<translation id="5610142619324316209">перевірити наÑвніÑÑ‚ÑŒ з’єднаннÑ</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">Ідентифікаційну інформацію цього веб-Ñайта не було перевірено.</translation>
<translation id="5720705177508910913">Поточний кориÑтувач</translation>
<translation id="5732392974455271431">Батьки можуть розблокувати його</translation>
-<translation id="57586589942790530">ÐедійÑний номер картки</translation>
+<translation id="5763042198335101085">Введіть дійÑну електронну адреÑу</translation>
+<translation id="5765072501007116331">Укажіть адреÑу, щоб переглÑнути ÑпоÑоби доÑтавки та вимоги.</translation>
<translation id="5784606427469807560">Ðе вдалоÑÑ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¸Ñ‚Ð¸ дані картки. Перевірте Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· Інтернетом Ñ– повторіть Ñпробу.</translation>
<translation id="5785756445106461925">Окрім цього, Ñторінка міÑтить незахищені реÑурÑи. Інші оÑоби можуть переглÑдати Ñ—Ñ… під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ð²Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ…, а зловмиÑники можуть змінювати виглÑд Ñторінки.</translation>
<translation id="5786044859038896871">ВвеÑти дані кредитної картки?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">Ðемає зв’Ñзку із Ñайтом</translation>
<translation id="5869522115854928033">Збережені паролі</translation>
<translation id="5872918882028971132">Поради Ð´Ð»Ñ Ð±Ð°Ñ‚ÑŒÐºÑ–Ð²</translation>
-<translation id="587760065310675640">ÐдреÑа доÑтавки не підтримуєтьÑÑ. Укажіть іншу адреÑу.</translation>
<translation id="5901630391730855834">Жовтий</translation>
-<translation id="59174027418879706">Увімкнено</translation>
<translation id="5926846154125914413">Ви можете втратити доÑтуп до платного вміÑту на деÑких Ñайтах.</translation>
<translation id="5959728338436674663">Ðвтоматично надÑилати в Google деÑку <ph name="BEGIN_WHITEPAPER_LINK" />інформацію про ÑиÑтему та вміÑÑ‚ Ñторінок<ph name="END_WHITEPAPER_LINK" />, щоб допомогти виÑвлÑти небезпечні додатки й Ñайти<ph name="PRIVACY_PAGE_LINK" />.</translation>
<translation id="5966707198760109579">Тиждень</translation>
<translation id="5967867314010545767">Видалити з Ñ–Ñторії</translation>
<translation id="5975083100439434680">Зменшити маÑштаб</translation>
+<translation id="598637245381783098">Ðеможливо відкрити додаток Ð´Ð»Ñ Ð¿Ð»Ð°Ñ‚ÐµÐ¶Ñ–Ð²</translation>
<translation id="5989320800837274978">Ðе вказано ні фікÑованих прокÑÑ–-Ñерверів, ні URL-Ð°Ð´Ñ€ÐµÑ Ñценарію .pac.</translation>
<translation id="5990559369517809815">ÐадÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñ–Ð² на Ñервер заблоковано розширеннÑм.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Дані картки й ÑпиÑок Ð°Ð´Ñ€ÐµÑ Ð¼Ñ–ÑÑ‚ÑÑ‚ÑŒÑÑ Ð² Chrome. Ðими можна керувати в <ph name="BEGIN_LINK" />ÐалаштуваннÑÑ…<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Сторінка 1}one{Сторінка #}few{Сторінка #}many{Сторінка #}other{Сторінка #}}</translation>
<translation id="6017514345406065928">Зелений</translation>
+<translation id="6027201098523975773">Введіть ім’Ñ</translation>
<translation id="6040143037577758943">Закрити</translation>
-<translation id="604124094241169006">Ðвтоматично</translation>
<translation id="6042308850641462728">Більше</translation>
<translation id="6060685159320643512">Обережно, ці екÑперименти ненадійні</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{немає}=1{1}one{#}few{#}many{#}other{#}}</translation>
@@ -543,9 +552,10 @@
приÑтрої, Ñкі ви викориÑтовуєте.</translation>
<translation id="614940544461990577">Спробуйте:</translation>
<translation id="6151417162996330722">Сертифікат Ñервера має задовгий термін дії.</translation>
-<translation id="615643356032862689">Завантажені файли та закладки буде збережено.</translation>
+<translation id="6157877588268064908">Укажіть адреÑу, щоб переглÑнути ÑпоÑоби Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ñ‚Ð° вимоги.</translation>
<translation id="6165508094623778733">Докладніше</translation>
<translation id="6177128806592000436">Ваше Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· цим Ñайтом не захищене</translation>
+<translation id="6184817833369986695">(когорта: <ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">Перевірте Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· Інтернетом</translation>
<translation id="6218753634732582820">Видалити адреÑу з Chromium?</translation>
<translation id="6251924700383757765">Політика конфіденційноÑÑ‚Ñ–</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Повторити перевпорÑдкуваннÑ</translation>
<translation id="6263376278284652872">Закладки <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">ПовернутиÑÑ Ð´Ð¾ безпечного режиму</translation>
+<translation id="6276112860590028508">Тут з’ÑвлÑтимутьÑÑ Ñторінки з вашого ÑпиÑку читаннÑ</translation>
+<translation id="6280223929691119688">Ðеможливо доÑтавити Ð·Ð°Ð¼Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð° цією адреÑою. Укажіть іншу адреÑу.</translation>
<translation id="6282194474023008486">Поштовий код</translation>
<translation id="6290238015253830360">Тут відображатимутьÑÑ Ð¿Ñ€Ð¾Ð¿Ð¾Ð½Ð¾Ð²Ð°Ð½Ñ– Ñтатті</translation>
<translation id="6305205051461490394">Сторінка <ph name="URL" /> недоÑтупна.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Ðеможливо перевірити, чи цей Ñертифікат було відкликано.</translation>
<translation id="6433490469411711332">Змінити контактні дані</translation>
<translation id="6433595998831338502">ХоÑÑ‚ <ph name="HOST_NAME" /> відхилив запит на з’єднаннÑ.</translation>
-<translation id="6443118737398455446">ÐедійÑна дата Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії</translation>
<translation id="6446608382365791566">Додати більше інформації</translation>
<translation id="6451458296329894277">Підтвердити повторне надÑÐ¸Ð»Ð°Ð½Ð½Ñ Ñ„Ð¾Ñ€Ð¼Ð¸</translation>
<translation id="6456339708790392414">Ваш платіж</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">Ðе вдалоÑÑ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¸Ñ‚Ð¸, що це Ñервер <ph name="DOMAIN" />. Можливо, його Ñертифікат безпеки відкликано. Імовірні причини: Ñервер налаштовано неправильно або хтоÑÑŒ намагаєтьÑÑ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð¿Ð¸Ñ‚Ð¸ ваше з’єднаннÑ. <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Правила приÑтрою</translation>
<translation id="6477321094435799029">Chrome виÑвив на цій Ñторінці незвичний код Ñ– заблокував його, щоб захиÑтити вашу оÑобиÑту інформацію (наприклад, паролі, номери телефонів або кредитних карток).</translation>
-<translation id="6477460825583319731">ÐедійÑна електронна адреÑа</translation>
<translation id="6489534406876378309">Почати Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… про аварійне Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸</translation>
<translation id="6508722015517270189">ПерезапуÑÑ‚Ñ–Ñ‚ÑŒ Chrome</translation>
-<translation id="6525462735697194615">ÐедійÑний міÑÑць Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії</translation>
<translation id="6529602333819889595">&amp;Повторити видаленнÑ</translation>
<translation id="6534179046333460208">Пропозиції ÑервіÑу "Інтернет навколо наÑ"</translation>
<translation id="6550675742724504774">Параметри</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685">Пошук <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Це правило більше не викориÑтовуєтьÑÑ.</translation>
<translation id="6652240803263749613">Ðе вдалоÑÑ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¸Ñ‚Ð¸, що це Ñервер <ph name="DOMAIN" />. Операційна ÑиÑтема вашого комп’ютера вважає його Ñертифікат безпеки ненадійним. Імовірні причини: Ñервер налаштовано неправильно або хтоÑÑŒ намагаєтьÑÑ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð¿Ð¸Ñ‚Ð¸ ваше з’єднаннÑ. <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" />.</translation>
-<translation id="6665267558048410100">Цей ÑпоÑіб Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ð½ÐµÐ´Ð¾Ñтупний. Виберіть інший ÑпоÑіб.</translation>
<translation id="6671697161687535275">Видалити пропозицію Ð°Ð²Ñ‚Ð¾Ð·Ð°Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ñ„Ð¾Ñ€Ð¼ із Chromium?</translation>
<translation id="6685834062052613830">Вийдіть з облікового запиÑу та завершіть процедуру налаштуваннÑ</translation>
<translation id="6710213216561001401">Попереднє</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Помилка прокÑÑ–-Ñервера або неправильна адреÑа.</translation>
<translation id="6727102863431372879">Ð’Ñтановити</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{немає}=1{1 запиÑ}one{# запиÑ}few{# запиÑи}many{# запиÑів}other{# запиÑу}}</translation>
-<translation id="6743044928064272573">СпоÑіб отриманнÑ</translation>
<translation id="674375294223700098">Помилка "Ðевідомий Ñертифікат Ñервера".</translation>
<translation id="6753269504797312559">Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð°</translation>
<translation id="6757797048963528358">Ваш приÑтрій перейшов у режим Ñну.</translation>
<translation id="6778737459546443941">Батьки ще не Ñхвалили його</translation>
<translation id="6810899417690483278">Ідентифікатор налаштуваннÑ</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ дані регіонів</translation>
<translation id="6831043979455480757">ПереклаÑти</translation>
<translation id="6839929833149231406">Регіон або територіÑ</translation>
<translation id="6874604403660855544">&amp;Повторити додаваннÑ</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Дані картки підтверджено</translation>
<translation id="6897140037006041989">Ðгент кориÑтувача</translation>
<translation id="6915804003454593391">КориÑтувач:</translation>
+<translation id="6948701128805548767">Укажіть адреÑу, щоб переглÑнути ÑпоÑоби Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ñ‚Ð° вимоги.</translation>
<translation id="6957887021205513506">Схоже, що Ñертифікат Ñервера підроблено.</translation>
<translation id="6965382102122355670">ТÐК</translation>
<translation id="6965978654500191972">ПриÑтрій</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">Указано фікÑовані прокÑÑ–-Ñервери та URL-адреÑа Ñценарію .pac.</translation>
<translation id="6989763994942163495">Показати розширені налаштуваннÑ...</translation>
<translation id="7000990526846637657">Ðемає запиÑів в Ñ–Ñторії</translation>
-<translation id="7001663382399377034">Додати одержувача</translation>
<translation id="7009986207543992532">Ви намагалиÑÑ Ð·Ð²â€™ÑзатиÑÑ Ð· доменом <ph name="DOMAIN" />, але Ñервер надав Ñертифікат із задовгим терміном дії. <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">ІÑÑ‚Ð¾Ñ€Ñ–Ñ Ð²ÐµÐ±-переглÑду також може зберігатиÑÑ Ñƒ вашому обліковому запиÑÑ– Google на Ñторінці <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Давніше</translation>
<translation id="7090678807593890770">Пошукайте за запитом "<ph name="LINK" />" у Google</translation>
<translation id="7119414471315195487">Закрийте інші вкладки та програми</translation>
+<translation id="7129409597930077180">Ðеможливо відправити Ð·Ð°Ð¼Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð½Ð° цю адреÑу. Укажіть іншу адреÑу.</translation>
+<translation id="7138472120740807366">СпоÑіб доÑтавки</translation>
<translation id="7139724024395191329">Емірат</translation>
<translation id="7155487117670177674">Платіж не захищено</translation>
<translation id="7179921470347911571">ПерезапуÑтити зараз</translation>
<translation id="7180611975245234373">Оновити</translation>
<translation id="7182878459783632708">Правила не вÑтановлено</translation>
<translation id="7186367841673660872">Цю Ñторінку перекладено. Мова оригіналу:<ph name="ORIGINAL_LANGUAGE" />мова перекладу:<ph name="LANGUAGE_LANGUAGE" /></translation>
+<translation id="7192203810768312527">ЗвільнÑÑ” до <ph name="SIZE" />. ДеÑкі Ñайти можуть завантажуватиÑÑ Ð¿Ð¾Ð²Ñ–Ð»ÑŒÐ½Ñ–ÑˆÐµ під Ñ‡Ð°Ñ Ð½Ð°Ñтупного відвідуваннÑ.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423">ХоÑÑ‚ <ph name="HOST_NAME" /> не відповідає Ñтандартам безпеки.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Докладніше<ph name="END_LINK" /> про цю проблему.</translation>
@@ -675,7 +686,6 @@
<translation id="7424977062513257142">ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð· вбудованої Ñторінки на цій веб-Ñторінці:</translation>
<translation id="7441627299479586546">Ðеправильна тема правила</translation>
<translation id="7444046173054089907">Цей Ñайт заблоковано</translation>
-<translation id="7444238235002594607">Укажіть адреÑу отриманнÑ, щоб переглÑнути ÑпоÑоби Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ñ‚Ð° вимоги.</translation>
<translation id="7445762425076701745">Ідентифікацію Ñервера, з Ñким ви з'єднані, не можна повніÑÑ‚ÑŽ підтвердити. Ви з'єднані із Ñервером за допомогою імені, дійÑного лише у вашій мережі, Ñ– зовнішній центр Ñертифікації не має ÑпоÑобів підтвердити право влаÑноÑÑ‚Ñ– на це ім'Ñ. Хоча деÑкі центри Ñертифікації, попри вÑе, видають Ñертифікати на такі імена, неможливо цілком упевнитиÑÑ, що ви з'єднані з безпечним Ñайтом, а не зі зловмиÑником.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />дізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ<ph name="END_LINK" /> про цю проблему.</translation>
<translation id="7460163899615895653">Тут відображатимутьÑÑ Ð²Ð°ÑˆÑ– оÑтанні вкладки з інших приÑтроїв</translation>
@@ -719,6 +729,7 @@
<translation id="7755287808199759310">ХтоÑÑŒ із батьків може розблокувати його</translation>
<translation id="7758069387465995638">Можливо, брандмауер або антивіруÑна програма заблокували з’єднаннÑ.</translation>
<translation id="7761701407923456692">Сертифікат Ñервера не відповідає URL-адреÑÑ–.</translation>
+<translation id="7763386264682878361">СинтакÑичний аналізатор маніфеÑту платежу</translation>
<translation id="7764225426217299476">Додати адреÑу</translation>
<translation id="777702478322588152">Префектура</translation>
<translation id="7791543448312431591">Додати</translation>
@@ -732,6 +743,7 @@
<translation id="785549533363645510">Ðавіть у режимі анонімного переглÑду ваш роботодавець, поÑтачальник поÑлуг Інтернету чи веб-Ñайти, Ñкі ви відвідуєте, можуть бачити, що ви переглÑдаєте.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" />: <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7887683347370398519">Перевірте код CVC й повторіть Ñпробу</translation>
+<translation id="79338296614623784">Введіть дійÑний номер телефону</translation>
<translation id="7935318582918952113">ДиÑтилÑтор DOM</translation>
<translation id="7938958445268990899">Сертифікат Ñервера ще не дійÑний.</translation>
<translation id="7942349550061667556">Червоний</translation>
@@ -751,6 +763,7 @@
<translation id="8088680233425245692">Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ³Ð»Ñнути Ñтаттю.</translation>
<translation id="8089520772729574115">менше 1 Мб</translation>
<translation id="8091372947890762290">ÐÐºÑ‚Ð¸Ð²Ð°Ñ†Ñ–Ñ Ð¾Ñ‡Ñ–ÐºÑƒÑ” на Ñервері</translation>
+<translation id="8118489163946903409">СпоÑіб оплати</translation>
<translation id="8131740175452115882">Підтвердити</translation>
<translation id="8134994873729925007">Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ <ph name="BEGIN_ABBR" />адреÑу DNS-Ñервера<ph name="END_ABBR" /> хоÑту <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Ваш комп’ютер перейшов у режим Ñну.</translation>
@@ -776,6 +789,7 @@
<translation id="8349305172487531364">Панель закладок</translation>
<translation id="8363502534493474904">вимкнути режим польоту</translation>
<translation id="8364627913115013041">Ðе вÑтановлено.</translation>
+<translation id="8368476060205742148">СервіÑи Google Play</translation>
<translation id="8380941800586852976">Ðебезпечна</translation>
<translation id="8382348898565613901">Тут відображатимутьÑÑ Ð½ÐµÑ‰Ð¾Ð´Ð°Ð²Ð½Ð¾ відкриті закладки</translation>
<translation id="8398259832188219207">Дата Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð·Ð²Ñ–Ñ‚Ñƒ про аварійне Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸: <ph name="UPLOAD_TIME" /></translation>
@@ -784,32 +798,30 @@
<translation id="8428213095426709021">ÐалаштуваннÑ</translation>
<translation id="8433057134996913067">Ви вийдете з облікового запиÑу на більшоÑÑ‚Ñ– веб-Ñайтів.</translation>
<translation id="8437238597147034694">&amp;Відмінити переміщеннÑ</translation>
-<translation id="8456681095658380701">ÐедійÑне ім’Ñ</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 кредитна картка}one{# кредитна картка}few{# кредитні картки}many{# кредитних карток}other{# кредитної картки}}</translation>
<translation id="8483780878231876732">Щоб кориÑтуватиÑÑ ÐºÐ°Ñ€Ñ‚ÐºÐ°Ð¼Ð¸ у Ñвоєму обліковому запиÑÑ– Google, увійдіть у Chrome</translation>
<translation id="8488350697529856933">ЗаÑтоÑовуєтьÑÑ Ð´Ð¾:</translation>
-<translation id="8492969205326575646">Ðепідтримуваний тип картки</translation>
<translation id="8498891568109133222">ХоÑÑ‚ <ph name="HOST_NAME" /> довго не відповідає.</translation>
<translation id="852346902619691059">Ðе вдалоÑÑ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¸Ñ‚Ð¸, що це Ñервер <ph name="DOMAIN" />. Операційна ÑиÑтема вашого приÑтрою вважає його Ñертифікат безпеки ненадійним. Імовірні причини: Ñервер налаштовано неправильно або хтоÑÑŒ намагаєтьÑÑ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð¿Ð¸Ñ‚Ð¸ ваше з’єднаннÑ. <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="8532105204136943229">Рік Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії</translation>
<translation id="8543181531796978784">Ви можете <ph name="BEGIN_ERROR_LINK" />повідомити про проблему з пошуком<ph name="END_ERROR_LINK" /> або <ph name="BEGIN_LINK" />перейти на цей незахищений Ñайт<ph name="END_LINK" /> (Ñкщо розумієте, наÑкільки це небезпечно).</translation>
<translation id="8553075262323480129">Помилка перекладу. Ðеможливо визначити мову Ñторінки.</translation>
<translation id="8559762987265718583">Ðе вдаєтьÑÑ Ð²Ñтановити конфіденційне Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, оÑкільки на приÑтрої вÑтановлено неправильні дату й Ñ‡Ð°Ñ (<ph name="DATE_AND_TIME" />).</translation>
-<translation id="8570229484593575558">Цю інформацію |не буде збережено|:#Ñ–ÑÑ‚Ð¾Ñ€Ñ–Ñ Ð²ÐµÐ±-переглÑду#пошукові запити#дані файлів cookie</translation>
<translation id="8571890674111243710">ВиконуєтьÑÑ Ð¿ÐµÑ€ÐµÐºÐ»Ð°Ð´ Ñторінки такою мовою: <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Вашу активніÑÑ‚ÑŒ |уÑе ще можуть бачити|:#веб-Ñайти, Ñкі ви відвідуєте#ваш роботодавець#ваш поÑтачальник поÑлуг Інтернету</translation>
<translation id="858637041960032120">Додати тел.номер
</translation>
<translation id="859285277496340001">Сертифікат не вказує на механізм перевірки його відкликаннÑ.</translation>
<translation id="8620436878122366504">Батьки ще не Ñхвалили його</translation>
<translation id="8647750283161643317">Скинути вÑе до налаштувань за умовчаннÑм</translation>
<translation id="8703575177326907206">Ваше Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· <ph name="DOMAIN" /> не зашифровано.</translation>
+<translation id="8718314106902482036">Оплату не завершено</translation>
<translation id="8725066075913043281">Повторити Ñпробу</translation>
<translation id="8728672262656704056">Ви перейшли в режим анонімного переглÑду</translation>
<translation id="8730621377337864115">Готово</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="8759274551635299824">Термін дії цієї картки минув</translation>
<translation id="8790007591277257123">&amp;Повторити видаленнÑ</translation>
-<translation id="8798099450830957504">За умовчаннÑм</translation>
<translation id="8800988563907321413">Тут відображатимутьÑÑ Ð¿Ñ€Ð¾Ð¿Ð¾Ð·Ð¸Ñ†Ñ–Ñ—</translation>
<translation id="8820817407110198400">Закладки</translation>
<translation id="883848425547221593">Інші закладки</translation>
@@ -819,6 +831,7 @@
<translation id="8866481888320382733">Помилка аналізу налаштувань правила</translation>
<translation id="8866959479196209191">ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð· цієї Ñторінки:</translation>
<translation id="8870413625673593573">Ðещодавно закриті</translation>
+<translation id="8874824191258364635">Введіть дійÑний номер картки</translation>
<translation id="8876793034577346603">Помилка аналізу конфігурації мережі.</translation>
<translation id="8877192140621905067">Щойно ви підтвердите дані картки, цей Ñайт отримає доÑтуп до них</translation>
<translation id="8889402386540077796">Тон</translation>
@@ -828,7 +841,6 @@
<translation id="8931333241327730545">Зберегти цю картку у вашому обліковому запиÑÑ– Google?</translation>
<translation id="8932102934695377596">Ваш годинник запізнюєтьÑÑ</translation>
<translation id="8954894007019320973">(Продовж.)</translation>
-<translation id="895548565263634352">Читайте Ñтатті автора <ph name="ARTICLE_PUBLISHER" /> Ñ– ще <ph name="OTHER_ARTICLE_COUNT" /></translation>
<translation id="8971063699422889582">Термін дії Ñертифіката Ñервера завершивÑÑ.</translation>
<translation id="8986494364107987395">Ðвтоматично надÑилати ÑтатиÑтику викориÑÑ‚Ð°Ð½Ð½Ñ Ñ‚Ð° звіти про аварійне Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ в Google</translation>
<translation id="8987927404178983737">МіÑÑць</translation>
@@ -846,7 +858,6 @@
<translation id="9068849894565669697">Вибрати колір</translation>
<translation id="9076283476770535406">Ðа ньому може бути вміÑÑ‚ Ð´Ð»Ñ Ð´Ð¾Ñ€Ð¾Ñлих</translation>
<translation id="9078964945751709336">Потрібно більше інформації</translation>
-<translation id="9094175695478007090">Ðе вдалоÑÑ Ð·Ð°Ð¿ÑƒÑтити додаток Ð´Ð»Ñ Ð¿Ð»Ð°Ñ‚ÐµÐ¶Ñ–Ð².</translation>
<translation id="9103872766612412690">Веб-Ñайт <ph name="SITE" /> зазвичай викориÑтовує ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð·Ð°Ñ…Ð¸Ñту вашої інформації. Під Ñ‡Ð°Ñ Ñ†Ñ–Ñ”Ñ— Ñпроби Chromium під’єднатиÑÑ Ð´Ð¾ Ñторінки <ph name="SITE" /> з неї отримано незвичні й неправильні облікові дані. Це може ÑтатиÑÑ, коли зловмиÑник намагаєтьÑÑ Ð²Ð¸Ð´Ð°Ð²Ð°Ñ‚Ð¸ Ñебе за веб-Ñайт <ph name="SITE" /> або Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÑ€Ð²Ð°Ð½Ð¾ екраном входу Wi-Fi. Ваша Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð·Ð°Ð»Ð¸ÑˆÐ°Ñ”Ñ‚ÑŒÑÑ Ð·Ð°Ñ…Ð¸Ñ‰ÐµÐ½Ð¾ÑŽ, оÑкільки Chromium припинив Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð´Ð¾ того, Ñк почавÑÑ Ð¾Ð±Ð¼Ñ–Ð½ будь-Ñкими даними.</translation>
<translation id="9137013805542155359">Показати оригінал</translation>
<translation id="9137248913990643158">Перш ніж кориÑтуватиÑÑ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð¼, увійдіть в обліковий Ð·Ð°Ð¿Ð¸Ñ Chrome.</translation>
diff --git a/chromium/components/strings/components_strings_vi.xtb b/chromium/components/strings/components_strings_vi.xtb
index 54cada4f184..81c4bed838f 100644
--- a/chromium/components/strings/components_strings_vi.xtb
+++ b/chromium/components/strings/components_strings_vi.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="vi">
<translation id="1008557486741366299">Không phải Bây giá»</translation>
<translation id="1015730422737071372">Cung cấp chi tiết bổ sung</translation>
+<translation id="1021110881106174305">Thẻ được chấp nhận</translation>
<translation id="1032854598605920125">Xoay theo chiá»u kim đồng hồ</translation>
<translation id="1038842779957582377">tên không biết</translation>
<translation id="1050038467049342496">Äóng các ứng dụng khác</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">Ẩn giá trị</translation>
<translation id="1228893227497259893">Số nhận dạng tổ chức không đúng</translation>
<translation id="1232569758102978740">Không tên</translation>
+<translation id="1263231323834454256">Danh sách Ä‘á»c</translation>
<translation id="1264126396475825575">Báo cáo sự cố được ghi lại vào <ph name="CRASH_TIME" /> (nhưng chưa tải lên hoặc đã bị bỠqua)</translation>
<translation id="1285320974508926690">Không bao giỠdịch trang web này</translation>
<translation id="129553762522093515">Các tab đã đóng gần đây</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Cài đặt tá»± Ä‘á»™ng Ä‘iá»n trong Chromium...</translation>
<translation id="1374468813861204354">đỠxuất</translation>
<translation id="1375198122581997741">Giới thiệu Phiên bản</translation>
+<translation id="1377321085342047638">Số thẻ</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> không gửi bất kỳ dữ liệu nào.</translation>
<translation id="1407135791313364759">Mở tất cả</translation>
<translation id="1413809658975081374">Lỗi bảo mật</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">Lịch sử</translation>
<translation id="1645368109819982629">Giao thức không được hỗ trợ</translation>
<translation id="1656489000284462475">Nhận hàng</translation>
+<translation id="1663943134801823270">Thẻ và địa chỉ từ Chrome. Bạn có thể quản lý thẻ và địa chỉ trong <ph name="BEGIN_LINK" />Cài đặt<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> thÆ°á»ng sá»­ dụng mã hóa để bảo vệ thông tin của bạn. Khi Google Chrome tìm cách kết nối vá»›i <ph name="SITE" /> tại thá»i Ä‘iểm này, trang web đã gá»­i lại thông tin đăng nhập không chính xác và bất thÆ°á»ng. Äiá»u này có thể xảy ra khi kẻ tấn công Ä‘ang cố gắng giả mạo là <ph name="SITE" /> hoặc màn hình đăng nhập Wi-Fi đã làm gián Ä‘oạn kết nối. Thông tin của bạn vẫn an toàn do Google Chrome đã ngừng kết nối trÆ°á»›c khi bất kỳ dữ liệu nào được trao đổi.</translation>
<translation id="168328519870909584">Những kẻ tấn công hiện đang truy cập <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> có thể cố cài đặt các ứng dụng nguy hiểm trên thiết bị của bạn để lấy cắp hoặc xóa thông tin của bạn (ví dụ: ảnh, mật khẩu, thư và thẻ tín dụng).</translation>
<translation id="168841957122794586">Chứng chỉ máy chủ chứa khóa mật mã yếu.</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Bạn cần được <ph name="NAME" /> cấp quyá»n để truy cập vào trang web này</translation>
+<translation id="1721424275792716183">TrÆ°á»ng * là bắt buá»™c</translation>
<translation id="1728677426644403582">Bạn đang xem nguồn của trang web</translation>
+<translation id="173080396488393970">Loại thẻ này không được hỗ trợ</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Thử liên hệ với quản trị viên hệ thống.</translation>
+<translation id="1740951997222943430">Nhập tháng hết hạn hợp lệ</translation>
<translation id="1745358365027406341">Tải trang xuống sau</translation>
<translation id="17513872634828108">Tab đang mở</translation>
<translation id="1753706481035618306">Số trang</translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">Vui lòng cập nhật cụm mật khẩu đồng bộ hóa của bạn.</translation>
<translation id="1787142507584202372">Tab đang mở của bạn xuất hiện ở đây</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">Chá»n địa chỉ giao hàng để kiểm tra các yêu cầu và phÆ°Æ¡ng thức giao hàng.</translation>
+<translation id="1803264062614276815">Tên chủ thẻ</translation>
<translation id="1803678881841855883">Gần đây, tính năng Duyệt web an toàn của Google <ph name="BEGIN_LINK" />đã phát hiện thấy phần má»m Ä‘á»™c hại<ph name="END_LINK" /> trên <ph name="SITE" />. Các trang web bình thÆ°á»ng vẫn an toàn đôi khi bị lây nhiá»…m phần má»m Ä‘á»™c hại. Ná»™i dung Ä‘á»™c hại đến từ <ph name="SUBRESOURCE_HOST" />, má»™t đối tượng phân phối phần má»m Ä‘á»™c hại đã biết. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1806541873155184440">Ngày thêm: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">Yêu cầu hoặc tham số yêu cầu không hợp lệ</translation>
<translation id="1826516787628120939">Äang kiểm tra</translation>
<translation id="1834321415901700177">Trang web này có chứa các chương trình độc hại</translation>
<translation id="1842969606798536927">Thanh toán</translation>
-<translation id="1864455488461349376">Tùy chá»n giao hàng</translation>
<translation id="1871208020102129563">Proxy được đặt để sử dụng máy chủ proxy cố định chứ không phải URL tập lệnh .pac.</translation>
<translation id="1871284979644508959">TrÆ°á»ng bắt buá»™c</translation>
<translation id="187918866476621466">Mở trang khởi động</translation>
<translation id="1883255238294161206">Thu gá»n danh sách</translation>
<translation id="1898423065542865115">Lá»c</translation>
<translation id="194030505837763158">Truy cập <ph name="LINK" /></translation>
-<translation id="1946821392246652573">Thẻ được chấp nhận</translation>
<translation id="1962204205936693436">Dấu trang của <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Lỗi nối tiếp hóa</translation>
<translation id="1974060860693918893">Nâng cao</translation>
<translation id="1978555033938440688">Phiên bản chương trình cơ sở</translation>
+<translation id="1995859865337580572">Vui lòng xác minh CVC của bạn</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{và 1 ứng dụng khác}other{và # ứng dụng khác}}</translation>
-<translation id="2020194265157481222">Yêu cầu tên trên thẻ</translation>
<translation id="2025186561304664664">Proxy được đặt thành định cấu hình tự động.</translation>
<translation id="2030481566774242610">à của bạn là <ph name="LINK" />?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Kiểm tra proxy và tÆ°á»ng lá»­a<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">Hôm nay</translation>
<translation id="2154054054215849342">Tính năng đồng bá»™ hóa không khả dụng cho miá»n của bạn</translation>
<translation id="2154484045852737596">Chỉnh sửa thẻ</translation>
-<translation id="2156993118928861787">ÄiÌ£a chỉ không hÆ¡Ì£p lệ</translation>
<translation id="2166049586286450108">Quyá»n truy cập quản trị đầy đủ</translation>
<translation id="2166378884831602661">Trang web này không thể cung cấp kết nối an toàn</translation>
<translation id="2181821976797666341">Chính sách</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 địa chỉ}other{# địa chỉ}}</translation>
+<translation id="2202020181578195191">Nhập năm hết hạn hợp lệ</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="2230458221926704099">Sửa kết nối bằng <ph name="BEGIN_LINK" />ứng dụng chẩn đoán<ph name="END_LINK" /></translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">Quyá»n truy cập Internet của bạn bị chặn</translation>
<translation id="230155334948463882">Thẻ mới?</translation>
<translation id="2305919008529760154">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ể đã được cấp má»™t cách gian lận. Äiá»u này có thể do cấu hình sai hoặc có kẻ tấn công chặn kết nối 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="230697611605700222">Tùy chá»n thẻ và địa chỉ từ Tài khoản Google (<ph name="ACCOUNT_EMAIL" />) của bạn và Chrome. Bạn có thể quản lý các mục này trong <ph name="BEGIN_LINK" />Cài đặt<ph name="END_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> yêu cầu tên ngÆ°á»i dùng và mật khẩu.</translation>
<translation id="2318774815570432836">Bạn không thể truy cập <ph name="SITE" /> ngay bây giá» vì trang web sá»­ dụng HSTS. Lá»—i mạng và các cuá»™c tấn công mạng thÆ°á»ng chỉ là tạm thá»i, do đó, trang này có thể sẽ hoạt Ä‘á»™ng lại sau. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2354001756790975382">Dấu trang khác</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">Äặt mặc định trong môi trÆ°á»ng doanh nghiệp</translation>
<translation id="2386255080630008482">Chứng chỉ của máy chủ đã bị thu hồi.</translation>
<translation id="2392959068659972793">Hiển thị chính sách không có giá trị được đặt</translation>
+<translation id="239429038616798445">Phương thức giao hàng này không có sẵn. Hãy thử một phương thức khác.</translation>
<translation id="2396249848217231973">&amp;Hoàn tác xóa</translation>
<translation id="2460160116472764928">Gần đây, tính năng Duyệt web an toàn của Google <ph name="BEGIN_LINK" />đã phát hiện thấy phần má»m Ä‘á»™c hại<ph name="END_LINK" /> trên <ph name="SITE" />. Các trang web bình thÆ°á»ng vẫn an toàn đôi khi bị lây nhiá»…m phần má»m Ä‘á»™c hại. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2463739503403862330">Äiá»n</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Chạy Chẩn đoán mạng<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL tìm kiếm hợp lệ.</translation>
<translation id="2491120439723279231">Chứng chỉ của máy chủ có lỗi.</translation>
-<translation id="24943777258388405">Số điện thoại không hợp lệ</translation>
<translation id="2495083838625180221">Trình phân tích cú pháp JSON</translation>
<translation id="2495093607237746763">Nếu được chá»n, Chromium sẽ lÆ°u trữ bản sao thẻ của bạn trên thiết bị này để Ä‘iá»n biểu mẫu nhanh hÆ¡n.</translation>
<translation id="2498091847651709837">Quét thẻ mới</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> đã gửi phản hồi không hợp lệ.</translation>
<translation id="2552545117464357659">Mới hơn</translation>
<translation id="2556876185419854533">&amp;Hoàn tác chỉnh sửa</translation>
+<translation id="2587730715158995865">Từ <ph name="ARTICLE_PUBLISHER" />. Äá»c tin bài này và <ph name="OTHER_ARTICLE_COUNT" /> tin bài khác.</translation>
<translation id="2587841377698384444">ID API thư mục:</translation>
<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>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Chạy Chẩn đoán kết nối<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">Ok</translation>
<translation id="2742870351467570537">Xóa các mục đã chá»n</translation>
+<translation id="277133753123645258">Phương thức giao hàng</translation>
<translation id="277499241957683684">Thiếu hồ sơ thiết bị</translation>
<translation id="2784949926578158345">Kết nối đã được đặt lại.</translation>
<translation id="2794233252405721443">Trang web đã bị chặn</translation>
-<translation id="2812680587231492111">Tùy chá»n lá»±a chá»n đó không khả dụng. Hãy thá»­ má»™t tùy chá»n khác.</translation>
<translation id="2824775600643448204">Thanh địa chỉ và tìm kiếm</translation>
<translation id="2826760142808435982">Kết nối được mã hóa và xác thá»±c bằng <ph name="CIPHER" /> đồng thá»i sá»­ dụng <ph name="KX" /> làm cÆ¡ chế trao đổi chính.</translation>
<translation id="2835170189407361413">Xóa biểu mẫu</translation>
-<translation id="2849041323157393173">Tùy chá»n giao hàng đó không khả dụng. Hãy thá»­ má»™t tùy chá»n khác.</translation>
<translation id="2889159643044928134">Không tải lại</translation>
<translation id="2900469785430194048">Google Chrome đã hết bộ nhớ khi cố gắng hiển thị trang web này.</translation>
<translation id="2909946352844186028">Äã phát hiện thấy thay đổi mạng.</translation>
<translation id="2916038427272391327">Äóng các chÆ°Æ¡ng trình khác</translation>
<translation id="2922350208395188000">Không thể kiểm tra chứng chỉ của máy chủ.</translation>
+<translation id="2928905813689894207">Ãịa chỉ thanh toá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>
<translation id="2955913368246107853">Äóng thanh tìm</translation>
<translation id="2958431318199492670">Cấu hình mạng không tuân thủ tiêu chuẩn ONC. Các bộ phận của cấu hình có thể không được nhập.</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">Äể 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 Chrome không thể xác minh các chứng chỉ này.</translation>
<translation id="2972581237482394796">&amp;Làm lại</translation>
<translation id="2985306909656435243">Nếu được bật, Chromium sẽ lÆ°u trữ bản sao thẻ của bạn trên thiết bị này để Ä‘iá»n vào biểu mẫu nhanh hÆ¡n.</translation>
+<translation id="2985398929374701810">Nhập địa chỉ hợp lệ</translation>
+<translation id="2986368408720340940">Phương thức nhận hàng này không có sẵn. Hãy thử một phương thức khác.</translation>
<translation id="2991174974383378012">Chia sẻ với trang web</translation>
<translation id="3005723025932146533">Hiển thị bản sao đã lưu</translation>
<translation id="3008447029300691911">Nhập CVC cho <ph name="CREDIT_CARD" />. Sau khi bạn xác nhận, chi tiết thẻ của bạn sẽ được chia sẻ với trang web này.</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{ít nhất 1 mục trên các thiết bị đã đồng bá»™ hóa}=1{1 mục (và nhiá»u mục khác trên các thiết bị đã đồng bá»™ hóa)}other{# mục (và nhiá»u mục khác trên các thiết bị đã đồng bá»™ hóa)}}</translation>
<translation id="3041612393474885105">Thông tin Chứng chỉ</translation>
<translation id="3063697135517575841">Chrome không thể xác nhận thẻ của bạn tại thá»i Ä‘iểm này. Vui lòng thá»­ lại sau.</translation>
+<translation id="3064966200440839136">Rá»i khá»i chế Ä‘á»™ ẩn danh để thanh toán qua má»™t ứng dụng bên ngoài. Tiếp tục?</translation>
<translation id="3093245981617870298">Bạn đang ngoại tuyến.</translation>
<translation id="3105172416063519923">ID phần tử:</translation>
<translation id="3109728660330352905">Bạn không có quyá»n xem trang này.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Thử chạy Chẩn đoán kết nối<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Không thể giải mã phản hồi</translation>
-<translation id="3149891296864842641">Tùy chá»n giao hàng</translation>
<translation id="3150653042067488994">Lá»—i máy chủ tạm thá»i</translation>
+<translation id="3154506275960390542">Trang này bao gồm biểu mẫu có thể được gá»­i không an toàn. Dữ liệu bạn gá»­i có thể bị ngÆ°á»i khác xem trong khi chuyển tuyến hoặc có thể bị kẻ tấn công sá»­a đổi nhằm thay đổi thông tin mà máy chủ nhận được.</translation>
<translation id="3157931365184549694">Khôi phục</translation>
<translation id="3167968892399408617">Các trang bạn xem trong tab ẩn danh sẽ không bị lÆ°u lại trong lịch sá»­ của trình duyệt, kho cookie hoặc lịch sá»­ tìm kiếm sau khi bạn đóng tất cả các tab ẩn danh của mình. Má»i tệp bạn tải xuống hoặc dấu trang mà bạn tạo sẽ được giữ nguyên.</translation>
<translation id="3169472444629675720">Khám phá</translation>
@@ -263,11 +271,13 @@
<translation id="3345135638360864351">Không thể gửi yêu cầu truy cập trang web này của bạn tới <ph name="NAME" />. Vui lòng thử lại.</translation>
<translation id="3355823806454867987">Thay đổi cài đặt proxy...</translation>
<translation id="3369192424181595722">Lỗi đồng hồ</translation>
+<translation id="337311366426640088"><ph name="ITEM_COUNT" /> mục khác...</translation>
<translation id="337363190475750230">Äã hủy cấp phép</translation>
<translation id="3377188786107721145">Lỗi phân tích cú pháp chính sách</translation>
<translation id="3380365263193509176">Lỗi không xác định</translation>
<translation id="3380864720620200369">ID ứng dụng khách:</translation>
<translation id="3391030046425686457">Äịa chỉ giao hàng</translation>
+<translation id="3395827396354264108">Phương thức nhận hàng</translation>
<translation id="340013220407300675">Có thể những kẻ tấn công đang cố đá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, tin nhắn hoặc thẻ tín dụng).</translation>
<translation id="3422248202833853650">Thử thoát các chương trình khác để giải phóng bộ nhớ.</translation>
<translation id="3422472998109090673">Hiện không thể truy cập <ph name="HOST_NAME" />.</translation>
@@ -278,12 +288,13 @@
<translation id="3450660100078934250">MasterCard</translation>
<translation id="3452404311384756672">Khoảng thá»i gian tìm nạp:</translation>
<translation id="3462200631372590220">Ẩn chi tiêÌt</translation>
+<translation id="3467763166455606212">Yêu cầu tên chủ thẻ</translation>
+<translation id="3478058380795961209">Tháng hết hạn</translation>
<translation id="3479539252931486093">Trang web này có như bạn mong đợi không? Hãy <ph name="BEGIN_LINK" />cho chúng tôi biết<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">Không phải bây giá»</translation>
<translation id="348000606199325318">ID sự cố <ph name="CRASH_LOCAL_ID" /> (ID máy chủ: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Chúng tôi không thể liên lạc vá»›i cha mẹ của bạn vào thá»i Ä‘iểm này. Vui lòng thá»­ lại.</translation>
<translation id="3528171143076753409">Chứng chỉ của máy chủ không đáng tin cậy.</translation>
-<translation id="3538531656504267329">Năm hết hạn không hợp lệ</translation>
<translation id="3539171420378717834">Giữ bản sao thẻ này trên thiết bị này</translation>
<translation id="3542684924769048008">Sử dụng mật khẩu cho:</translation>
<translation id="3549644494707163724">Mã hóa tất cả dữ liệu đã đồng bộ hóa bằng cụm mật khẩu đồng bộ hóa của riêng bạn</translation>
@@ -296,6 +307,7 @@
<translation id="3586931643579894722">Ẩn chi tiết</translation>
<translation id="3587482841069643663">Tất cả</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
+<translation id="3615877443314183785">Nhập ngày hết hạn hợp lệ</translation>
<translation id="36224234498066874">Xóa Dữ liệu Duyệt web...</translation>
<translation id="362276910939193118">Hiển thị Toàn bộ Lịch sử</translation>
<translation id="3623476034248543066">Hiển thị giá trị</translation>
@@ -312,7 +324,6 @@
<translation id="3693415264595406141">Mật khẩu:</translation>
<translation id="3696411085566228381">không có</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">Chá»n địa chỉ giao hàng để kiểm tra các yêu cầu và phÆ°Æ¡ng thức giao hàng.</translation>
<translation id="370665806235115550">Äang tải...</translation>
<translation id="3712624925041724820">Giấy phép không đủ</translation>
<translation id="3714780639079136834">Bật dữ liệu di dộng hoặc Wi-Fi</translation>
@@ -321,6 +332,7 @@
<translation id="3739623965217189342">Liên kết đã sao chép</translation>
<translation id="375403751935624634">Không thể dịch do lỗi máy chủ.</translation>
<translation id="3759461132968374835">Bạn không nhận được báo cáo sự cố nào gần đây. Sự cố xảy ra khi báo cáo sự cố đã bị tắt sẽ không xuất hiện ở đây.</translation>
+<translation id="3787705759683870569">Ngày hết hạn <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="382518646247711829">Nếu bạn sử dụng máy chủ proxy...</translation>
<translation id="3828924085048779000">Không cho phép cụm mật khẩu trống.</translation>
<translation id="3845539888601087042">Hiển thị lịch sử từ các thiết bị bạn đã đăng nhập. <ph name="BEGIN_LINK" />Tìm hiểu thêm<ph name="END_LINK" />.</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Bạn có muốn Chromium lưu thẻ này không?</translation>
<translation id="4171400957073367226">Chữ ký xác minh không hợp lệ</translation>
-<translation id="4176463684765177261">Äã bị vô hiệu</translation>
<translation id="4196861286325780578">&amp;Làm lại di chuyển</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Kiểm tra tÆ°á»ng lá»­a và cấu hình diệt vi-rút<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{không có gì}=1{1 ứng dụng ($1)}=2{2 ứng dụng ($1, $2)}other{# ứng dụng ($1, $2, $3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">kết quả tìm kiếm</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> không chấp nhận chứng chỉ đăng nhập của bạn hoặc có thể bạn chưa cung cấp chứng chỉ đăng nhậ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="4446242550670694251">GiỠđây, bạn có thể duyệt web ở chế Ä‘á»™ riêng tÆ° và những ngÆ°á»i khác sá»­ dụng thiết bị này sẽ không thấy hoạt Ä‘á»™ng của bạn.</translation>
<translation id="4492190037599258964">Kết quả tìm kiếm cho '<ph name="SEARCH_STRING" />'</translation>
<translation id="4506176782989081258">Lỗi xác thực: <ph name="VALIDATION_ERROR" />.</translation>
<translation id="4506599922270137252">Liên hệ với quản trị viên hệ thống</translation>
<translation id="450710068430902550">Chia sẻ với quản trị viên</translation>
+<translation id="4515275063822566619">Thẻ và địa chỉ từ Chrome và Tài khoản Google của bạn (<ph name="ACCOUNT_EMAIL" />). Bạn có thể quản lý thẻ và địa chỉ trong <ph name="BEGIN_LINK" />Cài đặt<ph name="END_LINK" />.</translation>
<translation id="4522570452068850558">Chi tiết</translation>
<translation id="4558551763791394412">Thử tắt tiện ích.</translation>
<translation id="457875822857220463">Giao hàng</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">Vừa với trang</translation>
<translation id="483020001682031208">Không có trang Web trong cuộc sống nào để hiển thị</translation>
<translation id="4850886885716139402">Xem</translation>
+<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="4858792381671956233">Bạn đã há»i cha mẹ mình xem có thể truy cập vào trang này hay không</translation>
<translation id="4880827082731008257">Lịch sử tìm kiếm</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">Trang này đã được dịch từ một ngôn ngữ không xác định sang <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Thanh toán</translation>
<translation id="4926049483395192435">Phải được chỉ định.</translation>
-<translation id="4941291666397027948">* biểu thị trÆ°á»ng bắt buá»™c</translation>
<translation id="495170559598752135">Tác vụ</translation>
<translation id="4958444002117714549">Mở rộng danh sách</translation>
<translation id="4962322354953122629">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 Chrome tin tưởng. Äiá»u này có thể do cấu hình sai hoặc có kẻ tấn công chặn kết nối của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -439,6 +450,7 @@
<translation id="5045550434625856497">Mật khẩu sai</translation>
<translation id="5056549851600133418">Bài viết dành cho bạn</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Kiểm tra địa chỉ proxy<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{Không có cookie}=1{1 trang web sử dụng cookie. }other{# trang web sử dụng cookie. }}</translation>
<translation id="5087286274860437796">Chứng chỉ của máy chủ không hợp lệ tại thá»i Ä‘iểm này.</translation>
<translation id="5087580092889165836">Thêm thẻ</translation>
<translation id="5089810972385038852">Tiểu bang</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">Hiển thị</translation>
<translation id="5308689395849655368">Báo cáo sự cố bị tắt.</translation>
<translation id="5317780077021120954">LÆ°u</translation>
-<translation id="5326702247179446998">Cần có ngÆ°á»i nhận</translation>
<translation id="5327248766486351172">Tên</translation>
<translation id="5337705430875057403">Kẻ tấn công trên <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> có thể đánh lừa bạn làm má»™t việc gì đó nguy hiểm nhÆ° cài đặt phần má»m hoặc tiết lá»™ thông tin cá nhân của bạn (ví dụ: mật khẩu, số Ä‘iện thoại hoặc thẻ tín dụng).</translation>
-<translation id="53553865750799677">Äịa chỉ nhận hàng không được há»— trợ. Hãy chá»n má»™t địa chỉ khác.</translation>
<translation id="5359637492792381994">Máy chủ này không chứng minh được rằng đó là <ph name="DOMAIN" />; hiện tại, chứng chỉ bảo mật của máy chủ này không hợp lệ. Äiá»u này có thể do cấu hình sai hoặc có kẻ tấn công chặn kết nối 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="536296301121032821">Không thể lưu trữ cài đặt chính sách</translation>
<translation id="5386426401304769735">Chuỗi chứng chỉ cho trang web này có chứa một chứng chỉ đã ký bằng SHA-1.</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102">Trang được nhúng tại <ph name="SITE" /> cho biết:</translation>
<translation id="5556459405103347317">Tải lại</translation>
<translation id="5565735124758917034">Äang hoaÌ£t động</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>
<translation id="5572851009514199876">Vui lòng khởi động và đăng nhập vào Chrome để Chrome có thể kiểm tra xem bạn có được phép truy cập trang web này không.</translation>
-<translation id="5575380383496039204">Äịa chỉ giao hàng không được há»— trợ. Hãy chá»n má»™t địa chỉ khác.</translation>
<translation id="5580958916614886209">Kiểm tra tháng hết hạn của bạn và thử lại</translation>
<translation id="560412284261940334">Không hỗ trợ quản lý</translation>
<translation id="5610142619324316209">Kiểm tra kết nối</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">Nhận dạng trang web này chưa được xác minh.</translation>
<translation id="5720705177508910913">NgÆ°á»i dùng hiện tại</translation>
<translation id="5732392974455271431">Cha mẹ của bạn có thể bỠchặn trang web cho bạn</translation>
-<translation id="57586589942790530">Số thẻ không hợp lệ</translation>
+<translation id="5763042198335101085">Nhập địa chỉ email hợp lệ</translation>
+<translation id="5765072501007116331">Äể xem các yêu cầu và phÆ°Æ¡ng thức phân phối, hãy chá»n má»™t địa chỉ</translation>
<translation id="5784606427469807560">Äã xảy ra sá»± cố khi xác nhận thẻ của bạn. Hãy kiểm tra kết nối Internet của bạn và thá»­ lại.</translation>
<translation id="5785756445106461925">Ngoài ra, trang này bao gồm các tài nguyên khác không an toàn. Những tài nguyên này có thể bị ngÆ°á»i khác xem khi Ä‘ang gá»­i và có thể bị kẻ tấn công sá»­a đổi nhằm thay đổi giao diện của trang.</translation>
<translation id="5786044859038896871">Bạn có muốn Ä‘iá»n thông tin thẻ của mình không?</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">Không thể truy cập trang web này</translation>
<translation id="5869522115854928033">Mật khẩu đã lưu</translation>
<translation id="5872918882028971132">Äá» xuất chính</translation>
-<translation id="587760065310675640">Äịa chỉ giao hàng không được há»— trợ. Hãy chá»n má»™t địa chỉ khác.</translation>
<translation id="5901630391730855834">Vàng</translation>
-<translation id="59174027418879706">Äã bật</translation>
<translation id="5926846154125914413">Bạn có thể mất quyá»n truy cập vào ná»™i dung cao cấp từ má»™t số trang web.</translation>
<translation id="5959728338436674663">Tự động gửi một số <ph name="BEGIN_WHITEPAPER_LINK" />thông tin hệ thống và nội dung trang<ph name="END_WHITEPAPER_LINK" /> tới Google để giúp phát hiện các ứng dụng và trang web nguy hiểm. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">Tuần</translation>
<translation id="5967867314010545767">Xóa khá»i lịch sá»­</translation>
<translation id="5975083100439434680">Thu nhá»</translation>
+<translation id="598637245381783098">Không thể mở ứng dụng thanh toán</translation>
<translation id="5989320800837274978">Cả máy chủ proxy cố định và URL tập lệnh .pac Ä‘á»u chÆ°a được chỉ định.</translation>
<translation id="5990559369517809815">Tiện ích đã chặn yêu cầu tới máy chủ.</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">Tùy chá»n thẻ và địa chỉ từ Chrome. Bạn có thể quản lý các mục này trong <ph name="BEGIN_LINK" />Cài đặt<ph name="END_LINK" />.</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Trang 1}other{Trang #}}</translation>
<translation id="6017514345406065928">Xanh lục</translation>
+<translation id="6027201098523975773">Nhập tên</translation>
<translation id="6040143037577758943">Äóng</translation>
-<translation id="604124094241169006">Tá»± Ä‘á»™ng</translation>
<translation id="6042308850641462728">Thêm</translation>
<translation id="6060685159320643512">Hãy cẩn thận, thử nghiệm này có thể gây lỗi</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{không có gì}=1{1}other{#}}</translation>
@@ -543,9 +552,10 @@
mạng khác mà bạn có thể đang sử dụng.</translation>
<translation id="614940544461990577">Hãy thử:</translation>
<translation id="6151417162996330722">Chứng chỉ máy chủ có thá»i gian hiệu lá»±c quá dài.</translation>
-<translation id="615643356032862689">Các tệp đã tải xuống và dấu trang sẽ được giữ nguyên.</translation>
+<translation id="6157877588268064908">Äể xem các yêu cầu và phÆ°Æ¡ng thức giao hàng, hãy chá»n má»™t địa chỉ</translation>
<translation id="6165508094623778733">Tìm hiểu thêm</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="6184817833369986695">(nhóm thuần tập: <ph name="UPDATE_COHORT_NAME" />)</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>
<translation id="6251924700383757765">ChiÌnh saÌch bảo mật</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">&amp;Làm lại sắp xếp lại</translation>
<translation id="6263376278284652872">Dấu trang trên <ph name="DOMAIN" /></translation>
<translation id="6264485186158353794">Quay lại an toàn</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="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="6290238015253830360">Bài viết được đỠxuất của bạn sẽ xuất hiện ở đây</translation>
<translation id="6305205051461490394">Không thể truy cập <ph name="URL" />.</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">Không thể kiểm tra liệu chứng chỉ đã bị thu hồi hay chưa.</translation>
<translation id="6433490469411711332">Chỉnh sửa thông tin liên hệ</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> đã từ chối kết nối.</translation>
-<translation id="6443118737398455446">Ngày hết hạn không hợp lệ</translation>
<translation id="6446608382365791566">Thêm thông tin khác</translation>
<translation id="6451458296329894277">Xác nhận việc Gửi lại Biểu mẫu</translation>
<translation id="6456339708790392414">Thanh toán của bạn</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">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 cấu hình sai hoặc có kẻ tấn công chặn kết nối 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="647261751007945333">Chính sách thiết bị</translation>
<translation id="6477321094435799029">Chrome đã phát hiện mã bất thÆ°á»ng trên trang này và đã chặn mã này để bảo vệ thông tin cá nhân của bạn (ví dụ nhÆ° mật khẩu, số Ä‘iện thoại và thẻ tín dụng).</translation>
-<translation id="6477460825583319731">Äịa chỉ email không hợp lệ</translation>
<translation id="6489534406876378309">Bắt đầu tải lên sự cố</translation>
<translation id="6508722015517270189">Khởi động lại Chrome</translation>
-<translation id="6525462735697194615">Tháng hết hạn không hợp lệ</translation>
<translation id="6529602333819889595">&amp;Làm lại xóa</translation>
<translation id="6534179046333460208">Äá» xuất Web trong cuá»™c sống</translation>
<translation id="6550675742724504774">Tùy chá»n</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685">Tìm kiếm trên <ph name="ENGINE" /></translation>
<translation id="6644283850729428850">Chính sách này không được chấp thuận.</translation>
<translation id="6652240803263749613">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 của máy tính tin tưởng. Äiá»u này có thể do cấu hình sai hoặc có kẻ tấn công chặn kết nối 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="6665267558048410100">Tùy chá»n vận chuyển đó không khả dụng. Hãy thá»­ má»™t tùy chá»n khác.</translation>
<translation id="6671697161687535275">Bạn muốn xóa Ä‘á» xuất biểu mẫu khá»i Chromium?</translation>
<translation id="6685834062052613830">Äăng xuất và hoàn thành quá trình thiết lập</translation>
<translation id="6710213216561001401">Trước đó</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Äã xảy ra sá»± cố vá»›i máy chủ proxy hoặc địa chỉ không chính xác.</translation>
<translation id="6727102863431372879">Äặt</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{không có gì}=1{1 mục}other{# mục}}</translation>
-<translation id="6743044928064272573">Tùy chá»n nhận hàng</translation>
<translation id="674375294223700098">Lỗi chứng chỉ máy chủ không xác định.</translation>
<translation id="6753269504797312559">Giá trị chính sách</translation>
<translation id="6757797048963528358">Thiết bị của bạn đã chuyển sang chế độ ngủ.</translation>
<translation id="6778737459546443941">Cha mẹ của bạn chưa phê duyệt trang web</translation>
<translation id="6810899417690483278">ID tùy chỉnh</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">Không tải được dữ liệu khu vực</translation>
<translation id="6831043979455480757">Dịch</translation>
<translation id="6839929833149231406">Khu vá»±c</translation>
<translation id="6874604403660855544">&amp;Làm lại thêm</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">Thẻ của bạn đã được xác nhận</translation>
<translation id="6897140037006041989">Tác nhân NgÆ°á»i dùng</translation>
<translation id="6915804003454593391">NgÆ°á»i dùng:</translation>
+<translation id="6948701128805548767">Äể xem các yêu cầu và phÆ°Æ¡ng thức nhận hàng, hãy chá»n má»™t địa chỉ</translation>
<translation id="6957887021205513506">Chứng chỉ của máy chủ dÆ°á»ng nhÆ° giả mạo.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Thiết bị</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">Cả hai máy chủ proxy cố định và URL tập lệnh .pac Ä‘á»u được chỉ định.</translation>
<translation id="6989763994942163495">Hiển thị cài đặt nâng cao...</translation>
<translation id="7000990526846637657">Không tìm thấy mục nhập lịch sử nào</translation>
-<translation id="7001663382399377034">Thêm ngÆ°á»i nhận</translation>
<translation id="7009986207543992532">Bạn đã cố gắng truy cập <ph name="DOMAIN" /> nhÆ°ng máy chủ đã xuất trình chứng chỉ có thá»i gian có hiệu lá»±c quá dài để có thể tin cậy. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7012372675181957985">Tài khoản Google của bạn có thể có các biểu mẫu lịch sử duyệt web khác tại <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
@@ -641,12 +649,15 @@
<translation id="7088615885725309056">Cũ hơn</translation>
<translation id="7090678807593890770">Tìm kiếm <ph name="LINK" /> trên Google</translation>
<translation id="7119414471315195487">Äóng các tab hoặc chÆ°Æ¡ng trình khác</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="7138472120740807366">Phương thức phân phối</translation>
<translation id="7139724024395191329">Tiểu vương quốc</translation>
<translation id="7155487117670177674">Thanh toán không an toàn</translation>
<translation id="7179921470347911571">Chạy lại ngay bây giá»</translation>
<translation id="7180611975245234373">Làm mới</translation>
<translation id="7182878459783632708">Không có chính sách nào được đặt</translation>
<translation id="7186367841673660872">Trang này đã được dịch từ<ph name="ORIGINAL_LANGUAGE" />sang<ph name="LANGUAGE_LANGUAGE" /></translation>
+<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="7210863904660874423"><ph name="HOST_NAME" /> không tuân thủ các tiêu chuẩn bảo mật.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Tìm hiểu thêm<ph name="END_LINK" /> vỠsự cố này.</translation>
@@ -675,7 +686,6 @@ Lưu ý! Chế độ ẩn danh <ph name="SHORTCUT_KEY" /> có thể hữu ích v
<translation id="7424977062513257142">Trang được nhúng trên trang web này cho biết:</translation>
<translation id="7441627299479586546">Chủ đỠchính sách sai</translation>
<translation id="7444046173054089907">Trang web này bị chặn</translation>
-<translation id="7444238235002594607">Chá»n địa chỉ nhận hàng để kiểm tra các yêu cầu và phÆ°Æ¡ng thức nhận hàng.</translation>
<translation id="7445762425076701745">Không thể xác thực đầy đủ nhận dạng của máy chủ bạn đã kết nối. Bạn đã kết nối vào máy chủ bằng một tên chỉ hợp lệ trong mạng của bạn và đó là tên mà các tổ chức phát hành chứng chỉ bên ngoài không thể xác thực được. Vì một số tổ chức phát hành chứng chỉ sẽ cấp chứng chỉ cho các tên này thay thế, nên không có cách nào đảm bảo bạn được kết nối tới trang web đã chỉ định và không phải là kẻ tấn công.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Tìm hiểu thêm<ph name="END_LINK" /> vỠsự cố này.</translation>
<translation id="7460163899615895653">Các tab gần đây của bạn từ các thiết bị khác xuất hiện ở đây</translation>
@@ -719,6 +729,7 @@ Lưu ý! Chế độ ẩn danh <ph name="SHORTCUT_KEY" /> có thể hữu ích v
<translation id="7755287808199759310">Cha mẹ của bạn có thể bỠchặn trang web cho bạn</translation>
<translation id="7758069387465995638">TÆ°á»ng lá»­a hoặc phần má»m diệt vi-rút có thể đã chặn kết nối.</translation>
<translation id="7761701407923456692">Chứng chỉ của máy chủ không phù hợp với URL.</translation>
+<translation id="7763386264682878361">Trình phân tích cú pháp tệp kê khai thanh toán</translation>
<translation id="7764225426217299476">Thêm địa chỉ</translation>
<translation id="777702478322588152">Quận</translation>
<translation id="7791543448312431591">Thêm</translation>
@@ -732,6 +743,7 @@ Lưu ý! Chế độ ẩn danh <ph name="SHORTCUT_KEY" /> có thể hữu ích v
<translation id="785549533363645510">Tuy nhiên, bạn không ẩn. Việc chuyển sang chế độ ẩn danh sẽ không ẩn thao tác duyệt của bạn với chủ lao động, nhà cung cấp dịch vụ internet hoặc các trang web bạn truy cập.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">Kiểm tra CVC của bạn và thử lại</translation>
+<translation id="79338296614623784">Nhập số điện thoại hợp lệ</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Chứng chỉ của máy chủ chưa hợp lệ.</translation>
<translation id="7942349550061667556">Äá»</translation>
@@ -751,6 +763,7 @@ Lưu ý! Chế độ ẩn danh <ph name="SHORTCUT_KEY" /> có thể hữu ích v
<translation id="8088680233425245692">Không xem được bài viết.</translation>
<translation id="8089520772729574115">dÆ°á»›i 1 MB</translation>
<translation id="8091372947890762290">Kích hoạt đang chỠxử lý trên máy chủ</translation>
+<translation id="8118489163946903409">Phương thức thanh toán</translation>
<translation id="8131740175452115882">Xác nhận</translation>
<translation id="8134994873729925007">Không thể tìm thấy <ph name="BEGIN_ABBR" />địa chỉ DNS<ph name="END_ABBR" /> của máy chủ của <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Máy tính của bạn đã chuyển sang chế độ ngủ.</translation>
@@ -776,6 +789,7 @@ Lưu ý! Chế độ ẩn danh <ph name="SHORTCUT_KEY" /> có thể hữu ích v
<translation id="8349305172487531364">Thanh dấu trang</translation>
<translation id="8363502534493474904">Tắt chế độ trên máy bay</translation>
<translation id="8364627913115013041">Chưa được đặt.</translation>
+<translation id="8368476060205742148">Dịch vụ của Google Play</translation>
<translation id="8380941800586852976">Nguy hiểm</translation>
<translation id="8382348898565613901">Dấu trang bạn truy cập gần đây sẽ xuất hiện ở đây</translation>
<translation id="8398259832188219207">Báo cáo sự cố được tải lên vào <ph name="UPLOAD_TIME" /></translation>
@@ -784,32 +798,30 @@ Lưu ý! Chế độ ẩn danh <ph name="SHORTCUT_KEY" /> có thể hữu ích v
<translation id="8428213095426709021">Cài đặt</translation>
<translation id="8433057134996913067">Thao tác này sẽ đăng xuất bạn khá»i hầu hết các trang web.</translation>
<translation id="8437238597147034694">&amp;Hoàn tác di chuyển</translation>
-<translation id="8456681095658380701">Tên không hợp lệ</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 thẻ tín dụng}other{# thẻ tín dụng}}</translation>
<translation id="8483780878231876732">Äể sá»­ dụng thẻ từ Tài khoản Google, hãy đăng nhập vào Chrome</translation>
<translation id="8488350697529856933">Ãp dụng cho</translation>
-<translation id="8492969205326575646">Loại thẻ không được hỗ trợ</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> mất quá nhiá»u thá»i gian để phản hồi.</translation>
<translation id="852346902619691059">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 của thiết bị tin tưởng. Äiá»u này có thể do cấu hình sai hoặc có kẻ tấn công chặn kết nối 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="8532105204136943229">Năm hết hạn</translation>
<translation id="8543181531796978784">Bạn có thể <ph name="BEGIN_ERROR_LINK" />báo cáo sự cố đã phát hiện<ph name="END_ERROR_LINK" /> hoặc nếu bạn hiểu rủi ro với bảo mật của mình, hãy <ph name="BEGIN_LINK" />truy cập trang web không an toàn này<ph name="END_LINK" />.</translation>
<translation id="8553075262323480129">Dịch thất bại do ngôn ngữ của trang không được xác định.</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="8570229484593575558">Thông tin này |sẽ không được lưu|:#Lịch sử duyệt web của bạn#Tìm kiếm của bạn#Dữ liệu cookie</translation>
<translation id="8571890674111243710">Äang dịch trang sang <ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">Hoạt động của bạn |có thể vẫn hiển thị| với:#Các trang web bạn truy cập#Chủ lao động của bạn#Nhà cung cấp dịch vụ Internet của bạn</translation>
<translation id="858637041960032120">Thêm số đ.thoại
</translation>
<translation id="859285277496340001">Chứng chỉ không ghi rõ cơ chế kiểm tra xem chứng chỉ đã bị thu hồi hay chưa.</translation>
<translation id="8620436878122366504">Cha mẹ của bạn chưa phê duyệt trang web</translation>
<translation id="8647750283161643317">Äặt lại tất cả vá» mặc định</translation>
<translation id="8703575177326907206">Kết nối của bạn đến <ph name="DOMAIN" /> không được mã hóa.</translation>
+<translation id="8718314106902482036">Thanh toán chưa hoàn tất</translation>
<translation id="8725066075913043281">Thử lại</translation>
-<translation id="8728672262656704056">Bạn đã truy cập ẩn danh</translation>
+<translation id="8728672262656704056">Bạn đã chuyển sang chế độ ẩn danh</translation>
<translation id="8730621377337864115">Hoàn tất</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="8759274551635299824">Thẻ này đã hết hạn</translation>
<translation id="8790007591277257123">&amp;Làm lại xóa</translation>
-<translation id="8798099450830957504">Mặc định</translation>
<translation id="8800988563907321413">Äá» xuất ở gần bạn xuất hiện ở đây</translation>
<translation id="8820817407110198400">Dấu trang</translation>
<translation id="883848425547221593">Dấu trang Khác</translation>
@@ -819,6 +831,7 @@ Lưu ý! Chế độ ẩn danh <ph name="SHORTCUT_KEY" /> có thể hữu ích v
<translation id="8866481888320382733">Lỗi phân tích cú pháp cài đặt chính sách</translation>
<translation id="8866959479196209191">Trang này cho biết:</translation>
<translation id="8870413625673593573">Các tab đã Äóng gần đây</translation>
+<translation id="8874824191258364635">Nhập số thẻ hợp lệ</translation>
<translation id="8876793034577346603">Không thể phân tích cú pháp cấu hình mạng.</translation>
<translation id="8877192140621905067">Sau khi bạn xác nhận, chi tiết thẻ của bạn sẽ được chia sẻ với trang web này</translation>
<translation id="8889402386540077796">Màu sắc</translation>
@@ -828,7 +841,6 @@ Lưu ý! Chế độ ẩn danh <ph name="SHORTCUT_KEY" /> có thể hữu ích v
<translation id="8931333241327730545">Bạn có muốn lưu thẻ này vào Tài khoản Google của mình không?</translation>
<translation id="8932102934695377596">Äồng hồ của bạn chạy chậm</translation>
<translation id="8954894007019320973">(Tiếp tục)</translation>
-<translation id="895548565263634352">Äá»c tin bài từ <ph name="ARTICLE_PUBLISHER" /> và <ph name="OTHER_ARTICLE_COUNT" /> tin bài khác</translation>
<translation id="8971063699422889582">Chứng chỉ của máy chủ đã hết hạn.</translation>
<translation id="8986494364107987395">Tự động gửi số liệu thống kê vỠviệc sử dụng và báo cáo sự cố cho Google</translation>
<translation id="8987927404178983737">Tháng</translation>
@@ -846,7 +858,6 @@ Lưu ý! Chế độ ẩn danh <ph name="SHORTCUT_KEY" /> có thể hữu ích v
<translation id="9068849894565669697">Chá»n màu</translation>
<translation id="9076283476770535406">Trang web có thể có ná»™i dung ngÆ°á»i lá»›n</translation>
<translation id="9078964945751709336">Yêu cầu thêm thông tin</translation>
-<translation id="9094175695478007090">Không thể khởi chạy ứng dụng thanh toán.</translation>
<translation id="9103872766612412690"><ph name="SITE" /> thÆ°á»ng sá»­ dụng mã hóa để bảo vệ thông tin của bạn. Khi Chromium cố gắng kết nối vá»›i <ph name="SITE" /> tại thá»i Ä‘iểm này, trang web đã gá»­i lại thông tin đăng nhập không chính xác và bất thÆ°á»ng. Äiá»u này có thể xảy ra khi kẻ tấn công Ä‘ang cố gắng giả mạo là <ph name="SITE" /> hoặc màn hình đăng nhập Wi-Fi đã làm gián Ä‘oạn kết nối. Thông tin của bạn vẫn an toàn do Chromium đã ngừng kết nối trÆ°á»›c khi bất kỳ dữ liệu nào được trao đổi.</translation>
<translation id="9137013805542155359">Hiển thị văn bản gốc</translation>
<translation id="9137248913990643158">Vui lòng khởi động và đăng nhập vào Chrome trước khi sử dụng ứng dụng này.</translation>
diff --git a/chromium/components/strings/components_strings_zh-CN.xtb b/chromium/components/strings/components_strings_zh-CN.xtb
index e818f56496b..89647697416 100644
--- a/chromium/components/strings/components_strings_zh-CN.xtb
+++ b/chromium/components/strings/components_strings_zh-CN.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="zh-CN">
<translation id="1008557486741366299">以åŽå†è¯´</translation>
<translation id="1015730422737071372">æ供其他详细信æ¯</translation>
+<translation id="1021110881106174305">接å—的信用å¡</translation>
<translation id="1032854598605920125">顺时针旋转</translation>
<translation id="1038842779957582377">未知å称</translation>
<translation id="1050038467049342496">关闭其他应用</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">éšè—值</translation>
<translation id="1228893227497259893">实体标识符有误</translation>
<translation id="1232569758102978740">无标题</translation>
+<translation id="1263231323834454256">阅读清å•</translation>
<translation id="1264126396475825575">崩溃报告获å–时间:<ph name="CRASH_TIME" />(该报告尚未上传或已被忽略)</translation>
<translation id="1285320974508926690">一律ä¸ç¿»è¯‘此网站</translation>
<translation id="129553762522093515">最近关闭的标签页</translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromium自动填充设置…</translation>
<translation id="1374468813861204354">建议</translation>
<translation id="1375198122581997741">关于版本</translation>
+<translation id="1377321085342047638">å¡å·</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> 未å‘é€ä»»ä½•æ•°æ®ã€‚</translation>
<translation id="1407135791313364759">全部打开</translation>
<translation id="1413809658975081374">éšç§è®¾ç½®é”™è¯¯</translation>
@@ -73,14 +76,18 @@
<translation id="1644574205037202324">历å²è®°å½•</translation>
<translation id="1645368109819982629">åè®®ä¸å—支æŒ</translation>
<translation id="1656489000284462475">å–è´§</translation>
+<translation id="1663943134801823270">信用å¡é€‰é¡¹å’Œåœ°å€é€‰é¡¹å‡æ¥è‡ª Chrome。您å¯åœ¨<ph name="BEGIN_LINK" />设置<ph name="END_LINK" />中管ç†è¿™äº›é€‰é¡¹ã€‚</translation>
<translation id="1676269943528358898"><ph name="SITE" /> 通常会使用加密技术æ¥ä¿æŠ¤æ‚¨çš„ä¿¡æ¯ã€‚Google Chrome 此次å°è¯•è¿žæŽ¥åˆ° <ph name="SITE" /> 时,此网站å‘回了异常的错误凭æ®ã€‚è¿™å¯èƒ½æ˜¯å› ä¸ºæœ‰æ”»å‡»è€…在试图冒充 <ph name="SITE" />,或 Wi-Fi 登录å±å¹•ä¸­æ–­äº†æ­¤æ¬¡è¿žæŽ¥ã€‚请放心,您的信æ¯ä»ç„¶æ˜¯å®‰å…¨çš„,因为 Google Chrome 尚未进行任何数æ®äº¤æ¢ä¾¿åœæ­¢äº†è¿žæŽ¥ã€‚</translation>
<translation id="168328519870909584"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 上的现有攻击者å¯èƒ½ä¼šè¯•å›¾é€šè¿‡åœ¨æ‚¨çš„设备上安装å±é™©åº”用æ¥çªƒå–或删除您的信æ¯ï¼ˆå¦‚照片ã€å¯†ç ã€é€šè®¯å†…容和信用å¡ä¿¡æ¯ï¼‰ã€‚</translation>
<translation id="168841957122794586">æœåŠ¡å™¨è¯ä¹¦åŒ…å«å¼±åŠ å¯†å¯†é’¥ã€‚</translation>
<translation id="1710259589646384581">æ“作系统</translation>
<translation id="1721312023322545264">您需è¦èŽ·å¾—<ph name="NAME" />的许å¯ï¼Œç„¶åŽæ‰èƒ½è®¿é—®æ­¤ç½‘ç«™</translation>
+<translation id="1721424275792716183">标有“*â€çš„字段å‡æ˜¯å¿…填字段</translation>
<translation id="1728677426644403582">您正在查看网页的æºä»£ç </translation>
+<translation id="173080396488393970">此信用å¡ç±»åž‹ä¸å—支æŒ</translation>
<translation id="1734864079702812349">美国è¿é€šå¡</translation>
<translation id="1734878702283171397">请å°è¯•è”系系统管ç†å‘˜ã€‚</translation>
+<translation id="1740951997222943430">请输入有效的失效月份</translation>
<translation id="1745358365027406341">ç¨åŽä¸‹è½½ç½‘页</translation>
<translation id="17513872634828108">ç›®å‰æ‰“开的标签页</translation>
<translation id="1753706481035618306">页ç </translation>
@@ -88,27 +95,25 @@
<translation id="1783075131180517613">请更新您的åŒæ­¥å¯†ç ã€‚</translation>
<translation id="1787142507584202372">您打开的标签页会显示在此处</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">选择递é€åœ°å€åŽæ‰èƒ½æŸ¥çœ‹é€’é€æ–¹å¼å’Œè¦æ±‚。</translation>
+<translation id="1803264062614276815">æŒå¡äººå§“å</translation>
<translation id="1803678881841855883">Google 安全æµè§ˆåŠŸèƒ½æœ€è¿‘在 <ph name="SITE" /> 上<ph name="BEGIN_LINK" />检测到æ¶æ„软件<ph name="END_LINK" />。平常éžå¸¸å®‰å…¨çš„网站有时也会感染æ¶æ„软件。这些æ¶æ„内容æ¥è‡ªå·²çŸ¥çš„æ¶æ„软件散布网站 <ph name="SUBRESOURCE_HOST" />。<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="1806541873155184440">添加日期:<ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">请求或请求å‚数无效</translation>
<translation id="1826516787628120939">正在检查</translation>
<translation id="1834321415901700177">此网站包å«æœ‰å®³ç¨‹åº</translation>
<translation id="1842969606798536927">付款</translation>
-<translation id="1864455488461349376">递é€é€‰é¡¹</translation>
<translation id="1871208020102129563">代ç†å·²è®¾ç½®ä¸ºä½¿ç”¨å›ºå®šçš„代ç†æœåŠ¡å™¨ï¼Œè€Œä¸æ˜¯ .pac 脚本网å€ã€‚</translation>
<translation id="1871284979644508959">必填字段</translation>
<translation id="187918866476621466">打开å¯åŠ¨é¡µ</translation>
<translation id="1883255238294161206">收起列表</translation>
<translation id="1898423065542865115">过滤</translation>
<translation id="194030505837763158">请访问<ph name="LINK" /></translation>
-<translation id="1946821392246652573">接å—的信用å¡</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" />书签</translation>
<translation id="1973335181906896915">åºåˆ—化错误</translation>
<translation id="1974060860693918893">高级</translation>
<translation id="1978555033938440688">固件版本</translation>
+<translation id="1995859865337580572">请验è¯æ‚¨çš„银行å¡éªŒè¯ç  (CVC)</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{以åŠå¦å¤– 1 个应用}other{以åŠå¦å¤– # 个应用}}</translation>
-<translation id="2020194265157481222">æŒå¡äººå§“å是必填项</translation>
<translation id="2025186561304664664">代ç†å·²è®¾ä¸ºè‡ªåŠ¨é…置。</translation>
<translation id="2030481566774242610">您是想访问<ph name="LINK" />å—?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />检查代ç†æœåŠ¡å™¨å’Œé˜²ç«å¢™<ph name="END_LINK" /></translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">今天</translation>
<translation id="2154054054215849342">您的网域ä¸æ”¯æŒåŒæ­¥</translation>
<translation id="2154484045852737596">修改支付å¡</translation>
-<translation id="2156993118928861787">地å€æ— æ•ˆ</translation>
<translation id="2166049586286450108">完全的管ç†å‘˜è®¿é—®æƒé™</translation>
<translation id="2166378884831602661">此网站无法æ供安全连接</translation>
<translation id="2181821976797666341">政策</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 个地å€}other{# 个地å€}}</translation>
+<translation id="2202020181578195191">请输入有效的失效年份</translation>
<translation id="2212735316055980242">找ä¸åˆ°ç­–ç•¥</translation>
<translation id="2213606439339815911">正在获å–æ¡ç›®â€¦</translation>
<translation id="2230458221926704099">请使用<ph name="BEGIN_LINK" />诊断应用<ph name="END_LINK" />ä¿®å¤ç½‘络连接</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">您被ç¦æ­¢è®¿é—®äº’è”网</translation>
<translation id="230155334948463882">è¦ä½¿ç”¨æ–°ä¿¡ç”¨å¡å—?</translation>
<translation id="2305919008529760154">æ­¤æœåŠ¡å™¨æ— æ³•è¯æ˜Žå…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›æœåŠ¡å™¨çš„安全è¯ä¹¦é¢å‘æ¥æºæœ‰æ¬ºè¯ˆå«Œç–‘。出现此问题的原因å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您的连接。<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
-<translation id="230697611605700222">信用å¡å’Œåœ°å€é€‰é¡¹å‡æ¥è‡ªæ‚¨çš„ Google å¸å· (<ph name="ACCOUNT_EMAIL" />) å’Œ Chrome。您å¯ä»¥åœ¨<ph name="BEGIN_LINK" />设置<ph name="END_LINK" />中管ç†è¿™äº›é€‰é¡¹ã€‚</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> è¦æ±‚æ供用户å和密ç ã€‚</translation>
<translation id="2318774815570432836">您目å‰æ— æ³•è®¿é—® <ph name="SITE" />,因为此网站使用了 HSTS。网络错误和攻击行为通常是暂时的,因此,此网页ç¨åŽå¯èƒ½å°±ä¼šæ¢å¤æ­£å¸¸ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="2354001756790975382">其他书签</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">在ä¼ä¸šçŽ¯å¢ƒä¸­é»˜è®¤å®žæ–½</translation>
<translation id="2386255080630008482">æœåŠ¡å™¨çš„è¯ä¹¦å·²æ’¤æ¶ˆã€‚</translation>
<translation id="2392959068659972793">显示未设定值的政策</translation>
+<translation id="239429038616798445">该é€è´§æ–¹å¼ä¸å¯ç”¨ã€‚请å¦é€‰ä¸€ç§æ–¹å¼ã€‚</translation>
<translation id="2396249848217231973">撤消删除(&amp;U)</translation>
<translation id="2460160116472764928">Google 安全æµè§ˆåŠŸèƒ½æœ€è¿‘在 <ph name="SITE" /> 上<ph name="BEGIN_LINK" />检测到æ¶æ„软件<ph name="END_LINK" />。平常éžå¸¸å®‰å…¨çš„网站有时也会感染æ¶æ„软件。<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="2463739503403862330">å¡«å……</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />è¿è¡Œç½‘络诊断<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">æœç´¢ç½‘å€æ— æ•ˆã€‚</translation>
<translation id="2491120439723279231">æœåŠ¡å™¨è¯ä¹¦ä¸­åŒ…å«é”™è¯¯ã€‚</translation>
-<translation id="24943777258388405">电è¯å·ç æ— æ•ˆ</translation>
<translation id="2495083838625180221">JSON 解æžå™¨</translation>
<translation id="2495093607237746763">选中åŽï¼ŒChromium 会将您的信用å¡å‰¯æœ¬å­˜å‚¨åœ¨æ­¤è®¾å¤‡ä¸Šï¼Œä»¥åŠ å¿«è¡¨å•å¡«å†™é€Ÿåº¦ã€‚</translation>
<translation id="2498091847651709837">扫æ新的信用å¡</translation>
@@ -172,6 +176,7 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> å‘é€çš„å“应无效。</translation>
<translation id="2552545117464357659">å¾€åŽ</translation>
<translation id="2556876185419854533">撤消修改(&amp;U)</translation>
+<translation id="2587730715158995865">æ¥è‡ª<ph name="ARTICLE_PUBLISHER" />。阅读这篇报é“以åŠå…¶ä»– <ph name="OTHER_ARTICLE_COUNT" /> 篇报é“。</translation>
<translation id="2587841377698384444">Directory API ID:</translation>
<translation id="2597378329261239068">本文档设置了密ç ä¿æŠ¤ï¼Œè¯·è¾“入密ç ã€‚</translation>
<translation id="2609632851001447353">其他å˜ä½“</translation>
@@ -197,19 +202,19 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />è¿è¡Œç½‘络连接诊断<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">确定</translation>
<translation id="2742870351467570537">移除所选项</translation>
+<translation id="277133753123645258">é€è´§æ–¹å¼</translation>
<translation id="277499241957683684">缺少设备记录</translation>
<translation id="2784949926578158345">连接已é‡ç½®ã€‚</translation>
<translation id="2794233252405721443">网站已被å±è”½</translation>
-<translation id="2812680587231492111">该å–货选项ä¸å¯ç”¨ã€‚请å¦é€‰ä¸€ä¸ªé€‰é¡¹ã€‚</translation>
<translation id="2824775600643448204">地å€å’Œæœç´¢æ </translation>
<translation id="2826760142808435982">该连接使用 <ph name="CIPHER" /> 进行加密和身份验è¯ï¼Œå¹¶ä½¿ç”¨ <ph name="KX" /> 作为密钥交æ¢æœºåˆ¶ã€‚</translation>
<translation id="2835170189407361413">清除表å•</translation>
-<translation id="2849041323157393173">该递é€é€‰é¡¹ä¸å¯ç”¨ã€‚请å¦é€‰ä¸€ä¸ªé€‰é¡¹ã€‚</translation>
<translation id="2889159643044928134">ä¸é‡æ–°åŠ è½½</translation>
<translation id="2900469785430194048">Google Chrome 在å°è¯•æ˜¾ç¤ºæ­¤ç½‘页时内存ä¸è¶³ã€‚</translation>
<translation id="2909946352844186028">检测到了网络å˜åŒ–。</translation>
<translation id="2916038427272391327">关闭其他程åº</translation>
<translation id="2922350208395188000">无法核实æœåŠ¡å™¨è¯ä¹¦ã€‚</translation>
+<translation id="2928905813689894207">å¸å•é‚®å¯„地å€</translation>
<translation id="2948083400971632585">您å¯ä»¥åœ¨è®¾ç½®é¡µé¢ä¸­åœç”¨ä»»ä½•é’ˆå¯¹æŸä¸ªè¿žæŽ¥é…置的代ç†ã€‚</translation>
<translation id="2955913368246107853">关闭查找æ </translation>
<translation id="2958431318199492670">网络é…ç½®ä¸ç¬¦åˆ ONC 标准。无法导入é…置的æŸäº›éƒ¨åˆ†ã€‚</translation>
@@ -218,6 +223,8 @@
<translation id="2969319727213777354">è¦å»ºç«‹å®‰å…¨è¿žæŽ¥ï¼Œæ‚¨çš„时钟设置必须正确。这是因为,网站用于è¯æ˜Žèº«ä»½çš„è¯ä¹¦ä»…在特定时间段有效。由于您设备的时钟ä¸æ­£ç¡®ï¼Œå› æ­¤ Google Chrome 无法验è¯è¿™äº›è¯ä¹¦ã€‚</translation>
<translation id="2972581237482394796">é‡åš(&amp;R)</translation>
<translation id="2985306909656435243">å¯ç”¨åŽï¼ŒChromium 会将您的信用å¡å‰¯æœ¬å­˜å‚¨åœ¨æ­¤è®¾å¤‡ä¸Šï¼Œä»¥åŠ å¿«è¡¨å•å¡«å†™é€Ÿåº¦ã€‚</translation>
+<translation id="2985398929374701810">请输入有效的é€è´§åœ°å€</translation>
+<translation id="2986368408720340940">该å–货方å¼ä¸å¯ç”¨ã€‚请å¦é€‰ä¸€ç§æ–¹å¼ã€‚</translation>
<translation id="2991174974383378012">与网站分享</translation>
<translation id="3005723025932146533">显示已ä¿å­˜çš„版本</translation>
<translation id="3008447029300691911">输入“<ph name="CREDIT_CARD" />â€çš„银行å¡éªŒè¯ç  (CVC)。在您确认åŽï¼Œæ‚¨çš„信用å¡è¯¦æƒ…将与此网站共享。</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{在已åŒæ­¥çš„设备上至少有 1 项内容}=1{1 项内容(在已åŒæ­¥çš„设备上还有更多内容)}other{# 项内容(在已åŒæ­¥çš„设备上还有更多内容)}}</translation>
<translation id="3041612393474885105">è¯ä¹¦ä¿¡æ¯</translation>
<translation id="3063697135517575841">Chrome ç›®å‰æ— æ³•ç¡®è®¤æ‚¨çš„信用å¡ï¼Œè¯·ç¨åŽé‡è¯•ã€‚</translation>
+<translation id="3064966200440839136">å°†è¦é€€å‡ºéšèº«æ¨¡å¼ï¼Œä»¥ä¾¿é€šè¿‡å¤–部应用付款。是å¦ç»§ç»­ï¼Ÿ</translation>
<translation id="3093245981617870298">您处于离线状æ€ã€‚</translation>
<translation id="3105172416063519923">资产 ID:</translation>
<translation id="3109728660330352905">您未获授æƒï¼Œæ— æ³•æŸ¥çœ‹æ­¤ç½‘页。</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />å°è¯•è¿è¡Œç½‘络连接诊断<ph name="END_LINK" />。</translation>
<translation id="3145945101586104090">无法对å“应解ç </translation>
-<translation id="3149891296864842641">é€è´§æ–¹å¼</translation>
<translation id="3150653042067488994">æœåŠ¡å™¨ä¸´æ—¶é”™è¯¯</translation>
+<translation id="3154506275960390542">此页包å«ä¸€ä¸ªå¯èƒ½æ— æ³•å®‰å…¨æ交的表å•ã€‚他人å¯èƒ½ä¼šåœ¨ä¼ è¾“过程中查看您所å‘é€çš„æ•°æ®ï¼›æ”»å‡»è€…也å¯èƒ½ä¼šä¿®æ”¹è¿™äº›æ•°æ®ï¼Œä»Žè€Œæ”¹å˜æœåŠ¡å™¨æ”¶åˆ°çš„内容。</translation>
<translation id="3157931365184549694">æ¢å¤</translation>
<translation id="3167968892399408617">在您关闭所有éšèº«æ ‡ç­¾é¡µåŽï¼Œæ‚¨åœ¨è¿™äº›æ ‡ç­¾é¡µä¸­æŸ¥çœ‹çš„网页ä¸ä¼šåœ¨æµè§ˆå™¨åŽ†å²è®°å½•ã€Cookie 存储区或æœç´¢è®°å½•ä¸­ç•™ä¸‹ä»»ä½•ç—•è¿¹ã€‚ä¸è¿‡ï¼Œæ‚¨ä¸‹è½½çš„所有文件或创建的书签å‡ä¼šä¿ç•™ä¸‹æ¥ã€‚</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -261,11 +269,13 @@
<translation id="3345135638360864351">无法将您访问此网站的请求å‘é€ç»™<ph name="NAME" />,请é‡è¯•ã€‚</translation>
<translation id="3355823806454867987">更改代ç†æœåŠ¡å™¨è®¾ç½®...</translation>
<translation id="3369192424181595722">时钟错误</translation>
+<translation id="337311366426640088">å¦å¤–还有 <ph name="ITEM_COUNT" /> 项…</translation>
<translation id="337363190475750230">å·²å–消é…ç½®</translation>
<translation id="3377188786107721145">策略解æžé”™è¯¯</translation>
<translation id="3380365263193509176">未知错误</translation>
<translation id="3380864720620200369">客户端 ID:</translation>
<translation id="3391030046425686457">递é€åœ°å€</translation>
+<translation id="3395827396354264108">å–货方å¼</translation>
<translation id="340013220407300675">攻击者å¯èƒ½ä¼šè¯•å›¾ä»Ž<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />窃å–您的信æ¯ï¼ˆä¾‹å¦‚:密ç ã€é€šè®¯å†…容或信用å¡ä¿¡æ¯ï¼‰ã€‚</translation>
<translation id="3422248202833853650">请å°è¯•é€€å‡ºå…¶ä»–程åºä»¥é‡Šæ”¾å†…存。</translation>
<translation id="3422472998109090673">ç›®å‰æ— æ³•è®¿é—® <ph name="HOST_NAME" />。</translation>
@@ -276,12 +286,13 @@
<translation id="3450660100078934250">Mastercard</translation>
<translation id="3452404311384756672">抓å–时间间隔:</translation>
<translation id="3462200631372590220">éšè—详情</translation>
+<translation id="3467763166455606212">必须输入æŒå¡äººå§“å</translation>
+<translation id="3478058380795961209">到期月份</translation>
<translation id="3479539252931486093">ä¸åº”该出现这ç§æƒ…况?请<ph name="BEGIN_LINK" />告诉我们<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">以åŽå†è¯´</translation>
<translation id="348000606199325318">崩溃 ID:<ph name="CRASH_LOCAL_ID" />(æœåŠ¡å™¨ ID:<ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">我们暂时无法与您父æ¯å–å¾—è”系,请é‡è¯•ã€‚</translation>
<translation id="3528171143076753409">æœåŠ¡å™¨çš„è¯ä¹¦ä¸å—信任。</translation>
-<translation id="3538531656504267329">到期年份无效</translation>
<translation id="3539171420378717834">在此设备上ä¿å­˜æ­¤ä¿¡ç”¨å¡çš„副本</translation>
<translation id="3542684924769048008">使用以下项的密ç ï¼š</translation>
<translation id="3549644494707163724">使用您自己的åŒæ­¥å¯†ç åŠ å¯†æ‰€æœ‰å·²åŒæ­¥æ•°æ®</translation>
@@ -294,6 +305,7 @@
<translation id="3586931643579894722">éšè—详细信æ¯</translation>
<translation id="3587482841069643663">全部</translation>
<translation id="3600246354004376029"><ph name="TITLE" />,<ph name="DOMAIN" />,<ph name="TIME" /></translation>
+<translation id="3615877443314183785">请输入有效的失效日期</translation>
<translation id="36224234498066874">清除æµè§ˆæ•°æ®...</translation>
<translation id="362276910939193118">显示所有历å²è®°å½•</translation>
<translation id="3623476034248543066">显示值</translation>
@@ -309,7 +321,6 @@
<translation id="3693415264595406141">密ç ï¼š</translation>
<translation id="3696411085566228381">æ— </translation>
<translation id="3704609568417268905"><ph name="TIME" /> - <ph name="BOOKMARKED" /> - <ph name="TITLE" /> - <ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">选择é€è´§åœ°å€åŽæ‰èƒ½æŸ¥çœ‹é€è´§æ–¹å¼å’Œè¦æ±‚。</translation>
<translation id="370665806235115550">正在加载...</translation>
<translation id="3712624925041724820">许å¯å·²ç”¨å°½</translation>
<translation id="3714780639079136834">å¼€å¯ç§»åŠ¨æ•°æ®ç½‘络或 Wi-Fi</translation>
@@ -318,6 +329,7 @@
<translation id="3739623965217189342">您å¤åˆ¶çš„链接</translation>
<translation id="375403751935624634">由于æœåŠ¡å™¨å‡ºé”™ï¼Œç¿»è¯‘失败。</translation>
<translation id="3759461132968374835">您最近未收到崩溃报告。崩溃报告åœç”¨æ—¶å‘生的崩溃ä¸ä¼šåœ¨æ­¤å¤„显示。</translation>
+<translation id="3787705759683870569">失效日期:<ph name="EXPIRATION_YEAR" /> 年 <ph name="EXPIRATION_MONTH" /> 月</translation>
<translation id="382518646247711829">如果您使用代ç†æœåŠ¡å™¨â€¦</translation>
<translation id="3828924085048779000">密ç è¾“入字段ä¸èƒ½ç•™ç©ºã€‚</translation>
<translation id="3845539888601087042">ç›®å‰æ˜¾ç¤ºçš„是您登录过的设备中的历å²è®°å½•ã€‚<ph name="BEGIN_LINK" />了解详情<ph name="END_LINK" />。</translation>
@@ -353,7 +365,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">您希望 Chromium ä¿å­˜æ­¤ä¿¡ç”¨å¡å—?</translation>
<translation id="4171400957073367226">验è¯ç­¾å无效</translation>
-<translation id="4176463684765177261">å·²åœç”¨</translation>
<translation id="4196861286325780578">æ¢å¤ç§»åŠ¨(&amp;R)</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />检查防ç«å¢™å’Œé˜²ç—…毒é…ç½®<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{æ— }=1{1 个应用 ($1)}=2{2 个应用($1ã€$2)}other{# 个应用($1ã€$2,$3)}}</translation>
@@ -380,11 +391,11 @@
<translation id="4406896451731180161">æœç´¢ç»“æžœ</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ä¸æŽ¥å—您的登录è¯ä¹¦ï¼Œæˆ–者您å¯èƒ½æ²¡æœ‰æ供登录è¯ä¹¦ã€‚</translation>
<translation id="443673843213245140">å·²åœç”¨ä»£ç†ï¼Œä½†æ˜¯æŒ‡å®šäº†æ˜Žç¡®çš„代ç†é…置。</translation>
-<translation id="4446242550670694251">现在您å¯ä»¥è¿›è¡Œç§å¯†æµè§ˆï¼Œè¿™æ ·ä¸€æ¥ï¼Œä½¿ç”¨æ­¤è®¾å¤‡çš„其他用户将ä¸ä¼šçœ‹åˆ°æ‚¨çš„活动。</translation>
<translation id="4492190037599258964">“<ph name="SEARCH_STRING" />â€çš„æœç´¢ç»“æžœ</translation>
<translation id="4506176782989081258">验è¯é”™è¯¯ï¼š<ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">è”系系统管ç†å‘˜</translation>
<translation id="450710068430902550">与管ç†å‘˜åˆ†äº«</translation>
+<translation id="4515275063822566619">信用å¡é€‰é¡¹å’Œåœ°å€é€‰é¡¹å‡æ¥è‡ª Chrome 和您的 Google å¸å· (<ph name="ACCOUNT_EMAIL" />)。您å¯åœ¨<ph name="BEGIN_LINK" />设置<ph name="END_LINK" />中管ç†è¿™äº›é€‰é¡¹ã€‚</translation>
<translation id="4522570452068850558">详细信æ¯</translation>
<translation id="4558551763791394412">å°è¯•åœç”¨æ‰©å±•ç¨‹åºã€‚</translation>
<translation id="457875822857220463">递é€</translation>
@@ -414,6 +425,7 @@
<translation id="4816492930507672669">适åˆé¡µé¢å¤§å°</translation>
<translation id="483020001682031208">没有å¯æ˜¾ç¤ºçš„实物网网页</translation>
<translation id="4850886885716139402">视图</translation>
+<translation id="4854362297993841467">该递é€æ–¹å¼ä¸å¯ç”¨ã€‚请å¦é€‰ä¸€ç§æ–¹å¼ã€‚</translation>
<translation id="4858792381671956233">您已å‘父æ¯å‘é€è¯·æ±‚,询问他们是å¦å…许您访问此网站</translation>
<translation id="4880827082731008257">æœç´¢åŽ†å²è®°å½•</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />ã€<ph name="TYPE_2" />ã€<ph name="TYPE_3" /></translation>
@@ -421,7 +433,6 @@
<translation id="4923417429809017348">翻译æœåŠ¡å™¨å·²å°†æ­¤ç½‘页从æŸç§æœªçŸ¥è¯­è¨€ç¿»è¯‘æˆäº†<ph name="LANGUAGE_LANGUAGE" />。</translation>
<translation id="4923459931733593730">付款</translation>
<translation id="4926049483395192435">必须指定。</translation>
-<translation id="4941291666397027948">*表示必填字段</translation>
<translation id="495170559598752135">æ“作</translation>
<translation id="4958444002117714549">展开列表</translation>
<translation id="4962322354953122629">æ­¤æœåŠ¡å™¨æ— æ³•è¯æ˜Žå…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›Chrome ä¸ä¿¡ä»»æœåŠ¡å™¨çš„安全è¯ä¹¦ã€‚出现此问题的原因å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您的连接。<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
@@ -436,6 +447,7 @@
<translation id="5045550434625856497">密ç ä¸æ­£ç¡®</translation>
<translation id="5056549851600133418">为您推è的文章</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />检查代ç†æœåŠ¡å™¨åœ°å€<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{没有 Cookie}=1{1 个网站使用 Cookie。}other{# 个网站使用 Cookie。}}</translation>
<translation id="5087286274860437796">æœåŠ¡å™¨çš„è¯ä¹¦ç›®å‰æ— æ•ˆã€‚</translation>
<translation id="5087580092889165836">添加新å¡</translation>
<translation id="5089810972385038852">å·ž</translation>
@@ -458,10 +470,8 @@
<translation id="5300589172476337783">显示</translation>
<translation id="5308689395849655368">å·²åœç”¨å´©æºƒæŠ¥å‘Šã€‚</translation>
<translation id="5317780077021120954">ä¿å­˜</translation>
-<translation id="5326702247179446998">收件人是必填项</translation>
<translation id="5327248766486351172">å称</translation>
<translation id="5337705430875057403"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 上的攻击者å¯èƒ½ä¼šè¯±éª—您åšä¸€äº›å±é™©çš„事情,如安装软件或泄露您的个人信æ¯ï¼ˆå¦‚密ç ã€ç”µè¯å·ç æˆ–信用å¡ä¿¡æ¯ï¼‰ã€‚</translation>
-<translation id="53553865750799677">ä¸æ”¯æŒæ­¤å–货地å€ã€‚请选择一个ä¸åŒçš„地å€ã€‚</translation>
<translation id="5359637492792381994">æ­¤æœåŠ¡å™¨æ— æ³•è¯æ˜Žå…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›æœåŠ¡å™¨çš„安全è¯ä¹¦ç›®å‰æ— æ•ˆã€‚出现此问题的原因å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您的连接。<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="536296301121032821">无法存储策略设置</translation>
<translation id="5386426401304769735">此网站的è¯ä¹¦é“¾åŒ…å«ä½¿ç”¨ SHA-1 签署的è¯ä¹¦ã€‚</translation>
@@ -487,8 +497,8 @@
<translation id="5544037170328430102"><ph name="SITE" /> 上的嵌入å¼é¡µé¢æ˜¾ç¤ºï¼š</translation>
<translation id="5556459405103347317">é‡æ–°åŠ è½½</translation>
<translation id="5565735124758917034">主动</translation>
+<translation id="5571083550517324815">无法从此地å€å–货。请å¦é€‰ä¸€ä¸ªåœ°å€ã€‚</translation>
<translation id="5572851009514199876">请å¯åŠ¨å¹¶ç™»å½• Chrome,以便 Chrome 能够检查您是å¦å¯ä»¥è®¿é—®æ­¤ç½‘站。</translation>
-<translation id="5575380383496039204">ä¸æ”¯æŒæ­¤é€’é€åœ°å€ã€‚请选择一个ä¸åŒçš„地å€ã€‚</translation>
<translation id="5580958916614886209">请检查您的信用å¡åˆ°æœŸæœˆä»½ï¼Œç„¶åŽé‡è¯•</translation>
<translation id="560412284261940334">ä¸æ”¯æŒç®¡ç†</translation>
<translation id="5610142619324316209">检查网络连接</translation>
@@ -504,7 +514,8 @@
<translation id="5710435578057952990">此网站尚未ç»è¿‡èº«ä»½éªŒè¯ã€‚</translation>
<translation id="5720705177508910913">当å‰ç”¨æˆ·</translation>
<translation id="5732392974455271431">您的父æ¯å¯ä¸ºæ‚¨å–消å±è”½æ­¤ç½‘ç«™</translation>
-<translation id="57586589942790530">å¡å·æ— æ•ˆ</translation>
+<translation id="5763042198335101085">请输入有效的电å­é‚®ä»¶åœ°å€</translation>
+<translation id="5765072501007116331">è¦æŸ¥çœ‹é€’é€æ–¹å¼å’Œè¦æ±‚,请选择相应地å€</translation>
<translation id="5784606427469807560">确认您的信用å¡æ—¶å‡ºçŽ°é—®é¢˜ã€‚请检查您的互è”网连接,然åŽé‡è¯•ã€‚</translation>
<translation id="5785756445106461925">而且,此页中包å«å…¶ä»–ä¸å®‰å…¨çš„资æºã€‚他人能在这些资æºä¼ è¾“过程中进行查看,攻击者也å¯ä»¥ä¿®æ”¹è¿™äº›èµ„æºï¼Œä»Žè€Œæ”¹å˜æ­¤é¡µçš„外观。</translation>
<translation id="5786044859038896871">è¦å¡«å……您的信用å¡ä¿¡æ¯å—?</translation>
@@ -517,31 +528,30 @@
<translation id="5869405914158311789">无法访问此网站</translation>
<translation id="5869522115854928033">å·²ä¿å­˜çš„密ç </translation>
<translation id="5872918882028971132">家长建议</translation>
-<translation id="587760065310675640">ä¸æ”¯æŒæ­¤é€è´§åœ°å€ã€‚请选择一个ä¸åŒçš„地å€ã€‚</translation>
<translation id="5901630391730855834">黄色</translation>
-<translation id="59174027418879706">å·²å¯ç”¨</translation>
<translation id="5926846154125914413">您å¯èƒ½æ— æ³•å†è®¿é—®æŸäº›ç½‘站上的付费内容。</translation>
<translation id="5959728338436674663">è‡ªåŠ¨å‘ Google å‘é€ä¸€äº›<ph name="BEGIN_WHITEPAPER_LINK" />系统信æ¯å’Œç½‘页内容<ph name="END_WHITEPAPER_LINK" />,以帮助检测å±é™©åº”用和网站。<ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">周</translation>
<translation id="5967867314010545767">从历å²è®°å½•ä¸­ç§»é™¤</translation>
<translation id="5975083100439434680">缩å°</translation>
+<translation id="598637245381783098">无法打开付款应用</translation>
<translation id="5989320800837274978">固定代ç†æœåŠ¡å™¨å’Œ .pac 脚本网å€å‡æœªæŒ‡å®šã€‚</translation>
<translation id="5990559369517809815">对æœåŠ¡å™¨çš„请求已é­åˆ°æŸä¸ªæ‰©å±•ç¨‹åºçš„阻止。</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">信用å¡å’Œåœ°å€é€‰é¡¹å‡æ¥è‡ª Chrome。您å¯ä»¥åœ¨<ph name="BEGIN_LINK" />设置<ph name="END_LINK" />中管ç†è¿™äº›é€‰é¡¹ã€‚</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{第 1 页}other{第 # 页}}</translation>
<translation id="6017514345406065928">绿色</translation>
+<translation id="6027201098523975773">请输入å称</translation>
<translation id="6040143037577758943">关闭</translation>
-<translation id="604124094241169006">自动</translation>
<translation id="6042308850641462728">更多</translation>
<translation id="6060685159320643512">请å°å¿ƒï¼Œè¿™äº›å®žéªŒæ€§åŠŸèƒ½å¯èƒ½æœ‰é£Žé™©</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{无}=1{1 个}other{# 个}}</translation>
<translation id="6146055958333702838">请检查所有网线是å¦éƒ½å·²è¿žå¥½ï¼Œç„¶åŽé‡æ–°å¯åŠ¨æ‚¨å¯èƒ½æ­£åœ¨ä½¿ç”¨çš„任何路由器ã€è°ƒåˆ¶è§£è°ƒå™¨æˆ–其他网络设备。</translation>
<translation id="614940544461990577">请试试以下办法:</translation>
<translation id="6151417162996330722">该æœåŠ¡å™¨è¯ä¹¦çš„有效期过长。</translation>
-<translation id="615643356032862689">书签和下载的文件将会ä¿ç•™ä¸‹æ¥ã€‚</translation>
+<translation id="6157877588268064908">è¦æŸ¥çœ‹é€è´§æ–¹å¼å’Œè¦æ±‚,请选择相应地å€</translation>
<translation id="6165508094623778733">了解详情</translation>
<translation id="6177128806592000436">您与此网站之间建立的连接ä¸å®‰å…¨</translation>
+<translation id="6184817833369986695">(åŒç±»ç¾¤ç»„:<ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">请检查您的互è”网连接是å¦æ­£å¸¸</translation>
<translation id="6218753634732582820">è¦ä»Ž Chromium 中移除地å€å—?</translation>
<translation id="6251924700383757765">éšç§æƒæ”¿ç­–</translation>
@@ -550,6 +560,8 @@
<translation id="6259156558325130047">æ¢å¤é¡ºåºè°ƒæ•´(&amp;R)</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> 书签</translation>
<translation id="6264485186158353794">返回安全连接</translation>
+<translation id="6276112860590028508">您的阅读清å•ä¸­çš„网页会显示在此处</translation>
+<translation id="6280223929691119688">无法递é€åˆ°æ­¤åœ°å€ã€‚请å¦é€‰ä¸€ä¸ªåœ°å€ã€‚</translation>
<translation id="6282194474023008486">邮编</translation>
<translation id="6290238015253830360">为您推è的文章会显示在此处</translation>
<translation id="6305205051461490394">无法访问 <ph name="URL" />。</translation>
@@ -571,7 +583,6 @@
<translation id="6417515091412812850">无法检查è¯ä¹¦æ˜¯å¦å·²åŠé”€ã€‚</translation>
<translation id="6433490469411711332">修改è”系信æ¯</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> æ‹’ç»äº†æˆ‘们的连接请求。</translation>
-<translation id="6443118737398455446">过期日期无效</translation>
<translation id="6446608382365791566">添加更多信æ¯</translation>
<translation id="6451458296329894277">确认é‡æ–°æ交表å•</translation>
<translation id="6456339708790392414">您的付款</translation>
@@ -579,10 +590,8 @@
<translation id="6462969404041126431">æ­¤æœåŠ¡å™¨æ— æ³•è¯æ˜Žå…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›æœåŠ¡å™¨çš„安全è¯ä¹¦å¯èƒ½é­åˆ°æ’¤æ¶ˆã€‚出现此问题的原因å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您的连接。<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="647261751007945333">设备政策</translation>
<translation id="6477321094435799029">Chrome 在此网页上检测到了异常代ç ã€‚为ä¿æŠ¤æ‚¨çš„个人信æ¯ï¼ˆä¾‹å¦‚密ç ã€ç”µè¯å·ç å’Œä¿¡ç”¨å¡ä¿¡æ¯ï¼‰ï¼ŒChrome 已将该网页拦截。</translation>
-<translation id="6477460825583319731">电å­é‚®ä»¶åœ°å€æ— æ•ˆ</translation>
<translation id="6489534406876378309">开始上传崩溃数æ®</translation>
<translation id="6508722015517270189">é‡æ–°å¯åŠ¨ Chrome</translation>
-<translation id="6525462735697194615">到期月份无效</translation>
<translation id="6529602333819889595">æ¢å¤åˆ é™¤(&amp;R)</translation>
<translation id="6534179046333460208">实物网建议</translation>
<translation id="6550675742724504774">选项</translation>
@@ -597,7 +606,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> æœç´¢</translation>
<translation id="6644283850729428850">此政策已弃用。</translation>
<translation id="6652240803263749613">æ­¤æœåŠ¡å™¨æ— æ³•è¯æ˜Žå…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />;您计算机的æ“作系统ä¸ä¿¡ä»»æœåŠ¡å™¨çš„安全è¯ä¹¦ã€‚出现此问题的原因å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您的连接。<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
-<translation id="6665267558048410100">该é€è´§é€‰é¡¹ä¸å¯ç”¨ã€‚请å¦é€‰ä¸€ä¸ªé€‰é¡¹ã€‚</translation>
<translation id="6671697161687535275">è¦ä»Ž Chromium 中移除表å•å¡«å†™å»ºè®®å—?</translation>
<translation id="6685834062052613830">请退出并完æˆè®¾ç½®</translation>
<translation id="6710213216561001401">上一个</translation>
@@ -605,13 +613,13 @@
<translation id="6711464428925977395">代ç†æœåŠ¡å™¨å‡ºçŽ°é—®é¢˜ï¼Œæˆ–者地å€æœ‰è¯¯ã€‚</translation>
<translation id="6727102863431372879">设置</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{无}=1{1 项内容}other{# 项内容}}</translation>
-<translation id="6743044928064272573">å–货选项</translation>
<translation id="674375294223700098">未知的æœåŠ¡å™¨è¯ä¹¦é”™è¯¯ã€‚</translation>
<translation id="6753269504797312559">政策值</translation>
<translation id="6757797048963528358">您的设备已进入休眠模å¼ã€‚</translation>
<translation id="6778737459546443941">您的父亲/æ¯äº²å°šæœªæ‰¹å‡†æ­¤ç½‘ç«™</translation>
<translation id="6810899417690483278">自定义 ID</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">未能加载区域数æ®</translation>
<translation id="6831043979455480757">翻译</translation>
<translation id="6839929833149231406">地域</translation>
<translation id="6874604403660855544">æ¢å¤æ·»åŠ (&amp;R)</translation>
@@ -619,6 +627,7 @@
<translation id="6895330447102777224">已确认您的信用å¡</translation>
<translation id="6897140037006041989">用户代ç†</translation>
<translation id="6915804003454593391">用户:</translation>
+<translation id="6948701128805548767">è¦æŸ¥çœ‹å–货方å¼å’Œè¦æ±‚,请选择相应地å€</translation>
<translation id="6957887021205513506">该æœåŠ¡å™¨çš„è¯ä¹¦ä¼¼ä¹Žæ˜¯ä¼ªé€ çš„。</translation>
<translation id="6965382102122355670">确定</translation>
<translation id="6965978654500191972">设备</translation>
@@ -626,7 +635,6 @@
<translation id="6973656660372572881">固定代ç†æœåŠ¡å™¨å’Œ .pac 脚本网å€å‡å·²æŒ‡å®šã€‚</translation>
<translation id="6989763994942163495">显示高级设置...</translation>
<translation id="7000990526846637657">未找到任何记录æ¡ç›®</translation>
-<translation id="7001663382399377034">添加收件人</translation>
<translation id="7009986207543992532">您å°è¯•è¿žæŽ¥åˆ° <ph name="DOMAIN" />,但æœåŠ¡å™¨æ供的è¯ä¹¦æœ‰æ•ˆæœŸè¿‡é•¿ï¼Œå› æ­¤éš¾ä»¥ä¿¡ä»»ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="7012363358306927923">中国银è”</translation>
<translation id="7012372675181957985">您的 Google å¸å·åœ¨ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> 上å¯èƒ½æœ‰å…¶ä»–å½¢å¼çš„æµè§ˆè®°å½•</translation>
@@ -637,12 +645,15 @@
<translation id="7088615885725309056">å¾€å‰</translation>
<translation id="7090678807593890770">请在 Google 中æœç´¢â€œ<ph name="LINK" />â€</translation>
<translation id="7119414471315195487">关闭其他标签页或程åº</translation>
+<translation id="7129409597930077180">无法å‘此地å€é€è´§ã€‚请å¦é€‰ä¸€ä¸ªåœ°å€ã€‚</translation>
+<translation id="7138472120740807366">递é€æ–¹å¼</translation>
<translation id="7139724024395191329">酋长国</translation>
<translation id="7155487117670177674">付款方å¼ä¸å®‰å…¨</translation>
<translation id="7179921470347911571">ç«‹å³é‡æ–°å¯åŠ¨</translation>
<translation id="7180611975245234373">刷新</translation>
<translation id="7182878459783632708">未设置任何政策</translation>
<translation id="7186367841673660872">已将此网页从<ph name="ORIGINAL_LANGUAGE" />翻译æˆ<ph name="LANGUAGE_LANGUAGE" /></translation>
+<translation id="7192203810768312527">释放了 <ph name="SIZE" />。当您下次访问时,æŸäº›ç½‘站的加载速度å¯èƒ½ä¼šæ›´æ…¢ã€‚</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ä¸ç¬¦åˆç›¸å…³å®‰å…¨æ ‡å‡†ã€‚</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />详细了解<ph name="END_LINK" />此问题。</translation>
@@ -671,7 +682,6 @@
<translation id="7424977062513257142">此网页上的嵌入å¼é¡µé¢æ˜¾ç¤ºï¼š</translation>
<translation id="7441627299479586546">策略主题有误</translation>
<translation id="7444046173054089907">此网站已被å±è”½</translation>
-<translation id="7444238235002594607">选择å–货地å€åŽæ‰èƒ½æŸ¥çœ‹å–货方å¼å’Œè¦æ±‚。</translation>
<translation id="7445762425076701745">无法完全验è¯æ‚¨æ‰€è¿žæŽ¥åˆ°çš„æœåŠ¡å™¨çš„身份。您在连接æœåŠ¡å™¨æ—¶ä½¿ç”¨çš„æœåŠ¡å™¨å称仅在您的网络中有效,而外部è¯ä¹¦æŽˆæƒä¸­å¿ƒæ— æ³•éªŒè¯è¯¥å称的所有æƒã€‚由于一些è¯ä¹¦æŽˆæƒä¸­å¿ƒä»ç„¶ä¼šä¸ºè¿™äº›å称é¢å‘è¯ä¹¦ï¼Œå› æ­¤æ— æ³•ç¡®ä¿æ‚¨è¿žæŽ¥åˆ°æƒ³è¦è®¿é—®çš„网站而ä¸æ˜¯æ”»å‡»ç½‘站。</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />详细了解<ph name="END_LINK" />此问题。</translation>
<translation id="7460163899615895653">此处将会显示您最近从其他设备打开的标签页</translation>
@@ -715,6 +725,7 @@
<translation id="7755287808199759310">您的父亲/æ¯äº²å¯ä¸ºæ‚¨å–消å±è”½æ­¤ç½‘ç«™</translation>
<translation id="7758069387465995638">防ç«å¢™æˆ–防病毒软件å¯èƒ½å·²é˜»æ­¢æ‚¨è¿žæŽ¥åˆ°ç½‘络。</translation>
<translation id="7761701407923456692">æœåŠ¡å™¨çš„è¯ä¹¦ä¸Žç½‘å€ä¸ç›¸ç¬¦ã€‚</translation>
+<translation id="7763386264682878361">付款清å•è§£æžå™¨</translation>
<translation id="7764225426217299476">添加地å€</translation>
<translation id="777702478322588152">县</translation>
<translation id="7791543448312431591">添加</translation>
@@ -728,6 +739,7 @@
<translation id="785549533363645510">但是,这并ä¸æ„味ç€æ‚¨èƒ½å®Œå…¨éšèº«ã€‚å³ä½¿æ‚¨è¿›å…¥éšèº«æ¨¡å¼ï¼Œæ‚¨çš„雇主ã€äº’è”网æœåŠ¡æ供商和您访问的网站ä»ç„¶èƒ½çœ‹åˆ°æ‚¨çš„æµè§ˆæ´»åŠ¨ã€‚</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">请检查您的银行å¡éªŒè¯ç  (CVC),然åŽé‡è¯•</translation>
+<translation id="79338296614623784">请输入有效的电è¯å·ç </translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">æœåŠ¡å™¨çš„è¯ä¹¦å°šæœªç”Ÿæ•ˆã€‚</translation>
<translation id="7942349550061667556">红色</translation>
@@ -747,6 +759,7 @@
<translation id="8088680233425245692">无法查看文章。</translation>
<translation id="8089520772729574115">å°äºŽ 1 MB</translation>
<translation id="8091372947890762290">正等待在æœåŠ¡å™¨ä¸Šæ¿€æ´»</translation>
+<translation id="8118489163946903409">付款方å¼</translation>
<translation id="8131740175452115882">确认</translation>
<translation id="8134994873729925007">找ä¸åˆ° <ph name="HOST_NAME" /> çš„æœåŠ¡å™¨ <ph name="BEGIN_ABBR" />DNS 地å€<ph name="END_ABBR" />。</translation>
<translation id="8149426793427495338">您的计算机已进入休眠模å¼ã€‚</translation>
@@ -772,6 +785,7 @@
<translation id="8349305172487531364">书签æ </translation>
<translation id="8363502534493474904">关闭飞行模å¼</translation>
<translation id="8364627913115013041">未设置。</translation>
+<translation id="8368476060205742148">Google Play æœåŠ¡</translation>
<translation id="8380941800586852976">å±é™©</translation>
<translation id="8382348898565613901">您最近访问过的书签会显示在此处</translation>
<translation id="8398259832188219207">崩溃报告的上传时间:<ph name="UPLOAD_TIME" /></translation>
@@ -780,32 +794,30 @@
<translation id="8428213095426709021">设置</translation>
<translation id="8433057134996913067">这将使您退出大多数网站。</translation>
<translation id="8437238597147034694">撤消移动(&amp;U)</translation>
-<translation id="8456681095658380701">å称无效</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 张信用å¡}other{# 张信用å¡}}</translation>
<translation id="8483780878231876732">è¦ä½¿ç”¨æ‚¨ Google å¸å·ä¸­çš„信用å¡ï¼Œè¯·ç™»å½• Chrome</translation>
<translation id="8488350697529856933">适用对象</translation>
-<translation id="8492969205326575646">该信用å¡ç±»åž‹ä¸å—支æŒ</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> çš„å“应时间过长。</translation>
<translation id="852346902619691059">æ­¤æœåŠ¡å™¨æ— æ³•è¯æ˜Žå…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />;您设备的æ“作系统ä¸ä¿¡ä»»æœåŠ¡å™¨çš„安全è¯ä¹¦ã€‚出现此问题的原因å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您的连接。<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
+<translation id="8532105204136943229">到期年份</translation>
<translation id="8543181531796978784">您å¯ä»¥<ph name="BEGIN_ERROR_LINK" />报告检测问题<ph name="END_ERROR_LINK" />;或者,如果您了解自己将é¢ä¸´çš„安全风险,则å¯ä»¥<ph name="BEGIN_LINK" />访问这个ä¸å®‰å…¨çš„网站<ph name="END_LINK" />。</translation>
<translation id="8553075262323480129">系统无法确定该网页的语言,因此无法进行翻译。</translation>
<translation id="8559762987265718583">您设备的日期和时间(<ph name="DATE_AND_TIME" />)ä¸æ­£ç¡®ï¼Œå› æ­¤æ— æ³•ä¸Ž <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立ç§å¯†è¿žæŽ¥ã€‚</translation>
-<translation id="8570229484593575558">系统|ä¸ä¼šä¿å­˜|以下信æ¯ï¼š#您的æµè§ˆè®°å½•#您的æœç´¢è®°å½•#Cookie æ•°æ®</translation>
<translation id="8571890674111243710">正在将网页翻译æˆ<ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">以下å„æ–¹|å¯èƒ½ä»ä¼šçœ‹åˆ°|您的活动:#您访问的网站#您的雇主#您的互è”网æœåŠ¡æ供商</translation>
<translation id="858637041960032120">添加电è¯å·ç 
</translation>
<translation id="859285277496340001">è¯ä¹¦æœªæŒ‡å®šç”¨äºŽæ£€æŸ¥æ˜¯å¦å·²åŠé”€è¯ä¹¦çš„机制。</translation>
<translation id="8620436878122366504">您的父æ¯å°šæœªæ‰¹å‡†æ­¤è¯·æ±‚</translation>
<translation id="8647750283161643317">全部é‡ç½®ä¸ºé»˜è®¤å€¼</translation>
<translation id="8703575177326907206">您与 <ph name="DOMAIN" /> 的连接未加密。</translation>
+<translation id="8718314106902482036">未能完æˆä»˜æ¬¾</translation>
<translation id="8725066075913043281">é‡è¯•</translation>
-<translation id="8728672262656704056">您已进入éšèº«æ¨¡å¼</translation>
+<translation id="8728672262656704056">您已进入无痕模å¼</translation>
<translation id="8730621377337864115">完æˆ</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="8759274551635299824">此信用å¡å·²å¤±æ•ˆ</translation>
<translation id="8790007591277257123">æ¢å¤åˆ é™¤(&amp;R)</translation>
-<translation id="8798099450830957504">默认</translation>
<translation id="8800988563907321413">此处将显示系统建议您æµè§ˆçš„附近网页</translation>
<translation id="8820817407110198400">书签</translation>
<translation id="883848425547221593">其他书签</translation>
@@ -815,6 +827,7 @@
<translation id="8866481888320382733">解æžç­–略设置时出错</translation>
<translation id="8866959479196209191">此网页显示:</translation>
<translation id="8870413625673593573">最近关闭的标签页</translation>
+<translation id="8874824191258364635">请输入有效的信用å¡å·</translation>
<translation id="8876793034577346603">无法解æžç½‘络é…置。</translation>
<translation id="8877192140621905067">在您确认åŽï¼Œæ‚¨çš„信用å¡è¯¦æƒ…将与此网站共享</translation>
<translation id="8889402386540077796">色调</translation>
@@ -824,7 +837,6 @@
<translation id="8931333241327730545">è¦å°†æ­¤å¡çš„ä¿¡æ¯ä¿å­˜åˆ°æ‚¨çš„ Google å¸å·å—?</translation>
<translation id="8932102934695377596">您的时钟慢了</translation>
<translation id="8954894007019320973">(续)</translation>
-<translation id="895548565263634352">阅读æ¥è‡ª<ph name="ARTICLE_PUBLISHER" />的报é“以åŠå¦å¤– <ph name="OTHER_ARTICLE_COUNT" /> 篇报é“</translation>
<translation id="8971063699422889582">æœåŠ¡å™¨çš„è¯ä¹¦å·²è¿‡æœŸã€‚</translation>
<translation id="8986494364107987395">将使用情况统计信æ¯å’Œå´©æºƒæŠ¥å‘Šè‡ªåŠ¨å‘é€ç»™ Google</translation>
<translation id="8987927404178983737">月</translation>
@@ -842,7 +854,6 @@
<translation id="9068849894565669697">选择颜色</translation>
<translation id="9076283476770535406">此网站å¯èƒ½åŒ…å«æˆäººå†…容</translation>
<translation id="9078964945751709336">å¿…é¡»æ供更多信æ¯</translation>
-<translation id="9094175695478007090">无法å¯åŠ¨ä»˜æ¬¾åº”用。</translation>
<translation id="9103872766612412690"><ph name="SITE" /> 通常会使用加密技术æ¥ä¿æŠ¤æ‚¨çš„ä¿¡æ¯ã€‚Chromium 此次å°è¯•è¿žæŽ¥åˆ° <ph name="SITE" /> 时,此网站å‘回了异常的错误凭æ®ã€‚è¿™å¯èƒ½æ˜¯å› ä¸ºæœ‰æ”»å‡»è€…在试图冒充 <ph name="SITE" />,或 Wi-Fi 登录å±å¹•ä¸­æ–­äº†æ­¤æ¬¡è¿žæŽ¥ã€‚请放心,您的信æ¯ä»ç„¶æ˜¯å®‰å…¨çš„,因为 Chromium 尚未进行任何数æ®äº¤æ¢ä¾¿åœæ­¢äº†è¿žæŽ¥ã€‚</translation>
<translation id="9137013805542155359">显示原始网页</translation>
<translation id="9137248913990643158">在使用此应用å‰ï¼Œè¯·å…ˆå¯åŠ¨å¹¶ç™»å½• Chrome。</translation>
diff --git a/chromium/components/strings/components_strings_zh-TW.xtb b/chromium/components/strings/components_strings_zh-TW.xtb
index ce8fd815ad9..cf06d29a33c 100644
--- a/chromium/components/strings/components_strings_zh-TW.xtb
+++ b/chromium/components/strings/components_strings_zh-TW.xtb
@@ -3,6 +3,7 @@
<translationbundle lang="zh-TW">
<translation id="1008557486741366299">ç¾åœ¨ä¸è¦</translation>
<translation id="1015730422737071372">æ供其他詳細資訊</translation>
+<translation id="1021110881106174305">接å—的信用å¡</translation>
<translation id="1032854598605920125">順時é‡æ—‹è½‰</translation>
<translation id="1038842779957582377">ä¸æ˜Žå稱</translation>
<translation id="1050038467049342496">關閉其他應用程å¼</translation>
@@ -35,6 +36,7 @@
<translation id="1227633850867390598">éš±è—政策值</translation>
<translation id="1228893227497259893">實體識別碼錯誤</translation>
<translation id="1232569758102978740">未命å</translation>
+<translation id="1263231323834454256">閱讀清單</translation>
<translation id="1264126396475825575">當機報告擷å–時間:<ph name="CRASH_TIME" /> (尚未上傳或略éŽ)</translation>
<translation id="1285320974508926690">一律ä¸ç¿»è­¯æ­¤ç¶²ç«™</translation>
<translation id="129553762522093515">最近關閉的分é </translation>
@@ -45,6 +47,7 @@
<translation id="1344588688991793829">Chromium 自動填入設定...</translation>
<translation id="1374468813861204354">建議</translation>
<translation id="1375198122581997741">關於版本</translation>
+<translation id="1377321085342047638">å¡è™Ÿ</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> 未傳é€ä»»ä½•è³‡æ–™ã€‚</translation>
<translation id="1407135791313364759">全部開啟</translation>
<translation id="1413809658975081374">éš±ç§æ¬Šè¨­å®šç™¼ç”ŸéŒ¯èª¤</translation>
@@ -58,7 +61,7 @@
<translation id="153384715582417236">暫無內容</translation>
<translation id="1549470594296187301">您必須啟用 JavaScript æ‰èƒ½ä½¿ç”¨é€™é …功能。</translation>
<translation id="1555130319947370107">è—色</translation>
-<translation id="1559528461873125649">找ä¸åˆ°æ‚¨æ‰€æŒ‡å®šçš„檔案或目錄</translation>
+<translation id="1559528461873125649">找ä¸åˆ°ä½ æ‰€æŒ‡å®šçš„檔案或目錄</translation>
<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>
@@ -73,44 +76,46 @@
<translation id="1644574205037202324">æ­·å²ç´€éŒ„</translation>
<translation id="1645368109819982629">ä¸æ”¯æ´çš„通訊å”定</translation>
<translation id="1656489000284462475">å–件</translation>
+<translation id="1663943134801823270">信用å¡å’Œåœ°å€è³‡è¨Šçš†ä¾†è‡ª Chrome。你å¯ä»¥åœ¨<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />é é¢ç®¡ç†é€™äº›è³‡è¨Šã€‚</translation>
<translation id="1676269943528358898"><ph name="SITE" /> 通常使用加密方å¼ä¿è­·æ‚¨çš„資訊。但 Google Chrome 這次嘗試連線到 <ph name="SITE" /> 時,該網站傳回了異常且錯誤的憑證。這å¯èƒ½æ˜¯å› ç‚ºæœ‰æ”»æ“Šè€…ä¼åœ–å½è£æˆ <ph name="SITE" />,或是å—到 Wi-Fi 登入畫é¢å½±éŸ¿è€Œé€ æˆé€£ç·šä¸­æ–·ã€‚ä¸éŽè«‹æ”¾å¿ƒï¼ŒGoogle Chrome å·²åŠæ™‚åœæ­¢é€£ç·šï¼Œä¸¦æœªå‚³è¼¸ä»»ä½•è³‡æ–™ï¼Œå› æ­¤æ‚¨çš„資訊ä»ç„¶å®‰å…¨ç„¡è™žã€‚</translation>
<translation id="168328519870909584">攻擊者目å‰å¯èƒ½æœƒè©¦åœ–é€éŽ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 在您的è£ç½®ä¸Šå®‰è£å±éšªçš„應用程å¼ï¼Œè—‰æ­¤ç«Šå–或刪除您的資訊 (例如相片ã€å¯†ç¢¼ã€éƒµä»¶æˆ–信用å¡è³‡æ–™)。</translation>
<translation id="168841957122794586">伺æœå™¨æ†‘è­‰å«æœ‰é˜²è­·åŠ›è–„弱的加密編譯金鑰。</translation>
<translation id="1710259589646384581">作業系統</translation>
<translation id="1721312023322545264">ä½ å¿…é ˆç²å¾—<ph name="NAME" />授權,æ‰èƒ½é€ è¨ªé€™å€‹ç¶²ç«™</translation>
+<translation id="1721424275792716183">* 這是必填欄ä½</translation>
<translation id="1728677426644403582">ç›®å‰é¡¯ç¤ºçš„是網é åŽŸå§‹ç¢¼</translation>
+<translation id="173080396488393970">ä¸æ”¯æ´é€™ç¨®ä¿¡ç”¨å¡é¡žåž‹</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">建議您與系統管ç†å“¡è¯çµ¡ã€‚</translation>
+<translation id="1740951997222943430">請輸入有效的到期月份</translation>
<translation id="1745358365027406341">ç¨å¾Œä¸‹è¼‰ç¶²é </translation>
<translation id="17513872634828108">開啟分é </translation>
<translation id="1753706481035618306">é ç¢¼</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />嘗試執行 Windows 網路診斷<ph name="END_LINK" />。</translation>
-<translation id="1783075131180517613">請更新您的åŒæ­¥é€šé—œå¯†èªžã€‚</translation>
+<translation id="1783075131180517613">è«‹æ›´æ–°ä½ çš„åŒæ­¥é€šé—œå¯†èªžã€‚</translation>
<translation id="1787142507584202372">這裡會顯示你最近開啟的分é </translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1797835274315207060">é¸å–å¿«éžåœ°å€å³å¯æŸ¥çœ‹å¿«éžæ–¹å¼å’Œéœ€æ±‚æ¢ä»¶ã€‚</translation>
+<translation id="1803264062614276815">æŒå¡äººå§“å</translation>
<translation id="1803678881841855883">Google 安全ç€è¦½åŠŸèƒ½æœ€è¿‘在 <ph name="SITE" /> 上<ph name="BEGIN_LINK" />åµæ¸¬åˆ°æƒ¡æ„軟體<ph name="END_LINK" />。å³ä½¿æ˜¯å¹³å¸¸å¯ä»¥å®‰å…¨ä½¿ç”¨çš„網站,有時也會é­åˆ°æƒ¡æ„軟體感染。這些惡æ„內容來自已知的惡æ„軟體散佈網站 <ph name="SUBRESOURCE_HOST" />。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1806541873155184440">新增日期:<ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="1821930232296380041">è¦æ±‚或è¦æ±‚åƒæ•¸ç„¡æ•ˆ</translation>
<translation id="1826516787628120939">檢查中</translation>
<translation id="1834321415901700177">這個網站å«æœ‰æœ‰å®³ç¨‹å¼</translation>
<translation id="1842969606798536927">支付</translation>
-<translation id="1864455488461349376">å¿«éžé¸é …</translation>
<translation id="1871208020102129563">Proxy 設定為使用固定的 Proxy 伺æœå™¨ï¼Œè€Œéž .pac 指令碼網å€ã€‚</translation>
<translation id="1871284979644508959">必填欄ä½</translation>
<translation id="187918866476621466">開啟起始網é </translation>
<translation id="1883255238294161206">收åˆæ¸…å–®</translation>
<translation id="1898423065542865115">篩é¸</translation>
<translation id="194030505837763158">å‰å¾€ <ph name="LINK" /></translation>
-<translation id="1946821392246652573">接å—的信用å¡</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> 書籤</translation>
<translation id="1973335181906896915">åºåˆ—化錯誤</translation>
<translation id="1974060860693918893">進階</translation>
<translation id="1978555033938440688">韌體版本</translation>
+<translation id="1995859865337580572">請確èªä½ çš„信用å¡å®‰å…¨ç¢¼</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{以åŠå¦å¤– 1 個應用程å¼}other{以åŠå¦å¤– # 個應用程å¼}}</translation>
-<translation id="2020194265157481222">è«‹æä¾›æŒå¡äººå§“å</translation>
<translation id="2025186561304664664">Proxy 已設為自動設定。</translation>
-<translation id="2030481566774242610">您è¦æ‰¾çš„是 <ph name="LINK" /> 嗎?</translation>
+<translation id="2030481566774242610">ä½ è¦æ‰¾çš„是 <ph name="LINK" /> 嗎?</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />檢查 Proxy 和防ç«ç‰†<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">郵éžå€è™Ÿ</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 個建議項目}other{# 個建議項目}}</translation>
@@ -128,11 +133,11 @@
<translation id="2148716181193084225">今天</translation>
<translation id="2154054054215849342">你的網域無法使用åŒæ­¥åŠŸèƒ½</translation>
<translation id="2154484045852737596">編輯å¡ç‰‡è³‡è¨Š</translation>
-<translation id="2156993118928861787">地å€ç„¡æ•ˆ</translation>
<translation id="2166049586286450108">完整管ç†å“¡å­˜å–權</translation>
<translation id="2166378884831602661">這個網站無法æ供安全連線</translation>
<translation id="2181821976797666341">政策</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 個地å€}other{# 個地å€}}</translation>
+<translation id="2202020181578195191">請輸入有效的到期年份</translation>
<translation id="2212735316055980242">找ä¸åˆ°æ”¿ç­–</translation>
<translation id="2213606439339815911">正在擷å–é …ç›®...</translation>
<translation id="2230458221926704099">請使用<ph name="BEGIN_LINK" />診斷應用程å¼<ph name="END_LINK" />修正連線å•é¡Œ</translation>
@@ -143,7 +148,6 @@
<translation id="2292556288342944218">您的網際網路存å–權é­åˆ°å°éŽ–</translation>
<translation id="230155334948463882">新信用å¡ï¼Ÿ</translation>
<translation id="2305919008529760154">這個伺æœå™¨ç„¡æ³•è­‰æ˜Žæ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨çš„安全性憑證核發來æºæœ‰è©æ¬ºå«Œç–‘。這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–是有攻擊者攔截你的連線。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="230697611605700222">信用å¡å’Œåœ°å€é¸é …來自你的 Google 帳戶 (<ph name="ACCOUNT_EMAIL" />) å’Œ Chrome。你å¯ä»¥åœ¨<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />中管ç†ç›¸é—œè³‡è¨Šã€‚</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> è¦æ±‚æ供使用者å稱和密碼。</translation>
<translation id="2318774815570432836">ç›®å‰ç„¡æ³•é€ è¨ª <ph name="SITE" />,因為這個網站使用 HSTS。網路錯誤和攻擊行為通常是暫時性的,因此這個網é å¯èƒ½ç¨å¾Œå°±æœƒæ¢å¾©æ­£å¸¸ç‹€æ…‹ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2354001756790975382">其他書籤</translation>
@@ -156,13 +160,13 @@
<translation id="2384307209577226199">ä¼æ¥­é è¨­</translation>
<translation id="2386255080630008482">伺æœå™¨æ†‘證已é­æ’¤éŠ·ã€‚</translation>
<translation id="2392959068659972793">顯示尚未設定任何值的政策</translation>
+<translation id="239429038616798445">ä¸æ”¯æ´æ‰€é¸çš„é‹é€æ–¹å¼ï¼Œè«‹æ”¹é¸å…¶ä»–æ–¹å¼ã€‚</translation>
<translation id="2396249848217231973">復原刪除(&amp;U)</translation>
<translation id="2460160116472764928">Google 安全ç€è¦½åŠŸèƒ½æœ€è¿‘在 <ph name="SITE" /> 上<ph name="BEGIN_LINK" />åµæ¸¬åˆ°æƒ¡æ„軟體<ph name="END_LINK" />。å³ä½¿æ˜¯å¹³å¸¸å¯ä»¥å®‰å…¨ä½¿ç”¨çš„網站,有時也會é­åˆ°æƒ¡æ„軟體感染。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2463739503403862330">å¡«å…¥</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />執行網路診斷<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">無效的æœå°‹ç¶²å€ã€‚</translation>
<translation id="2491120439723279231">伺æœå™¨æ†‘è­‰å«æœ‰éŒ¯èª¤ã€‚</translation>
-<translation id="24943777258388405">電話號碼無效</translation>
<translation id="2495083838625180221">JSON 剖æžå™¨</translation>
<translation id="2495093607237746763">勾é¸å¾Œï¼ŒChromium 會將您的信用å¡è³‡æ–™å„²å­˜åœ¨é€™å€‹è£ç½®ä¸Šï¼Œä»¥åŠ å¿«è¡¨å–®å¡«å¯«é€Ÿåº¦ã€‚</translation>
<translation id="2498091847651709837">掃æ新信用å¡</translation>
@@ -172,15 +176,16 @@
<translation id="255002559098805027"><ph name="HOST_NAME" /> 傳é€çš„回應無效。</translation>
<translation id="2552545117464357659">較新紀錄</translation>
<translation id="2556876185419854533">復原編輯(&amp;U)</translation>
+<translation id="2587730715158995865">出自「<ph name="ARTICLE_PUBLISHER" />ã€ã€‚閱讀這篇報導和å¦å¤– <ph name="OTHER_ARTICLE_COUNT" /> 篇報導。</translation>
<translation id="2587841377698384444">Directory API ID:</translation>
<translation id="2597378329261239068">此文件å—到密碼ä¿è­·ï¼Œè«‹è¼¸å…¥å¯†ç¢¼ã€‚</translation>
<translation id="2609632851001447353">變化版本</translation>
-<translation id="2625385379895617796">您的時é˜æ™‚é–“éŽå¿«</translation>
+<translation id="2625385379895617796">你的時é˜æ™‚é–“éŽå¿«</translation>
<translation id="2639739919103226564">狀態:</translation>
<translation id="2650446666397867134">å­˜å–檔案é­æ‹’</translation>
<translation id="2653659639078652383">æ交</translation>
<translation id="2666117266261740852">關閉其他分é æˆ–應用程å¼</translation>
-<translation id="2674170444375937751">確定è¦å¾žæ‚¨çš„紀錄中刪除這些網é å—Žï¼Ÿ</translation>
+<translation id="2674170444375937751">確定è¦å¾žä½ çš„紀錄中刪除這些網é å—Žï¼Ÿ</translation>
<translation id="2677748264148917807">離開</translation>
<translation id="269990154133806163">這個伺æœå™¨çš„憑證並未根據憑證é€æ˜ŽåŒ–政策å°å¤–公開。部分憑證必須符åˆé€™é …è¦å®šï¼Œä»¥ç¢ºä¿æ†‘證值得信任,ä¸æœƒè®“使用者é­åˆ°æ”»æ“Šã€‚<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2702801445560668637">閱讀清單</translation>
@@ -197,27 +202,29 @@
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />執行連線診斷<ph name="END_LINK" /></translation>
<translation id="2740531572673183784">確定</translation>
<translation id="2742870351467570537">移除é¸å–çš„é …ç›®</translation>
+<translation id="277133753123645258">é‹é€æ–¹å¼</translation>
<translation id="277499241957683684">沒有è£ç½®ç´€éŒ„</translation>
<translation id="2784949926578158345">連線已é‡è¨­ã€‚</translation>
<translation id="2794233252405721443">網站é­åˆ°å°éŽ–</translation>
-<translation id="2812680587231492111">ä¸æ”¯æ´æ‰€é¸çš„å–件é¸é …,請改é¸å…¶ä»–é¸é …。</translation>
<translation id="2824775600643448204">網å€èˆ‡æœå°‹åˆ—</translation>
<translation id="2826760142808435982">連線採用 <ph name="CIPHER" /> 加密,並設有 <ph name="KX" /> 金鑰交æ›æ©Ÿåˆ¶ã€‚</translation>
<translation id="2835170189407361413">清除表單</translation>
-<translation id="2849041323157393173">ä¸æ”¯æ´æ‰€é¸çš„å¿«éžé¸é …,請改é¸å…¶ä»–é¸é …。</translation>
<translation id="2889159643044928134">ä¸è¦é‡æ–°è¼‰å…¥</translation>
<translation id="2900469785430194048">Google Chrome 嘗試顯示這個網é æ™‚用盡了記憶體。</translation>
<translation id="2909946352844186028">系統åµæ¸¬åˆ°ç¶²è·¯è®Šæ›´ã€‚</translation>
<translation id="2916038427272391327">關閉其他程å¼</translation>
<translation id="2922350208395188000">無法檢查伺æœå™¨æ†‘證。</translation>
-<translation id="2948083400971632585">您å¯ä»¥åœ¨è¨­å®šé é¢åœç”¨ä»»ä½•ç‚ºé€£ç·šè¨­ç½®çš„ Proxy。</translation>
+<translation id="2928905813689894207">帳單地å€</translation>
+<translation id="2948083400971632585">ä½ å¯ä»¥åœ¨è¨­å®šé é¢åœç”¨ä»»ä½•ç‚ºé€£ç·šè¨­ç½®çš„ Proxy。</translation>
<translation id="2955913368246107853">關閉æœå°‹åˆ—</translation>
<translation id="2958431318199492670">網路設定未éµå¾ª ONC 標準,系統å¯èƒ½ç„¡æ³•åŒ¯å…¥éƒ¨åˆ†è¨­å®šã€‚</translation>
-<translation id="29611076221683977">攻擊者目å‰å¯èƒ½æœƒè©¦åœ–é€éŽ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 在您的 Mac 上安è£å±éšªç¨‹å¼ï¼Œè—‰æ­¤ç«Šå–或刪除您的資訊 (例如相片ã€å¯†ç¢¼ã€éƒµä»¶æˆ–信用å¡è³‡æ–™)。</translation>
+<translation id="29611076221683977">攻擊者目å‰å¯èƒ½æœƒè©¦åœ–é€éŽ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 在你的 Mac 上安è£å±éšªç¨‹å¼ï¼Œè—‰æ­¤ç«Šå–或刪除你的資訊 (例如相片ã€å¯†ç¢¼ã€éƒµä»¶æˆ–信用å¡è³‡æ–™)。</translation>
<translation id="2966678944701946121">到期日:<ph name="EXPIRATION_DATE_ABBR" />,新增日期:<ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
<translation id="2969319727213777354">您必須正確設定時é˜ï¼Œæ‰èƒ½å»ºç«‹å®‰å…¨é€£ç·šã€‚這是因為網站驗證身分時所使用的憑證僅於特定一段時間內有效。由於您è£ç½®çš„時é˜ä¸æ­£ç¢ºï¼Œå› æ­¤ Google Chrome 無法驗證這些憑證。</translation>
<translation id="2972581237482394796">é‡åš(&amp;R)</translation>
<translation id="2985306909656435243">啟用後,Chromium 會將您的信用å¡è³‡æ–™å„²å­˜åœ¨é€™å€‹è£ç½®ä¸Šï¼Œä»¥åŠ å¿«è¡¨å–®å¡«å¯«é€Ÿåº¦ã€‚</translation>
+<translation id="2985398929374701810">請輸入有效的地å€</translation>
+<translation id="2986368408720340940">ä¸æ”¯æ´æ‰€é¸çš„å–件方å¼ï¼Œè«‹æ”¹é¸å…¶ä»–æ–¹å¼ã€‚</translation>
<translation id="2991174974383378012">與網站分享</translation>
<translation id="3005723025932146533">顯示儲存的複本</translation>
<translation id="3008447029300691911">請輸入 <ph name="CREDIT_CARD" /> 的信用å¡å®‰å…¨ç¢¼ã€‚完æˆé©—證後,這個網站就會å–得您的信用å¡è©³ç´°è³‡è¨Šã€‚</translation>
@@ -228,13 +235,14 @@
<translation id="3040955737384246924">{COUNT,plural, =0{在已åŒæ­¥çš„è£ç½®ä¸Šè‡³å°‘有 1 個項目}=1{1 個項目 (在已åŒæ­¥çš„è£ç½®ä¸Šé‚„有更多項目)}other{# 個項目 (在已åŒæ­¥çš„è£ç½®ä¸Šé‚„有更多項目)}}</translation>
<translation id="3041612393474885105">憑證資訊</translation>
<translation id="3063697135517575841">Chrome ç›®å‰ç„¡æ³•é©—證您的信用å¡ï¼Œè«‹ç¨å¾Œå†è©¦ã€‚</translation>
-<translation id="3093245981617870298">您處於離線狀態。</translation>
+<translation id="3064966200440839136">å³å°‡é›¢é–‹ç„¡ç—•æ¨¡å¼ï¼Œæ”¹ç‚ºä½¿ç”¨å¤–部應用程å¼ä»˜æ¬¾ï¼Œè¦ç¹¼çºŒå—Žï¼Ÿ</translation>
+<translation id="3093245981617870298">你處於離線狀態。</translation>
<translation id="3105172416063519923">資產 ID:</translation>
<translation id="3109728660330352905">您未ç²å¾—授權,無法ç€è¦½é€™å€‹ç¶²é ã€‚</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />嘗試執行連線診斷<ph name="END_LINK" />。</translation>
<translation id="3145945101586104090">無法將回應解碼</translation>
-<translation id="3149891296864842641">é‹é€æ–¹å¼</translation>
<translation id="3150653042067488994">伺æœå™¨æš«æ™‚發生錯誤</translation>
+<translation id="3154506275960390542">這個網é ä¸­çš„表單å¯èƒ½ä¸æœƒç¶“由安全途徑æ交。其他人å¯èƒ½æœƒåœ¨å‚³è¼¸æœŸé–“檢視你的資料,攻擊者也å¯èƒ½æœƒä¿®æ”¹é€™äº›è³‡æ–™ï¼Œå°Žè‡´ä¼ºæœå™¨æŽ¥æ”¶ä¸åŒå…§å®¹ã€‚</translation>
<translation id="3157931365184549694">還原</translation>
<translation id="3167968892399408617">當您關閉所有無痕å¼åˆ†é å¾Œï¼Œæ‚¨åœ¨å…¶ä¸­ç€è¦½çš„網é éƒ½ä¸æœƒä¿ç•™åœ¨ç€è¦½å™¨ç´€éŒ„ã€Cookie 儲存庫或æœå°‹ç´€éŒ„中。ä¸éŽï¼Œæ‚¨ä¸‹è¼‰çš„檔案或建立的書籤全部都會ä¿ç•™ä¸‹ä¾†ã€‚</translation>
<translation id="3169472444629675720">Discover</translation>
@@ -263,12 +271,14 @@
<translation id="3345135638360864351">無法將您的網站存å–è¦æ±‚傳é€çµ¦<ph name="NAME" />,請å†è©¦ä¸€æ¬¡ã€‚</translation>
<translation id="3355823806454867987">變更 Proxy 設定...</translation>
<translation id="3369192424181595722">時é˜éŒ¯èª¤</translation>
+<translation id="337311366426640088">還有 <ph name="ITEM_COUNT" /> 個項目...</translation>
<translation id="337363190475750230">å·²å–消佈建</translation>
<translation id="3377188786107721145">政策解æžéŒ¯èª¤</translation>
<translation id="3380365263193509176">未知的錯誤</translation>
<translation id="3380864720620200369">用戶端 ID:</translation>
<translation id="3391030046425686457">å¿«éžåœ°å€</translation>
-<translation id="340013220407300675">攻擊者å¯èƒ½æœƒå˜—試從 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ç«Šå–您的資訊 (例如密碼ã€éƒµä»¶æˆ–信用å¡è³‡è¨Š)。</translation>
+<translation id="3395827396354264108">å–件方å¼</translation>
+<translation id="340013220407300675">攻擊者å¯èƒ½æœƒå˜—試從 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ç«Šå–你的資訊 (例如密碼ã€éƒµä»¶æˆ–信用å¡è³‡è¨Š)。</translation>
<translation id="3422248202833853650">嘗試關閉其他程å¼ä»¥é‡‹å‡ºè¨˜æ†¶é«”。</translation>
<translation id="3422472998109090673">ç›®å‰ç„¡æ³•é€£ä¸Š <ph name="HOST_NAME" />。</translation>
<translation id="3427342743765426898">é‡åšç·¨è¼¯(&amp;R)</translation>
@@ -278,32 +288,34 @@
<translation id="3450660100078934250">Mastercard</translation>
<translation id="3452404311384756672">æ“·å–間隔:</translation>
<translation id="3462200631372590220">éš±è—詳細資料</translation>
+<translation id="3467763166455606212">æŒå¡äººå§“å為必填項目</translation>
+<translation id="3478058380795961209">到期月份</translation>
<translation id="3479539252931486093">這是未é æœŸçš„情æ³å—Žï¼Ÿ<ph name="BEGIN_LINK" />通知我們<ph name="END_LINK" /></translation>
<translation id="3479552764303398839">ç¾åœ¨ä¸è¦</translation>
<translation id="348000606199325318">當機 ID:<ph name="CRASH_LOCAL_ID" /> (伺æœå™¨ ID:<ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">我們暫時無法與您的家長è¯çµ¡ï¼Œè«‹å†è©¦ä¸€æ¬¡ã€‚</translation>
<translation id="3528171143076753409">伺æœå™¨æ†‘證授權ä¸å¯é ã€‚</translation>
-<translation id="3538531656504267329">到期年份無效</translation>
<translation id="3539171420378717834">在這個è£ç½®ä¸Šä¿ç•™é€™å¼µä¿¡ç”¨å¡çš„複本</translation>
<translation id="3542684924769048008">é¸æ“‡å¯†ç¢¼ï¼š</translation>
-<translation id="3549644494707163724">使用您的通關密語å°æ‰€æœ‰å·²åŒæ­¥è™•ç†çš„資料進行加密</translation>
+<translation id="3549644494707163724">使用你的通關密語å°æ‰€æœ‰å·²åŒæ­¥è™•ç†çš„資料進行加密</translation>
<translation id="3549761410225185768">還有 <ph name="NUM_TABS_MORE" /> 個分é ...</translation>
<translation id="3555561725129903880">這個伺æœå™¨ç„¡æ³•è­‰æ˜Žæ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨çš„安全性憑證來自 <ph name="DOMAIN2" />。這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–是有攻擊者攔截你的連線。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3556433843310711081">你的管ç†å“¡å¯ä»¥ç‚ºä½ è§£é™¤å°éŽ–這個網站</translation>
-<translation id="3566021033012934673">您的連線ä¸æ˜¯ç§äººé€£ç·š</translation>
+<translation id="3566021033012934673">你的連線ä¸æ˜¯ç§äººé€£ç·š</translation>
<translation id="3582930987043644930">新增å稱</translation>
<translation id="3583757800736429874">é‡åšç§»å‹•(&amp;R)</translation>
<translation id="3586931643579894722">éš±è—詳細資訊</translation>
<translation id="3587482841069643663">全部</translation>
<translation id="3600246354004376029"><ph name="TITLE" />,<ph name="DOMAIN" />,<ph name="TIME" /></translation>
+<translation id="3615877443314183785">請輸入有效的到期日</translation>
<translation id="36224234498066874">清除ç€è¦½è³‡æ–™...</translation>
<translation id="362276910939193118">顯示完整記錄</translation>
<translation id="3623476034248543066">顯示政策值</translation>
<translation id="3630155396527302611">如果程å¼å·²åˆ—在å…許存å–網路的清單中,建議您
從清單中將其移除,然後å†é‡æ–°åŠ å…¥ã€‚</translation>
-<translation id="3648607100222897006">這些實驗性功能隨時都有å¯èƒ½è®Šå‹•ã€ä¸­æ–·æˆ–消失。我們完全無法ä¿è­‰å•Ÿç”¨é€™äº›å¯¦é©—性功能會導致何種後果,您的ç€è¦½å™¨èªªä¸å®šæœƒçªç„¶è‡ªå·±ç‡’掉。當然這åªæ˜¯çŽ©ç¬‘話,ä¸éŽæ‚¨çš„ç€è¦½å™¨å¯èƒ½çœŸçš„會刪除您的所有資料,或是æ„外洩æ¼æ‚¨çš„安全性和隱ç§æ¬Šè¨­å®šã€‚åªè¦æ‚¨å•Ÿç”¨äº†ä»»ä½•å¯¦é©—性功能,這個ç€è¦½å™¨çš„所有使用者都會啟用該功能。使用時請務必å°å¿ƒè¬¹æ…Žã€‚</translation>
+<translation id="3648607100222897006">這些實驗性功能隨時都有å¯èƒ½è®Šå‹•ã€ä¸­æ–·æˆ–消失。我們完全無法ä¿è­‰å•Ÿç”¨é€™äº›å¯¦é©—性功能會導致何種後果,你的ç€è¦½å™¨èªªä¸å®šæœƒçªç„¶è‡ªå·±ç‡’掉。當然這åªæ˜¯çŽ©ç¬‘話,ä¸éŽä½ çš„ç€è¦½å™¨å¯èƒ½çœŸçš„會刪除你的所有資料,或是æ„外洩æ¼ä½ çš„安全性和隱ç§æ¬Šè¨­å®šã€‚åªè¦ä½ å•Ÿç”¨äº†ä»»ä½•å¯¦é©—性功能,這個ç€è¦½å™¨çš„所有使用者都會啟用該功能。使用時請務必å°å¿ƒè¬¹æ…Žã€‚</translation>
<translation id="3650584904733503804">é©—è­‰æˆåŠŸ</translation>
-<translation id="3655670868607891010">如果您經常看到這個é é¢ï¼Œè«‹åƒè€ƒé€™äº›èªªæ˜Žï¼š<ph name="HELP_LINK" />。</translation>
+<translation id="3655670868607891010">如果你經常看到這個é é¢ï¼Œè«‹åƒè€ƒé€™äº›èªªæ˜Žï¼š<ph name="HELP_LINK" />。</translation>
<translation id="3658742229777143148">修訂版本</translation>
<translation id="3678029195006412963">無法簽署è¦æ±‚</translation>
<translation id="3679803492151881375">當機報告擷å–時間:<ph name="CRASH_TIME" />,報告上傳時間:<ph name="UPLOAD_TIME" /></translation>
@@ -312,16 +324,16 @@
<translation id="3693415264595406141">密碼:</translation>
<translation id="3696411085566228381">ç„¡</translation>
<translation id="3704609568417268905"><ph name="TIME" />,<ph name="BOOKMARKED" />,<ph name="TITLE" />,<ph name="DOMAIN" /></translation>
-<translation id="3706658020782046159">é¸å–é‹é€åœ°å€å³å¯æŸ¥çœ‹é‹é€æ–¹å¼å’Œéœ€æ±‚æ¢ä»¶ã€‚</translation>
<translation id="370665806235115550">載入中…</translation>
<translation id="3712624925041724820">授權已用盡</translation>
<translation id="3714780639079136834">開啟行動數據或 Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />檢查 Proxyã€é˜²ç«ç‰†å’Œ DNS 設定<ph name="END_LINK" /></translation>
-<translation id="3736520371357197498">如果您瞭解安全性風險,也å¯ä»¥é¸æ“‡åœ¨å±éšªç¨‹å¼å°šæœªé­åˆ°ç§»é™¤çš„狀態下<ph name="BEGIN_LINK" />造訪這個ä¸å®‰å…¨çš„網站<ph name="END_LINK" />。</translation>
+<translation id="3736520371357197498">如果你瞭解安全性風險,也å¯ä»¥é¸æ“‡åœ¨å±éšªç¨‹å¼å°šæœªé­åˆ°ç§»é™¤çš„狀態下<ph name="BEGIN_LINK" />造訪這個ä¸å®‰å…¨çš„網站<ph name="END_LINK" />。</translation>
<translation id="3739623965217189342">您複製的連çµ</translation>
<translation id="375403751935624634">伺æœå™¨éŒ¯èª¤ï¼Œç¿»è­¯ä½œæ¥­å¤±æ•—。</translation>
<translation id="3759461132968374835">最近沒有收到當機資訊。當機回報功能åœç”¨æ™‚發生的當機ä¸æœƒåˆ—在這裡。</translation>
-<translation id="382518646247711829">如果您使用 Proxy 伺æœå™¨...</translation>
+<translation id="3787705759683870569">到期日:<ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
+<translation id="382518646247711829">如果你使用 Proxy 伺æœå™¨...</translation>
<translation id="3828924085048779000">通關密語欄ä½ä¸å¾—留空。</translation>
<translation id="3845539888601087042">ç›®å‰é¡¯ç¤ºçš„æ­·å²ç´€éŒ„來æºåŒ…括您已登入帳戶的所有è£ç½®ã€‚<ph name="BEGIN_LINK" />瞭解詳情<ph name="END_LINK" /></translation>
<translation id="385051799172605136">返回</translation>
@@ -356,7 +368,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">您希望 Chromium 儲存這張信用å¡å—Žï¼Ÿ</translation>
<translation id="4171400957073367226">驗證簽å無效</translation>
-<translation id="4176463684765177261">å·²åœç”¨</translation>
<translation id="4196861286325780578">é‡åšç§»å‹•(&amp;R)</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />檢查防ç«ç‰†å’Œé˜²æ¯’軟體設定<ph name="END_LINK" /></translation>
<translation id="4206349416402437184">{COUNT,plural, =0{ç„¡}=1{1 å€‹æ‡‰ç”¨ç¨‹å¼ ($1)}=2{2 å€‹æ‡‰ç”¨ç¨‹å¼ ($1ã€$2)}other{# å€‹æ‡‰ç”¨ç¨‹å¼ ($1ã€$2ã€$3)}}</translation>
@@ -383,11 +394,11 @@
<translation id="4406896451731180161">æœå°‹çµæžœ</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ä¸æŽ¥å—你的登入憑證,或是你å¯èƒ½æœªæ供登入憑證。</translation>
<translation id="443673843213245140">雖然已åœç”¨ Proxy,ä¸éŽå·²æŒ‡å®šæ˜Žç¢º Proxy 設定。</translation>
-<translation id="4446242550670694251">ç¾åœ¨ä½ å¯ä»¥é€²è¡Œç§å¯†ç€è¦½ï¼Œå…±ç”¨é€™éƒ¨è£ç½®çš„其他使用者ä¸æœƒçœ‹åˆ°ä½ çš„活動。</translation>
<translation id="4492190037599258964">「<ph name="SEARCH_STRING" />ã€çš„æœå°‹çµæžœ</translation>
<translation id="4506176782989081258">驗證錯誤:<ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">與系統管ç†å“¡è¯çµ¡</translation>
<translation id="450710068430902550">與管ç†å“¡åˆ†äº«</translation>
+<translation id="4515275063822566619">信用å¡å’Œåœ°å€è³‡è¨Šçš†ä¾†è‡ª Chrome 和你的 Google 帳戶 (<ph name="ACCOUNT_EMAIL" />)。你å¯ä»¥åœ¨<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />é é¢ç®¡ç†é€™äº›è³‡è¨Šã€‚</translation>
<translation id="4522570452068850558">詳細資訊</translation>
<translation id="4558551763791394412">試試看åœç”¨æ“´å……功能。</translation>
<translation id="457875822857220463">å¿«éž</translation>
@@ -417,6 +428,7 @@
<translation id="4816492930507672669">ä¾é é¢å¤§å°è‡ªå‹•èª¿æ•´</translation>
<translation id="483020001682031208">沒有å¯é¡¯ç¤ºçš„實體化網路é é¢</translation>
<translation id="4850886885716139402">檢視</translation>
+<translation id="4854362297993841467">ä¸æ”¯æ´æ‰€é¸çš„å¿«éžæ–¹å¼ï¼Œè«‹æ”¹é¸å…¶ä»–æ–¹å¼ã€‚</translation>
<translation id="4858792381671956233">你已詢å•å®¶é•·æ˜¯å¦åŒæ„你造訪這個網站</translation>
<translation id="4880827082731008257">æœå°‹ç´€éŒ„</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />ã€<ph name="TYPE_2" />,<ph name="TYPE_3" /></translation>
@@ -424,7 +436,6 @@
<translation id="4923417429809017348">系統已將此網é å¾žä¸æ˜Žèªžè¨€ç¿»è­¯æˆ<ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">付款</translation>
<translation id="4926049483395192435">必須指定。</translation>
-<translation id="4941291666397027948">* 代表必填欄ä½</translation>
<translation id="495170559598752135">動作</translation>
<translation id="4958444002117714549">展開清單</translation>
<translation id="4962322354953122629">這個伺æœå™¨ç„¡æ³•è­‰æ˜Žæ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />ï¼›Chrome ä¸ä¿¡ä»»ä¼ºæœå™¨çš„安全性憑證。這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–是有攻擊者攔截你的連線。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -432,19 +443,20 @@
<translation id="5002932099480077015">啟用後,Chrome 會將您的信用å¡è¤‡æœ¬å„²å­˜åœ¨é€™å€‹è£ç½®ä¸Šï¼Œä»¥åŠ å¿«è¡¨å–®å¡«å¯«é€Ÿåº¦ã€‚</translation>
<translation id="5018422839182700155">無法開啟這個網é </translation>
<translation id="5019198164206649151">備份儲存狀態ä¸ä½³</translation>
-<translation id="5023310440958281426">請查看您的管ç†å“¡æ”¿ç­–</translation>
+<translation id="5023310440958281426">請查看你的管ç†å“¡æ”¿ç­–</translation>
<translation id="5029568752722684782">清除複本</translation>
<translation id="5031870354684148875">關於「Google 翻譯ã€</translation>
<translation id="5040262127954254034">éš±ç§æ¬Š</translation>
<translation id="5045550434625856497">密碼ä¸æ­£ç¢º</translation>
<translation id="5056549851600133418">為您推薦的文章</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />檢查 Proxy ä½å€<ph name="END_LINK" /></translation>
+<translation id="5076731569460970710">{COUNT,plural, =0{沒有任何 Cookie}=1{1 個網站會使用 Cookie。}other{# 個網站會使用 Cookie。}}</translation>
<translation id="5087286274860437796">伺æœå™¨æ†‘證目å‰ç„¡æ•ˆã€‚</translation>
<translation id="5087580092889165836">新增信用å¡</translation>
<translation id="5089810972385038852">å·ž</translation>
<translation id="5095208057601539847">çœ</translation>
<translation id="5115563688576182185">(64 ä½å…ƒ)</translation>
-<translation id="5141240743006678641">使用您的 Google 憑證å°å·²åŒæ­¥è™•ç†çš„密碼進行加密</translation>
+<translation id="5141240743006678641">使用你的 Google 憑證å°å·²åŒæ­¥è™•ç†çš„密碼進行加密</translation>
<translation id="514421653919133810">以無痕模å¼é–‹å•Ÿç¶²é  (Ctrl + Shift + N éµ)</translation>
<translation id="5145883236150621069">政策回應中存在錯誤代碼</translation>
<translation id="5171045022955879922">æœå°‹æˆ–輸入網å€</translation>
@@ -461,10 +473,8 @@
<translation id="5300589172476337783">顯示</translation>
<translation id="5308689395849655368">當機報告功能已åœç”¨ã€‚</translation>
<translation id="5317780077021120954">儲存</translation>
-<translation id="5326702247179446998">è«‹æ供收件者</translation>
<translation id="5327248766486351172">å稱</translation>
<translation id="5337705430875057403">攻擊者å¯èƒ½æœƒè©¦åœ–é€éŽ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 誘使您åšä¸€äº›å±éšªçš„事,例如安è£è»Ÿé«”或æ供個人資訊 (包括密碼ã€é›»è©±è™Ÿç¢¼æˆ–信用å¡è³‡æ–™)。</translation>
-<translation id="53553865750799677">ç›®å‰é¸å–的是ä¸æ”¯æ´çš„å–件地å€ï¼Œè«‹æ”¹ç”¨å…¶ä»–地å€ã€‚</translation>
<translation id="5359637492792381994">這個伺æœå™¨ç„¡æ³•è­‰æ˜Žæ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨çš„安全性憑證目å‰ç„¡æ•ˆã€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–是有攻擊者攔截你的連線。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">無法儲存政策設定</translation>
<translation id="5386426401304769735">這個網站的憑證éˆçµåŒ…å«ä½¿ç”¨ SHA-1 進行簽署的憑證。</translation>
@@ -490,8 +500,8 @@
<translation id="5544037170328430102"><ph name="SITE" /> 的嵌入å¼ç¶²é é¡¯ç¤ºï¼š</translation>
<translation id="5556459405103347317">é‡æ–°è¼‰å…¥</translation>
<translation id="5565735124758917034">管ç†ä¸­</translation>
+<translation id="5571083550517324815">無法在這個地å€å–件,請改用其他地å€ã€‚</translation>
<translation id="5572851009514199876">è«‹å•Ÿå‹• Chrome 並登入帳戶,Chrome 將確èªä½ æ˜¯å¦å¯å­˜å–這個網站。</translation>
-<translation id="5575380383496039204">ç›®å‰é¸å–的是ä¸æ”¯æ´çš„å¿«éžåœ°å€ï¼Œè«‹æ”¹ç”¨å…¶ä»–地å€ã€‚</translation>
<translation id="5580958916614886209">請檢查信用å¡åˆ°æœŸæœˆä»½ï¼Œç„¶å¾Œå†è©¦ä¸€æ¬¡</translation>
<translation id="560412284261940334">系統ä¸æ”¯æ´ç®¡ç†</translation>
<translation id="5610142619324316209">檢查連線狀態</translation>
@@ -507,7 +517,8 @@
<translation id="5710435578057952990">此網é çš„身分未經驗證。</translation>
<translation id="5720705177508910913">ç›®å‰ä½¿ç”¨è€…</translation>
<translation id="5732392974455271431">你的家長å¯ä»¥ç‚ºä½ è§£é™¤å°éŽ–這個網站</translation>
-<translation id="57586589942790530">無效的信用å¡è™Ÿç¢¼</translation>
+<translation id="5763042198335101085">請輸入有效的電å­éƒµä»¶åœ°å€</translation>
+<translation id="5765072501007116331">如è¦æŸ¥çœ‹å¿«éžæ–¹å¼å’Œç›¸é—œè¦å®šï¼Œè«‹é¸å–一個地å€</translation>
<translation id="5784606427469807560">驗證您的信用å¡æ™‚發生å•é¡Œã€‚請檢查網際網路連線,然後å†è©¦ä¸€æ¬¡ã€‚</translation>
<translation id="5785756445106461925">此外,這個網é å«æœ‰å…¶ä»–ä¸å®‰å…¨çš„資æºã€‚其他人å¯èƒ½æœƒåœ¨è³‡æºå‚³è¼¸æœŸé–“檢視這些資æºï¼Œæ”»æ“Šè€…也å¯èƒ½æœƒä¿®æ”¹é€™äº›è³‡æºï¼Œé€²è€Œè®Šæ›´ç¶²é å¤–觀。</translation>
<translation id="5786044859038896871">è¦å¡«å…¥ä½ çš„信用å¡è³‡è¨Šå—Žï¼Ÿ</translation>
@@ -520,22 +531,20 @@
<translation id="5869405914158311789">無法連上這個網站</translation>
<translation id="5869522115854928033">已儲存的密碼</translation>
<translation id="5872918882028971132">家長建議</translation>
-<translation id="587760065310675640">ç›®å‰é¸å–的是ä¸æ”¯æ´çš„é‹é€åœ°å€ï¼Œè«‹æ”¹ç”¨å…¶ä»–地å€ã€‚</translation>
<translation id="5901630391730855834">黃色</translation>
-<translation id="59174027418879706">已啟用</translation>
<translation id="5926846154125914413">您å¯èƒ½ç„¡æ³•å†å­˜å–部分網站的付費內容。</translation>
<translation id="5959728338436674663">自動傳é€éƒ¨åˆ†<ph name="BEGIN_WHITEPAPER_LINK" />系統資訊和網é å…§å®¹<ph name="END_WHITEPAPER_LINK" />給 Google,å”助åµæ¸¬å±éšªçš„應用程å¼å’Œç¶²ç«™ã€‚<ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5966707198760109579">週</translation>
<translation id="5967867314010545767">從紀錄中移除</translation>
<translation id="5975083100439434680">縮å°</translation>
+<translation id="598637245381783098">無法開啟付款應用程å¼</translation>
<translation id="5989320800837274978">沒有指定固定的 Proxy 伺æœå™¨å’Œ .pac 指令碼網å€ã€‚</translation>
<translation id="5990559369517809815">擴充功能已å°éŽ–è¦å‚³é€è‡³ä¼ºæœå™¨çš„è¦æ±‚。</translation>
<translation id="6008256403891681546">JCB</translation>
-<translation id="6011754012569870220">信用å¡å’Œåœ°å€é¸é …來自 Chrome。你å¯ä»¥åœ¨<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />中管ç†ç›¸é—œè³‡è¨Šã€‚</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{第 1 é }other{第 # é }}</translation>
<translation id="6017514345406065928">綠色</translation>
+<translation id="6027201098523975773">輸入å稱</translation>
<translation id="6040143037577758943">關閉</translation>
-<translation id="604124094241169006">自動</translation>
<translation id="6042308850641462728">更多</translation>
<translation id="6060685159320643512">請注æ„,這些實驗性功能å¯èƒ½å°é›»è…¦æœ‰å®³</translation>
<translation id="6108835911243775197">{COUNT,plural, =0{ç„¡}=1{1}other{#}}</translation>
@@ -543,9 +552,10 @@
數據機或其他網路è£ç½®ã€‚</translation>
<translation id="614940544461990577">建議åšæ³•ï¼š</translation>
<translation id="6151417162996330722">伺æœå™¨æ†‘證的有效期é™å¤ªé•·ã€‚</translation>
-<translation id="615643356032862689">系統會ä¿ç•™ä½ ä¸‹è¼‰çš„檔案和新增的書籤。</translation>
+<translation id="6157877588268064908">如è¦æŸ¥çœ‹é‹é€æ–¹å¼å’Œç›¸é—œè¦å®šï¼Œè«‹é¸å–一個地å€</translation>
<translation id="6165508094623778733">瞭解詳情</translation>
<translation id="6177128806592000436">你與這個網站的連線ä¸å®‰å…¨</translation>
+<translation id="6184817833369986695">(發佈版本:<ph name="UPDATE_COHORT_NAME" />)</translation>
<translation id="6203231073485539293">檢查網際網路連線</translation>
<translation id="6218753634732582820">è¦å¾ž Chromium 中移除地å€å—Žï¼Ÿ</translation>
<translation id="6251924700383757765">éš±ç§æ¬Šæ”¿ç­–</translation>
@@ -554,6 +564,8 @@
<translation id="6259156558325130047">é‡åšé‡æ–°æŽ’åº(&amp;R)</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> 書籤</translation>
<translation id="6264485186158353794">返回安全性ç€è¦½</translation>
+<translation id="6276112860590028508">你的閱讀清單中的é é¢æœƒé¡¯ç¤ºåœ¨é€™è£¡</translation>
+<translation id="6280223929691119688">å¿«éžç„¡æ³•é€è²¨åˆ°é€™å€‹åœ°å€ï¼Œè«‹æ”¹ç”¨å…¶ä»–地å€ã€‚</translation>
<translation id="6282194474023008486">郵éžå€è™Ÿ</translation>
<translation id="6290238015253830360">這裡會顯示為你推薦的文章</translation>
<translation id="6305205051461490394">無法連上 <ph name="URL" />。</translation>
@@ -575,7 +587,6 @@
<translation id="6417515091412812850">無法檢查憑證是å¦å·²é­æ’¤éŠ·ã€‚</translation>
<translation id="6433490469411711332">編輯è¯çµ¡è³‡è¨Š</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> 拒絕連線。</translation>
-<translation id="6443118737398455446">到期日無效</translation>
<translation id="6446608382365791566">新增詳細資訊</translation>
<translation id="6451458296329894277">確èªé‡æ–°æ交表單</translation>
<translation id="6456339708790392414">你的付款</translation>
@@ -583,10 +594,8 @@
<translation id="6462969404041126431">這個伺æœå™¨ç„¡æ³•è­‰æ˜Žæ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨çš„安全性憑證å¯èƒ½é­åˆ°æ’¤éŠ·ã€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–是有攻擊者攔截你的連線。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">è£ç½®æ”¿ç­–</translation>
<translation id="6477321094435799029">Chrome 在這個網é ä¸Šåµæ¸¬åˆ°ç•°å¸¸ä»£ç¢¼ã€‚為了ä¿è­·ä½ çš„個人資訊 (包括密碼ã€é›»è©±è™Ÿç¢¼æˆ–信用å¡è³‡æ–™),Chrome å·²å°éŽ–這個網é ã€‚</translation>
-<translation id="6477460825583319731">é›»å­éƒµä»¶åœ°å€ç„¡æ•ˆ</translation>
<translation id="6489534406876378309">開始上傳當機報告</translation>
<translation id="6508722015517270189">é‡æ–°å•Ÿå‹• Chrome</translation>
-<translation id="6525462735697194615">到期月份無效</translation>
<translation id="6529602333819889595">é‡åšåˆªé™¤(&amp;R)</translation>
<translation id="6534179046333460208">實體化網路建議</translation>
<translation id="6550675742724504774">é¸é …</translation>
@@ -601,7 +610,6 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> æœå°‹</translation>
<translation id="6644283850729428850">這項政策已é­å–代。</translation>
<translation id="6652240803263749613">這個伺æœå™¨ç„¡æ³•è­‰æ˜Žæ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;電腦的作業系統ä¸ä¿¡ä»»ä¼ºæœå™¨çš„安全性憑證。這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–是有攻擊者攔截你的連線。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
-<translation id="6665267558048410100">ä¸æ”¯æ´æ‰€é¸çš„貨é‹é¸é …,請改é¸å…¶ä»–é¸é …。</translation>
<translation id="6671697161687535275">è¦å¾ž Chromium 中移除表單填寫建議嗎?</translation>
<translation id="6685834062052613830">請登出並完æˆè¨­å®šç¨‹åº</translation>
<translation id="6710213216561001401">返回</translation>
@@ -609,13 +617,13 @@
<translation id="6711464428925977395">Proxy 伺æœå™¨ç™¼ç”ŸéŒ¯èª¤ï¼Œæˆ–是ä½å€ä¸æ­£ç¢ºã€‚</translation>
<translation id="6727102863431372879">設定</translation>
<translation id="6731320287533051140">{COUNT,plural, =0{無}=1{1 個項目}other{# 個項目}}</translation>
-<translation id="6743044928064272573">å–件é¸é …</translation>
<translation id="674375294223700098">ä¸æ˜Žçš„伺æœå™¨æ†‘證錯誤。</translation>
<translation id="6753269504797312559">政策值</translation>
<translation id="6757797048963528358">您的è£ç½®å·²é€²å…¥ç¡çœ æ¨¡å¼ã€‚</translation>
<translation id="6778737459546443941">你的家長尚未核准這個網站</translation>
<translation id="6810899417690483278">自訂 ID</translation>
<translation id="6820686453637990663">CVC</translation>
+<translation id="6824266427216888781">無法載入地å€è³‡æ–™</translation>
<translation id="6831043979455480757">翻譯</translation>
<translation id="6839929833149231406">å€</translation>
<translation id="6874604403660855544">é‡åšæ–°å¢ž(&amp;R)</translation>
@@ -623,6 +631,7 @@
<translation id="6895330447102777224">您的信用å¡å·²é€šéŽé©—è­‰</translation>
<translation id="6897140037006041989">使用者代ç†ç¨‹å¼</translation>
<translation id="6915804003454593391">使用者:</translation>
+<translation id="6948701128805548767">如è¦æŸ¥çœ‹å–件方å¼å’Œç›¸é—œè¦å®šï¼Œè«‹é¸å–一個地å€</translation>
<translation id="6957887021205513506">伺æœå™¨æ†‘證疑似å½é€ ã€‚</translation>
<translation id="6965382102122355670">確定</translation>
<translation id="6965978654500191972">è£ç½®</translation>
@@ -630,7 +639,6 @@
<translation id="6973656660372572881">已指定固定的 Proxy 伺æœå™¨å’Œ .pac 指令碼網å€ã€‚</translation>
<translation id="6989763994942163495">顯示進階設定...</translation>
<translation id="7000990526846637657">找ä¸åˆ°ä»»ä½•ç´€éŒ„é …ç›®</translation>
-<translation id="7001663382399377034">新增收件者</translation>
<translation id="7009986207543992532">你嘗試連上 <ph name="DOMAIN" />,但伺æœå™¨æ供的憑證有效期é™å¤ªé•·ï¼Œå› æ­¤é›£ä»¥ä¿¡ä»»ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">中國銀è¯</translation>
<translation id="7012372675181957985">ä½ ä»å¯å‰å¾€ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> å­˜å– Google 帳戶中ä¿å­˜çš„å„種ç€è¦½ç´€éŒ„</translation>
@@ -641,20 +649,23 @@
<translation id="7088615885725309056">較舊記錄</translation>
<translation id="7090678807593890770">è«‹é€éŽ Google æœå°‹ã€Œ<ph name="LINK" />ã€</translation>
<translation id="7119414471315195487">關閉其他分é æˆ–程å¼</translation>
+<translation id="7129409597930077180">無法é‹é€åˆ°é€™å€‹åœ°å€ï¼Œè«‹æ”¹ç”¨å…¶ä»–地å€ã€‚</translation>
+<translation id="7138472120740807366">å¿«éžæ–¹å¼</translation>
<translation id="7139724024395191329">大公國</translation>
<translation id="7155487117670177674">付款行為ä¸å®‰å…¨</translation>
<translation id="7179921470347911571">ç«‹å³é‡æ–°å•Ÿå‹•</translation>
<translation id="7180611975245234373">é‡æ–°æ•´ç†</translation>
<translation id="7182878459783632708">沒有設定任何政策</translation>
<translation id="7186367841673660872">此網é å…§å®¹å·²ç”±<ph name="ORIGINAL_LANGUAGE" />翻譯æˆ<ph name="LANGUAGE_LANGUAGE" /></translation>
+<translation id="7192203810768312527">釋出 <ph name="SIZE" />。下次造訪部分網站時,載入速度å¯èƒ½æœƒè®Šæ…¢ã€‚</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ä¸ç¬¦åˆå®‰å…¨æ€§æ¨™æº–。</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />進一步瞭解<ph name="END_LINK" />這個å•é¡Œã€‚</translation>
<translation id="7219179957768738017">這個連線使用 <ph name="SSL_VERSION" />。</translation>
<translation id="7220786058474068424">處ç†ä¸­</translation>
-<translation id="724691107663265825">您è¦é€ è¨ªçš„網站å«æœ‰æƒ¡æ„軟體</translation>
+<translation id="724691107663265825">ä½ è¦é€ è¨ªçš„網站å«æœ‰æƒ¡æ„軟體</translation>
<translation id="724975217298816891">請輸入 <ph name="CREDIT_CARD" /> 的有效日期和信用å¡å®‰å…¨ç¢¼ï¼Œæ›´æ–°æ‚¨çš„信用å¡è©³ç´°è³‡è¨Šã€‚完æˆé©—證後,這個網站就會å–得您的信用å¡è©³ç´°è³‡è¨Šã€‚</translation>
-<translation id="725866823122871198">您電腦的日期和時間 (<ph name="DATE_AND_TIME" />) ä¸æ­£ç¢ºï¼Œå› æ­¤ç„¡æ³•èˆ‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立ç§äººé€£ç·šã€‚</translation>
+<translation id="725866823122871198">你電腦的日期和時間 (<ph name="DATE_AND_TIME" />) ä¸æ­£ç¢ºï¼Œå› æ­¤ç„¡æ³•èˆ‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立ç§äººé€£ç·šã€‚</translation>
<translation id="7275334191706090484">å—管ç†æ›¸ç±¤</translation>
<translation id="7298195798382681320">建議採用</translation>
<translation id="7309308571273880165">當機報告擷å–時間:<ph name="CRASH_TIME" /> (使用者è¦æ±‚上傳,但尚未上傳)</translation>
@@ -667,16 +678,15 @@
<translation id="7378627244592794276">ä¸éœ€è¦</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7390545607259442187">驗證信用å¡</translation>
-<translation id="7394102162464064926">您確定è¦å¾žç´€éŒ„中刪除這些網é å—Žï¼Ÿ
+<translation id="7394102162464064926">你確定è¦å¾žç´€éŒ„中刪除這些網é å—Žï¼Ÿ
-æ醒您ï¼ä¸‹æ¬¡å¯ä»¥è©¦è©¦å¥½ç”¨çš„ç„¡ç—•æ¨¡å¼ (<ph name="SHORTCUT_KEY" />)。</translation>
+æ醒你ï¼ä¸‹æ¬¡å¯ä»¥è©¦è©¦å¥½ç”¨çš„ç„¡ç—•æ¨¡å¼ (<ph name="SHORTCUT_KEY" />)。</translation>
<translation id="7400418766976504921">網å€</translation>
<translation id="7419106976560586862">設定檔路徑</translation>
<translation id="7424977062513257142">這個網é ä¸Šçš„嵌入å¼ç¶²é é¡¯ç¤ºï¼š</translation>
<translation id="7441627299479586546">政策主體有誤</translation>
<translation id="7444046173054089907">這個網站é­åˆ°å°éŽ–</translation>
-<translation id="7444238235002594607">é¸å–å–件地å€å³å¯æŸ¥çœ‹å–件方å¼å’Œéœ€æ±‚æ¢ä»¶ã€‚</translation>
-<translation id="7445762425076701745">您所連線的伺æœå™¨èº«åˆ†ç„¡æ³•å®Œå…¨é©—證,該伺æœå™¨æ‰€ä½¿ç”¨çš„å稱僅在您的網路中有效,無法驗證外部憑證授權單ä½çš„æ“有權。å³ä½¿æŸäº›æ†‘證授權單ä½æœƒæ ¸ç™¼é€™äº›æ†‘證,ä¸éŽç„¡æ³•å°±æ­¤ç¢ºä¿æ‚¨æ‰€é€£ä¸Šçš„網站是正確的,而ä¸æœƒé­åˆ°ç¶²è·¯æ”»æ“Šã€‚</translation>
+<translation id="7445762425076701745">你所連線的伺æœå™¨èº«åˆ†ç„¡æ³•å®Œå…¨é©—證,該伺æœå™¨æ‰€ä½¿ç”¨çš„å稱僅在你的網路中有效,無法驗證外部憑證授權單ä½çš„æ“有權。å³ä½¿æŸäº›æ†‘證授權單ä½æœƒæ ¸ç™¼é€™äº›æ†‘證,ä¸éŽç„¡æ³•å°±æ­¤ç¢ºä¿ä½ æ‰€é€£ä¸Šçš„網站是正確的,而ä¸æœƒé­åˆ°ç¶²è·¯æ”»æ“Šã€‚</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />進一步瞭解<ph name="END_LINK" />這個å•é¡Œã€‚</translation>
<translation id="7460163899615895653">你最近在其他è£ç½®ä¸Šé–‹å•Ÿçš„分é æœƒé¡¯ç¤ºåœ¨é€™è£¡</translation>
<translation id="7469372306589899959">正在驗證信用å¡</translation>
@@ -689,10 +699,10 @@
<translation id="7537536606612762813">強制</translation>
<translation id="7542995811387359312">由於這個表單並未採用加密連線方å¼ï¼Œæ‰€ä»¥ä¿¡ç”¨å¡è‡ªå‹•å¡«å…¥åŠŸèƒ½å·²åœç”¨ã€‚</translation>
<translation id="7543525346216957623">請徵求家長åŒæ„</translation>
-<translation id="7549584377607005141">這個網é éœ€è¦ä½¿ç”¨æ‚¨å…ˆå‰è¼¸å…¥çš„資料æ‰èƒ½æ­£ç¢ºé¡¯ç¤ºã€‚您å¯ä»¥é‡æ–°å‚³é€é€™äº›è³‡æ–™ï¼Œä¸éŽé€™éº¼åšæœƒé‡è¤‡åŸ·è¡Œé€™å€‹ç¶²é å…ˆå‰åŸ·è¡ŒéŽçš„任何動作。</translation>
+<translation id="7549584377607005141">這個網é éœ€è¦ä½¿ç”¨ä½ å…ˆå‰è¼¸å…¥çš„資料æ‰èƒ½æ­£ç¢ºé¡¯ç¤ºã€‚ä½ å¯ä»¥é‡æ–°å‚³é€é€™äº›è³‡æ–™ï¼Œä¸éŽé€™éº¼åšæœƒé‡è¤‡åŸ·è¡Œé€™å€‹ç¶²é å…ˆå‰åŸ·è¡ŒéŽçš„任何動作。</translation>
<translation id="7552846755917812628">嘗試按照下列æ示æ“作:</translation>
<translation id="7554791636758816595">新增分é </translation>
-<translation id="7568593326407688803">此網é ç‚º<ph name="ORIGINAL_LANGUAGE" />您è¦ç¿»è­¯ç¶²é å…§å®¹å—Žï¼Ÿ</translation>
+<translation id="7568593326407688803">此網é ç‚º<ph name="ORIGINAL_LANGUAGE" />ä½ è¦ç¿»è­¯ç¶²é å…§å®¹å—Žï¼Ÿ</translation>
<translation id="7569952961197462199">è¦å¾ž Chrome 中移除信用å¡å—Žï¼Ÿ</translation>
<translation id="7569983096843329377">黑色</translation>
<translation id="7578104083680115302">在ä¸åŒçš„è£ç½®ä¸Šé€éŽå„個網站和應用程å¼æ¶ˆè²»æ™‚,使用您讓 Google 儲存的信用å¡è³‡æ–™å³å¯å¿«é€Ÿä»˜æ¬¾ã€‚</translation>
@@ -702,8 +712,8 @@
<translation id="7600965453749440009">一律ä¸ç¿»è­¯<ph name="LANGUAGE" /></translation>
<translation id="7610193165460212391">值超出 <ph name="VALUE" /> 的範åœã€‚</translation>
<translation id="7613889955535752492">有效期é™ï¼š<ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
-<translation id="7615602087246926389">您已經使用其他版本的「Google 帳戶ã€å¯†ç¢¼å°è³‡æ–™é€²è¡ŒåŠ å¯†ï¼Œè«‹åœ¨ä¸‹æ–¹è¼¸å…¥å¯†ç¢¼ã€‚</translation>
-<translation id="7634554953375732414">您與這個網站建立了éžç§äººé€£ç·šã€‚</translation>
+<translation id="7615602087246926389">你已經使用其他版本的「Google 帳戶ã€å¯†ç¢¼å°è³‡æ–™é€²è¡ŒåŠ å¯†ï¼Œè«‹åœ¨ä¸‹æ–¹è¼¸å…¥å¯†ç¢¼ã€‚</translation>
+<translation id="7634554953375732414">你與這個網站建立了éžç§äººé€£ç·šã€‚</translation>
<translation id="7637571805876720304">è¦å¾ž Chromium 中移除信用å¡å—Žï¼Ÿ</translation>
<translation id="765676359832457558">éš±è—進階設定...</translation>
<translation id="7658239707568436148">å–消</translation>
@@ -719,6 +729,7 @@
<translation id="7755287808199759310">你的家長å¯ä»¥ç‚ºä½ è§£é™¤å°éŽ–這個網站</translation>
<translation id="7758069387465995638">防ç«ç‰†æˆ–防毒軟體å¯èƒ½å°éŽ–了連線。</translation>
<translation id="7761701407923456692">伺æœå™¨æ†‘證與網å€ä¸ç¬¦ã€‚</translation>
+<translation id="7763386264682878361">付款資訊清單剖æžå™¨</translation>
<translation id="7764225426217299476">新增地å€</translation>
<translation id="777702478322588152">縣</translation>
<translation id="7791543448312431591">新增</translation>
@@ -732,6 +743,7 @@
<translation id="785549533363645510">ä¸éŽï¼Œé€™ä¸¦ä¸æ„味著您å¯ä»¥å®Œå…¨éš±å½¢ã€‚使用無痕模å¼æ™‚,您的雇主和網際網路æœå‹™ä¾›æ‡‰å•†ä»ç„¶å¯ä»¥è¿½è¹¤æ‚¨çš„ç€è¦½ç´€éŒ„,您所造訪的網站也å¯èƒ½æœƒè¨˜éŒ„您的ç€è¦½è¡Œç‚ºã€‚</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7887683347370398519">請檢查您的 CVC,然後å†è©¦ä¸€æ¬¡</translation>
+<translation id="79338296614623784">請輸入有效的電話號碼</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">伺æœå™¨æ†‘證尚未生效。</translation>
<translation id="7942349550061667556">紅色</translation>
@@ -751,6 +763,7 @@
<translation id="8088680233425245692">無法查看文章。</translation>
<translation id="8089520772729574115">ä¸åˆ° 1 MB</translation>
<translation id="8091372947890762290">尚未在伺æœå™¨ä¸Šå•Ÿå‹•</translation>
+<translation id="8118489163946903409">付款方å¼</translation>
<translation id="8131740175452115882">確èª</translation>
<translation id="8134994873729925007">找ä¸åˆ° <ph name="HOST_NAME" /> 的伺æœå™¨ <ph name="BEGIN_ABBR" />DNS ä½å€<ph name="END_ABBR" />。</translation>
<translation id="8149426793427495338">您的電腦已進入ç¡çœ æ¨¡å¼ã€‚</translation>
@@ -761,54 +774,53 @@
<translation id="8218327578424803826">指派的ä½ç½®ï¼š</translation>
<translation id="8225771182978767009">設定這部電腦的使用者é¸æ“‡å°éŽ–這個網站。</translation>
<translation id="822964464349305906"><ph name="TYPE_1" />ã€<ph name="TYPE_2" /></translation>
-<translation id="8230421197304563332">攻擊者目å‰å¯èƒ½æœƒè©¦åœ–é€éŽ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 在您的電腦上安è£å±éšªç¨‹å¼ï¼Œè—‰æ­¤ç«Šå–或刪除您的資訊 (例如相片ã€å¯†ç¢¼ã€éƒµä»¶æˆ–信用å¡è³‡æ–™)。</translation>
-<translation id="8241707690549784388">您尋找的網é ä½¿ç”¨äº†æ‚¨è¼¸å…¥çš„資料。返回該é æœƒé‡è¤‡æ‚¨å‰›æ‰çš„行動。您確定è¦ç¹¼çºŒå—Žï¼Ÿ</translation>
+<translation id="8230421197304563332">攻擊者目å‰å¯èƒ½æœƒè©¦åœ–é€éŽ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 在你的電腦上安è£å±éšªç¨‹å¼ï¼Œè—‰æ­¤ç«Šå–或刪除你的資訊 (例如相片ã€å¯†ç¢¼ã€éƒµä»¶æˆ–信用å¡è³‡æ–™)。</translation>
+<translation id="8241707690549784388">你尋找的網é ä½¿ç”¨äº†ä½ è¼¸å…¥çš„資料。返回該é æœƒé‡è¤‡ä½ å‰›æ‰çš„行動。你確定è¦ç¹¼çºŒå—Žï¼Ÿ</translation>
<translation id="8249320324621329438">上次擷å–時間:</translation>
<translation id="8253091569723639551">è«‹æ供帳單地å€</translation>
<translation id="8261506727792406068">刪除</translation>
-<translation id="8289355894181816810">如果您ä¸ç¢ºå®šé€™ä»£è¡¨ä»€éº¼æ„æ€ï¼Œè«‹èˆ‡ç¶²è·¯ç®¡ç†å“¡è¯çµ¡ã€‚</translation>
+<translation id="8289355894181816810">如果你ä¸ç¢ºå®šé€™ä»£è¡¨ä»€éº¼æ„æ€ï¼Œè«‹èˆ‡ç¶²è·¯ç®¡ç†å“¡è¯çµ¡ã€‚</translation>
<translation id="8293206222192510085">新增書籤</translation>
<translation id="8294431847097064396">來æº</translation>
<translation id="8308427013383895095">網路連線發生å•é¡Œï¼Œç¿»è­¯ä½œæ¥­å¤±æ•—。</translation>
<translation id="8332188693563227489">å­˜å– <ph name="HOST_NAME" /> çš„è¦æ±‚é­åˆ°æ‹’絕</translation>
-<translation id="834457929814110454">如果您瞭解安全性風險,也å¯ä»¥é¸æ“‡åœ¨æœ‰å®³ç¨‹å¼å°šæœªé­åˆ°ç§»é™¤çš„狀態下<ph name="BEGIN_LINK" />造訪這個網站<ph name="END_LINK" />。</translation>
+<translation id="834457929814110454">如果你瞭解安全性風險,也å¯ä»¥é¸æ“‡åœ¨æœ‰å®³ç¨‹å¼å°šæœªé­åˆ°ç§»é™¤çš„狀態下<ph name="BEGIN_LINK" />造訪這個網站<ph name="END_LINK" />。</translation>
<translation id="8344669043927012510">以無痕模å¼é–‹å•Ÿç¶²é  (⇧ + ⌘ + N éµ)</translation>
<translation id="8349305172487531364">書籤列</translation>
<translation id="8363502534493474904">關閉飛航模å¼</translation>
<translation id="8364627913115013041">未設定。</translation>
+<translation id="8368476060205742148">Google Play æœå‹™</translation>
<translation id="8380941800586852976">ä¸å®‰å…¨</translation>
<translation id="8382348898565613901">這裡會顯示你最近造訪éŽçš„書籤</translation>
<translation id="8398259832188219207">當機報告上傳時間:<ph name="UPLOAD_TIME" /></translation>
<translation id="8412145213513410671">當機次數 (<ph name="CRASH_COUNT" />)</translation>
-<translation id="8412392972487953978">您必須輸入兩次相åŒçš„通關密語。</translation>
+<translation id="8412392972487953978">你必須輸入兩次相åŒçš„通關密語。</translation>
<translation id="8428213095426709021">設定</translation>
<translation id="8433057134996913067">您會因此登出大多數網站。</translation>
<translation id="8437238597147034694">復原移動(&amp;U)</translation>
-<translation id="8456681095658380701">å稱無效</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 張信用å¡}other{# 張信用å¡}}</translation>
<translation id="8483780878231876732">如è¦ä½¿ç”¨æ‚¨çš„ Google 帳戶中的信用å¡ï¼Œè«‹ç™»å…¥ Chrome</translation>
<translation id="8488350697529856933">é©ç”¨å°è±¡</translation>
-<translation id="8492969205326575646">ä¸æ”¯æ´çš„信用å¡é¡žåž‹</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> 的回應時間éŽé•·ã€‚</translation>
<translation id="852346902619691059">這個伺æœå™¨ç„¡æ³•è­‰æ˜Žæ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />ï¼›è£ç½®çš„作業系統ä¸ä¿¡ä»»ä¼ºæœå™¨çš„安全性憑證。這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–是有攻擊者攔截你的連線。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="8532105204136943229">到期年份</translation>
<translation id="8543181531796978784">您å¯ä»¥<ph name="BEGIN_ERROR_LINK" />回報åµæ¸¬å•é¡Œ<ph name="END_ERROR_LINK" />。或者在您瞭解安全性風險後,ä»ç„¶å¯ä»¥<ph name="BEGIN_LINK" />å‰å¾€é€™å€‹ä¸å®‰å…¨çš„網站<ph name="END_LINK" />。</translation>
<translation id="8553075262323480129">無法判定網é çš„語言,翻譯作業失敗。</translation>
-<translation id="8559762987265718583">您è£ç½®çš„日期和時間 (<ph name="DATE_AND_TIME" />) ä¸æ­£ç¢ºï¼Œå› æ­¤ç„¡æ³•èˆ‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立ç§äººé€£ç·šã€‚</translation>
-<translation id="8570229484593575558">系統|ä¸æœƒå„²å­˜|以下資訊:#ä½ çš„ç€è¦½ç´€éŒ„#ä½ çš„æœå°‹æŸ¥è©¢#Cookie 資料</translation>
+<translation id="8559762987265718583">ä½ è£ç½®çš„日期和時間 (<ph name="DATE_AND_TIME" />) ä¸æ­£ç¢ºï¼Œå› æ­¤ç„¡æ³•èˆ‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立ç§äººé€£ç·šã€‚</translation>
<translation id="8571890674111243710">正在將網é ç¿»è­¯æˆ<ph name="LANGUAGE" />...</translation>
-<translation id="8584539743998202583">以下å„æ–¹|å¯èƒ½ä»æœƒçœ‹åˆ°|你的活動:#你造訪的網站#你的雇主#你的網際網路æœå‹™ä¾›æ‡‰å•†</translation>
<translation id="858637041960032120">新增電話號碼</translation>
<translation id="859285277496340001">憑證未指定負責檢查其本身是å¦å·²é­åˆ°æ’¤éŠ·çš„機制。</translation>
<translation id="8620436878122366504">你的家長尚未核准這個網站</translation>
<translation id="8647750283161643317">全部é‡è¨­ç‚ºé è¨­å€¼</translation>
-<translation id="8703575177326907206">您到 <ph name="DOMAIN" /> 的連線未加密。</translation>
+<translation id="8703575177326907206">你到 <ph name="DOMAIN" /> 的連線未加密。</translation>
+<translation id="8718314106902482036">未完æˆä»˜æ¬¾ç¨‹åº</translation>
<translation id="8725066075913043281">å†è©¦ä¸€æ¬¡</translation>
-<translation id="8728672262656704056">您已啟用無痕模å¼ã€‚</translation>
+<translation id="8728672262656704056">你已進入無痕模å¼</translation>
<translation id="8730621377337864115">完æˆ</translation>
-<translation id="8738058698779197622">您必須正確設定時é˜ï¼Œæ‰èƒ½å»ºç«‹å®‰å…¨é€£ç·šã€‚這是因為網站驗證身分時所使用的憑證僅於特定一段時間內有效。由於您è£ç½®çš„時é˜ä¸æ­£ç¢ºï¼Œå› æ­¤ Chromium 無法驗證這些憑證。</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="8759274551635299824">這張信用å¡å·²éŽæœŸ</translation>
<translation id="8790007591277257123">é‡åšåˆªé™¤(&amp;R)</translation>
-<translation id="8798099450830957504">é è¨­</translation>
<translation id="8800988563907321413">這裡會顯示系統建議你ç€è¦½çš„鄰近網é </translation>
<translation id="8820817407110198400">書籤</translation>
<translation id="883848425547221593">其他書籤</translation>
@@ -818,34 +830,33 @@
<translation id="8866481888320382733">解æžæ”¿ç­–設定時發生錯誤</translation>
<translation id="8866959479196209191">這個網é é¡¯ç¤ºï¼š</translation>
<translation id="8870413625673593573">最近關閉的分é </translation>
+<translation id="8874824191258364635">請輸入有效的信用å¡è™Ÿç¢¼</translation>
<translation id="8876793034577346603">無法解æžç¶²è·¯è¨­å®šã€‚</translation>
<translation id="8877192140621905067">完æˆé©—證後,這個網站就會å–得您的信用å¡è©³ç´°è³‡è¨Š</translation>
<translation id="8889402386540077796">色調</translation>
<translation id="8891727572606052622">Proxy 模å¼ç„¡æ•ˆã€‚</translation>
-<translation id="889901481107108152">很抱歉,這項實驗功能無法支æ´æ‚¨çš„å¹³å°ã€‚</translation>
+<translation id="889901481107108152">很抱歉,這項實驗功能無法支æ´ä½ çš„å¹³å°ã€‚</translation>
<translation id="8903921497873541725">放大</translation>
<translation id="8931333241327730545">您è¦å°‡é€™å¼µå¡ç‰‡çš„資訊儲存到您的 Google 帳戶嗎?</translation>
-<translation id="8932102934695377596">您的時é˜æ™‚é–“éŽæ…¢</translation>
+<translation id="8932102934695377596">你的時é˜æ™‚é–“éŽæ…¢</translation>
<translation id="8954894007019320973">(續)</translation>
-<translation id="895548565263634352">閱讀<ph name="ARTICLE_PUBLISHER" />的報導和å¦å¤– <ph name="OTHER_ARTICLE_COUNT" /> 篇報導</translation>
<translation id="8971063699422889582">伺æœå™¨æ†‘證已éŽæœŸã€‚</translation>
<translation id="8986494364107987395">自動傳é€ä½¿ç”¨çµ±è¨ˆè³‡æ–™åŠç•¶æ©Ÿå ±å‘Šçµ¦ Google</translation>
<translation id="8987927404178983737">月</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8996941253935762404">您è¦ç€è¦½çš„網站å«æœ‰æœ‰å®³ç¨‹å¼</translation>
+<translation id="8996941253935762404">ä½ è¦ç€è¦½çš„網站å«æœ‰æœ‰å®³ç¨‹å¼</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> Proxy è¦æ±‚æ供使用者å稱和密碼。</translation>
<translation id="901974403500617787">這些設定會套用至整個系統,åªæœ‰ä»¥ä¸‹ä½¿ç”¨è€…å¯è¨­å®šï¼š<ph name="OWNER_EMAIL" />。</translation>
<translation id="9020542370529661692">此網é å…§å®¹å·²ç¿»è­¯æˆ<ph name="TARGET_LANGUAGE" /></translation>
<translation id="9035022520814077154">安全性錯誤</translation>
<translation id="9038649477754266430">使用é æ¸¬æŸ¥è©¢å­—串æœå‹™ï¼Œè®“系統更快載入網é </translation>
<translation id="9039213469156557790">此外,這個網é å«æœ‰å…¶ä»–ä¸å®‰å…¨çš„資æºã€‚其他人å¯èƒ½æœƒåœ¨è³‡æºå‚³è¼¸æœŸé–“檢視這些資æºï¼Œæ”»æ“Šè€…也å¯èƒ½æœƒä¿®æ”¹é€™äº›è³‡æºï¼Œé€²è€Œè®Šæ›´ç¶²é è¡Œç‚ºã€‚</translation>
-<translation id="9040185888511745258">攻擊者ä¼åœ–在 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 誘使您安è£æœ‰å®³ç€è¦½é«”é©—çš„ç¨‹å¼ (比如竄改您的首é ï¼Œæˆ–在您造訪的網站上å¦å¤–顯示廣告)。</translation>
+<translation id="9040185888511745258">攻擊者ä¼åœ–在 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 誘使你安è£æœ‰å®³ç€è¦½é«”é©—çš„ç¨‹å¼ (比如竄改你的首é ï¼Œæˆ–在你造訪的網站上å¦å¤–顯示廣告)。</translation>
<translation id="9050666287014529139">通關密語</translation>
<translation id="9065203028668620118">編輯</translation>
<translation id="9068849894565669697">é¸å–é¡è‰²</translation>
<translation id="9076283476770535406">這個網站å¯èƒ½å«æœ‰æˆäººå…§å®¹</translation>
<translation id="9078964945751709336">è«‹æ供詳細資訊</translation>
-<translation id="9094175695478007090">無法啟動付款應用程å¼ã€‚</translation>
<translation id="9103872766612412690"><ph name="SITE" /> 通常使用加密方å¼ä¿è­·æ‚¨çš„資訊。但 Chromium 這次嘗試連線到 <ph name="SITE" /> 時,該網站傳回了異常且錯誤的憑證。這å¯èƒ½æ˜¯å› ç‚ºæœ‰æ”»æ“Šè€…ä¼åœ–å½è£æˆ <ph name="SITE" />,或是å—到 Wi-Fi 登入畫é¢å½±éŸ¿è€Œé€ æˆé€£ç·šä¸­æ–·ã€‚ä¸éŽè«‹æ”¾å¿ƒï¼ŒChromium å·²åŠæ™‚åœæ­¢é€£ç·šï¼Œä¸¦æœªå‚³è¼¸ä»»ä½•è³‡æ–™ï¼Œå› æ­¤æ‚¨çš„資訊ä»ç„¶å®‰å…¨ç„¡è™žã€‚</translation>
<translation id="9137013805542155359">顯示原文</translation>
<translation id="9137248913990643158">使用這個應用程å¼å‰ï¼Œè«‹å…ˆå•Ÿå‹• Chrome 並登入帳戶。</translation>
diff --git a/chromium/components/subresource_filter/content/browser/BUILD.gn b/chromium/components/subresource_filter/content/browser/BUILD.gn
index 44eeb1db6c4..bda66f04529 100644
--- a/chromium/components/subresource_filter/content/browser/BUILD.gn
+++ b/chromium/components/subresource_filter/content/browser/BUILD.gn
@@ -8,18 +8,27 @@ static_library("browser") {
"activation_state_computing_navigation_throttle.h",
"async_document_subresource_filter.cc",
"async_document_subresource_filter.h",
- "content_ruleset_service_delegate.cc",
- "content_ruleset_service_delegate.h",
+ "content_activation_list_utils.cc",
+ "content_activation_list_utils.h",
+ "content_ruleset_service.cc",
+ "content_ruleset_service.h",
"content_subresource_filter_driver_factory.cc",
"content_subresource_filter_driver_factory.h",
+ "content_subresource_filter_throttle_manager.cc",
+ "content_subresource_filter_throttle_manager.h",
"subframe_navigation_filtering_throttle.cc",
"subframe_navigation_filtering_throttle.h",
+ "subresource_filter_client.h",
+ "subresource_filter_safe_browsing_activation_throttle.cc",
+ "subresource_filter_safe_browsing_activation_throttle.h",
"verified_ruleset_dealer.cc",
"verified_ruleset_dealer.h",
]
deps = [
"//base",
+ "//components/safe_browsing_db:database_manager",
"//components/safe_browsing_db:util",
+ "//components/safe_browsing_db:v4_local_database_manager",
"//components/subresource_filter/content/common",
"//components/subresource_filter/core/browser",
"//components/subresource_filter/core/common",
@@ -34,17 +43,37 @@ static_library("browser") {
]
}
+static_library("test_support") {
+ testonly = true
+ sources = [
+ "async_document_subresource_filter_test_utils.cc",
+ "async_document_subresource_filter_test_utils.h",
+ ]
+ deps = [
+ ":browser",
+ "//base/test:test_support",
+ "//components/subresource_filter/core/common",
+ "//testing/gtest:gtest",
+ ]
+}
+
source_set("unit_tests") {
testonly = true
sources = [
+ "activation_state_computing_navigation_throttle_unittest.cc",
"async_document_subresource_filter_unittest.cc",
- "content_ruleset_service_delegate_unittest.cc",
+ "content_ruleset_service_unittest.cc",
"content_subresource_filter_driver_factory_unittest.cc",
+ "content_subresource_filter_throttle_manager_unittest.cc",
+ "subframe_navigation_filtering_throttle_unittest.cc",
+ "subresource_filter_safe_browsing_activation_throttle_unittest.cc",
"verified_ruleset_dealer_unittest.cc",
]
deps = [
":browser",
+ ":test_support",
"//base/test:test_support",
+ "//components/safe_browsing_db:test_database_manager",
"//components/safe_browsing_db:util",
"//components/subresource_filter/content/common",
"//components/subresource_filter/core/browser",
diff --git a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
index 5b1204fbcb1..fddc75bd4d2 100644
--- a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
+++ b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
@@ -58,12 +58,11 @@ void ActivationStateComputingNavigationThrottle::
const ActivationState& page_activation_state) {
DCHECK(navigation_handle()->IsInMainFrame());
DCHECK(!parent_activation_state_);
- DCHECK(!activation_state_);
DCHECK(!ruleset_handle_);
// DISABLED implies null ruleset.
DCHECK(page_activation_state.activation_level != ActivationLevel::DISABLED ||
!ruleset_handle);
- parent_activation_state_.emplace(page_activation_state);
+ parent_activation_state_ = page_activation_state;
ruleset_handle_ = ruleset_handle;
}
@@ -75,7 +74,6 @@ ActivationStateComputingNavigationThrottle::WillProcessResponse() {
parent_activation_state_->activation_level == ActivationLevel::DISABLED) {
DCHECK(navigation_handle()->IsInMainFrame());
DCHECK(!ruleset_handle_);
- activation_state_.emplace(ActivationLevel::DISABLED);
return content::NavigationThrottle::ThrottleCheckResult::PROCEED;
}
@@ -90,34 +88,31 @@ ActivationStateComputingNavigationThrottle::WillProcessResponse() {
DCHECK(parent);
params.parent_document_origin = parent->GetLastCommittedOrigin();
}
- // TODO(csharrison): Replace the empty OnceClosure with a UI-triggering
- // callback.
+
async_filter_ = base::MakeUnique<AsyncDocumentSubresourceFilter>(
ruleset_handle_, std::move(params),
base::Bind(&ActivationStateComputingNavigationThrottle::
- SetActivationStateAndResume,
- weak_ptr_factory_.GetWeakPtr()),
- base::OnceClosure());
+ OnActivationStateComputed,
+ weak_ptr_factory_.GetWeakPtr()));
return content::NavigationThrottle::ThrottleCheckResult::DEFER;
}
-void ActivationStateComputingNavigationThrottle::SetActivationStateAndResume(
+void ActivationStateComputingNavigationThrottle::OnActivationStateComputed(
ActivationState state) {
- // Cannot send activation level to the renderer until ReadyToCommitNavigation,
- // the driver will pull the state out of |this| when that callback occurs.
- DCHECK(!activation_state_);
- activation_state_.emplace(state);
navigation_handle()->Resume();
}
+// Ensure the caller cannot take ownership of a subresource filter for cases
+// when activation IPCs are not sent to the render process.
std::unique_ptr<AsyncDocumentSubresourceFilter>
ActivationStateComputingNavigationThrottle::ReleaseFilter() {
- return std::move(async_filter_);
+ return will_send_activation_to_renderer_ ? std::move(async_filter_) : nullptr;
}
-const ActivationState&
-ActivationStateComputingNavigationThrottle::GetActivationState() const {
- return activation_state_.value();
+void ActivationStateComputingNavigationThrottle::
+ WillSendActivationToRenderer() {
+ DCHECK(async_filter_);
+ will_send_activation_to_renderer_ = true;
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
index 2fc7917078c..c3415734a27 100644
--- a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
+++ b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
@@ -63,22 +63,23 @@ class ActivationStateComputingNavigationThrottle
// frame.
std::unique_ptr<AsyncDocumentSubresourceFilter> ReleaseFilter();
- // Gets the activation state calculated for this navigation. Must be called
- // after the navigation is resumed from getting paused in WillProcessResponse,
- // which, for example, will have happened at ReadyToCommitNavigation.
- const ActivationState& GetActivationState() const;
+ AsyncDocumentSubresourceFilter* filter() { return async_filter_.get(); }
+
+ void WillSendActivationToRenderer();
private:
- void SetActivationStateAndResume(ActivationState state);
+ void OnActivationStateComputed(ActivationState state);
+ void set_filter(
+ std::unique_ptr<AsyncDocumentSubresourceFilter> async_filter) {
+ async_filter_ = std::move(async_filter);
+ }
ActivationStateComputingNavigationThrottle(
content::NavigationHandle* navigation_handle,
const base::Optional<ActivationState> parent_activation_state,
VerifiedRuleset::Handle* ruleset_handle);
- // These members are optional to allow DCHECKing their existence at certain
- // points in the navigation flow.
- base::Optional<ActivationState> activation_state_;
+ // Optional to allow for DCHECKing.
base::Optional<ActivationState> parent_activation_state_;
std::unique_ptr<AsyncDocumentSubresourceFilter> async_filter_;
@@ -87,6 +88,12 @@ class ActivationStateComputingNavigationThrottle
// nullptr until NotifyPageActivationWithRuleset is called.
VerifiedRuleset::Handle* ruleset_handle_;
+ // Becomes true when the throttle manager reaches ReadyToCommitNavigation and
+ // sends an activation IPC to the render process. Makes sure a caller cannot
+ // take ownership of the subresource filter unless an activation IPC is sent
+ // to the renderer.
+ bool will_send_activation_to_renderer_ = false;
+
base::WeakPtrFactory<ActivationStateComputingNavigationThrottle>
weak_ptr_factory_;
diff --git a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc
new file mode 100644
index 00000000000..4be0506e0e0
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc
@@ -0,0 +1,416 @@
+// 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/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "base/test/test_simple_task_runner.h"
+#include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
+#include "components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h"
+#include "components/subresource_filter/core/common/activation_level.h"
+#include "components/subresource_filter/core/common/activation_state.h"
+#include "components/subresource_filter/core/common/proto/rules.pb.h"
+#include "components/subresource_filter/core/common/test_ruleset_creator.h"
+#include "components/subresource_filter/core/common/test_ruleset_utils.h"
+#include "content/public/browser/navigation_handle.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"
+
+namespace subresource_filter {
+
+class ActivationStateComputingNavigationThrottleTest
+ : public content::RenderViewHostTestHarness,
+ public content::WebContentsObserver {
+ public:
+ ActivationStateComputingNavigationThrottleTest() {}
+ ~ActivationStateComputingNavigationThrottleTest() override {}
+
+ void SetUp() override {
+ content::RenderViewHostTestHarness::SetUp();
+ NavigateAndCommit(GURL("https://example.first"));
+ InitializeRuleset();
+ Observe(RenderViewHostTestHarness::web_contents());
+ }
+
+ void TearDown() override {
+ ruleset_handle_.reset();
+ dealer_handle_.reset();
+ RunUntilIdle();
+ content::RenderViewHostTestHarness::TearDown();
+ }
+
+ void InitializeRuleset() {
+ std::vector<proto::UrlRule> rules;
+ rules.push_back(testing::CreateWhitelistRuleForDocument(
+ "whitelisted.com", proto::ACTIVATION_TYPE_DOCUMENT,
+ {"allow-child-to-be-whitelisted.com",
+ "whitelisted-generic-with-disabled-child.com"}));
+
+ rules.push_back(testing::CreateWhitelistRuleForDocument(
+ "whitelisted-generic.com", proto::ACTIVATION_TYPE_GENERICBLOCK,
+ {"allow-child-to-be-whitelisted.com"}));
+
+ rules.push_back(testing::CreateWhitelistRuleForDocument(
+ "whitelisted-generic-with-disabled-child.com",
+ proto::ACTIVATION_TYPE_GENERICBLOCK,
+ {"allow-child-to-be-whitelisted.com"}));
+
+ rules.push_back(testing::CreateWhitelistRuleForDocument(
+ "whitelisted-always.com", proto::ACTIVATION_TYPE_DOCUMENT));
+
+ ASSERT_NO_FATAL_FAILURE(test_ruleset_creator_.CreateRulesetWithRules(
+ rules, &test_ruleset_pair_));
+
+ // Make the blocking task runner run on the current task runner for the
+ // tests, to ensure that the NavigationSimulator properly runs all necessary
+ // tasks while waiting for throttle checks to finish.
+ dealer_handle_ = base::MakeUnique<VerifiedRulesetDealer::Handle>(
+ base::MessageLoop::current()->task_runner());
+ dealer_handle_->SetRulesetFile(
+ testing::TestRuleset::Open(test_ruleset_pair_.indexed));
+ ruleset_handle_ =
+ base::MakeUnique<VerifiedRuleset::Handle>(dealer_handle_.get());
+ }
+
+ void NavigateAndCommitMainFrameWithPageActivationState(
+ const GURL& document_url,
+ const ActivationState& page_activation) {
+ CreateTestNavigationForMainFrame(document_url);
+ SimulateStartAndExpectToProceed();
+
+ NotifyPageActivation(page_activation);
+ SimulateCommitAndExpectToProceed();
+ }
+
+ void RunUntilIdle() { base::RunLoop().RunUntilIdle(); }
+
+ void CreateTestNavigationForMainFrame(const GURL& first_url) {
+ navigation_simulator_ =
+ content::NavigationSimulator::CreateRendererInitiated(first_url,
+ main_rfh());
+ }
+
+ void CreateSubframeAndInitTestNavigation(
+ const GURL& first_url,
+ content::RenderFrameHost* parent,
+ const ActivationState& parent_activation_state) {
+ ASSERT_TRUE(parent);
+ parent_activation_state_ = parent_activation_state;
+ content::RenderFrameHost* navigating_subframe =
+ content::RenderFrameHostTester::For(parent)->AppendChild("subframe");
+ navigation_simulator_ =
+ content::NavigationSimulator::CreateRendererInitiated(
+ first_url, navigating_subframe);
+ }
+
+ void SimulateStartAndExpectToProceed() {
+ ASSERT_TRUE(navigation_simulator_);
+ navigation_simulator_->Start();
+ EXPECT_EQ(content::NavigationThrottle::PROCEED,
+ navigation_simulator_->GetLastThrottleCheckResult());
+ }
+
+ void SimulateRedirectAndExpectToProceed(const GURL& new_url) {
+ navigation_simulator_->Redirect(new_url);
+ EXPECT_EQ(content::NavigationThrottle::PROCEED,
+ navigation_simulator_->GetLastThrottleCheckResult());
+ }
+
+ void SimulateCommitAndExpectToProceed() {
+ navigation_simulator_->Commit();
+ EXPECT_EQ(content::NavigationThrottle::PROCEED,
+ navigation_simulator_->GetLastThrottleCheckResult());
+ }
+
+ void NotifyPageActivation(ActivationState state) {
+ test_throttle_->NotifyPageActivationWithRuleset(
+ state.activation_level == ActivationLevel::DISABLED
+ ? nullptr
+ : ruleset_handle_.get(),
+ state);
+ }
+
+ ActivationState last_activation_state() {
+ EXPECT_TRUE(last_activation_state_.has_value());
+ return last_activation_state_.value_or(
+ ActivationState(ActivationLevel::DISABLED));
+ }
+
+ content::RenderFrameHost* last_committed_frame_host() {
+ return last_committed_frame_host_;
+ }
+
+ protected:
+ // content::WebContentsObserver:
+ void DidStartNavigation(
+ content::NavigationHandle* navigation_handle) override {
+ std::unique_ptr<ActivationStateComputingNavigationThrottle> throttle =
+ navigation_handle->IsInMainFrame()
+ ? ActivationStateComputingNavigationThrottle::CreateForMainFrame(
+ navigation_handle)
+ : ActivationStateComputingNavigationThrottle::CreateForSubframe(
+ navigation_handle, ruleset_handle_.get(),
+ parent_activation_state_.value());
+ test_throttle_ = throttle.get();
+ navigation_handle->RegisterThrottleForTesting(std::move(throttle));
+ }
+
+ void ReadyToCommitNavigation(
+ content::NavigationHandle* navigation_handle) override {
+ if (!test_throttle_)
+ return;
+ ASSERT_EQ(navigation_handle, test_throttle_->navigation_handle());
+ if (test_throttle_->filter())
+ test_throttle_->WillSendActivationToRenderer();
+
+ if (auto filter = test_throttle_->ReleaseFilter()) {
+ EXPECT_NE(ActivationLevel::DISABLED,
+ filter->activation_state().activation_level);
+ last_activation_state_ = filter->activation_state();
+ } else {
+ last_activation_state_ = ActivationState(ActivationLevel::DISABLED);
+ }
+ }
+
+ void DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) override {
+ if (!test_throttle_)
+ return;
+ last_committed_frame_host_ = navigation_handle->GetRenderFrameHost();
+ test_throttle_ = nullptr;
+ }
+
+ private:
+ testing::TestRulesetCreator test_ruleset_creator_;
+ testing::TestRulesetPair test_ruleset_pair_;
+
+ std::unique_ptr<VerifiedRulesetDealer::Handle> dealer_handle_;
+ std::unique_ptr<VerifiedRuleset::Handle> ruleset_handle_;
+
+ std::unique_ptr<content::NavigationSimulator> navigation_simulator_;
+
+ // Owned by the current navigation.
+ ActivationStateComputingNavigationThrottle* test_throttle_;
+ base::Optional<ActivationState> last_activation_state_;
+ base::Optional<ActivationState> parent_activation_state_;
+
+ // Needed for potential cross process navigations which swap hosts.
+ content::RenderFrameHost* last_committed_frame_host_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(ActivationStateComputingNavigationThrottleTest);
+};
+
+typedef ActivationStateComputingNavigationThrottleTest
+ ActivationStateComputingThrottleMainFrameTest;
+typedef ActivationStateComputingNavigationThrottleTest
+ ActivationStateComputingThrottleSubFrameTest;
+
+TEST_F(ActivationStateComputingThrottleMainFrameTest, Activate) {
+ NavigateAndCommitMainFrameWithPageActivationState(
+ GURL("http://example.test/"), ActivationState(ActivationLevel::ENABLED));
+ ActivationState state = last_activation_state();
+ EXPECT_EQ(ActivationLevel::ENABLED, state.activation_level);
+ EXPECT_FALSE(state.filtering_disabled_for_document);
+}
+
+TEST_F(ActivationStateComputingThrottleMainFrameTest,
+ NoPageActivationNotification_NoActivation) {
+ CreateTestNavigationForMainFrame(GURL("http://example.test/"));
+ SimulateStartAndExpectToProceed();
+ SimulateRedirectAndExpectToProceed(GURL("http://example.test/?v=1"));
+
+ // Never send NotifyPageActivation.
+ SimulateCommitAndExpectToProceed();
+
+ ActivationState state = last_activation_state();
+ EXPECT_EQ(ActivationLevel::DISABLED, state.activation_level);
+}
+
+TEST_F(ActivationStateComputingThrottleMainFrameTest,
+ DisabledPageActivation_NoActivation) {
+ // Notify that the page level activation is explicitly disabled. Should be
+ // equivalent to not sending the message at all to the main frame throttle.
+ NavigateAndCommitMainFrameWithPageActivationState(
+ GURL("http://example.test/"), ActivationState(ActivationLevel::DISABLED));
+ ActivationState state = last_activation_state();
+ EXPECT_EQ(ActivationLevel::DISABLED, state.activation_level);
+}
+
+TEST_F(ActivationStateComputingThrottleMainFrameTest,
+ WhitelistDoesNotApply_CausesActivation) {
+ NavigateAndCommitMainFrameWithPageActivationState(
+ GURL("http://allow-child-to-be-whitelisted.com/"),
+ ActivationState(ActivationLevel::ENABLED));
+
+ NavigateAndCommitMainFrameWithPageActivationState(
+ GURL("http://whitelisted.com/"),
+ ActivationState(ActivationLevel::ENABLED));
+
+ ActivationState state = last_activation_state();
+ EXPECT_FALSE(state.filtering_disabled_for_document);
+ EXPECT_FALSE(state.generic_blocking_rules_disabled);
+ EXPECT_EQ(ActivationLevel::ENABLED, state.activation_level);
+}
+
+TEST_F(ActivationStateComputingThrottleMainFrameTest,
+ Whitelisted_DisablesFiltering) {
+ NavigateAndCommitMainFrameWithPageActivationState(
+ GURL("http://whitelisted-always.com/"),
+ ActivationState(ActivationLevel::ENABLED));
+
+ ActivationState state = last_activation_state();
+ EXPECT_TRUE(state.filtering_disabled_for_document);
+ EXPECT_FALSE(state.generic_blocking_rules_disabled);
+ EXPECT_EQ(ActivationLevel::ENABLED, state.activation_level);
+}
+
+TEST_F(ActivationStateComputingThrottleSubFrameTest, Activate) {
+ NavigateAndCommitMainFrameWithPageActivationState(
+ GURL("http://example.test/"), ActivationState(ActivationLevel::ENABLED));
+
+ CreateSubframeAndInitTestNavigation(GURL("http://example.child/"),
+ last_committed_frame_host(),
+ last_activation_state());
+ SimulateStartAndExpectToProceed();
+ SimulateRedirectAndExpectToProceed(GURL("http://example.child/?v=1"));
+ SimulateCommitAndExpectToProceed();
+
+ ActivationState state = last_activation_state();
+ EXPECT_EQ(ActivationLevel::ENABLED, state.activation_level);
+ EXPECT_FALSE(state.filtering_disabled_for_document);
+ EXPECT_FALSE(state.generic_blocking_rules_disabled);
+}
+
+TEST_F(ActivationStateComputingThrottleSubFrameTest,
+ WhitelistDoesNotApply_CausesActivation) {
+ NavigateAndCommitMainFrameWithPageActivationState(
+ GURL("http://disallows-child-to-be-whitelisted.com/"),
+ ActivationState(ActivationLevel::ENABLED));
+
+ CreateSubframeAndInitTestNavigation(GURL("http://whitelisted.com/"),
+ last_committed_frame_host(),
+ last_activation_state());
+ SimulateStartAndExpectToProceed();
+ SimulateCommitAndExpectToProceed();
+
+ ActivationState state = last_activation_state();
+ EXPECT_EQ(ActivationLevel::ENABLED, state.activation_level);
+ EXPECT_FALSE(state.filtering_disabled_for_document);
+ EXPECT_FALSE(state.generic_blocking_rules_disabled);
+}
+
+TEST_F(ActivationStateComputingThrottleSubFrameTest,
+ Whitelisted_DisableDocumentFiltering) {
+ NavigateAndCommitMainFrameWithPageActivationState(
+ GURL("http://allow-child-to-be-whitelisted.com/"),
+ ActivationState(ActivationLevel::ENABLED));
+
+ CreateSubframeAndInitTestNavigation(GURL("http://whitelisted.com/"),
+ last_committed_frame_host(),
+ last_activation_state());
+ SimulateStartAndExpectToProceed();
+ SimulateCommitAndExpectToProceed();
+
+ ActivationState state = last_activation_state();
+ EXPECT_TRUE(state.filtering_disabled_for_document);
+ EXPECT_FALSE(state.generic_blocking_rules_disabled);
+ EXPECT_EQ(ActivationLevel::ENABLED, state.activation_level);
+}
+
+TEST_F(ActivationStateComputingThrottleSubFrameTest,
+ Whitelisted_DisablesGenericRules) {
+ NavigateAndCommitMainFrameWithPageActivationState(
+ GURL("http://allow-child-to-be-whitelisted.com/"),
+ ActivationState(ActivationLevel::ENABLED));
+
+ CreateSubframeAndInitTestNavigation(GURL("http://whitelisted-generic.com/"),
+ last_committed_frame_host(),
+ last_activation_state());
+ SimulateStartAndExpectToProceed();
+ SimulateCommitAndExpectToProceed();
+
+ ActivationState state = last_activation_state();
+ EXPECT_FALSE(state.filtering_disabled_for_document);
+ EXPECT_TRUE(state.generic_blocking_rules_disabled);
+ EXPECT_EQ(ActivationLevel::ENABLED, state.activation_level);
+}
+
+TEST_F(ActivationStateComputingThrottleSubFrameTest, DryRunIsPropagated) {
+ NavigateAndCommitMainFrameWithPageActivationState(
+ GURL("http://example.test/"), ActivationState(ActivationLevel::DRYRUN));
+ EXPECT_EQ(ActivationLevel::DRYRUN, last_activation_state().activation_level);
+
+ CreateSubframeAndInitTestNavigation(GURL("http://example.child/"),
+ last_committed_frame_host(),
+ last_activation_state());
+ SimulateStartAndExpectToProceed();
+ SimulateRedirectAndExpectToProceed(GURL("http://example.child/?v=1"));
+ SimulateCommitAndExpectToProceed();
+
+ ActivationState state = last_activation_state();
+ EXPECT_EQ(ActivationLevel::DRYRUN, state.activation_level);
+ EXPECT_FALSE(state.filtering_disabled_for_document);
+ EXPECT_FALSE(state.generic_blocking_rules_disabled);
+}
+
+TEST_F(ActivationStateComputingThrottleSubFrameTest, DisabledStatePropagated) {
+ NavigateAndCommitMainFrameWithPageActivationState(
+ GURL("http://allow-child-to-be-whitelisted.com/"),
+ ActivationState(ActivationLevel::ENABLED));
+
+ CreateSubframeAndInitTestNavigation(GURL("http://whitelisted.com"),
+ last_committed_frame_host(),
+ last_activation_state());
+ SimulateStartAndExpectToProceed();
+ SimulateCommitAndExpectToProceed();
+
+ CreateSubframeAndInitTestNavigation(GURL("http://example.test/"),
+ last_committed_frame_host(),
+ last_activation_state());
+ SimulateStartAndExpectToProceed();
+ SimulateCommitAndExpectToProceed();
+
+ ActivationState state = last_activation_state();
+ EXPECT_EQ(ActivationLevel::ENABLED, state.activation_level);
+ EXPECT_TRUE(state.filtering_disabled_for_document);
+ EXPECT_FALSE(state.generic_blocking_rules_disabled);
+}
+
+TEST_F(ActivationStateComputingThrottleSubFrameTest, DisabledStatePropagated2) {
+ NavigateAndCommitMainFrameWithPageActivationState(
+ GURL("http://allow-child-to-be-whitelisted.com/"),
+ ActivationState(ActivationLevel::ENABLED));
+
+ CreateSubframeAndInitTestNavigation(
+ GURL("http://whitelisted-generic-with-disabled-child.com/"),
+ last_committed_frame_host(), last_activation_state());
+ SimulateStartAndExpectToProceed();
+ SimulateCommitAndExpectToProceed();
+
+ ActivationState state = last_activation_state();
+ EXPECT_FALSE(state.filtering_disabled_for_document);
+ EXPECT_TRUE(state.generic_blocking_rules_disabled);
+
+ CreateSubframeAndInitTestNavigation(GURL("http://whitelisted.com/"),
+ last_committed_frame_host(),
+ last_activation_state());
+ SimulateStartAndExpectToProceed();
+ SimulateCommitAndExpectToProceed();
+
+ state = last_activation_state();
+ EXPECT_EQ(ActivationLevel::ENABLED, state.activation_level);
+ EXPECT_TRUE(state.filtering_disabled_for_document);
+ EXPECT_TRUE(state.generic_blocking_rules_disabled);
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/async_document_subresource_filter.cc b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter.cc
index 099eec14aae..3d804da57d5 100644
--- a/chromium/components/subresource_filter/content/browser/async_document_subresource_filter.cc
+++ b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter.cc
@@ -53,12 +53,10 @@ InitializationParams& InitializationParams::operator=(InitializationParams&&) =
AsyncDocumentSubresourceFilter::AsyncDocumentSubresourceFilter(
VerifiedRuleset::Handle* ruleset_handle,
InitializationParams params,
- base::Callback<void(ActivationState)> activation_state_callback,
- base::OnceClosure first_disallowed_load_callback)
+ base::Callback<void(ActivationState)> activation_state_callback)
: task_runner_(ruleset_handle->task_runner()),
core_(new Core(), base::OnTaskRunnerDeleter(task_runner_)),
- first_disallowed_load_callback_(
- std::move(first_disallowed_load_callback)) {
+ weak_ptr_factory_(this) {
DCHECK_NE(ActivationLevel::DISABLED,
params.parent_activation_state.activation_level);
@@ -70,17 +68,26 @@ AsyncDocumentSubresourceFilter::AsyncDocumentSubresourceFilter(
task_runner_, FROM_HERE,
base::Bind(&Core::Initialize, base::Unretained(core_.get()),
base::Passed(&params), ruleset_handle->ruleset_.get()),
- std::move(activation_state_callback));
+ base::Bind(&AsyncDocumentSubresourceFilter::OnActivateStateCalculated,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(activation_state_callback)));
}
AsyncDocumentSubresourceFilter::~AsyncDocumentSubresourceFilter() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+}
+
+void AsyncDocumentSubresourceFilter::OnActivateStateCalculated(
+ base::Callback<void(ActivationState)> activation_state_callback,
+ ActivationState activation_state) {
+ activation_state_ = activation_state;
+ activation_state_callback.Run(activation_state);
}
void AsyncDocumentSubresourceFilter::GetLoadPolicyForSubdocument(
const GURL& subdocument_url,
LoadPolicyCallback result_callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
// TODO(pkalinnikov): Think about avoiding copy of |subdocument_url| if it is
// too big and won't be allowed anyway (e.g., it's a data: URI).
@@ -108,17 +115,17 @@ void AsyncDocumentSubresourceFilter::ReportDisallowedLoad() {
// AsyncDocumentSubresourceFilter::Core ----------------------------------------
AsyncDocumentSubresourceFilter::Core::Core() {
- thread_checker_.DetachFromThread();
+ sequence_checker_.DetachFromSequence();
}
AsyncDocumentSubresourceFilter::Core::~Core() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
}
ActivationState AsyncDocumentSubresourceFilter::Core::Initialize(
InitializationParams params,
VerifiedRuleset* verified_ruleset) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
DCHECK(verified_ruleset);
if (!verified_ruleset->Get())
diff --git a/chromium/components/subresource_filter/content/browser/async_document_subresource_filter.h b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter.h
index 3d4c9dd3f33..b96e827d398 100644
--- a/chromium/components/subresource_filter/content/browser/async_document_subresource_filter.h
+++ b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter.h
@@ -10,8 +10,8 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/optional.h"
+#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
-#include "base/threading/thread_checker.h"
#include "components/subresource_filter/content/browser/verified_ruleset_dealer.h"
#include "components/subresource_filter/core/common/activation_level.h"
#include "components/subresource_filter/core/common/activation_state.h"
@@ -82,14 +82,10 @@ class AsyncDocumentSubresourceFilter {
// with the current thread. If MemoryMappedRuleset is not present or
// malformed, then a default ActivationState is reported (with ActivationLevel
// equal to DISABLED).
- //
- // The |first_disallowed_load_callback|, if it is non-null, is invoked on the
- // first ReportDisallowedLoad() call.
AsyncDocumentSubresourceFilter(
VerifiedRuleset::Handle* ruleset_handle,
InitializationParams params,
- base::Callback<void(ActivationState)> activation_state_callback,
- base::OnceClosure first_disallowed_load_callback);
+ base::Callback<void(ActivationState)> activation_state_callback);
~AsyncDocumentSubresourceFilter();
@@ -104,13 +100,32 @@ class AsyncDocumentSubresourceFilter {
// |task_runner|.
void ReportDisallowedLoad();
+ // Must be called after activation state computation is finished.
+ const ActivationState& activation_state() const {
+ return activation_state_.value();
+ }
+
+ // The |first_disallowed_load_callback|, if it is non-null, is invoked on the
+ // first ReportDisallowedLoad() call.
+ void set_first_disallowed_load_callback(base::OnceClosure callback) {
+ first_disallowed_load_callback_ = std::move(callback);
+ }
+
private:
+ void OnActivateStateCalculated(
+ base::Callback<void(ActivationState)> activation_state_callback,
+ ActivationState activation_state);
+
// Note: Raw pointer, |core_| already holds a reference to |task_runner_|.
base::SequencedTaskRunner* task_runner_;
std::unique_ptr<Core, base::OnTaskRunnerDeleter> core_;
base::OnceClosure first_disallowed_load_callback_;
- base::ThreadChecker thread_checker_;
+ base::Optional<ActivationState> activation_state_;
+
+ base::SequenceChecker sequence_checker_;
+
+ base::WeakPtrFactory<AsyncDocumentSubresourceFilter> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(AsyncDocumentSubresourceFilter);
};
@@ -125,7 +140,7 @@ class AsyncDocumentSubresourceFilter::Core {
// Can return nullptr even after initialization in case MemoryMappedRuleset
// was not present, or was malformed during it.
DocumentSubresourceFilter* filter() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
return filter_ ? &filter_.value() : nullptr;
}
@@ -138,7 +153,7 @@ class AsyncDocumentSubresourceFilter::Core {
VerifiedRuleset* verified_ruleset);
base::Optional<DocumentSubresourceFilter> filter_;
- base::ThreadChecker thread_checker_;
+ base::SequenceChecker sequence_checker_;
DISALLOW_COPY_AND_ASSIGN(Core);
};
diff --git a/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.cc b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.cc
new file mode 100644
index 00000000000..34627e0dded
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.cc
@@ -0,0 +1,48 @@
+// 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/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace subresource_filter {
+namespace testing {
+
+TestActivationStateCallbackReceiver::TestActivationStateCallbackReceiver() =
+ default;
+TestActivationStateCallbackReceiver::~TestActivationStateCallbackReceiver() =
+ default;
+
+base::Callback<void(ActivationState)>
+TestActivationStateCallbackReceiver::GetCallback() {
+ return base::Bind(&TestActivationStateCallbackReceiver::Callback,
+ base::Unretained(this));
+}
+
+void TestActivationStateCallbackReceiver::WaitForActivationDecision() {
+ ASSERT_EQ(0, callback_count_);
+ base::RunLoop run_loop;
+ quit_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+}
+
+void TestActivationStateCallbackReceiver::ExpectReceivedOnce(
+ const ActivationState& expected_state) const {
+ ASSERT_EQ(1, callback_count_);
+ EXPECT_EQ(expected_state, last_activation_state_);
+}
+
+void TestActivationStateCallbackReceiver::Callback(
+ ActivationState activation_state) {
+ ++callback_count_;
+ last_activation_state_ = activation_state;
+ if (quit_closure_)
+ quit_closure_.Run();
+}
+
+} // namespace testing
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h
new file mode 100644
index 00000000000..4858adde5ef
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h
@@ -0,0 +1,42 @@
+// 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_SUBRESOURCE_FILTER_CONTENT_BROWSER_ASYNC_DOCUMENT_SUBRESOURCE_FILTER_TEST_UTILS_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_ASYNC_DOCUMENT_SUBRESOURCE_FILTER_TEST_UTILS_H_
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "components/subresource_filter/core/common/activation_state.h"
+
+namespace subresource_filter {
+namespace testing {
+
+// This test class is intended to be used in conjunction with an
+// AsyncDocumentSubresourceFilter, and can be used to expect a certain
+// activation result occured.
+class TestActivationStateCallbackReceiver {
+ public:
+ TestActivationStateCallbackReceiver();
+ ~TestActivationStateCallbackReceiver();
+
+ base::Callback<void(ActivationState)> GetCallback();
+ void WaitForActivationDecision();
+ void ExpectReceivedOnce(const ActivationState& expected_state) const;
+
+ private:
+ void Callback(ActivationState activation_state);
+
+ ActivationState last_activation_state_;
+ int callback_count_ = 0;
+
+ base::Closure quit_closure_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestActivationStateCallbackReceiver);
+};
+
+} // namespace testing
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_ASYNC_DOCUMENT_SUBRESOURCE_FILTER_TEST_UTILS_H_
diff --git a/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_unittest.cc b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_unittest.cc
index d8c7ea12871..88a08629c34 100644
--- a/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_unittest.cc
@@ -15,6 +15,7 @@
#include "base/run_loop.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h"
#include "components/subresource_filter/core/common/proto/rules.pb.h"
#include "components/subresource_filter/core/common/test_ruleset_creator.h"
#include "components/subresource_filter/core/common/test_ruleset_utils.h"
@@ -84,36 +85,14 @@ class AsyncDocumentSubresourceFilterTest : public ::testing::Test {
namespace {
-class TestActivationStateCallbackReceiver {
- public:
- TestActivationStateCallbackReceiver() = default;
-
- base::Callback<void(ActivationState)> callback() {
- return base::Bind(&TestActivationStateCallbackReceiver::Callback,
- base::Unretained(this));
- }
- void ExpectReceivedOnce(ActivationState expected_state) const {
- ASSERT_EQ(1, callback_count_);
- EXPECT_EQ(expected_state, last_activation_state_);
- }
-
- private:
- void Callback(ActivationState activation_state) {
- ++callback_count_;
- last_activation_state_ = activation_state;
- }
-
- ActivationState last_activation_state_;
- int callback_count_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(TestActivationStateCallbackReceiver);
-};
-
+// TODO(csharrison): If more consumers need to test these callbacks at this
+// granularity, consider moving these classes into
+// async_document_subresource_filter_test_utils.
class TestCallbackReceiver {
public:
TestCallbackReceiver() = default;
- base::Closure closure() {
+ base::Closure GetClosure() {
return base::Bind(&TestCallbackReceiver::Callback, base::Unretained(this));
}
int callback_count() const { return callback_count_; }
@@ -130,7 +109,7 @@ class LoadPolicyCallbackReceiver {
public:
LoadPolicyCallbackReceiver() = default;
- AsyncDocumentSubresourceFilter::LoadPolicyCallback callback() {
+ AsyncDocumentSubresourceFilter::LoadPolicyCallback GetCallback() {
return base::Bind(&LoadPolicyCallbackReceiver::Callback,
base::Unretained(this));
}
@@ -160,10 +139,9 @@ TEST_F(AsyncDocumentSubresourceFilterTest, ActivationStateIsReported) {
AsyncDocumentSubresourceFilter::InitializationParams params(
GURL("http://example.com"), ActivationLevel::ENABLED, false);
- TestActivationStateCallbackReceiver activation_state;
+ testing::TestActivationStateCallbackReceiver activation_state;
auto filter = base::MakeUnique<AsyncDocumentSubresourceFilter>(
- ruleset_handle.get(), std::move(params), activation_state.callback(),
- base::OnceClosure());
+ ruleset_handle.get(), std::move(params), activation_state.GetCallback());
RunUntilIdle();
activation_state.ExpectReceivedOnce(
@@ -178,10 +156,9 @@ TEST_F(AsyncDocumentSubresourceFilterTest, ActivationStateIsComputedCorrectly) {
GURL("http://whitelisted.subframe.com"), ActivationLevel::ENABLED, false);
params.parent_document_origin = url::Origin(GURL("http://example.com"));
- TestActivationStateCallbackReceiver activation_state;
+ testing::TestActivationStateCallbackReceiver activation_state;
auto filter = base::MakeUnique<AsyncDocumentSubresourceFilter>(
- ruleset_handle.get(), std::move(params), activation_state.callback(),
- base::OnceClosure());
+ ruleset_handle.get(), std::move(params), activation_state.GetCallback());
RunUntilIdle();
@@ -199,10 +176,9 @@ TEST_F(AsyncDocumentSubresourceFilterTest, DisabledForCorruptRuleset) {
AsyncDocumentSubresourceFilter::InitializationParams params(
GURL("http://example.com"), ActivationLevel::ENABLED, false);
- TestActivationStateCallbackReceiver activation_state;
+ testing::TestActivationStateCallbackReceiver activation_state;
auto filter = base::MakeUnique<AsyncDocumentSubresourceFilter>(
- ruleset_handle.get(), std::move(params), activation_state.callback(),
- base::OnceClosure());
+ ruleset_handle.get(), std::move(params), activation_state.GetCallback());
RunUntilIdle();
activation_state.ExpectReceivedOnce(
@@ -216,17 +192,16 @@ TEST_F(AsyncDocumentSubresourceFilterTest, GetLoadPolicyForSubdocument) {
AsyncDocumentSubresourceFilter::InitializationParams params(
GURL("http://example.com"), ActivationLevel::ENABLED, false);
- TestActivationStateCallbackReceiver activation_state;
+ testing::TestActivationStateCallbackReceiver activation_state;
auto filter = base::MakeUnique<AsyncDocumentSubresourceFilter>(
- ruleset_handle.get(), std::move(params), activation_state.callback(),
- base::OnceClosure());
+ ruleset_handle.get(), std::move(params), activation_state.GetCallback());
LoadPolicyCallbackReceiver load_policy_1;
LoadPolicyCallbackReceiver load_policy_2;
filter->GetLoadPolicyForSubdocument(GURL("http://example.com/allowed.html"),
- load_policy_1.callback());
+ load_policy_1.GetCallback());
filter->GetLoadPolicyForSubdocument(
- GURL("http://example.com/disallowed.html"), load_policy_2.callback());
+ GURL("http://example.com/disallowed.html"), load_policy_2.GetCallback());
RunUntilIdle();
load_policy_1.ExpectReceivedOnce(LoadPolicy::ALLOW);
@@ -241,21 +216,22 @@ TEST_F(AsyncDocumentSubresourceFilterTest, FirstDisallowedLoadIsReported) {
AsyncDocumentSubresourceFilter::InitializationParams params(
GURL("http://example.com"), ActivationLevel::ENABLED, false);
- TestActivationStateCallbackReceiver activation_state;
+ testing::TestActivationStateCallbackReceiver activation_state;
auto filter = base::MakeUnique<AsyncDocumentSubresourceFilter>(
- ruleset_handle.get(), std::move(params), activation_state.callback(),
- first_disallowed_load_receiver.closure());
+ ruleset_handle.get(), std::move(params), activation_state.GetCallback());
+ filter->set_first_disallowed_load_callback(
+ first_disallowed_load_receiver.GetClosure());
LoadPolicyCallbackReceiver load_policy_1;
filter->GetLoadPolicyForSubdocument(GURL("http://example.com/allowed.html"),
- load_policy_1.callback());
+ load_policy_1.GetCallback());
RunUntilIdle();
load_policy_1.ExpectReceivedOnce(LoadPolicy::ALLOW);
EXPECT_EQ(0, first_disallowed_load_receiver.callback_count());
LoadPolicyCallbackReceiver load_policy_2;
filter->GetLoadPolicyForSubdocument(
- GURL("http://example.com/disallowed.html"), load_policy_2.callback());
+ GURL("http://example.com/disallowed.html"), load_policy_2.GetCallback());
RunUntilIdle();
load_policy_2.ExpectReceivedOnce(LoadPolicy::DISALLOW);
EXPECT_EQ(0, first_disallowed_load_receiver.callback_count());
diff --git a/chromium/components/subresource_filter/content/browser/content_activation_list_utils.cc b/chromium/components/subresource_filter/content/browser/content_activation_list_utils.cc
new file mode 100644
index 00000000000..bff2cef641d
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/content_activation_list_utils.cc
@@ -0,0 +1,31 @@
+// 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/subresource_filter/content/browser/content_activation_list_utils.h"
+
+namespace subresource_filter {
+
+ActivationList GetListForThreatTypeAndMetadata(
+ safe_browsing::SBThreatType threat_type,
+ safe_browsing::ThreatPatternType threat_type_metadata) {
+ bool is_phishing_interstitial =
+ (threat_type == safe_browsing::SB_THREAT_TYPE_URL_PHISHING);
+ bool is_soc_engineering_ads_interstitial =
+ threat_type_metadata ==
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS;
+ bool subresource_filter =
+ (threat_type == safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER);
+ if (is_phishing_interstitial) {
+ if (is_soc_engineering_ads_interstitial) {
+ return ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL;
+ }
+ return ActivationList::PHISHING_INTERSTITIAL;
+ } else if (subresource_filter) {
+ return ActivationList::SUBRESOURCE_FILTER;
+ }
+
+ return ActivationList::NONE;
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/content_activation_list_utils.h b/chromium/components/subresource_filter/content/browser/content_activation_list_utils.h
new file mode 100644
index 00000000000..dc23a48b4d9
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/content_activation_list_utils.h
@@ -0,0 +1,19 @@
+// 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_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_ACTIVATION_LIST_UTILS_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_ACTIVATION_LIST_UTILS_H_
+
+#include "components/safe_browsing_db/util.h"
+#include "components/subresource_filter/core/common/activation_list.h"
+
+namespace subresource_filter {
+
+ActivationList GetListForThreatTypeAndMetadata(
+ safe_browsing::SBThreatType threat_type,
+ safe_browsing::ThreatPatternType threat_type_metadata);
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_ACTIVATION_LIST_UTILS_H_
diff --git a/chromium/components/subresource_filter/content/browser/content_ruleset_service_delegate.cc b/chromium/components/subresource_filter/content/browser/content_ruleset_service.cc
index 079798aaf55..72a5734ac46 100644
--- a/chromium/components/subresource_filter/content/browser/content_ruleset_service_delegate.cc
+++ b/chromium/components/subresource_filter/content/browser/content_ruleset_service.cc
@@ -2,13 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/subresource_filter/content/browser/content_ruleset_service_delegate.h"
+#include "components/subresource_filter/content/browser/content_ruleset_service.h"
#include <utility>
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "components/subresource_filter/content/common/subresource_filter_messages.h"
+#include "components/subresource_filter/core/browser/ruleset_service.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
@@ -42,7 +44,10 @@ void CloseFileOnFileThread(base::File* file) {
} // namespace
-ContentRulesetServiceDelegate::ContentRulesetServiceDelegate() {
+ContentRulesetService::ContentRulesetService(
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
+ : ruleset_dealer_(base::MakeUnique<VerifiedRulesetDealer::Handle>(
+ std::move(blocking_task_runner))) {
// Must rely on notifications as RenderProcessHostObserver::RenderProcessReady
// would only be called after queued IPC messages (potentially triggering a
// navigation) had already been sent to the new renderer.
@@ -51,26 +56,31 @@ ContentRulesetServiceDelegate::ContentRulesetServiceDelegate() {
content::NotificationService::AllBrowserContextsAndSources());
}
-ContentRulesetServiceDelegate::~ContentRulesetServiceDelegate() {
+ContentRulesetService::~ContentRulesetService() {
CloseFileOnFileThread(&ruleset_data_);
}
-void ContentRulesetServiceDelegate::SetRulesetPublishedCallbackForTesting(
+void ContentRulesetService::SetRulesetPublishedCallbackForTesting(
base::Closure callback) {
ruleset_published_callback_ = callback;
}
-void ContentRulesetServiceDelegate::PostAfterStartupTask(base::Closure task) {
+void ContentRulesetService::PostAfterStartupTask(base::Closure task) {
content::BrowserThread::PostAfterStartupTask(
- FROM_HERE, content::BrowserThread::GetTaskRunnerForThread(
- content::BrowserThread::UI),
+ FROM_HERE,
+ content::BrowserThread::GetTaskRunnerForThread(
+ content::BrowserThread::UI),
task);
}
-void ContentRulesetServiceDelegate::PublishNewRulesetVersion(
- base::File ruleset_data) {
+void ContentRulesetService::PublishNewRulesetVersion(base::File ruleset_data) {
DCHECK(ruleset_data.IsValid());
CloseFileOnFileThread(&ruleset_data_);
+
+ // Will not perform verification until the ruleset is retrieved the first
+ // time.
+ ruleset_dealer_->SetRulesetFile(ruleset_data.Duplicate());
+
ruleset_data_ = std::move(ruleset_data);
for (auto it = content::RenderProcessHost::AllHostsIterator(); !it.IsAtEnd();
it.Advance()) {
@@ -81,7 +91,19 @@ void ContentRulesetServiceDelegate::PublishNewRulesetVersion(
ruleset_published_callback_.Run();
}
-void ContentRulesetServiceDelegate::Observe(
+void ContentRulesetService::set_ruleset_service(
+ std::unique_ptr<RulesetService> ruleset_service) {
+ ruleset_service_ = std::move(ruleset_service);
+}
+
+void ContentRulesetService::IndexAndStoreAndPublishRulesetIfNeeded(
+ const UnindexedRulesetInfo& unindexed_ruleset_info) {
+ DCHECK(ruleset_service_);
+ ruleset_service_->IndexAndStoreAndPublishRulesetIfNeeded(
+ unindexed_ruleset_info);
+}
+
+void ContentRulesetService::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
diff --git a/chromium/components/subresource_filter/content/browser/content_ruleset_service_delegate.h b/chromium/components/subresource_filter/content/browser/content_ruleset_service.h
index ba5338c6fcd..97c049e14a6 100644
--- a/chromium/components/subresource_filter/content/browser/content_ruleset_service_delegate.h
+++ b/chromium/components/subresource_filter/content/browser/content_ruleset_service.h
@@ -2,19 +2,31 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_RULESET_SERVICE_DELEGATE_H_
-#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_RULESET_SERVICE_DELEGATE_H_
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_RULESET_SERVICE_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_RULESET_SERVICE_H_
+
+#include <memory>
#include "base/callback.h"
#include "base/files/file.h"
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "components/subresource_filter/content/browser/verified_ruleset_dealer.h"
#include "components/subresource_filter/core/browser/ruleset_service_delegate.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
+namespace base {
+class SequencedTaskRunner;
+} // namespace base
+
namespace subresource_filter {
-// The content-layer specific implementation of RulesetServiceDelegate.
+class RulesetService;
+struct UnindexedRulesetInfo;
+
+// The content-layer specific implementation of RulesetServiceDelegate. Owns the
+// underlying RulesetService.
//
// Its main responsibility is receiving new versions of subresource filtering
// rules from the RulesetService, and distributing them to renderer processes,
@@ -42,11 +54,12 @@ namespace subresource_filter {
//
// Note: UnverifiedRulesetDealer is shortened to *RulesetDealer above. There is
// also a VerifiedRulesetDealer which is used similarly on the browser side.
-class ContentRulesetServiceDelegate : public RulesetServiceDelegate,
- content::NotificationObserver {
+class ContentRulesetService : public RulesetServiceDelegate,
+ content::NotificationObserver {
public:
- ContentRulesetServiceDelegate();
- ~ContentRulesetServiceDelegate() override;
+ ContentRulesetService(
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
+ ~ContentRulesetService() override;
void SetRulesetPublishedCallbackForTesting(base::Closure callback);
@@ -54,6 +67,16 @@ class ContentRulesetServiceDelegate : public RulesetServiceDelegate,
void PostAfterStartupTask(base::Closure task) override;
void PublishNewRulesetVersion(base::File ruleset_data) override;
+ void set_ruleset_service(std::unique_ptr<RulesetService> ruleset_service);
+
+ // Forwards calls to the underlying ruleset_service_.
+ void IndexAndStoreAndPublishRulesetIfNeeded(
+ const UnindexedRulesetInfo& unindex_ruleset_info);
+
+ VerifiedRulesetDealer::Handle* ruleset_dealer() {
+ return ruleset_dealer_.get();
+ }
+
private:
// content::NotificationObserver:
void Observe(int type,
@@ -64,9 +87,12 @@ class ContentRulesetServiceDelegate : public RulesetServiceDelegate,
base::File ruleset_data_;
base::Closure ruleset_published_callback_;
- DISALLOW_COPY_AND_ASSIGN(ContentRulesetServiceDelegate);
+ std::unique_ptr<RulesetService> ruleset_service_;
+ std::unique_ptr<VerifiedRulesetDealer::Handle> ruleset_dealer_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentRulesetService);
};
} // namespace subresource_filter
-#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_RULESET_SERVICE_DELEGATE_H_
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_RULESET_SERVICE_H_
diff --git a/chromium/components/subresource_filter/content/browser/content_ruleset_service_delegate_unittest.cc b/chromium/components/subresource_filter/content/browser/content_ruleset_service_unittest.cc
index 643835a65ef..e99b4beeb2b 100644
--- a/chromium/components/subresource_filter/content/browser/content_ruleset_service_delegate_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/content_ruleset_service_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/subresource_filter/content/browser/content_ruleset_service_delegate.h"
+#include "components/subresource_filter/content/browser/content_ruleset_service.h"
#include <stddef.h>
@@ -19,6 +19,7 @@
#include "base/numerics/safe_conversions.h"
#include "base/run_loop.h"
#include "base/task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "components/subresource_filter/content/common/subresource_filter_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
@@ -47,21 +48,21 @@ class TestContentBrowserClient : public ::content::ContentBrowserClient {
// ::content::ContentBrowserClient:
void PostAfterStartupTask(const tracked_objects::Location&,
const scoped_refptr<base::TaskRunner>& task_runner,
- const base::Closure& task) override {
+ base::OnceClosure task) override {
scoped_refptr<base::TaskRunner> ui_task_runner =
content::BrowserThread::GetTaskRunnerForThread(
content::BrowserThread::UI);
EXPECT_EQ(ui_task_runner, task_runner);
- last_task_ = task;
+ last_task_ = std::move(task);
}
void RunAfterStartupTask() {
if (!last_task_.is_null())
- last_task_.Run();
+ std::move(last_task_).Run();
}
private:
- base::Closure last_task_;
+ base::OnceClosure last_task_;
DISALLOW_COPY_AND_ASSIGN(TestContentBrowserClient);
};
@@ -94,10 +95,9 @@ base::File ExtractRulesetFromMessage(const IPC::Message* message) {
} // namespace
-class SubresourceFilterContentRulesetServiceDelegateTest
- : public ::testing::Test {
+class SubresourceFilterContentRulesetServiceTest : public ::testing::Test {
public:
- SubresourceFilterContentRulesetServiceDelegateTest()
+ SubresourceFilterContentRulesetServiceTest()
: old_browser_client_(nullptr), existing_renderer_(&browser_context_) {}
protected:
@@ -134,20 +134,19 @@ class SubresourceFilterContentRulesetServiceDelegateTest
content::TestBrowserContext browser_context_;
NotifyingMockRenderProcessHost existing_renderer_;
- DISALLOW_COPY_AND_ASSIGN(SubresourceFilterContentRulesetServiceDelegateTest);
+ DISALLOW_COPY_AND_ASSIGN(SubresourceFilterContentRulesetServiceTest);
};
-TEST_F(SubresourceFilterContentRulesetServiceDelegateTest,
- NoRuleset_NoIPCMessages) {
+TEST_F(SubresourceFilterContentRulesetServiceTest, NoRuleset_NoIPCMessages) {
NotifyingMockRenderProcessHost existing_renderer(browser_context());
- ContentRulesetServiceDelegate delegate;
+ ContentRulesetService service(base::ThreadTaskRunnerHandle::Get());
NotifyingMockRenderProcessHost new_renderer(browser_context());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0u, existing_renderer.sink().message_count());
EXPECT_EQ(0u, new_renderer.sink().message_count());
}
-TEST_F(SubresourceFilterContentRulesetServiceDelegateTest,
+TEST_F(SubresourceFilterContentRulesetServiceTest,
PublishedRuleset_IsDistributedToExistingAndNewRenderers) {
const char kTestFileContents[] = "foobar";
base::WriteFile(scoped_temp_file(), kTestFileContents,
@@ -158,12 +157,12 @@ TEST_F(SubresourceFilterContentRulesetServiceDelegateTest,
base::File::FLAG_OPEN | base::File::FLAG_READ);
NotifyingMockRenderProcessHost existing_renderer(browser_context());
- ContentRulesetServiceDelegate delegate;
+ ContentRulesetService service(base::ThreadTaskRunnerHandle::Get());
MockClosureTarget publish_callback_target;
- delegate.SetRulesetPublishedCallbackForTesting(base::Bind(
+ service.SetRulesetPublishedCallbackForTesting(base::Bind(
&MockClosureTarget::Call, base::Unretained(&publish_callback_target)));
EXPECT_CALL(publish_callback_target, Call()).Times(1);
- delegate.PublishNewRulesetVersion(std::move(file));
+ service.PublishNewRulesetVersion(std::move(file));
base::RunLoop().RunUntilIdle();
::testing::Mock::VerifyAndClearExpectations(&publish_callback_target);
@@ -179,12 +178,11 @@ TEST_F(SubresourceFilterContentRulesetServiceDelegateTest,
second_renderer.sink().GetMessageAt(0), kTestFileContents));
}
-TEST_F(SubresourceFilterContentRulesetServiceDelegateTest,
- PostAfterStartupTask) {
- ContentRulesetServiceDelegate delegate;
+TEST_F(SubresourceFilterContentRulesetServiceTest, PostAfterStartupTask) {
+ ContentRulesetService service(base::ThreadTaskRunnerHandle::Get());
MockClosureTarget mock_closure_target;
- delegate.PostAfterStartupTask(base::Bind(
+ service.PostAfterStartupTask(base::Bind(
&MockClosureTarget::Call, base::Unretained(&mock_closure_target)));
EXPECT_CALL(mock_closure_target, Call()).Times(1);
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
index 7711de302b3..7ba5c822365 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
@@ -4,15 +4,19 @@
#include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
+#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
#include "base/time/time.h"
+#include "components/subresource_filter/content/browser/content_activation_list_utils.h"
+#include "components/subresource_filter/content/browser/subresource_filter_client.h"
#include "components/subresource_filter/content/common/subresource_filter_messages.h"
-#include "components/subresource_filter/core/browser/subresource_filter_client.h"
#include "components/subresource_filter/core/browser/subresource_filter_features.h"
#include "components/subresource_filter/core/common/activation_list.h"
+#include "components/subresource_filter/core/common/activation_state.h"
#include "components/subresource_filter/core/common/time_measurements.h"
#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/navigation_throttle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "ipc/ipc_message_macros.h"
@@ -30,17 +34,27 @@ std::string DistillURLToHostAndPath(const GURL& url) {
return url.host() + url.path();
}
-// Returns true with a probability of GetPerformanceMeasurementRate() if
+// Returns true with a probability given by |performance_measurement_rate| if
// ThreadTicks is supported, otherwise returns false.
-bool ShouldMeasurePerformanceForPageLoad() {
+bool ShouldMeasurePerformanceForPageLoad(double performance_measurement_rate) {
if (!base::ThreadTicks::IsSupported())
return false;
- // TODO(pkalinnikov): Cache |rate| and other variation params in
- // ContentSubresourceFilterDriverFactory.
- const double rate = GetPerformanceMeasurementRate();
- return rate == 1 || (rate > 0 && base::RandDouble() < rate);
+ return performance_measurement_rate == 1 ||
+ (performance_measurement_rate > 0 &&
+ base::RandDouble() < performance_measurement_rate);
}
+// Records histograms about the length of redirect chains, and about the pattern
+// of whether each URL in the chain matched the activation list.
+#define REPORT_REDIRECT_PATTERN_FOR_SUFFIX(suffix, hits_pattern, chain_size) \
+ do { \
+ UMA_HISTOGRAM_ENUMERATION( \
+ "SubresourceFilter.PageLoad.RedirectChainMatchPattern." suffix, \
+ hits_pattern, 0x10); \
+ UMA_HISTOGRAM_COUNTS( \
+ "SubresourceFilter.PageLoad.RedirectChainLength." suffix, chain_size); \
+ } while (0)
+
} // namespace
// static
@@ -76,7 +90,13 @@ ContentSubresourceFilterDriverFactory::ContentSubresourceFilterDriverFactory(
content::WebContents* web_contents,
std::unique_ptr<SubresourceFilterClient> client)
: content::WebContentsObserver(web_contents),
+ configuration_(GetActiveConfiguration()),
client_(std::move(client)),
+ throttle_manager_(
+ base::MakeUnique<ContentSubresourceFilterThrottleManager>(
+ this,
+ client_->GetRulesetDealer(),
+ web_contents)),
activation_level_(ActivationLevel::DISABLED),
activation_decision_(ActivationDecision::UNKNOWN),
measure_performance_(false) {}
@@ -84,14 +104,6 @@ ContentSubresourceFilterDriverFactory::ContentSubresourceFilterDriverFactory(
ContentSubresourceFilterDriverFactory::
~ContentSubresourceFilterDriverFactory() {}
-void ContentSubresourceFilterDriverFactory::OnFirstSubresourceLoadDisallowed() {
- if (ShouldSuppressNotifications())
- return;
-
- client_->ToggleNotificationVisibility(activation_level_ ==
- ActivationLevel::ENABLED);
-}
-
void ContentSubresourceFilterDriverFactory::OnDocumentLoadStatistics(
const DocumentLoadStatistics& statistics) {
// Note: Chances of overflow are negligible.
@@ -111,7 +123,8 @@ void ContentSubresourceFilterDriverFactory::OnDocumentLoadStatistics(
bool ContentSubresourceFilterDriverFactory::IsWhitelisted(
const GURL& url) const {
- return whitelisted_hosts_.find(url.host()) != whitelisted_hosts_.end();
+ return whitelisted_hosts_.find(url.host()) != whitelisted_hosts_.end() ||
+ client_->IsWhitelistedByContentSettings(url);
}
void ContentSubresourceFilterDriverFactory::
@@ -120,18 +133,8 @@ void ContentSubresourceFilterDriverFactory::
const std::vector<GURL>& redirect_urls,
safe_browsing::SBThreatType threat_type,
safe_browsing::ThreatPatternType threat_type_metadata) {
- bool is_phishing_interstitial =
- (threat_type == safe_browsing::SB_THREAT_TYPE_URL_PHISHING);
- bool is_soc_engineering_ads_interstitial =
- threat_type_metadata ==
- safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS;
-
- if (is_phishing_interstitial) {
- if (is_soc_engineering_ads_interstitial) {
- AddActivationListMatch(url, ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL);
- }
- AddActivationListMatch(url, ActivationList::PHISHING_INTERSTITIAL);
- }
+ AddActivationListMatch(
+ url, GetListForThreatTypeAndMetadata(threat_type, threat_type_metadata));
}
void ContentSubresourceFilterDriverFactory::AddHostOfURLToWhitelistSet(
@@ -143,11 +146,10 @@ void ContentSubresourceFilterDriverFactory::AddHostOfURLToWhitelistSet(
ContentSubresourceFilterDriverFactory::ActivationDecision
ContentSubresourceFilterDriverFactory::ComputeActivationDecisionForMainFrameURL(
const GURL& url) const {
- if (GetMaximumActivationLevel() == ActivationLevel::DISABLED)
+ if (configuration_.activation_level == ActivationLevel::DISABLED)
return ActivationDecision::ACTIVATION_DISABLED;
- ActivationScope scope = GetCurrentActivationScope();
- if (scope == ActivationScope::NO_SITES)
+ if (configuration_.activation_scope == ActivationScope::NO_SITES)
return ActivationDecision::ACTIVATION_DISABLED;
if (!url.SchemeIsHTTPOrHTTPS())
@@ -155,41 +157,99 @@ ContentSubresourceFilterDriverFactory::ComputeActivationDecisionForMainFrameURL(
if (IsWhitelisted(url))
return ActivationDecision::URL_WHITELISTED;
- switch (scope) {
+ switch (configuration_.activation_scope) {
case ActivationScope::ALL_SITES:
return ActivationDecision::ACTIVATED;
- case ActivationScope::ACTIVATION_LIST:
+ case ActivationScope::ACTIVATION_LIST: {
// The logic to ensure only http/https URLs are activated lives in
// AddActivationListMatch to ensure the activation list only has relevant
// entries.
DCHECK(url.SchemeIsHTTPOrHTTPS() ||
- !DidURLMatchCurrentActivationList(url));
- return DidURLMatchCurrentActivationList(url)
- ? ActivationDecision::ACTIVATED
- : ActivationDecision::ACTIVATION_LIST_NOT_MATCHED;
+ !DidURLMatchActivationList(url, configuration_.activation_list));
+ bool should_activate =
+ DidURLMatchActivationList(url, configuration_.activation_list);
+ if (configuration_.activation_list ==
+ ActivationList::PHISHING_INTERSTITIAL) {
+ // Handling special case, where activation on the phishing sites also
+ // mean the activation on the sites with social engineering metadata.
+ should_activate |= DidURLMatchActivationList(
+ url, ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL);
+ }
+ return should_activate ? ActivationDecision::ACTIVATED
+ : ActivationDecision::ACTIVATION_LIST_NOT_MATCHED;
+ }
default:
return ActivationDecision::ACTIVATION_DISABLED;
}
}
-void ContentSubresourceFilterDriverFactory::ActivateForFrameHostIfNeeded(
- content::RenderFrameHost* render_frame_host,
- const GURL& url) {
- if (activation_level_ != ActivationLevel::DISABLED) {
- render_frame_host->Send(
- new SubresourceFilterMsg_ActivateForNextCommittedLoad(
- render_frame_host->GetRoutingID(), activation_level_,
- measure_performance_));
- }
-}
-
void ContentSubresourceFilterDriverFactory::OnReloadRequested() {
UMA_HISTOGRAM_BOOLEAN("SubresourceFilter.Prompt.NumReloads", true);
const GURL& whitelist_url = web_contents()->GetLastCommittedURL();
- AddHostOfURLToWhitelistSet(whitelist_url);
+
+ // Only whitelist via content settings when using the experimental UI,
+ // otherwise could get into a situation where content settings cannot be
+ // adjusted.
+ if (base::FeatureList::IsEnabled(
+ subresource_filter::kSafeBrowsingSubresourceFilterExperimentalUI)) {
+ client_->WhitelistByContentSettings(whitelist_url);
+ } else {
+ AddHostOfURLToWhitelistSet(whitelist_url);
+ }
web_contents()->GetController().Reload(content::ReloadType::NORMAL, true);
}
+void ContentSubresourceFilterDriverFactory::WillProcessResponse(
+ content::NavigationHandle* navigation_handle) {
+ DCHECK(!navigation_handle->IsSameDocument());
+ if (!navigation_handle->IsInMainFrame() ||
+ navigation_handle->GetNetErrorCode() != net::OK) {
+ return;
+ }
+
+ const GURL& url = navigation_handle->GetURL();
+ const content::Referrer& referrer = navigation_handle->GetReferrer();
+ ui::PageTransition transition = navigation_handle->GetPageTransition();
+
+ RecordRedirectChainMatchPattern();
+
+ if (configuration_.should_whitelist_site_on_reload &&
+ NavigationIsPageReload(url, referrer, transition)) {
+ // Whitelist this host for the current as well as subsequent navigations.
+ AddHostOfURLToWhitelistSet(url);
+ }
+
+ activation_decision_ = ComputeActivationDecisionForMainFrameURL(url);
+ DCHECK(activation_decision_ != ActivationDecision::UNKNOWN);
+ if (activation_decision_ != ActivationDecision::ACTIVATED) {
+ ResetActivationState();
+ return;
+ }
+
+ activation_level_ = configuration_.activation_level;
+ measure_performance_ = activation_level_ != ActivationLevel::DISABLED &&
+ ShouldMeasurePerformanceForPageLoad(
+ configuration_.performance_measurement_rate);
+ ActivationState state = ActivationState(activation_level_);
+ state.measure_performance = measure_performance_;
+ throttle_manager_->NotifyPageActivationComputed(navigation_handle, state);
+}
+
+void ContentSubresourceFilterDriverFactory::OnFirstSubresourceLoadDisallowed() {
+ if (configuration_.should_suppress_notifications)
+ return;
+
+ client_->ToggleNotificationVisibility(activation_level_ ==
+ ActivationLevel::ENABLED);
+}
+
+bool ContentSubresourceFilterDriverFactory::ShouldSuppressActivation(
+ content::NavigationHandle* navigation_handle) {
+ // Never suppress subframe navigations.
+ return navigation_handle->IsInMainFrame() &&
+ IsWhitelisted(navigation_handle->GetURL());
+}
+
void ContentSubresourceFilterDriverFactory::ResetActivationState() {
navigation_chain_.clear();
activation_list_matches_.clear();
@@ -200,7 +260,8 @@ void ContentSubresourceFilterDriverFactory::ResetActivationState() {
void ContentSubresourceFilterDriverFactory::DidStartNavigation(
content::NavigationHandle* navigation_handle) {
- if (navigation_handle->IsInMainFrame() && !navigation_handle->IsSamePage()) {
+ if (navigation_handle->IsInMainFrame() &&
+ !navigation_handle->IsSameDocument()) {
activation_decision_ = ActivationDecision::UNKNOWN;
ResetActivationState();
navigation_chain_.push_back(navigation_handle->GetURL());
@@ -210,30 +271,11 @@ void ContentSubresourceFilterDriverFactory::DidStartNavigation(
void ContentSubresourceFilterDriverFactory::DidRedirectNavigation(
content::NavigationHandle* navigation_handle) {
- DCHECK(!navigation_handle->IsSamePage());
+ DCHECK(!navigation_handle->IsSameDocument());
if (navigation_handle->IsInMainFrame())
navigation_chain_.push_back(navigation_handle->GetURL());
}
-void ContentSubresourceFilterDriverFactory::ReadyToCommitNavigation(
- content::NavigationHandle* navigation_handle) {
- DCHECK(!navigation_handle->IsSamePage());
-
- // ReadyToCommitNavigation with browser-side navigation disabled is not called
- // in production code for failed navigations (e.g. network errors). We don't
- // want to activate on these pages, so we bail early to guarantee consistent
- // behavior regardless of whether browser-side navigation is enabled.
- if (navigation_handle->GetNetErrorCode() != net::OK)
- return;
-
- content::RenderFrameHost* render_frame_host =
- navigation_handle->GetRenderFrameHost();
- GURL url = navigation_handle->GetURL();
- const content::Referrer& referrer = navigation_handle->GetReferrer();
- ui::PageTransition transition = navigation_handle->GetPageTransition();
- ReadyToCommitNavigationInternal(render_frame_host, url, referrer, transition);
-}
-
void ContentSubresourceFilterDriverFactory::DidFinishLoad(
content::RenderFrameHost* render_frame_host,
const GURL& validated_url) {
@@ -280,8 +322,6 @@ bool ContentSubresourceFilterDriverFactory::OnMessageReceived(
content::RenderFrameHost* render_frame_host) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ContentSubresourceFilterDriverFactory, message)
- IPC_MESSAGE_HANDLER(SubresourceFilterHostMsg_DidDisallowFirstSubresource,
- OnFirstSubresourceLoadDisallowed)
IPC_MESSAGE_HANDLER(SubresourceFilterHostMsg_DocumentLoadStatistics,
OnDocumentLoadStatistics)
IPC_MESSAGE_UNHANDLED(handled = false)
@@ -289,85 +329,85 @@ bool ContentSubresourceFilterDriverFactory::OnMessageReceived(
return handled;
}
-void ContentSubresourceFilterDriverFactory::ReadyToCommitNavigationInternal(
- content::RenderFrameHost* render_frame_host,
+bool ContentSubresourceFilterDriverFactory::DidURLMatchActivationList(
const GURL& url,
- const content::Referrer& referrer,
- ui::PageTransition transition) {
- if (render_frame_host->GetParent()) {
- ActivateForFrameHostIfNeeded(render_frame_host, url);
- return;
- }
-
- RecordRedirectChainMatchPattern();
-
- if (ShouldWhitelistSiteOnReload() &&
- NavigationIsPageReload(url, referrer, transition)) {
- // Whitelist this host for the current as well as subsequent navigations.
- AddHostOfURLToWhitelistSet(url);
- }
-
- activation_decision_ = ComputeActivationDecisionForMainFrameURL(url);
- DCHECK(activation_decision_ != ActivationDecision::UNKNOWN);
- if (activation_decision_ != ActivationDecision::ACTIVATED) {
- ResetActivationState();
- return;
- }
-
- activation_level_ = GetMaximumActivationLevel();
- measure_performance_ = activation_level_ != ActivationLevel::DISABLED &&
- ShouldMeasurePerformanceForPageLoad();
- ActivateForFrameHostIfNeeded(render_frame_host, url);
-}
-
-bool ContentSubresourceFilterDriverFactory::DidURLMatchCurrentActivationList(
- const GURL& url) const {
+ ActivationList activation_list) const {
auto match_types =
activation_list_matches_.find(DistillURLToHostAndPath(url));
return match_types != activation_list_matches_.end() &&
- match_types->second.find(GetCurrentActivationList()) !=
- match_types->second.end();
+ match_types->second.find(activation_list) != match_types->second.end();
}
void ContentSubresourceFilterDriverFactory::AddActivationListMatch(
const GURL& url,
ActivationList match_type) {
+ if (match_type == ActivationList::NONE)
+ return;
if (url.has_host() && url.SchemeIsHTTPOrHTTPS())
activation_list_matches_[DistillURLToHostAndPath(url)].insert(match_type);
}
-void ContentSubresourceFilterDriverFactory::RecordRedirectChainMatchPattern()
- const {
+int ContentSubresourceFilterDriverFactory::CalculateHitPatternForActivationList(
+ ActivationList activation_list) const {
int hits_pattern = 0;
const int kInitialURLHitMask = 0x4;
const int kRedirectURLHitMask = 0x2;
const int kFinalURLHitMask = 0x1;
+
if (navigation_chain_.size() > 1) {
- if (DidURLMatchCurrentActivationList(navigation_chain_.back()))
+ if (DidURLMatchActivationList(navigation_chain_.back(), activation_list))
hits_pattern |= kFinalURLHitMask;
- if (DidURLMatchCurrentActivationList(navigation_chain_.front()))
+ if (DidURLMatchActivationList(navigation_chain_.front(), activation_list))
hits_pattern |= kInitialURLHitMask;
// Examine redirects.
for (size_t i = 1; i < navigation_chain_.size() - 1; ++i) {
- if (DidURLMatchCurrentActivationList(navigation_chain_[i])) {
+ if (DidURLMatchActivationList(navigation_chain_[i], activation_list)) {
hits_pattern |= kRedirectURLHitMask;
break;
}
}
} else {
if (navigation_chain_.size() &&
- DidURLMatchCurrentActivationList(navigation_chain_.front())) {
+ DidURLMatchActivationList(navigation_chain_.front(), activation_list)) {
hits_pattern = 0x8; // One url hit.
}
}
+ return hits_pattern;
+}
+
+void ContentSubresourceFilterDriverFactory::RecordRedirectChainMatchPattern()
+ const {
+ RecordRedirectChainMatchPatternForList(
+ ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL);
+ RecordRedirectChainMatchPatternForList(ActivationList::PHISHING_INTERSTITIAL);
+ RecordRedirectChainMatchPatternForList(ActivationList::SUBRESOURCE_FILTER);
+}
+
+void ContentSubresourceFilterDriverFactory::
+ RecordRedirectChainMatchPatternForList(
+ ActivationList activation_list) const {
+ int hits_pattern = CalculateHitPatternForActivationList(activation_list);
if (!hits_pattern)
return;
- UMA_HISTOGRAM_ENUMERATION(
- "SubresourceFilter.PageLoad.RedirectChainMatchPattern", hits_pattern,
- 0x10 /* max value */);
- UMA_HISTOGRAM_COUNTS("SubresourceFilter.PageLoad.RedirectChainLength",
- navigation_chain_.size());
+ size_t chain_size = navigation_chain_.size();
+ switch (activation_list) {
+ case ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL:
+ REPORT_REDIRECT_PATTERN_FOR_SUFFIX("SocialEngineeringAdsInterstitial",
+ hits_pattern, chain_size);
+ break;
+ case ActivationList::PHISHING_INTERSTITIAL:
+ REPORT_REDIRECT_PATTERN_FOR_SUFFIX("PhishingInterstital", hits_pattern,
+ chain_size);
+ break;
+ case ActivationList::SUBRESOURCE_FILTER:
+ REPORT_REDIRECT_PATTERN_FOR_SUFFIX("SubresourceFilterOnly", hits_pattern,
+ chain_size);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
index ee1abdaf0b0..7577274e45f 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
@@ -6,6 +6,7 @@
#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_DRIVER_FACTORY_H_
#include <map>
+#include <memory>
#include <set>
#include <string>
#include <utility>
@@ -15,6 +16,8 @@
#include "base/supports_user_data.h"
#include "base/time/time.h"
#include "components/safe_browsing_db/util.h"
+#include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
+#include "components/subresource_filter/core/browser/subresource_filter_features.h"
#include "components/subresource_filter/core/common/document_load_statistics.h"
#include "content/public/browser/web_contents_observer.h"
#include "ui/base/page_transition_types.h"
@@ -44,7 +47,8 @@ using URLToActivationListsMap =
// per-frame SubresourceFilterAgents on the renderer side.
class ContentSubresourceFilterDriverFactory
: public base::SupportsUserData::Data,
- public content::WebContentsObserver {
+ public content::WebContentsObserver,
+ public ContentSubresourceFilterThrottleManager::Delegate {
public:
// NOTE: ActivationDecision backs a UMA histogram, so it is append-only.
enum class ActivationDecision {
@@ -113,14 +117,31 @@ class ContentSubresourceFilterDriverFactory
return activation_decision_;
}
+ // ContentSubresourceFilterThrottleManager::Delegate:
+ void OnFirstSubresourceLoadDisallowed() override;
+ bool ShouldSuppressActivation(
+ content::NavigationHandle* navigation_handle) override;
+ void WillProcessResponse(
+ content::NavigationHandle* navigation_handle) override;
+
+ ContentSubresourceFilterThrottleManager* throttle_manager() {
+ return throttle_manager_.get();
+ }
+
+ // TODO(https://crbug.com/708181): Allow tests to change the configuration
+ // after construction (which happens at WebContents creation) but before a
+ // navigation start. Can be removed once the Safe Browsing navigation throttle
+ // handles all activation decisions.
+ void set_configuration_for_testing(Configuration configuration) {
+ configuration_ = std::move(configuration);
+ }
+
private:
friend class ContentSubresourceFilterDriverFactoryTest;
friend class safe_browsing::SafeBrowsingServiceTest;
void ResetActivationState();
- void OnFirstSubresourceLoadDisallowed();
-
void OnDocumentLoadStatistics(const DocumentLoadStatistics& statistics);
bool IsWhitelisted(const GURL& url) const;
@@ -130,8 +151,6 @@ class ContentSubresourceFilterDriverFactory
content::NavigationHandle* navigation_handle) override;
void DidRedirectNavigation(
content::NavigationHandle* navigation_handle) override;
- void ReadyToCommitNavigation(
- content::NavigationHandle* navigation_handle) override;
void DidFinishLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url) override;
bool OnMessageReceived(const IPC::Message& message,
@@ -141,24 +160,26 @@ class ContentSubresourceFilterDriverFactory
// activation signal should be sent.
ActivationDecision ComputeActivationDecisionForMainFrameURL(
const GURL& url) const;
- void ActivateForFrameHostIfNeeded(content::RenderFrameHost* render_frame_host,
- const GURL& url);
-
- // Internal implementation of ReadyToCommitNavigation which doesn't use
- // NavigationHandle to ease unit tests.
- void ReadyToCommitNavigationInternal(
- content::RenderFrameHost* render_frame_host,
- const GURL& url,
- const content::Referrer& referrer,
- ui::PageTransition page_transition);
- bool DidURLMatchCurrentActivationList(const GURL& url) const;
+ bool DidURLMatchActivationList(const GURL& url,
+ ActivationList activation_list) const;
void AddActivationListMatch(const GURL& url, ActivationList match_type);
+ int CalculateHitPatternForActivationList(
+ ActivationList activation_list) const;
void RecordRedirectChainMatchPattern() const;
+ void RecordRedirectChainMatchPatternForList(
+ ActivationList activation_list) const;
+
+ Configuration configuration_;
+
std::unique_ptr<SubresourceFilterClient> client_;
+ std::unique_ptr<ContentSubresourceFilterThrottleManager> throttle_manager_;
+
+ // Hosts to whitelist. This is only used for per-WebContents whitelisting and
+ // is distinct from content settings whitelisting.
HostPathSet whitelisted_hosts_;
ActivationLevel activation_level_;
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
index a2ffb3cb6c3..b230b216a93 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
@@ -7,12 +7,19 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
+#include "base/run_loop.h"
#include "base/test/histogram_tester.h"
#include "components/safe_browsing_db/util.h"
+#include "components/subresource_filter/content/browser/content_activation_list_utils.h"
+#include "components/subresource_filter/content/browser/subresource_filter_client.h"
#include "components/subresource_filter/content/common/subresource_filter_messages.h"
-#include "components/subresource_filter/core/browser/subresource_filter_client.h"
#include "components/subresource_filter/core/browser/subresource_filter_features.h"
#include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h"
+#include "components/subresource_filter/core/common/activation_list.h"
+#include "components/subresource_filter/core/common/test_ruleset_creator.h"
+#include "components/subresource_filter/core/common/test_ruleset_utils.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/navigation_throttle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/mock_render_process_host.h"
@@ -34,15 +41,17 @@ namespace {
const char kExampleUrlWithParams[] = "https://example.com/soceng?q=engsoc";
const char kExampleUrl[] = "https://example.com";
const char kExampleLoginUrl[] = "https://example.com/login";
-const char kMatchesPatternHistogramName[] =
- "SubresourceFilter.PageLoad.RedirectChainMatchPattern";
-const char kNavigationChainSize[] =
- "SubresourceFilter.PageLoad.RedirectChainLength";
const char kUrlA[] = "https://example_a.com";
const char kUrlB[] = "https://example_b.com";
const char kUrlC[] = "https://example_c.com";
const char kUrlD[] = "https://example_d.com";
const char kSubframeName[] = "Child";
+const char kDisallowedUrl[] = "https://example.com/disallowed.html";
+
+const char kMatchesPatternHistogramName[] =
+ "SubresourceFilter.PageLoad.RedirectChainMatchPattern.";
+const char kNavigationChainSize[] =
+ "SubresourceFilter.PageLoad.RedirectChainLength.";
// Human readable representation of expected redirect chain match patterns.
// The explanations for the buckets given for the following redirect chain:
@@ -61,6 +70,20 @@ enum RedirectChainMatchPattern {
NUM_HIT_PATTERNS,
};
+std::string GetSuffixForList(const ActivationList& type) {
+ switch (type) {
+ case ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL:
+ return "SocialEngineeringAdsInterstitial";
+ case ActivationList::PHISHING_INTERSTITIAL:
+ return "PhishingInterstital";
+ case ActivationList::SUBRESOURCE_FILTER:
+ return "SubresourceFilterOnly";
+ case ActivationList::NONE:
+ return std::string();
+ }
+ return std::string();
+}
+
struct ActivationListTestData {
ActivationDecision expected_activation_decision;
const char* const activation_list;
@@ -124,6 +147,10 @@ const ActivationListTestData kActivationListTestData[] = {
subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
+ {ActivationDecision::ACTIVATED,
+ subresource_filter::kActivationListPhishingInterstitial,
+ safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
};
struct ActivationScopeTestData {
@@ -158,20 +185,35 @@ const ActivationLevelTestData kActivationLevelTestData[] = {
class MockSubresourceFilterClient : public SubresourceFilterClient {
public:
- MockSubresourceFilterClient() {}
+ MockSubresourceFilterClient(VerifiedRulesetDealer::Handle* ruleset_dealer)
+ : ruleset_dealer_(ruleset_dealer) {}
~MockSubresourceFilterClient() override = default;
+ bool IsWhitelistedByContentSettings(const GURL& url) override {
+ return false;
+ }
+
+ void WhitelistByContentSettings(const GURL& url) override {}
+
+ VerifiedRulesetDealer::Handle* GetRulesetDealer() override {
+ return ruleset_dealer_;
+ }
+
MOCK_METHOD1(ToggleNotificationVisibility, void(bool));
private:
+ // Owned by the test harness.
+ VerifiedRulesetDealer::Handle* ruleset_dealer_;
+
DISALLOW_COPY_AND_ASSIGN(MockSubresourceFilterClient);
};
} // namespace
class ContentSubresourceFilterDriverFactoryTest
- : public content::RenderViewHostTestHarness {
+ : public content::RenderViewHostTestHarness,
+ public content::WebContentsObserver {
public:
ContentSubresourceFilterDriverFactoryTest() {}
~ContentSubresourceFilterDriverFactoryTest() override {}
@@ -180,26 +222,43 @@ class ContentSubresourceFilterDriverFactoryTest
void SetUp() override {
RenderViewHostTestHarness::SetUp();
- client_ = new MockSubresourceFilterClient();
+ std::vector<proto::UrlRule> rules;
+ rules.push_back(testing::CreateSuffixRule("disallowed.html"));
+ ASSERT_NO_FATAL_FAILURE(test_ruleset_creator_.CreateRulesetWithRules(
+ rules, &test_ruleset_pair_));
+ ruleset_dealer_ = base::MakeUnique<VerifiedRulesetDealer::Handle>(
+ base::MessageLoop::current()->task_runner());
+ ruleset_dealer_->SetRulesetFile(
+ testing::TestRuleset::Open(test_ruleset_pair_.indexed));
+ client_ = new MockSubresourceFilterClient(ruleset_dealer_.get());
ContentSubresourceFilterDriverFactory::CreateForWebContents(
- web_contents(), base::WrapUnique(client()));
+ RenderViewHostTestHarness::web_contents(), base::WrapUnique(client()));
// Add a subframe.
content::RenderFrameHostTester* rfh_tester =
content::RenderFrameHostTester::For(main_rfh());
rfh_tester->InitializeRenderFrameIfNeeded();
rfh_tester->AppendChild(kSubframeName);
+
+ Observe(content::RenderViewHostTestHarness::web_contents());
+ }
+
+ void TearDown() override {
+ ruleset_dealer_.reset();
+ base::RunLoop().RunUntilIdle();
+ RenderViewHostTestHarness::TearDown();
}
ContentSubresourceFilterDriverFactory* factory() {
return ContentSubresourceFilterDriverFactory::FromWebContents(
- web_contents());
+ RenderViewHostTestHarness::web_contents());
}
MockSubresourceFilterClient* client() { return client_; }
content::RenderFrameHost* GetSubframeRFH() {
- for (content::RenderFrameHost* rfh : web_contents()->GetAllFrames()) {
+ for (content::RenderFrameHost* rfh :
+ RenderViewHostTestHarness::web_contents()->GetAllFrames()) {
if (rfh->GetFrameName() == kSubframeName)
return rfh;
}
@@ -215,9 +274,10 @@ class ContentSubresourceFilterDriverFactoryTest
SubresourceFilterMsg_ActivateForNextCommittedLoad::ID);
ASSERT_EQ(expect_activation, !!message);
if (expect_activation) {
- std::tuple<ActivationLevel, bool> args;
+ std::tuple<ActivationState> args;
SubresourceFilterMsg_ActivateForNextCommittedLoad::Read(message, &args);
- EXPECT_NE(ActivationLevel::DISABLED, std::get<0>(args));
+ ActivationLevel level = std::get<0>(args).activation_level;
+ EXPECT_NE(ActivationLevel::DISABLED, level);
}
render_process_host->sink().ClearMessages();
}
@@ -268,19 +328,42 @@ class ContentSubresourceFilterDriverFactoryTest
content::RenderFrameHostTester* rfh_tester =
content::RenderFrameHostTester::For(main_rfh());
rfh_tester->AppendChild(kSubframeName);
-
+ ActivationList activation_list =
+ GetListForThreatTypeAndMetadata(threat_type, threat_type_metadata);
+
+ const std::string suffix(GetSuffixForList(activation_list));
+ size_t all_pattern =
+ tester.GetTotalCountsForPrefix(kMatchesPatternHistogramName).size();
+ size_t all_chain_size =
+ tester.GetTotalCountsForPrefix(kNavigationChainSize).size();
if (expected_pattern != EMPTY) {
- EXPECT_THAT(tester.GetAllSamples(kMatchesPatternHistogramName),
+ EXPECT_THAT(tester.GetAllSamples(kMatchesPatternHistogramName + suffix),
::testing::ElementsAre(base::Bucket(expected_pattern, 1)));
EXPECT_THAT(
- tester.GetAllSamples(kNavigationChainSize),
+ tester.GetAllSamples(kNavigationChainSize + suffix),
::testing::ElementsAre(base::Bucket(navigation_chain.size(), 1)));
+ // Check that we recorded only what is needed.
+ EXPECT_EQ(1u, all_pattern);
+ EXPECT_EQ(1u, all_chain_size);
+ } else {
+ EXPECT_EQ(0u, all_pattern);
+ EXPECT_EQ(0u, all_chain_size);
+ }
+ }
+ void NavigateSubframeAndExpectCheckResult(const GURL& url,
+ bool expect_cancelled) {
+ std::unique_ptr<content::NavigationSimulator> simulator =
+ content::NavigationSimulator::CreateRendererInitiated(url,
+ GetSubframeRFH());
+ simulator->Start();
+ content::NavigationThrottle::ThrottleCheckResult result =
+ simulator->GetLastThrottleCheckResult();
+ if (expect_cancelled) {
+ EXPECT_EQ(content::NavigationThrottle::CANCEL, result);
} else {
- EXPECT_THAT(tester.GetAllSamples(kMatchesPatternHistogramName),
- ::testing::IsEmpty());
- EXPECT_THAT(tester.GetAllSamples(kNavigationChainSize),
- ::testing::IsEmpty());
+ EXPECT_EQ(content::NavigationThrottle::PROCEED, result);
+ simulator->Commit();
}
}
@@ -324,13 +407,6 @@ class ContentSubresourceFilterDriverFactoryTest
expected_activation_decision);
}
- void EmulateDidDisallowFirstSubresourceMessage() {
- factory()->OnMessageReceived(
- SubresourceFilterHostMsg_DidDisallowFirstSubresource(
- main_rfh()->GetRoutingID()),
- main_rfh());
- }
-
void EmulateFailedNavigationAndExpectNoActivation(const GURL& url) {
EXPECT_CALL(*client(), ToggleNotificationVisibility(false)).Times(1);
@@ -362,22 +438,41 @@ class ContentSubresourceFilterDriverFactoryTest
std::unique_ptr<content::NavigationSimulator> navigation_simulator =
content::NavigationSimulator::CreateRendererInitiated(GURL(kExampleUrl),
main_rfh());
- navigation_simulator->CommitSamePage();
+ navigation_simulator->CommitSameDocument();
ExpectActivationSignalForFrame(main_rfh(), false);
::testing::Mock::VerifyAndClearExpectations(client());
}
+ protected:
+ // content::WebContentsObserver
+ void DidStartNavigation(
+ content::NavigationHandle* navigation_handle) override {
+ if (navigation_handle->IsSameDocument())
+ return;
+
+ std::vector<std::unique_ptr<content::NavigationThrottle>> throttles;
+ factory()->throttle_manager()->MaybeAppendNavigationThrottles(
+ navigation_handle, &throttles);
+ for (auto& it : throttles)
+ navigation_handle->RegisterThrottleForTesting(std::move(it));
+ }
+
private:
static bool expected_measure_performance() {
- const double rate = GetPerformanceMeasurementRate();
+ const double rate = GetActiveConfiguration().performance_measurement_rate;
// Note: The case when 0 < rate < 1 is not deterministic, don't test it.
EXPECT_TRUE(rate == 0 || rate == 1);
return rate == 1;
}
+ testing::TestRulesetCreator test_ruleset_creator_;
+ testing::TestRulesetPair test_ruleset_pair_;
+
// Owned by the factory.
MockSubresourceFilterClient* client_;
+ std::unique_ptr<VerifiedRulesetDealer::Handle> ruleset_dealer_;
+
DISALLOW_COPY_AND_ASSIGN(ContentSubresourceFilterDriverFactoryTest);
};
@@ -425,11 +520,12 @@ TEST_F(ContentSubresourceFilterDriverFactoryTest,
base::FeatureList::OVERRIDE_DISABLE_FEATURE, kActivationLevelEnabled,
kActivationScopeAllSites,
kActivationListSocialEngineeringAdsInterstitial);
+ factory()->set_configuration_for_testing(GetActiveConfiguration());
const GURL url(kExampleUrlWithParams);
- NavigateAndExpectActivation({true}, {url}, EMPTY,
+ NavigateAndExpectActivation({true}, {url}, NO_REDIRECTS_HIT,
ActivationDecision::ACTIVATION_DISABLED);
factory()->AddHostOfURLToWhitelistSet(url);
- NavigateAndExpectActivation({true}, {url}, EMPTY,
+ NavigateAndExpectActivation({true}, {url}, NO_REDIRECTS_HIT,
ActivationDecision::ACTIVATION_DISABLED);
}
@@ -439,6 +535,7 @@ TEST_F(ContentSubresourceFilterDriverFactoryTest, NoActivationWhenNoMatch) {
base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled,
kActivationScopeActivationList,
kActivationListSocialEngineeringAdsInterstitial);
+ factory()->set_configuration_for_testing(GetActiveConfiguration());
NavigateAndExpectActivation({false}, {GURL(kExampleUrl)}, EMPTY,
ActivationDecision::ACTIVATION_LIST_NOT_MATCHED);
}
@@ -451,6 +548,7 @@ TEST_F(ContentSubresourceFilterDriverFactoryTest,
testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled,
kActivationScopeAllSites);
+ factory()->set_configuration_for_testing(GetActiveConfiguration());
EmulateInPageNavigation({false}, EMPTY, ActivationDecision::ACTIVATED);
}
@@ -461,6 +559,7 @@ TEST_F(ContentSubresourceFilterDriverFactoryTest,
base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled,
kActivationScopeActivationList,
kActivationListSocialEngineeringAdsInterstitial);
+ factory()->set_configuration_for_testing(GetActiveConfiguration());
EmulateInPageNavigation({true}, NO_REDIRECTS_HIT,
ActivationDecision::ACTIVATED);
}
@@ -473,6 +572,7 @@ TEST_F(ContentSubresourceFilterDriverFactoryTest,
kActivationScopeActivationList,
kActivationListSocialEngineeringAdsInterstitial,
"1" /* performance_measurement_rate */);
+ factory()->set_configuration_for_testing(GetActiveConfiguration());
EmulateInPageNavigation({true}, NO_REDIRECTS_HIT,
ActivationDecision::ACTIVATED);
}
@@ -482,18 +582,22 @@ TEST_F(ContentSubresourceFilterDriverFactoryTest, FailedNavigation) {
testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled,
kActivationScopeAllSites);
+ factory()->set_configuration_for_testing(GetActiveConfiguration());
const GURL url(kExampleUrl);
NavigateAndExpectActivation({false}, {url}, EMPTY,
ActivationDecision::ACTIVATED);
EmulateFailedNavigationAndExpectNoActivation(url);
}
+// TODO(melandory): refactor the test so it no longer require the current
+// activation list to be matching.
TEST_F(ContentSubresourceFilterDriverFactoryTest, RedirectPatternTest) {
base::FieldTrialList field_trial_list(nullptr);
testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled,
kActivationScopeActivationList,
kActivationListSocialEngineeringAdsInterstitial);
+ factory()->set_configuration_for_testing(GetActiveConfiguration());
struct RedirectRedirectChainMatchPatternTestData {
std::vector<bool> blacklisted_urls;
std::vector<GURL> navigation_chain;
@@ -521,7 +625,6 @@ TEST_F(ContentSubresourceFilterDriverFactoryTest, RedirectPatternTest) {
{GURL(kUrlA), GURL(kUrlB)},
F1M0L1,
ActivationDecision::ACTIVATED},
-
{{false, false, false},
{GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)},
EMPTY,
@@ -572,6 +675,14 @@ TEST_F(ContentSubresourceFilterDriverFactoryTest, RedirectPatternTest) {
NavigateAndExpectActivation(
{false}, {GURL("https://dummy.com")}, EMPTY,
ActivationDecision::ACTIVATION_LIST_NOT_MATCHED);
+#if defined(GOOGLE_CHROME_BUILD)
+ NavigateAndExpectActivation(
+ test_data.blacklisted_urls, test_data.navigation_chain,
+ safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER,
+ safe_browsing::ThreatPatternType::NONE, content::Referrer(),
+ ui::PAGE_TRANSITION_LINK, test_data.hit_expected_pattern,
+ ActivationDecision::ACTIVATION_LIST_NOT_MATCHED);
+#endif
}
}
@@ -580,11 +691,13 @@ TEST_F(ContentSubresourceFilterDriverFactoryTest, NotificationVisibility) {
testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled,
kActivationScopeAllSites);
+ factory()->set_configuration_for_testing(GetActiveConfiguration());
NavigateAndExpectActivation({false}, {GURL(kExampleUrl)}, EMPTY,
ActivationDecision::ACTIVATED);
EXPECT_CALL(*client(), ToggleNotificationVisibility(true)).Times(1);
- EmulateDidDisallowFirstSubresourceMessage();
+ NavigateSubframeAndExpectCheckResult(GURL(kDisallowedUrl),
+ true /* expect_cancelled */);
}
TEST_F(ContentSubresourceFilterDriverFactoryTest,
@@ -595,11 +708,21 @@ TEST_F(ContentSubresourceFilterDriverFactoryTest,
kActivationScopeAllSites, "" /* activation_lists */,
"" /* performance_measurement_rate */,
"true" /* suppress_notifications */);
+ factory()->set_configuration_for_testing(GetActiveConfiguration());
NavigateAndExpectActivation({false}, {GURL(kExampleUrl)}, EMPTY,
ActivationDecision::ACTIVATED);
EXPECT_CALL(*client(), ToggleNotificationVisibility(::testing::_)).Times(0);
- EmulateDidDisallowFirstSubresourceMessage();
+ NavigateSubframeAndExpectCheckResult(GURL(kDisallowedUrl),
+ true /* expect_cancelled */);
+}
+
+TEST_F(ContentSubresourceFilterDriverFactoryTest,
+ InactiveMainFrame_SubframeNotFiltered) {
+ GURL url(kExampleUrl);
+ NavigateAndExpectActivation({false}, {url}, EMPTY,
+ ActivationDecision::ACTIVATION_DISABLED);
+ NavigateSubframeAndExpectCheckResult(url, false /* expect_cancelled */);
}
TEST_F(ContentSubresourceFilterDriverFactoryTest, WhitelistSiteOnReload) {
@@ -610,9 +733,9 @@ TEST_F(ContentSubresourceFilterDriverFactoryTest, WhitelistSiteOnReload) {
} kTestCases[] = {
{content::Referrer(), ui::PAGE_TRANSITION_LINK,
ActivationDecision::ACTIVATED},
- {content::Referrer(GURL(kUrlA), blink::WebReferrerPolicyDefault),
+ {content::Referrer(GURL(kUrlA), blink::kWebReferrerPolicyDefault),
ui::PAGE_TRANSITION_LINK, ActivationDecision::ACTIVATED},
- {content::Referrer(GURL(kExampleUrl), blink::WebReferrerPolicyDefault),
+ {content::Referrer(GURL(kExampleUrl), blink::kWebReferrerPolicyDefault),
ui::PAGE_TRANSITION_LINK, ActivationDecision::URL_WHITELISTED},
{content::Referrer(), ui::PAGE_TRANSITION_RELOAD,
ActivationDecision::URL_WHITELISTED}};
@@ -628,6 +751,7 @@ TEST_F(ContentSubresourceFilterDriverFactoryTest, WhitelistSiteOnReload) {
kActivationScopeAllSites, "" /* activation_lists */,
"" /* performance_measurement_rate */, "" /* suppress_notifications */,
"true" /* whitelist_site_on_reload */);
+ factory()->set_configuration_for_testing(GetActiveConfiguration());
NavigateAndExpectActivation(
{false}, {GURL(kExampleUrl)},
@@ -650,6 +774,7 @@ TEST_P(ContentSubresourceFilterDriverFactoryActivationLevelTest,
base::FeatureList::OVERRIDE_ENABLE_FEATURE, test_data.activation_level,
kActivationScopeActivationList,
kActivationListSocialEngineeringAdsInterstitial);
+ factory()->set_configuration_for_testing(GetActiveConfiguration());
const GURL url(kExampleUrlWithParams);
NavigateAndExpectActivation({true}, {url}, NO_REDIRECTS_HIT,
@@ -657,7 +782,7 @@ TEST_P(ContentSubresourceFilterDriverFactoryActivationLevelTest,
factory()->AddHostOfURLToWhitelistSet(url);
NavigateAndExpectActivation(
{true}, {GURL(kExampleUrlWithParams)}, NO_REDIRECTS_HIT,
- GetMaximumActivationLevel() == ActivationLevel::DISABLED
+ GetActiveConfiguration().activation_level == ActivationLevel::DISABLED
? ActivationDecision::ACTIVATION_DISABLED
: ActivationDecision::URL_WHITELISTED);
}
@@ -671,17 +796,19 @@ TEST_P(ContentSubresourceFilterDriverFactoryThreatTypeTest,
testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled,
kActivationScopeActivationList, test_data.activation_list);
+ factory()->set_configuration_for_testing(GetActiveConfiguration());
const GURL test_url("https://example.com/nonsoceng?q=engsocnon");
std::vector<GURL> navigation_chain;
- const bool expected_activation =
- test_data.expected_activation_decision == ActivationDecision::ACTIVATED;
+ ActivationList effective_list = GetListForThreatTypeAndMetadata(
+ test_data.threat_type, test_data.threat_type_metadata);
NavigateAndExpectActivation(
{false, false, false, true},
{GURL(kUrlA), GURL(kUrlB), GURL(kUrlC), test_url}, test_data.threat_type,
test_data.threat_type_metadata, content::Referrer(),
- ui::PAGE_TRANSITION_LINK, expected_activation ? F0M0L1 : EMPTY,
+ ui::PAGE_TRANSITION_LINK,
+ effective_list != ActivationList::NONE ? F0M0L1 : EMPTY,
test_data.expected_activation_decision);
};
@@ -693,6 +820,7 @@ TEST_P(ContentSubresourceFilterDriverFactoryActivationScopeTest,
base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled,
test_data.activation_scope,
kActivationListSocialEngineeringAdsInterstitial);
+ factory()->set_configuration_for_testing(GetActiveConfiguration());
const GURL test_url(kExampleUrlWithParams);
@@ -706,7 +834,7 @@ TEST_P(ContentSubresourceFilterDriverFactoryActivationScopeTest,
NavigateAndExpectActivation(
{test_data.url_matches_activation_list}, {GURL(kExampleUrlWithParams)},
expected_pattern,
- GetCurrentActivationScope() == ActivationScope::NO_SITES
+ GetActiveConfiguration().activation_scope == ActivationScope::NO_SITES
? ActivationDecision::ACTIVATION_DISABLED
: ActivationDecision::URL_WHITELISTED);
}
@@ -722,10 +850,13 @@ TEST_P(ContentSubresourceFilterDriverFactoryActivationScopeTest,
base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled,
test_data.activation_scope,
kActivationListSocialEngineeringAdsInterstitial);
+ factory()->set_configuration_for_testing(GetActiveConfiguration());
- const char* unsupported_urls[] = {
- "data:text/html,<p>Hello", "ftp://example.com/", "chrome://settings",
- "chrome-extension://some-extension", "file:///var/www/index.html"};
+ // data URLs are also not supported, but not listed here, as it's not possible
+ // for a page to redirect to them after https://crbug.com/594215 is fixed.
+ const char* unsupported_urls[] = {"ftp://example.com/", "chrome://settings",
+ "chrome-extension://some-extension",
+ "file:///var/www/index.html"};
const char* supported_urls[] = {"http://example.test",
"https://example.test"};
for (auto* url : unsupported_urls) {
@@ -733,7 +864,7 @@ TEST_P(ContentSubresourceFilterDriverFactoryActivationScopeTest,
RedirectChainMatchPattern expected_pattern = EMPTY;
NavigateAndExpectActivation(
{test_data.url_matches_activation_list}, {GURL(url)}, expected_pattern,
- GetCurrentActivationScope() == ActivationScope::NO_SITES
+ GetActiveConfiguration().activation_scope == ActivationScope::NO_SITES
? ActivationDecision::ACTIVATION_DISABLED
: ActivationDecision::UNSUPPORTED_SCHEME);
}
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
new file mode 100644
index 00000000000..eed2e727071
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
@@ -0,0 +1,248 @@
+// 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/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h"
+#include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
+#include "components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h"
+#include "components/subresource_filter/content/common/subresource_filter_messages.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "net/base/net_errors.h"
+
+namespace subresource_filter {
+
+namespace {
+
+// Used to forward calls to WillProcessResonse to the driver.
+// TODO(https://crbug.com/708181): Remove this once the safe browsing navigation
+// throttle is responsible for all activation decisions.
+class ForwardingNavigationThrottle : public content::NavigationThrottle {
+ public:
+ ForwardingNavigationThrottle(
+ content::NavigationHandle* handle,
+ ContentSubresourceFilterThrottleManager::Delegate* delegate)
+ : content::NavigationThrottle(handle), delegate_(delegate) {}
+ ~ForwardingNavigationThrottle() override {}
+
+ // content::NavigationThrottle:
+ content::NavigationThrottle::ThrottleCheckResult WillProcessResponse()
+ override {
+ delegate_->WillProcessResponse(navigation_handle());
+ return content::NavigationThrottle::PROCEED;
+ }
+
+ private:
+ ContentSubresourceFilterThrottleManager::Delegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(ForwardingNavigationThrottle);
+};
+
+} // namespace
+
+bool ContentSubresourceFilterThrottleManager::Delegate::
+ ShouldSuppressActivation(content::NavigationHandle* navigation_handle) {
+ return false;
+}
+
+ContentSubresourceFilterThrottleManager::
+ ContentSubresourceFilterThrottleManager(
+ Delegate* delegate,
+ VerifiedRulesetDealer::Handle* dealer_handle,
+ content::WebContents* web_contents)
+ : content::WebContentsObserver(web_contents),
+ dealer_handle_(dealer_handle),
+ delegate_(delegate),
+ weak_ptr_factory_(this) {}
+
+ContentSubresourceFilterThrottleManager::
+ ~ContentSubresourceFilterThrottleManager() {}
+
+void ContentSubresourceFilterThrottleManager::NotifyPageActivationComputed(
+ content::NavigationHandle* navigation_handle,
+ const ActivationState& activation_state) {
+ DCHECK(navigation_handle->IsInMainFrame());
+ DCHECK(!navigation_handle->HasCommitted());
+ auto it = ongoing_activation_throttles_.find(navigation_handle);
+ if (it != ongoing_activation_throttles_.end()) {
+ it->second->NotifyPageActivationWithRuleset(EnsureRulesetHandle(),
+ activation_state);
+ }
+}
+
+void ContentSubresourceFilterThrottleManager::RenderFrameDeleted(
+ content::RenderFrameHost* frame_host) {
+ activated_frame_hosts_.erase(frame_host);
+ DestroyRulesetHandleIfNoLongerUsed();
+}
+
+// Pull the AsyncDocumentSubresourceFilter and its associated ActivationState
+// out of the activation state computing throttle. Store it for later filtering
+// of subframe navigations.
+void ContentSubresourceFilterThrottleManager::ReadyToCommitNavigation(
+ content::NavigationHandle* navigation_handle) {
+ auto throttle = ongoing_activation_throttles_.find(navigation_handle);
+ if (throttle == ongoing_activation_throttles_.end())
+ return;
+
+ // A filter with DISABLED activation indicates a corrupted ruleset.
+ AsyncDocumentSubresourceFilter* filter = throttle->second->filter();
+ if (!filter || navigation_handle->GetNetErrorCode() != net::OK ||
+ filter->activation_state().activation_level ==
+ ActivationLevel::DISABLED ||
+ delegate_->ShouldSuppressActivation(navigation_handle)) {
+ return;
+ }
+
+ throttle->second->WillSendActivationToRenderer();
+
+ content::RenderFrameHost* frame_host =
+ navigation_handle->GetRenderFrameHost();
+ frame_host->Send(new SubresourceFilterMsg_ActivateForNextCommittedLoad(
+ frame_host->GetRoutingID(), filter->activation_state()));
+}
+
+void ContentSubresourceFilterThrottleManager::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ // Do nothing if the navigation finished in the same document. Just make sure
+ // to not leak throttle pointers.
+ if (!navigation_handle->HasCommitted() ||
+ navigation_handle->IsSameDocument()) {
+ ongoing_activation_throttles_.erase(navigation_handle);
+ return;
+ }
+
+ auto throttle = ongoing_activation_throttles_.find(navigation_handle);
+ std::unique_ptr<AsyncDocumentSubresourceFilter> filter;
+ if (throttle != ongoing_activation_throttles_.end()) {
+ filter = throttle->second->ReleaseFilter();
+ ongoing_activation_throttles_.erase(throttle);
+ }
+
+ // Make sure |activated_frame_hosts_| is updated or cleaned up depending on
+ // this navigation's activation state.
+ content::RenderFrameHost* frame_host =
+ navigation_handle->GetRenderFrameHost();
+ if (filter) {
+ filter->set_first_disallowed_load_callback(base::Bind(
+ &ContentSubresourceFilterThrottleManager::MaybeCallFirstDisallowedLoad,
+ weak_ptr_factory_.GetWeakPtr()));
+ activated_frame_hosts_[frame_host] = std::move(filter);
+ } else {
+ activated_frame_hosts_.erase(frame_host);
+ }
+
+ if (navigation_handle->IsInMainFrame())
+ current_committed_load_has_notified_disallowed_load_ = false;
+ DestroyRulesetHandleIfNoLongerUsed();
+}
+
+bool ContentSubresourceFilterThrottleManager::OnMessageReceived(
+ const IPC::Message& message,
+ content::RenderFrameHost* render_frame_host) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(ContentSubresourceFilterThrottleManager, message)
+ IPC_MESSAGE_HANDLER(SubresourceFilterHostMsg_DidDisallowFirstSubresource,
+ MaybeCallFirstDisallowedLoad)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void ContentSubresourceFilterThrottleManager::MaybeAppendNavigationThrottles(
+ content::NavigationHandle* navigation_handle,
+ std::vector<std::unique_ptr<content::NavigationThrottle>>* throttles) {
+ DCHECK(!navigation_handle->IsSameDocument());
+ if (navigation_handle->IsInMainFrame()) {
+ throttles->push_back(base::MakeUnique<ForwardingNavigationThrottle>(
+ navigation_handle, delegate_));
+ }
+ if (!dealer_handle_)
+ return;
+ if (auto filtering_throttle =
+ MaybeCreateSubframeNavigationFilteringThrottle(navigation_handle)) {
+ throttles->push_back(std::move(filtering_throttle));
+ }
+ if (auto activation_throttle =
+ MaybeCreateActivationStateComputingThrottle(navigation_handle)) {
+ ongoing_activation_throttles_[navigation_handle] =
+ activation_throttle.get();
+ throttles->push_back(std::move(activation_throttle));
+ }
+}
+
+std::unique_ptr<SubframeNavigationFilteringThrottle>
+ContentSubresourceFilterThrottleManager::
+ MaybeCreateSubframeNavigationFilteringThrottle(
+ content::NavigationHandle* navigation_handle) {
+ if (navigation_handle->IsInMainFrame())
+ return nullptr;
+ AsyncDocumentSubresourceFilter* parent_filter =
+ GetParentFrameFilter(navigation_handle);
+ return parent_filter ? base::MakeUnique<SubframeNavigationFilteringThrottle>(
+ navigation_handle, parent_filter)
+ : nullptr;
+}
+
+std::unique_ptr<ActivationStateComputingNavigationThrottle>
+ContentSubresourceFilterThrottleManager::
+ MaybeCreateActivationStateComputingThrottle(
+ content::NavigationHandle* navigation_handle) {
+ // Main frames: create unconditionally.
+ if (navigation_handle->IsInMainFrame()) {
+ return ActivationStateComputingNavigationThrottle::CreateForMainFrame(
+ navigation_handle);
+ }
+
+ // Subframes: create only for frames with activated parents.
+ AsyncDocumentSubresourceFilter* parent_filter =
+ GetParentFrameFilter(navigation_handle);
+ if (!parent_filter)
+ return nullptr;
+ DCHECK(ruleset_handle_);
+ return ActivationStateComputingNavigationThrottle::CreateForSubframe(
+ navigation_handle, ruleset_handle_.get(),
+ parent_filter->activation_state());
+}
+
+AsyncDocumentSubresourceFilter*
+ContentSubresourceFilterThrottleManager::GetParentFrameFilter(
+ content::NavigationHandle* child_frame_navigation) {
+ DCHECK(!child_frame_navigation->IsInMainFrame());
+ content::RenderFrameHost* parent = web_contents()->FindFrameByFrameTreeNodeId(
+ child_frame_navigation->GetParentFrameTreeNodeId());
+ DCHECK(parent);
+ auto it = activated_frame_hosts_.find(parent);
+ return it == activated_frame_hosts_.end() ? nullptr : it->second.get();
+}
+
+void ContentSubresourceFilterThrottleManager::MaybeCallFirstDisallowedLoad() {
+ if (current_committed_load_has_notified_disallowed_load_)
+ return;
+ delegate_->OnFirstSubresourceLoadDisallowed();
+ current_committed_load_has_notified_disallowed_load_ = true;
+}
+
+VerifiedRuleset::Handle*
+ContentSubresourceFilterThrottleManager::EnsureRulesetHandle() {
+ if (!ruleset_handle_)
+ ruleset_handle_ = base::MakeUnique<VerifiedRuleset::Handle>(dealer_handle_);
+ return ruleset_handle_.get();
+}
+
+void ContentSubresourceFilterThrottleManager::
+ DestroyRulesetHandleIfNoLongerUsed() {
+ if (activated_frame_hosts_.size() + ongoing_activation_throttles_.size() ==
+ 0u) {
+ ruleset_handle_.reset();
+ }
+}
+
+} // namespace subresource_filter
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
new file mode 100644
index 00000000000..e113c3cc890
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
@@ -0,0 +1,165 @@
+// 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_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_THROTTLE_MANAGER_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_THROTTLE_MANAGER_H_
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/subresource_filter/content/browser/verified_ruleset_dealer.h"
+#include "components/subresource_filter/core/common/activation_state.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+class NavigationHandle;
+class NavigationThrottle;
+class RenderFrameHost;
+} // namespace content
+
+namespace IPC {
+class Message;
+} // namespace IPC
+
+namespace subresource_filter {
+
+class AsyncDocumentSubresourceFilter;
+class ActivationStateComputingNavigationThrottle;
+class SubframeNavigationFilteringThrottle;
+
+// The ContentSubresourceFilterThrottleManager manages NavigationThrottles in
+// order to calculate frame activation states and subframe navigation filtering,
+// within a given WebContents. It contains a mapping of all activated
+// RenderFrameHosts, along with their associated DocumentSubresourceFilters.
+//
+// The class is designed to be used by a Delegate, which shares lifetime with
+// this class (aka the typical lifetime of a WebContentsObserver). The delegate
+// will be notified of the first disallowed subresource load for a top level
+// navgation, and has veto power for frame activation.
+class ContentSubresourceFilterThrottleManager
+ : public content::WebContentsObserver {
+ public:
+ // It is expected that the Delegate outlives |this|, and manages the lifetime
+ // of this class.
+ class Delegate {
+ public:
+ // The embedder may be interested in displaying UI to the user when the
+ // first load is disallowed for a given page load.
+ virtual void OnFirstSubresourceLoadDisallowed() {}
+
+ // Let the delegate have the last word when it comes to activation. It might
+ // have a specific whitelist.
+ virtual bool ShouldSuppressActivation(
+ content::NavigationHandle* navigation_handle);
+
+ // Temporary method to help the delegate compute the activation decision.
+ virtual void WillProcessResponse(
+ content::NavigationHandle* navigation_handle) {}
+ };
+
+ ContentSubresourceFilterThrottleManager(
+ Delegate* delegate,
+ VerifiedRulesetDealer::Handle* dealer_handle,
+ content::WebContents* web_contents);
+ ~ContentSubresourceFilterThrottleManager() override;
+
+ // Sets the desired page-level |activation_state| for the currently ongoing
+ // page load, identified by its main-frame |navigation_handle|. To be called
+ // by the embedder at the latest in the WillProcessResponse stage from a
+ // NavigationThrottle that was registered before the throttles created by this
+ // manager in MaybeAppendNavigationThrottles(). If this method is not called
+ // for a main-frame navigation, the default behavior is no activation for that
+ // page load.
+ void NotifyPageActivationComputed(
+ content::NavigationHandle* navigation_handle,
+ const ActivationState& activation_state);
+
+ // This method inspects |navigation_handle| and attaches navigation throttles
+ // appropriately, based on the current state of frame activation.
+ //
+ // 1. Subframe navigation filtering throttles are appended if the parent
+ // frame is activated.
+ // 2. Activation state computing throttles are appended if either the
+ // navigation is a main frame navigation, or if the parent frame is activated.
+ //
+ // Note that there is currently no constraints on the ordering of throttles.
+ void MaybeAppendNavigationThrottles(
+ content::NavigationHandle* navigation_handle,
+ std::vector<std::unique_ptr<content::NavigationThrottle>>* throttles);
+
+ VerifiedRuleset::Handle* ruleset_handle_for_testing() {
+ return ruleset_handle_.get();
+ }
+
+ protected:
+ // content::WebContentsObserver:
+ void RenderFrameDeleted(content::RenderFrameHost* frame_host) override;
+ void ReadyToCommitNavigation(
+ content::NavigationHandle* navigation_handle) override;
+ void DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) override;
+ bool OnMessageReceived(const IPC::Message& message,
+ content::RenderFrameHost* render_frame_host) override;
+
+ private:
+ std::unique_ptr<SubframeNavigationFilteringThrottle>
+ MaybeCreateSubframeNavigationFilteringThrottle(
+ content::NavigationHandle* navigation_handle);
+ std::unique_ptr<ActivationStateComputingNavigationThrottle>
+ MaybeCreateActivationStateComputingThrottle(
+ content::NavigationHandle* navigation_handle);
+
+ // Will return nullptr if the parent frame of this navigation is not
+ // activated (and therefore has no subresource filter).
+ AsyncDocumentSubresourceFilter* GetParentFrameFilter(
+ content::NavigationHandle* child_frame_navigation);
+
+ // Calls OnFirstSubresourceLoadDisallowed on the Delegate at most once per
+ // committed, non-same-page navigation in the main frame.
+ // TODO(csharrison): Ensure IPCs from the renderer go through this path when
+ // they disallow subresource loads.
+ void MaybeCallFirstDisallowedLoad();
+
+ VerifiedRuleset::Handle* EnsureRulesetHandle();
+ void DestroyRulesetHandleIfNoLongerUsed();
+
+ // For each RenderFrameHost where the last committed load has subresource
+ // filtering activated, owns the corresponding AsyncDocumentSubresourceFilter.
+ std::unordered_map<content::RenderFrameHost*,
+ std::unique_ptr<AsyncDocumentSubresourceFilter>>
+ activated_frame_hosts_;
+
+ // For each ongoing navigation that requires activation state computation,
+ // keeps track of the throttle that is carrying out that computation, so that
+ // the result can be retrieved when the navigation is ready to commit.
+ std::unordered_map<content::NavigationHandle*,
+ ActivationStateComputingNavigationThrottle*>
+ ongoing_activation_throttles_;
+
+ // Lazily instantiated in EnsureRulesetHandle when the first page level
+ // activation is triggered. Will go away when there are no more activated
+ // RenderFrameHosts (i.e. activated_frame_hosts_ is empty).
+ std::unique_ptr<VerifiedRuleset::Handle> ruleset_handle_;
+
+ // True if the current committed main frame load in this WebContents has
+ // notified the delegate that a subresource was disallowed. The callback
+ // should only be called at most once per main frame load.
+ bool current_committed_load_has_notified_disallowed_load_ = false;
+
+ // These members outlive this class.
+ VerifiedRulesetDealer::Handle* dealer_handle_;
+ Delegate* delegate_;
+
+ base::WeakPtrFactory<ContentSubresourceFilterThrottleManager>
+ weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentSubresourceFilterThrottleManager);
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_THROTTLE_MANAGER_H_
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
new file mode 100644
index 00000000000..6c988fb4e82
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
@@ -0,0 +1,700 @@
+// 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/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/test_simple_task_runner.h"
+#include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
+#include "components/subresource_filter/content/common/subresource_filter_messages.h"
+#include "components/subresource_filter/core/common/activation_level.h"
+#include "components/subresource_filter/core/common/activation_state.h"
+#include "components/subresource_filter/core/common/proto/rules.pb.h"
+#include "components/subresource_filter/core/common/test_ruleset_creator.h"
+#include "components/subresource_filter/core/common/test_ruleset_utils.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
+#include "net/base/net_errors.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/url_constants.h"
+
+namespace subresource_filter {
+
+const char kTestURLWithActivation[] = "https://www.page-with-activation.com/";
+const char kTestURLWithActivation2[] =
+ "https://www.page-with-activation-2.com/";
+const char kTestURLWithDryRun[] = "https://www.page-with-dryrun.com/";
+
+// Enum determining when the mock page state throttle notifies the throttle
+// manager of page level activation state.
+enum PageActivationNotificationTiming {
+ WILL_START_REQUEST,
+ WILL_PROCESS_RESPONSE,
+};
+
+// Simple throttle that sends page-level activation to the manager for a
+// specific set of URLs.
+class MockPageStateActivationThrottle : public content::NavigationThrottle {
+ public:
+ MockPageStateActivationThrottle(
+ content::NavigationHandle* navigation_handle,
+ PageActivationNotificationTiming activation_throttle_state,
+ ContentSubresourceFilterThrottleManager* throttle_manager)
+ : content::NavigationThrottle(navigation_handle),
+ activation_throttle_state_(activation_throttle_state),
+ throttle_manager_(throttle_manager) {
+ // Add some default activations.
+ mock_page_activations_[GURL(kTestURLWithActivation)] =
+ ActivationState(ActivationLevel::ENABLED);
+ mock_page_activations_[GURL(kTestURLWithActivation2)] =
+ ActivationState(ActivationLevel::ENABLED);
+ mock_page_activations_[GURL(kTestURLWithDryRun)] =
+ ActivationState(ActivationLevel::DRYRUN);
+ }
+ ~MockPageStateActivationThrottle() override {}
+
+ // content::NavigationThrottle:
+ content::NavigationThrottle::ThrottleCheckResult WillStartRequest() override {
+ return MaybeNotifyActivation(WILL_START_REQUEST);
+ }
+
+ content::NavigationThrottle::ThrottleCheckResult WillProcessResponse()
+ override {
+ return MaybeNotifyActivation(WILL_PROCESS_RESPONSE);
+ }
+
+ private:
+ content::NavigationThrottle::ThrottleCheckResult MaybeNotifyActivation(
+ PageActivationNotificationTiming throttle_state) {
+ if (throttle_state == activation_throttle_state_) {
+ auto it = mock_page_activations_.find(navigation_handle()->GetURL());
+ if (it != mock_page_activations_.end()) {
+ throttle_manager_->NotifyPageActivationComputed(navigation_handle(),
+ it->second);
+ }
+ }
+ return content::NavigationThrottle::PROCEED;
+ }
+
+ std::map<GURL, ActivationState> mock_page_activations_;
+ PageActivationNotificationTiming activation_throttle_state_;
+ ContentSubresourceFilterThrottleManager* throttle_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockPageStateActivationThrottle);
+};
+
+class ContentSubresourceFilterThrottleManagerTest
+ : public content::RenderViewHostTestHarness,
+ public content::WebContentsObserver,
+ public ContentSubresourceFilterThrottleManager::Delegate,
+ public ::testing::WithParamInterface<PageActivationNotificationTiming> {
+ public:
+ ContentSubresourceFilterThrottleManagerTest()
+ : ContentSubresourceFilterThrottleManager::Delegate() {}
+ ~ContentSubresourceFilterThrottleManagerTest() override {}
+
+ // content::RenderViewHostTestHarness:
+ void SetUp() override {
+ content::RenderViewHostTestHarness::SetUp();
+
+ NavigateAndCommit(GURL("https://example.first"));
+
+ Observe(RenderViewHostTestHarness::web_contents());
+
+ // Initialize the ruleset dealer.
+ std::vector<proto::UrlRule> rules;
+ rules.push_back(testing::CreateWhitelistRuleForDocument(
+ "whitelist.com", proto::ACTIVATION_TYPE_DOCUMENT,
+ {"page-with-activation.com"}));
+ rules.push_back(testing::CreateSuffixRule("disallowed.html"));
+ ASSERT_NO_FATAL_FAILURE(test_ruleset_creator_.CreateRulesetWithRules(
+ rules, &test_ruleset_pair_));
+
+ // Make the blocking task runner run on the current task runner for the
+ // tests, to ensure that the NavigationSimulator properly runs all necessary
+ // tasks while waiting for throttle checks to finish.
+ dealer_handle_ = base::MakeUnique<VerifiedRulesetDealer::Handle>(
+ base::MessageLoop::current()->task_runner());
+ dealer_handle_->SetRulesetFile(
+ testing::TestRuleset::Open(test_ruleset_pair_.indexed));
+
+ throttle_manager_ =
+ base::MakeUnique<ContentSubresourceFilterThrottleManager>(
+ this, dealer_handle_.get(),
+ RenderViewHostTestHarness::web_contents());
+ }
+
+ void TearDown() override {
+ throttle_manager_.reset();
+ dealer_handle_.reset();
+ base::RunLoop().RunUntilIdle();
+ content::RenderViewHostTestHarness::TearDown();
+ }
+
+ void ExpectActivationSignalForFrame(content::RenderFrameHost* rfh,
+ bool expect_activation) {
+ content::MockRenderProcessHost* render_process_host =
+ static_cast<content::MockRenderProcessHost*>(rfh->GetProcess());
+ const IPC::Message* message =
+ render_process_host->sink().GetFirstMessageMatching(
+ SubresourceFilterMsg_ActivateForNextCommittedLoad::ID);
+ ASSERT_EQ(expect_activation, !!message);
+ if (expect_activation) {
+ std::tuple<ActivationState> args;
+ SubresourceFilterMsg_ActivateForNextCommittedLoad::Read(message, &args);
+ ActivationLevel level = std::get<0>(args).activation_level;
+ EXPECT_NE(ActivationLevel::DISABLED, level);
+ }
+ render_process_host->sink().ClearMessages();
+ }
+
+ // Helper methods:
+
+ void CreateTestNavigation(const GURL& url,
+ content::RenderFrameHost* render_frame_host) {
+ DCHECK(!navigation_simulator_);
+ DCHECK(render_frame_host);
+ navigation_simulator_ =
+ content::NavigationSimulator::CreateRendererInitiated(
+ url, render_frame_host);
+ }
+
+ void CreateSubframeWithTestNavigation(const GURL& url,
+ content::RenderFrameHost* parent) {
+ content::RenderFrameHost* subframe =
+ content::RenderFrameHostTester::For(parent)->AppendChild(
+ base::StringPrintf("subframe-%s", url.spec().c_str()));
+ CreateTestNavigation(url, subframe);
+ }
+
+ void SimulateStartAndExpectResult(
+ content::NavigationThrottle::ThrottleCheckResult expect_result) {
+ navigation_simulator_->Start();
+ content::NavigationThrottle::ThrottleCheckResult result =
+ navigation_simulator_->GetLastThrottleCheckResult();
+ EXPECT_EQ(expect_result, result);
+ if (result != content::NavigationThrottle::PROCEED)
+ navigation_simulator_.reset();
+ }
+
+ void SimulateRedirectAndExpectResult(
+ const GURL& new_url,
+ content::NavigationThrottle::ThrottleCheckResult expect_result) {
+ navigation_simulator_->Redirect(new_url);
+ content::NavigationThrottle::ThrottleCheckResult result =
+ navigation_simulator_->GetLastThrottleCheckResult();
+ EXPECT_EQ(expect_result, result);
+ if (result != content::NavigationThrottle::PROCEED)
+ navigation_simulator_.reset();
+ }
+
+ // Returns the RenderFrameHost that the navigation commit in.
+ content::RenderFrameHost* SimulateCommitAndExpectResult(
+ content::NavigationThrottle::ThrottleCheckResult expect_result) {
+ navigation_simulator_->Commit();
+ content::NavigationThrottle::ThrottleCheckResult result =
+ navigation_simulator_->GetLastThrottleCheckResult();
+ EXPECT_EQ(expect_result, result);
+
+ auto scoped_simulator = std::move(navigation_simulator_);
+ if (result == content::NavigationThrottle::PROCEED)
+ return scoped_simulator->GetFinalRenderFrameHost();
+ return nullptr;
+ }
+
+ void SimulateSameDocumentCommit() {
+ navigation_simulator_->CommitSameDocument();
+ navigation_simulator_.reset();
+ }
+
+ void SimulateFailedNavigation(net::Error error) {
+ navigation_simulator_->Fail(error);
+ if (error != net::ERR_ABORTED) {
+ navigation_simulator_->CommitErrorPage();
+ }
+ navigation_simulator_.reset();
+ }
+
+ void NavigateAndCommitMainFrame(const GURL& url) {
+ CreateTestNavigation(url, main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ }
+
+ void SuppressActivationForUrl(const GURL& url) {
+ urls_to_suppress_activation_.insert(url);
+ }
+
+ bool ManagerHasRulesetHandle() {
+ return throttle_manager_->ruleset_handle_for_testing();
+ }
+
+ int disallowed_notification_count() { return disallowed_notification_count_; }
+
+ int attempted_frame_activations() { return attempted_frame_activations_; }
+
+ protected:
+ // content::WebContentsObserver
+ void DidStartNavigation(
+ content::NavigationHandle* navigation_handle) override {
+ if (navigation_handle->IsSameDocument())
+ return;
+
+ // Inject the proper throttles at this time.
+ std::vector<std::unique_ptr<content::NavigationThrottle>> throttles;
+ PageActivationNotificationTiming state =
+ ::testing::UnitTest::GetInstance()->current_test_info()->value_param()
+ ? GetParam()
+ : WILL_PROCESS_RESPONSE;
+ throttles.push_back(base::MakeUnique<MockPageStateActivationThrottle>(
+ navigation_handle, state, throttle_manager_.get()));
+ throttle_manager_->MaybeAppendNavigationThrottles(navigation_handle,
+ &throttles);
+ for (auto& it : throttles) {
+ navigation_handle->RegisterThrottleForTesting(std::move(it));
+ }
+ }
+
+ // ContentSubresourceFilterThrottleManager::Delegate:
+ void OnFirstSubresourceLoadDisallowed() override {
+ ++disallowed_notification_count_;
+ }
+
+ bool ShouldSuppressActivation(
+ content::NavigationHandle* navigation_handle) override {
+ ++attempted_frame_activations_;
+ return urls_to_suppress_activation_.find(navigation_handle->GetURL()) !=
+ urls_to_suppress_activation_.end();
+ }
+
+ private:
+ testing::TestRulesetCreator test_ruleset_creator_;
+ testing::TestRulesetPair test_ruleset_pair_;
+
+ std::set<GURL> urls_to_suppress_activation_;
+
+ std::unique_ptr<VerifiedRulesetDealer::Handle> dealer_handle_;
+
+ std::unique_ptr<ContentSubresourceFilterThrottleManager> throttle_manager_;
+
+ std::unique_ptr<content::NavigationSimulator> navigation_simulator_;
+
+ // Incremented on every OnFirstSubresourceLoadDisallowed call.
+ int disallowed_notification_count_ = 0;
+
+ // Incremented every time the manager queries the harness for activation
+ // suppression.
+ int attempted_frame_activations_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentSubresourceFilterThrottleManagerTest);
+};
+
+INSTANTIATE_TEST_CASE_P(PageActivationNotificationTiming,
+ ContentSubresourceFilterThrottleManagerTest,
+ ::testing::Values(WILL_START_REQUEST,
+ WILL_PROCESS_RESPONSE));
+
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ ActivateMainFrameAndFilterSubframeNavigation) {
+ // 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/disallowed.html"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::CANCEL);
+
+ EXPECT_EQ(1, disallowed_notification_count());
+ EXPECT_EQ(1, attempted_frame_activations());
+}
+
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ ActivateMainFrameAndDoNotFilterDryRun) {
+ // Commit a navigation that triggers page level activation.
+ NavigateAndCommitMainFrame(GURL(kTestURLWithDryRun));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+
+ // A disallowed subframe navigation should not be filtered in dry-run mode.
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/disallowed.html"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ content::RenderFrameHost* child =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ // But it should still be activated.
+ ExpectActivationSignalForFrame(child, true /* expect_activation */);
+
+ EXPECT_EQ(0, disallowed_notification_count());
+ EXPECT_EQ(2, attempted_frame_activations());
+}
+
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ ActivateMainFrameAndFilterSubframeNavigationOnRedirect) {
+ // Commit a navigation that triggers page level activation.
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+
+ // A disallowed subframe navigation via redirect should be successfully
+ // filtered.
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/before-redirect.html"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ SimulateRedirectAndExpectResult(
+ GURL("https://www.example.com/disallowed.html"),
+ content::NavigationThrottle::CANCEL);
+
+ EXPECT_EQ(1, disallowed_notification_count());
+ EXPECT_EQ(1, attempted_frame_activations());
+}
+
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ ActivateMainFrameAndDoNotFilterSubframeNavigation) {
+ // Commit a navigation that triggers page level activation.
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+
+ // An allowed subframe navigation should complete successfully.
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/allowed1.html"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ SimulateRedirectAndExpectResult(GURL("https://www.example.com/allowed2.html"),
+ content::NavigationThrottle::PROCEED);
+ content::RenderFrameHost* child =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(child, true /* expect_activation */);
+
+ EXPECT_EQ(0, disallowed_notification_count());
+ EXPECT_EQ(2, attempted_frame_activations());
+}
+
+// This should fail if the throttle manager notifies the delegate twice of a
+// disallowed load for the same page load.
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ 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());
+ SimulateStartAndExpectResult(content::NavigationThrottle::CANCEL);
+
+ EXPECT_EQ(1, disallowed_notification_count());
+
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/2/disallowed.html"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::CANCEL);
+
+ EXPECT_EQ(1, disallowed_notification_count());
+ EXPECT_EQ(1, attempted_frame_activations());
+}
+
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ 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());
+ SimulateStartAndExpectResult(content::NavigationThrottle::CANCEL);
+
+ EXPECT_EQ(1, disallowed_notification_count());
+
+ // Commit another navigation that triggers page level activation.
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation2));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/2/disallowed.html"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::CANCEL);
+
+ EXPECT_EQ(2, disallowed_notification_count());
+ EXPECT_EQ(2, attempted_frame_activations());
+}
+
+// Test that the disallow load notification will not be repeated for the first
+// disallowed load that follows a same-document navigation.
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ ActivateMainFrameDoNotNotifyAfterSameDocumentNav) {
+ // 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());
+ SimulateStartAndExpectResult(content::NavigationThrottle::CANCEL);
+
+ EXPECT_EQ(1, disallowed_notification_count());
+
+ // Commit another navigation that triggers page level activation.
+ GURL url2 = GURL(base::StringPrintf("%s#ref", kTestURLWithActivation));
+ CreateTestNavigation(url2, main_rfh());
+ SimulateSameDocumentCommit();
+ ExpectActivationSignalForFrame(main_rfh(), false /* expect_activation */);
+
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/2/disallowed.html"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::CANCEL);
+
+ EXPECT_EQ(1, disallowed_notification_count());
+ EXPECT_EQ(1, attempted_frame_activations());
+}
+
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ DoNotFilterForInactiveFrame) {
+ NavigateAndCommitMainFrame(GURL("https://do-not-activate.html"));
+ ExpectActivationSignalForFrame(main_rfh(), false /* expect_activation */);
+
+ // A subframe navigation should complete successfully.
+ CreateSubframeWithTestNavigation(GURL("https://www.example.com/allowed.html"),
+ main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ content::RenderFrameHost* child =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(child, false /* expect_activation */);
+
+ EXPECT_EQ(0, disallowed_notification_count());
+ EXPECT_EQ(0, attempted_frame_activations());
+}
+
+TEST_P(ContentSubresourceFilterThrottleManagerTest, SuppressActivation) {
+ SuppressActivationForUrl(GURL(kTestURLWithActivation));
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), false /* expect_activation */);
+
+ // A subframe navigation should complete successfully.
+ CreateSubframeWithTestNavigation(GURL("https://www.example.com/allowed.html"),
+ main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ content::RenderFrameHost* child =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(child, false /* expect_activation */);
+
+ EXPECT_EQ(0, disallowed_notification_count());
+ EXPECT_EQ(1, attempted_frame_activations());
+}
+
+// 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(ContentSubresourceFilterThrottleManagerTest, RulesetHandleRegeneration) {
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/disallowed.html"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::CANCEL);
+
+ EXPECT_EQ(1, disallowed_notification_count());
+
+ // 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 */);
+
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/disallowed.html"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::CANCEL);
+
+ EXPECT_EQ(2, disallowed_notification_count());
+ EXPECT_EQ(2, attempted_frame_activations());
+}
+
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ SameSiteNavigation_RulesetGoesAway) {
+ GURL same_site_inactive_url =
+ GURL(base::StringPrintf("%ssuppressed.html", kTestURLWithActivation));
+ SuppressActivationForUrl(same_site_inactive_url);
+
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+ EXPECT_TRUE(ManagerHasRulesetHandle());
+
+ NavigateAndCommitMainFrame(same_site_inactive_url);
+ ExpectActivationSignalForFrame(main_rfh(), false /* expect_activation */);
+ EXPECT_FALSE(ManagerHasRulesetHandle());
+
+ // A subframe navigation should complete successfully.
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/disallowed.html"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ content::RenderFrameHost* child =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(child, false /* expect_activation */);
+
+ EXPECT_EQ(0, disallowed_notification_count());
+ EXPECT_EQ(1, attempted_frame_activations());
+}
+
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ SameSiteFailedNavigation_MaintainActivation) {
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+ EXPECT_TRUE(ManagerHasRulesetHandle());
+
+ GURL same_site_inactive_url =
+ GURL(base::StringPrintf("%ssuppressed.html", kTestURLWithActivation));
+ SuppressActivationForUrl(same_site_inactive_url);
+
+ CreateTestNavigation(same_site_inactive_url, main_rfh());
+ SimulateFailedNavigation(net::ERR_ABORTED);
+ EXPECT_TRUE(ManagerHasRulesetHandle());
+ ExpectActivationSignalForFrame(main_rfh(), false /* expect_activation */);
+
+ // A subframe navigation fail.
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/disallowed.html"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::CANCEL);
+
+ EXPECT_EQ(1, disallowed_notification_count());
+ EXPECT_EQ(1, attempted_frame_activations());
+}
+
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ FailedNavigationToErrorPage_NoActivation) {
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+ EXPECT_TRUE(ManagerHasRulesetHandle());
+
+ GURL same_site_inactive_url =
+ GURL(base::StringPrintf("%ssuppressed.html", kTestURLWithActivation));
+ SuppressActivationForUrl(same_site_inactive_url);
+
+ CreateTestNavigation(same_site_inactive_url, main_rfh());
+ SimulateFailedNavigation(net::ERR_FAILED);
+ EXPECT_FALSE(ManagerHasRulesetHandle());
+ ExpectActivationSignalForFrame(main_rfh(), false /* expect_activation */);
+
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/disallowed.html"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ content::RenderFrameHost* child =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(child, false /* expect_activation */);
+
+ EXPECT_EQ(0, disallowed_notification_count());
+ EXPECT_EQ(1, attempted_frame_activations());
+}
+
+// Ensure activation propagates into great-grandchild frames, including cross
+// process ones.
+TEST_P(ContentSubresourceFilterThrottleManagerTest, ActivationPropagation) {
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+
+ // Navigate a subframe to a URL that is not itself disallowed. Subresource
+ // filtering for this subframe document should still be activated.
+ CreateSubframeWithTestNavigation(GURL("https://www.a.com/allowed.html"),
+ main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ content::RenderFrameHost* subframe1 =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(subframe1, true /* expect_activation */);
+
+ // Navigate a sub-subframe to a URL that is not itself disallowed. Subresource
+ // filtering for this subframe document should still be activated.
+ CreateSubframeWithTestNavigation(GURL("https://www.b.com/allowed.html"),
+ subframe1);
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ content::RenderFrameHost* subframe2 =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(subframe2, true /* expect_activation */);
+
+ // A final, nested subframe navigation is filtered.
+ CreateSubframeWithTestNavigation(GURL("https://www.c.com/disallowed.html"),
+ subframe2);
+ SimulateStartAndExpectResult(content::NavigationThrottle::CANCEL);
+
+ EXPECT_EQ(1, disallowed_notification_count());
+ EXPECT_EQ(3, attempted_frame_activations());
+}
+
+// Ensure activation propagates through whitelisted documents.
+TEST_P(ContentSubresourceFilterThrottleManagerTest, ActivationPropagation2) {
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+
+ // Navigate a subframe that is not filtered, but should still activate.
+ CreateSubframeWithTestNavigation(GURL("https://whitelist.com"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ content::RenderFrameHost* subframe1 =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(subframe1, true /* expect_activation */);
+
+ // Navigate a sub-subframe that is not filtered due to the whitelist.
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/disallowed.html"), subframe1);
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ content::RenderFrameHost* subframe2 =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(subframe2, true /* expect_activation */);
+
+ EXPECT_EQ(3, attempted_frame_activations());
+ EXPECT_EQ(0, disallowed_notification_count());
+
+ // An identical series of events that don't match whitelist rules cause
+ // filtering.
+ CreateSubframeWithTestNavigation(GURL("https://average-joe.com"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ content::RenderFrameHost* subframe3 =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(subframe3, true /* expect_activation */);
+
+ // Navigate a sub-subframe that is not filtered due to the whitelist.
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/disallowed.html"), subframe3);
+ SimulateStartAndExpectResult(content::NavigationThrottle::CANCEL);
+
+ EXPECT_EQ(4, attempted_frame_activations());
+ EXPECT_EQ(1, disallowed_notification_count());
+}
+
+// Same-site navigations within a single RFH do not persist activation.
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ SameSiteNavigationStopsActivation) {
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+ EXPECT_EQ(1, attempted_frame_activations());
+
+ // Mock a same-site navigation, in the same RFH, this URL does not trigger
+ // page level activation.
+ NavigateAndCommitMainFrame(
+ GURL(base::StringPrintf("%s/some_path/", kTestURLWithActivation)));
+ EXPECT_EQ(1, attempted_frame_activations());
+ ExpectActivationSignalForFrame(main_rfh(), false /* expect_activation */);
+
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/disallowed.html"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ content::RenderFrameHost* child =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(child, false /* expect_activation */);
+
+ EXPECT_EQ(0, disallowed_notification_count());
+ EXPECT_EQ(1, attempted_frame_activations());
+}
+
+// TODO(csharrison): Make sure the following conditions are exercised in tests:
+//
+// - Synchronous navigations to about:blank. These hit issues with the
+// NavigationSimulator currently.
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc b/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc
new file mode 100644
index 00000000000..71a590963ee
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc
@@ -0,0 +1,193 @@
+// 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/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h"
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
+#include "components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h"
+#include "components/subresource_filter/core/common/activation_level.h"
+#include "components/subresource_filter/core/common/activation_state.h"
+#include "components/subresource_filter/core/common/test_ruleset_creator.h"
+#include "content/public/browser/navigation_handle.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"
+
+namespace subresource_filter {
+
+class SubframeNavigationFilteringThrottleTest
+ : public content::RenderViewHostTestHarness,
+ public content::WebContentsObserver {
+ public:
+ SubframeNavigationFilteringThrottleTest() {}
+ ~SubframeNavigationFilteringThrottleTest() override {}
+
+ void SetUp() override {
+ content::RenderViewHostTestHarness::SetUp();
+ NavigateAndCommit(GURL("https://example.test"));
+ Observe(RenderViewHostTestHarness::web_contents());
+ }
+
+ void TearDown() override {
+ dealer_handle_.reset();
+ ruleset_handle_.reset();
+ parent_filter_.reset();
+ RunUntilIdle();
+ content::RenderViewHostTestHarness::TearDown();
+ }
+
+ // content::WebContentsObserver:
+ void DidStartNavigation(
+ content::NavigationHandle* navigation_handle) override {
+ ASSERT_FALSE(navigation_handle->IsInMainFrame());
+ // The |parent_filter_| is the parent frame's filter. Do not register a
+ // throttle if the parent is not activated with a valid filter.
+ if (parent_filter_) {
+ navigation_handle->RegisterThrottleForTesting(
+ base::MakeUnique<SubframeNavigationFilteringThrottle>(
+ navigation_handle, parent_filter_.get()));
+ }
+ }
+
+ void InitializeDocumentSubresourceFilter(const GURL& document_url) {
+ ASSERT_NO_FATAL_FAILURE(
+ test_ruleset_creator_.CreateRulesetToDisallowURLsWithPathSuffix(
+ "disallowed.html", &test_ruleset_pair_));
+
+ // Make the blocking task runner run on the current task runner for the
+ // tests, to ensure that the NavigationSimulator properly runs all necessary
+ // tasks while waiting for throttle checks to finish.
+ dealer_handle_ = base::MakeUnique<VerifiedRulesetDealer::Handle>(
+ base::MessageLoop::current()->task_runner());
+ dealer_handle_->SetRulesetFile(
+ testing::TestRuleset::Open(test_ruleset_pair_.indexed));
+ ruleset_handle_ =
+ base::MakeUnique<VerifiedRuleset::Handle>(dealer_handle_.get());
+
+ testing::TestActivationStateCallbackReceiver activation_state;
+ parent_filter_ = base::MakeUnique<AsyncDocumentSubresourceFilter>(
+ ruleset_handle_.get(),
+ AsyncDocumentSubresourceFilter::InitializationParams(
+ document_url, ActivationLevel::ENABLED,
+ false /* measure_performance */),
+ activation_state.GetCallback());
+ RunUntilIdle();
+ activation_state.ExpectReceivedOnce(
+ ActivationState(ActivationLevel::ENABLED));
+ }
+
+ void RunUntilIdle() { base::RunLoop().RunUntilIdle(); }
+
+ void CreateTestSubframeAndInitNavigation(const GURL& first_url,
+ content::RenderFrameHost* parent) {
+ content::RenderFrameHost* render_frame =
+ content::RenderFrameHostTester::For(parent)->AppendChild(
+ base::StringPrintf("subframe-%s", first_url.spec().c_str()));
+ navigation_simulator_ =
+ content::NavigationSimulator::CreateRendererInitiated(first_url,
+ render_frame);
+ }
+
+ void SimulateStartAndExpectResult(
+ content::NavigationThrottle::ThrottleCheckResult expect_result) {
+ navigation_simulator_->Start();
+ EXPECT_EQ(expect_result,
+ navigation_simulator_->GetLastThrottleCheckResult());
+ }
+
+ void SimulateRedirectAndExpectResult(
+ const GURL& new_url,
+ content::NavigationThrottle::ThrottleCheckResult expect_result) {
+ navigation_simulator_->Redirect(new_url);
+ EXPECT_EQ(expect_result,
+ navigation_simulator_->GetLastThrottleCheckResult());
+ }
+
+ void SimulateCommitAndExpectResult(
+ content::NavigationThrottle::ThrottleCheckResult expect_result) {
+ navigation_simulator_->Commit();
+ EXPECT_EQ(expect_result,
+ navigation_simulator_->GetLastThrottleCheckResult());
+ }
+
+ private:
+ testing::TestRulesetCreator test_ruleset_creator_;
+ testing::TestRulesetPair test_ruleset_pair_;
+
+ std::unique_ptr<VerifiedRulesetDealer::Handle> dealer_handle_;
+ std::unique_ptr<VerifiedRuleset::Handle> ruleset_handle_;
+
+ std::unique_ptr<AsyncDocumentSubresourceFilter> parent_filter_;
+
+ std::unique_ptr<content::NavigationSimulator> navigation_simulator_;
+
+ DISALLOW_COPY_AND_ASSIGN(SubframeNavigationFilteringThrottleTest);
+};
+
+TEST_F(SubframeNavigationFilteringThrottleTest, FilterOnStart) {
+ InitializeDocumentSubresourceFilter(GURL("https://example.test"));
+ CreateTestSubframeAndInitNavigation(
+ GURL("https://example.test/disallowed.html"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::CANCEL);
+}
+
+TEST_F(SubframeNavigationFilteringThrottleTest, FilterOnRedirect) {
+ InitializeDocumentSubresourceFilter(GURL("https://example.test"));
+ CreateTestSubframeAndInitNavigation(GURL("https://example.test/allowed.html"),
+ main_rfh());
+
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ SimulateRedirectAndExpectResult(GURL("https://example.test/disallowed.html"),
+ content::NavigationThrottle::CANCEL);
+}
+
+TEST_F(SubframeNavigationFilteringThrottleTest, FilterOnSecondRedirect) {
+ InitializeDocumentSubresourceFilter(GURL("https://example.test"));
+ CreateTestSubframeAndInitNavigation(GURL("https://example.test/allowed.html"),
+ main_rfh());
+
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ SimulateRedirectAndExpectResult(GURL("https://example.test/allowed2.html"),
+ content::NavigationThrottle::PROCEED);
+ SimulateRedirectAndExpectResult(GURL("https://example.test/disallowed.html"),
+ content::NavigationThrottle::CANCEL);
+}
+
+TEST_F(SubframeNavigationFilteringThrottleTest, NeverFilterNonMatchingRule) {
+ InitializeDocumentSubresourceFilter(GURL("https://example.test"));
+ CreateTestSubframeAndInitNavigation(GURL("https://example.test/allowed.html"),
+ main_rfh());
+
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ SimulateRedirectAndExpectResult(GURL("https://example.test/allowed2.html"),
+ content::NavigationThrottle::PROCEED);
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+}
+
+TEST_F(SubframeNavigationFilteringThrottleTest, FilterSubsubframe) {
+ // Fake an activation of the subframe.
+ content::RenderFrameHost* parent_subframe =
+ content::RenderFrameHostTester::For(main_rfh())
+ ->AppendChild("parent-sub");
+ GURL test_url = GURL("https://example.test");
+ content::RenderFrameHostTester::For(parent_subframe)
+ ->SimulateNavigationStart(test_url);
+ InitializeDocumentSubresourceFilter(GURL("https://example.test"));
+ content::RenderFrameHostTester::For(parent_subframe)
+ ->SimulateNavigationCommit(test_url);
+
+ CreateTestSubframeAndInitNavigation(
+ GURL("https://example.test/disallowed.html"), parent_subframe);
+ SimulateStartAndExpectResult(content::NavigationThrottle::CANCEL);
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_client.h b/chromium/components/subresource_filter/content/browser/subresource_filter_client.h
index f834a10263e..b9be5a5c831 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_client.h
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_client.h
@@ -5,6 +5,10 @@
#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_
#define COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_
+#include "components/subresource_filter/content/browser/verified_ruleset_dealer.h"
+
+class GURL;
+
namespace subresource_filter {
class SubresourceFilterClient {
@@ -18,6 +22,16 @@ class SubresourceFilterClient {
// a bubble is shown that explains the feature and alalows the user to turn it
// off.
virtual void ToggleNotificationVisibility(bool visibility) = 0;
+
+ // Returns true if the given URL is whitelisted from activation via content
+ // settings. This should only be called for main frame URLs.
+ virtual bool IsWhitelistedByContentSettings(const GURL& url) = 0;
+
+ // Adds |url| to the BLOCKED state via content settings for the current
+ // profile.
+ virtual void WhitelistByContentSettings(const GURL& url) = 0;
+
+ virtual VerifiedRulesetDealer::Handle* GetRulesetDealer() = 0;
};
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
new file mode 100644
index 00000000000..d75a56a3488
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
@@ -0,0 +1,144 @@
+// Copyright (c) 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/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h"
+
+#include <vector>
+
+#include "base/timer/timer.h"
+#include "components/safe_browsing_db/v4_local_database_manager.h"
+#include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+
+namespace {
+
+// Maximum time in milliseconds to wait for the Safe Browsing service to
+// verify a URL. After this amount of time the outstanding check will be
+// aborted, and the URL will be treated as if it didn't belong to the
+// Subresource Filter only list.
+constexpr base::TimeDelta kCheckURLTimeout = base::TimeDelta::FromSeconds(5);
+
+} // namespace
+
+namespace subresource_filter {
+
+class SubresourceFilterSafeBrowsingActivationThrottle::SBDatabaseClient
+ : public safe_browsing::SafeBrowsingDatabaseManager::Client {
+ public:
+ SBDatabaseClient(
+ scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
+ database_manager,
+ base::WeakPtr<SubresourceFilterSafeBrowsingActivationThrottle> throttle,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
+ : database_manager_(std::move(database_manager)),
+ throttle_(throttle),
+ io_task_runner_(io_task_runner) {}
+
+ ~SBDatabaseClient() override {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ database_manager_->CancelCheck(this);
+ }
+
+ void CheckUrlOnIO(const GURL& url) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ DCHECK(!url.is_empty());
+ url_being_checked_ = url;
+ if (database_manager_->CheckUrlForSubresourceFilter(url, this)) {
+ OnCheckBrowseUrlResult(url, safe_browsing::SB_THREAT_TYPE_SAFE,
+ safe_browsing::ThreatMetadata());
+ return;
+ }
+ timer_.Start(FROM_HERE, kCheckURLTimeout, this,
+ &SubresourceFilterSafeBrowsingActivationThrottle::
+ SBDatabaseClient::OnCheckUrlTimeout);
+ }
+
+ void OnCheckBrowseUrlResult(
+ const GURL& url,
+ safe_browsing::SBThreatType threat_type,
+ const safe_browsing::ThreatMetadata& metadata) override {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ DCHECK_EQ(url_being_checked_, url);
+ timer_.Stop(); // Cancel the timeout timer.
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&SubresourceFilterSafeBrowsingActivationThrottle::
+ OnCheckUrlResultOnUI,
+ throttle_, url, threat_type, metadata.threat_pattern_type));
+ }
+
+ // Callback for when the safe browsing check has taken longer than
+ // kCheckURLTimeout.
+ void OnCheckUrlTimeout() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ database_manager_->CancelCheck(this);
+
+ OnCheckBrowseUrlResult(url_being_checked_,
+ safe_browsing::SB_THREAT_TYPE_SAFE,
+ safe_browsing::ThreatMetadata());
+ }
+
+ private:
+ scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager_;
+
+ // Timer to abort the safe browsing check if it takes too long.
+ base::OneShotTimer timer_;
+ GURL url_being_checked_;
+
+ base::WeakPtr<SubresourceFilterSafeBrowsingActivationThrottle> throttle_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(SBDatabaseClient);
+};
+
+SubresourceFilterSafeBrowsingActivationThrottle::
+ SubresourceFilterSafeBrowsingActivationThrottle(
+ content::NavigationHandle* handle,
+ scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
+ database_manager)
+ : NavigationThrottle(handle),
+ io_task_runner_(content::BrowserThread::GetTaskRunnerForThread(
+ content::BrowserThread::IO)),
+ database_client_(
+ new SubresourceFilterSafeBrowsingActivationThrottle::SBDatabaseClient(
+ std::move(database_manager),
+ AsWeakPtr(),
+ base::ThreadTaskRunnerHandle::Get()),
+ base::OnTaskRunnerDeleter(io_task_runner_)) {}
+
+SubresourceFilterSafeBrowsingActivationThrottle::
+ ~SubresourceFilterSafeBrowsingActivationThrottle() {}
+
+content::NavigationThrottle::ThrottleCheckResult
+SubresourceFilterSafeBrowsingActivationThrottle::WillProcessResponse() {
+ io_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&SubresourceFilterSafeBrowsingActivationThrottle::
+ SBDatabaseClient::CheckUrlOnIO,
+ base::Unretained(database_client_.get()),
+ navigation_handle()->GetURL()));
+ return content::NavigationThrottle::ThrottleCheckResult::DEFER;
+}
+
+void SubresourceFilterSafeBrowsingActivationThrottle::OnCheckUrlResultOnUI(
+ const GURL& url,
+ safe_browsing::SBThreatType threat_type,
+ safe_browsing::ThreatPatternType pattern_type) {
+ content::WebContents* web_contents = navigation_handle()->GetWebContents();
+ if (web_contents) {
+ using subresource_filter::ContentSubresourceFilterDriverFactory;
+ ContentSubresourceFilterDriverFactory* driver_factory =
+ ContentSubresourceFilterDriverFactory::FromWebContents(web_contents);
+ DCHECK(driver_factory);
+
+ driver_factory->OnMainResourceMatchedSafeBrowsingBlacklist(
+ url, std::vector<GURL>(), threat_type, pattern_type);
+ }
+ // TODO(https://crbug.com/704508): We should measure the delay introduces by
+ // this check. Similarly, as it's done the Safe Browsing Resource throttle.
+ navigation_handle()->Resume();
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
new file mode 100644
index 00000000000..082076bada7
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
@@ -0,0 +1,51 @@
+// Copyright (c) 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_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_SAFE_BROWSING_ACTIVATION_THROTTLE_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_SAFE_BROWSING_ACTIVATION_THROTTLE_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "components/safe_browsing_db/database_manager.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "url/gurl.h"
+
+namespace subresource_filter {
+
+// Navigation throttle responsible for activating subresource filtering on page
+// loads that match the SUBRESOURCE_FILTER Safe Browsing list.
+class SubresourceFilterSafeBrowsingActivationThrottle
+ : public content::NavigationThrottle,
+ public base::SupportsWeakPtr<
+ SubresourceFilterSafeBrowsingActivationThrottle> {
+ public:
+ SubresourceFilterSafeBrowsingActivationThrottle(
+ content::NavigationHandle* handle,
+ scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
+ database_manager);
+
+ ~SubresourceFilterSafeBrowsingActivationThrottle() override;
+
+ // content::NavigationThrottle:
+ content::NavigationThrottle::ThrottleCheckResult WillProcessResponse()
+ override;
+
+ void OnCheckUrlResultOnUI(const GURL& url,
+ safe_browsing::SBThreatType threat_type,
+ safe_browsing::ThreatPatternType pattern_type);
+
+ private:
+ class SBDatabaseClient;
+
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+ std::unique_ptr<SBDatabaseClient, base::OnTaskRunnerDeleter> database_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(SubresourceFilterSafeBrowsingActivationThrottle);
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_SAFE_BROWSING_ACTIVATION_THROTTLE_H_
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
new file mode 100644
index 00000000000..0a49f61053c
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
@@ -0,0 +1,321 @@
+// 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/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h"
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial.h"
+#include "base/test/histogram_tester.h"
+#include "components/safe_browsing_db/test_database_manager.h"
+#include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
+#include "components/subresource_filter/content/browser/subresource_filter_client.h"
+#include "components/subresource_filter/core/browser/subresource_filter_features.h"
+#include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h"
+#include "components/subresource_filter/core/common/test_ruleset_creator.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.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/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace subresource_filter {
+
+namespace {
+
+char kURL[] = "http://example.test/";
+char kRedirectURL[] = "http://foo.test/";
+
+// Names of navigation chain patterns histogram.
+const char kMatchesPatternHistogramNameSubresourceFilterSuffix[] =
+ "SubresourceFilter.PageLoad.RedirectChainMatchPattern."
+ "SubresourceFilterOnly";
+const char kNavigationChainSizeSubresourceFilterSuffix[] =
+ "SubresourceFilter.PageLoad.RedirectChainLength.SubresourceFilterOnly";
+
+// Human readable representation of expected redirect chain match patterns.
+// The explanations for the buckets given for the following redirect chain:
+// A->B->C->D, where A is initial URL and D is a final URL.
+enum RedirectChainMatchPattern {
+ EMPTY, // No histograms were recorded.
+ F0M0L1, // D is a Safe Browsing match.
+ F0M1L0, // B or C, or both are Safe Browsing matches.
+ F0M1L1, // B or C, or both and D are Safe Browsing matches.
+ F1M0L0, // A is Safe Browsing match
+ F1M0L1, // A and D are Safe Browsing matches.
+ F1M1L0, // B and/or C and A are Safe Browsing matches.
+ F1M1L1, // B and/or C and A and D are Safe Browsing matches.
+ NO_REDIRECTS_HIT, // Redirect chain consists of single URL, aka no redirects
+ // has happened, and this URL was a Safe Browsing hit.
+ NUM_HIT_PATTERNS,
+};
+
+// Database manager that allows any URL to be configured as blacklisted for
+// testing.
+class FakeSafeBrowsingDatabaseManager
+ : public safe_browsing::TestSafeBrowsingDatabaseManager {
+ public:
+ FakeSafeBrowsingDatabaseManager() : simulate_timeout_(false) {}
+
+ void AddBlacklistedUrl(const GURL& url,
+ safe_browsing::SBThreatType threat_type) {
+ url_to_threat_type_[url] = threat_type;
+ }
+
+ void SimulateTimeout() { simulate_timeout_ = true; }
+
+ protected:
+ ~FakeSafeBrowsingDatabaseManager() override {}
+
+ bool CheckUrlForSubresourceFilter(const GURL& url, Client* client) override {
+ if (simulate_timeout_)
+ return false;
+ if (!url_to_threat_type_.count(url))
+ return true;
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
+ base::Bind(&Client::OnCheckBrowseUrlResult, base::Unretained(client),
+ url, url_to_threat_type_[url],
+ safe_browsing::ThreatMetadata()));
+ return false;
+ }
+
+ bool CheckResourceUrl(const GURL& url, Client* client) override {
+ return true;
+ }
+
+ bool IsSupported() const override { return true; }
+ bool ChecksAreAlwaysAsync() const override { return false; }
+ bool CanCheckResourceType(
+ content::ResourceType /* resource_type */) const override {
+ return true;
+ }
+
+ safe_browsing::ThreatSource GetThreatSource() const override {
+ return safe_browsing::ThreatSource::LOCAL_PVER4;
+ }
+
+ bool CheckExtensionIDs(const std::set<std::string>& extension_ids,
+ Client* client) override {
+ return true;
+ }
+
+ private:
+ std::map<GURL, safe_browsing::SBThreatType> url_to_threat_type_;
+ bool simulate_timeout_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingDatabaseManager);
+};
+
+class MockSubresourceFilterClient
+ : public subresource_filter::SubresourceFilterClient {
+ public:
+ MockSubresourceFilterClient() {}
+
+ ~MockSubresourceFilterClient() override = default;
+
+ MOCK_METHOD1(ToggleNotificationVisibility, void(bool));
+ MOCK_METHOD1(IsWhitelistedByContentSettings, bool(const GURL&));
+ MOCK_METHOD1(WhitelistByContentSettings, void(const GURL&));
+ MOCK_METHOD0(GetRulesetDealer, VerifiedRulesetDealer::Handle*());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockSubresourceFilterClient);
+};
+
+// Throttle to call WillProcessResponse on the factory, which is otherwise
+// called by the ThrottleManager.
+class TestForwardingNavigationThrottle : public content::NavigationThrottle {
+ public:
+ TestForwardingNavigationThrottle(content::NavigationHandle* handle)
+ : content::NavigationThrottle(handle) {}
+ ~TestForwardingNavigationThrottle() override {}
+
+ // content::NavigationThrottle:
+ content::NavigationThrottle::ThrottleCheckResult WillProcessResponse()
+ override {
+ content::WebContents* web_contents = navigation_handle()->GetWebContents();
+ ContentSubresourceFilterDriverFactory* factory =
+ ContentSubresourceFilterDriverFactory::FromWebContents(web_contents);
+ factory->WillProcessResponse(navigation_handle());
+ return content::NavigationThrottle::PROCEED;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestForwardingNavigationThrottle);
+};
+
+} // namespace
+
+class SubresourceFilterSafeBrowsingActivationThrottleTest
+ : public content::RenderViewHostTestHarness,
+ public content::WebContentsObserver {
+ public:
+ SubresourceFilterSafeBrowsingActivationThrottleTest()
+ : field_trial_list_(nullptr) {}
+ ~SubresourceFilterSafeBrowsingActivationThrottleTest() override {}
+
+ void SetUp() override {
+ content::RenderViewHostTestHarness::SetUp();
+ scoped_feature_toggle_.reset(
+ new testing::ScopedSubresourceFilterFeatureToggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled,
+ kActivationScopeActivationList, kActivationListSubresourceFilter));
+ auto client = base::MakeUnique<MockSubresourceFilterClient>();
+ ContentSubresourceFilterDriverFactory::CreateForWebContents(
+ RenderViewHostTestHarness::web_contents(), std::move(client));
+ fake_safe_browsing_database_ = new FakeSafeBrowsingDatabaseManager();
+ NavigateAndCommit(GURL("https://test.com"));
+ Observe(RenderViewHostTestHarness::web_contents());
+ }
+
+ ContentSubresourceFilterDriverFactory* factory() {
+ return ContentSubresourceFilterDriverFactory::FromWebContents(
+ RenderViewHostTestHarness::web_contents());
+ }
+
+ // content::WebContentsObserver:
+ void DidStartNavigation(
+ content::NavigationHandle* navigation_handle) override {
+ ASSERT_TRUE(navigation_handle->IsInMainFrame());
+ navigation_handle_ = navigation_handle;
+ navigation_handle->RegisterThrottleForTesting(
+ base::MakeUnique<SubresourceFilterSafeBrowsingActivationThrottle>(
+ navigation_handle, fake_safe_browsing_database_));
+ navigation_handle->RegisterThrottleForTesting(
+ base::MakeUnique<TestForwardingNavigationThrottle>(navigation_handle));
+ }
+
+ void SimulateStartAndExpectProceed() {
+ navigation_simulator_->Start();
+ EXPECT_EQ(content::NavigationThrottle::PROCEED,
+ navigation_simulator_->GetLastThrottleCheckResult());
+ }
+
+ void SimulateRedirectAndExpectProceed(const GURL& new_url) {
+ navigation_simulator_->Redirect(new_url);
+ EXPECT_EQ(content::NavigationThrottle::PROCEED,
+ navigation_simulator_->GetLastThrottleCheckResult());
+ }
+
+ void SimulateCommitAndExpectProceed() {
+ navigation_simulator_->Commit();
+ EXPECT_EQ(content::NavigationThrottle::PROCEED,
+ navigation_simulator_->GetLastThrottleCheckResult());
+ }
+
+ void CreateTestNavigationForMainFrame(const GURL& first_url) {
+ navigation_simulator_ =
+ content::NavigationSimulator::CreateRendererInitiated(first_url,
+ main_rfh());
+ }
+
+ void ConfigureAsSubresourceFilterOnlyURL(const GURL& url) {
+ fake_safe_browsing_database_->AddBlacklistedUrl(
+ url, safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER);
+ }
+
+ void SimulateTimeout() { fake_safe_browsing_database_->SimulateTimeout(); }
+
+ const base::HistogramTester& tester() const { return tester_; }
+
+ private:
+ base::FieldTrialList field_trial_list_;
+ std::unique_ptr<testing::ScopedSubresourceFilterFeatureToggle>
+ scoped_feature_toggle_;
+ std::unique_ptr<content::NavigationSimulator> navigation_simulator_;
+ scoped_refptr<FakeSafeBrowsingDatabaseManager> fake_safe_browsing_database_;
+ base::HistogramTester tester_;
+ content::NavigationHandle* navigation_handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(SubresourceFilterSafeBrowsingActivationThrottleTest);
+};
+
+TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
+ ListNotMatched_NoActivation) {
+ const GURL url(kURL);
+ CreateTestNavigationForMainFrame(url);
+ SimulateStartAndExpectProceed();
+ SimulateCommitAndExpectProceed();
+ EXPECT_EQ(ContentSubresourceFilterDriverFactory::ActivationDecision::
+ ACTIVATION_LIST_NOT_MATCHED,
+ factory()->GetActivationDecisionForLastCommittedPageLoad());
+ tester().ExpectTotalCount(kMatchesPatternHistogramNameSubresourceFilterSuffix,
+ 0);
+ tester().ExpectTotalCount(kNavigationChainSizeSubresourceFilterSuffix, 0);
+}
+
+TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
+ ListMatched_Activation) {
+ const GURL url(kURL);
+ ConfigureAsSubresourceFilterOnlyURL(url);
+ CreateTestNavigationForMainFrame(url);
+ SimulateStartAndExpectProceed();
+ SimulateCommitAndExpectProceed();
+ EXPECT_EQ(
+ ContentSubresourceFilterDriverFactory::ActivationDecision::ACTIVATED,
+ factory()->GetActivationDecisionForLastCommittedPageLoad());
+ tester().ExpectUniqueSample(
+ kMatchesPatternHistogramNameSubresourceFilterSuffix, NO_REDIRECTS_HIT, 1);
+ tester().ExpectUniqueSample(kNavigationChainSizeSubresourceFilterSuffix, 1,
+ 1);
+}
+
+TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
+ ListNotMatchedAfterRedirect_NoActivation) {
+ const GURL url(kURL);
+ CreateTestNavigationForMainFrame(url);
+ SimulateStartAndExpectProceed();
+ SimulateRedirectAndExpectProceed(GURL(kRedirectURL));
+ SimulateCommitAndExpectProceed();
+ EXPECT_EQ(ContentSubresourceFilterDriverFactory::ActivationDecision::
+ ACTIVATION_LIST_NOT_MATCHED,
+ factory()->GetActivationDecisionForLastCommittedPageLoad());
+ tester().ExpectTotalCount(kMatchesPatternHistogramNameSubresourceFilterSuffix,
+ 0);
+ tester().ExpectTotalCount(kNavigationChainSizeSubresourceFilterSuffix, 0);
+}
+
+TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
+ ListMatchedAfterRedirect_Activation) {
+ const GURL url(kURL);
+ ConfigureAsSubresourceFilterOnlyURL(GURL(kRedirectURL));
+ CreateTestNavigationForMainFrame(url);
+ SimulateStartAndExpectProceed();
+ SimulateRedirectAndExpectProceed(GURL(kRedirectURL));
+ SimulateCommitAndExpectProceed();
+ EXPECT_EQ(
+ ContentSubresourceFilterDriverFactory::ActivationDecision::ACTIVATED,
+ factory()->GetActivationDecisionForLastCommittedPageLoad());
+ tester().ExpectUniqueSample(
+ kMatchesPatternHistogramNameSubresourceFilterSuffix, F0M0L1, 1);
+ tester().ExpectUniqueSample(kNavigationChainSizeSubresourceFilterSuffix, 2,
+ 1);
+}
+
+TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
+ ListNotMatchedAndTimeout_NoActivation) {
+ const GURL url(kURL);
+ SimulateTimeout();
+ CreateTestNavigationForMainFrame(url);
+ SimulateStartAndExpectProceed();
+ SimulateCommitAndExpectProceed();
+ EXPECT_EQ(ContentSubresourceFilterDriverFactory::ActivationDecision::
+ ACTIVATION_LIST_NOT_MATCHED,
+ factory()->GetActivationDecisionForLastCommittedPageLoad());
+ tester().ExpectTotalCount(kMatchesPatternHistogramNameSubresourceFilterSuffix,
+ 0);
+ tester().ExpectTotalCount(kNavigationChainSizeSubresourceFilterSuffix, 0);
+}
+
+// TODO(melandory): Once non-defering check in WillStart is implemented add one
+// more test that destroys the Navigation along with corresponding throttles
+// while the SB check is pending? (To be run by ASAN bots to ensure
+// no use-after-free.)
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.cc b/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.cc
index fab4ae86807..e9467455402 100644
--- a/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.cc
+++ b/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.cc
@@ -25,7 +25,7 @@ void VerifiedRulesetDealer::SetRulesetFile(base::File ruleset_file) {
}
scoped_refptr<const MemoryMappedRuleset> VerifiedRulesetDealer::GetRuleset() {
- DCHECK(CalledOnValidThread());
+ DCHECK(CalledOnValidSequence());
// TODO(pkalinnikov): Record verification status to a histogram.
switch (status_) {
@@ -62,7 +62,7 @@ VerifiedRulesetDealer::Handle::~Handle() = default;
void VerifiedRulesetDealer::Handle::GetDealerAsync(
base::Callback<void(VerifiedRulesetDealer*)> callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
// NOTE: Properties of the sequenced |task_runner| guarantee that the
// |callback| will always be provided with a valid pointer, because the
@@ -73,7 +73,7 @@ void VerifiedRulesetDealer::Handle::GetDealerAsync(
}
void VerifiedRulesetDealer::Handle::SetRulesetFile(base::File file) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
task_runner_->PostTask(
FROM_HERE,
base::Bind(&VerifiedRulesetDealer::SetRulesetFile,
@@ -83,15 +83,15 @@ void VerifiedRulesetDealer::Handle::SetRulesetFile(base::File file) {
// VerifiedRuleset and its Handle. ---------------------------------------------
VerifiedRuleset::VerifiedRuleset() {
- thread_checker_.DetachFromThread();
+ sequence_checker_.DetachFromSequence();
}
VerifiedRuleset::~VerifiedRuleset() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
}
void VerifiedRuleset::Initialize(VerifiedRulesetDealer* dealer) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
DCHECK(dealer);
ruleset_ = dealer->GetRuleset();
}
@@ -104,12 +104,12 @@ VerifiedRuleset::Handle::Handle(VerifiedRulesetDealer::Handle* dealer_handle)
}
VerifiedRuleset::Handle::~Handle() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
}
void VerifiedRuleset::Handle::GetRulesetAsync(
base::Callback<void(VerifiedRuleset*)> callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
task_runner_->PostTask(FROM_HERE, base::Bind(callback, ruleset_.get()));
}
diff --git a/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.h b/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.h
index b49246b0616..3e1915d4ec2 100644
--- a/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.h
+++ b/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.h
@@ -10,8 +10,8 @@
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
-#include "base/threading/thread_checker.h"
#include "components/subresource_filter/content/common/ruleset_dealer.h"
namespace base {
@@ -85,7 +85,7 @@ class VerifiedRulesetDealer::Handle {
// Note: Raw pointer, |dealer_| already holds a reference to |task_runner_|.
base::SequencedTaskRunner* task_runner_;
std::unique_ptr<VerifiedRulesetDealer, base::OnTaskRunnerDeleter> dealer_;
- base::ThreadChecker thread_checker_;
+ base::SequenceChecker sequence_checker_;
DISALLOW_COPY_AND_ASSIGN(Handle);
};
@@ -106,7 +106,7 @@ class VerifiedRuleset {
// Can return nullptr even after initialization in case no ruleset is
// available, or if the ruleset is corrupted.
const MemoryMappedRuleset* Get() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
return ruleset_.get();
}
@@ -115,7 +115,7 @@ class VerifiedRuleset {
void Initialize(VerifiedRulesetDealer* dealer);
scoped_refptr<const MemoryMappedRuleset> ruleset_;
- base::ThreadChecker thread_checker_;
+ base::SequenceChecker sequence_checker_;
DISALLOW_COPY_AND_ASSIGN(VerifiedRuleset);
};
@@ -147,7 +147,7 @@ class VerifiedRuleset::Handle {
// Note: Raw pointer, |ruleset_| already holds a reference to |task_runner_|.
base::SequencedTaskRunner* task_runner_;
std::unique_ptr<VerifiedRuleset, base::OnTaskRunnerDeleter> ruleset_;
- base::ThreadChecker thread_checker_;
+ base::SequenceChecker sequence_checker_;
DISALLOW_COPY_AND_ASSIGN(Handle);
};
diff --git a/chromium/components/subresource_filter/content/common/BUILD.gn b/chromium/components/subresource_filter/content/common/BUILD.gn
index 15ebae2e006..05f9b61a9b4 100644
--- a/chromium/components/subresource_filter/content/common/BUILD.gn
+++ b/chromium/components/subresource_filter/content/common/BUILD.gn
@@ -10,7 +10,8 @@ static_library("common") {
"subresource_filter_message_generator.h",
"subresource_filter_messages.h",
]
- deps = [
+ public_deps = [
+ "//base",
"//components/subresource_filter/core/common",
"//content/public/common",
"//ipc",
diff --git a/chromium/components/subresource_filter/content/common/ruleset_dealer.cc b/chromium/components/subresource_filter/content/common/ruleset_dealer.cc
index 9cdbc3fb200..5977350a9bb 100644
--- a/chromium/components/subresource_filter/content/common/ruleset_dealer.cc
+++ b/chromium/components/subresource_filter/content/common/ruleset_dealer.cc
@@ -10,25 +10,25 @@
namespace subresource_filter {
RulesetDealer::RulesetDealer() {
- DetachFromThread();
+ sequence_checker_.DetachFromSequence();
}
RulesetDealer::~RulesetDealer() = default;
void RulesetDealer::SetRulesetFile(base::File ruleset_file) {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
DCHECK(ruleset_file.IsValid());
ruleset_file_ = std::move(ruleset_file);
weak_cached_ruleset_.reset();
}
bool RulesetDealer::IsRulesetFileAvailable() const {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
return ruleset_file_.IsValid();
}
scoped_refptr<const MemoryMappedRuleset> RulesetDealer::GetRuleset() {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
if (!ruleset_file_.IsValid())
return nullptr;
diff --git a/chromium/components/subresource_filter/content/common/ruleset_dealer.h b/chromium/components/subresource_filter/content/common/ruleset_dealer.h
index 593415418c5..14c1723fbdd 100644
--- a/chromium/components/subresource_filter/content/common/ruleset_dealer.h
+++ b/chromium/components/subresource_filter/content/common/ruleset_dealer.h
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/sequence_checker.h"
namespace subresource_filter {
@@ -30,7 +30,7 @@ class MemoryMappedRuleset;
// they will use the same, cached, MemoryMappedRuleset instance, and will
// not call mmap() multiple times.
//
-class RulesetDealer : protected base::NonThreadSafe {
+class RulesetDealer {
public:
RulesetDealer();
virtual ~RulesetDealer();
@@ -50,12 +50,19 @@ class RulesetDealer : protected base::NonThreadSafe {
// For testing only.
bool has_cached_ruleset() const { return !!weak_cached_ruleset_.get(); }
+ protected:
+ bool CalledOnValidSequence() const {
+ return sequence_checker_.CalledOnValidSequence();
+ }
+
private:
friend class SubresourceFilterRulesetDealerTest;
base::File ruleset_file_;
base::WeakPtr<MemoryMappedRuleset> weak_cached_ruleset_;
+ base::SequenceChecker sequence_checker_;
+
DISALLOW_COPY_AND_ASSIGN(RulesetDealer);
};
diff --git a/chromium/components/subresource_filter/content/common/subresource_filter_messages.h b/chromium/components/subresource_filter/content/common/subresource_filter_messages.h
index 07b4144132b..bef8fc95b23 100644
--- a/chromium/components/subresource_filter/content/common/subresource_filter_messages.h
+++ b/chromium/components/subresource_filter/content/common/subresource_filter_messages.h
@@ -6,6 +6,7 @@
#include "base/time/time.h"
#include "components/subresource_filter/core/common/activation_level.h"
+#include "components/subresource_filter/core/common/activation_state.h"
#include "components/subresource_filter/core/common/document_load_statistics.h"
#include "content/public/common/common_param_traits_macros.h"
#include "ipc/ipc_message.h"
@@ -18,6 +19,13 @@
IPC_ENUM_TRAITS_MAX_VALUE(subresource_filter::ActivationLevel,
subresource_filter::ActivationLevel::LAST);
+IPC_STRUCT_TRAITS_BEGIN(subresource_filter::ActivationState)
+ IPC_STRUCT_TRAITS_MEMBER(activation_level)
+ IPC_STRUCT_TRAITS_MEMBER(filtering_disabled_for_document)
+ IPC_STRUCT_TRAITS_MEMBER(generic_blocking_rules_disabled)
+ IPC_STRUCT_TRAITS_MEMBER(measure_performance)
+IPC_STRUCT_TRAITS_END()
+
IPC_STRUCT_TRAITS_BEGIN(subresource_filter::DocumentLoadStatistics)
IPC_STRUCT_TRAITS_MEMBER(num_loads_total)
IPC_STRUCT_TRAITS_MEMBER(num_loads_evaluated)
@@ -38,7 +46,7 @@ IPC_MESSAGE_CONTROL1(SubresourceFilterMsg_SetRulesetForProcess,
IPC::PlatformFileForTransit /* ruleset_file */);
// Instructs the renderer to activate subresource filtering at the specified
-// |activation_level| for the document load committed next in a frame.
+// |activation_state| for the document load committed next in a frame.
//
// Without browser-side navigation, the message must arrive just before the
// provisional load is committed on the renderer side. In practice, it is often
@@ -49,9 +57,8 @@ IPC_MESSAGE_CONTROL1(SubresourceFilterMsg_SetRulesetForProcess,
// FrameMsg_CommitNavigation.
//
// If no message arrives, the default behavior is ActivationLevel::DISABLED.
-IPC_MESSAGE_ROUTED2(SubresourceFilterMsg_ActivateForNextCommittedLoad,
- subresource_filter::ActivationLevel /* activation_level */,
- bool /* measure_performance */);
+IPC_MESSAGE_ROUTED1(SubresourceFilterMsg_ActivateForNextCommittedLoad,
+ subresource_filter::ActivationState /* activation_state */);
// ----------------------------------------------------------------------------
// Messages sent from the renderer to the browser.
diff --git a/chromium/components/subresource_filter/content/renderer/BUILD.gn b/chromium/components/subresource_filter/content/renderer/BUILD.gn
index 297d587813d..5ef9ab748bc 100644
--- a/chromium/components/subresource_filter/content/renderer/BUILD.gn
+++ b/chromium/components/subresource_filter/content/renderer/BUILD.gn
@@ -17,10 +17,12 @@ static_library("renderer") {
"//components/subresource_filter/core/common",
"//content/public/common",
"//content/public/renderer",
- "//ipc",
"//third_party/WebKit/public:blink",
"//url",
]
+ public_deps = [
+ "//ipc",
+ ]
}
source_set("unit_tests") {
diff --git a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc
index b23a8b2a29a..c9b47d51177 100644
--- a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc
+++ b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc
@@ -37,24 +37,14 @@ SubresourceFilterAgent::SubresourceFilterAgent(
SubresourceFilterAgent::~SubresourceFilterAgent() = default;
-std::vector<GURL> SubresourceFilterAgent::GetAncestorDocumentURLs() {
- std::vector<GURL> urls;
- // As a temporary workaround for --isolate-extensions, ignore the ancestor
- // hierarchy after crossing an extension/non-extension boundary. This,
- // however, will not be a satisfactory solution for OOPIF in general.
- // See: https://crbug.com/637415.
- blink::WebFrame* frame = render_frame()->GetWebFrame();
- do {
- urls.push_back(frame->document().url());
- frame = frame->parent();
- } while (frame && frame->isWebLocalFrame());
- return urls;
+GURL SubresourceFilterAgent::GetDocumentURL() {
+ return render_frame()->GetWebFrame()->GetDocument().Url();
}
void SubresourceFilterAgent::SetSubresourceFilterForCommittedLoad(
std::unique_ptr<blink::WebDocumentSubresourceFilter> filter) {
blink::WebLocalFrame* web_frame = render_frame()->GetWebFrame();
- web_frame->dataSource()->setSubresourceFilter(filter.release());
+ web_frame->DataSource()->SetSubresourceFilter(filter.release());
}
void SubresourceFilterAgent::
@@ -70,20 +60,20 @@ void SubresourceFilterAgent::SendDocumentLoadStatistics(
}
void SubresourceFilterAgent::OnActivateForNextCommittedLoad(
- ActivationLevel activation_level,
- bool measure_performance) {
- activation_level_for_next_commit_ = activation_level;
- measure_performance_for_next_commit_ = measure_performance;
+ ActivationState activation_state) {
+ activation_state_for_next_commit_ = activation_state;
}
void SubresourceFilterAgent::RecordHistogramsOnLoadCommitted() {
// Note: ActivationLevel used to be called ActivationState, the legacy name is
// kept for the histogram.
+ ActivationLevel activation_level =
+ activation_state_for_next_commit_.activation_level;
UMA_HISTOGRAM_ENUMERATION("SubresourceFilter.DocumentLoad.ActivationState",
- static_cast<int>(activation_level_for_next_commit_),
+ static_cast<int>(activation_level),
static_cast<int>(ActivationLevel::LAST) + 1);
- if (activation_level_for_next_commit_ != ActivationLevel::DISABLED) {
+ if (activation_level != ActivationLevel::DISABLED) {
UMA_HISTOGRAM_BOOLEAN("SubresourceFilter.DocumentLoad.RulesetIsAvailable",
ruleset_dealer_->IsRulesetFileAvailable());
}
@@ -133,8 +123,8 @@ void SubresourceFilterAgent::RecordHistogramsOnLoadFinished() {
}
void SubresourceFilterAgent::ResetActivatonStateForNextCommit() {
- activation_level_for_next_commit_ = ActivationLevel::DISABLED;
- measure_performance_for_next_commit_ = false;
+ activation_state_for_next_commit_ =
+ ActivationState(ActivationLevel::DISABLED);
}
void SubresourceFilterAgent::OnDestruct() {
@@ -143,17 +133,19 @@ void SubresourceFilterAgent::OnDestruct() {
void SubresourceFilterAgent::DidCommitProvisionalLoad(
bool is_new_navigation,
- bool is_same_page_navigation) {
- if (is_same_page_navigation)
+ bool is_same_document_navigation) {
+ if (is_same_document_navigation)
return;
filter_for_last_committed_load_.reset();
- std::vector<GURL> ancestor_document_urls = GetAncestorDocumentURLs();
- if (ancestor_document_urls.front().SchemeIsHTTPOrHTTPS() ||
- ancestor_document_urls.front().SchemeIsFile()) {
+ // TODO(csharrison): Use WebURL and WebSecurityOrigin for efficiency here,
+ // which require changes to the unit tests.
+ const GURL& url = GetDocumentURL();
+ if (url.SchemeIsHTTPOrHTTPS() || url.SchemeIsFile()) {
RecordHistogramsOnLoadCommitted();
- if (activation_level_for_next_commit_ != ActivationLevel::DISABLED &&
+ if (activation_state_for_next_commit_.activation_level !=
+ ActivationLevel::DISABLED &&
ruleset_dealer_->IsRulesetFileAvailable()) {
base::OnceClosure first_disallowed_load_callback(
base::BindOnce(&SubresourceFilterAgent::
@@ -162,13 +154,8 @@ void SubresourceFilterAgent::DidCommitProvisionalLoad(
auto ruleset = ruleset_dealer_->GetRuleset();
DCHECK(ruleset);
- ActivationState activation_state =
- ComputeActivationState(activation_level_for_next_commit_,
- measure_performance_for_next_commit_,
- ancestor_document_urls, ruleset.get());
- DCHECK(!ancestor_document_urls.empty());
auto filter = base::MakeUnique<WebDocumentSubresourceFilterImpl>(
- url::Origin(ancestor_document_urls[0]), activation_state,
+ url::Origin(url), activation_state_for_next_commit_,
std::move(ruleset), std::move(first_disallowed_load_callback));
filter_for_last_committed_load_ = filter->AsWeakPtr();
diff --git a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h
index 3269183d59a..22bc3fc2a8d 100644
--- a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h
+++ b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "components/subresource_filter/core/common/activation_level.h"
+#include "components/subresource_filter/core/common/activation_state.h"
#include "content/public/renderer/render_frame_observer.h"
#include "url/gurl.h"
@@ -40,10 +40,8 @@ class SubresourceFilterAgent
protected:
// Below methods are protected virtual so they can be mocked out in tests.
- // Returns the URLs of documents loaded into nested frames starting with the
- // current frame and ending with the main frame. The returned array is
- // guaranteed to have at least one element.
- virtual std::vector<GURL> GetAncestorDocumentURLs();
+ // Returns the URL of the currently committed document.
+ virtual GURL GetDocumentURL();
// Injects the provided subresource |filter| into the DocumentLoader
// orchestrating the most recently committed load.
@@ -59,8 +57,7 @@ class SubresourceFilterAgent
const DocumentLoadStatistics& statistics);
private:
- void OnActivateForNextCommittedLoad(ActivationLevel activation_level,
- bool measure_performance);
+ void OnActivateForNextCommittedLoad(ActivationState activation_state);
void RecordHistogramsOnLoadCommitted();
void RecordHistogramsOnLoadFinished();
void ResetActivatonStateForNextCommit();
@@ -68,7 +65,7 @@ class SubresourceFilterAgent
// content::RenderFrameObserver:
void OnDestruct() override;
void DidCommitProvisionalLoad(bool is_new_navigation,
- bool is_same_page_navigation) override;
+ bool is_same_document_navigation) override;
void DidFailProvisionalLoad(const blink::WebURLError& error) override;
void DidFinishLoad() override;
bool OnMessageReceived(const IPC::Message& message) override;
@@ -76,8 +73,7 @@ class SubresourceFilterAgent
// Owned by the ChromeContentRendererClient and outlives us.
UnverifiedRulesetDealer* ruleset_dealer_;
- ActivationLevel activation_level_for_next_commit_ = ActivationLevel::DISABLED;
- bool measure_performance_for_next_commit_ = false;
+ ActivationState activation_state_for_next_commit_;
base::WeakPtr<WebDocumentSubresourceFilterImpl>
filter_for_last_committed_load_;
diff --git a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
index bbda559ba50..eb8a67b4bc7 100644
--- a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
+++ b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
@@ -46,7 +46,7 @@ class SubresourceFilterAgentUnderTest : public SubresourceFilterAgent {
: SubresourceFilterAgent(nullptr /* RenderFrame */, ruleset_dealer) {}
~SubresourceFilterAgentUnderTest() = default;
- MOCK_METHOD0(GetAncestorDocumentURLs, std::vector<GURL>());
+ MOCK_METHOD0(GetDocumentURL, GURL());
MOCK_METHOD0(OnSetSubresourceFilterForCommittedLoadCalled, void());
MOCK_METHOD0(SignalFirstSubresourceDisallowedForCommittedLoad, void());
MOCK_METHOD1(SendDocumentLoadStatistics, void(const DocumentLoadStatistics&));
@@ -107,9 +107,8 @@ class SubresourceFilterAgentTest : public ::testing::Test {
void ResetAgent() {
agent_.reset(new ::testing::StrictMock<SubresourceFilterAgentUnderTest>(
&ruleset_dealer_));
- ON_CALL(*agent(), GetAncestorDocumentURLs())
- .WillByDefault(::testing::Return(std::vector<GURL>(
- {GURL("http://inner.com/"), GURL("http://outer.com/")})));
+ ON_CALL(*agent(), GetDocumentURL())
+ .WillByDefault(::testing::Return(GURL("http://example.com/")));
}
void SetTestRulesetToDisallowURLsWithPathSuffix(base::StringPiece suffix) {
@@ -121,39 +120,36 @@ class SubresourceFilterAgentTest : public ::testing::Test {
testing::TestRuleset::Open(test_ruleset_pair.indexed));
}
- void StartLoadWithoutSettingActivationLevel() {
+ void StartLoadWithoutSettingActivationState() {
agent_as_rfo()->DidStartProvisionalLoad(nullptr);
agent_as_rfo()->DidCommitProvisionalLoad(
- true /* is_new_navigation */, false /* is_same_page_navigation */);
+ true /* is_new_navigation */, false /* is_same_document_navigation */);
}
- void PerformSamePageNavigationWithoutSettingActivationLevel() {
+ void PerformSameDocumentNavigationWithoutSettingActivationLevel() {
agent_as_rfo()->DidStartProvisionalLoad(nullptr);
agent_as_rfo()->DidCommitProvisionalLoad(
- true /* is_new_navigation */, true /* is_same_page_navigation */);
+ true /* is_new_navigation */, true /* is_same_document_navigation */);
// No DidFinishLoad is called in this case.
}
- void StartLoadAndSetActivationLevel(ActivationLevel activation_level,
- bool measure_performance = false) {
+ void StartLoadAndSetActivationState(ActivationState state) {
agent_as_rfo()->DidStartProvisionalLoad(nullptr);
EXPECT_TRUE(agent_as_rfo()->OnMessageReceived(
- SubresourceFilterMsg_ActivateForNextCommittedLoad(
- 0, activation_level, measure_performance)));
+ SubresourceFilterMsg_ActivateForNextCommittedLoad(0, state)));
agent_as_rfo()->DidCommitProvisionalLoad(
- true /* is_new_navigation */, false /* is_same_page_navigation */);
+ true /* is_new_navigation */, false /* is_same_document_navigation */);
}
void FinishLoad() { agent_as_rfo()->DidFinishLoad(); }
void ExpectSubresourceFilterGetsInjected() {
- EXPECT_CALL(*agent(), GetAncestorDocumentURLs());
+ EXPECT_CALL(*agent(), GetDocumentURL());
EXPECT_CALL(*agent(), OnSetSubresourceFilterForCommittedLoadCalled());
}
void ExpectNoSubresourceFilterGetsInjected() {
- EXPECT_CALL(*agent(), GetAncestorDocumentURLs())
- .Times(::testing::AtLeast(0));
+ EXPECT_CALL(*agent(), GetDocumentURL()).Times(::testing::AtLeast(0));
EXPECT_CALL(*agent(), OnSetSubresourceFilterForCommittedLoadCalled())
.Times(0);
}
@@ -176,16 +172,16 @@ class SubresourceFilterAgentTest : public ::testing::Test {
blink::WebDocumentSubresourceFilter::LoadPolicy expected_policy) {
blink::WebURL url = GURL(url_spec);
blink::WebURLRequest::RequestContext request_context =
- blink::WebURLRequest::RequestContextImage;
+ blink::WebURLRequest::kRequestContextImage;
blink::WebDocumentSubresourceFilter::LoadPolicy actual_policy =
- agent()->filter()->getLoadPolicy(url, request_context);
+ agent()->filter()->GetLoadPolicy(url, request_context);
EXPECT_EQ(expected_policy, actual_policy);
// If the load policy indicated the load was filtered, simulate a filtered
// load callback. In production, this will be called in FrameFetchContext,
// but we simulate the call here.
- if (actual_policy == blink::WebDocumentSubresourceFilter::Disallow)
- agent()->filter()->reportDisallowedLoad();
+ if (actual_policy == blink::WebDocumentSubresourceFilter::kDisallow)
+ agent()->filter()->ReportDisallowedLoad();
}
SubresourceFilterAgentUnderTest* agent() { return agent_.get(); }
@@ -207,7 +203,7 @@ TEST_F(SubresourceFilterAgentTest, DisabledByDefault_NoFilterIsInjected) {
ASSERT_NO_FATAL_FAILURE(
SetTestRulesetToDisallowURLsWithPathSuffix(kTestBothURLsPathSuffix));
ExpectNoSubresourceFilterGetsInjected();
- StartLoadWithoutSettingActivationLevel();
+ StartLoadWithoutSettingActivationState();
FinishLoad();
histogram_tester.ExpectUniqueSample(
@@ -228,7 +224,7 @@ TEST_F(SubresourceFilterAgentTest, Disabled_NoFilterIsInjected) {
ASSERT_NO_FATAL_FAILURE(
SetTestRulesetToDisallowURLsWithPathSuffix(kTestBothURLsPathSuffix));
ExpectNoSubresourceFilterGetsInjected();
- StartLoadAndSetActivationLevel(ActivationLevel::DISABLED);
+ StartLoadAndSetActivationState(ActivationState(ActivationLevel::DISABLED));
FinishLoad();
}
@@ -236,7 +232,7 @@ TEST_F(SubresourceFilterAgentTest,
EnabledButRulesetUnavailable_NoFilterIsInjected) {
base::HistogramTester histogram_tester;
ExpectNoSubresourceFilterGetsInjected();
- StartLoadAndSetActivationLevel(ActivationLevel::ENABLED);
+ StartLoadAndSetActivationState(ActivationState(ActivationLevel::ENABLED));
FinishLoad();
histogram_tester.ExpectUniqueSample(
@@ -256,10 +252,9 @@ TEST_F(SubresourceFilterAgentTest,
TEST_F(SubresourceFilterAgentTest, EmptyDocumentLoad_NoFilterIsInjected) {
base::HistogramTester histogram_tester;
ExpectNoSubresourceFilterGetsInjected();
- EXPECT_CALL(*agent(), GetAncestorDocumentURLs())
- .WillOnce(::testing::Return(
- std::vector<GURL>({GURL("about:blank"), GURL("http://outer.com/")})));
- StartLoadAndSetActivationLevel(ActivationLevel::ENABLED);
+ EXPECT_CALL(*agent(), GetDocumentURL())
+ .WillOnce(::testing::Return(GURL("about:blank")));
+ StartLoadAndSetActivationState(ActivationState(ActivationLevel::ENABLED));
FinishLoad();
histogram_tester.ExpectTotalCount(kDocumentLoadActivationLevel, 0);
@@ -280,26 +275,26 @@ TEST_F(SubresourceFilterAgentTest, Enabled_FilteringIsInEffectForOneLoad) {
SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix));
ExpectSubresourceFilterGetsInjected();
- StartLoadAndSetActivationLevel(ActivationLevel::ENABLED);
+ StartLoadAndSetActivationState(ActivationState(ActivationLevel::ENABLED));
ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
ExpectSignalAboutFirstSubresourceDisallowed();
ExpectLoadPolicy(kTestFirstURL,
- blink::WebDocumentSubresourceFilter::Disallow);
- ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::Allow);
+ blink::WebDocumentSubresourceFilter::kDisallow);
+ ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::kAllow);
ExpectDocumentLoadStatisticsSent();
FinishLoad();
// In-page navigation should not count as a new load.
ExpectNoSubresourceFilterGetsInjected();
ExpectNoSignalAboutFirstSubresourceDisallowed();
- PerformSamePageNavigationWithoutSettingActivationLevel();
+ PerformSameDocumentNavigationWithoutSettingActivationLevel();
ExpectLoadPolicy(kTestFirstURL,
- blink::WebDocumentSubresourceFilter::Disallow);
- ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::Allow);
+ blink::WebDocumentSubresourceFilter::kDisallow);
+ ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::kAllow);
ExpectNoSubresourceFilterGetsInjected();
- StartLoadWithoutSettingActivationLevel();
+ StartLoadWithoutSettingActivationState();
FinishLoad();
// Resource loads after the in-page navigation should not be counted toward
@@ -323,33 +318,33 @@ TEST_F(SubresourceFilterAgentTest, Enabled_HistogramSamplesOverTwoLoads) {
ASSERT_NO_FATAL_FAILURE(
SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix));
ExpectSubresourceFilterGetsInjected();
- StartLoadAndSetActivationLevel(ActivationLevel::ENABLED,
- measure_performance);
+ ActivationState state(ActivationLevel::ENABLED);
+ state.measure_performance = measure_performance;
+ StartLoadAndSetActivationState(state);
ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
ExpectSignalAboutFirstSubresourceDisallowed();
ExpectLoadPolicy(kTestFirstURL,
- blink::WebDocumentSubresourceFilter::Disallow);
+ blink::WebDocumentSubresourceFilter::kDisallow);
ExpectNoSignalAboutFirstSubresourceDisallowed();
ExpectLoadPolicy(kTestFirstURL,
- blink::WebDocumentSubresourceFilter::Disallow);
+ blink::WebDocumentSubresourceFilter::kDisallow);
ExpectNoSignalAboutFirstSubresourceDisallowed();
ExpectLoadPolicy(kTestSecondURL,
- blink::WebDocumentSubresourceFilter::Allow);
+ blink::WebDocumentSubresourceFilter::kAllow);
ExpectDocumentLoadStatisticsSent();
FinishLoad();
ExpectSubresourceFilterGetsInjected();
- StartLoadAndSetActivationLevel(ActivationLevel::ENABLED,
- measure_performance);
+ StartLoadAndSetActivationState(state);
ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
ExpectNoSignalAboutFirstSubresourceDisallowed();
ExpectLoadPolicy(kTestSecondURL,
- blink::WebDocumentSubresourceFilter::Allow);
+ blink::WebDocumentSubresourceFilter::kAllow);
ExpectSignalAboutFirstSubresourceDisallowed();
ExpectLoadPolicy(kTestFirstURL,
- blink::WebDocumentSubresourceFilter::Disallow);
+ blink::WebDocumentSubresourceFilter::kDisallow);
ExpectDocumentLoadStatisticsSent();
FinishLoad();
@@ -380,7 +375,7 @@ TEST_F(SubresourceFilterAgentTest, Enabled_NewRulesetIsPickedUpAtNextLoad) {
ASSERT_NO_FATAL_FAILURE(
SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix));
ExpectSubresourceFilterGetsInjected();
- StartLoadAndSetActivationLevel(ActivationLevel::ENABLED);
+ StartLoadAndSetActivationState(ActivationState(ActivationLevel::ENABLED));
ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
// Set the new ruleset just after the deadline for being used for the current
@@ -390,19 +385,19 @@ TEST_F(SubresourceFilterAgentTest, Enabled_NewRulesetIsPickedUpAtNextLoad) {
ExpectSignalAboutFirstSubresourceDisallowed();
ExpectLoadPolicy(kTestFirstURL,
- blink::WebDocumentSubresourceFilter::Disallow);
- ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::Allow);
+ blink::WebDocumentSubresourceFilter::kDisallow);
+ ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::kAllow);
ExpectDocumentLoadStatisticsSent();
FinishLoad();
ExpectSubresourceFilterGetsInjected();
- StartLoadAndSetActivationLevel(ActivationLevel::ENABLED);
+ StartLoadAndSetActivationState(ActivationState(ActivationLevel::ENABLED));
ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
ExpectSignalAboutFirstSubresourceDisallowed();
- ExpectLoadPolicy(kTestFirstURL, blink::WebDocumentSubresourceFilter::Allow);
+ ExpectLoadPolicy(kTestFirstURL, blink::WebDocumentSubresourceFilter::kAllow);
ExpectLoadPolicy(kTestSecondURL,
- blink::WebDocumentSubresourceFilter::Disallow);
+ blink::WebDocumentSubresourceFilter::kDisallow);
ExpectDocumentLoadStatisticsSent();
FinishLoad();
}
@@ -415,13 +410,14 @@ TEST_F(SubresourceFilterAgentTest,
SetTestRulesetToDisallowURLsWithPathSuffix(kTestBothURLsPathSuffix));
ExpectNoSubresourceFilterGetsInjected();
agent_as_rfo()->DidStartProvisionalLoad(nullptr);
+ ActivationState state(ActivationLevel::ENABLED);
+ state.measure_performance = true;
EXPECT_TRUE(agent_as_rfo()->OnMessageReceived(
- SubresourceFilterMsg_ActivateForNextCommittedLoad(
- 0, ActivationLevel::ENABLED, true)));
+ SubresourceFilterMsg_ActivateForNextCommittedLoad(0, state)));
agent_as_rfo()->DidFailProvisionalLoad(blink::WebURLError());
agent_as_rfo()->DidStartProvisionalLoad(nullptr);
- agent_as_rfo()->DidCommitProvisionalLoad(true /* is_new_navigation */,
- false /* is_same_page_navigation */);
+ agent_as_rfo()->DidCommitProvisionalLoad(
+ true /* is_new_navigation */, false /* is_same_document_navigation */);
FinishLoad();
}
@@ -430,17 +426,17 @@ TEST_F(SubresourceFilterAgentTest, DryRun_ResourcesAreEvaluatedButNotFiltered) {
ASSERT_NO_FATAL_FAILURE(
SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix));
ExpectSubresourceFilterGetsInjected();
- StartLoadAndSetActivationLevel(ActivationLevel::DRYRUN);
+ StartLoadAndSetActivationState(ActivationState(ActivationLevel::DRYRUN));
ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
// In dry-run mode, loads to the first URL should be recorded as
// `MatchedRules`, but still be allowed to proceed and not recorded as
// `Disallowed`.
ExpectLoadPolicy(kTestFirstURL,
- blink::WebDocumentSubresourceFilter::WouldDisallow);
+ blink::WebDocumentSubresourceFilter::kWouldDisallow);
ExpectLoadPolicy(kTestFirstURL,
- blink::WebDocumentSubresourceFilter::WouldDisallow);
- ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::Allow);
+ blink::WebDocumentSubresourceFilter::kWouldDisallow);
+ ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::kAllow);
ExpectDocumentLoadStatisticsSent();
FinishLoad();
@@ -464,27 +460,27 @@ TEST_F(SubresourceFilterAgentTest,
ASSERT_NO_FATAL_FAILURE(
SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix));
ExpectSubresourceFilterGetsInjected();
- StartLoadAndSetActivationLevel(ActivationLevel::ENABLED);
+ StartLoadAndSetActivationState(ActivationState(ActivationLevel::ENABLED));
ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
ExpectSignalAboutFirstSubresourceDisallowed();
ExpectLoadPolicy(kTestFirstURL,
- blink::WebDocumentSubresourceFilter::Disallow);
+ blink::WebDocumentSubresourceFilter::kDisallow);
ExpectNoSignalAboutFirstSubresourceDisallowed();
ExpectLoadPolicy(kTestFirstURL,
- blink::WebDocumentSubresourceFilter::Disallow);
- ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::Allow);
+ blink::WebDocumentSubresourceFilter::kDisallow);
+ ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::kAllow);
ExpectDocumentLoadStatisticsSent();
FinishLoad();
ExpectSubresourceFilterGetsInjected();
- StartLoadAndSetActivationLevel(ActivationLevel::ENABLED);
+ StartLoadAndSetActivationState(ActivationState(ActivationLevel::ENABLED));
ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
- ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::Allow);
+ ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::kAllow);
ExpectSignalAboutFirstSubresourceDisallowed();
ExpectLoadPolicy(kTestFirstURL,
- blink::WebDocumentSubresourceFilter::Disallow);
+ blink::WebDocumentSubresourceFilter::kDisallow);
ExpectDocumentLoadStatisticsSent();
FinishLoad();
}
@@ -494,7 +490,7 @@ TEST_F(SubresourceFilterAgentTest,
ASSERT_NO_FATAL_FAILURE(
SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix));
ExpectSubresourceFilterGetsInjected();
- StartLoadAndSetActivationLevel(ActivationLevel::ENABLED);
+ StartLoadAndSetActivationState(ActivationState(ActivationLevel::ENABLED));
ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
auto filter = agent()->TakeFilter();
@@ -505,7 +501,7 @@ TEST_F(SubresourceFilterAgentTest,
// to the agent, nor should it cause a crash.
ExpectNoSignalAboutFirstSubresourceDisallowed();
- filter->reportDisallowedLoad();
+ filter->ReportDisallowedLoad();
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/renderer/unverified_ruleset_dealer.h b/chromium/components/subresource_filter/content/renderer/unverified_ruleset_dealer.h
index e46240a12ea..329e6122258 100644
--- a/chromium/components/subresource_filter/content/renderer/unverified_ruleset_dealer.h
+++ b/chromium/components/subresource_filter/content/renderer/unverified_ruleset_dealer.h
@@ -24,7 +24,7 @@ class MemoryMappedRuleset;
// sure that the file is valid.
//
// See RulesetDealerBase for details on the lifetime of MemoryMappedRuleset, and
-// the distribution pipeline diagram in content_ruleset_service_delegate.h.
+// the distribution pipeline diagram in content_ruleset_service.h.
class UnverifiedRulesetDealer : public RulesetDealer,
public content::RenderThreadObserver {
public:
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 668f113a302..80a57c64b6b 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
@@ -9,7 +9,6 @@
#include "base/memory/ref_counted.h"
#include "components/subresource_filter/core/common/activation_state.h"
#include "components/subresource_filter/core/common/memory_mapped_ruleset.h"
-#include "components/subresource_filter/core/common/proto/rules.pb.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "url/gurl.h"
@@ -24,51 +23,51 @@ using WebLoadPolicy = blink::WebDocumentSubresourceFilter::LoadPolicy;
proto::ElementType ToElementType(
blink::WebURLRequest::RequestContext request_context) {
switch (request_context) {
- case blink::WebURLRequest::RequestContextAudio:
- case blink::WebURLRequest::RequestContextVideo:
- case blink::WebURLRequest::RequestContextTrack:
+ case blink::WebURLRequest::kRequestContextAudio:
+ case blink::WebURLRequest::kRequestContextVideo:
+ case blink::WebURLRequest::kRequestContextTrack:
return proto::ELEMENT_TYPE_MEDIA;
- case blink::WebURLRequest::RequestContextBeacon:
- case blink::WebURLRequest::RequestContextPing:
+ case blink::WebURLRequest::kRequestContextBeacon:
+ case blink::WebURLRequest::kRequestContextPing:
return proto::ELEMENT_TYPE_PING;
- case blink::WebURLRequest::RequestContextEmbed:
- case blink::WebURLRequest::RequestContextObject:
- case blink::WebURLRequest::RequestContextPlugin:
+ case blink::WebURLRequest::kRequestContextEmbed:
+ case blink::WebURLRequest::kRequestContextObject:
+ case blink::WebURLRequest::kRequestContextPlugin:
return proto::ELEMENT_TYPE_OBJECT;
- case blink::WebURLRequest::RequestContextEventSource:
- case blink::WebURLRequest::RequestContextFetch:
- case blink::WebURLRequest::RequestContextXMLHttpRequest:
+ case blink::WebURLRequest::kRequestContextEventSource:
+ case blink::WebURLRequest::kRequestContextFetch:
+ case blink::WebURLRequest::kRequestContextXMLHttpRequest:
return proto::ELEMENT_TYPE_XMLHTTPREQUEST;
- case blink::WebURLRequest::RequestContextFavicon:
- case blink::WebURLRequest::RequestContextImage:
- case blink::WebURLRequest::RequestContextImageSet:
+ case blink::WebURLRequest::kRequestContextFavicon:
+ case blink::WebURLRequest::kRequestContextImage:
+ case blink::WebURLRequest::kRequestContextImageSet:
return proto::ELEMENT_TYPE_IMAGE;
- case blink::WebURLRequest::RequestContextFont:
+ case blink::WebURLRequest::kRequestContextFont:
return proto::ELEMENT_TYPE_FONT;
- case blink::WebURLRequest::RequestContextFrame:
- case blink::WebURLRequest::RequestContextForm:
- case blink::WebURLRequest::RequestContextHyperlink:
- case blink::WebURLRequest::RequestContextIframe:
- case blink::WebURLRequest::RequestContextInternal:
- case blink::WebURLRequest::RequestContextLocation:
+ case blink::WebURLRequest::kRequestContextFrame:
+ case blink::WebURLRequest::kRequestContextForm:
+ case blink::WebURLRequest::kRequestContextHyperlink:
+ case blink::WebURLRequest::kRequestContextIframe:
+ case blink::WebURLRequest::kRequestContextInternal:
+ case blink::WebURLRequest::kRequestContextLocation:
return proto::ELEMENT_TYPE_SUBDOCUMENT;
- case blink::WebURLRequest::RequestContextScript:
- case blink::WebURLRequest::RequestContextServiceWorker:
- case blink::WebURLRequest::RequestContextSharedWorker:
+ case blink::WebURLRequest::kRequestContextScript:
+ case blink::WebURLRequest::kRequestContextServiceWorker:
+ case blink::WebURLRequest::kRequestContextSharedWorker:
return proto::ELEMENT_TYPE_SCRIPT;
- case blink::WebURLRequest::RequestContextStyle:
- case blink::WebURLRequest::RequestContextXSLT:
+ case blink::WebURLRequest::kRequestContextStyle:
+ case blink::WebURLRequest::kRequestContextXSLT:
return proto::ELEMENT_TYPE_STYLESHEET;
- case blink::WebURLRequest::RequestContextPrefetch:
- case blink::WebURLRequest::RequestContextSubresource:
+ case blink::WebURLRequest::kRequestContextPrefetch:
+ case blink::WebURLRequest::kRequestContextSubresource:
return proto::ELEMENT_TYPE_OTHER;
- case blink::WebURLRequest::RequestContextCSPReport:
- case blink::WebURLRequest::RequestContextDownload:
- case blink::WebURLRequest::RequestContextImport:
- case blink::WebURLRequest::RequestContextManifest:
- case blink::WebURLRequest::RequestContextUnspecified:
+ case blink::WebURLRequest::kRequestContextCSPReport:
+ case blink::WebURLRequest::kRequestContextDownload:
+ case blink::WebURLRequest::kRequestContextImport:
+ case blink::WebURLRequest::kRequestContextManifest:
+ case blink::WebURLRequest::kRequestContextUnspecified:
default:
return proto::ELEMENT_TYPE_UNSPECIFIED;
}
@@ -77,14 +76,14 @@ proto::ElementType ToElementType(
WebLoadPolicy ToWebLoadPolicy(LoadPolicy load_policy) {
switch (load_policy) {
case LoadPolicy::ALLOW:
- return WebLoadPolicy::Allow;
+ return WebLoadPolicy::kAllow;
case LoadPolicy::DISALLOW:
- return WebLoadPolicy::Disallow;
+ return WebLoadPolicy::kDisallow;
case LoadPolicy::WOULD_DISALLOW:
- return WebLoadPolicy::WouldDisallow;
+ return WebLoadPolicy::kWouldDisallow;
default:
NOTREACHED();
- return WebLoadPolicy::Allow;
+ return WebLoadPolicy::kAllow;
}
}
@@ -101,24 +100,35 @@ WebDocumentSubresourceFilterImpl::WebDocumentSubresourceFilterImpl(
first_disallowed_load_callback_(
std::move(first_disallowed_load_callback)) {}
-blink::WebDocumentSubresourceFilter::LoadPolicy
-WebDocumentSubresourceFilterImpl::getLoadPolicy(
+WebLoadPolicy WebDocumentSubresourceFilterImpl::GetLoadPolicy(
const blink::WebURL& resourceUrl,
blink::WebURLRequest::RequestContext request_context) {
- if (filter_.activation_state().filtering_disabled_for_document ||
- resourceUrl.protocolIs(url::kDataScheme)) {
- ++filter_.statistics().num_loads_total;
- return WebLoadPolicy::Allow;
- }
+ return getLoadPolicyImpl(resourceUrl, ToElementType(request_context));
+}
- // TODO(pkalinnikov): Would be good to avoid converting to GURL.
- return ToWebLoadPolicy(
- filter_.GetLoadPolicy(GURL(resourceUrl), ToElementType(request_context)));
+WebLoadPolicy
+WebDocumentSubresourceFilterImpl::GetLoadPolicyForWebSocketConnect(
+ const blink::WebURL& url) {
+ DCHECK(url.ProtocolIs("ws") || url.ProtocolIs("wss"));
+ return getLoadPolicyImpl(url, proto::ELEMENT_TYPE_WEBSOCKET);
}
-void WebDocumentSubresourceFilterImpl::reportDisallowedLoad() {
+void WebDocumentSubresourceFilterImpl::ReportDisallowedLoad() {
if (!first_disallowed_load_callback_.is_null())
std::move(first_disallowed_load_callback_).Run();
}
+WebLoadPolicy WebDocumentSubresourceFilterImpl::getLoadPolicyImpl(
+ const blink::WebURL& url,
+ proto::ElementType element_type) {
+ if (filter_.activation_state().filtering_disabled_for_document ||
+ url.ProtocolIs(url::kDataScheme)) {
+ ++filter_.statistics().num_loads_total;
+ return WebLoadPolicy::kAllow;
+ }
+
+ // TODO(pkalinnikov): Would be good to avoid converting to GURL.
+ return ToWebLoadPolicy(filter_.GetLoadPolicy(GURL(url), element_type));
+}
+
} // namespace subresource_filter
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 32568bbc0ea..686a81e0752 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
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "components/subresource_filter/core/common/document_subresource_filter.h"
+#include "components/subresource_filter/core/common/proto/rules.pb.h"
#include "third_party/WebKit/public/platform/WebDocumentSubresourceFilter.h"
namespace subresource_filter {
@@ -35,12 +36,16 @@ class WebDocumentSubresourceFilterImpl
const DocumentSubresourceFilter& filter() const { return filter_; }
// blink::WebDocumentSubresourceFilter:
- blink::WebDocumentSubresourceFilter::LoadPolicy getLoadPolicy(
- const blink::WebURL& resourceUrl,
- blink::WebURLRequest::RequestContext) override;
- void reportDisallowedLoad() override;
+ LoadPolicy GetLoadPolicy(const blink::WebURL& resourceUrl,
+ blink::WebURLRequest::RequestContext) override;
+ LoadPolicy GetLoadPolicyForWebSocketConnect(
+ const blink::WebURL& url) override;
+ void ReportDisallowedLoad() override;
private:
+ LoadPolicy getLoadPolicyImpl(const blink::WebURL& url,
+ proto::ElementType element_type);
+
DocumentSubresourceFilter filter_;
base::OnceClosure first_disallowed_load_callback_;
diff --git a/chromium/components/subresource_filter/core/browser/BUILD.gn b/chromium/components/subresource_filter/core/browser/BUILD.gn
index a137defa711..d61c1c048b9 100644
--- a/chromium/components/subresource_filter/core/browser/BUILD.gn
+++ b/chromium/components/subresource_filter/core/browser/BUILD.gn
@@ -7,7 +7,6 @@ static_library("browser") {
"ruleset_service.cc",
"ruleset_service.h",
"ruleset_service_delegate.h",
- "subresource_filter_client.h",
"subresource_filter_constants.cc",
"subresource_filter_constants.h",
"subresource_filter_features.cc",
@@ -34,6 +33,7 @@ static_library("test_support") {
"//base/test:test_support",
"//components/variations",
"//testing/gtest",
+ "//third_party/protobuf:protobuf_lite",
]
}
@@ -50,6 +50,7 @@ source_set("unit_tests") {
"//base/test:test_support",
"//components/prefs:test_support",
"//components/subresource_filter/core/common:test_support",
+ "//components/subresource_filter/core/common/proto",
"//testing/gmock",
"//testing/gtest",
"//third_party/protobuf:protobuf_lite",
diff --git a/chromium/components/subresource_filter/core/browser/ruleset_service.cc b/chromium/components/subresource_filter/core/browser/ruleset_service.cc
index 179375b5069..46256729f5c 100644
--- a/chromium/components/subresource_filter/core/browser/ruleset_service.cc
+++ b/chromium/components/subresource_filter/core/browser/ruleset_service.cc
@@ -215,11 +215,11 @@ decltype(&base::ReplaceFile) RulesetService::g_replace_file_func =
RulesetService::RulesetService(
PrefService* local_state,
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
- std::unique_ptr<RulesetServiceDelegate> delegate,
+ RulesetServiceDelegate* delegate,
const base::FilePath& indexed_ruleset_base_dir)
: local_state_(local_state),
blocking_task_runner_(blocking_task_runner),
- delegate_(std::move(delegate)),
+ delegate_(delegate),
is_after_startup_(false),
indexed_ruleset_base_dir_(indexed_ruleset_base_dir) {
DCHECK(delegate_);
diff --git a/chromium/components/subresource_filter/core/browser/ruleset_service.h b/chromium/components/subresource_filter/core/browser/ruleset_service.h
index d460f14fde3..ef84c0ca6e6 100644
--- a/chromium/components/subresource_filter/core/browser/ruleset_service.h
+++ b/chromium/components/subresource_filter/core/browser/ruleset_service.h
@@ -170,7 +170,7 @@ class RulesetService : public base::SupportsWeakPtr<RulesetService> {
// See class comments for details of arguments.
RulesetService(PrefService* local_state,
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
- std::unique_ptr<RulesetServiceDelegate> delegate,
+ RulesetServiceDelegate* delegate,
const base::FilePath& indexed_ruleset_base_dir);
virtual ~RulesetService();
@@ -187,9 +187,6 @@ class RulesetService : public base::SupportsWeakPtr<RulesetService> {
virtual void IndexAndStoreAndPublishRulesetIfNeeded(
const UnindexedRulesetInfo& unindexed_ruleset_info);
- // Exposed for browser tests.
- RulesetServiceDelegate* delegate() { return delegate_.get(); }
-
private:
friend class SubresourceFilteringRulesetServiceTest;
FRIEND_TEST_ALL_PREFIXES(SubresourceFilteringRulesetServiceTest,
@@ -252,7 +249,9 @@ class RulesetService : public base::SupportsWeakPtr<RulesetService> {
PrefService* const local_state_;
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
- std::unique_ptr<RulesetServiceDelegate> delegate_;
+
+ // Must outlive |this| object.
+ RulesetServiceDelegate* delegate_;
UnindexedRulesetInfo queued_unindexed_ruleset_info_;
bool is_after_startup_;
diff --git a/chromium/components/subresource_filter/core/browser/ruleset_service_unittest.cc b/chromium/components/subresource_filter/core/browser/ruleset_service_unittest.cc
index 0e300937b96..fa7d2fb159d 100644
--- a/chromium/components/subresource_filter/core/browser/ruleset_service_unittest.cc
+++ b/chromium/components/subresource_filter/core/browser/ruleset_service_unittest.cc
@@ -27,6 +27,7 @@
#include "build/build_config.h"
#include "components/prefs/testing_pref_service.h"
#include "components/subresource_filter/core/browser/ruleset_service_delegate.h"
+#include "components/subresource_filter/core/common/proto/rules.pb.h"
#include "components/subresource_filter/core/common/test_ruleset_creator.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -145,8 +146,7 @@ class SubresourceFilteringRulesetServiceTest : public ::testing::Test {
public:
SubresourceFilteringRulesetServiceTest()
: task_runner_(new base::TestSimpleTaskRunner),
- task_runner_handle_(task_runner_),
- mock_delegate_(nullptr) {}
+ task_runner_handle_(task_runner_) {}
protected:
void SetUp() override {
@@ -172,15 +172,14 @@ class SubresourceFilteringRulesetServiceTest : public ::testing::Test {
}
void ResetRulesetService() {
+ mock_delegate_ = base::MakeUnique<MockRulesetServiceDelegate>();
service_ = base::MakeUnique<RulesetService>(
- &pref_service_, task_runner_,
- base::WrapUnique(mock_delegate_ = new MockRulesetServiceDelegate),
- base_dir());
+ &pref_service_, task_runner_, mock_delegate_.get(), base_dir());
}
void ClearRulesetService() {
- mock_delegate_ = nullptr;
service_.reset();
+ mock_delegate_.reset();
}
// Creates a new file with the given license |contents| at a unique temporary
@@ -269,7 +268,7 @@ class SubresourceFilteringRulesetServiceTest : public ::testing::Test {
PrefService* prefs() { return &pref_service_; }
RulesetService* service() { return service_.get(); }
- MockRulesetServiceDelegate* mock_delegate() { return mock_delegate_; }
+ MockRulesetServiceDelegate* mock_delegate() { return mock_delegate_.get(); }
virtual base::FilePath effective_temp_dir() const {
return scoped_temp_dir_.GetPath();
@@ -295,8 +294,8 @@ class SubresourceFilteringRulesetServiceTest : public ::testing::Test {
TestRulesetPair test_ruleset_2_;
TestRulesetPair test_ruleset_3_;
+ std::unique_ptr<MockRulesetServiceDelegate> mock_delegate_;
std::unique_ptr<RulesetService> service_;
- MockRulesetServiceDelegate* mock_delegate_; // Weak, owned by |service_|.
DISALLOW_COPY_AND_ASSIGN(SubresourceFilteringRulesetServiceTest);
};
@@ -661,13 +660,13 @@ TEST_F(SubresourceFilteringRulesetServiceTest,
base::HistogramTester histogram_tester;
mock_delegate()->SimulateStartupCompleted();
- // URL patterns longer than 255 characters are not supported.
- const std::string kTooLongSuffix(1000, 'a');
+ // The default field values are considered unsupported.
+ proto::UrlRule unfilled_rule;
+
TestRulesetPair ruleset_with_unsupported_rule;
ASSERT_NO_FATAL_FAILURE(
- test_ruleset_creator()
- ->CreateUnindexedRulesetToDisallowURLsWithPathSuffix(
- kTooLongSuffix, &ruleset_with_unsupported_rule.unindexed));
+ test_ruleset_creator()->CreateUnindexedRulesetWithRules(
+ {unfilled_rule}, &ruleset_with_unsupported_rule.unindexed));
IndexAndStoreAndPublishUpdatedRuleset(ruleset_with_unsupported_rule,
kTestContentVersion1);
RunUntilIdle();
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_constants.cc b/chromium/components/subresource_filter/core/browser/subresource_filter_constants.cc
index dd9b9a44da5..dbc9e0999c0 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_constants.cc
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_constants.cc
@@ -24,4 +24,10 @@ const base::FilePath::CharType kLicenseFileName[] =
const base::FilePath::CharType kSentinelFileName[] =
FILE_PATH_LITERAL("Indexing in Progress");
+const base::FilePath::CharType kUnindexedRulesetLicenseFileName[] =
+ FILE_PATH_LITERAL("LICENSE");
+
+const base::FilePath::CharType kUnindexedRulesetDataFileName[] =
+ FILE_PATH_LITERAL("Filtering Rules");
+
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_constants.h b/chromium/components/subresource_filter/core/browser/subresource_filter_constants.h
index 0d52ad778bf..d78b18fdda4 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_constants.h
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_constants.h
@@ -38,6 +38,15 @@ extern const base::FilePath::CharType kLicenseFileName[];
// ruleset is being indexed.
extern const base::FilePath::CharType kSentinelFileName[];
+// Paths under kUnindexedRulesetBaseDirectoryName
+// ----------------------------------------------
+
+// The name of the license file associated with the unindex ruleset.
+extern const base::FilePath::CharType kUnindexedRulesetLicenseFileName[];
+
+// The name of the file that stores the unindexed filtering rules.
+extern const base::FilePath::CharType kUnindexedRulesetDataFileName[];
+
} // namespace subresource_filter
#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CONSTANTS_H_
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc b/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc
index ef13cad4bc4..2ad875eaf25 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc
@@ -8,43 +8,27 @@
#include "base/metrics/field_trial_params.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "components/variations/variations_associated_data.h"
namespace subresource_filter {
-const base::Feature kSafeBrowsingSubresourceFilter{
- "SubresourceFilter", base::FEATURE_DISABLED_BY_DEFAULT};
-
-// Legacy name `activation_state` is used in variation parameters.
-const char kActivationLevelParameterName[] = "activation_state";
-const char kActivationLevelDryRun[] = "dryrun";
-const char kActivationLevelEnabled[] = "enabled";
-const char kActivationLevelDisabled[] = "disabled";
-
-const char kActivationScopeParameterName[] = "activation_scope";
-const char kActivationScopeAllSites[] = "all_sites";
-const char kActivationScopeActivationList[] = "activation_list";
-const char kActivationScopeNoSites[] = "no_sites";
-
-const char kActivationListsParameterName[] = "activation_lists";
-const char kActivationListSocialEngineeringAdsInterstitial[] =
- "social_engineering_ads_interstitial";
-const char kActivationListPhishingInterstitial[] = "phishing_interstitial";
-
-const char kRulesetFlavorParameterName[] = "ruleset_flavor";
-
-const char kPerformanceMeasurementRateParameterName[] =
- "performance_measurement_rate";
-
-const char kSuppressNotificationsParameterName[] = "suppress_notifications";
-
-const char kWhitelistSiteOnReloadParameterName[] = "whitelist_site_on_reload";
+namespace {
+
+std::string TakeVariationParamOrReturnEmpty(
+ std::map<std::string, std::string>* params,
+ const std::string& key) {
+ auto it = params->find(key);
+ if (it == params->end())
+ return std::string();
+ std::string value = std::move(it->second);
+ params->erase(it);
+ return value;
+}
-ActivationLevel GetMaximumActivationLevel() {
- std::string activation_level = variations::GetVariationParamValueByFeature(
- kSafeBrowsingSubresourceFilter, kActivationLevelParameterName);
+ActivationLevel ParseActivationLevel(const base::StringPiece activation_level) {
if (base::LowerCaseEqualsASCII(activation_level, kActivationLevelEnabled))
return ActivationLevel::ENABLED;
else if (base::LowerCaseEqualsASCII(activation_level, kActivationLevelDryRun))
@@ -52,9 +36,7 @@ ActivationLevel GetMaximumActivationLevel() {
return ActivationLevel::DISABLED;
}
-ActivationScope GetCurrentActivationScope() {
- std::string activation_scope = variations::GetVariationParamValueByFeature(
- kSafeBrowsingSubresourceFilter, kActivationScopeParameterName);
+ActivationScope ParseActivationScope(const base::StringPiece activation_scope) {
if (base::LowerCaseEqualsASCII(activation_scope, kActivationScopeAllSites))
return ActivationScope::ALL_SITES;
else if (base::LowerCaseEqualsASCII(activation_scope,
@@ -63,9 +45,7 @@ ActivationScope GetCurrentActivationScope() {
return ActivationScope::NO_SITES;
}
-ActivationList GetCurrentActivationList() {
- std::string activation_lists = variations::GetVariationParamValueByFeature(
- kSafeBrowsingSubresourceFilter, kActivationListsParameterName);
+ActivationList ParseActivationList(const base::StringPiece activation_lists) {
ActivationList activation_list_type = ActivationList::NONE;
for (const base::StringPiece& activation_list :
base::SplitStringPiece(activation_lists, ",", base::TRIM_WHITESPACE,
@@ -77,36 +57,95 @@ ActivationList GetCurrentActivationList() {
activation_list,
kActivationListSocialEngineeringAdsInterstitial)) {
activation_list_type = ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL;
+ } else if (base::LowerCaseEqualsASCII(activation_list,
+ kActivationListSubresourceFilter)) {
+ activation_list_type = ActivationList::SUBRESOURCE_FILTER;
}
}
return activation_list_type;
}
-double GetPerformanceMeasurementRate() {
- const std::string rate = variations::GetVariationParamValueByFeature(
- kSafeBrowsingSubresourceFilter, kPerformanceMeasurementRateParameterName);
+double ParsePerformanceMeasurementRate(const std::string& rate) {
double value = 0;
if (!base::StringToDouble(rate, &value) || value < 0)
return 0;
return value < 1 ? value : 1;
}
-bool ShouldSuppressNotifications() {
- return base::GetFieldTrialParamByFeatureAsBool(
- kSafeBrowsingSubresourceFilter, kSuppressNotificationsParameterName,
- false /* default value */);
+bool ParseBool(const base::StringPiece value) {
+ return base::LowerCaseEqualsASCII(value, "true");
}
-std::string GetRulesetFlavor() {
- return variations::GetVariationParamValueByFeature(
- subresource_filter::kSafeBrowsingSubresourceFilter,
- subresource_filter::kRulesetFlavorParameterName);
-}
+} // namespace
+
+const base::Feature kSafeBrowsingSubresourceFilter{
+ "SubresourceFilter", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kSafeBrowsingSubresourceFilterExperimentalUI{
+ "SubresourceFilterExperimentalUI", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Legacy name `activation_state` is used in variation parameters.
+const char kActivationLevelParameterName[] = "activation_state";
+const char kActivationLevelDryRun[] = "dryrun";
+const char kActivationLevelEnabled[] = "enabled";
+const char kActivationLevelDisabled[] = "disabled";
+
+const char kActivationScopeParameterName[] = "activation_scope";
+const char kActivationScopeAllSites[] = "all_sites";
+const char kActivationScopeActivationList[] = "activation_list";
+const char kActivationScopeNoSites[] = "no_sites";
+
+const char kActivationListsParameterName[] = "activation_lists";
+const char kActivationListSocialEngineeringAdsInterstitial[] =
+ "social_engineering_ads_interstitial";
+const char kActivationListPhishingInterstitial[] = "phishing_interstitial";
+const char kActivationListSubresourceFilter[] = "subresource_filter";
+
+const char kRulesetFlavorParameterName[] = "ruleset_flavor";
+
+const char kPerformanceMeasurementRateParameterName[] =
+ "performance_measurement_rate";
+
+const char kSuppressNotificationsParameterName[] = "suppress_notifications";
+
+const char kWhitelistSiteOnReloadParameterName[] = "whitelist_site_on_reload";
+
+Configuration::Configuration() = default;
+Configuration::~Configuration() = default;
+Configuration::Configuration(Configuration&&) = default;
+Configuration& Configuration::operator=(Configuration&&) = default;
+
+Configuration GetActiveConfiguration() {
+ Configuration active_configuration;
+
+ std::map<std::string, std::string> params;
+ base::GetFieldTrialParamsByFeature(kSafeBrowsingSubresourceFilter, &params);
+
+ active_configuration.activation_level = ParseActivationLevel(
+ TakeVariationParamOrReturnEmpty(&params, kActivationLevelParameterName));
+
+ active_configuration.activation_scope = ParseActivationScope(
+ TakeVariationParamOrReturnEmpty(&params, kActivationScopeParameterName));
+
+ active_configuration.activation_list = ParseActivationList(
+ TakeVariationParamOrReturnEmpty(&params, kActivationListsParameterName));
+
+ active_configuration.performance_measurement_rate =
+ ParsePerformanceMeasurementRate(TakeVariationParamOrReturnEmpty(
+ &params, kPerformanceMeasurementRateParameterName));
+
+ active_configuration.should_suppress_notifications =
+ ParseBool(TakeVariationParamOrReturnEmpty(
+ &params, kSuppressNotificationsParameterName));
+
+ active_configuration.ruleset_flavor =
+ TakeVariationParamOrReturnEmpty(&params, kRulesetFlavorParameterName);
+
+ active_configuration.should_whitelist_site_on_reload =
+ ParseBool(TakeVariationParamOrReturnEmpty(
+ &params, kWhitelistSiteOnReloadParameterName));
-bool ShouldWhitelistSiteOnReload() {
- return base::GetFieldTrialParamByFeatureAsBool(
- kSafeBrowsingSubresourceFilter, kWhitelistSiteOnReloadParameterName,
- false /* default value */);
+ return active_configuration;
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features.h b/chromium/components/subresource_filter/core/browser/subresource_filter_features.h
index 86b56aae34e..9ac8d317cb6 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features.h
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features.h
@@ -12,9 +12,58 @@
namespace subresource_filter {
+// Encapsulates all parameters that define how the subresource filter feature
+// should operate.
+struct Configuration {
+ Configuration();
+ ~Configuration();
+ Configuration(Configuration&&);
+ Configuration& operator=(Configuration&&);
+
+ // The maximum degree to which subresource filtering should be activated on
+ // any RenderFrame. This will be ActivationLevel::DISABLED unless the feature
+ // is enabled and variation parameters prescribe a higher activation level.
+ ActivationLevel activation_level = ActivationLevel::DISABLED;
+
+ // The activation scope. That is, the subset of page loads where subresource
+ // filtering should be activated. This will be ActivationScope::NO_SITES
+ // unless the feature is =enabled and variation parameters prescribe a wider
+ // activation scope.
+ ActivationScope activation_scope = ActivationScope::NO_SITES;
+
+ // The activation list to use when the |activation_scope| is ACTIVATION_LIST.
+ // This will be ActivationList::NONE unless variation parameters prescribe a
+ // recognized list.
+ ActivationList activation_list = ActivationList::NONE;
+
+ // A number in the range [0, 1], indicating the fraction of page loads that
+ // should have extended performance measurements enabled. The rate will
+ // be 0 unless a greater frequency is specified by variation parameters.
+ double performance_measurement_rate = 0.0;
+
+ // Whether notifications indicating that a subresource was disallowed should
+ // be suppressed in the UI.
+ bool should_suppress_notifications = false;
+
+ // The ruleset flavor to download through the component updater, or the empty
+ // string if the default ruleset should be used.
+ std::string ruleset_flavor;
+
+ // Whether to whitelist a site when a page loaded from that site is reloaded.
+ bool should_whitelist_site_on_reload = false;
+};
+
+// Retrieves the subresource filtering configuration to use. Expensive to call.
+Configuration GetActiveConfiguration();
+
+// Feature and variation parameter definitions -------------------------------
+
// The master toggle to enable/disable the Safe Browsing Subresource Filter.
extern const base::Feature kSafeBrowsingSubresourceFilter;
+// Enables the new experimental UI for the Subresource Filter.
+extern const base::Feature kSafeBrowsingSubresourceFilterExperimentalUI;
+
// Name/values of the variation parameter controlling maximum activation level.
extern const char kActivationLevelParameterName[];
extern const char kActivationLevelDryRun[];
@@ -29,6 +78,7 @@ extern const char kActivationScopeNoSites[];
extern const char kActivationListsParameterName[];
extern const char kActivationListSocialEngineeringAdsInterstitial[];
extern const char kActivationListPhishingInterstitial[];
+extern const char kActivationListSubresourceFilter[];
extern const char kRulesetFlavorParameterName[];
@@ -38,38 +88,6 @@ extern const char kSuppressNotificationsParameterName[];
extern const char kWhitelistSiteOnReloadParameterName[];
-// Returns the maximum degree to which subresource filtering should be activated
-// on any RenderFrame. This will be ActivationLevel::DISABLED unless the feature
-// is enabled and variation parameters prescribe a higher activation level.
-ActivationLevel GetMaximumActivationLevel();
-
-// Returns the current activation scope, that is, the subset of page loads where
-// subresource filtering should be activated. The function returns
-// ActivationScope::NO_SITES unless the feature is enabled and variation
-// parameters prescribe a wider activation scope.
-ActivationScope GetCurrentActivationScope();
-
-// Returns current activation list, based on the values from variation params in
-// the feature |kSafeBrowsingSubresourceFilter|. When the corresponding
-// variation param is empty, returns most conservative ActivationList::NONE.
-ActivationList GetCurrentActivationList();
-
-// Returns a number in the range [0, 1], indicating the fraction of page loads
-// that should have extended performance measurements enabled. The rate will be
-// 0 unless a greater frequency is specified by variation parameters.
-double GetPerformanceMeasurementRate();
-
-// Returns whether notifications indicating that a subresource was disallowed
-// should be suppressed in the UI.
-bool ShouldSuppressNotifications();
-
-// Returns the ruleset flavor, or the empty string if the default ruleset should
-// be used.
-std::string GetRulesetFlavor();
-
-// Returns whether the site of reloaded pages should be whitelisted.
-bool ShouldWhitelistSiteOnReload();
-
} // namespace subresource_filter
#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_FEATURES_H_
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc b/chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc
index 47ef01ab303..16b8354e0e7 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc
@@ -8,6 +8,7 @@
#include <memory>
#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
#include "components/subresource_filter/core/browser/subresource_filter_features.h"
#include "components/variations/variations_associated_data.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -41,9 +42,7 @@ ScopedSubresourceFilterFeatureToggle::ScopedSubresourceFilterFeatureToggle(
ScopedSubresourceFilterFeatureToggle::ScopedSubresourceFilterFeatureToggle(
base::FeatureList::OverrideState feature_state,
std::map<std::string, std::string> variation_params) {
- variations::testing::ClearAllVariationParams();
-
- EXPECT_TRUE(variations::AssociateVariationParams(
+ EXPECT_TRUE(base::AssociateFieldTrialParams(
kTestFieldTrialName, kTestExperimentGroupName, variation_params));
base::FieldTrial* field_trial = base::FieldTrialList::CreateFieldTrial(
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc b/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
index 1918d8c6669..204186832d2 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
@@ -42,8 +42,10 @@ TEST(SubresourceFilterFeaturesTest, ActivationLevel) {
: base::FeatureList::OVERRIDE_USE_DEFAULT,
test_case.activation_level_param, kActivationScopeNoSites);
- EXPECT_EQ(test_case.expected_activation_level, GetMaximumActivationLevel());
- EXPECT_EQ(ActivationScope::NO_SITES, GetCurrentActivationScope());
+ Configuration actual_configuration = GetActiveConfiguration();
+ EXPECT_EQ(test_case.expected_activation_level,
+ actual_configuration.activation_level);
+ EXPECT_EQ(ActivationScope::NO_SITES, actual_configuration.activation_scope);
}
}
@@ -77,8 +79,10 @@ TEST(SubresourceFilterFeaturesTest, ActivationScope) {
: base::FeatureList::OVERRIDE_USE_DEFAULT,
kActivationLevelDisabled, test_case.activation_scope_param);
- EXPECT_EQ(ActivationLevel::DISABLED, GetMaximumActivationLevel());
- EXPECT_EQ(test_case.expected_activation_scope, GetCurrentActivationScope());
+ Configuration actual_configuration = GetActiveConfiguration();
+ EXPECT_EQ(ActivationLevel::DISABLED, actual_configuration.activation_level);
+ EXPECT_EQ(test_case.expected_activation_scope,
+ actual_configuration.activation_scope);
}
}
@@ -126,8 +130,11 @@ TEST(SubresourceFilterFeaturesTest, ActivationLevelAndScope) {
: base::FeatureList::OVERRIDE_USE_DEFAULT,
test_case.activation_level_param, test_case.activation_scope_param);
- EXPECT_EQ(test_case.expected_activation_scope, GetCurrentActivationScope());
- EXPECT_EQ(test_case.expected_activation_level, GetMaximumActivationLevel());
+ Configuration actual_configuration = GetActiveConfiguration();
+ EXPECT_EQ(test_case.expected_activation_level,
+ actual_configuration.activation_level);
+ EXPECT_EQ(test_case.expected_activation_scope,
+ actual_configuration.activation_scope);
}
}
@@ -179,7 +186,9 @@ TEST(SubresourceFilterFeaturesTest, ActivationList) {
kActivationLevelDisabled, kActivationScopeNoSites,
test_case.activation_list_param);
- EXPECT_EQ(test_case.expected_activation_list, GetCurrentActivationList());
+ Configuration actual_configuration = GetActiveConfiguration();
+ EXPECT_EQ(test_case.expected_activation_list,
+ actual_configuration.activation_list);
}
}
@@ -214,8 +223,9 @@ TEST(SubresourceFilterFeaturesTest, PerfMeasurementRate) {
{{kPerformanceMeasurementRateParameterName,
test_case.perf_measurement_param}});
+ Configuration actual_configuration = GetActiveConfiguration();
EXPECT_EQ(test_case.expected_perf_measurement_rate,
- GetPerformanceMeasurementRate());
+ actual_configuration.performance_measurement_rate);
}
}
@@ -231,8 +241,8 @@ TEST(SubresourceFilterFeaturesTest, SuppressNotifications) {
{true, "", false},
{true, "false", false},
{true, "invalid value", false},
- {true, "True", false},
- {true, "TRUE", false},
+ {true, "True", true},
+ {true, "TRUE", true},
{true, "true", true}};
for (const auto& test_case : kTestCases) {
@@ -247,8 +257,9 @@ TEST(SubresourceFilterFeaturesTest, SuppressNotifications) {
{{kSuppressNotificationsParameterName,
test_case.suppress_notifications_param}});
+ Configuration actual_configuration = GetActiveConfiguration();
EXPECT_EQ(test_case.expected_suppress_notifications_value,
- ShouldSuppressNotifications());
+ actual_configuration.should_suppress_notifications);
}
}
@@ -264,8 +275,8 @@ TEST(SubresourceFilterFeaturesTest, WhitelistSiteOnReload) {
{true, "", false},
{true, "false", false},
{true, "invalid value", false},
- {true, "True", false},
- {true, "TRUE", false},
+ {true, "True", true},
+ {true, "TRUE", true},
{true, "true", true}};
for (const auto& test_case : kTestCases) {
@@ -280,8 +291,9 @@ TEST(SubresourceFilterFeaturesTest, WhitelistSiteOnReload) {
{{kWhitelistSiteOnReloadParameterName,
test_case.whitelist_site_on_reload_param}});
+ Configuration actual_configuration = GetActiveConfiguration();
EXPECT_EQ(test_case.expected_whitelist_site_on_reload_value,
- ShouldWhitelistSiteOnReload());
+ actual_configuration.should_whitelist_site_on_reload);
}
}
diff --git a/chromium/components/subresource_filter/core/common/BUILD.gn b/chromium/components/subresource_filter/core/common/BUILD.gn
index ef133bfe2e9..eed0e8a63fd 100644
--- a/chromium/components/subresource_filter/core/common/BUILD.gn
+++ b/chromium/components/subresource_filter/core/common/BUILD.gn
@@ -23,7 +23,6 @@ static_library("common") {
"fuzzy_pattern_matching.h",
"indexed_ruleset.cc",
"indexed_ruleset.h",
- "knuth_morris_pratt.h",
"memory_mapped_ruleset.cc",
"memory_mapped_ruleset.h",
"ngram_extractor.h",
@@ -35,7 +34,6 @@ static_library("common") {
"unindexed_ruleset.h",
"url_pattern.cc",
"url_pattern.h",
- "url_pattern_matching.h",
]
public_deps = [
@@ -76,12 +74,11 @@ source_set("unit_tests") {
"first_party_origin_unittest.cc",
"fuzzy_pattern_matching_unittest.cc",
"indexed_ruleset_unittest.cc",
- "knuth_morris_pratt_unittest.cc",
"ngram_extractor_unittest.cc",
"scoped_timers_unittest.cc",
"string_splitter_unittest.cc",
"unindexed_ruleset_unittest.cc",
- "url_pattern_matching_unittest.cc",
+ "url_pattern_unittest.cc",
]
deps = [
":common",
diff --git a/chromium/components/subresource_filter/core/common/DEPS b/chromium/components/subresource_filter/core/common/DEPS
new file mode 100644
index 00000000000..e579f595f63
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+components/safe_browsing_db/util.h",
+]
diff --git a/chromium/components/subresource_filter/core/common/activation_list.cc b/chromium/components/subresource_filter/core/common/activation_list.cc
index 090eeae134c..a5f50e1df33 100644
--- a/chromium/components/subresource_filter/core/common/activation_list.cc
+++ b/chromium/components/subresource_filter/core/common/activation_list.cc
@@ -21,6 +21,9 @@ std::ostream& operator<<(std::ostream& os, const ActivationList& type) {
case ActivationList::PHISHING_INTERSTITIAL:
os << "PHISHING_INTERSTITIAL";
break;
+ case ActivationList::SUBRESOURCE_FILTER:
+ os << "SUBRESOURCE_FILTER";
+ break;
default:
NOTREACHED();
break;
diff --git a/chromium/components/subresource_filter/core/common/activation_list.h b/chromium/components/subresource_filter/core/common/activation_list.h
index c24118ba715..e17cce074ec 100644
--- a/chromium/components/subresource_filter/core/common/activation_list.h
+++ b/chromium/components/subresource_filter/core/common/activation_list.h
@@ -13,7 +13,8 @@ enum class ActivationList {
NONE,
SOCIAL_ENG_ADS_INTERSTITIAL,
PHISHING_INTERSTITIAL,
- LAST = PHISHING_INTERSTITIAL,
+ SUBRESOURCE_FILTER,
+ LAST = SUBRESOURCE_FILTER,
};
// For logging use only.
diff --git a/chromium/components/subresource_filter/core/common/document_subresource_filter.cc b/chromium/components/subresource_filter/core/common/document_subresource_filter.cc
index e8af188333f..3895a3a88f8 100644
--- a/chromium/components/subresource_filter/core/common/document_subresource_filter.cc
+++ b/chromium/components/subresource_filter/core/common/document_subresource_filter.cc
@@ -17,13 +17,18 @@
namespace subresource_filter {
-namespace {
-
-ActivationState ComputeActivationStateImpl(
+ActivationState ComputeActivationState(
const GURL& document_url,
const url::Origin& parent_document_origin,
const ActivationState& parent_activation_state,
- const IndexedRulesetMatcher& matcher) {
+ const MemoryMappedRuleset* ruleset) {
+ DCHECK(ruleset);
+ SCOPED_UMA_HISTOGRAM_MICRO_TIMER(
+ "SubresourceFilter.DocumentLoad.Activation.WallDuration");
+ SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER(
+ "SubresourceFilter.DocumentLoad.Activation.CPUDuration");
+
+ IndexedRulesetMatcher matcher(ruleset->data(), ruleset->length());
ActivationState activation_state = parent_activation_state;
if (activation_state.filtering_disabled_for_document)
return activation_state;
@@ -42,48 +47,6 @@ ActivationState ComputeActivationStateImpl(
return activation_state;
}
-} // namespace
-
-ActivationState ComputeActivationState(
- const GURL& document_url,
- const url::Origin& parent_document_origin,
- const ActivationState& parent_activation_state,
- const MemoryMappedRuleset* ruleset) {
- DCHECK(ruleset);
- IndexedRulesetMatcher matcher(ruleset->data(), ruleset->length());
- return ComputeActivationStateImpl(document_url, parent_document_origin,
- parent_activation_state, matcher);
-}
-
-ActivationState ComputeActivationState(
- ActivationLevel activation_level,
- bool measure_performance,
- const std::vector<GURL>& ancestor_document_urls,
- const MemoryMappedRuleset* ruleset) {
- SCOPED_UMA_HISTOGRAM_MICRO_TIMER(
- "SubresourceFilter.DocumentLoad.Activation.WallDuration");
- SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER(
- "SubresourceFilter.DocumentLoad.Activation.CPUDuration");
-
- ActivationState activation_state(activation_level);
- activation_state.measure_performance = measure_performance;
- DCHECK(ruleset);
-
- IndexedRulesetMatcher matcher(ruleset->data(), ruleset->length());
-
- url::Origin parent_document_origin;
- for (auto iter = ancestor_document_urls.rbegin(),
- rend = ancestor_document_urls.rend();
- iter != rend; ++iter) {
- const GURL& document_url(*iter);
- activation_state = ComputeActivationStateImpl(
- document_url, parent_document_origin, activation_state, matcher);
- parent_document_origin = url::Origin(document_url);
- }
-
- return activation_state;
-}
-
DocumentSubresourceFilter::DocumentSubresourceFilter(
url::Origin document_origin,
ActivationState activation_state,
diff --git a/chromium/components/subresource_filter/core/common/document_subresource_filter.h b/chromium/components/subresource_filter/core/common/document_subresource_filter.h
index 5345624c0c4..611707d9c3d 100644
--- a/chromium/components/subresource_filter/core/common/document_subresource_filter.h
+++ b/chromium/components/subresource_filter/core/common/document_subresource_filter.h
@@ -45,19 +45,6 @@ ActivationState ComputeActivationState(
const ActivationState& parent_activation_state,
const MemoryMappedRuleset* ruleset);
-// Same as above, but instead of relying on the pre-computed activation state of
-// the parent, computes the activation state for a frame from scratch, based on
-// the page-level activation options |activation_level| and
-// |measure_performance|; as well as any deactivation rules in |ruleset| that
-// apply to |ancestor_document_urls|.
-//
-// TODO(pkalinnikov): Remove this when browser-side navigation is supported.
-ActivationState ComputeActivationState(
- ActivationLevel activation_level,
- bool measure_performance,
- const std::vector<GURL>& ancestor_document_urls,
- const MemoryMappedRuleset* ruleset);
-
// Performs filtering of subresource loads in the scope of a given document.
class DocumentSubresourceFilter {
public:
diff --git a/chromium/components/subresource_filter/core/common/document_subresource_filter_unittest.cc b/chromium/components/subresource_filter/core/common/document_subresource_filter_unittest.cc
index b7ea78249e1..71562368cc6 100644
--- a/chromium/components/subresource_filter/core/common/document_subresource_filter_unittest.cc
+++ b/chromium/components/subresource_filter/core/common/document_subresource_filter_unittest.cc
@@ -16,7 +16,6 @@ namespace subresource_filter {
namespace {
-constexpr auto kDisabled = ActivationLevel::DISABLED;
constexpr auto kDryRun = ActivationLevel::DRYRUN;
constexpr auto kEnabled = ActivationLevel::ENABLED;
@@ -25,6 +24,7 @@ constexpr auto kSubdocumentType = proto::ELEMENT_TYPE_SUBDOCUMENT;
constexpr const char kTestAlphaURL[] = "http://example.com/alpha";
constexpr const char kTestAlphaDataURI[] = "data:text/plain,alpha";
+constexpr const char kTestAlphaWSURI[] = "ws://example.com/alpha";
constexpr const char kTestBetaURL[] = "http://example.com/beta";
constexpr const char kTestAlphaURLPathSuffix[] = "alpha";
@@ -70,6 +70,9 @@ TEST_F(DocumentSubresourceFilterTest, DryRun) {
filter.GetLoadPolicy(GURL(kTestAlphaURL), kImageType));
EXPECT_EQ(LoadPolicy::ALLOW,
filter.GetLoadPolicy(GURL(kTestAlphaDataURI), kImageType));
+ EXPECT_EQ(
+ LoadPolicy::WOULD_DISALLOW,
+ filter.GetLoadPolicy(GURL(kTestAlphaWSURI), proto::ELEMENT_TYPE_OTHER));
EXPECT_EQ(LoadPolicy::ALLOW,
filter.GetLoadPolicy(GURL(kTestBetaURL), kImageType));
EXPECT_EQ(LoadPolicy::WOULD_DISALLOW,
@@ -78,9 +81,9 @@ TEST_F(DocumentSubresourceFilterTest, DryRun) {
filter.GetLoadPolicy(GURL(kTestBetaURL), kSubdocumentType));
const auto& statistics = filter.statistics();
- EXPECT_EQ(5, statistics.num_loads_total);
- EXPECT_EQ(4, statistics.num_loads_evaluated);
- EXPECT_EQ(2, statistics.num_loads_matching_rules);
+ EXPECT_EQ(6, statistics.num_loads_total);
+ EXPECT_EQ(5, statistics.num_loads_evaluated);
+ EXPECT_EQ(3, statistics.num_loads_matching_rules);
EXPECT_EQ(0, statistics.num_loads_disallowed);
}
@@ -95,6 +98,9 @@ TEST_F(DocumentSubresourceFilterTest, Enabled) {
filter.GetLoadPolicy(GURL(kTestAlphaURL), kImageType));
EXPECT_EQ(LoadPolicy::ALLOW,
filter.GetLoadPolicy(GURL(kTestAlphaDataURI), kImageType));
+ EXPECT_EQ(
+ LoadPolicy::DISALLOW,
+ filter.GetLoadPolicy(GURL(kTestAlphaWSURI), proto::ELEMENT_TYPE_OTHER));
EXPECT_EQ(LoadPolicy::ALLOW,
filter.GetLoadPolicy(GURL(kTestBetaURL), kImageType));
EXPECT_EQ(LoadPolicy::DISALLOW,
@@ -103,10 +109,10 @@ TEST_F(DocumentSubresourceFilterTest, Enabled) {
filter.GetLoadPolicy(GURL(kTestBetaURL), kSubdocumentType));
const auto& statistics = filter.statistics();
- EXPECT_EQ(5, statistics.num_loads_total);
- EXPECT_EQ(4, statistics.num_loads_evaluated);
- EXPECT_EQ(2, statistics.num_loads_matching_rules);
- EXPECT_EQ(2, statistics.num_loads_disallowed);
+ EXPECT_EQ(6, statistics.num_loads_total);
+ EXPECT_EQ(5, statistics.num_loads_evaluated);
+ EXPECT_EQ(3, statistics.num_loads_matching_rules);
+ EXPECT_EQ(3, statistics.num_loads_disallowed);
if (!measure_performance) {
EXPECT_TRUE(statistics.evaluation_total_cpu_duration.is_zero());
@@ -233,59 +239,4 @@ TEST_F(SubresourceFilterComputeActivationStateTest,
}
}
-TEST_F(SubresourceFilterComputeActivationStateTest,
- ActivationStateCorrectlyPropagatesDownDocumentHierarchy) {
- const struct {
- std::vector<std::string> ancestor_document_urls;
- ActivationLevel activation_level;
- ActivationState expected_activation_state;
- } kTestCases[] = {
- {{"http://example.com"}, kEnabled, MakeState(false)},
- {std::vector<std::string>(2, "http://example.com"), kEnabled,
- MakeState(false)},
- {std::vector<std::string>(4, "http://example.com"), kEnabled,
- MakeState(false)},
-
- {std::vector<std::string>(4, "http://example.com"), kEnabled,
- MakeState(false, false, kEnabled)},
- {std::vector<std::string>(4, "http://example.com"), kDisabled,
- MakeState(false, false, kDisabled)},
- {std::vector<std::string>(4, "http://example.com"), kDryRun,
- MakeState(false, false, kDryRun)},
-
- {{"http://ex.com", "http://child1.com", "http://parent1.com",
- "http://root.com"},
- kEnabled,
- MakeState(true)},
-
- {{"http://ex.com", "http://child1.com", "http://parent1.com",
- "http://root.com"},
- kEnabled,
- MakeState(true)},
-
- {{"http://ex.com", "http://child2.com", "http://parent1.com",
- "http://root.com"},
- kEnabled,
- MakeState(false, true)},
-
- {{"http://ex.com", "http://ex.com", "http://child3.com",
- "http://parent1.com", "http://root.com"},
- kDryRun,
- MakeState(true, false, kDryRun)},
- };
-
- for (size_t i = 0, size = arraysize(kTestCases); i != size; ++i) {
- const auto& test_case = kTestCases[i];
- SCOPED_TRACE(::testing::Message() << "Test number: " << i);
-
- std::vector<GURL> ancestor_document_urls;
- for (const auto& url_string : test_case.ancestor_document_urls)
- ancestor_document_urls.emplace_back(url_string);
-
- ActivationState activation_state = ComputeActivationState(
- test_case.activation_level, false, ancestor_document_urls, ruleset());
- EXPECT_EQ(test_case.expected_activation_state, activation_state);
- }
-}
-
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/flat/rules.fbs b/chromium/components/subresource_filter/core/common/flat/rules.fbs
index c75502838e4..fdeaea972ee 100644
--- a/chromium/components/subresource_filter/core/common/flat/rules.fbs
+++ b/chromium/components/subresource_filter/core/common/flat/rules.fbs
@@ -32,7 +32,8 @@ table UrlRule {
// A bitmask of element types, same as proto::UrlRule::element_types. Enables
// all element types except POPUP by default.
- element_types : ushort = 2047;
+ // Note: Keep it equal to ELEMENT_TYPE_ALL-ELEMENT_TYPE_POPUP for compactness.
+ element_types : ushort = 6143;
// A bitmask of activation types, same as proto::UrlRule::activation_types.
// Disables all activation types by default.
@@ -47,28 +48,11 @@ table UrlRule {
anchor_right : AnchorType = NONE;
// The list of domains to be included/excluded from the filter's affected set.
- // If a particular string in the list starts with '~' then the respective
- // domain is excluded, otherwise included.
- domains : [string];
+ domains_included : [string];
+ domains_excluded : [string];
// A URL pattern in the format defined by |url_pattern_type|.
url_pattern : string;
-
- // The compound Knuth-Morris-Pratt failure function corresponding to
- // |url_pattern|. Used for SUBSTRING and WILDCARDED URL patterns only.
- //
- // The |url_pattern| is split into subpatterns separated by a '*' wildcard.
- // Then for each subpattern a failure function of the KMP algorithm is built,
- // with the caveat that if some subpattern contains at least one '^'
- // placeholder, all the separator characters in this subpattern are
- // considered equivalent, and the failure function subarray is prefixed with
- // the value 1.
- //
- // The failure functions of subpatterns are stored sequentially in the
- // |failure_function| array. Some subpatterns, however, will not have a
- // corresponding failure function, e.g. the first subpattern if the rule's
- // |anchor_left| is BOUNDARY.
- failure_function : [ubyte];
}
// Contains an N-gram (acting as a key in a hash table) and a list of URL rules
@@ -110,8 +94,11 @@ table IndexedRuleset {
// The index of all blacklist URL rules.
blacklist_index : UrlPatternIndex;
- // The index of all whitelist URL rules.
+ // The index of all whitelist URL rules, except pure activation rules.
whitelist_index : UrlPatternIndex;
+
+ // The index of all whitelist URL rules with activation options.
+ activation_index : UrlPatternIndex;
}
root_type IndexedRuleset;
diff --git a/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.cc b/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.cc
index 96b0f5cb787..f0a4dfd50aa 100644
--- a/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.cc
+++ b/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.cc
@@ -4,6 +4,8 @@
#include "components/subresource_filter/core/common/fuzzy_pattern_matching.h"
+#include <algorithm>
+
namespace subresource_filter {
namespace {
@@ -35,4 +37,23 @@ bool EndsWithFuzzy(base::StringPiece text, base::StringPiece subpattern) {
subpattern);
}
+size_t FindFuzzy(base::StringPiece text,
+ base::StringPiece subpattern,
+ size_t from) {
+ if (from > text.size())
+ return base::StringPiece::npos;
+ if (subpattern.empty())
+ return from;
+
+ auto fuzzy_compare = [](char text_char, char subpattern_char) {
+ return text_char == subpattern_char ||
+ (subpattern_char == kSeparatorPlaceholder && IsSeparator(text_char));
+ };
+
+ base::StringPiece::const_iterator found =
+ std::search(text.begin() + from, text.end(), subpattern.begin(),
+ subpattern.end(), fuzzy_compare);
+ return found == text.end() ? base::StringPiece::npos : found - text.begin();
+}
+
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.h b/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.h
index 15e9fe79262..68472e76ae6 100644
--- a/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.h
+++ b/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.h
@@ -19,12 +19,7 @@
#include <stddef.h>
-#include <type_traits>
-#include <vector>
-
-#include "base/logging.h"
#include "base/strings/string_piece.h"
-#include "components/subresource_filter/core/common/knuth_morris_pratt.h"
namespace subresource_filter {
@@ -56,103 +51,17 @@ inline bool IsSeparator(char c) {
}
}
-class IsEqualOrBothSeparators {
- public:
- bool operator()(char first, char second) const {
- return first == second || (IsSeparator(first) && IsSeparator(second));
- }
-};
-
// Returns whether |text| starts with a fuzzy occurrence of |subpattern|.
bool StartsWithFuzzy(base::StringPiece text, base::StringPiece subpattern);
// Returns whether |text| ends with a fuzzy occurrence of |subpattern|.
bool EndsWithFuzzy(base::StringPiece text, base::StringPiece subpattern);
-// Appends elements of the Knuth-Morris-Pratt failure function corresponding to
-// |subpattern| at the end of the |failure| vector. All separator characters,
-// including the separator placeholder, are considered equivalent. This is
-// necessary in order to support fuzzy separator matching while also keeping the
-// equality predicate transitive and symmetric which is needed for KMP. However,
-// the separators will need to be checked in a second pass for KMP match
-// candidates, which is implemented by AllOccurrencesFuzzy.
-template <typename FailureFunctionElement>
-void BuildFailureFunctionFuzzy(base::StringPiece subpattern,
- std::vector<FailureFunctionElement>* failure) {
- static_assert(std::is_unsigned<FailureFunctionElement>::value,
- "The type is not unsigned.");
- BuildFailureFunction<FailureFunctionElement, IsEqualOrBothSeparators>(
- subpattern, failure);
-}
-
-// Iterator range that yields all fuzzy occurrences of |subpattern| in |text|.
-// The values in the range are the positions just beyond each occurrence.
-// Out-of-range iterators are dereferenced to base::StringPiece::npos.
-//
-// The |failure| array is the failure function created by
-// BuildFailureFunctionFuzzy for the same |subpattern|, and containing at least
-// subpattern.size() values.
-template <typename IntType>
-class AllOccurrencesFuzzy
- : private AllOccurrences<IntType, IsEqualOrBothSeparators> {
- public:
- using Base = AllOccurrences<IntType, IsEqualOrBothSeparators>;
- using BaseIterator = typename Base::Iterator;
-
- class Iterator : public BaseIterator {
- public:
- Iterator& operator++() {
- BaseIterator::operator++();
- AdvanceWhileFalsePositive();
- return *this;
- }
-
- Iterator operator++(int) {
- Iterator copy(*this);
- operator++();
- return copy;
- }
-
- private:
- friend class AllOccurrencesFuzzy;
-
- explicit Iterator(const BaseIterator& base_iterator)
- : BaseIterator(base_iterator) {
- AdvanceWhileFalsePositive();
- }
-
- const AllOccurrencesFuzzy& owner() const {
- return *static_cast<const AllOccurrencesFuzzy*>(BaseIterator::owner_);
- }
-
- // Moves the iterator forward until it either reaches the end, or meets an
- // occurrence exactly matching all non-placeholder separators.
- void AdvanceWhileFalsePositive() {
- while (BaseIterator::match_end_ != base::StringPiece::npos && !IsMatch())
- BaseIterator::operator++();
- }
-
- // Returns whether the currenct match meets all separators.
- bool IsMatch() const {
- DCHECK_LE(BaseIterator::match_end_, owner().text_.size());
- DCHECK_GE(BaseIterator::match_end_, owner().pattern_.size());
-
- // TODO(pkalinnikov): Store a vector of separator positions externally and
- // check if they are equal to the corresponding characters of the |text|.
- return StartsWithFuzzy(owner().text_.substr(BaseIterator::match_end_ -
- owner().pattern_.size()),
- owner().pattern_);
- }
- };
-
- AllOccurrencesFuzzy(base::StringPiece text,
- base::StringPiece subpattern,
- const IntType* failure)
- : Base(text, subpattern, failure) {}
-
- Iterator begin() const { return Iterator(Base::begin()); }
- Iterator end() const { return Iterator(Base::end()); }
-};
+// Returns the position of the leftmost fuzzy occurrence of a |subpattern| in
+// the |text| starting no earlier than |from| the specified position.
+size_t FindFuzzy(base::StringPiece text,
+ base::StringPiece subpattern,
+ size_t from = 0);
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching_unittest.cc b/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching_unittest.cc
index 0dc78a50899..0aab4832d2c 100644
--- a/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching_unittest.cc
+++ b/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching_unittest.cc
@@ -10,7 +10,7 @@
namespace subresource_filter {
-TEST(FuzzyPatternMatchingTest, StartsWithFuzzy) {
+TEST(SubresourceFilterFuzzyPatternMatchingTest, StartsWithFuzzy) {
const struct {
const char* text;
const char* subpattern;
@@ -34,7 +34,7 @@ TEST(FuzzyPatternMatchingTest, StartsWithFuzzy) {
}
}
-TEST(FuzzyPatternMatchingTest, EndsWithFuzzy) {
+TEST(SubresourceFilterFuzzyPatternMatchingTest, EndsWithFuzzy) {
const struct {
const char* text;
const char* subpattern;
@@ -56,33 +56,34 @@ TEST(FuzzyPatternMatchingTest, EndsWithFuzzy) {
EXPECT_EQ(test_case.expected_ends_with, ends_with);
}
}
-TEST(FuzzyPatternMatchingTest, AllOccurrences) {
+
+TEST(SubresourceFilterFuzzyPatternMatchingTest, FindFuzzy) {
const struct {
- const char* text;
- const char* subpattern;
- std::vector<size_t> expected_matches;
+ base::StringPiece text;
+ base::StringPiece subpattern;
+ std::vector<size_t> expected_occurrences;
} kTestCases[] = {
{"abcd", "", {0, 1, 2, 3, 4}},
{"abcd", "de", std::vector<size_t>()},
- {"abcd", "ab", {2}},
- {"abcd", "bc", {3}},
- {"abcd", "cd", {4}},
+ {"abcd", "ab", {0}},
+ {"abcd", "bc", {1}},
+ {"abcd", "cd", {2}},
{"a/bc/a/b", "", {0, 1, 2, 3, 4, 5, 6, 7, 8}},
{"a/bc/a/b", "de", std::vector<size_t>()},
- {"a/bc/a/b", "a/", {2, 7}},
- {"a/bc/a/c", "a/c", {8}},
- {"a/bc/a/c", "a^c", {8}},
+ {"a/bc/a/b", "a/", {0, 5}},
+ {"a/bc/a/c", "a/c", {5}},
+ {"a/bc/a/c", "a^c", {5}},
{"a/bc/a/c", "a?c", std::vector<size_t>()},
{"ab^cd", "ab/cd", std::vector<size_t>()},
{"ab^cd", "b/c", std::vector<size_t>()},
- {"ab^cd", "ab^cd", {5}},
- {"ab^cd", "b^c", {4}},
- {"ab^b/b", "b/b", {6}},
+ {"ab^cd", "ab^cd", {0}},
+ {"ab^cd", "b^c", {1}},
+ {"ab^b/b", "b/b", {3}},
- {"a/a/a/a", "a/a", {3, 5, 7}},
- {"a/a/a/a", "^a^a^a", {7}},
+ {"a/a/a/a", "a/a", {0, 2, 4}},
+ {"a/a/a/a", "^a^a^a", {1}},
{"a/a/a/a", "^a^a?a", std::vector<size_t>()},
{"a/a/a/a", "?a?a?a", std::vector<size_t>()},
};
@@ -92,13 +93,15 @@ TEST(FuzzyPatternMatchingTest, AllOccurrences) {
<< "Test: " << test_case.text
<< "; Subpattern: " << test_case.subpattern);
- std::vector<size_t> failure;
- BuildFailureFunctionFuzzy(test_case.subpattern, &failure);
+ std::vector<size_t> occurrences;
+ for (size_t position = 0; position <= test_case.text.size(); ++position) {
+ position = FindFuzzy(test_case.text, test_case.subpattern, position);
+ if (position == base::StringPiece::npos)
+ break;
+ occurrences.push_back(position);
+ }
- const auto& occurrences = AllOccurrencesFuzzy<size_t>(
- test_case.text, test_case.subpattern, failure.data());
- std::vector<size_t> matches(occurrences.begin(), occurrences.end());
- EXPECT_EQ(test_case.expected_matches, matches);
+ EXPECT_EQ(test_case.expected_occurrences, occurrences);
}
}
diff --git a/chromium/components/subresource_filter/core/common/indexed_ruleset.cc b/chromium/components/subresource_filter/core/common/indexed_ruleset.cc
index b5455cc368f..66d08f4c4a4 100644
--- a/chromium/components/subresource_filter/core/common/indexed_ruleset.cc
+++ b/chromium/components/subresource_filter/core/common/indexed_ruleset.cc
@@ -10,10 +10,10 @@
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_util.h"
#include "components/subresource_filter/core/common/first_party_origin.h"
#include "components/subresource_filter/core/common/ngram_extractor.h"
#include "components/subresource_filter/core/common/url_pattern.h"
-#include "components/subresource_filter/core/common/url_pattern_matching.h"
#include "third_party/flatbuffers/src/include/flatbuffers/flatbuffers.h"
namespace subresource_filter {
@@ -21,6 +21,26 @@ namespace subresource_filter {
namespace {
using FlatStringOffset = flatbuffers::Offset<flatbuffers::String>;
+using FlatDomains = flatbuffers::Vector<FlatStringOffset>;
+using FlatDomainsOffset = flatbuffers::Offset<FlatDomains>;
+
+base::StringPiece ToStringPiece(const flatbuffers::String* string) {
+ DCHECK(string);
+ return base::StringPiece(string->c_str(), string->size());
+}
+
+// Performs three-way comparison between two domains. In the total order defined
+// by this predicate, the lengths of domains will be monotonically decreasing.
+int CompareDomains(base::StringPiece lhs_domain, base::StringPiece rhs_domain) {
+ if (lhs_domain.size() != rhs_domain.size())
+ return lhs_domain.size() > rhs_domain.size() ? -1 : 1;
+ return lhs_domain.compare(rhs_domain);
+}
+
+bool HasNoUpperAscii(base::StringPiece string) {
+ return std::none_of(string.begin(), string.end(),
+ [](char c) { return base::IsAsciiUpper(c); });
+}
// Checks whether a URL |rule| can be converted to its FlatBuffers equivalent,
// and performs the actual conversion.
@@ -31,7 +51,8 @@ class UrlRuleFlatBufferConverter {
// |rule| to FlatBuffer, are initialized (|options|, |anchor_right|, etc.).
UrlRuleFlatBufferConverter(const proto::UrlRule& rule) : rule_(rule) {
is_convertible_ = InitializeOptions() && InitializeElementTypes() &&
- InitializeActivationTypes() && InitializeUrlPattern();
+ InitializeActivationTypes() && InitializeUrlPattern() &&
+ IsMeaningful();
}
// Returns whether the |rule| can be converted to its FlatBuffers equivalent.
@@ -39,40 +60,67 @@ class UrlRuleFlatBufferConverter {
// this client version.
bool is_convertible() const { return is_convertible_; }
+ bool has_element_types() const { return !!element_types_; }
+ bool has_activation_types() const { return !!activation_types_; }
+
// Writes the URL |rule| to the FlatBuffer using the |builder|, and returns
// the offset to the serialized rule.
flatbuffers::Offset<flat::UrlRule> SerializeConvertedRule(
flatbuffers::FlatBufferBuilder* builder) const {
DCHECK(is_convertible());
- flatbuffers::Offset<flatbuffers::Vector<FlatStringOffset>> domains_offset;
+ FlatDomainsOffset domains_included_offset;
+ FlatDomainsOffset domains_excluded_offset;
if (rule_.domains_size()) {
- std::vector<FlatStringOffset> domains;
- domains.reserve(rule_.domains_size());
+ // TODO(pkalinnikov): Consider sharing the vectors between rules.
+ 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());
- std::string domain;
for (const auto& domain_list_item : rule_.domains()) {
- domain.clear();
- domain.reserve(domain_list_item.domain().size() + 1);
+ // Note: The |domain| can have non-ASCII UTF-8 characters, but
+ // ToLowerASCII leaves these intact.
+ // TODO(pkalinnikov): Convert non-ASCII characters to lower case too.
+ // TODO(pkalinnikov): Possibly convert Punycode to IDN here or directly
+ // assume this is done in the proto::UrlRule.
+ const std::string& domain = domain_list_item.domain();
+ auto offset = builder->CreateSharedString(
+ HasNoUpperAscii(domain) ? domain : base::ToLowerASCII(domain));
+
if (domain_list_item.exclude())
- domain += '~';
- domain += domain_list_item.domain();
- domains.push_back(builder->CreateString(domain));
+ domains_excluded.push_back(offset);
+ else
+ domains_included.push_back(offset);
+ }
+
+ // The comparator ensuring the domains order necessary for fast matching.
+ auto precedes = [&builder](FlatStringOffset lhs, FlatStringOffset rhs) {
+ return CompareDomains(ToStringPiece(flatbuffers::GetTemporaryPointer(
+ *builder, lhs)),
+ ToStringPiece(flatbuffers::GetTemporaryPointer(
+ *builder, rhs))) < 0;
+ };
+
+ // The domains are stored in sorted order to support fast matching.
+ if (!domains_included.empty()) {
+ // TODO(pkalinnikov): Don't sort if it is already sorted offline.
+ std::sort(domains_included.begin(), domains_included.end(), precedes);
+ domains_included_offset = builder->CreateVector(domains_included);
+ }
+ if (!domains_excluded.empty()) {
+ std::sort(domains_excluded.begin(), domains_excluded.end(), precedes);
+ domains_excluded_offset = builder->CreateVector(domains_excluded);
}
- domains_offset = builder->CreateVector(domains);
}
auto url_pattern_offset = builder->CreateString(rule_.url_pattern());
- std::vector<uint8_t> failure_function;
- BuildFailureFunction(UrlPattern(rule_), &failure_function);
- auto failure_function_offset =
- builder->CreateVector(failure_function.data(), failure_function.size());
-
- return flat::CreateUrlRule(*builder, options_, element_types_,
- activation_types_, url_pattern_type_,
- anchor_left_, anchor_right_, domains_offset,
- url_pattern_offset, failure_function_offset);
+ return flat::CreateUrlRule(
+ *builder, options_, element_types_, activation_types_,
+ url_pattern_type_, anchor_left_, anchor_right_, domains_included_offset,
+ domains_excluded_offset, url_pattern_offset);
}
private:
@@ -126,15 +174,18 @@ class UrlRuleFlatBufferConverter {
static_assert(
proto::ELEMENT_TYPE_ALL <= std::numeric_limits<uint16_t>::max(),
"Element types can not be stored in uint16_t.");
- if ((rule_.element_types() & proto::ELEMENT_TYPE_ALL) !=
- rule_.element_types()) {
- return false; // Unsupported element types.
- }
element_types_ = static_cast<uint16_t>(rule_.element_types());
+
// Note: Normally we can not distinguish between the main plugin resource
// and any other loads it makes. We treat them both as OBJECT requests.
if (element_types_ & proto::ELEMENT_TYPE_OBJECT_SUBREQUEST)
element_types_ |= proto::ELEMENT_TYPE_OBJECT;
+
+ // Ignore unknown element types.
+ element_types_ &= proto::ELEMENT_TYPE_ALL;
+ // Filtering popups is not supported.
+ element_types_ &= ~proto::ELEMENT_TYPE_POPUP;
+
return true;
}
@@ -142,22 +193,18 @@ class UrlRuleFlatBufferConverter {
static_assert(
proto::ACTIVATION_TYPE_ALL <= std::numeric_limits<uint8_t>::max(),
"Activation types can not be stored in uint8_t.");
- if ((rule_.activation_types() & proto::ACTIVATION_TYPE_ALL) !=
- rule_.activation_types()) {
- return false; // Unsupported activation types.
- }
activation_types_ = static_cast<uint8_t>(rule_.activation_types());
+
+ // Ignore unknown activation types.
+ activation_types_ &= proto::ACTIVATION_TYPE_ALL;
+ // No need in CSS activation, because the CSS rules are not supported.
+ activation_types_ &=
+ ~(proto::ACTIVATION_TYPE_ELEMHIDE | proto::ACTIVATION_TYPE_GENERICHIDE);
+
return true;
}
bool InitializeUrlPattern() {
- if (rule_.url_pattern().size() >
- static_cast<size_t>(std::numeric_limits<uint8_t>::max())) {
- // Failure function can not always be stored as an array of uint8_t in
- // case the pattern's length exceeds 255.
- return false;
- }
-
switch (rule_.url_pattern_type()) {
case proto::URL_PATTERN_TYPE_SUBSTRING:
url_pattern_type_ = flat::UrlPatternType_SUBSTRING;
@@ -165,10 +212,9 @@ class UrlRuleFlatBufferConverter {
case proto::URL_PATTERN_TYPE_WILDCARDED:
url_pattern_type_ = flat::UrlPatternType_WILDCARDED;
break;
- case proto::URL_PATTERN_TYPE_REGEXP:
- url_pattern_type_ = flat::UrlPatternType_REGEXP;
- break;
+ // TODO(pkalinnikov): Implement REGEXP rules matching.
+ case proto::URL_PATTERN_TYPE_REGEXP:
default:
return false; // Unsupported URL pattern type.
}
@@ -183,6 +229,9 @@ class UrlRuleFlatBufferConverter {
return true;
}
+ // Returns whether the rule is not a no-op after all the modifications above.
+ bool IsMeaningful() const { return element_types_ || activation_types_; }
+
const proto::UrlRule& rule_;
uint8_t options_ = 0;
@@ -200,7 +249,7 @@ class UrlRuleFlatBufferConverter {
// RulesetIndexer --------------------------------------------------------------
// static
-const int RulesetIndexer::kIndexedFormatVersion = 11;
+const int RulesetIndexer::kIndexedFormatVersion = 17;
RulesetIndexer::MutableUrlPatternIndex::MutableUrlPatternIndex() = default;
RulesetIndexer::MutableUrlPatternIndex::~MutableUrlPatternIndex() = default;
@@ -212,23 +261,27 @@ bool RulesetIndexer::AddUrlRule(const proto::UrlRule& rule) {
UrlRuleFlatBufferConverter converter(rule);
if (!converter.is_convertible())
return false;
+ DCHECK_NE(rule.url_pattern_type(), proto::URL_PATTERN_TYPE_REGEXP);
auto rule_offset = converter.SerializeConvertedRule(&builder_);
- MutableUrlPatternIndex* index_part =
- (rule.semantics() == proto::RULE_SEMANTICS_BLACKLIST ? &blacklist_
- : &whitelist_);
-
- NGram ngram = 0;
- if (rule.url_pattern_type() != proto::URL_PATTERN_TYPE_REGEXP) {
- ngram =
- GetMostDistinctiveNGram(index_part->ngram_index, rule.url_pattern());
- }
+ auto add_rule_to_index = [&rule, rule_offset](MutableUrlPatternIndex* index) {
+ NGram ngram =
+ GetMostDistinctiveNGram(index->ngram_index, rule.url_pattern());
+ if (ngram) {
+ index->ngram_index[ngram].push_back(rule_offset);
+ } else {
+ // TODO(pkalinnikov): Index fallback rules as well.
+ index->fallback_rules.push_back(rule_offset);
+ }
+ };
- if (ngram) {
- index_part->ngram_index[ngram].push_back(rule_offset);
+ if (rule.semantics() == proto::RULE_SEMANTICS_BLACKLIST) {
+ add_rule_to_index(&blacklist_);
} else {
- // TODO(pkalinnikov): Index fallback rules as well.
- index_part->fallback_rules.push_back(rule_offset);
+ if (converter.has_element_types())
+ add_rule_to_index(&whitelist_);
+ if (converter.has_activation_types())
+ add_rule_to_index(&activation_);
}
return true;
@@ -237,12 +290,14 @@ bool RulesetIndexer::AddUrlRule(const proto::UrlRule& rule) {
void RulesetIndexer::Finish() {
auto blacklist_offset = SerializeUrlPatternIndex(blacklist_);
auto whitelist_offset = SerializeUrlPatternIndex(whitelist_);
+ auto activation_offset = SerializeUrlPatternIndex(activation_);
- auto url_rules_index_offset =
- flat::CreateIndexedRuleset(builder_, blacklist_offset, whitelist_offset);
+ auto url_rules_index_offset = flat::CreateIndexedRuleset(
+ builder_, blacklist_offset, whitelist_offset, activation_offset);
builder_.Finish(url_rules_index_offset);
}
+// static
NGram RulesetIndexer::GetMostDistinctiveNGram(
const MutableNGramIndex& ngram_index,
base::StringPiece pattern) {
@@ -304,73 +359,108 @@ using FlatUrlRuleList = flatbuffers::Vector<flatbuffers::Offset<flat::UrlRule>>;
using FlatNGramIndex =
flatbuffers::Vector<flatbuffers::Offset<flat::NGramToRules>>;
-// Returns whether the |origin| matches the list of |domains|. 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 |domains| lists.
+// Returns the size of the longest (sub-)domain of |origin| matching one of the
+// |domains| in the list.
//
-// TODO(pkalinnikov): Make it fast.
-bool DoesInitiatorMatchDomainList(
- const url::Origin& initiator,
- const flatbuffers::Vector<FlatStringOffset>& domains,
- bool disable_generic_rules) {
- if (!domains.size())
- return !disable_generic_rules;
- // Unique |initiator| matches lists of exception domains only.
- if (initiator.unique()) {
- for (const flatbuffers::String* domain_filter : domains) {
- DCHECK_GT(domain_filter->size(), 0u);
- if (domain_filter->Get(0) != '~')
- return false;
+// The |domains| should be sorted in descending order of their length, and
+// ascending alphabetical order within the groups of same-length domains.
+size_t GetLongestMatchingSubdomain(const url::Origin& origin,
+ const FlatDomains& domains) {
+ // If the |domains| list is short, then the simple strategy is usually faster.
+ if (domains.size() <= 5) {
+ for (auto* domain : domains) {
+ const base::StringPiece domain_piece = ToStringPiece(domain);
+ if (origin.DomainIs(domain_piece))
+ return domain_piece.size();
}
- return !disable_generic_rules;
+ return 0;
}
+ // Otherwise look for each subdomain of the |origin| using binary search.
+
+ DCHECK(!origin.unique());
+ base::StringPiece canonicalized_host(origin.host());
+ if (canonicalized_host.empty())
+ return 0;
+
+ // If the host name ends with a dot, then ignore it.
+ if (canonicalized_host.back() == '.')
+ canonicalized_host.remove_suffix(1);
+
+ // The |left| bound of the search is shared between iterations, because
+ // subdomains are considered in decreasing order of their lengths, therefore
+ // each consecutive lower_bound will be at least as far as the previous.
+ flatbuffers::uoffset_t left = 0;
+ for (size_t position = 0;; ++position) {
+ const base::StringPiece subdomain = canonicalized_host.substr(position);
+
+ flatbuffers::uoffset_t right = domains.size();
+ while (left + 1 < right) {
+ auto middle = left + (right - left) / 2;
+ DCHECK_LT(middle, domains.size());
+ if (CompareDomains(ToStringPiece(domains[middle]), subdomain) <= 0)
+ left = middle;
+ else
+ right = middle;
+ }
- size_t max_domain_length = 0;
- bool is_positive = true;
- bool negatives_only = true;
+ DCHECK_LT(left, domains.size());
+ if (ToStringPiece(domains[left]) == subdomain)
+ return subdomain.size();
- for (flatbuffers::uoffset_t i = 0, size = domains.size(); i != size; ++i) {
- const flatbuffers::String* domain_filter = domains.Get(i);
- if (domain_filter->Length() <= max_domain_length)
- continue;
+ position = canonicalized_host.find('.', position);
+ if (position == base::StringPiece::npos)
+ break;
+ }
- base::StringPiece filter_piece(domain_filter->c_str(),
- domain_filter->Length());
- const bool is_negative = (domain_filter->Get(0) == '~');
- if (is_negative) {
- filter_piece.remove_prefix(1);
- if (filter_piece.length() == max_domain_length)
- continue;
- } else {
- negatives_only = false;
- }
+ return 0;
+}
- if (!initiator.DomainIs(filter_piece))
- continue;
- max_domain_length = filter_piece.length();
- is_positive = !is_negative;
- }
+// 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) {
+ const bool is_generic = !rule.domains_included();
+ DCHECK(is_generic || rule.domains_included()->size());
+ if (disable_generic_rules && is_generic)
+ return false;
+
+ // Unique |origin| matches lists of exception domains only.
+ if (origin.unique())
+ return is_generic;
- return max_domain_length ? is_positive
- : negatives_only && !disable_generic_rules;
+ size_t longest_matching_included_domain_length = 1;
+ if (!is_generic) {
+ longest_matching_included_domain_length =
+ GetLongestMatchingSubdomain(origin, *rule.domains_included());
+ }
+ if (longest_matching_included_domain_length && rule.domains_excluded()) {
+ return GetLongestMatchingSubdomain(origin, *rule.domains_excluded()) <
+ longest_matching_included_domain_length;
+ }
+ return !!longest_matching_included_domain_length;
}
-// Returns true iff the request to |url| of type |element_type| requested by
-// |initiator| matches the |rule|'s metadata: resource type, first/third party,
-// domain list.
-bool DoesRuleMetadataMatch(const flat::UrlRule& rule,
- const url::Origin& initiator,
- proto::ElementType element_type,
- proto::ActivationType activation_type,
- bool is_third_party,
- bool disable_generic_rules) {
+// Returns whether the request matches flags of the specified URL |rule|. Takes
+// into account:
+// - |element_type| of the requested resource, if not *_UNSPECIFIED.
+// - |activation_type| for a subdocument request, if not *_UNSPECIFIED.
+// - Whether the resource |is_third_party| w.r.t. its embedding document.
+bool DoesRuleFlagsMatch(const flat::UrlRule& rule,
+ proto::ElementType element_type,
+ proto::ActivationType activation_type,
+ bool is_third_party) {
+ DCHECK(element_type == proto::ELEMENT_TYPE_UNSPECIFIED ||
+ activation_type == proto::ACTIVATION_TYPE_UNSPECIFIED);
+
if (element_type != proto::ELEMENT_TYPE_UNSPECIFIED &&
!(rule.element_types() & element_type)) {
return false;
@@ -389,14 +479,12 @@ bool DoesRuleMetadataMatch(const flat::UrlRule& rule,
return false;
}
- return rule.domains() ? DoesInitiatorMatchDomainList(
- initiator, *rule.domains(), disable_generic_rules)
- : !disable_generic_rules;
+ return true;
}
bool MatchesAny(const FlatUrlRuleList* rules,
const GURL& url,
- const url::Origin& initiator,
+ const url::Origin& document_origin,
proto::ElementType element_type,
proto::ActivationType activation_type,
bool is_third_party,
@@ -405,19 +493,16 @@ bool MatchesAny(const FlatUrlRuleList* rules,
return false;
for (const flat::UrlRule* rule : *rules) {
DCHECK_NE(rule, nullptr);
-
- if (rule->url_pattern_type() != flat::UrlPatternType_REGEXP) {
- const uint8_t* begin = rule->failure_function()->data();
- const uint8_t* end = begin + rule->failure_function()->size();
- if (!IsUrlPatternMatch(url, UrlPattern(*rule), begin, end))
- continue;
- } else {
- // TODO(pkalinnikov): Implement REGEXP rules matching.
+ DCHECK_NE(rule->url_pattern_type(), flat::UrlPatternType_REGEXP);
+ if (!DoesRuleFlagsMatch(*rule, element_type, activation_type,
+ is_third_party)) {
continue;
}
+ if (!UrlPattern(*rule).MatchesUrl(url))
+ continue;
- if (DoesRuleMetadataMatch(*rule, initiator, element_type, activation_type,
- is_third_party, disable_generic_rules)) {
+ if (DoesOriginMatchDomainList(document_origin, *rule,
+ disable_generic_rules)) {
return true;
}
}
@@ -426,10 +511,11 @@ bool MatchesAny(const FlatUrlRuleList* rules,
}
// Returns whether the network request matches a particular part of the index.
-// |is_third_party| should reflect the relation between |url| and |initiator|.
+// |is_third_party| should reflect the relation between |url| and
+// |document_origin|.
bool IsMatch(const flat::UrlPatternIndex* index,
const GURL& url,
- const url::Origin& initiator,
+ const url::Origin& document_origin,
proto::ElementType element_type,
proto::ActivationType activation_type,
bool is_third_party,
@@ -457,14 +543,14 @@ bool IsMatch(const flat::UrlPatternIndex* index,
const flat::NGramToRules* entry = hash_table->Get(slot_index);
if (entry == empty_slot)
continue;
- if (MatchesAny(entry->rule_list(), url, initiator, element_type,
+ if (MatchesAny(entry->rule_list(), url, document_origin, element_type,
activation_type, is_third_party, disable_generic_rules)) {
return true;
}
}
const FlatUrlRuleList* rules = index->fallback_rules();
- return MatchesAny(rules, url, initiator, element_type, activation_type,
+ return MatchesAny(rules, url, document_origin, element_type, activation_type,
is_third_party, disable_generic_rules);
}
@@ -493,7 +579,7 @@ bool IndexedRulesetMatcher::ShouldDisableFilteringForDocument(
return false;
}
return IsMatch(
- root_->whitelist_index(), document_url, parent_document_origin,
+ root_->activation_index(), document_url, parent_document_origin,
proto::ELEMENT_TYPE_UNSPECIFIED, activation_type,
FirstPartyOrigin::IsThirdParty(document_url, parent_document_origin),
false);
diff --git a/chromium/components/subresource_filter/core/common/indexed_ruleset.h b/chromium/components/subresource_filter/core/common/indexed_ruleset.h
index 811f9d93aa4..a9fbd941e02 100644
--- a/chromium/components/subresource_filter/core/common/indexed_ruleset.h
+++ b/chromium/components/subresource_filter/core/common/indexed_ruleset.h
@@ -95,6 +95,7 @@ class RulesetIndexer {
MutableUrlPatternIndex blacklist_;
MutableUrlPatternIndex whitelist_;
+ MutableUrlPatternIndex activation_;
flatbuffers::FlatBufferBuilder builder_;
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 f423be3d6c3..998fd747322 100644
--- a/chromium/components/subresource_filter/core/common/indexed_ruleset_unittest.cc
+++ b/chromium/components/subresource_filter/core/common/indexed_ruleset_unittest.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/macros.h"
+#include "base/strings/string_util.h"
#include "components/subresource_filter/core/common/first_party_origin.h"
#include "components/subresource_filter/core/common/proto/rules.pb.h"
#include "components/subresource_filter/core/common/url_pattern.h"
@@ -28,6 +29,18 @@ constexpr proto::SourceType kAnyParty = proto::SOURCE_TYPE_ANY;
constexpr proto::SourceType kFirstParty = proto::SOURCE_TYPE_FIRST_PARTY;
constexpr proto::SourceType kThirdParty = proto::SOURCE_TYPE_THIRD_PARTY;
+constexpr proto::ElementType kAllElementTypes = proto::ELEMENT_TYPE_ALL;
+constexpr proto::ElementType kOther = proto::ELEMENT_TYPE_OTHER;
+constexpr proto::ElementType kImage = proto::ELEMENT_TYPE_IMAGE;
+constexpr proto::ElementType kFont = proto::ELEMENT_TYPE_FONT;
+constexpr proto::ElementType kScript = proto::ELEMENT_TYPE_SCRIPT;
+constexpr proto::ElementType kPopup = proto::ELEMENT_TYPE_POPUP;
+constexpr proto::ElementType kWebSocket = proto::ELEMENT_TYPE_WEBSOCKET;
+
+constexpr proto::ActivationType kDocument = proto::ACTIVATION_TYPE_DOCUMENT;
+constexpr proto::ActivationType kGenericBlock =
+ proto::ACTIVATION_TYPE_GENERICBLOCK;
+
// Note: Returns unique origin on origin_string == nullptr.
url::Origin GetOrigin(const char* origin_string) {
return origin_string ? url::Origin(GURL(origin_string)) : url::Origin();
@@ -46,13 +59,13 @@ class UrlRuleBuilder {
: proto::RULE_SEMANTICS_BLACKLIST);
rule_.set_source_type(source_type);
- rule_.set_element_types(proto::ELEMENT_TYPE_ALL);
+ rule_.set_element_types(kAllElementTypes);
- rule_.set_url_pattern_type(url_pattern.type);
- rule_.set_anchor_left(url_pattern.anchor_left);
- rule_.set_anchor_right(url_pattern.anchor_right);
- rule_.set_match_case(url_pattern.match_case);
- rule_.set_url_pattern(url_pattern.url_pattern.as_string());
+ rule_.set_url_pattern_type(url_pattern.type());
+ rule_.set_anchor_left(url_pattern.anchor_left());
+ rule_.set_anchor_right(url_pattern.anchor_right());
+ rule_.set_match_case(url_pattern.match_case());
+ rule_.set_url_pattern(url_pattern.url_pattern().as_string());
}
UrlRuleBuilder& AddDomain(std::string domain_pattern) {
@@ -83,35 +96,34 @@ class UrlRuleBuilder {
} // namespace
-class IndexedRulesetTest : public testing::Test {
+class SubresourceFilterIndexedRulesetTest : public testing::Test {
public:
- IndexedRulesetTest() = default;
+ SubresourceFilterIndexedRulesetTest() = default;
protected:
bool ShouldAllow(const char* url,
- const char* initiator = nullptr,
- proto::ElementType element_type = proto::ELEMENT_TYPE_OTHER,
+ const char* document_origin = nullptr,
+ proto::ElementType element_type = kOther,
bool disable_generic_rules = false) const {
DCHECK_NE(matcher_.get(), nullptr);
- url::Origin origin = GetOrigin(initiator);
+ url::Origin origin = GetOrigin(document_origin);
FirstPartyOrigin first_party(origin);
return !matcher_->ShouldDisallowResourceLoad(
GURL(url), first_party, element_type, disable_generic_rules);
}
bool ShouldAllow(const char* url,
- const char* initiator,
+ const char* document_origin,
bool disable_generic_rules) const {
- return ShouldAllow(url, initiator, proto::ELEMENT_TYPE_OTHER,
- disable_generic_rules);
+ return ShouldAllow(url, document_origin, kOther, disable_generic_rules);
}
bool ShouldDeactivate(const char* document_url,
- const char* initiator = nullptr,
+ const char* parent_document_origin = nullptr,
proto::ActivationType activation_type =
proto::ACTIVATION_TYPE_UNSPECIFIED) const {
DCHECK(matcher_);
- url::Origin origin = GetOrigin(initiator);
+ url::Origin origin = GetOrigin(parent_document_origin);
return matcher_->ShouldDisableFilteringForDocument(GURL(document_url),
origin, activation_type);
}
@@ -153,10 +165,10 @@ class IndexedRulesetTest : public testing::Test {
std::unique_ptr<IndexedRulesetMatcher> matcher_;
private:
- DISALLOW_COPY_AND_ASSIGN(IndexedRulesetTest);
+ DISALLOW_COPY_AND_ASSIGN(SubresourceFilterIndexedRulesetTest);
};
-TEST_F(IndexedRulesetTest, OneRuleWithoutMetaInfo) {
+TEST_F(SubresourceFilterIndexedRulesetTest, OneRuleWithoutMetaInfo) {
const struct {
UrlPattern url_pattern;
const char* url;
@@ -291,9 +303,8 @@ TEST_F(IndexedRulesetTest, OneRuleWithoutMetaInfo) {
};
for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message()
- << "Rule: " << test_case.url_pattern.url_pattern
- << "; URL: " << test_case.url);
+ SCOPED_TRACE(testing::Message() << "Rule: " << test_case.url_pattern
+ << "; URL: " << test_case.url);
AddBlacklistRule(test_case.url_pattern);
Finish();
@@ -303,13 +314,13 @@ TEST_F(IndexedRulesetTest, OneRuleWithoutMetaInfo) {
}
}
-TEST_F(IndexedRulesetTest, OneRuleWithThirdParty) {
+TEST_F(SubresourceFilterIndexedRulesetTest, OneRuleWithThirdParty) {
const struct {
const char* url_pattern;
proto::SourceType source_type;
const char* url;
- const char* initiator;
+ const char* document_origin;
bool expect_allowed;
} kTestCases[] = {
{"example.com", kThirdParty, "http://example.com", "http://exmpl.org",
@@ -349,124 +360,174 @@ TEST_F(IndexedRulesetTest, OneRuleWithThirdParty) {
SCOPED_TRACE(testing::Message()
<< "Rule: " << test_case.url_pattern << "; source: "
<< (int)test_case.source_type << "; URL: " << test_case.url
- << "; Initiator: " << test_case.initiator);
+ << "; document: " << test_case.document_origin);
AddBlacklistRule(UrlPattern(test_case.url_pattern, kSubstring),
test_case.source_type);
Finish();
EXPECT_EQ(test_case.expect_allowed,
- ShouldAllow(test_case.url, test_case.initiator));
+ ShouldAllow(test_case.url, test_case.document_origin));
Reset();
}
}
-TEST_F(IndexedRulesetTest, OneRuleWithDomainList) {
+TEST_F(SubresourceFilterIndexedRulesetTest, OneRuleWithDomainList) {
+ constexpr const char* kUrl = "http://example.com";
+
const struct {
- const char* url_pattern;
std::vector<std::string> domains;
+ const char* document_origin;
- const char* url;
- const char* initiator;
bool expect_allowed;
} kTestCases[] = {
- {"example.com",
- {"domain1.com", "domain2.com"},
- "http://example.com",
- "http://domain1.com",
+ {std::vector<std::string>(), nullptr, false},
+ {std::vector<std::string>(), "http://domain.com", false},
+
+ {{"domain.com"}, nullptr, true},
+ {{"domain.com"}, "http://domain.com", false},
+ {{"ddomain.com"}, "http://domain.com", true},
+ {{"domain.com"}, "http://ddomain.com", true},
+ {{"domain.com"}, "http://sub.domain.com", false},
+ {{"sub.domain.com"}, "http://domain.com", true},
+ {{"sub.domain.com"}, "http://sub.domain.com", false},
+ {{"sub.domain.com"}, "http://a.b.c.sub.domain.com", false},
+ {{"sub.domain.com"}, "http://sub.domain.com.com", true},
+
+ // TODO(pkalinnikov): Probably need to canonicalize domain patterns to
+ // avoid subtleties like below.
+ {{"domain.com"}, "http://domain.com.", false},
+ {{"domain.com"}, "http://.domain.com", false},
+ {{"domain.com"}, "http://.domain.com.", false},
+ {{".domain.com"}, "http://.domain.com", false},
+ {{"domain.com."}, "http://domain.com", true},
+ {{"domain.com."}, "http://domain.com.", false},
+
+ {{"domain..com"}, "http://domain.com", true},
+ {{"domain.com"}, "http://domain..com", true},
+ {{"domain..com"}, "http://domain..com", false},
+
+ {{"~domain.com"}, nullptr, false},
+ {{"~domain.com"}, "http://domain.com", true},
+ {{"~ddomain.com"}, "http://domain.com", false},
+ {{"~domain.com"}, "http://ddomain.com", false},
+ {{"~domain.com"}, "http://sub.domain.com", true},
+ {{"~sub.domain.com"}, "http://domain.com", false},
+ {{"~sub.domain.com"}, "http://sub.domain.com", true},
+ {{"~sub.domain.com"}, "http://a.b.c.sub.domain.com", true},
+ {{"~sub.domain.com"}, "http://sub.domain.com.com", false},
+
+ {{"domain1.com", "domain2.com"}, nullptr, true},
+ {{"domain1.com", "domain2.com"}, "http://domain1.com", false},
+ {{"domain1.com", "domain2.com"}, "http://domain2.com", false},
+ {{"domain1.com", "domain2.com"}, "http://domain3.com", true},
+ {{"domain1.com", "domain2.com"}, "http://not_domain1.com", true},
+ {{"domain1.com", "domain2.com"}, "http://sub.domain1.com", false},
+ {{"domain1.com", "domain2.com"}, "http://a.b.c.sub.domain2.com", false},
+
+ {{"~domain1.com", "~domain2.com"}, "http://domain1.com", true},
+ {{"~domain1.com", "~domain2.com"}, "http://domain2.com", true},
+ {{"~domain1.com", "~domain2.com"}, "http://domain3.com", false},
+
+ {{"domain.com", "~sub.domain.com"}, "http://domain.com", false},
+ {{"domain.com", "~sub.domain.com"}, "http://sub.domain.com", true},
+ {{"domain.com", "~sub.domain.com"}, "http://a.b.sub.domain.com", true},
+ {{"domain.com", "~sub.domain.com"}, "http://ssub.domain.com", false},
+
+ {{"domain.com", "~a.domain.com", "~b.domain.com"},
+ "http://domain.com",
false},
-
- {"example.com",
- {"domain1.com", "domain2.com"},
- "http://example.com",
- "http://not_domain1.com",
+ {{"domain.com", "~a.domain.com", "~b.domain.com"},
+ "http://a.domain.com",
true},
-
- {"example.com",
- {"domain1.com", "domain2.com"},
- "http://example.com",
- "http://domain2.com",
- false},
-
- {"example.com",
- {"domain1.com", "domain2.com"},
- "http://example.com",
- "http://subdomain.domain2.com",
- false},
-
- {"example.com",
- {"domain1.com", "domain2.com"},
- "http://example.com",
- "http://domain3.com",
+ {{"domain.com", "~a.domain.com", "~b.domain.com"},
+ "http://b.domain.com",
true},
- {"example.com",
- {"~domain1.com", "~domain2.com"},
- "http://example.com",
- "http://domain2.com",
+ {{"domain.com", "~a.domain.com", "b.a.domain.com"},
+ "http://domain.com",
+ false},
+ {{"domain.com", "~a.domain.com", "b.a.domain.com"},
+ "http://a.domain.com",
true},
-
- {"example.com",
- {"~domain1.com", "~domain2.com"},
- "http://example.com",
- "http://domain3.com",
+ {{"domain.com", "~a.domain.com", "b.a.domain.com"},
+ "http://b.a.domain.com",
false},
-
- {"example.com",
- {"domain1.com", "~subdomain1.domain1.com"},
- "http://example.com",
- "http://subdomain2.domain1.com",
+ {{"domain.com", "~a.domain.com", "b.a.domain.com"},
+ "http://c.b.a.domain.com",
false},
- {"example.com",
- {"domain1.com", "~subdomain1.domain1.com"},
- "http://example.com",
- "http://subdomain1.domain1.com",
- true},
-
- {"example.com",
- {"domain1.com", "domain2.com"},
- "http://example.com",
- nullptr,
- true},
-
// The following test addresses a former bug in domain list matcher. When
// "domain.com" was matched, the positive filters lookup stopped, and the
// next domain was considered as a negative. The initial character was
// skipped (supposing it's a '~') and the remainder was considered a
// domain. So "ddomain.com" would be matched and thus the whole rule would
// be classified as non-matching, which is not correct.
- {"ex.com",
- {"domain.com", "ddomain.com", "~sub.domain.com"},
- "http://ex.com",
+ {{"domain.com", "ddomain.com", "~sub.domain.com"},
"http://domain.com",
false},
};
for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message() << "Rule: " << test_case.url_pattern
- << "; URL: " << test_case.url
- << "; Initiator: " << test_case.initiator);
+ SCOPED_TRACE(testing::Message()
+ << "Domains: " << base::JoinString(test_case.domains, "|")
+ << "; document: " << test_case.document_origin);
- UrlRuleBuilder builder(UrlPattern(test_case.url_pattern, kSubstring));
+ UrlRuleBuilder builder(UrlPattern(kUrl, kSubstring));
builder.AddDomains(test_case.domains);
AddUrlRule(builder.rule());
Finish();
EXPECT_EQ(test_case.expect_allowed,
- ShouldAllow(test_case.url, test_case.initiator));
+ ShouldAllow(kUrl, test_case.document_origin));
Reset();
}
}
-TEST_F(IndexedRulesetTest, OneRuleWithElementTypes) {
- constexpr proto::ElementType kAll = proto::ELEMENT_TYPE_ALL;
- constexpr proto::ElementType kImage = proto::ELEMENT_TYPE_IMAGE;
- constexpr proto::ElementType kFont = proto::ELEMENT_TYPE_FONT;
- constexpr proto::ElementType kScript = proto::ELEMENT_TYPE_SCRIPT;
- constexpr proto::ElementType kSubdoc = proto::ELEMENT_TYPE_SUBDOCUMENT;
- constexpr proto::ElementType kPopup = proto::ELEMENT_TYPE_POPUP;
+TEST_F(SubresourceFilterIndexedRulesetTest, OneRuleWithLongDomainList) {
+ constexpr const char* kUrl = "http://example.com";
+ constexpr size_t kDomains = 200;
+
+ std::vector<std::string> domains;
+ for (size_t i = 0; i < kDomains; ++i) {
+ const std::string domain = "domain" + std::to_string(i) + ".com";
+ domains.push_back(domain);
+ domains.push_back("~sub." + domain);
+ domains.push_back("a.sub." + domain);
+ domains.push_back("b.sub." + domain);
+ domains.push_back("c.sub." + domain);
+ domains.push_back("~aa.sub." + domain);
+ domains.push_back("~ab.sub." + domain);
+ domains.push_back("~ba.sub." + domain);
+ domains.push_back("~bb.sub." + domain);
+ domains.push_back("~sub.sub.c.sub." + domain);
+ }
+
+ UrlRuleBuilder builder(UrlPattern(kUrl, kSubstring));
+ builder.AddDomains(domains);
+ AddUrlRule(builder.rule());
+ Finish();
+
+ for (size_t i = 0; i < kDomains; ++i) {
+ SCOPED_TRACE(testing::Message() << "Iteration: " << i);
+ const std::string domain = "domain" + std::to_string(i) + ".com";
+
+ EXPECT_FALSE(ShouldAllow(kUrl, ("http://" + domain).c_str()));
+ EXPECT_TRUE(ShouldAllow(kUrl, ("http://sub." + domain).c_str()));
+ EXPECT_FALSE(ShouldAllow(kUrl, ("http://a.sub." + domain).c_str()));
+ EXPECT_FALSE(ShouldAllow(kUrl, ("http://b.sub." + domain).c_str()));
+ EXPECT_FALSE(ShouldAllow(kUrl, ("http://c.sub." + domain).c_str()));
+ EXPECT_TRUE(ShouldAllow(kUrl, ("http://aa.sub." + domain).c_str()));
+ EXPECT_TRUE(ShouldAllow(kUrl, ("http://ab.sub." + domain).c_str()));
+ EXPECT_TRUE(ShouldAllow(kUrl, ("http://ba.sub." + domain).c_str()));
+ EXPECT_TRUE(ShouldAllow(kUrl, ("http://bb.sub." + domain).c_str()));
+ EXPECT_FALSE(ShouldAllow(kUrl, ("http://sub.c.sub." + domain).c_str()));
+ EXPECT_TRUE(ShouldAllow(kUrl, ("http://sub.sub.c.sub." + domain).c_str()));
+ }
+}
+TEST_F(SubresourceFilterIndexedRulesetTest, OneRuleWithElementTypes) {
+ constexpr auto kAll = kAllElementTypes;
const struct {
const char* url_pattern;
int32_t element_types;
@@ -490,11 +551,11 @@ TEST_F(IndexedRulesetTest, OneRuleWithElementTypes) {
{"ex.com", kAll & ~kFont & ~kScript, "http://ex.com/font", kFont, true},
{"ex.com", kAll & ~kFont & ~kScript, "http://ex.com/scr", kScript, true},
{"ex.com", kAll & ~kFont & ~kScript, "http://ex.com/img", kImage, false},
- {"ex.com$subdocument,~subdocument", kSubdoc & ~kSubdoc,
- "http://ex.com/sub", kSubdoc, true},
{"ex.com", kAll, "http://ex.com", proto::ELEMENT_TYPE_OTHER, false},
{"ex.com", kAll, "http://ex.com", proto::ELEMENT_TYPE_UNSPECIFIED, true},
+ {"ex.com", kWebSocket, "ws://ex.com", proto::ELEMENT_TYPE_WEBSOCKET,
+ false},
};
for (const auto& test_case : kTestCases) {
@@ -509,15 +570,14 @@ TEST_F(IndexedRulesetTest, OneRuleWithElementTypes) {
Finish();
EXPECT_EQ(test_case.expect_allowed,
- ShouldAllow(test_case.url, nullptr /* initiator */,
+ ShouldAllow(test_case.url, nullptr /* document_origin */,
test_case.element_type));
Reset();
}
}
-TEST_F(IndexedRulesetTest, OneRuleWithActivationTypes) {
+TEST_F(SubresourceFilterIndexedRulesetTest, OneRuleWithActivationTypes) {
constexpr proto::ActivationType kNone = proto::ACTIVATION_TYPE_UNSPECIFIED;
- constexpr proto::ActivationType kDocument = proto::ACTIVATION_TYPE_DOCUMENT;
const struct {
const char* url_pattern;
@@ -531,9 +591,9 @@ TEST_F(IndexedRulesetTest, OneRuleWithActivationTypes) {
{"xample.com", kDocument, "http://example.com", kDocument, true},
{"exampl.com", kDocument, "http://example.com", kDocument, false},
- {"example.com", kNone, "http://example.com", kDocument, false},
+ {"example.com", kGenericBlock, "http://example.com", kDocument, false},
{"example.com", kDocument, "http://example.com", kNone, false},
- {"example.com", kNone, "http://example.com", kNone, false},
+ {"example.com", kGenericBlock, "http://example.com", kNone, false},
// Invalid GURL.
{"example.com", kDocument, "http;//example.com", kDocument, false},
@@ -552,7 +612,8 @@ TEST_F(IndexedRulesetTest, OneRuleWithActivationTypes) {
Finish();
EXPECT_EQ(test_case.expect_disabled,
- ShouldDeactivate(test_case.document_url, nullptr /* initiator */,
+ ShouldDeactivate(test_case.document_url,
+ nullptr /* parent_document_origin */,
test_case.activation_type));
EXPECT_EQ(test_case.expect_disabled,
ShouldDeactivate(test_case.document_url, "http://example.com/",
@@ -564,7 +625,24 @@ TEST_F(IndexedRulesetTest, OneRuleWithActivationTypes) {
}
}
-TEST_F(IndexedRulesetTest, MatchWithDisableGenericRules) {
+TEST_F(SubresourceFilterIndexedRulesetTest, RuleWithElementAndActivationTypes) {
+ UrlRuleBuilder builder(UrlPattern("allow.ex.com"), true /* is_whitelist */);
+ builder.rule().set_activation_types(kDocument);
+
+ AddUrlRule(builder.rule());
+ AddBlacklistRule(UrlPattern("ex.com"));
+ Finish();
+
+ EXPECT_FALSE(ShouldAllow("http://ex.com"));
+ EXPECT_TRUE(ShouldAllow("http://allow.ex.com"));
+ EXPECT_FALSE(ShouldDeactivate("http://allow.ex.com",
+ nullptr /* parent_document_origin */,
+ kGenericBlock));
+ EXPECT_TRUE(ShouldDeactivate(
+ "http://allow.ex.com", nullptr /* parent_document_origin */, kDocument));
+}
+
+TEST_F(SubresourceFilterIndexedRulesetTest, MatchWithDisableGenericRules) {
// Generic rules.
ASSERT_NO_FATAL_FAILURE(
AddUrlRule(UrlRuleBuilder(UrlPattern("some_text", kSubstring)).rule()));
@@ -588,12 +666,15 @@ TEST_F(IndexedRulesetTest, MatchWithDisableGenericRules) {
.AddDomain("example1.com")
.AddDomain("sub.example2.com")
.rule()));
+ // Note: Some of the rules have common domains (e.g., example1.com), which are
+ // ultimately shared by FlatBuffers' CreateSharedString. The test also makes
+ // sure that the data structure works properly with such optimization.
Finish();
const struct {
const char* url_pattern;
- const char* initiator;
+ const char* document_origin;
bool should_allow_with_disable_generic_rules;
bool should_allow_with_enable_all_rules;
} kTestCases[] = {
@@ -616,26 +697,27 @@ TEST_F(IndexedRulesetTest, MatchWithDisableGenericRules) {
constexpr bool kDisableGenericRules = true;
constexpr bool kEnableAllRules = false;
for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message() << "Url: " << test_case.url_pattern
- << "; Initiator: " << test_case.initiator);
+ SCOPED_TRACE(testing::Message()
+ << "Url: " << test_case.url_pattern
+ << "; document: " << test_case.document_origin);
EXPECT_EQ(test_case.should_allow_with_disable_generic_rules,
- ShouldAllow(test_case.url_pattern, test_case.initiator,
+ ShouldAllow(test_case.url_pattern, test_case.document_origin,
kDisableGenericRules));
EXPECT_EQ(test_case.should_allow_with_enable_all_rules,
- ShouldAllow(test_case.url_pattern, test_case.initiator,
+ ShouldAllow(test_case.url_pattern, test_case.document_origin,
kEnableAllRules));
}
}
-TEST_F(IndexedRulesetTest, EmptyRuleset) {
+TEST_F(SubresourceFilterIndexedRulesetTest, EmptyRuleset) {
Finish();
EXPECT_TRUE(ShouldAllow("http://example.com"));
EXPECT_TRUE(ShouldAllow("http://another.example.com?param=val"));
EXPECT_TRUE(ShouldAllow(nullptr));
}
-TEST_F(IndexedRulesetTest, NoRuleApplies) {
+TEST_F(SubresourceFilterIndexedRulesetTest, NoRuleApplies) {
AddSimpleRule(UrlPattern("?filtered_content=", kSubstring), false);
AddSimpleRule(UrlPattern("&filtered_content=", kSubstring), false);
Finish();
@@ -644,7 +726,7 @@ TEST_F(IndexedRulesetTest, NoRuleApplies) {
EXPECT_TRUE(ShouldAllow("http://example.com?filtered_not"));
}
-TEST_F(IndexedRulesetTest, SimpleBlacklist) {
+TEST_F(SubresourceFilterIndexedRulesetTest, SimpleBlacklist) {
AddSimpleRule(UrlPattern("?param=", kSubstring), false);
Finish();
@@ -652,14 +734,14 @@ TEST_F(IndexedRulesetTest, SimpleBlacklist) {
EXPECT_FALSE(ShouldAllow("http://example.org?param=image1"));
}
-TEST_F(IndexedRulesetTest, SimpleWhitelist) {
+TEST_F(SubresourceFilterIndexedRulesetTest, SimpleWhitelist) {
AddSimpleRule(UrlPattern("example.com/?filtered_content=", kSubstring), true);
Finish();
EXPECT_TRUE(ShouldAllow("https://example.com?filtered_content=image1"));
}
-TEST_F(IndexedRulesetTest, BlacklistWhitelist) {
+TEST_F(SubresourceFilterIndexedRulesetTest, BlacklistWhitelist) {
AddSimpleRule(UrlPattern("?filter=", kSubstring), false);
AddSimpleRule(UrlPattern("whitelisted.com/?filter=", kSubstring), true);
Finish();
@@ -669,9 +751,7 @@ TEST_F(IndexedRulesetTest, BlacklistWhitelist) {
EXPECT_FALSE(ShouldAllow("http://blacklisted.com?filter=on"));
}
-TEST_F(IndexedRulesetTest, BlacklistAndActivationType) {
- const auto kDocument = proto::ACTIVATION_TYPE_DOCUMENT;
-
+TEST_F(SubresourceFilterIndexedRulesetTest, BlacklistAndActivationType) {
AddSimpleRule(UrlPattern("example.com", kSubstring), false);
AddWhitelistRuleWithActivationTypes(UrlPattern("example.com", kSubstring),
kDocument);
@@ -683,19 +763,62 @@ TEST_F(IndexedRulesetTest, BlacklistAndActivationType) {
EXPECT_TRUE(ShouldAllow("https://xample.com"));
}
-TEST_F(IndexedRulesetTest, RuleWithUnsupportedOptions) {
- UrlRuleBuilder builder(UrlPattern("exmpl"), proto::SOURCE_TYPE_ANY, false);
- builder.rule().set_activation_types(builder.rule().activation_types() |
- (proto::ACTIVATION_TYPE_MAX << 1));
- builder.rule().set_element_types(builder.rule().element_types() |
- (proto::ELEMENT_TYPE_MAX << 1));
- EXPECT_FALSE(indexer_.AddUrlRule(builder.rule()));
+TEST_F(SubresourceFilterIndexedRulesetTest, RuleWithUnsupportedTypes) {
+ const struct {
+ int element_types;
+ int activation_types;
+ } kRules[] = {
+ {proto::ELEMENT_TYPE_MAX << 1, 0},
+ {0, proto::ACTIVATION_TYPE_MAX << 1},
+ {proto::ELEMENT_TYPE_MAX << 1, proto::ACTIVATION_TYPE_MAX << 1},
+
+ {kPopup, 0},
+ {0, proto::ACTIVATION_TYPE_ELEMHIDE},
+ {0, proto::ACTIVATION_TYPE_GENERICHIDE},
+ {0, proto::ACTIVATION_TYPE_ELEMHIDE | proto::ACTIVATION_TYPE_GENERICHIDE},
+ {proto::ELEMENT_TYPE_POPUP, proto::ACTIVATION_TYPE_ELEMHIDE},
+ };
+
+ for (const auto& rule : kRules) {
+ UrlRuleBuilder builder(UrlPattern("example.com"));
+ builder.rule().set_element_types(rule.element_types);
+ builder.rule().set_activation_types(rule.activation_types);
+ EXPECT_FALSE(indexer_.AddUrlRule(builder.rule()));
+ }
+ AddSimpleRule(UrlPattern("exmpl.com", kSubstring), false);
- AddSimpleRule(UrlPattern("example.com", kSubstring), false);
Finish();
+ EXPECT_TRUE(ShouldAllow("http://example.com/"));
+ EXPECT_FALSE(ShouldAllow("https://exmpl.com/"));
+}
- EXPECT_TRUE(ShouldAllow("https://exmpl.com"));
- EXPECT_FALSE(ShouldAllow("https://example.com"));
+TEST_F(SubresourceFilterIndexedRulesetTest,
+ RuleWithSupportedAndUnsupportedTypes) {
+ const struct {
+ int element_types;
+ int activation_types;
+ } kRules[] = {
+ {kImage | (proto::ELEMENT_TYPE_MAX << 1), 0},
+ {kScript | kPopup, 0},
+ {0, kDocument | (proto::ACTIVATION_TYPE_MAX << 1)},
+ };
+
+ for (const auto& rule : kRules) {
+ UrlRuleBuilder builder(UrlPattern("example.com"));
+ builder.rule().set_element_types(rule.element_types);
+ builder.rule().set_activation_types(rule.activation_types);
+ if (rule.activation_types)
+ builder.rule().set_semantics(proto::RULE_SEMANTICS_WHITELIST);
+ EXPECT_TRUE(indexer_.AddUrlRule(builder.rule()));
+ }
+ Finish();
+
+ EXPECT_FALSE(ShouldAllow("http://example.com/", nullptr, kImage));
+ EXPECT_FALSE(ShouldAllow("http://example.com/", nullptr, kScript));
+ EXPECT_TRUE(ShouldAllow("http://example.com/"));
+
+ EXPECT_TRUE(ShouldDeactivate("http://example.com", nullptr, kDocument));
+ EXPECT_FALSE(ShouldDeactivate("http://example.com", nullptr, kGenericBlock));
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/knuth_morris_pratt.h b/chromium/components/subresource_filter/core/common/knuth_morris_pratt.h
deleted file mode 100644
index 29e50e7307b..00000000000
--- a/chromium/components/subresource_filter/core/common/knuth_morris_pratt.h
+++ /dev/null
@@ -1,249 +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.
-
-// This file implements the "failure function" notion used by the
-// Knuth-Morris-Pratt algorithm for solving the string matching problem, i.e.
-// finding all occurences of some pattern |P| in arbitrary text. It also
-// provides tools for traversing these occurences.
-//
-// Consider a character string |P| of length |n|. The failure function of this
-// string is an integer array |F| of length |n|, defined in the following way:
-// F[i] = max{0 <= j <= i : P[0..j-1] == P[i-j+1..i]},
-// i.e. F[i] is the length of the longest proper suffix of P[0..i] that is also
-// a prefix of |P|.
-//
-// For example, the "abacaba" string has the following failure function:
-// [0, 0, 1, 0, 1, 2, 3].
-// For further examples see the "knuth_morris_pratt_unittest.cc" file.
-
-#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_KNUTH_MORRIS_PRATT_H_
-#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_KNUTH_MORRIS_PRATT_H_
-
-#include <stddef.h>
-
-#include <functional>
-#include <iterator>
-#include <limits>
-#include <type_traits>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/strings/string_piece.h"
-
-namespace subresource_filter {
-
-// Appends elements of the Knuth-Morris-Pratt failure function corresponding to
-// |pattern| at the end of the |failure| vector. The EquivalentTo should be a
-// bool(char, char) functor returning true iff the two characters are
-// equivalent, and is required to be reflexive, symmetric and transitive.
-template <typename IntType, typename EquivalentTo = std::equal_to<char>>
-void BuildFailureFunction(base::StringPiece pattern,
- std::vector<IntType>* failure,
- EquivalentTo equivalent_to = EquivalentTo()) {
- static_assert(std::is_unsigned<IntType>::value, "IntType is not unsigned.");
- DCHECK_LE(pattern.size(), std::numeric_limits<IntType>::max());
-
- if (pattern.empty())
- return;
-
- const size_t base_index = failure->size();
- failure->push_back(0);
- for (size_t i = 1; i != pattern.size(); ++i) {
- const char c = pattern[i];
-
- IntType prefix_match_size = failure->back();
- DCHECK_LT(prefix_match_size, i);
- while (prefix_match_size && !equivalent_to(pattern[prefix_match_size], c))
- prefix_match_size = (*failure)[base_index + prefix_match_size - 1];
-
- if (prefix_match_size || equivalent_to(pattern[0], c))
- ++prefix_match_size;
- failure->push_back(prefix_match_size);
- }
-}
-
-// Returns the position of the leftmost occurrence of the |pattern| in the
-// |text|, i.e. the index of the character coming *after* the occurrence, within
-// the [0, text.size()] range. If the pattern does not occur in the |text|, the
-// returned value is base::StringPiece::npos.
-//
-// The method supports the use-case when the |text| is assumed to be the
-// continuation of some imaginary string matching the initial
-// |prefix_match_size| characters of the |pattern|. Hence, the |pattern| can be
-// partially matched by this imaginary string and partially by the actual prefix
-// of the |text|.
-//
-// The |failure| array is the failure function created by BuildFailureFunction
-// with the same EquivalentTo and |pattern|, and containing at least
-// pattern.size() values.
-template <typename IntType, typename EquivalentTo = std::equal_to<char>>
-size_t FindOccurrence(base::StringPiece text,
- base::StringPiece pattern,
- const IntType* failure,
- IntType prefix_match_size,
- EquivalentTo equivalent_to = EquivalentTo()) {
- static_assert(std::is_unsigned<IntType>::value, "IntType is not unsigned.");
- DCHECK_LE(prefix_match_size, pattern.size());
- DCHECK_LE(pattern.size(), std::numeric_limits<IntType>::max());
-
- if (prefix_match_size == pattern.size())
- return 0;
-
- for (size_t i = 0; i != text.size(); ++i) {
- const char c = text[i];
- while (prefix_match_size && !equivalent_to(pattern[prefix_match_size], c))
- prefix_match_size = failure[prefix_match_size - 1];
- if (prefix_match_size || equivalent_to(pattern[0], c))
- ++prefix_match_size;
- if (prefix_match_size == pattern.size())
- return i + 1;
- }
- return base::StringPiece::npos;
-}
-
-// Same as FindOccurrence, but starts the search from scratch, i.e. with
-// prefix_match_size == 0.
-template <typename IntType, typename EquivalentTo = std::equal_to<char>>
-size_t FindFirstOccurrence(base::StringPiece text,
- base::StringPiece pattern,
- const IntType* failure,
- EquivalentTo equivalent_to = EquivalentTo()) {
- return FindOccurrence(text, pattern, failure, static_cast<IntType>(0),
- equivalent_to);
-}
-
-// Same as FindOccurrence, but preforms the search assuming the |text| starts
-// right after a full match of the |pattern|. The returned value is either
-// base::StringPiece::npos if no more occurrences found, or is within the range
-// [1, text.size()] if there are occurrences apart from the virtual prefix.
-template <typename IntType, typename EquivalentTo = std::equal_to<char>>
-size_t FindNextOccurrence(base::StringPiece text,
- base::StringPiece pattern,
- const IntType* failure,
- EquivalentTo equivalent_to = EquivalentTo()) {
- if (pattern.empty())
- return text.empty() ? base::StringPiece::npos : 1;
-
- const IntType prefix_match_size = failure[pattern.size() - 1];
- return FindOccurrence(text, pattern, failure, prefix_match_size,
- equivalent_to);
-}
-
-// AllOccurrences can be used to find all occurrences of a |pattern| in a |text|
-// with respect to EquivalentTo relation between characters, and iterate over
-// them using an input iterator. The values pointed to by an iterator indicate
-// positions of occurrences, i.e. indices of |text| characters coming *after*
-// the occurrences. Out-of-range iterators are dereferenced to
-// base::StringPiece::npos.
-template <typename IntType, typename EquivalentTo = std::equal_to<char>>
-class AllOccurrences {
- public:
- static_assert(std::is_unsigned<IntType>::value, "IntType is not unsigned.");
-
- class Iterator : public std::iterator<std::input_iterator_tag, size_t> {
- public:
- bool operator==(const Iterator& rhs) const {
- return match_end_ == rhs.match_end_;
- }
-
- bool operator!=(const Iterator& rhs) const { return !operator==(rhs); }
-
- size_t operator*() const { return match_end_; }
- const size_t* operator->() const { return &match_end_; }
-
- Iterator& operator++() {
- DCHECK(match_end_ == base::StringPiece::npos ||
- match_end_ <= owner_->text_.size());
-
- const size_t relative_match_end = owner_->FindNextOccurrence(match_end_);
- if (relative_match_end == base::StringPiece::npos)
- match_end_ = base::StringPiece::npos;
- else
- match_end_ += relative_match_end;
-
- return *this;
- }
-
- Iterator operator++(int) {
- Iterator copy(*this);
- operator++();
- return copy;
- }
-
- protected:
- friend class AllOccurrences;
-
- // Creates an iterator, which points to the occurrence ending just before
- // the position denoted by |match_end|. If |match_end| ==
- // base::StringPiece::npos, the iterator is assumed to be at the end.
- Iterator(const AllOccurrences* owner, size_t match_end)
- : owner_(owner), match_end_(match_end) {}
-
- const AllOccurrences* owner_;
- size_t match_end_;
- };
-
- AllOccurrences(base::StringPiece text,
- base::StringPiece pattern,
- const IntType* failure,
- EquivalentTo equivalent_to = EquivalentTo())
- : text_(text),
- pattern_(pattern),
- failure_(failure),
- equivalent_to_(equivalent_to) {}
-
- Iterator begin() const {
- const size_t match_end =
- FindFirstOccurrence(text_, pattern_, failure_, equivalent_to_);
- return Iterator(this, match_end);
- }
-
- Iterator end() const { return Iterator(this, base::StringPiece::npos); }
-
- protected:
- // Returns the position of the next occurrence assuming the current occurrence
- // ends right before the |match_end| position.
- size_t FindNextOccurrence(size_t match_end) const {
- return subresource_filter::FindNextOccurrence(
- text_.substr(match_end), pattern_, failure_, equivalent_to_);
- }
-
- base::StringPiece text_;
- base::StringPiece pattern_;
- const IntType* failure_;
-
- EquivalentTo equivalent_to_;
-};
-
-// A helper function used to create an AllOccurrences instance without knowing
-// the direct type of the |equivalent_to| functor.
-//
-// Typical usage:
-// auto occurrences = CreateAllOccurrences(
-// "word, word: word-word",
-// "word?",
-// <failure function for "word?">,
-// [](char c1, char c2) {
-// return c1 == c2 || (ispunct(c1) && ispunct(c2));
-// });
-//
-// for (size_t match_end : occurrences) {
-// // The |pattern| matches the following substring of the |text|:
-// // text[|match_end|-pattern.size()..|match_end|-1]
-// ... process the |match_end| ...
-// }
-template <typename IntType, typename EquivalentTo = std::equal_to<char>>
-AllOccurrences<IntType, EquivalentTo> CreateAllOccurrences(
- base::StringPiece text,
- base::StringPiece pattern,
- const IntType* failure,
- EquivalentTo equivalent_to = EquivalentTo()) {
- return AllOccurrences<IntType, EquivalentTo>(text, pattern, failure,
- equivalent_to);
-}
-
-} // namespace subresource_filter
-
-#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_KNUTH_MORRIS_PRATT_H_
diff --git a/chromium/components/subresource_filter/core/common/knuth_morris_pratt_unittest.cc b/chromium/components/subresource_filter/core/common/knuth_morris_pratt_unittest.cc
deleted file mode 100644
index 7d2d1be9a8f..00000000000
--- a/chromium/components/subresource_filter/core/common/knuth_morris_pratt_unittest.cc
+++ /dev/null
@@ -1,218 +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/subresource_filter/core/common/knuth_morris_pratt.h"
-
-#include <cctype>
-#include <functional>
-#include <string>
-#include <vector>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace subresource_filter {
-
-namespace {
-
-bool NumerophobicEquivalentTo(char first, char second) {
- return first == second || (std::isdigit(first) && std::isdigit(second));
-}
-
-template <typename EquivalentTo = std::equal_to<char>>
-std::vector<size_t> FindAllOccurrences(
- base::StringPiece string,
- base::StringPiece pattern,
- const std::vector<size_t>& failure_function,
- EquivalentTo equivalent_to = EquivalentTo()) {
- std::vector<size_t> positions;
-
- size_t position = 0;
- size_t relative_position = FindFirstOccurrence(
- string, pattern, failure_function.data(), equivalent_to);
-
- while (relative_position != base::StringPiece::npos) {
- position += relative_position;
- positions.push_back(position);
- relative_position =
- FindNextOccurrence(string.substr(position), pattern,
- failure_function.data(), equivalent_to);
- }
-
- return positions;
-}
-
-} // namespace
-
-TEST(KnuthMorrisPrattTest, BuildFailureFunctionRegular) {
- const struct {
- std::string string;
- std::vector<size_t> expected_failure_function;
- } kTestCases[] = {
- {"", std::vector<size_t>()},
- {"a", {0}},
- {"aa", {0, 1}},
- {"aaa", {0, 1, 2}},
- {"abc", {0, 0, 0}},
- {"abca", {0, 0, 0, 1}},
- {"abacaba", {0, 0, 1, 0, 1, 2, 3}},
- {"str-sstrr", {0, 0, 0, 0, 1, 1, 2, 3, 0}},
- {"sts-ststs", {0, 0, 1, 0, 1, 2, 3, 2, 3}},
- };
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message() << "String: " << test_case.string);
-
- std::vector<size_t> failure;
- BuildFailureFunction(test_case.string, &failure);
- EXPECT_EQ(test_case.expected_failure_function, failure);
- }
-}
-
-TEST(KnuthMorrisPrattTest, BuildFailureFunctionWithEquivalentChars) {
- const struct {
- std::string string;
- std::vector<size_t> expected_failure_function;
- } kTestCases[] = {
- {"123", {0, 1, 2}},
- {"0str1str", {0, 0, 0, 0, 1, 2, 3, 4}},
- {"7str8srr", {0, 0, 0, 0, 1, 2, 0, 0}},
- {"567str9sr", {0, 1, 2, 0, 0, 0, 1, 0, 0}},
- {"567str999sr", {0, 1, 2, 0, 0, 0, 1, 2, 3, 4, 0}},
- {"str9sr6", {0, 0, 0, 0, 1, 0, 0}},
- {"5a6a7a8a9a", {0, 0, 1, 2, 3, 4, 5, 6, 7, 8}},
- };
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message() << "String: " << test_case.string);
-
- std::vector<size_t> failure;
- BuildFailureFunction(test_case.string, &failure, NumerophobicEquivalentTo);
- EXPECT_EQ(test_case.expected_failure_function, failure);
- }
-}
-
-TEST(KnuthMorrisPrattTest, FindSubstringsRegular) {
- const struct {
- std::string string;
- std::string pattern;
- std::vector<size_t> expected_positions;
- } kTestCases[] = {
- {"", "abc", std::vector<size_t>()},
- {"abc", "", {0, 1, 2, 3}},
- {"abc", "abc", {3}},
- {"aaaabc", "abc", {6}},
- {"abcccc", "abc", {3}},
- {"aabcc", "abc", {4}},
- {"aabcabcabcc", "abc", {4, 7, 10}},
- {"abcabcabc", "abc", {3, 6, 9}},
- {"abab", "abc", std::vector<size_t>()},
- {"ababac", "abc", std::vector<size_t>()},
- {"aaaaaa", "a", {1, 2, 3, 4, 5, 6}},
- {"aaaaaa", "aaa", {3, 4, 5, 6}},
- {"abababa", "aba", {3, 5, 7}},
- {"acdacdacdac", "cdacd", {6, 9}},
- };
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message() << "String: " << test_case.string
- << "; Pattern: " << test_case.pattern);
-
- std::vector<size_t> failure;
- BuildFailureFunction(test_case.pattern, &failure);
-
- std::vector<size_t> positions =
- FindAllOccurrences(test_case.string, test_case.pattern, failure);
- EXPECT_EQ(test_case.expected_positions, positions);
-
- auto occurrences = CreateAllOccurrences(test_case.string, test_case.pattern,
- failure.data());
- positions.assign(occurrences.begin(), occurrences.end());
- EXPECT_EQ(test_case.expected_positions, positions);
- }
-}
-
-TEST(KnuthMorrisPrattTest, FindSubstringsWithEquivalentChars) {
- const struct {
- std::string string;
- std::string pattern;
- std::vector<size_t> expected_positions;
- } kTestCases[] = {
- {"", "abc", std::vector<size_t>()},
- {"012", "1", {1, 2, 3}},
- {"012", "012", {3}},
- {"123456", "000", {3, 4, 5, 6}},
- {"0a1a2a3a", "1a2", {3, 5, 7}},
- {"0aa1a2aa3a", "1aa2", {4, 9}},
- };
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message() << "String: " << test_case.string
- << "; Pattern: " << test_case.pattern);
-
- std::vector<size_t> failure;
- BuildFailureFunction(test_case.pattern, &failure, NumerophobicEquivalentTo);
-
- std::vector<size_t> positions = FindAllOccurrences(
- test_case.string, test_case.pattern, failure, NumerophobicEquivalentTo);
- EXPECT_EQ(test_case.expected_positions, positions);
-
- auto occurrences =
- CreateAllOccurrences(test_case.string, test_case.pattern,
- failure.data(), NumerophobicEquivalentTo);
- positions.assign(occurrences.begin(), occurrences.end());
- EXPECT_EQ(test_case.expected_positions, positions);
- }
-}
-
-TEST(KnuthMorrisPrattTest, AllOccurrencesIterator) {
- const struct {
- std::string string;
- std::string pattern;
- std::vector<size_t> expected_positions;
- } kTestCases[] = {
- {"", "abc", std::vector<size_t>()},
- {"abc", "", {0, 1, 2, 3}},
- {"abc", "abc", {3}},
- {"aaa", "a", {1, 2, 3}},
- {"aaaabc", "abc", {6}},
- };
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message() << "String: " << test_case.string
- << "; Pattern: " << test_case.pattern);
-
- std::vector<size_t> failure;
- BuildFailureFunction(test_case.pattern, &failure);
-
- auto occurrences = CreateAllOccurrences(test_case.string, test_case.pattern,
- failure.data());
-
- auto iterator = occurrences.begin();
- const size_t size = test_case.expected_positions.size();
- for (size_t i = 0; i != size; ++i, ++iterator) {
- const size_t expected_position = test_case.expected_positions[i];
- EXPECT_EQ(expected_position, *iterator);
-
- auto iterator_copy = iterator;
- EXPECT_EQ(iterator, iterator_copy);
- EXPECT_EQ(expected_position, *iterator_copy);
-
- EXPECT_EQ(iterator_copy, iterator++);
- EXPECT_NE(iterator_copy, iterator);
- if (i + 1 != size) {
- EXPECT_NE(occurrences.end(), iterator);
- EXPECT_EQ(test_case.expected_positions[i + 1], *iterator);
- } else {
- EXPECT_EQ(occurrences.end(), iterator);
- }
-
- iterator = iterator_copy;
- EXPECT_EQ(expected_position, *iterator);
- }
-
- EXPECT_EQ(occurrences.end(), iterator);
- }
-}
-
-} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/proto/rules.proto b/chromium/components/subresource_filter/core/common/proto/rules.proto
index f651c04abd2..b918dd95a99 100644
--- a/chromium/components/subresource_filter/core/common/proto/rules.proto
+++ b/chromium/components/subresource_filter/core/common/proto/rules.proto
@@ -65,10 +65,11 @@ enum ElementType {
ELEMENT_TYPE_MEDIA = 512;
ELEMENT_TYPE_FONT = 1024;
ELEMENT_TYPE_POPUP = 2048;
+ ELEMENT_TYPE_WEBSOCKET = 4096;
// NOTE: Keep these two values consistent with the values above.
- ELEMENT_TYPE_MAX = 2048;
- ELEMENT_TYPE_ALL = 4095;
+ ELEMENT_TYPE_MAX = 4096;
+ ELEMENT_TYPE_ALL = 8191;
};
// The options controlling whether or not to activate filtering for subresources
diff --git a/chromium/components/subresource_filter/core/common/test_ruleset_creator.cc b/chromium/components/subresource_filter/core/common/test_ruleset_creator.cc
index d87cf1b408d..408a9845353 100644
--- a/chromium/components/subresource_filter/core/common/test_ruleset_creator.cc
+++ b/chromium/components/subresource_filter/core/common/test_ruleset_creator.cc
@@ -45,11 +45,6 @@ std::vector<uint8_t> SerializeUnindexedRulesetWithMultipleRules(
return std::vector<uint8_t>(data, data + ruleset_contents.size());
}
-std::vector<uint8_t> SerializeUnindexedRulesetWithSingleRule(
- const proto::UrlRule& rule) {
- return SerializeUnindexedRulesetWithMultipleRules({rule});
-}
-
std::vector<uint8_t> SerializeIndexedRulesetWithMultipleRules(
const std::vector<proto::UrlRule>& rules) {
RulesetIndexer indexer;
@@ -126,9 +121,8 @@ void TestRulesetCreator::CreateUnindexedRulesetToDisallowURLsWithPathSuffix(
TestRuleset* test_unindexed_ruleset) {
DCHECK(test_unindexed_ruleset);
proto::UrlRule suffix_rule = CreateSuffixRule(suffix);
- ASSERT_NO_FATAL_FAILURE(CreateTestRulesetFromContents(
- SerializeUnindexedRulesetWithSingleRule(suffix_rule),
- test_unindexed_ruleset));
+ ASSERT_NO_FATAL_FAILURE(
+ CreateUnindexedRulesetWithRules({suffix_rule}, test_unindexed_ruleset));
}
void TestRulesetCreator::CreateRulesetToDisallowURLsWithManySuffixes(
@@ -157,6 +151,14 @@ void TestRulesetCreator::CreateRulesetWithRules(
&test_ruleset_pair->indexed));
}
+void TestRulesetCreator::CreateUnindexedRulesetWithRules(
+ const std::vector<proto::UrlRule>& rules,
+ TestRuleset* test_unindexed_ruleset) {
+ ASSERT_NO_FATAL_FAILURE(CreateTestRulesetFromContents(
+ SerializeUnindexedRulesetWithMultipleRules(rules),
+ test_unindexed_ruleset));
+}
+
void TestRulesetCreator::GetUniqueTemporaryPath(base::FilePath* path) {
DCHECK(path);
ASSERT_TRUE(scoped_temp_dir_.IsValid() ||
diff --git a/chromium/components/subresource_filter/core/common/test_ruleset_creator.h b/chromium/components/subresource_filter/core/common/test_ruleset_creator.h
index 9ff0b53e2ee..88338f60922 100644
--- a/chromium/components/subresource_filter/core/common/test_ruleset_creator.h
+++ b/chromium/components/subresource_filter/core/common/test_ruleset_creator.h
@@ -85,6 +85,8 @@ class TestRulesetCreator {
void CreateRulesetWithRules(const std::vector<proto::UrlRule>& rules,
TestRulesetPair* test_ruleset_pair);
+ void CreateUnindexedRulesetWithRules(const std::vector<proto::UrlRule>& rules,
+ TestRuleset* test_unindexed_ruleset);
// Returns a unique |path| that is valid for the lifetime of this instance.
// No file at |path| will be automatically created.
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 ef7086502ea..d7023f86b05 100644
--- a/chromium/components/subresource_filter/core/common/test_ruleset_utils.h
+++ b/chromium/components/subresource_filter/core/common/test_ruleset_utils.h
@@ -15,8 +15,13 @@
namespace subresource_filter {
namespace testing {
+// Creates a blacklist URL rule which targets subresources of any type such that
+// the resource URL ends with |suffix|.
proto::UrlRule CreateSuffixRule(base::StringPiece suffix);
+// Same as CreateUrlRule(pattern, proto::URL_PATTERN_TYPE_WILDCARDED), but the
+// rule applies to the specified |activation_types|, and to no element types.
+// Additionally, it is restricted to a set of |domains| (if provided).
proto::UrlRule CreateWhitelistRuleForDocument(
base::StringPiece pattern,
int32_t activation_types = proto::ACTIVATION_TYPE_DOCUMENT,
diff --git a/chromium/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc b/chromium/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc
index 812d1b9ea09..bc66bbe13a4 100644
--- a/chromium/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc
+++ b/chromium/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc
@@ -44,11 +44,11 @@ proto::UrlRule CreateRule(const UrlPattern& url_pattern,
rule.set_source_type(source_type);
rule.set_element_types(proto::ELEMENT_TYPE_ALL);
- rule.set_url_pattern_type(url_pattern.type);
- rule.set_anchor_left(url_pattern.anchor_left);
- rule.set_anchor_right(url_pattern.anchor_right);
- rule.set_match_case(url_pattern.match_case);
- rule.set_url_pattern(url_pattern.url_pattern.as_string());
+ rule.set_url_pattern_type(url_pattern.type());
+ rule.set_anchor_left(url_pattern.anchor_left());
+ rule.set_anchor_right(url_pattern.anchor_right());
+ rule.set_match_case(url_pattern.match_case());
+ rule.set_url_pattern(url_pattern.url_pattern().as_string());
return rule;
}
diff --git a/chromium/components/subresource_filter/core/common/url_pattern.cc b/chromium/components/subresource_filter/core/common/url_pattern.cc
index 1cfa663762a..d601f41e6d5 100644
--- a/chromium/components/subresource_filter/core/common/url_pattern.cc
+++ b/chromium/components/subresource_filter/core/common/url_pattern.cc
@@ -2,14 +2,39 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// The matching logic distinguishes between the terms URL pattern and
+// subpattern. A URL pattern usually stands for the full thing, e.g.
+// "example.com^*path*par=val^", whereas subpattern denotes a maximal substring
+// of a pattern not containing the wildcard '*' character. For the example above
+// the subpatterns are: "example.com^", "path" and "par=val^".
+//
+// The separator placeholder '^' symbol is used in subpatterns to match any
+// separator character, which is any ASCII symbol except letters, digits, and
+// the following: '_', '-', '.', '%'. Note that the separator placeholder
+// character '^' is itself a separator, as well as '\0'.
+
#include "components/subresource_filter/core/common/url_pattern.h"
+#include <stddef.h>
+
+#include <ostream>
+
+#include "base/logging.h"
#include "components/subresource_filter/core/common/flat/rules_generated.h"
+#include "components/subresource_filter/core/common/fuzzy_pattern_matching.h"
+#include "components/subresource_filter/core/common/string_splitter.h"
+#include "url/gurl.h"
+#include "url/third_party/mozilla/url_parse.h"
namespace subresource_filter {
namespace {
+class IsWildcard {
+ public:
+ bool operator()(char c) const { return c == '*'; }
+};
+
proto::UrlPatternType ConvertUrlPatternType(flat::UrlPatternType type) {
switch (type) {
case flat::UrlPatternType_SUBSTRING:
@@ -41,36 +66,191 @@ base::StringPiece ConvertString(const flatbuffers::String* string) {
: base::StringPiece();
}
+// Returns whether |position| within the |url| belongs to its |host| component
+// and corresponds to the beginning of a (sub-)domain.
+inline bool IsSubdomainAnchored(base::StringPiece url,
+ url::Component host,
+ size_t position) {
+ DCHECK_LE(position, url.size());
+ const size_t host_begin = static_cast<size_t>(host.begin);
+ const size_t host_end = static_cast<size_t>(host.end());
+ DCHECK_LE(host_end, url.size());
+
+ return position == host_begin ||
+ (position > host_begin && position <= host_end &&
+ url[position - 1] == '.');
+}
+
+// Returns the position of the leftmost occurrence of a |subpattern| in the
+// |text| starting no earlier than |from| the specified position. If the
+// |subpattern| has separator placeholders, searches for a fuzzy occurrence.
+size_t FindSubpattern(base::StringPiece text,
+ base::StringPiece subpattern,
+ size_t from = 0) {
+ const bool is_fuzzy =
+ (subpattern.find(kSeparatorPlaceholder) != base::StringPiece::npos);
+ return is_fuzzy ? FindFuzzy(text, subpattern, from)
+ : text.find(subpattern, from);
+}
+
+// Same as FindSubpattern(url, subpattern), but searches for an occurrence that
+// starts at the beginning of a (sub-)domain within the url's |host| component.
+size_t FindSubdomainAnchoredSubpattern(base::StringPiece url,
+ url::Component host,
+ base::StringPiece subpattern) {
+ const bool is_fuzzy =
+ (subpattern.find(kSeparatorPlaceholder) != base::StringPiece::npos);
+
+ for (size_t position = 0; position <= url.size(); ++position) {
+ position = is_fuzzy ? FindFuzzy(url, subpattern, position)
+ : url.find(subpattern, position);
+ if (position == base::StringPiece::npos ||
+ IsSubdomainAnchored(url, host, position)) {
+ return position;
+ }
+ }
+ return base::StringPiece::npos;
+}
+
} // namespace
UrlPattern::UrlPattern() = default;
UrlPattern::UrlPattern(base::StringPiece url_pattern,
proto::UrlPatternType type)
- : type(type), url_pattern(url_pattern) {}
+ : type_(type), url_pattern_(url_pattern) {}
UrlPattern::UrlPattern(base::StringPiece url_pattern,
proto::AnchorType anchor_left,
proto::AnchorType anchor_right)
- : type(proto::URL_PATTERN_TYPE_WILDCARDED),
- url_pattern(url_pattern),
- anchor_left(anchor_left),
- anchor_right(anchor_right) {}
+ : type_(proto::URL_PATTERN_TYPE_WILDCARDED),
+ url_pattern_(url_pattern),
+ anchor_left_(anchor_left),
+ anchor_right_(anchor_right) {}
UrlPattern::UrlPattern(const flat::UrlRule& rule)
- : type(ConvertUrlPatternType(rule.url_pattern_type())),
- url_pattern(ConvertString(rule.url_pattern())),
- anchor_left(ConvertAnchorType(rule.anchor_left())),
- anchor_right(ConvertAnchorType(rule.anchor_right())),
- match_case(!!(rule.options() & flat::OptionFlag_IS_MATCH_CASE)) {}
+ : type_(ConvertUrlPatternType(rule.url_pattern_type())),
+ url_pattern_(ConvertString(rule.url_pattern())),
+ anchor_left_(ConvertAnchorType(rule.anchor_left())),
+ anchor_right_(ConvertAnchorType(rule.anchor_right())),
+ match_case_(!!(rule.options() & flat::OptionFlag_IS_MATCH_CASE)) {}
UrlPattern::UrlPattern(const proto::UrlRule& rule)
- : type(rule.url_pattern_type()),
- url_pattern(rule.url_pattern()),
- anchor_left(rule.anchor_left()),
- anchor_right(rule.anchor_right()),
- match_case(rule.match_case()) {}
+ : type_(rule.url_pattern_type()),
+ url_pattern_(rule.url_pattern()),
+ anchor_left_(rule.anchor_left()),
+ anchor_right_(rule.anchor_right()),
+ match_case_(rule.match_case()) {}
UrlPattern::~UrlPattern() = default;
+bool UrlPattern::MatchesUrl(const GURL& url) const {
+ // Note: Empty domains are also invalid.
+ DCHECK(url.is_valid());
+ DCHECK(type_ == proto::URL_PATTERN_TYPE_SUBSTRING ||
+ type_ == proto::URL_PATTERN_TYPE_WILDCARDED);
+
+ StringSplitter<IsWildcard> subpatterns(url_pattern_);
+ auto subpattern_it = subpatterns.begin();
+ auto subpattern_end = subpatterns.end();
+
+ if (subpattern_it == subpattern_end) {
+ return anchor_left_ == proto::ANCHOR_TYPE_NONE ||
+ anchor_right_ == proto::ANCHOR_TYPE_NONE;
+ }
+
+ const base::StringPiece spec = url.possibly_invalid_spec();
+ const url::Component host_part = url.parsed_for_possibly_invalid_spec().host;
+ DCHECK(!spec.empty());
+
+ base::StringPiece subpattern = *subpattern_it;
+ ++subpattern_it;
+
+ // If there is only one |subpattern|, and it has a right anchor, then simply
+ // check that it is a suffix of the |spec|, and the left anchor is fulfilled.
+ if (subpattern_it == subpattern_end &&
+ anchor_right_ == proto::ANCHOR_TYPE_BOUNDARY) {
+ if (!EndsWithFuzzy(spec, subpattern))
+ return false;
+ if (anchor_left_ == proto::ANCHOR_TYPE_BOUNDARY)
+ return spec.size() == subpattern.size();
+ if (anchor_left_ == proto::ANCHOR_TYPE_SUBDOMAIN) {
+ DCHECK_LE(subpattern.size(), spec.size());
+ return url.has_host() &&
+ IsSubdomainAnchored(spec, host_part,
+ spec.size() - subpattern.size());
+ }
+ return true;
+ }
+
+ // Otherwise, the first |subpattern| does not have to be a suffix. But it
+ // still can have a left anchor. Check and handle that.
+ base::StringPiece text = spec;
+ if (anchor_left_ == proto::ANCHOR_TYPE_BOUNDARY) {
+ if (!StartsWithFuzzy(spec, subpattern))
+ return false;
+ if (subpattern_it == subpattern_end) {
+ DCHECK_EQ(anchor_right_, proto::ANCHOR_TYPE_NONE);
+ return true;
+ }
+ text.remove_prefix(subpattern.size());
+ } else if (anchor_left_ == proto::ANCHOR_TYPE_SUBDOMAIN) {
+ if (!url.has_host())
+ return false;
+ const size_t match_begin =
+ FindSubdomainAnchoredSubpattern(spec, host_part, subpattern);
+ if (match_begin == base::StringPiece::npos)
+ return false;
+ if (subpattern_it == subpattern_end) {
+ DCHECK_EQ(anchor_right_, proto::ANCHOR_TYPE_NONE);
+ return true;
+ }
+ text.remove_prefix(match_begin + subpattern.size());
+ } else {
+ DCHECK_EQ(anchor_left_, proto::ANCHOR_TYPE_NONE);
+ // Get back to the initial |subpattern|, process it in the loop below.
+ subpattern_it = subpatterns.begin();
+ }
+
+ // Consecutively find all the remaining subpatterns in the |text|. If the
+ // pattern has a right anchor, don't search for the last subpattern, but
+ // instead check that it is a suffix of the |text|.
+ while (subpattern_it != subpattern_end) {
+ subpattern = *subpattern_it;
+ DCHECK(!subpattern.empty());
+
+ if (++subpattern_it == subpattern_end &&
+ anchor_right_ == proto::ANCHOR_TYPE_BOUNDARY) {
+ break;
+ }
+
+ const size_t match_position = FindSubpattern(text, subpattern);
+ if (match_position == base::StringPiece::npos)
+ return false;
+ text.remove_prefix(match_position + subpattern.size());
+ }
+
+ return anchor_right_ != proto::ANCHOR_TYPE_BOUNDARY ||
+ EndsWithFuzzy(text, subpattern);
+}
+
+std::ostream& operator<<(std::ostream& out, const UrlPattern& pattern) {
+ // Note: Each fall-through in this switch is intentional.
+ switch (pattern.anchor_left()) {
+ case proto::ANCHOR_TYPE_SUBDOMAIN:
+ out << '|';
+ case proto::ANCHOR_TYPE_BOUNDARY:
+ out << '|';
+ default:
+ break;
+ }
+ out << pattern.url_pattern();
+ if (pattern.anchor_right() == proto::ANCHOR_TYPE_BOUNDARY)
+ out << '|';
+ if (pattern.match_case())
+ out << "$match-case";
+
+ return out;
+}
+
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/url_pattern.h b/chromium/components/subresource_filter/core/common/url_pattern.h
index f49b5ea610b..edbef99a6d4 100644
--- a/chromium/components/subresource_filter/core/common/url_pattern.h
+++ b/chromium/components/subresource_filter/core/common/url_pattern.h
@@ -5,10 +5,14 @@
#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_H_
#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_H_
+#include <iosfwd>
+
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "components/subresource_filter/core/common/proto/rules.pb.h"
+class GURL;
+
namespace subresource_filter {
namespace flat {
@@ -16,8 +20,9 @@ struct UrlRule; // The FlatBuffers version of UrlRule.
}
// The structure used to mirror a URL pattern regardless of the representation
-// of the UrlRule that owns it.
-struct UrlPattern {
+// of the UrlRule that owns it, and to match it against URLs.
+class UrlPattern {
+ public:
UrlPattern();
// Creates a |url_pattern| of a certain |type|.
@@ -36,18 +41,39 @@ struct UrlPattern {
~UrlPattern();
- proto::UrlPatternType type = proto::URL_PATTERN_TYPE_UNSPECIFIED;
- base::StringPiece url_pattern;
+ proto::UrlPatternType type() const { return type_; }
+ base::StringPiece url_pattern() const { return url_pattern_; }
+ proto::AnchorType anchor_left() const { return anchor_left_; }
+ proto::AnchorType anchor_right() const { return anchor_right_; }
+ bool match_case() const { return match_case_; }
- proto::AnchorType anchor_left = proto::ANCHOR_TYPE_NONE;
- proto::AnchorType anchor_right = proto::ANCHOR_TYPE_NONE;
-
- bool match_case = false;
+ // Returns whether the |url| matches the URL |pattern|. Requires the type of
+ // |this| pattern to be either SUBSTRING or WILDCARDED.
+ //
+ // Splits the pattern into subpatterns separated by '*' wildcards, and
+ // greedily finds each of them in the spec of the |url|. Respects anchors at
+ // either end of the pattern, and '^' separator placeholders when comparing a
+ // subpattern to a subtring of the spec.
+ bool MatchesUrl(const GURL& url) const;
private:
+ // TODO(pkalinnikov): Store flat:: types instead of proto::, in order to avoid
+ // conversions in IndexedRuleset.
+ proto::UrlPatternType type_ = proto::URL_PATTERN_TYPE_UNSPECIFIED;
+ base::StringPiece url_pattern_;
+
+ proto::AnchorType anchor_left_ = proto::ANCHOR_TYPE_NONE;
+ proto::AnchorType anchor_right_ = proto::ANCHOR_TYPE_NONE;
+
+ // TODO(pkalinnikov): Implement case-insensitive matching.
+ bool match_case_ = false;
+
DISALLOW_COPY_AND_ASSIGN(UrlPattern);
};
+// Allow pretty-printing URLPatterns when they are used in GTest assertions.
+std::ostream& operator<<(std::ostream& out, const UrlPattern& pattern);
+
} // namespace subresource_filter
#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_H_
diff --git a/chromium/components/subresource_filter/core/common/url_pattern_matching.h b/chromium/components/subresource_filter/core/common/url_pattern_matching.h
deleted file mode 100644
index 937b703edfa..00000000000
--- a/chromium/components/subresource_filter/core/common/url_pattern_matching.h
+++ /dev/null
@@ -1,277 +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.
-
-// The matching logic distinguishes between the terms URL pattern and
-// subpattern. A URL pattern usually stands for the full thing, e.g.
-// "example.com^*path*par=val^", whereas subpattern denotes a maximal substring
-// of a pattern not containing the wildcard '*' character. For the example above
-// the subpatterns are: "example.com^", "path" and "par=val^".
-//
-// The separator placeholder '^' symbol is used in subpatterns to match any
-// separator character, which is any ASCII symbol except letters, digits, and
-// the following: '_', '-', '.', '%'. Note that the separator placeholder
-// character '^' is itself a separator, as well as '\0'.
-
-#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_MATCHING_H_
-#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_MATCHING_H_
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <iterator>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/strings/string_piece.h"
-#include "components/subresource_filter/core/common/fuzzy_pattern_matching.h"
-#include "components/subresource_filter/core/common/knuth_morris_pratt.h"
-#include "components/subresource_filter/core/common/string_splitter.h"
-#include "components/subresource_filter/core/common/url_pattern.h"
-#include "url/gurl.h"
-#include "url/third_party/mozilla/url_parse.h"
-
-namespace subresource_filter {
-
-// Public interface declaration ------------------------------------------------
-
-// Builds a compound Knuth-Morris-Pratt failure function used to match URLs
-// against the |pattern|.
-//
-// The |pattern| is split on the '*' wildcard symbol and then a failure function
-// is built for each subpattern by BuildFailureFunctionFuzzy or
-// BuildFailureFunction (depending on whether the subpattern contains separator
-// placeholders), and appended to the returned vector. Some of the subpatterns
-// can be exempted from being indexed. E.g., if the |pattern| has a BOUNDARY
-// left anchor, the first subpattern can be matched by checking if it's a prefix
-// of a URL.
-//
-// Each subpattern indexed with BuildFailureFunctionFuzzy is prepended with a
-// value 1 (to distinguish them from the subpatterns indexed with
-// BuildFailureFunction, their failure functions always start with 0).
-//
-// The URL |pattern| must be normalized. Namely, it must not have the following
-// substrings: **, *<END>, <BEGIN>*. If the the |pattern| has a BOUNDARY anchor,
-// the corresponding side of its string must not end with a '*' wildcard.
-template <typename IntType>
-void BuildFailureFunction(const UrlPattern& pattern,
- std::vector<IntType>* failure);
-
-// Returns whether the |url| matches the URL |pattern|. The |failure| function
-// between |failure_begin| and |failure_end| must be the output of
-// BuildFailureFunction() called with the same |pattern|.
-//
-// TODO(pkalinnikov): Outline algorithms implemented in this function.
-template <typename FailureIter>
-bool IsUrlPatternMatch(const GURL& url,
- const UrlPattern& pattern,
- FailureIter failure_begin,
- FailureIter failure_end);
-
-// Implementation --------------------------------------------------------------
-
-namespace impl {
-
-class IsWildcard {
- public:
- bool operator()(char c) const { return c == '*'; }
-};
-
-// Returns whether |position| within the |url| belongs to its |host| component
-// and corresponds to the beginning of a (sub-)domain.
-inline bool IsSubdomainAnchored(base::StringPiece url,
- url::Component host,
- size_t position) {
- DCHECK_LE(position, url.size());
- const size_t host_begin = static_cast<size_t>(host.begin);
- const size_t host_end = static_cast<size_t>(host.end());
- DCHECK_LE(host_end, url.size());
-
- return position == host_begin ||
- (position > host_begin && position <= host_end &&
- url[position - 1] == '.');
-}
-
-// Returns the position just beyond the leftmost fuzzy occurrence of
-// |subpattern| in the |text|.
-template <typename IntType>
-inline size_t FindFirstOccurrenceFuzzy(base::StringPiece text,
- base::StringPiece subpattern,
- const IntType* failure) {
- return *AllOccurrencesFuzzy<IntType>(text, subpattern, failure).begin();
-}
-
-// Returns the position just beyond the leftmost occurrence of |subpattern| in
-// the |url|, such that it satisfies a SUBDOMAIN anchor.
-template <typename IntType>
-inline size_t FindSubdomainAnchored(base::StringPiece url,
- url::Component host,
- base::StringPiece subpattern,
- const IntType* failure) {
- auto occurrences = AllOccurrences<IntType>(url, subpattern, failure);
- return *std::find_if(occurrences.begin(), occurrences.end(),
- [url, host, subpattern](size_t match_end_position) {
- DCHECK_GE(match_end_position, subpattern.size());
- return IsSubdomainAnchored(
- url, host, match_end_position - subpattern.size());
- });
-}
-
-// Returns the position just beyond the leftmost fuzzy occurrence of
-// |subpattern| in the |url|, such that it satisfies a SUBDOMAIN anchor.
-template <typename IntType>
-inline size_t FindSubdomainAnchoredFuzzy(base::StringPiece url,
- url::Component host,
- base::StringPiece subpattern,
- const IntType* failure) {
- auto occurrences = AllOccurrencesFuzzy<IntType>(url, subpattern, failure);
- return *std::find_if(occurrences.begin(), occurrences.end(),
- [url, host, subpattern](size_t match_end_position) {
- DCHECK_GE(match_end_position, subpattern.size());
- return IsSubdomainAnchored(
- url, host, match_end_position - subpattern.size());
- });
-}
-
-} // namespace impl
-
-template <typename IntType>
-void BuildFailureFunction(const UrlPattern& pattern,
- std::vector<IntType>* failure) {
- StringSplitter<impl::IsWildcard> subpatterns(pattern.url_pattern);
- auto subpattern_it = subpatterns.begin();
- auto subpattern_end = subpatterns.end();
-
- if (subpattern_it == subpattern_end)
- return;
- if (pattern.anchor_left == proto::ANCHOR_TYPE_BOUNDARY)
- ++subpattern_it;
-
- while (subpattern_it != subpattern_end) {
- const base::StringPiece part = *subpattern_it++;
- DCHECK(!part.empty());
- if (pattern.anchor_right == proto::ANCHOR_TYPE_BOUNDARY &&
- subpattern_it == subpattern_end) {
- break;
- }
-
- if (part.find(kSeparatorPlaceholder) == base::StringPiece::npos) {
- BuildFailureFunction(part, failure);
- } else {
- // Prepend the value '1' to the failure function to let matchers
- // distinguish between the subpatterns with separator placeholders and
- // those without.
- failure->push_back(1);
- BuildFailureFunctionFuzzy(part, failure);
- }
- }
-}
-
-template <typename FailureIter>
-bool IsUrlPatternMatch(const GURL& url,
- const UrlPattern& pattern,
- FailureIter failure_begin,
- FailureIter failure_end) {
- DCHECK(url.is_valid());
-
- StringSplitter<impl::IsWildcard> subpatterns(pattern.url_pattern);
- auto subpattern_it = subpatterns.begin();
- auto subpattern_end = subpatterns.end();
-
- if (subpattern_it == subpattern_end) {
- return pattern.anchor_left != proto::ANCHOR_TYPE_BOUNDARY ||
- pattern.anchor_right != proto::ANCHOR_TYPE_BOUNDARY ||
- url.is_empty();
- }
-
- const base::StringPiece spec = url.possibly_invalid_spec();
- const url::Component host_part = url.parsed_for_possibly_invalid_spec().host;
-
- base::StringPiece subpattern = *subpattern_it++;
- if (subpattern_it == subpattern_end &&
- pattern.anchor_right == proto::ANCHOR_TYPE_BOUNDARY) {
- if (!EndsWithFuzzy(spec, subpattern))
- return false;
- if (pattern.anchor_left == proto::ANCHOR_TYPE_BOUNDARY)
- return spec.size() == subpattern.size();
- if (pattern.anchor_left == proto::ANCHOR_TYPE_SUBDOMAIN) {
- DCHECK_LE(subpattern.size(), spec.size());
- return url.has_host() &&
- impl::IsSubdomainAnchored(spec, host_part,
- spec.size() - subpattern.size());
- }
- return true;
- }
-
- base::StringPiece text = spec;
- if (pattern.anchor_left == proto::ANCHOR_TYPE_BOUNDARY) {
- if (!StartsWithFuzzy(spec, subpattern))
- return false;
- if (subpattern_it == subpattern_end)
- return true;
- text.remove_prefix(subpattern.size());
- } else if (pattern.anchor_left == proto::ANCHOR_TYPE_SUBDOMAIN) {
- if (!url.has_host())
- return false;
-
- const bool has_separator_placeholders = (*failure_begin != 0);
- if (has_separator_placeholders)
- ++failure_begin;
-
- const size_t position =
- has_separator_placeholders
- ? impl::FindSubdomainAnchoredFuzzy(spec, host_part, subpattern,
- &*failure_begin)
- : impl::FindSubdomainAnchored(spec, host_part, subpattern,
- &*failure_begin);
- if (position == base::StringPiece::npos)
- return false;
- if (subpattern_it == subpattern_end)
- return true;
- text.remove_prefix(position);
- } else {
- DCHECK_EQ(pattern.anchor_left, proto::ANCHOR_TYPE_NONE);
- // Get back to the initial subpattern, process it in the loop below.
- subpattern_it = subpatterns.begin();
- }
-
- while (subpattern_it != subpattern_end) {
- subpattern = *subpattern_it++;
- DCHECK(!subpattern.empty());
-
- if (subpattern_it == subpattern_end &&
- pattern.anchor_right == proto::ANCHOR_TYPE_BOUNDARY) {
- break;
- }
-
- // The subpatterns with separator placeholders were indexed differently and
- // should be matched accordingly. Their failure functions were prepended by
- // a non-zero value, and we need to skip it. If the value turned to be zero,
- // it is the initial value of a failure function of a regular substring.
- CHECK(failure_begin < failure_end);
- const bool has_separator_placeholders = (*failure_begin != 0);
- if (has_separator_placeholders)
- ++failure_begin;
- CHECK(static_cast<size_t>(std::distance(failure_begin, failure_end)) >=
- subpattern.size());
-
- // If the subpattern has separator placeholders, it should be matched with
- // FindFirstOccurrenceOfSubpattern, otherwise it can be found as a regular
- // substring.
- const size_t match_end =
- (has_separator_placeholders
- ? impl::FindFirstOccurrenceFuzzy(text, subpattern, &*failure_begin)
- : FindFirstOccurrence(text, subpattern, &*failure_begin));
- if (match_end == base::StringPiece::npos)
- return false;
- text.remove_prefix(match_end);
- failure_begin += subpattern.size();
- }
-
- return pattern.anchor_right != proto::ANCHOR_TYPE_BOUNDARY ||
- EndsWithFuzzy(text, subpattern);
-}
-
-} // namespace subresource_filter
-
-#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_MATCHING_H_
diff --git a/chromium/components/subresource_filter/core/common/url_pattern_matching_unittest.cc b/chromium/components/subresource_filter/core/common/url_pattern_unittest.cc
index cdf36add41c..91ba4fa7d6f 100644
--- a/chromium/components/subresource_filter/core/common/url_pattern_matching_unittest.cc
+++ b/chromium/components/subresource_filter/core/common/url_pattern_unittest.cc
@@ -2,11 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/subresource_filter/core/common/url_pattern_matching.h"
-
-#include <vector>
-
#include "components/subresource_filter/core/common/url_pattern.h"
+
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -20,52 +17,26 @@ constexpr proto::AnchorType kSubdomain = proto::ANCHOR_TYPE_SUBDOMAIN;
} // namespace
-TEST(UrlPatternMatchingTest, BuildFailureFunctionForUrlPattern) {
- const struct {
- UrlPattern url_pattern;
- std::vector<size_t> expected_failure_function;
- } kTestCases[] = {
- {{"abcd", proto::URL_PATTERN_TYPE_SUBSTRING}, {0, 0, 0, 0}},
- {{"&a?a/"}, {0, 0, 0, 0, 0}},
- {{"^a?a/"}, {1, 0, 0, 1, 2, 3}},
-
- {{"abc*abc", kBoundary, kAnchorNone}, {0, 0, 0}},
- {{"abc*aaa", kBoundary, kAnchorNone}, {0, 1, 2}},
- {{"aaa*abc", kBoundary, kAnchorNone}, {0, 0, 0}},
-
- {{"abc*abc", kAnchorNone, kBoundary}, {0, 0, 0}},
- {{"abc*aaa", kAnchorNone, kBoundary}, {0, 0, 0}},
- {{"aaa*abc", kAnchorNone, kBoundary}, {0, 1, 2}},
-
- {{"abc*cca", kSubdomain, kAnchorNone}, {0, 0, 0, 0, 1, 0}},
- {{"abc*cca", kBoundary, kAnchorNone}, {0, 1, 0}},
- {{"abc*cca"}, {0, 0, 0, 0, 1, 0}},
-
- {{"abc*abacaba*cab"}, {0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0}},
- {{"aaa*a^d*^^b"}, {0, 1, 2, 1, 0, 0, 0, 1, 0, 1, 0}},
- {{"aaa*a^d*^^b", kAnchorNone, kBoundary}, {0, 1, 2, 1, 0, 0, 0}},
- {{"^^a*a^d*^^b", kBoundary, kAnchorNone}, {1, 0, 0, 0, 1, 0, 1, 0}},
- };
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message()
- << "Pattern: " << test_case.url_pattern.url_pattern
- << "; Anchors: "
- << static_cast<int>(test_case.url_pattern.anchor_left) << ", "
- << static_cast<int>(test_case.url_pattern.anchor_right));
-
- std::vector<size_t> failure;
- BuildFailureFunction(test_case.url_pattern, &failure);
- EXPECT_EQ(test_case.expected_failure_function, failure);
- }
-}
-
-TEST(UrlPatternMatchingTest, IsUrlPatternMatch) {
+TEST(SubresourceFilterUrlPatternTest, MatchesUrl) {
const struct {
UrlPattern url_pattern;
const char* url;
bool expect_match;
} kTestCases[] = {
+ {{"", proto::URL_PATTERN_TYPE_SUBSTRING}, "http://ex.com/", true},
+ {{"", proto::URL_PATTERN_TYPE_WILDCARDED}, "http://ex.com/", true},
+ {{"", kBoundary, kAnchorNone}, "http://ex.com/", true},
+ {{"", kSubdomain, kAnchorNone}, "http://ex.com/", true},
+ {{"", kSubdomain, kAnchorNone}, "http://ex.com/", true},
+ {{"^", kSubdomain, kAnchorNone}, "http://ex.com/", false},
+ {{".", kSubdomain, kAnchorNone}, "http://ex.com/", false},
+ {{"", kAnchorNone, kBoundary}, "http://ex.com/", true},
+ {{"^", kAnchorNone, kBoundary}, "http://ex.com/", true},
+ {{".", kAnchorNone, kBoundary}, "http://ex.com/", false},
+ {{"", kBoundary, kBoundary}, "http://ex.com/", false},
+ {{"", kSubdomain, kBoundary}, "http://ex.com/", false},
+ {{"com/", kSubdomain, kBoundary}, "http://ex.com/", true},
+
{{"xampl", proto::URL_PATTERN_TYPE_SUBSTRING},
"http://example.com",
true},
@@ -76,9 +47,18 @@ TEST(UrlPatternMatchingTest, IsUrlPatternMatch) {
{{"^abc"}, "http://ex.com/abc?a", true},
{{"^abc"}, "http://ex.com/a?abc", true},
{{"^abc"}, "http://ex.com/abc?abc", true},
+ {{"^abc^abc"}, "http://ex.com/abc?abc", true},
+ {{"^com^abc^abc"}, "http://ex.com/abc?abc", false},
{{"http://ex", kBoundary, kAnchorNone}, "http://example.com", true},
+ {{"http://ex", kAnchorNone, kAnchorNone}, "http://example.com", true},
{{"mple.com/", kAnchorNone, kBoundary}, "http://example.com", true},
+ {{"mple.com/", kAnchorNone, kAnchorNone}, "http://example.com", true},
+ {{"mple.com/", kSubdomain, kAnchorNone}, "http://example.com", false},
+ {{"ex.com", kSubdomain, kAnchorNone}, "http://hex.com", false},
+ {{"ex.com", kSubdomain, kAnchorNone}, "http://ex.com", true},
+ {{"ex.com", kSubdomain, kAnchorNone}, "http://hex.ex.com", true},
+ {{"ex.com", kSubdomain, kAnchorNone}, "http://hex.hex.com", false},
// Note: "example.com" will be normalized into "example.com/".
{{"http://*mpl", kBoundary, kAnchorNone}, "http://example.com", true},
@@ -133,18 +113,10 @@ TEST(UrlPatternMatchingTest, IsUrlPatternMatch) {
};
for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message()
- << "Rule: " << test_case.url_pattern.url_pattern
- << "; Anchors: "
- << static_cast<int>(test_case.url_pattern.anchor_left) << ", "
- << static_cast<int>(test_case.url_pattern.anchor_right)
- << "; URL: " << GURL(test_case.url));
-
- std::vector<size_t> failure;
- BuildFailureFunction(test_case.url_pattern, &failure);
- const bool is_match =
- IsUrlPatternMatch(GURL(test_case.url), test_case.url_pattern,
- failure.begin(), failure.end());
+ SCOPED_TRACE(testing::Message() << "Rule: " << test_case.url_pattern
+ << "; URL: " << GURL(test_case.url));
+
+ const bool is_match = test_case.url_pattern.MatchesUrl(GURL(test_case.url));
EXPECT_EQ(test_case.expect_match, is_match);
}
}
diff --git a/chromium/components/suggestions/BUILD.gn b/chromium/components/suggestions/BUILD.gn
index 32fb84f2996..9d4a692b276 100644
--- a/chromium/components/suggestions/BUILD.gn
+++ b/chromium/components/suggestions/BUILD.gn
@@ -29,7 +29,7 @@ static_library("suggestions") {
deps = [
"//components/data_use_measurement/core",
"//components/google/core/browser",
- "//components/image_fetcher",
+ "//components/image_fetcher/core",
"//components/keyed_service/core",
"//components/leveldb_proto",
"//components/pref_registry",
@@ -58,7 +58,7 @@ source_set("unit_tests") {
deps = [
":suggestions",
"//base/test:test_support",
- "//components/image_fetcher",
+ "//components/image_fetcher/core",
"//components/leveldb_proto:test_support",
"//components/signin/core/browser:test_support",
"//components/sync",
diff --git a/chromium/components/suggestions/image_manager.cc b/chromium/components/suggestions/image_manager.cc
index b3aee7fb581..366a6a2018c 100644
--- a/chromium/components/suggestions/image_manager.cc
+++ b/chromium/components/suggestions/image_manager.cc
@@ -10,7 +10,7 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/task_runner_util.h"
-#include "components/image_fetcher/image_fetcher.h"
+#include "components/image_fetcher/core/image_fetcher.h"
#include "components/suggestions/image_encoder.h"
#include "ui/gfx/image/image.h"
@@ -34,7 +34,8 @@ std::unique_ptr<SkBitmap> DecodeImage(
void WrapCallback(
const suggestions::ImageManager::ImageCallback& wrapped_callback,
const std::string& url,
- const gfx::Image& image) {
+ const gfx::Image& image,
+ const image_fetcher::RequestMetadata& metadata) {
wrapped_callback.Run(GURL(url), image);
}
diff --git a/chromium/components/suggestions/image_manager.h b/chromium/components/suggestions/image_manager.h
index 68589cf4305..20de2eea4d3 100644
--- a/chromium/components/suggestions/image_manager.h
+++ b/chromium/components/suggestions/image_manager.h
@@ -18,7 +18,7 @@
#include "base/memory/weak_ptr.h"
#include "base/task_runner.h"
#include "base/threading/thread_checker.h"
-#include "components/image_fetcher/image_fetcher_delegate.h"
+#include "components/image_fetcher/core/image_fetcher_delegate.h"
#include "components/leveldb_proto/proto_database.h"
#include "components/suggestions/proto/suggestions.pb.h"
#include "ui/gfx/image/image_skia.h"
diff --git a/chromium/components/suggestions/image_manager_unittest.cc b/chromium/components/suggestions/image_manager_unittest.cc
index 8846aefaeca..0966a21a7f1 100644
--- a/chromium/components/suggestions/image_manager_unittest.cc
+++ b/chromium/components/suggestions/image_manager_unittest.cc
@@ -10,9 +10,10 @@
#include "base/files/file_path.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "components/image_fetcher/image_fetcher.h"
-#include "components/image_fetcher/image_fetcher_delegate.h"
+#include "components/image_fetcher/core/image_fetcher.h"
+#include "components/image_fetcher/core/image_fetcher_delegate.h"
#include "components/leveldb_proto/proto_database.h"
#include "components/leveldb_proto/testing/fake_db.h"
#include "components/suggestions/image_encoder.h"
@@ -49,12 +50,15 @@ class MockImageFetcher : public ImageFetcher {
MockImageFetcher() {}
virtual ~MockImageFetcher() {}
MOCK_METHOD3(StartOrQueueNetworkRequest,
- void(const std::string&, const GURL&,
- base::Callback<void(const std::string&,
- const gfx::Image&)>));
+ void(const std::string&,
+ const GURL&,
+ const ImageFetcherCallback&));
MOCK_METHOD1(SetImageFetcherDelegate, void(ImageFetcherDelegate*));
MOCK_METHOD1(SetDataUseServiceName, void(DataUseServiceName));
+ MOCK_METHOD1(SetImageDownloadLimit,
+ void(base::Optional<int64_t> max_download_bytes));
MOCK_METHOD1(SetDesiredImageFrameSize, void(const gfx::Size&));
+ MOCK_METHOD0(GetImageDecoder, image_fetcher::ImageDecoder*());
};
class ImageManagerTest : public testing::Test {
@@ -136,7 +140,7 @@ class ImageManagerTest : public testing::Test {
int num_callback_null_called_;
int num_callback_valid_called_;
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
// Under test.
std::unique_ptr<ImageManager> image_manager_;
diff --git a/chromium/components/suggestions/suggestions_service_impl.cc b/chromium/components/suggestions/suggestions_service_impl.cc
index c16216bf57f..6e41445d9a6 100644
--- a/chromium/components/suggestions/suggestions_service_impl.cc
+++ b/chromium/components/suggestions/suggestions_service_impl.cc
@@ -35,6 +35,7 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
#include "net/http/http_util.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_status.h"
@@ -381,8 +382,39 @@ std::unique_ptr<net::URLFetcher>
SuggestionsServiceImpl::CreateSuggestionsRequest(
const GURL& url,
const std::string& access_token) {
- std::unique_ptr<net::URLFetcher> request =
- net::URLFetcher::Create(0, url, net::URLFetcher::GET, this);
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("suggestions_service", R"(
+ semantics {
+ sender: "Suggestions Service"
+ description:
+ "For signed-in users with History Sync enabled, the Suggestions "
+ "Service fetches website suggestions, based on the user's browsing "
+ "history, for display on the New Tab page."
+ trigger: "Opening a New Tab page."
+ data: "The user's OAuth2 credentials."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "Users can disable this feature by signing out of Chromium, or "
+ "disabling Sync or History Sync in Chromium settings under "
+ "Advanced sync settings. The feature is enabled by default."
+ chrome_policy {
+ SyncDisabled {
+ policy_options {mode: MANDATORY}
+ SyncDisabled: true
+ }
+ }
+ chrome_policy {
+ SigninAllowed {
+ policy_options {mode: MANDATORY}
+ SigninAllowed: false
+ }
+ }
+ })");
+ std::unique_ptr<net::URLFetcher> request = net::URLFetcher::Create(
+ 0, url, net::URLFetcher::GET, this, traffic_annotation);
data_use_measurement::DataUseUserData::AttachToFetcher(
request.get(), data_use_measurement::DataUseUserData::SUGGESTIONS);
int load_flags = net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SEND_COOKIES |
diff --git a/chromium/components/supervised_user_error_page/OWNERS b/chromium/components/supervised_user_error_page/OWNERS
index 1fc7bea8214..5ce5d83eac0 100644
--- a/chromium/components/supervised_user_error_page/OWNERS
+++ b/chromium/components/supervised_user_error_page/OWNERS
@@ -2,3 +2,5 @@ aberent@chromium.org
bauerb@chromium.org
pam@chromium.org
treib@chromium.org
+
+# COMPONENT: Services>SupervisedUser
diff --git a/chromium/components/supervised_user_error_page/gin_wrapper.cc b/chromium/components/supervised_user_error_page/gin_wrapper.cc
index 23728d8d7e0..e6bb37f18c5 100644
--- a/chromium/components/supervised_user_error_page/gin_wrapper.cc
+++ b/chromium/components/supervised_user_error_page/gin_wrapper.cc
@@ -34,10 +34,10 @@ void GinWrapper::Loader::DidClearWindowObject() {
}
void GinWrapper::Loader::InstallGinWrapper() {
- v8::Isolate* isolate = blink::mainThreadIsolate();
+ v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
- render_frame()->GetWebFrame()->mainWorldScriptContext();
+ render_frame()->GetWebFrame()->MainWorldScriptContext();
if (context.IsEmpty())
return;
v8::Context::Scope context_scope(context);
@@ -74,7 +74,7 @@ GinWrapper::~GinWrapper() {}
bool GinWrapper::RequestPermission(
v8::Local<v8::Function> setRequestStatusCallback) {
- setRequestStatusCallback_.Reset(blink::mainThreadIsolate(),
+ setRequestStatusCallback_.Reset(blink::MainThreadIsolate(),
setRequestStatusCallback);
web_restrictions_service_->RequestPermission(
url_, base::Bind(&GinWrapper::OnAccessRequestAdded,
@@ -87,7 +87,7 @@ void GinWrapper::OnAccessRequestAdded(bool success) {
return;
}
- v8::Isolate* isolate = blink::mainThreadIsolate();
+ v8::Isolate* isolate = blink::MainThreadIsolate();
v8::Local<v8::Value> args = v8::Boolean::New(isolate, success);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Function> callback =
diff --git a/chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.css b/chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.css
index a381ab8dd88..e84b3bcea04 100644
--- a/chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.css
+++ b/chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.css
@@ -150,6 +150,8 @@ html {
align-items: center;
display: flex;
font-size: 12px;
+ line-height: normal;
+ margin-top: 14px;
}
.custodian-name {
diff --git a/chromium/components/sync/BUILD.gn b/chromium/components/sync/BUILD.gn
index d58dde07da8..a941fa2220d 100644
--- a/chromium/components/sync/BUILD.gn
+++ b/chromium/components/sync/BUILD.gn
@@ -61,8 +61,6 @@ static_library("sync") {
"base/proto_value_ptr.h",
"base/report_unrecoverable_error.cc",
"base/report_unrecoverable_error.h",
- "base/scoped_event_signal.cc",
- "base/scoped_event_signal.h",
"base/stop_source.h",
"base/sync_features.cc",
"base/sync_features.h",
@@ -844,7 +842,6 @@ source_set("unit_tests") {
"base/ordinal_unittest.cc",
"base/proto_value_ptr_unittest.cc",
"base/protobuf_unittest.cc",
- "base/scoped_event_signal_unittest.cc",
"base/sync_prefs_unittest.cc",
"base/system_encryptor_unittest.cc",
"base/unique_position_unittest.cc",
@@ -936,6 +933,7 @@ source_set("unit_tests") {
"syncable/model_type_unittest.cc",
"syncable/nigori_util_unittest.cc",
"syncable/parent_child_index_unittest.cc",
+ "syncable/syncable_delete_journal_unittest.cc",
"syncable/syncable_enum_conversions_unittest.cc",
"syncable/syncable_id_unittest.cc",
"syncable/syncable_unittest.cc",
diff --git a/chromium/components/sync/protocol/protocol_sources.gni b/chromium/components/sync/protocol/protocol_sources.gni
index a43123a528a..5b58e1a9e3b 100644
--- a/chromium/components/sync/protocol/protocol_sources.gni
+++ b/chromium/components/sync/protocol/protocol_sources.gni
@@ -50,5 +50,6 @@ sync_protocol_sources = [
"//components/sync/protocol/theme_specifics.proto",
"//components/sync/protocol/typed_url_specifics.proto",
"//components/sync/protocol/unique_position.proto",
+ "//components/sync/protocol/user_event_specifics.proto",
"//components/sync/protocol/wifi_credential_specifics.proto",
]
diff --git a/chromium/components/sync_preferences/BUILD.gn b/chromium/components/sync_preferences/BUILD.gn
index d04fbd82744..e8786777f6c 100644
--- a/chromium/components/sync_preferences/BUILD.gn
+++ b/chromium/components/sync_preferences/BUILD.gn
@@ -24,6 +24,7 @@ static_library("sync_preferences") {
"//components/pref_registry",
"//components/prefs",
"//components/sync",
+ "//services/preferences/public/cpp",
]
if (!is_ios) {
diff --git a/chromium/components/sync_preferences/DEPS b/chromium/components/sync_preferences/DEPS
index 648f01f6572..4b15f8d3c5d 100644
--- a/chromium/components/sync_preferences/DEPS
+++ b/chromium/components/sync_preferences/DEPS
@@ -4,6 +4,8 @@ include_rules = [
"+components/pref_registry",
"+components/prefs",
"+components/sync",
+ "+services/preferences/public",
+ "+services/service_manager/public",
# sync_preferences can be used on all platforms, including iOS. Do not allow
# platform-specific dependencies.
diff --git a/chromium/components/sync_preferences/OWNERS b/chromium/components/sync_preferences/OWNERS
index 2d870381cb7..e04d3d44deb 100644
--- a/chromium/components/sync_preferences/OWNERS
+++ b/chromium/components/sync_preferences/OWNERS
@@ -2,3 +2,5 @@ battre@chromium.org
bauerb@chromium.org
gab@chromium.org
pam@chromium.org
+
+# COMPONENT: UI>Browser>Preferences
diff --git a/chromium/components/sync_preferences/pref_model_associator.cc b/chromium/components/sync_preferences/pref_model_associator.cc
index 7f893cf9432..6bb1801dc52 100644
--- a/chromium/components/sync_preferences/pref_model_associator.cc
+++ b/chromium/components/sync_preferences/pref_model_associator.cc
@@ -77,7 +77,7 @@ void PrefModelAssociator::InitPrefAndAssociate(
const std::string& pref_name,
syncer::SyncChangeList* sync_changes) {
const base::Value* user_pref_value =
- pref_service_->GetUserPrefValue(pref_name.c_str());
+ pref_service_->GetUserPrefValue(pref_name);
VLOG(1) << "Associating preference " << pref_name;
if (sync_pref.IsValid()) {
@@ -103,14 +103,14 @@ void PrefModelAssociator::InitPrefAndAssociate(
// ignored if the preference is policy controlled.
if (new_value->IsType(base::Value::Type::NONE)) {
LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str();
- pref_service_->ClearPref(pref_name.c_str());
+ pref_service_->ClearPref(pref_name);
} else if (!new_value->IsType(user_pref_value->GetType())) {
LOG(WARNING) << "Synced value for " << preference.name()
<< " is of type " << new_value->GetType()
<< " which doesn't match pref type "
<< user_pref_value->GetType();
} else if (!user_pref_value->Equals(new_value.get())) {
- pref_service_->Set(pref_name.c_str(), *new_value);
+ pref_service_->Set(pref_name, *new_value);
}
// If the merge resulted in an updated value, inform the syncer.
@@ -126,7 +126,7 @@ void PrefModelAssociator::InitPrefAndAssociate(
}
} else if (!sync_value->IsType(base::Value::Type::NONE)) {
// Only a server value exists. Just set the local user value.
- pref_service_->Set(pref_name.c_str(), *sync_value);
+ pref_service_->Set(pref_name, *sync_value);
} else {
LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str();
}
@@ -291,7 +291,7 @@ base::Value* PrefModelAssociator::MergeListValues(const base::Value& from_value,
base::ListValue* result = to_list_value.DeepCopy();
for (const auto& value : from_list_value) {
- result->AppendIfNotPresent(value->CreateDeepCopy());
+ result->AppendIfNotPresent(value.CreateDeepCopy());
}
return result;
}
@@ -343,8 +343,7 @@ syncer::SyncDataList PrefModelAssociator::GetAllSyncData(
for (PreferenceSet::const_iterator iter = synced_preferences_.begin();
iter != synced_preferences_.end(); ++iter) {
std::string name = *iter;
- const PrefService::Preference* pref =
- pref_service_->FindPreference(name.c_str());
+ const PrefService::Preference* pref = pref_service_->FindPreference(name);
DCHECK(pref);
if (!pref->IsUserControlled() || pref->IsDefaultValue())
continue; // This is not data we care about.
@@ -475,7 +474,7 @@ void PrefModelAssociator::ProcessPrefChange(const std::string& name) {
return;
const PrefService::Preference* preference =
- pref_service_->FindPreference(name.c_str());
+ pref_service_->FindPreference(name);
if (!preference)
return;
diff --git a/chromium/components/sync_preferences/pref_model_associator_unittest.cc b/chromium/components/sync_preferences/pref_model_associator_unittest.cc
index eac90d7f527..d9c4f17d4e6 100644
--- a/chromium/components/sync_preferences/pref_model_associator_unittest.cc
+++ b/chromium/components/sync_preferences/pref_model_associator_unittest.cc
@@ -7,6 +7,7 @@
#include <memory>
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/values.h"
#include "components/prefs/scoped_user_pref_update.h"
@@ -117,8 +118,7 @@ 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::StringValue(server_url0_));
+ 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()));
@@ -134,7 +134,7 @@ TEST_F(ListPreferenceMergeTest, LocalEmpty) {
}
TEST_F(ListPreferenceMergeTest, ServerNull) {
- std::unique_ptr<base::Value> null_value = base::Value::CreateNullValue();
+ auto null_value = base::MakeUnique<base::Value>();
{
ListPrefUpdate update(pref_service_.get(), kListPrefName);
base::ListValue* local_list_value = update.Get();
@@ -256,7 +256,7 @@ TEST_F(DictionaryPreferenceMergeTest, LocalEmpty) {
}
TEST_F(DictionaryPreferenceMergeTest, ServerNull) {
- std::unique_ptr<base::Value> null_value = base::Value::CreateNullValue();
+ auto null_value = base::MakeUnique<base::Value>();
{
DictionaryPrefUpdate update(pref_service_.get(), kDictionaryPrefName);
base::DictionaryValue* local_dict_value = update.Get();
diff --git a/chromium/components/sync_preferences/pref_service_syncable_factory.cc b/chromium/components/sync_preferences/pref_service_syncable_factory.cc
index 2d314f51952..bc593d468b6 100644
--- a/chromium/components/sync_preferences/pref_service_syncable_factory.cc
+++ b/chromium/components/sync_preferences/pref_service_syncable_factory.cc
@@ -11,6 +11,9 @@
#include "components/prefs/pref_notifier_impl.h"
#include "components/prefs/pref_value_store.h"
#include "components/sync_preferences/pref_service_syncable.h"
+#include "services/preferences/public/cpp/pref_store_adapter.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
#if !defined(OS_IOS)
#include "components/policy/core/browser/browser_policy_connector.h"
@@ -52,16 +55,52 @@ void PrefServiceSyncableFactory::SetPrefModelAssociatorClient(
pref_model_associator_client_ = pref_model_associator_client;
}
+namespace {
+
+// Expose the |backing_pref_store| through the prefs service.
+scoped_refptr<::PrefStore> CreateRegisteredPrefStore(
+ service_manager::Connector* connector,
+ scoped_refptr<::PrefStore> backing_pref_store,
+ PrefValueStore::PrefStoreType type) {
+ // If we're testing or if the prefs service feature flag is off we don't
+ // register.
+ if (!connector || !backing_pref_store)
+ return backing_pref_store;
+
+ prefs::mojom::PrefStoreRegistryPtr registry_ptr;
+ connector->BindInterface(prefs::mojom::kServiceName, &registry_ptr);
+ return make_scoped_refptr(new prefs::PrefStoreAdapter(
+ backing_pref_store, prefs::PrefStoreImpl::Create(
+ registry_ptr.get(), backing_pref_store, type)));
+}
+
+} // namespace
+
std::unique_ptr<PrefServiceSyncable> PrefServiceSyncableFactory::CreateSyncable(
- user_prefs::PrefRegistrySyncable* pref_registry) {
+ user_prefs::PrefRegistrySyncable* pref_registry,
+ service_manager::Connector* connector) {
TRACE_EVENT0("browser", "PrefServiceSyncableFactory::CreateSyncable");
PrefNotifierImpl* pref_notifier = new PrefNotifierImpl();
+
+ // Expose all read-only stores through the prefs service.
+ auto managed = CreateRegisteredPrefStore(connector, managed_prefs_,
+ PrefValueStore::MANAGED_STORE);
+ auto supervised = CreateRegisteredPrefStore(
+ connector, supervised_user_prefs_, PrefValueStore::SUPERVISED_USER_STORE);
+ auto extension = CreateRegisteredPrefStore(connector, extension_prefs_,
+ PrefValueStore::EXTENSION_STORE);
+ auto command_line = CreateRegisteredPrefStore(
+ connector, command_line_prefs_, PrefValueStore::COMMAND_LINE_STORE);
+ auto recommended = CreateRegisteredPrefStore(
+ connector, recommended_prefs_, PrefValueStore::RECOMMENDED_STORE);
+
+ // TODO(sammc): Register Mojo user pref store once implemented.
std::unique_ptr<PrefServiceSyncable> pref_service(new PrefServiceSyncable(
pref_notifier,
- new 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),
+ new PrefValueStore(managed.get(), supervised.get(), extension.get(),
+ command_line.get(), user_prefs_.get(),
+ recommended.get(), pref_registry->defaults().get(),
+ pref_notifier),
user_prefs_.get(), pref_registry, pref_model_associator_client_,
read_error_callback_, async_));
return pref_service;
diff --git a/chromium/components/sync_preferences/pref_service_syncable_factory.h b/chromium/components/sync_preferences/pref_service_syncable_factory.h
index 9a8994b6c6a..3b9bb394421 100644
--- a/chromium/components/sync_preferences/pref_service_syncable_factory.h
+++ b/chromium/components/sync_preferences/pref_service_syncable_factory.h
@@ -15,6 +15,10 @@ class BrowserPolicyConnector;
class PolicyService;
}
+namespace service_manager {
+class Connector;
+}
+
namespace user_prefs {
class PrefRegistrySyncable;
}
@@ -42,8 +46,11 @@ class PrefServiceSyncableFactory : public PrefServiceFactory {
void SetPrefModelAssociatorClient(
PrefModelAssociatorClient* pref_model_associator_client);
+ // |connector| might be null during test or if we're not using the Mojo pref
+ // |service.
std::unique_ptr<PrefServiceSyncable> CreateSyncable(
- user_prefs::PrefRegistrySyncable* registry);
+ user_prefs::PrefRegistrySyncable* registry,
+ service_manager::Connector* connector = nullptr);
private:
PrefModelAssociatorClient* pref_model_associator_client_;
diff --git a/chromium/components/sync_preferences/pref_service_syncable_unittest.cc b/chromium/components/sync_preferences/pref_service_syncable_unittest.cc
index 4123ebef704..008446ba150 100644
--- a/chromium/components/sync_preferences/pref_service_syncable_unittest.cc
+++ b/chromium/components/sync_preferences/pref_service_syncable_unittest.cc
@@ -273,13 +273,13 @@ TEST_F(PrefServiceSyncableTest, ModelAssociationCloudHasData) {
syncer::SyncDataList in;
syncer::SyncChangeList out;
- AddToRemoteDataList(kStringPrefName, base::StringValue(kExampleUrl1), &in);
+ AddToRemoteDataList(kStringPrefName, base::Value(kExampleUrl1), &in);
base::ListValue urls_to_restore;
urls_to_restore.AppendString(kExampleUrl1);
urls_to_restore.AppendString(kExampleUrl2);
AddToRemoteDataList(kListPrefName, urls_to_restore, &in);
AddToRemoteDataList(kDefaultCharsetPrefName,
- base::StringValue(kNonDefaultCharsetValue), &in);
+ base::Value(kNonDefaultCharsetValue), &in);
InitWithSyncDataTakeOutput(in, &out);
ASSERT_FALSE(FindValue(kStringPrefName, out).get());
@@ -316,7 +316,7 @@ TEST_F(PrefServiceSyncableTest, UpdatedPreferenceWithDefaultValue) {
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
out.clear();
- base::StringValue expected(kExampleUrl0);
+ base::Value expected(kExampleUrl0);
GetPrefs()->Set(kStringPrefName, expected);
std::unique_ptr<base::Value> actual(FindValue(kStringPrefName, out));
@@ -330,7 +330,7 @@ TEST_F(PrefServiceSyncableTest, UpdatedPreferenceWithValue) {
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
out.clear();
- base::StringValue expected(kExampleUrl1);
+ base::Value expected(kExampleUrl1);
GetPrefs()->Set(kStringPrefName, expected);
std::unique_ptr<base::Value> actual(FindValue(kStringPrefName, out));
@@ -342,7 +342,7 @@ TEST_F(PrefServiceSyncableTest, UpdatedSyncNodeActionUpdate) {
GetPrefs()->SetString(kStringPrefName, kExampleUrl0);
InitWithNoSyncData();
- base::StringValue expected(kExampleUrl1);
+ base::Value expected(kExampleUrl1);
syncer::SyncChangeList list;
list.push_back(MakeRemoteChange(1, kStringPrefName, expected,
SyncChange::ACTION_UPDATE));
@@ -355,7 +355,7 @@ TEST_F(PrefServiceSyncableTest, UpdatedSyncNodeActionUpdate) {
TEST_F(PrefServiceSyncableTest, UpdatedSyncNodeActionAdd) {
InitWithNoSyncData();
- base::StringValue expected(kExampleUrl0);
+ base::Value expected(kExampleUrl0);
syncer::SyncChangeList list;
list.push_back(
MakeRemoteChange(1, kStringPrefName, expected, SyncChange::ACTION_ADD));
@@ -370,7 +370,7 @@ TEST_F(PrefServiceSyncableTest, UpdatedSyncNodeActionAdd) {
TEST_F(PrefServiceSyncableTest, UpdatedSyncNodeUnknownPreference) {
InitWithNoSyncData();
syncer::SyncChangeList list;
- base::StringValue expected(kExampleUrl0);
+ base::Value expected(kExampleUrl0);
list.push_back(MakeRemoteChange(1, "unknown preference", expected,
SyncChange::ACTION_UPDATE));
pref_sync_service_->ProcessSyncChanges(FROM_HERE, list);
@@ -380,21 +380,21 @@ TEST_F(PrefServiceSyncableTest, UpdatedSyncNodeUnknownPreference) {
TEST_F(PrefServiceSyncableTest, ManagedPreferences) {
// Make the homepage preference managed.
- base::StringValue managed_value("http://example.com");
- prefs_.SetManagedPref(kStringPrefName, managed_value.DeepCopy());
+ base::Value managed_value("http://example.com");
+ prefs_.SetManagedPref(kStringPrefName, managed_value.CreateDeepCopy());
syncer::SyncChangeList out;
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
out.clear();
// Changing the homepage preference should not sync anything.
- base::StringValue user_value("http://chromium..com");
- prefs_.SetUserPref(kStringPrefName, user_value.DeepCopy());
+ base::Value user_value("http://chromium..com");
+ prefs_.SetUserPref(kStringPrefName, user_value.CreateDeepCopy());
EXPECT_TRUE(out.empty());
// An incoming sync transaction should change the user value, not the managed
// value.
- base::StringValue sync_value("http://crbug.com");
+ base::Value sync_value("http://crbug.com");
syncer::SyncChangeList list;
list.push_back(MakeRemoteChange(1, kStringPrefName, sync_value,
SyncChange::ACTION_UPDATE));
@@ -412,7 +412,7 @@ TEST_F(PrefServiceSyncableTest, ManagedListPreferences) {
base::ListValue managed_value;
managed_value.AppendString(kExampleUrl0);
managed_value.AppendString(kExampleUrl1);
- prefs_.SetManagedPref(kListPrefName, managed_value.DeepCopy());
+ prefs_.SetManagedPref(kListPrefName, managed_value.CreateDeepCopy());
// Set a cloud version.
syncer::SyncDataList in;
@@ -431,7 +431,7 @@ TEST_F(PrefServiceSyncableTest, ManagedListPreferences) {
// anything.
base::ListValue user_value;
user_value.AppendString("http://chromium.org");
- prefs_.SetUserPref(kListPrefName, user_value.DeepCopy());
+ prefs_.SetUserPref(kListPrefName, user_value.CreateDeepCopy());
EXPECT_FALSE(FindValue(kListPrefName, out).get());
// An incoming sync transaction should change the user value, not the managed
@@ -451,16 +451,16 @@ TEST_F(PrefServiceSyncableTest, DynamicManagedPreferences) {
syncer::SyncChangeList out;
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
out.clear();
- base::StringValue initial_value("http://example.com/initial");
+ base::Value initial_value("http://example.com/initial");
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()));
// Switch kHomePage to managed and set a different value.
- base::StringValue managed_value("http://example.com/managed");
+ base::Value managed_value("http://example.com/managed");
GetTestingPrefService()->SetManagedPref(kStringPrefName,
- managed_value.DeepCopy());
+ managed_value.CreateDeepCopy());
// The pref value should be the one dictated by policy.
EXPECT_TRUE(managed_value.Equals(&GetPreferenceValue(kStringPrefName)));
@@ -477,18 +477,18 @@ TEST_F(PrefServiceSyncableTest, DynamicManagedPreferencesWithSyncChange) {
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
out.clear();
- base::StringValue initial_value("http://example.com/initial");
+ 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()));
// Switch kHomePage to managed and set a different value.
- base::StringValue managed_value("http://example.com/managed");
+ base::Value managed_value("http://example.com/managed");
GetTestingPrefService()->SetManagedPref(kStringPrefName,
- managed_value.DeepCopy());
+ managed_value.CreateDeepCopy());
// Change the sync value.
- base::StringValue sync_value("http://example.com/sync");
+ base::Value sync_value("http://example.com/sync");
syncer::SyncChangeList list;
list.push_back(MakeRemoteChange(1, kStringPrefName, sync_value,
SyncChange::ACTION_UPDATE));
@@ -516,9 +516,9 @@ TEST_F(PrefServiceSyncableTest, DynamicManagedDefaultPreferences) {
out.clear();
// Switch kHomePage to managed and set a different value.
- base::StringValue managed_value("http://example.com/managed");
+ base::Value managed_value("http://example.com/managed");
GetTestingPrefService()->SetManagedPref(kStringPrefName,
- managed_value.DeepCopy());
+ managed_value.CreateDeepCopy());
// The pref value should be the one dictated by policy.
EXPECT_TRUE(managed_value.Equals(&GetPreferenceValue(kStringPrefName)));
EXPECT_FALSE(pref->IsDefaultValue());
@@ -539,7 +539,7 @@ TEST_F(PrefServiceSyncableTest, DeletePreference) {
InitWithNoSyncData();
- std::unique_ptr<base::Value> null_value = base::Value::CreateNullValue();
+ auto null_value = base::MakeUnique<base::Value>();
syncer::SyncChangeList list;
list.push_back(MakeRemoteChange(1, kStringPrefName, *null_value,
SyncChange::ACTION_DELETE));
diff --git a/chromium/components/sync_preferences/synced_pref_change_registrar.cc b/chromium/components/sync_preferences/synced_pref_change_registrar.cc
index 3d8fa89bf23..5e2682ea98a 100644
--- a/chromium/components/sync_preferences/synced_pref_change_registrar.cc
+++ b/chromium/components/sync_preferences/synced_pref_change_registrar.cc
@@ -59,7 +59,7 @@ bool SyncedPrefChangeRegistrar::IsObserved(const char* path) const {
void SyncedPrefChangeRegistrar::OnSyncedPrefChanged(const std::string& path,
bool from_sync) {
- if (pref_service_->IsManagedPreference(path.c_str()))
+ if (pref_service_->IsManagedPreference(path))
return;
ObserverMap::const_iterator iter = observers_.find(path);
if (iter == observers_.end())
diff --git a/chromium/components/sync_sessions/fake_sync_sessions_client.cc b/chromium/components/sync_sessions/fake_sync_sessions_client.cc
index 9bdc8213a55..3ef4ae03835 100644
--- a/chromium/components/sync_sessions/fake_sync_sessions_client.cc
+++ b/chromium/components/sync_sessions/fake_sync_sessions_client.cc
@@ -33,8 +33,7 @@ FakeSyncSessionsClient::GetSyncedWindowDelegatesGetter() {
return nullptr;
}
-std::unique_ptr<LocalSessionEventRouter>
-FakeSyncSessionsClient::GetLocalSessionEventRouter() {
+LocalSessionEventRouter* FakeSyncSessionsClient::GetLocalSessionEventRouter() {
return nullptr;
}
diff --git a/chromium/components/sync_sessions/fake_sync_sessions_client.h b/chromium/components/sync_sessions/fake_sync_sessions_client.h
index 7b17f3a1d88..acffdce1f3a 100644
--- a/chromium/components/sync_sessions/fake_sync_sessions_client.h
+++ b/chromium/components/sync_sessions/fake_sync_sessions_client.h
@@ -24,8 +24,7 @@ class FakeSyncSessionsClient : public SyncSessionsClient {
history::HistoryService* GetHistoryService() override;
bool ShouldSyncURL(const GURL& url) const override;
SyncedWindowDelegatesGetter* GetSyncedWindowDelegatesGetter() override;
- std::unique_ptr<LocalSessionEventRouter> GetLocalSessionEventRouter()
- override;
+ LocalSessionEventRouter* GetLocalSessionEventRouter() override;
private:
DISALLOW_COPY_AND_ASSIGN(FakeSyncSessionsClient);
diff --git a/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.cc b/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.cc
index ccb603aa25e..1a99c70a7dd 100644
--- a/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.cc
+++ b/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.cc
@@ -57,7 +57,7 @@ void SessionsPageRevisitObserver::CheckForRevisit(
if (provider_->GetAllForeignSessions(&foreign_sessions)) {
for (const SyncedSession* session : foreign_sessions) {
for (const auto& key_value : session->windows) {
- for (const auto& tab : key_value.second->tabs) {
+ for (const auto& tab : key_value.second->wrapped_window.tabs) {
// These matchers look identical and could easily implement an
// interface and we could iterate through a vector of matchers here.
// However this would cause quite a bit of overhead at the inner most
diff --git a/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc b/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc
index e7b3181d3d3..b86549eba22 100644
--- a/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc
+++ b/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc
@@ -87,39 +87,39 @@ TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoSessions) {
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoWindows) {
- std::unique_ptr<SyncedSession> session = base::MakeUnique<SyncedSession>();
+ auto session = base::MakeUnique<SyncedSession>();
CheckAndExpect(session.get(), GURL(kExampleUrl), false, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoTabs) {
- std::unique_ptr<SyncedSession> session = base::MakeUnique<SyncedSession>();
- session->windows[0] = base::MakeUnique<SessionWindow>();
+ auto session = base::MakeUnique<SyncedSession>();
+ session->windows[0] = base::MakeUnique<SyncedSessionWindow>();
CheckAndExpect(session.get(), GURL(kExampleUrl), false, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoEntries) {
- std::unique_ptr<SessionWindow> window = base::MakeUnique<SessionWindow>();
- window->tabs.push_back(base::MakeUnique<SessionTab>());
- std::unique_ptr<SyncedSession> session = base::MakeUnique<SyncedSession>();
+ auto window = base::MakeUnique<SyncedSessionWindow>();
+ window->wrapped_window.tabs.push_back(base::MakeUnique<SessionTab>());
+ auto session = base::MakeUnique<SyncedSession>();
session->windows[0] = std::move(window);
CheckAndExpect(session.get(), GURL(kExampleUrl), false, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersSingle) {
- std::unique_ptr<SessionTab> tab = base::MakeUnique<SessionTab>();
+ auto tab = base::MakeUnique<SessionTab>();
tab->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
tab->current_navigation_index = 0;
- std::unique_ptr<SessionWindow> window = base::MakeUnique<SessionWindow>();
- window->tabs.push_back(std::move(tab));
- std::unique_ptr<SyncedSession> session = base::MakeUnique<SyncedSession>();
+ auto window = base::MakeUnique<SyncedSessionWindow>();
+ window->wrapped_window.tabs.push_back(std::move(tab));
+ auto session = base::MakeUnique<SyncedSession>();
session->windows[0] = std::move(window);
CheckAndExpect(session.get(), GURL(kExampleUrl), true, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersFalseProvider) {
- std::unique_ptr<SessionTab> tab = base::MakeUnique<SessionTab>();
+ auto tab = base::MakeUnique<SessionTab>();
tab->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
@@ -127,9 +127,9 @@ TEST_F(SessionsPageRevisitObserverTest, RunMatchersFalseProvider) {
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
tab->current_navigation_index = 1;
- std::unique_ptr<SessionWindow> window = base::MakeUnique<SessionWindow>();
- window->tabs.push_back(std::move(tab));
- std::unique_ptr<SyncedSession> session = base::MakeUnique<SyncedSession>();
+ auto window = base::MakeUnique<SyncedSessionWindow>();
+ window->wrapped_window.tabs.push_back(std::move(tab));
+ auto session = base::MakeUnique<SyncedSession>();
session->windows[0] = std::move(window);
// The provider returns false when asked for foreign sessions, even though
@@ -142,25 +142,25 @@ TEST_F(SessionsPageRevisitObserverTest, RunMatchersFalseProvider) {
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersMany) {
- std::unique_ptr<SessionTab> tab1 = base::MakeUnique<SessionTab>();
+ auto tab1 = base::MakeUnique<SessionTab>();
tab1->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
tab1->current_navigation_index = 0;
- std::unique_ptr<SessionTab> tab2 = base::MakeUnique<SessionTab>();
+ auto tab2 = base::MakeUnique<SessionTab>();
tab2->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kDifferentUrl, ""));
tab2->current_navigation_index = 0;
- std::unique_ptr<SessionTab> tab3 = base::MakeUnique<SessionTab>();
+ auto tab3 = base::MakeUnique<SessionTab>();
tab3->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kDifferentUrl, ""));
tab3->current_navigation_index = 0;
- std::unique_ptr<SessionTab> tab4 = base::MakeUnique<SessionTab>();
+ auto tab4 = base::MakeUnique<SessionTab>();
tab4->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
@@ -169,17 +169,17 @@ TEST_F(SessionsPageRevisitObserverTest, RunMatchersMany) {
kDifferentUrl, ""));
tab4->current_navigation_index = 1;
- std::unique_ptr<SessionWindow> window1 = base::MakeUnique<SessionWindow>();
- window1->tabs.push_back(std::move(tab1));
- std::unique_ptr<SessionWindow> window2 = base::MakeUnique<SessionWindow>();
- window2->tabs.push_back(std::move(tab2));
- std::unique_ptr<SessionWindow> window3 = base::MakeUnique<SessionWindow>();
- window3->tabs.push_back(std::move(tab3));
- window3->tabs.push_back(std::move(tab4));
+ auto window1 = base::MakeUnique<SyncedSessionWindow>();
+ window1->wrapped_window.tabs.push_back(std::move(tab1));
+ auto window2 = base::MakeUnique<SyncedSessionWindow>();
+ window2->wrapped_window.tabs.push_back(std::move(tab2));
+ auto window3 = base::MakeUnique<SyncedSessionWindow>();
+ window3->wrapped_window.tabs.push_back(std::move(tab3));
+ window3->wrapped_window.tabs.push_back(std::move(tab4));
- std::unique_ptr<SyncedSession> session1 = base::MakeUnique<SyncedSession>();
+ auto session1 = base::MakeUnique<SyncedSession>();
session1->windows[1] = std::move(window1);
- std::unique_ptr<SyncedSession> session2 = base::MakeUnique<SyncedSession>();
+ auto session2 = base::MakeUnique<SyncedSession>();
session2->windows[2] = std::move(window2);
session2->windows[3] = std::move(window3);
diff --git a/chromium/components/sync_sessions/session_sync_test_helper.cc b/chromium/components/sync_sessions/session_sync_test_helper.cc
index ac5b699d988..90076fd542e 100644
--- a/chromium/components/sync_sessions/session_sync_test_helper.cc
+++ b/chromium/components/sync_sessions/session_sync_test_helper.cc
@@ -62,7 +62,7 @@ void SessionSyncTestHelper::VerifySyncedSession(
sessions::SessionWindow* win_ptr;
auto map_iter = session.windows.find(i);
if (map_iter != session.windows.end())
- win_ptr = map_iter->second.get();
+ win_ptr = &map_iter->second->wrapped_window;
else
FAIL();
ASSERT_EQ(win_iter->size(), win_ptr->tabs.size());
diff --git a/chromium/components/sync_sessions/sessions_sync_manager.cc b/chromium/components/sync_sessions/sessions_sync_manager.cc
index d61d75591b9..665929fcd4e 100644
--- a/chromium/components/sync_sessions/sessions_sync_manager.cc
+++ b/chromium/components/sync_sessions/sessions_sync_manager.cc
@@ -25,7 +25,6 @@
#include "components/sync_sessions/synced_window_delegate.h"
#include "components/sync_sessions/synced_window_delegates_getter.h"
#include "components/sync_sessions/tab_node_pool.h"
-#include "components/variations/variations_associated_data.h"
using sessions::SerializedNavigationEntry;
using syncer::DeviceInfo;
@@ -106,7 +105,7 @@ void AppendDeletionsForTabNodes(const std::set<int>& tab_node_ids,
// Ensure that the tab id is not invalid.
bool ShouldSyncTabId(SessionID::id_type tab_id) {
- if (tab_id == TabNodePool::kInvalidTabID)
+ if (tab_id == kInvalidTabID)
return false;
return true;
}
@@ -119,7 +118,7 @@ SessionsSyncManager::SessionsSyncManager(
sync_sessions::SyncSessionsClient* sessions_client,
syncer::SyncPrefs* sync_prefs,
LocalDeviceInfoProvider* local_device,
- std::unique_ptr<LocalSessionEventRouter> router,
+ LocalSessionEventRouter* router,
const base::Closure& sessions_updated_callback,
const base::Closure& datatype_refresh_callback)
: sessions_client_(sessions_client),
@@ -391,7 +390,6 @@ void SessionsSyncManager::AssociateTab(SyncedTabDelegate* const tab_delegate,
// Update the tracker's session representation.
SetSessionTabFromDelegate(*tab_delegate, base::Time::Now(), session_tab);
- SetVariationIds(session_tab);
session_tracker_.GetSession(current_machine_tag())->modified_time =
base::Time::Now();
@@ -512,13 +510,13 @@ syncer::SyncDataList SessionsSyncManager::GetAllSyncData(
header_entity.mutable_session()->set_session_tag(current_machine_tag());
sync_pb::SessionHeader* header_specifics =
header_entity.mutable_session()->mutable_header();
- header_specifics->MergeFrom(session->ToSessionHeader());
+ header_specifics->MergeFrom(session->ToSessionHeaderProto());
syncer::SyncData data = syncer::SyncData::CreateLocalData(
current_machine_tag(), current_session_name_, header_entity);
list.push_back(data);
for (auto& win_iter : session->windows) {
- for (auto& tab : win_iter.second->tabs) {
+ for (auto& tab : win_iter.second->wrapped_window.tabs) {
// TODO(zea): replace with with the correct tab node id once there's a
// sync specific wrapper for SessionTab. This method is only used in
// tests though, so it's fine for now. crbug.com/662597
@@ -681,7 +679,7 @@ bool SessionsSyncManager::InitFromSyncModel(
syncer::SyncChange tombstone(TombstoneTab(specifics));
if (tombstone.IsValid())
new_changes->push_back(tombstone);
- } else if (specifics.tab().tab_id() == TabNodePool::kInvalidTabID) {
+ } else if (specifics.tab().tab_id() == kInvalidTabID) {
LOG(WARNING) << "Found tab node with invalid tab id.";
syncer::SyncChange tombstone(TombstoneTab(specifics));
if (tombstone.IsValid())
@@ -867,14 +865,15 @@ void SessionsSyncManager::BuildSyncedSessionFromSpecifics(
const std::string& session_tag,
const sync_pb::SessionWindow& specifics,
base::Time mtime,
- sessions::SessionWindow* session_window) {
+ SyncedSessionWindow* synced_session_window) {
+ sessions::SessionWindow* session_window =
+ &synced_session_window->wrapped_window;
if (specifics.has_window_id())
session_window->window_id.set_id(specifics.window_id());
if (specifics.has_selected_tab_index())
session_window->selected_tab_index = specifics.selected_tab_index();
+ synced_session_window->window_type = specifics.browser_type();
if (specifics.has_browser_type()) {
- // TODO(skuhne): Sync data writes |BrowserType| not
- // |SessionWindow::WindowType|. This should get changed.
if (specifics.browser_type() ==
sync_pb::SessionWindow_BrowserType_TYPE_TABBED) {
session_window->type = sessions::SessionWindow::TYPE_TABBED;
@@ -1093,18 +1092,6 @@ void SessionsSyncManager::SetSessionTabFromDelegate(
session_tab->session_storage_persistent_id.clear();
}
-// static
-void SessionsSyncManager::SetVariationIds(sessions::SessionTab* session_tab) {
- base::FieldTrial::ActiveGroups active_groups;
- base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
- for (const base::FieldTrial::ActiveGroup& group : active_groups) {
- const variations::VariationID id = variations::GetGoogleVariationID(
- variations::CHROME_SYNC_SERVICE, group.trial_name, group.group_name);
- if (id != variations::EMPTY_ID)
- session_tab->variation_ids.push_back(id);
- }
-}
-
FaviconCache* SessionsSyncManager::GetFaviconCache() {
return &favicon_cache_;
}
diff --git a/chromium/components/sync_sessions/sessions_sync_manager.h b/chromium/components/sync_sessions/sessions_sync_manager.h
index d685c65cd42..bf72e9e716e 100644
--- a/chromium/components/sync_sessions/sessions_sync_manager.h
+++ b/chromium/components/sync_sessions/sessions_sync_manager.h
@@ -62,7 +62,7 @@ class SessionsSyncManager : public syncer::SyncableService,
SessionsSyncManager(SyncSessionsClient* sessions_client,
syncer::SyncPrefs* sync_prefs,
syncer::LocalDeviceInfoProvider* local_device,
- std::unique_ptr<LocalSessionEventRouter> router,
+ LocalSessionEventRouter* router,
const base::Closure& sessions_updated_callback,
const base::Closure& datatype_refresh_callback);
~SessionsSyncManager() override;
@@ -146,7 +146,6 @@ class SessionsSyncManager : public syncer::SyncableService,
FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, SwappedOutOnRestore);
FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest,
ProcessRemoteDeleteOfLocalSession);
- FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, SetVariationIds);
void InitializeCurrentMachineTag(const std::string& cache_guid);
@@ -195,10 +194,11 @@ class SessionsSyncManager : public syncer::SyncableService,
// Builds |session_window| from the session specifics window
// provided and updates the SessionTracker with foreign session data created.
- void BuildSyncedSessionFromSpecifics(const std::string& session_tag,
- const sync_pb::SessionWindow& specifics,
- base::Time mtime,
- sessions::SessionWindow* session_window);
+ void BuildSyncedSessionFromSpecifics(
+ const std::string& session_tag,
+ const sync_pb::SessionWindow& specifics,
+ base::Time mtime,
+ SyncedSessionWindow* synced_session_window);
// Resync local window information. Updates the local sessions header node
// with the status of open windows and the order of tabs they contain. Should
@@ -230,10 +230,6 @@ class SessionsSyncManager : public syncer::SyncableService,
base::Time mtime,
sessions::SessionTab* session_tab);
- // Sets |variation_ids| field of |session_tab| with the ids of the currently
- // assigned variations which should be sent to sync.
- static void SetVariationIds(sessions::SessionTab* session_tab);
-
// Populates |specifics| based on the data in |tab_delegate|.
void LocalTabDelegateToSpecifics(const SyncedTabDelegate& tab_delegate,
sync_pb::SessionSpecifics* specifics);
@@ -309,7 +305,7 @@ class SessionsSyncManager : public syncer::SyncableService,
// stale and a candidate for garbage collection.
int stale_session_threshold_days_;
- std::unique_ptr<LocalSessionEventRouter> local_event_router_;
+ LocalSessionEventRouter* local_event_router_;
// Owns revisiting instrumentation logic for page visit events.
PageRevisitBroadcaster page_revisit_broadcaster_;
diff --git a/chromium/components/sync_sessions/sessions_sync_manager_unittest.cc b/chromium/components/sync_sessions/sessions_sync_manager_unittest.cc
index ab5cbfde94d..7479a1833c5 100644
--- a/chromium/components/sync_sessions/sessions_sync_manager_unittest.cc
+++ b/chromium/components/sync_sessions/sessions_sync_manager_unittest.cc
@@ -211,6 +211,8 @@ class TestSyncedTabDelegate : public SyncedTabDelegate {
return http_count > 0;
}
+ SessionID::id_type GetSourceTabID() const override { return kInvalidTabID; }
+
void AppendEntry(std::unique_ptr<sessions::SerializedNavigationEntry> entry) {
entries_.push_back(std::move(entry));
}
@@ -322,6 +324,8 @@ class PlaceholderTabDelegate : public SyncedTabDelegate {
return false;
}
+ SessionID::id_type GetSourceTabID() const override { return kInvalidTabID; }
+
private:
SessionID::id_type session_id_;
int sync_id_;
@@ -370,7 +374,7 @@ class TestSyncedWindowDelegate : public SyncedWindowDelegate {
SessionID::id_type GetTabIdAt(int index) const override {
SyncedTabDelegate* delegate = GetTabAt(index);
if (!delegate)
- return TabNodePool::kInvalidTabID;
+ return kInvalidTabID;
return delegate->GetSessionId();
}
@@ -512,9 +516,10 @@ class SessionsSyncManagerTest : public testing::Test {
base::MakeUnique<SyncSessionsClientShim>(&window_getter_);
sync_prefs_ =
base::MakeUnique<syncer::SyncPrefs>(sync_client_->GetPrefService());
+ router_ = base::MakeUnique<DummyRouter>();
manager_ = base::MakeUnique<SessionsSyncManager>(
sessions_client_shim(), sync_prefs_.get(), local_device_.get(),
- std::unique_ptr<LocalSessionEventRouter>(NewDummyRouter()),
+ router_.get(),
base::Bind(&SessionNotificationObserver::NotifyOfUpdate,
base::Unretained(&observer_)),
base::Bind(&SessionNotificationObserver::NotifyOfRefresh,
@@ -546,12 +551,6 @@ class SessionsSyncManagerTest : public testing::Test {
}
SyncedWindowDelegatesGetter* window_getter() { return &window_getter_; }
- std::unique_ptr<LocalSessionEventRouter> NewDummyRouter() {
- std::unique_ptr<DummyRouter> router(new DummyRouter());
- router_ = router.get();
- return std::unique_ptr<LocalSessionEventRouter>(std::move(router));
- }
-
void InitWithSyncDataTakeOutput(const SyncDataList& initial_data,
SyncChangeList* output) {
test_processor_ = new TestSyncChangeProcessor(output);
@@ -728,7 +727,7 @@ class SessionsSyncManagerTest : public testing::Test {
std::unique_ptr<SyncSessionsClientShim> sessions_client_shim_;
std::unique_ptr<syncer::SyncPrefs> sync_prefs_;
SessionNotificationObserver observer_;
- DummyRouter* router_ = nullptr;
+ std::unique_ptr<DummyRouter> router_;
std::unique_ptr<SessionsSyncManager> manager_;
SessionSyncTestHelper helper_;
TestSyncChangeProcessor* test_processor_ = nullptr;
@@ -764,9 +763,10 @@ TEST_F(SessionsSyncManagerTest, PopulateSessionWindow) {
manager()->session_tracker_.PutWindowInSession(kTag1, 0);
manager()->BuildSyncedSessionFromSpecifics(kTag1, window_s, base::Time(),
session->windows[0].get());
- ASSERT_EQ(1U, session->windows[0]->tabs.size());
- ASSERT_EQ(1, session->windows[0]->selected_tab_index);
- ASSERT_EQ(sessions::SessionWindow::TYPE_TABBED, session->windows[0]->type);
+ ASSERT_EQ(1U, session->windows[0]->wrapped_window.tabs.size());
+ ASSERT_EQ(1, session->windows[0]->wrapped_window.selected_tab_index);
+ ASSERT_EQ(sessions::SessionWindow::TYPE_TABBED,
+ session->windows[0]->wrapped_window.type);
ASSERT_EQ(1U, manager()->session_tracker_.num_synced_sessions());
ASSERT_EQ(1U, manager()->session_tracker_.num_synced_tabs(kTag1));
}
@@ -1121,8 +1121,12 @@ TEST_F(SessionsSyncManagerTest, UpdatesAfterMixedMerge) {
std::vector<const SyncedSession*> foreign_sessions;
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(1U, foreign_sessions.size());
- ASSERT_EQ(4U, foreign_sessions[0]->windows.find(0)->second->tabs.size());
- ASSERT_EQ(4U, foreign_sessions[0]->windows.find(1)->second->tabs.size());
+ ASSERT_EQ(
+ 4U,
+ foreign_sessions[0]->windows.find(0)->second->wrapped_window.tabs.size());
+ ASSERT_EQ(
+ 4U,
+ foreign_sessions[0]->windows.find(1)->second->wrapped_window.tabs.size());
helper()->VerifySyncedSession(kTag1, meta1_reference, *(foreign_sessions[0]));
// Add a new foreign session.
@@ -1140,7 +1144,9 @@ TEST_F(SessionsSyncManagerTest, UpdatesAfterMixedMerge) {
std::vector<std::vector<SessionID::id_type>> meta2_reference;
meta2_reference.push_back(tag2_tab_list);
ASSERT_EQ(2U, foreign_sessions.size());
- ASSERT_EQ(2U, foreign_sessions[1]->windows.find(0)->second->tabs.size());
+ ASSERT_EQ(
+ 2U,
+ foreign_sessions[1]->windows.find(0)->second->wrapped_window.tabs.size());
helper()->VerifySyncedSession(kTag2, meta2_reference, *(foreign_sessions[1]));
foreign_sessions.clear();
@@ -1160,7 +1166,9 @@ TEST_F(SessionsSyncManagerTest, UpdatesAfterMixedMerge) {
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(2U, foreign_sessions.size());
- ASSERT_EQ(3U, foreign_sessions[0]->windows.find(0)->second->tabs.size());
+ ASSERT_EQ(
+ 3U,
+ foreign_sessions[0]->windows.find(0)->second->wrapped_window.tabs.size());
helper()->VerifySyncedSession(kTag1, meta1_reference, *(foreign_sessions[0]));
}
@@ -1273,8 +1281,12 @@ TEST_F(SessionsSyncManagerTest, WriteForeignSessionToNodeMissingTabs) {
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
ASSERT_EQ(1U, foreign_sessions.size());
ASSERT_EQ(2U, foreign_sessions[0]->windows.size());
- ASSERT_EQ(4U, foreign_sessions[0]->windows.find(0)->second->tabs.size());
- ASSERT_EQ(4U, foreign_sessions[0]->windows.find(1)->second->tabs.size());
+ ASSERT_EQ(
+ 4U,
+ foreign_sessions[0]->windows.find(0)->second->wrapped_window.tabs.size());
+ ASSERT_EQ(
+ 4U,
+ foreign_sessions[0]->windows.find(1)->second->wrapped_window.tabs.size());
// Close the second window.
meta.mutable_header()->clear_window();
@@ -2142,7 +2154,7 @@ TEST_F(SessionsSyncManagerTest, ReceiveDuplicateUnassociatedTabs) {
ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
const std::vector<std::unique_ptr<sessions::SessionTab>>& window_tabs =
- foreign_sessions[0]->windows.find(0)->second->tabs;
+ foreign_sessions[0]->windows.find(0)->second->wrapped_window.tabs;
ASSERT_EQ(4U, window_tabs.size());
// The first one is from the original set of tabs.
ASSERT_EQ(1, window_tabs[0]->tab_visual_index);
diff --git a/chromium/components/sync_sessions/sync_sessions_client.h b/chromium/components/sync_sessions/sync_sessions_client.h
index fab928ffeff..e8b4874a784 100644
--- a/chromium/components/sync_sessions/sync_sessions_client.h
+++ b/chromium/components/sync_sessions/sync_sessions_client.h
@@ -52,8 +52,7 @@ class SyncSessionsClient {
// Returns a LocalSessionEventRouter instance that is customized for the
// embedder's context.
- virtual std::unique_ptr<LocalSessionEventRouter>
- GetLocalSessionEventRouter() = 0;
+ virtual LocalSessionEventRouter* GetLocalSessionEventRouter() = 0;
// TODO(zea): add getters for the history and favicon services for the favicon
// cache to consume once it's componentized.
diff --git a/chromium/components/sync_sessions/sync_sessions_metrics.cc b/chromium/components/sync_sessions/sync_sessions_metrics.cc
index 1242b095e32..b5cf37e3473 100644
--- a/chromium/components/sync_sessions/sync_sessions_metrics.cc
+++ b/chromium/components/sync_sessions/sync_sessions_metrics.cc
@@ -9,7 +9,6 @@
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics.h"
#include "base/time/time.h"
#include "components/sessions/core/session_types.h"
#include "components/sync_sessions/sessions_sync_manager.h"
@@ -51,7 +50,7 @@ base::Time SyncSessionsMetrics::MaxTabTimestamp(
break;
}
for (const auto& key_value : session->windows) {
- for (const auto& tab : key_value.second->tabs) {
+ for (const auto& tab : key_value.second->wrapped_window.tabs) {
best = std::max(best, tab->timestamp);
}
}
diff --git a/chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc b/chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc
index f351d3de168..987e0a52c79 100644
--- a/chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc
+++ b/chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc
@@ -70,17 +70,21 @@ class SyncSessionsMetricsTest : public ::testing::Test {
if (sessions_[tabIndex]->windows.find(windowIndex) ==
sessions_[tabIndex]->windows.end()) {
sessions_[tabIndex]->windows[windowIndex] =
- base::MakeUnique<SessionWindow>();
+ base::MakeUnique<SyncedSessionWindow>();
}
sessions_[tabIndex]->modified_time =
std::max(sessions_[tabIndex]->modified_time, timestamp);
- sessions_[tabIndex]->windows[windowIndex]->timestamp = std::max(
- sessions_[tabIndex]->windows[windowIndex]->timestamp, timestamp);
- sessions_[tabIndex]->windows[windowIndex]->tabs.push_back(
+ sessions_[tabIndex]->windows[windowIndex]->wrapped_window.timestamp =
+ std::max(
+ sessions_[tabIndex]->windows[windowIndex]->wrapped_window.timestamp,
+ timestamp);
+ sessions_[tabIndex]->windows[windowIndex]->wrapped_window.tabs.push_back(
base::MakeUnique<SessionTab>());
- sessions_[tabIndex]->windows[windowIndex]->tabs.back()->timestamp =
- timestamp;
+ sessions_[tabIndex]
+ ->windows[windowIndex]
+ ->wrapped_window.tabs.back()
+ ->timestamp = timestamp;
}
// Removes the last tab at the given indexes. The idexes provided should be
@@ -89,9 +93,11 @@ class SyncSessionsMetricsTest : public ::testing::Test {
void PopTab(size_t tabIndex, int windowIndex, Time timestamp) {
sessions_[tabIndex]->modified_time =
std::max(sessions_[tabIndex]->modified_time, timestamp);
- sessions_[tabIndex]->windows[windowIndex]->timestamp = std::max(
- sessions_[tabIndex]->windows[windowIndex]->timestamp, timestamp);
- sessions_[tabIndex]->windows[windowIndex]->tabs.pop_back();
+ sessions_[tabIndex]->windows[windowIndex]->wrapped_window.timestamp =
+ std::max(
+ sessions_[tabIndex]->windows[windowIndex]->wrapped_window.timestamp,
+ timestamp);
+ sessions_[tabIndex]->windows[windowIndex]->wrapped_window.tabs.pop_back();
}
// Runs MaxTabTimestamp on the current sessions data.
diff --git a/chromium/components/sync_sessions/synced_session.cc b/chromium/components/sync_sessions/synced_session.cc
index c22e1728d20..0cba248c8f6 100644
--- a/chromium/components/sync_sessions/synced_session.cc
+++ b/chromium/components/sync_sessions/synced_session.cc
@@ -6,16 +6,32 @@
namespace sync_sessions {
+SyncedSessionWindow::SyncedSessionWindow() {}
+
+SyncedSessionWindow::~SyncedSessionWindow() {}
+
+sync_pb::SessionWindow SyncedSessionWindow::ToSessionWindowProto() const {
+ sync_pb::SessionWindow sync_data;
+ sync_data.set_browser_type(window_type);
+ sync_data.set_window_id(wrapped_window.window_id.id());
+ sync_data.set_selected_tab_index(wrapped_window.selected_tab_index);
+
+ for (const auto& tab : wrapped_window.tabs)
+ sync_data.add_tab(tab->tab_id.id());
+
+ return sync_data;
+}
+
SyncedSession::SyncedSession()
: session_tag("invalid"), device_type(TYPE_UNSET) {}
SyncedSession::~SyncedSession() {}
-sync_pb::SessionHeader SyncedSession::ToSessionHeader() const {
+sync_pb::SessionHeader SyncedSession::ToSessionHeaderProto() const {
sync_pb::SessionHeader header;
for (const auto& window_pair : windows) {
sync_pb::SessionWindow* w = header.add_window();
- w->CopyFrom(window_pair.second->ToSyncData());
+ w->CopyFrom(window_pair.second->ToSessionWindowProto());
}
header.set_client_name(session_name);
switch (device_type) {
diff --git a/chromium/components/sync_sessions/synced_session.h b/chromium/components/sync_sessions/synced_session.h
index e0defd96623..c3471ae20d4 100644
--- a/chromium/components/sync_sessions/synced_session.h
+++ b/chromium/components/sync_sessions/synced_session.h
@@ -16,12 +16,26 @@
#include "components/sessions/core/session_types.h"
#include "components/sync/protocol/session_specifics.pb.h"
-namespace sessions {
-struct SessionWindow;
-}
-
namespace sync_sessions {
+// A Sync wrapper for a SessionWindow.
+struct SyncedSessionWindow {
+ SyncedSessionWindow();
+ ~SyncedSessionWindow();
+
+ // Convert this object into its sync protocol buffer equivalent.
+ sync_pb::SessionWindow ToSessionWindowProto() const;
+
+ // Type of the window. See session_specifics.proto.
+ sync_pb::SessionWindow::BrowserType window_type;
+
+ // The SessionWindow this object wraps.
+ sessions::SessionWindow wrapped_window;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SyncedSessionWindow);
+};
+
// Defines a synced session for use by session sync. A synced session is a
// list of windows along with a unique session identifer (tag) and meta-data
// about the device being synced.
@@ -55,8 +69,7 @@ struct SyncedSession {
base::Time modified_time;
// Map of windows that make up this session.
- std::map<SessionID::id_type, std::unique_ptr<sessions::SessionWindow>>
- windows;
+ std::map<SessionID::id_type, std::unique_ptr<SyncedSessionWindow>> windows;
// A tab node id is part of the identifier for the sync tab objects. Tab node
// ids are not used for interacting with the model/browser tabs. However, when
@@ -95,7 +108,7 @@ struct SyncedSession {
// Convert this object to its protocol buffer equivalent. Shallow conversion,
// does not create SessionTab protobufs.
- sync_pb::SessionHeader ToSessionHeader() const;
+ sync_pb::SessionHeader ToSessionHeaderProto() const;
private:
DISALLOW_COPY_AND_ASSIGN(SyncedSession);
diff --git a/chromium/components/sync_sessions/synced_session_tracker.cc b/chromium/components/sync_sessions/synced_session_tracker.cc
index 87ee848bc5d..94e6e9ff386 100644
--- a/chromium/components/sync_sessions/synced_session_tracker.cc
+++ b/chromium/components/sync_sessions/synced_session_tracker.cc
@@ -10,7 +10,7 @@
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/sync_sessions/sync_sessions_client.h"
-
+#include "components/sync_sessions/synced_tab_delegate.h"
namespace sync_sessions {
namespace {
@@ -35,7 +35,8 @@ bool IsPresentable(SyncSessionsClient* sessions_client,
SyncedSession* foreign_session) {
for (auto iter = foreign_session->windows.begin();
iter != foreign_session->windows.end(); ++iter) {
- if (ShouldSyncSessionWindow(sessions_client, *(iter->second))) {
+ if (ShouldSyncSessionWindow(sessions_client,
+ iter->second->wrapped_window)) {
return true;
}
}
@@ -83,7 +84,7 @@ bool SyncedSessionTracker::LookupSessionWindows(
if (iter == synced_session_map_.end())
return false;
for (const auto& window_pair : iter->second->windows)
- windows->push_back(window_pair.second.get());
+ windows->push_back(&window_pair.second->wrapped_window);
return true;
}
@@ -92,7 +93,7 @@ bool SyncedSessionTracker::LookupSessionTab(
const std::string& tag,
SessionID::id_type tab_id,
const sessions::SessionTab** tab) const {
- if (tab_id == TabNodePool::kInvalidTabID)
+ if (tab_id == kInvalidTabID)
return false;
DCHECK(tab);
@@ -181,11 +182,11 @@ void SyncedSessionTracker::ResetSessionTracking(
for (auto& window_pair : session->windows) {
// First unmap the tabs in the window.
- for (auto& tab : window_pair.second->tabs) {
+ for (auto& tab : window_pair.second->wrapped_window.tabs) {
SessionID::id_type tab_id = tab->tab_id.id();
unmapped_tabs_[session_tag][tab_id] = std::move(tab);
}
- window_pair.second->tabs.clear();
+ window_pair.second->wrapped_window.tabs.clear();
// Then unmap the window itself.
unmapped_windows_[session_tag][window_pair.first] =
@@ -220,7 +221,7 @@ bool SyncedSessionTracker::IsTabUnmappedForTesting(SessionID::id_type tab_id) {
void SyncedSessionTracker::PutWindowInSession(const std::string& session_tag,
SessionID::id_type window_id) {
- std::unique_ptr<sessions::SessionWindow> window;
+ std::unique_ptr<SyncedSessionWindow> window;
auto iter = unmapped_windows_[session_tag].find(window_id);
if (iter != unmapped_windows_[session_tag].end()) {
@@ -232,14 +233,14 @@ void SyncedSessionTracker::PutWindowInSession(const std::string& session_tag,
: session_tag);
} else {
// Create the window.
- window = base::MakeUnique<sessions::SessionWindow>();
- window->window_id.set_id(window_id);
+ window = base::MakeUnique<SyncedSessionWindow>();
+ window->wrapped_window.window_id.set_id(window_id);
synced_window_map_[session_tag][window_id] = window.get();
DVLOG(1) << "Putting new window " << window_id << " at " << window.get()
<< "in " << (session_tag == local_session_tag_ ? "local session"
: session_tag);
}
- DCHECK_EQ(window->window_id.id(), window_id);
+ DCHECK_EQ(window->wrapped_window.window_id.id(), window_id);
DCHECK(GetSession(session_tag)->windows.end() ==
GetSession(session_tag)->windows.find(window_id));
GetSession(session_tag)->windows[window_id] = std::move(window);
@@ -273,14 +274,14 @@ void SyncedSessionTracker::PutTabInWindow(const std::string& session_tag,
// window.
for (auto& window_iter_pair : GetSession(session_tag)->windows) {
auto tab_iter = std::find_if(
- window_iter_pair.second->tabs.begin(),
- window_iter_pair.second->tabs.end(),
+ 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;
});
- if (tab_iter != window_iter_pair.second->tabs.end()) {
+ if (tab_iter != window_iter_pair.second->wrapped_window.tabs.end()) {
tab = std::move(*tab_iter);
- window_iter_pair.second->tabs.erase(tab_iter);
+ window_iter_pair.second->wrapped_window.tabs.erase(tab_iter);
DVLOG(1) << "Moving tab " << tab_id << " from window "
<< window_iter_pair.first << " to " << window_id;
@@ -297,8 +298,9 @@ void SyncedSessionTracker::PutTabInWindow(const std::string& session_tag,
DVLOG(1) << " - tab " << tab_id << " added to window " << window_id;
DCHECK(GetSession(session_tag)->windows.find(window_id) !=
GetSession(session_tag)->windows.end());
- auto& window_tabs = GetSession(session_tag)->windows[window_id]->tabs;
- window_tabs.push_back(std::move(tab));
+ GetSession(session_tag)
+ ->windows[window_id]
+ ->wrapped_window.tabs.push_back(std::move(tab));
}
void SyncedSessionTracker::OnTabNodeSeen(const std::string& session_tag,
@@ -382,15 +384,14 @@ bool SyncedSessionTracker::GetTabNodeFromLocalTabId(SessionID::id_type tab_id,
bool SyncedSessionTracker::IsLocalTabNodeAssociated(int tab_node_id) {
if (tab_node_id == TabNodePool::kInvalidTabNodeID)
return false;
- return local_tab_pool_.GetTabIdFromTabNodeId(tab_node_id) !=
- TabNodePool::kInvalidTabID;
+ return local_tab_pool_.GetTabIdFromTabNodeId(tab_node_id) != kInvalidTabID;
}
void SyncedSessionTracker::ReassociateLocalTab(int tab_node_id,
SessionID::id_type new_tab_id) {
DCHECK(!local_session_tag_.empty());
DCHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id);
- DCHECK_NE(TabNodePool::kInvalidTabID, new_tab_id);
+ DCHECK_NE(kInvalidTabID, new_tab_id);
SessionID::id_type old_tab_id =
local_tab_pool_.GetTabIdFromTabNodeId(tab_node_id);
@@ -399,7 +400,7 @@ void SyncedSessionTracker::ReassociateLocalTab(int tab_node_id,
sessions::SessionTab* tab_ptr = nullptr;
auto old_tab_iter = synced_tab_map_[local_session_tag_].find(old_tab_id);
- if (old_tab_id != TabNodePool::kInvalidTabID &&
+ if (old_tab_id != kInvalidTabID &&
old_tab_iter != synced_tab_map_[local_session_tag_].end()) {
tab_ptr = old_tab_iter->second;
// Remove the tab from the synced tab map under the old id.
@@ -412,7 +413,7 @@ void SyncedSessionTracker::ReassociateLocalTab(int tab_node_id,
// If the old tab is unmapped, update the tab id under which it is indexed.
auto unmapped_tabs_iter = unmapped_tabs_[local_session_tag_].find(old_tab_id);
- if (old_tab_id != TabNodePool::kInvalidTabID &&
+ if (old_tab_id != kInvalidTabID &&
unmapped_tabs_iter != unmapped_tabs_[local_session_tag_].end()) {
std::unique_ptr<sessions::SessionTab> tab =
std::move(unmapped_tabs_iter->second);
@@ -422,7 +423,7 @@ void SyncedSessionTracker::ReassociateLocalTab(int tab_node_id,
}
// Update the tab id.
- if (old_tab_id != TabNodePool::kInvalidTabID) {
+ if (old_tab_id != kInvalidTabID) {
DVLOG(1) << "Remapped tab " << old_tab_id << " with node " << tab_node_id
<< " to tab " << new_tab_id;
} else {
diff --git a/chromium/components/sync_sessions/synced_session_tracker.h b/chromium/components/sync_sessions/synced_session_tracker.h
index ccd47839e24..506d3d0cbee 100644
--- a/chromium/components/sync_sessions/synced_session_tracker.h
+++ b/chromium/components/sync_sessions/synced_session_tracker.h
@@ -219,7 +219,7 @@ class SyncedSessionTracker {
// Map: session tag -> (tab/window -> SessionTab*/SessionWindow*)
std::map<std::string, std::map<SessionID::id_type, sessions::SessionTab*>>
synced_tab_map_;
- std::map<std::string, std::map<SessionID::id_type, sessions::SessionWindow*>>
+ std::map<std::string, std::map<SessionID::id_type, SyncedSessionWindow*>>
synced_window_map_;
// The collection that owns the SyncedSessions, and transitively, all of the
@@ -237,9 +237,8 @@ class SyncedSessionTracker {
std::map<std::string,
std::map<SessionID::id_type, std::unique_ptr<sessions::SessionTab>>>
unmapped_tabs_;
- std::map<
- std::string,
- std::map<SessionID::id_type, std::unique_ptr<sessions::SessionWindow>>>
+ std::map<std::string,
+ std::map<SessionID::id_type, std::unique_ptr<SyncedSessionWindow>>>
unmapped_windows_;
// The tag for this machine's local session, so we can distinguish the foreign
diff --git a/chromium/components/sync_sessions/synced_session_tracker_unittest.cc b/chromium/components/sync_sessions/synced_session_tracker_unittest.cc
index 0728a369cbd..9da19516ab0 100644
--- a/chromium/components/sync_sessions/synced_session_tracker_unittest.cc
+++ b/chromium/components/sync_sessions/synced_session_tracker_unittest.cc
@@ -9,6 +9,7 @@
#include "base/strings/utf_string_conversions.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
#include "components/sync_sessions/fake_sync_sessions_client.h"
+#include "components/sync_sessions/synced_tab_delegate.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace sync_sessions {
@@ -68,9 +69,9 @@ TEST_F(SyncedSessionTrackerTest, PutTabInWindow) {
GetTracker()->PutTabInWindow(kTag, 10, 15); // win id 10, tab id 15
SyncedSession* session = GetTracker()->GetSession(kTag);
ASSERT_EQ(1U, session->windows.size());
- ASSERT_EQ(1U, session->windows[10]->tabs.size());
+ ASSERT_EQ(1U, session->windows[10]->wrapped_window.tabs.size());
ASSERT_EQ(GetTracker()->GetTab(kTag, 15),
- session->windows[10]->tabs[0].get());
+ session->windows[10]->wrapped_window.tabs[0].get());
// Should clean up memory on its own.
}
@@ -124,8 +125,7 @@ TEST_F(SyncedSessionTrackerTest, LookupSessionWindows) {
TEST_F(SyncedSessionTrackerTest, LookupSessionTab) {
const sessions::SessionTab* tab;
- ASSERT_FALSE(
- GetTracker()->LookupSessionTab(kTag, TabNodePool::kInvalidTabID, &tab));
+ ASSERT_FALSE(GetTracker()->LookupSessionTab(kTag, kInvalidTabID, &tab));
ASSERT_FALSE(GetTracker()->LookupSessionTab(kTag, 5, &tab));
GetTracker()->GetSession(kTag);
GetTracker()->PutWindowInSession(kTag, 0);
@@ -295,8 +295,8 @@ TEST_F(SyncedSessionTrackerTest, SessionTracking) {
GetTracker()->PutTabInWindow(kTag, 1, 4);
GetTracker()->PutTabInWindow(kTag, 1, 5);
ASSERT_EQ(2U, session1->windows.size());
- ASSERT_EQ(2U, session1->windows[0]->tabs.size());
- ASSERT_EQ(2U, session1->windows[1]->tabs.size());
+ ASSERT_EQ(2U, session1->windows[0]->wrapped_window.tabs.size());
+ ASSERT_EQ(2U, session1->windows[1]->wrapped_window.tabs.size());
ASSERT_EQ(6U, GetTracker()->num_synced_tabs(kTag));
// Create a session that should not be affected.
@@ -304,7 +304,7 @@ TEST_F(SyncedSessionTrackerTest, SessionTracking) {
GetTracker()->PutWindowInSession(kTag2, 2);
GetTracker()->PutTabInWindow(kTag2, 2, 1);
ASSERT_EQ(1U, session2->windows.size());
- ASSERT_EQ(1U, session2->windows[2]->tabs.size());
+ ASSERT_EQ(1U, session2->windows[2]->wrapped_window.tabs.size());
ASSERT_EQ(1U, GetTracker()->num_synced_tabs(kTag2));
// Reset tracking and get the current windows/tabs.
@@ -328,9 +328,9 @@ TEST_F(SyncedSessionTrackerTest, SessionTracking) {
// Verify that only those parts of the session not owned have been removed.
ASSERT_EQ(1U, session1->windows.size());
- ASSERT_EQ(4U, session1->windows[0]->tabs.size());
+ ASSERT_EQ(4U, session1->windows[0]->wrapped_window.tabs.size());
ASSERT_EQ(1U, session2->windows.size());
- ASSERT_EQ(1U, session2->windows[2]->tabs.size());
+ ASSERT_EQ(1U, session2->windows[2]->wrapped_window.tabs.size());
ASSERT_EQ(2U, GetTracker()->num_synced_sessions());
ASSERT_EQ(4U, GetTracker()->num_synced_tabs(kTag));
ASSERT_EQ(1U, GetTracker()->num_synced_tabs(kTag2));
@@ -440,9 +440,9 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabMapped) {
EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab1));
SyncedSession* session = GetTracker()->GetSession(kTag);
ASSERT_EQ(1U, session->windows.size());
- ASSERT_EQ(1U, session->windows[kWindow1]->tabs.size());
+ ASSERT_EQ(1U, session->windows[kWindow1]->wrapped_window.tabs.size());
ASSERT_EQ(GetTracker()->GetTab(kTag, kTab1),
- session->windows[kWindow1]->tabs[0].get());
+ session->windows[kWindow1]->wrapped_window.tabs[0].get());
// Then reassociate with a new tab id.
GetTracker()->ReassociateLocalTab(kTabNode, kTab2);
@@ -462,7 +462,7 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabMapped) {
// Now that it's been mapped, it should be accessible both via the
// GetSession as well as the GetTab.
ASSERT_EQ(GetTracker()->GetTab(kTag, kTab2),
- session->windows[kWindow1]->tabs[0].get());
+ session->windows[kWindow1]->wrapped_window.tabs[0].get());
ASSERT_EQ(session->tab_node_ids.size(),
session->tab_node_ids.count(kTabNode));
ASSERT_EQ(1U, GetTabNodePool()->Capacity());
@@ -487,9 +487,9 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabMappedTwice) {
EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab1));
SyncedSession* session = GetTracker()->GetSession(kTag);
ASSERT_EQ(1U, session->windows.size());
- ASSERT_EQ(1U, session->windows[kWindow1]->tabs.size());
+ ASSERT_EQ(1U, session->windows[kWindow1]->wrapped_window.tabs.size());
EXPECT_EQ(GetTracker()->GetTab(kTag, kTab1),
- session->windows[kWindow1]->tabs[0].get());
+ session->windows[kWindow1]->wrapped_window.tabs[0].get());
// Then reassociate with a new tab id.
GetTracker()->ReassociateLocalTab(kTabNode, kTab2);
@@ -516,7 +516,7 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabMappedTwice) {
// Now that it's been mapped, it should be accessible both via the
// GetSession as well as the GetTab.
EXPECT_EQ(GetTracker()->GetTab(kTag, kTab2),
- session->windows[kWindow1]->tabs[1].get());
+ session->windows[kWindow1]->wrapped_window.tabs[1].get());
EXPECT_EQ(session->tab_node_ids.size(),
session->tab_node_ids.count(kTabNode));
EXPECT_EQ(1U, GetTabNodePool()->Capacity());
@@ -554,7 +554,7 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabUnmapped) {
// GetSession as well as GetTab.
SyncedSession* session = GetTracker()->GetSession(kTag);
ASSERT_EQ(GetTracker()->GetTab(kTag, kTab2),
- session->windows[kWindow1]->tabs[0].get());
+ session->windows[kWindow1]->wrapped_window.tabs[0].get());
ASSERT_EQ(session->tab_node_ids.size(),
session->tab_node_ids.count(kTabNode));
ASSERT_EQ(1U, GetTabNodePool()->Capacity());
diff --git a/chromium/components/sync_sessions/synced_tab_delegate.h b/chromium/components/sync_sessions/synced_tab_delegate.h
index 9781578c777..c69de8755d8 100644
--- a/chromium/components/sync_sessions/synced_tab_delegate.h
+++ b/chromium/components/sync_sessions/synced_tab_delegate.h
@@ -20,6 +20,8 @@ class SyncSessionsClient;
namespace sync_sessions {
+enum InvalidTab { kInvalidTabID = -1 };
+
// A SyncedTabDelegate is used to insulate the sync code from depending
// directly on WebContents, NavigationController, and the extensions TabHelper.
class SyncedTabDelegate {
@@ -31,6 +33,10 @@ class SyncedTabDelegate {
virtual SessionID::id_type GetSessionId() const = 0;
virtual bool IsBeingDestroyed() const = 0;
+ // Get the tab id of the tab responsible for opening this tab, if applicable.
+ // Returns kUnknownTabID(-1) if no such tab relationship is known.
+ virtual SessionID::id_type GetSourceTabID() const = 0;
+
// Method derived from extensions TabHelper.
virtual std::string GetExtensionAppId() const = 0;
diff --git a/chromium/components/sync_sessions/tab_node_pool.cc b/chromium/components/sync_sessions/tab_node_pool.cc
index f187d23dc76..1b4c1f88f62 100644
--- a/chromium/components/sync_sessions/tab_node_pool.cc
+++ b/chromium/components/sync_sessions/tab_node_pool.cc
@@ -10,6 +10,7 @@
#include "components/sync/base/model_type.h"
#include "components/sync/protocol/session_specifics.pb.h"
#include "components/sync/protocol/sync.pb.h"
+#include "components/sync_sessions/synced_tab_delegate.h"
namespace sync_sessions {
diff --git a/chromium/components/sync_sessions/tab_node_pool.h b/chromium/components/sync_sessions/tab_node_pool.h
index 365edc46328..84f2c347b66 100644
--- a/chromium/components/sync_sessions/tab_node_pool.h
+++ b/chromium/components/sync_sessions/tab_node_pool.h
@@ -32,7 +32,6 @@ class TabNodePool {
public:
TabNodePool();
~TabNodePool();
- enum InvalidTab { kInvalidTabID = -1 };
// If free nodes > kFreeNodesHighWatermark, delete all free nodes until
// free nodes <= kFreeNodesLowWatermark.
diff --git a/chromium/components/sync_wifi/wifi_config_delegate_chromeos_unittest.cc b/chromium/components/sync_wifi/wifi_config_delegate_chromeos_unittest.cc
index eb8d347f6ba..1f142a16ce3 100644
--- a/chromium/components/sync_wifi/wifi_config_delegate_chromeos_unittest.cc
+++ b/chromium/components/sync_wifi/wifi_config_delegate_chromeos_unittest.cc
@@ -74,6 +74,12 @@ class FakeManagedNetworkConfigurationHandler
const ErrorCallback& error_callback) const override {
NOTIMPLEMENTED();
}
+ void RemoveConfigurationFromCurrentProfile(
+ const std::string& service_path,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) const override {
+ NOTIMPLEMENTED();
+ }
void SetPolicy(::onc::ONCSource onc_source,
const std::string& userhash,
const base::ListValue& network_configs_onc,
diff --git a/chromium/components/sync_wifi/wifi_credential.cc b/chromium/components/sync_wifi/wifi_credential.cc
index a6a0e389ec0..0337ee8188f 100644
--- a/chromium/components/sync_wifi/wifi_credential.cc
+++ b/chromium/components/sync_wifi/wifi_credential.cc
@@ -55,17 +55,17 @@ std::unique_ptr<base::DictionaryValue> WifiCredential::ToOncProperties() const {
std::unique_ptr<base::DictionaryValue> onc_properties(
new base::DictionaryValue());
onc_properties->Set(onc::toplevel_config::kType,
- new base::StringValue(onc::network_type::kWiFi));
+ new base::Value(onc::network_type::kWiFi));
// TODO(quiche): Switch to the HexSSID property, once ONC fully supports it.
// crbug.com/432546.
onc_properties->Set(onc::network_config::WifiProperty(onc::wifi::kSSID),
- new base::StringValue(ssid_utf8));
+ new base::Value(ssid_utf8));
onc_properties->Set(onc::network_config::WifiProperty(onc::wifi::kSecurity),
- new base::StringValue(onc_security));
+ new base::Value(onc_security));
if (WifiSecurityClassSupportsPassphrases(security_class())) {
onc_properties->Set(
onc::network_config::WifiProperty(onc::wifi::kPassphrase),
- new base::StringValue(passphrase()));
+ new base::Value(passphrase()));
}
return onc_properties;
}
diff --git a/chromium/components/task_scheduler_util/browser/initialization.cc b/chromium/components/task_scheduler_util/browser/initialization.cc
index 29223f5656d..c6e492bf2ea 100644
--- a/chromium/components/task_scheduler_util/browser/initialization.cc
+++ b/chromium/components/task_scheduler_util/browser/initialization.cc
@@ -8,11 +8,8 @@
#include <string>
#include "base/command_line.h"
-#include "base/logging.h"
#include "base/task_scheduler/scheduler_worker_params.h"
#include "base/task_scheduler/switches.h"
-#include "base/task_scheduler/task_traits.h"
-#include "base/threading/platform_thread.h"
#include "base/threading/sequenced_worker_pool.h"
#include "components/task_scheduler_util/common/variations_util.h"
#include "components/variations/variations_associated_data.h"
@@ -23,51 +20,16 @@ namespace {
constexpr char kFieldTrialName[] = "BrowserScheduler";
-enum WorkerPoolType : size_t {
- BACKGROUND = 0,
- BACKGROUND_BLOCKING,
- FOREGROUND,
- FOREGROUND_BLOCKING,
- WORKER_POOL_COUNT // Always last.
-};
-
} // namespace
-std::vector<base::SchedulerWorkerPoolParams>
-GetBrowserWorkerPoolParamsFromVariations() {
- using ThreadPriority = base::ThreadPriority;
-
+std::unique_ptr<base::TaskScheduler::InitParams>
+GetBrowserTaskSchedulerInitParamsFromVariations() {
std::map<std::string, std::string> variation_params;
if (!::variations::GetVariationParams(kFieldTrialName, &variation_params))
- return std::vector<base::SchedulerWorkerPoolParams>();
-
- std::vector<SchedulerImmutableWorkerPoolParams> immutable_worker_pool_params;
- DCHECK_EQ(BACKGROUND, immutable_worker_pool_params.size());
- immutable_worker_pool_params.emplace_back("Background",
- ThreadPriority::BACKGROUND);
- DCHECK_EQ(BACKGROUND_BLOCKING, immutable_worker_pool_params.size());
- immutable_worker_pool_params.emplace_back("BackgroundBlocking",
- ThreadPriority::BACKGROUND);
- DCHECK_EQ(FOREGROUND, immutable_worker_pool_params.size());
- immutable_worker_pool_params.emplace_back("Foreground",
- ThreadPriority::NORMAL);
- // Tasks posted to SequencedWorkerPool or BrowserThreadImpl may be redirected
- // to this pool. Since COM STA is initialized in these environments, it must
- // also be initialized in this pool.
- DCHECK_EQ(FOREGROUND_BLOCKING, immutable_worker_pool_params.size());
- immutable_worker_pool_params.emplace_back(
- "ForegroundBlocking", ThreadPriority::NORMAL,
- base::SchedulerBackwardCompatibility::INIT_COM_STA);
-
- return GetWorkerPoolParams(immutable_worker_pool_params, variation_params);
-}
+ return nullptr;
-size_t BrowserWorkerPoolIndexForTraits(const base::TaskTraits& traits) {
- const bool is_background =
- traits.priority() == base::TaskPriority::BACKGROUND;
- if (traits.may_block() || traits.with_base_sync_primitives())
- return is_background ? BACKGROUND_BLOCKING : FOREGROUND_BLOCKING;
- return is_background ? BACKGROUND : FOREGROUND;
+ return GetTaskSchedulerInitParams(
+ "", variation_params, base::SchedulerBackwardCompatibility::INIT_COM_STA);
}
void MaybePerformBrowserTaskSchedulerRedirection() {
diff --git a/chromium/components/task_scheduler_util/browser/initialization.h b/chromium/components/task_scheduler_util/browser/initialization.h
index d4584eeca4a..46ad21860f2 100644
--- a/chromium/components/task_scheduler_util/browser/initialization.h
+++ b/chromium/components/task_scheduler_util/browser/initialization.h
@@ -5,26 +5,16 @@
#ifndef COMPONENTS_TASK_SCHEDULER_UTIL_BROWSER_INITIALIZATION_H_
#define COMPONENTS_TASK_SCHEDULER_UTIL_BROWSER_INITIALIZATION_H_
-#include <stddef.h>
+#include <memory>
-#include <vector>
-
-#include "base/task_scheduler/scheduler_worker_pool_params.h"
-
-namespace base {
-class TaskTraits;
-}
+#include "base/task_scheduler/task_scheduler.h"
namespace task_scheduler_util {
-// Gets a vector of SchedulerWorkerPoolParams to initialize TaskScheduler in the
-// browser based off variations. Returns an empty vector on failure.
-std::vector<base::SchedulerWorkerPoolParams>
-GetBrowserWorkerPoolParamsFromVariations();
-
-// Maps |traits| to the index of a browser worker pool vector provided by
-// GetBrowserWorkerPoolParamsFromVariations().
-size_t BrowserWorkerPoolIndexForTraits(const base::TaskTraits& traits);
+// Gets a TaskScheduler::InitParams object to initialize TaskScheduler in the
+// browser based off variations. Returns nullptr on failure.
+std::unique_ptr<base::TaskScheduler::InitParams>
+GetBrowserTaskSchedulerInitParamsFromVariations();
// Redirects zero-to-many PostTask APIs to the browser task scheduler based off
// variations.
diff --git a/chromium/components/task_scheduler_util/common/variations_util.cc b/chromium/components/task_scheduler_util/common/variations_util.cc
index bdca8c8f961..04ef1dfa1bf 100644
--- a/chromium/components/task_scheduler_util/common/variations_util.cc
+++ b/chromium/components/task_scheduler_util/common/variations_util.cc
@@ -6,8 +6,8 @@
#include "base/command_line.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/task_scheduler/initialization_util.h"
@@ -18,12 +18,6 @@ namespace task_scheduler_util {
namespace {
-struct SchedulerCustomizableWorkerPoolParams {
- base::SchedulerWorkerPoolParams::StandbyThreadPolicy standby_thread_policy;
- int max_threads = 0;
- base::TimeDelta detach_period;
-};
-
#if !defined(OS_IOS)
constexpr char kTaskSchedulerVariationParamsSwitch[] =
"task-scheduler-variation-params";
@@ -35,10 +29,12 @@ bool ContainsSeparator(const std::string& str) {
}
#endif // !defined(OS_IOS)
-// Converts |pool_descriptor| to a SchedulerWorkerPoolVariableParams. Returns a
-// default SchedulerWorkerPoolVariableParams on failure.
+// Builds a SchedulerWorkerPoolParams from the pool descriptor in
+// |variation_params[variation_param_prefix + pool_name]| and
+// |backward_compatibility|. Returns an invalid SchedulerWorkerPoolParams on
+// failure.
//
-// |pool_descriptor| is a semi-colon separated value string with the following
+// The pool descriptor is a semi-colon separated value string with the following
// items:
// 0. Minimum Thread Count (int)
// 1. Maximum Thread Count (int)
@@ -47,10 +43,21 @@ bool ContainsSeparator(const std::string& str) {
// 4. Detach Time in Milliseconds (int)
// 5. Standby Thread Policy (string)
// Additional values may appear as necessary and will be ignored.
-SchedulerCustomizableWorkerPoolParams StringToVariableWorkerPoolParams(
- const base::StringPiece pool_descriptor) {
+std::unique_ptr<base::SchedulerWorkerPoolParams> GetWorkerPoolParams(
+ base::StringPiece variation_param_prefix,
+ base::StringPiece pool_name,
+ const std::map<std::string, std::string>& variation_params,
+ base::SchedulerBackwardCompatibility backward_compatibility =
+ base::SchedulerBackwardCompatibility::DISABLED) {
using StandbyThreadPolicy =
base::SchedulerWorkerPoolParams::StandbyThreadPolicy;
+
+ auto pool_descriptor_it = variation_params.find(
+ base::JoinString({variation_param_prefix, pool_name}, ""));
+ if (pool_descriptor_it == variation_params.end())
+ return nullptr;
+ const auto& pool_descriptor = pool_descriptor_it->second;
+
const std::vector<base::StringPiece> tokens = SplitStringPiece(
pool_descriptor, ";", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
// Normally, we wouldn't initialize the values below because we don't read
@@ -63,65 +70,66 @@ SchedulerCustomizableWorkerPoolParams StringToVariableWorkerPoolParams(
int detach_milliseconds = 0;
// Checking for a size greater than the expected amount allows us to be
// forward compatible if we add more variation values.
- if (tokens.size() >= 5 && base::StringToInt(tokens[0], &min) &&
- base::StringToInt(tokens[1], &max) &&
- base::StringToDouble(tokens[2].as_string(), &cores_multiplier) &&
- base::StringToInt(tokens[3], &offset) &&
- base::StringToInt(tokens[4], &detach_milliseconds)) {
- SchedulerCustomizableWorkerPoolParams params;
- params.max_threads = base::RecommendedMaxNumberOfThreadsInPool(
- min, max, cores_multiplier, offset);
- params.detach_period =
- base::TimeDelta::FromMilliseconds(detach_milliseconds);
- params.standby_thread_policy = (tokens.size() >= 6 && tokens[5] == "lazy")
- ? StandbyThreadPolicy::LAZY
- : StandbyThreadPolicy::ONE;
- return params;
+ if (tokens.size() < 5 || !base::StringToInt(tokens[0], &min) ||
+ !base::StringToInt(tokens[1], &max) ||
+ !base::StringToDouble(tokens[2].as_string(), &cores_multiplier) ||
+ !base::StringToInt(tokens[3], &offset) ||
+ !base::StringToInt(tokens[4], &detach_milliseconds)) {
+ DLOG(ERROR) << "Invalid Worker Pool Descriptor Format: " << pool_descriptor;
+ return nullptr;
}
- DLOG(ERROR) << "Invalid Worker Pool Descriptor: " << pool_descriptor;
- return SchedulerCustomizableWorkerPoolParams();
+
+ auto params = base::MakeUnique<base::SchedulerWorkerPoolParams>(
+ (tokens.size() >= 6 && tokens[5] == "lazy") ? StandbyThreadPolicy::LAZY
+ : StandbyThreadPolicy::ONE,
+ base::RecommendedMaxNumberOfThreadsInPool(min, max, cores_multiplier,
+ offset),
+ base::TimeDelta::FromMilliseconds(detach_milliseconds),
+ backward_compatibility);
+
+ if (params->max_threads() <= 0) {
+ DLOG(ERROR) << "Invalid max threads in the Worker Pool Descriptor: "
+ << params->max_threads();
+ return nullptr;
+ }
+
+ if (params->suggested_reclaim_time() < base::TimeDelta()) {
+ DLOG(ERROR)
+ << "Invalid suggested reclaim time in the Worker Pool Descriptor:"
+ << params->suggested_reclaim_time();
+ return nullptr;
+ }
+
+ return params;
}
} // namespace
-SchedulerImmutableWorkerPoolParams::SchedulerImmutableWorkerPoolParams(
- const char* name,
- base::ThreadPriority priority_hint,
- base::SchedulerBackwardCompatibility backward_compatibility)
- : name_(name),
- priority_hint_(priority_hint),
- backward_compatibility_(backward_compatibility) {}
-
-std::vector<base::SchedulerWorkerPoolParams> GetWorkerPoolParams(
- const std::vector<SchedulerImmutableWorkerPoolParams>&
- constant_worker_pool_params_vector,
- const std::map<std::string, std::string>& variation_params) {
- std::vector<base::SchedulerWorkerPoolParams> worker_pool_params_vector;
- for (const auto& constant_worker_pool_params :
- constant_worker_pool_params_vector) {
- const char* const worker_pool_name = constant_worker_pool_params.name();
- auto it = variation_params.find(worker_pool_name);
- if (it == variation_params.end()) {
- // Non-branded builds don't have access to external worker pool
- // configurations.
- return std::vector<base::SchedulerWorkerPoolParams>();
- }
- const auto variable_worker_pool_params =
- StringToVariableWorkerPoolParams(it->second);
- if (variable_worker_pool_params.max_threads <= 0 ||
- variable_worker_pool_params.detach_period <= base::TimeDelta()) {
- DLOG(ERROR) << "Invalid Worker Pool Configuration: " << worker_pool_name
- << " [" << it->second << "]";
- return std::vector<base::SchedulerWorkerPoolParams>();
- }
- worker_pool_params_vector.emplace_back(
- worker_pool_name, constant_worker_pool_params.priority_hint(),
- variable_worker_pool_params.standby_thread_policy,
- variable_worker_pool_params.max_threads,
- variable_worker_pool_params.detach_period,
- constant_worker_pool_params.backward_compatibility());
+std::unique_ptr<base::TaskScheduler::InitParams> GetTaskSchedulerInitParams(
+ base::StringPiece variation_param_prefix,
+ const std::map<std::string, std::string>& variation_params,
+ base::SchedulerBackwardCompatibility
+ foreground_blocking_backward_compatibility) {
+ const auto background_worker_pool_params = GetWorkerPoolParams(
+ variation_param_prefix, "Background", variation_params);
+ const auto background_blocking_worker_pool_params = GetWorkerPoolParams(
+ variation_param_prefix, "BackgroundBlocking", variation_params);
+ const auto foreground_worker_pool_params = GetWorkerPoolParams(
+ variation_param_prefix, "Foreground", variation_params);
+ const auto foreground_blocking_worker_pool_params = GetWorkerPoolParams(
+ variation_param_prefix, "ForegroundBlocking", variation_params,
+ foreground_blocking_backward_compatibility);
+
+ if (!background_worker_pool_params ||
+ !background_blocking_worker_pool_params ||
+ !foreground_worker_pool_params ||
+ !foreground_blocking_worker_pool_params) {
+ return nullptr;
}
- return worker_pool_params_vector;
+
+ return base::MakeUnique<base::TaskScheduler::InitParams>(
+ *background_worker_pool_params, *background_blocking_worker_pool_params,
+ *foreground_worker_pool_params, *foreground_blocking_worker_pool_params);
}
#if !defined(OS_IOS)
@@ -133,7 +141,7 @@ void AddVariationParamsToCommandLine(base::StringPiece key_prefix,
if (!variations::GetVariationParams("BrowserScheduler", &variation_params))
return;
- std::vector<std::string> parts;
+ std::vector<base::StringPiece> parts;
for (const auto& key_value : variation_params) {
if (base::StartsWith(key_value.first, key_prefix,
base::CompareCase::SENSITIVE)) {
diff --git a/chromium/components/task_scheduler_util/common/variations_util.h b/chromium/components/task_scheduler_util/common/variations_util.h
index f92b2977008..3fd49ce7a76 100644
--- a/chromium/components/task_scheduler_util/common/variations_util.h
+++ b/chromium/components/task_scheduler_util/common/variations_util.h
@@ -6,14 +6,13 @@
#define COMPONENTS_TASK_SCHEDULER_UTIL_COMMON_VARIATIONS_UTIL_H_
#include <map>
+#include <memory>
#include <string>
-#include <vector>
-#include "build/build_config.h"
#include "base/strings/string_piece.h"
#include "base/task_scheduler/scheduler_worker_params.h"
-#include "base/task_scheduler/scheduler_worker_pool_params.h"
-#include "base/threading/platform_thread.h"
+#include "base/task_scheduler/task_scheduler.h"
+#include "build/build_config.h"
namespace base {
class CommandLine;
@@ -21,34 +20,16 @@ class CommandLine;
namespace task_scheduler_util {
-class SchedulerImmutableWorkerPoolParams {
- public:
- SchedulerImmutableWorkerPoolParams(
- const char* name,
- base::ThreadPriority priority_hint,
- base::SchedulerBackwardCompatibility backward_compatibility =
- base::SchedulerBackwardCompatibility::DISABLED);
-
- const char* name() const { return name_; }
- base::ThreadPriority priority_hint() const { return priority_hint_; }
- base::SchedulerBackwardCompatibility backward_compatibility() const {
- return backward_compatibility_;
- }
-
- private:
- const char* name_;
- base::ThreadPriority priority_hint_;
- base::SchedulerBackwardCompatibility backward_compatibility_;
-};
-
-// Returns a SchedulerWorkerPoolParams vector to initialize pools specified in
-// |constant_worker_pool_params_vector|. SchedulerWorkerPoolParams members
-// without a counterpart in SchedulerImmutableWorkerPoolParams are initialized
-// based of |variation_params|. Returns an empty vector on failure.
-std::vector<base::SchedulerWorkerPoolParams> GetWorkerPoolParams(
- const std::vector<SchedulerImmutableWorkerPoolParams>&
- constant_worker_pool_params_vector,
- const std::map<std::string, std::string>& variation_params);
+// Builds a TaskScheduler::InitParams from pool descriptors in
+// |variations_params| that are prefixed with |variation_param_prefix|.
+// |foreground_blocking_backward_compatibility| controls backward compatibility
+// in the foreground blocking pool. Returns nullptr on failure.
+std::unique_ptr<base::TaskScheduler::InitParams> GetTaskSchedulerInitParams(
+ base::StringPiece variation_param_prefix,
+ const std::map<std::string, std::string>& variation_params,
+ base::SchedulerBackwardCompatibility
+ foreground_blocking_backward_compatibility =
+ base::SchedulerBackwardCompatibility::DISABLED);
#if !defined(OS_IOS)
// Serializes variation params from the BrowserScheduler field trial whose key
diff --git a/chromium/components/task_scheduler_util/common/variations_util_unittest.cc b/chromium/components/task_scheduler_util/common/variations_util_unittest.cc
index 5618106542a..d5612f7a011 100644
--- a/chromium/components/task_scheduler_util/common/variations_util_unittest.cc
+++ b/chromium/components/task_scheduler_util/common/variations_util_unittest.cc
@@ -14,7 +14,6 @@
#include "base/metrics/field_trial.h"
#include "base/task_scheduler/scheduler_worker_params.h"
#include "base/task_scheduler/scheduler_worker_pool_params.h"
-#include "base/threading/platform_thread.h"
#include "components/variations/variations_associated_data.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,7 +23,7 @@ namespace {
using StandbyThreadPolicy =
base::SchedulerWorkerPoolParams::StandbyThreadPolicy;
-using ThreadPriority = base::ThreadPriority;
+using SchedulerBackwardCompatibility = base::SchedulerBackwardCompatibility;
#if !defined(OS_IOS)
constexpr char kFieldTrialName[] = "BrowserScheduler";
@@ -33,20 +32,6 @@ constexpr char kTaskSchedulerVariationParamsSwitch[] =
"task-scheduler-variation-params";
#endif // !defined(OS_IOS)
-std::vector<SchedulerImmutableWorkerPoolParams> GetImmutableWorkerPoolParams() {
- std::vector<SchedulerImmutableWorkerPoolParams> constant_worker_pool_params;
- constant_worker_pool_params.emplace_back("Background",
- ThreadPriority::BACKGROUND);
- constant_worker_pool_params.emplace_back("BackgroundFileIO",
- ThreadPriority::BACKGROUND);
- constant_worker_pool_params.emplace_back("Foreground",
- ThreadPriority::NORMAL);
- constant_worker_pool_params.emplace_back(
- "ForegroundFileIO", ThreadPriority::NORMAL,
- base::SchedulerBackwardCompatibility::INIT_COM_STA);
- return constant_worker_pool_params;
-}
-
class TaskSchedulerUtilVariationsUtilTest : public testing::Test {
public:
TaskSchedulerUtilVariationsUtilTest() : field_trial_list_(nullptr) {}
@@ -67,128 +52,172 @@ class TaskSchedulerUtilVariationsUtilTest : public testing::Test {
TEST_F(TaskSchedulerUtilVariationsUtilTest, OrderingParams5) {
std::map<std::string, std::string> variation_params;
- variation_params["Background"] = "1;1;1;0;42";
- variation_params["BackgroundFileIO"] = "2;2;1;0;52";
- variation_params["Foreground"] = "4;4;1;0;62";
- variation_params["ForegroundFileIO"] = "8;8;1;0;72";
-
- auto params_vector =
- GetWorkerPoolParams(GetImmutableWorkerPoolParams(), variation_params);
- ASSERT_EQ(4U, params_vector.size());
-
- EXPECT_EQ("Background", params_vector[0].name());
- EXPECT_EQ(ThreadPriority::BACKGROUND, params_vector[0].priority_hint());
- EXPECT_EQ(StandbyThreadPolicy::ONE, params_vector[0].standby_thread_policy());
- EXPECT_EQ(1U, params_vector[0].max_threads());
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(42),
- params_vector[0].suggested_reclaim_time());
- EXPECT_EQ(base::SchedulerBackwardCompatibility::DISABLED,
- params_vector[0].backward_compatibility());
+ variation_params["RendererBackground"] = "1;1;1;0;42";
+ variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52";
+ variation_params["RendererForeground"] = "4;4;1;0;62";
+ variation_params["RendererForegroundBlocking"] = "8;8;1;0;72";
- EXPECT_EQ("BackgroundFileIO", params_vector[1].name());
- EXPECT_EQ(ThreadPriority::BACKGROUND, params_vector[1].priority_hint());
- EXPECT_EQ(StandbyThreadPolicy::ONE, params_vector[1].standby_thread_policy());
- EXPECT_EQ(2U, params_vector[1].max_threads());
+ auto init_params = GetTaskSchedulerInitParams(
+ "Renderer", variation_params,
+ base::SchedulerBackwardCompatibility::INIT_COM_STA);
+ ASSERT_TRUE(init_params);
+
+ EXPECT_EQ(StandbyThreadPolicy::ONE,
+ init_params->background_worker_pool_params.standby_thread_policy());
+ EXPECT_EQ(1, init_params->background_worker_pool_params.max_threads());
+ EXPECT_EQ(
+ base::TimeDelta::FromMilliseconds(42),
+ init_params->background_worker_pool_params.suggested_reclaim_time());
+ EXPECT_EQ(
+ base::SchedulerBackwardCompatibility::DISABLED,
+ init_params->background_worker_pool_params.backward_compatibility());
+
+ EXPECT_EQ(StandbyThreadPolicy::ONE,
+ init_params->background_blocking_worker_pool_params
+ .standby_thread_policy());
+ EXPECT_EQ(2,
+ init_params->background_blocking_worker_pool_params.max_threads());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(52),
- params_vector[1].suggested_reclaim_time());
- EXPECT_EQ(base::SchedulerBackwardCompatibility::DISABLED,
- params_vector[1].backward_compatibility());
-
- EXPECT_EQ("Foreground", params_vector[2].name());
- EXPECT_EQ(ThreadPriority::NORMAL, params_vector[2].priority_hint());
- EXPECT_EQ(StandbyThreadPolicy::ONE, params_vector[2].standby_thread_policy());
- EXPECT_EQ(4U, params_vector[2].max_threads());
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(62),
- params_vector[2].suggested_reclaim_time());
+ init_params->background_blocking_worker_pool_params
+ .suggested_reclaim_time());
EXPECT_EQ(base::SchedulerBackwardCompatibility::DISABLED,
- params_vector[2].backward_compatibility());
-
- EXPECT_EQ("ForegroundFileIO", params_vector[3].name());
- EXPECT_EQ(ThreadPriority::NORMAL, params_vector[3].priority_hint());
- EXPECT_EQ(StandbyThreadPolicy::ONE, params_vector[3].standby_thread_policy());
- EXPECT_EQ(8U, params_vector[3].max_threads());
+ init_params->background_blocking_worker_pool_params
+ .backward_compatibility());
+
+ EXPECT_EQ(StandbyThreadPolicy::ONE,
+ init_params->foreground_worker_pool_params.standby_thread_policy());
+ EXPECT_EQ(4, init_params->foreground_worker_pool_params.max_threads());
+ EXPECT_EQ(
+ base::TimeDelta::FromMilliseconds(62),
+ init_params->foreground_worker_pool_params.suggested_reclaim_time());
+ EXPECT_EQ(
+ base::SchedulerBackwardCompatibility::DISABLED,
+ init_params->foreground_worker_pool_params.backward_compatibility());
+
+ EXPECT_EQ(StandbyThreadPolicy::ONE,
+ init_params->foreground_blocking_worker_pool_params
+ .standby_thread_policy());
+ EXPECT_EQ(8,
+ init_params->foreground_blocking_worker_pool_params.max_threads());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(72),
- params_vector[3].suggested_reclaim_time());
+ init_params->foreground_blocking_worker_pool_params
+ .suggested_reclaim_time());
EXPECT_EQ(base::SchedulerBackwardCompatibility::INIT_COM_STA,
- params_vector[3].backward_compatibility());
+ init_params->foreground_blocking_worker_pool_params
+ .backward_compatibility());
}
TEST_F(TaskSchedulerUtilVariationsUtilTest, OrderingParams6) {
std::map<std::string, std::string> variation_params;
- variation_params["Background"] = "1;1;1;0;42;lazy";
- variation_params["BackgroundFileIO"] = "2;2;1;0;52;one";
- variation_params["Foreground"] = "4;4;1;0;62;lazy";
- variation_params["ForegroundFileIO"] = "8;8;1;0;72;one";
+ variation_params["RendererBackground"] = "1;1;1;0;42;lazy";
+ variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52;one";
+ variation_params["RendererForeground"] = "4;4;1;0;62;lazy";
+ variation_params["RendererForegroundBlocking"] = "8;8;1;0;72;one";
- auto params_vector =
- GetWorkerPoolParams(GetImmutableWorkerPoolParams(), variation_params);
- ASSERT_EQ(4U, params_vector.size());
+ auto init_params = GetTaskSchedulerInitParams(
+ "Renderer", variation_params,
+ base::SchedulerBackwardCompatibility::INIT_COM_STA);
+ ASSERT_TRUE(init_params);
- EXPECT_EQ("Background", params_vector[0].name());
- EXPECT_EQ(ThreadPriority::BACKGROUND, params_vector[0].priority_hint());
EXPECT_EQ(StandbyThreadPolicy::LAZY,
- params_vector[0].standby_thread_policy());
- EXPECT_EQ(1U, params_vector[0].max_threads());
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(42),
- params_vector[0].suggested_reclaim_time());
- EXPECT_EQ(base::SchedulerBackwardCompatibility::DISABLED,
- params_vector[0].backward_compatibility());
-
- EXPECT_EQ("BackgroundFileIO", params_vector[1].name());
- EXPECT_EQ(ThreadPriority::BACKGROUND, params_vector[1].priority_hint());
- EXPECT_EQ(StandbyThreadPolicy::ONE, params_vector[1].standby_thread_policy());
- EXPECT_EQ(2U, params_vector[1].max_threads());
+ init_params->background_worker_pool_params.standby_thread_policy());
+ EXPECT_EQ(1, init_params->background_worker_pool_params.max_threads());
+ EXPECT_EQ(
+ base::TimeDelta::FromMilliseconds(42),
+ init_params->background_worker_pool_params.suggested_reclaim_time());
+ EXPECT_EQ(
+ base::SchedulerBackwardCompatibility::DISABLED,
+ init_params->background_worker_pool_params.backward_compatibility());
+
+ EXPECT_EQ(StandbyThreadPolicy::ONE,
+ init_params->background_blocking_worker_pool_params
+ .standby_thread_policy());
+ EXPECT_EQ(2,
+ init_params->background_blocking_worker_pool_params.max_threads());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(52),
- params_vector[1].suggested_reclaim_time());
+ init_params->background_blocking_worker_pool_params
+ .suggested_reclaim_time());
EXPECT_EQ(base::SchedulerBackwardCompatibility::DISABLED,
- params_vector[1].backward_compatibility());
+ init_params->background_blocking_worker_pool_params
+ .backward_compatibility());
- EXPECT_EQ("Foreground", params_vector[2].name());
- EXPECT_EQ(ThreadPriority::NORMAL, params_vector[2].priority_hint());
EXPECT_EQ(StandbyThreadPolicy::LAZY,
- params_vector[2].standby_thread_policy());
- EXPECT_EQ(4U, params_vector[2].max_threads());
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(62),
- params_vector[2].suggested_reclaim_time());
- EXPECT_EQ(base::SchedulerBackwardCompatibility::DISABLED,
- params_vector[2].backward_compatibility());
-
- EXPECT_EQ("ForegroundFileIO", params_vector[3].name());
- EXPECT_EQ(ThreadPriority::NORMAL, params_vector[3].priority_hint());
- EXPECT_EQ(StandbyThreadPolicy::ONE, params_vector[3].standby_thread_policy());
- EXPECT_EQ(8U, params_vector[3].max_threads());
+ init_params->foreground_worker_pool_params.standby_thread_policy());
+ EXPECT_EQ(4, init_params->foreground_worker_pool_params.max_threads());
+ EXPECT_EQ(
+ base::TimeDelta::FromMilliseconds(62),
+ init_params->foreground_worker_pool_params.suggested_reclaim_time());
+ EXPECT_EQ(
+ base::SchedulerBackwardCompatibility::DISABLED,
+ init_params->foreground_worker_pool_params.backward_compatibility());
+
+ EXPECT_EQ(StandbyThreadPolicy::ONE,
+ init_params->foreground_blocking_worker_pool_params
+ .standby_thread_policy());
+ EXPECT_EQ(8,
+ init_params->foreground_blocking_worker_pool_params.max_threads());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(72),
- params_vector[3].suggested_reclaim_time());
+ init_params->foreground_blocking_worker_pool_params
+ .suggested_reclaim_time());
EXPECT_EQ(base::SchedulerBackwardCompatibility::INIT_COM_STA,
- params_vector[3].backward_compatibility());
+ init_params->foreground_blocking_worker_pool_params
+ .backward_compatibility());
}
TEST_F(TaskSchedulerUtilVariationsUtilTest, NoData) {
- EXPECT_TRUE(GetWorkerPoolParams(GetImmutableWorkerPoolParams(),
- std::map<std::string, std::string>())
- .empty());
+ EXPECT_FALSE(GetTaskSchedulerInitParams(
+ "Renderer", std::map<std::string, std::string>()));
}
TEST_F(TaskSchedulerUtilVariationsUtilTest, IncompleteParameters) {
std::map<std::string, std::string> variation_params;
- variation_params["Background"] = "1;1;1;0";
- variation_params["BackgroundFileIO"] = "2;2;1;0";
- variation_params["Foreground"] = "4;4;1;0";
- variation_params["ForegroundFileIO"] = "8;8;1;0";
- EXPECT_TRUE(
- GetWorkerPoolParams(GetImmutableWorkerPoolParams(), variation_params)
- .empty());
+ variation_params["RendererBackground"] = "1;1;1;0";
+ variation_params["RendererBackgroundBlocking"] = "2;2;1;0";
+ variation_params["RendererForeground"] = "4;4;1;0";
+ variation_params["RendererForegroundBlocking"] = "8;8;1;0";
+ EXPECT_FALSE(GetTaskSchedulerInitParams("Renderer", variation_params));
}
-TEST_F(TaskSchedulerUtilVariationsUtilTest, InvalidParameters) {
+TEST_F(TaskSchedulerUtilVariationsUtilTest, InvalidParametersFormat) {
std::map<std::string, std::string> variation_params;
- variation_params["Background"] = "a;b;c;d;e";
- variation_params["BackgroundFileIO"] = "a;b;c;d;e";
- variation_params["Foreground"] = "a;b;c;d;e";
- variation_params["ForegroundFileIO"] = "a;b;c;d;e";
- EXPECT_TRUE(
- GetWorkerPoolParams(GetImmutableWorkerPoolParams(), variation_params)
- .empty());
+ variation_params["RendererBackground"] = "a;b;c;d;e";
+ variation_params["RendererBackgroundBlocking"] = "a;b;c;d;e";
+ variation_params["RendererForeground"] = "a;b;c;d;e";
+ variation_params["RendererForegroundBlocking"] = "a;b;c;d;e";
+ EXPECT_FALSE(GetTaskSchedulerInitParams("Renderer", variation_params));
+}
+
+TEST_F(TaskSchedulerUtilVariationsUtilTest, ZeroMaxThreads) {
+ // The Background pool has a maximum number of threads equal to zero, which is
+ // invalid.
+ std::map<std::string, std::string> variation_params;
+ variation_params["RendererBackground"] = "0;0;0;0;0;lazy";
+ variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52;one";
+ variation_params["RendererForeground"] = "4;4;1;0;62;lazy";
+ variation_params["RendererForegroundBlocking"] = "8;8;1;0;72;one";
+ EXPECT_FALSE(GetTaskSchedulerInitParams("Renderer", variation_params));
+}
+
+TEST_F(TaskSchedulerUtilVariationsUtilTest, NegativeMaxThreads) {
+ // The Background pool has a negative maximum number of threads, which is
+ // invalid.
+ std::map<std::string, std::string> variation_params;
+ variation_params["RendererBackground"] = "-5;-5;0;0;0;lazy";
+ variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52;one";
+ variation_params["RendererForeground"] = "4;4;1;0;62;lazy";
+ variation_params["RendererForegroundBlocking"] = "8;8;1;0;72;one";
+ EXPECT_FALSE(GetTaskSchedulerInitParams("Renderer", variation_params));
+}
+
+TEST_F(TaskSchedulerUtilVariationsUtilTest, NegativeSuggestedReclaimTime) {
+ // The Background pool has a negative suggested reclaim time, which is
+ // invalid.
+ std::map<std::string, std::string> variation_params;
+ variation_params["RendererBackground"] = "1;1;1;0;-5;lazy";
+ variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52;one";
+ variation_params["RendererForeground"] = "4;4;1;0;62;lazy";
+ variation_params["RendererForegroundBlocking"] = "8;8;1;0;72;one";
+ EXPECT_FALSE(GetTaskSchedulerInitParams("Renderer", variation_params));
}
#if !defined(OS_IOS)
diff --git a/chromium/components/task_scheduler_util/renderer/initialization.cc b/chromium/components/task_scheduler_util/renderer/initialization.cc
index 0bef44603c6..854bfe0d334 100644
--- a/chromium/components/task_scheduler_util/renderer/initialization.cc
+++ b/chromium/components/task_scheduler_util/renderer/initialization.cc
@@ -4,55 +4,16 @@
#include "components/task_scheduler_util/renderer/initialization.h"
-#include <map>
-#include <string>
-
#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/task_scheduler/task_traits.h"
-#include "base/threading/platform_thread.h"
#include "components/task_scheduler_util/common/variations_util.h"
namespace task_scheduler_util {
-namespace {
-
-enum WorkerPoolType : size_t {
- BACKGROUND = 0,
- BACKGROUND_BLOCKING,
- FOREGROUND,
- FOREGROUND_BLOCKING,
- WORKER_POOL_COUNT // Always last.
-};
-
-} // namespace
-
-std::vector<base::SchedulerWorkerPoolParams> GetRendererWorkerPoolParams() {
- using ThreadPriority = base::ThreadPriority;
- std::vector<SchedulerImmutableWorkerPoolParams> immutable_worker_pool_params;
- DCHECK_EQ(BACKGROUND, immutable_worker_pool_params.size());
- immutable_worker_pool_params.emplace_back("RendererBackground",
- ThreadPriority::BACKGROUND);
- DCHECK_EQ(BACKGROUND_BLOCKING, immutable_worker_pool_params.size());
- immutable_worker_pool_params.emplace_back("RendererBackgroundBlocking",
- ThreadPriority::BACKGROUND);
- DCHECK_EQ(FOREGROUND, immutable_worker_pool_params.size());
- immutable_worker_pool_params.emplace_back("RendererForeground",
- ThreadPriority::NORMAL);
- DCHECK_EQ(FOREGROUND_BLOCKING, immutable_worker_pool_params.size());
- immutable_worker_pool_params.emplace_back("RendererForegroundBlocking",
- ThreadPriority::NORMAL);
- return GetWorkerPoolParams(immutable_worker_pool_params,
- GetVariationParamsFromCommandLine(
- *base::CommandLine::ForCurrentProcess()));
-}
-
-size_t RendererWorkerPoolIndexForTraits(const base::TaskTraits& traits) {
- const bool is_background =
- traits.priority() == base::TaskPriority::BACKGROUND;
- if (traits.may_block() || traits.with_base_sync_primitives())
- return is_background ? BACKGROUND_BLOCKING : FOREGROUND_BLOCKING;
- return is_background ? BACKGROUND : FOREGROUND;
+std::unique_ptr<base::TaskScheduler::InitParams>
+GetRendererTaskSchedulerInitParamsFromCommandLine() {
+ return GetTaskSchedulerInitParams(
+ "Renderer", GetVariationParamsFromCommandLine(
+ *base::CommandLine::ForCurrentProcess()));
}
} // namespace task_scheduler_util
diff --git a/chromium/components/task_scheduler_util/renderer/initialization.h b/chromium/components/task_scheduler_util/renderer/initialization.h
index 6f351507eec..9199c6bb198 100644
--- a/chromium/components/task_scheduler_util/renderer/initialization.h
+++ b/chromium/components/task_scheduler_util/renderer/initialization.h
@@ -5,27 +5,17 @@
#ifndef COMPONENTS_TASK_SCHEDULER_UTIL_RENDERER_INITIALIZATION_H_
#define COMPONENTS_TASK_SCHEDULER_UTIL_RENDERER_INITIALIZATION_H_
-#include <stddef.h>
+#include <memory>
-#include <vector>
-
-#include "base/task_scheduler/scheduler_worker_pool_params.h"
-
-namespace base {
-class TaskTraits;
-}
+#include "base/task_scheduler/task_scheduler.h"
namespace task_scheduler_util {
-// Gets a vector of SchedulerWorkerPoolParams to initialize TaskScheduler in a
-// renderer based off variation params specified on the command line. Returns an
-// empty vector if variation params specified on the command line are incomplete
-// or invalid.
-std::vector<base::SchedulerWorkerPoolParams> GetRendererWorkerPoolParams();
-
-// Maps |traits| to the index of a renderer worker pool vector provided by
-// GetRendererWorkerPoolParams().
-size_t RendererWorkerPoolIndexForTraits(const base::TaskTraits& traits);
+// Gets a TaskScheduler::InitParams object to initialize TaskScheduler in a
+// renderer based off variations specified on the command line. Returns nullptr
+// on failure.
+std::unique_ptr<base::TaskScheduler::InitParams>
+GetRendererTaskSchedulerInitParamsFromCommandLine();
} // namespace task_scheduler_util
diff --git a/chromium/components/toolbar/BUILD.gn b/chromium/components/toolbar/BUILD.gn
index 08478b45ae4..66164fc0744 100644
--- a/chromium/components/toolbar/BUILD.gn
+++ b/chromium/components/toolbar/BUILD.gn
@@ -9,9 +9,6 @@ aggregate_vector_icons("toolbar_vector_icons") {
icon_directory = "vector_icons"
icons = [
- # TODO(estade): this is the same as ui/gfx/vector_icons/business.icon. Use
- # that one instead once it's been updated from VectorIconId to VectorIcon.
- "business.icon",
"http.1x.icon",
"http.icon",
"https_invalid.1x.icon",
@@ -35,23 +32,29 @@ static_library("toolbar") {
"toolbar_model_impl.h",
]
- deps = [
+ public_deps = [
"//base",
+ "//components/security_state/core",
+ "//url",
+ ]
+
+ deps = [
"//components/google/core/browser",
"//components/prefs",
"//components/resources",
- "//components/security_state/core",
"//components/strings",
"//components/url_formatter",
"//net",
"//ui/base",
"//ui/gfx",
- "//url",
]
if (!is_android && !is_ios) {
sources += get_target_outputs(":toolbar_vector_icons")
- deps += [ ":toolbar_vector_icons" ]
+ deps += [
+ ":toolbar_vector_icons",
+ "//ui/vector_icons",
+ ]
}
}
diff --git a/chromium/components/toolbar/DEPS b/chromium/components/toolbar/DEPS
index 8dee43cba04..999012d6e34 100644
--- a/chromium/components/toolbar/DEPS
+++ b/chromium/components/toolbar/DEPS
@@ -8,4 +8,5 @@ include_rules = [
"+net",
"+ui/base",
"+ui/gfx",
+ "+ui/vector_icons",
]
diff --git a/chromium/components/toolbar/toolbar_model_impl.cc b/chromium/components/toolbar/toolbar_model_impl.cc
index 017c5a9c199..fee722b7abb 100644
--- a/chromium/components/toolbar/toolbar_model_impl.cc
+++ b/chromium/components/toolbar/toolbar_model_impl.cc
@@ -23,6 +23,7 @@
#if !defined(OS_ANDROID) && !defined(OS_IOS)
#include "components/toolbar/vector_icons.h" // nogncheck
+#include "ui/vector_icons/vector_icons.h" // nogncheck
#endif
ToolbarModelImpl::ToolbarModelImpl(ToolbarModelDelegate* delegate,
@@ -88,7 +89,7 @@ const gfx::VectorIcon& ToolbarModelImpl::GetVectorIcon() const {
// Surface Dubious as Neutral.
return toolbar::kHttpIcon;
case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
- return toolbar::kBusinessIcon;
+ return ui::kBusinessIcon;
case security_state::DANGEROUS:
return toolbar::kHttpsInvalidIcon;
}
diff --git a/chromium/components/toolbar/vector_icons/business.icon b/chromium/components/toolbar/vector_icons/business.icon
deleted file mode 100644
index bfefb7b4a3d..00000000000
--- a/chromium/components/toolbar/vector_icons/business.icon
+++ /dev/null
@@ -1,87 +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.
-
-MOVE_TO, 24, 14,
-V_LINE_TO, 6,
-H_LINE_TO, 4,
-R_V_LINE_TO, 36,
-R_H_LINE_TO, 40,
-V_LINE_TO, 14,
-H_LINE_TO, 24,
-CLOSE,
-MOVE_TO, 12, 38,
-H_LINE_TO, 8,
-R_V_LINE_TO, -4,
-R_H_LINE_TO, 4,
-R_V_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 0, -8,
-H_LINE_TO, 8,
-R_V_LINE_TO, -4,
-R_H_LINE_TO, 4,
-R_V_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 0, -8,
-H_LINE_TO, 8,
-R_V_LINE_TO, -4,
-R_H_LINE_TO, 4,
-R_V_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 0, -8,
-H_LINE_TO, 8,
-R_V_LINE_TO, -4,
-R_H_LINE_TO, 4,
-R_V_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 8, 24,
-R_H_LINE_TO, -4,
-R_V_LINE_TO, -4,
-R_H_LINE_TO, 4,
-R_V_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 0, -8,
-R_H_LINE_TO, -4,
-R_V_LINE_TO, -4,
-R_H_LINE_TO, 4,
-R_V_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 0, -8,
-R_H_LINE_TO, -4,
-R_V_LINE_TO, -4,
-R_H_LINE_TO, 4,
-R_V_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 0, -8,
-R_H_LINE_TO, -4,
-R_V_LINE_TO, -4,
-R_H_LINE_TO, 4,
-R_V_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 20, 24,
-H_LINE_TO, 24,
-R_V_LINE_TO, -4,
-R_H_LINE_TO, 4,
-R_V_LINE_TO, -4,
-R_H_LINE_TO, -4,
-R_V_LINE_TO, -4,
-R_H_LINE_TO, 4,
-R_V_LINE_TO, -4,
-R_H_LINE_TO, -4,
-R_V_LINE_TO, -4,
-R_H_LINE_TO, 16,
-R_V_LINE_TO, 20,
-CLOSE,
-R_MOVE_TO, -4, -16,
-R_H_LINE_TO, -4,
-R_V_LINE_TO, 4,
-R_H_LINE_TO, 4,
-R_V_LINE_TO, -4,
-CLOSE,
-R_MOVE_TO, 0, 8,
-R_H_LINE_TO, -4,
-R_V_LINE_TO, 4,
-R_H_LINE_TO, 4,
-R_V_LINE_TO, -4,
-CLOSE,
-END
diff --git a/chromium/components/tracing/BUILD.gn b/chromium/components/tracing/BUILD.gn
index deab4a66a3d..8b0bd09b7ac 100644
--- a/chromium/components/tracing/BUILD.gn
+++ b/chromium/components/tracing/BUILD.gn
@@ -7,8 +7,6 @@ import("//third_party/protobuf/proto_library.gni")
component("tracing") {
sources = [
- "child/child_memory_dump_manager_delegate_impl.cc",
- "child/child_memory_dump_manager_delegate_impl.h",
"child/child_trace_message_filter.cc",
"child/child_trace_message_filter.h",
"common/graphics_memory_dump_provider_android.cc",
@@ -101,6 +99,7 @@ source_set("unit_tests") {
"core/trace_buffer_writer_unittest.cc",
"core/trace_ring_buffer_unittest.cc",
"test/fake_scattered_buffer.cc",
+ "test/fake_scattered_buffer.h",
"test/proto_zero_generation_unittest.cc",
]
diff --git a/chromium/components/tracing/child/child_memory_dump_manager_delegate_impl.cc b/chromium/components/tracing/child/child_memory_dump_manager_delegate_impl.cc
deleted file mode 100644
index f0c4517b2ea..00000000000
--- a/chromium/components/tracing/child/child_memory_dump_manager_delegate_impl.cc
+++ /dev/null
@@ -1,114 +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/tracing/child/child_memory_dump_manager_delegate_impl.h"
-
-#include "base/single_thread_task_runner.h"
-#include "build/build_config.h"
-#include "components/tracing/child/child_trace_message_filter.h"
-#include "components/tracing/common/process_metrics_memory_dump_provider.h"
-
-namespace tracing {
-
-namespace {
-void AbortDumpRequest(const base::trace_event::MemoryDumpRequestArgs& args,
- const base::trace_event::MemoryDumpCallback& callback) {
- if (!callback.is_null())
- callback.Run(args.dump_guid, false /* success */);
-}
-} // namespace
-
-// static
-ChildMemoryDumpManagerDelegateImpl*
-ChildMemoryDumpManagerDelegateImpl::GetInstance() {
- return base::Singleton<
- ChildMemoryDumpManagerDelegateImpl,
- base::LeakySingletonTraits<ChildMemoryDumpManagerDelegateImpl>>::get();
-}
-
-ChildMemoryDumpManagerDelegateImpl::ChildMemoryDumpManagerDelegateImpl()
- : ctmf_(nullptr),
- tracing_process_id_(
- base::trace_event::MemoryDumpManager::kInvalidTracingProcessId) {
-}
-
-ChildMemoryDumpManagerDelegateImpl::~ChildMemoryDumpManagerDelegateImpl() {}
-
-void ChildMemoryDumpManagerDelegateImpl::SetChildTraceMessageFilter(
- ChildTraceMessageFilter* ctmf) {
- auto* task_runner = ctmf ? (ctmf->ipc_task_runner()) : nullptr;
- // Check that we are either registering the CTMF or tearing it down, but not
- // replacing a valid instance with another one (should never happen).
- DCHECK(!ctmf_ || (!ctmf && ctmf_task_runner_));
- ctmf_ = ctmf;
-
- {
- base::AutoLock lock(lock_);
- ctmf_task_runner_ = task_runner;
- }
-
- if (ctmf) {
- base::trace_event::MemoryDumpManager::GetInstance()->Initialize(
- this /* delegate */, false /* is_coordinator */);
-
-#if !defined(OS_LINUX) && !defined(OS_NACL)
- // On linux the browser process takes care of dumping process metrics.
- // The child process is not allowed to do so due to BPF sandbox.
- tracing::ProcessMetricsMemoryDumpProvider::RegisterForProcess(
- base::kNullProcessId);
-#endif
- }
-}
-
-// Invoked in child processes by the MemoryDumpManager.
-void ChildMemoryDumpManagerDelegateImpl::RequestGlobalMemoryDump(
- const base::trace_event::MemoryDumpRequestArgs& args,
- const base::trace_event::MemoryDumpCallback& callback) {
- // RequestGlobalMemoryDump can be called on any thread, cannot access
- // ctmf_task_runner_ as it could be racy.
- scoped_refptr<base::SingleThreadTaskRunner> ctmf_task_runner;
- {
- base::AutoLock lock(lock_);
- ctmf_task_runner = ctmf_task_runner_;
- }
-
- // Bail out if we receive a dump request from the manager before the
- // ChildTraceMessageFilter has been initialized.
- if (!ctmf_task_runner) {
- VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix
- << " failed because child trace message filter hasn't been"
- << " initialized";
- return AbortDumpRequest(args, callback);
- }
-
- // Make sure we access |ctmf_| only on the thread where it lives to avoid
- // races on shutdown.
- if (!ctmf_task_runner->BelongsToCurrentThread()) {
- const bool did_post_task = ctmf_task_runner->PostTask(
- FROM_HERE,
- base::Bind(&ChildMemoryDumpManagerDelegateImpl::RequestGlobalMemoryDump,
- base::Unretained(this), args, callback));
- if (!did_post_task)
- return AbortDumpRequest(args, callback);
- return;
- }
-
- // The ChildTraceMessageFilter could have been destroyed while hopping on the
- // right thread. If this is the case, bail out.
- if (!ctmf_) {
- VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix
- << " failed because child trace message filter was"
- << " destroyed while switching threads";
- return AbortDumpRequest(args, callback);
- }
-
- // Send the request up to the browser process' MessageDumpmanager.
- ctmf_->SendGlobalMemoryDumpRequest(args, callback);
-}
-
-uint64_t ChildMemoryDumpManagerDelegateImpl::GetTracingProcessId() const {
- return tracing_process_id_;
-}
-
-} // namespace tracing
diff --git a/chromium/components/tracing/child/child_memory_dump_manager_delegate_impl.h b/chromium/components/tracing/child/child_memory_dump_manager_delegate_impl.h
deleted file mode 100644
index fc27d96f279..00000000000
--- a/chromium/components/tracing/child/child_memory_dump_manager_delegate_impl.h
+++ /dev/null
@@ -1,85 +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_TRACING_CHILD_CHILD_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_
-#define COMPONENTS_TRACING_CHILD_CHILD_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_
-
-#include "base/trace_event/memory_dump_manager.h"
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/singleton.h"
-#include "base/synchronization/lock.h"
-#include "components/tracing/tracing_export.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-} // namespace base
-
-namespace tracing {
-
-class ChildTraceMessageFilter;
-
-// This class is a simple proxy class between the MemoryDumpManager and the
-// ChildTraceMessageFilter. It's only purpose is to adapt the lifetime of
-// CTMF to the demands of MDM, which expects the delegate to be thread-safe
-// and long lived. CTMF, instead, can be torn down during browser shutdown.
-// This class is registered as MDM delegate in child processes and handles
-// gracefully (and thread-safely) failures in the case of a lack of the CTMF.
-class TRACING_EXPORT ChildMemoryDumpManagerDelegateImpl
- : public base::trace_event::MemoryDumpManagerDelegate {
- public:
- static ChildMemoryDumpManagerDelegateImpl* GetInstance();
-
- // base::trace_event::MemoryDumpManagerDelegate implementation.
- void RequestGlobalMemoryDump(
- const base::trace_event::MemoryDumpRequestArgs& args,
- const base::trace_event::MemoryDumpCallback& callback) override;
- uint64_t GetTracingProcessId() const override;
-
- void SetChildTraceMessageFilter(ChildTraceMessageFilter* ctmf);
-
- // Pass kInvalidTracingProcessId to invalidate the id.
- void set_tracing_process_id(uint64_t id) {
- DCHECK(tracing_process_id_ ==
- base::trace_event::MemoryDumpManager::kInvalidTracingProcessId ||
- id ==
- base::trace_event::MemoryDumpManager::kInvalidTracingProcessId ||
- id == tracing_process_id_);
- tracing_process_id_ = id;
- }
-
- protected:
- // Make CreateProcessDump() visible to ChildTraceMessageFilter.
- friend class ChildTraceMessageFilter;
-
- private:
- friend struct base::DefaultSingletonTraits<
- ChildMemoryDumpManagerDelegateImpl>;
-
- ChildMemoryDumpManagerDelegateImpl();
- ~ChildMemoryDumpManagerDelegateImpl() override;
-
- ChildTraceMessageFilter* ctmf_; // Not owned.
-
- // The SingleThreadTaskRunner where the |ctmf_| lives.
- // It is NULL iff |cmtf_| is NULL.
- scoped_refptr<base::SingleThreadTaskRunner> ctmf_task_runner_;
-
- // Protects from concurrent access to |ctmf_task_runner_| to allow
- // RequestGlobalMemoryDump to be called from arbitrary threads.
- base::Lock lock_;
-
- // The unique id of the child process, created for tracing and is expected to
- // be valid only when tracing is enabled.
- uint64_t tracing_process_id_;
-
- DISALLOW_COPY_AND_ASSIGN(ChildMemoryDumpManagerDelegateImpl);
-};
-
-} // namespace tracing
-
-#endif // COMPONENTS_TRACING_CHILD_CHILD_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_
diff --git a/chromium/components/tracing/child/child_trace_message_filter.cc b/chromium/components/tracing/child/child_trace_message_filter.cc
index ed2be875c7d..2cd76dc7b2a 100644
--- a/chromium/components/tracing/child/child_trace_message_filter.cc
+++ b/chromium/components/tracing/child/child_trace_message_filter.cc
@@ -8,11 +8,13 @@
#include "base/memory/ref_counted_memory.h"
#include "base/metrics/statistics_recorder.h"
+#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_event.h"
-#include "components/tracing/child/child_memory_dump_manager_delegate_impl.h"
+#include "components/tracing/common/process_metrics_memory_dump_provider.h"
#include "components/tracing/common/tracing_messages.h"
#include "ipc/ipc_channel.h"
+using base::trace_event::MemoryDumpManager;
using base::trace_event::TraceLog;
namespace tracing {
@@ -25,16 +27,20 @@ const int kMinTimeBetweenHistogramChangesInSeconds = 10;
ChildTraceMessageFilter::ChildTraceMessageFilter(
base::SingleThreadTaskRunner* ipc_task_runner)
- : sender_(NULL),
- ipc_task_runner_(ipc_task_runner),
- pending_memory_dump_guid_(0) {
-}
+ : enabled_tracing_modes_(0),
+ sender_(NULL),
+ ipc_task_runner_(ipc_task_runner) {}
void ChildTraceMessageFilter::OnFilterAdded(IPC::Channel* channel) {
sender_ = channel;
sender_->Send(new TracingHostMsg_ChildSupportsTracing());
- ChildMemoryDumpManagerDelegateImpl::GetInstance()->SetChildTraceMessageFilter(
- this);
+
+#if !defined(OS_LINUX) && !defined(OS_NACL)
+ // On linux the browser process takes care of dumping process metrics.
+ // The child process is not allowed to do so due to BPF sandbox.
+ tracing::ProcessMetricsMemoryDumpProvider::RegisterForProcess(
+ base::kNullProcessId);
+#endif
}
void ChildTraceMessageFilter::SetSenderForTesting(IPC::Sender* sender) {
@@ -42,8 +48,6 @@ void ChildTraceMessageFilter::SetSenderForTesting(IPC::Sender* sender) {
}
void ChildTraceMessageFilter::OnFilterRemoved() {
- ChildMemoryDumpManagerDelegateImpl::GetInstance()->SetChildTraceMessageFilter(
- nullptr);
sender_ = NULL;
}
@@ -54,10 +58,6 @@ bool ChildTraceMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(TracingMsg_EndTracing, OnEndTracing)
IPC_MESSAGE_HANDLER(TracingMsg_CancelTracing, OnCancelTracing)
IPC_MESSAGE_HANDLER(TracingMsg_GetTraceLogStatus, OnGetTraceLogStatus)
- IPC_MESSAGE_HANDLER(TracingMsg_ProcessMemoryDumpRequest,
- OnProcessMemoryDumpRequest)
- IPC_MESSAGE_HANDLER(TracingMsg_GlobalMemoryDumpResponse,
- OnGlobalMemoryDumpResponse)
IPC_MESSAGE_HANDLER(TracingMsg_SetUMACallback, OnSetUMACallback)
IPC_MESSAGE_HANDLER(TracingMsg_ClearUMACallback, OnClearUMACallback)
IPC_MESSAGE_UNHANDLED(handled = false)
@@ -78,15 +78,18 @@ void ChildTraceMessageFilter::OnBeginTracing(
base::TimeDelta time_offset = base::TimeTicks::Now() - browser_time;
TraceLog::GetInstance()->SetTimeOffset(time_offset);
#endif
- ChildMemoryDumpManagerDelegateImpl::GetInstance()->set_tracing_process_id(
- tracing_process_id);
- TraceLog::GetInstance()->SetEnabled(
- base::trace_event::TraceConfig(trace_config_str),
- base::trace_event::TraceLog::RECORDING_MODE);
+ MemoryDumpManager::GetInstance()->set_tracing_process_id(tracing_process_id);
+ const base::trace_event::TraceConfig trace_config(trace_config_str);
+ enabled_tracing_modes_ = base::trace_event::TraceLog::RECORDING_MODE;
+ if (!trace_config.event_filters().empty())
+ enabled_tracing_modes_ |= base::trace_event::TraceLog::FILTERING_MODE;
+ TraceLog::GetInstance()->SetEnabled(trace_config, enabled_tracing_modes_);
}
void ChildTraceMessageFilter::OnEndTracing() {
- TraceLog::GetInstance()->SetDisabled();
+ DCHECK(enabled_tracing_modes_);
+ TraceLog::GetInstance()->SetDisabled(enabled_tracing_modes_);
+ enabled_tracing_modes_ = 0;
// Flush will generate one or more callbacks to OnTraceDataCollected
// synchronously or asynchronously. EndTracingAck will be sent in the last
@@ -95,8 +98,8 @@ void ChildTraceMessageFilter::OnEndTracing() {
TraceLog::GetInstance()->Flush(
base::Bind(&ChildTraceMessageFilter::OnTraceDataCollected, this));
- ChildMemoryDumpManagerDelegateImpl::GetInstance()->set_tracing_process_id(
- base::trace_event::MemoryDumpManager::kInvalidTracingProcessId);
+ MemoryDumpManager::GetInstance()->set_tracing_process_id(
+ MemoryDumpManager::kInvalidTracingProcessId);
}
void ChildTraceMessageFilter::OnCancelTracing() {
@@ -129,52 +132,6 @@ void ChildTraceMessageFilter::OnTraceDataCollected(
}
}
-// Sent by the Browser's MemoryDumpManager when coordinating a global dump.
-void ChildTraceMessageFilter::OnProcessMemoryDumpRequest(
- const base::trace_event::MemoryDumpRequestArgs& args) {
- ChildMemoryDumpManagerDelegateImpl::GetInstance()->CreateProcessDump(
- args,
- base::Bind(&ChildTraceMessageFilter::OnProcessMemoryDumpDone, this));
-}
-
-void ChildTraceMessageFilter::OnProcessMemoryDumpDone(uint64_t dump_guid,
- bool success) {
- sender_->Send(
- new TracingHostMsg_ProcessMemoryDumpResponse(dump_guid, success));
-}
-
-// Initiates a dump request, asking the Browser's MemoryDumpManager to
-// coordinate a global memory dump. The Browser's MDM will answer back with a
-// MemoryDumpResponse when all the child processes (including this one) have
-// dumped, or with a NACK (|success| == false) if the dump failed (e.g., due to
-// a collision with a concurrent request from another child process).
-void ChildTraceMessageFilter::SendGlobalMemoryDumpRequest(
- const base::trace_event::MemoryDumpRequestArgs& args,
- const base::trace_event::MemoryDumpCallback& callback) {
- // If there is already another dump request pending from this child process,
- // there is no point bothering the Browser's MemoryDumpManager.
- if (pending_memory_dump_guid_) {
- if (!callback.is_null())
- callback.Run(args.dump_guid, false);
- return;
- }
-
- pending_memory_dump_guid_ = args.dump_guid;
- pending_memory_dump_callback_ = callback;
- sender_->Send(new TracingHostMsg_GlobalMemoryDumpRequest(args));
-}
-
-// Sent by the Browser's MemoryDumpManager in response of a dump request
-// initiated by this child process.
-void ChildTraceMessageFilter::OnGlobalMemoryDumpResponse(uint64_t dump_guid,
- bool success) {
- DCHECK_NE(0U, pending_memory_dump_guid_);
- pending_memory_dump_guid_ = 0;
- if (pending_memory_dump_callback_.is_null())
- return;
- pending_memory_dump_callback_.Run(dump_guid, success);
-}
-
void ChildTraceMessageFilter::OnHistogramChanged(
const std::string& histogram_name,
base::Histogram::Sample reference_lower_value,
diff --git a/chromium/components/tracing/child/child_trace_message_filter.h b/chromium/components/tracing/child/child_trace_message_filter.h
index 287abd3503d..929fa7e21cd 100644
--- a/chromium/components/tracing/child/child_trace_message_filter.h
+++ b/chromium/components/tracing/child/child_trace_message_filter.h
@@ -12,7 +12,6 @@
#include "base/memory/ref_counted_memory.h"
#include "base/metrics/histogram.h"
#include "base/time/time.h"
-#include "base/trace_event/memory_dump_request_args.h"
#include "components/tracing/tracing_export.h"
#include "ipc/message_filter.h"
@@ -33,10 +32,6 @@ class TRACING_EXPORT ChildTraceMessageFilter : public IPC::MessageFilter {
void OnFilterRemoved() override;
bool OnMessageReceived(const IPC::Message& message) override;
- void SendGlobalMemoryDumpRequest(
- const base::trace_event::MemoryDumpRequestArgs& args,
- const base::trace_event::MemoryDumpCallback& callback);
-
base::SingleThreadTaskRunner* ipc_task_runner() const {
return ipc_task_runner_;
}
@@ -58,9 +53,6 @@ class TRACING_EXPORT ChildTraceMessageFilter : public IPC::MessageFilter {
const std::string& event_name);
void OnCancelWatchEvent();
void OnWatchEventMatched();
- void OnProcessMemoryDumpRequest(
- const base::trace_event::MemoryDumpRequestArgs& args);
- void OnGlobalMemoryDumpResponse(uint64_t dump_guid, bool success);
void OnSetUMACallback(const std::string& histogram_name,
int histogram_lower_value,
int histogram_upper_value,
@@ -79,20 +71,13 @@ class TRACING_EXPORT ChildTraceMessageFilter : public IPC::MessageFilter {
const scoped_refptr<base::RefCountedString>& events_str_ptr,
bool has_more_events);
- void OnProcessMemoryDumpDone(uint64_t dump_guid, bool success);
-
void SetSenderForTesting(IPC::Sender* sender);
+ uint8_t enabled_tracing_modes_;
+
IPC::Sender* sender_;
base::SingleThreadTaskRunner* ipc_task_runner_;
- // guid of the outstanding request (to the Browser's MemoryDumpManager), if
- // any. 0 if there is no request pending.
- uint64_t pending_memory_dump_guid_;
-
- // callback of the outstanding memory dump request, if any.
- base::trace_event::MemoryDumpCallback pending_memory_dump_callback_;
-
base::Time histogram_last_changed_;
DISALLOW_COPY_AND_ASSIGN(ChildTraceMessageFilter);
diff --git a/chromium/components/tracing/child/child_trace_message_filter_browsertest.cc b/chromium/components/tracing/child/child_trace_message_filter_browsertest.cc
deleted file mode 100644
index d0d2d020a88..00000000000
--- a/chromium/components/tracing/child/child_trace_message_filter_browsertest.cc
+++ /dev/null
@@ -1,326 +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 <stdint.h>
-
-#include <memory>
-#include <tuple>
-
-#include "base/callback.h"
-#include "base/run_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "base/trace_event/memory_dump_provider.h"
-#include "base/trace_event/trace_event.h"
-#include "components/tracing/child/child_memory_dump_manager_delegate_impl.h"
-#include "components/tracing/child/child_trace_message_filter.h"
-#include "components/tracing/common/tracing_messages.h"
-#include "content/public/test/render_view_test.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using base::trace_event::MemoryDumpManager;
-using base::trace_event::MemoryDumpRequestArgs;
-using base::trace_event::MemoryDumpArgs;
-using base::trace_event::MemoryDumpLevelOfDetail;
-using base::trace_event::MemoryDumpType;
-using testing::_;
-using testing::Return;
-
-namespace tracing {
-
-// A mock dump provider, used to check that dump requests actually end up
-// creating memory dumps.
-class MockDumpProvider : public base::trace_event::MemoryDumpProvider {
- public:
- MOCK_METHOD2(OnMemoryDump,
- bool(const MemoryDumpArgs& args,
- base::trace_event::ProcessMemoryDump* pmd));
-};
-
-class ChildTracingTest : public content::RenderViewTest, public IPC::Listener {
- public:
- // Used as callback argument for MemoryDumpManager::RequestGlobalDump():
- void OnMemoryDumpCallback(uint64_t dump_guid, bool status) {
- last_callback_dump_guid_ = dump_guid;
- last_callback_status_ = status;
- ++callback_call_count_;
- }
-
- protected:
- void SetUp() override {
- // RenderViewTest::SetUp causes additional registrations, so we first
- // register the mock dump provider and ignore registrations from then on.
- // In addition to the mock dump provider, the TraceLog has already
- // registered itself by now; this cannot be prevented easily.
- mock_dump_provider_.reset(new MockDumpProvider());
- MemoryDumpManager::GetInstance()->RegisterDumpProvider(
- mock_dump_provider_.get(), "MockDumpProvider",
- base::ThreadTaskRunnerHandle::Get());
- MemoryDumpManager::GetInstance()
- ->set_dumper_registrations_ignored_for_testing(true);
-
- RenderViewTest::SetUp();
-
- callback_call_count_ = 0;
- last_callback_dump_guid_ = 0;
- last_callback_status_ = false;
- wait_for_ipc_message_type_ = 0;
- callback_ = base::Bind(&ChildTracingTest::OnMemoryDumpCallback,
- base::Unretained(this));
- task_runner_ = base::ThreadTaskRunnerHandle::Get();
- ctmf_ = make_scoped_refptr(new ChildTraceMessageFilter(task_runner_.get()));
- render_thread_->AddFilter(ctmf_.get());
-
- // Add a filter to the TestSink which allows to WaitForIPCMessage() by
- // posting a nested RunLoop closure when a given IPC Message is seen.
- render_thread_->sink().AddFilter(this);
-
- // Getting an instance of |ChildMemoryDumpManagerDelegateImpl| calls
- // |MemoryDumpManager::Initialize| with the correct delegate.
- ChildMemoryDumpManagerDelegateImpl::GetInstance();
- }
-
- void TearDown() override {
- render_thread_->sink().RemoveFilter(this);
- RenderViewTest::TearDown();
- MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
- mock_dump_provider_.get());
- mock_dump_provider_.reset();
- ctmf_ = nullptr;
- task_runner_ = nullptr;
- }
-
- // IPC::Filter implementation.
- bool OnMessageReceived(const IPC::Message& message) override {
- if (message.type() == wait_for_ipc_message_type_) {
- DCHECK(!wait_for_ipc_closure_.is_null());
- task_runner_->PostTask(FROM_HERE, wait_for_ipc_closure_);
- }
- // Always propagate messages to the sink, never consume them here.
- return false;
- }
-
- const IPC::Message* WaitForIPCMessage(uint32_t message_type) {
- base::RunLoop run_loop;
- wait_for_ipc_message_type_ = message_type;
- wait_for_ipc_closure_ = run_loop.QuitClosure();
- run_loop.Run();
- wait_for_ipc_message_type_ = 0;
- wait_for_ipc_closure_.Reset();
- return render_thread_->sink().GetUniqueMessageMatching(message_type);
- }
-
- // Simulates a synthetic browser -> child (this process) IPC message.
- void SimulateSyntheticMessageFromBrowser(const IPC::Message& msg) {
- ctmf_->OnMessageReceived(msg);
- }
-
- void EnableTracingWithMemoryDumps() {
- // Re-enabling tracing could crash these tests https://crbug.com/656729 .
- if (base::trace_event::TraceLog::GetInstance()->IsEnabled()) {
- FAIL() << "Tracing seems to be already enabled. "
- "Very likely this is because the startup tracing file "
- "has been leaked from a previous test.";
- }
-
- std::string category_filter = "-*,"; // Disable all other trace categories.
- category_filter += MemoryDumpManager::kTraceCategory;
- base::trace_event::TraceConfig trace_config(category_filter, "");
- TracingMsg_BeginTracing msg(trace_config.ToString(), base::TimeTicks(), 0);
- SimulateSyntheticMessageFromBrowser(msg);
- }
-
- void DisableTracing() {
- SimulateSyntheticMessageFromBrowser(TracingMsg_EndTracing());
- }
-
- // Simulates a synthetic browser -> child process memory dump request and
- // checks that the child actually sends a response to that.
- void RequestProcessMemoryDumpAndCheckResponse(uint64_t dump_guid) {
- SimulateSyntheticMessageFromBrowser(TracingMsg_ProcessMemoryDumpRequest(
- {dump_guid, MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED}));
-
- // Check that a child -> browser response to the local dump request is sent.
- const IPC::Message* msg =
- WaitForIPCMessage(TracingHostMsg_ProcessMemoryDumpResponse::ID);
- EXPECT_NE(nullptr, msg);
-
- // Check that the |dump_guid| and the |success| fields are properly set.
- TracingHostMsg_ProcessMemoryDumpResponse::Param params;
- TracingHostMsg_ProcessMemoryDumpResponse::Read(msg, &params);
- const uint64_t resp_guid = std::get<0>(params);
- const bool resp_success = std::get<1>(params);
- EXPECT_EQ(dump_guid, resp_guid);
- EXPECT_TRUE(resp_success);
- }
-
- // Retrieves the MemoryDumpRequestArgs of the global memory dump request that
- // this child process tried to send to the browser. Fails if either none or
- // multiple requests were sent.
- MemoryDumpRequestArgs GetInterceptedGlobalMemoryDumpRequest() {
- const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
- TracingHostMsg_GlobalMemoryDumpRequest::ID);
- EXPECT_NE(nullptr, msg);
- TracingHostMsg_GlobalMemoryDumpRequest::Param params;
- TracingHostMsg_GlobalMemoryDumpRequest::Read(msg, &params);
- MemoryDumpRequestArgs args = std::get<0>(params);
- EXPECT_NE(0U, args.dump_guid);
- return args;
- }
-
- scoped_refptr<ChildTraceMessageFilter> ctmf_;
- std::unique_ptr<MockDumpProvider> mock_dump_provider_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- base::trace_event::MemoryDumpCallback callback_;
- uint32_t wait_for_ipc_message_type_;
- base::Closure wait_for_ipc_closure_;
- uint32_t callback_call_count_;
- uint64_t last_callback_dump_guid_;
- bool last_callback_status_;
-};
-
-// Covers the case of some browser-initiated memory dumps.
-#if defined(OS_ANDROID)
-// Flaky on Android. http://crbug.com/620734.
-#define MAYBE_BrowserInitiatedMemoryDumps DISABLED_BrowserInitiatedMemoryDumps
-#else
-#define MAYBE_BrowserInitiatedMemoryDumps BrowserInitiatedMemoryDumps
-#endif
-TEST_F(ChildTracingTest, MAYBE_BrowserInitiatedMemoryDumps) {
- const uint32_t kNumDumps = 3;
-
- EnableTracingWithMemoryDumps();
- EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_, _))
- .Times(kNumDumps)
- .WillRepeatedly(Return(true));
-
- for (uint32_t i = 0; i < kNumDumps; ++i) {
- render_thread_->sink().ClearMessages();
- RequestProcessMemoryDumpAndCheckResponse(i + 1);
- }
-
- DisableTracing();
-}
-
-// Covers the case of one simple child-initiated memory dump without callback,
-// simulating a global memory dump request to the browser (+ response).
-TEST_F(ChildTracingTest, SingleChildInitiatedMemoryDump) {
- EnableTracingWithMemoryDumps();
-
- // Expect that our mock dump provider is called when the emulated memory dump
- // request (browser -> child) is sent.
- EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_, _))
- .Times(1)
- .WillRepeatedly(Return(true));
-
- // Send the global memory dump request to the browser.
- render_thread_->sink().ClearMessages();
- MemoryDumpManager::GetInstance()->RequestGlobalDump(
- MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::DETAILED);
- base::RunLoop().RunUntilIdle();
-
- // Check that the child -> browser global dump request IPC is actually sent.
- MemoryDumpRequestArgs args = GetInterceptedGlobalMemoryDumpRequest();
- EXPECT_EQ(MemoryDumpType::EXPLICITLY_TRIGGERED, args.dump_type);
-
- // Emulate a browser -> child process dump request and corresponding response.
- RequestProcessMemoryDumpAndCheckResponse(args.dump_guid);
-
- // Send a synthetic browser -> child global memory dump response.
- SimulateSyntheticMessageFromBrowser(
- TracingMsg_GlobalMemoryDumpResponse(args.dump_guid, true));
-
- DisableTracing();
-}
-
-// Covers the case of a global memory dump being requested while another one is
-// in progress and has not been acknowledged by the browser. The second request
-// is expected to fail immediately, while the first one is expected to suceed.
-TEST_F(ChildTracingTest, OverlappingChildInitiatedMemoryDumps) {
- EnableTracingWithMemoryDumps();
-
- // Expect that our mock dump provider is called only once.
- EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_, _))
- .Times(1)
- .WillRepeatedly(Return(true));
-
- // Send the global memory dump request to the browser.
- render_thread_->sink().ClearMessages();
- MemoryDumpManager::GetInstance()->RequestGlobalDump(
- MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::DETAILED,
- callback_);
- base::RunLoop().RunUntilIdle();
-
- // Check that the child -> browser global dump request IPC is actually sent.
- MemoryDumpRequestArgs args = GetInterceptedGlobalMemoryDumpRequest();
- EXPECT_EQ(MemoryDumpType::EXPLICITLY_TRIGGERED, args.dump_type);
-
- // Emulate a browser -> child process dump request and corresponding response.
- RequestProcessMemoryDumpAndCheckResponse(args.dump_guid);
-
- // Before the response for the first global dump is sent, send another one,
- // and expect that to fail.
- render_thread_->sink().ClearMessages();
- MemoryDumpManager::GetInstance()->RequestGlobalDump(
- MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::DETAILED,
- callback_);
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(1u, callback_call_count_);
- EXPECT_FALSE(last_callback_status_);
- // Whatever the guid of the second failing request is, it cannot possibly be
- // equal to the guid of the first request.
- EXPECT_NE(args.dump_guid, last_callback_dump_guid_);
-
- // Also, check that no request has been forwarded to the browser (because the
- // first request is still outstanding and has not received any response yet).
- EXPECT_EQ(nullptr, render_thread_->sink().GetUniqueMessageMatching(
- TracingHostMsg_GlobalMemoryDumpRequest::ID));
-
- // Now send a synthetic browser -> child response to the first request.
- SimulateSyntheticMessageFromBrowser(
- TracingMsg_GlobalMemoryDumpResponse(args.dump_guid, true));
-
- // Verify that the the callback for the first request is finally called.
- EXPECT_EQ(2u, callback_call_count_);
- EXPECT_EQ(args.dump_guid, last_callback_dump_guid_);
- EXPECT_TRUE(last_callback_status_);
-
- DisableTracing();
-}
-
-// Covers the case of five child-initiated global memory dumps. Each global dump
-// request has a callback, which is expected to fail for 3 out of 5 cases.
-TEST_F(ChildTracingTest, MultipleChildInitiatedMemoryDumpWithFailures) {
- const uint32_t kNumRequests = 5;
- MemoryDumpType kDumpType = MemoryDumpType::EXPLICITLY_TRIGGERED;
-
- EnableTracingWithMemoryDumps();
- EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_, _))
- .Times(kNumRequests)
- .WillRepeatedly(Return(true));
-
- for (uint32_t i = 0; i < kNumRequests; ++i) {
- render_thread_->sink().ClearMessages();
- MemoryDumpManager::GetInstance()->RequestGlobalDump(
- kDumpType, MemoryDumpLevelOfDetail::DETAILED, callback_);
- base::RunLoop().RunUntilIdle();
-
- MemoryDumpRequestArgs args = GetInterceptedGlobalMemoryDumpRequest();
- EXPECT_EQ(kDumpType, args.dump_type);
- RequestProcessMemoryDumpAndCheckResponse(args.dump_guid);
-
- const bool success = (i & 1) ? true : false;
- SimulateSyntheticMessageFromBrowser(
- TracingMsg_GlobalMemoryDumpResponse(args.dump_guid, success));
- EXPECT_EQ(i + 1, callback_call_count_);
- EXPECT_EQ(args.dump_guid, last_callback_dump_guid_);
- EXPECT_EQ(success, last_callback_status_);
- }
-
- DisableTracing();
-}
-
-} // namespace tracing
diff --git a/chromium/components/tracing/common/process_metrics_memory_dump_provider.cc b/chromium/components/tracing/common/process_metrics_memory_dump_provider.cc
index d8a29651182..2936256acd3 100644
--- a/chromium/components/tracing/common/process_metrics_memory_dump_provider.cc
+++ b/chromium/components/tracing/common/process_metrics_memory_dump_provider.cc
@@ -36,6 +36,7 @@
#include <mach/mach.h>
#include "base/numerics/safe_math.h"
+#include "base/process/process_metrics.h"
#endif // defined(OS_MACOSX)
#if defined(OS_WIN)
@@ -387,31 +388,20 @@ bool GetDyldRegions(std::vector<VMRegion>* regions) {
return true;
}
-void PopulateByteStats(VMRegion* region, const vm_region_submap_info_64& info) {
- uint32_t share_mode = info.share_mode;
- if (share_mode == SM_COW && info.ref_count == 1)
- share_mode = SM_PRIVATE;
-
- uint64_t dirty_bytes = info.pages_dirtied * PAGE_SIZE;
- uint64_t clean_bytes =
- (info.pages_resident - info.pages_reusable - info.pages_dirtied) *
- PAGE_SIZE;
- switch (share_mode) {
+void PopulateByteStats(VMRegion* region,
+ const vm_region_top_info_data_t& info) {
+ uint64_t dirty_bytes =
+ (info.private_pages_resident + info.shared_pages_resident) * PAGE_SIZE;
+ switch (info.share_mode) {
case SM_LARGE_PAGE:
case SM_PRIVATE:
- region->byte_stats_private_dirty_resident = dirty_bytes;
- region->byte_stats_private_clean_resident = clean_bytes;
- break;
case SM_COW:
region->byte_stats_private_dirty_resident = dirty_bytes;
- region->byte_stats_shared_clean_resident = clean_bytes;
- break;
case SM_SHARED:
case SM_PRIVATE_ALIASED:
case SM_TRUESHARED:
case SM_SHARED_ALIASED:
region->byte_stats_shared_dirty_resident = dirty_bytes;
- region->byte_stats_shared_clean_resident = clean_bytes;
break;
case SM_EMPTY:
break;
@@ -421,38 +411,45 @@ void PopulateByteStats(VMRegion* region, const vm_region_submap_info_64& info) {
}
}
-// Creates VMRegions from mach_vm_region_recurse. Returns whether the operation
+// Creates VMRegions using mach vm syscalls. Returns whether the operation
// succeeded.
bool GetAllRegions(std::vector<VMRegion>* regions) {
const int pid = getpid();
task_t task = mach_task_self();
mach_vm_size_t size = 0;
- vm_region_submap_info_64 info;
- natural_t depth = 1;
- mach_msg_type_number_t count = sizeof(info);
- for (mach_vm_address_t address = MACH_VM_MIN_ADDRESS;; address += size) {
- memset(&info, 0, sizeof(info));
- kern_return_t kr = mach_vm_region_recurse(
- task, &address, &size, &depth,
- reinterpret_cast<vm_region_info_t>(&info), &count);
- if (kr == KERN_INVALID_ADDRESS) // nothing else left
+ mach_vm_address_t address = MACH_VM_MIN_ADDRESS;
+ while (true) {
+ base::CheckedNumeric<mach_vm_address_t> next_address(address);
+ next_address += size;
+ if (!next_address.IsValid())
+ return false;
+ address = next_address.ValueOrDie();
+ mach_vm_address_t address_copy = address;
+
+ vm_region_top_info_data_t info;
+ base::MachVMRegionResult result =
+ base::GetTopInfo(task, &size, &address, &info);
+ if (result == base::MachVMRegionResult::Error)
+ return false;
+ if (result == base::MachVMRegionResult::Finished)
break;
- if (kr != KERN_SUCCESS) // something bad
+
+ vm_region_basic_info_64 basic_info;
+ mach_vm_size_t dummy_size = 0;
+ result = base::GetBasicInfo(task, &dummy_size, &address_copy, &basic_info);
+ if (result == base::MachVMRegionResult::Error)
return false;
- if (info.is_submap) {
- size = 0;
- ++depth;
- continue;
- }
+ if (result == base::MachVMRegionResult::Finished)
+ break;
VMRegion region;
PopulateByteStats(&region, info);
- if (info.protection & VM_PROT_READ)
+ if (basic_info.protection & VM_PROT_READ)
region.protection_flags |= VMRegion::kProtectionFlagsRead;
- if (info.protection & VM_PROT_WRITE)
+ if (basic_info.protection & VM_PROT_WRITE)
region.protection_flags |= VMRegion::kProtectionFlagsWrite;
- if (info.protection & VM_PROT_EXECUTE)
+ if (basic_info.protection & VM_PROT_EXECUTE)
region.protection_flags |= VMRegion::kProtectionFlagsExec;
char buffer[MAXPATHLEN];
@@ -460,16 +457,12 @@ bool GetAllRegions(std::vector<VMRegion>* regions) {
if (length != 0)
region.mapped_file.assign(buffer, length);
- region.byte_stats_swapped = info.pages_swapped_out * PAGE_SIZE;
+ // There's no way to get swapped or clean bytes without doing a
+ // very expensive syscalls that crawls every single page in the memory
+ // object.
region.start_address = address;
region.size_in_bytes = size;
regions->push_back(region);
-
- base::CheckedNumeric<mach_vm_address_t> numeric(address);
- numeric += size;
- if (!numeric.IsValid())
- return false;
- address = numeric.ValueOrDie();
}
return true;
}
@@ -608,9 +601,24 @@ bool ProcessMetricsMemoryDumpProvider::OnMemoryDump(
bool ProcessMetricsMemoryDumpProvider::DumpProcessTotals(
const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) {
- const uint64_t rss_bytes = rss_bytes_for_testing
- ? rss_bytes_for_testing
- : process_metrics_->GetWorkingSetSize();
+#if defined(OS_MACOSX)
+ size_t private_bytes;
+ size_t shared_bytes;
+ size_t resident_bytes;
+ size_t locked_bytes;
+ if (!process_metrics_->GetMemoryBytes(&private_bytes, &shared_bytes,
+ &resident_bytes, &locked_bytes)) {
+ return false;
+ }
+ uint64_t rss_bytes = resident_bytes;
+ pmd->process_totals()->SetExtraFieldInBytes("private_bytes", private_bytes);
+ pmd->process_totals()->SetExtraFieldInBytes("shared_bytes", shared_bytes);
+ pmd->process_totals()->SetExtraFieldInBytes("locked_bytes", locked_bytes);
+#else
+ uint64_t rss_bytes = process_metrics_->GetWorkingSetSize();
+#endif // defined(OS_MACOSX)
+ if (rss_bytes_for_testing)
+ rss_bytes = rss_bytes_for_testing;
// rss_bytes will be 0 if the process ended while dumping.
if (!rss_bytes)
@@ -637,12 +645,6 @@ bool ProcessMetricsMemoryDumpProvider::DumpProcessTotals(
}
close(clear_refs_fd);
}
-#elif defined(MACOSX)
- size_t private_bytes;
- bool res = process_metrics_->GetMemoryBytes(&private_bytes,
- nullptr /* shared_bytes */);
- if (res)
- pmd->process_totals()->SetExtraFieldInBytes("private_bytes", private_bytes);
#elif defined(OS_WIN)
if (args.level_of_detail ==
base::trace_event::MemoryDumpLevelOfDetail::DETAILED) {
diff --git a/chromium/components/tracing/common/process_metrics_memory_dump_provider_unittest.cc b/chromium/components/tracing/common/process_metrics_memory_dump_provider_unittest.cc
index 77124349694..b28d3f2aad6 100644
--- a/chromium/components/tracing/common/process_metrics_memory_dump_provider_unittest.cc
+++ b/chromium/components/tracing/common/process_metrics_memory_dump_provider_unittest.cc
@@ -410,28 +410,5 @@ TEST(ProcessMetricsMemoryDumpProviderTest, TestMachOReading) {
EXPECT_TRUE(found_appkit);
}
-TEST(ProcessMetricsMemoryDumpProviderTest, NoDuplicateRegions) {
- using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion;
- ProcessMetricsMemoryDumpProvider mdp(base::kNullProcessId);
- base::trace_event::MemoryDumpArgs args;
- base::trace_event::ProcessMemoryDump dump(nullptr, args);
- ASSERT_TRUE(mdp.DumpProcessMemoryMaps(args, &dump));
- ASSERT_TRUE(dump.has_process_mmaps());
-
- std::vector<VMRegion> regions;
- regions.reserve(dump.process_mmaps()->vm_regions().size());
- for (const VMRegion& region : dump.process_mmaps()->vm_regions())
- regions.push_back(region);
- std::sort(regions.begin(), regions.end(),
- [](const VMRegion& a, const VMRegion& b) -> bool {
- return a.start_address < b.start_address;
- });
- uint64_t last_address = 0;
- for (const VMRegion& region : regions) {
- EXPECT_GE(region.start_address, last_address);
- last_address = region.start_address + region.size_in_bytes;
- }
-}
-
#endif // defined(OS_MACOSX)
} // namespace tracing
diff --git a/chromium/components/tracing/common/trace_startup.cc b/chromium/components/tracing/common/trace_startup.cc
index 2c8ae37025c..551564c6709 100644
--- a/chromium/components/tracing/common/trace_startup.cc
+++ b/chromium/components/tracing/common/trace_startup.cc
@@ -38,10 +38,14 @@ void EnableStartupTracingIfNeeded(bool can_access_file_system) {
trace_config, base::trace_event::TraceLog::RECORDING_MODE);
} else if (can_access_file_system &&
tracing::TraceConfigFile::GetInstance()->IsEnabled()) {
+ const base::trace_event::TraceConfig& trace_config =
+ tracing::TraceConfigFile::GetInstance()->GetTraceConfig();
+ uint8_t modes = base::trace_event::TraceLog::RECORDING_MODE;
+ if (!trace_config.event_filters().empty())
+ modes |= base::trace_event::TraceLog::FILTERING_MODE;
// This checks kTraceConfigFile switch.
base::trace_event::TraceLog::GetInstance()->SetEnabled(
- tracing::TraceConfigFile::GetInstance()->GetTraceConfig(),
- base::trace_event::TraceLog::RECORDING_MODE);
+ tracing::TraceConfigFile::GetInstance()->GetTraceConfig(), modes);
}
}
diff --git a/chromium/components/tracing/core/proto_zero_message.cc b/chromium/components/tracing/core/proto_zero_message.cc
index a555683428c..20785476d13 100644
--- a/chromium/components/tracing/core/proto_zero_message.cc
+++ b/chromium/components/tracing/core/proto_zero_message.cc
@@ -24,7 +24,7 @@ ProtoZeroMessage::ProtoZeroMessage() {
// |nested_messages_arena_| and implictly destroyed when the arena of the
// root message goes away. This is fine as long as all the fields are PODs,
// hence the static_assert below.
- static_assert(base::is_trivially_destructible<ProtoZeroMessage>::value,
+ static_assert(std::is_trivially_destructible<ProtoZeroMessage>::value,
"ProtoZeroMessage must be trivially destructible");
static_assert(
diff --git a/chromium/components/tracing/tools/proto_zero_plugin/BUILD.gn b/chromium/components/tracing/tools/proto_zero_plugin/BUILD.gn
index cdf0eb16073..15a71404391 100644
--- a/chromium/components/tracing/tools/proto_zero_plugin/BUILD.gn
+++ b/chromium/components/tracing/tools/proto_zero_plugin/BUILD.gn
@@ -12,5 +12,11 @@ if (current_toolchain == host_toolchain) {
deps = [
"//third_party/protobuf:protoc_lib",
]
+ if (is_win) {
+ # TODO(thomasanderson): remove when https://crbug.com/703251 is resolved
+ # by Microsoft.
+ configs -= [ "//build/config/win:default_incremental_linking" ]
+ configs += [ "//build/config/win:no_incremental_linking" ]
+ }
}
}
diff --git a/chromium/components/translate/core/browser/BUILD.gn b/chromium/components/translate/core/browser/BUILD.gn
index fc31a04facd..1e56c7eae3f 100644
--- a/chromium/components/translate/core/browser/BUILD.gn
+++ b/chromium/components/translate/core/browser/BUILD.gn
@@ -11,6 +11,10 @@ static_library("browser") {
"language_state.cc",
"language_state.h",
"page_translated_details.h",
+ "ranker_model.cc",
+ "ranker_model.h",
+ "ranker_model_loader.cc",
+ "ranker_model_loader.h",
"translate_accept_languages.cc",
"translate_accept_languages.h",
"translate_browser_metrics.cc",
@@ -30,10 +34,9 @@ static_library("browser") {
"translate_manager.h",
"translate_prefs.cc",
"translate_prefs.h",
- "translate_ranker.cc",
"translate_ranker.h",
- "translate_ranker_metrics_provider.cc",
- "translate_ranker_metrics_provider.h",
+ "translate_ranker_impl.cc",
+ "translate_ranker_impl.h",
"translate_script.cc",
"translate_script.h",
"translate_step.h",
@@ -59,6 +62,7 @@ static_library("browser") {
"//components/strings",
"//components/translate/core/browser/proto",
"//components/translate/core/common",
+ "//components/ukm",
"//components/variations",
"//google_apis",
"//net",
@@ -90,11 +94,15 @@ source_set("unit_tests") {
"language_state_unittest.cc",
"mock_translate_driver.cc",
"mock_translate_driver.h",
+ "mock_translate_ranker.cc",
+ "mock_translate_ranker.h",
+ "ranker_model_loader_unittest.cc",
+ "ranker_model_unittest.cc",
"translate_browser_metrics_unittest.cc",
"translate_language_list_unittest.cc",
"translate_manager_unittest.cc",
"translate_prefs_unittest.cc",
- "translate_ranker_unittest.cc",
+ "translate_ranker_impl_unittest.cc",
"translate_script_unittest.cc",
"translate_ui_delegate_unittest.cc",
]
@@ -109,6 +117,8 @@ source_set("unit_tests") {
"//components/sync_preferences:test_support",
"//components/translate/core/browser/proto",
"//components/translate/core/common",
+ "//components/ukm",
+ "//components/ukm:test_support",
"//components/variations",
"//net:test_support",
"//testing/gtest",
diff --git a/chromium/components/translate/core/browser/proto/BUILD.gn b/chromium/components/translate/core/browser/proto/BUILD.gn
index c064a49e781..e7424bd588b 100644
--- a/chromium/components/translate/core/browser/proto/BUILD.gn
+++ b/chromium/components/translate/core/browser/proto/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/protobuf/proto_library.gni")
proto_library("proto") {
sources = [
+ "ranker_model.proto",
"translate_ranker_model.proto",
]
}
diff --git a/chromium/components/translate/ios/browser/BUILD.gn b/chromium/components/translate/ios/browser/BUILD.gn
index b514e9169f6..f4b7c5db0a2 100644
--- a/chromium/components/translate/ios/browser/BUILD.gn
+++ b/chromium/components/translate/ios/browser/BUILD.gn
@@ -43,6 +43,7 @@ js_compile_checked("injected_js") {
}
source_set("unit_tests") {
+ configs += [ "//build/config/compiler:enable_arc" ]
testonly = true
sources = [
"js_translate_manager_unittest.mm",
diff --git a/chromium/components/ui_devtools/string_util.h b/chromium/components/ui_devtools/string_util.h
index 4efb835380f..d08b8b6f22f 100644
--- a/chromium/components/ui_devtools/string_util.h
+++ b/chromium/components/ui_devtools/string_util.h
@@ -45,6 +45,11 @@ class StringUtil {
static String fromDouble(double number) {
return base::DoubleToString(number);
}
+ static double toDouble(const char* s, size_t len, bool* ok) {
+ double v = 0.0;
+ *ok = base::StringToDouble(std::string(s, len), &v);
+ return *ok ? v : 0.0;
+ }
static void builderAppend(StringBuilder& builder, const String& s) {
builder.append(s);
}
diff --git a/chromium/components/ukm/BUILD.gn b/chromium/components/ukm/BUILD.gn
index 89308477735..dc9c405b757 100644
--- a/chromium/components/ukm/BUILD.gn
+++ b/chromium/components/ukm/BUILD.gn
@@ -9,8 +9,6 @@ import("//testing/test.gni")
# URLs for top-level navigations.
static_library("ukm") {
sources = [
- "metrics_reporting_scheduler.cc",
- "metrics_reporting_scheduler.h",
"persisted_logs_metrics_impl.cc",
"persisted_logs_metrics_impl.h",
"ukm_entry.cc",
@@ -19,6 +17,10 @@ static_library("ukm") {
"ukm_entry_builder.h",
"ukm_pref_names.cc",
"ukm_pref_names.h",
+ "ukm_reporting_service.cc",
+ "ukm_reporting_service.h",
+ "ukm_rotation_scheduler.cc",
+ "ukm_rotation_scheduler.h",
"ukm_service.cc",
"ukm_service.h",
"ukm_source.cc",
diff --git a/chromium/components/ukm/OWNERS b/chromium/components/ukm/OWNERS
index 1cfdbd829ee..189104122ea 100644
--- a/chromium/components/ukm/OWNERS
+++ b/chromium/components/ukm/OWNERS
@@ -1,3 +1,5 @@
asvitkine@chromium.org
holte@chromium.org
rkaplow@chromium.org
+
+# COMPONENT: Internals>Metrics
diff --git a/chromium/components/ukm/metrics_reporting_scheduler.cc b/chromium/components/ukm/metrics_reporting_scheduler.cc
deleted file mode 100644
index cea69c84854..00000000000
--- a/chromium/components/ukm/metrics_reporting_scheduler.cc
+++ /dev/null
@@ -1,31 +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/ukm/metrics_reporting_scheduler.h"
-
-#include "base/metrics/histogram_macros.h"
-
-namespace ukm {
-
-MetricsReportingScheduler::MetricsReportingScheduler(
- const base::Closure& upload_callback,
- const base::Callback<base::TimeDelta(void)>& upload_interval_callback)
- : metrics::MetricsReportingScheduler(upload_callback,
- upload_interval_callback) {}
-
-MetricsReportingScheduler::~MetricsReportingScheduler() = default;
-
-void MetricsReportingScheduler::LogMetricsInitSequence(InitSequence sequence) {
- UMA_HISTOGRAM_ENUMERATION("UKM.InitSequence", sequence,
- INIT_SEQUENCE_ENUM_SIZE);
-}
-
-void MetricsReportingScheduler::LogActualUploadInterval(
- base::TimeDelta interval) {
- UMA_HISTOGRAM_CUSTOM_COUNTS("UKM.ActualLogUploadInterval",
- interval.InMinutes(), 1,
- base::TimeDelta::FromHours(12).InMinutes(), 50);
-}
-
-} // namespace ukm
diff --git a/chromium/components/ukm/metrics_reporting_scheduler.h b/chromium/components/ukm/metrics_reporting_scheduler.h
deleted file mode 100644
index 2641330e5b1..00000000000
--- a/chromium/components/ukm/metrics_reporting_scheduler.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_UKM_METRICS_REPORTING_SCHEDULER_H_
-#define COMPONENTS_UKM_METRICS_REPORTING_SCHEDULER_H_
-
-#include "base/time/time.h"
-#include "components/metrics/metrics_reporting_scheduler.h"
-
-namespace ukm {
-
-// Scheduler task to drive a MetricsService object's uploading.
-class MetricsReportingScheduler : public metrics::MetricsReportingScheduler {
- public:
- // Creates MetricsServiceScheduler object with the given |upload_callback|
- // callback to call when uploading should happen and
- // |upload_interval_callback| to determine the interval between uploads
- // in steady state.
- MetricsReportingScheduler(
- const base::Closure& upload_callback,
- const base::Callback<base::TimeDelta(void)>& upload_interval_callback);
- ~MetricsReportingScheduler() override;
-
- private:
- // Record the init sequence order histogram.
- void LogMetricsInitSequence(InitSequence sequence) override;
-
- // Record the upload interval time.
- void LogActualUploadInterval(base::TimeDelta interval) override;
-
- DISALLOW_COPY_AND_ASSIGN(MetricsReportingScheduler);
-};
-
-} // namespace ukm
-
-#endif // COMPONENTS_UKM_METRICS_REPORTING_SCHEDULER_H_
diff --git a/chromium/components/ukm/test_ukm_service.cc b/chromium/components/ukm/test_ukm_service.cc
index b22e5f3de10..824fa25a7fe 100644
--- a/chromium/components/ukm/test_ukm_service.cc
+++ b/chromium/components/ukm/test_ukm_service.cc
@@ -4,6 +4,11 @@
#include "components/ukm/test_ukm_service.h"
+#include "base/logging.h"
+#include "base/metrics/metrics_hashes.h"
+#include "components/ukm/ukm_entry.h"
+#include "components/ukm/ukm_source.h"
+
namespace ukm {
UkmServiceTestingHarness::UkmServiceTestingHarness() {
@@ -25,12 +30,44 @@ TestUkmService::TestUkmService(PrefService* prefs_service)
TestUkmService::~TestUkmService() = default;
-const UkmSource* TestUkmService::GetSource(size_t source_num) const {
- return sources_for_testing()[source_num].get();
+const std::map<int32_t, std::unique_ptr<UkmSource>>&
+TestUkmService::GetSources() const {
+ return sources_for_testing();
+}
+
+const UkmSource* TestUkmService::GetSourceForUrl(const char* url) const {
+ const UkmSource* source = nullptr;
+ for (const auto& kv : sources_for_testing()) {
+ if (kv.second->url() == url) {
+ DCHECK_EQ(nullptr, source);
+ source = kv.second.get();
+ }
+ }
+ return source;
+}
+
+const UkmSource* TestUkmService::GetSourceForSourceId(int32_t source_id) const {
+ const UkmSource* source = nullptr;
+ for (const auto& kv : sources_for_testing()) {
+ if (kv.second->id() == source_id) {
+ DCHECK_EQ(nullptr, source);
+ source = kv.second.get();
+ }
+ }
+ return source;
}
const UkmEntry* TestUkmService::GetEntry(size_t entry_num) const {
return entries_for_testing()[entry_num].get();
}
+const UkmEntry* TestUkmService::GetEntryForEntryName(
+ const char* entry_name) const {
+ for (const auto& it : entries_for_testing()) {
+ if (it->event_hash() == base::HashMetricName(entry_name))
+ return it.get();
+ }
+ return nullptr;
+}
+
} // namespace ukm
diff --git a/chromium/components/ukm/test_ukm_service.h b/chromium/components/ukm/test_ukm_service.h
index 33c81f28f2f..55d5920411d 100644
--- a/chromium/components/ukm/test_ukm_service.h
+++ b/chromium/components/ukm/test_ukm_service.h
@@ -22,10 +22,13 @@ class TestUkmService : public UkmService {
~TestUkmService() override;
size_t sources_count() const { return sources_for_testing().size(); }
- const UkmSource* GetSource(size_t source_num) const;
+ const std::map<int32_t, std::unique_ptr<UkmSource>>& GetSources() const;
+ const UkmSource* GetSourceForUrl(const char* url) const;
+ const UkmSource* GetSourceForSourceId(int32_t source_id) const;
size_t entries_count() const { return entries_for_testing().size(); }
const UkmEntry* GetEntry(size_t entry_num) const;
+ const UkmEntry* GetEntryForEntryName(const char* entry_name) const;
private:
metrics::TestMetricsServiceClient test_metrics_service_client_;
diff --git a/chromium/components/ukm/ukm_entry.cc b/chromium/components/ukm/ukm_entry.cc
index 69e61040213..88b724c06f6 100644
--- a/chromium/components/ukm/ukm_entry.cc
+++ b/chromium/components/ukm/ukm_entry.cc
@@ -18,7 +18,6 @@ UkmEntry::~UkmEntry() {}
void UkmEntry::PopulateProto(Entry* proto_entry) const {
DCHECK(!proto_entry->has_source_id());
DCHECK(!proto_entry->has_event_hash());
- DCHECK(proto_entry->metrics_size() == 0);
proto_entry->set_source_id(source_id_);
proto_entry->set_event_hash(event_hash_);
diff --git a/chromium/components/ukm/ukm_entry.h b/chromium/components/ukm/ukm_entry.h
index d432bd0c1dd..9adcedb3fa0 100644
--- a/chromium/components/ukm/ukm_entry.h
+++ b/chromium/components/ukm/ukm_entry.h
@@ -29,6 +29,7 @@ class UkmEntry {
void PopulateProto(Entry* proto_entry) const;
int32_t source_id() const { return source_id_; }
+ uint64_t event_hash() const { return event_hash_; }
~UkmEntry();
diff --git a/chromium/components/ukm/ukm_entry_builder.cc b/chromium/components/ukm/ukm_entry_builder.cc
index fd640342ba5..fdff949038c 100644
--- a/chromium/components/ukm/ukm_entry_builder.cc
+++ b/chromium/components/ukm/ukm_entry_builder.cc
@@ -17,9 +17,6 @@ UkmEntryBuilder::UkmEntryBuilder(const UkmService::AddEntryCallback& callback,
entry_(new UkmEntry(source_id, event_name)) {}
UkmEntryBuilder::~UkmEntryBuilder() {
- if (entry_->metrics_.empty())
- return;
-
add_entry_callback_.Run(std::move(entry_));
}
diff --git a/chromium/components/ukm/ukm_reporting_service.cc b/chromium/components/ukm/ukm_reporting_service.cc
new file mode 100644
index 00000000000..aba99ad1cea
--- /dev/null
+++ b/chromium/components/ukm/ukm_reporting_service.cc
@@ -0,0 +1,104 @@
+// 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.
+
+// ReportingService specialized to report UKM metrics.
+
+#include "components/ukm/ukm_reporting_service.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_macros.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/ukm/persisted_logs_metrics_impl.h"
+#include "components/ukm/ukm_pref_names.h"
+#include "components/ukm/ukm_service.h"
+
+namespace ukm {
+
+namespace {
+
+// The UKM server's URL.
+constexpr char kMimeType[] = "application/vnd.chrome.ukm";
+
+// The number of UKM logs that will be stored in PersistedLogs before logs
+// start being dropped.
+constexpr int kMinPersistedLogs = 8;
+
+// The number of bytes UKM logs that will be stored in PersistedLogs before
+// logs start being dropped.
+// This ensures that a reasonable amount of history will be stored even if there
+// is a long series of very small logs.
+constexpr int kMinPersistedBytes = 300000;
+
+// If an upload fails, and the transmission was over this byte count, 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.
+constexpr size_t kMaxLogRetransmitSize = 100 * 1024;
+
+std::string GetServerUrl() {
+ constexpr char kDefaultServerUrl[] = "https://clients4.google.com/ukm";
+ std::string server_url =
+ base::GetFieldTrialParamValueByFeature(kUkmFeature, "ServerUrl");
+ if (!server_url.empty())
+ return server_url;
+ return kDefaultServerUrl;
+}
+
+} // namespace
+
+// static
+void UkmReportingService::RegisterPrefs(PrefRegistrySimple* registry) {
+ registry->RegisterListPref(prefs::kUkmPersistedLogs);
+ // Base class already registered by MetricsReportingService::RegisterPrefs
+ // ReportingService::RegisterPrefs(registry);
+}
+
+UkmReportingService::UkmReportingService(metrics::MetricsServiceClient* client,
+ PrefService* local_state)
+ : ReportingService(client, local_state, kMaxLogRetransmitSize),
+ persisted_logs_(base::MakeUnique<ukm::PersistedLogsMetricsImpl>(),
+ local_state,
+ prefs::kUkmPersistedLogs,
+ kMinPersistedLogs,
+ kMinPersistedBytes,
+ kMaxLogRetransmitSize) {}
+
+UkmReportingService::~UkmReportingService() {}
+
+metrics::LogStore* UkmReportingService::log_store() {
+ return &persisted_logs_;
+}
+
+std::string UkmReportingService::GetUploadUrl() const {
+ return GetServerUrl();
+}
+
+base::StringPiece UkmReportingService::upload_mime_type() const {
+ return kMimeType;
+}
+
+metrics::MetricsLogUploader::MetricServiceType
+UkmReportingService::service_type() const {
+ return metrics::MetricsLogUploader::UKM;
+}
+
+void UkmReportingService::LogCellularConstraint(bool upload_canceled) {
+ UMA_HISTOGRAM_BOOLEAN("UKM.LogUpload.Canceled.CellularConstraint",
+ upload_canceled);
+}
+
+void UkmReportingService::LogResponseOrErrorCode(int response_code,
+ int error_code) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("UKM.LogUpload.ResponseOrErrorCode",
+ response_code >= 0 ? response_code : error_code);
+}
+
+void UkmReportingService::LogSuccess(size_t log_size) {
+ UMA_HISTOGRAM_COUNTS_10000("UKM.LogSize.OnSuccess", log_size / 1024);
+}
+
+void UkmReportingService::LogLargeRejection(size_t log_size) {}
+
+} // namespace metrics
diff --git a/chromium/components/ukm/ukm_reporting_service.h b/chromium/components/ukm/ukm_reporting_service.h
new file mode 100644
index 00000000000..c62a5e3fdcd
--- /dev/null
+++ b/chromium/components/ukm/ukm_reporting_service.h
@@ -0,0 +1,65 @@
+// 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.
+
+// This file defines a service that sends ukm logs to a server.
+
+#ifndef COMPONENTS_UKM_UKM_REPORTING_SERVICE_H_
+#define COMPONENTS_UKM_UKM_REPORTING_SERVICE_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "components/metrics/persisted_logs.h"
+#include "components/metrics/reporting_service.h"
+
+class PrefService;
+class PrefRegistrySimple;
+
+namespace metrics {
+class MetricsServiceClient;
+}
+
+namespace ukm {
+
+// A service that uploads logs to the UKM server.
+class UkmReportingService : public metrics::ReportingService {
+ public:
+ // Creates the UkmReportingService with the given |client|, and
+ // |local_state|. Does not take ownership of the paramaters; instead stores
+ // a weak pointer to each. Caller should ensure that the parameters are valid
+ // for the lifetime of this class.
+ UkmReportingService(metrics::MetricsServiceClient* client,
+ PrefService* local_state);
+ ~UkmReportingService() override;
+
+ // At startup, prefs needs to be called with a list of all the pref names and
+ // types we'll be using.
+ static void RegisterPrefs(PrefRegistrySimple* registry);
+
+ metrics::PersistedLogs* ukm_log_store() { return &persisted_logs_; }
+ const metrics::PersistedLogs* ukm_log_store() const {
+ return &persisted_logs_;
+ }
+
+ private:
+ // metrics:ReportingService:
+ metrics::LogStore* log_store() override;
+ std::string GetUploadUrl() const override;
+ base::StringPiece upload_mime_type() const override;
+ metrics::MetricsLogUploader::MetricServiceType service_type() const override;
+ void LogCellularConstraint(bool upload_canceled) override;
+ void LogResponseOrErrorCode(int response_code, int error_code) override;
+ void LogSuccess(size_t log_size) override;
+ void LogLargeRejection(size_t log_size) override;
+
+ metrics::PersistedLogs persisted_logs_;
+
+ DISALLOW_COPY_AND_ASSIGN(UkmReportingService);
+};
+
+} // namespace ukm
+
+#endif // COMPONENTS_UKM_UKM_REPORTING_SERVICE_H_
diff --git a/chromium/components/ukm/ukm_rotation_scheduler.cc b/chromium/components/ukm/ukm_rotation_scheduler.cc
new file mode 100644
index 00000000000..787ed1abad1
--- /dev/null
+++ b/chromium/components/ukm/ukm_rotation_scheduler.cc
@@ -0,0 +1,24 @@
+// 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/ukm/ukm_rotation_scheduler.h"
+
+#include "base/metrics/histogram_macros.h"
+
+namespace ukm {
+
+UkmRotationScheduler::UkmRotationScheduler(
+ const base::Closure& upload_callback,
+ const base::Callback<base::TimeDelta(void)>& upload_interval_callback)
+ : metrics::MetricsRotationScheduler(upload_callback,
+ upload_interval_callback) {}
+
+UkmRotationScheduler::~UkmRotationScheduler() = default;
+
+void UkmRotationScheduler::LogMetricsInitSequence(InitSequence sequence) {
+ UMA_HISTOGRAM_ENUMERATION("UKM.InitSequence", sequence,
+ INIT_SEQUENCE_ENUM_SIZE);
+}
+
+} // namespace ukm
diff --git a/chromium/components/ukm/ukm_rotation_scheduler.h b/chromium/components/ukm/ukm_rotation_scheduler.h
new file mode 100644
index 00000000000..5c835277ea8
--- /dev/null
+++ b/chromium/components/ukm/ukm_rotation_scheduler.h
@@ -0,0 +1,33 @@
+// 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_UKM_METRICS_REPORTING_SCHEDULER_H_
+#define COMPONENTS_UKM_METRICS_REPORTING_SCHEDULER_H_
+
+#include "base/time/time.h"
+#include "components/metrics/metrics_rotation_scheduler.h"
+
+namespace ukm {
+
+// Scheduler to drive a UkmService object's log rotations.
+class UkmRotationScheduler : public metrics::MetricsRotationScheduler {
+ public:
+ // Creates UkmRotationScheduler object with the given |rotation_callback|
+ // callback to call when log rotation should happen and |interval_callback|
+ // to determine the interval between rotations in steady state.
+ UkmRotationScheduler(
+ const base::Closure& rotation_callback,
+ const base::Callback<base::TimeDelta(void)>& interval_callback);
+ ~UkmRotationScheduler() override;
+
+ private:
+ // Record the init sequence order histogram.
+ void LogMetricsInitSequence(InitSequence sequence) override;
+
+ DISALLOW_COPY_AND_ASSIGN(UkmRotationScheduler);
+};
+
+} // namespace ukm
+
+#endif // COMPONENTS_UKM_METRICS_REPORTING_SCHEDULER_H_
diff --git a/chromium/components/ukm/ukm_service.cc b/chromium/components/ukm/ukm_service.cc
index a43f426f346..4c190c946ff 100644
--- a/chromium/components/ukm/ukm_service.cc
+++ b/chromium/components/ukm/ukm_service.cc
@@ -14,8 +14,11 @@
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
+#include "base/metrics/metrics_hashes.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/metrics/metrics_log.h"
#include "components/metrics/metrics_log_uploader.h"
@@ -25,47 +28,26 @@
#include "components/metrics/proto/ukm/source.pb.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
-#include "components/ukm/metrics_reporting_scheduler.h"
#include "components/ukm/persisted_logs_metrics_impl.h"
#include "components/ukm/ukm_entry.h"
#include "components/ukm/ukm_entry_builder.h"
#include "components/ukm/ukm_pref_names.h"
+#include "components/ukm/ukm_rotation_scheduler.h"
#include "components/ukm/ukm_source.h"
namespace ukm {
namespace {
-constexpr char kMimeType[] = "application/vnd.chrome.ukm";
-
// The delay, in seconds, after starting recording before doing expensive
// initialization work.
constexpr int kInitializationDelaySeconds = 5;
-// The number of UKM logs that will be stored in PersistedLogs before logs
-// start being dropped.
-constexpr int kMinPersistedLogs = 8;
-
-// The number of bytes UKM logs that will be stored in PersistedLogs before
-// logs start being dropped.
-// This ensures that a reasonable amount of history will be stored even if there
-// is a long series of very small logs.
-constexpr int kMinPersistedBytes = 300000;
-
-// If an upload fails, and the transmission was over this byte count, 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.
-constexpr size_t kMaxLogRetransmitSize = 100 * 1024;
-
-// Gets the UKM Server URL.
-std::string GetServerUrl() {
- constexpr char kDefaultServerUrl[] = "https://clients4.google.com/ukm";
- std::string server_url =
- base::GetFieldTrialParamValueByFeature(kUkmFeature, "ServerUrl");
- if (!server_url.empty())
- return server_url;
- return kDefaultServerUrl;
+// Gets the list of whitelisted Entries as string. Format is a comma seperated
+// list of Entry names (as strings).
+std::string GetWhitelistEntries() {
+ return base::GetFieldTrialParamValueByFeature(kUkmFeature,
+ "WhitelistEntries");
}
// Gets the maximum number of Sources we'll keep in memory before discarding any
@@ -126,6 +108,7 @@ enum class DroppedDataReason {
NOT_DROPPED = 0,
RECORDING_DISABLED = 1,
MAX_HIT = 2,
+ NOT_WHITELISTED = 3,
NUM_DROPPED_DATA_REASONS
};
@@ -152,22 +135,15 @@ UkmService::UkmService(PrefService* pref_service,
client_id_(0),
session_id_(0),
client_(client),
- persisted_logs_(std::unique_ptr<ukm::PersistedLogsMetricsImpl>(
- new ukm::PersistedLogsMetricsImpl()),
- pref_service,
- prefs::kUkmPersistedLogs,
- kMinPersistedLogs,
- kMinPersistedBytes,
- kMaxLogRetransmitSize),
+ reporting_service_(client, pref_service),
initialize_started_(false),
initialize_complete_(false),
- log_upload_in_progress_(false),
self_ptr_factory_(this) {
DCHECK(pref_service_);
DCHECK(client_);
DVLOG(1) << "UkmService::Constructor";
- persisted_logs_.LoadPersistedUnsentLogs();
+ reporting_service_.Initialize();
base::Closure rotate_callback =
base::Bind(&UkmService::RotateLog, self_ptr_factory_.GetWeakPtr());
@@ -176,11 +152,13 @@ UkmService::UkmService(PrefService* pref_service,
const base::Callback<base::TimeDelta(void)>& get_upload_interval_callback =
base::Bind(&metrics::MetricsServiceClient::GetStandardUploadInterval,
base::Unretained(client_));
- scheduler_.reset(new ukm::MetricsReportingScheduler(
- rotate_callback, get_upload_interval_callback));
+ scheduler_.reset(new ukm::UkmRotationScheduler(rotate_callback,
+ get_upload_interval_callback));
for (auto& provider : metrics_providers_)
provider->Init();
+
+ StoreWhitelistedEntries();
}
UkmService::~UkmService() {
@@ -210,6 +188,8 @@ void UkmService::DisableRecording() {
void UkmService::EnableReporting() {
DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(1) << "UkmService::EnableReporting";
+ if (reporting_service_.reporting_active())
+ return;
for (auto& provider : metrics_providers_)
provider->OnRecordingEnabled();
@@ -217,12 +197,15 @@ void UkmService::EnableReporting() {
if (!initialize_started_)
Initialize();
scheduler_->Start();
+ reporting_service_.EnableReporting();
}
void UkmService::DisableReporting() {
DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(1) << "UkmService::DisableReporting";
+ reporting_service_.DisableReporting();
+
for (auto& provider : metrics_providers_)
provider->OnRecordingDisabled();
@@ -264,14 +247,13 @@ void UkmService::Flush() {
DCHECK(thread_checker_.CalledOnValidThread());
if (initialize_complete_)
BuildAndStoreLog();
- persisted_logs_.PersistUnsentLogs();
+ reporting_service_.ukm_log_store()->PersistUnsentLogs();
}
void UkmService::Purge() {
DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(1) << "UkmService::Purge";
-
- persisted_logs_.Purge();
+ reporting_service_.ukm_log_store()->Purge();
sources_.clear();
entries_.clear();
}
@@ -292,7 +274,7 @@ void UkmService::RegisterMetricsProvider(
void UkmService::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterInt64Pref(prefs::kUkmClientId, 0);
registry->RegisterIntegerPref(prefs::kUkmSessionId, 0);
- registry->RegisterListPref(prefs::kUkmPersistedLogs);
+ UkmReportingService::RegisterPrefs(registry);
}
void UkmService::StartInitTask() {
@@ -313,11 +295,10 @@ void UkmService::FinishedInitTask() {
void UkmService::RotateLog() {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!log_upload_in_progress_);
DVLOG(1) << "UkmService::RotateLog";
- if (!persisted_logs_.has_unsent_logs())
+ if (!reporting_service_.ukm_log_store()->has_unsent_logs())
BuildAndStoreLog();
- StartScheduledUpload();
+ reporting_service_.Start();
}
void UkmService::BuildAndStoreLog() {
@@ -334,9 +315,9 @@ void UkmService::BuildAndStoreLog() {
if (ShouldRecordSessionId())
report.set_session_id(session_id_);
- for (const auto& source : sources_) {
+ for (const auto& kv : sources_) {
Source* proto_source = report.add_sources();
- source->PopulateProto(proto_source);
+ kv.second->PopulateProto(proto_source);
if (!ShouldRecordInitialUrl())
proto_source->clear_initial_url();
}
@@ -359,83 +340,7 @@ void UkmService::BuildAndStoreLog() {
std::string serialized_log;
report.SerializeToString(&serialized_log);
- persisted_logs_.StoreLog(serialized_log);
-}
-
-void UkmService::StartScheduledUpload() {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!log_upload_in_progress_);
- if (!persisted_logs_.has_unsent_logs()) {
- // No logs to send, so early out and schedule the next rotation.
- scheduler_->UploadFinished(true, /* has_unsent_logs */ false);
- return;
- }
- if (!persisted_logs_.has_staged_log())
- persisted_logs_.StageNextLog();
- // TODO(holte): Handle data usage on cellular, etc.
- if (!log_uploader_) {
- log_uploader_ = client_->CreateUploader(
- GetServerUrl(), kMimeType, metrics::MetricsLogUploader::UKM,
- base::Bind(&UkmService::OnLogUploadComplete,
- self_ptr_factory_.GetWeakPtr()));
- }
- log_upload_in_progress_ = true;
-
- const std::string hash =
- base::HexEncode(persisted_logs_.staged_log_hash().data(),
- persisted_logs_.staged_log_hash().size());
- log_uploader_->UploadLog(persisted_logs_.staged_log(), hash);
-}
-
-void UkmService::OnLogUploadComplete(int response_code) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(log_upload_in_progress_);
- DVLOG(1) << "UkmService::OnLogUploadComplete";
- log_upload_in_progress_ = false;
-
- UMA_HISTOGRAM_SPARSE_SLOWLY("UKM.Upload.ResponseCode", response_code);
-
- bool upload_succeeded = response_code == 200;
-
- // Provide boolean for error recovery (allow us to ignore response_code).
- bool discard_log = false;
- const size_t log_size_bytes = persisted_logs_.staged_log().length();
- if (upload_succeeded) {
- UMA_HISTOGRAM_COUNTS_10000("UKM.LogSize.OnSuccess", log_size_bytes / 1024);
- } else if (response_code == 400) {
- // Bad syntax. Retransmission won't work.
- discard_log = true;
- }
-
- if (upload_succeeded || discard_log) {
- // TODO(holte): The if below is a temporary fix for a crash bug. We should
- // revisit the logic and update it with a more correct fix. crbug.com/698819
- if (persisted_logs_.has_staged_log())
- persisted_logs_.DiscardStagedLog();
- // Store the updated list to disk now that the removed log is uploaded.
- persisted_logs_.PersistUnsentLogs();
- }
-
- // Error 400 indicates a problem with the log, not with the server, so
- // don't consider that a sign that the server is in trouble.
- bool server_is_healthy = upload_succeeded || response_code == 400;
- scheduler_->UploadFinished(server_is_healthy,
- persisted_logs_.has_unsent_logs());
-}
-
-void UkmService::RecordSource(std::unique_ptr<UkmSource> source) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- if (!recording_enabled_) {
- RecordDroppedSource(DroppedDataReason::RECORDING_DISABLED);
- return;
- }
- if (sources_.size() >= GetMaxSources()) {
- RecordDroppedSource(DroppedDataReason::MAX_HIT);
- return;
- }
-
- sources_.push_back(std::move(source));
+ reporting_service_.ukm_log_store()->StoreLog(serialized_log);
}
// static
@@ -463,11 +368,8 @@ void UkmService::UpdateSourceURL(int32_t source_id, const GURL& url) {
// Update the pre-existing source if there is any. This happens when the
// initial URL is different from the committed URL for the same source, e.g.,
// when there is redirection.
- for (auto& source : sources_) {
- if (source_id != source->id())
- continue;
-
- source->UpdateUrl(url);
+ if (base::ContainsKey(sources_, source_id)) {
+ sources_[source_id]->UpdateUrl(url);
return;
}
@@ -478,7 +380,7 @@ void UkmService::UpdateSourceURL(int32_t source_id, const GURL& url) {
std::unique_ptr<UkmSource> source = base::MakeUnique<UkmSource>();
source->set_id(source_id);
source->set_url(url);
- sources_.push_back(std::move(source));
+ sources_.insert(std::make_pair(source_id, std::move(source)));
}
void UkmService::AddEntry(std::unique_ptr<UkmEntry> entry) {
@@ -493,7 +395,22 @@ void UkmService::AddEntry(std::unique_ptr<UkmEntry> entry) {
return;
}
+ if (!whitelisted_entry_hashes_.empty() &&
+ !base::ContainsKey(whitelisted_entry_hashes_, entry->event_hash())) {
+ RecordDroppedEntry(DroppedDataReason::NOT_WHITELISTED);
+ return;
+ }
+
entries_.push_back(std::move(entry));
}
+void UkmService::StoreWhitelistedEntries() {
+ const auto entries =
+ base::SplitString(GetWhitelistEntries(), ",", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+ for (const auto& entry_string : entries) {
+ whitelisted_entry_hashes_.insert(base::HashMetricName(entry_string));
+ }
+}
+
} // namespace ukm
diff --git a/chromium/components/ukm/ukm_service.h b/chromium/components/ukm/ukm_service.h
index 67ec63573d6..9b493a2a213 100644
--- a/chromium/components/ukm/ukm_service.h
+++ b/chromium/components/ukm/ukm_service.h
@@ -16,8 +16,8 @@
#include "base/threading/thread_checker.h"
#include "build/build_config.h"
#include "components/metrics/metrics_provider.h"
-#include "components/metrics/metrics_reporting_scheduler.h"
-#include "components/metrics/persisted_logs.h"
+#include "components/metrics/metrics_rotation_scheduler.h"
+#include "components/ukm/ukm_reporting_service.h"
#include "url/gurl.h"
class PluginInfoMessageFilter;
@@ -29,8 +29,15 @@ namespace autofill {
class AutofillMetrics;
} // namespace autofill
+namespace translate {
+class TranslateRankerImpl;
+}
+
+namespace payments {
+class JourneyLogger;
+} // namespace payments
+
namespace metrics {
-class MetricsLogUploader;
class MetricsServiceClient;
}
@@ -100,7 +107,8 @@ class UkmService {
using AddEntryCallback = base::Callback<void(std::unique_ptr<UkmEntry>)>;
protected:
- const std::vector<std::unique_ptr<UkmSource>>& sources_for_testing() const {
+ const std::map<int32_t, std::unique_ptr<UkmSource>>& sources_for_testing()
+ const {
return sources_;
}
@@ -110,14 +118,17 @@ class UkmService {
private:
friend autofill::AutofillMetrics;
+ friend payments::JourneyLogger;
friend PluginInfoMessageFilter;
friend UkmPageLoadMetricsObserver;
- FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, AddEntryOnlyWithNonEmptyMetrics);
+ friend translate::TranslateRankerImpl;
+ FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, AddEntryWithEmptyMetrics);
FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, EntryBuilderAndSerialization);
FRIEND_TEST_ALL_PREFIXES(UkmServiceTest,
LogsUploadedOnlyWhenHavingSourcesOrEntries);
FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, MetricsProviderTest);
FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, PersistAndPurge);
+ FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, WhitelistEntryTest);
// Get a new UkmEntryBuilder object for the specified source ID and event,
// which can get metrics added to.
@@ -128,11 +139,6 @@ class UkmService {
std::unique_ptr<UkmEntryBuilder> GetEntryBuilder(int32_t source_id,
const char* event_name);
- // Adds a new source of UKM metrics, which will be stored until periodically
- // serialized for upload, and then deleted. This method is deprecated. Please
- // use GetEntryBuilder and UpdateSourceURL above.
- void RecordSource(std::unique_ptr<UkmSource> source);
-
// Starts metrics client initialization.
void StartInitTask();
@@ -156,6 +162,9 @@ class UkmService {
// Add an entry to the UkmEntry list.
void AddEntry(std::unique_ptr<UkmEntry> entry);
+ // Cache the list of whitelisted entries from the field trial parameter.
+ void StoreWhitelistedEntries();
+
// A weak pointer to the PrefService used to read and write preferences.
PrefService* pref_service_;
@@ -175,27 +184,25 @@ class UkmService {
// Registered metrics providers.
std::vector<std::unique_ptr<metrics::MetricsProvider>> metrics_providers_;
- // Logs that have not yet been sent.
- metrics::PersistedLogs persisted_logs_;
+ // Log reporting service.
+ ukm::UkmReportingService reporting_service_;
// The scheduler for determining when uploads should happen.
- std::unique_ptr<metrics::MetricsReportingScheduler> scheduler_;
+ std::unique_ptr<metrics::MetricsRotationScheduler> scheduler_;
base::ThreadChecker thread_checker_;
- // Instance of the helper class for uploading logs.
- std::unique_ptr<metrics::MetricsLogUploader> log_uploader_;
-
bool initialize_started_;
bool initialize_complete_;
- bool log_upload_in_progress_;
// Contains newly added sources and entries of UKM metrics which periodically
// get serialized and cleared by BuildAndStoreLog().
- // TODO(zhenw): update sources to a map keyed by source ID.
- std::vector<std::unique_ptr<UkmSource>> sources_;
+ std::map<int32_t, std::unique_ptr<UkmSource>> sources_;
std::vector<std::unique_ptr<UkmEntry>> entries_;
+ // Whitelisted Entry hashes, only the ones in this set will be recorded.
+ std::set<uint64_t> whitelisted_entry_hashes_;
+
// Weak pointers factory used to post task on different threads. All weak
// pointers managed by this factory have the same lifetime as UkmService.
base::WeakPtrFactory<UkmService> self_ptr_factory_;
diff --git a/chromium/components/ukm/ukm_service_unittest.cc b/chromium/components/ukm/ukm_service_unittest.cc
index 8a2782af38c..6177f7c345d 100644
--- a/chromium/components/ukm/ukm_service_unittest.cc
+++ b/chromium/components/ukm/ukm_service_unittest.cc
@@ -259,7 +259,7 @@ TEST_F(UkmServiceTest, EntryBuilderAndSerialization) {
EXPECT_EQ(10, proto_entry_foo_end.value());
}
-TEST_F(UkmServiceTest, AddEntryOnlyWithNonEmptyMetrics) {
+TEST_F(UkmServiceTest, AddEntryWithEmptyMetrics) {
UkmService service(&prefs_, &client_);
EXPECT_EQ(0, GetPersistedLogCount());
service.Initialize();
@@ -277,17 +277,7 @@ TEST_F(UkmServiceTest, AddEntryOnlyWithNonEmptyMetrics) {
service.Flush();
EXPECT_EQ(1, GetPersistedLogCount());
Report proto_report = GetPersistedReport();
- EXPECT_EQ(0, proto_report.entries_size());
-
- {
- std::unique_ptr<UkmEntryBuilder> builder =
- service.GetEntryBuilder(id, "PageLoad");
- builder->AddMetric("FirstContentfulPaint", 300);
- }
- service.Flush();
- EXPECT_EQ(2, GetPersistedLogCount());
- Report proto_report_with_entries = GetPersistedReport();
- EXPECT_EQ(1, proto_report_with_entries.entries_size());
+ EXPECT_EQ(1, proto_report.entries_size());
}
TEST_F(UkmServiceTest, MetricsProviderTest) {
@@ -470,4 +460,98 @@ TEST_F(UkmServiceTest, SourceSize) {
EXPECT_EQ(2, proto_report.sources_size());
}
+TEST_F(UkmServiceTest, PurgeMidUpload) {
+ UkmService service(&prefs_, &client_);
+ EXPECT_EQ(GetPersistedLogCount(), 0);
+ service.Initialize();
+ task_runner_->RunUntilIdle();
+ service.EnableRecording();
+ service.EnableReporting();
+ auto id = UkmService::GetNewSourceID();
+ service.UpdateSourceURL(id, GURL("https://google.com/foobar1"));
+ // Should init, generate a log, and start an upload.
+ task_runner_->RunPendingTasks();
+ EXPECT_TRUE(client_.uploader()->is_uploading());
+ // Purge should delete all logs, including the one being sent.
+ service.Purge();
+ // Upload succeeds after logs was deleted.
+ client_.uploader()->CompleteUpload(200);
+ EXPECT_EQ(GetPersistedLogCount(), 0);
+ EXPECT_FALSE(client_.uploader()->is_uploading());
+}
+
+TEST_F(UkmServiceTest, WhitelistEntryTest) {
+ base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
+ // Testing two whitelisted Entries.
+ ScopedUkmFeatureParams params(base::FeatureList::OVERRIDE_ENABLE_FEATURE,
+ {{"WhitelistEntries", "EntryA,EntryB"}});
+
+ ClearPrefs();
+ UkmService service(&prefs_, &client_);
+ EXPECT_EQ(0, GetPersistedLogCount());
+ service.Initialize();
+ task_runner_->RunUntilIdle();
+ service.EnableRecording();
+ service.EnableReporting();
+
+ auto id = UkmService::GetNewSourceID();
+ service.UpdateSourceURL(id, GURL("https://google.com/foobar1"));
+
+ {
+ std::unique_ptr<UkmEntryBuilder> builder =
+ service.GetEntryBuilder(id, "EntryA");
+ builder->AddMetric("MetricA", 300);
+ }
+ {
+ std::unique_ptr<UkmEntryBuilder> builder =
+ service.GetEntryBuilder(id, "EntryB");
+ builder->AddMetric("MetricB", 400);
+ }
+ // Note that this third entry is not in the whitelist.
+ {
+ std::unique_ptr<UkmEntryBuilder> builder =
+ service.GetEntryBuilder(id, "EntryC");
+ builder->AddMetric("MetricC", 500);
+ }
+
+ service.Flush();
+ EXPECT_EQ(1, GetPersistedLogCount());
+ Report proto_report = GetPersistedReport();
+
+ // Verify we've added one source and 2 entries.
+ EXPECT_EQ(1, proto_report.sources_size());
+ ASSERT_EQ(2, proto_report.entries_size());
+
+ const Entry& proto_entry_a = proto_report.entries(0);
+ EXPECT_EQ(id, proto_entry_a.source_id());
+ EXPECT_EQ(base::HashMetricName("EntryA"), proto_entry_a.event_hash());
+
+ const Entry& proto_entry_b = proto_report.entries(1);
+ EXPECT_EQ(id, proto_entry_b.source_id());
+ EXPECT_EQ(base::HashMetricName("EntryB"), proto_entry_b.event_hash());
+}
+
+TEST_F(UkmServiceTest, SourceURLLength) {
+ UkmService service(&prefs_, &client_);
+ EXPECT_EQ(0, GetPersistedLogCount());
+ service.Initialize();
+ task_runner_->RunUntilIdle();
+ service.EnableRecording();
+ service.EnableReporting();
+
+ auto id = UkmService::GetNewSourceID();
+
+ // This URL is too long to be recorded fully.
+ const std::string long_string = "https://" + std::string(10000, 'a');
+ service.UpdateSourceURL(id, GURL(long_string));
+
+ service.Flush();
+ EXPECT_EQ(1, GetPersistedLogCount());
+
+ auto proto_report = GetPersistedReport();
+ ASSERT_EQ(1, proto_report.sources_size());
+ const Source& proto_source = proto_report.sources(0);
+ EXPECT_EQ("URLTooLong", proto_source.url());
+}
+
} // namespace ukm
diff --git a/chromium/components/ukm/ukm_source.cc b/chromium/components/ukm/ukm_source.cc
index 182ce126918..c9eda128a8f 100644
--- a/chromium/components/ukm/ukm_source.cc
+++ b/chromium/components/ukm/ukm_source.cc
@@ -9,6 +9,24 @@
namespace ukm {
+namespace {
+
+// The maximum length of a URL we will record.
+constexpr int kMaxURLLength = 2 * 1024;
+
+// The string sent in place of a URL if the real URL was too long.
+constexpr char kMaxUrlLengthMessage[] = "URLTooLong";
+
+// Returns a URL that is under the length limit, by returning a constant
+// string when the URl is too long.
+std::string GetShortenedURL(const GURL& url) {
+ if (url.spec().length() > kMaxURLLength)
+ return kMaxUrlLengthMessage;
+ return url.spec();
+}
+
+} // namespace
+
UkmSource::UkmSource() = default;
UkmSource::~UkmSource() = default;
@@ -28,9 +46,9 @@ void UkmSource::PopulateProto(Source* proto_source) const {
DCHECK(!proto_source->has_initial_url());
proto_source->set_id(id_);
- proto_source->set_url(url_.spec());
+ proto_source->set_url(GetShortenedURL(url_));
if (!initial_url_.is_empty())
- proto_source->set_initial_url(initial_url_.spec());
+ proto_source->set_initial_url(GetShortenedURL(initial_url_));
}
} // namespace ukm
diff --git a/chromium/components/update_client/BUILD.gn b/chromium/components/update_client/BUILD.gn
index e35d4f4c7d9..b5a29805ef5 100644
--- a/chromium/components/update_client/BUILD.gn
+++ b/chromium/components/update_client/BUILD.gn
@@ -64,6 +64,7 @@ static_library("update_client") {
"//components/crx_file",
"//components/data_use_measurement/core",
"//components/prefs",
+ "//components/version_info:version_info",
"//courgette:courgette_lib",
"//crypto",
"//net",
@@ -122,6 +123,7 @@ source_set("unit_tests") {
testonly = true
sources = [
"component_patcher_unittest.cc",
+ "component_patcher_unittest.h",
"component_unpacker_unittest.cc",
"persisted_data_unittest.cc",
"ping_manager_unittest.cc",
@@ -145,6 +147,7 @@ source_set("unit_tests") {
"//base",
"//components/prefs",
"//components/prefs:test_support",
+ "//components/version_info:version_info",
"//courgette:courgette_lib",
"//net:test_support",
"//testing/gmock",
diff --git a/chromium/components/update_client/DEPS b/chromium/components/update_client/DEPS
index dfa2193a915..ca6755e33e6 100644
--- a/chromium/components/update_client/DEPS
+++ b/chromium/components/update_client/DEPS
@@ -3,6 +3,7 @@ include_rules = [
"+components/crx_file",
"+components/data_use_measurement/core",
"+components/prefs",
+ "+components/version_info",
"+courgette",
"+crypto",
"+libxml",
diff --git a/chromium/components/update_client/OWNERS b/chromium/components/update_client/OWNERS
index 75e2f4d442c..ddb2169c83a 100644
--- a/chromium/components/update_client/OWNERS
+++ b/chromium/components/update_client/OWNERS
@@ -1,4 +1,3 @@
-asargent@chromium.org
cpu@chromium.org
sorin@chromium.org
waffles@chromium.org
diff --git a/chromium/components/update_client/action_update.cc b/chromium/components/update_client/action_update.cc
index 3888d7c1214..4d4fce297c2 100644
--- a/chromium/components/update_client/action_update.cc
+++ b/chromium/components/update_client/action_update.cc
@@ -103,12 +103,10 @@ void ActionUpdate::DownloadComplete(
OnDownloadError(item, download_result);
} else {
OnDownloadSuccess(item, download_result);
- update_context_->main_task_runner->PostDelayedTask(
+ update_context_->main_task_runner->PostTask(
FROM_HERE,
base::Bind(&ActionUpdate::StartInstall, base::Unretained(this), item,
- download_result.response),
- base::TimeDelta::FromMilliseconds(
- update_context_->config->StepDelay()));
+ download_result.response));
}
}
@@ -184,11 +182,10 @@ void ActionUpdate::InstallCompleteOnBlockingTaskRunner(
int error,
int extended_error) {
update_client::DeleteFileAndEmptyParentDirectory(crx_path);
- update_context_->main_task_runner->PostDelayedTask(
+ update_context_->main_task_runner->PostTask(
FROM_HERE,
base::Bind(&ActionUpdate::InstallComplete, base::Unretained(this),
- item->id, error_category, error, extended_error),
- base::TimeDelta::FromMilliseconds(update_context_->config->StepDelay()));
+ item->id, error_category, error, extended_error));
}
CrxInstaller::Result ActionUpdate::DoInstall(
diff --git a/chromium/components/update_client/component_patcher.cc b/chromium/components/update_client/component_patcher.cc
index afafd8744e9..0bd27dd2776 100644
--- a/chromium/components/update_client/component_patcher.cc
+++ b/chromium/components/update_client/component_patcher.cc
@@ -80,7 +80,7 @@ void ComponentPatcher::PatchNextFile() {
return;
}
const base::DictionaryValue* command_args;
- if (!(*next_command_)->GetAsDictionary(&command_args)) {
+ if (!next_command_->GetAsDictionary(&command_args)) {
DonePatching(UnpackerError::kDeltaBadCommands, 0);
return;
}
diff --git a/chromium/components/update_client/configurator.h b/chromium/components/update_client/configurator.h
index c0217108ee6..be2caff58d8 100644
--- a/chromium/components/update_client/configurator.h
+++ b/chromium/components/update_client/configurator.h
@@ -39,9 +39,6 @@ class Configurator : public base::RefCountedThreadSafe<Configurator> {
// Delay in seconds to every subsequent update check. 0 means don't check.
virtual int NextCheckDelay() const = 0;
- // Delay in seconds from each task step. Used to smooth out CPU/IO usage.
- virtual int StepDelay() const = 0;
-
// Minimum delta time in seconds before an on-demand check is allowed
// for the same component.
virtual int OnDemandDelay() const = 0;
diff --git a/chromium/components/update_client/ping_manager_unittest.cc b/chromium/components/update_client/ping_manager_unittest.cc
index ba7464c8bf0..9795d6762e0 100644
--- a/chromium/components/update_client/ping_manager_unittest.cc
+++ b/chromium/components/update_client/ping_manager_unittest.cc
@@ -58,8 +58,7 @@ void ComponentUpdaterPingManagerTest::RunThreadsUntilIdle() {
base::RunLoop().RunUntilIdle();
}
-// Test is flaky: http://crbug.com/349547
-TEST_F(ComponentUpdaterPingManagerTest, DISABLED_PingManagerTest) {
+TEST_F(ComponentUpdaterPingManagerTest, PingManagerTest) {
std::unique_ptr<InterceptorFactory> interceptor_factory(
new InterceptorFactory(base::ThreadTaskRunnerHandle::Get()));
URLRequestPostInterceptor* interceptor =
@@ -176,6 +175,9 @@ TEST_F(ComponentUpdaterPingManagerTest, DISABLED_PingManagerTest) {
"download_time_ms=\"9870\"/></app>"))
<< interceptor->GetRequestsAsString();
interceptor->Reset();
+
+ interceptor_factory.reset();
+ base::RunLoop().RunUntilIdle();
}
// Tests that sending the ping fails when the component requires encryption but
diff --git a/chromium/components/update_client/request_sender.cc b/chromium/components/update_client/request_sender.cc
index b99648a6c25..782ada6a270 100644
--- a/chromium/components/update_client/request_sender.cc
+++ b/chromium/components/update_client/request_sender.cc
@@ -26,10 +26,10 @@ namespace update_client {
namespace {
// This is an ECDSA prime256v1 named-curve key.
-const int kKeyVersion = 6;
+const int kKeyVersion = 7;
const char kKeyPubBytesBase64[] =
- "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECEDSRcZPKv8k4JEYbF7MJxxx56m+x8Z+svg5gB"
- "mRX1J8A9DYRL6NvFkNcmcRtSNemUm7/iqrUnxaadkqcWSODw==";
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEj0QKufXIOBN30DtKeOYA5NV64FfY"
+ "HDou4sGqtcNUIlxpTzIbO45rB45QILhW6aDTwwjWLR1YCqpEAGICvFs8dQ==";
// The ETag header carries the ECSDA signature of the protocol response, if
// signing has been used.
diff --git a/chromium/components/update_client/test_configurator.cc b/chromium/components/update_client/test_configurator.cc
index edf5ddfac50..322044ac9db 100644
--- a/chromium/components/update_client/test_configurator.cc
+++ b/chromium/components/update_client/test_configurator.cc
@@ -47,10 +47,6 @@ int TestConfigurator::NextCheckDelay() const {
return 1;
}
-int TestConfigurator::StepDelay() const {
- return 0;
-}
-
int TestConfigurator::OnDemandDelay() const {
return ondemand_time_;
}
diff --git a/chromium/components/update_client/test_configurator.h b/chromium/components/update_client/test_configurator.h
index 7a103f47941..1f26ec051d2 100644
--- a/chromium/components/update_client/test_configurator.h
+++ b/chromium/components/update_client/test_configurator.h
@@ -62,7 +62,6 @@ class TestConfigurator : public Configurator {
// Overrrides for Configurator.
int InitialDelay() const override;
int NextCheckDelay() const override;
- int StepDelay() const override;
int OnDemandDelay() const override;
int UpdateDelay() const override;
std::vector<GURL> UpdateUrl() const override;
diff --git a/chromium/components/update_client/update_query_params.cc b/chromium/components/update_client/update_query_params.cc
index 5cd745b1198..5a81a94b775 100644
--- a/chromium/components/update_client/update_query_params.cc
+++ b/chromium/components/update_client/update_query_params.cc
@@ -8,6 +8,7 @@
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "components/update_client/update_query_params_delegate.h"
+#include "components/version_info/version_info.h"
#if defined(OS_WIN)
#include "base/win/windows_version.h"
@@ -130,6 +131,11 @@ const char* UpdateQueryParams::GetNaclArch() {
}
// static
+std::string UpdateQueryParams::GetProdVersion() {
+ return version_info::GetVersionNumber();
+}
+
+// static
void UpdateQueryParams::SetDelegate(UpdateQueryParamsDelegate* delegate) {
DCHECK(!g_delegate || !delegate || (delegate == g_delegate));
g_delegate = delegate;
diff --git a/chromium/components/update_client/update_query_params.h b/chromium/components/update_client/update_query_params.h
index f625b4203d8..a35e4c3771f 100644
--- a/chromium/components/update_client/update_query_params.h
+++ b/chromium/components/update_client/update_query_params.h
@@ -48,6 +48,9 @@ class UpdateQueryParams {
// "arm", and "mips32".
static const char* GetNaclArch();
+ // Returns the current version of Chrome/Chromium.
+ static std::string GetProdVersion();
+
// Use this delegate.
static void SetDelegate(UpdateQueryParamsDelegate* delegate);
diff --git a/chromium/components/update_client/update_query_params_unittest.cc b/chromium/components/update_client/update_query_params_unittest.cc
index 992dbd37a98..92666780ac6 100644
--- a/chromium/components/update_client/update_query_params_unittest.cc
+++ b/chromium/components/update_client/update_query_params_unittest.cc
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/strings/stringprintf.h"
#include "components/update_client/update_query_params.h"
+#include "base/strings/stringprintf.h"
#include "components/update_client/update_query_params_delegate.h"
+#include "components/version_info/version_info.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::StringPrintf;
@@ -41,7 +42,14 @@ void TestParams(UpdateQueryParams::ProdId prod_id, bool extra_params) {
EXPECT_TRUE(Contains(params, "cat=dog"));
}
+void TestProdVersion() {
+ EXPECT_EQ(version_info::GetVersionNumber(),
+ UpdateQueryParams::GetProdVersion());
+}
+
TEST(UpdateQueryParamsTest, GetParams) {
+ TestProdVersion();
+
TestParams(UpdateQueryParams::CRX, false);
TestParams(UpdateQueryParams::CHROME, false);
diff --git a/chromium/components/url_formatter/elide_url.h b/chromium/components/url_formatter/elide_url.h
index fb07e4ecfe9..8f53bf233c2 100644
--- a/chromium/components/url_formatter/elide_url.h
+++ b/chromium/components/url_formatter/elide_url.h
@@ -77,7 +77,7 @@ enum class SchemeDisplay {
//
// Generally, prefer SchemeDisplay::SHOW to omitting the scheme unless there is
// plenty of indication as to whether the origin is secure elsewhere in the UX.
-// For example, in Chrome's Origin Info Bubble, there are icons and strings
+// For example, in Chrome's Page Info Bubble, there are icons and strings
// indicating origin (non-)security. But in the HTTP Basic Auth prompt (for
// example), the scheme may be the only indicator.
base::string16 FormatUrlForSecurityDisplay(
diff --git a/chromium/components/url_formatter/elide_url_unittest.cc b/chromium/components/url_formatter/elide_url_unittest.cc
index e92df4eabc4..f8f52f96416 100644
--- a/chromium/components/url_formatter/elide_url_unittest.cc
+++ b/chromium/components/url_formatter/elide_url_unittest.cc
@@ -183,11 +183,6 @@ TEST(TextEliderTest, TestHostEliding) {
"reallyreallyreallylongdomainname.com"},
{"http://foo", "foo"},
{"http://foo.bar", "foo.bar"},
-#if !defined(OS_IOS)
- // iOS width calculations are off by a letter from other platforms for
- // strings with too many kerned letters on the default font set.
- // TODO(rohitrao): Fix secure_display::ElideHost for iOS
- // (crbug.com/517604).
{"http://subdomain.google.com", kEllipsisStr + ".google.com"},
{"http://a.b.c.d.e.f.com", kEllipsisStr + "f.com"},
{"http://subdomain.foo.bar", kEllipsisStr + "in.foo.bar"},
@@ -197,7 +192,6 @@ TEST(TextEliderTest, TestHostEliding) {
// IDN - Greek alpha.beta.gamma.delta.epsilon.zeta.com
{"http://xn--mxa.xn--nxa.xn--oxa.xn--pxa.xn--qxa.xn--rxa.com",
kEllipsisStr + ".\xCE\xB5.\xCE\xB6.com"},
-#endif // !defined(OS_IOS)
};
for (size_t i = 0; i < arraysize(testcases); ++i) {
diff --git a/chromium/components/url_formatter/url_formatter.cc b/chromium/components/url_formatter/url_formatter.cc
index 3d5740fd377..e17f7c5a46b 100644
--- a/chromium/components/url_formatter/url_formatter.cc
+++ b/chromium/components/url_formatter/url_formatter.cc
@@ -324,12 +324,13 @@ IDNSpoofChecker::IDNSpoofChecker() {
non_ascii_latin_letters_.freeze();
// These letters are parts of |dangerous_patterns_|.
- kana_letters_exceptions_ = icu::UnicodeSet(UNICODE_STRING_SIMPLE(
- "[\\u3078-\\u307a\\u30d8-\\u30da\\u30fb\\u30fc]"), status);
+ kana_letters_exceptions_ = icu::UnicodeSet(
+ UNICODE_STRING_SIMPLE("[\\u3078-\\u307a\\u30d8-\\u30da\\u30fb-\\u30fe]"),
+ status);
kana_letters_exceptions_.freeze();
// These Cyrillic letters look like Latin. A domain label entirely made of
- // these letters is blocked as a simpliified whole-script-spoofable.
+ // these letters is blocked as a simplified whole-script-spoofable.
cyrillic_letters_latin_alike_ =
icu::UnicodeSet(icu::UnicodeString("[аÑÔеһіјÓорԛѕÔхуъЬҽпгѵѡ]"), status);
cyrillic_letters_latin_alike_.freeze();
@@ -406,26 +407,32 @@ bool IDNSpoofChecker::Check(base::StringPiece16 label, bool is_tld_ascii) {
// TODO(jshin): adjust the pattern once the above ICU bug is fixed.
// - Disallow U+30FB (Katakana Middle Dot) and U+30FC (Hiragana-Katakana
// Prolonged Sound) used out-of-context.
+ // - Dislallow U+30FD/E (Katakana iteration mark/voiced iteration mark)
+ // unless they're preceded by a Katakana.
// - Disallow three Hiragana letters (U+307[8-A]) or Katakana letters
// (U+30D[8-A]) that look exactly like each other when they're used in a
// label otherwise entirely in Katakna or Hiragana.
// - Disallow U+0585 (Armenian Small Letter Oh) and U+0581 (Armenian Small
// Letter Co) to be next to Latin.
// - Disallow Latin 'o' and 'g' next to Armenian.
+ // - Disalow mixing of Latin and Canadian Syllabary.
dangerous_pattern = new icu::RegexMatcher(
icu::UnicodeString(
"[^\\p{scx=kana}\\p{scx=hira}\\p{scx=hani}]"
"[\\u30ce\\u30f3\\u30bd\\u30be]"
"[^\\p{scx=kana}\\p{scx=hira}\\p{scx=hani}]|"
- "[^\\p{scx=kana}\\p{scx=hira}]\\u30fc|"
- "\\u30fc[^\\p{scx=kana}\\p{scx=hira}]|"
+ "[^\\p{scx=kana}\\p{scx=hira}]\\u30fc|^\\u30fc|"
+ "[^\\p{scx=kana}][\\u30fd\\u30fe]|^[\\u30fd\\u30fe]|"
"^[\\p{scx=kana}]+[\\u3078-\\u307a][\\p{scx=kana}]+$|"
"^[\\p{scx=hira}]+[\\u30d8-\\u30da][\\p{scx=hira}]+$|"
"[a-z]\\u30fb|\\u30fb[a-z]|"
"^[\\u0585\\u0581]+[a-z]|[a-z][\\u0585\\u0581]+$|"
"[a-z][\\u0585\\u0581]+[a-z]|"
"^[og]+[\\p{scx=armn}]|[\\p{scx=armn}][og]+$|"
- "[\\p{scx=armn}][og]+[\\p{scx=armn}]", -1, US_INV),
+ "[\\p{scx=armn}][og]+[\\p{scx=armn}]|"
+ "[\\p{sc=cans}].*[a-z]|[a-z].*[\\p{sc=cans}]|"
+ "[\\p{sc=tfng}].*[a-z]|[a-z].*[\\p{sc=tfng}]",
+ -1, US_INV),
0, status);
tls_index.Set(dangerous_pattern);
}
@@ -519,6 +526,21 @@ void IDNSpoofChecker::SetAllowedUnicodeSet(UErrorCode* status) {
allowed_set.remove(0x2010u); // Hyphen
allowed_set.remove(0x2027u); // Hyphenation Point
+#if defined(OS_MACOSX)
+ // 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.
+
+ // Arabic letter KASHMIRI YEH. Not used in Arabic and Persian.
+ allowed_set.remove(0x0620u);
+
+ // Tibetan characters used for transliteration of ancient texts:
+ allowed_set.remove(0x0F8Cu);
+ allowed_set.remove(0x0F8Du);
+ allowed_set.remove(0x0F8Eu);
+ allowed_set.remove(0x0F8Fu);
+#endif
+
uspoof_setAllowedUnicodeSet(checker_, &allowed_set, status);
}
diff --git a/chromium/components/url_formatter/url_formatter_unittest.cc b/chromium/components/url_formatter/url_formatter_unittest.cc
index 5b2646ce09c..3bd98fa2009 100644
--- a/chromium/components/url_formatter/url_formatter_unittest.cc
+++ b/chromium/components/url_formatter/url_formatter_unittest.cc
@@ -125,7 +125,8 @@ const IDNTestCase idn_cases[] = {
// ASCII-Latin + Japn (Kana + Han)
// ASCII-Latin + Kore (Hangul + Han)
// ASCII-Latin + Han + Bopomofo
- // ASCII-Latin + any allowed script other than Cyrillic, Greek and Cherokee
+ // ASCII-Latin + any allowed script other than Cyrillic, Greek, Cherokee
+ // and Unified Canadian Syllabary
// "payp<alpha>l.com"
{"www.xn--paypl-g9d.com", L"payp\x03b1l.com", false},
// google.gr with Greek omicron and epsilon
@@ -179,6 +180,16 @@ const IDNTestCase idn_cases[] = {
{"xn--t2bes3ds6749n.com", L"\x0930\x094b\x0932\x0947\x76e7\x0938.com", false},
// Devanagari + Bengali
{"xn--11b0x.in", L"\x0915\x0995.in", false},
+ // Canadian Syllabary + Latin
+ {"xn--ab-lym.com", L"ab\x14BF.com", false},
+ {"xn--ab1-p6q.com", L"ab1\x14BF.com", false},
+ {"xn--1ab-m6qd.com", L"\x14BF" L"1ab.com", false},
+ {"xn--ab-jymc.com", L"\x14BF" L"ab.com", false},
+ // Tifinagh + Latin
+ {"xn--liy-go4a.com", L"li\u24dfy.com", false},
+ {"xn--rol-ho4a.com", L"rol\u24df.com", false},
+ {"xn--ily-eo4a.com", L"\u24dfily.com", false},
+ {"xn--1ly-eo4a.com", L"\u24df1ly.com", false},
// Invisibility check
// Thai tone mark malek(U+0E48) repeated
@@ -187,6 +198,8 @@ const IDNTestCase idn_cases[] = {
{"xn--a-xbba.com", L"a\x0301\x0301.com", false},
// 'a' with acuted accent + another acute accent
{"xn--1ca20i.com", L"\x00e1\x0301.com", false},
+ // Combining mark at the beginning
+ {"xn--abc-fdc.jp", L"\x0300" L"abc.jp", false},
// Mixed script confusable
// google with Armenian Small Letter Oh(U+0585)
@@ -199,17 +212,51 @@ const IDNTestCase idn_cases[] = {
// Hiragana HE(U+3078) mixed with Katakana
{"xn--49jxi3as0d0fpc.com",
L"\x30e2\x30d2\x30fc\x30c8\x3078\x30d6\x30f3.com", false},
+
+ // U+30FC should be preceded by a Hiragana/Katakana.
+ // Katakana + U+30FC + Han
+ {"xn--lck0ip02qw5ya.jp", L"\x30ab\x30fc\x91ce\x7403.jp", true},
+ // Hiragana + U+30FC + Han
+ {"xn--u8j5tr47nw5ya.jp", L"\x304b\x30fc\x91ce\x7403.jp", true},
// U+30FC + Han
{"xn--weka801xo02a.com", L"\x30fc\x52d5\x753b\x30fc.com", false},
// Han + U+30FC + Han
{"xn--wekz60nb2ay85atj0b.jp", L"\x65e5\x672c\x30fc\x91ce\x7403.jp", false},
+ // U+30FC at the beginning
+ {"xn--wek060nb2a.jp", L"\x30fc\x65e5\x672c", false},
// Latin + U+30FC + Latin
{"xn--abcdef-r64e.jp", L"abc\x30fc" L"def.jp", false},
+
+ // U+30FB (・) is not allowed next to Latin, but allowed otherwise.
+ // U+30FB + Han
+ {"xn--vekt920a.jp", L"\x30fb\x91ce.jp", true},
+ // Han + U+30FB + Han
+ {"xn--vek160nb2ay85atj0b.jp", L"\x65e5\x672c\x30fb\x91ce\x7403.jp", true},
// Latin + U+30FB + Latin
{"xn--abcdef-k64e.jp", L"abc\x30fb" L"def.jp", false},
// U+30FB + Latin
{"xn--abc-os4b.jp", L"\x30fb" L"abc.jp", false},
+ // U+30FD (ヽ) is allowed only after Katakana.
+ // Katakana + U+30FD
+ {"xn--lck2i.jp", L"\x30ab\x30fd.jp", true},
+ // Hiragana + U+30FD
+ {"xn--u8j7t.jp", L"\x304b\x30fd.jp", false},
+ // Han + U+30FD
+ {"xn--xek368f.jp", L"\x4e00\x30fd.jp", false},
+ {"xn--aa-mju.jp", L"a\x30fd.jp", false},
+ {"xn--a1-bo4a.jp", L"a1\x30fd.jp", false},
+
+ // U+30FE (ヾ) is allowed only after Katakana.
+ // Katakana + U+30FE
+ {"xn--lck4i.jp", L"\x30ab\x30fe.jp", true},
+ // Hiragana + U+30FE
+ {"xn--u8j9t.jp", L"\x304b\x30fe.jp", false},
+ // Han + U+30FE
+ {"xn--yek168f.jp", L"\x4e00\x30fe.jp", false},
+ {"xn--a-oju.jp", L"a\x30fe.jp", false},
+ {"xn--a1-eo4a.jp", L"a1\x30fe.jp", false},
+
// Cyrillic labels made of Latin-look-alike Cyrillic letters.
// Ñ•Ñоре.com with Ñ•Ñоре in Cyrillic
{"xn--e1argc3h.com", L"\x0455\x0441\x043e\x0440\x0435.com", false},
@@ -319,6 +366,13 @@ const IDNTestCase idn_cases[] = {
{"xn--ab-yod.com", L"a\x05f4" L"b.com", false},
// Hebrew Gershayim with Arabic is disallowed.
{"xn--5eb7h.eg", L"\x0628\x05f4.eg", false},
+#if defined(OS_MACOSX)
+ // These characters are blocked due to a font issue on Mac.
+ // Tibetan transliteration characters.
+ {"xn--com-luma.test.pl", L"\u0f8c.test.pl", false},
+ // Arabic letter KASHMIRI YEH
+ {"xn--fgb.com", L"\u0620.com", false},
+#endif
// Hyphens (http://unicode.org/cldr/utility/confusables.jsp?a=-)
// Hyphen-Minus (the only hyphen allowed)
diff --git a/chromium/components/url_matcher/url_matcher_factory.cc b/chromium/components/url_matcher/url_matcher_factory.cc
index 5793f68e82f..253d022ece1 100644
--- a/chromium/components/url_matcher/url_matcher_factory.cc
+++ b/chromium/components/url_matcher/url_matcher_factory.cc
@@ -98,7 +98,7 @@ class URLMatcherConditionFactoryMethods {
DISALLOW_COPY_AND_ASSIGN(URLMatcherConditionFactoryMethods);
};
-static base::LazyInstance<URLMatcherConditionFactoryMethods>
+static base::LazyInstance<URLMatcherConditionFactoryMethods>::DestructorAtExit
g_url_matcher_condition_factory_methods = LAZY_INSTANCE_INITIALIZER;
} // namespace
@@ -250,10 +250,10 @@ std::unique_ptr<URLMatcherPortFilter> URLMatcherFactory::CreateURLMatcherPorts(
for (const auto& entry : *value_list) {
int port = 0;
- base::ListValue* range = NULL;
- if (entry->GetAsInteger(&port)) {
+ const base::ListValue* range = NULL;
+ if (entry.GetAsInteger(&port)) {
ranges.push_back(URLMatcherPortFilter::CreateRange(port));
- } else if (entry->GetAsList(&range)) {
+ } else if (entry.GetAsList(&range)) {
int from = 0, to = 0;
if (range->GetSize() != 2u ||
!range->GetInteger(0, &from) ||
diff --git a/chromium/components/user_manager/fake_user_manager.cc b/chromium/components/user_manager/fake_user_manager.cc
index f05eb58709b..69cb7469e2c 100644
--- a/chromium/components/user_manager/fake_user_manager.cc
+++ b/chromium/components/user_manager/fake_user_manager.cc
@@ -19,9 +19,9 @@ namespace {
class FakeTaskRunner : public base::TaskRunner {
public:
bool PostDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
+ base::OnceClosure task,
base::TimeDelta delay) override {
- task.Run();
+ std::move(task).Run();
return true;
}
bool RunsTasksOnCurrentThread() const override { return true; }
@@ -54,6 +54,10 @@ const user_manager::User* FakeUserManager::AddUserWithAffiliation(
return user;
}
+void FakeUserManager::OnProfileInitialized(User* user) {
+ user->set_profile_ever_initialized(true);
+}
+
void FakeUserManager::RemoveUserFromList(const AccountId& account_id) {
const user_manager::UserList::iterator it =
std::find_if(users_.begin(), users_.end(),
diff --git a/chromium/components/user_manager/fake_user_manager.h b/chromium/components/user_manager/fake_user_manager.h
index d1c9b70ed2f..221dc42d71a 100644
--- a/chromium/components/user_manager/fake_user_manager.h
+++ b/chromium/components/user_manager/fake_user_manager.h
@@ -64,6 +64,7 @@ class USER_MANAGER_EXPORT FakeUserManager : public UserManagerBase {
user_manager::UserList GetUnlockUsers() const override;
const AccountId& GetOwnerAccountId() const override;
void OnSessionStarted() override {}
+ void OnProfileInitialized(User* user) override;
void RemoveUser(const AccountId& account_id,
user_manager::RemoveUserDelegate* delegate) override {}
void RemoveUserFromList(const AccountId& account_id) override;
diff --git a/chromium/components/user_manager/known_user.cc b/chromium/components/user_manager/known_user.cc
index 815d105e187..22db652965c 100644
--- a/chromium/components/user_manager/known_user.cc
+++ b/chromium/components/user_manager/known_user.cc
@@ -53,6 +53,9 @@ const char kReauthReasonKey[] = "reauth_reason";
// Key for the GaiaId migration status.
const char kGaiaIdMigration[] = "gaia_id_migration";
+// Key of the boolean flag telling if user session has finished init yet.
+const char kProfileEverInitialized[] = "profile_ever_initialized";
+
PrefService* GetLocalState() {
if (!UserManager::IsInitialized())
return nullptr;
@@ -451,6 +454,22 @@ bool IsUsingSAML(const AccountId& account_id) {
return false;
}
+bool WasProfileEverInitialized(const AccountId& account_id) {
+ bool profile_ever_initialized;
+ if (GetBooleanPref(account_id, kProfileEverInitialized,
+ &profile_ever_initialized))
+ return profile_ever_initialized;
+
+ // Sessions created before we started setting the session_initialized flag
+ // should default to "initialized = true".
+ LOG(WARNING) << "Treating unmigrated user as profile_ever_initialized=true";
+ return true;
+}
+
+void SetProfileEverInitialized(const AccountId& account_id, bool initialized) {
+ SetBooleanPref(account_id, kProfileEverInitialized, initialized);
+}
+
void UpdateReauthReason(const AccountId& account_id, const int reauth_reason) {
SetIntegerPref(account_id, kReauthReasonKey, reauth_reason);
}
@@ -478,6 +497,11 @@ void RemovePrefs(const AccountId& account_id) {
}
}
+// Exported so tests can call this from other components.
+void RemovePrefsForTesting(const AccountId& account_id) {
+ RemovePrefs(account_id);
+}
+
void RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterListPref(kKnownUsers);
}
diff --git a/chromium/components/user_manager/known_user.h b/chromium/components/user_manager/known_user.h
index 245ed573f38..da26caaac53 100644
--- a/chromium/components/user_manager/known_user.h
+++ b/chromium/components/user_manager/known_user.h
@@ -127,6 +127,17 @@ void USER_MANAGER_EXPORT UpdateUsingSAML(const AccountId& account_id,
// returns false.
bool USER_MANAGER_EXPORT IsUsingSAML(const AccountId& account_id);
+// Returns true if the user's session has already completed initialization
+// (set to false when session is created, and then is set to true once
+// the profile is intiaiized - this allows us to detect crashes/restarts during
+// initial session creation so we can recover gracefully).
+bool USER_MANAGER_EXPORT WasProfileEverInitialized(const AccountId& account_id);
+
+// Sets the flag that denotes whether the session associated with a user has
+// completed initialization at least once.
+void USER_MANAGER_EXPORT SetProfileEverInitialized(const AccountId& account_id,
+ bool initialized);
+
// Saves why the user has to go through re-auth flow.
void USER_MANAGER_EXPORT UpdateReauthReason(const AccountId& account_id,
const int reauth_reason);
@@ -138,8 +149,10 @@ bool USER_MANAGER_EXPORT FindReauthReason(const AccountId& account_id,
int* out_value);
// Removes all user preferences associated with |account_id|.
-// (This one used by user_manager only and thus not exported.)
+// Not exported as code should not be calling this outside this component
+// (with the exception of tests, so a test-only API is exposed).
void RemovePrefs(const AccountId& account_id);
+void USER_MANAGER_EXPORT RemovePrefsForTesting(const AccountId& account_id);
// Register known user prefs.
void USER_MANAGER_EXPORT RegisterPrefs(PrefRegistrySimple* registry);
diff --git a/chromium/components/user_manager/user.h b/chromium/components/user_manager/user.h
index 26c52599632..fecc33bec1d 100644
--- a/chromium/components/user_manager/user.h
+++ b/chromium/components/user_manager/user.h
@@ -171,6 +171,9 @@ class USER_MANAGER_EXPORT User : public UserInfo {
// user's next sign-in.
bool force_online_signin() const { return force_online_signin_; }
+ // Whether the user's session has completed initialization yet.
+ bool profile_ever_initialized() const { return profile_ever_initialized_; }
+
// True if the user's session can be locked (i.e. the user has a password with
// which to unlock the session).
bool can_lock() const;
@@ -200,6 +203,7 @@ class USER_MANAGER_EXPORT User : public UserInfo {
friend class chromeos::MockUserManager;
friend class chromeos::UserAddingScreenTest;
FRIEND_TEST_ALL_PREFIXES(UserTest, DeviceLocalAccountAffiliation);
+ FRIEND_TEST_ALL_PREFIXES(UserTest, UserSessionInitialized);
// Do not allow anyone else to create new User instances.
static User* CreateRegularUser(const AccountId& account_id);
@@ -249,6 +253,10 @@ class USER_MANAGER_EXPORT User : public UserInfo {
force_online_signin_ = force_online_signin;
}
+ void set_profile_ever_initialized(bool profile_ever_initialized) {
+ profile_ever_initialized_ = profile_ever_initialized;
+ }
+
void set_username_hash(const std::string& username_hash) {
username_hash_ = username_hash;
}
@@ -276,6 +284,7 @@ class USER_MANAGER_EXPORT User : public UserInfo {
std::unique_ptr<UserImage> user_image_;
OAuthTokenStatus oauth_token_status_ = OAUTH_TOKEN_STATUS_UNKNOWN;
bool force_online_signin_ = false;
+ bool profile_ever_initialized_ = false;
// This is set to chromeos locale if account data has been downloaded.
// (Or failed to download, but at least one download attempt finished).
diff --git a/chromium/components/user_manager/user_manager.h b/chromium/components/user_manager/user_manager.h
index 1029959282f..b3eb6682bc6 100644
--- a/chromium/components/user_manager/user_manager.h
+++ b/chromium/components/user_manager/user_manager.h
@@ -175,6 +175,14 @@ class USER_MANAGER_EXPORT UserManager {
// Invoked by session manager to inform session start.
virtual void OnSessionStarted() = 0;
+ // Invoked once profile initialization has been completed. This allows various
+ // subsystems (for example, policy framework) to skip an expensive online
+ // initialization process, and also allows the signin screen to force an
+ // online signin if it knows that profile initialization has not yet
+ // completed. |user| is the User associated with the profile that has
+ // completed initialization.
+ virtual void OnProfileInitialized(User* user) = 0;
+
// Removes the user from the device. Note, it will verify that the given user
// isn't the owner, so calling this method for the owner will take no effect.
// Note, |delegate| can be NULL.
diff --git a/chromium/components/user_manager/user_manager_base.cc b/chromium/components/user_manager/user_manager_base.cc
index 5805a9ca35b..182024c90cd 100644
--- a/chromium/components/user_manager/user_manager_base.cc
+++ b/chromium/components/user_manager/user_manager_base.cc
@@ -265,6 +265,16 @@ void UserManagerBase::OnSessionStarted() {
GetLocalState()->CommitPendingWrite();
}
+void UserManagerBase::OnProfileInitialized(User* user) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ // Mark the user as having an initialized session and persist this in
+ // the known_user DB.
+ user->set_profile_ever_initialized(true);
+ known_user::SetProfileEverInitialized(user->GetAccountId(), true);
+ GetLocalState()->CommitPendingWrite();
+}
+
void UserManagerBase::RemoveUser(const AccountId& account_id,
RemoveUserDelegate* delegate) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
@@ -302,7 +312,7 @@ void UserManagerBase::RemoveUserFromList(const AccountId& account_id) {
// Special case, removing partially-constructed supervised user or
// boostrapping user during user list loading.
ListPrefUpdate users_update(GetLocalState(), kRegularUsers);
- users_update->Remove(base::StringValue(account_id.GetUserEmail()), nullptr);
+ users_update->Remove(base::Value(account_id.GetUserEmail()), nullptr);
OnUserRemoved(account_id);
} else {
NOTREACHED() << "Users are not loaded yet.";
@@ -402,7 +412,7 @@ void UserManagerBase::SaveUserDisplayName(const AccountId& account_id,
DictionaryPrefUpdate display_name_update(GetLocalState(),
kUserDisplayName);
display_name_update->SetWithoutPathExpansion(
- account_id.GetUserEmail(), new base::StringValue(display_name));
+ account_id.GetUserEmail(), new base::Value(display_name));
}
}
}
@@ -431,8 +441,8 @@ void UserManagerBase::SaveUserDisplayEmail(const AccountId& account_id,
return;
DictionaryPrefUpdate display_email_update(GetLocalState(), kUserDisplayEmail);
- display_email_update->SetWithoutPathExpansion(
- account_id.GetUserEmail(), new base::StringValue(display_email));
+ display_email_update->SetWithoutPathExpansion(account_id.GetUserEmail(),
+ new base::Value(display_email));
}
std::string UserManagerBase::GetUserDisplayEmail(
@@ -474,8 +484,8 @@ void UserManagerBase::UpdateUserAccountData(
user->set_given_name(given_name);
if (!IsUserNonCryptohomeDataEphemeral(account_id)) {
DictionaryPrefUpdate given_name_update(GetLocalState(), kUserGivenName);
- given_name_update->SetWithoutPathExpansion(
- account_id.GetUserEmail(), new base::StringValue(given_name));
+ given_name_update->SetWithoutPathExpansion(account_id.GetUserEmail(),
+ new base::Value(given_name));
}
}
@@ -792,6 +802,8 @@ void UserManagerBase::EnsureUsersLoaded() {
const AccountId account_id = user->GetAccountId();
user->set_oauth_token_status(LoadUserOAuthStatus(*it));
user->set_force_online_signin(LoadForceOnlineSignin(*it));
+ user->set_profile_ever_initialized(
+ known_user::WasProfileEverInitialized(*it));
user->set_using_saml(known_user::IsUsingSAML(*it));
users_.push_back(user);
@@ -813,7 +825,6 @@ void UserManagerBase::EnsureUsersLoaded() {
user->set_display_email(display_email);
}
}
-
user_loading_stage_ = STAGE_LOADED;
PerformPostUserListLoadingActions();
@@ -860,8 +871,8 @@ void UserManagerBase::GuestUserLoggedIn() {
void UserManagerBase::AddUserRecord(User* user) {
// Add the user to the front of the user list.
ListPrefUpdate prefs_users_update(GetLocalState(), kRegularUsers);
- prefs_users_update->Insert(0, base::MakeUnique<base::StringValue>(
- user->GetAccountId().GetUserEmail()));
+ prefs_users_update->Insert(
+ 0, base::MakeUnique<base::Value>(user->GetAccountId().GetUserEmail()));
users_.insert(users_.begin(), user);
}
@@ -876,6 +887,8 @@ void UserManagerBase::RegularUserLoggedIn(const AccountId& account_id) {
active_user_->set_oauth_token_status(LoadUserOAuthStatus(account_id));
SaveUserDisplayName(active_user_->GetAccountId(),
base::UTF8ToUTF16(active_user_->GetAccountName(true)));
+ known_user::SetProfileEverInitialized(
+ active_user_->GetAccountId(), active_user_->profile_ever_initialized());
}
AddUserRecord(active_user_);
diff --git a/chromium/components/user_manager/user_manager_base.h b/chromium/components/user_manager/user_manager_base.h
index 9e9fec63919..70776a72077 100644
--- a/chromium/components/user_manager/user_manager_base.h
+++ b/chromium/components/user_manager/user_manager_base.h
@@ -56,6 +56,7 @@ class USER_MANAGER_EXPORT UserManagerBase : public UserManager {
void SwitchActiveUser(const AccountId& account_id) override;
void SwitchToLastActiveUser() override;
void OnSessionStarted() override;
+ void OnProfileInitialized(User* user) override;
void RemoveUser(const AccountId& account_id,
RemoveUserDelegate* delegate) override;
void RemoveUserFromList(const AccountId& account_id) override;
@@ -309,6 +310,10 @@ class USER_MANAGER_EXPORT UserManagerBase : public UserManager {
// be enforced during the user's next sign-in from local state preferences.
bool LoadForceOnlineSignin(const AccountId& account_id) const;
+ // Read a flag indicating whether session initialization has completed at
+ // least once.
+ bool LoadSessionInitialized(const AccountId& account_id) const;
+
// Notifies observers that merge session state had changed.
void NotifyMergeSessionStateChanged();
diff --git a/chromium/components/user_manager/user_unittest.cc b/chromium/components/user_manager/user_unittest.cc
index 05f563f5d2d..eb3ca8bfcaa 100644
--- a/chromium/components/user_manager/user_unittest.cc
+++ b/chromium/components/user_manager/user_unittest.cc
@@ -44,4 +44,12 @@ TEST(UserTest, DeviceLocalAccountAffiliation) {
EXPECT_TRUE(arc_kiosk_user.IsAffiliated());
}
+TEST(UserTest, UserSessionInitialized) {
+ const AccountId account_id = AccountId::FromUserEmailGaiaId(kEmail, kGaiaId);
+ std::unique_ptr<User> user(User::CreateRegularUser(account_id));
+ EXPECT_FALSE(user->profile_ever_initialized());
+ user->set_profile_ever_initialized(true);
+ EXPECT_TRUE(user->profile_ever_initialized());
+}
+
} // namespace user_manager
diff --git a/chromium/components/user_prefs/OWNERS b/chromium/components/user_prefs/OWNERS
index 2d870381cb7..e04d3d44deb 100644
--- a/chromium/components/user_prefs/OWNERS
+++ b/chromium/components/user_prefs/OWNERS
@@ -2,3 +2,5 @@ battre@chromium.org
bauerb@chromium.org
gab@chromium.org
pam@chromium.org
+
+# COMPONENT: UI>Browser>Preferences
diff --git a/chromium/components/user_prefs/tracked/BUILD.gn b/chromium/components/user_prefs/tracked/BUILD.gn
deleted file mode 100644
index d2108c61762..00000000000
--- a/chromium/components/user_prefs/tracked/BUILD.gn
+++ /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.
-
-static_library("user_prefs_tracked") {
- sources = [
- "device_id.h",
- "device_id_mac.cc",
- "device_id_stub.cc",
- "device_id_win.cc",
- "dictionary_hash_store_contents.cc",
- "dictionary_hash_store_contents.h",
- "hash_store_contents.h",
- "interceptable_pref_filter.cc",
- "interceptable_pref_filter.h",
- "pref_hash_calculator.cc",
- "pref_hash_calculator.h",
- "pref_hash_filter.cc",
- "pref_hash_filter.h",
- "pref_hash_store.h",
- "pref_hash_store_impl.cc",
- "pref_hash_store_impl.h",
- "pref_hash_store_transaction.h",
- "pref_names.cc",
- "pref_names.h",
- "registry_hash_store_contents_win.cc",
- "registry_hash_store_contents_win.h",
- "segregated_pref_store.cc",
- "segregated_pref_store.h",
- "tracked_atomic_preference.cc",
- "tracked_atomic_preference.h",
- "tracked_preference.h",
- "tracked_preference_helper.cc",
- "tracked_preference_helper.h",
- "tracked_preference_histogram_names.cc",
- "tracked_preference_histogram_names.h",
- "tracked_preference_validation_delegate.h",
- "tracked_preferences_migration.cc",
- "tracked_preferences_migration.h",
- "tracked_split_preference.cc",
- "tracked_split_preference.h",
- ]
-
- if (is_win || is_mac) {
- sources -= [ "device_id_stub.cc" ]
- }
-
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
- deps = [
- "//base:base",
- "//components/pref_registry",
- "//components/prefs",
- "//crypto:crypto",
- ]
-}
-
-static_library("user_prefs_tracked_test_support") {
- testonly = true
- sources = [
- "mock_validation_delegate.cc",
- "mock_validation_delegate.h",
- ]
-
- deps = [
- ":user_prefs_tracked",
- "//base:base",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "device_id_unittest.cc",
- "pref_hash_calculator_unittest.cc",
- "pref_hash_filter_unittest.cc",
- "pref_hash_store_impl_unittest.cc",
- "registry_hash_store_contents_win_unittest.cc",
- "segregated_pref_store_unittest.cc",
- "tracked_preferences_migration_unittest.cc",
- ]
-
- deps = [
- ":user_prefs_tracked",
- ":user_prefs_tracked_test_support",
- "//base:base",
- "//base/test:test_support",
- "//components/prefs:test_support",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/user_prefs/tracked/DEPS b/chromium/components/user_prefs/tracked/DEPS
deleted file mode 100644
index 6ccb05e9fab..00000000000
--- a/chromium/components/user_prefs/tracked/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "+components/pref_registry",
- "+crypto/hmac.h",
-]
diff --git a/chromium/components/user_prefs/tracked/OWNERS b/chromium/components/user_prefs/tracked/OWNERS
deleted file mode 100644
index 2845b0f366d..00000000000
--- a/chromium/components/user_prefs/tracked/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-bauerb@chromium.org
-gab@chromium.org
diff --git a/chromium/components/user_prefs/tracked/device_id.h b/chromium/components/user_prefs/tracked/device_id.h
deleted file mode 100644
index 2d6d1b8e8b6..00000000000
--- a/chromium/components/user_prefs/tracked/device_id.h
+++ /dev/null
@@ -1,23 +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_USER_PREFS_TRACKED_DEVICE_ID_H_
-#define COMPONENTS_USER_PREFS_TRACKED_DEVICE_ID_H_
-
-#include <string>
-
-enum class MachineIdStatus {
- SUCCESS = 0,
- FAILURE, // Returned if attempt to obtain a machine-specific ID fails.
- NOT_IMPLEMENTED // Returned if the method for obtaining a machine-specific ID
- // is not implemented for the system.
-};
-
-// Populates |machine_id| with a deterministic ID for this machine. |machine_id|
-// must not be null. Returns |FAILURE| if a machine ID cannot be obtained or
-// |NOT_IMPLEMENTED| on systems for which this feature is not supported (in both
-// cases |machine_id| is left untouched).
-MachineIdStatus GetDeterministicMachineSpecificId(std::string* machine_id);
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_DEVICE_ID_H_
diff --git a/chromium/components/user_prefs/tracked/device_id_mac.cc b/chromium/components/user_prefs/tracked/device_id_mac.cc
deleted file mode 100644
index bd5ce805647..00000000000
--- a/chromium/components/user_prefs/tracked/device_id_mac.cc
+++ /dev/null
@@ -1,32 +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/user_prefs/tracked/device_id.h"
-
-#include <IOKit/IOKitLib.h>
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "base/mac/scoped_ioobject.h"
-#include "base/strings/sys_string_conversions.h"
-
-MachineIdStatus GetDeterministicMachineSpecificId(std::string* machine_id) {
- base::mac::ScopedIOObject<io_service_t> platform_expert(
- IOServiceGetMatchingService(kIOMasterPortDefault,
- IOServiceMatching("IOPlatformExpertDevice")));
- if (!platform_expert.get())
- return MachineIdStatus::FAILURE;
-
- base::ScopedCFTypeRef<CFTypeRef> uuid(IORegistryEntryCreateCFProperty(
- platform_expert, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0));
- if (!uuid.get())
- return MachineIdStatus::FAILURE;
-
- CFStringRef uuid_string = base::mac::CFCast<CFStringRef>(uuid);
- if (!uuid_string)
- return MachineIdStatus::FAILURE;
-
- *machine_id = base::SysCFStringRefToUTF8(uuid_string);
- return MachineIdStatus::SUCCESS;
-}
diff --git a/chromium/components/user_prefs/tracked/device_id_stub.cc b/chromium/components/user_prefs/tracked/device_id_stub.cc
deleted file mode 100644
index 07ffb944fe5..00000000000
--- a/chromium/components/user_prefs/tracked/device_id_stub.cc
+++ /dev/null
@@ -1,11 +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/user_prefs/tracked/device_id.h"
-#include "base/logging.h"
-
-MachineIdStatus GetDeterministicMachineSpecificId(std::string* machine_id) {
- DCHECK(machine_id);
- return MachineIdStatus::NOT_IMPLEMENTED;
-}
diff --git a/chromium/components/user_prefs/tracked/device_id_unittest.cc b/chromium/components/user_prefs/tracked/device_id_unittest.cc
deleted file mode 100644
index badc02bae67..00000000000
--- a/chromium/components/user_prefs/tracked/device_id_unittest.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/user_prefs/tracked/device_id.h"
-
-#include "build/build_config.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-TEST(GetDeterministicMachineSpecificIdTest, IsDeterministic) {
- std::string first_machine_id;
- std::string second_machine_id;
-
- const MachineIdStatus kExpectedStatus =
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
- MachineIdStatus::SUCCESS;
-#else
- MachineIdStatus::NOT_IMPLEMENTED;
-#endif
-
- ASSERT_EQ(kExpectedStatus,
- GetDeterministicMachineSpecificId(&first_machine_id));
- ASSERT_EQ(kExpectedStatus,
- GetDeterministicMachineSpecificId(&second_machine_id));
-
- // The reason for using |EXPECT_TRUE| with one argument instead of |EXPECT_EQ|
- // with two arguments is a compiler bug in gcc that results in a "converting
- // 'false' to pointer type" error when the first argument to |EXPECT_EQ| is a
- // compile-time const false value. See also the following bug reports:
- // https://code.google.com/p/googletest/issues/detail?id=322
- // https://code.google.com/p/googletest/issues/detail?id=458
- EXPECT_TRUE((kExpectedStatus == MachineIdStatus::SUCCESS) ==
- !first_machine_id.empty());
- EXPECT_EQ(first_machine_id, second_machine_id);
-}
diff --git a/chromium/components/user_prefs/tracked/device_id_win.cc b/chromium/components/user_prefs/tracked/device_id_win.cc
deleted file mode 100644
index 4f0c1db031e..00000000000
--- a/chromium/components/user_prefs/tracked/device_id_win.cc
+++ /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.
-
-#include "components/user_prefs/tracked/device_id.h"
-
-#include <windows.h>
-#include <sddl.h> // For ConvertSidToStringSidA.
-
-#include <memory>
-
-#include "base/logging.h"
-#include "base/macros.h"
-
-MachineIdStatus GetDeterministicMachineSpecificId(std::string* machine_id) {
- DCHECK(machine_id);
-
- wchar_t computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {};
- DWORD computer_name_size = arraysize(computer_name);
-
- if (!::GetComputerNameW(computer_name, &computer_name_size))
- return MachineIdStatus::FAILURE;
-
- DWORD sid_size = SECURITY_MAX_SID_SIZE;
- char sid_buffer[SECURITY_MAX_SID_SIZE];
- SID* sid = reinterpret_cast<SID*>(sid_buffer);
- DWORD domain_size = 128; // Will expand below if needed.
- std::unique_ptr<wchar_t[]> domain_buffer(new wchar_t[domain_size]);
- SID_NAME_USE sid_name_use;
-
- // Although the fifth argument to |LookupAccountNameW()|,
- // |ReferencedDomainName|, is annotated as |_Out_opt_|, if a null
- // value is passed in, zero is returned and |GetLastError()| will
- // return |ERROR_INSUFFICIENT_BUFFER| (assuming that nothing else went
- // wrong). In order to ensure that the call to |LookupAccountNameW()|
- // has succeeded, it is necessary to include the following logic and
- // obtain the domain name.
- if (!::LookupAccountNameW(nullptr, computer_name, sid, &sid_size,
- domain_buffer.get(), &domain_size, &sid_name_use)) {
- // If the initial size of |domain_buffer| was too small, the
- // required size is now found in |domain_size|. Resize and try
- // again.
- if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- return MachineIdStatus::FAILURE;
-
- domain_buffer.reset(new wchar_t[domain_size]);
- if (!::LookupAccountNameW(nullptr, computer_name, sid, &sid_size,
- domain_buffer.get(), &domain_size,
- &sid_name_use)) {
- return MachineIdStatus::FAILURE;
- }
- }
-
- // Ensure that the correct type of SID was obtained. The
- // |LookupAccountNameW()| function seems to always return
- // |SidTypeDomain| instead of |SidTypeComputer| when the computer name
- // is passed in as its second argument and therefore both enum values
- // will be considered acceptable. If the computer name and user name
- // coincide, |LookupAccountNameW()| seems to always return the machine
- // SID and set the returned enum to |SidTypeDomain|.
- DCHECK(sid_name_use == SID_NAME_USE::SidTypeComputer ||
- sid_name_use == SID_NAME_USE::SidTypeDomain);
-
- char* sid_string = nullptr;
- if (!::ConvertSidToStringSidA(sid, &sid_string))
- return MachineIdStatus::FAILURE;
-
- *machine_id = sid_string;
- ::LocalFree(sid_string);
-
- return MachineIdStatus::SUCCESS;
-}
diff --git a/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.cc b/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.cc
deleted file mode 100644
index 288c1bf45db..00000000000
--- a/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.cc
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright (c) 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/user_prefs/tracked/dictionary_hash_store_contents.h"
-
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/values.h"
-#include "components/pref_registry/pref_registry_syncable.h"
-#include "components/prefs/persistent_pref_store.h"
-
-namespace {
-const char kPreferenceMACs[] = "protection.macs";
-const char kSuperMACPref[] = "protection.super_mac";
-}
-
-DictionaryHashStoreContents::DictionaryHashStoreContents(
- base::DictionaryValue* storage)
- : storage_(storage) {
-}
-
-// static
-void DictionaryHashStoreContents::RegisterProfilePrefs(
- user_prefs::PrefRegistrySyncable* registry) {
- registry->RegisterDictionaryPref(kPreferenceMACs);
- registry->RegisterStringPref(kSuperMACPref, std::string());
-}
-
-bool DictionaryHashStoreContents::IsCopyable() const {
- return false;
-}
-
-std::unique_ptr<HashStoreContents> DictionaryHashStoreContents::MakeCopy()
- const {
- NOTREACHED() << "DictionaryHashStoreContents does not support MakeCopy";
- return nullptr;
-}
-
-base::StringPiece DictionaryHashStoreContents::GetUMASuffix() const {
- // To stay consistent with existing reported data, do not append a suffix
- // when reporting UMA stats for this content.
- return base::StringPiece();
-}
-
-void DictionaryHashStoreContents::Reset() {
- storage_->Remove(kPreferenceMACs, NULL);
-}
-
-bool DictionaryHashStoreContents::GetMac(const std::string& path,
- std::string* out_value) {
- const base::DictionaryValue* macs_dict = GetContents();
- if (macs_dict)
- return macs_dict->GetString(path, out_value);
-
- return false;
-}
-
-bool DictionaryHashStoreContents::GetSplitMacs(
- const std::string& path,
- std::map<std::string, std::string>* split_macs) {
- DCHECK(split_macs);
- DCHECK(split_macs->empty());
-
- const base::DictionaryValue* macs_dict = GetContents();
- const base::DictionaryValue* split_macs_dict = NULL;
- if (!macs_dict || !macs_dict->GetDictionary(path, &split_macs_dict))
- return false;
- for (base::DictionaryValue::Iterator it(*split_macs_dict); !it.IsAtEnd();
- it.Advance()) {
- std::string mac_string;
- if (!it.value().GetAsString(&mac_string)) {
- NOTREACHED();
- continue;
- }
- split_macs->insert(make_pair(it.key(), mac_string));
- }
- return true;
-}
-
-void DictionaryHashStoreContents::SetMac(const std::string& path,
- const std::string& value) {
- base::DictionaryValue* macs_dict = GetMutableContents(true);
- macs_dict->SetString(path, value);
-}
-
-void DictionaryHashStoreContents::SetSplitMac(const std::string& path,
- const std::string& split_path,
- const std::string& value) {
- // DictionaryValue handles a '.' delimiter.
- SetMac(path + '.' + split_path, value);
-}
-
-void DictionaryHashStoreContents::ImportEntry(const std::string& path,
- const base::Value* in_value) {
- base::DictionaryValue* macs_dict = GetMutableContents(true);
- macs_dict->Set(path, in_value->DeepCopy());
-}
-
-bool DictionaryHashStoreContents::RemoveEntry(const std::string& path) {
- base::DictionaryValue* macs_dict = GetMutableContents(false);
- if (macs_dict)
- return macs_dict->RemovePath(path, NULL);
-
- return false;
-}
-
-std::string DictionaryHashStoreContents::GetSuperMac() const {
- std::string super_mac_string;
- storage_->GetString(kSuperMACPref, &super_mac_string);
- return super_mac_string;
-}
-
-void DictionaryHashStoreContents::SetSuperMac(const std::string& super_mac) {
- storage_->SetString(kSuperMACPref, super_mac);
-}
-
-const base::DictionaryValue* DictionaryHashStoreContents::GetContents() const {
- const base::DictionaryValue* macs_dict = NULL;
- storage_->GetDictionary(kPreferenceMACs, &macs_dict);
- return macs_dict;
-}
-
-base::DictionaryValue* DictionaryHashStoreContents::GetMutableContents(
- bool create_if_null) {
- base::DictionaryValue* macs_dict = NULL;
- storage_->GetDictionary(kPreferenceMACs, &macs_dict);
- if (!macs_dict && create_if_null) {
- macs_dict = new base::DictionaryValue;
- storage_->Set(kPreferenceMACs, macs_dict);
- }
- return macs_dict;
-}
diff --git a/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.h b/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.h
deleted file mode 100644
index f231c257bdd..00000000000
--- a/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.h
+++ /dev/null
@@ -1,62 +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_USER_PREFS_TRACKED_DICTIONARY_HASH_STORE_CONTENTS_H_
-#define COMPONENTS_USER_PREFS_TRACKED_DICTIONARY_HASH_STORE_CONTENTS_H_
-
-#include "base/macros.h"
-#include "components/user_prefs/tracked/hash_store_contents.h"
-
-namespace base {
-class DictionaryValue;
-class Value;
-} // namespace base
-
-namespace user_prefs {
-class PrefRegistrySyncable;
-} // namespace user_prefs
-
-// Implements HashStoreContents by storing MACs in a DictionaryValue. The
-// DictionaryValue is presumed to be the contents of a PrefStore.
-// RegisterProfilePrefs() may be used to register all of the preferences used by
-// this object.
-class DictionaryHashStoreContents : public HashStoreContents {
- public:
- // Constructs a DictionaryHashStoreContents that reads from and writes to
- // |storage|.
- explicit DictionaryHashStoreContents(base::DictionaryValue* storage);
-
- // Registers required preferences.
- static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
-
- // HashStoreContents implementation
- bool IsCopyable() const override;
- std::unique_ptr<HashStoreContents> MakeCopy() const override;
- base::StringPiece GetUMASuffix() const override;
- void Reset() override;
- bool GetMac(const std::string& path, std::string* out_value) override;
- bool GetSplitMacs(const std::string& path,
- std::map<std::string, std::string>* split_macs) override;
- void SetMac(const std::string& path, const std::string& value) override;
- void SetSplitMac(const std::string& path,
- const std::string& split_path,
- const std::string& value) override;
- void ImportEntry(const std::string& path,
- const base::Value* in_value) override;
- bool RemoveEntry(const std::string& path) override;
- const base::DictionaryValue* GetContents() const override;
- std::string GetSuperMac() const override;
- void SetSuperMac(const std::string& super_mac) override;
-
- private:
- base::DictionaryValue* storage_;
-
- // Helper function to get a mutable version of the macs from |storage_|,
- // creating it if needed and |create_if_null| is true.
- base::DictionaryValue* GetMutableContents(bool create_if_null);
-
- DISALLOW_COPY_AND_ASSIGN(DictionaryHashStoreContents);
-};
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_DICTIONARY_HASH_STORE_CONTENTS_H_
diff --git a/chromium/components/user_prefs/tracked/hash_store_contents.h b/chromium/components/user_prefs/tracked/hash_store_contents.h
deleted file mode 100644
index 9cc8abba090..00000000000
--- a/chromium/components/user_prefs/tracked/hash_store_contents.h
+++ /dev/null
@@ -1,90 +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_USER_PREFS_TRACKED_HASH_STORE_CONTENTS_H_
-#define COMPONENTS_USER_PREFS_TRACKED_HASH_STORE_CONTENTS_H_
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include "base/strings/string_piece.h"
-
-namespace base {
-class DictionaryValue;
-class Value;
-} // namespace base
-
-// Provides access to the contents of a preference hash store. The store
-// contains the following data:
-// Contents: a client-defined dictionary that should map preference names to
-// MACs.
-// Version: a client-defined version number for the format of Contents.
-// Super MAC: a MAC that authenticates the entirety of Contents.
-class HashStoreContents {
- public:
- virtual ~HashStoreContents() {}
-
- // Returns true if this implementation of HashStoreContents can be copied via
- // MakeCopy().
- virtual bool IsCopyable() const = 0;
-
- // Returns a copy of this HashStoreContents. Must only be called on
- // lightweight implementations (which return true from IsCopyable()) and only
- // in scenarios where a copy cannot be avoided.
- virtual std::unique_ptr<HashStoreContents> MakeCopy() const = 0;
-
- // Returns the suffix to be appended to UMA histograms for this store type.
- // The returned value must either be an empty string or one of the values in
- // histograms.xml's TrackedPreferencesExternalValidators.
- virtual base::StringPiece GetUMASuffix() const = 0;
-
- // Discards all data related to this hash store.
- virtual void Reset() = 0;
-
- // Outputs the MAC validating the preference at path. Returns true if a MAC
- // was successfully read and false otherwise.
- virtual bool GetMac(const std::string& path, std::string* out_value) = 0;
-
- // Outputs the MACS validating the split preference at path. Returns true if
- // MACS were successfully read and false otherwise.
- virtual bool GetSplitMacs(const std::string& path,
- std::map<std::string, std::string>* out_value) = 0;
-
- // Set the MAC validating the preference at path.
- virtual void SetMac(const std::string& path, const std::string& value) = 0;
-
- // Set the MAC validating the split preference at path and split_path.
- // For example, |path| is 'extension' and |split_path| is some extenson id.
- virtual void SetSplitMac(const std::string& path,
- const std::string& split_path,
- const std::string& value) = 0;
-
- // Sets the MAC for the preference at |path|.
- // If |path| is a split preference |in_value| must be a DictionaryValue whose
- // keys are keys in the split preference and whose values are MACs of the
- // corresponding values in the split preference.
- // If |path| is an atomic preference |in_value| must be a StringValue
- // containing a MAC of the preference value.
- virtual void ImportEntry(const std::string& path,
- const base::Value* in_value) = 0;
-
- // Removes the MAC (for atomic preferences) or MACs (for split preferences)
- // at |path|. Returns true if there was an entry at |path| which was
- // successfully removed.
- virtual bool RemoveEntry(const std::string& path) = 0;
-
- // Only needed if this store supports super MACs.
- virtual const base::DictionaryValue* GetContents() const = 0;
-
- // Retrieves the super MAC value previously stored by SetSuperMac. May be
- // empty if no super MAC has been stored or if this store does not support
- // super MACs.
- virtual std::string GetSuperMac() const = 0;
-
- // Stores a super MAC value for this hash store.
- virtual void SetSuperMac(const std::string& super_mac) = 0;
-};
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_HASH_STORE_CONTENTS_H_
diff --git a/chromium/components/user_prefs/tracked/interceptable_pref_filter.cc b/chromium/components/user_prefs/tracked/interceptable_pref_filter.cc
deleted file mode 100644
index f3ee3c7187c..00000000000
--- a/chromium/components/user_prefs/tracked/interceptable_pref_filter.cc
+++ /dev/null
@@ -1,41 +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/user_prefs/tracked/interceptable_pref_filter.h"
-
-#include <utility>
-
-#include "base/bind.h"
-
-InterceptablePrefFilter::InterceptablePrefFilter() {
-}
-InterceptablePrefFilter::~InterceptablePrefFilter() {
-}
-
-void InterceptablePrefFilter::FilterOnLoad(
- const PostFilterOnLoadCallback& post_filter_on_load_callback,
- std::unique_ptr<base::DictionaryValue> pref_store_contents) {
- if (filter_on_load_interceptor_.is_null()) {
- FinalizeFilterOnLoad(post_filter_on_load_callback,
- std::move(pref_store_contents), false);
- } else {
- // Note, in practice (in the implementation as it was in May 2014) it would
- // be okay to pass an unretained |this| pointer below, but in order to avoid
- // having to augment the API everywhere to explicitly enforce the ownership
- // model as it happens to currently be: make the relationship simpler by
- // weakly binding the FinalizeFilterOnLoadCallback below to |this|.
- const FinalizeFilterOnLoadCallback finalize_filter_on_load(
- base::Bind(&InterceptablePrefFilter::FinalizeFilterOnLoad, AsWeakPtr(),
- post_filter_on_load_callback));
- filter_on_load_interceptor_.Run(finalize_filter_on_load,
- std::move(pref_store_contents));
- filter_on_load_interceptor_.Reset();
- }
-}
-
-void InterceptablePrefFilter::InterceptNextFilterOnLoad(
- const FilterOnLoadInterceptor& filter_on_load_interceptor) {
- DCHECK(filter_on_load_interceptor_.is_null());
- filter_on_load_interceptor_ = filter_on_load_interceptor;
-}
diff --git a/chromium/components/user_prefs/tracked/interceptable_pref_filter.h b/chromium/components/user_prefs/tracked/interceptable_pref_filter.h
deleted file mode 100644
index 39dc9d955fc..00000000000
--- a/chromium/components/user_prefs/tracked/interceptable_pref_filter.h
+++ /dev/null
@@ -1,68 +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_USER_PREFS_TRACKED_INTERCEPTABLE_PREF_FILTER_H_
-#define COMPONENTS_USER_PREFS_TRACKED_INTERCEPTABLE_PREF_FILTER_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "base/values.h"
-#include "components/prefs/pref_filter.h"
-
-// A partial implementation of a PrefFilter whose FilterOnLoad call may be
-// intercepted by a FilterOnLoadInterceptor. Implementations of
-// InterceptablePrefFilter are expected to override FinalizeFilterOnLoad rather
-// than re-overriding FilterOnLoad.
-class InterceptablePrefFilter
- : public PrefFilter,
- public base::SupportsWeakPtr<InterceptablePrefFilter> {
- public:
- // A callback to be invoked by a FilterOnLoadInterceptor when its ready to
- // hand back the |prefs| it was handed for early filtering. |prefs_altered|
- // indicates whether the |prefs| were actually altered by the
- // FilterOnLoadInterceptor before being handed back.
- typedef base::Callback<void(std::unique_ptr<base::DictionaryValue> prefs,
- bool prefs_altered)>
- FinalizeFilterOnLoadCallback;
-
- // A callback to be invoked from FilterOnLoad. It takes ownership of prefs
- // and may modify them before handing them back to this
- // InterceptablePrefFilter via |finalize_filter_on_load|.
- typedef base::Callback<void(
- const FinalizeFilterOnLoadCallback& finalize_filter_on_load,
- std::unique_ptr<base::DictionaryValue> prefs)>
- FilterOnLoadInterceptor;
-
- InterceptablePrefFilter();
- ~InterceptablePrefFilter() override;
-
- // PrefFilter partial implementation.
- void FilterOnLoad(
- const PostFilterOnLoadCallback& post_filter_on_load_callback,
- std::unique_ptr<base::DictionaryValue> pref_store_contents) override;
-
- // Registers |filter_on_load_interceptor| to intercept the next FilterOnLoad
- // event. At most one FilterOnLoadInterceptor should be registered per
- // PrefFilter.
- void InterceptNextFilterOnLoad(
- const FilterOnLoadInterceptor& filter_on_load_interceptor);
-
- private:
- // Does any extra filtering required by the implementation of this
- // InterceptablePrefFilter and hands back the |pref_store_contents| to the
- // initial caller of FilterOnLoad.
- virtual void FinalizeFilterOnLoad(
- const PostFilterOnLoadCallback& post_filter_on_load_callback,
- std::unique_ptr<base::DictionaryValue> pref_store_contents,
- bool prefs_altered) = 0;
-
- // Callback to be invoked only once (and subsequently reset) on the next
- // FilterOnLoad event. It will be allowed to modify the |prefs| handed to
- // FilterOnLoad before handing them back to this PrefHashFilter.
- FilterOnLoadInterceptor filter_on_load_interceptor_;
-};
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_INTERCEPTABLE_PREF_FILTER_H_
diff --git a/chromium/components/user_prefs/tracked/mock_validation_delegate.cc b/chromium/components/user_prefs/tracked/mock_validation_delegate.cc
deleted file mode 100644
index e0e88283c48..00000000000
--- a/chromium/components/user_prefs/tracked/mock_validation_delegate.cc
+++ /dev/null
@@ -1,73 +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/user_prefs/tracked/mock_validation_delegate.h"
-
-MockValidationDelegate::MockValidationDelegate() {
-}
-
-MockValidationDelegate::~MockValidationDelegate() {
-}
-
-size_t MockValidationDelegate::CountValidationsOfState(
- PrefHashStoreTransaction::ValueState value_state) const {
- size_t count = 0;
- for (size_t i = 0; i < validations_.size(); ++i) {
- if (validations_[i].value_state == value_state)
- ++count;
- }
- return count;
-}
-
-size_t MockValidationDelegate::CountExternalValidationsOfState(
- PrefHashStoreTransaction::ValueState value_state) const {
- size_t count = 0;
- for (size_t i = 0; i < validations_.size(); ++i) {
- if (validations_[i].external_validation_value_state == value_state)
- ++count;
- }
- return count;
-}
-
-const MockValidationDelegate::ValidationEvent*
-MockValidationDelegate::GetEventForPath(const std::string& pref_path) const {
- for (size_t i = 0; i < validations_.size(); ++i) {
- if (validations_[i].pref_path == pref_path)
- return &validations_[i];
- }
- return NULL;
-}
-
-void MockValidationDelegate::OnAtomicPreferenceValidation(
- const std::string& pref_path,
- const base::Value* value,
- PrefHashStoreTransaction::ValueState value_state,
- PrefHashStoreTransaction::ValueState external_validation_value_state,
- bool is_personal) {
- RecordValidation(pref_path, value_state, external_validation_value_state,
- is_personal, PrefHashFilter::TRACKING_STRATEGY_ATOMIC);
-}
-
-void MockValidationDelegate::OnSplitPreferenceValidation(
- const std::string& pref_path,
- const base::DictionaryValue* dict_value,
- const std::vector<std::string>& invalid_keys,
- const std::vector<std::string>& external_validation_invalid_keys,
- PrefHashStoreTransaction::ValueState value_state,
- PrefHashStoreTransaction::ValueState external_validation_value_state,
- bool is_personal) {
- RecordValidation(pref_path, value_state, external_validation_value_state,
- is_personal, PrefHashFilter::TRACKING_STRATEGY_SPLIT);
-}
-
-void MockValidationDelegate::RecordValidation(
- const std::string& pref_path,
- PrefHashStoreTransaction::ValueState value_state,
- PrefHashStoreTransaction::ValueState external_validation_value_state,
- bool is_personal,
- PrefHashFilter::PrefTrackingStrategy strategy) {
- validations_.push_back(ValidationEvent(pref_path, value_state,
- external_validation_value_state,
- is_personal, strategy));
-}
diff --git a/chromium/components/user_prefs/tracked/mock_validation_delegate.h b/chromium/components/user_prefs/tracked/mock_validation_delegate.h
deleted file mode 100644
index de95f0599ed..00000000000
--- a/chromium/components/user_prefs/tracked/mock_validation_delegate.h
+++ /dev/null
@@ -1,89 +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_USER_PREFS_TRACKED_MOCK_VALIDATION_DELEGATE_H_
-#define COMPONENTS_USER_PREFS_TRACKED_MOCK_VALIDATION_DELEGATE_H_
-
-#include <stddef.h>
-
-#include <string>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "components/user_prefs/tracked/pref_hash_filter.h"
-#include "components/user_prefs/tracked/pref_hash_store_transaction.h"
-#include "components/user_prefs/tracked/tracked_preference_validation_delegate.h"
-
-// A mock tracked preference validation delegate for use by tests.
-class MockValidationDelegate : public TrackedPreferenceValidationDelegate {
- public:
- struct ValidationEvent {
- ValidationEvent(
- const std::string& path,
- PrefHashStoreTransaction::ValueState state,
- PrefHashStoreTransaction::ValueState external_validation_state,
- bool is_personal,
- PrefHashFilter::PrefTrackingStrategy tracking_strategy)
- : pref_path(path),
- value_state(state),
- external_validation_value_state(external_validation_state),
- is_personal(is_personal),
- strategy(tracking_strategy) {}
-
- std::string pref_path;
- PrefHashStoreTransaction::ValueState value_state;
- PrefHashStoreTransaction::ValueState external_validation_value_state;
- bool is_personal;
- PrefHashFilter::PrefTrackingStrategy strategy;
- };
-
- MockValidationDelegate();
- ~MockValidationDelegate() override;
-
- // Returns the number of recorded validations.
- size_t recorded_validations_count() const { return validations_.size(); }
-
- // Returns the number of validations of a given value state.
- size_t CountValidationsOfState(
- PrefHashStoreTransaction::ValueState value_state) const;
-
- // Returns the number of external validations of a given value state.
- size_t CountExternalValidationsOfState(
- PrefHashStoreTransaction::ValueState value_state) const;
-
- // Returns the event for the preference with a given path.
- const ValidationEvent* GetEventForPath(const std::string& pref_path) const;
-
- // TrackedPreferenceValidationDelegate implementation.
- void OnAtomicPreferenceValidation(
- const std::string& pref_path,
- const base::Value* value,
- PrefHashStoreTransaction::ValueState value_state,
- PrefHashStoreTransaction::ValueState external_validation_value_state,
- bool is_personal) override;
- void OnSplitPreferenceValidation(
- const std::string& pref_path,
- const base::DictionaryValue* dict_value,
- const std::vector<std::string>& invalid_keys,
- const std::vector<std::string>& external_validation_invalid_keys,
- PrefHashStoreTransaction::ValueState value_state,
- PrefHashStoreTransaction::ValueState external_validation_value_state,
- bool is_personal) override;
-
- private:
- // Adds a new validation event.
- void RecordValidation(
- const std::string& pref_path,
- PrefHashStoreTransaction::ValueState value_state,
- PrefHashStoreTransaction::ValueState external_validation_value_state,
- bool is_personal,
- PrefHashFilter::PrefTrackingStrategy strategy);
-
- std::vector<ValidationEvent> validations_;
-
- DISALLOW_COPY_AND_ASSIGN(MockValidationDelegate);
-};
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_MOCK_VALIDATION_DELEGATE_H_
diff --git a/chromium/components/user_prefs/tracked/pref_hash_calculator.cc b/chromium/components/user_prefs/tracked/pref_hash_calculator.cc
deleted file mode 100644
index 8d73c1dcbc9..00000000000
--- a/chromium/components/user_prefs/tracked/pref_hash_calculator.cc
+++ /dev/null
@@ -1,113 +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/user_prefs/tracked/pref_hash_calculator.h"
-
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/json/json_string_value_serializer.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/values.h"
-#include "crypto/hmac.h"
-
-namespace {
-
-// Calculates an HMAC of |message| using |key|, encoded as a hexadecimal string.
-std::string GetDigestString(const std::string& key,
- const std::string& message) {
- crypto::HMAC hmac(crypto::HMAC::SHA256);
- std::vector<uint8_t> digest(hmac.DigestLength());
- if (!hmac.Init(key) || !hmac.Sign(message, &digest[0], digest.size())) {
- NOTREACHED();
- return std::string();
- }
- return base::HexEncode(&digest[0], digest.size());
-}
-
-// Verifies that |digest_string| is a valid HMAC of |message| using |key|.
-// |digest_string| must be encoded as a hexadecimal string.
-bool VerifyDigestString(const std::string& key,
- const std::string& message,
- const std::string& digest_string) {
- crypto::HMAC hmac(crypto::HMAC::SHA256);
- std::vector<uint8_t> digest;
- return base::HexStringToBytes(digest_string, &digest) && hmac.Init(key) &&
- hmac.Verify(message,
- base::StringPiece(reinterpret_cast<char*>(&digest[0]),
- digest.size()));
-}
-
-// Renders |value| as a string. |value| may be NULL, in which case the result
-// is an empty string. This method can be expensive and its result should be
-// re-used rather than recomputed where possible.
-std::string ValueAsString(const base::Value* value) {
- // Dictionary values may contain empty lists and sub-dictionaries. Make a
- // deep copy with those removed to make the hash more stable.
- const base::DictionaryValue* dict_value;
- std::unique_ptr<base::DictionaryValue> canonical_dict_value;
- if (value && value->GetAsDictionary(&dict_value)) {
- canonical_dict_value = dict_value->DeepCopyWithoutEmptyChildren();
- value = canonical_dict_value.get();
- }
-
- std::string value_as_string;
- if (value) {
- JSONStringValueSerializer serializer(&value_as_string);
- serializer.Serialize(*value);
- }
-
- return value_as_string;
-}
-
-// Concatenates |device_id|, |path|, and |value_as_string| to give the hash
-// input.
-std::string GetMessage(const std::string& device_id,
- const std::string& path,
- const std::string& value_as_string) {
- std::string message;
- message.reserve(device_id.size() + path.size() + value_as_string.size());
- message.append(device_id);
- message.append(path);
- message.append(value_as_string);
- return message;
-}
-
-} // namespace
-
-PrefHashCalculator::PrefHashCalculator(const std::string& seed,
- const std::string& device_id,
- const std::string& legacy_device_id)
- : seed_(seed), device_id_(device_id), legacy_device_id_(legacy_device_id) {}
-
-PrefHashCalculator::~PrefHashCalculator() {
-}
-
-std::string PrefHashCalculator::Calculate(const std::string& path,
- const base::Value* value) const {
- return GetDigestString(seed_,
- GetMessage(device_id_, path, ValueAsString(value)));
-}
-
-PrefHashCalculator::ValidationResult PrefHashCalculator::Validate(
- const std::string& path,
- const base::Value* value,
- const std::string& digest_string) const {
- const std::string value_as_string(ValueAsString(value));
- if (VerifyDigestString(seed_, GetMessage(device_id_, path, value_as_string),
- digest_string)) {
- return VALID;
- }
- if (VerifyDigestString(seed_,
- GetMessage(legacy_device_id_, path, value_as_string),
- digest_string)) {
- return VALID_SECURE_LEGACY;
- }
- return INVALID;
-}
diff --git a/chromium/components/user_prefs/tracked/pref_hash_calculator.h b/chromium/components/user_prefs/tracked/pref_hash_calculator.h
deleted file mode 100644
index 92b0c3a05d9..00000000000
--- a/chromium/components/user_prefs/tracked/pref_hash_calculator.h
+++ /dev/null
@@ -1,55 +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.
-
-#ifndef COMPONENTS_USER_PREFS_TRACKED_PREF_HASH_CALCULATOR_H_
-#define COMPONENTS_USER_PREFS_TRACKED_PREF_HASH_CALCULATOR_H_
-
-#include <string>
-
-#include "base/macros.h"
-
-namespace base {
-class Value;
-} // namespace base
-
-// Calculates and validates preference value hashes.
-class PrefHashCalculator {
- public:
- enum ValidationResult {
- INVALID,
- VALID,
- // Valid under a deprecated but as secure algorithm.
- VALID_SECURE_LEGACY,
- };
-
- // Constructs a PrefHashCalculator using |seed|, |device_id| and
- // |legacy_device_id|. The same parameters must be used in order to
- // successfully validate generated hashes. |_device_id| or |legacy_device_id|
- // may be empty.
- PrefHashCalculator(const std::string& seed,
- const std::string& device_id,
- const std::string& legacy_device_id);
-
- ~PrefHashCalculator();
-
- // Calculates a hash value for the supplied preference |path| and |value|.
- // |value| may be null if the preference has no value.
- std::string Calculate(const std::string& path,
- const base::Value* value) const;
-
- // Validates the provided preference hash using current and legacy hashing
- // algorithms.
- ValidationResult Validate(const std::string& path,
- const base::Value* value,
- const std::string& hash) const;
-
- private:
- const std::string seed_;
- const std::string device_id_;
- const std::string legacy_device_id_;
-
- DISALLOW_COPY_AND_ASSIGN(PrefHashCalculator);
-};
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_PREF_HASH_CALCULATOR_H_
diff --git a/chromium/components/user_prefs/tracked/pref_hash_calculator_unittest.cc b/chromium/components/user_prefs/tracked/pref_hash_calculator_unittest.cc
deleted file mode 100644
index 11e38f1d76d..00000000000
--- a/chromium/components/user_prefs/tracked/pref_hash_calculator_unittest.cc
+++ /dev/null
@@ -1,197 +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/user_prefs/tracked/pref_hash_calculator.h"
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/string_util.h"
-#include "base/values.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-TEST(PrefHashCalculatorTest, TestCurrentAlgorithm) {
- base::StringValue string_value_1("string value 1");
- base::StringValue string_value_2("string value 2");
- base::DictionaryValue dictionary_value_1;
- dictionary_value_1.SetInteger("int value", 1);
- dictionary_value_1.Set("nested empty map", new base::DictionaryValue);
- base::DictionaryValue dictionary_value_1_equivalent;
- dictionary_value_1_equivalent.SetInteger("int value", 1);
- base::DictionaryValue dictionary_value_2;
- dictionary_value_2.SetInteger("int value", 2);
-
- PrefHashCalculator calc1("seed1", "deviceid", "legacydeviceid");
- PrefHashCalculator calc1_dup("seed1", "deviceid", "legacydeviceid");
- PrefHashCalculator calc2("seed2", "deviceid", "legacydeviceid");
- PrefHashCalculator calc3("seed1", "deviceid2", "legacydeviceid");
-
- // Two calculators with same seed produce same hash.
- ASSERT_EQ(calc1.Calculate("pref_path", &string_value_1),
- calc1_dup.Calculate("pref_path", &string_value_1));
- ASSERT_EQ(PrefHashCalculator::VALID,
- calc1_dup.Validate("pref_path", &string_value_1,
- calc1.Calculate("pref_path", &string_value_1)));
-
- // Different seeds, different hashes.
- ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
- calc2.Calculate("pref_path", &string_value_1));
- ASSERT_EQ(PrefHashCalculator::INVALID,
- calc2.Validate("pref_path", &string_value_1,
- calc1.Calculate("pref_path", &string_value_1)));
-
- // Different device IDs, different hashes.
- ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
- calc3.Calculate("pref_path", &string_value_1));
-
- // Different values, different hashes.
- ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
- calc1.Calculate("pref_path", &string_value_2));
-
- // Different paths, different hashes.
- ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
- calc1.Calculate("pref_path_2", &string_value_1));
-
- // Works for dictionaries.
- ASSERT_EQ(calc1.Calculate("pref_path", &dictionary_value_1),
- calc1.Calculate("pref_path", &dictionary_value_1));
- ASSERT_NE(calc1.Calculate("pref_path", &dictionary_value_1),
- calc1.Calculate("pref_path", &dictionary_value_2));
-
- // Empty dictionary children are pruned.
- ASSERT_EQ(calc1.Calculate("pref_path", &dictionary_value_1),
- calc1.Calculate("pref_path", &dictionary_value_1_equivalent));
-
- // NULL value is supported.
- ASSERT_FALSE(calc1.Calculate("pref_path", NULL).empty());
-}
-
-// Tests the output against a known value to catch unexpected algorithm changes.
-// The test hashes below must NEVER be updated, the serialization algorithm used
-// must always be able to generate data that will produce these exact hashes.
-TEST(PrefHashCalculatorTest, CatchHashChanges) {
- static const char kSeed[] = "0123456789ABCDEF0123456789ABCDEF";
- static const char kDeviceId[] = "test_device_id1";
-
- std::unique_ptr<base::Value> null_value = base::Value::CreateNullValue();
- std::unique_ptr<base::Value> bool_value(new base::Value(false));
- std::unique_ptr<base::Value> int_value(new base::Value(1234567890));
- std::unique_ptr<base::Value> double_value(new base::Value(123.0987654321));
- std::unique_ptr<base::Value> string_value(
- new base::StringValue("testing with special chars:\n<>{}:^^@#$\\/"));
-
- // For legacy reasons, we have to support pruning of empty lists/dictionaries
- // and nested empty ists/dicts in the hash generation algorithm.
- std::unique_ptr<base::DictionaryValue> nested_empty_dict(
- new base::DictionaryValue);
- nested_empty_dict->Set("a", new base::DictionaryValue);
- nested_empty_dict->Set("b", new base::ListValue);
- std::unique_ptr<base::ListValue> nested_empty_list(new base::ListValue);
- nested_empty_list->Append(base::MakeUnique<base::DictionaryValue>());
- nested_empty_list->Append(base::MakeUnique<base::ListValue>());
- nested_empty_list->Append(nested_empty_dict->CreateDeepCopy());
-
- // A dictionary with an empty dictionary, an empty list, and nested empty
- // dictionaries/lists in it.
- std::unique_ptr<base::DictionaryValue> dict_value(new base::DictionaryValue);
- dict_value->Set("a", new base::StringValue("foo"));
- dict_value->Set("d", new base::ListValue);
- dict_value->Set("b", new base::DictionaryValue);
- dict_value->Set("c", new base::StringValue("baz"));
- dict_value->Set("e", nested_empty_dict.release());
- dict_value->Set("f", nested_empty_list.release());
-
- std::unique_ptr<base::ListValue> list_value(new base::ListValue);
- list_value->AppendBoolean(true);
- list_value->AppendInteger(100);
- list_value->AppendDouble(1.0);
-
- ASSERT_EQ(base::Value::Type::NONE, null_value->GetType());
- ASSERT_EQ(base::Value::Type::BOOLEAN, bool_value->GetType());
- ASSERT_EQ(base::Value::Type::INTEGER, int_value->GetType());
- ASSERT_EQ(base::Value::Type::DOUBLE, double_value->GetType());
- ASSERT_EQ(base::Value::Type::STRING, string_value->GetType());
- ASSERT_EQ(base::Value::Type::DICTIONARY, dict_value->GetType());
- ASSERT_EQ(base::Value::Type::LIST, list_value->GetType());
-
- // Test every value type independently. Intentionally omits Type::BINARY which
- // isn't even allowed in JSONWriter's input.
- static const char kExpectedNullValue[] =
- "82A9F3BBC7F9FF84C76B033C854E79EEB162783FA7B3E99FF9372FA8E12C44F7";
- EXPECT_EQ(PrefHashCalculator::VALID,
- PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
- .Validate("pref.path", null_value.get(), kExpectedNullValue));
-
- static const char kExpectedBooleanValue[] =
- "A520D8F43EA307B0063736DC9358C330539D0A29417580514C8B9862632C4CCC";
- EXPECT_EQ(
- PrefHashCalculator::VALID,
- PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
- .Validate("pref.path", bool_value.get(), kExpectedBooleanValue));
-
- static const char kExpectedIntegerValue[] =
- "8D60DA1F10BF5AA29819D2D66D7CCEF9AABC5DA93C11A0D2BD21078D63D83682";
- EXPECT_EQ(PrefHashCalculator::VALID,
- PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
- .Validate("pref.path", int_value.get(), kExpectedIntegerValue));
-
- static const char kExpectedDoubleValue[] =
- "C9D94772516125BEEDAE68C109D44BC529E719EE020614E894CC7FB4098C545D";
- EXPECT_EQ(
- PrefHashCalculator::VALID,
- PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
- .Validate("pref.path", double_value.get(), kExpectedDoubleValue));
-
- static const char kExpectedStringValue[] =
- "05ACCBD3B05C45C36CD06190F63EC577112311929D8380E26E5F13182EB68318";
- EXPECT_EQ(
- PrefHashCalculator::VALID,
- PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
- .Validate("pref.path", string_value.get(), kExpectedStringValue));
-
- static const char kExpectedDictValue[] =
- "7A84DCC710D796C771F789A4DA82C952095AA956B6F1667EE42D0A19ECAA3C4A";
- EXPECT_EQ(PrefHashCalculator::VALID,
- PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
- .Validate("pref.path", dict_value.get(), kExpectedDictValue));
-
- static const char kExpectedListValue[] =
- "8D5A25972DF5AE20D041C780E7CA54E40F614AD53513A0724EE8D62D4F992740";
- EXPECT_EQ(PrefHashCalculator::VALID,
- PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
- .Validate("pref.path", list_value.get(), kExpectedListValue));
-
- // Also test every value type together in the same dictionary.
- base::DictionaryValue everything;
- everything.Set("null", null_value.release());
- everything.Set("bool", bool_value.release());
- everything.Set("int", int_value.release());
- everything.Set("double", double_value.release());
- everything.Set("string", string_value.release());
- everything.Set("list", list_value.release());
- everything.Set("dict", dict_value.release());
- static const char kExpectedEverythingValue[] =
- "B97D09BE7005693574DCBDD03D8D9E44FB51F4008B73FB56A49A9FA671A1999B";
- EXPECT_EQ(PrefHashCalculator::VALID,
- PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
- .Validate("pref.path", &everything, kExpectedEverythingValue));
-}
-
-TEST(PrefHashCalculatorTest, TestCompatibilityWithLegacyDeviceId) {
- static const char kSeed[] = "0123456789ABCDEF0123456789ABCDEF";
- static const char kNewDeviceId[] = "new_test_device_id1";
- static const char kLegacyDeviceId[] = "test_device_id1";
-
- // As in PrefHashCalculatorTest.CatchHashChanges.
- const base::StringValue string_value(
- "testing with special chars:\n<>{}:^^@#$\\/");
- static const char kExpectedValue[] =
- "05ACCBD3B05C45C36CD06190F63EC577112311929D8380E26E5F13182EB68318";
-
- EXPECT_EQ(PrefHashCalculator::VALID_SECURE_LEGACY,
- PrefHashCalculator(kSeed, kNewDeviceId, kLegacyDeviceId)
- .Validate("pref.path", &string_value, kExpectedValue));
-}
diff --git a/chromium/components/user_prefs/tracked/pref_hash_filter.cc b/chromium/components/user_prefs/tracked/pref_hash_filter.cc
deleted file mode 100644
index 6ae59af8e21..00000000000
--- a/chromium/components/user_prefs/tracked/pref_hash_filter.cc
+++ /dev/null
@@ -1,370 +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/user_prefs/tracked/pref_hash_filter.h"
-
-#include <stdint.h>
-#include <algorithm>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/time/time.h"
-#include "base/values.h"
-#include "components/pref_registry/pref_registry_syncable.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/pref_store.h"
-#include "components/user_prefs/tracked/dictionary_hash_store_contents.h"
-#include "components/user_prefs/tracked/pref_hash_store.h"
-#include "components/user_prefs/tracked/pref_hash_store_transaction.h"
-#include "components/user_prefs/tracked/pref_names.h"
-#include "components/user_prefs/tracked/tracked_atomic_preference.h"
-#include "components/user_prefs/tracked/tracked_split_preference.h"
-
-namespace {
-
-void CleanupDeprecatedTrackedPreferences(
- base::DictionaryValue* pref_store_contents,
- PrefHashStoreTransaction* hash_store_transaction) {
- // Add deprecated previously tracked preferences below for them to be cleaned
- // up from both the pref files and the hash store.
- static const char* const kDeprecatedTrackedPreferences[] = {
- // TODO(a-v-y): Remove in M60+,
- "default_search_provider.search_url",
- "default_search_provider.name",
- "default_search_provider.keyword"
- };
-
- for (size_t i = 0; i < arraysize(kDeprecatedTrackedPreferences); ++i) {
- const char* key = kDeprecatedTrackedPreferences[i];
- pref_store_contents->Remove(key, NULL);
- hash_store_transaction->ClearHash(key);
- }
-}
-
-} // namespace
-
-PrefHashFilter::PrefHashFilter(
- std::unique_ptr<PrefHashStore> pref_hash_store,
- StoreContentsPair external_validation_hash_store_pair,
- const std::vector<TrackedPreferenceMetadata>& tracked_preferences,
- const base::Closure& on_reset_on_load,
- TrackedPreferenceValidationDelegate* delegate,
- size_t reporting_ids_count,
- bool report_super_mac_validity)
- : pref_hash_store_(std::move(pref_hash_store)),
- external_validation_hash_store_pair_(
- external_validation_hash_store_pair.first
- ? base::make_optional(
- std::move(external_validation_hash_store_pair))
- : base::nullopt),
- on_reset_on_load_(on_reset_on_load),
- report_super_mac_validity_(report_super_mac_validity) {
- DCHECK(pref_hash_store_);
- DCHECK_GE(reporting_ids_count, tracked_preferences.size());
- // Verify that, if |external_validation_hash_store_pair_| is present, both its
- // items are non-null.
- DCHECK(!external_validation_hash_store_pair_.has_value() ||
- (external_validation_hash_store_pair_->first &&
- external_validation_hash_store_pair_->second));
-
- for (size_t i = 0; i < tracked_preferences.size(); ++i) {
- const TrackedPreferenceMetadata& metadata = tracked_preferences[i];
-
- std::unique_ptr<TrackedPreference> tracked_preference;
- switch (metadata.strategy) {
- case TRACKING_STRATEGY_ATOMIC:
- tracked_preference.reset(
- new TrackedAtomicPreference(metadata.name,
- metadata.reporting_id,
- reporting_ids_count,
- metadata.enforcement_level,
- metadata.value_type,
- delegate));
- break;
- case TRACKING_STRATEGY_SPLIT:
- tracked_preference.reset(
- new TrackedSplitPreference(metadata.name,
- metadata.reporting_id,
- reporting_ids_count,
- metadata.enforcement_level,
- metadata.value_type,
- delegate));
- break;
- }
- DCHECK(tracked_preference);
-
- bool is_new = tracked_paths_
- .insert(std::make_pair(metadata.name,
- std::move(tracked_preference)))
- .second;
- DCHECK(is_new);
- }
-}
-
-PrefHashFilter::~PrefHashFilter() {
- // Ensure new values for all |changed_paths_| have been flushed to
- // |pref_hash_store_| already.
- DCHECK(changed_paths_.empty());
-}
-
-// static
-void PrefHashFilter::RegisterProfilePrefs(
- user_prefs::PrefRegistrySyncable* registry) {
- // See GetResetTime for why this is a StringPref and not Int64Pref.
- registry->RegisterStringPref(
- user_prefs::kPreferenceResetTime,
- base::Int64ToString(base::Time().ToInternalValue()));
-}
-
-// static
-base::Time PrefHashFilter::GetResetTime(PrefService* user_prefs) {
- // Provide our own implementation (identical to the PrefService::GetInt64) in
- // order to ensure it remains consistent with the way we store this value
- // (which we do via a PrefStore, preventing us from reusing
- // PrefService::SetInt64).
- int64_t internal_value = base::Time().ToInternalValue();
- if (!base::StringToInt64(
- user_prefs->GetString(user_prefs::kPreferenceResetTime),
- &internal_value)) {
- // Somehow the value stored on disk is not a valid int64_t.
- NOTREACHED();
- return base::Time();
- }
- return base::Time::FromInternalValue(internal_value);
-}
-
-// static
-void PrefHashFilter::ClearResetTime(PrefService* user_prefs) {
- user_prefs->ClearPref(user_prefs::kPreferenceResetTime);
-}
-
-void PrefHashFilter::Initialize(base::DictionaryValue* pref_store_contents) {
- DictionaryHashStoreContents dictionary_contents(pref_store_contents);
- std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction(
- pref_hash_store_->BeginTransaction(&dictionary_contents));
- for (auto it = tracked_paths_.begin(); it != tracked_paths_.end(); ++it) {
- const std::string& initialized_path = it->first;
- const TrackedPreference* initialized_preference = it->second.get();
- const base::Value* value = nullptr;
- pref_store_contents->Get(initialized_path, &value);
- initialized_preference->OnNewValue(value, hash_store_transaction.get());
- }
-}
-
-// Marks |path| has having changed if it is part of |tracked_paths_|. A new hash
-// will be stored for it the next time FilterSerializeData() is invoked.
-void PrefHashFilter::FilterUpdate(const std::string& path) {
- auto it = tracked_paths_.find(path);
- if (it != tracked_paths_.end())
- changed_paths_.insert(std::make_pair(path, it->second.get()));
-}
-
-// Updates the stored hashes for |changed_paths_| before serializing data to
-// disk. This is required as storing the hash everytime a pref's value changes
-// is too expensive (see perf regression @ http://crbug.com/331273).
-PrefFilter::OnWriteCallbackPair PrefHashFilter::FilterSerializeData(
- base::DictionaryValue* pref_store_contents) {
- // Generate the callback pair before clearing |changed_paths_|.
- PrefFilter::OnWriteCallbackPair callback_pair =
- GetOnWriteSynchronousCallbacks(pref_store_contents);
-
- if (!changed_paths_.empty()) {
- base::TimeTicks checkpoint = base::TimeTicks::Now();
- {
- DictionaryHashStoreContents dictionary_contents(pref_store_contents);
- std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction(
- pref_hash_store_->BeginTransaction(&dictionary_contents));
-
- std::unique_ptr<PrefHashStoreTransaction>
- external_validation_hash_store_transaction;
- if (external_validation_hash_store_pair_) {
- external_validation_hash_store_transaction =
- external_validation_hash_store_pair_->first->BeginTransaction(
- external_validation_hash_store_pair_->second.get());
- }
-
- for (ChangedPathsMap::const_iterator it = changed_paths_.begin();
- it != changed_paths_.end(); ++it) {
- const std::string& changed_path = it->first;
- const TrackedPreference* changed_preference = it->second;
- const base::Value* value = nullptr;
- pref_store_contents->Get(changed_path, &value);
- changed_preference->OnNewValue(value, hash_store_transaction.get());
- }
- changed_paths_.clear();
- }
- UMA_HISTOGRAM_TIMES("Settings.FilterSerializeDataTime",
- base::TimeTicks::Now() - checkpoint);
- }
-
- return callback_pair;
-}
-
-void PrefHashFilter::FinalizeFilterOnLoad(
- const PostFilterOnLoadCallback& post_filter_on_load_callback,
- std::unique_ptr<base::DictionaryValue> pref_store_contents,
- bool prefs_altered) {
- DCHECK(pref_store_contents);
- base::TimeTicks checkpoint = base::TimeTicks::Now();
-
- bool did_reset = false;
- {
- DictionaryHashStoreContents dictionary_contents(pref_store_contents.get());
- std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction(
- pref_hash_store_->BeginTransaction(&dictionary_contents));
-
- std::unique_ptr<PrefHashStoreTransaction>
- external_validation_hash_store_transaction;
- if (external_validation_hash_store_pair_) {
- external_validation_hash_store_transaction =
- external_validation_hash_store_pair_->first->BeginTransaction(
- external_validation_hash_store_pair_->second.get());
- }
-
- CleanupDeprecatedTrackedPreferences(
- pref_store_contents.get(), hash_store_transaction.get());
-
- if (report_super_mac_validity_) {
- UMA_HISTOGRAM_BOOLEAN("Settings.HashesDictionaryTrusted",
- hash_store_transaction->IsSuperMACValid());
- }
-
- for (auto it = tracked_paths_.begin(); it != tracked_paths_.end(); ++it) {
- if (it->second->EnforceAndReport(
- pref_store_contents.get(), hash_store_transaction.get(),
- external_validation_hash_store_transaction.get())) {
- did_reset = true;
- prefs_altered = true;
- }
- }
- if (hash_store_transaction->StampSuperMac())
- prefs_altered = true;
- }
-
- if (did_reset) {
- pref_store_contents->Set(user_prefs::kPreferenceResetTime,
- new base::StringValue(base::Int64ToString(
- base::Time::Now().ToInternalValue())));
- FilterUpdate(user_prefs::kPreferenceResetTime);
-
- if (!on_reset_on_load_.is_null())
- on_reset_on_load_.Run();
- }
-
- UMA_HISTOGRAM_TIMES("Settings.FilterOnLoadTime",
- base::TimeTicks::Now() - checkpoint);
-
- post_filter_on_load_callback.Run(std::move(pref_store_contents),
- prefs_altered);
-}
-
-// static
-void PrefHashFilter::ClearFromExternalStore(
- HashStoreContents* external_validation_hash_store_contents,
- const base::DictionaryValue* changed_paths_and_macs) {
- DCHECK(!changed_paths_and_macs->empty());
-
- for (base::DictionaryValue::Iterator it(*changed_paths_and_macs);
- !it.IsAtEnd(); it.Advance()) {
- external_validation_hash_store_contents->RemoveEntry(it.key());
- }
-}
-
-// static
-void PrefHashFilter::FlushToExternalStore(
- std::unique_ptr<HashStoreContents> external_validation_hash_store_contents,
- std::unique_ptr<base::DictionaryValue> changed_paths_and_macs,
- bool write_success) {
- DCHECK(!changed_paths_and_macs->empty());
- DCHECK(external_validation_hash_store_contents);
- if (!write_success)
- return;
-
- for (base::DictionaryValue::Iterator it(*changed_paths_and_macs);
- !it.IsAtEnd(); it.Advance()) {
- const std::string& changed_path = it.key();
-
- const base::DictionaryValue* split_values = nullptr;
- if (it.value().GetAsDictionary(&split_values)) {
- for (base::DictionaryValue::Iterator inner_it(*split_values);
- !inner_it.IsAtEnd(); inner_it.Advance()) {
- std::string mac;
- bool is_string = inner_it.value().GetAsString(&mac);
- DCHECK(is_string);
-
- external_validation_hash_store_contents->SetSplitMac(
- changed_path, inner_it.key(), mac);
- }
- } else {
- const base::StringValue* value_as_string;
- bool is_string = it.value().GetAsString(&value_as_string);
- DCHECK(is_string);
-
- external_validation_hash_store_contents->SetMac(
- changed_path, value_as_string->GetString());
- }
- }
-}
-
-PrefFilter::OnWriteCallbackPair PrefHashFilter::GetOnWriteSynchronousCallbacks(
- base::DictionaryValue* pref_store_contents) {
- if (changed_paths_.empty() || !external_validation_hash_store_pair_) {
- return std::make_pair(base::Closure(),
- base::Callback<void(bool success)>());
- }
-
- std::unique_ptr<base::DictionaryValue> changed_paths_macs =
- base::MakeUnique<base::DictionaryValue>();
-
- for (ChangedPathsMap::const_iterator it = changed_paths_.begin();
- it != changed_paths_.end(); ++it) {
- const std::string& changed_path = it->first;
- const TrackedPreference* changed_preference = it->second;
-
- switch (changed_preference->GetType()) {
- case TrackedPreferenceType::ATOMIC: {
- const base::Value* new_value = nullptr;
- pref_store_contents->Get(changed_path, &new_value);
- changed_paths_macs->SetStringWithoutPathExpansion(
- changed_path,
- external_validation_hash_store_pair_->first->ComputeMac(
- changed_path, new_value));
- break;
- }
- case TrackedPreferenceType::SPLIT: {
- const base::DictionaryValue* dict_value = nullptr;
- pref_store_contents->GetDictionary(changed_path, &dict_value);
- changed_paths_macs->SetWithoutPathExpansion(
- changed_path,
- external_validation_hash_store_pair_->first->ComputeSplitMacs(
- changed_path, dict_value));
- break;
- }
- }
- }
-
- DCHECK(external_validation_hash_store_pair_->second->IsCopyable())
- << "External HashStoreContents must be copyable as it needs to be used "
- "off-thread";
-
- std::unique_ptr<HashStoreContents> hash_store_contents_copy =
- external_validation_hash_store_pair_->second->MakeCopy();
-
- // We can use raw pointers for the first callback instead of making more
- // copies as it will be executed in sequence before the second callback,
- // which owns the pointers.
- HashStoreContents* raw_contents = hash_store_contents_copy.get();
- base::DictionaryValue* raw_changed_paths_macs = changed_paths_macs.get();
-
- return std::make_pair(
- base::Bind(&ClearFromExternalStore, base::Unretained(raw_contents),
- base::Unretained(raw_changed_paths_macs)),
- base::Bind(&FlushToExternalStore, base::Passed(&hash_store_contents_copy),
- base::Passed(&changed_paths_macs)));
-}
diff --git a/chromium/components/user_prefs/tracked/pref_hash_filter.h b/chromium/components/user_prefs/tracked/pref_hash_filter.h
deleted file mode 100644
index 3f68011c161..00000000000
--- a/chromium/components/user_prefs/tracked/pref_hash_filter.h
+++ /dev/null
@@ -1,176 +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.
-
-#ifndef COMPONENTS_USER_PREFS_TRACKED_PREF_HASH_FILTER_H_
-#define COMPONENTS_USER_PREFS_TRACKED_PREF_HASH_FILTER_H_
-
-#include <stddef.h>
-
-#include <map>
-#include <memory>
-#include <set>
-#include <unordered_map>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/optional.h"
-#include "components/user_prefs/tracked/hash_store_contents.h"
-#include "components/user_prefs/tracked/interceptable_pref_filter.h"
-#include "components/user_prefs/tracked/tracked_preference.h"
-
-class PrefHashStore;
-class PrefService;
-class TrackedPreferenceValidationDelegate;
-
-namespace base {
-class DictionaryValue;
-class Time;
-} // namespace base
-
-namespace user_prefs {
-class PrefRegistrySyncable;
-} // namespace user_prefs
-
-// Intercepts preference values as they are loaded from disk and verifies them
-// using a PrefHashStore. Keeps the PrefHashStore contents up to date as values
-// are changed.
-class PrefHashFilter : public InterceptablePrefFilter {
- public:
- enum EnforcementLevel { NO_ENFORCEMENT, ENFORCE_ON_LOAD };
-
- enum PrefTrackingStrategy {
- // Atomic preferences are tracked as a whole.
- TRACKING_STRATEGY_ATOMIC,
- // Split preferences are dictionaries for which each top-level entry is
- // tracked independently. Note: preferences using this strategy must be kept
- // in sync with TrackedSplitPreferences in histograms.xml.
- TRACKING_STRATEGY_SPLIT,
- };
-
- enum ValueType {
- VALUE_IMPERSONAL,
- // The preference value may contain personal information.
- VALUE_PERSONAL,
- };
-
- struct TrackedPreferenceMetadata {
- size_t reporting_id;
- const char* name;
- EnforcementLevel enforcement_level;
- PrefTrackingStrategy strategy;
- ValueType value_type;
- };
-
- using StoreContentsPair = std::pair<std::unique_ptr<PrefHashStore>,
- std::unique_ptr<HashStoreContents>>;
-
- // Constructs a PrefHashFilter tracking the specified |tracked_preferences|
- // using |pref_hash_store| to check/store hashes. An optional |delegate| is
- // notified of the status of each preference as it is checked.
- // If |on_reset_on_load| is provided, it will be invoked if a reset occurs in
- // FilterOnLoad.
- // |reporting_ids_count| is the count of all possible IDs (possibly greater
- // than |tracked_preferences.size()|). If |report_super_mac_validity| is true,
- // the state of the super MAC will be reported via UMA during
- // FinalizeFilterOnLoad.
- // |external_validation_hash_store_pair_| will be used (if non-null) to
- // perform extra validations without triggering resets.
- PrefHashFilter(
- std::unique_ptr<PrefHashStore> pref_hash_store,
- StoreContentsPair external_validation_hash_store_pair_,
- const std::vector<TrackedPreferenceMetadata>& tracked_preferences,
- const base::Closure& on_reset_on_load,
- TrackedPreferenceValidationDelegate* delegate,
- size_t reporting_ids_count,
- bool report_super_mac_validity);
-
- ~PrefHashFilter() override;
-
- // Registers required user preferences.
- static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
-
- // Retrieves the time of the last reset event, if any, for the provided user
- // preferences. If no reset has occurred, Returns a null |Time|.
- static base::Time GetResetTime(PrefService* user_prefs);
-
- // Clears the time of the last reset event, if any, for the provided user
- // preferences.
- static void ClearResetTime(PrefService* user_prefs);
-
- // Initializes the PrefHashStore with hashes of the tracked preferences in
- // |pref_store_contents|. |pref_store_contents| will be the |storage| passed
- // to PrefHashStore::BeginTransaction().
- void Initialize(base::DictionaryValue* pref_store_contents);
-
- // PrefFilter remaining implementation.
- void FilterUpdate(const std::string& path) override;
- OnWriteCallbackPair FilterSerializeData(
- base::DictionaryValue* pref_store_contents) override;
-
- private:
- // InterceptablePrefFilter implementation.
- void FinalizeFilterOnLoad(
- const PostFilterOnLoadCallback& post_filter_on_load_callback,
- std::unique_ptr<base::DictionaryValue> pref_store_contents,
- bool prefs_altered) override;
-
- // Helper function to generate FilterSerializeData()'s pre-write and
- // post-write callbacks. The returned callbacks are thread-safe.
- OnWriteCallbackPair GetOnWriteSynchronousCallbacks(
- base::DictionaryValue* pref_store_contents);
-
- // Clears the MACs contained in |external_validation_hash_store_contents|
- // which are present in |paths_to_clear|.
- static void ClearFromExternalStore(
- HashStoreContents* external_validation_hash_store_contents,
- const base::DictionaryValue* changed_paths_and_macs);
-
- // Flushes the MACs contained in |changed_paths_and_mac| to
- // external_hash_store_contents if |write_success|, otherwise discards the
- // changes.
- static void FlushToExternalStore(
- std::unique_ptr<HashStoreContents> external_hash_store_contents,
- std::unique_ptr<base::DictionaryValue> changed_paths_and_macs,
- bool write_success);
-
- // Callback to be invoked only once (and subsequently reset) on the next
- // FilterOnLoad event. It will be allowed to modify the |prefs| handed to
- // FilterOnLoad before handing them back to this PrefHashFilter.
- FilterOnLoadInterceptor filter_on_load_interceptor_;
-
- // A map of paths to TrackedPreferences; this map owns this individual
- // TrackedPreference objects.
- using TrackedPreferencesMap =
- std::unordered_map<std::string, std::unique_ptr<TrackedPreference>>;
-
- // A map from changed paths to their corresponding TrackedPreferences (which
- // aren't owned by this map).
- using ChangedPathsMap = std::map<std::string, const TrackedPreference*>;
-
- std::unique_ptr<PrefHashStore> pref_hash_store_;
-
- // A store and contents on which to perform extra validations without
- // triggering resets.
- // Will be null if the platform does not support external validation.
- const base::Optional<StoreContentsPair> external_validation_hash_store_pair_;
-
- // Invoked if a reset occurs in a call to FilterOnLoad.
- const base::Closure on_reset_on_load_;
-
- TrackedPreferencesMap tracked_paths_;
-
- // The set of all paths whose value has changed since the last call to
- // FilterSerializeData.
- ChangedPathsMap changed_paths_;
-
- // Whether to report the validity of the super MAC at load time (via UMA).
- bool report_super_mac_validity_;
-
- DISALLOW_COPY_AND_ASSIGN(PrefHashFilter);
-};
-
-#endif // COMPONENTS_PREFS_TRACKED_PREF_HASH_FILTER_H_
diff --git a/chromium/components/user_prefs/tracked/pref_hash_filter_unittest.cc b/chromium/components/user_prefs/tracked/pref_hash_filter_unittest.cc
deleted file mode 100644
index 42ea4f5092a..00000000000
--- a/chromium/components/user_prefs/tracked/pref_hash_filter_unittest.cc
+++ /dev/null
@@ -1,1393 +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/user_prefs/tracked/pref_hash_filter.h"
-
-#include <stddef.h>
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback_forward.h"
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_base.h"
-#include "base/metrics/histogram_samples.h"
-#include "base/metrics/statistics_recorder.h"
-#include "base/values.h"
-#include "components/prefs/testing_pref_store.h"
-#include "components/user_prefs/tracked/hash_store_contents.h"
-#include "components/user_prefs/tracked/mock_validation_delegate.h"
-#include "components/user_prefs/tracked/pref_hash_store.h"
-#include "components/user_prefs/tracked/pref_hash_store_transaction.h"
-#include "components/user_prefs/tracked/pref_names.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-const char kAtomicPref[] = "atomic_pref";
-const char kAtomicPref2[] = "atomic_pref2";
-const char kAtomicPref3[] = "pref3";
-const char kAtomicPref4[] = "pref4";
-const char kReportOnlyPref[] = "report_only";
-const char kReportOnlySplitPref[] = "report_only_split_pref";
-const char kSplitPref[] = "split_pref";
-
-const PrefHashFilter::TrackedPreferenceMetadata kTestTrackedPrefs[] = {
- {0,
- kAtomicPref,
- PrefHashFilter::ENFORCE_ON_LOAD,
- PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
- PrefHashFilter::VALUE_PERSONAL},
- {1,
- kReportOnlyPref,
- PrefHashFilter::NO_ENFORCEMENT,
- PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
- PrefHashFilter::VALUE_IMPERSONAL},
- {2,
- kSplitPref,
- PrefHashFilter::ENFORCE_ON_LOAD,
- PrefHashFilter::TRACKING_STRATEGY_SPLIT,
- PrefHashFilter::VALUE_IMPERSONAL},
- {3,
- kReportOnlySplitPref,
- PrefHashFilter::NO_ENFORCEMENT,
- PrefHashFilter::TRACKING_STRATEGY_SPLIT,
- PrefHashFilter::VALUE_IMPERSONAL},
- {4,
- kAtomicPref2,
- PrefHashFilter::ENFORCE_ON_LOAD,
- PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
- PrefHashFilter::VALUE_IMPERSONAL},
- {5,
- kAtomicPref3,
- PrefHashFilter::ENFORCE_ON_LOAD,
- PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
- PrefHashFilter::VALUE_IMPERSONAL},
- {6,
- kAtomicPref4,
- PrefHashFilter::ENFORCE_ON_LOAD,
- PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
- PrefHashFilter::VALUE_IMPERSONAL},
-};
-
-} // namespace
-
-// A PrefHashStore that allows simulation of CheckValue results and captures
-// checked and stored values.
-class MockPrefHashStore : public PrefHashStore {
- public:
- typedef std::pair<const void*, PrefHashFilter::PrefTrackingStrategy>
- ValuePtrStrategyPair;
-
- MockPrefHashStore()
- : stamp_super_mac_result_(false),
- is_super_mac_valid_result_(false),
- transactions_performed_(0),
- transaction_active_(false) {}
-
- ~MockPrefHashStore() override { EXPECT_FALSE(transaction_active_); }
-
- // Set the result that will be returned when |path| is passed to
- // |CheckValue/CheckSplitValue|.
- void SetCheckResult(const std::string& path,
- PrefHashStoreTransaction::ValueState result);
-
- // Set the invalid_keys that will be returned when |path| is passed to
- // |CheckSplitValue|. SetCheckResult should already have been called for
- // |path| with |result == CHANGED| for this to make any sense.
- void SetInvalidKeysResult(
- const std::string& path,
- const std::vector<std::string>& invalid_keys_result);
-
- // Sets the value that will be returned from
- // PrefHashStoreTransaction::StampSuperMAC().
- void set_stamp_super_mac_result(bool result) {
- stamp_super_mac_result_ = result;
- }
-
- // Sets the value that will be returned from
- // PrefHashStoreTransaction::IsSuperMACValid().
- void set_is_super_mac_valid_result(bool result) {
- is_super_mac_valid_result_ = result;
- }
-
- // Returns the number of transactions that were performed.
- size_t transactions_performed() { return transactions_performed_; }
-
- // Returns the number of paths checked.
- size_t checked_paths_count() const { return checked_values_.size(); }
-
- // Returns the number of paths stored.
- size_t stored_paths_count() const { return stored_values_.size(); }
-
- // Returns the pointer value and strategy that was passed to
- // |CheckHash/CheckSplitHash| for |path|. The returned pointer could since
- // have been freed and is thus not safe to dereference.
- ValuePtrStrategyPair checked_value(const std::string& path) const {
- std::map<std::string, ValuePtrStrategyPair>::const_iterator value =
- checked_values_.find(path);
- if (value != checked_values_.end())
- return value->second;
- return std::make_pair(
- reinterpret_cast<void*>(0xBAD),
- static_cast<PrefHashFilter::PrefTrackingStrategy>(-1));
- }
-
- // Returns the pointer value that was passed to |StoreHash/StoreSplitHash| for
- // |path|. The returned pointer could since have been freed and is thus not
- // safe to dereference.
- ValuePtrStrategyPair stored_value(const std::string& path) const {
- std::map<std::string, ValuePtrStrategyPair>::const_iterator value =
- stored_values_.find(path);
- if (value != stored_values_.end())
- return value->second;
- return std::make_pair(
- reinterpret_cast<void*>(0xBAD),
- static_cast<PrefHashFilter::PrefTrackingStrategy>(-1));
- }
-
- // PrefHashStore implementation.
- std::unique_ptr<PrefHashStoreTransaction> BeginTransaction(
- HashStoreContents* storage) override;
- std::string ComputeMac(const std::string& path,
- const base::Value* new_value) override;
- std::unique_ptr<base::DictionaryValue> ComputeSplitMacs(
- const std::string& path,
- const base::DictionaryValue* split_values) override;
-
- private:
- // A MockPrefHashStoreTransaction is handed to the caller on
- // MockPrefHashStore::BeginTransaction(). It then stores state in its
- // underlying MockPrefHashStore about calls it receives from that same caller
- // which can later be verified in tests.
- class MockPrefHashStoreTransaction : public PrefHashStoreTransaction {
- public:
- explicit MockPrefHashStoreTransaction(MockPrefHashStore* outer)
- : outer_(outer) {}
-
- ~MockPrefHashStoreTransaction() override {
- outer_->transaction_active_ = false;
- ++outer_->transactions_performed_;
- }
-
- // PrefHashStoreTransaction implementation.
- base::StringPiece GetStoreUMASuffix() const override;
- PrefHashStoreTransaction::ValueState CheckValue(
- const std::string& path,
- const base::Value* value) const override;
- void StoreHash(const std::string& path,
- const base::Value* new_value) override;
- PrefHashStoreTransaction::ValueState CheckSplitValue(
- const std::string& path,
- const base::DictionaryValue* initial_split_value,
- std::vector<std::string>* invalid_keys) const override;
- void StoreSplitHash(const std::string& path,
- const base::DictionaryValue* split_value) override;
- bool HasHash(const std::string& path) const override;
- void ImportHash(const std::string& path, const base::Value* hash) override;
- void ClearHash(const std::string& path) override;
- bool IsSuperMACValid() const override;
- bool StampSuperMac() override;
-
- private:
- MockPrefHashStore* outer_;
-
- DISALLOW_COPY_AND_ASSIGN(MockPrefHashStoreTransaction);
- };
-
- // Records a call to this mock's CheckValue/CheckSplitValue methods.
- PrefHashStoreTransaction::ValueState RecordCheckValue(
- const std::string& path,
- const base::Value* value,
- PrefHashFilter::PrefTrackingStrategy strategy);
-
- // Records a call to this mock's StoreHash/StoreSplitHash methods.
- void RecordStoreHash(const std::string& path,
- const base::Value* new_value,
- PrefHashFilter::PrefTrackingStrategy strategy);
-
- std::map<std::string, PrefHashStoreTransaction::ValueState> check_results_;
- std::map<std::string, std::vector<std::string>> invalid_keys_results_;
-
- bool stamp_super_mac_result_;
- bool is_super_mac_valid_result_;
-
- std::map<std::string, ValuePtrStrategyPair> checked_values_;
- std::map<std::string, ValuePtrStrategyPair> stored_values_;
-
- // Number of transactions that were performed via this MockPrefHashStore.
- size_t transactions_performed_;
-
- // Whether a transaction is currently active (only one transaction should be
- // active at a time).
- bool transaction_active_;
-
- DISALLOW_COPY_AND_ASSIGN(MockPrefHashStore);
-};
-
-void MockPrefHashStore::SetCheckResult(
- const std::string& path,
- PrefHashStoreTransaction::ValueState result) {
- check_results_.insert(std::make_pair(path, result));
-}
-
-void MockPrefHashStore::SetInvalidKeysResult(
- const std::string& path,
- const std::vector<std::string>& invalid_keys_result) {
- // Ensure |check_results_| has a CHANGED entry for |path|.
- std::map<std::string, PrefHashStoreTransaction::ValueState>::const_iterator
- result = check_results_.find(path);
- ASSERT_TRUE(result != check_results_.end());
- ASSERT_EQ(PrefHashStoreTransaction::CHANGED, result->second);
-
- invalid_keys_results_.insert(std::make_pair(path, invalid_keys_result));
-}
-
-std::unique_ptr<PrefHashStoreTransaction> MockPrefHashStore::BeginTransaction(
- HashStoreContents* storage) {
- EXPECT_FALSE(transaction_active_);
- return std::unique_ptr<PrefHashStoreTransaction>(
- new MockPrefHashStoreTransaction(this));
-}
-
-std::string MockPrefHashStore::ComputeMac(const std::string& path,
- const base::Value* new_value) {
- return "atomic mac for: " + path;
-};
-
-std::unique_ptr<base::DictionaryValue> MockPrefHashStore::ComputeSplitMacs(
- const std::string& path,
- const base::DictionaryValue* split_values) {
- std::unique_ptr<base::DictionaryValue> macs_dict(new base::DictionaryValue);
- for (base::DictionaryValue::Iterator it(*split_values); !it.IsAtEnd();
- it.Advance()) {
- macs_dict->SetStringWithoutPathExpansion(
- it.key(), "split mac for: " + path + "/" + it.key());
- }
- return macs_dict;
-};
-
-PrefHashStoreTransaction::ValueState MockPrefHashStore::RecordCheckValue(
- const std::string& path,
- const base::Value* value,
- PrefHashFilter::PrefTrackingStrategy strategy) {
- // Record that |path| was checked and validate that it wasn't previously
- // checked.
- EXPECT_TRUE(checked_values_.insert(std::make_pair(
- path, std::make_pair(value, strategy)))
- .second);
- std::map<std::string, PrefHashStoreTransaction::ValueState>::const_iterator
- result = check_results_.find(path);
- if (result != check_results_.end())
- return result->second;
- return PrefHashStoreTransaction::UNCHANGED;
-}
-
-void MockPrefHashStore::RecordStoreHash(
- const std::string& path,
- const base::Value* new_value,
- PrefHashFilter::PrefTrackingStrategy strategy) {
- EXPECT_TRUE(
- stored_values_.insert(std::make_pair(path,
- std::make_pair(new_value, strategy)))
- .second);
-}
-
-base::StringPiece
-MockPrefHashStore::MockPrefHashStoreTransaction::GetStoreUMASuffix() const {
- return "unused";
-}
-
-PrefHashStoreTransaction::ValueState
-MockPrefHashStore::MockPrefHashStoreTransaction::CheckValue(
- const std::string& path,
- const base::Value* value) const {
- return outer_->RecordCheckValue(path, value,
- PrefHashFilter::TRACKING_STRATEGY_ATOMIC);
-}
-
-void MockPrefHashStore::MockPrefHashStoreTransaction::StoreHash(
- const std::string& path,
- const base::Value* new_value) {
- outer_->RecordStoreHash(path, new_value,
- PrefHashFilter::TRACKING_STRATEGY_ATOMIC);
-}
-
-PrefHashStoreTransaction::ValueState
-MockPrefHashStore::MockPrefHashStoreTransaction::CheckSplitValue(
- const std::string& path,
- const base::DictionaryValue* initial_split_value,
- std::vector<std::string>* invalid_keys) const {
- EXPECT_TRUE(invalid_keys && invalid_keys->empty());
-
- std::map<std::string, std::vector<std::string>>::const_iterator
- invalid_keys_result = outer_->invalid_keys_results_.find(path);
- if (invalid_keys_result != outer_->invalid_keys_results_.end()) {
- invalid_keys->insert(invalid_keys->begin(),
- invalid_keys_result->second.begin(),
- invalid_keys_result->second.end());
- }
-
- return outer_->RecordCheckValue(path, initial_split_value,
- PrefHashFilter::TRACKING_STRATEGY_SPLIT);
-}
-
-void MockPrefHashStore::MockPrefHashStoreTransaction::StoreSplitHash(
- const std::string& path,
- const base::DictionaryValue* new_value) {
- outer_->RecordStoreHash(path, new_value,
- PrefHashFilter::TRACKING_STRATEGY_SPLIT);
-}
-
-bool MockPrefHashStore::MockPrefHashStoreTransaction::HasHash(
- const std::string& path) const {
- ADD_FAILURE() << "Unexpected call.";
- return false;
-}
-
-void MockPrefHashStore::MockPrefHashStoreTransaction::ImportHash(
- const std::string& path,
- const base::Value* hash) {
- ADD_FAILURE() << "Unexpected call.";
-}
-
-void MockPrefHashStore::MockPrefHashStoreTransaction::ClearHash(
- const std::string& path) {
- // Allow this to be called by PrefHashFilter's deprecated tracked prefs
- // cleanup tasks.
-}
-
-bool MockPrefHashStore::MockPrefHashStoreTransaction::IsSuperMACValid() const {
- return outer_->is_super_mac_valid_result_;
-}
-
-bool MockPrefHashStore::MockPrefHashStoreTransaction::StampSuperMac() {
- return outer_->stamp_super_mac_result_;
-}
-
-std::vector<PrefHashFilter::TrackedPreferenceMetadata> GetConfiguration(
- PrefHashFilter::EnforcementLevel max_enforcement_level) {
- std::vector<PrefHashFilter::TrackedPreferenceMetadata> configuration(
- kTestTrackedPrefs, kTestTrackedPrefs + arraysize(kTestTrackedPrefs));
- for (std::vector<PrefHashFilter::TrackedPreferenceMetadata>::iterator it =
- configuration.begin();
- it != configuration.end(); ++it) {
- if (it->enforcement_level > max_enforcement_level)
- it->enforcement_level = max_enforcement_level;
- }
- return configuration;
-}
-
-class MockHashStoreContents : public HashStoreContents {
- public:
- MockHashStoreContents(){};
-
- // Returns the number of hashes stored.
- size_t stored_hashes_count() const { return dictionary_.size(); }
-
- // Returns the number of paths cleared.
- size_t cleared_paths_count() const { return removed_entries_.size(); }
-
- // Returns the stored MAC for an Atomic preference.
- std::string GetStoredMac(const std::string& path) const;
- // Returns the stored MAC for a Split preference.
- std::string GetStoredSplitMac(const std::string& path,
- const std::string& split_path) const;
-
- // HashStoreContents implementation.
- bool IsCopyable() const override;
- std::unique_ptr<HashStoreContents> MakeCopy() const override;
- base::StringPiece GetUMASuffix() const override;
- void Reset() override;
- bool GetMac(const std::string& path, std::string* out_value) override;
- bool GetSplitMacs(const std::string& path,
- std::map<std::string, std::string>* split_macs) override;
- void SetMac(const std::string& path, const std::string& value) override;
- void SetSplitMac(const std::string& path,
- const std::string& split_path,
- const std::string& value) override;
- void ImportEntry(const std::string& path,
- const base::Value* in_value) override;
- bool RemoveEntry(const std::string& path) override;
- const base::DictionaryValue* GetContents() const override;
- std::string GetSuperMac() const override;
- void SetSuperMac(const std::string& super_mac) override;
-
- private:
- MockHashStoreContents(MockHashStoreContents* origin_mock);
-
- // Records calls to this mock's SetMac/SetSplitMac methods.
- void RecordSetMac(const std::string& path, const std::string& mac) {
- dictionary_.SetStringWithoutPathExpansion(path, mac);
- }
- void RecordSetSplitMac(const std::string& path,
- const std::string& split_path,
- const std::string& mac) {
- base::DictionaryValue* mac_dict = nullptr;
- dictionary_.GetDictionaryWithoutPathExpansion(path, &mac_dict);
- if (!mac_dict) {
- mac_dict = new base::DictionaryValue;
- dictionary_.SetWithoutPathExpansion(path, mac_dict);
- }
- mac_dict->SetStringWithoutPathExpansion(split_path, mac);
- }
-
- // Records a call to this mock's RemoveEntry method.
- void RecordRemoveEntry(const std::string& path) {
- // Don't expect the same pref to be cleared more than once.
- EXPECT_EQ(removed_entries_.end(), removed_entries_.find(path));
- removed_entries_.insert(path);
- }
-
- base::DictionaryValue dictionary_;
- std::set<std::string> removed_entries_;
-
- // The code being tested copies its HashStoreContents for use in a callback
- // which can be executed during shutdown. To be able to capture the behavior
- // of the copy, we make it forward calls to the mock it was created from.
- // Once set, |origin_mock_| must outlive this instance.
- MockHashStoreContents* origin_mock_;
-
- DISALLOW_COPY_AND_ASSIGN(MockHashStoreContents);
-};
-
-std::string MockHashStoreContents::GetStoredMac(const std::string& path) const {
- const base::Value* out_value;
- if (dictionary_.GetWithoutPathExpansion(path, &out_value)) {
- const base::StringValue* value_as_string;
- EXPECT_TRUE(out_value->GetAsString(&value_as_string));
-
- return value_as_string->GetString();
- }
-
- return std::string();
-}
-
-std::string MockHashStoreContents::GetStoredSplitMac(
- const std::string& path,
- const std::string& split_path) const {
- const base::Value* out_value;
- if (dictionary_.GetWithoutPathExpansion(path, &out_value)) {
- const base::DictionaryValue* value_as_dict;
- EXPECT_TRUE(out_value->GetAsDictionary(&value_as_dict));
-
- if (value_as_dict->GetWithoutPathExpansion(split_path, &out_value)) {
- const base::StringValue* value_as_string;
- EXPECT_TRUE(out_value->GetAsString(&value_as_string));
-
- return value_as_string->GetString();
- }
- }
-
- return std::string();
-}
-
-MockHashStoreContents::MockHashStoreContents(MockHashStoreContents* origin_mock)
- : origin_mock_(origin_mock) {}
-
-bool MockHashStoreContents::IsCopyable() const {
- return true;
-}
-
-std::unique_ptr<HashStoreContents> MockHashStoreContents::MakeCopy() const {
- // Return a new MockHashStoreContents which forwards all requests to this
- // mock instance.
- return std::unique_ptr<HashStoreContents>(
- new MockHashStoreContents(const_cast<MockHashStoreContents*>(this)));
-}
-
-base::StringPiece MockHashStoreContents::GetUMASuffix() const {
- return "Unused";
-}
-
-void MockHashStoreContents::Reset() {
- ADD_FAILURE() << "Unexpected call.";
-}
-
-bool MockHashStoreContents::GetMac(const std::string& path,
- std::string* out_value) {
- ADD_FAILURE() << "Unexpected call.";
- return false;
-}
-
-bool MockHashStoreContents::GetSplitMacs(
- const std::string& path,
- std::map<std::string, std::string>* split_macs) {
- ADD_FAILURE() << "Unexpected call.";
- return false;
-}
-
-void MockHashStoreContents::SetMac(const std::string& path,
- const std::string& value) {
- if (origin_mock_)
- origin_mock_->RecordSetMac(path, value);
- else
- RecordSetMac(path, value);
-}
-
-void MockHashStoreContents::SetSplitMac(const std::string& path,
- const std::string& split_path,
- const std::string& value) {
- if (origin_mock_)
- origin_mock_->RecordSetSplitMac(path, split_path, value);
- else
- RecordSetSplitMac(path, split_path, value);
-}
-
-void MockHashStoreContents::ImportEntry(const std::string& path,
- const base::Value* in_value) {
- ADD_FAILURE() << "Unexpected call.";
-}
-
-bool MockHashStoreContents::RemoveEntry(const std::string& path) {
- if (origin_mock_)
- origin_mock_->RecordRemoveEntry(path);
- else
- RecordRemoveEntry(path);
- return true;
-}
-
-const base::DictionaryValue* MockHashStoreContents::GetContents() const {
- ADD_FAILURE() << "Unexpected call.";
- return nullptr;
-}
-
-std::string MockHashStoreContents::GetSuperMac() const {
- ADD_FAILURE() << "Unexpected call.";
- return std::string();
-}
-
-void MockHashStoreContents::SetSuperMac(const std::string& super_mac) {
- ADD_FAILURE() << "Unexpected call.";
-}
-
-class PrefHashFilterTest
- : public testing::TestWithParam<PrefHashFilter::EnforcementLevel> {
- public:
- PrefHashFilterTest()
- : mock_pref_hash_store_(NULL),
- pref_store_contents_(new base::DictionaryValue),
- reset_recorded_(false) {}
-
- void SetUp() override {
- base::StatisticsRecorder::Initialize();
- Reset();
- }
-
- protected:
- // Reset the PrefHashFilter instance.
- void Reset() {
- // Construct a PrefHashFilter and MockPrefHashStore for the test.
- InitializePrefHashFilter(GetConfiguration(GetParam()));
- }
-
- // Initializes |pref_hash_filter_| with a PrefHashFilter that uses a
- // MockPrefHashStore. The raw pointer to the MockPrefHashStore (owned by the
- // PrefHashFilter) is stored in |mock_pref_hash_store_|.
- void InitializePrefHashFilter(const std::vector<
- PrefHashFilter::TrackedPreferenceMetadata>& configuration) {
- std::unique_ptr<MockPrefHashStore> temp_mock_pref_hash_store(
- new MockPrefHashStore);
- std::unique_ptr<MockPrefHashStore>
- temp_mock_external_validation_pref_hash_store(new MockPrefHashStore);
- std::unique_ptr<MockHashStoreContents>
- temp_mock_external_validation_hash_store_contents(
- new MockHashStoreContents);
- mock_pref_hash_store_ = temp_mock_pref_hash_store.get();
- mock_external_validation_pref_hash_store_ =
- temp_mock_external_validation_pref_hash_store.get();
- mock_external_validation_hash_store_contents_ =
- temp_mock_external_validation_hash_store_contents.get();
- pref_hash_filter_.reset(new PrefHashFilter(
- std::move(temp_mock_pref_hash_store),
- PrefHashFilter::StoreContentsPair(
- std::move(temp_mock_external_validation_pref_hash_store),
- std::move(temp_mock_external_validation_hash_store_contents)),
- configuration,
- base::Bind(&PrefHashFilterTest::RecordReset, base::Unretained(this)),
- &mock_validation_delegate_, arraysize(kTestTrackedPrefs), true));
- }
-
- // Verifies whether a reset was reported by the PrefHashFiler. Also verifies
- // that kPreferenceResetTime was set (or not) accordingly.
- void VerifyRecordedReset(bool reset_expected) {
- EXPECT_EQ(reset_expected, reset_recorded_);
- EXPECT_EQ(reset_expected,
- pref_store_contents_->Get(
- user_prefs::kPreferenceResetTime, NULL));
- }
-
- // Calls FilterOnLoad() on |pref_hash_Filter_|. |pref_store_contents_| is
- // handed off, but should be given back to us synchronously through
- // GetPrefsBack() as there is no FilterOnLoadInterceptor installed on
- // |pref_hash_filter_|.
- void DoFilterOnLoad(bool expect_prefs_modifications) {
- pref_hash_filter_->FilterOnLoad(
- base::Bind(&PrefHashFilterTest::GetPrefsBack, base::Unretained(this),
- expect_prefs_modifications),
- std::move(pref_store_contents_));
- }
-
- MockPrefHashStore* mock_pref_hash_store_;
- MockPrefHashStore* mock_external_validation_pref_hash_store_;
- MockHashStoreContents* mock_external_validation_hash_store_contents_;
- std::unique_ptr<base::DictionaryValue> pref_store_contents_;
- MockValidationDelegate mock_validation_delegate_;
- std::unique_ptr<PrefHashFilter> pref_hash_filter_;
-
- private:
- // Stores |prefs| back in |pref_store_contents| and ensure
- // |expected_schedule_write| matches the reported |schedule_write|.
- void GetPrefsBack(bool expected_schedule_write,
- std::unique_ptr<base::DictionaryValue> prefs,
- bool schedule_write) {
- pref_store_contents_ = std::move(prefs);
- EXPECT_TRUE(pref_store_contents_);
- EXPECT_EQ(expected_schedule_write, schedule_write);
- }
-
- void RecordReset() {
- // As-is |reset_recorded_| is only designed to remember a single reset, make
- // sure none was previously recorded.
- EXPECT_FALSE(reset_recorded_);
- reset_recorded_ = true;
- }
-
- bool reset_recorded_;
-
- DISALLOW_COPY_AND_ASSIGN(PrefHashFilterTest);
-};
-
-TEST_P(PrefHashFilterTest, EmptyAndUnchanged) {
- DoFilterOnLoad(false);
- // All paths checked.
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_pref_hash_store_->checked_paths_count());
- // No paths stored, since they all return |UNCHANGED|.
- ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
- // Since there was nothing in |pref_store_contents_| the checked value should
- // have been NULL for all tracked preferences.
- for (size_t i = 0; i < arraysize(kTestTrackedPrefs); ++i) {
- ASSERT_EQ(
- NULL,
- mock_pref_hash_store_->checked_value(kTestTrackedPrefs[i].name).first);
- }
- ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
- VerifyRecordedReset(false);
-
- // Delegate saw all paths, and all unchanged.
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_validation_delegate_.recorded_validations_count());
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_validation_delegate_.CountValidationsOfState(
- PrefHashStoreTransaction::UNCHANGED));
-}
-
-TEST_P(PrefHashFilterTest, StampSuperMACAltersStore) {
- mock_pref_hash_store_->set_stamp_super_mac_result(true);
- DoFilterOnLoad(true);
- // No paths stored, since they all return |UNCHANGED|. The StampSuperMAC
- // result is the only reason the prefs were considered altered.
- ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
-}
-
-TEST_P(PrefHashFilterTest, FilterTrackedPrefUpdate) {
- base::DictionaryValue root_dict;
- // Ownership of |string_value| is transfered to |root_dict|.
- base::Value* string_value = new base::StringValue("string value");
- root_dict.Set(kAtomicPref, string_value);
-
- // No path should be stored on FilterUpdate.
- pref_hash_filter_->FilterUpdate(kAtomicPref);
- ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
-
- // One path should be stored on FilterSerializeData.
- pref_hash_filter_->FilterSerializeData(&root_dict);
- ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
- MockPrefHashStore::ValuePtrStrategyPair stored_value =
- mock_pref_hash_store_->stored_value(kAtomicPref);
- ASSERT_EQ(string_value, stored_value.first);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, stored_value.second);
-
- ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
- VerifyRecordedReset(false);
-}
-
-TEST_P(PrefHashFilterTest, ReportSuperMacValidity) {
- // Do this once just to force the histogram to be defined.
- DoFilterOnLoad(false);
-
- base::HistogramBase* histogram = base::StatisticsRecorder::FindHistogram(
- "Settings.HashesDictionaryTrusted");
- ASSERT_TRUE(histogram);
-
- base::HistogramBase::Count initial_untrusted =
- histogram->SnapshotSamples()->GetCount(0);
- base::HistogramBase::Count initial_trusted =
- histogram->SnapshotSamples()->GetCount(1);
-
- Reset();
-
- // Run with an invalid super MAC.
- mock_pref_hash_store_->set_is_super_mac_valid_result(false);
-
- DoFilterOnLoad(false);
-
- // Verify that the invalidity was reported.
- ASSERT_EQ(initial_untrusted + 1, histogram->SnapshotSamples()->GetCount(0));
- ASSERT_EQ(initial_trusted, histogram->SnapshotSamples()->GetCount(1));
-
- Reset();
-
- // Run with a valid super MAC.
- mock_pref_hash_store_->set_is_super_mac_valid_result(true);
-
- DoFilterOnLoad(false);
-
- // Verify that the validity was reported.
- ASSERT_EQ(initial_untrusted + 1, histogram->SnapshotSamples()->GetCount(0));
- ASSERT_EQ(initial_trusted + 1, histogram->SnapshotSamples()->GetCount(1));
-}
-
-TEST_P(PrefHashFilterTest, FilterSplitPrefUpdate) {
- base::DictionaryValue root_dict;
- // Ownership of |dict_value| is transfered to |root_dict|.
- base::DictionaryValue* dict_value = new base::DictionaryValue;
- dict_value->SetString("a", "foo");
- dict_value->SetInteger("b", 1234);
- root_dict.Set(kSplitPref, dict_value);
-
- // No path should be stored on FilterUpdate.
- pref_hash_filter_->FilterUpdate(kSplitPref);
- ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
-
- // One path should be stored on FilterSerializeData.
- pref_hash_filter_->FilterSerializeData(&root_dict);
- ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
- MockPrefHashStore::ValuePtrStrategyPair stored_value =
- mock_pref_hash_store_->stored_value(kSplitPref);
- ASSERT_EQ(dict_value, stored_value.first);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_value.second);
-
- ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
- VerifyRecordedReset(false);
-}
-
-TEST_P(PrefHashFilterTest, FilterUntrackedPrefUpdate) {
- base::DictionaryValue root_dict;
- root_dict.Set("untracked", new base::StringValue("some value"));
- pref_hash_filter_->FilterUpdate("untracked");
-
- // No paths should be stored on FilterUpdate.
- ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
-
- // Nor on FilterSerializeData.
- pref_hash_filter_->FilterSerializeData(&root_dict);
- ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
-
- // No transaction should even be started on FilterSerializeData() if there are
- // no updates to perform.
- ASSERT_EQ(0u, mock_pref_hash_store_->transactions_performed());
-}
-
-TEST_P(PrefHashFilterTest, MultiplePrefsFilterSerializeData) {
- base::DictionaryValue root_dict;
- // Ownership of the following values is transfered to |root_dict|.
- base::Value* int_value1 = new base::Value(1);
- base::Value* int_value2 = new base::Value(2);
- base::Value* int_value3 = new base::Value(3);
- base::Value* int_value4 = new base::Value(4);
- base::DictionaryValue* dict_value = new base::DictionaryValue;
- dict_value->Set("a", new base::Value(true));
- root_dict.Set(kAtomicPref, int_value1);
- root_dict.Set(kAtomicPref2, int_value2);
- root_dict.Set(kAtomicPref3, int_value3);
- root_dict.Set("untracked", int_value4);
- root_dict.Set(kSplitPref, dict_value);
-
- // Only update kAtomicPref, kAtomicPref3, and kSplitPref.
- pref_hash_filter_->FilterUpdate(kAtomicPref);
- pref_hash_filter_->FilterUpdate(kAtomicPref3);
- pref_hash_filter_->FilterUpdate(kSplitPref);
- ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
-
- // Update kAtomicPref3 again, nothing should be stored still.
- base::Value* int_value5 = new base::Value(5);
- root_dict.Set(kAtomicPref3, int_value5);
- ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
-
- // On FilterSerializeData, only kAtomicPref, kAtomicPref3, and kSplitPref
- // should get a new hash.
- pref_hash_filter_->FilterSerializeData(&root_dict);
- ASSERT_EQ(3u, mock_pref_hash_store_->stored_paths_count());
- MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic1 =
- mock_pref_hash_store_->stored_value(kAtomicPref);
- ASSERT_EQ(int_value1, stored_value_atomic1.first);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
- stored_value_atomic1.second);
- ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
-
- MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic3 =
- mock_pref_hash_store_->stored_value(kAtomicPref3);
- ASSERT_EQ(int_value5, stored_value_atomic3.first);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
- stored_value_atomic3.second);
-
- MockPrefHashStore::ValuePtrStrategyPair stored_value_split =
- mock_pref_hash_store_->stored_value(kSplitPref);
- ASSERT_EQ(dict_value, stored_value_split.first);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_value_split.second);
-}
-
-TEST_P(PrefHashFilterTest, UnknownNullValue) {
- ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
- ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL));
- // NULL values are always trusted by the PrefHashStore.
- mock_pref_hash_store_->SetCheckResult(
- kAtomicPref, PrefHashStoreTransaction::TRUSTED_NULL_VALUE);
- mock_pref_hash_store_->SetCheckResult(
- kSplitPref, PrefHashStoreTransaction::TRUSTED_NULL_VALUE);
- DoFilterOnLoad(false);
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_pref_hash_store_->checked_paths_count());
- ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
- ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
-
- MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
- mock_pref_hash_store_->stored_value(kAtomicPref);
- ASSERT_EQ(NULL, stored_atomic_value.first);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
- stored_atomic_value.second);
-
- MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
- mock_pref_hash_store_->stored_value(kSplitPref);
- ASSERT_EQ(NULL, stored_split_value.first);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_split_value.second);
-
- // Delegate saw all prefs, two of which had the expected value_state.
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_validation_delegate_.recorded_validations_count());
- ASSERT_EQ(2u, mock_validation_delegate_.CountValidationsOfState(
- PrefHashStoreTransaction::TRUSTED_NULL_VALUE));
- ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
- mock_validation_delegate_.CountValidationsOfState(
- PrefHashStoreTransaction::UNCHANGED));
-
- const MockValidationDelegate::ValidationEvent* validated_split_pref =
- mock_validation_delegate_.GetEventForPath(kSplitPref);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
- validated_split_pref->strategy);
- ASSERT_FALSE(validated_split_pref->is_personal);
- const MockValidationDelegate::ValidationEvent* validated_atomic_pref =
- mock_validation_delegate_.GetEventForPath(kAtomicPref);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
- validated_atomic_pref->strategy);
- ASSERT_TRUE(validated_atomic_pref->is_personal);
-}
-
-TEST_P(PrefHashFilterTest, InitialValueUnknown) {
- // Ownership of these values is transfered to |pref_store_contents_|.
- base::StringValue* string_value = new base::StringValue("string value");
- pref_store_contents_->Set(kAtomicPref, string_value);
-
- base::DictionaryValue* dict_value = new base::DictionaryValue;
- dict_value->SetString("a", "foo");
- dict_value->SetInteger("b", 1234);
- pref_store_contents_->Set(kSplitPref, dict_value);
-
- ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
- ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
-
- mock_pref_hash_store_->SetCheckResult(
- kAtomicPref, PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE);
- mock_pref_hash_store_->SetCheckResult(
- kSplitPref, PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE);
- // If we are enforcing, expect this to report changes.
- DoFilterOnLoad(GetParam() >= PrefHashFilter::ENFORCE_ON_LOAD);
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_pref_hash_store_->checked_paths_count());
- ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
- ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
-
- // Delegate saw all prefs, two of which had the expected value_state.
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_validation_delegate_.recorded_validations_count());
- ASSERT_EQ(2u, mock_validation_delegate_.CountValidationsOfState(
- PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE));
- ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
- mock_validation_delegate_.CountValidationsOfState(
- PrefHashStoreTransaction::UNCHANGED));
-
- MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
- mock_pref_hash_store_->stored_value(kAtomicPref);
- MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
- mock_pref_hash_store_->stored_value(kSplitPref);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
- stored_atomic_value.second);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_split_value.second);
- if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
- // Ensure the prefs were cleared and the hashes for NULL were restored if
- // the current enforcement level denies seeding.
- ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
- ASSERT_EQ(NULL, stored_atomic_value.first);
-
- ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL));
- ASSERT_EQ(NULL, stored_split_value.first);
-
- VerifyRecordedReset(true);
- } else {
- // Otherwise the values should have remained intact and the hashes should
- // have been updated to match them.
- const base::Value* atomic_value_in_store;
- ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store));
- ASSERT_EQ(string_value, atomic_value_in_store);
- ASSERT_EQ(string_value, stored_atomic_value.first);
-
- const base::Value* split_value_in_store;
- ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
- ASSERT_EQ(dict_value, split_value_in_store);
- ASSERT_EQ(dict_value, stored_split_value.first);
-
- VerifyRecordedReset(false);
- }
-}
-
-TEST_P(PrefHashFilterTest, InitialValueTrustedUnknown) {
- // Ownership of this value is transfered to |pref_store_contents_|.
- base::Value* string_value = new base::StringValue("test");
- pref_store_contents_->Set(kAtomicPref, string_value);
-
- base::DictionaryValue* dict_value = new base::DictionaryValue;
- dict_value->SetString("a", "foo");
- dict_value->SetInteger("b", 1234);
- pref_store_contents_->Set(kSplitPref, dict_value);
-
- ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
- ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
-
- mock_pref_hash_store_->SetCheckResult(
- kAtomicPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE);
- mock_pref_hash_store_->SetCheckResult(
- kSplitPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE);
- DoFilterOnLoad(false);
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_pref_hash_store_->checked_paths_count());
- ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
- ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
-
- // Delegate saw all prefs, two of which had the expected value_state.
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_validation_delegate_.recorded_validations_count());
- ASSERT_EQ(2u, mock_validation_delegate_.CountValidationsOfState(
- PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE));
- ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
- mock_validation_delegate_.CountValidationsOfState(
- PrefHashStoreTransaction::UNCHANGED));
-
- // Seeding is always allowed for trusted unknown values.
- const base::Value* atomic_value_in_store;
- ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store));
- ASSERT_EQ(string_value, atomic_value_in_store);
- MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
- mock_pref_hash_store_->stored_value(kAtomicPref);
- ASSERT_EQ(string_value, stored_atomic_value.first);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
- stored_atomic_value.second);
-
- const base::Value* split_value_in_store;
- ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
- ASSERT_EQ(dict_value, split_value_in_store);
- MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
- mock_pref_hash_store_->stored_value(kSplitPref);
- ASSERT_EQ(dict_value, stored_split_value.first);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_split_value.second);
-}
-
-TEST_P(PrefHashFilterTest, InitialValueChanged) {
- // Ownership of this value is transfered to |pref_store_contents_|.
- base::Value* int_value = new base::Value(1234);
- pref_store_contents_->Set(kAtomicPref, int_value);
-
- base::DictionaryValue* dict_value = new base::DictionaryValue;
- dict_value->SetString("a", "foo");
- dict_value->SetInteger("b", 1234);
- dict_value->SetInteger("c", 56);
- dict_value->SetBoolean("d", false);
- pref_store_contents_->Set(kSplitPref, dict_value);
-
- ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
- ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
-
- mock_pref_hash_store_->SetCheckResult(kAtomicPref,
- PrefHashStoreTransaction::CHANGED);
- mock_pref_hash_store_->SetCheckResult(kSplitPref,
- PrefHashStoreTransaction::CHANGED);
-
- std::vector<std::string> mock_invalid_keys;
- mock_invalid_keys.push_back("a");
- mock_invalid_keys.push_back("c");
- mock_pref_hash_store_->SetInvalidKeysResult(kSplitPref, mock_invalid_keys);
-
- DoFilterOnLoad(GetParam() >= PrefHashFilter::ENFORCE_ON_LOAD);
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_pref_hash_store_->checked_paths_count());
- ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
- ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
-
- MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
- mock_pref_hash_store_->stored_value(kAtomicPref);
- MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
- mock_pref_hash_store_->stored_value(kSplitPref);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
- stored_atomic_value.second);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_split_value.second);
- if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
- // Ensure the atomic pref was cleared and the hash for NULL was restored if
- // the current enforcement level prevents changes.
- ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
- ASSERT_EQ(NULL, stored_atomic_value.first);
-
- // The split pref on the other hand should only have been stripped of its
- // invalid keys.
- const base::Value* split_value_in_store;
- ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
- ASSERT_EQ(2U, dict_value->size());
- ASSERT_FALSE(dict_value->HasKey("a"));
- ASSERT_TRUE(dict_value->HasKey("b"));
- ASSERT_FALSE(dict_value->HasKey("c"));
- ASSERT_TRUE(dict_value->HasKey("d"));
- ASSERT_EQ(dict_value, stored_split_value.first);
-
- VerifyRecordedReset(true);
- } else {
- // Otherwise the value should have remained intact and the hash should have
- // been updated to match it.
- const base::Value* atomic_value_in_store;
- ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store));
- ASSERT_EQ(int_value, atomic_value_in_store);
- ASSERT_EQ(int_value, stored_atomic_value.first);
-
- const base::Value* split_value_in_store;
- ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
- ASSERT_EQ(dict_value, split_value_in_store);
- ASSERT_EQ(4U, dict_value->size());
- ASSERT_TRUE(dict_value->HasKey("a"));
- ASSERT_TRUE(dict_value->HasKey("b"));
- ASSERT_TRUE(dict_value->HasKey("c"));
- ASSERT_TRUE(dict_value->HasKey("d"));
- ASSERT_EQ(dict_value, stored_split_value.first);
-
- VerifyRecordedReset(false);
- }
-}
-
-TEST_P(PrefHashFilterTest, EmptyCleared) {
- ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
- ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL));
- mock_pref_hash_store_->SetCheckResult(kAtomicPref,
- PrefHashStoreTransaction::CLEARED);
- mock_pref_hash_store_->SetCheckResult(kSplitPref,
- PrefHashStoreTransaction::CLEARED);
- DoFilterOnLoad(false);
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_pref_hash_store_->checked_paths_count());
- ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
- ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
-
- // Delegate saw all prefs, two of which had the expected value_state.
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_validation_delegate_.recorded_validations_count());
- ASSERT_EQ(2u, mock_validation_delegate_.CountValidationsOfState(
- PrefHashStoreTransaction::CLEARED));
- ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
- mock_validation_delegate_.CountValidationsOfState(
- PrefHashStoreTransaction::UNCHANGED));
-
- // Regardless of the enforcement level, the only thing that should be done is
- // to restore the hash for NULL. The value itself should still be NULL.
- ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
- MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
- mock_pref_hash_store_->stored_value(kAtomicPref);
- ASSERT_EQ(NULL, stored_atomic_value.first);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
- stored_atomic_value.second);
-
- ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL));
- MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
- mock_pref_hash_store_->stored_value(kSplitPref);
- ASSERT_EQ(NULL, stored_split_value.first);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_split_value.second);
-}
-
-TEST_P(PrefHashFilterTest, InitialValueUnchangedLegacyId) {
- // Ownership of these values is transfered to |pref_store_contents_|.
- base::StringValue* string_value = new base::StringValue("string value");
- pref_store_contents_->Set(kAtomicPref, string_value);
-
- base::DictionaryValue* dict_value = new base::DictionaryValue;
- dict_value->SetString("a", "foo");
- dict_value->SetInteger("b", 1234);
- pref_store_contents_->Set(kSplitPref, dict_value);
-
- ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
- ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
-
- mock_pref_hash_store_->SetCheckResult(
- kAtomicPref, PrefHashStoreTransaction::SECURE_LEGACY);
- mock_pref_hash_store_->SetCheckResult(
- kSplitPref, PrefHashStoreTransaction::SECURE_LEGACY);
- DoFilterOnLoad(false);
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_pref_hash_store_->checked_paths_count());
- ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
-
- // Delegate saw all prefs, two of which had the expected value_state.
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_validation_delegate_.recorded_validations_count());
- ASSERT_EQ(2u, mock_validation_delegate_.CountValidationsOfState(
- PrefHashStoreTransaction::SECURE_LEGACY));
- ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
- mock_validation_delegate_.CountValidationsOfState(
- PrefHashStoreTransaction::UNCHANGED));
-
- // Ensure that both the atomic and split hashes were restored.
- ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
-
- // In all cases, the values should have remained intact and the hashes should
- // have been updated to match them.
-
- MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
- mock_pref_hash_store_->stored_value(kAtomicPref);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
- stored_atomic_value.second);
- const base::Value* atomic_value_in_store;
- ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store));
- ASSERT_EQ(string_value, atomic_value_in_store);
- ASSERT_EQ(string_value, stored_atomic_value.first);
-
- MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
- mock_pref_hash_store_->stored_value(kSplitPref);
- ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_split_value.second);
- const base::Value* split_value_in_store;
- ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
- ASSERT_EQ(dict_value, split_value_in_store);
- ASSERT_EQ(dict_value, stored_split_value.first);
-
- VerifyRecordedReset(false);
-}
-
-TEST_P(PrefHashFilterTest, DontResetReportOnly) {
- // Ownership of these values is transfered to |pref_store_contents_|.
- base::Value* int_value1 = new base::Value(1);
- base::Value* int_value2 = new base::Value(2);
- base::Value* report_only_val = new base::Value(3);
- base::DictionaryValue* report_only_split_val = new base::DictionaryValue;
- report_only_split_val->SetInteger("a", 1234);
- pref_store_contents_->Set(kAtomicPref, int_value1);
- pref_store_contents_->Set(kAtomicPref2, int_value2);
- pref_store_contents_->Set(kReportOnlyPref, report_only_val);
- pref_store_contents_->Set(kReportOnlySplitPref, report_only_split_val);
-
- ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
- ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref2, NULL));
- ASSERT_TRUE(pref_store_contents_->Get(kReportOnlyPref, NULL));
- ASSERT_TRUE(pref_store_contents_->Get(kReportOnlySplitPref, NULL));
-
- mock_pref_hash_store_->SetCheckResult(kAtomicPref,
- PrefHashStoreTransaction::CHANGED);
- mock_pref_hash_store_->SetCheckResult(kAtomicPref2,
- PrefHashStoreTransaction::CHANGED);
- mock_pref_hash_store_->SetCheckResult(kReportOnlyPref,
- PrefHashStoreTransaction::CHANGED);
- mock_pref_hash_store_->SetCheckResult(kReportOnlySplitPref,
- PrefHashStoreTransaction::CHANGED);
-
- DoFilterOnLoad(GetParam() >= PrefHashFilter::ENFORCE_ON_LOAD);
- // All prefs should be checked and a new hash should be stored for each tested
- // pref.
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_pref_hash_store_->checked_paths_count());
- ASSERT_EQ(4u, mock_pref_hash_store_->stored_paths_count());
- ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
-
- // Delegate saw all prefs, four of which had the expected value_state.
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_validation_delegate_.recorded_validations_count());
- ASSERT_EQ(4u, mock_validation_delegate_.CountValidationsOfState(
- PrefHashStoreTransaction::CHANGED));
- ASSERT_EQ(arraysize(kTestTrackedPrefs) - 4u,
- mock_validation_delegate_.CountValidationsOfState(
- PrefHashStoreTransaction::UNCHANGED));
-
- // No matter what the enforcement level is, the report only pref should never
- // be reset.
- ASSERT_TRUE(pref_store_contents_->Get(kReportOnlyPref, NULL));
- ASSERT_TRUE(pref_store_contents_->Get(kReportOnlySplitPref, NULL));
- ASSERT_EQ(report_only_val,
- mock_pref_hash_store_->stored_value(kReportOnlyPref).first);
- ASSERT_EQ(report_only_split_val,
- mock_pref_hash_store_->stored_value(kReportOnlySplitPref).first);
-
- // All other prefs should have been reset if the enforcement level allows it.
- if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
- ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
- ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref2, NULL));
- ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kAtomicPref).first);
- ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kAtomicPref2).first);
-
- VerifyRecordedReset(true);
- } else {
- const base::Value* value_in_store;
- const base::Value* value_in_store2;
- ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &value_in_store));
- ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref2, &value_in_store2));
- ASSERT_EQ(int_value1, value_in_store);
- ASSERT_EQ(int_value1,
- mock_pref_hash_store_->stored_value(kAtomicPref).first);
- ASSERT_EQ(int_value2, value_in_store2);
- ASSERT_EQ(int_value2,
- mock_pref_hash_store_->stored_value(kAtomicPref2).first);
-
- VerifyRecordedReset(false);
- }
-}
-
-TEST_P(PrefHashFilterTest, CallFilterSerializeDataCallbacks) {
- base::DictionaryValue root_dict;
- // Ownership of the following values is transfered to |root_dict|.
- base::Value* int_value1 = new base::Value(1);
- base::Value* int_value2 = new base::Value(2);
- base::DictionaryValue* dict_value = new base::DictionaryValue;
- dict_value->Set("a", new base::Value(true));
- root_dict.Set(kAtomicPref, int_value1);
- root_dict.Set(kAtomicPref2, int_value2);
- root_dict.Set(kSplitPref, dict_value);
-
- // Skip updating kAtomicPref2.
- pref_hash_filter_->FilterUpdate(kAtomicPref);
- pref_hash_filter_->FilterUpdate(kSplitPref);
-
- PrefHashFilter::OnWriteCallbackPair callbacks =
- pref_hash_filter_->FilterSerializeData(&root_dict);
-
- ASSERT_FALSE(callbacks.first.is_null());
-
- // Prefs should be cleared from the external validation store only once the
- // before-write callback is run.
- ASSERT_EQ(
- 0u, mock_external_validation_hash_store_contents_->cleared_paths_count());
- callbacks.first.Run();
- ASSERT_EQ(
- 2u, mock_external_validation_hash_store_contents_->cleared_paths_count());
-
- // No pref write should occur before the after-write callback is run.
- ASSERT_EQ(
- 0u, mock_external_validation_hash_store_contents_->stored_hashes_count());
-
- callbacks.second.Run(true);
-
- ASSERT_EQ(
- 2u, mock_external_validation_hash_store_contents_->stored_hashes_count());
- ASSERT_EQ(
- "atomic mac for: atomic_pref",
- mock_external_validation_hash_store_contents_->GetStoredMac(kAtomicPref));
- ASSERT_EQ("split mac for: split_pref/a",
- mock_external_validation_hash_store_contents_->GetStoredSplitMac(
- kSplitPref, "a"));
-
- // The callbacks should write directly to the contents without going through
- // a pref hash store.
- ASSERT_EQ(0u,
- mock_external_validation_pref_hash_store_->stored_paths_count());
-}
-
-TEST_P(PrefHashFilterTest, CallFilterSerializeDataCallbacksWithFailure) {
- base::DictionaryValue root_dict;
- // Ownership of the following values is transfered to |root_dict|.
- base::Value* int_value1 = new base::Value(1);
- root_dict.Set(kAtomicPref, int_value1);
-
- // Only update kAtomicPref.
- pref_hash_filter_->FilterUpdate(kAtomicPref);
-
- PrefHashFilter::OnWriteCallbackPair callbacks =
- pref_hash_filter_->FilterSerializeData(&root_dict);
-
- ASSERT_FALSE(callbacks.first.is_null());
-
- callbacks.first.Run();
-
- // The pref should have been cleared from the external validation store.
- ASSERT_EQ(
- 1u, mock_external_validation_hash_store_contents_->cleared_paths_count());
-
- callbacks.second.Run(false);
-
- // Expect no writes to the external validation hash store contents.
- ASSERT_EQ(0u,
- mock_external_validation_pref_hash_store_->stored_paths_count());
- ASSERT_EQ(
- 0u, mock_external_validation_hash_store_contents_->stored_hashes_count());
-}
-
-TEST_P(PrefHashFilterTest, ExternalValidationValueChanged) {
- // Ownership of this value is transfered to |pref_store_contents_|.
- base::Value* int_value = new base::Value(1234);
- pref_store_contents_->Set(kAtomicPref, int_value);
-
- base::DictionaryValue* dict_value = new base::DictionaryValue;
- dict_value->SetString("a", "foo");
- dict_value->SetInteger("b", 1234);
- dict_value->SetInteger("c", 56);
- dict_value->SetBoolean("d", false);
- pref_store_contents_->Set(kSplitPref, dict_value);
-
- mock_external_validation_pref_hash_store_->SetCheckResult(
- kAtomicPref, PrefHashStoreTransaction::CHANGED);
- mock_external_validation_pref_hash_store_->SetCheckResult(
- kSplitPref, PrefHashStoreTransaction::CHANGED);
-
- std::vector<std::string> mock_invalid_keys;
- mock_invalid_keys.push_back("a");
- mock_invalid_keys.push_back("c");
- mock_external_validation_pref_hash_store_->SetInvalidKeysResult(
- kSplitPref, mock_invalid_keys);
-
- DoFilterOnLoad(false);
-
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_external_validation_pref_hash_store_->checked_paths_count());
- ASSERT_EQ(2u,
- mock_external_validation_pref_hash_store_->stored_paths_count());
- ASSERT_EQ(
- 1u, mock_external_validation_pref_hash_store_->transactions_performed());
-
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_validation_delegate_.recorded_validations_count());
-
- // Regular validation should not have any CHANGED prefs.
- ASSERT_EQ(arraysize(kTestTrackedPrefs),
- mock_validation_delegate_.CountValidationsOfState(
- PrefHashStoreTransaction::UNCHANGED));
-
- // External validation should have two CHANGED prefs (kAtomic and kSplit).
- ASSERT_EQ(2u, mock_validation_delegate_.CountExternalValidationsOfState(
- PrefHashStoreTransaction::CHANGED));
- ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
- mock_validation_delegate_.CountExternalValidationsOfState(
- PrefHashStoreTransaction::UNCHANGED));
-}
-
-INSTANTIATE_TEST_CASE_P(PrefHashFilterTestInstance,
- PrefHashFilterTest,
- testing::Values(PrefHashFilter::NO_ENFORCEMENT,
- PrefHashFilter::ENFORCE_ON_LOAD));
diff --git a/chromium/components/user_prefs/tracked/pref_hash_store.h b/chromium/components/user_prefs/tracked/pref_hash_store.h
deleted file mode 100644
index 67808fd3939..00000000000
--- a/chromium/components/user_prefs/tracked/pref_hash_store.h
+++ /dev/null
@@ -1,48 +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.
-
-#ifndef COMPONENTS_PREFS_TRACKED_PREF_HASH_STORE_H_
-#define COMPONENTS_PREFS_TRACKED_PREF_HASH_STORE_H_
-
-#include <memory>
-#include <string>
-
-#include "base/values.h"
-#include "components/user_prefs/tracked/pref_hash_store_transaction.h"
-
-class HashStoreContents;
-class PrefHashStoreTransaction;
-
-// Holds the configuration and implementation used to calculate and verify
-// preference MACs.
-// TODO(gab): Rename this class as it is no longer a store.
-class PrefHashStore {
- public:
- virtual ~PrefHashStore() {}
-
- // Returns a PrefHashStoreTransaction which can be used to perform a series
- // of operations on the hash store. |storage| MAY be used as the backing store
- // depending on the implementation. Therefore the HashStoreContents used for
- // related transactions should correspond to the same underlying data store.
- // |storage| must outlive the returned transaction.
- virtual std::unique_ptr<PrefHashStoreTransaction> BeginTransaction(
- HashStoreContents* storage) = 0;
-
- // Computes the MAC to be associated with |path| and |value| in this store.
- // PrefHashStoreTransaction typically uses this internally but it's also
- // exposed for users that want to compute MACs ahead of time for asynchronous
- // operations.
- virtual std::string ComputeMac(const std::string& path,
- const base::Value* value) = 0;
-
- // Computes the MAC to be associated with |path| and |split_values| in this
- // store. PrefHashStoreTransaction typically uses this internally but it's
- // also exposed for users that want to compute MACs ahead of time for
- // asynchronous operations.
- virtual std::unique_ptr<base::DictionaryValue> ComputeSplitMacs(
- const std::string& path,
- const base::DictionaryValue* split_values) = 0;
-};
-
-#endif // COMPONENTS_PREFS_TRACKED_PREF_HASH_STORE_H_
diff --git a/chromium/components/user_prefs/tracked/pref_hash_store_impl.cc b/chromium/components/user_prefs/tracked/pref_hash_store_impl.cc
deleted file mode 100644
index bb920ca4c98..00000000000
--- a/chromium/components/user_prefs/tracked/pref_hash_store_impl.cc
+++ /dev/null
@@ -1,319 +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/user_prefs/tracked/pref_hash_store_impl.h"
-
-#include <stddef.h>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/metrics/histogram_macros.h"
-#include "components/user_prefs/tracked/device_id.h"
-#include "components/user_prefs/tracked/hash_store_contents.h"
-
-namespace {
-
-// Returns a deterministic ID for this machine.
-std::string GenerateDeviceId() {
- static std::string cached_device_id;
- if (!cached_device_id.empty())
- return cached_device_id;
-
- std::string device_id;
- MachineIdStatus status = GetDeterministicMachineSpecificId(&device_id);
- if (status != MachineIdStatus::NOT_IMPLEMENTED) {
- // TODO(proberge): Remove this histogram once we validate that machine id
- // generation is not flaky and consider adding a CHECK or DCHECK.
- UMA_HISTOGRAM_BOOLEAN("Settings.MachineIdGenerationSuccess",
- status == MachineIdStatus::SUCCESS);
- }
-
- if (status == MachineIdStatus::SUCCESS) {
- cached_device_id = device_id;
- return device_id;
- }
-
- return std::string();
-}
-
-} // namespace
-
-class PrefHashStoreImpl::PrefHashStoreTransactionImpl
- : public PrefHashStoreTransaction {
- public:
- // Constructs a PrefHashStoreTransactionImpl which can use the private
- // members of its |outer| PrefHashStoreImpl.
- PrefHashStoreTransactionImpl(PrefHashStoreImpl* outer,
- HashStoreContents* storage);
- ~PrefHashStoreTransactionImpl() override;
-
- // PrefHashStoreTransaction implementation.
- base::StringPiece GetStoreUMASuffix() const override;
- ValueState CheckValue(const std::string& path,
- const base::Value* value) const override;
- void StoreHash(const std::string& path, const base::Value* value) override;
- ValueState CheckSplitValue(
- const std::string& path,
- const base::DictionaryValue* initial_split_value,
- std::vector<std::string>* invalid_keys) const override;
- void StoreSplitHash(const std::string& path,
- const base::DictionaryValue* split_value) override;
- bool HasHash(const std::string& path) const override;
- void ImportHash(const std::string& path, const base::Value* hash) override;
- void ClearHash(const std::string& path) override;
- bool IsSuperMACValid() const override;
- bool StampSuperMac() override;
-
- private:
- PrefHashStoreImpl* outer_;
- HashStoreContents* contents_;
-
- bool super_mac_valid_;
- bool super_mac_dirty_;
-
- DISALLOW_COPY_AND_ASSIGN(PrefHashStoreTransactionImpl);
-};
-
-PrefHashStoreImpl::PrefHashStoreImpl(const std::string& seed,
- const std::string& legacy_device_id,
- bool use_super_mac)
- : pref_hash_calculator_(seed, GenerateDeviceId(), legacy_device_id),
- use_super_mac_(use_super_mac) {}
-
-PrefHashStoreImpl::~PrefHashStoreImpl() {
-}
-
-std::unique_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction(
- HashStoreContents* storage) {
- return std::unique_ptr<PrefHashStoreTransaction>(
- new PrefHashStoreTransactionImpl(this, std::move(storage)));
-}
-
-std::string PrefHashStoreImpl::ComputeMac(const std::string& path,
- const base::Value* value) {
- return pref_hash_calculator_.Calculate(path, value);
-}
-
-std::unique_ptr<base::DictionaryValue> PrefHashStoreImpl::ComputeSplitMacs(
- const std::string& path,
- const base::DictionaryValue* split_values) {
- DCHECK(split_values);
-
- std::string keyed_path(path);
- keyed_path.push_back('.');
- const size_t common_part_length = keyed_path.length();
-
- std::unique_ptr<base::DictionaryValue> split_macs(new base::DictionaryValue);
-
- for (base::DictionaryValue::Iterator it(*split_values); !it.IsAtEnd();
- it.Advance()) {
- // Keep the common part from the old |keyed_path| and replace the key to
- // get the new |keyed_path|.
- keyed_path.replace(common_part_length, std::string::npos, it.key());
-
- split_macs->SetStringWithoutPathExpansion(
- it.key(), ComputeMac(keyed_path, &it.value()));
- }
-
- return split_macs;
-}
-
-PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl(
- PrefHashStoreImpl* outer,
- HashStoreContents* storage)
- : outer_(outer),
- contents_(std::move(storage)),
- super_mac_valid_(false),
- super_mac_dirty_(false) {
- if (!outer_->use_super_mac_)
- return;
-
- // The store must have a valid super MAC to be trusted.
- std::string super_mac = contents_->GetSuperMac();
- if (super_mac.empty())
- return;
-
- super_mac_valid_ =
- outer_->pref_hash_calculator_.Validate(
- "", contents_->GetContents(), super_mac) == PrefHashCalculator::VALID;
-}
-
-PrefHashStoreImpl::PrefHashStoreTransactionImpl::
- ~PrefHashStoreTransactionImpl() {
- if (super_mac_dirty_ && outer_->use_super_mac_) {
- // Get the dictionary of hashes (or NULL if it doesn't exist).
- const base::DictionaryValue* hashes_dict = contents_->GetContents();
- contents_->SetSuperMac(outer_->ComputeMac("", hashes_dict));
- }
-}
-
-base::StringPiece
-PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetStoreUMASuffix() const {
- return contents_->GetUMASuffix();
-}
-
-PrefHashStoreTransaction::ValueState
-PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue(
- const std::string& path,
- const base::Value* initial_value) const {
- std::string last_hash;
- contents_->GetMac(path, &last_hash);
-
- if (last_hash.empty()) {
- // In the absence of a hash for this pref, always trust a NULL value, but
- // only trust an existing value if the initial hashes dictionary is trusted.
- if (!initial_value)
- return TRUSTED_NULL_VALUE;
- else if (super_mac_valid_)
- return TRUSTED_UNKNOWN_VALUE;
- else
- return UNTRUSTED_UNKNOWN_VALUE;
- }
-
- PrefHashCalculator::ValidationResult validation_result =
- outer_->pref_hash_calculator_.Validate(path, initial_value, last_hash);
- switch (validation_result) {
- case PrefHashCalculator::VALID:
- return UNCHANGED;
- case PrefHashCalculator::VALID_SECURE_LEGACY:
- return SECURE_LEGACY;
- case PrefHashCalculator::INVALID:
- return initial_value ? CHANGED : CLEARED;
- }
- NOTREACHED() << "Unexpected PrefHashCalculator::ValidationResult: "
- << validation_result;
- return UNTRUSTED_UNKNOWN_VALUE;
-}
-
-void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash(
- const std::string& path,
- const base::Value* new_value) {
- const std::string mac = outer_->ComputeMac(path, new_value);
- contents_->SetMac(path, mac);
- super_mac_dirty_ = true;
-}
-
-PrefHashStoreTransaction::ValueState
-PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue(
- const std::string& path,
- const base::DictionaryValue* initial_split_value,
- std::vector<std::string>* invalid_keys) const {
- DCHECK(invalid_keys && invalid_keys->empty());
-
- std::map<std::string, std::string> split_macs;
- const bool has_hashes = contents_->GetSplitMacs(path, &split_macs);
-
- // Treat NULL and empty the same; otherwise we would need to store a hash for
- // the entire dictionary (or some other special beacon) to differentiate these
- // two cases which are really the same for dictionaries.
- if (!initial_split_value || initial_split_value->empty())
- return has_hashes ? CLEARED : UNCHANGED;
-
- if (!has_hashes)
- return super_mac_valid_ ? TRUSTED_UNKNOWN_VALUE : UNTRUSTED_UNKNOWN_VALUE;
-
- bool has_secure_legacy_id_hashes = false;
- std::string keyed_path(path);
- keyed_path.push_back('.');
- const size_t common_part_length = keyed_path.length();
- for (base::DictionaryValue::Iterator it(*initial_split_value); !it.IsAtEnd();
- it.Advance()) {
- std::map<std::string, std::string>::iterator entry =
- split_macs.find(it.key());
- if (entry == split_macs.end()) {
- invalid_keys->push_back(it.key());
- } else {
- // Keep the common part from the old |keyed_path| and replace the key to
- // get the new |keyed_path|.
- keyed_path.replace(common_part_length, std::string::npos, it.key());
- switch (outer_->pref_hash_calculator_.Validate(keyed_path, &it.value(),
- entry->second)) {
- case PrefHashCalculator::VALID:
- break;
- case SECURE_LEGACY:
- // Secure legacy device IDs based hashes are still accepted, but we
- // should make sure to notify the caller for them to update the legacy
- // hashes.
- has_secure_legacy_id_hashes = true;
- break;
- case PrefHashCalculator::INVALID:
- invalid_keys->push_back(it.key());
- break;
- }
- // Remove processed MACs, remaining MACs at the end will also be
- // considered invalid.
- split_macs.erase(entry);
- }
- }
-
- // Anything left in the map is missing from the data.
- for (std::map<std::string, std::string>::const_iterator it =
- split_macs.begin();
- it != split_macs.end(); ++it) {
- invalid_keys->push_back(it->first);
- }
-
- return invalid_keys->empty()
- ? (has_secure_legacy_id_hashes ? SECURE_LEGACY : UNCHANGED)
- : CHANGED;
-}
-
-void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreSplitHash(
- const std::string& path,
- const base::DictionaryValue* split_value) {
- contents_->RemoveEntry(path);
-
- if (split_value) {
- std::unique_ptr<base::DictionaryValue> split_macs =
- outer_->ComputeSplitMacs(path, split_value);
-
- for (base::DictionaryValue::Iterator it(*split_macs); !it.IsAtEnd();
- it.Advance()) {
- const base::StringValue* value_as_string;
- bool is_string = it.value().GetAsString(&value_as_string);
- DCHECK(is_string);
-
- contents_->SetSplitMac(path, it.key(), value_as_string->GetString());
- }
- }
- super_mac_dirty_ = true;
-}
-
-bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::HasHash(
- const std::string& path) const {
- std::string out_value;
- std::map<std::string, std::string> out_values;
- return contents_->GetMac(path, &out_value) ||
- contents_->GetSplitMacs(path, &out_values);
-}
-
-void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ImportHash(
- const std::string& path,
- const base::Value* hash) {
- DCHECK(hash);
-
- contents_->ImportEntry(path, hash);
-
- if (super_mac_valid_)
- super_mac_dirty_ = true;
-}
-
-void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ClearHash(
- const std::string& path) {
- if (contents_->RemoveEntry(path) && super_mac_valid_) {
- super_mac_dirty_ = true;
- }
-}
-
-bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::IsSuperMACValid() const {
- return super_mac_valid_;
-}
-
-bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::StampSuperMac() {
- if (!outer_->use_super_mac_ || super_mac_valid_)
- return false;
- super_mac_dirty_ = true;
- return true;
-}
diff --git a/chromium/components/user_prefs/tracked/pref_hash_store_impl.h b/chromium/components/user_prefs/tracked/pref_hash_store_impl.h
deleted file mode 100644
index 76b6f7597e1..00000000000
--- a/chromium/components/user_prefs/tracked/pref_hash_store_impl.h
+++ /dev/null
@@ -1,61 +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.
-
-#ifndef COMPONENTS_USER_PREFS_TRACKED_PREF_HASH_STORE_IMPL_H_
-#define COMPONENTS_USER_PREFS_TRACKED_PREF_HASH_STORE_IMPL_H_
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "components/user_prefs/tracked/pref_hash_calculator.h"
-#include "components/user_prefs/tracked/pref_hash_store.h"
-
-// Implements PrefHashStoreImpl by storing preference hashes in a
-// HashStoreContents.
-class PrefHashStoreImpl : public PrefHashStore {
- public:
- enum StoreVersion {
- // No hashes have been stored in this PrefHashStore yet.
- VERSION_UNINITIALIZED = 0,
- // The hashes in this PrefHashStore were stored before the introduction
- // of a version number and should be re-initialized.
- VERSION_PRE_MIGRATION = 1,
- // The hashes in this PrefHashStore were stored using the latest algorithm.
- VERSION_LATEST = 2,
- };
-
- // Constructs a PrefHashStoreImpl that calculates hashes using
- // |seed| and |legacy_device_id| and stores them in |contents|.
- //
- // The same |seed| and |legacy_device_id| must be used to load and validate
- // previously stored hashes in |contents|.
- PrefHashStoreImpl(const std::string& seed,
- const std::string& legacy_device_id,
- bool use_super_mac);
-
- ~PrefHashStoreImpl() override;
-
- // Clears the contents of this PrefHashStore. |IsInitialized()| will return
- // false after this call.
- void Reset();
-
- // PrefHashStore implementation.
- std::unique_ptr<PrefHashStoreTransaction> BeginTransaction(
- HashStoreContents* storage) override;
-
- std::string ComputeMac(const std::string& path,
- const base::Value* new_value) override;
- std::unique_ptr<base::DictionaryValue> ComputeSplitMacs(
- const std::string& path,
- const base::DictionaryValue* split_values) override;
-
- private:
- class PrefHashStoreTransactionImpl;
-
- const PrefHashCalculator pref_hash_calculator_;
- bool use_super_mac_;
-
- DISALLOW_COPY_AND_ASSIGN(PrefHashStoreImpl);
-};
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_PREF_HASH_STORE_IMPL_H_
diff --git a/chromium/components/user_prefs/tracked/pref_hash_store_impl_unittest.cc b/chromium/components/user_prefs/tracked/pref_hash_store_impl_unittest.cc
deleted file mode 100644
index f5d92182a53..00000000000
--- a/chromium/components/user_prefs/tracked/pref_hash_store_impl_unittest.cc
+++ /dev/null
@@ -1,518 +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/user_prefs/tracked/pref_hash_store_impl.h"
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/values.h"
-#include "components/user_prefs/tracked/dictionary_hash_store_contents.h"
-#include "components/user_prefs/tracked/hash_store_contents.h"
-#include "components/user_prefs/tracked/pref_hash_store_impl.h"
-#include "components/user_prefs/tracked/pref_hash_store_transaction.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class PrefHashStoreImplTest : public testing::Test {
- public:
- PrefHashStoreImplTest() : contents_(&pref_store_contents_) {}
-
- protected:
- HashStoreContents* GetHashStoreContents() { return &contents_; }
-
- private:
- base::DictionaryValue pref_store_contents_;
- // Must be declared after |pref_store_contents_| as it needs to be outlived
- // by it.
- DictionaryHashStoreContents contents_;
-
- DISALLOW_COPY_AND_ASSIGN(PrefHashStoreImplTest);
-};
-
-TEST_F(PrefHashStoreImplTest, ComputeMac) {
- base::StringValue string_1("string1");
- base::StringValue string_2("string2");
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
-
- std::string computed_mac_1 = pref_hash_store.ComputeMac("path1", &string_1);
- std::string computed_mac_2 = pref_hash_store.ComputeMac("path1", &string_2);
- std::string computed_mac_3 = pref_hash_store.ComputeMac("path2", &string_1);
-
- // Quick sanity checks here, see pref_hash_calculator_unittest.cc for more
- // complete tests.
- EXPECT_EQ(computed_mac_1, pref_hash_store.ComputeMac("path1", &string_1));
- EXPECT_NE(computed_mac_1, computed_mac_2);
- EXPECT_NE(computed_mac_1, computed_mac_3);
- EXPECT_EQ(64U, computed_mac_1.size());
-}
-
-TEST_F(PrefHashStoreImplTest, ComputeSplitMacs) {
- base::DictionaryValue dict;
- dict.Set("a", new base::StringValue("string1"));
- dict.Set("b", new base::StringValue("string2"));
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
-
- std::unique_ptr<base::DictionaryValue> computed_macs =
- pref_hash_store.ComputeSplitMacs("foo.bar", &dict);
-
- std::string mac_1;
- std::string mac_2;
- ASSERT_TRUE(computed_macs->GetString("a", &mac_1));
- ASSERT_TRUE(computed_macs->GetString("b", &mac_2));
-
- EXPECT_EQ(2U, computed_macs->size());
-
- base::StringValue string_1("string1");
- base::StringValue string_2("string2");
- EXPECT_EQ(pref_hash_store.ComputeMac("foo.bar.a", &string_1), mac_1);
- EXPECT_EQ(pref_hash_store.ComputeMac("foo.bar.b", &string_2), mac_2);
-}
-
-TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
- base::StringValue string_1("string1");
- base::StringValue string_2("string2");
-
- {
- // 32 NULL bytes is the seed that was used to generate the legacy hash.
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(GetHashStoreContents()));
-
- // Only NULL should be trusted in the absence of a hash.
- EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
- transaction->CheckValue("path1", &string_1));
- EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_NULL_VALUE,
- transaction->CheckValue("path1", NULL));
-
- transaction->StoreHash("path1", &string_1);
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckValue("path1", &string_1));
- EXPECT_EQ(PrefHashStoreTransaction::CLEARED,
- transaction->CheckValue("path1", NULL));
- transaction->StoreHash("path1", NULL);
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckValue("path1", NULL));
- EXPECT_EQ(PrefHashStoreTransaction::CHANGED,
- transaction->CheckValue("path1", &string_2));
-
- base::DictionaryValue dict;
- dict.Set("a", new base::StringValue("foo"));
- dict.Set("d", new base::StringValue("bad"));
- dict.Set("b", new base::StringValue("bar"));
- dict.Set("c", new base::StringValue("baz"));
-
- transaction->StoreHash("path1", &dict);
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckValue("path1", &dict));
- }
-
- ASSERT_FALSE(GetHashStoreContents()->GetSuperMac().empty());
-
- {
- // |pref_hash_store2| should trust its initial hashes dictionary and thus
- // trust new unknown values.
- PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store2.BeginTransaction(GetHashStoreContents()));
- EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
- transaction->CheckValue("new_path", &string_1));
- EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
- transaction->CheckValue("new_path", &string_2));
- EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_NULL_VALUE,
- transaction->CheckValue("new_path", NULL));
- }
-
- // Manually corrupt the super MAC.
- GetHashStoreContents()->SetSuperMac(std::string(64, 'A'));
-
- {
- // |pref_hash_store3| should no longer trust its initial hashes dictionary
- // and thus shouldn't trust non-NULL unknown values.
- PrefHashStoreImpl pref_hash_store3(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store3.BeginTransaction(GetHashStoreContents()));
- EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
- transaction->CheckValue("new_path", &string_1));
- EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
- transaction->CheckValue("new_path", &string_2));
- EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_NULL_VALUE,
- transaction->CheckValue("new_path", NULL));
- }
-}
-
-TEST_F(PrefHashStoreImplTest, ImportExportOperations) {
- base::StringValue string_1("string1");
- base::StringValue string_2("string2");
-
- // Initial state: no super MAC.
- {
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(GetHashStoreContents()));
- ASSERT_FALSE(transaction->IsSuperMACValid());
-
- ASSERT_FALSE(transaction->HasHash("path1"));
-
- // Storing a hash will stamp the super MAC.
- transaction->StoreHash("path1", &string_1);
-
- ASSERT_TRUE(transaction->HasHash("path1"));
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckValue("path1", &string_1));
- EXPECT_EQ(PrefHashStoreTransaction::CHANGED,
- transaction->CheckValue("path1", &string_2));
- }
-
- // Make a copy of the stored hash for future use.
- const base::Value* hash = NULL;
- ASSERT_TRUE(GetHashStoreContents()->GetContents()->Get("path1", &hash));
- std::unique_ptr<base::Value> path_1_string_1_hash_copy(hash->DeepCopy());
- hash = NULL;
-
- // Verify that the super MAC was stamped.
- {
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(GetHashStoreContents()));
- ASSERT_TRUE(transaction->IsSuperMACValid());
- ASSERT_TRUE(transaction->HasHash("path1"));
-
- // Clearing the hash should preserve validity.
- transaction->ClearHash("path1");
-
- // The effects of the clear should be immediately visible.
- ASSERT_FALSE(transaction->HasHash("path1"));
- EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_NULL_VALUE,
- transaction->CheckValue("path1", NULL));
- EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
- transaction->CheckValue("path1", &string_1));
- }
-
- // Verify that validity was preserved and that the clear took effect.
- {
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(GetHashStoreContents()));
- ASSERT_TRUE(transaction->IsSuperMACValid());
- ASSERT_FALSE(transaction->HasHash("path1"));
- }
-
- // Invalidate the super MAC.
- GetHashStoreContents()->SetSuperMac(std::string());
-
- {
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(GetHashStoreContents()));
- ASSERT_FALSE(transaction->IsSuperMACValid());
- ASSERT_FALSE(transaction->HasHash("path1"));
-
- // An import should preserve invalidity.
- transaction->ImportHash("path1", path_1_string_1_hash_copy.get());
-
- ASSERT_TRUE(transaction->HasHash("path1"));
-
- // The imported hash should be usable for validating the original value.
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckValue("path1", &string_1));
- }
-
- // Verify that invalidity was preserved and that the import took effect.
- {
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(GetHashStoreContents()));
- ASSERT_FALSE(transaction->IsSuperMACValid());
- ASSERT_TRUE(transaction->HasHash("path1"));
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckValue("path1", &string_1));
-
- // After clearing the hash, non-null values are UNTRUSTED_UNKNOWN.
- transaction->ClearHash("path1");
-
- EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_NULL_VALUE,
- transaction->CheckValue("path1", NULL));
- EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
- transaction->CheckValue("path1", &string_1));
- }
-
- {
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(GetHashStoreContents()));
- ASSERT_FALSE(transaction->IsSuperMACValid());
-
- // Test StampSuperMac.
- transaction->StampSuperMac();
- }
-
- // Verify that the store is now valid.
- {
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(GetHashStoreContents()));
- ASSERT_TRUE(transaction->IsSuperMACValid());
-
- // Store the hash of a different value to test an "over-import".
- transaction->StoreHash("path1", &string_2);
- EXPECT_EQ(PrefHashStoreTransaction::CHANGED,
- transaction->CheckValue("path1", &string_1));
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckValue("path1", &string_2));
- }
-
- {
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(GetHashStoreContents()));
- ASSERT_TRUE(transaction->IsSuperMACValid());
-
- // "Over-import". An import should preserve validity.
- transaction->ImportHash("path1", path_1_string_1_hash_copy.get());
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckValue("path1", &string_1));
- EXPECT_EQ(PrefHashStoreTransaction::CHANGED,
- transaction->CheckValue("path1", &string_2));
- }
-
- // Verify that validity was preserved and the "over-import" took effect.
- {
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(GetHashStoreContents()));
- ASSERT_TRUE(transaction->IsSuperMACValid());
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckValue("path1", &string_1));
- EXPECT_EQ(PrefHashStoreTransaction::CHANGED,
- transaction->CheckValue("path1", &string_2));
- }
-}
-
-TEST_F(PrefHashStoreImplTest, SuperMACDisabled) {
- base::StringValue string_1("string1");
- base::StringValue string_2("string2");
-
- {
- // Pass |use_super_mac| => false.
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", false);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(GetHashStoreContents()));
-
- transaction->StoreHash("path1", &string_2);
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckValue("path1", &string_2));
- }
-
- ASSERT_TRUE(GetHashStoreContents()->GetSuperMac().empty());
-
- {
- PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", false);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store2.BeginTransaction(GetHashStoreContents()));
- EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
- transaction->CheckValue("new_path", &string_1));
- }
-}
-
-TEST_F(PrefHashStoreImplTest, SplitHashStoreAndCheck) {
- base::DictionaryValue dict;
- dict.Set("a", new base::StringValue("to be replaced"));
- dict.Set("b", new base::StringValue("same"));
- dict.Set("o", new base::StringValue("old"));
-
- base::DictionaryValue modified_dict;
- modified_dict.Set("a", new base::StringValue("replaced"));
- modified_dict.Set("b", new base::StringValue("same"));
- modified_dict.Set("c", new base::StringValue("new"));
-
- base::DictionaryValue empty_dict;
-
- std::vector<std::string> invalid_keys;
-
- {
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(GetHashStoreContents()));
-
- // No hashes stored yet and hashes dictionary is empty (and thus not
- // trusted).
- EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
- transaction->CheckSplitValue("path1", &dict, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
-
- transaction->StoreSplitHash("path1", &dict);
-
- // Verify match post storage.
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckSplitValue("path1", &dict, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
-
- // Verify new path is still unknown.
- EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
- transaction->CheckSplitValue("path2", &dict, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
-
- // Verify NULL or empty dicts are declared as having been cleared.
- EXPECT_EQ(PrefHashStoreTransaction::CLEARED,
- transaction->CheckSplitValue("path1", NULL, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
- EXPECT_EQ(
- PrefHashStoreTransaction::CLEARED,
- transaction->CheckSplitValue("path1", &empty_dict, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
-
- // Verify changes are properly detected.
- EXPECT_EQ(
- PrefHashStoreTransaction::CHANGED,
- transaction->CheckSplitValue("path1", &modified_dict, &invalid_keys));
- std::vector<std::string> expected_invalid_keys1;
- expected_invalid_keys1.push_back("a");
- expected_invalid_keys1.push_back("c");
- expected_invalid_keys1.push_back("o");
- EXPECT_EQ(expected_invalid_keys1, invalid_keys);
- invalid_keys.clear();
-
- // Verify |dict| still matches post check.
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckSplitValue("path1", &dict, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
-
- // Store hash for |modified_dict|.
- transaction->StoreSplitHash("path1", &modified_dict);
-
- // Verify |modified_dict| is now the one that verifies correctly.
- EXPECT_EQ(
- PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckSplitValue("path1", &modified_dict, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
-
- // Verify old dict no longer matches.
- EXPECT_EQ(PrefHashStoreTransaction::CHANGED,
- transaction->CheckSplitValue("path1", &dict, &invalid_keys));
- std::vector<std::string> expected_invalid_keys2;
- expected_invalid_keys2.push_back("a");
- expected_invalid_keys2.push_back("o");
- expected_invalid_keys2.push_back("c");
- EXPECT_EQ(expected_invalid_keys2, invalid_keys);
- invalid_keys.clear();
- }
-
- {
- // |pref_hash_store2| should trust its initial hashes dictionary and thus
- // trust new unknown values.
- PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store2.BeginTransaction(GetHashStoreContents()));
- EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
- transaction->CheckSplitValue("new_path", &dict, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
- }
-
- // Manually corrupt the super MAC.
- GetHashStoreContents()->SetSuperMac(std::string(64, 'A'));
-
- {
- // |pref_hash_store3| should no longer trust its initial hashes dictionary
- // and thus shouldn't trust unknown values.
- PrefHashStoreImpl pref_hash_store3(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store3.BeginTransaction(GetHashStoreContents()));
- EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
- transaction->CheckSplitValue("new_path", &dict, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
- }
-}
-
-TEST_F(PrefHashStoreImplTest, EmptyAndNULLSplitDict) {
- base::DictionaryValue empty_dict;
-
- std::vector<std::string> invalid_keys;
-
- {
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(GetHashStoreContents()));
-
- // Store hashes for a random dict to be overwritten below.
- base::DictionaryValue initial_dict;
- initial_dict.Set("a", new base::StringValue("foo"));
- transaction->StoreSplitHash("path1", &initial_dict);
-
- // Verify stored empty dictionary matches NULL and empty dictionary back.
- transaction->StoreSplitHash("path1", &empty_dict);
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckSplitValue("path1", NULL, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
- EXPECT_EQ(
- PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckSplitValue("path1", &empty_dict, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
-
- // Same when storing NULL directly.
- transaction->StoreSplitHash("path1", NULL);
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckSplitValue("path1", NULL, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
- EXPECT_EQ(
- PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckSplitValue("path1", &empty_dict, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
- }
-
- {
- // |pref_hash_store2| should trust its initial hashes dictionary (and thus
- // trust new unknown values) even though the last action done was to clear
- // the hashes for path1 by setting its value to NULL (this is a regression
- // test ensuring that the internal action of clearing some hashes does
- // update the stored hash of hashes).
- PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store2.BeginTransaction(GetHashStoreContents()));
-
- base::DictionaryValue tested_dict;
- tested_dict.Set("a", new base::StringValue("foo"));
- tested_dict.Set("b", new base::StringValue("bar"));
- EXPECT_EQ(
- PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
- transaction->CheckSplitValue("new_path", &tested_dict, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
- }
-}
-
-// Test that the PrefHashStore returns TRUSTED_UNKNOWN_VALUE when checking for
-// a split preference even if there is an existing atomic preference's hash
-// stored. There is no point providing a migration path for preferences
-// switching strategies after their initial release as split preferences are
-// turned into split preferences specifically because the atomic hash isn't
-// considered useful.
-TEST_F(PrefHashStoreImplTest, TrustedUnknownSplitValueFromExistingAtomic) {
- base::StringValue string("string1");
-
- base::DictionaryValue dict;
- dict.Set("a", new base::StringValue("foo"));
- dict.Set("d", new base::StringValue("bad"));
- dict.Set("b", new base::StringValue("bar"));
- dict.Set("c", new base::StringValue("baz"));
-
- {
- PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(GetHashStoreContents()));
-
- transaction->StoreHash("path1", &string);
- EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
- transaction->CheckValue("path1", &string));
- }
-
- {
- // Load a new |pref_hash_store2| in which the hashes dictionary is trusted.
- PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store2.BeginTransaction(GetHashStoreContents()));
- std::vector<std::string> invalid_keys;
- EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
- transaction->CheckSplitValue("path1", &dict, &invalid_keys));
- EXPECT_TRUE(invalid_keys.empty());
- }
-}
diff --git a/chromium/components/user_prefs/tracked/pref_hash_store_transaction.h b/chromium/components/user_prefs/tracked/pref_hash_store_transaction.h
deleted file mode 100644
index 55d99d2d03f..00000000000
--- a/chromium/components/user_prefs/tracked/pref_hash_store_transaction.h
+++ /dev/null
@@ -1,102 +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_USER_PREFS_TRACKED_PREF_HASH_STORE_TRANSACTION_H_
-#define COMPONENTS_USER_PREFS_TRACKED_PREF_HASH_STORE_TRANSACTION_H_
-
-#include <string>
-#include <vector>
-
-#include "base/strings/string_piece.h"
-
-namespace base {
-class DictionaryValue;
-class Value;
-} // namespace base
-
-// Used to perform a series of checks/transformations on a PrefHashStore.
-class PrefHashStoreTransaction {
- public:
- enum ValueState {
- // The preference value corresponds to its stored hash.
- UNCHANGED,
- // The preference has been cleared since the last hash.
- CLEARED,
- // The preference value corresponds to its stored hash, but the hash was
- // calculated using a deprecated hash algorithm which is just as safe as
- // the current one.
- SECURE_LEGACY,
- // The preference value has been changed since the last hash.
- CHANGED,
- // No stored hash exists for the preference value.
- UNTRUSTED_UNKNOWN_VALUE,
- // No stored hash exists for the preference value, but the current set of
- // hashes stored is trusted and thus this value can safely be seeded. This
- // happens when all hashes are already properly seeded and a newly
- // tracked value needs to be seeded).
- TRUSTED_UNKNOWN_VALUE,
- // NULL values are inherently trusted.
- TRUSTED_NULL_VALUE,
- // This transaction's store type is not supported.
- UNSUPPORTED,
- };
-
- // Finalizes any remaining work after the transaction has been performed.
- virtual ~PrefHashStoreTransaction() {}
-
- // Returns the suffix to be appended to UMA histograms for the store contained
- // in this transaction.
- virtual base::StringPiece GetStoreUMASuffix() const = 0;
-
- // Checks |initial_value| against the existing stored value hash.
- virtual ValueState CheckValue(const std::string& path,
- const base::Value* initial_value) const = 0;
-
- // Stores a hash of the current |value| of the preference at |path|.
- virtual void StoreHash(const std::string& path, const base::Value* value) = 0;
-
- // Checks |initial_value| against the existing stored hashes for the split
- // preference at |path|. |initial_split_value| being an empty dictionary or
- // NULL is equivalent. |invalid_keys| must initially be empty. |invalid_keys|
- // will not be modified unless the return value is CHANGED, in which case it
- // will be filled with the keys that are considered invalid (unknown or
- // changed).
- virtual ValueState CheckSplitValue(
- const std::string& path,
- const base::DictionaryValue* initial_split_value,
- std::vector<std::string>* invalid_keys) const = 0;
-
- // Stores hashes for the |value| of the split preference at |path|.
- // |split_value| being an empty dictionary or NULL is equivalent.
- virtual void StoreSplitHash(const std::string& path,
- const base::DictionaryValue* split_value) = 0;
-
- // Indicates whether the store contains a hash for the preference at |path|.
- virtual bool HasHash(const std::string& path) const = 0;
-
- // Sets the hash for the preference at |path|.
- // If |path| is a split preference |hash| must be a DictionaryValue whose
- // keys are keys in the split preference and whose values are MACs of the
- // corresponding values in the split preference.
- // If |path| is an atomic preference |hash| must be a StringValue
- // containing a MAC of the preference value.
- // |hash| should originate from a PrefHashStore sharing the same MAC
- // parameters as this transaction's store.
- // The (in)validity of the super MAC will be maintained by this call.
- virtual void ImportHash(const std::string& path, const base::Value* hash) = 0;
-
- // Removes the hash stored at |path|. The (in)validity of the super MAC will
- // be maintained by this call.
- virtual void ClearHash(const std::string& path) = 0;
-
- // Indicates whether the super MAC was successfully verified at the beginning
- // of this transaction.
- virtual bool IsSuperMACValid() const = 0;
-
- // Forces a valid super MAC to be stored when this transaction terminates.
- // Returns true if this results in a change to the store contents.
- virtual bool StampSuperMac() = 0;
-};
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_PREF_HASH_STORE_TRANSACTION_H_
diff --git a/chromium/components/user_prefs/tracked/pref_names.cc b/chromium/components/user_prefs/tracked/pref_names.cc
deleted file mode 100644
index a6c73a65228..00000000000
--- a/chromium/components/user_prefs/tracked/pref_names.cc
+++ /dev/null
@@ -1,13 +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/user_prefs/tracked/pref_names.h"
-
-namespace user_prefs {
-
-// A timestamp (stored in base::Time::ToInternalValue format) of the last time
-// a preference was reset.
-const char kPreferenceResetTime[] = "prefs.preference_reset_time";
-
-} // namespace user_prefs
diff --git a/chromium/components/user_prefs/tracked/pref_names.h b/chromium/components/user_prefs/tracked/pref_names.h
deleted file mode 100644
index 80aa6bf5d07..00000000000
--- a/chromium/components/user_prefs/tracked/pref_names.h
+++ /dev/null
@@ -1,14 +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_USER_PREFS_TRACKED_PREF_NAMES_H_
-#define COMPONENTS_USER_PREFS_TRACKED_PREF_NAMES_H_
-
-namespace user_prefs {
-
-extern const char kPreferenceResetTime[];
-
-} // namespace user_prefs
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_PREF_NAMES_H_
diff --git a/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.cc b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.cc
deleted file mode 100644
index 03d789839c5..00000000000
--- a/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.cc
+++ /dev/null
@@ -1,182 +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/user_prefs/tracked/registry_hash_store_contents_win.h"
-
-#include <windows.h>
-
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "base/win/registry.h"
-#include "components/user_prefs/tracked/tracked_preference_histogram_names.h"
-
-using base::win::RegistryValueIterator;
-
-namespace {
-
-constexpr size_t kMacSize = 64;
-
-base::string16 GetSplitPrefKeyName(const base::string16& reg_key_name,
- const std::string& split_key_name) {
- return reg_key_name + L"\\" + base::UTF8ToUTF16(split_key_name);
-}
-
-bool ReadMacFromRegistry(const base::win::RegKey& key,
- const std::string& value_name,
- std::string* out_mac) {
- base::string16 string_value;
- if (key.ReadValue(base::UTF8ToUTF16(value_name).c_str(), &string_value) ==
- ERROR_SUCCESS &&
- string_value.size() == kMacSize) {
- out_mac->assign(base::UTF16ToUTF8(string_value));
- return true;
- }
- return false;
-}
-
-// Removes |value_name| under |reg_key_name|. Returns true if found and
-// successfully removed.
-bool ClearAtomicMac(const base::string16& reg_key_name,
- const std::string& value_name) {
- base::win::RegKey key;
- if (key.Open(HKEY_CURRENT_USER, reg_key_name.c_str(),
- KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
- return key.DeleteValue(base::UTF8ToUTF16(value_name).c_str()) ==
- ERROR_SUCCESS;
- }
- return false;
-}
-
-// Deletes |split_key_name| under |reg_key_name|. Returns true if found and
-// successfully removed.
-bool ClearSplitMac(const base::string16& reg_key_name,
- const std::string& split_key_name) {
- base::win::RegKey key;
- if (key.Open(HKEY_CURRENT_USER,
- GetSplitPrefKeyName(reg_key_name, split_key_name).c_str(),
- KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
- return key.DeleteKey(L"") == ERROR_SUCCESS;
- }
- return false;
-}
-
-} // namespace
-
-RegistryHashStoreContentsWin::RegistryHashStoreContentsWin(
- const base::string16& registry_path,
- const base::string16& store_key)
- : preference_key_name_(registry_path + L"\\PreferenceMACs\\" + store_key) {}
-
-RegistryHashStoreContentsWin::RegistryHashStoreContentsWin(
- const RegistryHashStoreContentsWin& other) = default;
-
-bool RegistryHashStoreContentsWin::IsCopyable() const {
- return true;
-}
-
-std::unique_ptr<HashStoreContents> RegistryHashStoreContentsWin::MakeCopy()
- const {
- return base::WrapUnique(new RegistryHashStoreContentsWin(*this));
-}
-
-base::StringPiece RegistryHashStoreContentsWin::GetUMASuffix() const {
- return user_prefs::tracked::kTrackedPrefRegistryValidationSuffix;
-}
-
-void RegistryHashStoreContentsWin::Reset() {
- base::win::RegKey key;
- if (key.Open(HKEY_CURRENT_USER, preference_key_name_.c_str(),
- KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
- LONG result = key.DeleteKey(L"");
- DCHECK(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND) << result;
- }
-}
-
-bool RegistryHashStoreContentsWin::GetMac(const std::string& path,
- std::string* out_value) {
- base::win::RegKey key;
- if (key.Open(HKEY_CURRENT_USER, preference_key_name_.c_str(),
- KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
- return ReadMacFromRegistry(key, path, out_value);
- }
-
- return false;
-}
-
-bool RegistryHashStoreContentsWin::GetSplitMacs(
- const std::string& path,
- std::map<std::string, std::string>* split_macs) {
- DCHECK(split_macs);
- DCHECK(split_macs->empty());
-
- RegistryValueIterator iter_key(
- HKEY_CURRENT_USER,
- GetSplitPrefKeyName(preference_key_name_, path).c_str());
-
- for (; iter_key.Valid(); ++iter_key) {
- split_macs->insert(make_pair(base::UTF16ToUTF8(iter_key.Name()),
- base::UTF16ToUTF8(iter_key.Value())));
- }
-
- return !split_macs->empty();
-}
-
-void RegistryHashStoreContentsWin::SetMac(const std::string& path,
- const std::string& value) {
- base::win::RegKey key;
- DCHECK_EQ(kMacSize, value.size());
-
- if (key.Create(HKEY_CURRENT_USER, preference_key_name_.c_str(),
- KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
- key.WriteValue(base::UTF8ToUTF16(path).c_str(),
- base::UTF8ToUTF16(value).c_str());
- }
-}
-
-void RegistryHashStoreContentsWin::SetSplitMac(const std::string& path,
- const std::string& split_path,
- const std::string& value) {
- base::win::RegKey key;
- DCHECK_EQ(kMacSize, value.size());
-
- if (key.Create(HKEY_CURRENT_USER,
- GetSplitPrefKeyName(preference_key_name_, path).c_str(),
- KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
- key.WriteValue(base::UTF8ToUTF16(split_path).c_str(),
- base::UTF8ToUTF16(value).c_str());
- }
-}
-
-bool RegistryHashStoreContentsWin::RemoveEntry(const std::string& path) {
- return ClearAtomicMac(preference_key_name_, path) ||
- ClearSplitMac(preference_key_name_, path);
-}
-
-void RegistryHashStoreContentsWin::ImportEntry(const std::string& path,
- const base::Value* in_value) {
- NOTREACHED()
- << "RegistryHashStoreContents does not support the ImportEntry operation";
-}
-
-const base::DictionaryValue* RegistryHashStoreContentsWin::GetContents() const {
- NOTREACHED()
- << "RegistryHashStoreContents does not support the GetContents operation";
- return NULL;
-}
-
-std::string RegistryHashStoreContentsWin::GetSuperMac() const {
- NOTREACHED()
- << "RegistryHashStoreContents does not support the GetSuperMac operation";
- return NULL;
-}
-
-void RegistryHashStoreContentsWin::SetSuperMac(const std::string& super_mac) {
- NOTREACHED()
- << "RegistryHashStoreContents does not support the SetSuperMac operation";
-}
diff --git a/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.h b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.h
deleted file mode 100644
index b44898ef698..00000000000
--- a/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.h
+++ /dev/null
@@ -1,49 +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_USER_PREFS_TRACKED_PREF_REGISTRY_HASH_STORE_CONTENTS_WIN_H_
-#define COMPONENTS_USER_PREFS_TRACKED_PREF_REGISTRY_HASH_STORE_CONTENTS_WIN_H_
-
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "components/user_prefs/tracked/hash_store_contents.h"
-
-// Implements HashStoreContents by storing MACs in the Windows registry.
-class RegistryHashStoreContentsWin : public HashStoreContents {
- public:
- // Constructs a RegistryHashStoreContents which acts on a registry entry
- // defined by |registry_path| and |store_key|.
- explicit RegistryHashStoreContentsWin(const base::string16& registry_path,
- const base::string16& store_key);
-
- // HashStoreContents overrides:
- bool IsCopyable() const override;
- std::unique_ptr<HashStoreContents> MakeCopy() const override;
- base::StringPiece GetUMASuffix() const override;
- void Reset() override;
- bool GetMac(const std::string& path, std::string* out_value) override;
- bool GetSplitMacs(const std::string& path,
- std::map<std::string, std::string>* split_macs) override;
- void SetMac(const std::string& path, const std::string& value) override;
- void SetSplitMac(const std::string& path,
- const std::string& split_path,
- const std::string& value) override;
- bool RemoveEntry(const std::string& path) override;
-
- // Unsupported HashStoreContents overrides:
- void ImportEntry(const std::string& path,
- const base::Value* in_value) override;
- const base::DictionaryValue* GetContents() const override;
- std::string GetSuperMac() const override;
- void SetSuperMac(const std::string& super_mac) override;
-
- private:
- // Helper constructor for |MakeCopy|.
- explicit RegistryHashStoreContentsWin(
- const RegistryHashStoreContentsWin& other);
-
- const base::string16 preference_key_name_;
-};
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_PREF_REGISTRY_HASH_STORE_CONTENTS_H_
diff --git a/chromium/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc
deleted file mode 100644
index 8b53b920da3..00000000000
--- a/chromium/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc
+++ /dev/null
@@ -1,120 +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/user_prefs/tracked/registry_hash_store_contents_win.h"
-
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/test_reg_util_win.h"
-#include "base/values.h"
-#include "base/win/registry.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-constexpr base::char16 kRegistryPath[] = L"Foo\\TestStore";
-constexpr base::char16 kStoreKey[] = L"test_store_key";
-
-// Hex-encoded MACs are 64 characters long.
-constexpr char kTestStringA[] =
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
-constexpr char kTestStringB[] =
- "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
-
-constexpr char kAtomicPrefPath[] = "path1";
-constexpr char kSplitPrefPath[] = "extension";
-
-class RegistryHashStoreContentsWinTest : public testing::Test {
- protected:
- RegistryHashStoreContentsWinTest() {}
-
- void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(
- registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
-
- contents.reset(new RegistryHashStoreContentsWin(kRegistryPath, kStoreKey));
- }
-
- std::unique_ptr<HashStoreContents> contents;
-
- private:
- registry_util::RegistryOverrideManager registry_override_manager_;
-
- DISALLOW_COPY_AND_ASSIGN(RegistryHashStoreContentsWinTest);
-};
-
-} // namespace
-
-TEST_F(RegistryHashStoreContentsWinTest, TestSetAndGetMac) {
- std::string stored_mac;
- EXPECT_FALSE(contents->GetMac(kAtomicPrefPath, &stored_mac));
-
- contents->SetMac(kAtomicPrefPath, kTestStringA);
-
- EXPECT_TRUE(contents->GetMac(kAtomicPrefPath, &stored_mac));
- EXPECT_EQ(kTestStringA, stored_mac);
-}
-
-TEST_F(RegistryHashStoreContentsWinTest, TestSetAndGetSplitMacs) {
- std::map<std::string, std::string> split_macs;
- EXPECT_FALSE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
-
- contents->SetSplitMac(kSplitPrefPath, "a", kTestStringA);
- contents->SetSplitMac(kSplitPrefPath, "b", kTestStringB);
-
- EXPECT_TRUE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
- EXPECT_EQ(2U, split_macs.size());
- EXPECT_EQ(kTestStringA, split_macs.at("a"));
- EXPECT_EQ(kTestStringB, split_macs.at("b"));
-}
-
-TEST_F(RegistryHashStoreContentsWinTest, TestRemoveAtomicMac) {
- contents->SetMac(kAtomicPrefPath, kTestStringA);
-
- std::string stored_mac;
- EXPECT_TRUE(contents->GetMac(kAtomicPrefPath, &stored_mac));
- EXPECT_EQ(kTestStringA, stored_mac);
-
- contents->RemoveEntry(kAtomicPrefPath);
-
- EXPECT_FALSE(contents->GetMac(kAtomicPrefPath, &stored_mac));
-}
-
-TEST_F(RegistryHashStoreContentsWinTest, TestRemoveSplitMacs) {
- contents->SetSplitMac(kSplitPrefPath, "a", kTestStringA);
- contents->SetSplitMac(kSplitPrefPath, "b", kTestStringB);
-
- std::map<std::string, std::string> split_macs;
- EXPECT_TRUE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
- EXPECT_EQ(2U, split_macs.size());
-
- contents->RemoveEntry(kSplitPrefPath);
-
- split_macs.clear();
- EXPECT_FALSE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
- EXPECT_EQ(0U, split_macs.size());
-}
-
-TEST_F(RegistryHashStoreContentsWinTest, TestReset) {
- contents->SetMac(kAtomicPrefPath, kTestStringA);
- contents->SetSplitMac(kSplitPrefPath, "a", kTestStringA);
-
- std::string stored_mac;
- EXPECT_TRUE(contents->GetMac(kAtomicPrefPath, &stored_mac));
- EXPECT_EQ(kTestStringA, stored_mac);
-
- std::map<std::string, std::string> split_macs;
- EXPECT_TRUE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
- EXPECT_EQ(1U, split_macs.size());
-
- contents->Reset();
-
- stored_mac.clear();
- EXPECT_FALSE(contents->GetMac(kAtomicPrefPath, &stored_mac));
- EXPECT_TRUE(stored_mac.empty());
-
- split_macs.clear();
- EXPECT_FALSE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
- EXPECT_EQ(0U, split_macs.size());
-}
diff --git a/chromium/components/user_prefs/tracked/segregated_pref_store.cc b/chromium/components/user_prefs/tracked/segregated_pref_store.cc
deleted file mode 100644
index 297e2a7e58f..00000000000
--- a/chromium/components/user_prefs/tracked/segregated_pref_store.cc
+++ /dev/null
@@ -1,194 +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/user_prefs/tracked/segregated_pref_store.h"
-
-#include <utility>
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "base/values.h"
-
-SegregatedPrefStore::AggregatingObserver::AggregatingObserver(
- SegregatedPrefStore* outer)
- : outer_(outer),
- failed_sub_initializations_(0),
- successful_sub_initializations_(0) {
-}
-
-void SegregatedPrefStore::AggregatingObserver::OnPrefValueChanged(
- const std::string& key) {
- // There is no need to tell clients about changes if they have not yet been
- // told about initialization.
- if (failed_sub_initializations_ + successful_sub_initializations_ < 2)
- return;
-
- for (auto& observer : outer_->observers_)
- observer.OnPrefValueChanged(key);
-}
-
-void SegregatedPrefStore::AggregatingObserver::OnInitializationCompleted(
- bool succeeded) {
- if (succeeded)
- ++successful_sub_initializations_;
- else
- ++failed_sub_initializations_;
-
- DCHECK_LE(failed_sub_initializations_ + successful_sub_initializations_, 2);
-
- if (failed_sub_initializations_ + successful_sub_initializations_ == 2) {
- if (successful_sub_initializations_ == 2 && outer_->read_error_delegate_) {
- PersistentPrefStore::PrefReadError read_error = outer_->GetReadError();
- if (read_error != PersistentPrefStore::PREF_READ_ERROR_NONE)
- outer_->read_error_delegate_->OnError(read_error);
- }
-
- for (auto& observer : outer_->observers_)
- observer.OnInitializationCompleted(successful_sub_initializations_ == 2);
- }
-}
-
-SegregatedPrefStore::SegregatedPrefStore(
- const scoped_refptr<PersistentPrefStore>& default_pref_store,
- const scoped_refptr<PersistentPrefStore>& selected_pref_store,
- const std::set<std::string>& selected_pref_names)
- : default_pref_store_(default_pref_store),
- selected_pref_store_(selected_pref_store),
- selected_preference_names_(selected_pref_names),
- aggregating_observer_(this) {
- default_pref_store_->AddObserver(&aggregating_observer_);
- selected_pref_store_->AddObserver(&aggregating_observer_);
-}
-
-void SegregatedPrefStore::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
-
-void SegregatedPrefStore::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
-
-bool SegregatedPrefStore::HasObservers() const {
- return observers_.might_have_observers();
-}
-
-bool SegregatedPrefStore::IsInitializationComplete() const {
- return default_pref_store_->IsInitializationComplete() &&
- selected_pref_store_->IsInitializationComplete();
-}
-
-bool SegregatedPrefStore::GetValue(const std::string& key,
- const base::Value** result) const {
- return StoreForKey(key)->GetValue(key, result);
-}
-
-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)) {
- values->Set(key, value->CreateDeepCopy());
- } else {
- values->Remove(key, nullptr);
- }
- }
- return values;
-}
-
-void SegregatedPrefStore::SetValue(const std::string& key,
- std::unique_ptr<base::Value> value,
- uint32_t flags) {
- StoreForKey(key)->SetValue(key, std::move(value), flags);
-}
-
-void SegregatedPrefStore::RemoveValue(const std::string& key, uint32_t flags) {
- StoreForKey(key)->RemoveValue(key, flags);
-}
-
-bool SegregatedPrefStore::GetMutableValue(const std::string& key,
- base::Value** result) {
- return StoreForKey(key)->GetMutableValue(key, result);
-}
-
-void SegregatedPrefStore::ReportValueChanged(const std::string& key,
- uint32_t flags) {
- StoreForKey(key)->ReportValueChanged(key, flags);
-}
-
-void SegregatedPrefStore::SetValueSilently(const std::string& key,
- std::unique_ptr<base::Value> value,
- uint32_t flags) {
- StoreForKey(key)->SetValueSilently(key, std::move(value), flags);
-}
-
-bool SegregatedPrefStore::ReadOnly() const {
- return selected_pref_store_->ReadOnly() || default_pref_store_->ReadOnly();
-}
-
-PersistentPrefStore::PrefReadError SegregatedPrefStore::GetReadError() const {
- PersistentPrefStore::PrefReadError read_error =
- default_pref_store_->GetReadError();
- if (read_error == PersistentPrefStore::PREF_READ_ERROR_NONE) {
- read_error = selected_pref_store_->GetReadError();
- // Ignore NO_FILE from selected_pref_store_.
- if (read_error == PersistentPrefStore::PREF_READ_ERROR_NO_FILE)
- read_error = PersistentPrefStore::PREF_READ_ERROR_NONE;
- }
- return read_error;
-}
-
-PersistentPrefStore::PrefReadError SegregatedPrefStore::ReadPrefs() {
- // Note: Both of these stores own PrefFilters which makes ReadPrefs
- // asynchronous. This is okay in this case as only the first call will be
- // truly asynchronous, the second call will then unblock the migration in
- // TrackedPreferencesMigrator and complete synchronously.
- default_pref_store_->ReadPrefs();
- PersistentPrefStore::PrefReadError selected_store_read_error =
- selected_pref_store_->ReadPrefs();
- DCHECK_NE(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
- selected_store_read_error);
-
- return GetReadError();
-}
-
-void SegregatedPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
- read_error_delegate_.reset(error_delegate);
- default_pref_store_->ReadPrefsAsync(NULL);
- selected_pref_store_->ReadPrefsAsync(NULL);
-}
-
-void SegregatedPrefStore::CommitPendingWrite() {
- default_pref_store_->CommitPendingWrite();
- selected_pref_store_->CommitPendingWrite();
-}
-
-void SegregatedPrefStore::SchedulePendingLossyWrites() {
- default_pref_store_->SchedulePendingLossyWrites();
- selected_pref_store_->SchedulePendingLossyWrites();
-}
-
-void SegregatedPrefStore::ClearMutableValues() {
- NOTIMPLEMENTED();
-}
-
-SegregatedPrefStore::~SegregatedPrefStore() {
- default_pref_store_->RemoveObserver(&aggregating_observer_);
- selected_pref_store_->RemoveObserver(&aggregating_observer_);
-}
-
-PersistentPrefStore* SegregatedPrefStore::StoreForKey(const std::string& key) {
- return (base::ContainsKey(selected_preference_names_, key)
- ? selected_pref_store_
- : default_pref_store_)
- .get();
-}
-
-const PersistentPrefStore* SegregatedPrefStore::StoreForKey(
- const std::string& key) const {
- return (base::ContainsKey(selected_preference_names_, key)
- ? selected_pref_store_
- : default_pref_store_)
- .get();
-}
diff --git a/chromium/components/user_prefs/tracked/segregated_pref_store.h b/chromium/components/user_prefs/tracked/segregated_pref_store.h
deleted file mode 100644
index 40629768f01..00000000000
--- a/chromium/components/user_prefs/tracked/segregated_pref_store.h
+++ /dev/null
@@ -1,115 +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_USER_PREFS_TRACKED_SEGREGATED_PREF_STORE_H_
-#define COMPONENTS_USER_PREFS_TRACKED_SEGREGATED_PREF_STORE_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <set>
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/observer_list.h"
-#include "components/prefs/persistent_pref_store.h"
-
-// Provides a unified PersistentPrefStore implementation that splits its storage
-// and retrieval between two underlying PersistentPrefStore instances: a set of
-// preference names is used to partition the preferences.
-//
-// Combines properties of the two stores as follows:
-// * The unified read error will be:
-// Selected Store Error
-// Default Store Error | NO_ERROR | NO_FILE | other selected |
-// NO_ERROR | NO_ERROR | NO_ERROR | other selected |
-// NO_FILE | NO_FILE | NO_FILE | NO_FILE |
-// other default | other default | other default | other default |
-// * The unified initialization success, initialization completion, and
-// read-only state are the boolean OR of the underlying stores' properties.
-class SegregatedPrefStore : public PersistentPrefStore {
- public:
- // Creates an instance that delegates to |selected_pref_store| for the
- // preferences named in |selected_pref_names| and to |default_pref_store|
- // for all others. If an unselected preference is present in
- // |selected_pref_store| (i.e. because it was previously selected) it will
- // be migrated back to |default_pref_store| upon access via a non-const
- // method.
- // |on_initialization| will be invoked when both stores have been initialized,
- // before observers of the SegregatedPrefStore store are notified.
- SegregatedPrefStore(
- const scoped_refptr<PersistentPrefStore>& default_pref_store,
- const scoped_refptr<PersistentPrefStore>& selected_pref_store,
- const std::set<std::string>& selected_pref_names);
-
- // PrefStore implementation
- void AddObserver(Observer* observer) override;
- void RemoveObserver(Observer* observer) override;
- bool HasObservers() const override;
- bool IsInitializationComplete() const override;
- bool GetValue(const std::string& key,
- const base::Value** result) const override;
- std::unique_ptr<base::DictionaryValue> GetValues() const override;
-
- // WriteablePrefStore implementation
- void SetValue(const std::string& key,
- std::unique_ptr<base::Value> value,
- uint32_t flags) override;
- void RemoveValue(const std::string& key, uint32_t flags) override;
-
- // PersistentPrefStore implementation
- bool GetMutableValue(const std::string& key, base::Value** result) override;
- void ReportValueChanged(const std::string& key, uint32_t flags) override;
- void SetValueSilently(const std::string& key,
- std::unique_ptr<base::Value> value,
- uint32_t flags) override;
- bool ReadOnly() const override;
- PrefReadError GetReadError() const override;
- PrefReadError ReadPrefs() override;
- void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
- void CommitPendingWrite() override;
- void SchedulePendingLossyWrites() override;
-
- void ClearMutableValues() override;
-
- private:
- // Aggregates events from the underlying stores and synthesizes external
- // events via |on_initialization|, |read_error_delegate_|, and |observers_|.
- class AggregatingObserver : public PrefStore::Observer {
- public:
- explicit AggregatingObserver(SegregatedPrefStore* outer);
-
- // PrefStore::Observer implementation
- void OnPrefValueChanged(const std::string& key) override;
- void OnInitializationCompleted(bool succeeded) override;
-
- private:
- SegregatedPrefStore* outer_;
- int failed_sub_initializations_;
- int successful_sub_initializations_;
-
- DISALLOW_COPY_AND_ASSIGN(AggregatingObserver);
- };
-
- ~SegregatedPrefStore() override;
-
- // Returns |selected_pref_store| if |key| is selected and |default_pref_store|
- // otherwise.
- PersistentPrefStore* StoreForKey(const std::string& key);
- const PersistentPrefStore* StoreForKey(const std::string& key) const;
-
- scoped_refptr<PersistentPrefStore> default_pref_store_;
- scoped_refptr<PersistentPrefStore> selected_pref_store_;
- std::set<std::string> selected_preference_names_;
-
- std::unique_ptr<PersistentPrefStore::ReadErrorDelegate> read_error_delegate_;
- base::ObserverList<PrefStore::Observer, true> observers_;
- AggregatingObserver aggregating_observer_;
-
- DISALLOW_COPY_AND_ASSIGN(SegregatedPrefStore);
-};
-
-#endif // COMPONENTS_PREFS_TRACKED_SEGREGATED_PREF_STORE_H_
diff --git a/chromium/components/user_prefs/tracked/segregated_pref_store_unittest.cc b/chromium/components/user_prefs/tracked/segregated_pref_store_unittest.cc
deleted file mode 100644
index a4b40b15778..00000000000
--- a/chromium/components/user_prefs/tracked/segregated_pref_store_unittest.cc
+++ /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.
-
-#include "components/user_prefs/tracked/segregated_pref_store.h"
-
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/values.h"
-#include "components/prefs/persistent_pref_store.h"
-#include "components/prefs/pref_store_observer_mock.h"
-#include "components/prefs/testing_pref_store.h"
-#include "components/user_prefs/tracked/segregated_pref_store.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-const char kSelectedPref[] = "selected_pref";
-const char kUnselectedPref[] = "unselected_pref";
-const char kSharedPref[] = "shared_pref";
-
-const char kValue1[] = "value1";
-const char kValue2[] = "value2";
-
-class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
- public:
- struct Data {
- Data(bool invoked_in, PersistentPrefStore::PrefReadError read_error_in)
- : invoked(invoked_in), read_error(read_error_in) {}
-
- bool invoked;
- PersistentPrefStore::PrefReadError read_error;
- };
-
- explicit MockReadErrorDelegate(Data* data) : data_(data) {
- DCHECK(data_);
- EXPECT_FALSE(data_->invoked);
- }
-
- // PersistentPrefStore::ReadErrorDelegate implementation
- void OnError(PersistentPrefStore::PrefReadError read_error) override {
- EXPECT_FALSE(data_->invoked);
- data_->invoked = true;
- data_->read_error = read_error;
- }
-
- private:
- Data* data_;
-};
-
-} // namespace
-
-class SegregatedPrefStoreTest : public testing::Test {
- public:
- SegregatedPrefStoreTest()
- : read_error_delegate_data_(false,
- PersistentPrefStore::PREF_READ_ERROR_NONE),
- read_error_delegate_(
- new MockReadErrorDelegate(&read_error_delegate_data_)) {}
-
- void SetUp() override {
- selected_store_ = new TestingPrefStore;
- default_store_ = new TestingPrefStore;
-
- std::set<std::string> selected_pref_names;
- selected_pref_names.insert(kSelectedPref);
- selected_pref_names.insert(kSharedPref);
-
- segregated_store_ = new SegregatedPrefStore(default_store_, selected_store_,
- selected_pref_names);
-
- segregated_store_->AddObserver(&observer_);
- }
-
- void TearDown() override { segregated_store_->RemoveObserver(&observer_); }
-
- protected:
- std::unique_ptr<PersistentPrefStore::ReadErrorDelegate>
- GetReadErrorDelegate() {
- EXPECT_TRUE(read_error_delegate_);
- return std::move(read_error_delegate_);
- }
-
- PrefStoreObserverMock observer_;
-
- scoped_refptr<TestingPrefStore> default_store_;
- scoped_refptr<TestingPrefStore> selected_store_;
- scoped_refptr<SegregatedPrefStore> segregated_store_;
-
- MockReadErrorDelegate::Data read_error_delegate_data_;
-
- private:
- std::unique_ptr<MockReadErrorDelegate> read_error_delegate_;
-};
-
-TEST_F(SegregatedPrefStoreTest, StoreValues) {
- ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
- segregated_store_->ReadPrefs());
-
- // Properly stores new values.
- segregated_store_->SetValue(kSelectedPref,
- base::MakeUnique<base::StringValue>(kValue1),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
- segregated_store_->SetValue(kUnselectedPref,
- base::MakeUnique<base::StringValue>(kValue2),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
-
- ASSERT_TRUE(selected_store_->GetValue(kSelectedPref, NULL));
- ASSERT_FALSE(selected_store_->GetValue(kUnselectedPref, NULL));
- ASSERT_FALSE(default_store_->GetValue(kSelectedPref, NULL));
- ASSERT_TRUE(default_store_->GetValue(kUnselectedPref, NULL));
-
- ASSERT_TRUE(segregated_store_->GetValue(kSelectedPref, NULL));
- ASSERT_TRUE(segregated_store_->GetValue(kUnselectedPref, NULL));
-
- ASSERT_FALSE(selected_store_->committed());
- ASSERT_FALSE(default_store_->committed());
-
- segregated_store_->CommitPendingWrite();
-
- ASSERT_TRUE(selected_store_->committed());
- ASSERT_TRUE(default_store_->committed());
-}
-
-TEST_F(SegregatedPrefStoreTest, ReadValues) {
- selected_store_->SetValue(kSelectedPref,
- base::MakeUnique<base::StringValue>(kValue1),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
- default_store_->SetValue(kUnselectedPref,
- base::MakeUnique<base::StringValue>(kValue2),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
-
- // Works properly with values that are already there.
- ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
- segregated_store_->ReadPrefs());
- ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
- segregated_store_->GetReadError());
-
- ASSERT_TRUE(selected_store_->GetValue(kSelectedPref, NULL));
- ASSERT_FALSE(selected_store_->GetValue(kUnselectedPref, NULL));
- ASSERT_FALSE(default_store_->GetValue(kSelectedPref, NULL));
- ASSERT_TRUE(default_store_->GetValue(kUnselectedPref, NULL));
-
- ASSERT_TRUE(segregated_store_->GetValue(kSelectedPref, NULL));
- ASSERT_TRUE(segregated_store_->GetValue(kUnselectedPref, NULL));
-}
-
-TEST_F(SegregatedPrefStoreTest, Observer) {
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
- segregated_store_->ReadPrefs());
- EXPECT_TRUE(observer_.initialized);
- EXPECT_TRUE(observer_.initialization_success);
- EXPECT_TRUE(observer_.changed_keys.empty());
- segregated_store_->SetValue(kSelectedPref,
- base::MakeUnique<base::StringValue>(kValue1),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
- observer_.VerifyAndResetChangedKey(kSelectedPref);
- segregated_store_->SetValue(kUnselectedPref,
- base::MakeUnique<base::StringValue>(kValue2),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
- observer_.VerifyAndResetChangedKey(kUnselectedPref);
-}
-
-TEST_F(SegregatedPrefStoreTest, SelectedPrefReadNoFileError) {
- // PREF_READ_ERROR_NO_FILE for the selected prefs file is silently converted
- // to PREF_READ_ERROR_NONE.
- selected_store_->set_read_error(PersistentPrefStore::PREF_READ_ERROR_NO_FILE);
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
- segregated_store_->ReadPrefs());
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
- segregated_store_->GetReadError());
-}
-
-TEST_F(SegregatedPrefStoreTest, SelectedPrefReadError) {
- selected_store_->set_read_error(
- PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED);
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED,
- segregated_store_->ReadPrefs());
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED,
- segregated_store_->GetReadError());
-}
-
-TEST_F(SegregatedPrefStoreTest, SelectedPrefReadNoFileErrorAsync) {
- // PREF_READ_ERROR_NO_FILE for the selected prefs file is silently converted
- // to PREF_READ_ERROR_NONE.
- selected_store_->set_read_error(PersistentPrefStore::PREF_READ_ERROR_NO_FILE);
-
- default_store_->SetBlockAsyncRead(true);
-
- EXPECT_FALSE(read_error_delegate_data_.invoked);
-
- segregated_store_->ReadPrefsAsync(GetReadErrorDelegate().release());
-
- EXPECT_FALSE(read_error_delegate_data_.invoked);
-
- default_store_->SetBlockAsyncRead(false);
-
- // ReadErrorDelegate is not invoked for ERROR_NONE.
- EXPECT_FALSE(read_error_delegate_data_.invoked);
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
- segregated_store_->GetReadError());
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
- segregated_store_->GetReadError());
-}
-
-TEST_F(SegregatedPrefStoreTest, UnselectedPrefReadNoFileError) {
- default_store_->set_read_error(PersistentPrefStore::PREF_READ_ERROR_NO_FILE);
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
- segregated_store_->ReadPrefs());
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
- segregated_store_->GetReadError());
-}
-
-TEST_F(SegregatedPrefStoreTest, UnselectedPrefReadError) {
- default_store_->set_read_error(
- PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED);
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED,
- segregated_store_->ReadPrefs());
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED,
- segregated_store_->GetReadError());
-}
-
-TEST_F(SegregatedPrefStoreTest, BothPrefReadError) {
- default_store_->set_read_error(PersistentPrefStore::PREF_READ_ERROR_NO_FILE);
- selected_store_->set_read_error(
- PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED);
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
- segregated_store_->ReadPrefs());
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
- segregated_store_->GetReadError());
-}
-
-TEST_F(SegregatedPrefStoreTest, BothPrefReadErrorAsync) {
- default_store_->set_read_error(PersistentPrefStore::PREF_READ_ERROR_NO_FILE);
- selected_store_->set_read_error(
- PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED);
-
- selected_store_->SetBlockAsyncRead(true);
-
- EXPECT_FALSE(read_error_delegate_data_.invoked);
-
- segregated_store_->ReadPrefsAsync(GetReadErrorDelegate().release());
-
- EXPECT_FALSE(read_error_delegate_data_.invoked);
-
- selected_store_->SetBlockAsyncRead(false);
-
- EXPECT_TRUE(read_error_delegate_data_.invoked);
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
- segregated_store_->GetReadError());
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
- segregated_store_->GetReadError());
-}
-
-TEST_F(SegregatedPrefStoreTest, IsInitializationComplete) {
- EXPECT_FALSE(segregated_store_->IsInitializationComplete());
- segregated_store_->ReadPrefs();
- EXPECT_TRUE(segregated_store_->IsInitializationComplete());
-}
-
-TEST_F(SegregatedPrefStoreTest, IsInitializationCompleteAsync) {
- selected_store_->SetBlockAsyncRead(true);
- default_store_->SetBlockAsyncRead(true);
- EXPECT_FALSE(segregated_store_->IsInitializationComplete());
- segregated_store_->ReadPrefsAsync(NULL);
- EXPECT_FALSE(segregated_store_->IsInitializationComplete());
- selected_store_->SetBlockAsyncRead(false);
- EXPECT_FALSE(segregated_store_->IsInitializationComplete());
- default_store_->SetBlockAsyncRead(false);
- EXPECT_TRUE(segregated_store_->IsInitializationComplete());
-}
-
-TEST_F(SegregatedPrefStoreTest, GetValues) {
- // To check merge behavior, create selected and default stores so each has a
- // key the other doesn't have and they have one key in common.
- selected_store_->SetValue(kSelectedPref,
- base::MakeUnique<base::StringValue>(kValue1),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
- default_store_->SetValue(kUnselectedPref,
- base::MakeUnique<base::StringValue>(kValue2),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
- selected_store_->SetValue(kSharedPref,
- base::MakeUnique<base::StringValue>(kValue1),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
-
- auto values = segregated_store_->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));
-
- // Check that a a default preference is returned.
- ASSERT_TRUE(values->Get(kUnselectedPref, &value));
- EXPECT_TRUE(base::Value(kValue2).Equals(value));
-
- // Check that the selected preference is preferred.
- ASSERT_TRUE(values->Get(kSharedPref, &value));
- EXPECT_TRUE(base::Value(kValue1).Equals(value));
-}
diff --git a/chromium/components/user_prefs/tracked/tracked_atomic_preference.cc b/chromium/components/user_prefs/tracked/tracked_atomic_preference.cc
deleted file mode 100644
index e2b76784b81..00000000000
--- a/chromium/components/user_prefs/tracked/tracked_atomic_preference.cc
+++ /dev/null
@@ -1,91 +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/user_prefs/tracked/tracked_atomic_preference.h"
-
-#include "base/values.h"
-#include "components/user_prefs/tracked/pref_hash_store_transaction.h"
-#include "components/user_prefs/tracked/tracked_preference_validation_delegate.h"
-
-TrackedAtomicPreference::TrackedAtomicPreference(
- const std::string& pref_path,
- size_t reporting_id,
- size_t reporting_ids_count,
- PrefHashFilter::EnforcementLevel enforcement_level,
- PrefHashFilter::ValueType value_type,
- TrackedPreferenceValidationDelegate* delegate)
- : pref_path_(pref_path),
- helper_(pref_path,
- reporting_id,
- reporting_ids_count,
- enforcement_level,
- value_type),
- delegate_(delegate) {
-}
-
-TrackedPreferenceType TrackedAtomicPreference::GetType() const {
- return TrackedPreferenceType::ATOMIC;
-}
-
-void TrackedAtomicPreference::OnNewValue(
- const base::Value* value,
- PrefHashStoreTransaction* transaction) const {
- transaction->StoreHash(pref_path_, value);
-}
-
-bool TrackedAtomicPreference::EnforceAndReport(
- base::DictionaryValue* pref_store_contents,
- PrefHashStoreTransaction* transaction,
- PrefHashStoreTransaction* external_validation_transaction) const {
- const base::Value* value = NULL;
- pref_store_contents->Get(pref_path_, &value);
- PrefHashStoreTransaction::ValueState value_state =
- transaction->CheckValue(pref_path_, value);
- helper_.ReportValidationResult(value_state, transaction->GetStoreUMASuffix());
-
- PrefHashStoreTransaction::ValueState external_validation_value_state =
- PrefHashStoreTransaction::UNSUPPORTED;
- if (external_validation_transaction) {
- external_validation_value_state =
- external_validation_transaction->CheckValue(pref_path_, value);
- helper_.ReportValidationResult(
- external_validation_value_state,
- external_validation_transaction->GetStoreUMASuffix());
- }
-
- if (delegate_) {
- delegate_->OnAtomicPreferenceValidation(pref_path_, value, value_state,
- external_validation_value_state,
- helper_.IsPersonal());
- }
- TrackedPreferenceHelper::ResetAction reset_action =
- helper_.GetAction(value_state);
- helper_.ReportAction(reset_action);
-
- bool was_reset = false;
- if (reset_action == TrackedPreferenceHelper::DO_RESET) {
- pref_store_contents->RemovePath(pref_path_, NULL);
- was_reset = true;
- }
-
- if (value_state != PrefHashStoreTransaction::UNCHANGED) {
- // Store the hash for the new value (whether it was reset or not).
- const base::Value* new_value = NULL;
- pref_store_contents->Get(pref_path_, &new_value);
- transaction->StoreHash(pref_path_, new_value);
- }
-
- // Update MACs in the external store if there is one and there either was a
- // reset or external validation failed.
- if (external_validation_transaction &&
- (was_reset ||
- external_validation_value_state !=
- PrefHashStoreTransaction::UNCHANGED)) {
- const base::Value* new_value = nullptr;
- pref_store_contents->Get(pref_path_, &new_value);
- external_validation_transaction->StoreHash(pref_path_, new_value);
- }
-
- return was_reset;
-}
diff --git a/chromium/components/user_prefs/tracked/tracked_atomic_preference.h b/chromium/components/user_prefs/tracked/tracked_atomic_preference.h
deleted file mode 100644
index e279af85947..00000000000
--- a/chromium/components/user_prefs/tracked/tracked_atomic_preference.h
+++ /dev/null
@@ -1,49 +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_USER_PREFS_TRACKED_ATOMIC_PREFERENCE_H_
-#define COMPONENTS_USER_PREFS_TRACKED_ATOMIC_PREFERENCE_H_
-
-#include <stddef.h>
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "components/user_prefs/tracked/pref_hash_filter.h"
-#include "components/user_prefs/tracked/tracked_preference.h"
-#include "components/user_prefs/tracked/tracked_preference_helper.h"
-
-class TrackedPreferenceValidationDelegate;
-
-// A TrackedAtomicPreference is tracked as a whole. A hash is stored for its
-// entire value and it is entirely reset on mismatch. An optional delegate is
-// notified of the status of the preference during enforcement.
-class TrackedAtomicPreference : public TrackedPreference {
- public:
- TrackedAtomicPreference(const std::string& pref_path,
- size_t reporting_id,
- size_t reporting_ids_count,
- PrefHashFilter::EnforcementLevel enforcement_level,
- PrefHashFilter::ValueType value_type,
- TrackedPreferenceValidationDelegate* delegate);
-
- // TrackedPreference implementation.
- TrackedPreferenceType GetType() const override;
- void OnNewValue(const base::Value* value,
- PrefHashStoreTransaction* transaction) const override;
- bool EnforceAndReport(
- base::DictionaryValue* pref_store_contents,
- PrefHashStoreTransaction* transaction,
- PrefHashStoreTransaction* external_validation_transaction) const override;
-
- private:
- const std::string pref_path_;
- const TrackedPreferenceHelper helper_;
- TrackedPreferenceValidationDelegate* delegate_;
-
- DISALLOW_COPY_AND_ASSIGN(TrackedAtomicPreference);
-};
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_ATOMIC_PREFERENCE_H_
diff --git a/chromium/components/user_prefs/tracked/tracked_preference.h b/chromium/components/user_prefs/tracked/tracked_preference.h
deleted file mode 100644
index 97666a0fcf8..00000000000
--- a/chromium/components/user_prefs/tracked/tracked_preference.h
+++ /dev/null
@@ -1,44 +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_USER_PREFS_TRACKED_TRACKED_PREFERENCE_H_
-#define COMPONENTS_USER_PREFS_TRACKED_TRACKED_PREFERENCE_H_
-
-class PrefHashStoreTransaction;
-
-namespace base {
-class DictionaryValue;
-class Value;
-}
-
-enum class TrackedPreferenceType { ATOMIC, SPLIT };
-
-// A TrackedPreference tracks changes to an individual preference, reporting and
-// reacting to them according to preference-specific and browser-wide policies.
-class TrackedPreference {
- public:
- virtual ~TrackedPreference() {}
-
- virtual TrackedPreferenceType GetType() const = 0;
-
- // Notifies the underlying TrackedPreference about its new |value| which
- // can update hashes in the corresponding hash store via |transaction|.
- virtual void OnNewValue(const base::Value* value,
- PrefHashStoreTransaction* transaction) const = 0;
-
- // Verifies that the value of this TrackedPreference in |pref_store_contents|
- // is valid. Responds to verification failures according to
- // preference-specific and browser-wide policy and reports results to via UMA.
- // May use |transaction| to check/modify hashes in the corresponding hash
- // store. Performs validation and reports results without enforcing for
- // |external_validation_transaction|. This call assumes exclusive access to
- // |external_validation_transaction| and its associated state and as such
- // should only be called before any other subsystem is made aware of it.
- virtual bool EnforceAndReport(
- base::DictionaryValue* pref_store_contents,
- PrefHashStoreTransaction* transaction,
- PrefHashStoreTransaction* external_validation_transaction) const = 0;
-};
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_TRACKED_PREFERENCE_H_
diff --git a/chromium/components/user_prefs/tracked/tracked_preference_helper.cc b/chromium/components/user_prefs/tracked/tracked_preference_helper.cc
deleted file mode 100644
index fb36a2a1518..00000000000
--- a/chromium/components/user_prefs/tracked/tracked_preference_helper.cc
+++ /dev/null
@@ -1,135 +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/user_prefs/tracked/tracked_preference_helper.h"
-
-#include "base/logging.h"
-#include "base/metrics/histogram.h"
-#include "base/metrics/histogram_macros.h"
-#include "components/user_prefs/tracked/tracked_preference_histogram_names.h"
-
-TrackedPreferenceHelper::TrackedPreferenceHelper(
- const std::string& pref_path,
- size_t reporting_id,
- size_t reporting_ids_count,
- PrefHashFilter::EnforcementLevel enforcement_level,
- PrefHashFilter::ValueType value_type)
- : pref_path_(pref_path),
- reporting_id_(reporting_id),
- reporting_ids_count_(reporting_ids_count),
- enforce_(enforcement_level == PrefHashFilter::ENFORCE_ON_LOAD),
- personal_(value_type == PrefHashFilter::VALUE_PERSONAL) {
-}
-
-TrackedPreferenceHelper::ResetAction TrackedPreferenceHelper::GetAction(
- PrefHashStoreTransaction::ValueState value_state) const {
- switch (value_state) {
- case PrefHashStoreTransaction::UNCHANGED:
- // Desired case, nothing to do.
- return DONT_RESET;
- case PrefHashStoreTransaction::CLEARED:
- // Unfortunate case, but there is nothing we can do.
- return DONT_RESET;
- case PrefHashStoreTransaction::TRUSTED_NULL_VALUE: // Falls through.
- case PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE:
- // It is okay to seed the hash in this case.
- return DONT_RESET;
- case PrefHashStoreTransaction::SECURE_LEGACY:
- // Accept secure legacy device ID based hashes.
- return DONT_RESET;
- case PrefHashStoreTransaction::UNSUPPORTED:
- NOTREACHED()
- << "GetAction should not be called with an UNSUPPORTED value state";
- return DONT_RESET;
- case PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE: // Falls through.
- case PrefHashStoreTransaction::CHANGED:
- return enforce_ ? DO_RESET : WANTED_RESET;
- }
- NOTREACHED() << "Unexpected PrefHashStoreTransaction::ValueState: "
- << value_state;
- return DONT_RESET;
-}
-
-bool TrackedPreferenceHelper::IsPersonal() const {
- return personal_;
-}
-
-void TrackedPreferenceHelper::ReportValidationResult(
- PrefHashStoreTransaction::ValueState value_state,
- base::StringPiece validation_type_suffix) const {
- const char* histogram_name = nullptr;
- switch (value_state) {
- case PrefHashStoreTransaction::UNCHANGED:
- histogram_name = user_prefs::tracked::kTrackedPrefHistogramUnchanged;
- break;
- case PrefHashStoreTransaction::CLEARED:
- histogram_name = user_prefs::tracked::kTrackedPrefHistogramCleared;
- break;
- case PrefHashStoreTransaction::SECURE_LEGACY:
- histogram_name =
- user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId;
- break;
- case PrefHashStoreTransaction::CHANGED:
- histogram_name = user_prefs::tracked::kTrackedPrefHistogramChanged;
- break;
- case PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE:
- histogram_name = user_prefs::tracked::kTrackedPrefHistogramInitialized;
- break;
- case PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE:
- histogram_name =
- user_prefs::tracked::kTrackedPrefHistogramTrustedInitialized;
- break;
- case PrefHashStoreTransaction::TRUSTED_NULL_VALUE:
- histogram_name =
- user_prefs::tracked::kTrackedPrefHistogramNullInitialized;
- break;
- case PrefHashStoreTransaction::UNSUPPORTED:
- NOTREACHED() << "ReportValidationResult should not be called with an "
- "UNSUPPORTED value state";
- return;
- }
- DCHECK(histogram_name);
-
- std::string full_histogram_name(histogram_name);
- if (!validation_type_suffix.empty()) {
- full_histogram_name.push_back('.');
- validation_type_suffix.AppendToString(&full_histogram_name);
- }
-
- // Using FactoryGet to allow dynamic histogram names. This is equivalent to
- // UMA_HISTOGRAM_ENUMERATION(name, reporting_id_, reporting_ids_count_);
- base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
- full_histogram_name, 1, reporting_ids_count_, reporting_ids_count_ + 1,
- base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->Add(reporting_id_);
-}
-
-void TrackedPreferenceHelper::ReportAction(ResetAction reset_action) const {
- switch (reset_action) {
- case DONT_RESET:
- // No report for DONT_RESET.
- break;
- case WANTED_RESET:
- UMA_HISTOGRAM_ENUMERATION(
- user_prefs::tracked::kTrackedPrefHistogramWantedReset, reporting_id_,
- reporting_ids_count_);
- break;
- case DO_RESET:
- UMA_HISTOGRAM_ENUMERATION(user_prefs::tracked::kTrackedPrefHistogramReset,
- reporting_id_, reporting_ids_count_);
- break;
- }
-}
-
-void TrackedPreferenceHelper::ReportSplitPreferenceChangedCount(
- size_t count) const {
- // The histogram below is an expansion of the UMA_HISTOGRAM_COUNTS_100 macro
- // adapted to allow for a dynamically suffixed histogram name.
- // Note: The factory creates and owns the histogram.
- base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
- user_prefs::tracked::kTrackedSplitPrefHistogramChanged + pref_path_, 1,
- 100, // Allow counts up to 100.
- 101, base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->Add(count);
-}
diff --git a/chromium/components/user_prefs/tracked/tracked_preference_helper.h b/chromium/components/user_prefs/tracked/tracked_preference_helper.h
deleted file mode 100644
index 57b35fb32a3..00000000000
--- a/chromium/components/user_prefs/tracked/tracked_preference_helper.h
+++ /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.
-
-#ifndef COMPONENTS_USER_PREFS_TRACKED_TRACKED_PREFERENCE_HELPER_H_
-#define COMPONENTS_USER_PREFS_TRACKED_TRACKED_PREFERENCE_HELPER_H_
-
-#include <stddef.h>
-
-#include <string>
-
-#include "base/macros.h"
-#include "components/user_prefs/tracked/pref_hash_filter.h"
-#include "components/user_prefs/tracked/pref_hash_store_transaction.h"
-
-// A TrackedPreferenceHelper is a helper class for TrackedPreference which
-// handles decision making and reporting for TrackedPreference's
-// implementations.
-class TrackedPreferenceHelper {
- public:
- enum ResetAction {
- DONT_RESET,
- // WANTED_RESET is reported when DO_RESET would have been reported but the
- // current |enforcement_level| doesn't allow a reset for the detected state.
- WANTED_RESET,
- DO_RESET,
- };
-
- TrackedPreferenceHelper(const std::string& pref_path,
- size_t reporting_id,
- size_t reporting_ids_count,
- PrefHashFilter::EnforcementLevel enforcement_level,
- PrefHashFilter::ValueType value_type);
-
- // Returns a ResetAction stating whether a reset is desired (DO_RESET) or not
- // (DONT_RESET) based on observing |value_state|. Can also return WANTED_RESET
- // if a reset would have been desired but the current |enforcement_level|
- // doesn't allow it.
- ResetAction GetAction(PrefHashStoreTransaction::ValueState value_state) const;
-
- // Returns true if the preference value may contain personal information.
- bool IsPersonal() const;
-
- // Reports |value_state| via UMA under |reporting_id_|.
- // |validation_type_suffix| is appended to the reported histogram's name.
- void ReportValidationResult(PrefHashStoreTransaction::ValueState value_state,
- base::StringPiece validation_type_suffix) const;
-
- // Reports |reset_action| via UMA under |reporting_id_|.
- void ReportAction(ResetAction reset_action) const;
-
- // Reports, via UMA, the |count| of split preference entries that were
- // considered invalid in a CHANGED event.
- void ReportSplitPreferenceChangedCount(size_t count) const;
-
- private:
- const std::string pref_path_;
-
- const size_t reporting_id_;
- const size_t reporting_ids_count_;
-
- // Deny setting changes and hash seeding/migration.
- const bool enforce_;
-
- const bool personal_;
-
- DISALLOW_COPY_AND_ASSIGN(TrackedPreferenceHelper);
-};
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_TRACKED_PREFERENCE_HELPER_H_
diff --git a/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.cc b/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.cc
deleted file mode 100644
index 431bb9a31cf..00000000000
--- a/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.cc
+++ /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.
-
-#include "components/user_prefs/tracked/tracked_preference_histogram_names.h"
-
-namespace user_prefs {
-namespace tracked {
-
-// Tracked pref histogram names.
-const char kTrackedPrefHistogramUnchanged[] =
- "Settings.TrackedPreferenceUnchanged";
-const char kTrackedPrefHistogramCleared[] = "Settings.TrackedPreferenceCleared";
-const char kTrackedPrefHistogramMigratedLegacyDeviceId[] =
- "Settings.TrackedPreferenceMigratedLegacyDeviceId";
-const char kTrackedPrefHistogramChanged[] = "Settings.TrackedPreferenceChanged";
-const char kTrackedPrefHistogramInitialized[] =
- "Settings.TrackedPreferenceInitialized";
-const char kTrackedPrefHistogramTrustedInitialized[] =
- "Settings.TrackedPreferenceTrustedInitialized";
-const char kTrackedPrefHistogramNullInitialized[] =
- "Settings.TrackedPreferenceNullInitialized";
-const char kTrackedPrefHistogramWantedReset[] =
- "Settings.TrackedPreferenceWantedReset";
-const char kTrackedPrefHistogramReset[] = "Settings.TrackedPreferenceReset";
-const char kTrackedSplitPrefHistogramChanged[] =
- "Settings.TrackedSplitPreferenceChanged.";
-const char kTrackedPrefRegistryValidationSuffix[] = "FromRegistry";
-
-} // namespace tracked
-} // namespace user_prefs
diff --git a/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.h b/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.h
deleted file mode 100644
index 31b9ce30448..00000000000
--- a/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.h
+++ /dev/null
@@ -1,26 +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_USER_PREFS_TRACKED_TRACKED_PREFERENCE_HISTOGRAM_NAMES_H_
-#define COMPONENTS_USER_PREFS_TRACKED_TRACKED_PREFERENCE_HISTOGRAM_NAMES_H_
-
-namespace user_prefs {
-namespace tracked {
-
-extern const char kTrackedPrefHistogramUnchanged[];
-extern const char kTrackedPrefHistogramCleared[];
-extern const char kTrackedPrefHistogramMigratedLegacyDeviceId[];
-extern const char kTrackedPrefHistogramChanged[];
-extern const char kTrackedPrefHistogramInitialized[];
-extern const char kTrackedPrefHistogramTrustedInitialized[];
-extern const char kTrackedPrefHistogramNullInitialized[];
-extern const char kTrackedPrefHistogramWantedReset[];
-extern const char kTrackedPrefHistogramReset[];
-extern const char kTrackedSplitPrefHistogramChanged[];
-extern const char kTrackedPrefRegistryValidationSuffix[];
-
-} // namespace tracked
-} // namespace user_prefs
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_TRACKED_PREFERENCE_HISTOGRAM_NAMES_H_
diff --git a/chromium/components/user_prefs/tracked/tracked_preference_validation_delegate.h b/chromium/components/user_prefs/tracked/tracked_preference_validation_delegate.h
deleted file mode 100644
index d010df5aee3..00000000000
--- a/chromium/components/user_prefs/tracked/tracked_preference_validation_delegate.h
+++ /dev/null
@@ -1,47 +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_USER_PREFS_TRACKED_TRACKED_PREFERENCE_VALIDATION_DELEGATE_H_
-#define COMPONENTS_USER_PREFS_TRACKED_TRACKED_PREFERENCE_VALIDATION_DELEGATE_H_
-
-#include <string>
-#include <vector>
-
-#include "components/user_prefs/tracked/pref_hash_store_transaction.h"
-
-namespace base {
-class DictionaryValue;
-class Value;
-}
-
-// A TrackedPreferenceValidationDelegate is notified of the results of each
-// tracked preference validation event.
-class TrackedPreferenceValidationDelegate {
- public:
- virtual ~TrackedPreferenceValidationDelegate() {}
-
- // Notifies observes of the result (|value_state|) of checking the atomic
- // |value| (which may be NULL) at |pref_path|. |is_personal| indicates whether
- // or not the value may contain personal information.
- virtual void OnAtomicPreferenceValidation(
- const std::string& pref_path,
- const base::Value* value,
- PrefHashStoreTransaction::ValueState value_state,
- PrefHashStoreTransaction::ValueState external_validation_value_state,
- bool is_personal) = 0;
-
- // Notifies observes of the result (|value_state|) of checking the split
- // |dict_value| (which may be NULL) at |pref_path|. |is_personal| indicates
- // whether or not the value may contain personal information.
- virtual void OnSplitPreferenceValidation(
- const std::string& pref_path,
- const base::DictionaryValue* dict_value,
- const std::vector<std::string>& invalid_keys,
- const std::vector<std::string>& external_validation_invalid_keys,
- PrefHashStoreTransaction::ValueState value_state,
- PrefHashStoreTransaction::ValueState external_validation_value_state,
- bool is_personal) = 0;
-};
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_TRACKED_PREFERENCE_VALIDATION_DELEGATE_H_
diff --git a/chromium/components/user_prefs/tracked/tracked_preferences_migration.cc b/chromium/components/user_prefs/tracked/tracked_preferences_migration.cc
deleted file mode 100644
index 50299141ed5..00000000000
--- a/chromium/components/user_prefs/tracked/tracked_preferences_migration.cc
+++ /dev/null
@@ -1,342 +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/user_prefs/tracked/tracked_preferences_migration.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/metrics/histogram.h"
-#include "base/values.h"
-#include "components/user_prefs/tracked/dictionary_hash_store_contents.h"
-#include "components/user_prefs/tracked/hash_store_contents.h"
-#include "components/user_prefs/tracked/interceptable_pref_filter.h"
-#include "components/user_prefs/tracked/pref_hash_store.h"
-#include "components/user_prefs/tracked/pref_hash_store_transaction.h"
-
-namespace {
-
-class TrackedPreferencesMigrator
- : public base::RefCounted<TrackedPreferencesMigrator> {
- public:
- TrackedPreferencesMigrator(
- const std::set<std::string>& unprotected_pref_names,
- const std::set<std::string>& protected_pref_names,
- const base::Callback<void(const std::string& key)>&
- unprotected_store_cleaner,
- const base::Callback<void(const std::string& key)>&
- protected_store_cleaner,
- const base::Callback<void(const base::Closure&)>&
- register_on_successful_unprotected_store_write_callback,
- const base::Callback<void(const base::Closure&)>&
- register_on_successful_protected_store_write_callback,
- std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
- std::unique_ptr<PrefHashStore> protected_pref_hash_store,
- InterceptablePrefFilter* unprotected_pref_filter,
- InterceptablePrefFilter* protected_pref_filter);
-
- private:
- friend class base::RefCounted<TrackedPreferencesMigrator>;
-
- enum PrefFilterID {
- UNPROTECTED_PREF_FILTER,
- PROTECTED_PREF_FILTER
- };
-
- ~TrackedPreferencesMigrator();
-
- // Stores the data coming in from the filter identified by |id| into this
- // class and then calls MigrateIfReady();
- void InterceptFilterOnLoad(
- PrefFilterID id,
- const InterceptablePrefFilter::FinalizeFilterOnLoadCallback&
- finalize_filter_on_load,
- std::unique_ptr<base::DictionaryValue> prefs);
-
- // Proceeds with migration if both |unprotected_prefs_| and |protected_prefs_|
- // have been set.
- void MigrateIfReady();
-
- const std::set<std::string> unprotected_pref_names_;
- const std::set<std::string> protected_pref_names_;
-
- const base::Callback<void(const std::string& key)> unprotected_store_cleaner_;
- const base::Callback<void(const std::string& key)> protected_store_cleaner_;
- const base::Callback<void(const base::Closure&)>
- register_on_successful_unprotected_store_write_callback_;
- const base::Callback<void(const base::Closure&)>
- register_on_successful_protected_store_write_callback_;
-
- InterceptablePrefFilter::FinalizeFilterOnLoadCallback
- finalize_unprotected_filter_on_load_;
- InterceptablePrefFilter::FinalizeFilterOnLoadCallback
- finalize_protected_filter_on_load_;
-
- std::unique_ptr<PrefHashStore> unprotected_pref_hash_store_;
- std::unique_ptr<PrefHashStore> protected_pref_hash_store_;
-
- std::unique_ptr<base::DictionaryValue> unprotected_prefs_;
- std::unique_ptr<base::DictionaryValue> protected_prefs_;
-
- DISALLOW_COPY_AND_ASSIGN(TrackedPreferencesMigrator);
-};
-
-// Invokes |store_cleaner| for every |keys_to_clean|.
-void CleanupPrefStore(
- const base::Callback<void(const std::string& key)>& store_cleaner,
- const std::set<std::string>& keys_to_clean) {
- for (std::set<std::string>::const_iterator it = keys_to_clean.begin();
- it != keys_to_clean.end(); ++it) {
- store_cleaner.Run(*it);
- }
-}
-
-// If |wait_for_commit_to_destination_store|: schedules (via
-// |register_on_successful_destination_store_write_callback|) a cleanup of the
-// |keys_to_clean| from the source pref store (through |source_store_cleaner|)
-// once the destination pref store they were migrated to was successfully
-// written to disk. Otherwise, executes the cleanup right away.
-void ScheduleSourcePrefStoreCleanup(
- const base::Callback<void(const base::Closure&)>&
- register_on_successful_destination_store_write_callback,
- const base::Callback<void(const std::string& key)>& source_store_cleaner,
- const std::set<std::string>& keys_to_clean,
- bool wait_for_commit_to_destination_store) {
- DCHECK(!keys_to_clean.empty());
- if (wait_for_commit_to_destination_store) {
- register_on_successful_destination_store_write_callback.Run(
- base::Bind(&CleanupPrefStore, source_store_cleaner, keys_to_clean));
- } else {
- CleanupPrefStore(source_store_cleaner, keys_to_clean);
- }
-}
-
-// Removes hashes for |migrated_pref_names| from |origin_pref_store| using
-// the configuration/implementation in |origin_pref_hash_store|.
-void CleanupMigratedHashes(const std::set<std::string>& migrated_pref_names,
- PrefHashStore* origin_pref_hash_store,
- base::DictionaryValue* origin_pref_store) {
- DictionaryHashStoreContents dictionary_contents(origin_pref_store);
- std::unique_ptr<PrefHashStoreTransaction> transaction(
- origin_pref_hash_store->BeginTransaction(&dictionary_contents));
- for (std::set<std::string>::const_iterator it = migrated_pref_names.begin();
- it != migrated_pref_names.end();
- ++it) {
- transaction->ClearHash(*it);
- }
-}
-
-// Copies the value of each pref in |pref_names| which is set in |old_store|,
-// but not in |new_store| into |new_store|. Sets |old_store_needs_cleanup| to
-// true if any old duplicates remain in |old_store| and sets |new_store_altered|
-// to true if any value was copied to |new_store|.
-void MigratePrefsFromOldToNewStore(const std::set<std::string>& pref_names,
- base::DictionaryValue* old_store,
- base::DictionaryValue* new_store,
- PrefHashStore* new_hash_store,
- bool* old_store_needs_cleanup,
- bool* new_store_altered) {
- const base::DictionaryValue* old_hash_store_contents =
- DictionaryHashStoreContents(old_store).GetContents();
- DictionaryHashStoreContents dictionary_contents(new_store);
- std::unique_ptr<PrefHashStoreTransaction> new_hash_store_transaction(
- new_hash_store->BeginTransaction(&dictionary_contents));
-
- for (std::set<std::string>::const_iterator it = pref_names.begin();
- it != pref_names.end();
- ++it) {
- const std::string& pref_name = *it;
- const base::Value* value_in_old_store = NULL;
-
- // If the destination does not have a hash for this pref we will
- // unconditionally attempt to move it.
- bool destination_hash_missing =
- !new_hash_store_transaction->HasHash(pref_name);
- // If we migrate the value we will also attempt to migrate the hash.
- bool migrated_value = false;
- if (old_store->Get(pref_name, &value_in_old_store)) {
- // Whether this value ends up being copied below or was left behind by a
- // previous incomplete migration, it should be cleaned up.
- *old_store_needs_cleanup = true;
-
- if (!new_store->Get(pref_name, NULL)) {
- // Copy the value from |old_store| to |new_store| rather than moving it
- // to avoid data loss should |old_store| be flushed to disk without
- // |new_store| having equivalently been successfully flushed to disk
- // (e.g., on crash or in cases where |new_store| is read-only following
- // a read error on startup).
- new_store->Set(pref_name, value_in_old_store->DeepCopy());
- migrated_value = true;
- *new_store_altered = true;
- }
- }
-
- if (destination_hash_missing || migrated_value) {
- const base::Value* old_hash = NULL;
- if (old_hash_store_contents)
- old_hash_store_contents->Get(pref_name, &old_hash);
- if (old_hash) {
- new_hash_store_transaction->ImportHash(pref_name, old_hash);
- *new_store_altered = true;
- } else if (!destination_hash_missing) {
- // Do not allow values to be migrated without MACs if the destination
- // already has a MAC (http://crbug.com/414554). Remove the migrated
- // value in order to provide the same no-op behaviour as if the pref was
- // added to the wrong file when there was already a value for
- // |pref_name| in |new_store|.
- new_store->Remove(pref_name, NULL);
- *new_store_altered = true;
- }
- }
- }
-}
-
-TrackedPreferencesMigrator::TrackedPreferencesMigrator(
- const std::set<std::string>& unprotected_pref_names,
- const std::set<std::string>& protected_pref_names,
- const base::Callback<void(const std::string& key)>&
- unprotected_store_cleaner,
- const base::Callback<void(const std::string& key)>& protected_store_cleaner,
- const base::Callback<void(const base::Closure&)>&
- register_on_successful_unprotected_store_write_callback,
- const base::Callback<void(const base::Closure&)>&
- register_on_successful_protected_store_write_callback,
- std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
- std::unique_ptr<PrefHashStore> protected_pref_hash_store,
- InterceptablePrefFilter* unprotected_pref_filter,
- InterceptablePrefFilter* protected_pref_filter)
- : unprotected_pref_names_(unprotected_pref_names),
- protected_pref_names_(protected_pref_names),
- unprotected_store_cleaner_(unprotected_store_cleaner),
- protected_store_cleaner_(protected_store_cleaner),
- register_on_successful_unprotected_store_write_callback_(
- register_on_successful_unprotected_store_write_callback),
- register_on_successful_protected_store_write_callback_(
- register_on_successful_protected_store_write_callback),
- unprotected_pref_hash_store_(std::move(unprotected_pref_hash_store)),
- protected_pref_hash_store_(std::move(protected_pref_hash_store)) {
- // The callbacks bound below will own this TrackedPreferencesMigrator by
- // reference.
- unprotected_pref_filter->InterceptNextFilterOnLoad(
- base::Bind(&TrackedPreferencesMigrator::InterceptFilterOnLoad,
- this,
- UNPROTECTED_PREF_FILTER));
- protected_pref_filter->InterceptNextFilterOnLoad(
- base::Bind(&TrackedPreferencesMigrator::InterceptFilterOnLoad,
- this,
- PROTECTED_PREF_FILTER));
-}
-
-TrackedPreferencesMigrator::~TrackedPreferencesMigrator() {}
-
-void TrackedPreferencesMigrator::InterceptFilterOnLoad(
- PrefFilterID id,
- const InterceptablePrefFilter::FinalizeFilterOnLoadCallback&
- finalize_filter_on_load,
- std::unique_ptr<base::DictionaryValue> prefs) {
- switch (id) {
- case UNPROTECTED_PREF_FILTER:
- finalize_unprotected_filter_on_load_ = finalize_filter_on_load;
- unprotected_prefs_ = std::move(prefs);
- break;
- case PROTECTED_PREF_FILTER:
- finalize_protected_filter_on_load_ = finalize_filter_on_load;
- protected_prefs_ = std::move(prefs);
- break;
- }
-
- MigrateIfReady();
-}
-
-void TrackedPreferencesMigrator::MigrateIfReady() {
- // Wait for both stores to have been read before proceeding.
- if (!protected_prefs_ || !unprotected_prefs_)
- return;
-
- bool protected_prefs_need_cleanup = false;
- bool unprotected_prefs_altered = false;
- MigratePrefsFromOldToNewStore(
- unprotected_pref_names_, protected_prefs_.get(), unprotected_prefs_.get(),
- unprotected_pref_hash_store_.get(), &protected_prefs_need_cleanup,
- &unprotected_prefs_altered);
- bool unprotected_prefs_need_cleanup = false;
- bool protected_prefs_altered = false;
- MigratePrefsFromOldToNewStore(
- protected_pref_names_, unprotected_prefs_.get(), protected_prefs_.get(),
- protected_pref_hash_store_.get(), &unprotected_prefs_need_cleanup,
- &protected_prefs_altered);
-
- if (!unprotected_prefs_altered && !protected_prefs_altered) {
- // Clean up any MACs that might have been previously migrated from the
- // various stores. It's safe to leave them behind for a little while as they
- // will be ignored unless the corresponding value is _also_ present. The
- // cleanup must be deferred until the MACs have been written to their target
- // stores, and doing so in a subsequent launch is easier than within the
- // same process.
- CleanupMigratedHashes(unprotected_pref_names_,
- protected_pref_hash_store_.get(),
- protected_prefs_.get());
- CleanupMigratedHashes(protected_pref_names_,
- unprotected_pref_hash_store_.get(),
- unprotected_prefs_.get());
- }
-
- // Hand the processed prefs back to their respective filters.
- finalize_unprotected_filter_on_load_.Run(std::move(unprotected_prefs_),
- unprotected_prefs_altered);
- finalize_protected_filter_on_load_.Run(std::move(protected_prefs_),
- protected_prefs_altered);
-
- if (unprotected_prefs_need_cleanup) {
- // Schedule a cleanup of the |protected_pref_names_| from the unprotected
- // prefs once the protected prefs were successfully written to disk (or
- // do it immediately if |!protected_prefs_altered|).
- ScheduleSourcePrefStoreCleanup(
- register_on_successful_protected_store_write_callback_,
- unprotected_store_cleaner_,
- protected_pref_names_,
- protected_prefs_altered);
- }
-
- if (protected_prefs_need_cleanup) {
- // Schedule a cleanup of the |unprotected_pref_names_| from the protected
- // prefs once the unprotected prefs were successfully written to disk (or
- // do it immediately if |!unprotected_prefs_altered|).
- ScheduleSourcePrefStoreCleanup(
- register_on_successful_unprotected_store_write_callback_,
- protected_store_cleaner_,
- unprotected_pref_names_,
- unprotected_prefs_altered);
- }
-}
-
-} // namespace
-
-void SetupTrackedPreferencesMigration(
- const std::set<std::string>& unprotected_pref_names,
- const std::set<std::string>& protected_pref_names,
- const base::Callback<void(const std::string& key)>&
- unprotected_store_cleaner,
- const base::Callback<void(const std::string& key)>& protected_store_cleaner,
- const base::Callback<void(const base::Closure&)>&
- register_on_successful_unprotected_store_write_callback,
- const base::Callback<void(const base::Closure&)>&
- register_on_successful_protected_store_write_callback,
- std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
- std::unique_ptr<PrefHashStore> protected_pref_hash_store,
- InterceptablePrefFilter* unprotected_pref_filter,
- InterceptablePrefFilter* protected_pref_filter) {
- scoped_refptr<TrackedPreferencesMigrator> prefs_migrator(
- new TrackedPreferencesMigrator(
- unprotected_pref_names, protected_pref_names,
- unprotected_store_cleaner, protected_store_cleaner,
- register_on_successful_unprotected_store_write_callback,
- register_on_successful_protected_store_write_callback,
- std::move(unprotected_pref_hash_store),
- std::move(protected_pref_hash_store), unprotected_pref_filter,
- protected_pref_filter));
-}
diff --git a/chromium/components/user_prefs/tracked/tracked_preferences_migration.h b/chromium/components/user_prefs/tracked/tracked_preferences_migration.h
deleted file mode 100644
index 290e5fbdb65..00000000000
--- a/chromium/components/user_prefs/tracked/tracked_preferences_migration.h
+++ /dev/null
@@ -1,45 +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_USER_PREFS_TRACKED_TRACKED_PREFERENCES_MIGRATION_H_
-#define COMPONENTS_USER_PREFS_TRACKED_TRACKED_PREFERENCES_MIGRATION_H_
-
-#include <memory>
-#include <set>
-#include <string>
-
-#include "base/callback_forward.h"
-#include "components/user_prefs/tracked/pref_hash_store.h"
-
-class InterceptablePrefFilter;
-class PrefHashStore;
-
-// Sets up InterceptablePrefFilter::FilterOnLoadInterceptors on
-// |unprotected_pref_filter| and |protected_pref_filter| which prevents each
-// filter from running their on load operations until the interceptors decide to
-// hand the prefs back to them (after migration is complete). |
-// (un)protected_store_cleaner| and
-// |register_on_successful_(un)protected_store_write_callback| are used to do
-// post-migration cleanup tasks. Those should be bound to weak pointers to avoid
-// blocking shutdown. |(un)protected_pref_hash_store| is used to migrate MACs
-// along with their protected preferences. Migrated MACs will only be cleared
-// from their old location in a subsequent run. The migration framework is
-// resilient to a failed cleanup (it will simply try again in the next Chrome
-// run).
-void SetupTrackedPreferencesMigration(
- const std::set<std::string>& unprotected_pref_names,
- const std::set<std::string>& protected_pref_names,
- const base::Callback<void(const std::string& key)>&
- unprotected_store_cleaner,
- const base::Callback<void(const std::string& key)>& protected_store_cleaner,
- const base::Callback<void(const base::Closure&)>&
- register_on_successful_unprotected_store_write_callback,
- const base::Callback<void(const base::Closure&)>&
- register_on_successful_protected_store_write_callback,
- std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
- std::unique_ptr<PrefHashStore> protected_pref_hash_store,
- InterceptablePrefFilter* unprotected_pref_filter,
- InterceptablePrefFilter* protected_pref_filter);
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_TRACKED_PREFERENCES_MIGRATION_H_
diff --git a/chromium/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc b/chromium/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc
deleted file mode 100644
index b1137543d3c..00000000000
--- a/chromium/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc
+++ /dev/null
@@ -1,655 +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/user_prefs/tracked/tracked_preferences_migration.h"
-
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/strings/string_split.h"
-#include "base/values.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/user_prefs/tracked/dictionary_hash_store_contents.h"
-#include "components/user_prefs/tracked/hash_store_contents.h"
-#include "components/user_prefs/tracked/interceptable_pref_filter.h"
-#include "components/user_prefs/tracked/pref_hash_store.h"
-#include "components/user_prefs/tracked/pref_hash_store_impl.h"
-#include "components/user_prefs/tracked/pref_hash_store_transaction.h"
-#include "components/user_prefs/tracked/tracked_preferences_migration.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-// An unprotected pref.
-const char kUnprotectedPref[] = "unprotected";
-// A protected pref.
-const char kProtectedPref[] = "protected";
-// A protected pref which is initially stored in the unprotected store.
-const char kPreviouslyUnprotectedPref[] = "previously.unprotected";
-// An unprotected pref which is initially stored in the protected store.
-const char kPreviouslyProtectedPref[] = "previously.protected";
-
-const char kUnprotectedPrefValue[] = "unprotected_value";
-const char kProtectedPrefValue[] = "protected_value";
-const char kPreviouslyUnprotectedPrefValue[] = "previously_unprotected_value";
-const char kPreviouslyProtectedPrefValue[] = "previously_protected_value";
-
-// A simple InterceptablePrefFilter which doesn't do anything but hand the prefs
-// back downstream in FinalizeFilterOnLoad.
-class SimpleInterceptablePrefFilter : public InterceptablePrefFilter {
- public:
- // PrefFilter remaining implementation.
- void FilterUpdate(const std::string& path) override { ADD_FAILURE(); }
- OnWriteCallbackPair FilterSerializeData(
- base::DictionaryValue* pref_store_contents) override {
- ADD_FAILURE();
- return std::make_pair(base::Closure(),
- base::Callback<void(bool success)>());
- }
-
- private:
- // InterceptablePrefFilter implementation.
- void FinalizeFilterOnLoad(
- const PostFilterOnLoadCallback& post_filter_on_load_callback,
- std::unique_ptr<base::DictionaryValue> pref_store_contents,
- bool prefs_altered) override {
- post_filter_on_load_callback.Run(std::move(pref_store_contents),
- prefs_altered);
- }
-};
-
-// A test fixture designed to be used like this:
-// 1) Set up initial store prefs with PresetStoreValue().
-// 2) Hand both sets of prefs to the migrator via HandPrefsToMigrator().
-// 3) Migration completes synchronously when the second store hands its prefs
-// over.
-// 4) Verifications can be made via various methods of this fixture.
-// Call Reset() to perform a second migration.
-class TrackedPreferencesMigrationTest : public testing::Test {
- public:
- enum MockPrefStoreID {
- MOCK_UNPROTECTED_PREF_STORE,
- MOCK_PROTECTED_PREF_STORE,
- };
-
- TrackedPreferencesMigrationTest()
- : unprotected_prefs_(new base::DictionaryValue),
- protected_prefs_(new base::DictionaryValue),
- migration_modified_unprotected_store_(false),
- migration_modified_protected_store_(false),
- unprotected_store_migration_complete_(false),
- protected_store_migration_complete_(false) {}
-
- void SetUp() override {
- Reset();
- }
-
- void Reset() {
- std::set<std::string> unprotected_pref_names;
- std::set<std::string> protected_pref_names;
- unprotected_pref_names.insert(kUnprotectedPref);
- unprotected_pref_names.insert(kPreviouslyProtectedPref);
- protected_pref_names.insert(kProtectedPref);
- protected_pref_names.insert(kPreviouslyUnprotectedPref);
-
- migration_modified_unprotected_store_ = false;
- migration_modified_protected_store_ = false;
- unprotected_store_migration_complete_ = false;
- protected_store_migration_complete_ = false;
-
- unprotected_store_successful_write_callback_.Reset();
- protected_store_successful_write_callback_.Reset();
-
- SetupTrackedPreferencesMigration(
- unprotected_pref_names, protected_pref_names,
- base::Bind(&TrackedPreferencesMigrationTest::RemovePathFromStore,
- base::Unretained(this), MOCK_UNPROTECTED_PREF_STORE),
- base::Bind(&TrackedPreferencesMigrationTest::RemovePathFromStore,
- base::Unretained(this), MOCK_PROTECTED_PREF_STORE),
- base::Bind(
- &TrackedPreferencesMigrationTest::RegisterSuccessfulWriteClosure,
- base::Unretained(this), MOCK_UNPROTECTED_PREF_STORE),
- base::Bind(
- &TrackedPreferencesMigrationTest::RegisterSuccessfulWriteClosure,
- base::Unretained(this), MOCK_PROTECTED_PREF_STORE),
- std::unique_ptr<PrefHashStore>(
- new PrefHashStoreImpl(kSeed, kDeviceId, false)),
- std::unique_ptr<PrefHashStore>(
- new PrefHashStoreImpl(kSeed, kDeviceId, true)),
- &mock_unprotected_pref_filter_, &mock_protected_pref_filter_);
-
- // Verify initial expectations are met.
- EXPECT_TRUE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
- EXPECT_FALSE(
- WasOnSuccessfulWriteCallbackRegistered(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_FALSE(
- WasOnSuccessfulWriteCallbackRegistered(MOCK_PROTECTED_PREF_STORE));
- }
-
- protected:
- // Sets |key| to |value| in the test store identified by |store_id| before
- // migration begins. Also sets the corresponding hash in the same store.
- void PresetStoreValue(MockPrefStoreID store_id,
- const std::string& key,
- const std::string value) {
- PresetStoreValueOnly(store_id, key, value);
- PresetStoreValueHash(store_id, key, value);
- }
-
- // Stores a hash for |key| and |value| in the hash store identified by
- // |store_id| before migration begins.
- void PresetStoreValueHash(MockPrefStoreID store_id,
- const std::string& key,
- const std::string value) {
- base::DictionaryValue* store = NULL;
- std::unique_ptr<PrefHashStore> pref_hash_store;
- switch (store_id) {
- case MOCK_UNPROTECTED_PREF_STORE:
- store = unprotected_prefs_.get();
- pref_hash_store.reset(new PrefHashStoreImpl(kSeed, kDeviceId, false));
- break;
- case MOCK_PROTECTED_PREF_STORE:
- store = protected_prefs_.get();
- pref_hash_store.reset(new PrefHashStoreImpl(kSeed, kDeviceId, true));
- break;
- }
- DCHECK(store);
-
- base::StringValue string_value(value);
- DictionaryHashStoreContents contents(store);
- pref_hash_store->BeginTransaction(&contents)->StoreHash(key, &string_value);
- }
-
- // Returns true if the store opposite to |store_id| is observed for its next
- // successful write.
- bool WasOnSuccessfulWriteCallbackRegistered(MockPrefStoreID store_id) {
- switch (store_id) {
- case MOCK_UNPROTECTED_PREF_STORE:
- return !protected_store_successful_write_callback_.is_null();
- case MOCK_PROTECTED_PREF_STORE:
- return !unprotected_store_successful_write_callback_.is_null();
- }
- NOTREACHED();
- return false;
- }
-
- // Verifies that the (key, value) pairs in |expected_prefs_in_store| are found
- // in the store identified by |store_id|.
- void VerifyValuesStored(
- MockPrefStoreID store_id,
- const base::StringPairs& expected_prefs_in_store) {
- base::DictionaryValue* store = NULL;
- switch (store_id) {
- case MOCK_UNPROTECTED_PREF_STORE:
- store = unprotected_prefs_.get();
- break;
- case MOCK_PROTECTED_PREF_STORE:
- store = protected_prefs_.get();
- break;
- }
- DCHECK(store);
-
- for (base::StringPairs::const_iterator it = expected_prefs_in_store.begin();
- it != expected_prefs_in_store.end(); ++it) {
- std::string val;
- EXPECT_TRUE(store->GetString(it->first, &val));
- EXPECT_EQ(it->second, val);
- }
- }
-
- // Determines whether |expected_pref_in_hash_store| has a hash in the hash
- // store identified by |store_id|.
- bool ContainsHash(MockPrefStoreID store_id,
- std::string expected_pref_in_hash_store) {
- base::DictionaryValue* store = NULL;
- switch (store_id) {
- case MOCK_UNPROTECTED_PREF_STORE:
- store = unprotected_prefs_.get();
- break;
- case MOCK_PROTECTED_PREF_STORE:
- store = protected_prefs_.get();
- break;
- }
- DCHECK(store);
- const base::DictionaryValue* hash_store_contents =
- DictionaryHashStoreContents(store).GetContents();
- return hash_store_contents &&
- hash_store_contents->GetString(expected_pref_in_hash_store,
- static_cast<std::string*>(NULL));
- }
-
- // Both stores need to hand their prefs over in order for migration to kick
- // in.
- void HandPrefsToMigrator(MockPrefStoreID store_id) {
- switch (store_id) {
- case MOCK_UNPROTECTED_PREF_STORE:
- mock_unprotected_pref_filter_.FilterOnLoad(
- base::Bind(&TrackedPreferencesMigrationTest::GetPrefsBack,
- base::Unretained(this), MOCK_UNPROTECTED_PREF_STORE),
- std::move(unprotected_prefs_));
- break;
- case MOCK_PROTECTED_PREF_STORE:
- mock_protected_pref_filter_.FilterOnLoad(
- base::Bind(&TrackedPreferencesMigrationTest::GetPrefsBack,
- base::Unretained(this), MOCK_PROTECTED_PREF_STORE),
- std::move(protected_prefs_));
- break;
- }
- }
-
- bool HasPrefs(MockPrefStoreID store_id) {
- switch (store_id) {
- case MOCK_UNPROTECTED_PREF_STORE:
- return !!unprotected_prefs_;
- case MOCK_PROTECTED_PREF_STORE:
- return !!protected_prefs_;
- }
- NOTREACHED();
- return false;
- }
-
- bool StoreModifiedByMigration(MockPrefStoreID store_id) {
- switch (store_id) {
- case MOCK_UNPROTECTED_PREF_STORE:
- return migration_modified_unprotected_store_;
- case MOCK_PROTECTED_PREF_STORE:
- return migration_modified_protected_store_;
- }
- NOTREACHED();
- return false;
- }
-
- bool MigrationCompleted() {
- return unprotected_store_migration_complete_ &&
- protected_store_migration_complete_;
- }
-
- void SimulateSuccessfulWrite(MockPrefStoreID store_id) {
- switch (store_id) {
- case MOCK_UNPROTECTED_PREF_STORE:
- EXPECT_FALSE(unprotected_store_successful_write_callback_.is_null());
- unprotected_store_successful_write_callback_.Run();
- unprotected_store_successful_write_callback_.Reset();
- break;
- case MOCK_PROTECTED_PREF_STORE:
- EXPECT_FALSE(protected_store_successful_write_callback_.is_null());
- protected_store_successful_write_callback_.Run();
- protected_store_successful_write_callback_.Reset();
- break;
- }
- }
-
- private:
- void RegisterSuccessfulWriteClosure(
- MockPrefStoreID store_id,
- const base::Closure& successful_write_closure) {
- switch (store_id) {
- case MOCK_UNPROTECTED_PREF_STORE:
- EXPECT_TRUE(unprotected_store_successful_write_callback_.is_null());
- unprotected_store_successful_write_callback_ = successful_write_closure;
- break;
- case MOCK_PROTECTED_PREF_STORE:
- EXPECT_TRUE(protected_store_successful_write_callback_.is_null());
- protected_store_successful_write_callback_ = successful_write_closure;
- break;
- }
- }
-
- // Helper given as an InterceptablePrefFilter::FinalizeFilterOnLoadCallback
- // to the migrator to be invoked when it's done.
- void GetPrefsBack(MockPrefStoreID store_id,
- std::unique_ptr<base::DictionaryValue> prefs,
- bool prefs_altered) {
- switch (store_id) {
- case MOCK_UNPROTECTED_PREF_STORE:
- EXPECT_FALSE(unprotected_prefs_);
- unprotected_prefs_ = std::move(prefs);
- migration_modified_unprotected_store_ = prefs_altered;
- unprotected_store_migration_complete_ = true;
- break;
- case MOCK_PROTECTED_PREF_STORE:
- EXPECT_FALSE(protected_prefs_);
- protected_prefs_ = std::move(prefs);
- migration_modified_protected_store_ = prefs_altered;
- protected_store_migration_complete_ = true;
- break;
- }
- }
-
- // Helper given as a cleaning callback to the migrator.
- void RemovePathFromStore(MockPrefStoreID store_id, const std::string& key) {
- switch (store_id) {
- case MOCK_UNPROTECTED_PREF_STORE:
- ASSERT_TRUE(unprotected_prefs_);
- unprotected_prefs_->RemovePath(key, NULL);
- break;
- case MOCK_PROTECTED_PREF_STORE:
- ASSERT_TRUE(protected_prefs_);
- protected_prefs_->RemovePath(key, NULL);
- break;
- }
- }
-
- // Sets |key| to |value| in the test store identified by |store_id| before
- // migration begins. Does not store a preference hash.
- void PresetStoreValueOnly(MockPrefStoreID store_id,
- const std::string& key,
- const std::string value) {
- base::DictionaryValue* store = NULL;
- switch (store_id) {
- case MOCK_UNPROTECTED_PREF_STORE:
- store = unprotected_prefs_.get();
- break;
- case MOCK_PROTECTED_PREF_STORE:
- store = protected_prefs_.get();
- break;
- }
- DCHECK(store);
-
- store->SetString(key, value);
- }
-
- static const char kSeed[];
- static const char kDeviceId[];
-
- std::unique_ptr<base::DictionaryValue> unprotected_prefs_;
- std::unique_ptr<base::DictionaryValue> protected_prefs_;
-
- SimpleInterceptablePrefFilter mock_unprotected_pref_filter_;
- SimpleInterceptablePrefFilter mock_protected_pref_filter_;
-
- base::Closure unprotected_store_successful_write_callback_;
- base::Closure protected_store_successful_write_callback_;
-
- bool migration_modified_unprotected_store_;
- bool migration_modified_protected_store_;
-
- bool unprotected_store_migration_complete_;
- bool protected_store_migration_complete_;
-
- TestingPrefServiceSimple local_state_;
-
- DISALLOW_COPY_AND_ASSIGN(TrackedPreferencesMigrationTest);
-};
-
-// static
-const char TrackedPreferencesMigrationTest::kSeed[] = "seed";
-
-// static
-const char TrackedPreferencesMigrationTest::kDeviceId[] = "device-id";
-
-} // namespace
-
-TEST_F(TrackedPreferencesMigrationTest, NoMigrationRequired) {
- PresetStoreValue(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref,
- kUnprotectedPrefValue);
- PresetStoreValue(MOCK_PROTECTED_PREF_STORE, kProtectedPref,
- kProtectedPrefValue);
-
- EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
-
- EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
-
- // Hand unprotected prefs to the migrator which should wait for the protected
- // prefs.
- HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE);
- EXPECT_FALSE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
- EXPECT_FALSE(MigrationCompleted());
-
- // Hand protected prefs to the migrator which should proceed with the
- // migration synchronously.
- HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE);
- EXPECT_TRUE(MigrationCompleted());
-
- // Prefs should have been handed back over.
- EXPECT_TRUE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
- EXPECT_FALSE(
- WasOnSuccessfulWriteCallbackRegistered(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_FALSE(
- WasOnSuccessfulWriteCallbackRegistered(MOCK_PROTECTED_PREF_STORE));
- EXPECT_FALSE(StoreModifiedByMigration(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_FALSE(StoreModifiedByMigration(MOCK_PROTECTED_PREF_STORE));
-
- base::StringPairs expected_unprotected_values;
- expected_unprotected_values.push_back(
- std::make_pair(kUnprotectedPref, kUnprotectedPrefValue));
- VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE, expected_unprotected_values);
-
- base::StringPairs expected_protected_values;
- expected_protected_values.push_back(
- std::make_pair(kProtectedPref, kProtectedPrefValue));
- VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values);
-
- EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
-
- EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
-}
-
-TEST_F(TrackedPreferencesMigrationTest, FullMigration) {
- PresetStoreValue(
- MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref, kUnprotectedPrefValue);
- PresetStoreValue(MOCK_UNPROTECTED_PREF_STORE,
- kPreviouslyUnprotectedPref,
- kPreviouslyUnprotectedPrefValue);
- PresetStoreValue(
- MOCK_PROTECTED_PREF_STORE, kProtectedPref, kProtectedPrefValue);
- PresetStoreValue(MOCK_PROTECTED_PREF_STORE,
- kPreviouslyProtectedPref,
- kPreviouslyProtectedPrefValue);
-
- EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_FALSE(
- ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref));
-
- EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_FALSE(
- ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
- EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref));
-
- HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE);
- EXPECT_FALSE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
- EXPECT_FALSE(MigrationCompleted());
-
- HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE);
- EXPECT_TRUE(MigrationCompleted());
-
- EXPECT_TRUE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
- EXPECT_TRUE(
- WasOnSuccessfulWriteCallbackRegistered(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_TRUE(
- WasOnSuccessfulWriteCallbackRegistered(MOCK_PROTECTED_PREF_STORE));
- EXPECT_TRUE(StoreModifiedByMigration(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_TRUE(StoreModifiedByMigration(MOCK_PROTECTED_PREF_STORE));
-
- // Values should have been migrated to their store, but migrated values should
- // still remain in the source store until cleanup tasks are later invoked.
- {
- base::StringPairs expected_unprotected_values;
- expected_unprotected_values.push_back(std::make_pair(
- kUnprotectedPref, kUnprotectedPrefValue));
- expected_unprotected_values.push_back(std::make_pair(
- kPreviouslyProtectedPref, kPreviouslyProtectedPrefValue));
- expected_unprotected_values.push_back(std::make_pair(
- kPreviouslyUnprotectedPref, kPreviouslyUnprotectedPrefValue));
- VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE,
- expected_unprotected_values);
-
- base::StringPairs expected_protected_values;
- expected_protected_values.push_back(std::make_pair(
- kProtectedPref, kProtectedPrefValue));
- expected_protected_values.push_back(std::make_pair(
- kPreviouslyUnprotectedPref, kPreviouslyUnprotectedPrefValue));
- expected_unprotected_values.push_back(std::make_pair(
- kPreviouslyProtectedPref, kPreviouslyProtectedPrefValue));
- VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values);
-
- EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref));
-
- EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
- EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref));
- }
-
- // A successful write of the protected pref store should result in a clean up
- // of the unprotected store.
- SimulateSuccessfulWrite(MOCK_PROTECTED_PREF_STORE);
-
- {
- base::StringPairs expected_unprotected_values;
- expected_unprotected_values.push_back(std::make_pair(
- kUnprotectedPref, kUnprotectedPrefValue));
- expected_unprotected_values.push_back(std::make_pair(
- kPreviouslyProtectedPref, kPreviouslyProtectedPrefValue));
- VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE,
- expected_unprotected_values);
-
- base::StringPairs expected_protected_values;
- expected_protected_values.push_back(std::make_pair(
- kProtectedPref, kProtectedPrefValue));
- expected_protected_values.push_back(std::make_pair(
- kPreviouslyUnprotectedPref, kPreviouslyUnprotectedPrefValue));
- expected_unprotected_values.push_back(std::make_pair(
- kPreviouslyProtectedPref, kPreviouslyProtectedPrefValue));
- VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values);
- }
-
- SimulateSuccessfulWrite(MOCK_UNPROTECTED_PREF_STORE);
-
- {
- base::StringPairs expected_unprotected_values;
- expected_unprotected_values.push_back(std::make_pair(
- kUnprotectedPref, kUnprotectedPrefValue));
- expected_unprotected_values.push_back(std::make_pair(
- kPreviouslyProtectedPref, kPreviouslyProtectedPrefValue));
- VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE,
- expected_unprotected_values);
-
- base::StringPairs expected_protected_values;
- expected_protected_values.push_back(std::make_pair(
- kProtectedPref, kProtectedPrefValue));
- expected_protected_values.push_back(std::make_pair(
- kPreviouslyUnprotectedPref, kPreviouslyUnprotectedPrefValue));
- VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values);
- }
-
- // Hashes are not cleaned up yet.
- EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref));
-
- EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
- EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref));
-
- Reset();
-
- HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE);
- HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE);
- EXPECT_TRUE(MigrationCompleted());
-
- // Hashes are cleaned up.
- EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_FALSE(
- ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref));
-
- EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
- EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_FALSE(
- ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref));
-}
-
-TEST_F(TrackedPreferencesMigrationTest, CleanupOnly) {
- // Already migrated; only cleanup needed.
- PresetStoreValue(
- MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref, kUnprotectedPrefValue);
- PresetStoreValue(MOCK_UNPROTECTED_PREF_STORE,
- kPreviouslyProtectedPref,
- kPreviouslyProtectedPrefValue);
- PresetStoreValue(MOCK_UNPROTECTED_PREF_STORE,
- kPreviouslyUnprotectedPref,
- kPreviouslyUnprotectedPrefValue);
- PresetStoreValue(
- MOCK_PROTECTED_PREF_STORE, kProtectedPref, kProtectedPrefValue);
- PresetStoreValue(MOCK_PROTECTED_PREF_STORE,
- kPreviouslyProtectedPref,
- kPreviouslyProtectedPrefValue);
- PresetStoreValue(MOCK_PROTECTED_PREF_STORE,
- kPreviouslyUnprotectedPref,
- kPreviouslyUnprotectedPrefValue);
-
- HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE);
- EXPECT_FALSE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
- EXPECT_FALSE(MigrationCompleted());
-
- HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE);
- EXPECT_TRUE(MigrationCompleted());
-
- EXPECT_TRUE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
- EXPECT_FALSE(
- WasOnSuccessfulWriteCallbackRegistered(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_FALSE(
- WasOnSuccessfulWriteCallbackRegistered(MOCK_PROTECTED_PREF_STORE));
- EXPECT_FALSE(StoreModifiedByMigration(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_FALSE(StoreModifiedByMigration(MOCK_PROTECTED_PREF_STORE));
-
- // Cleanup should happen synchronously if the values were already present in
- // their destination stores.
- {
- base::StringPairs expected_unprotected_values;
- expected_unprotected_values.push_back(std::make_pair(
- kUnprotectedPref, kUnprotectedPrefValue));
- expected_unprotected_values.push_back(std::make_pair(
- kPreviouslyProtectedPref, kPreviouslyProtectedPrefValue));
- VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE,
- expected_unprotected_values);
-
- base::StringPairs expected_protected_values;
- expected_protected_values.push_back(std::make_pair(
- kProtectedPref, kProtectedPrefValue));
- expected_protected_values.push_back(std::make_pair(
- kPreviouslyUnprotectedPref, kPreviouslyUnprotectedPrefValue));
- VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values);
- }
-}
diff --git a/chromium/components/user_prefs/tracked/tracked_split_preference.cc b/chromium/components/user_prefs/tracked/tracked_split_preference.cc
deleted file mode 100644
index 2094d97b71e..00000000000
--- a/chromium/components/user_prefs/tracked/tracked_split_preference.cc
+++ /dev/null
@@ -1,121 +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/user_prefs/tracked/tracked_split_preference.h"
-
-#include <vector>
-
-#include "base/logging.h"
-#include "base/values.h"
-#include "components/user_prefs/tracked/pref_hash_store_transaction.h"
-#include "components/user_prefs/tracked/tracked_preference_validation_delegate.h"
-
-TrackedSplitPreference::TrackedSplitPreference(
- const std::string& pref_path,
- size_t reporting_id,
- size_t reporting_ids_count,
- PrefHashFilter::EnforcementLevel enforcement_level,
- PrefHashFilter::ValueType value_type,
- TrackedPreferenceValidationDelegate* delegate)
- : pref_path_(pref_path),
- helper_(pref_path,
- reporting_id,
- reporting_ids_count,
- enforcement_level,
- value_type),
- delegate_(delegate) {
-}
-
-TrackedPreferenceType TrackedSplitPreference::GetType() const {
- return TrackedPreferenceType::SPLIT;
-}
-
-void TrackedSplitPreference::OnNewValue(
- const base::Value* value,
- PrefHashStoreTransaction* transaction) const {
- const base::DictionaryValue* dict_value = NULL;
- if (value && !value->GetAsDictionary(&dict_value)) {
- NOTREACHED();
- return;
- }
- transaction->StoreSplitHash(pref_path_, dict_value);
-}
-
-bool TrackedSplitPreference::EnforceAndReport(
- base::DictionaryValue* pref_store_contents,
- PrefHashStoreTransaction* transaction,
- PrefHashStoreTransaction* external_validation_transaction) const {
- base::DictionaryValue* dict_value = NULL;
- if (!pref_store_contents->GetDictionary(pref_path_, &dict_value) &&
- pref_store_contents->Get(pref_path_, NULL)) {
- // There should be a dictionary or nothing at |pref_path_|.
- NOTREACHED();
- return false;
- }
-
- std::vector<std::string> invalid_keys;
- PrefHashStoreTransaction::ValueState value_state =
- transaction->CheckSplitValue(pref_path_, dict_value, &invalid_keys);
-
- if (value_state == PrefHashStoreTransaction::CHANGED)
- helper_.ReportSplitPreferenceChangedCount(invalid_keys.size());
-
- helper_.ReportValidationResult(value_state, transaction->GetStoreUMASuffix());
-
- PrefHashStoreTransaction::ValueState external_validation_value_state =
- PrefHashStoreTransaction::UNSUPPORTED;
- std::vector<std::string> external_validation_invalid_keys;
- if (external_validation_transaction) {
- external_validation_value_state =
- external_validation_transaction->CheckSplitValue(
- pref_path_, dict_value, &external_validation_invalid_keys);
- helper_.ReportValidationResult(
- external_validation_value_state,
- external_validation_transaction->GetStoreUMASuffix());
- }
-
- if (delegate_) {
- delegate_->OnSplitPreferenceValidation(
- pref_path_, dict_value, invalid_keys, external_validation_invalid_keys,
- value_state, external_validation_value_state, helper_.IsPersonal());
- }
- TrackedPreferenceHelper::ResetAction reset_action =
- helper_.GetAction(value_state);
- helper_.ReportAction(reset_action);
-
- bool was_reset = false;
- if (reset_action == TrackedPreferenceHelper::DO_RESET) {
- if (value_state == PrefHashStoreTransaction::CHANGED) {
- DCHECK(!invalid_keys.empty());
-
- for (std::vector<std::string>::const_iterator it = invalid_keys.begin();
- it != invalid_keys.end(); ++it) {
- dict_value->Remove(*it, NULL);
- }
- } else {
- pref_store_contents->RemovePath(pref_path_, NULL);
- }
- was_reset = true;
- }
-
- if (value_state != PrefHashStoreTransaction::UNCHANGED) {
- // Store the hash for the new value (whether it was reset or not).
- const base::DictionaryValue* new_dict_value = NULL;
- pref_store_contents->GetDictionary(pref_path_, &new_dict_value);
- transaction->StoreSplitHash(pref_path_, new_dict_value);
- }
-
- // Update MACs in the external store if there is one and there either was a
- // reset or external validation failed.
- if (external_validation_transaction &&
- (was_reset ||
- external_validation_value_state !=
- PrefHashStoreTransaction::UNCHANGED)) {
- const base::DictionaryValue* new_dict_value = nullptr;
- pref_store_contents->GetDictionary(pref_path_, &new_dict_value);
- external_validation_transaction->StoreSplitHash(pref_path_, new_dict_value);
- }
-
- return was_reset;
-}
diff --git a/chromium/components/user_prefs/tracked/tracked_split_preference.h b/chromium/components/user_prefs/tracked/tracked_split_preference.h
deleted file mode 100644
index 359c8e1f570..00000000000
--- a/chromium/components/user_prefs/tracked/tracked_split_preference.h
+++ /dev/null
@@ -1,52 +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_USER_PREFS_TRACKED_TRACKED_SPLIT_PREFERENCE_H_
-#define COMPONENTS_USER_PREFS_TRACKED_TRACKED_SPLIT_PREFERENCE_H_
-
-#include <stddef.h>
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "components/user_prefs/tracked/pref_hash_filter.h"
-#include "components/user_prefs/tracked/tracked_preference.h"
-#include "components/user_prefs/tracked/tracked_preference_helper.h"
-
-class TrackedPreferenceValidationDelegate;
-
-// A TrackedSplitPreference must be tracking a dictionary pref. Each top-level
-// entry in its dictionary is tracked and enforced independently. An optional
-// delegate is notified of the status of the preference during enforcement.
-// Note: preferences using this strategy must be kept in sync with
-// TrackedSplitPreferences in histograms.xml.
-class TrackedSplitPreference : public TrackedPreference {
- public:
- // Constructs a TrackedSplitPreference. |pref_path| must be a dictionary pref.
- TrackedSplitPreference(const std::string& pref_path,
- size_t reporting_id,
- size_t reporting_ids_count,
- PrefHashFilter::EnforcementLevel enforcement_level,
- PrefHashFilter::ValueType value_type,
- TrackedPreferenceValidationDelegate* delegate);
-
- // TrackedPreference implementation.
- TrackedPreferenceType GetType() const override;
- void OnNewValue(const base::Value* value,
- PrefHashStoreTransaction* transaction) const override;
- bool EnforceAndReport(
- base::DictionaryValue* pref_store_contents,
- PrefHashStoreTransaction* transaction,
- PrefHashStoreTransaction* external_validation_transaction) const override;
-
- private:
- const std::string pref_path_;
- const TrackedPreferenceHelper helper_;
- TrackedPreferenceValidationDelegate* delegate_;
-
- DISALLOW_COPY_AND_ASSIGN(TrackedSplitPreference);
-};
-
-#endif // COMPONENTS_USER_PREFS_TRACKED_TRACKED_SPLIT_PREFERENCE_H_
diff --git a/chromium/components/variations/OWNERS b/chromium/components/variations/OWNERS
index b19eb09b8b8..1b1cf9d979d 100644
--- a/chromium/components/variations/OWNERS
+++ b/chromium/components/variations/OWNERS
@@ -1,3 +1,5 @@
asvitkine@chromium.org
jwd@chromium.org
rkaplow@chromium.org
+
+# COMPONENT: Internals>Metrics
diff --git a/chromium/components/variations/metrics_util.cc b/chromium/components/variations/metrics_util.cc
index 52fa0be09c6..e6e713c4c6f 100644
--- a/chromium/components/variations/metrics_util.cc
+++ b/chromium/components/variations/metrics_util.cc
@@ -11,13 +11,12 @@
namespace metrics {
-uint32_t HashName(const std::string& name) {
+uint32_t HashName(base::StringPiece name) {
// SHA-1 is designed to produce a uniformly random spread in its output space,
// even for nearly-identical inputs.
unsigned char sha1_hash[base::kSHA1Length];
- base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(name.c_str()),
- name.size(),
- sha1_hash);
+ base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(name.data()),
+ name.size(), sha1_hash);
uint32_t bits;
static_assert(sizeof(bits) < sizeof(sha1_hash), "more data required");
diff --git a/chromium/components/variations/metrics_util.h b/chromium/components/variations/metrics_util.h
index 823fcd7ba23..0a03fd43460 100644
--- a/chromium/components/variations/metrics_util.h
+++ b/chromium/components/variations/metrics_util.h
@@ -7,14 +7,13 @@
#include <stdint.h>
-#include <string>
-
+#include "base/strings/string_piece.h"
namespace metrics {
// Computes a uint32_t hash of a given string based on its SHA1 hash. Suitable
// for uniquely identifying field trial names and group names.
-uint32_t HashName(const std::string& name);
+uint32_t HashName(base::StringPiece name);
} // namespace metrics
diff --git a/chromium/components/variations/variations_url_constants.cc b/chromium/components/variations/variations_url_constants.cc
index f530ff5cc93..b233bb6435c 100644
--- a/chromium/components/variations/variations_url_constants.cc
+++ b/chromium/components/variations/variations_url_constants.cc
@@ -4,17 +4,10 @@
#include "components/variations/variations_url_constants.h"
-#include "build/build_config.h"
-
namespace variations {
// Default server of Variations seed info.
-#if defined(OS_ANDROID)
const char kDefaultServerUrl[] =
"https://clientservices.googleapis.com/chrome-variations/seed";
-#else
-const char kDefaultServerUrl[] =
- "https://clients4.google.com/chrome-variations/seed";
-#endif
} // namespace variations
diff --git a/chromium/components/version_info/BUILD.gn b/chromium/components/version_info/BUILD.gn
index 5dbee5f87a5..1fe5cfb1cad 100644
--- a/chromium/components/version_info/BUILD.gn
+++ b/chromium/components/version_info/BUILD.gn
@@ -22,12 +22,22 @@ static_library("version_info") {
"//components/strings",
]
+ public_deps = [
+ ":channel",
+ ]
+
if (use_unofficial_version_number) {
defines = [ "USE_UNOFFICIAL_VERSION_NUMBER" ]
deps += [ "//ui/base" ]
}
}
+source_set("channel") {
+ sources = [
+ "channel.h",
+ ]
+}
+
process_version("generate_version_info") {
template_file = "version_info_values.h.version"
sources = [
diff --git a/chromium/components/version_info/channel.h b/chromium/components/version_info/channel.h
new file mode 100644
index 00000000000..d3c48840d51
--- /dev/null
+++ b/chromium/components/version_info/channel.h
@@ -0,0 +1,15 @@
+// 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_VERSION_INFO_CHANNEL_H_
+#define COMPONENTS_VERSION_INFO_CHANNEL_H_
+
+namespace version_info {
+
+// The possible channels for an installation, from most fun to most stable.
+enum class Channel { UNKNOWN = 0, CANARY, DEV, BETA, STABLE };
+
+} // namespace version_info
+
+#endif // COMPONENTS_VERSION_INFO_CHANNEL_H_
diff --git a/chromium/components/version_info/version_info.h b/chromium/components/version_info/version_info.h
index 59a074ed17e..62125412b65 100644
--- a/chromium/components/version_info/version_info.h
+++ b/chromium/components/version_info/version_info.h
@@ -7,10 +7,9 @@
#include <string>
-namespace version_info {
+#include "components/version_info/channel.h"
-// The possible channels for an installation, from most fun to most stable.
-enum class Channel { UNKNOWN = 0, CANARY, DEV, BETA, STABLE };
+namespace version_info {
// Returns the product name and version information for UserAgent header,
// e.g. "Chrome/a.b.c.d".
diff --git a/chromium/components/version_ui/OWNERS b/chromium/components/version_ui/OWNERS
index c4cf1964147..e87625e132a 100644
--- a/chromium/components/version_ui/OWNERS
+++ b/chromium/components/version_ui/OWNERS
@@ -1 +1,3 @@
file://ui/webui/OWNERS
+
+# COMPONENT: UI>Browser>WebUI
diff --git a/chromium/components/version_ui/resources/about_version.html b/chromium/components/version_ui/resources/about_version.html
index aee4c518f78..19a261c948f 100644
--- a/chromium/components/version_ui/resources/about_version.html
+++ b/chromium/components/version_ui/resources/about_version.html
@@ -50,6 +50,9 @@ about:version template page
(<span i18n-content="official"></span>)
<span i18n-content="version_modifier"></span>
<span i18n-content="version_bitsize"></span>
+<if expr="is_win">
+ <span i18n-content="update_cohort_name"></span>
+</if>
</td>
</tr>
<tr>
@@ -69,6 +72,14 @@ about:version template page
</td>
</tr>
</if>
+<if expr="is_android">
+ <tr>
+ <td class="label" i18n-content="gms_name"></td>
+ <td class="version" id="gms_version">
+ <span i18n-content="gms_version"></span>
+ </td>
+ </tr>
+</if>
<if expr="chromeos">
<tr>
<td class="label" i18n-content="platform"></td>
diff --git a/chromium/components/version_ui/version_ui_constants.cc b/chromium/components/version_ui/version_ui_constants.cc
index 5c567099b06..f482a465c36 100644
--- a/chromium/components/version_ui/version_ui_constants.cc
+++ b/chromium/components/version_ui/version_ui_constants.cc
@@ -27,6 +27,7 @@ const char kCommandLineName[] = "command_line_name";
const char kCompany[] = "company";
#if defined(OS_WIN)
const char kCompiler[] = "compiler";
+const char kUpdateCohortName[] = "update_cohort_name";
#endif
const char kCopyright[] = "copyright";
#if defined(OS_CHROMEOS)
@@ -54,6 +55,8 @@ const char kOSType[] = "os_type";
#endif
#if defined(OS_ANDROID)
const char kOSVersion[] = "os_version";
+const char kGmsName[] = "gms_name";
+const char kGmsVersion[] = "gms_version";
#endif
#if defined(OS_CHROMEOS)
const char kPlatform[] = "platform";
diff --git a/chromium/components/version_ui/version_ui_constants.h b/chromium/components/version_ui/version_ui_constants.h
index 13f6b6e8536..186ba51e65e 100644
--- a/chromium/components/version_ui/version_ui_constants.h
+++ b/chromium/components/version_ui/version_ui_constants.h
@@ -33,6 +33,7 @@ extern const char kCommandLineName[];
extern const char kCompany[];
#if defined(OS_WIN)
extern const char kCompiler[];
+extern const char kUpdateCohortName[];
#endif
extern const char kCopyright[];
#if defined(OS_CHROMEOS)
@@ -60,6 +61,8 @@ extern const char kOSType[];
#endif
#if defined(OS_ANDROID)
extern const char kOSVersion[];
+extern const char kGmsName[];
+extern const char kGmsVersion[];
#endif
#if defined(OS_CHROMEOS)
extern const char kPlatform[];
diff --git a/chromium/components/version_ui_strings.grdp b/chromium/components/version_ui_strings.grdp
index 5107add322b..55076d27567 100644
--- a/chromium/components/version_ui_strings.grdp
+++ b/chromium/components/version_ui_strings.grdp
@@ -21,23 +21,28 @@
<message name="IDS_VERSION_UI_OS" desc="label for the OS on the about:version page">
OS
</message>
+ <if expr="is_android">
+ <message name="IDS_VERSION_UI_GMS" desc="label for the Google Play services info on the about:version page">
+ Google Play services
+ </message>
+ </if>
<message name="IDS_VERSION_UI_USER_AGENT" desc="label for the user agent on the about:version page">
User Agent
</message>
<message name="IDS_VERSION_UI_COMMAND_LINE" desc="label for the command line on the about:version page">
Command Line
</message>
-<if expr="chromeos">
- <message name="IDS_VERSION_UI_BUILD_DATE" desc="label for build date on the about:version page">
- Build Date
- </message>
- <message name="IDS_VERSION_UI_CUSTOMIZATION_ID" desc="label for the device customization ID if present on the about:version page">
- Customization ID
- </message>
- <message name="IDS_VERSION_UI_FIRMWARE_VERSION" desc="label for the firmware version on the about:version page">
- Firmware Version
- </message>
-</if>
+ <if expr="chromeos">
+ <message name="IDS_VERSION_UI_BUILD_DATE" desc="label for build date on the about:version page">
+ Build Date
+ </message>
+ <message name="IDS_VERSION_UI_CUSTOMIZATION_ID" desc="label for the device customization ID if present on the about:version page">
+ Customization ID
+ </message>
+ <message name="IDS_VERSION_UI_FIRMWARE_VERSION" desc="label for the firmware version on the about:version page">
+ Firmware Version
+ </message>
+ </if>
<message name="IDS_VERSION_UI_EXECUTABLE_PATH" desc="label for the executable path on the about:version page">
Executable Path
</message>
@@ -50,4 +55,9 @@
<message name="IDS_VERSION_UI_VARIATIONS" desc="label for the variations list on the about:version page">
Variations
</message>
+ <if expr="is_win">
+ <message name="IDS_VERSION_UI_COHORT_NAME" desc="Update cohort substring included in the version number line on the about:version page.">
+ (cohort: <ph name="UPDATE_COHORT_NAME">$1<ex>Stable</ex></ph>)
+ </message>
+ </if>
</grit-part>
diff --git a/chromium/components/visitedlink/browser/visitedlink_event_listener.cc b/chromium/components/visitedlink/browser/visitedlink_event_listener.cc
index a116e98c27d..52410fca667 100644
--- a/chromium/components/visitedlink/browser/visitedlink_event_listener.cc
+++ b/chromium/components/visitedlink/browser/visitedlink_event_listener.cc
@@ -44,9 +44,8 @@ class VisitedLinkUpdater {
: reset_needed_(false),
invalidate_hashes_(false),
render_process_id_(render_process_id) {
- content::RenderProcessHost::FromID(render_process_id)
- ->GetRemoteInterfaces()
- ->GetInterface(&sink_);
+ BindInterface(content::RenderProcessHost::FromID(render_process_id),
+ &sink_);
}
// Informs the renderer about a new visited link table.
diff --git a/chromium/components/visitedlink/renderer/visitedlink_slave.cc b/chromium/components/visitedlink/renderer/visitedlink_slave.cc
index bbc9b5d96b4..5355c14d5a1 100644
--- a/chromium/components/visitedlink/renderer/visitedlink_slave.cc
+++ b/chromium/components/visitedlink/renderer/visitedlink_slave.cc
@@ -63,11 +63,11 @@ void VisitedLinkSlave::UpdateVisitedLinks(
void VisitedLinkSlave::AddVisitedLinks(
const std::vector<VisitedLinkSlave::Fingerprint>& fingerprints) {
for (size_t i = 0; i < fingerprints.size(); ++i)
- WebView::updateVisitedLinkState(fingerprints[i]);
+ WebView::UpdateVisitedLinkState(fingerprints[i]);
}
void VisitedLinkSlave::ResetVisitedLinks(bool invalidate_hashes) {
- WebView::resetVisitedLinkState(invalidate_hashes);
+ WebView::ResetVisitedLinkState(invalidate_hashes);
}
void VisitedLinkSlave::FreeTable() {
diff --git a/chromium/components/viz/DEPS b/chromium/components/viz/DEPS
new file mode 100644
index 00000000000..f8654e9ef32
--- /dev/null
+++ b/chromium/components/viz/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+gpu",
+ "+mojo/public",
+]
diff --git a/chromium/components/viz/OWNERS b/chromium/components/viz/OWNERS
new file mode 100644
index 00000000000..6c960a1408b
--- /dev/null
+++ b/chromium/components/viz/OWNERS
@@ -0,0 +1,10 @@
+fsamuel@chromium.org
+rjkroege@chromium.org
+sadrul@chromium.org
+danakj@chromium.org
+enne@chromium.org
+vmpstr@chromium.org
+piman@chromium.org
+jbauman@chromium.org
+
+# COMPONENT: Internals>GPU>Internals
diff --git a/chromium/components/viz/PRESUBMIT.py b/chromium/components/viz/PRESUBMIT.py
new file mode 100644
index 00000000000..a3b3d1b46d1
--- /dev/null
+++ b/chromium/components/viz/PRESUBMIT.py
@@ -0,0 +1,318 @@
+# 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.
+
+"""Top-level presubmit script for components/viz.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+import re
+import string
+
+VIZ_SOURCE_FILES=(r'^components[\\/]viz[\\/].*\.(cc|h)$',)
+
+def CheckChangeLintsClean(input_api, output_api):
+ source_filter = lambda x: input_api.FilterSourceFile(
+ x, white_list=VIZ_SOURCE_FILES, black_list=None)
+
+ return input_api.canned_checks.CheckChangeLintsClean(
+ input_api, output_api, source_filter, lint_filters=[], verbose_level=1)
+
+def CheckAsserts(input_api, output_api, white_list=VIZ_SOURCE_FILES, black_list=None):
+ black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
+ source_file_filter = lambda x: input_api.FilterSourceFile(x, white_list, black_list)
+
+ assert_files = []
+
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ # WebKit ASSERT() is not allowed.
+ if re.search(r"\bASSERT\(", contents):
+ assert_files.append(f.LocalPath())
+
+ if assert_files:
+ return [output_api.PresubmitError(
+ 'These files use ASSERT instead of using DCHECK:',
+ items=assert_files)]
+ return []
+
+def CheckStdAbs(input_api, output_api,
+ white_list=VIZ_SOURCE_FILES, black_list=None):
+ black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
+ source_file_filter = lambda x: input_api.FilterSourceFile(x,
+ white_list,
+ black_list)
+
+ using_std_abs_files = []
+ found_fabs_files = []
+ missing_std_prefix_files = []
+
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ if re.search(r"using std::f?abs;", contents):
+ using_std_abs_files.append(f.LocalPath())
+ if re.search(r"\bfabsf?\(", contents):
+ found_fabs_files.append(f.LocalPath());
+
+ no_std_prefix = r"(?<!std::)"
+ # Matches occurrences of abs/absf/fabs/fabsf without a "std::" prefix.
+ abs_without_prefix = r"%s(\babsf?\()" % no_std_prefix
+ fabs_without_prefix = r"%s(\bfabsf?\()" % no_std_prefix
+ # Skips matching any lines that have "// NOLINT".
+ no_nolint = r"(?![^\n]*//\s+NOLINT)"
+
+ expression = re.compile("(%s|%s)%s" %
+ (abs_without_prefix, fabs_without_prefix, no_nolint))
+ if expression.search(contents):
+ missing_std_prefix_files.append(f.LocalPath())
+
+ result = []
+ if using_std_abs_files:
+ result.append(output_api.PresubmitError(
+ 'These files have "using std::abs" which is not permitted.',
+ items=using_std_abs_files))
+ if found_fabs_files:
+ result.append(output_api.PresubmitError(
+ 'std::abs() should be used instead of std::fabs() for consistency.',
+ items=found_fabs_files))
+ if missing_std_prefix_files:
+ result.append(output_api.PresubmitError(
+ 'These files use abs(), absf(), fabs(), or fabsf() without qualifying '
+ 'the std namespace. Please use std::abs() in all places.',
+ items=missing_std_prefix_files))
+ return result
+
+def CheckPassByValue(input_api,
+ output_api,
+ white_list=VIZ_SOURCE_FILES,
+ black_list=None):
+ black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
+ source_file_filter = lambda x: input_api.FilterSourceFile(x,
+ white_list,
+ black_list)
+
+ local_errors = []
+
+ # Well-defined simple classes the same size as a primitive type.
+ pass_by_value_types = ['base::Time',
+ 'base::TimeTicks',
+ ]
+
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ match = re.search(
+ r'\bconst +' + '(?P<type>(%s))&' %
+ string.join(pass_by_value_types, '|'),
+ contents)
+ if match:
+ local_errors.append(output_api.PresubmitError(
+ '%s passes %s by const ref instead of by value.' %
+ (f.LocalPath(), match.group('type'))))
+ return local_errors
+
+def CheckTodos(input_api, output_api):
+ errors = []
+
+ source_file_filter = lambda x: x
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ if ('FIX'+'ME') in contents:
+ errors.append(f.LocalPath())
+
+ if errors:
+ return [output_api.PresubmitError(
+ 'All TODO comments should be of the form TODO(name/bug). ' +
+ 'Use TODO instead of FIX' + 'ME',
+ items=errors)]
+ return []
+
+def CheckDoubleAngles(input_api, output_api, white_list=VIZ_SOURCE_FILES,
+ black_list=None):
+ errors = []
+
+ source_file_filter = lambda x: input_api.FilterSourceFile(x,
+ white_list,
+ black_list)
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ if ('> >') in contents:
+ errors.append(f.LocalPath())
+
+ if errors:
+ return [output_api.PresubmitError('Use >> instead of > >:', items=errors)]
+ return []
+
+def CheckUniquePtr(input_api, output_api,
+ white_list=VIZ_SOURCE_FILES, black_list=None):
+ black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
+ source_file_filter = lambda x: input_api.FilterSourceFile(x,
+ white_list,
+ black_list)
+ errors = []
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ for line_number, line in f.ChangedContents():
+ # Disallow:
+ # return std::unique_ptr<T>(foo);
+ # bar = std::unique_ptr<T>(foo);
+ # But allow:
+ # return std::unique_ptr<T[]>(foo);
+ # bar = std::unique_ptr<T[]>(foo);
+ if re.search(r'(=|\breturn)\s*std::unique_ptr<.*?(?<!])>\([^)]+\)', line):
+ errors.append(output_api.PresubmitError(
+ ('%s:%d uses explicit std::unique_ptr constructor. ' +
+ 'Use base::MakeUnique<T>() instead.') %
+ (f.LocalPath(), line_number)))
+ # Disallow:
+ # std::unique_ptr<T>()
+ if re.search(r'\bstd::unique_ptr<.*?>\(\)', line):
+ errors.append(output_api.PresubmitError(
+ '%s:%d uses std::unique_ptr<T>(). Use nullptr instead.' %
+ (f.LocalPath(), line_number)))
+ return errors
+
+def FindUnquotedQuote(contents, pos):
+ match = re.search(r"(?<!\\)(?P<quote>\")", contents[pos:])
+ return -1 if not match else match.start("quote") + pos
+
+def FindUselessIfdefs(input_api, output_api):
+ errors = []
+ source_file_filter = lambda x: x
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ if re.search(r'#if\s*0\s', contents):
+ errors.append(f.LocalPath())
+ if errors:
+ return [output_api.PresubmitError(
+ 'Don\'t use #if '+'0; just delete the code.',
+ items=errors)]
+ return []
+
+def FindNamespaceInBlock(pos, namespace, contents, whitelist=[]):
+ open_brace = -1
+ close_brace = -1
+ quote = -1
+ name = -1
+ brace_count = 1
+ quote_count = 0
+ while pos < len(contents) and brace_count > 0:
+ if open_brace < pos: open_brace = contents.find("{", pos)
+ if close_brace < pos: close_brace = contents.find("}", pos)
+ if quote < pos: quote = FindUnquotedQuote(contents, pos)
+ if name < pos: name = contents.find(("%s::" % namespace), pos)
+
+ if name < 0:
+ return False # The namespace is not used at all.
+ if open_brace < 0:
+ open_brace = len(contents)
+ if close_brace < 0:
+ close_brace = len(contents)
+ if quote < 0:
+ quote = len(contents)
+
+ next = min(open_brace, min(close_brace, min(quote, name)))
+
+ if next == open_brace:
+ brace_count += 1
+ elif next == close_brace:
+ brace_count -= 1
+ elif next == quote:
+ quote_count = 0 if quote_count else 1
+ elif next == name and not quote_count:
+ in_whitelist = False
+ for w in whitelist:
+ if re.match(w, contents[next:]):
+ in_whitelist = True
+ break
+ if not in_whitelist:
+ return True
+ pos = next + 1
+ return False
+
+# Checks for the use of viz:: within the viz namespace, which is usually
+# redundant.
+def CheckNamespace(input_api, output_api):
+ errors = []
+
+ source_file_filter = lambda x: x
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ match = re.search(r'namespace\s*viz\s*{', contents)
+ if match:
+ whitelist = []
+ if FindNamespaceInBlock(match.end(), 'viz', contents, whitelist=whitelist):
+ errors.append(f.LocalPath())
+
+ if errors:
+ return [output_api.PresubmitError(
+ 'Do not use viz:: inside of the viz namespace.',
+ items=errors)]
+ return []
+
+def CheckForUseOfWrongClock(input_api,
+ output_api,
+ white_list=VIZ_SOURCE_FILES,
+ black_list=None):
+ """Make sure new lines of code don't use a clock susceptible to skew."""
+ black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
+ source_file_filter = lambda x: input_api.FilterSourceFile(x,
+ white_list,
+ black_list)
+ # Regular expression that should detect any explicit references to the
+ # base::Time type (or base::Clock/DefaultClock), whether in using decls,
+ # typedefs, or to call static methods.
+ base_time_type_pattern = r'(^|\W)base::(Time|Clock|DefaultClock)(\W|$)'
+
+ # Regular expression that should detect references to the base::Time class
+ # members, such as a call to base::Time::Now.
+ base_time_member_pattern = r'(^|\W)(Time|Clock|DefaultClock)::'
+
+ # Regular expression to detect "using base::Time" declarations. We want to
+ # prevent these from triggerring a warning. For example, it's perfectly
+ # reasonable for code to be written like this:
+ #
+ # using base::Time;
+ # ...
+ # int64 foo_us = foo_s * Time::kMicrosecondsPerSecond;
+ using_base_time_decl_pattern = r'^\s*using\s+(::)?base::Time\s*;'
+
+ # Regular expression to detect references to the kXXX constants in the
+ # base::Time class. We want to prevent these from triggerring a warning.
+ base_time_konstant_pattern = r'(^|\W)Time::k\w+'
+
+ problem_re = input_api.re.compile(
+ r'(' + base_time_type_pattern + r')|(' + base_time_member_pattern + r')')
+ exception_re = input_api.re.compile(
+ r'(' + using_base_time_decl_pattern + r')|(' +
+ base_time_konstant_pattern + r')')
+ problems = []
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ for line_number, line in f.ChangedContents():
+ if problem_re.search(line):
+ if not exception_re.search(line):
+ problems.append(
+ ' %s:%d\n %s' % (f.LocalPath(), line_number, line.strip()))
+
+ if problems:
+ return [output_api.PresubmitPromptOrNotify(
+ 'You added one or more references to the base::Time class and/or one\n'
+ 'of its member functions (or base::Clock/DefaultClock). In cc code,\n'
+ 'it is most certainly incorrect! Instead use base::TimeTicks.\n\n'
+ '\n'.join(problems))]
+ else:
+ return []
+
+def CheckChangeOnUpload(input_api, output_api):
+ results = []
+ results += CheckAsserts(input_api, output_api)
+ results += CheckStdAbs(input_api, output_api)
+ results += CheckPassByValue(input_api, output_api)
+ results += CheckChangeLintsClean(input_api, output_api)
+ results += CheckTodos(input_api, output_api)
+ results += CheckDoubleAngles(input_api, output_api)
+ results += CheckUniquePtr(input_api, output_api)
+ results += CheckNamespace(input_api, output_api)
+ results += CheckForUseOfWrongClock(input_api, output_api)
+ results += FindUselessIfdefs(input_api, output_api)
+ return results
diff --git a/chromium/components/viz/frame_sinks/BUILD.gn b/chromium/components/viz/frame_sinks/BUILD.gn
new file mode 100644
index 00000000000..750e684d93d
--- /dev/null
+++ b/chromium/components/viz/frame_sinks/BUILD.gn
@@ -0,0 +1,25 @@
+# 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.
+
+source_set("frame_sinks") {
+ sources = [
+ "display_provider.h",
+ "gpu_compositor_frame_sink.cc",
+ "gpu_compositor_frame_sink.h",
+ "gpu_compositor_frame_sink_delegate.h",
+ "gpu_root_compositor_frame_sink.cc",
+ "gpu_root_compositor_frame_sink.h",
+ "mojo_frame_sink_manager.cc",
+ "mojo_frame_sink_manager.h",
+ ]
+
+ deps = [
+ "//base",
+ "//cc",
+ "//cc/ipc:interfaces",
+ "//cc/surfaces",
+ "//components/display_compositor",
+ "//gpu/ipc:command_buffer",
+ ]
+}
diff --git a/chromium/components/viz/frame_sinks/DEPS b/chromium/components/viz/frame_sinks/DEPS
new file mode 100644
index 00000000000..fc0222f9b78
--- /dev/null
+++ b/chromium/components/viz/frame_sinks/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ "+cc/base",
+ "+cc/ipc",
+ "+cc/surfaces",
+ "+cc/scheduler",
+]
diff --git a/chromium/components/viz/frame_sinks/display_provider.h b/chromium/components/viz/frame_sinks/display_provider.h
new file mode 100644
index 00000000000..de6127b5d7c
--- /dev/null
+++ b/chromium/components/viz/frame_sinks/display_provider.h
@@ -0,0 +1,36 @@
+// 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_VIZ_FRAME_SINKS_DISPLAY_PROVIDER_H_
+#define COMPONENTS_VIZ_FRAME_SINKS_DISPLAY_PROVIDER_H_
+
+#include <memory>
+
+#include "gpu/ipc/common/surface_handle.h"
+
+namespace cc {
+class BeginFrameSource;
+class Display;
+class FrameSinkId;
+}
+
+namespace viz {
+
+// Handles creating new cc::Displays and related classes for
+// MojoFrameSinkManager.
+class DisplayProvider {
+ public:
+ virtual ~DisplayProvider() {}
+
+ // Creates a new cc::Display for |surface_handle| with |frame_sink_id|. Will
+ // also create cc::BeginFrameSource and return it in |begin_frame_source|.
+ virtual std::unique_ptr<cc::Display> CreateDisplay(
+ const cc::FrameSinkId& frame_sink_id,
+ gpu::SurfaceHandle surface_handle,
+ std::unique_ptr<cc::BeginFrameSource>* begin_frame_source) = 0;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_FRAME_SINKS_DISPLAY_PROVIDER_H_
diff --git a/chromium/components/display_compositor/gpu_compositor_frame_sink.cc b/chromium/components/viz/frame_sinks/gpu_compositor_frame_sink.cc
index c572eb57093..683374f88fb 100644
--- a/chromium/components/display_compositor/gpu_compositor_frame_sink.cc
+++ b/chromium/components/viz/frame_sinks/gpu_compositor_frame_sink.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/display_compositor/gpu_compositor_frame_sink.h"
+#include "components/viz/frame_sinks/gpu_compositor_frame_sink.h"
-namespace display_compositor {
+namespace viz {
GpuCompositorFrameSink::GpuCompositorFrameSink(
GpuCompositorFrameSinkDelegate* delegate,
@@ -15,7 +15,7 @@ GpuCompositorFrameSink::GpuCompositorFrameSink(
compositor_frame_sink_private_request,
cc::mojom::MojoCompositorFrameSinkClientPtr client)
: delegate_(delegate),
- support_(base::MakeUnique<cc::CompositorFrameSinkSupport>(
+ support_(cc::CompositorFrameSinkSupport::Create(
this,
surface_manager,
frame_sink_id,
@@ -50,9 +50,15 @@ void GpuCompositorFrameSink::SubmitCompositorFrame(
support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
}
-void GpuCompositorFrameSink::DidReceiveCompositorFrameAck() {
+void GpuCompositorFrameSink::BeginFrameDidNotSwap(
+ const cc::BeginFrameAck& begin_frame_ack) {
+ support_->BeginFrameDidNotSwap(begin_frame_ack);
+}
+
+void GpuCompositorFrameSink::DidReceiveCompositorFrameAck(
+ const cc::ReturnedResourceArray& resources) {
if (client_)
- client_->DidReceiveCompositorFrameAck();
+ client_->DidReceiveCompositorFrameAck(resources);
}
void GpuCompositorFrameSink::ClaimTemporaryReference(
@@ -78,10 +84,7 @@ void GpuCompositorFrameSink::ReclaimResources(
void GpuCompositorFrameSink::WillDrawSurface(
const cc::LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) {
- if (client_)
- client_->WillDrawSurface(local_surface_id, damage_rect);
-}
+ const gfx::Rect& damage_rect) {}
void GpuCompositorFrameSink::OnClientConnectionLost() {
client_connection_lost_ = true;
@@ -97,4 +100,4 @@ void GpuCompositorFrameSink::OnPrivateConnectionLost() {
client_connection_lost_);
}
-} // namespace display_compositor
+} // namespace viz
diff --git a/chromium/components/display_compositor/gpu_compositor_frame_sink.h b/chromium/components/viz/frame_sinks/gpu_compositor_frame_sink.h
index 48365f176ee..beb2bd27b40 100644
--- a/chromium/components/display_compositor/gpu_compositor_frame_sink.h
+++ b/chromium/components/viz/frame_sinks/gpu_compositor_frame_sink.h
@@ -2,28 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_DISPLAY_COMPOSITOR_GPU_COMPOSITOR_FRAME_SINK_H_
-#define COMPONENTS_DISPLAY_COMPOSITOR_GPU_COMPOSITOR_FRAME_SINK_H_
+#ifndef COMPONENTS_VIZ_FRAME_SINKS_GPU_COMPOSITOR_FRAME_SINK_H_
+#define COMPONENTS_VIZ_FRAME_SINKS_GPU_COMPOSITOR_FRAME_SINK_H_
#include <memory>
#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "cc/ipc/display_compositor.mojom.h"
#include "cc/ipc/mojo_compositor_frame_sink.mojom.h"
#include "cc/surfaces/compositor_frame_sink_support.h"
#include "cc/surfaces/compositor_frame_sink_support_client.h"
#include "cc/surfaces/local_surface_id.h"
#include "cc/surfaces/surface_id.h"
-#include "components/display_compositor/display_compositor_export.h"
-#include "components/display_compositor/gpu_compositor_frame_sink_delegate.h"
+#include "components/viz/frame_sinks/gpu_compositor_frame_sink_delegate.h"
#include "mojo/public/cpp/bindings/binding.h"
-namespace display_compositor {
+namespace viz {
// Server side representation of a WindowSurface.
-class DISPLAY_COMPOSITOR_EXPORT GpuCompositorFrameSink
+class GpuCompositorFrameSink
: public NON_EXPORTED_BASE(cc::CompositorFrameSinkSupportClient),
public NON_EXPORTED_BASE(cc::mojom::MojoCompositorFrameSink),
public NON_EXPORTED_BASE(cc::mojom::MojoCompositorFrameSinkPrivate) {
@@ -43,6 +41,7 @@ class DISPLAY_COMPOSITOR_EXPORT GpuCompositorFrameSink
void SetNeedsBeginFrame(bool needs_begin_frame) override;
void SubmitCompositorFrame(const cc::LocalSurfaceId& local_surface_id,
cc::CompositorFrame frame) override;
+ void BeginFrameDidNotSwap(const cc::BeginFrameAck& begin_frame_ack) override;
// cc::mojom::MojoCompositorFrameSinkPrivate:
void ClaimTemporaryReference(const cc::SurfaceId& surface_id) override;
@@ -51,7 +50,8 @@ class DISPLAY_COMPOSITOR_EXPORT GpuCompositorFrameSink
private:
// cc::CompositorFrameSinkSupportClient implementation:
- void DidReceiveCompositorFrameAck() override;
+ void DidReceiveCompositorFrameAck(
+ const cc::ReturnedResourceArray& resources) override;
void OnBeginFrame(const cc::BeginFrameArgs& args) override;
void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id,
@@ -75,6 +75,6 @@ class DISPLAY_COMPOSITOR_EXPORT GpuCompositorFrameSink
DISALLOW_COPY_AND_ASSIGN(GpuCompositorFrameSink);
};
-} // namespace display_compositor
+} // namespace viz
-#endif // COMPONENTS_DISPLAY_COMPOSITOR_GPU_COMPOSITOR_FRAME_SINK_H_
+#endif // COMPONENTS_VIZ_FRAME_SINKS_GPU_COMPOSITOR_FRAME_SINK_H_
diff --git a/chromium/components/display_compositor/gpu_compositor_frame_sink_delegate.h b/chromium/components/viz/frame_sinks/gpu_compositor_frame_sink_delegate.h
index e1c4382a664..d9d45ae2a6b 100644
--- a/chromium/components/display_compositor/gpu_compositor_frame_sink_delegate.h
+++ b/chromium/components/viz/frame_sinks/gpu_compositor_frame_sink_delegate.h
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_DISPLAY_COMPOSITOR_GPU_COMPOSITOR_FRAME_SINK_DELEGATE_H_
-#define COMPONENTS_DISPLAY_COMPOSITOR_GPU_COMPOSITOR_FRAME_SINK_DELEGATE_H_
+#ifndef COMPONENTS_VIZ_FRAME_SINKS_GPU_COMPOSITOR_FRAME_SINK_DELEGATE_H_
+#define COMPONENTS_VIZ_FRAME_SINKS_GPU_COMPOSITOR_FRAME_SINK_DELEGATE_H_
namespace cc {
class FrameSinkId;
}
-namespace display_compositor {
+namespace viz {
class GpuCompositorFrameSinkDelegate {
public:
@@ -25,6 +25,6 @@ class GpuCompositorFrameSinkDelegate {
virtual ~GpuCompositorFrameSinkDelegate() {}
};
-} // namespace display_compositor
+} // namespace viz
-#endif // COMPONENTS_DISPLAY_COMPOSITOR_GPU_COMPOSITOR_FRAME_SINK_DELEGATE_H_
+#endif // COMPONENTS_VIZ_FRAME_SINKS_GPU_COMPOSITOR_FRAME_SINK_DELEGATE_H_
diff --git a/chromium/components/display_compositor/gpu_root_compositor_frame_sink.cc b/chromium/components/viz/frame_sinks/gpu_root_compositor_frame_sink.cc
index 73ddf26b03e..5aa6bad8bc7 100644
--- a/chromium/components/display_compositor/gpu_root_compositor_frame_sink.cc
+++ b/chromium/components/viz/frame_sinks/gpu_root_compositor_frame_sink.cc
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/display_compositor/gpu_root_compositor_frame_sink.h"
+#include "components/viz/frame_sinks/gpu_root_compositor_frame_sink.h"
#include "cc/surfaces/compositor_frame_sink_support.h"
#include "cc/surfaces/display.h"
-namespace display_compositor {
+namespace viz {
GpuRootCompositorFrameSink::GpuRootCompositorFrameSink(
GpuCompositorFrameSinkDelegate* delegate,
@@ -21,7 +21,7 @@ GpuRootCompositorFrameSink::GpuRootCompositorFrameSink(
cc::mojom::MojoCompositorFrameSinkClientPtr client,
cc::mojom::DisplayPrivateAssociatedRequest display_private_request)
: delegate_(delegate),
- support_(base::MakeUnique<cc::CompositorFrameSinkSupport>(
+ support_(cc::CompositorFrameSinkSupport::Create(
this,
surface_manager,
frame_sink_id,
@@ -61,7 +61,7 @@ void GpuRootCompositorFrameSink::ResizeDisplay(const gfx::Size& size) {
void GpuRootCompositorFrameSink::SetDisplayColorSpace(
const gfx::ColorSpace& color_space) {
DCHECK(display_);
- display_->SetColorSpace(color_space);
+ display_->SetColorSpace(color_space, color_space);
}
void GpuRootCompositorFrameSink::SetOutputIsSecure(bool secure) {
@@ -89,6 +89,11 @@ void GpuRootCompositorFrameSink::SubmitCompositorFrame(
support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
}
+void GpuRootCompositorFrameSink::BeginFrameDidNotSwap(
+ const cc::BeginFrameAck& begin_frame_ack) {
+ support_->BeginFrameDidNotSwap(begin_frame_ack);
+}
+
void GpuRootCompositorFrameSink::ClaimTemporaryReference(
const cc::SurfaceId& surface_id) {
support_->ClaimTemporaryReference(surface_id);
@@ -110,9 +115,10 @@ void GpuRootCompositorFrameSink::DisplayWillDrawAndSwap(
void GpuRootCompositorFrameSink::DisplayDidDrawAndSwap() {}
-void GpuRootCompositorFrameSink::DidReceiveCompositorFrameAck() {
+void GpuRootCompositorFrameSink::DidReceiveCompositorFrameAck(
+ const cc::ReturnedResourceArray& resources) {
if (client_)
- client_->DidReceiveCompositorFrameAck();
+ client_->DidReceiveCompositorFrameAck(resources);
}
void GpuRootCompositorFrameSink::OnBeginFrame(const cc::BeginFrameArgs& args) {
@@ -128,10 +134,7 @@ void GpuRootCompositorFrameSink::ReclaimResources(
void GpuRootCompositorFrameSink::WillDrawSurface(
const cc::LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) {
- if (client_)
- client_->WillDrawSurface(local_surface_id, damage_rect);
-}
+ const gfx::Rect& damage_rect) {}
void GpuRootCompositorFrameSink::OnClientConnectionLost() {
client_connection_lost_ = true;
@@ -147,4 +150,4 @@ void GpuRootCompositorFrameSink::OnPrivateConnectionLost() {
client_connection_lost_);
}
-} // namespace display_compositor
+} // namespace viz
diff --git a/chromium/components/display_compositor/gpu_root_compositor_frame_sink.h b/chromium/components/viz/frame_sinks/gpu_root_compositor_frame_sink.h
index d152bb18e1a..5dceef590ba 100644
--- a/chromium/components/display_compositor/gpu_root_compositor_frame_sink.h
+++ b/chromium/components/viz/frame_sinks/gpu_root_compositor_frame_sink.h
@@ -2,17 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_DISPLAY_COMPOSITOR_GPU_ROOT_COMPOSITOR_FRAME_SINK_H_
-#define COMPONENTS_DISPLAY_COMPOSITOR_GPU_ROOT_COMPOSITOR_FRAME_SINK_H_
+#ifndef COMPONENTS_VIZ_FRAME_SINKS_GPU_ROOT_COMPOSITOR_FRAME_SINK_H_
+#define COMPONENTS_VIZ_FRAME_SINKS_GPU_ROOT_COMPOSITOR_FRAME_SINK_H_
-#include "cc/ipc/display_compositor.mojom.h"
+#include "cc/ipc/frame_sink_manager.mojom.h"
#include "cc/ipc/mojo_compositor_frame_sink.mojom.h"
#include "cc/surfaces/compositor_frame_sink_support_client.h"
#include "cc/surfaces/display_client.h"
#include "cc/surfaces/local_surface_id.h"
#include "cc/surfaces/surface_id.h"
-#include "components/display_compositor/display_compositor_export.h"
-#include "components/display_compositor/gpu_compositor_frame_sink_delegate.h"
+#include "components/viz/frame_sinks/gpu_compositor_frame_sink_delegate.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "mojo/public/cpp/bindings/binding.h"
@@ -23,11 +22,11 @@ class Display;
class SurfaceManager;
}
-namespace display_compositor {
+namespace viz {
class GpuCompositorFrameSinkDelegate;
-class DISPLAY_COMPOSITOR_EXPORT GpuRootCompositorFrameSink
+class GpuRootCompositorFrameSink
: public NON_EXPORTED_BASE(cc::CompositorFrameSinkSupportClient),
public NON_EXPORTED_BASE(cc::mojom::MojoCompositorFrameSink),
public NON_EXPORTED_BASE(cc::mojom::MojoCompositorFrameSinkPrivate),
@@ -60,6 +59,7 @@ class DISPLAY_COMPOSITOR_EXPORT GpuRootCompositorFrameSink
void SetNeedsBeginFrame(bool needs_begin_frame) override;
void SubmitCompositorFrame(const cc::LocalSurfaceId& local_surface_id,
cc::CompositorFrame frame) override;
+ void BeginFrameDidNotSwap(const cc::BeginFrameAck& begin_frame_ack) override;
// cc::mojom::MojoCompositorFrameSinkPrivate:
void ClaimTemporaryReference(const cc::SurfaceId& surface_id) override;
@@ -74,7 +74,8 @@ class DISPLAY_COMPOSITOR_EXPORT GpuRootCompositorFrameSink
void DisplayDidDrawAndSwap() override;
// cc::CompositorFrameSinkSupportClient:
- void DidReceiveCompositorFrameAck() override;
+ void DidReceiveCompositorFrameAck(
+ const cc::ReturnedResourceArray& resources) override;
void OnBeginFrame(const cc::BeginFrameArgs& args) override;
void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id,
@@ -104,6 +105,6 @@ class DISPLAY_COMPOSITOR_EXPORT GpuRootCompositorFrameSink
DISALLOW_COPY_AND_ASSIGN(GpuRootCompositorFrameSink);
};
-} // namespace display_compositor
+} // namespace viz
-#endif // COMPONENTS_DISPLAY_COMPOSITOR_GPU_ROOT_COMPOSITOR_FRAME_SINK_H_
+#endif // COMPONENTS_VIZ_FRAME_SINKS_GPU_ROOT_COMPOSITOR_FRAME_SINK_H_
diff --git a/chromium/components/viz/frame_sinks/mojo_frame_sink_manager.cc b/chromium/components/viz/frame_sinks/mojo_frame_sink_manager.cc
new file mode 100644
index 00000000000..71b56c630d3
--- /dev/null
+++ b/chromium/components/viz/frame_sinks/mojo_frame_sink_manager.cc
@@ -0,0 +1,147 @@
+// 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/viz/frame_sinks/mojo_frame_sink_manager.h"
+
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
+#include "cc/base/switches.h"
+#include "cc/scheduler/begin_frame_source.h"
+#include "cc/surfaces/display.h"
+#include "cc/surfaces/surface_dependency_tracker.h"
+#include "components/viz/frame_sinks/display_provider.h"
+#include "components/viz/frame_sinks/gpu_compositor_frame_sink.h"
+#include "components/viz/frame_sinks/gpu_root_compositor_frame_sink.h"
+
+namespace viz {
+
+MojoFrameSinkManager::MojoFrameSinkManager(
+ bool use_surface_references,
+ DisplayProvider* display_provider,
+ cc::mojom::FrameSinkManagerRequest request,
+ cc::mojom::FrameSinkManagerClientPtr client)
+ : manager_(use_surface_references
+ ? cc::SurfaceManager::LifetimeType::REFERENCES
+ : cc::SurfaceManager::LifetimeType::SEQUENCES),
+ display_provider_(display_provider),
+ client_(std::move(client)),
+ binding_(this, std::move(request)) {
+ manager_.AddObserver(this);
+}
+
+MojoFrameSinkManager::~MojoFrameSinkManager() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ manager_.RemoveObserver(this);
+}
+
+void MojoFrameSinkManager::CreateRootCompositorFrameSink(
+ const cc::FrameSinkId& frame_sink_id,
+ gpu::SurfaceHandle surface_handle,
+ cc::mojom::MojoCompositorFrameSinkAssociatedRequest request,
+ cc::mojom::MojoCompositorFrameSinkPrivateRequest private_request,
+ cc::mojom::MojoCompositorFrameSinkClientPtr client,
+ cc::mojom::DisplayPrivateAssociatedRequest display_private_request) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_NE(surface_handle, gpu::kNullSurfaceHandle);
+ DCHECK_EQ(0u, compositor_frame_sinks_.count(frame_sink_id));
+ DCHECK(display_provider_);
+
+ std::unique_ptr<cc::BeginFrameSource> begin_frame_source;
+ std::unique_ptr<cc::Display> display = display_provider_->CreateDisplay(
+ frame_sink_id, surface_handle, &begin_frame_source);
+
+ // Lazily inject a SurfaceDependencyTracker into SurfaceManager if surface
+ // synchronization is enabled.
+ if (!manager_.dependency_tracker() &&
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ cc::switches::kEnableSurfaceSynchronization)) {
+ std::unique_ptr<cc::SurfaceDependencyTracker> dependency_tracker(
+ new cc::SurfaceDependencyTracker(&manager_, begin_frame_source.get()));
+ manager_.SetDependencyTracker(std::move(dependency_tracker));
+ }
+
+ compositor_frame_sinks_[frame_sink_id] =
+ base::MakeUnique<GpuRootCompositorFrameSink>(
+ this, &manager_, frame_sink_id, std::move(display),
+ std::move(begin_frame_source), std::move(request),
+ std::move(private_request), std::move(client),
+ std::move(display_private_request));
+}
+
+void MojoFrameSinkManager::CreateCompositorFrameSink(
+ const cc::FrameSinkId& frame_sink_id,
+ cc::mojom::MojoCompositorFrameSinkRequest request,
+ cc::mojom::MojoCompositorFrameSinkPrivateRequest private_request,
+ cc::mojom::MojoCompositorFrameSinkClientPtr client) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_EQ(0u, compositor_frame_sinks_.count(frame_sink_id));
+
+ compositor_frame_sinks_[frame_sink_id] =
+ base::MakeUnique<GpuCompositorFrameSink>(
+ this, &manager_, frame_sink_id, std::move(request),
+ std::move(private_request), std::move(client));
+}
+
+void MojoFrameSinkManager::RegisterFrameSinkHierarchy(
+ const cc::FrameSinkId& parent_frame_sink_id,
+ const cc::FrameSinkId& child_frame_sink_id) {
+ manager_.RegisterFrameSinkHierarchy(parent_frame_sink_id,
+ child_frame_sink_id);
+}
+
+void MojoFrameSinkManager::UnregisterFrameSinkHierarchy(
+ const cc::FrameSinkId& parent_frame_sink_id,
+ const cc::FrameSinkId& child_frame_sink_id) {
+ manager_.UnregisterFrameSinkHierarchy(parent_frame_sink_id,
+ child_frame_sink_id);
+}
+
+void MojoFrameSinkManager::DropTemporaryReference(
+ const cc::SurfaceId& surface_id) {
+ manager_.DropTemporaryReference(surface_id);
+}
+
+void MojoFrameSinkManager::DestroyCompositorFrameSink(cc::FrameSinkId sink_id) {
+ compositor_frame_sinks_.erase(sink_id);
+}
+
+void MojoFrameSinkManager::OnSurfaceCreated(
+ const cc::SurfaceInfo& surface_info) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_GT(surface_info.device_scale_factor(), 0.0f);
+
+ // TODO(kylechar): |client_| will try to find an owner for the temporary
+ // reference to the new surface. With surface synchronization this might not
+ // be necessary, because a surface reference might already exist and no
+ // temporary reference was created. It could be useful to let |client_| know
+ // if it should find an owner.
+ if (client_)
+ client_->OnSurfaceCreated(surface_info);
+}
+
+void MojoFrameSinkManager::OnSurfaceDamaged(const cc::SurfaceId& surface_id,
+ bool* changed) {}
+
+void MojoFrameSinkManager::OnClientConnectionLost(
+ const cc::FrameSinkId& frame_sink_id,
+ bool destroy_compositor_frame_sink) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (destroy_compositor_frame_sink)
+ DestroyCompositorFrameSink(frame_sink_id);
+ // TODO(fsamuel): Tell the frame sink manager host that the client connection
+ // has been lost so that it can drop its private connection and allow a new
+ // client instance to create a new CompositorFrameSink.
+}
+
+void MojoFrameSinkManager::OnPrivateConnectionLost(
+ const cc::FrameSinkId& frame_sink_id,
+ bool destroy_compositor_frame_sink) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (destroy_compositor_frame_sink)
+ DestroyCompositorFrameSink(frame_sink_id);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/frame_sinks/mojo_frame_sink_manager.h b/chromium/components/viz/frame_sinks/mojo_frame_sink_manager.h
new file mode 100644
index 00000000000..53785d95dee
--- /dev/null
+++ b/chromium/components/viz/frame_sinks/mojo_frame_sink_manager.h
@@ -0,0 +1,111 @@
+// 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_VIZ_FRAME_SINKS_MOJO_FRAME_SINK_MANAGER_H_
+#define COMPONENTS_VIZ_FRAME_SINKS_MOJO_FRAME_SINK_MANAGER_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <unordered_map>
+
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "cc/ipc/frame_sink_manager.mojom.h"
+#include "cc/surfaces/frame_sink_id.h"
+#include "cc/surfaces/surface_manager.h"
+#include "cc/surfaces/surface_observer.h"
+#include "components/viz/frame_sinks/gpu_compositor_frame_sink_delegate.h"
+#include "gpu/ipc/common/surface_handle.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace viz {
+
+class DisplayProvider;
+
+// MojoFrameSinkManager manages state associated with CompositorFrameSinks. It
+// provides a Mojo interface to create CompositorFrameSinks, manages BeginFrame
+// hierarchy and manages surface lifetime.
+//
+// This is intended to be created in the viz or GPU process. For mus+ash this
+// will be true after the mus process split. For non-mus Chrome this will be
+// created in the browser process, at least until GPU implementations can be
+// unified.
+class MojoFrameSinkManager : public cc::SurfaceObserver,
+ public GpuCompositorFrameSinkDelegate,
+ public cc::mojom::FrameSinkManager {
+ public:
+ MojoFrameSinkManager(bool use_surface_references,
+ DisplayProvider* display_provider,
+ cc::mojom::FrameSinkManagerRequest request,
+ cc::mojom::FrameSinkManagerClientPtr client);
+ ~MojoFrameSinkManager() override;
+
+ cc::SurfaceManager* surface_manager() { return &manager_; }
+
+ // cc::mojom::MojoFrameSinkManager implementation:
+ void CreateRootCompositorFrameSink(
+ const cc::FrameSinkId& frame_sink_id,
+ gpu::SurfaceHandle surface_handle,
+ cc::mojom::MojoCompositorFrameSinkAssociatedRequest request,
+ cc::mojom::MojoCompositorFrameSinkPrivateRequest private_request,
+ cc::mojom::MojoCompositorFrameSinkClientPtr client,
+ cc::mojom::DisplayPrivateAssociatedRequest display_private_request)
+ override;
+ void CreateCompositorFrameSink(
+ const cc::FrameSinkId& frame_sink_id,
+ cc::mojom::MojoCompositorFrameSinkRequest request,
+ cc::mojom::MojoCompositorFrameSinkPrivateRequest private_request,
+ cc::mojom::MojoCompositorFrameSinkClientPtr client) override;
+ void RegisterFrameSinkHierarchy(
+ const cc::FrameSinkId& parent_frame_sink_id,
+ const cc::FrameSinkId& child_frame_sink_id) override;
+ void UnregisterFrameSinkHierarchy(
+ const cc::FrameSinkId& parent_frame_sink_id,
+ const cc::FrameSinkId& child_frame_sink_id) override;
+ void DropTemporaryReference(const cc::SurfaceId& surface_id) override;
+
+ private:
+ // It is necessary to pass |frame_sink_id| by value because the id
+ // is owned by the GpuCompositorFrameSink in the map. When the sink is
+ // removed from the map, |frame_sink_id| would also be destroyed if it were a
+ // reference. But the map can continue to iterate and try to use it. Passing
+ // by value avoids this.
+ void DestroyCompositorFrameSink(cc::FrameSinkId frame_sink_id);
+
+ // cc::SurfaceObserver implementation.
+ void OnSurfaceCreated(const cc::SurfaceInfo& surface_info) override;
+ void OnSurfaceDamaged(const cc::SurfaceId& surface_id,
+ bool* changed) override;
+
+ // GpuCompositorFrameSinkDelegate implementation.
+ void OnClientConnectionLost(const cc::FrameSinkId& frame_sink_id,
+ bool destroy_compositor_frame_sink) override;
+ void OnPrivateConnectionLost(const cc::FrameSinkId& frame_sink_id,
+ bool destroy_compositor_frame_sink) override;
+
+ // SurfaceManager should be the first object constructed and the last object
+ // destroyed in order to ensure that all other objects that depend on it have
+ // access to a valid pointer for the entirety of their lifetimes.
+ cc::SurfaceManager manager_;
+
+ // Provides a cc::Display for CreateRootCompositorFrameSink().
+ DisplayProvider* const display_provider_;
+
+ std::unordered_map<cc::FrameSinkId,
+ std::unique_ptr<cc::mojom::MojoCompositorFrameSink>,
+ cc::FrameSinkIdHash>
+ compositor_frame_sinks_;
+
+ base::ThreadChecker thread_checker_;
+
+ cc::mojom::FrameSinkManagerClientPtr client_;
+ mojo::Binding<cc::mojom::FrameSinkManager> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoFrameSinkManager);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_FRAME_SINKS_MOJO_FRAME_SINK_MANAGER_H_
diff --git a/chromium/components/wallpaper/OWNERS b/chromium/components/wallpaper/OWNERS
index 7ab58077e17..a9af8c98de7 100644
--- a/chromium/components/wallpaper/OWNERS
+++ b/chromium/components/wallpaper/OWNERS
@@ -1,2 +1,4 @@
bshe@chromium.org
xdai@chromium.org
+
+# COMPONENT: UI>Shell>Wallpaper
diff --git a/chromium/components/wallpaper/wallpaper_color_calculator.cc b/chromium/components/wallpaper/wallpaper_color_calculator.cc
index 0096d5d1916..499fdd544da 100644
--- a/chromium/components/wallpaper/wallpaper_color_calculator.cc
+++ b/chromium/components/wallpaper/wallpaper_color_calculator.cc
@@ -11,9 +11,44 @@
#include "base/metrics/histogram_macros.h"
#include "base/task_runner.h"
#include "base/task_runner_util.h"
+#include "components/wallpaper/wallpaper_color_calculator_observer.h"
namespace wallpaper {
+namespace {
+
+// The largest image size, in pixels, to synchronously calculate the prominent
+// color. This is a simple heuristic optimization because extraction on images
+// smaller than this should run very quickly, and offloading the task to another
+// thread would actually take longer.
+const int kMaxPixelsForSynchronousCalculation = 100;
+
+// Wrapper for color_utils::CalculateProminentColorOfBitmap() that records
+// wallpaper specific metrics.
+//
+// NOTE: |image| is intentionally a copy to ensure it exists for the duration of
+// the calculation.
+SkColor CalculateWallpaperColor(const gfx::ImageSkia image,
+ color_utils::LumaRange luma,
+ color_utils::SaturationRange saturation) {
+ base::TimeTicks start_time = base::TimeTicks::Now();
+ const SkColor prominent_color = color_utils::CalculateProminentColorOfBitmap(
+ *image.bitmap(), luma, saturation);
+
+ UMA_HISTOGRAM_TIMES("Ash.Wallpaper.ColorExtraction.Durations",
+ base::TimeTicks::Now() - start_time);
+ UMA_HISTOGRAM_BOOLEAN("Ash.Wallpaper.ColorExtractionResult",
+ prominent_color != SK_ColorTRANSPARENT);
+
+ return prominent_color;
+}
+
+bool ShouldCalculateSync(const gfx::ImageSkia& image) {
+ return image.width() * image.height() <= kMaxPixelsForSynchronousCalculation;
+}
+
+} // namespace
+
WallpaperColorCalculator::WallpaperColorCalculator(
const gfx::ImageSkia& image,
color_utils::LumaRange luma,
@@ -38,15 +73,19 @@ void WallpaperColorCalculator::RemoveObserver(
}
bool WallpaperColorCalculator::StartCalculation() {
- start_calculation_time_ = base::Time::Now();
+ if (ShouldCalculateSync(image_)) {
+ const SkColor prominent_color =
+ CalculateWallpaperColor(image_, luma_, saturation_);
+ NotifyCalculationComplete(prominent_color);
+ return true;
+ }
image_.MakeThreadSafe();
if (base::PostTaskAndReplyWithResult(
task_runner_.get(), FROM_HERE,
- base::Bind(&color_utils::CalculateProminentColorOfBitmap,
- *image_.bitmap(), luma_, saturation_),
- base::Bind(&WallpaperColorCalculator::NotifyCalculationComplete,
- weak_ptr_factory_.GetWeakPtr()))) {
+ base::Bind(&CalculateWallpaperColor, image_, luma_, saturation_),
+ base::Bind(&WallpaperColorCalculator::OnAsyncCalculationComplete,
+ weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now()))) {
return true;
}
@@ -62,11 +101,16 @@ void WallpaperColorCalculator::SetTaskRunnerForTest(
task_runner_ = task_runner;
}
-void WallpaperColorCalculator::NotifyCalculationComplete(
+void WallpaperColorCalculator::OnAsyncCalculationComplete(
+ base::TimeTicks async_start_time,
SkColor prominent_color) {
- UMA_HISTOGRAM_MEDIUM_TIMES("Ash.Wallpaper.TimeSpentExtractingColors",
- base::Time::Now() - start_calculation_time_);
+ UMA_HISTOGRAM_TIMES("Ash.Wallpaper.ColorExtraction.UserDelay",
+ base::TimeTicks::Now() - async_start_time);
+ NotifyCalculationComplete(prominent_color);
+}
+void WallpaperColorCalculator::NotifyCalculationComplete(
+ SkColor prominent_color) {
prominent_color_ = prominent_color;
for (auto& observer : observers_)
observer.OnColorCalculationComplete();
diff --git a/chromium/components/wallpaper/wallpaper_color_calculator.h b/chromium/components/wallpaper/wallpaper_color_calculator.h
index efad64bec17..c59c12e7139 100644
--- a/chromium/components/wallpaper/wallpaper_color_calculator.h
+++ b/chromium/components/wallpaper/wallpaper_color_calculator.h
@@ -10,7 +10,6 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
-#include "components/wallpaper/wallpaper_color_calculator_observer.h"
#include "components/wallpaper/wallpaper_export.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/color_analysis.h"
@@ -23,7 +22,7 @@ class TaskRunner;
namespace wallpaper {
class WallpaperColorCalculatorObserver;
-// Asynchronously calculates colors based on a wallpaper image.
+// Calculates colors based on a wallpaper image.
class WALLPAPER_EXPORT WallpaperColorCalculator {
public:
// |image|, |luma| and |saturation| are the input parameters to the color
@@ -39,7 +38,8 @@ class WALLPAPER_EXPORT WallpaperColorCalculator {
void RemoveObserver(WallpaperColorCalculatorObserver* observer);
// Initiates the calculation and returns false if the calculation fails to be
- // initiated. Callers should be aware that this will make |image_| read-only.
+ // initiated. Observers may be notified synchronously or asynchronously.
+ // Callers should be aware that this will make |image_| read-only.
bool StartCalculation() WARN_UNUSED_RESULT;
SkColor prominent_color() const { return prominent_color_; }
@@ -52,6 +52,11 @@ class WALLPAPER_EXPORT WallpaperColorCalculator {
void SetTaskRunnerForTest(scoped_refptr<base::TaskRunner> task_runner);
private:
+ // Handles asynchronous calculation results. |async_start_time| is used to
+ // record duration metrics.
+ void OnAsyncCalculationComplete(base::TimeTicks async_start_time,
+ SkColor prominent_color);
+
// Notifies observers that a color calulation has completed. Called on the
// same thread that constructed |this|.
void NotifyCalculationComplete(SkColor prominent_color);
@@ -71,10 +76,6 @@ class WALLPAPER_EXPORT WallpaperColorCalculator {
// The task runner to run the calculation on.
scoped_refptr<base::TaskRunner> task_runner_;
- // The time that StartCalculation() was last called. Used for recording
- // timing metrics.
- base::Time start_calculation_time_;
-
base::ObserverList<WallpaperColorCalculatorObserver> observers_;
base::WeakPtrFactory<WallpaperColorCalculator> weak_ptr_factory_;
diff --git a/chromium/components/wallpaper/wallpaper_color_calculator_unittest.cc b/chromium/components/wallpaper/wallpaper_color_calculator_unittest.cc
index 398d0fa95cb..938ec5ee85f 100644
--- a/chromium/components/wallpaper/wallpaper_color_calculator_unittest.cc
+++ b/chromium/components/wallpaper/wallpaper_color_calculator_unittest.cc
@@ -8,6 +8,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/test/histogram_tester.h"
#include "base/test/null_task_runner.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -27,6 +28,18 @@ namespace {
const SkColor kDefaultColor = SK_ColorTRANSPARENT;
+const SkColor kGray = SkColorSetRGB(10, 10, 10);
+
+const SkColor kVibrantGreen = SkColorSetRGB(25, 200, 25);
+
+// Image size that causes the WallpaperColorCalculator to synchronously extract
+// the prominent color.
+constexpr gfx::Size kSyncImageSize = gfx::Size(5, 5);
+
+// Image size that causes the WallpaperColorCalculator to asynchronously extract
+// the prominent color.
+constexpr gfx::Size kAsyncImageSize = gfx::Size(50, 50);
+
class TestWallpaperColorCalculatorObserver
: public WallpaperColorCalculatorObserver {
public:
@@ -45,6 +58,24 @@ class TestWallpaperColorCalculatorObserver
DISALLOW_COPY_AND_ASSIGN(TestWallpaperColorCalculatorObserver);
};
+// Returns an image that will yield a color when processing it with
+// color_utils::CalculateProminentColorOfBitmap() using the LumaRange::NORMAL
+// and SaturationRange::VIBRANT values.
+gfx::ImageSkia CreateColorProducingImage(const gfx::Size& size) {
+ gfx::Canvas canvas(size, 1.0f, true);
+ canvas.DrawColor(kGray);
+ canvas.FillRect(gfx::Rect(0, 1, size.height(), 1), kVibrantGreen);
+ return gfx::ImageSkia::CreateFrom1xBitmap(canvas.GetBitmap());
+}
+
+// Returns an image that will not yield a color when processing it with
+// color_utils::CalculateProminentColorOfBitmap().
+gfx::ImageSkia CreateNonColorProducingImage(const gfx::Size& size) {
+ gfx::Canvas canvas(size, 1.0f, true);
+ canvas.DrawColor(kGray);
+ return gfx::ImageSkia::CreateFrom1xBitmap(canvas.GetBitmap());
+}
+
} // namespace
class WallPaperColorCalculatorTest : public testing::Test {
@@ -53,19 +84,26 @@ class WallPaperColorCalculatorTest : public testing::Test {
~WallPaperColorCalculatorTest() override;
protected:
+ // Installs the given |task_runner| globally and on the |calculator_| instance
+ // if it exists.
void InstallTaskRunner(
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
- gfx::ImageSkia image_;
+ // Creates a new |calculator_| for the given |image| and installs the current
+ // |task_runner_|.
+ void CreateCalculator(const gfx::ImageSkia& image);
std::unique_ptr<WallpaperColorCalculator> calculator_;
+ // Required for asynchronous calculations.
scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
TestWallpaperColorCalculatorObserver observer_;
+ base::HistogramTester histograms_;
+
private:
- // Required by PostTaskAndReplyImpl.
+ // Required for asynchronous calculations, e.g. by PostTaskAndReplyImpl.
std::unique_ptr<base::ThreadTaskRunnerHandle> task_runner_handle_;
DISALLOW_COPY_AND_ASSIGN(WallPaperColorCalculatorTest);
@@ -73,22 +111,7 @@ class WallPaperColorCalculatorTest : public testing::Test {
WallPaperColorCalculatorTest::WallPaperColorCalculatorTest()
: task_runner_(new base::TestMockTimeTaskRunner()) {
- // Creates an |image_| that will yield a non-default prominent color.
- const gfx::Size kImageSize(300, 200);
- const SkColor kGray = SkColorSetRGB(10, 10, 10);
- const SkColor kVibrantGreen = SkColorSetRGB(25, 200, 25);
-
- gfx::Canvas canvas(kImageSize, 1.0f, true);
- canvas.FillRect(gfx::Rect(kImageSize), kGray);
- canvas.FillRect(gfx::Rect(0, 1, 300, 1), kVibrantGreen);
-
- image_ = gfx::ImageSkia::CreateFrom1xBitmap(canvas.ToBitmap());
-
- calculator_ = base::MakeUnique<WallpaperColorCalculator>(
- image_, color_utils::LumaRange::NORMAL,
- color_utils::SaturationRange::VIBRANT, nullptr);
- calculator_->AddObserver(&observer_);
-
+ CreateCalculator(CreateColorProducingImage(kAsyncImageSize));
InstallTaskRunner(task_runner_);
}
@@ -99,20 +122,55 @@ void WallPaperColorCalculatorTest::InstallTaskRunner(
task_runner_handle_.reset();
task_runner_handle_ =
base::MakeUnique<base::ThreadTaskRunnerHandle>(task_runner);
- calculator_->SetTaskRunnerForTest(task_runner);
+ if (calculator_)
+ calculator_->SetTaskRunnerForTest(task_runner);
}
-TEST_F(WallPaperColorCalculatorTest,
- StartCalculationReturnsFalseWhenPostingTaskFails) {
+void WallPaperColorCalculatorTest::CreateCalculator(
+ const gfx::ImageSkia& image) {
+ calculator_ = base::MakeUnique<WallpaperColorCalculator>(
+ image, color_utils::LumaRange::NORMAL,
+ color_utils::SaturationRange::VIBRANT, task_runner_);
+ calculator_->AddObserver(&observer_);
+}
+
+// Used to group the asynchronous calculation tests.
+typedef WallPaperColorCalculatorTest WallPaperColorCalculatorAsyncTest;
+
+TEST_F(WallPaperColorCalculatorAsyncTest, MetricsForSuccessfulExtraction) {
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtractionResult", 0);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.Durations", 0);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.UserDelay", 0);
+
+ EXPECT_TRUE(calculator_->StartCalculation());
+ task_runner_->RunUntilIdle();
+
+ histograms_.ExpectUniqueSample("Ash.Wallpaper.ColorExtractionResult", true,
+ 1);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.Durations", 1);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.UserDelay", 1);
+}
+
+TEST_F(WallPaperColorCalculatorAsyncTest, MetricsWhenPostingTaskFails) {
scoped_refptr<base::NullTaskRunner> task_runner = new base::NullTaskRunner();
InstallTaskRunner(task_runner);
- calculator_->set_prominent_color_for_test(SK_ColorBLACK);
+
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtractionResult", 0);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.Durations", 0);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.UserDelay", 0);
EXPECT_FALSE(calculator_->StartCalculation());
+ task_runner_->RunUntilIdle();
+
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtractionResult", 0);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.Durations", 0);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.UserDelay", 0);
+
EXPECT_EQ(kDefaultColor, calculator_->prominent_color());
}
-TEST_F(WallPaperColorCalculatorTest, ObserverNotifiedOnSuccessfulCalculation) {
+TEST_F(WallPaperColorCalculatorAsyncTest,
+ ObserverNotifiedOnSuccessfulCalculation) {
EXPECT_FALSE(observer_.WasNotified());
EXPECT_TRUE(calculator_->StartCalculation());
@@ -122,7 +180,7 @@ TEST_F(WallPaperColorCalculatorTest, ObserverNotifiedOnSuccessfulCalculation) {
EXPECT_TRUE(observer_.WasNotified());
}
-TEST_F(WallPaperColorCalculatorTest, ColorUpdatedOnSuccessfulCalculation) {
+TEST_F(WallPaperColorCalculatorAsyncTest, ColorUpdatedOnSuccessfulCalculation) {
calculator_->set_prominent_color_for_test(kDefaultColor);
EXPECT_TRUE(calculator_->StartCalculation());
@@ -132,7 +190,7 @@ TEST_F(WallPaperColorCalculatorTest, ColorUpdatedOnSuccessfulCalculation) {
EXPECT_NE(kDefaultColor, calculator_->prominent_color());
}
-TEST_F(WallPaperColorCalculatorTest,
+TEST_F(WallPaperColorCalculatorAsyncTest,
NoCrashWhenCalculatorDestroyedBeforeTaskProcessing) {
EXPECT_TRUE(calculator_->StartCalculation());
calculator_.reset();
@@ -144,4 +202,38 @@ TEST_F(WallPaperColorCalculatorTest,
EXPECT_FALSE(task_runner_->HasPendingTask());
}
+// Used to group the synchronous calculation tests.
+typedef WallPaperColorCalculatorTest WallPaperColorCalculatorSyncTest;
+
+TEST_F(WallPaperColorCalculatorSyncTest, MetricsForSuccessfulExtraction) {
+ CreateCalculator(CreateColorProducingImage(kSyncImageSize));
+ calculator_->SetTaskRunnerForTest(nullptr);
+
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtractionResult", 0);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.Durations", 0);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.UserDelay", 0);
+
+ EXPECT_TRUE(calculator_->StartCalculation());
+
+ histograms_.ExpectUniqueSample("Ash.Wallpaper.ColorExtractionResult", true,
+ 1);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.Durations", 1);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.UserDelay", 0);
+}
+
+TEST_F(WallPaperColorCalculatorSyncTest, MetricsForFailedExctraction) {
+ CreateCalculator(CreateNonColorProducingImage(kSyncImageSize));
+
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtractionResult", 0);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.Durations", 0);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.UserDelay", 0);
+
+ EXPECT_TRUE(calculator_->StartCalculation());
+
+ histograms_.ExpectUniqueSample("Ash.Wallpaper.ColorExtractionResult", false,
+ 1);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.Durations", 1);
+ histograms_.ExpectTotalCount("Ash.Wallpaper.ColorExtraction.UserDelay", 0);
+}
+
} // namespace wallpaper
diff --git a/chromium/components/wallpaper/wallpaper_manager_base.cc b/chromium/components/wallpaper/wallpaper_manager_base.cc
index f81a395cbc5..188580d6e89 100644
--- a/chromium/components/wallpaper/wallpaper_manager_base.cc
+++ b/chromium/components/wallpaper/wallpaper_manager_base.cc
@@ -372,6 +372,22 @@ bool WallpaperManagerBase::GetLoggedInUserWallpaperInfo(WallpaperInfo* info) {
user_manager::UserManager::Get()->GetActiveUser()->GetAccountId(), info);
}
+void WallpaperManagerBase::SetDefaultWallpaper(const AccountId& account_id,
+ bool update_wallpaper) {
+ RemoveUserWallpaperInfo(account_id);
+
+ const wallpaper::WallpaperInfo info = {
+ std::string(), wallpaper::WALLPAPER_LAYOUT_CENTER,
+ user_manager::User::DEFAULT, base::Time::Now().LocalMidnight()};
+ const bool is_persistent =
+ !user_manager::UserManager::Get()->IsUserNonCryptohomeDataEphemeral(
+ account_id);
+ SetUserWallpaperInfo(account_id, info, is_persistent);
+
+ if (update_wallpaper)
+ SetDefaultWallpaperNow(account_id);
+}
+
// static
bool WallpaperManagerBase::ResizeImage(
const gfx::ImageSkia& image,
diff --git a/chromium/components/wallpaper/wallpaper_manager_base.h b/chromium/components/wallpaper/wallpaper_manager_base.h
index 3c31f52bf5a..88601cc801e 100644
--- a/chromium/components/wallpaper/wallpaper_manager_base.h
+++ b/chromium/components/wallpaper/wallpaper_manager_base.h
@@ -276,6 +276,11 @@ class WALLPAPER_EXPORT WallpaperManagerBase {
const gfx::ImageSkia& image,
bool update_wallpaper) = 0;
+ // Updates wallpaper info for |account_id| to default. If |update_wallpaper|
+ // is false, don't change wallpaper but only update cache.
+ virtual void SetDefaultWallpaper(const AccountId& account_id,
+ bool update_wallpaper);
+
// Use given files as new default wallpaper.
// Reloads current wallpaper, if old default was loaded.
// Current value of default_wallpaper_image_ is destroyed.
diff --git a/chromium/components/wallpaper/wallpaper_resizer.cc b/chromium/components/wallpaper/wallpaper_resizer.cc
index 545a9cc4d00..0bfa3d4648c 100644
--- a/chromium/components/wallpaper/wallpaper_resizer.cc
+++ b/chromium/components/wallpaper/wallpaper_resizer.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
#include "base/task_runner.h"
#include "components/wallpaper/wallpaper_resizer_observer.h"
#include "third_party/skia/include/core/SkImage.h"
@@ -23,14 +24,19 @@ int RoundPositive(double x) {
return static_cast<int>(floor(x + 0.5));
}
-// Resizes |orig_bitmap| to |target_size| using |layout| and stores the
+// Resizes |image| to |target_size| using |layout| and stores the
// resulting bitmap at |resized_bitmap_out|.
-void Resize(SkBitmap orig_bitmap,
+//
+// NOTE: |image| is intentionally a copy to ensure it exists for the duration of
+// the function.
+void Resize(const gfx::ImageSkia image,
const gfx::Size& target_size,
WallpaperLayout layout,
SkBitmap* resized_bitmap_out,
base::TaskRunner* task_runner) {
DCHECK(task_runner->RunsTasksOnCurrentThread());
+
+ SkBitmap orig_bitmap = *image.bitmap();
SkBitmap new_bitmap = orig_bitmap;
const int orig_width = orig_bitmap.width();
@@ -121,11 +127,13 @@ WallpaperResizer::~WallpaperResizer() {
}
void WallpaperResizer::StartResize() {
+ start_calculation_time_ = base::TimeTicks::Now();
+
SkBitmap* resized_bitmap = new SkBitmap;
if (!task_runner_->PostTaskAndReply(
FROM_HERE,
- base::Bind(&Resize, *image_.bitmap(), target_size_, layout_,
- resized_bitmap, base::RetainedRef(task_runner_)),
+ base::Bind(&Resize, image_, target_size_, layout_, resized_bitmap,
+ base::RetainedRef(task_runner_)),
base::Bind(&WallpaperResizer::OnResizeFinished,
weak_ptr_factory_.GetWeakPtr(),
base::Owned(resized_bitmap)))) {
@@ -144,6 +152,9 @@ void WallpaperResizer::RemoveObserver(WallpaperResizerObserver* observer) {
void WallpaperResizer::OnResizeFinished(SkBitmap* resized_bitmap) {
image_ = gfx::ImageSkia::CreateFrom1xBitmap(*resized_bitmap);
+ UMA_HISTOGRAM_TIMES("Ash.Wallpaper.TimeSpentResizing",
+ base::TimeTicks::Now() - start_calculation_time_);
+
for (auto& observer : observers_)
observer.OnWallpaperResized();
}
diff --git a/chromium/components/wallpaper/wallpaper_resizer.h b/chromium/components/wallpaper/wallpaper_resizer.h
index 836470d58af..ee96fc403ad 100644
--- a/chromium/components/wallpaper/wallpaper_resizer.h
+++ b/chromium/components/wallpaper/wallpaper_resizer.h
@@ -11,6 +11,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
+#include "base/time/time.h"
#include "components/wallpaper/wallpaper_layout.h"
#include "components/wallpaper/wallpaper_resizer_observer.h"
#include "skia/ext/image_operations.h"
@@ -73,6 +74,10 @@ class WALLPAPER_EXPORT WallpaperResizer {
WallpaperLayout layout_;
+ // The time that StartResize() was last called. Used for recording timing
+ // metrics.
+ base::TimeTicks start_calculation_time_;
+
scoped_refptr<base::TaskRunner> task_runner_;
base::WeakPtrFactory<WallpaperResizer> weak_ptr_factory_;
diff --git a/chromium/components/web_cache/browser/web_cache_manager.cc b/chromium/components/web_cache/browser/web_cache_manager.cc
index fe215e6a3c3..e94ef7f3801 100644
--- a/chromium/components/web_cache/browser/web_cache_manager.cc
+++ b/chromium/components/web_cache/browser/web_cache_manager.cc
@@ -94,7 +94,7 @@ void WebCacheManager::Add(int renderer_id) {
content::RenderProcessHost::FromID(renderer_id);
if (host) {
mojom::WebCachePtr service;
- host->GetRemoteInterfaces()->GetInterface(&service);
+ BindInterface(host, &service);
web_cache_services_[renderer_id] = std::move(service);
}
diff --git a/chromium/components/web_cache/browser/web_cache_manager_unittest.cc b/chromium/components/web_cache/browser/web_cache_manager_unittest.cc
index e697b36e217..b8f50253499 100644
--- a/chromium/components/web_cache/browser/web_cache_manager_unittest.cc
+++ b/chromium/components/web_cache/browser/web_cache_manager_unittest.cc
@@ -6,15 +6,12 @@
#include <string>
-#include "base/message_loop/message_loop.h"
#include "components/web_cache/browser/web_cache_manager.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::Time;
using base::TimeDelta;
-using content::BrowserThread;
-
namespace web_cache {
class WebCacheManagerTest : public testing::Test {
@@ -28,9 +25,7 @@ class WebCacheManagerTest : public testing::Test {
static const WebCacheManager::RendererInfo kStats;
static const WebCacheManager::RendererInfo kStats2;
- WebCacheManagerTest()
- : ui_thread_(BrowserThread::UI, &message_loop_) {
- }
+ WebCacheManagerTest() = default;
// Thunks to access protected members of WebCacheManager
static std::map<int, WebCacheManager::RendererInfo>& stats(
@@ -99,8 +94,7 @@ class WebCacheManagerTest : public testing::Test {
private:
WebCacheManager manager_;
- base::MessageLoop message_loop_;
- content::TestBrowserThread ui_thread_;
+ content::TestBrowserThreadBundle test_browser_thread_bundle_;
};
// static
diff --git a/chromium/components/web_cache/renderer/web_cache_impl.cc b/chromium/components/web_cache/renderer/web_cache_impl.cc
index 664c4fff595..c4e73bf95f5 100644
--- a/chromium/components/web_cache/renderer/web_cache_impl.cc
+++ b/chromium/components/web_cache/renderer/web_cache_impl.cc
@@ -36,7 +36,7 @@ void WebCacheImpl::ExecutePendingClearCache() {
case kNavigate_Pending:
break;
case kClearCache_Pending:
- blink::WebCache::clear();
+ blink::WebCache::Clear();
clear_cache_state_ = kInit;
break;
}
@@ -45,12 +45,12 @@ void WebCacheImpl::ExecutePendingClearCache() {
void WebCacheImpl::SetCacheCapacity(uint64_t capacity64) {
size_t capacity = base::checked_cast<size_t>(capacity64);
- blink::WebCache::setCapacity(capacity);
+ blink::WebCache::SetCapacity(capacity);
}
void WebCacheImpl::ClearCache(bool on_navigation) {
if (!on_navigation) {
- blink::WebCache::clear();
+ blink::WebCache::Clear();
return;
}
@@ -59,7 +59,7 @@ void WebCacheImpl::ClearCache(bool on_navigation) {
clear_cache_state_ = kClearCache_Pending;
break;
case kNavigate_Pending:
- blink::WebCache::clear();
+ blink::WebCache::Clear();
clear_cache_state_ = kInit;
break;
case kClearCache_Pending:
diff --git a/chromium/components/web_contents_delegate_android/OWNERS b/chromium/components/web_contents_delegate_android/OWNERS
index 4048140c419..be737980458 100644
--- a/chromium/components/web_contents_delegate_android/OWNERS
+++ b/chromium/components/web_contents_delegate_android/OWNERS
@@ -1,2 +1,4 @@
boliu@chromium.org
tedchoc@chromium.org
+
+# COMPONENT: Internals>Core
diff --git a/chromium/components/web_modal/BUILD.gn b/chromium/components/web_modal/BUILD.gn
index a06653225d4..40e777598dc 100644
--- a/chromium/components/web_modal/BUILD.gn
+++ b/chromium/components/web_modal/BUILD.gn
@@ -17,12 +17,15 @@ static_library("web_modal") {
"web_contents_modal_dialog_manager_delegate.h",
]
- deps = [
+ public_deps = [
"//base",
"//content/public/browser",
+ "//ui/gfx",
+ ]
+
+ deps = [
"//net",
"//skia",
- "//ui/gfx",
"//ui/gfx/geometry",
]
}
diff --git a/chromium/components/web_resource/BUILD.gn b/chromium/components/web_resource/BUILD.gn
index a80ee8d2520..c4b874b848b 100644
--- a/chromium/components/web_resource/BUILD.gn
+++ b/chromium/components/web_resource/BUILD.gn
@@ -43,6 +43,7 @@ source_set("unit_tests") {
sources = [
"eula_accepted_notifier_unittest.cc",
"resource_request_allowed_notifier_unittest.cc",
+ "web_resource_service_unittest.cc",
]
deps = [
diff --git a/chromium/components/web_resource/web_resource_service.cc b/chromium/components/web_resource/web_resource_service.cc
index 9d2e5d70abc..d65904c166e 100644
--- a/chromium/components/web_resource/web_resource_service.cc
+++ b/chromium/components/web_resource/web_resource_service.cc
@@ -42,9 +42,12 @@ WebResourceService::WebResourceService(
int cache_update_delay_ms,
net::URLRequestContextGetter* request_context,
const char* disable_network_switch,
- const ParseJSONCallback& parse_json_callback)
+ const ParseJSONCallback& parse_json_callback,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation)
: prefs_(prefs),
- resource_request_allowed_notifier_(prefs, disable_network_switch),
+ resource_request_allowed_notifier_(
+ new ResourceRequestAllowedNotifier(prefs, disable_network_switch)),
+ fetch_scheduled_(false),
in_fetch_(false),
web_resource_server_(web_resource_server),
application_locale_(application_locale),
@@ -53,14 +56,15 @@ WebResourceService::WebResourceService(
cache_update_delay_ms_(cache_update_delay_ms),
request_context_(request_context),
parse_json_callback_(parse_json_callback),
+ traffic_annotation_(traffic_annotation),
weak_ptr_factory_(this) {
- resource_request_allowed_notifier_.Init(this);
+ resource_request_allowed_notifier_->Init(this);
DCHECK(prefs);
}
void WebResourceService::StartAfterDelay() {
// If resource requests are not allowed, we'll get a callback when they are.
- if (resource_request_allowed_notifier_.ResourceRequestsAllowed())
+ if (resource_request_allowed_notifier_->ResourceRequestsAllowed())
OnResourceRequestsAllowed();
}
@@ -100,15 +104,35 @@ void WebResourceService::OnURLFetchComplete(const net::URLFetcher* source) {
// Delay initial load of resource data into cache so as not to interfere
// with startup time.
void WebResourceService::ScheduleFetch(int64_t delay_ms) {
+ if (fetch_scheduled_)
+ return;
+ fetch_scheduled_ = true;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::Bind(&WebResourceService::StartFetch,
weak_ptr_factory_.GetWeakPtr()),
base::TimeDelta::FromMilliseconds(delay_ms));
}
+void WebResourceService::SetResourceRequestAllowedNotifier(
+ std::unique_ptr<ResourceRequestAllowedNotifier> notifier) {
+ resource_request_allowed_notifier_ = std::move(notifier);
+ resource_request_allowed_notifier_->Init(this);
+}
+
+bool WebResourceService::GetFetchScheduled() const {
+ return fetch_scheduled_;
+}
+
// Initializes the fetching of data from the resource server. Data
// load calls OnURLFetchComplete.
void WebResourceService::StartFetch() {
+ // Set to false so that next fetch can be scheduled after this fetch or
+ // if we recieve notification that resource is allowed.
+ fetch_scheduled_ = false;
+ // Check whether fetching is allowed.
+ if (!resource_request_allowed_notifier_->ResourceRequestsAllowed())
+ return;
+
// First, put our next cache load on the MessageLoop.
ScheduleFetch(cache_update_delay_ms_);
@@ -128,8 +152,8 @@ void WebResourceService::StartFetch() {
application_locale_);
DVLOG(1) << "WebResourceService StartFetch " << web_resource_server;
- url_fetcher_ =
- net::URLFetcher::Create(web_resource_server, net::URLFetcher::GET, this);
+ url_fetcher_ = net::URLFetcher::Create(
+ web_resource_server, net::URLFetcher::GET, this, traffic_annotation_);
data_use_measurement::DataUseUserData::AttachToFetcher(
url_fetcher_.get(),
data_use_measurement::DataUseUserData::WEB_RESOURCE_SERVICE);
diff --git a/chromium/components/web_resource/web_resource_service.h b/chromium/components/web_resource/web_resource_service.h
index 1c1103ab951..7dab6ab9a75 100644
--- a/chromium/components/web_resource/web_resource_service.h
+++ b/chromium/components/web_resource/web_resource_service.h
@@ -15,6 +15,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "components/web_resource/resource_request_allowed_notifier.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "url/gurl.h"
@@ -47,15 +48,17 @@ class WebResourceService
// Creates a new WebResourceService.
// If |application_locale| is not empty, it will be appended as a locale
// parameter to the resource URL.
- WebResourceService(PrefService* prefs,
- const GURL& web_resource_server,
- const std::string& application_locale, // May be empty
- const char* last_update_time_pref_name,
- int start_fetch_delay_ms,
- int cache_update_delay_ms,
- net::URLRequestContextGetter* request_context,
- const char* disable_network_switch,
- const ParseJSONCallback& parse_json_callback);
+ WebResourceService(
+ PrefService* prefs,
+ const GURL& web_resource_server,
+ const std::string& application_locale, // May be empty
+ const char* last_update_time_pref_name,
+ int start_fetch_delay_ms,
+ int cache_update_delay_ms,
+ net::URLRequestContextGetter* request_context,
+ const char* disable_network_switch,
+ const ParseJSONCallback& parse_json_callback,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation);
~WebResourceService() override;
@@ -64,10 +67,17 @@ class WebResourceService
// Then begin updating resources.
void StartAfterDelay();
+ // Sets the ResourceRequestAllowedNotifier to make it configurable.
+ void SetResourceRequestAllowedNotifier(
+ std::unique_ptr<ResourceRequestAllowedNotifier> notifier);
+
protected:
PrefService* prefs_;
+ bool GetFetchScheduled() const;
private:
+ friend class WebResourceServiceTest;
+
// For the subclasses to process the result of a fetch.
virtual void Unpack(const base::DictionaryValue& parsed_json) = 0;
@@ -92,7 +102,15 @@ class WebResourceService
// Helper class used to tell this service if it's allowed to make network
// resource requests.
- ResourceRequestAllowedNotifier resource_request_allowed_notifier_;
+ std::unique_ptr<ResourceRequestAllowedNotifier>
+ resource_request_allowed_notifier_;
+
+ // True if we have scheduled a fetch after start_fetch_delay_ms_
+ // or another one in |cache_update_delay_ms_| time. Set to false
+ // before fetching starts so that next fetch is scheduled. This
+ // is to make sure not more than one fetch is scheduled for given
+ // point in time.
+ bool fetch_scheduled_;
// The tool that fetches the url data from the server.
std::unique_ptr<net::URLFetcher> url_fetcher_;
@@ -124,6 +142,9 @@ class WebResourceService
// Callback used to parse JSON.
ParseJSONCallback parse_json_callback_;
+ // Network traffic annotation for initialization of URLFetcher.
+ const net::NetworkTrafficAnnotationTag traffic_annotation_;
+
// So that we can delay our start so as not to affect start-up time; also,
// so that we can schedule future cache updates.
base::WeakPtrFactory<WebResourceService> weak_ptr_factory_;
diff --git a/chromium/components/web_resource/web_resource_service_unittest.cc b/chromium/components/web_resource/web_resource_service_unittest.cc
new file mode 100644
index 00000000000..b8758105d3f
--- /dev/null
+++ b/chromium/components/web_resource/web_resource_service_unittest.cc
@@ -0,0 +1,156 @@
+// 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 <utility>
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/values.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/web_resource/resource_request_allowed_notifier.h"
+#include "components/web_resource/web_resource_service.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "net/url_request/url_request_status.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+const std::string kTestUrl = "http://www.test.com";
+const std::string kCacheUpdatePath = "cache_update_path";
+std::string error_message_;
+} // namespace
+
+namespace web_resource {
+
+class TestResourceRequestAllowedNotifier
+ : public ResourceRequestAllowedNotifier {
+ public:
+ TestResourceRequestAllowedNotifier(PrefService* prefs,
+ const char* disable_network_switch)
+ : ResourceRequestAllowedNotifier(prefs, disable_network_switch) {}
+
+ ResourceRequestAllowedNotifier::State GetResourceRequestsAllowedState()
+ override {
+ return state_;
+ }
+
+ void SetState(ResourceRequestAllowedNotifier::State state) { state_ = state; }
+
+ void NotifyState(ResourceRequestAllowedNotifier::State state) {
+ SetState(state);
+ SetObserverRequestedForTesting(true);
+ MaybeNotifyObserver();
+ }
+
+ private:
+ ResourceRequestAllowedNotifier::State state_;
+};
+
+class TestWebResourceService : public WebResourceService {
+ public:
+ TestWebResourceService(PrefService* prefs,
+ const GURL& web_resource_server,
+ const std::string& application_locale,
+ const char* last_update_time_pref_name,
+ int start_fetch_delay_ms,
+ int cache_update_delay_ms,
+ net::URLRequestContextGetter* request_context,
+ const char* disable_network_switch,
+ const ParseJSONCallback& parse_json_callback)
+ : WebResourceService(prefs,
+ web_resource_server,
+ application_locale,
+ last_update_time_pref_name,
+ start_fetch_delay_ms,
+ cache_update_delay_ms,
+ request_context,
+ disable_network_switch,
+ parse_json_callback,
+ TRAFFIC_ANNOTATION_FOR_TESTS){};
+
+ void Unpack(const base::DictionaryValue& parsed_json) override{};
+};
+
+class WebResourceServiceTest : public testing::Test {
+ public:
+ WebResourceServiceTest() {}
+
+ void SetUp() override {
+ request_context_getter_ = new net::TestURLRequestContextGetter(
+ base::ThreadTaskRunnerHandle::Get());
+ local_state_.reset(new TestingPrefServiceSimple());
+ local_state_->registry()->RegisterStringPref(kCacheUpdatePath, "0");
+ test_web_resource_service_.reset(new TestWebResourceService(
+ local_state_.get(), GURL(kTestUrl), "", kCacheUpdatePath.c_str(), 100,
+ 5000, request_context_getter_.get(), nullptr,
+ base::Bind(web_resource::WebResourceServiceTest::Parse)));
+ error_message_ = "";
+ TestResourceRequestAllowedNotifier* notifier =
+ new TestResourceRequestAllowedNotifier(local_state_.get(), nullptr);
+ notifier->SetState(ResourceRequestAllowedNotifier::ALLOWED);
+ test_web_resource_service_->SetResourceRequestAllowedNotifier(
+ std::unique_ptr<ResourceRequestAllowedNotifier>(notifier));
+ }
+
+ TestResourceRequestAllowedNotifier* resource_notifier() {
+ return static_cast<TestResourceRequestAllowedNotifier*>(
+ test_web_resource_service_->resource_request_allowed_notifier_.get());
+ }
+
+ bool GetFetchScheduled() {
+ return test_web_resource_service_->GetFetchScheduled();
+ }
+
+ void CallScheduleFetch(int64_t delay_ms) {
+ return test_web_resource_service_->ScheduleFetch(delay_ms);
+ }
+
+ static void Parse(const std::string& unsafe_json,
+ const WebResourceService::SuccessCallback& success_callback,
+ const WebResourceService::ErrorCallback& error_callback) {
+ std::unique_ptr<base::Value> value;
+ if (!error_message_.empty())
+ error_callback.Run(error_message_);
+ else
+ success_callback.Run(std::move(value));
+ }
+
+ WebResourceService* web_resource_service() {
+ return test_web_resource_service_.get();
+ }
+
+ void CallStartFetch() { test_web_resource_service_->StartFetch(); }
+
+ private:
+ base::MessageLoop message_loop_; // needed for TestURLFetcherFactory
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+ std::unique_ptr<TestingPrefServiceSimple> local_state_;
+ std::unique_ptr<TestWebResourceService> test_web_resource_service_;
+};
+
+TEST_F(WebResourceServiceTest, FetchScheduledAfterStartDelayTest) {
+ web_resource_service()->StartAfterDelay();
+ EXPECT_TRUE(GetFetchScheduled());
+}
+
+TEST_F(WebResourceServiceTest, FetchScheduledOnScheduleFetchTest) {
+ web_resource_service()->StartAfterDelay();
+ resource_notifier()->NotifyState(ResourceRequestAllowedNotifier::ALLOWED);
+ EXPECT_TRUE(GetFetchScheduled());
+}
+
+TEST_F(WebResourceServiceTest, FetchScheduledOnStartFetchTest) {
+ resource_notifier()->NotifyState(
+ ResourceRequestAllowedNotifier::DISALLOWED_NETWORK_DOWN);
+ CallStartFetch();
+ EXPECT_FALSE(GetFetchScheduled());
+ resource_notifier()->NotifyState(ResourceRequestAllowedNotifier::ALLOWED);
+ EXPECT_TRUE(GetFetchScheduled());
+}
+
+} // namespace web_resource
diff --git a/chromium/components/webcrypto/BUILD.gn b/chromium/components/webcrypto/BUILD.gn
index 1b13587e66f..576247ddf4e 100644
--- a/chromium/components/webcrypto/BUILD.gn
+++ b/chromium/components/webcrypto/BUILD.gn
@@ -164,7 +164,7 @@ fuzzer_test("webcrypto_rsa_import_key_pkcs8_fuzzer") {
# Tests the import of SPKI formatted RSA keys.
fuzzer_test("webcrypto_rsa_import_key_spki_fuzzer") {
sources = [
- "rsa_import_key_pkcs8_fuzzer.cc",
+ "rsa_import_key_spki_fuzzer.cc",
]
deps = [
":fuzzer_support",
diff --git a/chromium/components/webcrypto/algorithm_dispatch.cc b/chromium/components/webcrypto/algorithm_dispatch.cc
index 5c503167051..52d3adef363 100644
--- a/chromium/components/webcrypto/algorithm_dispatch.cc
+++ b/chromium/components/webcrypto/algorithm_dispatch.cc
@@ -22,11 +22,11 @@ Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
- if (algorithm.id() != key.algorithm().id())
+ if (algorithm.Id() != key.Algorithm().Id())
return Status::ErrorUnexpected();
const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
+ Status status = GetAlgorithmImplementation(algorithm.Id(), &impl);
if (status.IsError())
return status;
@@ -37,11 +37,11 @@ Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
- if (algorithm.id() != key.algorithm().id())
+ if (algorithm.Id() != key.Algorithm().Id())
return Status::ErrorUnexpected();
const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
+ Status status = GetAlgorithmImplementation(algorithm.Id(), &impl);
if (status.IsError())
return status;
@@ -52,7 +52,7 @@ Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format,
const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) {
const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(key.algorithm().id(), &impl);
+ Status status = GetAlgorithmImplementation(key.Algorithm().Id(), &impl);
if (status.IsError())
return status;
@@ -65,7 +65,7 @@ Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
- if (!key.keyUsageAllows(blink::WebCryptoKeyUsageEncrypt))
+ if (!key.KeyUsageAllows(blink::kWebCryptoKeyUsageEncrypt))
return Status::ErrorUnexpected();
return EncryptDontCheckUsage(algorithm, key, data, buffer);
}
@@ -74,7 +74,7 @@ Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
- if (!key.keyUsageAllows(blink::WebCryptoKeyUsageDecrypt))
+ if (!key.KeyUsageAllows(blink::kWebCryptoKeyUsageDecrypt))
return Status::ErrorUnexpected();
return DecryptDontCheckKeyUsage(algorithm, key, data, buffer);
}
@@ -83,7 +83,7 @@ Status Digest(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
+ Status status = GetAlgorithmImplementation(algorithm.Id(), &impl);
if (status.IsError())
return status;
@@ -95,7 +95,7 @@ Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
blink::WebCryptoKeyUsageMask usages,
GenerateKeyResult* result) {
const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
+ Status status = GetAlgorithmImplementation(algorithm.Id(), &impl);
if (status.IsError())
return status;
@@ -125,7 +125,7 @@ Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
if (key == NULL)
return Status::ErrorUnexpected();
- if (key->usages() == 0) {
+ if (key->Usages() == 0) {
return Status::ErrorCreateKeyEmptyUsages();
}
@@ -139,7 +139,7 @@ Status ImportKey(blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) {
const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
+ Status status = GetAlgorithmImplementation(algorithm.Id(), &impl);
if (status.IsError())
return status;
@@ -155,8 +155,9 @@ Status ImportKey(blink::WebCryptoKeyFormat format,
//
// 14.3.9.9: If the [[type]] internal slot of result is "secret" or "private"
// and usages is empty, then throw a SyntaxError.
- if (key->usages() == 0 && (key->type() == blink::WebCryptoKeyTypeSecret ||
- key->type() == blink::WebCryptoKeyTypePrivate)) {
+ if (key->Usages() == 0 &&
+ (key->GetType() == blink::kWebCryptoKeyTypeSecret ||
+ key->GetType() == blink::kWebCryptoKeyTypePrivate)) {
return Status::ErrorCreateKeyEmptyUsages();
}
@@ -166,7 +167,7 @@ Status ImportKey(blink::WebCryptoKeyFormat format,
Status ExportKey(blink::WebCryptoKeyFormat format,
const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) {
- if (!key.extractable())
+ if (!key.Extractable())
return Status::ErrorKeyNotExtractable();
return ExportKeyDontCheckExtractability(format, key, buffer);
}
@@ -175,13 +176,13 @@ Status Sign(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
- if (!key.keyUsageAllows(blink::WebCryptoKeyUsageSign))
+ if (!key.KeyUsageAllows(blink::kWebCryptoKeyUsageSign))
return Status::ErrorUnexpected();
- if (algorithm.id() != key.algorithm().id())
+ if (algorithm.Id() != key.Algorithm().Id())
return Status::ErrorUnexpected();
const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
+ Status status = GetAlgorithmImplementation(algorithm.Id(), &impl);
if (status.IsError())
return status;
@@ -193,13 +194,13 @@ Status Verify(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& signature,
const CryptoData& data,
bool* signature_match) {
- if (!key.keyUsageAllows(blink::WebCryptoKeyUsageVerify))
+ if (!key.KeyUsageAllows(blink::kWebCryptoKeyUsageVerify))
return Status::ErrorUnexpected();
- if (algorithm.id() != key.algorithm().id())
+ if (algorithm.Id() != key.Algorithm().Id())
return Status::ErrorUnexpected();
const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
+ Status status = GetAlgorithmImplementation(algorithm.Id(), &impl);
if (status.IsError())
return status;
@@ -211,7 +212,7 @@ Status WrapKey(blink::WebCryptoKeyFormat format,
const blink::WebCryptoKey& wrapping_key,
const blink::WebCryptoAlgorithm& wrapping_algorithm,
std::vector<uint8_t>* buffer) {
- if (!wrapping_key.keyUsageAllows(blink::WebCryptoKeyUsageWrapKey))
+ if (!wrapping_key.KeyUsageAllows(blink::kWebCryptoKeyUsageWrapKey))
return Status::ErrorUnexpected();
std::vector<uint8_t> exported_data;
@@ -230,9 +231,9 @@ Status UnwrapKey(blink::WebCryptoKeyFormat format,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) {
- if (!wrapping_key.keyUsageAllows(blink::WebCryptoKeyUsageUnwrapKey))
+ if (!wrapping_key.KeyUsageAllows(blink::kWebCryptoKeyUsageUnwrapKey))
return Status::ErrorUnexpected();
- if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
+ if (wrapping_algorithm.Id() != wrapping_key.Algorithm().Id())
return Status::ErrorUnexpected();
std::vector<uint8_t> buffer;
@@ -254,14 +255,14 @@ Status DeriveBits(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& base_key,
unsigned int length_bits,
std::vector<uint8_t>* derived_bytes) {
- if (!base_key.keyUsageAllows(blink::WebCryptoKeyUsageDeriveBits))
+ if (!base_key.KeyUsageAllows(blink::kWebCryptoKeyUsageDeriveBits))
return Status::ErrorUnexpected();
- if (algorithm.id() != base_key.algorithm().id())
+ if (algorithm.Id() != base_key.Algorithm().Id())
return Status::ErrorUnexpected();
const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
+ Status status = GetAlgorithmImplementation(algorithm.Id(), &impl);
if (status.IsError())
return status;
@@ -276,18 +277,18 @@ Status DeriveKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* derived_key) {
- if (!base_key.keyUsageAllows(blink::WebCryptoKeyUsageDeriveKey))
+ if (!base_key.KeyUsageAllows(blink::kWebCryptoKeyUsageDeriveKey))
return Status::ErrorUnexpected();
- if (algorithm.id() != base_key.algorithm().id())
+ if (algorithm.Id() != base_key.Algorithm().Id())
return Status::ErrorUnexpected();
- if (import_algorithm.id() != key_length_algorithm.id())
+ if (import_algorithm.Id() != key_length_algorithm.Id())
return Status::ErrorUnexpected();
const AlgorithmImplementation* import_impl = NULL;
Status status =
- GetAlgorithmImplementation(import_algorithm.id(), &import_impl);
+ GetAlgorithmImplementation(import_algorithm.Id(), &import_impl);
if (status.IsError())
return status;
@@ -301,7 +302,7 @@ Status DeriveKey(const blink::WebCryptoAlgorithm& algorithm,
// Derive the key bytes.
const AlgorithmImplementation* derive_impl = NULL;
- status = GetAlgorithmImplementation(algorithm.id(), &derive_impl);
+ status = GetAlgorithmImplementation(algorithm.Id(), &derive_impl);
if (status.IsError())
return status;
@@ -312,7 +313,7 @@ Status DeriveKey(const blink::WebCryptoAlgorithm& algorithm,
return status;
// Create the key using the derived bytes.
- return ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(derived_bytes),
+ return ImportKey(blink::kWebCryptoKeyFormatRaw, CryptoData(derived_bytes),
import_algorithm, extractable, usages, derived_key);
}
@@ -325,7 +326,7 @@ std::unique_ptr<blink::WebCryptoDigestor> CreateDigestor(
bool SerializeKeyForClone(const blink::WebCryptoKey& key,
blink::WebVector<uint8_t>* key_data) {
const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(key.algorithm().id(), &impl);
+ Status status = GetAlgorithmImplementation(key.Algorithm().Id(), &impl);
if (status.IsError())
return false;
@@ -340,7 +341,7 @@ bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
const CryptoData& key_data,
blink::WebCryptoKey* key) {
const AlgorithmImplementation* impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
+ Status status = GetAlgorithmImplementation(algorithm.Id(), &impl);
if (status.IsError())
return false;
diff --git a/chromium/components/webcrypto/algorithm_registry.cc b/chromium/components/webcrypto/algorithm_registry.cc
index fddf89af47d..89ffdabfe92 100644
--- a/chromium/components/webcrypto/algorithm_registry.cc
+++ b/chromium/components/webcrypto/algorithm_registry.cc
@@ -37,34 +37,34 @@ class AlgorithmRegistry {
const AlgorithmImplementation* GetAlgorithm(
blink::WebCryptoAlgorithmId id) const {
switch (id) {
- case blink::WebCryptoAlgorithmIdSha1:
- case blink::WebCryptoAlgorithmIdSha256:
- case blink::WebCryptoAlgorithmIdSha384:
- case blink::WebCryptoAlgorithmIdSha512:
+ case blink::kWebCryptoAlgorithmIdSha1:
+ case blink::kWebCryptoAlgorithmIdSha256:
+ case blink::kWebCryptoAlgorithmIdSha384:
+ case blink::kWebCryptoAlgorithmIdSha512:
return sha_.get();
- case blink::WebCryptoAlgorithmIdAesGcm:
+ case blink::kWebCryptoAlgorithmIdAesGcm:
return aes_gcm_.get();
- case blink::WebCryptoAlgorithmIdAesCbc:
+ case blink::kWebCryptoAlgorithmIdAesCbc:
return aes_cbc_.get();
- case blink::WebCryptoAlgorithmIdAesCtr:
+ case blink::kWebCryptoAlgorithmIdAesCtr:
return aes_ctr_.get();
- case blink::WebCryptoAlgorithmIdAesKw:
+ case blink::kWebCryptoAlgorithmIdAesKw:
return aes_kw_.get();
- case blink::WebCryptoAlgorithmIdHmac:
+ case blink::kWebCryptoAlgorithmIdHmac:
return hmac_.get();
- case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
+ case blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
return rsa_ssa_.get();
- case blink::WebCryptoAlgorithmIdRsaOaep:
+ case blink::kWebCryptoAlgorithmIdRsaOaep:
return rsa_oaep_.get();
- case blink::WebCryptoAlgorithmIdRsaPss:
+ case blink::kWebCryptoAlgorithmIdRsaPss:
return rsa_pss_.get();
- case blink::WebCryptoAlgorithmIdEcdsa:
+ case blink::kWebCryptoAlgorithmIdEcdsa:
return ecdsa_.get();
- case blink::WebCryptoAlgorithmIdEcdh:
+ case blink::kWebCryptoAlgorithmIdEcdh:
return ecdh_.get();
- case blink::WebCryptoAlgorithmIdHkdf:
+ case blink::kWebCryptoAlgorithmIdHkdf:
return hkdf_.get();
- case blink::WebCryptoAlgorithmIdPbkdf2:
+ case blink::kWebCryptoAlgorithmIdPbkdf2:
return pbkdf2_.get();
default:
return NULL;
diff --git a/chromium/components/webcrypto/algorithms/aes.cc b/chromium/components/webcrypto/algorithms/aes.cc
index 1a21dc5ca1a..caeb132cb6a 100644
--- a/chromium/components/webcrypto/algorithms/aes.cc
+++ b/chromium/components/webcrypto/algorithms/aes.cc
@@ -37,7 +37,7 @@ std::string MakeJwkAesAlgorithmName(const std::string& suffix,
// deserialization can re-use the ImportKey*() methods.
blink::WebCryptoAlgorithm SynthesizeImportAlgorithmForClone(
const blink::WebCryptoKeyAlgorithm& algorithm) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(algorithm.id(),
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(algorithm.Id(),
nullptr);
}
@@ -49,12 +49,11 @@ AesAlgorithm::AesAlgorithm(blink::WebCryptoKeyUsageMask all_key_usages,
}
AesAlgorithm::AesAlgorithm(const std::string& jwk_suffix)
- : all_key_usages_(blink::WebCryptoKeyUsageEncrypt |
- blink::WebCryptoKeyUsageDecrypt |
- blink::WebCryptoKeyUsageWrapKey |
- blink::WebCryptoKeyUsageUnwrapKey),
- jwk_suffix_(jwk_suffix) {
-}
+ : all_key_usages_(blink::kWebCryptoKeyUsageEncrypt |
+ blink::kWebCryptoKeyUsageDecrypt |
+ blink::kWebCryptoKeyUsageWrapKey |
+ blink::kWebCryptoKeyUsageUnwrapKey),
+ jwk_suffix_(jwk_suffix) {}
Status AesAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
@@ -64,7 +63,7 @@ Status AesAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
if (status.IsError())
return status;
- unsigned int keylen_bits = algorithm.aesKeyGenParams()->lengthBits();
+ unsigned int keylen_bits = algorithm.AesKeyGenParams()->LengthBits();
// 192-bit AES is intentionally unsupported (http://crbug.com/533699).
if (keylen_bits == 192)
@@ -74,7 +73,7 @@ Status AesAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
return Status::ErrorGenerateAesKeyLength();
return GenerateWebCryptoSecretKey(
- blink::WebCryptoKeyAlgorithm::createAes(algorithm.id(), keylen_bits),
+ blink::WebCryptoKeyAlgorithm::CreateAes(algorithm.Id(), keylen_bits),
extractable, usages, keylen_bits, result);
}
@@ -85,9 +84,9 @@ Status AesAlgorithm::ImportKey(blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
switch (format) {
- case blink::WebCryptoKeyFormatRaw:
+ case blink::kWebCryptoKeyFormatRaw:
return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
- case blink::WebCryptoKeyFormatJwk:
+ case blink::kWebCryptoKeyFormatJwk:
return ImportKeyJwk(key_data, algorithm, extractable, usages, key);
default:
return Status::ErrorUnsupportedImportKeyFormat();
@@ -98,9 +97,9 @@ Status AesAlgorithm::ExportKey(blink::WebCryptoKeyFormat format,
const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
switch (format) {
- case blink::WebCryptoKeyFormatRaw:
+ case blink::kWebCryptoKeyFormatRaw:
return ExportKeyRaw(key, buffer);
- case blink::WebCryptoKeyFormatJwk:
+ case blink::kWebCryptoKeyFormatJwk:
return ExportKeyJwk(key, buffer);
default:
return Status::ErrorUnsupportedExportKeyFormat();
@@ -130,7 +129,7 @@ Status AesAlgorithm::ImportKeyRaw(const CryptoData& key_data,
return CreateWebCryptoSecretKey(
key_data,
- blink::WebCryptoKeyAlgorithm::createAes(algorithm.id(), keylen_bits),
+ blink::WebCryptoKeyAlgorithm::CreateAes(algorithm.Id(), keylen_bits),
extractable, usages, key);
}
@@ -187,7 +186,7 @@ Status AesAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
WriteSecretKeyJwk(CryptoData(raw_data),
MakeJwkAesAlgorithmName(jwk_suffix_, raw_data.size()),
- key.extractable(), key.usages(), buffer);
+ key.Extractable(), key.Usages(), buffer);
return Status::Success();
}
@@ -199,8 +198,8 @@ Status AesAlgorithm::DeserializeKeyForClone(
blink::WebCryptoKeyUsageMask usages,
const CryptoData& key_data,
blink::WebCryptoKey* key) const {
- if (algorithm.paramsType() != blink::WebCryptoKeyAlgorithmParamsTypeAes ||
- type != blink::WebCryptoKeyTypeSecret)
+ if (algorithm.ParamsType() != blink::kWebCryptoKeyAlgorithmParamsTypeAes ||
+ type != blink::kWebCryptoKeyTypeSecret)
return Status::ErrorUnexpected();
return ImportKeyRaw(key_data, SynthesizeImportAlgorithmForClone(algorithm),
@@ -212,7 +211,7 @@ Status AesAlgorithm::GetKeyLength(
bool* has_length_bits,
unsigned int* length_bits) const {
*has_length_bits = true;
- *length_bits = key_length_algorithm.aesDerivedKeyParams()->lengthBits();
+ *length_bits = key_length_algorithm.AesDerivedKeyParams()->LengthBits();
if (*length_bits == 128 || *length_bits == 256)
return Status::Success();
diff --git a/chromium/components/webcrypto/algorithms/aes_cbc.cc b/chromium/components/webcrypto/algorithms/aes_cbc.cc
index 678aa5ac2ce..5c6e303ba34 100644
--- a/chromium/components/webcrypto/algorithms/aes_cbc.cc
+++ b/chromium/components/webcrypto/algorithms/aes_cbc.cc
@@ -42,10 +42,10 @@ Status AesCbcEncryptDecrypt(EncryptOrDecrypt cipher_operation,
std::vector<uint8_t>* buffer) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
+ const blink::WebCryptoAesCbcParams* params = algorithm.AesCbcParams();
const std::vector<uint8_t>& raw_key = GetSymmetricKeyData(key);
- if (params->iv().size() != 16)
+ if (params->Iv().size() != 16)
return Status::ErrorIncorrectSizeAesCbcIv();
// According to the openssl docs, the amount of data written may be as large
@@ -69,7 +69,7 @@ Status AesCbcEncryptDecrypt(EncryptOrDecrypt cipher_operation,
bssl::ScopedEVP_CIPHER_CTX context;
if (!EVP_CipherInit_ex(context.get(), cipher, NULL, &raw_key[0],
- params->iv().data(), cipher_operation)) {
+ params->Iv().Data(), cipher_operation)) {
return Status::OperationError();
}
diff --git a/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc b/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc
index 57cff25478b..86c67db9842 100644
--- a/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc
@@ -22,13 +22,13 @@ namespace {
// Creates an AES-CBC algorithm.
blink::WebCryptoAlgorithm CreateAesCbcAlgorithm(
const std::vector<uint8_t>& iv) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdAesCbc, new blink::WebCryptoAesCbcParams(iv));
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ blink::kWebCryptoAlgorithmIdAesCbc, new blink::WebCryptoAesCbcParams(iv));
}
blink::WebCryptoAlgorithm CreateAesCbcKeyGenAlgorithm(
unsigned short key_length_bits) {
- return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesCbc,
+ return CreateAesKeyGenAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc,
key_length_bits);
}
@@ -36,13 +36,13 @@ blink::WebCryptoKey GetTestAesCbcKey() {
const std::string key_hex = "2b7e151628aed2a6abf7158809cf4f3c";
blink::WebCryptoKey key = ImportSecretKeyFromRaw(
HexStringToBytes(key_hex),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc),
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt);
// Verify exported raw key is identical to the imported data
std::vector<uint8_t> raw_key;
EXPECT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, key, &raw_key));
EXPECT_BYTES_EQ_HEX(key_hex, raw_key);
return key;
}
@@ -78,10 +78,10 @@ TEST_F(WebCryptoAesCbcTest, ExportKeyUnsupportedFormat) {
// keys).
EXPECT_EQ(
Status::ErrorUnsupportedExportKeyFormat(),
- ExportKey(blink::WebCryptoKeyFormatSpki, GetTestAesCbcKey(), &output));
+ ExportKey(blink::kWebCryptoKeyFormatSpki, GetTestAesCbcKey(), &output));
EXPECT_EQ(
Status::ErrorUnsupportedExportKeyFormat(),
- ExportKey(blink::WebCryptoKeyFormatPkcs8, GetTestAesCbcKey(), &output));
+ ExportKey(blink::kWebCryptoKeyFormatPkcs8, GetTestAesCbcKey(), &output));
}
// Tests importing of keys (in a variety of formats), errors during import,
@@ -105,8 +105,8 @@ TEST_F(WebCryptoAesCbcTest, KnownAnswerEncryptDecrypt) {
blink::WebCryptoKey key;
Status status = ImportKey(
key_format, CryptoData(key_data),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), true,
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt,
&key);
ASSERT_EQ(import_error, StatusToString(status));
if (status.IsError())
@@ -177,13 +177,13 @@ TEST_F(WebCryptoAesCbcTest, GenerateKeyIsRandom) {
ASSERT_EQ(Status::Success(),
GenerateSecretKey(
CreateAesCbcKeyGenAlgorithm(kKeyLength[key_length_i]), true,
- blink::WebCryptoKeyUsageEncrypt, &key));
- EXPECT_TRUE(key.handle());
- EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
+ blink::kWebCryptoKeyUsageEncrypt, &key));
+ EXPECT_TRUE(key.Handle());
+ EXPECT_EQ(blink::kWebCryptoKeyTypeSecret, key.GetType());
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, key, &key_bytes));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, key, &key_bytes));
EXPECT_EQ(key_bytes.size() * 8,
- key.algorithm().aesParams()->lengthBits());
+ key.Algorithm().AesParams()->LengthBits());
keys.push_back(key_bytes);
}
// Ensure all entries in the key sample set are unique. This is a simplistic
@@ -199,16 +199,16 @@ TEST_F(WebCryptoAesCbcTest, GenerateKeyBadLength) {
SCOPED_TRACE(i);
EXPECT_EQ(Status::ErrorGenerateAesKeyLength(),
GenerateSecretKey(CreateAesCbcKeyGenAlgorithm(kKeyLen[i]), true,
- blink::WebCryptoKeyUsageEncrypt, &key));
+ blink::kWebCryptoKeyUsageEncrypt, &key));
}
}
TEST_F(WebCryptoAesCbcTest, ImportKeyEmptyUsage) {
blink::WebCryptoKey key;
ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
- ImportKey(blink::WebCryptoKeyFormatRaw,
+ ImportKey(blink::kWebCryptoKeyFormatRaw,
CryptoData(std::vector<uint8_t>(16)),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), true,
0, &key));
}
@@ -224,14 +224,14 @@ TEST_F(WebCryptoAesCbcTest, ImportKeyJwkEmptyKeyOps) {
// The JWK does not contain encrypt usages.
EXPECT_EQ(Status::ErrorJwkKeyopsInconsistent(),
ImportKeyJwkFromDict(
- dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
- blink::WebCryptoKeyUsageEncrypt, &key));
+ dict, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc),
+ false, blink::kWebCryptoKeyUsageEncrypt, &key));
// The JWK does not contain sign usage (nor is it applicable).
EXPECT_EQ(Status::ErrorCreateKeyBadUsages(),
ImportKeyJwkFromDict(
- dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
- blink::WebCryptoKeyUsageSign, &key));
+ dict, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc),
+ false, blink::kWebCryptoKeyUsageSign, &key));
}
// If key_ops is missing, then any key usages can be specified.
@@ -243,16 +243,16 @@ TEST_F(WebCryptoAesCbcTest, ImportKeyJwkNoKeyOps) {
EXPECT_EQ(Status::Success(),
ImportKeyJwkFromDict(
- dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
- blink::WebCryptoKeyUsageEncrypt, &key));
+ dict, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc),
+ false, blink::kWebCryptoKeyUsageEncrypt, &key));
- EXPECT_EQ(blink::WebCryptoKeyUsageEncrypt, key.usages());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageEncrypt, key.Usages());
// The JWK does not contain sign usage (nor is it applicable).
EXPECT_EQ(Status::ErrorCreateKeyBadUsages(),
ImportKeyJwkFromDict(
- dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
- blink::WebCryptoKeyUsageVerify, &key));
+ dict, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc),
+ false, blink::kWebCryptoKeyUsageVerify, &key));
}
TEST_F(WebCryptoAesCbcTest, ImportKeyJwkKeyOpsEncryptDecrypt) {
@@ -267,29 +267,29 @@ TEST_F(WebCryptoAesCbcTest, ImportKeyJwkKeyOpsEncryptDecrypt) {
EXPECT_EQ(Status::Success(),
ImportKeyJwkFromDict(
- dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
- blink::WebCryptoKeyUsageEncrypt, &key));
+ dict, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc),
+ false, blink::kWebCryptoKeyUsageEncrypt, &key));
- EXPECT_EQ(blink::WebCryptoKeyUsageEncrypt, key.usages());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageEncrypt, key.Usages());
key_ops->AppendString("decrypt");
EXPECT_EQ(Status::Success(),
ImportKeyJwkFromDict(
- dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
- blink::WebCryptoKeyUsageDecrypt, &key));
+ dict, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc),
+ false, blink::kWebCryptoKeyUsageDecrypt, &key));
- EXPECT_EQ(blink::WebCryptoKeyUsageDecrypt, key.usages());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageDecrypt, key.Usages());
EXPECT_EQ(
Status::Success(),
ImportKeyJwkFromDict(
- dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
- blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageEncrypt,
+ dict, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), false,
+ blink::kWebCryptoKeyUsageDecrypt | blink::kWebCryptoKeyUsageEncrypt,
&key));
- EXPECT_EQ(blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
- key.usages());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt,
+ key.Usages());
}
// Test failure if input usage is NOT a strict subset of the JWK usage.
@@ -306,8 +306,8 @@ TEST_F(WebCryptoAesCbcTest, ImportKeyJwkKeyOpsNotSuperset) {
EXPECT_EQ(
Status::ErrorJwkKeyopsInconsistent(),
ImportKeyJwkFromDict(
- dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
+ dict, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), false,
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt,
&key));
}
@@ -323,15 +323,15 @@ TEST_F(WebCryptoAesCbcTest, ImportKeyJwkUseEnc) {
EXPECT_EQ(
Status::Success(),
ImportKeyJwkFromDict(
- dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
- blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageEncrypt |
- blink::WebCryptoKeyUsageWrapKey |
- blink::WebCryptoKeyUsageUnwrapKey,
+ dict, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), false,
+ blink::kWebCryptoKeyUsageDecrypt | blink::kWebCryptoKeyUsageEncrypt |
+ blink::kWebCryptoKeyUsageWrapKey |
+ blink::kWebCryptoKeyUsageUnwrapKey,
&key));
- EXPECT_EQ(blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageEncrypt |
- blink::WebCryptoKeyUsageWrapKey |
- blink::WebCryptoKeyUsageUnwrapKey,
- key.usages());
+ EXPECT_EQ(
+ blink::kWebCryptoKeyUsageDecrypt | blink::kWebCryptoKeyUsageEncrypt |
+ blink::kWebCryptoKeyUsageWrapKey | blink::kWebCryptoKeyUsageUnwrapKey,
+ key.Usages());
}
TEST_F(WebCryptoAesCbcTest, ImportJwkInvalidJson) {
@@ -339,9 +339,9 @@ TEST_F(WebCryptoAesCbcTest, ImportJwkInvalidJson) {
// Fail on empty JSON.
EXPECT_EQ(
Status::ErrorJwkNotDictionary(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(MakeJsonVector("")),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
- blink::WebCryptoKeyUsageEncrypt, &key));
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(MakeJsonVector("")),
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), false,
+ blink::kWebCryptoKeyUsageEncrypt, &key));
// Fail on invalid JSON.
const std::vector<uint8_t> bad_json_vec = MakeJsonVector(
@@ -350,9 +350,9 @@ TEST_F(WebCryptoAesCbcTest, ImportJwkInvalidJson) {
"\"alg\" : \"HS256\","
"\"use\" : ");
EXPECT_EQ(Status::ErrorJwkNotDictionary(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(bad_json_vec),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
- blink::WebCryptoKeyUsageEncrypt, &key));
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(bad_json_vec),
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc),
+ false, blink::kWebCryptoKeyUsageEncrypt, &key));
}
// Fail on inconsistent key_ops - asking for "encrypt" however JWK contains
@@ -370,29 +370,29 @@ TEST_F(WebCryptoAesCbcTest, ImportJwkKeyOpsLacksUsages) {
key_ops->AppendString("foo");
EXPECT_EQ(Status::ErrorJwkKeyopsInconsistent(),
ImportKeyJwkFromDict(
- dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), false,
- blink::WebCryptoKeyUsageEncrypt, &key));
+ dict, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc),
+ false, blink::kWebCryptoKeyUsageEncrypt, &key));
}
TEST_F(WebCryptoAesCbcTest, ImportExportJwk) {
const blink::WebCryptoAlgorithm algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc);
// AES-CBC 128
ImportExportJwkSymmetricKey(
128, algorithm,
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt,
"A128CBC");
// AES-CBC 256
- ImportExportJwkSymmetricKey(256, algorithm, blink::WebCryptoKeyUsageDecrypt,
+ ImportExportJwkSymmetricKey(256, algorithm, blink::kWebCryptoKeyUsageDecrypt,
"A256CBC");
// Large usage value
ImportExportJwkSymmetricKey(
256, algorithm,
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
- blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt |
+ blink::kWebCryptoKeyUsageWrapKey | blink::kWebCryptoKeyUsageUnwrapKey,
"A256CBC");
}
@@ -400,7 +400,7 @@ TEST_F(WebCryptoAesCbcTest, ImportExportJwk) {
TEST_F(WebCryptoAesCbcTest, GenerateAesCbc192) {
blink::WebCryptoKey key;
Status status = GenerateSecretKey(CreateAesCbcKeyGenAlgorithm(192), true,
- blink::WebCryptoKeyUsageEncrypt, &key);
+ blink::kWebCryptoKeyUsageEncrypt, &key);
ASSERT_EQ(Status::ErrorAes192BitUnsupported(), status);
}
@@ -411,16 +411,16 @@ TEST_F(WebCryptoAesCbcTest, UnwrapAesCbc192) {
"1A07ACAB6C906E50883173C29441DB1DE91D34F45C435B5F99C822867FB3956F");
blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
- wrapping_key_data, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw),
- blink::WebCryptoKeyUsageUnwrapKey);
+ wrapping_key_data, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw),
+ blink::kWebCryptoKeyUsageUnwrapKey);
blink::WebCryptoKey unwrapped_key;
- ASSERT_EQ(
- Status::ErrorAes192BitUnsupported(),
- UnwrapKey(blink::WebCryptoKeyFormatRaw, CryptoData(wrapped_key),
- wrapping_key, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
- blink::WebCryptoKeyUsageEncrypt, &unwrapped_key));
+ ASSERT_EQ(Status::ErrorAes192BitUnsupported(),
+ UnwrapKey(blink::kWebCryptoKeyFormatRaw, CryptoData(wrapped_key),
+ wrapping_key,
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw),
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), true,
+ blink::kWebCryptoKeyUsageEncrypt, &unwrapped_key));
}
// Try importing an AES-CBC key with unsupported key usages using raw
@@ -428,13 +428,13 @@ TEST_F(WebCryptoAesCbcTest, UnwrapAesCbc192) {
// 'encrypt', 'decrypt', 'wrapKey', 'unwrapKey'
TEST_F(WebCryptoAesCbcTest, ImportKeyBadUsage_Raw) {
const blink::WebCryptoAlgorithm algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc);
blink::WebCryptoKeyUsageMask bad_usages[] = {
- blink::WebCryptoKeyUsageSign,
- blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageDecrypt,
- blink::WebCryptoKeyUsageDeriveBits,
- blink::WebCryptoKeyUsageUnwrapKey | blink::WebCryptoKeyUsageVerify,
+ blink::kWebCryptoKeyUsageSign,
+ blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageDecrypt,
+ blink::kWebCryptoKeyUsageDeriveBits,
+ blink::kWebCryptoKeyUsageUnwrapKey | blink::kWebCryptoKeyUsageVerify,
};
std::vector<uint8_t> key_bytes(16);
@@ -444,7 +444,7 @@ TEST_F(WebCryptoAesCbcTest, ImportKeyBadUsage_Raw) {
blink::WebCryptoKey key;
ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
- ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(key_bytes),
+ ImportKey(blink::kWebCryptoKeyFormatRaw, CryptoData(key_bytes),
algorithm, true, bad_usages[i], &key));
}
}
@@ -453,9 +453,8 @@ TEST_F(WebCryptoAesCbcTest, ImportKeyBadUsage_Raw) {
// 'encrypt', 'decrypt', 'wrapKey', 'unwrapKey'
TEST_F(WebCryptoAesCbcTest, GenerateKeyBadUsages) {
blink::WebCryptoKeyUsageMask bad_usages[] = {
- blink::WebCryptoKeyUsageSign,
- blink::WebCryptoKeyUsageVerify,
- blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageVerify,
+ blink::kWebCryptoKeyUsageSign, blink::kWebCryptoKeyUsageVerify,
+ blink::kWebCryptoKeyUsageDecrypt | blink::kWebCryptoKeyUsageVerify,
};
for (size_t i = 0; i < arraysize(bad_usages); ++i) {
@@ -485,8 +484,8 @@ TEST_F(WebCryptoAesCbcTest, WrapUnwrapRoundtripSpkiPkcs8) {
blink::WebCryptoKey wrapping_key;
ASSERT_EQ(Status::Success(),
GenerateSecretKey(CreateAesCbcKeyGenAlgorithm(128), true,
- blink::WebCryptoKeyUsageWrapKey |
- blink::WebCryptoKeyUsageUnwrapKey,
+ blink::kWebCryptoKeyUsageWrapKey |
+ blink::kWebCryptoKeyUsageUnwrapKey,
&wrapping_key));
// Generate an RSA key pair to be wrapped.
@@ -497,19 +496,19 @@ TEST_F(WebCryptoAesCbcTest, WrapUnwrapRoundtripSpkiPkcs8) {
blink::WebCryptoKey private_key;
ASSERT_EQ(Status::Success(),
GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256,
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256,
modulus_length, public_exponent),
- true, blink::WebCryptoKeyUsageSign, &public_key,
+ true, blink::kWebCryptoKeyUsageSign, &public_key,
&private_key));
// Export key pair as SPKI + PKCS8
std::vector<uint8_t> public_key_spki;
- ASSERT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatSpki,
+ ASSERT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatSpki,
public_key, &public_key_spki));
std::vector<uint8_t> private_key_pkcs8;
- ASSERT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatPkcs8,
+ ASSERT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatPkcs8,
private_key, &private_key_pkcs8));
// Wrap the key pair.
@@ -518,44 +517,45 @@ TEST_F(WebCryptoAesCbcTest, WrapUnwrapRoundtripSpkiPkcs8) {
std::vector<uint8_t> wrapped_public_key;
ASSERT_EQ(Status::Success(),
- WrapKey(blink::WebCryptoKeyFormatSpki, public_key, wrapping_key,
+ WrapKey(blink::kWebCryptoKeyFormatSpki, public_key, wrapping_key,
wrap_algorithm, &wrapped_public_key));
std::vector<uint8_t> wrapped_private_key;
ASSERT_EQ(Status::Success(),
- WrapKey(blink::WebCryptoKeyFormatPkcs8, private_key, wrapping_key,
+ WrapKey(blink::kWebCryptoKeyFormatPkcs8, private_key, wrapping_key,
wrap_algorithm, &wrapped_private_key));
// Unwrap the key pair.
blink::WebCryptoAlgorithm rsa_import_algorithm =
- CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256);
+ CreateRsaHashedImportAlgorithm(
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256);
blink::WebCryptoKey unwrapped_public_key;
ASSERT_EQ(
Status::Success(),
- UnwrapKey(blink::WebCryptoKeyFormatSpki, CryptoData(wrapped_public_key),
+ UnwrapKey(blink::kWebCryptoKeyFormatSpki, CryptoData(wrapped_public_key),
wrapping_key, wrap_algorithm, rsa_import_algorithm, true,
- blink::WebCryptoKeyUsageVerify, &unwrapped_public_key));
+ blink::kWebCryptoKeyUsageVerify, &unwrapped_public_key));
blink::WebCryptoKey unwrapped_private_key;
- ASSERT_EQ(
- Status::Success(),
- UnwrapKey(blink::WebCryptoKeyFormatPkcs8, CryptoData(wrapped_private_key),
- wrapping_key, wrap_algorithm, rsa_import_algorithm, true,
- blink::WebCryptoKeyUsageSign, &unwrapped_private_key));
+ ASSERT_EQ(Status::Success(),
+ UnwrapKey(blink::kWebCryptoKeyFormatPkcs8,
+ CryptoData(wrapped_private_key), wrapping_key,
+ wrap_algorithm, rsa_import_algorithm, true,
+ blink::kWebCryptoKeyUsageSign, &unwrapped_private_key));
// Export unwrapped key pair as SPKI + PKCS8
std::vector<uint8_t> unwrapped_public_key_spki;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatSpki, unwrapped_public_key,
+ ExportKey(blink::kWebCryptoKeyFormatSpki, unwrapped_public_key,
&unwrapped_public_key_spki));
std::vector<uint8_t> unwrapped_private_key_pkcs8;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatPkcs8, unwrapped_private_key,
+ ExportKey(blink::kWebCryptoKeyFormatPkcs8, unwrapped_private_key,
&unwrapped_private_key_pkcs8));
EXPECT_EQ(public_key_spki, unwrapped_public_key_spki);
diff --git a/chromium/components/webcrypto/algorithms/aes_ctr.cc b/chromium/components/webcrypto/algorithms/aes_ctr.cc
index 3525c5ff37d..7c48824ed77 100644
--- a/chromium/components/webcrypto/algorithms/aes_ctr.cc
+++ b/chromium/components/webcrypto/algorithms/aes_ctr.cc
@@ -145,13 +145,13 @@ Status AesCtrEncryptDecrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
- const blink::WebCryptoAesCtrParams* params = algorithm.aesCtrParams();
+ const blink::WebCryptoAesCtrParams* params = algorithm.AesCtrParams();
const std::vector<uint8_t>& raw_key = GetSymmetricKeyData(key);
- if (params->counter().size() != 16)
+ if (params->Counter().size() != 16)
return Status::ErrorIncorrectSizeAesCtrCounter();
- unsigned int counter_length_bits = params->lengthBits();
+ unsigned int counter_length_bits = params->LengthBits();
if (counter_length_bits < 1 || counter_length_bits > 128)
return Status::ErrorInvalidAesCtrCounterLength();
@@ -165,7 +165,7 @@ Status AesCtrEncryptDecrypt(const blink::WebCryptoAlgorithm& algorithm,
if (!cipher)
return Status::ErrorUnexpected();
- const CryptoData counter_block(params->counter());
+ const CryptoData counter_block(params->Counter());
buffer->resize(base::ValueOrDieForType<size_t>(output_max_len));
// The total number of possible counter values is pow(2, counter_length_bits)
diff --git a/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc b/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc
index eaee87eee7a..c9a73418953 100644
--- a/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc
@@ -22,8 +22,8 @@ namespace {
blink::WebCryptoAlgorithm CreateAesCtrAlgorithm(
const std::vector<uint8_t>& counter,
uint8_t length_bits) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdAesCtr,
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ blink::kWebCryptoAlgorithmIdAesCtr,
new blink::WebCryptoAesCtrParams(length_bits, counter));
}
@@ -49,10 +49,10 @@ TEST_F(WebCryptoAesCtrTest, EncryptDecryptKnownAnswer) {
GetBytesFromHexString(test, "cipher_text");
blink::WebCryptoKey key = ImportSecretKeyFromRaw(
- test_key, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr),
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
+ test_key, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCtr),
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt);
- EXPECT_EQ(test_key.size() * 8, key.algorithm().aesParams()->lengthBits());
+ EXPECT_EQ(test_key.size() * 8, key.Algorithm().AesParams()->LengthBits());
std::vector<uint8_t> output;
@@ -76,8 +76,8 @@ TEST_F(WebCryptoAesCtrTest, InvalidCounterBlockLength) {
blink::WebCryptoKey key = ImportSecretKeyFromRaw(
std::vector<uint8_t>(16), // 128-bit key of all zeros.
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr),
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCtr),
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt);
std::vector<uint8_t> input(32);
std::vector<uint8_t> output;
@@ -101,8 +101,8 @@ TEST_F(WebCryptoAesCtrTest, InvalidCounterLength) {
blink::WebCryptoKey key = ImportSecretKeyFromRaw(
std::vector<uint8_t>(16), // 128-bit key of all zeros.
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr),
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCtr),
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt);
std::vector<uint8_t> counter(16);
std::vector<uint8_t> input(32);
@@ -134,8 +134,8 @@ TEST_F(WebCryptoAesCtrTest, OverflowAndRepeatCounter) {
blink::WebCryptoKey key = ImportSecretKeyFromRaw(
std::vector<uint8_t>(16), // 128-bit key of all zeros.
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr),
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCtr),
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt);
std::vector<uint8_t> buffer(272);
diff --git a/chromium/components/webcrypto/algorithms/aes_gcm.cc b/chromium/components/webcrypto/algorithms/aes_gcm.cc
index 39bcb4bb1ce..a1d5bf91540 100644
--- a/chromium/components/webcrypto/algorithms/aes_gcm.cc
+++ b/chromium/components/webcrypto/algorithms/aes_gcm.cc
@@ -40,13 +40,13 @@ Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
const std::vector<uint8_t>& raw_key = GetSymmetricKeyData(key);
- const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
+ const blink::WebCryptoAesGcmParams* params = algorithm.AesGcmParams();
// The WebCrypto spec defines the default value for the tag length, as well as
// the allowed values for tag length.
unsigned int tag_length_bits = 128;
- if (params->hasTagLengthBits()) {
- tag_length_bits = params->optionalTagLengthBits();
+ if (params->HasTagLengthBits()) {
+ tag_length_bits = params->OptionalTagLengthBits();
if (tag_length_bits != 32 && tag_length_bits != 64 &&
tag_length_bits != 96 && tag_length_bits != 104 &&
tag_length_bits != 112 && tag_length_bits != 120 &&
@@ -56,8 +56,8 @@ Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode,
}
return AeadEncryptDecrypt(
- mode, raw_key, data, tag_length_bits / 8, CryptoData(params->iv()),
- CryptoData(params->optionalAdditionalData()),
+ mode, raw_key, data, tag_length_bits / 8, CryptoData(params->Iv()),
+ CryptoData(params->OptionalAdditionalData()),
GetAesGcmAlgorithmFromKeySize(raw_key.size()), buffer);
}
diff --git a/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc b/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc
index d0a851b0566..e4df16ae686 100644
--- a/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc
@@ -24,15 +24,15 @@ blink::WebCryptoAlgorithm CreateAesGcmAlgorithm(
const std::vector<uint8_t>& iv,
const std::vector<uint8_t>& additional_data,
unsigned int tag_length_bits) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdAesGcm,
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ blink::kWebCryptoAlgorithmIdAesGcm,
new blink::WebCryptoAesGcmParams(iv, true, additional_data, true,
tag_length_bits));
}
blink::WebCryptoAlgorithm CreateAesGcmKeyGenAlgorithm(
unsigned short key_length_bits) {
- return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesGcm,
+ return CreateAesKeyGenAlgorithm(blink::kWebCryptoAlgorithmIdAesGcm,
key_length_bits);
}
@@ -103,7 +103,7 @@ TEST_F(WebCryptoAesGcmTest, GenerateKeyBadLength) {
SCOPED_TRACE(i);
EXPECT_EQ(Status::ErrorGenerateAesKeyLength(),
GenerateSecretKey(CreateAesGcmKeyGenAlgorithm(kKeyLen[i]), true,
- blink::WebCryptoKeyUsageDecrypt, &key));
+ blink::kWebCryptoKeyUsageDecrypt, &key));
}
}
@@ -115,16 +115,16 @@ TEST_F(WebCryptoAesGcmTest, GenerateKeyEmptyUsage) {
TEST_F(WebCryptoAesGcmTest, ImportExportJwk) {
const blink::WebCryptoAlgorithm algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesGcm);
// AES-GCM 128
ImportExportJwkSymmetricKey(
128, algorithm,
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt,
"A128GCM");
// AES-GCM 256
- ImportExportJwkSymmetricKey(256, algorithm, blink::WebCryptoKeyUsageDecrypt,
+ ImportExportJwkSymmetricKey(256, algorithm, blink::kWebCryptoKeyUsageDecrypt,
"A256GCM");
}
@@ -156,13 +156,13 @@ TEST_F(WebCryptoAesGcmTest, SampleSets) {
GetBytesFromHexString(test, "cipher_text");
blink::WebCryptoKey key = ImportSecretKeyFromRaw(
- test_key, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm),
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
+ test_key, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesGcm),
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt);
// Verify exported raw key is identical to the imported data
std::vector<uint8_t> raw_key;
EXPECT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, key, &raw_key));
EXPECT_BYTES_EQ(test_key, raw_key);
diff --git a/chromium/components/webcrypto/algorithms/aes_kw.cc b/chromium/components/webcrypto/algorithms/aes_kw.cc
index bd11159bd6b..4a5f9525dd6 100644
--- a/chromium/components/webcrypto/algorithms/aes_kw.cc
+++ b/chromium/components/webcrypto/algorithms/aes_kw.cc
@@ -24,9 +24,9 @@ namespace {
class AesKwImplementation : public AesAlgorithm {
public:
AesKwImplementation()
- : AesAlgorithm(
- blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
- "KW") {}
+ : AesAlgorithm(blink::kWebCryptoKeyUsageWrapKey |
+ blink::kWebCryptoKeyUsageUnwrapKey,
+ "KW") {}
Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
diff --git a/chromium/components/webcrypto/algorithms/aes_kw_unittest.cc b/chromium/components/webcrypto/algorithms/aes_kw_unittest.cc
index 0c98ef499b5..293510021f2 100644
--- a/chromium/components/webcrypto/algorithms/aes_kw_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/aes_kw_unittest.cc
@@ -21,7 +21,7 @@ namespace {
blink::WebCryptoAlgorithm CreateAesKwKeyGenAlgorithm(
unsigned short key_length_bits) {
- return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesKw,
+ return CreateAesKeyGenAlgorithm(blink::kWebCryptoAlgorithmIdAesKw,
key_length_bits);
}
@@ -34,7 +34,7 @@ TEST_F(WebCryptoAesKwTest, GenerateKeyBadLength) {
SCOPED_TRACE(i);
EXPECT_EQ(Status::ErrorGenerateAesKeyLength(),
GenerateSecretKey(CreateAesKwKeyGenAlgorithm(kKeyLen[i]), true,
- blink::WebCryptoKeyUsageWrapKey, &key));
+ blink::kWebCryptoKeyUsageWrapKey, &key));
}
}
@@ -47,9 +47,9 @@ TEST_F(WebCryptoAesKwTest, GenerateKeyEmptyUsage) {
TEST_F(WebCryptoAesKwTest, ImportKeyEmptyUsage) {
blink::WebCryptoKey key;
EXPECT_EQ(Status::ErrorCreateKeyEmptyUsages(),
- ImportKey(blink::WebCryptoKeyFormatRaw,
+ ImportKey(blink::kWebCryptoKeyFormatRaw,
CryptoData(std::vector<uint8_t>(16)),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw), true,
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw), true,
0, &key));
}
@@ -65,99 +65,99 @@ TEST_F(WebCryptoAesKwTest, ImportKeyJwkKeyOpsWrapUnwrap) {
EXPECT_EQ(Status::Success(),
ImportKeyJwkFromDict(
- dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw), false,
- blink::WebCryptoKeyUsageWrapKey, &key));
+ dict, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw), false,
+ blink::kWebCryptoKeyUsageWrapKey, &key));
- EXPECT_EQ(blink::WebCryptoKeyUsageWrapKey, key.usages());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageWrapKey, key.Usages());
key_ops->AppendString("unwrapKey");
EXPECT_EQ(Status::Success(),
ImportKeyJwkFromDict(
- dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw), false,
- blink::WebCryptoKeyUsageUnwrapKey, &key));
+ dict, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw), false,
+ blink::kWebCryptoKeyUsageUnwrapKey, &key));
- EXPECT_EQ(blink::WebCryptoKeyUsageUnwrapKey, key.usages());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageUnwrapKey, key.Usages());
}
TEST_F(WebCryptoAesKwTest, ImportExportJwk) {
const blink::WebCryptoAlgorithm algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw);
// AES-KW 128
ImportExportJwkSymmetricKey(
128, algorithm,
- blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
+ blink::kWebCryptoKeyUsageWrapKey | blink::kWebCryptoKeyUsageUnwrapKey,
"A128KW");
// AES-KW 256
ImportExportJwkSymmetricKey(
256, algorithm,
- blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
+ blink::kWebCryptoKeyUsageWrapKey | blink::kWebCryptoKeyUsageUnwrapKey,
"A256KW");
}
TEST_F(WebCryptoAesKwTest, AesKwKeyImport) {
blink::WebCryptoKey key;
blink::WebCryptoAlgorithm algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw);
// Import a 128-bit Key Encryption Key (KEK)
std::string key_raw_hex_in = "025a8cf3f08b4f6c5f33bbc76a471939";
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatRaw,
+ ImportKey(blink::kWebCryptoKeyFormatRaw,
CryptoData(HexStringToBytes(key_raw_hex_in)), algorithm,
- true, blink::WebCryptoKeyUsageWrapKey, &key));
+ true, blink::kWebCryptoKeyUsageWrapKey, &key));
std::vector<uint8_t> key_raw_out;
EXPECT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, key, &key_raw_out));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, key, &key_raw_out));
EXPECT_BYTES_EQ_HEX(key_raw_hex_in, key_raw_out);
// Import a 192-bit KEK
key_raw_hex_in = "c0192c6466b2370decbb62b2cfef4384544ffeb4d2fbc103";
ASSERT_EQ(Status::ErrorAes192BitUnsupported(),
- ImportKey(blink::WebCryptoKeyFormatRaw,
+ ImportKey(blink::kWebCryptoKeyFormatRaw,
CryptoData(HexStringToBytes(key_raw_hex_in)), algorithm,
- true, blink::WebCryptoKeyUsageWrapKey, &key));
+ true, blink::kWebCryptoKeyUsageWrapKey, &key));
// Import a 256-bit Key Encryption Key (KEK)
key_raw_hex_in =
"e11fe66380d90fa9ebefb74e0478e78f95664d0c67ca20ce4a0b5842863ac46f";
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatRaw,
+ ImportKey(blink::kWebCryptoKeyFormatRaw,
CryptoData(HexStringToBytes(key_raw_hex_in)), algorithm,
- true, blink::WebCryptoKeyUsageWrapKey, &key));
+ true, blink::kWebCryptoKeyUsageWrapKey, &key));
EXPECT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, key, &key_raw_out));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, key, &key_raw_out));
EXPECT_BYTES_EQ_HEX(key_raw_hex_in, key_raw_out);
// Fail import of 0 length key
EXPECT_EQ(
Status::ErrorImportAesKeyLength(),
- ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(HexStringToBytes("")),
- algorithm, true, blink::WebCryptoKeyUsageWrapKey, &key));
+ ImportKey(blink::kWebCryptoKeyFormatRaw, CryptoData(HexStringToBytes("")),
+ algorithm, true, blink::kWebCryptoKeyUsageWrapKey, &key));
// Fail import of 124-bit KEK
key_raw_hex_in = "3e4566a2bdaa10cb68134fa66c15ddb";
EXPECT_EQ(Status::ErrorImportAesKeyLength(),
- ImportKey(blink::WebCryptoKeyFormatRaw,
+ ImportKey(blink::kWebCryptoKeyFormatRaw,
CryptoData(HexStringToBytes(key_raw_hex_in)), algorithm,
- true, blink::WebCryptoKeyUsageWrapKey, &key));
+ true, blink::kWebCryptoKeyUsageWrapKey, &key));
// Fail import of 200-bit KEK
key_raw_hex_in = "0a1d88608a5ad9fec64f1ada269ebab4baa2feeb8d95638c0e";
EXPECT_EQ(Status::ErrorImportAesKeyLength(),
- ImportKey(blink::WebCryptoKeyFormatRaw,
+ ImportKey(blink::kWebCryptoKeyFormatRaw,
CryptoData(HexStringToBytes(key_raw_hex_in)), algorithm,
- true, blink::WebCryptoKeyUsageWrapKey, &key));
+ true, blink::kWebCryptoKeyUsageWrapKey, &key));
// Fail import of 260-bit KEK
key_raw_hex_in =
"72d4e475ff34215416c9ad9c8281247a4d730c5f275ac23f376e73e3bce8d7d5a";
EXPECT_EQ(Status::ErrorImportAesKeyLength(),
- ImportKey(blink::WebCryptoKeyFormatRaw,
+ ImportKey(blink::kWebCryptoKeyFormatRaw,
CryptoData(HexStringToBytes(key_raw_hex_in)), algorithm,
- true, blink::WebCryptoKeyUsageWrapKey, &key));
+ true, blink::kWebCryptoKeyUsageWrapKey, &key));
}
TEST_F(WebCryptoAesKwTest, UnwrapFailures) {
@@ -175,14 +175,14 @@ TEST_F(WebCryptoAesKwTest, UnwrapFailures) {
// Using a wrapping algorithm that does not match the wrapping key algorithm
// should fail.
blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
- test_kek, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw),
- blink::WebCryptoKeyUsageUnwrapKey);
+ test_kek, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw),
+ blink::kWebCryptoKeyUsageUnwrapKey);
EXPECT_EQ(Status::ErrorUnexpected(),
- UnwrapKey(blink::WebCryptoKeyFormatRaw, CryptoData(test_ciphertext),
- wrapping_key,
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
- blink::WebCryptoKeyUsageEncrypt, &unwrapped_key));
+ UnwrapKey(blink::kWebCryptoKeyFormatRaw,
+ CryptoData(test_ciphertext), wrapping_key,
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc),
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), true,
+ blink::kWebCryptoKeyUsageEncrypt, &unwrapped_key));
}
TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyWrapUnwrapKnownAnswer) {
@@ -198,23 +198,23 @@ TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyWrapUnwrapKnownAnswer) {
const std::vector<uint8_t> test_ciphertext =
GetBytesFromHexString(test, "ciphertext");
const blink::WebCryptoAlgorithm wrapping_algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw);
// Import the wrapping key.
blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
test_kek, wrapping_algorithm,
- blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey);
+ blink::kWebCryptoKeyUsageWrapKey | blink::kWebCryptoKeyUsageUnwrapKey);
// Import the key to be wrapped.
blink::WebCryptoKey key = ImportSecretKeyFromRaw(
test_key,
- CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha1),
- blink::WebCryptoKeyUsageSign);
+ CreateHmacImportAlgorithmNoLength(blink::kWebCryptoAlgorithmIdSha1),
+ blink::kWebCryptoKeyUsageSign);
// Wrap the key and verify the ciphertext result against the known answer.
std::vector<uint8_t> wrapped_key;
ASSERT_EQ(Status::Success(),
- WrapKey(blink::WebCryptoKeyFormatRaw, key, wrapping_key,
+ WrapKey(blink::kWebCryptoKeyFormatRaw, key, wrapping_key,
wrapping_algorithm, &wrapped_key));
EXPECT_BYTES_EQ(test_ciphertext, wrapped_key);
@@ -223,21 +223,21 @@ TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyWrapUnwrapKnownAnswer) {
ASSERT_EQ(
Status::Success(),
UnwrapKey(
- blink::WebCryptoKeyFormatRaw, CryptoData(test_ciphertext),
+ blink::kWebCryptoKeyFormatRaw, CryptoData(test_ciphertext),
wrapping_key, wrapping_algorithm,
- CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageSign, &unwrapped_key));
- EXPECT_FALSE(key.isNull());
- EXPECT_TRUE(key.handle());
- EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
- EXPECT_EQ(true, key.extractable());
- EXPECT_EQ(blink::WebCryptoKeyUsageSign, key.usages());
+ CreateHmacImportAlgorithmNoLength(blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageSign, &unwrapped_key));
+ EXPECT_FALSE(key.IsNull());
+ EXPECT_TRUE(key.Handle());
+ EXPECT_EQ(blink::kWebCryptoKeyTypeSecret, key.GetType());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdHmac, key.Algorithm().Id());
+ EXPECT_EQ(true, key.Extractable());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageSign, key.Usages());
// Export the new key and compare its raw bytes with the original known key.
std::vector<uint8_t> raw_key;
- EXPECT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
+ EXPECT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatRaw,
+ unwrapped_key, &raw_key));
EXPECT_BYTES_EQ(test_key, raw_key);
}
}
@@ -254,35 +254,36 @@ TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyUnwrapSignVerifyHmac) {
const std::vector<uint8_t> test_ciphertext =
GetBytesFromHexString(test, "ciphertext");
const blink::WebCryptoAlgorithm wrapping_algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw);
// Import the wrapping key.
blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
- test_kek, wrapping_algorithm, blink::WebCryptoKeyUsageUnwrapKey);
+ test_kek, wrapping_algorithm, blink::kWebCryptoKeyUsageUnwrapKey);
// Unwrap the known ciphertext.
blink::WebCryptoKey key;
ASSERT_EQ(
Status::Success(),
UnwrapKey(
- blink::WebCryptoKeyFormatRaw, CryptoData(test_ciphertext),
+ blink::kWebCryptoKeyFormatRaw, CryptoData(test_ciphertext),
wrapping_key, wrapping_algorithm,
- CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha1),
- false, blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
+ CreateHmacImportAlgorithmNoLength(blink::kWebCryptoAlgorithmIdSha1),
+ false,
+ blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify,
&key));
- EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
- EXPECT_FALSE(key.extractable());
- EXPECT_EQ(blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
- key.usages());
+ EXPECT_EQ(blink::kWebCryptoKeyTypeSecret, key.GetType());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdHmac, key.Algorithm().Id());
+ EXPECT_FALSE(key.Extractable());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify,
+ key.Usages());
// Sign an empty message and ensure it is verified.
std::vector<uint8_t> test_message;
std::vector<uint8_t> signature;
ASSERT_EQ(Status::Success(),
- Sign(CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac), key,
+ Sign(CreateAlgorithm(blink::kWebCryptoAlgorithmIdHmac), key,
CryptoData(test_message), &signature));
EXPECT_GT(signature.size(), 0u);
@@ -290,7 +291,7 @@ TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyUnwrapSignVerifyHmac) {
bool verify_result;
ASSERT_EQ(
Status::Success(),
- Verify(CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac), key,
+ Verify(CreateAlgorithm(blink::kWebCryptoAlgorithmIdHmac), key,
CryptoData(signature), CryptoData(test_message), &verify_result));
}
@@ -305,34 +306,34 @@ TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyWrapUnwrapErrors) {
const std::vector<uint8_t> test_ciphertext =
GetBytesFromHexString(test, "ciphertext");
const blink::WebCryptoAlgorithm wrapping_algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw);
const blink::WebCryptoAlgorithm key_algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc);
// Import the wrapping key.
blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
test_kek, wrapping_algorithm,
- blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey);
+ blink::kWebCryptoKeyUsageWrapKey | blink::kWebCryptoKeyUsageUnwrapKey);
// Import the key to be wrapped.
blink::WebCryptoKey key = ImportSecretKeyFromRaw(
- test_key, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
- blink::WebCryptoKeyUsageEncrypt);
+ test_key, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc),
+ blink::kWebCryptoKeyUsageEncrypt);
// Unwrap with wrapped data too small must fail.
const std::vector<uint8_t> small_data(test_ciphertext.begin(),
test_ciphertext.begin() + 23);
blink::WebCryptoKey unwrapped_key;
EXPECT_EQ(Status::ErrorDataTooSmall(),
- UnwrapKey(blink::WebCryptoKeyFormatRaw, CryptoData(small_data),
+ UnwrapKey(blink::kWebCryptoKeyFormatRaw, CryptoData(small_data),
wrapping_key, wrapping_algorithm, key_algorithm, true,
- blink::WebCryptoKeyUsageEncrypt, &unwrapped_key));
+ blink::kWebCryptoKeyUsageEncrypt, &unwrapped_key));
// Unwrap with wrapped data size not a multiple of 8 bytes must fail.
const std::vector<uint8_t> unaligned_data(test_ciphertext.begin(),
test_ciphertext.end() - 2);
EXPECT_EQ(Status::ErrorInvalidAesKwDataLength(),
- UnwrapKey(blink::WebCryptoKeyFormatRaw, CryptoData(unaligned_data),
+ UnwrapKey(blink::kWebCryptoKeyFormatRaw, CryptoData(unaligned_data),
wrapping_key, wrapping_algorithm, key_algorithm, true,
- blink::WebCryptoKeyUsageEncrypt, &unwrapped_key));
+ blink::kWebCryptoKeyUsageEncrypt, &unwrapped_key));
}
TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyUnwrapCorruptData) {
@@ -346,22 +347,22 @@ TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyUnwrapCorruptData) {
const std::vector<uint8_t> test_ciphertext =
GetBytesFromHexString(test, "ciphertext");
const blink::WebCryptoAlgorithm wrapping_algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw);
// Import the wrapping key.
blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
test_kek, wrapping_algorithm,
- blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey);
+ blink::kWebCryptoKeyUsageWrapKey | blink::kWebCryptoKeyUsageUnwrapKey);
// Unwrap of a corrupted version of the known ciphertext should fail, due to
// AES-KW's built-in integrity check.
blink::WebCryptoKey unwrapped_key;
EXPECT_EQ(Status::OperationError(),
- UnwrapKey(blink::WebCryptoKeyFormatRaw,
+ UnwrapKey(blink::kWebCryptoKeyFormatRaw,
CryptoData(Corrupted(test_ciphertext)), wrapping_key,
wrapping_algorithm,
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
- blink::WebCryptoKeyUsageEncrypt, &unwrapped_key));
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), true,
+ blink::kWebCryptoKeyUsageEncrypt, &unwrapped_key));
}
TEST_F(WebCryptoAesKwTest, AesKwJwkSymkeyUnwrapKnownData) {
@@ -382,37 +383,38 @@ TEST_F(WebCryptoAesKwTest, AesKwJwkSymkeyUnwrapKnownData) {
const std::vector<uint8_t> wrapping_key_data =
HexStringToBytes("000102030405060708090A0B0C0D0E0F");
const blink::WebCryptoAlgorithm wrapping_algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw);
// Import the wrapping key.
- blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
- wrapping_key_data, wrapping_algorithm, blink::WebCryptoKeyUsageUnwrapKey);
+ blink::WebCryptoKey wrapping_key =
+ ImportSecretKeyFromRaw(wrapping_key_data, wrapping_algorithm,
+ blink::kWebCryptoKeyUsageUnwrapKey);
// Unwrap the known wrapped key data to produce a new key
blink::WebCryptoKey unwrapped_key;
ASSERT_EQ(
Status::Success(),
UnwrapKey(
- blink::WebCryptoKeyFormatJwk, CryptoData(wrapped_key_data),
+ blink::kWebCryptoKeyFormatJwk, CryptoData(wrapped_key_data),
wrapping_key, wrapping_algorithm,
- CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha256),
- true, blink::WebCryptoKeyUsageVerify, &unwrapped_key));
+ CreateHmacImportAlgorithmNoLength(blink::kWebCryptoAlgorithmIdSha256),
+ true, blink::kWebCryptoKeyUsageVerify, &unwrapped_key));
// Validate the new key's attributes.
- EXPECT_FALSE(unwrapped_key.isNull());
- EXPECT_TRUE(unwrapped_key.handle());
- EXPECT_EQ(blink::WebCryptoKeyTypeSecret, unwrapped_key.type());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, unwrapped_key.algorithm().id());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
- unwrapped_key.algorithm().hmacParams()->hash().id());
- EXPECT_EQ(256u, unwrapped_key.algorithm().hmacParams()->lengthBits());
- EXPECT_EQ(true, unwrapped_key.extractable());
- EXPECT_EQ(blink::WebCryptoKeyUsageVerify, unwrapped_key.usages());
+ EXPECT_FALSE(unwrapped_key.IsNull());
+ EXPECT_TRUE(unwrapped_key.Handle());
+ EXPECT_EQ(blink::kWebCryptoKeyTypeSecret, unwrapped_key.GetType());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdHmac, unwrapped_key.Algorithm().Id());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha256,
+ unwrapped_key.Algorithm().HmacParams()->GetHash().Id());
+ EXPECT_EQ(256u, unwrapped_key.Algorithm().HmacParams()->LengthBits());
+ EXPECT_EQ(true, unwrapped_key.Extractable());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageVerify, unwrapped_key.Usages());
// Export the new key's raw data and compare to the known original.
std::vector<uint8_t> raw_key;
EXPECT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
EXPECT_BYTES_EQ(key_data, raw_key);
}
@@ -421,15 +423,15 @@ TEST_F(WebCryptoAesKwTest, AesKwJwkSymkeyUnwrapKnownData) {
// 'wrapKey', 'unwrapKey'
TEST_F(WebCryptoAesKwTest, ImportKeyBadUsage_Raw) {
const blink::WebCryptoAlgorithm algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw);
blink::WebCryptoKeyUsageMask bad_usages[] = {
- blink::WebCryptoKeyUsageEncrypt,
- blink::WebCryptoKeyUsageDecrypt,
- blink::WebCryptoKeyUsageSign,
- blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageUnwrapKey,
- blink::WebCryptoKeyUsageDeriveBits,
- blink::WebCryptoKeyUsageUnwrapKey | blink::WebCryptoKeyUsageVerify,
+ blink::kWebCryptoKeyUsageEncrypt,
+ blink::kWebCryptoKeyUsageDecrypt,
+ blink::kWebCryptoKeyUsageSign,
+ blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageUnwrapKey,
+ blink::kWebCryptoKeyUsageDeriveBits,
+ blink::kWebCryptoKeyUsageUnwrapKey | blink::kWebCryptoKeyUsageVerify,
};
std::vector<uint8_t> key_bytes(16);
@@ -439,7 +441,7 @@ TEST_F(WebCryptoAesKwTest, ImportKeyBadUsage_Raw) {
blink::WebCryptoKey key;
ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
- ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(key_bytes),
+ ImportKey(blink::kWebCryptoKeyFormatRaw, CryptoData(key_bytes),
algorithm, true, bad_usages[i], &key));
}
}
@@ -449,22 +451,22 @@ TEST_F(WebCryptoAesKwTest, ImportKeyBadUsage_Raw) {
// 'sign', 'verify'
TEST_F(WebCryptoAesKwTest, UnwrapHmacKeyBadUsage_JWK) {
const blink::WebCryptoAlgorithm unwrap_algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw);
blink::WebCryptoKeyUsageMask bad_usages[] = {
- blink::WebCryptoKeyUsageEncrypt,
- blink::WebCryptoKeyUsageDecrypt,
- blink::WebCryptoKeyUsageWrapKey,
- blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageWrapKey,
- blink::WebCryptoKeyUsageVerify | blink::WebCryptoKeyUsageDeriveKey,
+ blink::kWebCryptoKeyUsageEncrypt,
+ blink::kWebCryptoKeyUsageDecrypt,
+ blink::kWebCryptoKeyUsageWrapKey,
+ blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageWrapKey,
+ blink::kWebCryptoKeyUsageVerify | blink::kWebCryptoKeyUsageDeriveKey,
};
// Import the wrapping key.
blink::WebCryptoKey wrapping_key;
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatRaw,
+ ImportKey(blink::kWebCryptoKeyFormatRaw,
CryptoData(std::vector<uint8_t>(16)), unwrap_algorithm,
- true, blink::WebCryptoKeyUsageUnwrapKey, &wrapping_key));
+ true, blink::kWebCryptoKeyUsageUnwrapKey, &wrapping_key));
// The JWK plain text is:
// {"kty":"oct","alg":"HS256","k":"GADWrMRHwQfoNaXU5fZvTg"}
@@ -477,13 +479,13 @@ TEST_F(WebCryptoAesKwTest, UnwrapHmacKeyBadUsage_JWK) {
blink::WebCryptoKey key;
- ASSERT_EQ(
- Status::ErrorCreateKeyBadUsages(),
- UnwrapKey(blink::WebCryptoKeyFormatJwk,
- CryptoData(HexStringToBytes(kWrappedJwk)), wrapping_key,
- unwrap_algorithm, CreateHmacImportAlgorithmNoLength(
- blink::WebCryptoAlgorithmIdSha256),
- true, bad_usages[i], &key));
+ ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
+ UnwrapKey(blink::kWebCryptoKeyFormatJwk,
+ CryptoData(HexStringToBytes(kWrappedJwk)), wrapping_key,
+ unwrap_algorithm,
+ CreateHmacImportAlgorithmNoLength(
+ blink::kWebCryptoAlgorithmIdSha256),
+ true, bad_usages[i], &key));
}
}
@@ -492,22 +494,22 @@ TEST_F(WebCryptoAesKwTest, UnwrapHmacKeyBadUsage_JWK) {
// 'verify'
TEST_F(WebCryptoAesKwTest, UnwrapRsaSsaPublicKeyBadUsage_JWK) {
const blink::WebCryptoAlgorithm unwrap_algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesKw);
blink::WebCryptoKeyUsageMask bad_usages[] = {
- blink::WebCryptoKeyUsageEncrypt,
- blink::WebCryptoKeyUsageSign,
- blink::WebCryptoKeyUsageDecrypt,
- blink::WebCryptoKeyUsageWrapKey,
- blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageWrapKey,
+ blink::kWebCryptoKeyUsageEncrypt,
+ blink::kWebCryptoKeyUsageSign,
+ blink::kWebCryptoKeyUsageDecrypt,
+ blink::kWebCryptoKeyUsageWrapKey,
+ blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageWrapKey,
};
// Import the wrapping key.
blink::WebCryptoKey wrapping_key;
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatRaw,
+ ImportKey(blink::kWebCryptoKeyFormatRaw,
CryptoData(std::vector<uint8_t>(16)), unwrap_algorithm,
- true, blink::WebCryptoKeyUsageUnwrapKey, &wrapping_key));
+ true, blink::kWebCryptoKeyUsageUnwrapKey, &wrapping_key));
// The JWK plaintext is:
// { "kty": "RSA","alg": "RS256","n": "...","e": "AQAB"}
@@ -527,12 +529,12 @@ TEST_F(WebCryptoAesKwTest, UnwrapRsaSsaPublicKeyBadUsage_JWK) {
blink::WebCryptoKey key;
ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
- UnwrapKey(blink::WebCryptoKeyFormatJwk,
+ UnwrapKey(blink::kWebCryptoKeyFormatJwk,
CryptoData(HexStringToBytes(kWrappedJwk)), wrapping_key,
unwrap_algorithm,
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256),
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256),
true, bad_usages[i], &key));
}
}
diff --git a/chromium/components/webcrypto/algorithms/asymmetric_key_util.cc b/chromium/components/webcrypto/algorithms/asymmetric_key_util.cc
index 2a631ad0db4..07d4f6b33d3 100644
--- a/chromium/components/webcrypto/algorithms/asymmetric_key_util.cc
+++ b/chromium/components/webcrypto/algorithms/asymmetric_key_util.cc
@@ -69,9 +69,9 @@ Status CreateWebCryptoPublicKey(bssl::UniquePtr<EVP_PKEY> public_key,
if (status.IsError())
return status;
- *key = blink::WebCryptoKey::create(
+ *key = blink::WebCryptoKey::Create(
CreateAsymmetricKeyHandle(std::move(public_key), spki_data),
- blink::WebCryptoKeyTypePublic, extractable, algorithm, usages);
+ blink::kWebCryptoKeyTypePublic, extractable, algorithm, usages);
return Status::Success();
}
@@ -87,9 +87,9 @@ Status CreateWebCryptoPrivateKey(bssl::UniquePtr<EVP_PKEY> private_key,
if (status.IsError())
return status;
- *key = blink::WebCryptoKey::create(
+ *key = blink::WebCryptoKey::Create(
CreateAsymmetricKeyHandle(std::move(private_key), pkcs8_data),
- blink::WebCryptoKeyTypePrivate, extractable, algorithm, usages);
+ blink::kWebCryptoKeyTypePrivate, extractable, algorithm, usages);
return Status::Success();
}
diff --git a/chromium/components/webcrypto/algorithms/ec.cc b/chromium/components/webcrypto/algorithms/ec.cc
index 2a6d312de3a..fd45a2346f2 100644
--- a/chromium/components/webcrypto/algorithms/ec.cc
+++ b/chromium/components/webcrypto/algorithms/ec.cc
@@ -34,13 +34,13 @@ namespace {
// BoringSSL.
Status WebCryptoCurveToNid(blink::WebCryptoNamedCurve named_curve, int* nid) {
switch (named_curve) {
- case blink::WebCryptoNamedCurveP256:
+ case blink::kWebCryptoNamedCurveP256:
*nid = NID_X9_62_prime256v1;
return Status::Success();
- case blink::WebCryptoNamedCurveP384:
+ case blink::kWebCryptoNamedCurveP384:
*nid = NID_secp384r1;
return Status::Success();
- case blink::WebCryptoNamedCurveP521:
+ case blink::kWebCryptoNamedCurveP521:
*nid = NID_secp521r1;
return Status::Success();
}
@@ -51,13 +51,13 @@ Status WebCryptoCurveToNid(blink::WebCryptoNamedCurve named_curve, int* nid) {
Status NidToWebCryptoCurve(int nid, blink::WebCryptoNamedCurve* named_curve) {
switch (nid) {
case NID_X9_62_prime256v1:
- *named_curve = blink::WebCryptoNamedCurveP256;
+ *named_curve = blink::kWebCryptoNamedCurveP256;
return Status::Success();
case NID_secp384r1:
- *named_curve = blink::WebCryptoNamedCurveP384;
+ *named_curve = blink::kWebCryptoNamedCurveP384;
return Status::Success();
case NID_secp521r1:
- *named_curve = blink::WebCryptoNamedCurveP521;
+ *named_curve = blink::kWebCryptoNamedCurveP521;
return Status::Success();
}
return Status::ErrorImportedEcKeyIncorrectCurve();
@@ -69,9 +69,9 @@ struct JwkCrvMapping {
};
const JwkCrvMapping kJwkCrvMappings[] = {
- {"P-256", blink::WebCryptoNamedCurveP256},
- {"P-384", blink::WebCryptoNamedCurveP384},
- {"P-521", blink::WebCryptoNamedCurveP521},
+ {"P-256", blink::kWebCryptoNamedCurveP256},
+ {"P-384", blink::kWebCryptoNamedCurveP384},
+ {"P-521", blink::kWebCryptoNamedCurveP521},
};
// Gets the "crv" parameter from a JWK and converts it to a WebCryptoNamedCurve.
@@ -129,7 +129,7 @@ Status VerifyEcKeyAfterSpkiOrPkcs8Import(
// Make sure the curve matches the expected curve name.
int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
- blink::WebCryptoNamedCurve named_curve = blink::WebCryptoNamedCurveP256;
+ blink::WebCryptoNamedCurve named_curve = blink::kWebCryptoNamedCurveP256;
Status status = NidToWebCryptoCurve(curve_nid, &named_curve);
if (status.IsError())
return status;
@@ -214,9 +214,9 @@ Status GetPublicKey(EC_KEY* ec,
// deserialization can re-use the ImportKey*() methods.
blink::WebCryptoAlgorithm SynthesizeImportAlgorithmForClone(
const blink::WebCryptoKeyAlgorithm& algorithm) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- algorithm.id(), new blink::WebCryptoEcKeyImportParams(
- algorithm.ecParams()->namedCurve()));
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ algorithm.Id(), new blink::WebCryptoEcKeyImportParams(
+ algorithm.EcParams()->NamedCurve()));
}
} // namespace
@@ -234,13 +234,13 @@ Status EcAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
if (status.IsError())
return status;
- const blink::WebCryptoEcKeyGenParams* params = algorithm.ecKeyGenParams();
+ const blink::WebCryptoEcKeyGenParams* params = algorithm.EcKeyGenParams();
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
// Generate an EC key pair.
bssl::UniquePtr<EC_KEY> ec_private_key;
- status = CreateEC_KEY(params->namedCurve(), &ec_private_key);
+ status = CreateEC_KEY(params->NamedCurve(), &ec_private_key);
if (status.IsError())
return status;
@@ -257,7 +257,7 @@ Status EcAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
// Construct an EVP_PKEY for just the public key.
bssl::UniquePtr<EC_KEY> ec_public_key;
bssl::UniquePtr<EVP_PKEY> public_pkey(EVP_PKEY_new());
- status = CreateEC_KEY(params->namedCurve(), &ec_public_key);
+ status = CreateEC_KEY(params->NamedCurve(), &ec_public_key);
if (status.IsError())
return status;
if (!EC_KEY_set_public_key(ec_public_key.get(),
@@ -273,8 +273,8 @@ Status EcAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
blink::WebCryptoKey private_key;
blink::WebCryptoKeyAlgorithm key_algorithm =
- blink::WebCryptoKeyAlgorithm::createEc(algorithm.id(),
- params->namedCurve());
+ blink::WebCryptoKeyAlgorithm::CreateEc(algorithm.Id(),
+ params->NamedCurve());
// Note that extractable is unconditionally set to true. This is because per
// the WebCrypto spec generated public keys are always extractable.
@@ -299,13 +299,13 @@ Status EcAlgorithm::ImportKey(blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
switch (format) {
- case blink::WebCryptoKeyFormatRaw:
+ case blink::kWebCryptoKeyFormatRaw:
return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
- case blink::WebCryptoKeyFormatPkcs8:
+ case blink::kWebCryptoKeyFormatPkcs8:
return ImportKeyPkcs8(key_data, algorithm, extractable, usages, key);
- case blink::WebCryptoKeyFormatSpki:
+ case blink::kWebCryptoKeyFormatSpki:
return ImportKeySpki(key_data, algorithm, extractable, usages, key);
- case blink::WebCryptoKeyFormatJwk:
+ case blink::kWebCryptoKeyFormatJwk:
return ImportKeyJwk(key_data, algorithm, extractable, usages, key);
default:
return Status::ErrorUnsupportedImportKeyFormat();
@@ -316,13 +316,13 @@ Status EcAlgorithm::ExportKey(blink::WebCryptoKeyFormat format,
const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
switch (format) {
- case blink::WebCryptoKeyFormatRaw:
+ case blink::kWebCryptoKeyFormatRaw:
return ExportKeyRaw(key, buffer);
- case blink::WebCryptoKeyFormatPkcs8:
+ case blink::kWebCryptoKeyFormatPkcs8:
return ExportKeyPkcs8(key, buffer);
- case blink::WebCryptoKeyFormatSpki:
+ case blink::kWebCryptoKeyFormatSpki:
return ExportKeySpki(key, buffer);
- case blink::WebCryptoKeyFormatJwk:
+ case blink::kWebCryptoKeyFormatJwk:
return ExportKeyJwk(key, buffer);
default:
return Status::ErrorUnsupportedExportKeyFormat();
@@ -341,11 +341,11 @@ Status EcAlgorithm::ImportKeyRaw(const CryptoData& key_data,
return status;
const blink::WebCryptoEcKeyImportParams* params =
- algorithm.ecKeyImportParams();
+ algorithm.EcKeyImportParams();
// Create an EC_KEY.
bssl::UniquePtr<EC_KEY> ec;
- status = CreateEC_KEY(params->namedCurve(), &ec);
+ status = CreateEC_KEY(params->NamedCurve(), &ec);
if (status.IsError())
return status;
@@ -373,8 +373,8 @@ Status EcAlgorithm::ImportKeyRaw(const CryptoData& key_data,
return Status::OperationError();
blink::WebCryptoKeyAlgorithm key_algorithm =
- blink::WebCryptoKeyAlgorithm::createEc(algorithm.id(),
- params->namedCurve());
+ blink::WebCryptoKeyAlgorithm::CreateEc(algorithm.Id(),
+ params->NamedCurve());
// Wrap the EVP_PKEY into a WebCryptoKey
return CreateWebCryptoPublicKey(std::move(pkey), key_algorithm, extractable,
@@ -396,16 +396,16 @@ Status EcAlgorithm::ImportKeyPkcs8(const CryptoData& key_data,
return status;
const blink::WebCryptoEcKeyImportParams* params =
- algorithm.ecKeyImportParams();
+ algorithm.EcKeyImportParams();
status = VerifyEcKeyAfterSpkiOrPkcs8Import(private_key.get(),
- params->namedCurve());
+ params->NamedCurve());
if (status.IsError())
return status;
return CreateWebCryptoPrivateKey(std::move(private_key),
- blink::WebCryptoKeyAlgorithm::createEc(
- algorithm.id(), params->namedCurve()),
+ blink::WebCryptoKeyAlgorithm::CreateEc(
+ algorithm.Id(), params->NamedCurve()),
extractable, usages, key);
}
@@ -424,16 +424,16 @@ Status EcAlgorithm::ImportKeySpki(const CryptoData& key_data,
return status;
const blink::WebCryptoEcKeyImportParams* params =
- algorithm.ecKeyImportParams();
+ algorithm.EcKeyImportParams();
status =
- VerifyEcKeyAfterSpkiOrPkcs8Import(public_key.get(), params->namedCurve());
+ VerifyEcKeyAfterSpkiOrPkcs8Import(public_key.get(), params->NamedCurve());
if (status.IsError())
return status;
return CreateWebCryptoPublicKey(std::move(public_key),
- blink::WebCryptoKeyAlgorithm::createEc(
- algorithm.id(), params->namedCurve()),
+ blink::WebCryptoKeyAlgorithm::CreateEc(
+ algorithm.Id(), params->NamedCurve()),
extractable, usages, key);
}
@@ -447,7 +447,7 @@ Status EcAlgorithm::ImportKeyJwk(const CryptoData& key_data,
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
const blink::WebCryptoEcKeyImportParams* params =
- algorithm.ecKeyImportParams();
+ algorithm.EcKeyImportParams();
// When importing EC keys from JWK there may be up to *three* separate curve
// names:
@@ -460,16 +460,16 @@ Status EcAlgorithm::ImportKeyJwk(const CryptoData& key_data,
JwkReader jwk;
Status status = jwk.Init(key_data, extractable, usages, "EC",
- GetJwkAlgorithm(params->namedCurve()));
+ GetJwkAlgorithm(params->NamedCurve()));
if (status.IsError())
return status;
// Verify that "crv" matches expected curve.
- blink::WebCryptoNamedCurve jwk_crv = blink::WebCryptoNamedCurveP256;
+ blink::WebCryptoNamedCurve jwk_crv = blink::kWebCryptoNamedCurveP256;
status = ReadJwkCrv(jwk, &jwk_crv);
if (status.IsError())
return status;
- if (jwk_crv != params->namedCurve())
+ if (jwk_crv != params->NamedCurve())
return Status::ErrorJwkIncorrectCrv();
// Only private keys have a "d" parameter. The key may still be invalid, but
@@ -488,7 +488,7 @@ Status EcAlgorithm::ImportKeyJwk(const CryptoData& key_data,
// Create an EC_KEY.
bssl::UniquePtr<EC_KEY> ec;
- status = CreateEC_KEY(params->namedCurve(), &ec);
+ status = CreateEC_KEY(params->NamedCurve(), &ec);
if (status.IsError())
return status;
@@ -533,8 +533,8 @@ Status EcAlgorithm::ImportKeyJwk(const CryptoData& key_data,
return Status::OperationError();
blink::WebCryptoKeyAlgorithm key_algorithm =
- blink::WebCryptoKeyAlgorithm::createEc(algorithm.id(),
- params->namedCurve());
+ blink::WebCryptoKeyAlgorithm::CreateEc(algorithm.Id(),
+ params->NamedCurve());
// Wrap the EVP_PKEY into a WebCryptoKey
if (is_private_key) {
@@ -549,7 +549,7 @@ Status EcAlgorithm::ExportKeyRaw(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- if (key.type() != blink::WebCryptoKeyTypePublic)
+ if (key.GetType() != blink::kWebCryptoKeyTypePublic)
return Status::ErrorUnexpectedKeyType();
EVP_PKEY* pkey = GetEVP_PKEY(key);
@@ -577,7 +577,7 @@ Status EcAlgorithm::ExportKeyRaw(const blink::WebCryptoKey& key,
Status EcAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
- if (key.type() != blink::WebCryptoKeyTypePrivate)
+ if (key.GetType() != blink::kWebCryptoKeyTypePrivate)
return Status::ErrorUnexpectedKeyType();
// This relies on the fact that PKCS8 formatted data was already
// associated with the key during its creation (used by
@@ -588,7 +588,7 @@ Status EcAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
Status EcAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
- if (key.type() != blink::WebCryptoKeyTypePublic)
+ if (key.GetType() != blink::kWebCryptoKeyTypePublic)
return Status::ErrorUnexpectedKeyType();
// This relies on the fact that SPKI formatted data was already
// associated with the key during its creation (used by
@@ -610,12 +610,12 @@ Status EcAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
return Status::ErrorUnexpected();
// No "alg" is set for EC keys.
- JwkWriter jwk(std::string(), key.extractable(), key.usages(), "EC");
+ JwkWriter jwk(std::string(), key.Extractable(), key.Usages(), "EC");
// Set the crv
std::string crv;
Status status =
- WebCryptoCurveToJwkCrv(key.algorithm().ecParams()->namedCurve(), &crv);
+ WebCryptoCurveToJwkCrv(key.Algorithm().EcParams()->NamedCurve(), &crv);
if (status.IsError())
return status;
@@ -637,7 +637,7 @@ Status EcAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
if (status.IsError())
return status;
- if (key.type() == blink::WebCryptoKeyTypePrivate) {
+ if (key.GetType() == blink::kWebCryptoKeyTypePrivate) {
const BIGNUM* d = EC_KEY_get0_private_key(ec);
status = WritePaddedBIGNUM("d", d, degree_bytes, &jwk);
if (status.IsError())
@@ -656,7 +656,7 @@ Status EcAlgorithm::DeserializeKeyForClone(
blink::WebCryptoKeyUsageMask usages,
const CryptoData& key_data,
blink::WebCryptoKey* key) const {
- if (algorithm.paramsType() != blink::WebCryptoKeyAlgorithmParamsTypeEc)
+ if (algorithm.ParamsType() != blink::kWebCryptoKeyAlgorithmParamsTypeEc)
return Status::ErrorUnexpected();
blink::WebCryptoAlgorithm import_algorithm =
@@ -666,11 +666,11 @@ Status EcAlgorithm::DeserializeKeyForClone(
// The serialized data will be either SPKI or PKCS8 formatted.
switch (type) {
- case blink::WebCryptoKeyTypePublic:
+ case blink::kWebCryptoKeyTypePublic:
status =
ImportKeySpki(key_data, import_algorithm, extractable, usages, key);
break;
- case blink::WebCryptoKeyTypePrivate:
+ case blink::kWebCryptoKeyTypePrivate:
status =
ImportKeyPkcs8(key_data, import_algorithm, extractable, usages, key);
break;
@@ -683,14 +683,14 @@ Status EcAlgorithm::DeserializeKeyForClone(
// key data). Use this extra information to further validate what was
// deserialized from the key data.
- if (algorithm.id() != key->algorithm().id())
+ if (algorithm.Id() != key->Algorithm().Id())
return Status::ErrorUnexpected();
- if (type != key->type())
+ if (type != key->GetType())
return Status::ErrorUnexpected();
- if (algorithm.ecParams()->namedCurve() !=
- key->algorithm().ecParams()->namedCurve()) {
+ if (algorithm.EcParams()->NamedCurve() !=
+ key->Algorithm().EcParams()->NamedCurve()) {
return Status::ErrorUnexpected();
}
diff --git a/chromium/components/webcrypto/algorithms/ecdh.cc b/chromium/components/webcrypto/algorithms/ecdh.cc
index 2c0c2da559c..f261a0afe54 100644
--- a/chromium/components/webcrypto/algorithms/ecdh.cc
+++ b/chromium/components/webcrypto/algorithms/ecdh.cc
@@ -37,8 +37,8 @@ class EcdhImplementation : public EcAlgorithm {
public:
EcdhImplementation()
: EcAlgorithm(0,
- blink::WebCryptoKeyUsageDeriveKey |
- blink::WebCryptoKeyUsageDeriveBits) {}
+ blink::kWebCryptoKeyUsageDeriveKey |
+ blink::kWebCryptoKeyUsageDeriveBits) {}
const char* GetJwkAlgorithm(
const blink::WebCryptoNamedCurve curve) const override {
@@ -51,30 +51,30 @@ class EcdhImplementation : public EcAlgorithm {
bool has_optional_length_bits,
unsigned int optional_length_bits,
std::vector<uint8_t>* derived_bytes) const override {
- if (base_key.type() != blink::WebCryptoKeyTypePrivate)
+ if (base_key.GetType() != blink::kWebCryptoKeyTypePrivate)
return Status::ErrorUnexpectedKeyType();
// Verify the "publicKey" parameter. The only guarantee from Blink is that
// it is a valid WebCryptoKey, but it could be any type.
const blink::WebCryptoKey& public_key =
- algorithm.ecdhKeyDeriveParams()->publicKey();
+ algorithm.EcdhKeyDeriveParams()->PublicKey();
- if (public_key.type() != blink::WebCryptoKeyTypePublic)
+ if (public_key.GetType() != blink::kWebCryptoKeyTypePublic)
return Status::ErrorEcdhPublicKeyWrongType();
// Make sure it is an EC key.
- if (!public_key.algorithm().ecParams())
+ if (!public_key.Algorithm().EcParams())
return Status::ErrorEcdhPublicKeyWrongType();
// TODO(eroman): This is not described by the spec:
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=27404
- if (public_key.algorithm().id() != blink::WebCryptoAlgorithmIdEcdh)
+ if (public_key.Algorithm().Id() != blink::kWebCryptoAlgorithmIdEcdh)
return Status::ErrorEcdhPublicKeyWrongAlgorithm();
// The public and private keys come from different key pairs, however their
// curves must match.
- if (public_key.algorithm().ecParams()->namedCurve() !=
- base_key.algorithm().ecParams()->namedCurve()) {
+ if (public_key.Algorithm().EcParams()->NamedCurve() !=
+ base_key.Algorithm().EcParams()->NamedCurve()) {
return Status::ErrorEcdhCurveMismatch();
}
diff --git a/chromium/components/webcrypto/algorithms/ecdh_unittest.cc b/chromium/components/webcrypto/algorithms/ecdh_unittest.cc
index 387b16ae9b2..3332cfd6346 100644
--- a/chromium/components/webcrypto/algorithms/ecdh_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/ecdh_unittest.cc
@@ -24,20 +24,20 @@ namespace {
blink::WebCryptoAlgorithm CreateEcdhImportAlgorithm(
blink::WebCryptoNamedCurve named_curve) {
- return CreateEcImportAlgorithm(blink::WebCryptoAlgorithmIdEcdh, named_curve);
+ return CreateEcImportAlgorithm(blink::kWebCryptoAlgorithmIdEcdh, named_curve);
}
blink::WebCryptoAlgorithm CreateEcdhDeriveParams(
const blink::WebCryptoKey& public_key) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdEcdh,
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ blink::kWebCryptoAlgorithmIdEcdh,
new blink::WebCryptoEcdhKeyDeriveParams(public_key));
}
blink::WebCryptoAlgorithm CreateAesGcmDerivedKeyParams(
unsigned short length_bits) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdAesGcm,
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ blink::kWebCryptoAlgorithmIdAesGcm,
new blink::WebCryptoAesDerivedKeyParams(length_bits));
}
@@ -51,7 +51,7 @@ bool ImportKeysFromTest(const base::DictionaryValue* test,
blink::WebCryptoNamedCurve curve =
GetCurveNameFromDictionary(public_key_json);
EXPECT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatJwk,
+ ImportKey(blink::kWebCryptoKeyFormatJwk,
CryptoData(MakeJsonVector(*public_key_json)),
CreateEcdhImportAlgorithm(curve), true, 0, public_key));
@@ -65,10 +65,10 @@ bool ImportKeysFromTest(const base::DictionaryValue* test,
EXPECT_TRUE(test->GetDictionary("private_key", &private_key_json));
curve = GetCurveNameFromDictionary(private_key_json);
Status status = ImportKey(
- blink::WebCryptoKeyFormatJwk,
+ blink::kWebCryptoKeyFormatJwk,
CryptoData(MakeJsonVector(*private_key_json)),
CreateEcdhImportAlgorithm(curve), true,
- blink::WebCryptoKeyUsageDeriveBits | blink::WebCryptoKeyUsageDeriveKey,
+ blink::kWebCryptoKeyUsageDeriveBits | blink::kWebCryptoKeyUsageDeriveKey,
private_key);
EXPECT_EQ(expected_private_key_error, StatusToString(status));
return status.IsSuccess();
@@ -139,8 +139,8 @@ TEST_F(WebCryptoEcdhTest, DeriveBitsKnownAnswer) {
ImportKeysFromTest(test, public_key, private_key);
- EXPECT_EQ(blink::WebCryptoNamedCurveP521,
- public_key->algorithm().ecParams()->namedCurve());
+ EXPECT_EQ(blink::kWebCryptoNamedCurveP521,
+ public_key->Algorithm().EcParams()->NamedCurve());
return ::testing::AssertionSuccess();
}
@@ -155,9 +155,9 @@ TEST_F(WebCryptoEcdhTest, DeriveKeyBadAesLength) {
ASSERT_EQ(Status::ErrorGetAesKeyLength(),
DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm),
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesGcm),
CreateAesGcmDerivedKeyParams(129), true,
- blink::WebCryptoKeyUsageEncrypt, &derived_key));
+ blink::kWebCryptoKeyUsageEncrypt, &derived_key));
}
// Try deriving an AES key of length 192 bits.
@@ -170,9 +170,9 @@ TEST_F(WebCryptoEcdhTest, DeriveKeyUnsupportedAesLength) {
ASSERT_EQ(Status::ErrorAes192BitUnsupported(),
DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm),
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesGcm),
CreateAesGcmDerivedKeyParams(192), true,
- blink::WebCryptoKeyUsageEncrypt, &derived_key));
+ blink::kWebCryptoKeyUsageEncrypt, &derived_key));
}
// Try deriving an HMAC key of length 0 bits.
@@ -184,12 +184,12 @@ TEST_F(WebCryptoEcdhTest, DeriveKeyZeroLengthHmac) {
blink::WebCryptoKey derived_key;
const blink::WebCryptoAlgorithm import_algorithm =
- CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0);
+ CreateHmacImportAlgorithm(blink::kWebCryptoAlgorithmIdSha1, 0);
ASSERT_EQ(Status::ErrorGetHmacKeyLengthZero(),
DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
import_algorithm, import_algorithm, true,
- blink::WebCryptoKeyUsageSign, &derived_key));
+ blink::kWebCryptoKeyUsageSign, &derived_key));
}
// Derive an HMAC key of length 19 bits.
@@ -201,22 +201,22 @@ TEST_F(WebCryptoEcdhTest, DeriveKeyHmac19Bits) {
blink::WebCryptoKey derived_key;
const blink::WebCryptoAlgorithm import_algorithm =
- CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1, 19);
+ CreateHmacImportAlgorithm(blink::kWebCryptoAlgorithmIdSha1, 19);
ASSERT_EQ(Status::Success(),
DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
import_algorithm, import_algorithm, true,
- blink::WebCryptoKeyUsageSign, &derived_key));
+ blink::kWebCryptoKeyUsageSign, &derived_key));
- ASSERT_EQ(blink::WebCryptoAlgorithmIdHmac, derived_key.algorithm().id());
- ASSERT_EQ(blink::WebCryptoAlgorithmIdSha1,
- derived_key.algorithm().hmacParams()->hash().id());
- ASSERT_EQ(19u, derived_key.algorithm().hmacParams()->lengthBits());
+ ASSERT_EQ(blink::kWebCryptoAlgorithmIdHmac, derived_key.Algorithm().Id());
+ ASSERT_EQ(blink::kWebCryptoAlgorithmIdSha1,
+ derived_key.Algorithm().HmacParams()->GetHash().Id());
+ ASSERT_EQ(19u, derived_key.Algorithm().HmacParams()->LengthBits());
// Export the key and verify its contents.
std::vector<uint8_t> raw_key;
EXPECT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, derived_key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, derived_key, &raw_key));
EXPECT_EQ(3u, raw_key.size());
// The last 7 bits of the key should be zero.
EXPECT_EQ(0, raw_key.back() & 0x1f);
@@ -231,22 +231,22 @@ TEST_F(WebCryptoEcdhTest, DeriveKeyHmacSha256NoLength) {
blink::WebCryptoKey derived_key;
const blink::WebCryptoAlgorithm import_algorithm =
- CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha256);
+ CreateHmacImportAlgorithmNoLength(blink::kWebCryptoAlgorithmIdSha256);
ASSERT_EQ(Status::Success(),
DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
import_algorithm, import_algorithm, true,
- blink::WebCryptoKeyUsageSign, &derived_key));
+ blink::kWebCryptoKeyUsageSign, &derived_key));
- ASSERT_EQ(blink::WebCryptoAlgorithmIdHmac, derived_key.algorithm().id());
- ASSERT_EQ(blink::WebCryptoAlgorithmIdSha256,
- derived_key.algorithm().hmacParams()->hash().id());
- ASSERT_EQ(512u, derived_key.algorithm().hmacParams()->lengthBits());
+ ASSERT_EQ(blink::kWebCryptoAlgorithmIdHmac, derived_key.Algorithm().Id());
+ ASSERT_EQ(blink::kWebCryptoAlgorithmIdSha256,
+ derived_key.Algorithm().HmacParams()->GetHash().Id());
+ ASSERT_EQ(512u, derived_key.Algorithm().HmacParams()->LengthBits());
// Export the key and verify its contents.
std::vector<uint8_t> raw_key;
EXPECT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, derived_key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, derived_key, &raw_key));
EXPECT_EQ(64u, raw_key.size());
}
@@ -267,12 +267,12 @@ TEST_F(WebCryptoEcdhTest, DeriveKeyHmacSha512NoLength) {
blink::WebCryptoKey derived_key;
const blink::WebCryptoAlgorithm import_algorithm =
- CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha512);
+ CreateHmacImportAlgorithmNoLength(blink::kWebCryptoAlgorithmIdSha512);
ASSERT_EQ(Status::ErrorEcdhLengthTooBig(528),
DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
import_algorithm, import_algorithm, true,
- blink::WebCryptoKeyUsageSign, &derived_key));
+ blink::kWebCryptoKeyUsageSign, &derived_key));
}
// Try deriving an AES key of length 128 bits.
@@ -285,17 +285,17 @@ TEST_F(WebCryptoEcdhTest, DeriveKeyAes128) {
ASSERT_EQ(Status::Success(),
DeriveKey(CreateEcdhDeriveParams(public_key), base_key,
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm),
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesGcm),
CreateAesGcmDerivedKeyParams(128), true,
- blink::WebCryptoKeyUsageEncrypt, &derived_key));
+ blink::kWebCryptoKeyUsageEncrypt, &derived_key));
- ASSERT_EQ(blink::WebCryptoAlgorithmIdAesGcm, derived_key.algorithm().id());
- ASSERT_EQ(128, derived_key.algorithm().aesParams()->lengthBits());
+ ASSERT_EQ(blink::kWebCryptoAlgorithmIdAesGcm, derived_key.Algorithm().Id());
+ ASSERT_EQ(128, derived_key.Algorithm().AesParams()->LengthBits());
// Export the key and verify its contents.
std::vector<uint8_t> raw_key;
EXPECT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, derived_key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, derived_key, &raw_key));
EXPECT_EQ(16u, raw_key.size());
}
@@ -314,17 +314,17 @@ TEST_F(WebCryptoEcdhTest, ImportKeyEmptyUsage) {
blink::WebCryptoNamedCurve curve =
GetCurveNameFromDictionary(public_key_json);
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatJwk,
+ ImportKey(blink::kWebCryptoKeyFormatJwk,
CryptoData(MakeJsonVector(*public_key_json)),
CreateEcdhImportAlgorithm(curve), true, 0, &key));
- EXPECT_EQ(0, key.usages());
+ EXPECT_EQ(0, key.Usages());
// Import the private key.
const base::DictionaryValue* private_key_json = NULL;
EXPECT_TRUE(test->GetDictionary("private_key", &private_key_json));
curve = GetCurveNameFromDictionary(private_key_json);
ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
- ImportKey(blink::WebCryptoKeyFormatJwk,
+ ImportKey(blink::kWebCryptoKeyFormatJwk,
CryptoData(MakeJsonVector(*private_key_json)),
CreateEcdhImportAlgorithm(curve), true, 0, &key));
}
diff --git a/chromium/components/webcrypto/algorithms/ecdsa.cc b/chromium/components/webcrypto/algorithms/ecdsa.cc
index 9c6762664e9..8f9f45a203f 100644
--- a/chromium/components/webcrypto/algorithms/ecdsa.cc
+++ b/chromium/components/webcrypto/algorithms/ecdsa.cc
@@ -38,7 +38,7 @@ Status GetPKeyAndDigest(const blink::WebCryptoAlgorithm& algorithm,
EVP_PKEY** pkey,
const EVP_MD** digest) {
*pkey = GetEVP_PKEY(key);
- *digest = GetDigest(algorithm.ecdsaParams()->hash());
+ *digest = GetDigest(algorithm.EcdsaParams()->GetHash());
if (!*digest)
return Status::ErrorUnsupported();
return Status::Success();
@@ -156,17 +156,17 @@ Status ConvertWebCryptoSignatureToDerSignature(
class EcdsaImplementation : public EcAlgorithm {
public:
EcdsaImplementation()
- : EcAlgorithm(blink::WebCryptoKeyUsageVerify,
- blink::WebCryptoKeyUsageSign) {}
+ : EcAlgorithm(blink::kWebCryptoKeyUsageVerify,
+ blink::kWebCryptoKeyUsageSign) {}
const char* GetJwkAlgorithm(
const blink::WebCryptoNamedCurve curve) const override {
switch (curve) {
- case blink::WebCryptoNamedCurveP256:
+ case blink::kWebCryptoNamedCurveP256:
return "ES256";
- case blink::WebCryptoNamedCurveP384:
+ case blink::kWebCryptoNamedCurveP384:
return "ES384";
- case blink::WebCryptoNamedCurveP521:
+ case blink::kWebCryptoNamedCurveP521:
// This is not a typo! ES512 means P-521 with SHA-512.
return "ES512";
default:
@@ -178,7 +178,7 @@ class EcdsaImplementation : public EcAlgorithm {
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) const override {
- if (key.type() != blink::WebCryptoKeyTypePrivate)
+ if (key.GetType() != blink::kWebCryptoKeyTypePrivate)
return Status::ErrorUnexpectedKeyType();
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
@@ -216,7 +216,7 @@ class EcdsaImplementation : public EcAlgorithm {
const CryptoData& signature,
const CryptoData& data,
bool* signature_match) const override {
- if (key.type() != blink::WebCryptoKeyTypePublic)
+ if (key.GetType() != blink::kWebCryptoKeyTypePublic)
return Status::ErrorUnexpectedKeyType();
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
diff --git a/chromium/components/webcrypto/algorithms/ecdsa_unittest.cc b/chromium/components/webcrypto/algorithms/ecdsa_unittest.cc
index 2b847bda2b3..03f9d0b1159 100644
--- a/chromium/components/webcrypto/algorithms/ecdsa_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/ecdsa_unittest.cc
@@ -20,20 +20,21 @@ namespace {
blink::WebCryptoAlgorithm CreateEcdsaKeyGenAlgorithm(
blink::WebCryptoNamedCurve named_curve) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdEcdsa,
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ blink::kWebCryptoAlgorithmIdEcdsa,
new blink::WebCryptoEcKeyGenParams(named_curve));
}
blink::WebCryptoAlgorithm CreateEcdsaImportAlgorithm(
blink::WebCryptoNamedCurve named_curve) {
- return CreateEcImportAlgorithm(blink::WebCryptoAlgorithmIdEcdsa, named_curve);
+ return CreateEcImportAlgorithm(blink::kWebCryptoAlgorithmIdEcdsa,
+ named_curve);
}
blink::WebCryptoAlgorithm CreateEcdsaAlgorithm(
blink::WebCryptoAlgorithmId hash_id) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdEcdsa,
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ blink::kWebCryptoAlgorithmIdEcdsa,
new blink::WebCryptoEcdsaParams(CreateAlgorithm(hash_id)));
}
@@ -44,7 +45,7 @@ class WebCryptoEcdsaTest : public WebCryptoTestBase {};
// ensure that the keys are otherwise usable (by trying to sign/verify with
// them).
TEST_F(WebCryptoEcdsaTest, GenerateKeyIsRandom) {
- blink::WebCryptoNamedCurve named_curve = blink::WebCryptoNamedCurveP256;
+ blink::WebCryptoNamedCurve named_curve = blink::kWebCryptoNamedCurveP256;
std::vector<std::vector<uint8_t>> serialized_keys;
@@ -55,23 +56,23 @@ TEST_F(WebCryptoEcdsaTest, GenerateKeyIsRandom) {
ASSERT_EQ(Status::Success(),
GenerateKeyPair(CreateEcdsaKeyGenAlgorithm(named_curve), true,
- blink::WebCryptoKeyUsageSign, &public_key,
+ blink::kWebCryptoKeyUsageSign, &public_key,
&private_key));
// Basic sanity checks on the generated key pair.
- EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
- EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
- EXPECT_EQ(named_curve, public_key.algorithm().ecParams()->namedCurve());
- EXPECT_EQ(named_curve, private_key.algorithm().ecParams()->namedCurve());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key.GetType());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePrivate, private_key.GetType());
+ EXPECT_EQ(named_curve, public_key.Algorithm().EcParams()->NamedCurve());
+ EXPECT_EQ(named_curve, private_key.Algorithm().EcParams()->NamedCurve());
// Export the key pair to JWK.
std::vector<uint8_t> key_bytes;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &key_bytes));
+ ExportKey(blink::kWebCryptoKeyFormatJwk, public_key, &key_bytes));
serialized_keys.push_back(key_bytes);
- ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatJwk, private_key, &key_bytes));
+ ASSERT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatJwk,
+ private_key, &key_bytes));
serialized_keys.push_back(key_bytes);
}
@@ -81,7 +82,7 @@ TEST_F(WebCryptoEcdsaTest, GenerateKeyIsRandom) {
}
TEST_F(WebCryptoEcdsaTest, GenerateKeyEmptyUsage) {
- blink::WebCryptoNamedCurve named_curve = blink::WebCryptoNamedCurveP256;
+ blink::WebCryptoNamedCurve named_curve = blink::kWebCryptoNamedCurveP256;
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
@@ -108,7 +109,7 @@ TEST_F(WebCryptoEcdsaTest, SignatureIsRandom) {
ASSERT_EQ(
Status::Success(),
ImportKeyJwkFromDict(*key_jwk, CreateEcdsaImportAlgorithm(curve), true,
- blink::WebCryptoKeyUsageSign, &private_key));
+ blink::kWebCryptoKeyUsageSign, &private_key));
// 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
@@ -119,12 +120,12 @@ TEST_F(WebCryptoEcdsaTest, SignatureIsRandom) {
ASSERT_EQ(Status::Success(),
ImportKeyJwkFromDict(*key_jwk_copy.get(),
CreateEcdsaImportAlgorithm(curve), true,
- blink::WebCryptoKeyUsageVerify, &public_key));
+ blink::kWebCryptoKeyUsageVerify, &public_key));
// Sign twice
std::vector<uint8_t> message(10);
blink::WebCryptoAlgorithm algorithm =
- CreateEcdsaAlgorithm(blink::WebCryptoAlgorithmIdSha1);
+ CreateEcdsaAlgorithm(blink::kWebCryptoAlgorithmIdSha1);
std::vector<uint8_t> signature1;
std::vector<uint8_t> signature2;
@@ -173,15 +174,15 @@ TEST_F(WebCryptoEcdsaTest, VerifyKnownAnswer) {
blink::WebCryptoKey key;
Status status = ImportKey(key_format, CryptoData(key_data),
CreateEcdsaImportAlgorithm(curve), true,
- blink::WebCryptoKeyUsageVerify, &key);
+ blink::kWebCryptoKeyUsageVerify, &key);
ASSERT_EQ(expected_error, StatusToString(status));
if (status.IsError())
continue;
// Basic sanity checks on the imported public key.
- EXPECT_EQ(blink::WebCryptoKeyTypePublic, key.type());
- EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
- EXPECT_EQ(curve, key.algorithm().ecParams()->namedCurve());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePublic, key.GetType());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageVerify, key.Usages());
+ EXPECT_EQ(curve, key.Algorithm().EcParams()->NamedCurve());
// Now try to verify the given message and signature.
std::vector<uint8_t> message = GetBytesFromHexString(test, "msg");
@@ -189,7 +190,7 @@ TEST_F(WebCryptoEcdsaTest, VerifyKnownAnswer) {
blink::WebCryptoAlgorithm hash = GetDigestAlgorithm(test, "hash");
bool verify_result;
- status = Verify(CreateEcdsaAlgorithm(hash.id()), key, CryptoData(signature),
+ status = Verify(CreateEcdsaAlgorithm(hash.Id()), key, CryptoData(signature),
CryptoData(message), &verify_result);
ASSERT_EQ(expected_error, StatusToString(status));
if (status.IsError())
@@ -209,17 +210,17 @@ TEST_F(WebCryptoEcdsaTest, VerifyKnownAnswer) {
blink::WebCryptoKeyUsageMask GetExpectedUsagesForKeyImport(
blink::WebCryptoKeyFormat key_format,
const base::DictionaryValue* test) {
- blink::WebCryptoKeyUsageMask kPublicUsages = blink::WebCryptoKeyUsageVerify;
- blink::WebCryptoKeyUsageMask kPrivateUsages = blink::WebCryptoKeyUsageSign;
+ blink::WebCryptoKeyUsageMask kPublicUsages = blink::kWebCryptoKeyUsageVerify;
+ blink::WebCryptoKeyUsageMask kPrivateUsages = blink::kWebCryptoKeyUsageSign;
switch (key_format) {
- case blink::WebCryptoKeyFormatRaw:
- case blink::WebCryptoKeyFormatSpki:
+ case blink::kWebCryptoKeyFormatRaw:
+ case blink::kWebCryptoKeyFormatSpki:
return kPublicUsages;
- case blink::WebCryptoKeyFormatPkcs8:
+ case blink::kWebCryptoKeyFormatPkcs8:
return kPrivateUsages;
break;
- case blink::WebCryptoKeyFormatJwk: {
+ case blink::kWebCryptoKeyFormatJwk: {
const base::DictionaryValue* key = NULL;
if (!test->GetDictionary("key", &key))
ADD_FAILURE() << "Missing key property";
@@ -286,14 +287,14 @@ TEST_F(WebCryptoEcdsaTest, ImportExportPrivateKey) {
// Import the key using JWK
blink::WebCryptoKey key;
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(jwk_bytes),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(jwk_bytes),
CreateEcdsaImportAlgorithm(curve), true,
- blink::WebCryptoKeyUsageSign, &key));
+ blink::kWebCryptoKeyUsageSign, &key));
// Export the key as JWK
std::vector<uint8_t> exported_bytes;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatJwk, key, &exported_bytes));
+ ExportKey(blink::kWebCryptoKeyFormatJwk, key, &exported_bytes));
// NOTE: The exported bytes can't be directly compared to jwk_bytes because
// the exported JWK differs from the imported one. In particular it contains
@@ -303,18 +304,18 @@ TEST_F(WebCryptoEcdsaTest, ImportExportPrivateKey) {
// expectation.
jwk_bytes = exported_bytes;
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(jwk_bytes),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(jwk_bytes),
CreateEcdsaImportAlgorithm(curve), true,
- blink::WebCryptoKeyUsageSign, &key));
+ blink::kWebCryptoKeyUsageSign, &key));
// Export the key as JWK (again)
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatJwk, key, &exported_bytes));
+ ExportKey(blink::kWebCryptoKeyFormatJwk, key, &exported_bytes));
EXPECT_EQ(CryptoData(jwk_bytes), CryptoData(exported_bytes));
// Export the key as PKCS8
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_bytes));
+ ExportKey(blink::kWebCryptoKeyFormatPkcs8, key, &exported_bytes));
EXPECT_EQ(CryptoData(pkcs8_bytes), CryptoData(exported_bytes));
// -------------------------------------------------
@@ -331,18 +332,18 @@ TEST_F(WebCryptoEcdsaTest, ImportExportPrivateKey) {
// Import the key using PKCS8
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatPkcs8, pkcs8_input_data,
+ ImportKey(blink::kWebCryptoKeyFormatPkcs8, pkcs8_input_data,
CreateEcdsaImportAlgorithm(curve), true,
- blink::WebCryptoKeyUsageSign, &key));
+ blink::kWebCryptoKeyUsageSign, &key));
// Export the key as PKCS8
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_bytes));
+ ExportKey(blink::kWebCryptoKeyFormatPkcs8, key, &exported_bytes));
EXPECT_EQ(CryptoData(pkcs8_bytes), CryptoData(exported_bytes));
// Export the key as JWK
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatJwk, key, &exported_bytes));
+ ExportKey(blink::kWebCryptoKeyFormatJwk, key, &exported_bytes));
EXPECT_EQ(CryptoData(jwk_bytes), CryptoData(exported_bytes));
}
}
diff --git a/chromium/components/webcrypto/algorithms/hkdf.cc b/chromium/components/webcrypto/algorithms/hkdf.cc
index f5ac563e3db..f3381100e16 100644
--- a/chromium/components/webcrypto/algorithms/hkdf.cc
+++ b/chromium/components/webcrypto/algorithms/hkdf.cc
@@ -23,7 +23,7 @@ namespace webcrypto {
namespace {
const blink::WebCryptoKeyUsageMask kValidUsages =
- blink::WebCryptoKeyUsageDeriveKey | blink::WebCryptoKeyUsageDeriveBits;
+ blink::kWebCryptoKeyUsageDeriveKey | blink::kWebCryptoKeyUsageDeriveBits;
class HkdfImplementation : public AlgorithmImplementation {
public:
@@ -36,7 +36,7 @@ class HkdfImplementation : public AlgorithmImplementation {
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const override {
switch (format) {
- case blink::WebCryptoKeyFormatRaw:
+ case blink::kWebCryptoKeyFormatRaw:
return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
default:
return Status::ErrorUnsupportedImportKeyFormat();
@@ -56,8 +56,9 @@ class HkdfImplementation : public AlgorithmImplementation {
return Status::ErrorImportExtractableKdfKey();
return CreateWebCryptoSecretKey(
- key_data, blink::WebCryptoKeyAlgorithm::createWithoutParams(
- blink::WebCryptoAlgorithmIdHkdf),
+ key_data,
+ blink::WebCryptoKeyAlgorithm::CreateWithoutParams(
+ blink::kWebCryptoAlgorithmIdHkdf),
extractable, usages, key);
}
@@ -70,9 +71,9 @@ class HkdfImplementation : public AlgorithmImplementation {
if (!has_optional_length_bits)
return Status::ErrorHkdfDeriveBitsLengthNotSpecified();
- const blink::WebCryptoHkdfParams* params = algorithm.hkdfParams();
+ const blink::WebCryptoHkdfParams* params = algorithm.HkdfParams();
- const EVP_MD* digest_algorithm = GetDigest(params->hash());
+ const EVP_MD* digest_algorithm = GetDigest(params->GetHash());
if (!digest_algorithm)
return Status::ErrorUnsupported();
@@ -84,9 +85,9 @@ class HkdfImplementation : public AlgorithmImplementation {
// |algorithm|.
const std::vector<uint8_t>& raw_key = GetSymmetricKeyData(base_key);
if (!HKDF(derived_bytes->data(), derived_bytes_len, digest_algorithm,
- raw_key.data(), raw_key.size(), params->salt().data(),
- params->salt().size(), params->info().data(),
- params->info().size())) {
+ raw_key.data(), raw_key.size(), params->Salt().Data(),
+ params->Salt().size(), params->Info().Data(),
+ params->Info().size())) {
uint32_t error = ERR_get_error();
if (ERR_GET_LIB(error) == ERR_LIB_HKDF &&
ERR_GET_REASON(error) == HKDF_R_OUTPUT_TOO_LARGE) {
@@ -105,8 +106,8 @@ class HkdfImplementation : public AlgorithmImplementation {
blink::WebCryptoKeyUsageMask usages,
const CryptoData& key_data,
blink::WebCryptoKey* key) const override {
- if (algorithm.paramsType() != blink::WebCryptoKeyAlgorithmParamsTypeNone ||
- type != blink::WebCryptoKeyTypeSecret)
+ if (algorithm.ParamsType() != blink::kWebCryptoKeyAlgorithmParamsTypeNone ||
+ type != blink::kWebCryptoKeyTypeSecret)
return Status::ErrorUnexpected();
// NOTE: Unlike ImportKeyRaw(), this does not enforce extractable==false.
diff --git a/chromium/components/webcrypto/algorithms/hmac.cc b/chromium/components/webcrypto/algorithms/hmac.cc
index 9678654b630..8194beae815 100644
--- a/chromium/components/webcrypto/algorithms/hmac.cc
+++ b/chromium/components/webcrypto/algorithms/hmac.cc
@@ -54,13 +54,13 @@ Status GetHmacImportKeyLengthBits(
// Determine how many bits of the input to use.
*keylen_bits = data_keylen_bits;
- if (params->hasLengthBits()) {
+ if (params->HasLengthBits()) {
// The requested bit length must be:
// * No longer than the input data length
// * At most 7 bits shorter.
- if (NumBitsToBytes(params->optionalLengthBits()) != key_data_byte_length)
+ if (NumBitsToBytes(params->OptionalLengthBits()) != key_data_byte_length)
return Status::ErrorHmacImportBadLength();
- *keylen_bits = params->optionalLengthBits();
+ *keylen_bits = params->OptionalLengthBits();
}
return Status::Success();
@@ -68,13 +68,13 @@ Status GetHmacImportKeyLengthBits(
const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) {
switch (hash) {
- case blink::WebCryptoAlgorithmIdSha1:
+ case blink::kWebCryptoAlgorithmIdSha1:
return "HS1";
- case blink::WebCryptoAlgorithmIdSha256:
+ case blink::kWebCryptoAlgorithmIdSha256:
return "HS256";
- case blink::WebCryptoAlgorithmIdSha384:
+ case blink::kWebCryptoAlgorithmIdSha384:
return "HS384";
- case blink::WebCryptoAlgorithmIdSha512:
+ case blink::kWebCryptoAlgorithmIdSha512:
return "HS512";
default:
return NULL;
@@ -82,7 +82,7 @@ const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) {
}
const blink::WebCryptoKeyUsageMask kAllKeyUsages =
- blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
+ blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify;
Status SignHmac(const std::vector<uint8_t>& raw_key,
const blink::WebCryptoAlgorithm& hash,
@@ -123,22 +123,22 @@ class HmacImplementation : public AlgorithmImplementation {
return status;
const blink::WebCryptoHmacKeyGenParams* params =
- algorithm.hmacKeyGenParams();
+ algorithm.HmacKeyGenParams();
unsigned int keylen_bits = 0;
- if (params->hasLengthBits()) {
- keylen_bits = params->optionalLengthBits();
+ if (params->HasLengthBits()) {
+ keylen_bits = params->OptionalLengthBits();
// Zero-length HMAC keys are disallowed by the spec.
if (keylen_bits == 0)
return Status::ErrorGenerateHmacKeyLengthZero();
} else {
- status = GetDigestBlockSizeBits(params->hash(), &keylen_bits);
+ status = GetDigestBlockSizeBits(params->GetHash(), &keylen_bits);
if (status.IsError())
return status;
}
- return GenerateWebCryptoSecretKey(blink::WebCryptoKeyAlgorithm::createHmac(
- params->hash().id(), keylen_bits),
+ return GenerateWebCryptoSecretKey(blink::WebCryptoKeyAlgorithm::CreateHmac(
+ params->GetHash().Id(), keylen_bits),
extractable, usages, keylen_bits, result);
}
@@ -149,9 +149,9 @@ class HmacImplementation : public AlgorithmImplementation {
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const override {
switch (format) {
- case blink::WebCryptoKeyFormatRaw:
+ case blink::kWebCryptoKeyFormatRaw:
return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
- case blink::WebCryptoKeyFormatJwk:
+ case blink::kWebCryptoKeyFormatJwk:
return ImportKeyJwk(key_data, algorithm, extractable, usages, key);
default:
return Status::ErrorUnsupportedImportKeyFormat();
@@ -162,9 +162,9 @@ class HmacImplementation : public AlgorithmImplementation {
const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const override {
switch (format) {
- case blink::WebCryptoKeyFormatRaw:
+ case blink::kWebCryptoKeyFormatRaw:
return ExportKeyRaw(key, buffer);
- case blink::WebCryptoKeyFormatJwk:
+ case blink::kWebCryptoKeyFormatJwk:
return ExportKeyJwk(key, buffer);
default:
return Status::ErrorUnsupportedExportKeyFormat();
@@ -181,7 +181,7 @@ class HmacImplementation : public AlgorithmImplementation {
return status;
const blink::WebCryptoHmacImportParams* params =
- algorithm.hmacImportParams();
+ algorithm.HmacImportParams();
unsigned int keylen_bits = 0;
status = GetHmacImportKeyLengthBits(params, key_data.byte_length(),
@@ -190,7 +190,7 @@ class HmacImplementation : public AlgorithmImplementation {
return status;
const blink::WebCryptoKeyAlgorithm key_algorithm =
- blink::WebCryptoKeyAlgorithm::createHmac(params->hash().id(),
+ blink::WebCryptoKeyAlgorithm::CreateHmac(params->GetHash().Id(),
keylen_bits);
// If no bit truncation was requested, then done!
@@ -217,7 +217,7 @@ class HmacImplementation : public AlgorithmImplementation {
return status;
const char* algorithm_name =
- GetJwkHmacAlgorithmName(algorithm.hmacImportParams()->hash().id());
+ GetJwkHmacAlgorithmName(algorithm.HmacImportParams()->GetHash().Id());
if (!algorithm_name)
return Status::ErrorUnexpected();
@@ -246,12 +246,12 @@ class HmacImplementation : public AlgorithmImplementation {
const std::vector<uint8_t>& raw_data = GetSymmetricKeyData(key);
const char* algorithm_name =
- GetJwkHmacAlgorithmName(key.algorithm().hmacParams()->hash().id());
+ GetJwkHmacAlgorithmName(key.Algorithm().HmacParams()->GetHash().Id());
if (!algorithm_name)
return Status::ErrorUnexpected();
- WriteSecretKeyJwk(CryptoData(raw_data), algorithm_name, key.extractable(),
- key.usages(), buffer);
+ WriteSecretKeyJwk(CryptoData(raw_data), algorithm_name, key.Extractable(),
+ key.Usages(), buffer);
return Status::Success();
}
@@ -261,7 +261,7 @@ class HmacImplementation : public AlgorithmImplementation {
const CryptoData& data,
std::vector<uint8_t>* buffer) const override {
const blink::WebCryptoAlgorithm& hash =
- key.algorithm().hmacParams()->hash();
+ key.Algorithm().HmacParams()->GetHash();
return SignHmac(GetSymmetricKeyData(key), hash, data, buffer);
}
@@ -291,8 +291,8 @@ class HmacImplementation : public AlgorithmImplementation {
blink::WebCryptoKeyUsageMask usages,
const CryptoData& key_data,
blink::WebCryptoKey* key) const override {
- if (algorithm.paramsType() != blink::WebCryptoKeyAlgorithmParamsTypeHmac ||
- type != blink::WebCryptoKeyTypeSecret)
+ if (algorithm.ParamsType() != blink::kWebCryptoKeyAlgorithmParamsTypeHmac ||
+ type != blink::kWebCryptoKeyTypeSecret)
return Status::ErrorUnexpected();
return CreateWebCryptoSecretKey(key_data, algorithm, extractable, usages,
@@ -303,17 +303,17 @@ class HmacImplementation : public AlgorithmImplementation {
bool* has_length_bits,
unsigned int* length_bits) const override {
const blink::WebCryptoHmacImportParams* params =
- key_length_algorithm.hmacImportParams();
+ key_length_algorithm.HmacImportParams();
*has_length_bits = true;
- if (params->hasLengthBits()) {
- *length_bits = params->optionalLengthBits();
+ if (params->HasLengthBits()) {
+ *length_bits = params->OptionalLengthBits();
if (*length_bits == 0)
return Status::ErrorGetHmacKeyLengthZero();
return Status::Success();
}
- return GetDigestBlockSizeBits(params->hash(), length_bits);
+ return GetDigestBlockSizeBits(params->GetHash(), length_bits);
}
};
diff --git a/chromium/components/webcrypto/algorithms/hmac_unittest.cc b/chromium/components/webcrypto/algorithms/hmac_unittest.cc
index 67fb4f0c35a..fe5b331323e 100644
--- a/chromium/components/webcrypto/algorithms/hmac_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/hmac_unittest.cc
@@ -26,10 +26,10 @@ namespace {
blink::WebCryptoAlgorithm CreateHmacKeyGenAlgorithm(
blink::WebCryptoAlgorithmId hash_id,
unsigned int key_length_bits) {
- DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
+ DCHECK(blink::WebCryptoAlgorithm::IsHash(hash_id));
// key_length_bytes == 0 means unspecified
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdHmac,
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ blink::kWebCryptoAlgorithmIdHmac,
new blink::WebCryptoHmacKeyGenParams(
CreateAlgorithm(hash_id), (key_length_bits != 0), key_length_bits));
}
@@ -37,9 +37,9 @@ blink::WebCryptoAlgorithm CreateHmacKeyGenAlgorithm(
blink::WebCryptoAlgorithm CreateHmacImportAlgorithmWithLength(
blink::WebCryptoAlgorithmId hash_id,
unsigned int length_bits) {
- DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdHmac,
+ DCHECK(blink::WebCryptoAlgorithm::IsHash(hash_id));
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ blink::kWebCryptoAlgorithmIdHmac,
new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), true,
length_bits));
}
@@ -61,22 +61,22 @@ TEST_F(WebCryptoHmacTest, HMACSampleSets) {
const std::vector<uint8_t> test_mac = GetBytesFromHexString(test, "mac");
blink::WebCryptoAlgorithm algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdHmac);
blink::WebCryptoAlgorithm import_algorithm =
- CreateHmacImportAlgorithmNoLength(test_hash.id());
+ CreateHmacImportAlgorithmNoLength(test_hash.Id());
blink::WebCryptoKey key = ImportSecretKeyFromRaw(
test_key, import_algorithm,
- blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify);
+ blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify);
- EXPECT_EQ(test_hash.id(), key.algorithm().hmacParams()->hash().id());
- EXPECT_EQ(test_key.size() * 8, key.algorithm().hmacParams()->lengthBits());
+ EXPECT_EQ(test_hash.Id(), key.Algorithm().HmacParams()->GetHash().Id());
+ EXPECT_EQ(test_key.size() * 8, key.Algorithm().HmacParams()->LengthBits());
// Verify exported raw key is identical to the imported data
std::vector<uint8_t> raw_key;
EXPECT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, key, &raw_key));
EXPECT_BYTES_EQ(test_key, raw_key);
std::vector<uint8_t> output;
@@ -123,21 +123,21 @@ TEST_F(WebCryptoHmacTest, GenerateKeyIsRandom) {
std::vector<uint8_t> key_bytes;
blink::WebCryptoKey key;
blink::WebCryptoAlgorithm algorithm =
- CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 512);
- ASSERT_EQ(
- Status::Success(),
- GenerateSecretKey(algorithm, true, blink::WebCryptoKeyUsageSign, &key));
- EXPECT_FALSE(key.isNull());
- EXPECT_TRUE(key.handle());
- EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
- key.algorithm().hmacParams()->hash().id());
- EXPECT_EQ(512u, key.algorithm().hmacParams()->lengthBits());
+ CreateHmacKeyGenAlgorithm(blink::kWebCryptoAlgorithmIdSha1, 512);
+ ASSERT_EQ(Status::Success(),
+ GenerateSecretKey(algorithm, true, blink::kWebCryptoKeyUsageSign,
+ &key));
+ EXPECT_FALSE(key.IsNull());
+ EXPECT_TRUE(key.Handle());
+ EXPECT_EQ(blink::kWebCryptoKeyTypeSecret, key.GetType());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdHmac, key.Algorithm().Id());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha1,
+ key.Algorithm().HmacParams()->GetHash().Id());
+ EXPECT_EQ(512u, key.Algorithm().HmacParams()->LengthBits());
std::vector<uint8_t> raw_key;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, key, &raw_key));
EXPECT_EQ(64U, raw_key.size());
keys.push_back(raw_key);
}
@@ -150,19 +150,19 @@ TEST_F(WebCryptoHmacTest, GenerateKeyIsRandom) {
TEST_F(WebCryptoHmacTest, GenerateKeyNoLengthSha1) {
blink::WebCryptoKey key;
blink::WebCryptoAlgorithm algorithm =
- CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0);
+ CreateHmacKeyGenAlgorithm(blink::kWebCryptoAlgorithmIdSha1, 0);
ASSERT_EQ(
Status::Success(),
- GenerateSecretKey(algorithm, true, blink::WebCryptoKeyUsageSign, &key));
- EXPECT_TRUE(key.handle());
- EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
- key.algorithm().hmacParams()->hash().id());
- EXPECT_EQ(512u, key.algorithm().hmacParams()->lengthBits());
+ GenerateSecretKey(algorithm, true, blink::kWebCryptoKeyUsageSign, &key));
+ EXPECT_TRUE(key.Handle());
+ EXPECT_EQ(blink::kWebCryptoKeyTypeSecret, key.GetType());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdHmac, key.Algorithm().Id());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha1,
+ key.Algorithm().HmacParams()->GetHash().Id());
+ EXPECT_EQ(512u, key.Algorithm().HmacParams()->LengthBits());
std::vector<uint8_t> raw_key;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, key, &raw_key));
EXPECT_EQ(64U, raw_key.size());
}
@@ -170,24 +170,24 @@ TEST_F(WebCryptoHmacTest, GenerateKeyNoLengthSha1) {
TEST_F(WebCryptoHmacTest, GenerateKeyNoLengthSha512) {
blink::WebCryptoKey key;
blink::WebCryptoAlgorithm algorithm =
- CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha512, 0);
+ CreateHmacKeyGenAlgorithm(blink::kWebCryptoAlgorithmIdSha512, 0);
ASSERT_EQ(
Status::Success(),
- GenerateSecretKey(algorithm, true, blink::WebCryptoKeyUsageSign, &key));
- EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdSha512,
- key.algorithm().hmacParams()->hash().id());
- EXPECT_EQ(1024u, key.algorithm().hmacParams()->lengthBits());
+ GenerateSecretKey(algorithm, true, blink::kWebCryptoKeyUsageSign, &key));
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdHmac, key.Algorithm().Id());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha512,
+ key.Algorithm().HmacParams()->GetHash().Id());
+ EXPECT_EQ(1024u, key.Algorithm().HmacParams()->LengthBits());
std::vector<uint8_t> raw_key;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, key, &raw_key));
EXPECT_EQ(128U, raw_key.size());
}
TEST_F(WebCryptoHmacTest, GenerateKeyEmptyUsage) {
blink::WebCryptoKey key;
blink::WebCryptoAlgorithm algorithm =
- CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha512, 0);
+ CreateHmacKeyGenAlgorithm(blink::kWebCryptoAlgorithmIdSha512, 0);
ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
GenerateSecretKey(algorithm, true, 0, &key));
}
@@ -197,16 +197,16 @@ TEST_F(WebCryptoHmacTest, GenerateKeyEmptyUsage) {
TEST_F(WebCryptoHmacTest, Generate1BitKey) {
blink::WebCryptoKey key;
blink::WebCryptoAlgorithm algorithm =
- CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 1);
+ CreateHmacKeyGenAlgorithm(blink::kWebCryptoAlgorithmIdSha1, 1);
ASSERT_EQ(
Status::Success(),
- GenerateSecretKey(algorithm, true, blink::WebCryptoKeyUsageSign, &key));
- EXPECT_EQ(1u, key.algorithm().hmacParams()->lengthBits());
+ GenerateSecretKey(algorithm, true, blink::kWebCryptoKeyUsageSign, &key));
+ EXPECT_EQ(1u, key.Algorithm().HmacParams()->LengthBits());
std::vector<uint8_t> raw_key;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, key, &raw_key));
ASSERT_EQ(1U, raw_key.size());
EXPECT_FALSE(raw_key[0] & 0x7F);
@@ -216,10 +216,10 @@ TEST_F(WebCryptoHmacTest, ImportKeyEmptyUsage) {
blink::WebCryptoKey key;
std::string key_raw_hex_in = "025a8cf3f08b4f6c5f33bbc76a471939";
EXPECT_EQ(Status::ErrorCreateKeyEmptyUsages(),
- ImportKey(blink::WebCryptoKeyFormatRaw,
+ ImportKey(blink::kWebCryptoKeyFormatRaw,
CryptoData(HexStringToBytes(key_raw_hex_in)),
CreateHmacImportAlgorithmNoLength(
- blink::WebCryptoAlgorithmIdSha1),
+ blink::kWebCryptoAlgorithmIdSha1),
true, 0, &key));
}
@@ -234,20 +234,22 @@ TEST_F(WebCryptoHmacTest, ImportKeyJwkKeyOpsSignVerify) {
key_ops->AppendString("sign");
EXPECT_EQ(Status::Success(),
- ImportKeyJwkFromDict(dict, CreateHmacImportAlgorithmNoLength(
- blink::WebCryptoAlgorithmIdSha256),
- false, blink::WebCryptoKeyUsageSign, &key));
+ ImportKeyJwkFromDict(dict,
+ CreateHmacImportAlgorithmNoLength(
+ blink::kWebCryptoAlgorithmIdSha256),
+ false, blink::kWebCryptoKeyUsageSign, &key));
- EXPECT_EQ(blink::WebCryptoKeyUsageSign, key.usages());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageSign, key.Usages());
key_ops->AppendString("verify");
EXPECT_EQ(Status::Success(),
- ImportKeyJwkFromDict(dict, CreateHmacImportAlgorithmNoLength(
- blink::WebCryptoAlgorithmIdSha256),
- false, blink::WebCryptoKeyUsageVerify, &key));
+ ImportKeyJwkFromDict(dict,
+ CreateHmacImportAlgorithmNoLength(
+ blink::kWebCryptoAlgorithmIdSha256),
+ false, blink::kWebCryptoKeyUsageVerify, &key));
- EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageVerify, key.Usages());
}
// Test 'use' inconsistent with 'key_ops'.
@@ -268,8 +270,9 @@ TEST_F(WebCryptoHmacTest, ImportKeyJwkUseInconsisteWithKeyOps) {
Status::ErrorJwkUseAndKeyopsInconsistent(),
ImportKeyJwkFromDict(
dict,
- CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha256),
- false, blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
+ CreateHmacImportAlgorithmNoLength(blink::kWebCryptoAlgorithmIdSha256),
+ false,
+ blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify,
&key));
}
@@ -285,12 +288,13 @@ TEST_F(WebCryptoHmacTest, ImportKeyJwkUseSig) {
Status::Success(),
ImportKeyJwkFromDict(
dict,
- CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha256),
- false, blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
+ CreateHmacImportAlgorithmNoLength(blink::kWebCryptoAlgorithmIdSha256),
+ false,
+ blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify,
&key));
- EXPECT_EQ(blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
- key.usages());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify,
+ key.Usages());
}
TEST_F(WebCryptoHmacTest, ImportJwkInputConsistency) {
@@ -301,24 +305,24 @@ TEST_F(WebCryptoHmacTest, ImportJwkInputConsistency) {
blink::WebCryptoKey key;
bool extractable = false;
blink::WebCryptoAlgorithm algorithm =
- CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha256);
- blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageVerify;
+ CreateHmacImportAlgorithmNoLength(blink::kWebCryptoAlgorithmIdSha256);
+ blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageVerify;
base::DictionaryValue dict;
dict.SetString("kty", "oct");
dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg");
std::vector<uint8_t> json_vec = MakeJsonVector(dict);
EXPECT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(json_vec),
algorithm, extractable, usages, &key));
- EXPECT_TRUE(key.handle());
- EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
- EXPECT_EQ(extractable, key.extractable());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
- key.algorithm().hmacParams()->hash().id());
- EXPECT_EQ(320u, key.algorithm().hmacParams()->lengthBits());
- EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
- key = blink::WebCryptoKey::createNull();
+ EXPECT_TRUE(key.Handle());
+ EXPECT_EQ(blink::kWebCryptoKeyTypeSecret, key.GetType());
+ EXPECT_EQ(extractable, key.Extractable());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdHmac, key.Algorithm().Id());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha256,
+ key.Algorithm().HmacParams()->GetHash().Id());
+ EXPECT_EQ(320u, key.Algorithm().HmacParams()->LengthBits());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageVerify, key.Usages());
+ key = blink::WebCryptoKey::CreateNull();
// Consistency rules when JWK value exists: Fail if inconsistency is found.
@@ -331,7 +335,7 @@ TEST_F(WebCryptoHmacTest, ImportJwkInputConsistency) {
dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg");
json_vec = MakeJsonVector(dict);
EXPECT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(json_vec),
algorithm, extractable, usages, &key));
// Extractable cases:
@@ -340,19 +344,19 @@ TEST_F(WebCryptoHmacTest, ImportJwkInputConsistency) {
// 2. input=T, JWK=T ==> pass, result extractable is T
// 3. input=F, JWK=T ==> pass, result extractable is F
EXPECT_EQ(Status::ErrorJwkExtInconsistent(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(json_vec),
algorithm, true, usages, &key));
EXPECT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(json_vec),
algorithm, false, usages, &key));
- EXPECT_FALSE(key.extractable());
+ EXPECT_FALSE(key.Extractable());
dict.SetBoolean("ext", true);
EXPECT_EQ(Status::Success(),
ImportKeyJwkFromDict(dict, algorithm, true, usages, &key));
- EXPECT_TRUE(key.extractable());
+ EXPECT_TRUE(key.Extractable());
EXPECT_EQ(Status::Success(),
ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
- EXPECT_FALSE(key.extractable());
+ EXPECT_FALSE(key.Extractable());
dict.SetBoolean("ext", true); // restore previous value
// Fail: Input algorithm (AES-CBC) is inconsistent with JWK value
@@ -363,44 +367,45 @@ TEST_F(WebCryptoHmacTest, ImportJwkInputConsistency) {
dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg");
EXPECT_EQ(Status::ErrorJwkAlgorithmInconsistent(),
ImportKeyJwkFromDict(
- dict, CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
- extractable, blink::WebCryptoKeyUsageEncrypt, &key));
+ dict, CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc),
+ extractable, blink::kWebCryptoKeyUsageEncrypt, &key));
// Fail: Input usage (encrypt) is inconsistent with JWK value (use=sig).
EXPECT_EQ(Status::ErrorJwkUseInconsistent(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
- extractable, blink::WebCryptoKeyUsageEncrypt, &key));
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(json_vec),
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc),
+ extractable, blink::kWebCryptoKeyUsageEncrypt, &key));
// Fail: Input algorithm (HMAC SHA1) is inconsistent with JWK value
// (HMAC SHA256).
EXPECT_EQ(Status::ErrorJwkAlgorithmInconsistent(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(json_vec),
CreateHmacImportAlgorithmNoLength(
- blink::WebCryptoAlgorithmIdSha1),
+ blink::kWebCryptoAlgorithmIdSha1),
extractable, usages, &key));
// Pass: JWK alg missing but input algorithm specified: use input value
dict.Remove("alg", NULL);
EXPECT_EQ(Status::Success(),
- ImportKeyJwkFromDict(dict, CreateHmacImportAlgorithmNoLength(
- blink::WebCryptoAlgorithmIdSha256),
+ ImportKeyJwkFromDict(dict,
+ CreateHmacImportAlgorithmNoLength(
+ blink::kWebCryptoAlgorithmIdSha256),
extractable, usages, &key));
- EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, algorithm.id());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdHmac, algorithm.Id());
dict.SetString("alg", "HS256");
// Fail: Input usages (encrypt) is not a subset of the JWK value
// (sign|verify). Moreover "encrypt" is not a valid usage for HMAC.
EXPECT_EQ(
Status::ErrorCreateKeyBadUsages(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec), algorithm,
- extractable, blink::WebCryptoKeyUsageEncrypt, &key));
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(json_vec), algorithm,
+ extractable, blink::kWebCryptoKeyUsageEncrypt, &key));
// Fail: Input usages (encrypt|sign|verify) is not a subset of the JWK
// value (sign|verify). Moreover "encrypt" is not a valid usage for HMAC.
- usages = blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageSign |
- blink::WebCryptoKeyUsageVerify;
+ usages = blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageSign |
+ blink::kWebCryptoKeyUsageVerify;
EXPECT_EQ(Status::ErrorCreateKeyBadUsages(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json_vec),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(json_vec),
algorithm, extractable, usages, &key));
// TODO(padolph): kty vs alg consistency tests: Depending on the kty value,
@@ -418,8 +423,8 @@ TEST_F(WebCryptoHmacTest, ImportJwkHappy) {
blink::WebCryptoKey key;
bool extractable = false;
blink::WebCryptoAlgorithm algorithm =
- CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha256);
- blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
+ CreateHmacImportAlgorithmNoLength(blink::kWebCryptoAlgorithmIdSha256);
+ blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageSign;
// Import a symmetric key JWK and HMAC-SHA256 sign()
// Uses the first SHA256 test vector from the HMAC sample set above.
@@ -434,8 +439,8 @@ TEST_F(WebCryptoHmacTest, ImportJwkHappy) {
ASSERT_EQ(Status::Success(),
ImportKeyJwkFromDict(dict, algorithm, extractable, usages, &key));
- EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
- key.algorithm().hmacParams()->hash().id());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha256,
+ key.Algorithm().HmacParams()->GetHash().Id());
const std::vector<uint8_t> message_raw = HexStringToBytes(
"b1689c2591eaf3c9e66070f8a77954ffb81749f1b00346f9dfe0b2ee905dcc288baf4a"
@@ -446,7 +451,7 @@ TEST_F(WebCryptoHmacTest, ImportJwkHappy) {
std::vector<uint8_t> output;
ASSERT_EQ(Status::Success(),
- Sign(CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac), key,
+ Sign(CreateAlgorithm(blink::kWebCryptoAlgorithmIdHmac), key,
CryptoData(message_raw), &output));
const std::string mac_raw =
@@ -460,70 +465,72 @@ TEST_F(WebCryptoHmacTest, ImportJwkHappy) {
TEST_F(WebCryptoHmacTest, ImportExportJwk) {
// HMAC SHA-1
ImportExportJwkSymmetricKey(
- 256, CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha1),
- blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify, "HS1");
+ 256, CreateHmacImportAlgorithmNoLength(blink::kWebCryptoAlgorithmIdSha1),
+ blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify, "HS1");
// HMAC SHA-384
ImportExportJwkSymmetricKey(
- 384, CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha384),
- blink::WebCryptoKeyUsageSign, "HS384");
+ 384,
+ CreateHmacImportAlgorithmNoLength(blink::kWebCryptoAlgorithmIdSha384),
+ blink::kWebCryptoKeyUsageSign, "HS384");
// HMAC SHA-512
ImportExportJwkSymmetricKey(
- 512, CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha512),
- blink::WebCryptoKeyUsageVerify, "HS512");
+ 512,
+ CreateHmacImportAlgorithmNoLength(blink::kWebCryptoAlgorithmIdSha512),
+ blink::kWebCryptoKeyUsageVerify, "HS512");
}
TEST_F(WebCryptoHmacTest, ExportJwkEmptyKey) {
- blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
+ blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageSign;
// Importing empty HMAC key is no longer allowed. However such a key can be
// created via de-serialization.
blink::WebCryptoKey key;
- ASSERT_TRUE(DeserializeKeyForClone(blink::WebCryptoKeyAlgorithm::createHmac(
- blink::WebCryptoAlgorithmIdSha1, 0),
- blink::WebCryptoKeyTypeSecret, true,
+ ASSERT_TRUE(DeserializeKeyForClone(blink::WebCryptoKeyAlgorithm::CreateHmac(
+ blink::kWebCryptoAlgorithmIdSha1, 0),
+ blink::kWebCryptoKeyTypeSecret, true,
usages, CryptoData(), &key));
// Export the key in JWK format and validate.
std::vector<uint8_t> json;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatJwk, key, &json));
+ ExportKey(blink::kWebCryptoKeyFormatJwk, key, &json));
EXPECT_TRUE(VerifySecretJwk(json, "HS1", "", usages));
// Now try re-importing the JWK key.
- key = blink::WebCryptoKey::createNull();
+ key = blink::WebCryptoKey::CreateNull();
EXPECT_EQ(Status::ErrorHmacImportEmptyKey(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(json),
CreateHmacImportAlgorithmNoLength(
- blink::WebCryptoAlgorithmIdSha1),
+ blink::kWebCryptoAlgorithmIdSha1),
true, usages, &key));
}
// Imports an HMAC key contaning no byte data.
TEST_F(WebCryptoHmacTest, ImportRawEmptyKey) {
const blink::WebCryptoAlgorithm import_algorithm =
- CreateHmacImportAlgorithmNoLength(blink::WebCryptoAlgorithmIdSha1);
+ CreateHmacImportAlgorithmNoLength(blink::kWebCryptoAlgorithmIdSha1);
- blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
+ blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageSign;
blink::WebCryptoKey key;
ASSERT_EQ(Status::ErrorHmacImportEmptyKey(),
- ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(),
+ ImportKey(blink::kWebCryptoKeyFormatRaw, CryptoData(),
import_algorithm, true, usages, &key));
}
// Imports an HMAC key contaning 1 byte data, however the length was set to 0.
TEST_F(WebCryptoHmacTest, ImportRawKeyWithZeroLength) {
const blink::WebCryptoAlgorithm import_algorithm =
- CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0);
+ CreateHmacImportAlgorithm(blink::kWebCryptoAlgorithmIdSha1, 0);
- blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
+ blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageSign;
blink::WebCryptoKey key;
std::vector<uint8_t> key_data(1);
ASSERT_EQ(Status::ErrorHmacImportBadLength(),
- ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(key_data),
+ ImportKey(blink::kWebCryptoKeyFormatRaw, CryptoData(key_data),
import_algorithm, true, usages, &key));
}
@@ -534,32 +541,32 @@ TEST_F(WebCryptoHmacTest, ImportRawKeyTooLarge) {
blink::WebCryptoKey key;
EXPECT_EQ(Status::ErrorDataTooLarge(),
- ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(big_data),
+ ImportKey(blink::kWebCryptoKeyFormatRaw, CryptoData(big_data),
CreateHmacImportAlgorithmNoLength(
- blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageSign, &key));
+ blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageSign, &key));
}
// Import an HMAC key with 120 bits of data, however request 128 bits worth.
TEST_F(WebCryptoHmacTest, ImportRawKeyLengthTooLarge) {
blink::WebCryptoKey key;
EXPECT_EQ(Status::ErrorHmacImportBadLength(),
- ImportKey(blink::WebCryptoKeyFormatRaw,
+ ImportKey(blink::kWebCryptoKeyFormatRaw,
CryptoData(std::vector<uint8_t>(15)),
CreateHmacImportAlgorithmWithLength(
- blink::WebCryptoAlgorithmIdSha1, 128),
- true, blink::WebCryptoKeyUsageSign, &key));
+ blink::kWebCryptoAlgorithmIdSha1, 128),
+ true, blink::kWebCryptoKeyUsageSign, &key));
}
// Import an HMAC key with 128 bits of data, however request 120 bits worth.
TEST_F(WebCryptoHmacTest, ImportRawKeyLengthTooSmall) {
blink::WebCryptoKey key;
EXPECT_EQ(Status::ErrorHmacImportBadLength(),
- ImportKey(blink::WebCryptoKeyFormatRaw,
+ ImportKey(blink::kWebCryptoKeyFormatRaw,
CryptoData(std::vector<uint8_t>(16)),
CreateHmacImportAlgorithmWithLength(
- blink::WebCryptoAlgorithmIdSha1, 120),
- true, blink::WebCryptoKeyUsageSign, &key));
+ blink::kWebCryptoAlgorithmIdSha1, 120),
+ true, blink::kWebCryptoKeyUsageSign, &key));
}
// Import an HMAC key with 16 bits of data and request a 12 bit key, using the
@@ -569,15 +576,15 @@ TEST_F(WebCryptoHmacTest, ImportRawKeyTruncation) {
blink::WebCryptoKey key;
EXPECT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(data),
+ ImportKey(blink::kWebCryptoKeyFormatRaw, CryptoData(data),
CreateHmacImportAlgorithmWithLength(
- blink::WebCryptoAlgorithmIdSha1, 12),
- true, blink::WebCryptoKeyUsageSign, &key));
+ blink::kWebCryptoAlgorithmIdSha1, 12),
+ true, blink::kWebCryptoKeyUsageSign, &key));
// On export the last 4 bits has been set to zero.
std::vector<uint8_t> raw_key;
EXPECT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, key, &raw_key));
EXPECT_BYTES_EQ(HexStringToBytes("b1f0"), raw_key);
}
@@ -589,14 +596,15 @@ TEST_F(WebCryptoHmacTest, ImportJwkKeyTruncation) {
blink::WebCryptoKey key;
EXPECT_EQ(Status::Success(),
- ImportKeyJwkFromDict(dict, CreateHmacImportAlgorithmWithLength(
- blink::WebCryptoAlgorithmIdSha1, 12),
- true, blink::WebCryptoKeyUsageSign, &key));
+ ImportKeyJwkFromDict(dict,
+ CreateHmacImportAlgorithmWithLength(
+ blink::kWebCryptoAlgorithmIdSha1, 12),
+ true, blink::kWebCryptoKeyUsageSign, &key));
// On export the last 4 bits has been set to zero.
std::vector<uint8_t> raw_key;
EXPECT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, key, &raw_key));
EXPECT_BYTES_EQ(HexStringToBytes("b1f0"), raw_key);
}
diff --git a/chromium/components/webcrypto/algorithms/pbkdf2.cc b/chromium/components/webcrypto/algorithms/pbkdf2.cc
index 53e65ce0748..142172b700a 100644
--- a/chromium/components/webcrypto/algorithms/pbkdf2.cc
+++ b/chromium/components/webcrypto/algorithms/pbkdf2.cc
@@ -22,7 +22,7 @@ namespace webcrypto {
namespace {
const blink::WebCryptoKeyUsageMask kAllKeyUsages =
- blink::WebCryptoKeyUsageDeriveKey | blink::WebCryptoKeyUsageDeriveBits;
+ blink::kWebCryptoKeyUsageDeriveKey | blink::kWebCryptoKeyUsageDeriveBits;
class Pbkdf2Implementation : public AlgorithmImplementation {
public:
@@ -35,7 +35,7 @@ class Pbkdf2Implementation : public AlgorithmImplementation {
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const override {
switch (format) {
- case blink::WebCryptoKeyFormatRaw:
+ case blink::kWebCryptoKeyFormatRaw:
return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
default:
return Status::ErrorUnsupportedImportKeyFormat();
@@ -55,8 +55,8 @@ class Pbkdf2Implementation : public AlgorithmImplementation {
return Status::ErrorImportExtractableKdfKey();
const blink::WebCryptoKeyAlgorithm key_algorithm =
- blink::WebCryptoKeyAlgorithm::createWithoutParams(
- blink::WebCryptoAlgorithmIdPbkdf2);
+ blink::WebCryptoKeyAlgorithm::CreateWithoutParams(
+ blink::kWebCryptoAlgorithmIdPbkdf2);
return CreateWebCryptoSecretKey(key_data, key_algorithm, extractable,
usages, key);
@@ -81,12 +81,12 @@ class Pbkdf2Implementation : public AlgorithmImplementation {
if (optional_length_bits == 0)
return Status::ErrorPbkdf2DeriveBitsLengthZero();
- const blink::WebCryptoPbkdf2Params* params = algorithm.pbkdf2Params();
+ const blink::WebCryptoPbkdf2Params* params = algorithm.Pbkdf2Params();
- if (params->iterations() == 0)
+ if (params->Iterations() == 0)
return Status::ErrorPbkdf2Iterations0();
- const EVP_MD* digest_algorithm = GetDigest(params->hash());
+ const EVP_MD* digest_algorithm = GetDigest(params->GetHash());
if (!digest_algorithm)
return Status::ErrorUnsupported();
@@ -97,7 +97,7 @@ class Pbkdf2Implementation : public AlgorithmImplementation {
if (!PKCS5_PBKDF2_HMAC(
reinterpret_cast<const char*>(password.data()), password.size(),
- params->salt().data(), params->salt().size(), params->iterations(),
+ params->Salt().Data(), params->Salt().size(), params->Iterations(),
digest_algorithm, keylen_bytes, derived_bytes->data())) {
return Status::OperationError();
}
@@ -110,8 +110,8 @@ class Pbkdf2Implementation : public AlgorithmImplementation {
blink::WebCryptoKeyUsageMask usages,
const CryptoData& key_data,
blink::WebCryptoKey* key) const override {
- if (algorithm.paramsType() != blink::WebCryptoKeyAlgorithmParamsTypeNone ||
- type != blink::WebCryptoKeyTypeSecret)
+ if (algorithm.ParamsType() != blink::kWebCryptoKeyAlgorithmParamsTypeNone ||
+ type != blink::kWebCryptoKeyTypeSecret)
return Status::ErrorUnexpected();
// NOTE: Unlike ImportKeyRaw(), this does not enforce extractable==false.
diff --git a/chromium/components/webcrypto/algorithms/rsa.cc b/chromium/components/webcrypto/algorithms/rsa.cc
index 35053d889c9..00b1f01b879 100644
--- a/chromium/components/webcrypto/algorithms/rsa.cc
+++ b/chromium/components/webcrypto/algorithms/rsa.cc
@@ -127,7 +127,7 @@ Status CreateRsaHashedKeyAlgorithm(
if (e.size() != BN_bn2bin(rsa->e, &e[0]))
return Status::ErrorUnexpected();
- *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(
+ *key_algorithm = blink::WebCryptoKeyAlgorithm::CreateRsaHashed(
rsa_algorithm, modulus_length_bits, &e[0],
static_cast<unsigned int>(e.size()), hash_algorithm);
@@ -144,7 +144,7 @@ Status CreateWebCryptoRsaPrivateKey(
blink::WebCryptoKey* key) {
blink::WebCryptoKeyAlgorithm key_algorithm;
Status status = CreateRsaHashedKeyAlgorithm(
- rsa_algorithm_id, hash.id(), private_key.get(), &key_algorithm);
+ rsa_algorithm_id, hash.Id(), private_key.get(), &key_algorithm);
if (status.IsError())
return status;
@@ -161,7 +161,7 @@ Status CreateWebCryptoRsaPublicKey(
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) {
blink::WebCryptoKeyAlgorithm key_algorithm;
- Status status = CreateRsaHashedKeyAlgorithm(rsa_algorithm_id, hash.id(),
+ Status status = CreateRsaHashedKeyAlgorithm(rsa_algorithm_id, hash.Id(),
public_key.get(), &key_algorithm);
if (status.IsError())
return status;
@@ -200,9 +200,9 @@ Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get()))
return Status::OperationError();
- return CreateWebCryptoRsaPrivateKey(std::move(pkey), algorithm.id(),
- algorithm.rsaHashedImportParams()->hash(),
- extractable, usages, key);
+ return CreateWebCryptoRsaPrivateKey(
+ std::move(pkey), algorithm.Id(),
+ algorithm.RsaHashedImportParams()->GetHash(), extractable, usages, key);
}
Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
@@ -224,9 +224,9 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get()))
return Status::OperationError();
- return CreateWebCryptoRsaPublicKey(std::move(pkey), algorithm.id(),
- algorithm.rsaHashedImportParams()->hash(),
- extractable, usages, key);
+ return CreateWebCryptoRsaPublicKey(
+ std::move(pkey), algorithm.Id(),
+ algorithm.RsaHashedImportParams()->GetHash(), extractable, usages, key);
}
// Converts a BIGNUM to a big endian byte array.
@@ -240,9 +240,9 @@ std::vector<uint8_t> BIGNUMToVector(const BIGNUM* n) {
// deserialization can re-use the ImportKey*() methods.
blink::WebCryptoAlgorithm SynthesizeImportAlgorithmForClone(
const blink::WebCryptoKeyAlgorithm& algorithm) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- algorithm.id(), new blink::WebCryptoRsaHashedImportParams(
- algorithm.rsaHashedParams()->hash()));
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ algorithm.Id(), new blink::WebCryptoRsaHashedImportParams(
+ algorithm.RsaHashedParams()->GetHash()));
}
} // namespace
@@ -262,9 +262,9 @@ Status RsaHashedAlgorithm::GenerateKey(
return status;
const blink::WebCryptoRsaHashedKeyGenParams* params =
- algorithm.rsaHashedKeyGenParams();
+ algorithm.RsaHashedKeyGenParams();
- unsigned int modulus_length_bits = params->modulusLengthBits();
+ unsigned int modulus_length_bits = params->ModulusLengthBits();
// Limit the RSA key sizes to:
// * Multiple of 8 bits
@@ -279,7 +279,7 @@ Status RsaHashedAlgorithm::GenerateKey(
}
unsigned int public_exponent = 0;
- if (!params->convertPublicExponentToUnsigned(public_exponent))
+ if (!params->ConvertPublicExponentToUnsigned(public_exponent))
return Status::ErrorGenerateKeyPublicExponent();
// OpenSSL hangs when given bad public exponents. Use a whitelist.
@@ -321,14 +321,14 @@ Status RsaHashedAlgorithm::GenerateKey(
// Note that extractable is unconditionally set to true. This is because per
// the WebCrypto spec generated public keys are always extractable.
- status = CreateWebCryptoRsaPublicKey(std::move(public_pkey), algorithm.id(),
- params->hash(), true, public_usages,
+ status = CreateWebCryptoRsaPublicKey(std::move(public_pkey), algorithm.Id(),
+ params->GetHash(), true, public_usages,
&public_key);
if (status.IsError())
return status;
- status = CreateWebCryptoRsaPrivateKey(std::move(private_pkey), algorithm.id(),
- params->hash(), extractable,
+ status = CreateWebCryptoRsaPrivateKey(std::move(private_pkey), algorithm.Id(),
+ params->GetHash(), extractable,
private_usages, &private_key);
if (status.IsError())
return status;
@@ -344,11 +344,11 @@ Status RsaHashedAlgorithm::ImportKey(blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
switch (format) {
- case blink::WebCryptoKeyFormatPkcs8:
+ case blink::kWebCryptoKeyFormatPkcs8:
return ImportKeyPkcs8(key_data, algorithm, extractable, usages, key);
- case blink::WebCryptoKeyFormatSpki:
+ case blink::kWebCryptoKeyFormatSpki:
return ImportKeySpki(key_data, algorithm, extractable, usages, key);
- case blink::WebCryptoKeyFormatJwk:
+ case blink::kWebCryptoKeyFormatJwk:
return ImportKeyJwk(key_data, algorithm, extractable, usages, key);
default:
return Status::ErrorUnsupportedImportKeyFormat();
@@ -359,11 +359,11 @@ Status RsaHashedAlgorithm::ExportKey(blink::WebCryptoKeyFormat format,
const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
switch (format) {
- case blink::WebCryptoKeyFormatPkcs8:
+ case blink::kWebCryptoKeyFormatPkcs8:
return ExportKeyPkcs8(key, buffer);
- case blink::WebCryptoKeyFormatSpki:
+ case blink::kWebCryptoKeyFormatSpki:
return ExportKeySpki(key, buffer);
- case blink::WebCryptoKeyFormatJwk:
+ case blink::kWebCryptoKeyFormatJwk:
return ExportKeyJwk(key, buffer);
default:
return Status::ErrorUnsupportedExportKeyFormat();
@@ -395,9 +395,9 @@ Status RsaHashedAlgorithm::ImportKeyPkcs8(
// TODO(eroman): Validate the algorithm OID against the webcrypto provided
// hash. http://crbug.com/389400
- return CreateWebCryptoRsaPrivateKey(std::move(private_key), algorithm.id(),
- algorithm.rsaHashedImportParams()->hash(),
- extractable, usages, key);
+ return CreateWebCryptoRsaPrivateKey(
+ std::move(private_key), algorithm.Id(),
+ algorithm.RsaHashedImportParams()->GetHash(), extractable, usages, key);
}
Status RsaHashedAlgorithm::ImportKeySpki(
@@ -418,9 +418,9 @@ Status RsaHashedAlgorithm::ImportKeySpki(
// TODO(eroman): Validate the algorithm OID against the webcrypto provided
// hash. http://crbug.com/389400
- return CreateWebCryptoRsaPublicKey(std::move(public_key), algorithm.id(),
- algorithm.rsaHashedImportParams()->hash(),
- extractable, usages, key);
+ return CreateWebCryptoRsaPublicKey(
+ std::move(public_key), algorithm.Id(),
+ algorithm.RsaHashedImportParams()->GetHash(), extractable, usages, key);
}
Status RsaHashedAlgorithm::ImportKeyJwk(
@@ -432,7 +432,7 @@ Status RsaHashedAlgorithm::ImportKeyJwk(
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
const char* jwk_algorithm =
- GetJwkAlgorithm(algorithm.rsaHashedImportParams()->hash().id());
+ GetJwkAlgorithm(algorithm.RsaHashedImportParams()->GetHash().Id());
if (!jwk_algorithm)
return Status::ErrorUnexpected();
@@ -461,7 +461,7 @@ Status RsaHashedAlgorithm::ImportKeyJwk(
Status RsaHashedAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
- if (key.type() != blink::WebCryptoKeyTypePrivate)
+ if (key.GetType() != blink::kWebCryptoKeyTypePrivate)
return Status::ErrorUnexpectedKeyType();
// This relies on the fact that PKCS8 formatted data was already
// associated with the key during its creation (used by
@@ -472,7 +472,7 @@ Status RsaHashedAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
Status RsaHashedAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
- if (key.type() != blink::WebCryptoKeyTypePublic)
+ if (key.GetType() != blink::kWebCryptoKeyTypePublic)
return Status::ErrorUnexpectedKeyType();
// This relies on the fact that SPKI formatted data was already
// associated with the key during its creation (used by
@@ -491,20 +491,20 @@ Status RsaHashedAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
return Status::ErrorUnexpected();
const char* jwk_algorithm =
- GetJwkAlgorithm(key.algorithm().rsaHashedParams()->hash().id());
+ GetJwkAlgorithm(key.Algorithm().RsaHashedParams()->GetHash().Id());
if (!jwk_algorithm)
return Status::ErrorUnexpected();
- switch (key.type()) {
- case blink::WebCryptoKeyTypePublic: {
- JwkWriter writer(jwk_algorithm, key.extractable(), key.usages(), "RSA");
+ switch (key.GetType()) {
+ case blink::kWebCryptoKeyTypePublic: {
+ JwkWriter writer(jwk_algorithm, key.Extractable(), key.Usages(), "RSA");
writer.SetBytes("n", CryptoData(BIGNUMToVector(rsa->n)));
writer.SetBytes("e", CryptoData(BIGNUMToVector(rsa->e)));
writer.ToJson(buffer);
return Status::Success();
}
- case blink::WebCryptoKeyTypePrivate: {
- JwkWriter writer(jwk_algorithm, key.extractable(), key.usages(), "RSA");
+ case blink::kWebCryptoKeyTypePrivate: {
+ JwkWriter writer(jwk_algorithm, key.Extractable(), key.Usages(), "RSA");
writer.SetBytes("n", CryptoData(BIGNUMToVector(rsa->n)));
writer.SetBytes("e", CryptoData(BIGNUMToVector(rsa->e)));
writer.SetBytes("d", CryptoData(BIGNUMToVector(rsa->d)));
@@ -532,7 +532,8 @@ Status RsaHashedAlgorithm::DeserializeKeyForClone(
blink::WebCryptoKeyUsageMask usages,
const CryptoData& key_data,
blink::WebCryptoKey* key) const {
- if (algorithm.paramsType() != blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed)
+ if (algorithm.ParamsType() !=
+ blink::kWebCryptoKeyAlgorithmParamsTypeRsaHashed)
return Status::ErrorUnexpected();
blink::WebCryptoAlgorithm import_algorithm =
@@ -542,11 +543,11 @@ Status RsaHashedAlgorithm::DeserializeKeyForClone(
// The serialized data will be either SPKI or PKCS8 formatted.
switch (type) {
- case blink::WebCryptoKeyTypePublic:
+ case blink::kWebCryptoKeyTypePublic:
status =
ImportKeySpki(key_data, import_algorithm, extractable, usages, key);
break;
- case blink::WebCryptoKeyTypePrivate:
+ case blink::kWebCryptoKeyTypePrivate:
status =
ImportKeyPkcs8(key_data, import_algorithm, extractable, usages, key);
break;
@@ -559,23 +560,23 @@ Status RsaHashedAlgorithm::DeserializeKeyForClone(
// key data). Use this extra information to further validate what was
// deserialized from the key data.
- if (algorithm.id() != key->algorithm().id())
+ if (algorithm.Id() != key->Algorithm().Id())
return Status::ErrorUnexpected();
- if (key->type() != type)
+ if (key->GetType() != type)
return Status::ErrorUnexpected();
- if (algorithm.rsaHashedParams()->modulusLengthBits() !=
- key->algorithm().rsaHashedParams()->modulusLengthBits()) {
+ if (algorithm.RsaHashedParams()->ModulusLengthBits() !=
+ key->Algorithm().RsaHashedParams()->ModulusLengthBits()) {
return Status::ErrorUnexpected();
}
- if (algorithm.rsaHashedParams()->publicExponent().size() !=
- key->algorithm().rsaHashedParams()->publicExponent().size() ||
+ if (algorithm.RsaHashedParams()->PublicExponent().size() !=
+ key->Algorithm().RsaHashedParams()->PublicExponent().size() ||
0 !=
- memcmp(algorithm.rsaHashedParams()->publicExponent().data(),
- key->algorithm().rsaHashedParams()->publicExponent().data(),
- key->algorithm().rsaHashedParams()->publicExponent().size())) {
+ memcmp(algorithm.RsaHashedParams()->PublicExponent().Data(),
+ key->Algorithm().RsaHashedParams()->PublicExponent().Data(),
+ key->Algorithm().RsaHashedParams()->PublicExponent().size())) {
return Status::ErrorUnexpected();
}
diff --git a/chromium/components/webcrypto/algorithms/rsa_oaep.cc b/chromium/components/webcrypto/algorithms/rsa_oaep.cc
index c1ba94e3930..ad0b7fc1459 100644
--- a/chromium/components/webcrypto/algorithms/rsa_oaep.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_oaep.cc
@@ -46,7 +46,8 @@ Status CommonEncryptDecrypt(InitFunc init_func,
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
EVP_PKEY* pkey = GetEVP_PKEY(key);
- const EVP_MD* digest = GetDigest(key.algorithm().rsaHashedParams()->hash());
+ const EVP_MD* digest =
+ GetDigest(key.Algorithm().RsaHashedParams()->GetHash());
if (!digest)
return Status::ErrorUnsupported();
@@ -60,14 +61,14 @@ Status CommonEncryptDecrypt(InitFunc init_func,
}
const blink::WebVector<uint8_t>& label =
- algorithm.rsaOaepParams()->optionalLabel();
+ algorithm.RsaOaepParams()->OptionalLabel();
if (label.size()) {
// Make a copy of the label, since the ctx takes ownership of it when
// calling set0_rsa_oaep_label().
bssl::UniquePtr<uint8_t> label_copy;
label_copy.reset(static_cast<uint8_t*>(OPENSSL_malloc(label.size())));
- memcpy(label_copy.get(), label.data(), label.size());
+ memcpy(label_copy.get(), label.Data(), label.size());
if (1 != EVP_PKEY_CTX_set0_rsa_oaep_label(ctx.get(), label_copy.release(),
label.size())) {
@@ -97,20 +98,20 @@ class RsaOaepImplementation : public RsaHashedAlgorithm {
public:
RsaOaepImplementation()
: RsaHashedAlgorithm(
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey,
- blink::WebCryptoKeyUsageDecrypt |
- blink::WebCryptoKeyUsageUnwrapKey) {}
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageWrapKey,
+ blink::kWebCryptoKeyUsageDecrypt |
+ blink::kWebCryptoKeyUsageUnwrapKey) {}
const char* GetJwkAlgorithm(
const blink::WebCryptoAlgorithmId hash) const override {
switch (hash) {
- case blink::WebCryptoAlgorithmIdSha1:
+ case blink::kWebCryptoAlgorithmIdSha1:
return "RSA-OAEP";
- case blink::WebCryptoAlgorithmIdSha256:
+ case blink::kWebCryptoAlgorithmIdSha256:
return "RSA-OAEP-256";
- case blink::WebCryptoAlgorithmIdSha384:
+ case blink::kWebCryptoAlgorithmIdSha384:
return "RSA-OAEP-384";
- case blink::WebCryptoAlgorithmIdSha512:
+ case blink::kWebCryptoAlgorithmIdSha512:
return "RSA-OAEP-512";
default:
return NULL;
@@ -121,7 +122,7 @@ class RsaOaepImplementation : public RsaHashedAlgorithm {
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) const override {
- if (key.type() != blink::WebCryptoKeyTypePublic)
+ if (key.GetType() != blink::kWebCryptoKeyTypePublic)
return Status::ErrorUnexpectedKeyType();
return CommonEncryptDecrypt(EVP_PKEY_encrypt_init, EVP_PKEY_encrypt,
@@ -132,7 +133,7 @@ class RsaOaepImplementation : public RsaHashedAlgorithm {
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) const override {
- if (key.type() != blink::WebCryptoKeyTypePrivate)
+ if (key.GetType() != blink::kWebCryptoKeyTypePrivate)
return Status::ErrorUnexpectedKeyType();
return CommonEncryptDecrypt(EVP_PKEY_decrypt_init, EVP_PKEY_decrypt,
diff --git a/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc b/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc
index 4712edd4916..5c92958a096 100644
--- a/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc
@@ -24,8 +24,8 @@ namespace {
// Creates an RSA-OAEP algorithm
blink::WebCryptoAlgorithm CreateRsaOaepAlgorithm(
const std::vector<uint8_t>& label) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdRsaOaep,
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ blink::kWebCryptoAlgorithmIdRsaOaep,
new blink::WebCryptoRsaOaepParams(!label.empty(), label));
}
@@ -57,12 +57,12 @@ class WebCryptoRsaOaepTest : public WebCryptoTestBase {};
TEST_F(WebCryptoRsaOaepTest, ImportPkcs8WithRsaEncryption) {
blink::WebCryptoKey private_key;
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatPkcs8,
+ ImportKey(blink::kWebCryptoKeyFormatPkcs8,
CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaOaep,
- blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageDecrypt, &private_key));
+ blink::kWebCryptoAlgorithmIdRsaOaep,
+ blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageDecrypt, &private_key));
}
TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithNoAlg) {
@@ -71,10 +71,11 @@ TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithNoAlg) {
blink::WebCryptoKey public_key;
ASSERT_EQ(
Status::Success(),
- ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaOaep,
- blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageEncrypt, &public_key));
+ ImportKeyJwkFromDict(
+ *jwk.get(),
+ CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaOaep,
+ blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageEncrypt, &public_key));
}
TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithMatchingAlg) {
@@ -84,10 +85,11 @@ TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithMatchingAlg) {
blink::WebCryptoKey public_key;
ASSERT_EQ(
Status::Success(),
- ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaOaep,
- blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageEncrypt, &public_key));
+ ImportKeyJwkFromDict(
+ *jwk.get(),
+ CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaOaep,
+ blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageEncrypt, &public_key));
}
TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedAlgFails) {
@@ -97,10 +99,11 @@ TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedAlgFails) {
blink::WebCryptoKey public_key;
ASSERT_EQ(
Status::ErrorJwkAlgorithmInconsistent(),
- ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaOaep,
- blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageEncrypt, &public_key));
+ ImportKeyJwkFromDict(
+ *jwk.get(),
+ CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaOaep,
+ blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageEncrypt, &public_key));
}
TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedTypeFails) {
@@ -111,20 +114,21 @@ TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedTypeFails) {
blink::WebCryptoKey public_key;
ASSERT_EQ(
Status::ErrorJwkUnexpectedKty("RSA"),
- ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaOaep,
- blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageEncrypt, &public_key));
+ ImportKeyJwkFromDict(
+ *jwk.get(),
+ CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaOaep,
+ blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageEncrypt, &public_key));
}
TEST_F(WebCryptoRsaOaepTest, ExportPublicJwk) {
struct TestData {
blink::WebCryptoAlgorithmId hash_alg;
const char* expected_jwk_alg;
- } kTestData[] = {{blink::WebCryptoAlgorithmIdSha1, "RSA-OAEP"},
- {blink::WebCryptoAlgorithmIdSha256, "RSA-OAEP-256"},
- {blink::WebCryptoAlgorithmIdSha384, "RSA-OAEP-384"},
- {blink::WebCryptoAlgorithmIdSha512, "RSA-OAEP-512"}};
+ } kTestData[] = {{blink::kWebCryptoAlgorithmIdSha1, "RSA-OAEP"},
+ {blink::kWebCryptoAlgorithmIdSha256, "RSA-OAEP-256"},
+ {blink::kWebCryptoAlgorithmIdSha384, "RSA-OAEP-384"},
+ {blink::kWebCryptoAlgorithmIdSha512, "RSA-OAEP-512"}};
for (size_t i = 0; i < arraysize(kTestData); ++i) {
const TestData& test_data = kTestData[i];
SCOPED_TRACE(test_data.expected_jwk_alg);
@@ -138,16 +142,16 @@ TEST_F(WebCryptoRsaOaepTest, ExportPublicJwk) {
ImportKeyJwkFromDict(
*jwk.get(),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaOaep, test_data.hash_alg),
- true, blink::WebCryptoKeyUsageEncrypt, &public_key));
+ blink::kWebCryptoAlgorithmIdRsaOaep, test_data.hash_alg),
+ true, blink::kWebCryptoKeyUsageEncrypt, &public_key));
// Now export the key as JWK and verify its contents
std::vector<uint8_t> jwk_data;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk_data));
+ ExportKey(blink::kWebCryptoKeyFormatJwk, public_key, &jwk_data));
EXPECT_TRUE(VerifyPublicJwk(jwk_data, test_data.expected_jwk_alg,
kPublicKeyModulusHex, kPublicKeyExponentHex,
- blink::WebCryptoKeyUsageEncrypt));
+ blink::kWebCryptoKeyUsageEncrypt));
}
}
@@ -163,7 +167,7 @@ TEST_F(WebCryptoRsaOaepTest, EncryptDecryptKnownAnswerTest) {
blink::WebCryptoAlgorithm digest_algorithm =
GetDigestAlgorithm(test, "hash");
- ASSERT_FALSE(digest_algorithm.isNull());
+ ASSERT_FALSE(digest_algorithm.IsNull());
std::vector<uint8_t> public_key_der =
GetBytesFromHexString(test, "public_key");
std::vector<uint8_t> private_key_der =
@@ -173,13 +177,13 @@ TEST_F(WebCryptoRsaOaepTest, EncryptDecryptKnownAnswerTest) {
std::vector<uint8_t> label = GetBytesFromHexString(test, "label");
blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaOaep, digest_algorithm.id());
+ blink::kWebCryptoAlgorithmIdRsaOaep, digest_algorithm.Id());
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
public_key_der, private_key_der, import_algorithm, false,
- blink::WebCryptoKeyUsageEncrypt, blink::WebCryptoKeyUsageDecrypt,
+ blink::kWebCryptoKeyUsageEncrypt, blink::kWebCryptoKeyUsageDecrypt,
&public_key, &private_key));
blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label);
@@ -201,7 +205,7 @@ TEST_F(WebCryptoRsaOaepTest, EncryptDecryptKnownAnswerTest) {
}
TEST_F(WebCryptoRsaOaepTest, EncryptWithLargeMessageFails) {
- const blink::WebCryptoAlgorithmId kHash = blink::WebCryptoAlgorithmIdSha1;
+ const blink::WebCryptoAlgorithmId kHash = blink::kWebCryptoAlgorithmIdSha1;
const size_t kHashSize = 20;
std::unique_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
@@ -209,9 +213,10 @@ TEST_F(WebCryptoRsaOaepTest, EncryptWithLargeMessageFails) {
blink::WebCryptoKey public_key;
ASSERT_EQ(Status::Success(),
ImportKeyJwkFromDict(
- *jwk.get(), CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaOaep, kHash),
- true, blink::WebCryptoKeyUsageEncrypt, &public_key));
+ *jwk.get(),
+ CreateRsaHashedImportAlgorithm(
+ blink::kWebCryptoAlgorithmIdRsaOaep, kHash),
+ true, blink::kWebCryptoKeyUsageEncrypt, &public_key));
// The maximum size of an encrypted message is:
// modulus length
@@ -257,16 +262,17 @@ TEST_F(WebCryptoRsaOaepTest, EncryptWithLargeMessageFails) {
// uses OAEP with SHA-512, since it requires 1040 bits to encode
// (2 * hash size + 2 padding bytes).
TEST_F(WebCryptoRsaOaepTest, EncryptWithLargeDigestFails) {
- const blink::WebCryptoAlgorithmId kHash = blink::WebCryptoAlgorithmIdSha512;
+ const blink::WebCryptoAlgorithmId kHash = blink::kWebCryptoAlgorithmIdSha512;
std::unique_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
blink::WebCryptoKey public_key;
ASSERT_EQ(Status::Success(),
ImportKeyJwkFromDict(
- *jwk.get(), CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaOaep, kHash),
- true, blink::WebCryptoKeyUsageEncrypt, &public_key));
+ *jwk.get(),
+ CreateRsaHashedImportAlgorithm(
+ blink::kWebCryptoAlgorithmIdRsaOaep, kHash),
+ true, blink::kWebCryptoKeyUsageEncrypt, &public_key));
// The label has no influence on the maximum message size. For simplicity,
// use the empty string.
@@ -285,12 +291,12 @@ TEST_F(WebCryptoRsaOaepTest, EncryptWithLargeDigestFails) {
TEST_F(WebCryptoRsaOaepTest, DecryptWithLargeMessageFails) {
blink::WebCryptoKey private_key;
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatPkcs8,
+ ImportKey(blink::kWebCryptoKeyFormatPkcs8,
CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaOaep,
- blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageDecrypt, &private_key));
+ blink::kWebCryptoAlgorithmIdRsaOaep,
+ blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageDecrypt, &private_key));
// The label has no influence on the maximum message size. For simplicity,
// use the empty string.
@@ -307,15 +313,15 @@ TEST_F(WebCryptoRsaOaepTest, DecryptWithLargeMessageFails) {
TEST_F(WebCryptoRsaOaepTest, WrapUnwrapRawKey) {
blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaOaep, blink::WebCryptoAlgorithmIdSha1);
+ blink::kWebCryptoAlgorithmIdRsaOaep, blink::kWebCryptoAlgorithmIdSha1);
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
HexStringToBytes(kPublicKeySpkiDerHex),
HexStringToBytes(kPrivateKeyPkcs8DerHex), import_algorithm, false,
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey,
- blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageUnwrapKey,
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageWrapKey,
+ blink::kWebCryptoKeyUsageDecrypt | blink::kWebCryptoKeyUsageUnwrapKey,
&public_key, &private_key));
std::vector<uint8_t> label;
@@ -323,16 +329,16 @@ TEST_F(WebCryptoRsaOaepTest, WrapUnwrapRawKey) {
const std::string key_hex = "000102030405060708090A0B0C0D0E0F";
const blink::WebCryptoAlgorithm key_algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc);
blink::WebCryptoKey key =
ImportSecretKeyFromRaw(HexStringToBytes(key_hex), key_algorithm,
- blink::WebCryptoKeyUsageEncrypt);
- ASSERT_FALSE(key.isNull());
+ blink::kWebCryptoKeyUsageEncrypt);
+ ASSERT_FALSE(key.IsNull());
std::vector<uint8_t> wrapped_key;
ASSERT_EQ(Status::Success(),
- WrapKey(blink::WebCryptoKeyFormatRaw, key, public_key,
+ WrapKey(blink::kWebCryptoKeyFormatRaw, key, public_key,
wrapping_algorithm, &wrapped_key));
// Verify that |wrapped_key| can be decrypted and yields the key data.
@@ -346,14 +352,14 @@ TEST_F(WebCryptoRsaOaepTest, WrapUnwrapRawKey) {
// Now attempt to unwrap the key, which should also decrypt the data.
blink::WebCryptoKey unwrapped_key;
ASSERT_EQ(Status::Success(),
- UnwrapKey(blink::WebCryptoKeyFormatRaw, CryptoData(wrapped_key),
+ UnwrapKey(blink::kWebCryptoKeyFormatRaw, CryptoData(wrapped_key),
private_key, wrapping_algorithm, key_algorithm, true,
- blink::WebCryptoKeyUsageEncrypt, &unwrapped_key));
- ASSERT_FALSE(unwrapped_key.isNull());
+ blink::kWebCryptoKeyUsageEncrypt, &unwrapped_key));
+ ASSERT_FALSE(unwrapped_key.IsNull());
std::vector<uint8_t> raw_key;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
EXPECT_BYTES_EQ_HEX(key_hex, raw_key);
}
@@ -406,15 +412,15 @@ TEST_F(WebCryptoRsaOaepTest, WrapUnwrapJwkSymKey) {
"3db99fdbf5e74848ed4fa7bdfc2ebb60e2aaa5354770a763e1399ab7a2099762d525fea0"
"37f3e1972c45a477e66db95c9609bb27f862700ef93379930786cf751b";
blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaOaep, blink::WebCryptoAlgorithmIdSha1);
+ blink::kWebCryptoAlgorithmIdRsaOaep, blink::kWebCryptoAlgorithmIdSha1);
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
HexStringToBytes(kPublicKey2048SpkiDerHex),
HexStringToBytes(kPrivateKey2048Pkcs8DerHex), import_algorithm, false,
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey,
- blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageUnwrapKey,
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageWrapKey,
+ blink::kWebCryptoKeyUsageDecrypt | blink::kWebCryptoKeyUsageUnwrapKey,
&public_key, &private_key));
std::vector<uint8_t> label;
@@ -422,16 +428,16 @@ TEST_F(WebCryptoRsaOaepTest, WrapUnwrapJwkSymKey) {
const std::string key_hex = "000102030405060708090a0b0c0d0e0f";
const blink::WebCryptoAlgorithm key_algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc);
blink::WebCryptoKey key =
ImportSecretKeyFromRaw(HexStringToBytes(key_hex), key_algorithm,
- blink::WebCryptoKeyUsageEncrypt);
- ASSERT_FALSE(key.isNull());
+ blink::kWebCryptoKeyUsageEncrypt);
+ ASSERT_FALSE(key.IsNull());
std::vector<uint8_t> wrapped_key;
ASSERT_EQ(Status::Success(),
- WrapKey(blink::WebCryptoKeyFormatJwk, key, public_key,
+ WrapKey(blink::kWebCryptoKeyFormatJwk, key, public_key,
wrapping_algorithm, &wrapped_key));
// Verify that |wrapped_key| can be decrypted and yields a valid JWK object.
@@ -441,19 +447,19 @@ TEST_F(WebCryptoRsaOaepTest, WrapUnwrapJwkSymKey) {
Decrypt(wrapping_algorithm, private_key, CryptoData(wrapped_key),
&decrypted_jwk));
EXPECT_TRUE(VerifySecretJwk(decrypted_jwk, "A128CBC", key_hex,
- blink::WebCryptoKeyUsageEncrypt));
+ blink::kWebCryptoKeyUsageEncrypt));
// Now attempt to unwrap the key, which should also decrypt the data.
blink::WebCryptoKey unwrapped_key;
ASSERT_EQ(Status::Success(),
- UnwrapKey(blink::WebCryptoKeyFormatJwk, CryptoData(wrapped_key),
+ UnwrapKey(blink::kWebCryptoKeyFormatJwk, CryptoData(wrapped_key),
private_key, wrapping_algorithm, key_algorithm, true,
- blink::WebCryptoKeyUsageEncrypt, &unwrapped_key));
- ASSERT_FALSE(unwrapped_key.isNull());
+ blink::kWebCryptoKeyUsageEncrypt, &unwrapped_key));
+ ASSERT_FALSE(unwrapped_key.IsNull());
std::vector<uint8_t> raw_key;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
EXPECT_BYTES_EQ_HEX(key_hex, raw_key);
}
@@ -463,50 +469,47 @@ TEST_F(WebCryptoRsaOaepTest, ImportExportJwkRsaPublicKey) {
const blink::WebCryptoKeyUsageMask usage;
const char* const jwk_alg;
};
- const TestCase kTests[] = {{blink::WebCryptoAlgorithmIdSha1,
- blink::WebCryptoKeyUsageEncrypt,
- "RSA-OAEP"},
- {blink::WebCryptoAlgorithmIdSha256,
- blink::WebCryptoKeyUsageEncrypt,
- "RSA-OAEP-256"},
- {blink::WebCryptoAlgorithmIdSha384,
- blink::WebCryptoKeyUsageEncrypt,
- "RSA-OAEP-384"},
- {blink::WebCryptoAlgorithmIdSha512,
- blink::WebCryptoKeyUsageEncrypt,
- "RSA-OAEP-512"}};
+ const TestCase kTests[] = {
+ {blink::kWebCryptoAlgorithmIdSha1, blink::kWebCryptoKeyUsageEncrypt,
+ "RSA-OAEP"},
+ {blink::kWebCryptoAlgorithmIdSha256, blink::kWebCryptoKeyUsageEncrypt,
+ "RSA-OAEP-256"},
+ {blink::kWebCryptoAlgorithmIdSha384, blink::kWebCryptoKeyUsageEncrypt,
+ "RSA-OAEP-384"},
+ {blink::kWebCryptoAlgorithmIdSha512, blink::kWebCryptoKeyUsageEncrypt,
+ "RSA-OAEP-512"}};
for (size_t test_index = 0; test_index < arraysize(kTests); ++test_index) {
SCOPED_TRACE(test_index);
const TestCase& test = kTests[test_index];
const blink::WebCryptoAlgorithm import_algorithm =
- CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep,
+ CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaOaep,
test.hash);
// Import the spki to create a public key
blink::WebCryptoKey public_key;
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatSpki,
+ ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
import_algorithm, true, test.usage, &public_key));
// Export the public key as JWK and verify its contents
std::vector<uint8_t> jwk;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk));
+ ExportKey(blink::kWebCryptoKeyFormatJwk, public_key, &jwk));
EXPECT_TRUE(VerifyPublicJwk(jwk, test.jwk_alg, kPublicKeyModulusHex,
kPublicKeyExponentHex, test.usage));
// Import the JWK back in to create a new key
blink::WebCryptoKey public_key2;
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(jwk),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(jwk),
import_algorithm, true, test.usage, &public_key2));
- ASSERT_TRUE(public_key2.handle());
- EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type());
- EXPECT_TRUE(public_key2.extractable());
- EXPECT_EQ(import_algorithm.id(), public_key2.algorithm().id());
+ ASSERT_TRUE(public_key2.Handle());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key2.GetType());
+ EXPECT_TRUE(public_key2.Extractable());
+ EXPECT_EQ(import_algorithm.Id(), public_key2.Algorithm().Id());
// TODO(eroman): Export the SPKI and verify matches.
}
diff --git a/chromium/components/webcrypto/algorithms/rsa_pss.cc b/chromium/components/webcrypto/algorithms/rsa_pss.cc
index 9754adfd8a2..592c84763d4 100644
--- a/chromium/components/webcrypto/algorithms/rsa_pss.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_pss.cc
@@ -17,19 +17,19 @@ namespace {
class RsaPssImplementation : public RsaHashedAlgorithm {
public:
RsaPssImplementation()
- : RsaHashedAlgorithm(blink::WebCryptoKeyUsageVerify,
- blink::WebCryptoKeyUsageSign) {}
+ : RsaHashedAlgorithm(blink::kWebCryptoKeyUsageVerify,
+ blink::kWebCryptoKeyUsageSign) {}
const char* GetJwkAlgorithm(
const blink::WebCryptoAlgorithmId hash) const override {
switch (hash) {
- case blink::WebCryptoAlgorithmIdSha1:
+ case blink::kWebCryptoAlgorithmIdSha1:
return "PS1";
- case blink::WebCryptoAlgorithmIdSha256:
+ case blink::kWebCryptoAlgorithmIdSha256:
return "PS256";
- case blink::WebCryptoAlgorithmIdSha384:
+ case blink::kWebCryptoAlgorithmIdSha384:
return "PS384";
- case blink::WebCryptoAlgorithmIdSha512:
+ case blink::kWebCryptoAlgorithmIdSha512:
return "PS512";
default:
return NULL;
@@ -40,7 +40,7 @@ class RsaPssImplementation : public RsaHashedAlgorithm {
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) const override {
- return RsaSign(key, algorithm.rsaPssParams()->saltLengthBytes(), data,
+ return RsaSign(key, algorithm.RsaPssParams()->SaltLengthBytes(), data,
buffer);
}
@@ -49,7 +49,7 @@ class RsaPssImplementation : public RsaHashedAlgorithm {
const CryptoData& signature,
const CryptoData& data,
bool* signature_match) const override {
- return RsaVerify(key, algorithm.rsaPssParams()->saltLengthBytes(),
+ return RsaVerify(key, algorithm.RsaPssParams()->SaltLengthBytes(),
signature, data, signature_match);
}
};
diff --git a/chromium/components/webcrypto/algorithms/rsa_pss_unittest.cc b/chromium/components/webcrypto/algorithms/rsa_pss_unittest.cc
index 61b5d50c6ab..a701ec0d408 100644
--- a/chromium/components/webcrypto/algorithms/rsa_pss_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_pss_unittest.cc
@@ -23,8 +23,8 @@ namespace {
blink::WebCryptoAlgorithm CreateRsaPssAlgorithm(
unsigned int salt_length_bytes) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdRsaPss,
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ blink::kWebCryptoAlgorithmIdRsaPss,
new blink::WebCryptoRsaPssParams(salt_length_bytes));
}
@@ -34,15 +34,15 @@ class WebCryptoRsaPssTest : public WebCryptoTestBase {};
// lengthed salt.
TEST_F(WebCryptoRsaPssTest, SignIsRandom) {
// Import public/private key pair.
- blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
- blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
+ blink::WebCryptoKey public_key = blink::WebCryptoKey::CreateNull();
+ blink::WebCryptoKey private_key = blink::WebCryptoKey::CreateNull();
ImportRsaKeyPair(
HexStringToBytes(kPublicKeySpkiDerHex),
HexStringToBytes(kPrivateKeyPkcs8DerHex),
- CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss,
- blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign,
+ CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaPss,
+ blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageVerify, blink::kWebCryptoKeyUsageSign,
&public_key, &private_key);
// Use a 20-byte length salt.
@@ -87,15 +87,15 @@ TEST_F(WebCryptoRsaPssTest, SignIsRandom) {
// case is not random.
TEST_F(WebCryptoRsaPssTest, SignVerifyNoSalt) {
// Import public/private key pair.
- blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
- blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
+ blink::WebCryptoKey public_key = blink::WebCryptoKey::CreateNull();
+ blink::WebCryptoKey private_key = blink::WebCryptoKey::CreateNull();
ImportRsaKeyPair(
HexStringToBytes(kPublicKeySpkiDerHex),
HexStringToBytes(kPrivateKeyPkcs8DerHex),
- CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss,
- blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign,
+ CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaPss,
+ blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageVerify, blink::kWebCryptoKeyUsageSign,
&public_key, &private_key);
// Zero-length salt.
@@ -132,15 +132,15 @@ TEST_F(WebCryptoRsaPssTest, SignVerifyNoSalt) {
TEST_F(WebCryptoRsaPssTest, SignEmptyMessage) {
// Import public/private key pair.
- blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
- blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
+ blink::WebCryptoKey public_key = blink::WebCryptoKey::CreateNull();
+ blink::WebCryptoKey private_key = blink::WebCryptoKey::CreateNull();
ImportRsaKeyPair(
HexStringToBytes(kPublicKeySpkiDerHex),
HexStringToBytes(kPrivateKeyPkcs8DerHex),
- CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss,
- blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign,
+ CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaPss,
+ blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageVerify, blink::kWebCryptoKeyUsageSign,
&public_key, &private_key);
blink::WebCryptoAlgorithm params = CreateRsaPssAlgorithm(20);
@@ -189,15 +189,15 @@ TEST_F(WebCryptoRsaPssTest, VerifyKnownAnswer) {
ASSERT_TRUE(test->GetString("key", &key_name));
// Import the public key.
- blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
+ blink::WebCryptoKey public_key = blink::WebCryptoKey::CreateNull();
std::vector<uint8_t> spki_bytes =
GetBytesFromHexString(keys_dict, key_name);
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatSpki, CryptoData(spki_bytes),
+ ImportKey(blink::kWebCryptoKeyFormatSpki, CryptoData(spki_bytes),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaPss, hash.id()),
- true, blink::WebCryptoKeyUsageVerify, &public_key));
+ blink::kWebCryptoAlgorithmIdRsaPss, hash.Id()),
+ true, blink::kWebCryptoKeyUsageVerify, &public_key));
int saltLength;
ASSERT_TRUE(test->GetInteger("saltLength", &saltLength));
diff --git a/chromium/components/webcrypto/algorithms/rsa_sign.cc b/chromium/components/webcrypto/algorithms/rsa_sign.cc
index af28061db78..d5ce8b16a51 100644
--- a/chromium/components/webcrypto/algorithms/rsa_sign.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_sign.cc
@@ -27,7 +27,7 @@ Status GetPKeyAndDigest(const blink::WebCryptoKey& key,
const EVP_MD** digest) {
*pkey = GetEVP_PKEY(key);
- *digest = GetDigest(key.algorithm().rsaHashedParams()->hash());
+ *digest = GetDigest(key.Algorithm().RsaHashedParams()->GetHash());
if (!*digest)
return Status::ErrorUnsupported();
@@ -42,9 +42,10 @@ Status ApplyRsaPssOptions(const blink::WebCryptoKey& key,
unsigned int salt_length_bytes,
EVP_PKEY_CTX* pctx) {
// Only apply RSA-PSS options if the key is for RSA-PSS.
- if (key.algorithm().id() != blink::WebCryptoAlgorithmIdRsaPss) {
+ if (key.Algorithm().Id() != blink::kWebCryptoAlgorithmIdRsaPss) {
DCHECK_EQ(0u, salt_length_bytes);
- DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, key.algorithm().id());
+ DCHECK_EQ(blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ key.Algorithm().Id());
return Status::Success();
}
@@ -72,7 +73,7 @@ Status RsaSign(const blink::WebCryptoKey& key,
unsigned int pss_salt_length_bytes,
const CryptoData& data,
std::vector<uint8_t>* buffer) {
- if (key.type() != blink::WebCryptoKeyTypePrivate)
+ if (key.GetType() != blink::kWebCryptoKeyTypePrivate)
return Status::ErrorUnexpectedKeyType();
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
@@ -116,7 +117,7 @@ Status RsaVerify(const blink::WebCryptoKey& key,
const CryptoData& signature,
const CryptoData& data,
bool* signature_match) {
- if (key.type() != blink::WebCryptoKeyTypePublic)
+ if (key.GetType() != blink::kWebCryptoKeyTypePublic)
return Status::ErrorUnexpectedKeyType();
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
diff --git a/chromium/components/webcrypto/algorithms/rsa_ssa.cc b/chromium/components/webcrypto/algorithms/rsa_ssa.cc
index e9cea331e42..ec9f0ab711d 100644
--- a/chromium/components/webcrypto/algorithms/rsa_ssa.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_ssa.cc
@@ -16,19 +16,19 @@ namespace {
class RsaSsaImplementation : public RsaHashedAlgorithm {
public:
RsaSsaImplementation()
- : RsaHashedAlgorithm(blink::WebCryptoKeyUsageVerify,
- blink::WebCryptoKeyUsageSign) {}
+ : RsaHashedAlgorithm(blink::kWebCryptoKeyUsageVerify,
+ blink::kWebCryptoKeyUsageSign) {}
const char* GetJwkAlgorithm(
const blink::WebCryptoAlgorithmId hash) const override {
switch (hash) {
- case blink::WebCryptoAlgorithmIdSha1:
+ case blink::kWebCryptoAlgorithmIdSha1:
return "RS1";
- case blink::WebCryptoAlgorithmIdSha256:
+ case blink::kWebCryptoAlgorithmIdSha256:
return "RS256";
- case blink::WebCryptoAlgorithmIdSha384:
+ case blink::kWebCryptoAlgorithmIdSha384:
return "RS384";
- case blink::WebCryptoAlgorithmIdSha512:
+ case blink::kWebCryptoAlgorithmIdSha512:
return "RS512";
default:
return NULL;
diff --git a/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc b/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc
index fea882a5f39..cf90554e048 100644
--- a/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc
@@ -43,53 +43,53 @@ TEST_F(WebCryptoRsaSsaTest, ImportExportSpki) {
// Passing case: Import a valid RSA key in SPKI format.
blink::WebCryptoKey key;
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatSpki,
+ ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256),
- true, blink::WebCryptoKeyUsageVerify, &key));
- EXPECT_TRUE(key.handle());
- EXPECT_EQ(blink::WebCryptoKeyTypePublic, key.type());
- EXPECT_TRUE(key.extractable());
- EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256),
+ true, blink::kWebCryptoKeyUsageVerify, &key));
+ EXPECT_TRUE(key.Handle());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePublic, key.GetType());
+ EXPECT_TRUE(key.Extractable());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageVerify, key.Usages());
EXPECT_EQ(kModulusLengthBits,
- key.algorithm().rsaHashedParams()->modulusLengthBits());
+ key.Algorithm().RsaHashedParams()->ModulusLengthBits());
EXPECT_BYTES_EQ_HEX(
"010001",
- CryptoData(key.algorithm().rsaHashedParams()->publicExponent()));
+ CryptoData(key.Algorithm().RsaHashedParams()->PublicExponent()));
// Failing case: Import RSA key but provide an inconsistent input algorithm.
EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
- ImportKey(blink::WebCryptoKeyFormatSpki,
+ ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
- blink::WebCryptoKeyUsageEncrypt, &key));
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), true,
+ blink::kWebCryptoKeyUsageEncrypt, &key));
// Passing case: Export a previously imported RSA public key in SPKI format
// and compare to original data.
std::vector<uint8_t> output;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatSpki, key, &output));
+ ExportKey(blink::kWebCryptoKeyFormatSpki, key, &output));
EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, output);
// Failing case: Try to export a previously imported RSA public key in raw
// format (not allowed for a public key).
EXPECT_EQ(Status::ErrorUnsupportedExportKeyFormat(),
- ExportKey(blink::WebCryptoKeyFormatRaw, key, &output));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, key, &output));
// Failing case: Try to export a non-extractable key
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatSpki,
+ ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256),
- false, blink::WebCryptoKeyUsageVerify, &key));
- EXPECT_TRUE(key.handle());
- EXPECT_FALSE(key.extractable());
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256),
+ false, blink::kWebCryptoKeyUsageVerify, &key));
+ EXPECT_TRUE(key.Handle());
+ EXPECT_FALSE(key.Extractable());
EXPECT_EQ(Status::ErrorKeyNotExtractable(),
- ExportKey(blink::WebCryptoKeyFormatSpki, key, &output));
+ ExportKey(blink::kWebCryptoKeyFormatSpki, key, &output));
// TODO(eroman): Failing test: Import a SPKI with an unrecognized hash OID
// TODO(eroman): Failing test: Import a SPKI with invalid algorithm params
@@ -103,27 +103,27 @@ TEST_F(WebCryptoRsaSsaTest, ImportExportPkcs8) {
// Passing case: Import a valid RSA key in PKCS#8 format.
blink::WebCryptoKey key;
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatPkcs8,
+ ImportKey(blink::kWebCryptoKeyFormatPkcs8,
CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageSign, &key));
- EXPECT_TRUE(key.handle());
- EXPECT_EQ(blink::WebCryptoKeyTypePrivate, key.type());
- EXPECT_TRUE(key.extractable());
- EXPECT_EQ(blink::WebCryptoKeyUsageSign, key.usages());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
- key.algorithm().rsaHashedParams()->hash().id());
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageSign, &key));
+ EXPECT_TRUE(key.Handle());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePrivate, key.GetType());
+ EXPECT_TRUE(key.Extractable());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageSign, key.Usages());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha1,
+ key.Algorithm().RsaHashedParams()->GetHash().Id());
EXPECT_EQ(kModulusLengthBits,
- key.algorithm().rsaHashedParams()->modulusLengthBits());
+ key.Algorithm().RsaHashedParams()->ModulusLengthBits());
EXPECT_BYTES_EQ_HEX(
"010001",
- CryptoData(key.algorithm().rsaHashedParams()->publicExponent()));
+ CryptoData(key.Algorithm().RsaHashedParams()->PublicExponent()));
std::vector<uint8_t> exported_key;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_key));
+ ExportKey(blink::kWebCryptoKeyFormatPkcs8, key, &exported_key));
EXPECT_BYTES_EQ_HEX(kPrivateKeyPkcs8DerHex, exported_key);
// Failing case: Import RSA key but provide an inconsistent input algorithm
@@ -131,10 +131,10 @@ TEST_F(WebCryptoRsaSsaTest, ImportExportPkcs8) {
// * AES-CBC doesn't support PKCS8 key format
// * AES-CBC doesn't support "sign" usage
EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
- ImportKey(blink::WebCryptoKeyFormatPkcs8,
+ ImportKey(blink::kWebCryptoKeyFormatPkcs8,
CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
- blink::WebCryptoKeyUsageSign, &key));
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), true,
+ blink::kWebCryptoKeyUsageSign, &key));
}
// Tests JWK import and export by doing a roundtrip key conversion and ensuring
@@ -144,16 +144,16 @@ TEST_F(WebCryptoRsaSsaTest, ImportExportPkcs8) {
TEST_F(WebCryptoRsaSsaTest, ImportRsaPrivateKeyJwkToPkcs8RoundTrip) {
blink::WebCryptoKey key;
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatPkcs8,
+ ImportKey(blink::kWebCryptoKeyFormatPkcs8,
CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageSign, &key));
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageSign, &key));
std::vector<uint8_t> exported_key_jwk;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatJwk, key, &exported_key_jwk));
+ ExportKey(blink::kWebCryptoKeyFormatJwk, key, &exported_key_jwk));
// All of the optional parameters (p, q, dp, dq, qi) should be present in the
// output.
@@ -180,14 +180,14 @@ TEST_F(WebCryptoRsaSsaTest, ImportRsaPrivateKeyJwkToPkcs8RoundTrip) {
ASSERT_EQ(
Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(exported_key_jwk),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(exported_key_jwk),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageSign, &key));
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageSign, &key));
std::vector<uint8_t> exported_key_pkcs8;
- ASSERT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatPkcs8, key,
+ ASSERT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatPkcs8, key,
&exported_key_pkcs8));
ASSERT_EQ(CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
@@ -233,21 +233,22 @@ TEST_F(WebCryptoRsaSsaTest, ImportMultipleRSAPrivateKeysJwk) {
// Import the key from JWK.
ASSERT_EQ(Status::Success(),
ImportKeyJwkFromDict(
- *key_jwk, CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256),
- true, blink::WebCryptoKeyUsageSign, &private_key));
+ *key_jwk,
+ CreateRsaHashedImportAlgorithm(
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256),
+ true, blink::kWebCryptoKeyUsageSign, &private_key));
live_keys.push_back(private_key);
EXPECT_EQ(
modulus_length_bits,
static_cast<int>(
- private_key.algorithm().rsaHashedParams()->modulusLengthBits()));
+ private_key.Algorithm().RsaHashedParams()->ModulusLengthBits()));
// Export to PKCS8 and verify that it matches expectation.
std::vector<uint8_t> exported_key_pkcs8;
- ASSERT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatPkcs8,
+ ASSERT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatPkcs8,
private_key, &exported_key_pkcs8));
EXPECT_BYTES_EQ(pkcs8_bytes, exported_key_pkcs8);
@@ -269,14 +270,15 @@ TEST_F(WebCryptoRsaSsaTest, ImportJwkExistingModulusAndInvalid) {
ASSERT_TRUE(key1_props->GetDictionary("jwk", &key1_jwk));
blink::WebCryptoKey key1;
- ASSERT_EQ(Status::Success(),
- ImportKeyJwkFromDict(*key1_jwk,
- CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256),
- true, blink::WebCryptoKeyUsageSign, &key1));
+ ASSERT_EQ(
+ Status::Success(),
+ ImportKeyJwkFromDict(*key1_jwk,
+ CreateRsaHashedImportAlgorithm(
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256),
+ true, blink::kWebCryptoKeyUsageSign, &key1));
- ASSERT_EQ(1024u, key1.algorithm().rsaHashedParams()->modulusLengthBits());
+ ASSERT_EQ(1024u, key1.Algorithm().RsaHashedParams()->ModulusLengthBits());
// Construct a JWK using the modulus of key1, but all the other fields from
// another key (also a 1024-bit private key).
@@ -291,12 +293,13 @@ TEST_F(WebCryptoRsaSsaTest, ImportJwkExistingModulusAndInvalid) {
// This should fail, as the n,e,d parameters are not consistent. It MUST NOT
// somehow return the key created earlier.
blink::WebCryptoKey key2;
- ASSERT_EQ(Status::OperationError(),
- ImportKeyJwkFromDict(*key2_jwk,
- CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256),
- true, blink::WebCryptoKeyUsageSign, &key2));
+ ASSERT_EQ(
+ Status::OperationError(),
+ ImportKeyJwkFromDict(*key2_jwk,
+ CreateRsaHashedImportAlgorithm(
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256),
+ true, blink::kWebCryptoKeyUsageSign, &key2));
}
TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsa) {
@@ -306,71 +309,71 @@ TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsa) {
const unsigned int modulus_length = 256;
const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256, modulus_length, public_exponent);
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256, modulus_length, public_exponent);
bool extractable = true;
const blink::WebCryptoKeyUsageMask public_usages =
- blink::WebCryptoKeyUsageVerify;
+ blink::kWebCryptoKeyUsageVerify;
const blink::WebCryptoKeyUsageMask private_usages =
- blink::WebCryptoKeyUsageSign;
+ blink::kWebCryptoKeyUsageSign;
const blink::WebCryptoKeyUsageMask usages = public_usages | private_usages;
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, extractable, usages,
&public_key, &private_key));
- ASSERT_FALSE(public_key.isNull());
- ASSERT_FALSE(private_key.isNull());
- EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
- EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
+ ASSERT_FALSE(public_key.IsNull());
+ ASSERT_FALSE(private_key.IsNull());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key.GetType());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePrivate, private_key.GetType());
EXPECT_EQ(modulus_length,
- public_key.algorithm().rsaHashedParams()->modulusLengthBits());
+ public_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
EXPECT_EQ(modulus_length,
- private_key.algorithm().rsaHashedParams()->modulusLengthBits());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
- public_key.algorithm().rsaHashedParams()->hash().id());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
- private_key.algorithm().rsaHashedParams()->hash().id());
- EXPECT_TRUE(public_key.extractable());
- EXPECT_EQ(extractable, private_key.extractable());
- EXPECT_EQ(public_usages, public_key.usages());
- EXPECT_EQ(private_usages, private_key.usages());
+ private_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha256,
+ public_key.Algorithm().RsaHashedParams()->GetHash().Id());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha256,
+ private_key.Algorithm().RsaHashedParams()->GetHash().Id());
+ EXPECT_TRUE(public_key.Extractable());
+ EXPECT_EQ(extractable, private_key.Extractable());
+ EXPECT_EQ(public_usages, public_key.Usages());
+ EXPECT_EQ(private_usages, private_key.Usages());
// Try exporting the generated key pair, and then re-importing to verify that
// the exported data was valid.
std::vector<uint8_t> public_key_spki;
- EXPECT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatSpki,
+ EXPECT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatSpki,
public_key, &public_key_spki));
- public_key = blink::WebCryptoKey::createNull();
+ public_key = blink::WebCryptoKey::CreateNull();
ASSERT_EQ(
Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatSpki, CryptoData(public_key_spki),
+ ImportKey(blink::kWebCryptoKeyFormatSpki, CryptoData(public_key_spki),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256),
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256),
true, public_usages, &public_key));
EXPECT_EQ(modulus_length,
- public_key.algorithm().rsaHashedParams()->modulusLengthBits());
+ public_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
std::vector<uint8_t> private_key_pkcs8;
- EXPECT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatPkcs8,
+ EXPECT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatPkcs8,
private_key, &private_key_pkcs8));
- private_key = blink::WebCryptoKey::createNull();
+ private_key = blink::WebCryptoKey::CreateNull();
ASSERT_EQ(
Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatPkcs8, CryptoData(private_key_pkcs8),
+ ImportKey(blink::kWebCryptoKeyFormatPkcs8, CryptoData(private_key_pkcs8),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256),
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256),
true, private_usages, &private_key));
EXPECT_EQ(modulus_length,
- private_key.algorithm().rsaHashedParams()->modulusLengthBits());
+ private_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
// Fail with bad modulus.
algorithm = CreateRsaHashedKeyGenAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256, 0, public_exponent);
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256, 0, public_exponent);
EXPECT_EQ(Status::ErrorGenerateRsaUnsupportedModulus(),
GenerateKeyPair(algorithm, extractable, usages, &public_key,
&private_key));
@@ -379,8 +382,8 @@ TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsa) {
unsigned int exponent_length = sizeof(unsigned long) + 1; // NOLINT
const std::vector<uint8_t> long_exponent(exponent_length, 0x01);
algorithm = CreateRsaHashedKeyGenAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256, modulus_length, long_exponent);
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256, modulus_length, long_exponent);
EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
GenerateKeyPair(algorithm, extractable, usages, &public_key,
&private_key));
@@ -388,8 +391,8 @@ TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsa) {
// Fail with bad exponent: empty.
const std::vector<uint8_t> empty_exponent;
algorithm = CreateRsaHashedKeyGenAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256, modulus_length, empty_exponent);
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256, modulus_length, empty_exponent);
EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
GenerateKeyPair(algorithm, extractable, usages, &public_key,
&private_key));
@@ -397,8 +400,8 @@ TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsa) {
// Fail with bad exponent: all zeros.
std::vector<uint8_t> exponent_with_leading_zeros(15, 0x00);
algorithm = CreateRsaHashedKeyGenAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256, modulus_length,
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256, modulus_length,
exponent_with_leading_zeros);
EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
GenerateKeyPair(algorithm, extractable, usages, &public_key,
@@ -409,57 +412,57 @@ TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsa) {
public_exponent.begin(),
public_exponent.end());
algorithm = CreateRsaHashedKeyGenAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256, modulus_length,
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256, modulus_length,
exponent_with_leading_zeros);
EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, extractable, usages,
&public_key, &private_key));
- EXPECT_FALSE(public_key.isNull());
- EXPECT_FALSE(private_key.isNull());
- EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
- EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
- EXPECT_TRUE(public_key.extractable());
- EXPECT_EQ(extractable, private_key.extractable());
- EXPECT_EQ(public_usages, public_key.usages());
- EXPECT_EQ(private_usages, private_key.usages());
+ EXPECT_FALSE(public_key.IsNull());
+ EXPECT_FALSE(private_key.IsNull());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key.GetType());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePrivate, private_key.GetType());
+ EXPECT_TRUE(public_key.Extractable());
+ EXPECT_EQ(extractable, private_key.Extractable());
+ EXPECT_EQ(public_usages, public_key.Usages());
+ EXPECT_EQ(private_usages, private_key.Usages());
// Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha1)
algorithm = CreateRsaHashedKeyGenAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha1, modulus_length, public_exponent);
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha1, modulus_length, public_exponent);
EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, false, usages,
&public_key, &private_key));
- EXPECT_FALSE(public_key.isNull());
- EXPECT_FALSE(private_key.isNull());
- EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
- EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
+ EXPECT_FALSE(public_key.IsNull());
+ EXPECT_FALSE(private_key.IsNull());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key.GetType());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePrivate, private_key.GetType());
EXPECT_EQ(modulus_length,
- public_key.algorithm().rsaHashedParams()->modulusLengthBits());
+ public_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
EXPECT_EQ(modulus_length,
- private_key.algorithm().rsaHashedParams()->modulusLengthBits());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
- public_key.algorithm().rsaHashedParams()->hash().id());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
- private_key.algorithm().rsaHashedParams()->hash().id());
+ private_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha1,
+ public_key.Algorithm().RsaHashedParams()->GetHash().Id());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha1,
+ private_key.Algorithm().RsaHashedParams()->GetHash().Id());
// Even though "extractable" was set to false, the public key remains
// extractable.
- EXPECT_TRUE(public_key.extractable());
- EXPECT_FALSE(private_key.extractable());
- EXPECT_EQ(public_usages, public_key.usages());
- EXPECT_EQ(private_usages, private_key.usages());
+ EXPECT_TRUE(public_key.Extractable());
+ EXPECT_FALSE(private_key.Extractable());
+ EXPECT_EQ(public_usages, public_key.Usages());
+ EXPECT_EQ(private_usages, private_key.Usages());
// Exporting a private key as SPKI format doesn't make sense. However this
// will first fail because the key is not extractable.
std::vector<uint8_t> output;
EXPECT_EQ(Status::ErrorKeyNotExtractable(),
- ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output));
+ ExportKey(blink::kWebCryptoKeyFormatSpki, private_key, &output));
// Re-generate an extractable private_key and try to export it as SPKI format.
// This should fail since spki is for public keys.
EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, true, usages,
&public_key, &private_key));
EXPECT_EQ(Status::ErrorUnexpectedKeyType(),
- ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output));
+ ExportKey(blink::kWebCryptoKeyFormatSpki, private_key, &output));
}
TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadModulusLength) {
@@ -477,11 +480,11 @@ TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadModulusLength) {
for (size_t i = 0; i < arraysize(kBadModulusBits); ++i) {
const unsigned int modulus_length_bits = kBadModulusBits[i];
blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256, modulus_length_bits,
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256, modulus_length_bits,
public_exponent);
bool extractable = true;
- const blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
+ const blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageSign;
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
@@ -509,34 +512,34 @@ TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadExponent) {
for (size_t i = 0; i < arraysize(kPublicExponents); ++i) {
SCOPED_TRACE(i);
blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256, modulus_length,
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256, modulus_length,
HexStringToBytes(kPublicExponents[i]));
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
- GenerateKeyPair(algorithm, true, blink::WebCryptoKeyUsageSign,
+ GenerateKeyPair(algorithm, true, blink::kWebCryptoKeyUsageSign,
&public_key, &private_key));
}
}
TEST_F(WebCryptoRsaSsaTest, SignVerifyFailures) {
// Import a key pair.
- blink::WebCryptoAlgorithm import_algorithm =
- CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha1);
+ blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha1);
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
HexStringToBytes(kPublicKeySpkiDerHex),
HexStringToBytes(kPrivateKeyPkcs8DerHex), import_algorithm, false,
- blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign, &public_key,
- &private_key));
+ blink::kWebCryptoKeyUsageVerify, blink::kWebCryptoKeyUsageSign,
+ &public_key, &private_key));
blink::WebCryptoAlgorithm algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
std::vector<uint8_t> signature;
bool signature_match;
@@ -578,7 +581,7 @@ TEST_F(WebCryptoRsaSsaTest, SignVerifyFailures) {
EXPECT_FALSE(signature_match);
// Ensure that signing and verifying with an incompatible algorithm fails.
- algorithm = CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep);
+ algorithm = CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaOaep);
EXPECT_EQ(Status::ErrorUnexpected(),
Sign(algorithm, private_key, CryptoData(data), &signature));
@@ -597,31 +600,31 @@ TEST_F(WebCryptoRsaSsaTest, SignVerifyFailures) {
// Compute a signature using SHA-1 as the inner hash.
EXPECT_EQ(Status::Success(),
- Sign(CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
+ Sign(CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
private_key, CryptoData(data), &signature));
blink::WebCryptoKey public_key_256;
EXPECT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatSpki,
+ ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256),
- true, blink::WebCryptoKeyUsageVerify, &public_key_256));
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256),
+ true, blink::kWebCryptoKeyUsageVerify, &public_key_256));
// Now verify using an algorithm whose inner hash is SHA-256, not SHA-1. The
// signature should not verify.
// NOTE: public_key was produced by generateKey, and so its associated
// algorithm has WebCryptoRsaKeyGenParams and not WebCryptoRsaSsaParams. Thus
// it has no inner hash to conflict with the input algorithm.
- EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
- private_key.algorithm().rsaHashedParams()->hash().id());
- EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
- public_key_256.algorithm().rsaHashedParams()->hash().id());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha1,
+ private_key.Algorithm().RsaHashedParams()->GetHash().Id());
+ EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha256,
+ public_key_256.Algorithm().RsaHashedParams()->GetHash().Id());
bool is_match;
EXPECT_EQ(Status::Success(),
- Verify(CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
+ Verify(CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
public_key_256, CryptoData(signature), CryptoData(data),
&is_match));
EXPECT_FALSE(is_match);
@@ -632,19 +635,19 @@ TEST_F(WebCryptoRsaSsaTest, SignVerifyKnownAnswer) {
ASSERT_TRUE(ReadJsonTestFileToList("pkcs1v15_sign.json", &tests));
// Import the key pair.
- blink::WebCryptoAlgorithm import_algorithm =
- CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha1);
+ blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha1);
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
HexStringToBytes(kPublicKeySpkiDerHex),
HexStringToBytes(kPrivateKeyPkcs8DerHex), import_algorithm, false,
- blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign, &public_key,
- &private_key));
+ blink::kWebCryptoKeyUsageVerify, blink::kWebCryptoKeyUsageSign,
+ &public_key, &private_key));
blink::WebCryptoAlgorithm algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
+ CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
// Validate the signatures are computed and verified as expected.
std::vector<uint8_t> signature;
@@ -675,15 +678,15 @@ TEST_F(WebCryptoRsaSsaTest, SignVerifyKnownAnswer) {
// Try importing an RSA-SSA public key with unsupported key usages using SPKI
// format. RSA-SSA public keys only support the 'verify' usage.
TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_SPKI) {
- const blink::WebCryptoAlgorithm algorithm =
- CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256);
+ const blink::WebCryptoAlgorithm algorithm = CreateRsaHashedImportAlgorithm(
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256);
blink::WebCryptoKeyUsageMask bad_usages[] = {
- blink::WebCryptoKeyUsageSign,
- blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
- blink::WebCryptoKeyUsageEncrypt,
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
+ blink::kWebCryptoKeyUsageSign,
+ blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify,
+ blink::kWebCryptoKeyUsageEncrypt,
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt,
};
for (size_t i = 0; i < arraysize(bad_usages); ++i) {
@@ -691,7 +694,7 @@ TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_SPKI) {
blink::WebCryptoKey public_key;
ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
- ImportKey(blink::WebCryptoKeyFormatSpki,
+ ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
algorithm, false, bad_usages[i], &public_key));
}
@@ -700,15 +703,15 @@ TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_SPKI) {
// Try importing an RSA-SSA public key with unsupported key usages using JWK
// format. RSA-SSA public keys only support the 'verify' usage.
TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_JWK) {
- const blink::WebCryptoAlgorithm algorithm =
- CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256);
+ const blink::WebCryptoAlgorithm algorithm = CreateRsaHashedImportAlgorithm(
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256);
blink::WebCryptoKeyUsageMask bad_usages[] = {
- blink::WebCryptoKeyUsageSign,
- blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
- blink::WebCryptoKeyUsageEncrypt,
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
+ blink::kWebCryptoKeyUsageSign,
+ blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify,
+ blink::kWebCryptoKeyUsageEncrypt,
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt,
};
base::DictionaryValue dict;
@@ -730,9 +733,9 @@ TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_JWK) {
// 'sign', 'verify'
TEST_F(WebCryptoRsaSsaTest, GenerateKeyBadUsages) {
blink::WebCryptoKeyUsageMask bad_usages[] = {
- blink::WebCryptoKeyUsageDecrypt,
- blink::WebCryptoKeyUsageVerify | blink::WebCryptoKeyUsageDecrypt,
- blink::WebCryptoKeyUsageWrapKey,
+ blink::kWebCryptoKeyUsageDecrypt,
+ blink::kWebCryptoKeyUsageVerify | blink::kWebCryptoKeyUsageDecrypt,
+ blink::kWebCryptoKeyUsageWrapKey,
};
const unsigned int modulus_length = 256;
@@ -746,8 +749,8 @@ TEST_F(WebCryptoRsaSsaTest, GenerateKeyBadUsages) {
ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256,
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256,
modulus_length, public_exponent),
true, bad_usages[i], &public_key, &private_key));
}
@@ -763,29 +766,30 @@ TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairIntersectUsages) {
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
- ASSERT_EQ(Status::Success(),
- GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256,
- modulus_length, public_exponent),
- true, blink::WebCryptoKeyUsageSign |
- blink::WebCryptoKeyUsageVerify,
- &public_key, &private_key));
+ ASSERT_EQ(
+ Status::Success(),
+ GenerateKeyPair(
+ CreateRsaHashedKeyGenAlgorithm(
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256, modulus_length,
+ public_exponent),
+ true, blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify,
+ &public_key, &private_key));
- EXPECT_EQ(blink::WebCryptoKeyUsageVerify, public_key.usages());
- EXPECT_EQ(blink::WebCryptoKeyUsageSign, private_key.usages());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageVerify, public_key.Usages());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageSign, private_key.Usages());
// Try again but this time without the Verify usages.
ASSERT_EQ(Status::Success(),
GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256,
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256,
modulus_length, public_exponent),
- true, blink::WebCryptoKeyUsageSign, &public_key,
+ true, blink::kWebCryptoKeyUsageSign, &public_key,
&private_key));
- EXPECT_EQ(0, public_key.usages());
- EXPECT_EQ(blink::WebCryptoKeyUsageSign, private_key.usages());
+ EXPECT_EQ(0, public_key.Usages());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageSign, private_key.Usages());
}
TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairEmptyUsages) {
@@ -797,8 +801,8 @@ TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairEmptyUsages) {
ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256,
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256,
modulus_length, public_exponent),
true, 0, &public_key, &private_key));
}
@@ -809,52 +813,52 @@ TEST_F(WebCryptoRsaSsaTest, ImportKeyEmptyUsages) {
// Public without usage does not throw an error.
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatSpki,
+ ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256),
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256),
true, 0, &public_key));
- EXPECT_EQ(0, public_key.usages());
+ EXPECT_EQ(0, public_key.Usages());
// Private empty usage will throw an error.
ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
- ImportKey(blink::WebCryptoKeyFormatPkcs8,
+ ImportKey(blink::kWebCryptoKeyFormatPkcs8,
CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha1),
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha1),
true, 0, &private_key));
std::vector<uint8_t> public_jwk;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &public_jwk));
+ ExportKey(blink::kWebCryptoKeyFormatJwk, public_key, &public_jwk));
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(public_jwk),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(public_jwk),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256),
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256),
true, 0, &public_key));
- EXPECT_EQ(0, public_key.usages());
+ EXPECT_EQ(0, public_key.Usages());
// With correct usage to get correct imported private_key
std::vector<uint8_t> private_jwk;
- ImportKey(
- blink::WebCryptoKeyFormatPkcs8,
- CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
- CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha1),
- true, blink::WebCryptoKeyUsageSign, &private_key);
+ ImportKey(blink::kWebCryptoKeyFormatPkcs8,
+ CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
+ CreateRsaHashedImportAlgorithm(
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha1),
+ true, blink::kWebCryptoKeyUsageSign, &private_key);
- ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatJwk, private_key, &private_jwk));
+ ASSERT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatJwk,
+ private_key, &private_jwk));
ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(private_jwk),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(private_jwk),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha1),
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha1),
true, 0, &private_key));
}
@@ -864,17 +868,14 @@ TEST_F(WebCryptoRsaSsaTest, ImportExportJwkRsaPublicKey) {
const blink::WebCryptoKeyUsageMask usage;
const char* const jwk_alg;
};
- const TestCase kTests[] = {
- {blink::WebCryptoAlgorithmIdSha1, blink::WebCryptoKeyUsageVerify, "RS1"},
- {blink::WebCryptoAlgorithmIdSha256,
- blink::WebCryptoKeyUsageVerify,
- "RS256"},
- {blink::WebCryptoAlgorithmIdSha384,
- blink::WebCryptoKeyUsageVerify,
- "RS384"},
- {blink::WebCryptoAlgorithmIdSha512,
- blink::WebCryptoKeyUsageVerify,
- "RS512"}};
+ const TestCase kTests[] = {{blink::kWebCryptoAlgorithmIdSha1,
+ blink::kWebCryptoKeyUsageVerify, "RS1"},
+ {blink::kWebCryptoAlgorithmIdSha256,
+ blink::kWebCryptoKeyUsageVerify, "RS256"},
+ {blink::kWebCryptoAlgorithmIdSha384,
+ blink::kWebCryptoKeyUsageVerify, "RS384"},
+ {blink::kWebCryptoAlgorithmIdSha512,
+ blink::kWebCryptoKeyUsageVerify, "RS512"}};
for (size_t test_index = 0; test_index < arraysize(kTests); ++test_index) {
SCOPED_TRACE(test_index);
@@ -882,36 +883,36 @@ TEST_F(WebCryptoRsaSsaTest, ImportExportJwkRsaPublicKey) {
const blink::WebCryptoAlgorithm import_algorithm =
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, test.hash);
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5, test.hash);
// Import the spki to create a public key
blink::WebCryptoKey public_key;
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatSpki,
+ ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
import_algorithm, true, test.usage, &public_key));
// Export the public key as JWK and verify its contents
std::vector<uint8_t> jwk;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk));
+ ExportKey(blink::kWebCryptoKeyFormatJwk, public_key, &jwk));
EXPECT_TRUE(VerifyPublicJwk(jwk, test.jwk_alg, kPublicKeyModulusHex,
kPublicKeyExponentHex, test.usage));
// Import the JWK back in to create a new key
blink::WebCryptoKey public_key2;
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(jwk),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(jwk),
import_algorithm, true, test.usage, &public_key2));
- ASSERT_TRUE(public_key2.handle());
- EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type());
- EXPECT_TRUE(public_key2.extractable());
- EXPECT_EQ(import_algorithm.id(), public_key2.algorithm().id());
+ ASSERT_TRUE(public_key2.Handle());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key2.GetType());
+ EXPECT_TRUE(public_key2.Extractable());
+ EXPECT_EQ(import_algorithm.Id(), public_key2.Algorithm().Id());
// Export the new key as spki and compare to the original.
std::vector<uint8_t> spki;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatSpki, public_key2, &spki));
+ ExportKey(blink::kWebCryptoKeyFormatSpki, public_key2, &spki));
EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, CryptoData(spki));
}
}
@@ -919,10 +920,10 @@ TEST_F(WebCryptoRsaSsaTest, ImportExportJwkRsaPublicKey) {
TEST_F(WebCryptoRsaSsaTest, ImportJwkRsaFailures) {
base::DictionaryValue dict;
RestoreJwkRsaDictionary(&dict);
- blink::WebCryptoAlgorithm algorithm =
- CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256);
- blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageVerify;
+ blink::WebCryptoAlgorithm algorithm = CreateRsaHashedImportAlgorithm(
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256);
+ blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageVerify;
blink::WebCryptoKey key;
// An RSA public key JWK _must_ have an "n" (modulus) and an "e" (exponent)
@@ -934,10 +935,10 @@ TEST_F(WebCryptoRsaSsaTest, ImportJwkRsaFailures) {
// Baseline pass.
EXPECT_EQ(Status::Success(),
ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
- EXPECT_EQ(algorithm.id(), key.algorithm().id());
- EXPECT_FALSE(key.extractable());
- EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
- EXPECT_EQ(blink::WebCryptoKeyTypePublic, key.type());
+ EXPECT_EQ(algorithm.Id(), key.Algorithm().Id());
+ EXPECT_FALSE(key.Extractable());
+ EXPECT_EQ(blink::kWebCryptoKeyUsageVerify, key.Usages());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePublic, key.GetType());
// The following are specific failure cases for when kty = "RSA".
@@ -972,14 +973,15 @@ TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaJwkBadUsageAndData) {
std::string bad_data = "hello";
blink::WebCryptoKey key;
- ASSERT_EQ(Status::ErrorJwkNotDictionary(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(bad_data),
- CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256),
- true, blink::WebCryptoKeyUsageVerify |
- blink::WebCryptoKeyUsageSign,
- &key));
+ ASSERT_EQ(
+ Status::ErrorJwkNotDictionary(),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(bad_data),
+ CreateRsaHashedImportAlgorithm(
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256),
+ true,
+ blink::kWebCryptoKeyUsageVerify | blink::kWebCryptoKeyUsageSign,
+ &key));
}
// Imports invalid JWK/SPKI/PKCS8 data and verifies that it fails as expected.
@@ -999,14 +1001,14 @@ TEST_F(WebCryptoRsaSsaTest, ImportInvalidKeyData) {
std::string test_error;
ASSERT_TRUE(test->GetString("error", &test_error));
- blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
- if (key_format == blink::WebCryptoKeyFormatSpki)
- usages = blink::WebCryptoKeyUsageVerify;
+ blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageSign;
+ if (key_format == blink::kWebCryptoKeyFormatSpki)
+ usages = blink::kWebCryptoKeyUsageVerify;
blink::WebCryptoKey key;
Status status = ImportKey(key_format, CryptoData(key_data),
CreateRsaHashedImportAlgorithm(
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- blink::WebCryptoAlgorithmIdSha256),
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ blink::kWebCryptoAlgorithmIdSha256),
true, usages, &key);
EXPECT_EQ(test_error, StatusToString(status));
}
diff --git a/chromium/components/webcrypto/algorithms/secret_key_util.cc b/chromium/components/webcrypto/algorithms/secret_key_util.cc
index ee2448483ea..cb20290b4ea 100644
--- a/chromium/components/webcrypto/algorithms/secret_key_util.cc
+++ b/chromium/components/webcrypto/algorithms/secret_key_util.cc
@@ -31,9 +31,9 @@ Status GenerateWebCryptoSecretKey(const blink::WebCryptoKeyAlgorithm& algorithm,
TruncateToBitLength(keylen_bits, &random_bytes);
}
- result->AssignSecretKey(blink::WebCryptoKey::create(
+ result->AssignSecretKey(blink::WebCryptoKey::Create(
CreateSymmetricKeyHandle(CryptoData(random_bytes)),
- blink::WebCryptoKeyTypeSecret, extractable, algorithm, usages));
+ blink::kWebCryptoKeyTypeSecret, extractable, algorithm, usages));
return Status::Success();
}
@@ -43,9 +43,9 @@ Status CreateWebCryptoSecretKey(const CryptoData& key_data,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) {
- *key = blink::WebCryptoKey::create(CreateSymmetricKeyHandle(key_data),
- blink::WebCryptoKeyTypeSecret, extractable,
- algorithm, usages);
+ *key = blink::WebCryptoKey::Create(CreateSymmetricKeyHandle(key_data),
+ blink::kWebCryptoKeyTypeSecret,
+ extractable, algorithm, usages);
return Status::Success();
}
diff --git a/chromium/components/webcrypto/algorithms/sha.cc b/chromium/components/webcrypto/algorithms/sha.cc
index 1201bba77fd..b3e38f4d52c 100644
--- a/chromium/components/webcrypto/algorithms/sha.cc
+++ b/chromium/components/webcrypto/algorithms/sha.cc
@@ -29,7 +29,7 @@ class DigestorImpl : public blink::WebCryptoDigestor {
: initialized_(false),
algorithm_id_(algorithm_id) {}
- bool consume(const unsigned char* data, unsigned int size) override {
+ bool Consume(const unsigned char* data, unsigned int size) override {
return ConsumeWithStatus(data, size).IsSuccess();
}
@@ -45,7 +45,7 @@ class DigestorImpl : public blink::WebCryptoDigestor {
return Status::Success();
}
- bool finish(unsigned char*& result_data,
+ bool Finish(unsigned char*& result_data,
unsigned int& result_data_size) override {
Status error = FinishInternal(result_, &result_data_size);
if (!error.IsSuccess())
@@ -106,7 +106,7 @@ class ShaImplementation : public AlgorithmImplementation {
Status Digest(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& data,
std::vector<uint8_t>* buffer) const override {
- DigestorImpl digestor(algorithm.id());
+ DigestorImpl digestor(algorithm.Id());
Status error = digestor.ConsumeWithStatus(data.bytes(), data.byte_length());
// http://crbug.com/366427: the spec does not define any other failures for
// digest, so none of the subsequent errors are spec compliant.
diff --git a/chromium/components/webcrypto/algorithms/sha_unittest.cc b/chromium/components/webcrypto/algorithms/sha_unittest.cc
index 202b7df77d9..4102c75c20d 100644
--- a/chromium/components/webcrypto/algorithms/sha_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/sha_unittest.cc
@@ -64,19 +64,19 @@ TEST_F(WebCryptoShaTest, DigestSampleSetsInChunks) {
static const size_t kChunkSizeBytes = 129;
size_t length = test_input.size();
std::unique_ptr<blink::WebCryptoDigestor> digestor(
- CreateDigestor(test_algorithm.id()));
+ CreateDigestor(test_algorithm.Id()));
std::vector<uint8_t>::iterator begin = test_input.begin();
size_t chunk_index = 0;
while (begin != test_input.end()) {
size_t chunk_length = std::min(kChunkSizeBytes, length - chunk_index);
std::vector<uint8_t> chunk(begin, begin + chunk_length);
ASSERT_TRUE(chunk.size() > 0);
- EXPECT_TRUE(digestor->consume(chunk.data(),
+ EXPECT_TRUE(digestor->Consume(chunk.data(),
static_cast<unsigned int>(chunk.size())));
chunk_index = chunk_index + chunk_length;
begin = begin + chunk_length;
}
- EXPECT_TRUE(digestor->finish(output, output_length));
+ EXPECT_TRUE(digestor->Finish(output, output_length));
EXPECT_BYTES_EQ(test_output, CryptoData(output, output_length));
}
}
diff --git a/chromium/components/webcrypto/algorithms/test_helpers.cc b/chromium/components/webcrypto/algorithms/test_helpers.cc
index 8138f0d5493..0d569eae0e5 100644
--- a/chromium/components/webcrypto/algorithms/test_helpers.cc
+++ b/chromium/components/webcrypto/algorithms/test_helpers.cc
@@ -75,17 +75,17 @@ bool operator!=(const CryptoData& a, const CryptoData& b) {
static std::string ErrorTypeToString(blink::WebCryptoErrorType type) {
switch (type) {
- case blink::WebCryptoErrorTypeNotSupported:
+ case blink::kWebCryptoErrorTypeNotSupported:
return "NotSupported";
- case blink::WebCryptoErrorTypeType:
+ case blink::kWebCryptoErrorTypeType:
return "TypeError";
- case blink::WebCryptoErrorTypeData:
+ case blink::kWebCryptoErrorTypeData:
return "DataError";
- case blink::WebCryptoErrorTypeSyntax:
+ case blink::kWebCryptoErrorTypeSyntax:
return "SyntaxError";
- case blink::WebCryptoErrorTypeOperation:
+ case blink::kWebCryptoErrorTypeOperation:
return "OperationError";
- case blink::WebCryptoErrorTypeInvalidAccess:
+ case blink::kWebCryptoErrorTypeInvalidAccess:
return "InvalidAccess";
default:
return "?";
@@ -107,8 +107,8 @@ blink::WebCryptoAlgorithm CreateRsaHashedKeyGenAlgorithm(
const blink::WebCryptoAlgorithmId hash_id,
unsigned int modulus_length,
const std::vector<uint8_t>& public_exponent) {
- DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ DCHECK(blink::WebCryptoAlgorithm::IsHash(hash_id));
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
algorithm_id,
new blink::WebCryptoRsaHashedKeyGenParams(
CreateAlgorithm(hash_id), modulus_length, public_exponent));
@@ -227,17 +227,17 @@ blink::WebCryptoAlgorithm GetDigestAlgorithm(const base::DictionaryValue* dict,
std::string algorithm_name;
if (!dict->GetString(property_name, &algorithm_name)) {
ADD_FAILURE() << "Couldn't get string property: " << property_name;
- return blink::WebCryptoAlgorithm::createNull();
+ return blink::WebCryptoAlgorithm::CreateNull();
}
struct {
const char* name;
blink::WebCryptoAlgorithmId id;
} kDigestNameToId[] = {
- {"sha-1", blink::WebCryptoAlgorithmIdSha1},
- {"sha-256", blink::WebCryptoAlgorithmIdSha256},
- {"sha-384", blink::WebCryptoAlgorithmIdSha384},
- {"sha-512", blink::WebCryptoAlgorithmIdSha512},
+ {"sha-1", blink::kWebCryptoAlgorithmIdSha1},
+ {"sha-256", blink::kWebCryptoAlgorithmIdSha256},
+ {"sha-384", blink::kWebCryptoAlgorithmIdSha384},
+ {"sha-512", blink::kWebCryptoAlgorithmIdSha512},
};
for (size_t i = 0; i < arraysize(kDigestNameToId); ++i) {
@@ -245,7 +245,7 @@ blink::WebCryptoAlgorithm GetDigestAlgorithm(const base::DictionaryValue* dict,
return CreateAlgorithm(kDigestNameToId[i].id);
}
- return blink::WebCryptoAlgorithm::createNull();
+ return blink::WebCryptoAlgorithm::CreateNull();
}
// Creates a comparator for |bufs| which operates on indices rather than values.
@@ -280,7 +280,7 @@ bool CopiesExist(const std::vector<std::vector<uint8_t>>& bufs) {
blink::WebCryptoAlgorithm CreateAesKeyGenAlgorithm(
blink::WebCryptoAlgorithmId aes_alg_id,
unsigned short length) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
aes_alg_id, new blink::WebCryptoAesKeyGenParams(length));
}
@@ -334,15 +334,15 @@ blink::WebCryptoKey ImportSecretKeyFromRaw(
blink::WebCryptoKey key;
bool extractable = true;
EXPECT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(key_raw),
+ ImportKey(blink::kWebCryptoKeyFormatRaw, CryptoData(key_raw),
algorithm, extractable, usage, &key));
- EXPECT_FALSE(key.isNull());
- EXPECT_TRUE(key.handle());
- EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
- EXPECT_EQ(algorithm.id(), key.algorithm().id());
- EXPECT_EQ(extractable, key.extractable());
- EXPECT_EQ(usage, key.usages());
+ EXPECT_FALSE(key.IsNull());
+ EXPECT_TRUE(key.Handle());
+ EXPECT_EQ(blink::kWebCryptoKeyTypeSecret, key.GetType());
+ EXPECT_EQ(algorithm.Id(), key.Algorithm().Id());
+ EXPECT_EQ(extractable, key.Extractable());
+ EXPECT_EQ(usage, key.Usages());
return key;
}
@@ -355,24 +355,24 @@ void ImportRsaKeyPair(const std::vector<uint8_t>& spki_der,
blink::WebCryptoKey* public_key,
blink::WebCryptoKey* private_key) {
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatSpki, CryptoData(spki_der),
+ ImportKey(blink::kWebCryptoKeyFormatSpki, CryptoData(spki_der),
algorithm, true, public_key_usages, public_key));
- EXPECT_FALSE(public_key->isNull());
- EXPECT_TRUE(public_key->handle());
- EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key->type());
- EXPECT_EQ(algorithm.id(), public_key->algorithm().id());
- EXPECT_TRUE(public_key->extractable());
- EXPECT_EQ(public_key_usages, public_key->usages());
+ EXPECT_FALSE(public_key->IsNull());
+ EXPECT_TRUE(public_key->Handle());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key->GetType());
+ EXPECT_EQ(algorithm.Id(), public_key->Algorithm().Id());
+ EXPECT_TRUE(public_key->Extractable());
+ EXPECT_EQ(public_key_usages, public_key->Usages());
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatPkcs8, CryptoData(pkcs8_der),
+ ImportKey(blink::kWebCryptoKeyFormatPkcs8, CryptoData(pkcs8_der),
algorithm, extractable, private_key_usages, private_key));
- EXPECT_FALSE(private_key->isNull());
- EXPECT_TRUE(private_key->handle());
- EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key->type());
- EXPECT_EQ(algorithm.id(), private_key->algorithm().id());
- EXPECT_EQ(extractable, private_key->extractable());
- EXPECT_EQ(private_key_usages, private_key->usages());
+ EXPECT_FALSE(private_key->IsNull());
+ EXPECT_TRUE(private_key->Handle());
+ EXPECT_EQ(blink::kWebCryptoKeyTypePrivate, private_key->GetType());
+ EXPECT_EQ(algorithm.Id(), private_key->Algorithm().Id());
+ EXPECT_EQ(extractable, private_key->Extractable());
+ EXPECT_EQ(private_key_usages, private_key->Usages());
}
Status ImportKeyJwkFromDict(const base::DictionaryValue& dict,
@@ -380,7 +380,7 @@ Status ImportKeyJwkFromDict(const base::DictionaryValue& dict,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) {
- return ImportKey(blink::WebCryptoKeyFormatJwk,
+ return ImportKey(blink::kWebCryptoKeyFormatJwk,
CryptoData(MakeJsonVector(dict)), algorithm, extractable,
usages, key);
}
@@ -464,8 +464,7 @@ std::unique_ptr<base::DictionaryValue> GetJwkDictionary(
if (!Base64DecodeUrlSafe(value_string, &k_value))
return ::testing::AssertionFailure() << "Base64DecodeUrlSafe(k) failed";
if (!base::LowerCaseEqualsASCII(
- base::HexEncode(k_value.data(), k_value.size()),
- k_expected_hex.c_str())) {
+ base::HexEncode(k_value.data(), k_value.size()), k_expected_hex)) {
return ::testing::AssertionFailure() << "Expected 'k' to be "
<< k_expected_hex
<< " but found something different";
@@ -504,8 +503,7 @@ std::unique_ptr<base::DictionaryValue> GetJwkDictionary(
if (!Base64DecodeUrlSafe(value_string, &e_value))
return ::testing::AssertionFailure() << "Base64DecodeUrlSafe(e) failed";
if (!base::LowerCaseEqualsASCII(
- base::HexEncode(e_value.data(), e_value.size()),
- e_expected_hex.c_str())) {
+ base::HexEncode(e_value.data(), e_value.size()), e_expected_hex)) {
return ::testing::AssertionFailure() << "Expected 'e' to be "
<< e_expected_hex
<< " but found something different";
@@ -551,23 +549,23 @@ void ImportExportJwkSymmetricKey(
// Export the key in JWK format and validate.
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatJwk, key, &json));
+ ExportKey(blink::kWebCryptoKeyFormatJwk, key, &json));
EXPECT_TRUE(VerifySecretJwk(json, jwk_alg, key_hex, usages));
// Import the JWK-formatted key.
ASSERT_EQ(Status::Success(),
- ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(json),
+ ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(json),
import_algorithm, true, usages, &key));
- EXPECT_TRUE(key.handle());
- EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
- EXPECT_EQ(import_algorithm.id(), key.algorithm().id());
- EXPECT_EQ(true, key.extractable());
- EXPECT_EQ(usages, key.usages());
+ EXPECT_TRUE(key.Handle());
+ EXPECT_EQ(blink::kWebCryptoKeyTypeSecret, key.GetType());
+ EXPECT_EQ(import_algorithm.Id(), key.Algorithm().Id());
+ EXPECT_EQ(true, key.Extractable());
+ EXPECT_EQ(usages, key.Usages());
// Export the key in raw format and compare to the original.
std::vector<uint8_t> key_raw_out;
ASSERT_EQ(Status::Success(),
- ExportKey(blink::WebCryptoKeyFormatRaw, key, &key_raw_out));
+ ExportKey(blink::kWebCryptoKeyFormatRaw, key, &key_raw_out));
EXPECT_BYTES_EQ_HEX(key_hex, key_raw_out);
}
@@ -612,22 +610,22 @@ blink::WebCryptoKeyFormat GetKeyFormatFromJsonTestCase(
std::string format;
EXPECT_TRUE(test->GetString("key_format", &format));
if (format == "jwk")
- return blink::WebCryptoKeyFormatJwk;
+ return blink::kWebCryptoKeyFormatJwk;
else if (format == "pkcs8")
- return blink::WebCryptoKeyFormatPkcs8;
+ return blink::kWebCryptoKeyFormatPkcs8;
else if (format == "spki")
- return blink::WebCryptoKeyFormatSpki;
+ return blink::kWebCryptoKeyFormatSpki;
else if (format == "raw")
- return blink::WebCryptoKeyFormatRaw;
+ return blink::kWebCryptoKeyFormatRaw;
ADD_FAILURE() << "Unrecognized key format: " << format;
- return blink::WebCryptoKeyFormatRaw;
+ return blink::kWebCryptoKeyFormatRaw;
}
std::vector<uint8_t> GetKeyDataFromJsonTestCase(
const base::DictionaryValue* test,
blink::WebCryptoKeyFormat key_format) {
- if (key_format == blink::WebCryptoKeyFormatJwk) {
+ if (key_format == blink::kWebCryptoKeyFormatJwk) {
const base::DictionaryValue* json;
EXPECT_TRUE(test->GetDictionary("key", &json));
return MakeJsonVector(*json);
@@ -640,55 +638,55 @@ blink::WebCryptoNamedCurve GetCurveNameFromDictionary(
std::string curve_str;
if (!dict->GetString("crv", &curve_str)) {
ADD_FAILURE() << "Missing crv parameter";
- return blink::WebCryptoNamedCurveP384;
+ return blink::kWebCryptoNamedCurveP384;
}
if (curve_str == "P-256")
- return blink::WebCryptoNamedCurveP256;
+ return blink::kWebCryptoNamedCurveP256;
if (curve_str == "P-384")
- return blink::WebCryptoNamedCurveP384;
+ return blink::kWebCryptoNamedCurveP384;
if (curve_str == "P-521")
- return blink::WebCryptoNamedCurveP521;
+ return blink::kWebCryptoNamedCurveP521;
else
ADD_FAILURE() << "Unrecognized curve name: " << curve_str;
- return blink::WebCryptoNamedCurveP384;
+ return blink::kWebCryptoNamedCurveP384;
}
blink::WebCryptoAlgorithm CreateHmacImportAlgorithm(
blink::WebCryptoAlgorithmId hash_id,
unsigned int length_bits) {
- DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdHmac,
+ DCHECK(blink::WebCryptoAlgorithm::IsHash(hash_id));
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ blink::kWebCryptoAlgorithmIdHmac,
new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), true,
length_bits));
}
blink::WebCryptoAlgorithm CreateHmacImportAlgorithmNoLength(
blink::WebCryptoAlgorithmId hash_id) {
- DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdHmac,
+ DCHECK(blink::WebCryptoAlgorithm::IsHash(hash_id));
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
+ blink::kWebCryptoAlgorithmIdHmac,
new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), false, 0));
}
blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, nullptr);
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(id, nullptr);
}
blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm(
blink::WebCryptoAlgorithmId id,
blink::WebCryptoAlgorithmId hash_id) {
- DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ DCHECK(blink::WebCryptoAlgorithm::IsHash(hash_id));
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id)));
}
blink::WebCryptoAlgorithm CreateEcImportAlgorithm(
blink::WebCryptoAlgorithmId id,
blink::WebCryptoNamedCurve named_curve) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
id, new blink::WebCryptoEcKeyImportParams(named_curve));
}
diff --git a/chromium/components/webcrypto/algorithms/util.cc b/chromium/components/webcrypto/algorithms/util.cc
index 9deb678ff81..086f933b965 100644
--- a/chromium/components/webcrypto/algorithms/util.cc
+++ b/chromium/components/webcrypto/algorithms/util.cc
@@ -15,18 +15,18 @@
namespace webcrypto {
const EVP_MD* GetDigest(const blink::WebCryptoAlgorithm& hash_algorithm) {
- return GetDigest(hash_algorithm.id());
+ return GetDigest(hash_algorithm.Id());
}
const EVP_MD* GetDigest(blink::WebCryptoAlgorithmId id) {
switch (id) {
- case blink::WebCryptoAlgorithmIdSha1:
+ case blink::kWebCryptoAlgorithmIdSha1:
return EVP_sha1();
- case blink::WebCryptoAlgorithmIdSha256:
+ case blink::kWebCryptoAlgorithmIdSha256:
return EVP_sha256();
- case blink::WebCryptoAlgorithmIdSha384:
+ case blink::kWebCryptoAlgorithmIdSha384:
return EVP_sha384();
- case blink::WebCryptoAlgorithmIdSha512:
+ case blink::kWebCryptoAlgorithmIdSha512:
return EVP_sha512();
default:
return NULL;
diff --git a/chromium/components/webcrypto/blink_key_handle.cc b/chromium/components/webcrypto/blink_key_handle.cc
index c0c71b1d56b..389783c0ea2 100644
--- a/chromium/components/webcrypto/blink_key_handle.cc
+++ b/chromium/components/webcrypto/blink_key_handle.cc
@@ -84,19 +84,19 @@ class AsymKey : public Key {
};
Key* GetKey(const blink::WebCryptoKey& key) {
- return reinterpret_cast<Key*>(key.handle());
+ return reinterpret_cast<Key*>(key.Handle());
}
} // namespace
const std::vector<uint8_t>& GetSymmetricKeyData(
const blink::WebCryptoKey& key) {
- DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
+ DCHECK_EQ(blink::kWebCryptoKeyTypeSecret, key.GetType());
return GetKey(key)->AsSymKey()->raw_key_data();
}
EVP_PKEY* GetEVP_PKEY(const blink::WebCryptoKey& key) {
- DCHECK_NE(blink::WebCryptoKeyTypeSecret, key.type());
+ DCHECK_NE(blink::kWebCryptoKeyTypeSecret, key.GetType());
return GetKey(key)->AsAsymKey()->pkey();
}
diff --git a/chromium/components/webcrypto/crypto_data.cc b/chromium/components/webcrypto/crypto_data.cc
index f2937da3d86..222f5f2681c 100644
--- a/chromium/components/webcrypto/crypto_data.cc
+++ b/chromium/components/webcrypto/crypto_data.cc
@@ -24,8 +24,7 @@ CryptoData::CryptoData(const std::string& bytes)
}
CryptoData::CryptoData(const blink::WebVector<unsigned char>& bytes)
- : bytes_(bytes.data()),
- byte_length_(static_cast<unsigned int>(bytes.size())) {
-}
+ : bytes_(bytes.Data()),
+ byte_length_(static_cast<unsigned int>(bytes.size())) {}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/ec_import_key_pkcs8_fuzzer.cc b/chromium/components/webcrypto/ec_import_key_pkcs8_fuzzer.cc
index 154004cb22e..0f0ba7b4461 100644
--- a/chromium/components/webcrypto/ec_import_key_pkcs8_fuzzer.cc
+++ b/chromium/components/webcrypto/ec_import_key_pkcs8_fuzzer.cc
@@ -10,6 +10,6 @@
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
webcrypto::ImportEcKeyFromDerFuzzData(data, size,
- blink::WebCryptoKeyFormatPkcs8);
+ blink::kWebCryptoKeyFormatPkcs8);
return 0;
}
diff --git a/chromium/components/webcrypto/ec_import_key_spki_fuzzer.cc b/chromium/components/webcrypto/ec_import_key_spki_fuzzer.cc
index 7f16cfcacf9..a0cbef036bf 100644
--- a/chromium/components/webcrypto/ec_import_key_spki_fuzzer.cc
+++ b/chromium/components/webcrypto/ec_import_key_spki_fuzzer.cc
@@ -10,6 +10,6 @@
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
webcrypto::ImportEcKeyFromDerFuzzData(data, size,
- blink::WebCryptoKeyFormatSpki);
+ blink::kWebCryptoKeyFormatSpki);
return 0;
}
diff --git a/chromium/components/webcrypto/fuzzer_support.cc b/chromium/components/webcrypto/fuzzer_support.cc
index 4c5efc3a4df..832a9b87e15 100644
--- a/chromium/components/webcrypto/fuzzer_support.cc
+++ b/chromium/components/webcrypto/fuzzer_support.cc
@@ -23,7 +23,7 @@ class InitOnce : NON_EXPORTED_BASE(public blink::Platform) {
public:
InitOnce() {
base::CommandLine::Init(0, nullptr);
- blink::Platform::initialize(this);
+ blink::Platform::Initialize(this);
}
~InitOnce() override {}
};
@@ -37,17 +37,17 @@ void EnsureInitialized() {
blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm(
blink::WebCryptoAlgorithmId id,
blink::WebCryptoAlgorithmId hash_id) {
- DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ DCHECK(blink::WebCryptoAlgorithm::IsHash(hash_id));
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
id,
new blink::WebCryptoRsaHashedImportParams(
- blink::WebCryptoAlgorithm::adoptParamsAndCreate(hash_id, nullptr)));
+ blink::WebCryptoAlgorithm::AdoptParamsAndCreate(hash_id, nullptr)));
}
blink::WebCryptoAlgorithm CreateEcImportAlgorithm(
blink::WebCryptoAlgorithmId id,
blink::WebCryptoNamedCurve named_curve) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
id, new blink::WebCryptoEcKeyImportParams(named_curve));
}
@@ -58,26 +58,26 @@ blink::WebCryptoKeyUsageMask GetCompatibleKeyUsages(
// SPKI format implies import of a public key, whereas PKCS8 implies import
// of a private key. Pick usages that are compatible with a signature
// algorithm.
- return format == blink::WebCryptoKeyFormatSpki
- ? blink::WebCryptoKeyUsageVerify
- : blink::WebCryptoKeyUsageSign;
+ return format == blink::kWebCryptoKeyFormatSpki
+ ? blink::kWebCryptoKeyUsageVerify
+ : blink::kWebCryptoKeyUsageSign;
}
void ImportEcKeyFromDerFuzzData(const uint8_t* data,
size_t size,
blink::WebCryptoKeyFormat format) {
- DCHECK(format == blink::WebCryptoKeyFormatSpki ||
- format == blink::WebCryptoKeyFormatPkcs8);
+ DCHECK(format == blink::kWebCryptoKeyFormatSpki ||
+ format == blink::kWebCryptoKeyFormatPkcs8);
EnsureInitialized();
// There are 3 possible EC named curves. Fix this parameter. It shouldn't
// matter based on the current implementation for PKCS8 or SPKI. But it
// will have an impact when parsing JWK format.
- blink::WebCryptoNamedCurve curve = blink::WebCryptoNamedCurveP384;
+ blink::WebCryptoNamedCurve curve = blink::kWebCryptoNamedCurveP384;
// Always use ECDSA as the algorithm. Shouldn't make much difference for
// non-JWK formats.
- blink::WebCryptoAlgorithmId algorithm_id = blink::WebCryptoAlgorithmIdEcdsa;
+ blink::WebCryptoAlgorithmId algorithm_id = blink::kWebCryptoAlgorithmIdEcdsa;
// Use key usages that are compatible with the chosen algorithm and key type.
blink::WebCryptoKeyUsageMask usages = GetCompatibleKeyUsages(format);
@@ -111,25 +111,25 @@ void ImportEcKeyFromRawFuzzData(const uint8_t* data, size_t size) {
switch (curve_index % 3) {
case 0:
- curve = blink::WebCryptoNamedCurveP256;
+ curve = blink::kWebCryptoNamedCurveP256;
break;
case 1:
- curve = blink::WebCryptoNamedCurveP384;
+ curve = blink::kWebCryptoNamedCurveP384;
break;
default:
- curve = blink::WebCryptoNamedCurveP521;
+ curve = blink::kWebCryptoNamedCurveP521;
break;
}
// Always use ECDSA as the algorithm. Shouldn't make an difference for import.
- blink::WebCryptoAlgorithmId algorithm_id = blink::WebCryptoAlgorithmIdEcdsa;
+ blink::WebCryptoAlgorithmId algorithm_id = blink::kWebCryptoAlgorithmIdEcdsa;
// Use key usages that are compatible with the chosen algorithm and key type.
- blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageVerify;
+ blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageVerify;
blink::WebCryptoKey key;
webcrypto::Status status = webcrypto::ImportKey(
- blink::WebCryptoKeyFormatRaw,
+ blink::kWebCryptoKeyFormatRaw,
webcrypto::CryptoData(data, base::checked_cast<uint32_t>(size)),
CreateEcImportAlgorithm(algorithm_id, curve), true, usages, &key);
@@ -144,19 +144,19 @@ void ImportEcKeyFromRawFuzzData(const uint8_t* data, size_t size) {
void ImportRsaKeyFromDerFuzzData(const uint8_t* data,
size_t size,
blink::WebCryptoKeyFormat format) {
- DCHECK(format == blink::WebCryptoKeyFormatSpki ||
- format == blink::WebCryptoKeyFormatPkcs8);
+ DCHECK(format == blink::kWebCryptoKeyFormatSpki ||
+ format == blink::kWebCryptoKeyFormatPkcs8);
EnsureInitialized();
// There are several possible hash functions. Fix this parameter. It shouldn't
// matter based on the current implementation for PKCS8 or SPKI. But it
// will have an impact when parsing JWK format.
- blink::WebCryptoAlgorithmId hash_id = blink::WebCryptoAlgorithmIdSha256;
+ blink::WebCryptoAlgorithmId hash_id = blink::kWebCryptoAlgorithmIdSha256;
// Always use RSA-SSA PKCS#1 as the algorithm. Shouldn't make much difference
// for non-JWK formats.
blink::WebCryptoAlgorithmId algorithm_id =
- blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5;
+ blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5;
// Use key usages that are compatible with the chosen algorithm and key type.
blink::WebCryptoKeyUsageMask usages = GetCompatibleKeyUsages(format);
diff --git a/chromium/components/webcrypto/generate_key_result.cc b/chromium/components/webcrypto/generate_key_result.cc
index 3c0c4e85692..63b4050d211 100644
--- a/chromium/components/webcrypto/generate_key_result.cc
+++ b/chromium/components/webcrypto/generate_key_result.cc
@@ -48,10 +48,10 @@ void GenerateKeyResult::Complete(blink::WebCryptoResult* out) const {
NOTREACHED();
break;
case TYPE_SECRET_KEY:
- out->completeWithKey(secret_key());
+ out->CompleteWithKey(secret_key());
break;
case TYPE_PUBLIC_PRIVATE_KEY_PAIR:
- out->completeWithKeyPair(public_key(), private_key());
+ out->CompleteWithKeyPair(public_key(), private_key());
break;
}
}
diff --git a/chromium/components/webcrypto/jwk.cc b/chromium/components/webcrypto/jwk.cc
index ffe2e2e167a..326ce2b8862 100644
--- a/chromium/components/webcrypto/jwk.cc
+++ b/chromium/components/webcrypto/jwk.cc
@@ -40,11 +40,11 @@ namespace {
// Web Crypto equivalent usage mask for JWK 'use' = 'enc'.
const blink::WebCryptoKeyUsageMask kJwkEncUsage =
- blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
- blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey;
+ blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt |
+ blink::kWebCryptoKeyUsageWrapKey | blink::kWebCryptoKeyUsageUnwrapKey;
// Web Crypto equivalent usage mask for JWK 'use' = 'sig'.
const blink::WebCryptoKeyUsageMask kJwkSigUsage =
- blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
+ blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify;
// Checks that the "ext" member of the JWK is consistent with
// "expected_extractable".
@@ -69,14 +69,14 @@ struct JwkToWebCryptoUsageMapping {
// values". While this is not required for spec compliance,
// it makes the ordering of key_ops match that of WebCrypto's Key.usages.
const JwkToWebCryptoUsageMapping kJwkWebCryptoUsageMap[] = {
- {"encrypt", blink::WebCryptoKeyUsageEncrypt},
- {"decrypt", blink::WebCryptoKeyUsageDecrypt},
- {"sign", blink::WebCryptoKeyUsageSign},
- {"verify", blink::WebCryptoKeyUsageVerify},
- {"deriveKey", blink::WebCryptoKeyUsageDeriveKey},
- {"deriveBits", blink::WebCryptoKeyUsageDeriveBits},
- {"wrapKey", blink::WebCryptoKeyUsageWrapKey},
- {"unwrapKey", blink::WebCryptoKeyUsageUnwrapKey}};
+ {"encrypt", blink::kWebCryptoKeyUsageEncrypt},
+ {"decrypt", blink::kWebCryptoKeyUsageDecrypt},
+ {"sign", blink::kWebCryptoKeyUsageSign},
+ {"verify", blink::kWebCryptoKeyUsageVerify},
+ {"deriveKey", blink::kWebCryptoKeyUsageDeriveKey},
+ {"deriveBits", blink::kWebCryptoKeyUsageDeriveBits},
+ {"wrapKey", blink::kWebCryptoKeyUsageWrapKey},
+ {"unwrapKey", blink::kWebCryptoKeyUsageUnwrapKey}};
bool JwkKeyOpToWebCryptoUsage(const std::string& key_op,
blink::WebCryptoKeyUsage* usage) {
diff --git a/chromium/components/webcrypto/rsa_import_key_pkcs8_fuzzer.cc b/chromium/components/webcrypto/rsa_import_key_pkcs8_fuzzer.cc
index 184012299e5..aa9170f8623 100644
--- a/chromium/components/webcrypto/rsa_import_key_pkcs8_fuzzer.cc
+++ b/chromium/components/webcrypto/rsa_import_key_pkcs8_fuzzer.cc
@@ -10,6 +10,6 @@
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
webcrypto::ImportRsaKeyFromDerFuzzData(data, size,
- blink::WebCryptoKeyFormatPkcs8);
+ blink::kWebCryptoKeyFormatPkcs8);
return 0;
}
diff --git a/chromium/components/webcrypto/rsa_import_key_spki_fuzzer.cc b/chromium/components/webcrypto/rsa_import_key_spki_fuzzer.cc
index e91b1403738..9aa760f61f3 100644
--- a/chromium/components/webcrypto/rsa_import_key_spki_fuzzer.cc
+++ b/chromium/components/webcrypto/rsa_import_key_spki_fuzzer.cc
@@ -10,6 +10,6 @@
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
webcrypto::ImportRsaKeyFromDerFuzzData(data, size,
- blink::WebCryptoKeyFormatSpki);
+ blink::kWebCryptoKeyFormatSpki);
return 0;
}
diff --git a/chromium/components/webcrypto/status.cc b/chromium/components/webcrypto/status.cc
index 6ba4cbfccde..7dcbb93c888 100644
--- a/chromium/components/webcrypto/status.cc
+++ b/chromium/components/webcrypto/status.cc
@@ -22,170 +22,170 @@ Status Status::Success() {
}
Status Status::OperationError() {
- return Status(blink::WebCryptoErrorTypeOperation, "");
+ return Status(blink::kWebCryptoErrorTypeOperation, "");
}
Status Status::DataError() {
- return Status(blink::WebCryptoErrorTypeData, "");
+ return Status(blink::kWebCryptoErrorTypeData, "");
}
Status Status::ErrorJwkNotDictionary() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"JWK input could not be parsed to a JSON dictionary");
}
Status Status::ErrorJwkMemberMissing(const std::string& member_name) {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The required JWK member \"" + member_name + "\" was missing");
}
Status Status::ErrorJwkMemberWrongType(const std::string& member_name,
const std::string& expected_type) {
return Status(
- blink::WebCryptoErrorTypeData,
+ blink::kWebCryptoErrorTypeData,
"The JWK member \"" + member_name + "\" must be a " + expected_type);
}
Status Status::ErrorJwkBase64Decode(const std::string& member_name) {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The JWK member \"" + member_name +
"\" could not be base64url decoded or contained padding");
}
Status Status::ErrorJwkExtInconsistent() {
return Status(
- blink::WebCryptoErrorTypeData,
+ blink::kWebCryptoErrorTypeData,
"The \"ext\" member of the JWK dictionary is inconsistent what that "
"specified by the Web Crypto call");
}
Status Status::ErrorJwkAlgorithmInconsistent() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The JWK \"alg\" member was inconsistent with that specified "
"by the Web Crypto call");
}
Status Status::ErrorJwkUnrecognizedUse() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The JWK \"use\" member could not be parsed");
}
Status Status::ErrorJwkUnrecognizedKeyop() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The JWK \"key_ops\" member could not be parsed");
}
Status Status::ErrorJwkUseInconsistent() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The JWK \"use\" member was inconsistent with that specified "
"by the Web Crypto call. The JWK usage must be a superset of "
"those requested");
}
Status Status::ErrorJwkKeyopsInconsistent() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The JWK \"key_ops\" member was inconsistent with that "
"specified by the Web Crypto call. The JWK usage must be a "
"superset of those requested");
}
Status Status::ErrorJwkUseAndKeyopsInconsistent() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The JWK \"use\" and \"key_ops\" properties were both found "
"but are inconsistent with each other.");
}
Status Status::ErrorJwkUnexpectedKty(const std::string& expected) {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The JWK \"kty\" member was not \"" + expected + "\"");
}
Status Status::ErrorJwkIncorrectKeyLength() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The JWK \"k\" member did not include the right length "
"of key data for the given algorithm.");
}
Status Status::ErrorJwkEmptyBigInteger(const std::string& member_name) {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The JWK \"" + member_name + "\" member was empty.");
}
Status Status::ErrorJwkBigIntegerHasLeadingZero(
const std::string& member_name) {
return Status(
- blink::WebCryptoErrorTypeData,
+ blink::kWebCryptoErrorTypeData,
"The JWK \"" + member_name + "\" member contained a leading zero.");
}
Status Status::ErrorJwkDuplicateKeyOps() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The \"key_ops\" member of the JWK dictionary contains "
"duplicate usages.");
}
Status Status::ErrorUnsupportedImportKeyFormat() {
- return Status(blink::WebCryptoErrorTypeNotSupported,
+ return Status(blink::kWebCryptoErrorTypeNotSupported,
"Unsupported import key format for algorithm");
}
Status Status::ErrorUnsupportedExportKeyFormat() {
- return Status(blink::WebCryptoErrorTypeNotSupported,
+ return Status(blink::kWebCryptoErrorTypeNotSupported,
"Unsupported export key format for algorithm");
}
Status Status::ErrorImportAesKeyLength() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"AES key data must be 128 or 256 bits");
}
Status Status::ErrorGetAesKeyLength() {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
"AES key length must be 128 or 256 bits");
}
Status Status::ErrorGenerateAesKeyLength() {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
"AES key length must be 128 or 256 bits");
}
Status Status::ErrorAes192BitUnsupported() {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
"192-bit AES keys are not supported");
}
Status Status::ErrorUnexpectedKeyType() {
- return Status(blink::WebCryptoErrorTypeInvalidAccess,
+ return Status(blink::kWebCryptoErrorTypeInvalidAccess,
"The key is not of the expected type");
}
Status Status::ErrorIncorrectSizeAesCbcIv() {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
"The \"iv\" has an unexpected length -- must be 16 bytes");
}
Status Status::ErrorIncorrectSizeAesCtrCounter() {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
"The \"counter\" has an unexpected length -- must be 16 bytes");
}
Status Status::ErrorInvalidAesCtrCounterLength() {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
"The \"length\" member must be >= 1 and <= 128");
}
Status Status::ErrorAesCtrInputTooLongCounterRepeated() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The input is too large for the counter length.");
}
Status Status::ErrorDataTooLarge() {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
"The provided data is too large");
}
Status Status::ErrorDataTooSmall() {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
"The provided data is too small");
}
@@ -194,98 +194,98 @@ Status Status::ErrorUnsupported() {
}
Status Status::ErrorUnsupported(const std::string& message) {
- return Status(blink::WebCryptoErrorTypeNotSupported, message);
+ return Status(blink::kWebCryptoErrorTypeNotSupported, message);
}
Status Status::ErrorUnexpected() {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
"Something unexpected happened...");
}
Status Status::ErrorInvalidAesGcmTagLength() {
return Status(
- blink::WebCryptoErrorTypeOperation,
+ blink::kWebCryptoErrorTypeOperation,
"The tag length is invalid: Must be 32, 64, 96, 104, 112, 120, or 128 "
"bits");
}
Status Status::ErrorInvalidAesKwDataLength() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The AES-KW input data length is invalid: not a multiple of 8 "
"bytes");
}
Status Status::ErrorGenerateKeyPublicExponent() {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
"The \"publicExponent\" must be either 3 or 65537");
}
Status Status::ErrorImportRsaEmptyModulus() {
- return Status(blink::WebCryptoErrorTypeData, "The modulus is empty");
+ return Status(blink::kWebCryptoErrorTypeData, "The modulus is empty");
}
Status Status::ErrorGenerateRsaUnsupportedModulus() {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
"The modulus length must be a multiple of 8 bits and >= 256 "
"and <= 16384");
}
Status Status::ErrorImportRsaEmptyExponent() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"No bytes for the exponent were provided");
}
Status Status::ErrorKeyNotExtractable() {
- return Status(blink::WebCryptoErrorTypeInvalidAccess,
+ return Status(blink::kWebCryptoErrorTypeInvalidAccess,
"They key is not extractable");
}
Status Status::ErrorGenerateHmacKeyLengthZero() {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
"HMAC key length must not be zero");
}
Status Status::ErrorHmacImportEmptyKey() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"HMAC key data must not be empty");
}
Status Status::ErrorGetHmacKeyLengthZero() {
- return Status(blink::WebCryptoErrorTypeType,
+ return Status(blink::kWebCryptoErrorTypeType,
"HMAC key length must not be zero");
}
Status Status::ErrorHmacImportBadLength() {
return Status(
- blink::WebCryptoErrorTypeData,
+ blink::kWebCryptoErrorTypeData,
"The optional HMAC key length must be shorter than the key data, and by "
"no more than 7 bits.");
}
Status Status::ErrorCreateKeyBadUsages() {
- return Status(blink::WebCryptoErrorTypeSyntax,
+ return Status(blink::kWebCryptoErrorTypeSyntax,
"Cannot create a key using the specified key usages.");
}
Status Status::ErrorCreateKeyEmptyUsages() {
- return Status(blink::WebCryptoErrorTypeSyntax,
+ return Status(blink::kWebCryptoErrorTypeSyntax,
"Usages cannot be empty when creating a key.");
}
Status Status::ErrorImportedEcKeyIncorrectCurve() {
return Status(
- blink::WebCryptoErrorTypeData,
+ blink::kWebCryptoErrorTypeData,
"The imported EC key specifies a different curve than requested");
}
Status Status::ErrorJwkIncorrectCrv() {
return Status(
- blink::WebCryptoErrorTypeData,
+ blink::kWebCryptoErrorTypeData,
"The JWK's \"crv\" member specifies a different curve than requested");
}
Status Status::ErrorEcKeyInvalid() {
- return Status(blink::WebCryptoErrorTypeData,
+ return Status(blink::kWebCryptoErrorTypeData,
"The imported EC key is invalid");
}
@@ -293,7 +293,7 @@ Status Status::JwkOctetStringWrongLength(const std::string& member_name,
size_t expected_length,
size_t actual_length) {
return Status(
- blink::WebCryptoErrorTypeData,
+ blink::kWebCryptoErrorTypeData,
base::StringPrintf(
"The JWK's \"%s\" member defines an octet string of length %" PRIuS
" bytes but should be %" PRIuS,
@@ -302,24 +302,24 @@ Status Status::JwkOctetStringWrongLength(const std::string& member_name,
Status Status::ErrorEcdhPublicKeyWrongType() {
return Status(
- blink::WebCryptoErrorTypeInvalidAccess,
+ blink::kWebCryptoErrorTypeInvalidAccess,
"The public parameter for ECDH key derivation is not a public EC key");
}
Status Status::ErrorEcdhPublicKeyWrongAlgorithm() {
return Status(
- blink::WebCryptoErrorTypeInvalidAccess,
+ blink::kWebCryptoErrorTypeInvalidAccess,
"The public parameter for ECDH key derivation must be for ECDH");
}
Status Status::ErrorEcdhCurveMismatch() {
- return Status(blink::WebCryptoErrorTypeInvalidAccess,
+ return Status(blink::kWebCryptoErrorTypeInvalidAccess,
"The public parameter for ECDH key derivation is for a "
"different named curve");
}
Status Status::ErrorEcdhLengthTooBig(unsigned int max_length_bits) {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
base::StringPrintf(
"Length specified for ECDH key derivation is too large. "
"Maximum allowed is %u bits",
@@ -327,7 +327,7 @@ Status Status::ErrorEcdhLengthTooBig(unsigned int max_length_bits) {
}
Status Status::ErrorHkdfLengthTooLong() {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
"The length provided for HKDF is too large.");
}
@@ -335,35 +335,35 @@ Status Status::ErrorHkdfDeriveBitsLengthNotSpecified() {
// TODO(nharper): The spec might change so that an OperationError should be
// thrown here instead of a TypeError.
// (https://www.w3.org/Bugs/Public/show_bug.cgi?id=27771)
- return Status(blink::WebCryptoErrorTypeType,
+ return Status(blink::kWebCryptoErrorTypeType,
"No length was specified for the HKDF Derive Bits operation.");
}
Status Status::ErrorPbkdf2InvalidLength() {
return Status(
- blink::WebCryptoErrorTypeOperation,
+ blink::kWebCryptoErrorTypeOperation,
"Length for PBKDF2 key derivation must be a multiple of 8 bits.");
}
Status Status::ErrorPbkdf2DeriveBitsLengthNotSpecified() {
return Status(
- blink::WebCryptoErrorTypeOperation,
+ blink::kWebCryptoErrorTypeOperation,
"No length was specified for the PBKDF2 Derive Bits operation.");
}
Status Status::ErrorPbkdf2DeriveBitsLengthZero() {
return Status(
- blink::WebCryptoErrorTypeOperation,
+ blink::kWebCryptoErrorTypeOperation,
"A length of 0 was specified for PBKDF2's Derive Bits operation.");
}
Status Status::ErrorPbkdf2Iterations0() {
- return Status(blink::WebCryptoErrorTypeOperation,
+ return Status(blink::kWebCryptoErrorTypeOperation,
"PBKDF2 requires iterations > 0");
}
Status Status::ErrorImportExtractableKdfKey() {
- return Status(blink::WebCryptoErrorTypeSyntax,
+ return Status(blink::kWebCryptoErrorTypeSyntax,
"KDF keys must set extractable=false");
}
diff --git a/chromium/components/webcrypto/status_unittest.cc b/chromium/components/webcrypto/status_unittest.cc
index ad79136f5ef..b831cebd748 100644
--- a/chromium/components/webcrypto/status_unittest.cc
+++ b/chromium/components/webcrypto/status_unittest.cc
@@ -37,28 +37,28 @@ TEST(WebCryptoStatusTest, Basic) {
status = Status::OperationError();
EXPECT_TRUE(status.IsError());
EXPECT_EQ("", status.error_details());
- EXPECT_EQ(blink::WebCryptoErrorTypeOperation, status.error_type());
+ EXPECT_EQ(blink::kWebCryptoErrorTypeOperation, status.error_type());
status = Status::DataError();
EXPECT_TRUE(status.IsError());
EXPECT_EQ("", status.error_details());
- EXPECT_EQ(blink::WebCryptoErrorTypeData, status.error_type());
+ EXPECT_EQ(blink::kWebCryptoErrorTypeData, status.error_type());
status = Status::ErrorUnsupported();
EXPECT_TRUE(status.IsError());
EXPECT_EQ("The requested operation is unsupported", status.error_details());
- EXPECT_EQ(blink::WebCryptoErrorTypeNotSupported, status.error_type());
+ EXPECT_EQ(blink::kWebCryptoErrorTypeNotSupported, status.error_type());
status = Status::ErrorJwkMemberMissing("kty");
EXPECT_TRUE(status.IsError());
EXPECT_EQ("The required JWK member \"kty\" was missing",
status.error_details());
- EXPECT_EQ(blink::WebCryptoErrorTypeData, status.error_type());
+ EXPECT_EQ(blink::kWebCryptoErrorTypeData, status.error_type());
status = Status::ErrorJwkMemberWrongType("kty", "string");
EXPECT_TRUE(status.IsError());
EXPECT_EQ("The JWK member \"kty\" must be a string", status.error_details());
- EXPECT_EQ(blink::WebCryptoErrorTypeData, status.error_type());
+ EXPECT_EQ(blink::kWebCryptoErrorTypeData, status.error_type());
status = Status::ErrorJwkBase64Decode("n");
EXPECT_TRUE(status.IsError());
@@ -66,7 +66,7 @@ TEST(WebCryptoStatusTest, Basic) {
"The JWK member \"n\" could not be base64url decoded or contained "
"padding",
status.error_details());
- EXPECT_EQ(blink::WebCryptoErrorTypeData, status.error_type());
+ EXPECT_EQ(blink::kWebCryptoErrorTypeData, status.error_type());
}
} // namespace
diff --git a/chromium/components/webcrypto/webcrypto_impl.cc b/chromium/components/webcrypto/webcrypto_impl.cc
index cac891e7a4b..8a97e4d450b 100644
--- a/chromium/components/webcrypto/webcrypto_impl.cc
+++ b/chromium/components/webcrypto/webcrypto_impl.cc
@@ -101,15 +101,15 @@ bool CryptoThreadPool::PostTask(const tracked_objects::Location& from_here,
}
void CompleteWithThreadPoolError(blink::WebCryptoResult* result) {
- result->completeWithError(blink::WebCryptoErrorTypeOperation,
+ result->CompleteWithError(blink::kWebCryptoErrorTypeOperation,
"Failed posting to crypto worker pool");
}
void CompleteWithError(const Status& status, blink::WebCryptoResult* result) {
DCHECK(status.IsError());
- result->completeWithError(status.error_type(),
- blink::WebString::fromUTF8(status.error_details()));
+ result->CompleteWithError(status.error_type(),
+ blink::WebString::FromUTF8(status.error_details()));
}
void CompleteWithBufferOrError(const Status& status,
@@ -123,7 +123,7 @@ void CompleteWithBufferOrError(const Status& status,
// theoretically this could overflow.
CompleteWithError(Status::ErrorUnexpected(), result);
} else {
- result->completeWithBuffer(buffer.data(),
+ result->CompleteWithBuffer(buffer.data(),
static_cast<unsigned int>(buffer.size()));
}
}
@@ -135,7 +135,7 @@ void CompleteWithKeyOrError(const Status& status,
if (status.IsError()) {
CompleteWithError(status, result);
} else {
- result->completeWithKey(key);
+ result->CompleteWithKey(key);
}
}
@@ -166,7 +166,7 @@ struct BaseState {
explicit BaseState(const blink::WebCryptoResult& result)
: origin_thread(GetCurrentBlinkThread()), result(result) {}
- bool cancelled() { return result.cancelled(); }
+ bool cancelled() { return result.Cancelled(); }
scoped_refptr<base::TaskRunner> origin_thread;
@@ -448,9 +448,9 @@ void DoImportKey(std::unique_ptr<ImportKeyState> passed_state) {
state->format, webcrypto::CryptoData(state->key_data), state->algorithm,
state->extractable, state->usages, &state->key);
if (state->status.IsSuccess()) {
- DCHECK(state->key.handle());
- DCHECK(!state->key.algorithm().isNull());
- DCHECK_EQ(state->extractable, state->key.extractable());
+ DCHECK(state->key.Handle());
+ DCHECK(!state->key.Algorithm().IsNull());
+ DCHECK_EQ(state->extractable, state->key.Extractable());
}
state->origin_thread->PostTask(
@@ -458,7 +458,7 @@ void DoImportKey(std::unique_ptr<ImportKeyState> passed_state) {
}
void DoExportKeyReply(std::unique_ptr<ExportKeyState> state) {
- if (state->format != blink::WebCryptoKeyFormatJwk) {
+ if (state->format != blink::kWebCryptoKeyFormatJwk) {
CompleteWithBufferOrError(state->status, state->buffer, &state->result);
return;
}
@@ -466,7 +466,7 @@ void DoExportKeyReply(std::unique_ptr<ExportKeyState> state) {
if (state->status.IsError()) {
CompleteWithError(state->status, &state->result);
} else {
- state->result.completeWithJson(
+ state->result.CompleteWithJson(
reinterpret_cast<const char*>(state->buffer.data()),
static_cast<unsigned int>(state->buffer.size()));
}
@@ -502,7 +502,7 @@ void DoVerifyReply(std::unique_ptr<VerifySignatureState> state) {
if (state->status.IsError()) {
CompleteWithError(state->status, &state->result);
} else {
- state->result.completeWithBoolean(state->verify_result);
+ state->result.CompleteWithBoolean(state->verify_result);
}
}
@@ -592,11 +592,11 @@ WebCryptoImpl::WebCryptoImpl() {
WebCryptoImpl::~WebCryptoImpl() {
}
-void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm,
+void WebCryptoImpl::Encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) {
- DCHECK(!algorithm.isNull());
+ DCHECK(!algorithm.IsNull());
std::unique_ptr<EncryptState> state(
new EncryptState(algorithm, key, std::move(data), result));
@@ -606,11 +606,11 @@ void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm,
}
}
-void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm,
+void WebCryptoImpl::Decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) {
- DCHECK(!algorithm.isNull());
+ DCHECK(!algorithm.IsNull());
std::unique_ptr<DecryptState> state(
new DecryptState(algorithm, key, std::move(data), result));
@@ -620,24 +620,24 @@ void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm,
}
}
-void WebCryptoImpl::digest(const blink::WebCryptoAlgorithm& algorithm,
+void WebCryptoImpl::Digest(const blink::WebCryptoAlgorithm& algorithm,
blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) {
- DCHECK(!algorithm.isNull());
+ DCHECK(!algorithm.IsNull());
std::unique_ptr<DigestState> state(new DigestState(
- algorithm, blink::WebCryptoKey::createNull(), std::move(data), result));
+ algorithm, blink::WebCryptoKey::CreateNull(), std::move(data), result));
if (!CryptoThreadPool::PostTask(FROM_HERE,
base::Bind(DoDigest, base::Passed(&state)))) {
CompleteWithThreadPoolError(&result);
}
}
-void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm,
+void WebCryptoImpl::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoResult result) {
- DCHECK(!algorithm.isNull());
+ DCHECK(!algorithm.IsNull());
std::unique_ptr<GenerateKeyState> state(
new GenerateKeyState(algorithm, extractable, usages, result));
@@ -647,7 +647,7 @@ void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm,
}
}
-void WebCryptoImpl::importKey(blink::WebCryptoKeyFormat format,
+void WebCryptoImpl::ImportKey(blink::WebCryptoKeyFormat format,
blink::WebVector<unsigned char> key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
@@ -661,7 +661,7 @@ void WebCryptoImpl::importKey(blink::WebCryptoKeyFormat format,
}
}
-void WebCryptoImpl::exportKey(blink::WebCryptoKeyFormat format,
+void WebCryptoImpl::ExportKey(blink::WebCryptoKeyFormat format,
const blink::WebCryptoKey& key,
blink::WebCryptoResult result) {
std::unique_ptr<ExportKeyState> state(
@@ -672,7 +672,7 @@ void WebCryptoImpl::exportKey(blink::WebCryptoKeyFormat format,
}
}
-void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm,
+void WebCryptoImpl::Sign(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) {
@@ -684,7 +684,7 @@ void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm,
}
}
-void WebCryptoImpl::verifySignature(const blink::WebCryptoAlgorithm& algorithm,
+void WebCryptoImpl::VerifySignature(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
blink::WebVector<unsigned char> signature,
blink::WebVector<unsigned char> data,
@@ -697,7 +697,7 @@ void WebCryptoImpl::verifySignature(const blink::WebCryptoAlgorithm& algorithm,
}
}
-void WebCryptoImpl::wrapKey(blink::WebCryptoKeyFormat format,
+void WebCryptoImpl::WrapKey(blink::WebCryptoKeyFormat format,
const blink::WebCryptoKey& key,
const blink::WebCryptoKey& wrapping_key,
const blink::WebCryptoAlgorithm& wrap_algorithm,
@@ -710,7 +710,7 @@ void WebCryptoImpl::wrapKey(blink::WebCryptoKeyFormat format,
}
}
-void WebCryptoImpl::unwrapKey(
+void WebCryptoImpl::UnwrapKey(
blink::WebCryptoKeyFormat format,
blink::WebVector<unsigned char> wrapped_key,
const blink::WebCryptoKey& wrapping_key,
@@ -728,7 +728,7 @@ void WebCryptoImpl::unwrapKey(
}
}
-void WebCryptoImpl::deriveBits(const blink::WebCryptoAlgorithm& algorithm,
+void WebCryptoImpl::DeriveBits(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& base_key,
unsigned int length_bits,
blink::WebCryptoResult result) {
@@ -740,7 +740,7 @@ void WebCryptoImpl::deriveBits(const blink::WebCryptoAlgorithm& algorithm,
}
}
-void WebCryptoImpl::deriveKey(
+void WebCryptoImpl::DeriveKey(
const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& base_key,
const blink::WebCryptoAlgorithm& import_algorithm,
@@ -757,12 +757,12 @@ void WebCryptoImpl::deriveKey(
}
}
-std::unique_ptr<blink::WebCryptoDigestor> WebCryptoImpl::createDigestor(
+std::unique_ptr<blink::WebCryptoDigestor> WebCryptoImpl::CreateDigestor(
blink::WebCryptoAlgorithmId algorithm_id) {
return webcrypto::CreateDigestor(algorithm_id);
}
-bool WebCryptoImpl::deserializeKeyForClone(
+bool WebCryptoImpl::DeserializeKeyForClone(
const blink::WebCryptoKeyAlgorithm& algorithm,
blink::WebCryptoKeyType type,
bool extractable,
@@ -775,7 +775,7 @@ bool WebCryptoImpl::deserializeKeyForClone(
webcrypto::CryptoData(key_data, key_data_size), &key);
}
-bool WebCryptoImpl::serializeKeyForClone(
+bool WebCryptoImpl::SerializeKeyForClone(
const blink::WebCryptoKey& key,
blink::WebVector<unsigned char>& key_data) {
return webcrypto::SerializeKeyForClone(key, &key_data);
diff --git a/chromium/components/webcrypto/webcrypto_impl.h b/chromium/components/webcrypto/webcrypto_impl.h
index 20de3ed802d..261359cdce3 100644
--- a/chromium/components/webcrypto/webcrypto_impl.h
+++ b/chromium/components/webcrypto/webcrypto_impl.h
@@ -25,45 +25,45 @@ class WebCryptoImpl : public blink::WebCrypto {
~WebCryptoImpl() override;
- void encrypt(const blink::WebCryptoAlgorithm& algorithm,
+ void Encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) override;
- void decrypt(const blink::WebCryptoAlgorithm& algorithm,
+ void Decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) override;
- void digest(const blink::WebCryptoAlgorithm& algorithm,
+ void Digest(const blink::WebCryptoAlgorithm& algorithm,
blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) override;
- void generateKey(const blink::WebCryptoAlgorithm& algorithm,
+ void GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoResult result) override;
- void importKey(blink::WebCryptoKeyFormat format,
+ void ImportKey(blink::WebCryptoKeyFormat format,
blink::WebVector<unsigned char> key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoResult result) override;
- void exportKey(blink::WebCryptoKeyFormat format,
+ void ExportKey(blink::WebCryptoKeyFormat format,
const blink::WebCryptoKey& key,
blink::WebCryptoResult result) override;
- void sign(const blink::WebCryptoAlgorithm& algorithm,
+ void Sign(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) override;
- void verifySignature(const blink::WebCryptoAlgorithm& algorithm,
+ void VerifySignature(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
blink::WebVector<unsigned char> signature,
blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) override;
- void wrapKey(blink::WebCryptoKeyFormat format,
+ void WrapKey(blink::WebCryptoKeyFormat format,
const blink::WebCryptoKey& key,
const blink::WebCryptoKey& wrapping_key,
const blink::WebCryptoAlgorithm& wrap_algorithm,
blink::WebCryptoResult result) override;
- void unwrapKey(blink::WebCryptoKeyFormat format,
+ void UnwrapKey(blink::WebCryptoKeyFormat format,
blink::WebVector<unsigned char> wrapped_key,
const blink::WebCryptoKey& wrapping_key,
const blink::WebCryptoAlgorithm& unwrap_algorithm,
@@ -72,12 +72,12 @@ class WebCryptoImpl : public blink::WebCrypto {
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoResult result) override;
- void deriveBits(const blink::WebCryptoAlgorithm& algorithm,
+ void DeriveBits(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& base_key,
unsigned int length_bits,
blink::WebCryptoResult result) override;
- void deriveKey(const blink::WebCryptoAlgorithm& algorithm,
+ void DeriveKey(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& base_key,
const blink::WebCryptoAlgorithm& import_algorithm,
const blink::WebCryptoAlgorithm& key_length_algorithm,
@@ -89,10 +89,10 @@ class WebCryptoImpl : public blink::WebCrypto {
// compute a digest one chunk at a time. Thus, the consume does not need to
// hold onto a large buffer with all the data to digest. Chunks can be given
// one at a time and the digest will be computed piecemeal.
- std::unique_ptr<blink::WebCryptoDigestor> createDigestor(
+ std::unique_ptr<blink::WebCryptoDigestor> CreateDigestor(
blink::WebCryptoAlgorithmId algorithm_id) override;
- bool deserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
+ bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
blink::WebCryptoKeyType type,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
@@ -100,7 +100,7 @@ class WebCryptoImpl : public blink::WebCrypto {
unsigned key_data_size,
blink::WebCryptoKey& key) override;
- bool serializeKeyForClone(const blink::WebCryptoKey& key,
+ bool SerializeKeyForClone(const blink::WebCryptoKey& key,
blink::WebVector<unsigned char>& key_data) override;
private:
diff --git a/chromium/components/webdata/OWNERS b/chromium/components/webdata/OWNERS
index 882e1e2813d..986f4a93a9d 100644
--- a/chromium/components/webdata/OWNERS
+++ b/chromium/components/webdata/OWNERS
@@ -1,6 +1,6 @@
pkasting@chromium.org
# For sqlite stuff:
-shess@chromium.org
+pwnall@chromium.org
# COMPONENT: Internals
diff --git a/chromium/components/webdata_services/BUILD.gn b/chromium/components/webdata_services/BUILD.gn
index 1818a437aa5..aa4b4a20489 100644
--- a/chromium/components/webdata_services/BUILD.gn
+++ b/chromium/components/webdata_services/BUILD.gn
@@ -21,6 +21,10 @@ static_library("webdata_services") {
"//components/webdata/common",
"//sql",
]
+
+ if (is_android) {
+ deps += [ "//components/payments/android" ]
+ }
}
static_library("test_support") {
diff --git a/chromium/components/webdata_services/DEPS b/chromium/components/webdata_services/DEPS
index ff4a094d4ac..2b14aa6ec6e 100644
--- a/chromium/components/webdata_services/DEPS
+++ b/chromium/components/webdata_services/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+components/autofill/core/browser/webdata",
"+components/keyed_service/core",
"+components/password_manager/core/browser/webdata",
+ "+components/payments/android",
"+components/search_engines/keyword_table.h",
"+components/search_engines/keyword_web_data_service.h",
"+components/signin/core/browser/webdata",
diff --git a/chromium/components/webdata_services/OWNERS b/chromium/components/webdata_services/OWNERS
index 882e1e2813d..986f4a93a9d 100644
--- a/chromium/components/webdata_services/OWNERS
+++ b/chromium/components/webdata_services/OWNERS
@@ -1,6 +1,6 @@
pkasting@chromium.org
# For sqlite stuff:
-shess@chromium.org
+pwnall@chromium.org
# COMPONENT: Internals
diff --git a/chromium/components/webdata_services/web_data_service_wrapper.cc b/chromium/components/webdata_services/web_data_service_wrapper.cc
index a8ff689fe48..f0c068a84c2 100644
--- a/chromium/components/webdata_services/web_data_service_wrapper.cc
+++ b/chromium/components/webdata_services/web_data_service_wrapper.cc
@@ -31,6 +31,11 @@
#include "components/password_manager/core/browser/webdata/password_web_data_service_win.h"
#endif
+#if defined(OS_ANDROID)
+#include "components/payments/android/payment_method_manifest_table.h"
+#include "components/payments/android/web_app_manifest_section_table.h"
+#endif
+
namespace {
void InitSyncableServicesOnDBThread(
@@ -86,13 +91,19 @@ WebDataServiceWrapper::WebDataServiceWrapper(
// All tables objects that participate in managing the database must
// be added here.
- web_database_->AddTable(base::WrapUnique(new autofill::AutofillTable));
- web_database_->AddTable(base::WrapUnique(new KeywordTable));
+ web_database_->AddTable(base::MakeUnique<autofill::AutofillTable>());
+ web_database_->AddTable(base::MakeUnique<KeywordTable>());
// TODO(mdm): We only really need the LoginsTable on Windows for IE7 password
// access, but for now, we still create it on all platforms since it deletes
// the old logins table. We can remove this after a while, e.g. in M22 or so.
- web_database_->AddTable(base::WrapUnique(new LoginsTable));
- web_database_->AddTable(base::WrapUnique(new TokenServiceTable));
+ web_database_->AddTable(base::MakeUnique<LoginsTable>());
+ web_database_->AddTable(base::MakeUnique<TokenServiceTable>());
+#if defined(OS_ANDROID)
+ web_database_->AddTable(
+ base::MakeUnique<payments::PaymentMethodManifestTable>());
+ web_database_->AddTable(
+ base::MakeUnique<payments::WebAppManifestSectionTable>());
+#endif
web_database_->LoadDatabase();
autofill_web_data_ = new autofill::AutofillWebDataService(
diff --git a/chromium/components/wifi/fake_wifi_service.cc b/chromium/components/wifi/fake_wifi_service.cc
index bbf3f8e4f01..e3a46836a0f 100644
--- a/chromium/components/wifi/fake_wifi_service.cc
+++ b/chromium/components/wifi/fake_wifi_service.cc
@@ -5,9 +5,11 @@
#include "components/wifi/fake_wifi_service.h"
#include <memory>
+#include <utility>
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
+#include "base/values.h"
#include "components/onc/onc_constants.h"
namespace wifi {
@@ -118,7 +120,7 @@ void FakeWiFiService::GetVisibleNetworks(const std::string& network_type,
it->type == network_type) {
std::unique_ptr<base::DictionaryValue> network(
it->ToValue(!include_details));
- network_list->Append(network.release());
+ network_list->Append(std::move(network));
}
}
}
diff --git a/chromium/components/wifi/wifi_service_mac.mm b/chromium/components/wifi/wifi_service_mac.mm
index 17ee60cf6d8..5b43a4af897 100644
--- a/chromium/components/wifi/wifi_service_mac.mm
+++ b/chromium/components/wifi/wifi_service_mac.mm
@@ -8,6 +8,8 @@
#import <netinet/in.h>
#import <SystemConfiguration/SystemConfiguration.h>
+#include <utility>
+
#include "base/bind.h"
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
@@ -16,6 +18,7 @@
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/sys_string_conversions.h"
+#include "base/values.h"
#include "components/onc/onc_constants.h"
#include "components/wifi/network_properties.h"
#include "crypto/apple_keychain.h"
@@ -264,7 +267,7 @@ void WiFiServiceMac::GetVisibleNetworks(const std::string& network_type,
++it) {
std::unique_ptr<base::DictionaryValue> network(
it->ToValue(!include_details));
- network_list->Append(network.release());
+ network_list->Append(std::move(network));
}
}
diff --git a/chromium/components/zoom/OWNERS b/chromium/components/zoom/OWNERS
index aede3068c3a..2cd925c2d95 100644
--- a/chromium/components/zoom/OWNERS
+++ b/chromium/components/zoom/OWNERS
@@ -1,2 +1,4 @@
dbeam@chromium.org
wjmaclean@chromium.org
+
+# COMPONENT: UI>Browser>Zoom
diff --git a/chromium/components/zoom/page_zoom.cc b/chromium/components/zoom/page_zoom.cc
index bbd1a745ea7..98dea1e6b2b 100644
--- a/chromium/components/zoom/page_zoom.cc
+++ b/chromium/components/zoom/page_zoom.cc
@@ -9,12 +9,12 @@
#include <algorithm>
#include <cmath>
+#include "base/metrics/user_metrics.h"
#include "components/prefs/pref_service.h"
#include "components/zoom/page_zoom_constants.h"
#include "components/zoom/zoom_controller.h"
#include "content/public/browser/host_zoom_map.h"
#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/page_zoom.h"
#include "content/public/common/renderer_preferences.h"
@@ -86,7 +86,7 @@ void PageZoom::Zoom(content::WebContents* web_contents,
if (zoom == content::PAGE_ZOOM_RESET) {
zoom_controller->SetZoomLevel(default_zoom_level);
web_contents->SetPageScale(1.f);
- content::RecordAction(UserMetricsAction("ZoomNormal"));
+ base::RecordAction(UserMetricsAction("ZoomNormal"));
return;
}
@@ -104,11 +104,11 @@ void PageZoom::Zoom(content::WebContents* web_contents,
continue;
if (zoom_level < current_zoom_level) {
zoom_controller->SetZoomLevel(zoom_level);
- content::RecordAction(UserMetricsAction("ZoomMinus"));
+ base::RecordAction(UserMetricsAction("ZoomMinus"));
return;
}
}
- content::RecordAction(UserMetricsAction("ZoomMinus_AtMinimum"));
+ base::RecordAction(UserMetricsAction("ZoomMinus_AtMinimum"));
} else {
// Iterate through the zoom levels in normal order to find the next
// higher level based on the current zoom level for this page.
@@ -119,11 +119,11 @@ void PageZoom::Zoom(content::WebContents* web_contents,
continue;
if (zoom_level > current_zoom_level) {
zoom_controller->SetZoomLevel(zoom_level);
- content::RecordAction(UserMetricsAction("ZoomPlus"));
+ base::RecordAction(UserMetricsAction("ZoomPlus"));
return;
}
}
- content::RecordAction(UserMetricsAction("ZoomPlus_AtMaximum"));
+ base::RecordAction(UserMetricsAction("ZoomPlus_AtMaximum"));
}
}
diff --git a/chromium/components/zoom/zoom_controller.cc b/chromium/components/zoom/zoom_controller.cc
index 8d258a5d7ad..dd3dafcd4b2 100644
--- a/chromium/components/zoom/zoom_controller.cc
+++ b/chromium/components/zoom/zoom_controller.cc
@@ -293,7 +293,7 @@ void ZoomController::DidFinishNavigation(
if (navigation_handle->IsErrorPage())
content::HostZoomMap::SendErrorPageZoomLevelRefresh(web_contents());
- if (!navigation_handle->IsSamePage())
+ if (!navigation_handle->IsSameDocument())
ResetZoomModeOnNavigationIfNeeded(navigation_handle->GetURL());
// If the main frame's content has changed, the new page may have a different